6

I am writing a very basic SSL client to connect to a HTTPS web server. I can connect and process the request/response just fine. However OpenSSL is reporting UNABLE_TO_GET_ISSUER_CERT_LOCALLY, but so far I choose to ignore the error :-). Now I want to solve that part of the problem.

I am testing by connecting to a public SSL server on HTTPS, such as Google or Yahoo, and checking the return of SSL_get_verify_result(...).

As I understand it, I need the CA pem files for that specific site so that OpenSSL can verify the chain to a trusted certificate authority. In this case, that would be the authority that signed the certs for Google or Yahoo.

To get the PEM files which I expect should work, I opened my FireFox, navigated to those sites, and performed a View Certificate and exported each one up the list. So for example, I have a file called "GeoTrustGlobalCA.pem" which all looks good. In fact, when I went to the GeoTrust site directly and downloaded their root certificate, it is identical to the one I exported from FireFox, as I would expect.

So, for example with Google which showed two certificates in the tree in FireFox, I load each one with:

result = SSL_CTX_load_verify_locations(ctx,"GoogleInternetAuthorityG2.pem",NULL);
if (result == 0) {
    puts("Opps...  Can't load the certificate");
}

result = SSL_CTX_load_verify_locations(ctx,"GeoTrustGlobalCA.pem",NULL);
if (result == 0) {
    puts("Opps...  Can't load the certificate");
}

After that, the usual stuff to connect and communicate:

BIO_set_conn_hostname(bio, "www.google.com:https");

And get no errors when loading or connecting.

However, the verification does not work.

result = SSL_get_verify_result(ssl);
printf("The Verify Result is %d \n",result);

I get the return UNABLE_TO_GET_ISSUER_CERT_LOCALLY (error code 20).

So, am I missing some concept here? Wouldn't this give me the X509_V_OK result because it has the trusted certificates? There were only two that were up the chain from google.com, and I used them.

SpacemanScott
  • 953
  • 9
  • 21

2 Answers2

2

The second call to SSL_CTX_load_verify_locations is replacing the certificate from the first call.

You should combine your roots into a single file:

$ cat my-trusted-roots.pem
-----BEGIN CERTIFICATE-----
... (CA certificate in base64 encoding) ...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (CA certificate in base64 encoding) ...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (CA certificate in base64 encoding) ...
-----END CERTIFICATE-----

And then load that single file with SSL_CTX_load_verify_locations. See the OpenSSL docs on SSL_CTX_load_verify_locations. In partuclar, the NOTES section:

If CAfile is not NULL, it points to a file of CA certificates in PEM format. The file can contain several CA certificates identified by

-----BEGIN CERTIFICATE-----

... (CA certificate in base64 encoding) ...

-----END CERTIFICATE-----

sequences. Before, between, and after the certificates text is allowed which can be used e.g. for descriptions of the certificates.


Just bike shedding here...

result = SSL_get_verify_result(ssl);
printf("The Verify Result is %d \n",result);

That's one of three tests you need to perform.

The second test you need to perform is below. Anonymous Diffie-Hellman (ADH) does not use a certificate, so you need to check for that.

X509* cert = SSL_get_peer_certificate(ssl);
if(cert) X509_free(cert);

if(cert == NULL)
    /* Error - Anonymous Diffie-Hellman */

SSL_get_peer_certificate bumps the reference count on the certificate, so you need a matching call to X509_free.

The third test you need to perform is hostname matching. OpenSSL 1.1.0 WILL perform hostname matching (and other name matching, like PKCS9 email addresses); but lesser versions, like 0.9.8 and 1.0.1, DO NOT perform the matching.

jww
  • 97,681
  • 90
  • 411
  • 885
  • I appreciate this (I am not getting emails that there was an answer... maybe I should post a question about that :-). As for checking the peer certificate, doesn't only apply if I want to verify the client? If I'm allowing anonymous clients, but just want to avoid sniffing, it's not required is it? – SpacemanScott Jul 03 '14 at 21:58
  • (yes, this is test is as client, just asking because I will eventually need to support both types) – SpacemanScott Jul 03 '14 at 22:09
  • As a additional problem, this works fine with "google", however when I use our company website, I still get the error code 20 on the `SSL_get_verify_result()` call. Is this a result of our using a "wildcard" certificate? _*.domain.com_. The version of OpenSSL I am currently using is 1.0.1g – SpacemanScott Oct 23 '18 at 19:13
2

Thanks to this post I could finally get the SSL/TLS Client to work on Windows. I built openssl using MSYS2. I had to make some changes to the openssl-bio-fetch.tar.gz code so it could build/run in Windows/MSYS2, mostly adjusting the Makefile includes and setting -DNDEBUG to avoid the Posix signals.

However when running the code I got:

    $ ./openssl-bio-fetch.exe
    Warning: thread locking is not implemented
    verify_callback (depth=1)(preverify=0)
        Issuer (cn): DigiCert High Assurance EV Root CA
        Subject (cn): DigiCert SHA2 Extended Validation Server CA
        Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
    certificate verify failed

I had to download the 2 .pem files:

DigiCert High Assurance EV Root CA

DigiCert SHA2 Extended Validation Server CA

AND PASTE THE CERTIFICATES TO THE SAME .pem FILE ALREADY IN USE BY THE CODE: random-org-chain.pem

Thank You!

Dani
  • 21
  • 2