Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OPENSSL connection to a public server gives X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY

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.

like image 505
SpacemanScott Avatar asked Jun 19 '14 20:06

SpacemanScott


People also ask

How do I fix unable to get local issuer certificate?

When ssl certificate problem unable to get local issuer certificate error is caused by a self-signed certificate, the fix is to add the certificate to the trusted certificate store. Open the file ca-bundle. crt located in the directory above, then copy and paste the Git SSL certificate to the end of the file.

How do I check OpenSSL connection?

In the command line, enter openssl s_client -connect <hostname> : <port> . This opens an SSL connection to the specified hostname and port and prints the SSL certificate. Check the availability of the domain from the connection results. The following table includes some commonly used s_client commands.

What does OpenSSL command do?

OpenSSL is an open-source command line tool that is commonly used to generate private keys, create CSRs, install your SSL/TLS certificate, and identify certificate information.


1 Answers

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.

like image 72
jww Avatar answered Oct 30 '22 18:10

jww