1

Context: I've got some C++ code that uses curl with GnuTLS that's failing to connect to https://googleapis.com since Ubuntu updated the ca-certificates package. That, as far as I can tell, corresponds to Debian bug #858064.

That's not (yet) the interesting part, though. Note, in particular, that this C++ code has been working fine for several years, and works if I provide it with the previous version of the /etc/ssl/certs/ca-certificates.crt file.

Problem: When I use the following commands:

$ openssl s_client -connect sheets.googleapis.com:443 \
    -CApath /etc/ssl/certs/ca-certificates.crt
$ gnutls-cli sheets.googleapis.com
    --x509cafile /etc/ssl/certs/ca-certificates.crt
$ curl --cacert /etc/ssl/certs/ca-certificates.crt \
    https://sheets.googleapis.com

...they all work correctly. As do Google Chrome and Mozilla Firefox.

And I can't figure out why they work, when my C++ code doesn't. It fails with CURLE_SSL_CACERT (60): Peer certificate cannot be authenticated with known CA certificates.

Google's server returns the following certificate chain, according to OpenSSL; the GnuTLS one looks the same, as far as I can tell; and I see 3 certificates in Wireshark:

Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.googleapis.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority

Question: I'm trying to understand how GnuTLS, in particular, builds and verifies its certificate chain on Linux. That "Equifax Secure Certificate Authority" certificate appears to have been removed in the ca-certificates update, and yet it doesn't appear to have broken anything (except my code).

If I look at the certificate in Google Chrome, that root certificate isn't shown, and the chain terminates at the "GeoTrust Global CA" certificate instead, which looks to be self-signed.

  • Why is OpenSSL showing different results from Chrome?
  • Why is OpenSSL (apparently) still trusting a removed CA certificate?
  • How do I check that the certificates shown by OpenSSL/GnuTLS/etc. map to the relevant files in /etc/ssl/certs?
Roger Lipscombe
  • 2,317
  • 3
  • 14
  • 20

1 Answers1

4

Why is OpenSSL showing different results from Chrome?

OpenSSL is showing the certificate chain send by the server. Chrome is showing the chain used for validation. Since there is a self-signed CA certificate for GeoTrust Global CA which uses the same key as the one signed by Equifax the Equifax CA certificate is no longer needed to verify the chain.

This self-signed CA certificate for GeoTrust Global CA is also contained in the current versions of the ca-certificates package so that the Equifax is no longer needed by current OpenSSL versions to validate the chain. There was a bug though with older OpenSSL versions where it failed to validate the chain if the Equifax signed CA was included in the chain but the Equifax CA was not in the trust store. See Python Requests SSL Verification.

Why is OpenSSL (apparently) still trusting a removed CA certificate?

It does not. It trusts instead the GeoTrust Global CA included in the trust store and ignores the Equifax issued chain certificate (which has the same key).

How do I check that the certificates shown by OpenSSL/GnuTLS/etc. map to the relevant files in /etc/ssl/certs

I'm not sure what you mean with "map". But you can make s_client show you all the certificates with the -showcerts and then check if exact these certificates are included in your trust store (i.e. string comparison). If you want instead to check if a specific certificate chain can be verified with your trust store use openssl verify -CAfile ca-certificates.pem -untrusted chain-certs.pem leaf-cert.pem. See also Use openssl to individually verify components of a certificate chain.

Steffen Ullrich
  • 190,458
  • 29
  • 381
  • 434
  • `openssl verify ... cert1 cert2` doesn't verify a chain of cert1 and cert2, it verifies each of cert1 and cert2 _separately_, against the (specified or defaulted) truststore. And neither does `verify ... chainfile`. To verify a chain use `-untrusted` (and maybe `-purpose`); see https://security.stackexchange.com/questions/163577/should-a-server-or-a-client-be-able-to-verify-a-client-server-certificate-inte or https://stackoverflow.com/questions/29436967/how-to-chain-a-ssl-server-certificate-with-the-intermediate-and-root-ca-certific – dave_thompson_085 Oct 24 '17 at 01:23
  • @dave_thompson_085: thanks for the comment. I've adapted the answer. – Steffen Ullrich Oct 24 '17 at 04:08
  • "There was a bug though with older OpenSSL versions"; yeah it says that in the Debian changelog. Do you know if GnuTLS suffered from a similar bug? As in: do I need to upgrade the gnutls I'm linking with? – Roger Lipscombe Oct 24 '17 at 11:10
  • @RogerLipscombe: I'm not aware of a similar bug in GnuTLS - but I'm neither aware that they never had this problem :) – Steffen Ullrich Oct 24 '17 at 11:35
  • MCVE: https://stackoverflow.com/q/46935436/8446 – Roger Lipscombe Oct 25 '17 at 14:44