Homebrew / legacy-homebrew

💀 The former home of Homebrew/homebrew (deprecated)
https://brew.sh
26.97k stars 11.35k forks source link

OpenSSL and dealing with expired Root CA certs #32251

Closed ghost closed 10 years ago

ghost commented 10 years ago

I was going crazy trying to figure out why I was getting the following SSL verification error:

ruby -rnet/https -e "Net::HTTP.get URI('https://api.xively.com/')"
/usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:920:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:920:in `block in connect'
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/timeout.rb:76:in `timeout'
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:920:in `connect'
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:863:in `do_start'
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:852:in `start'
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:583:in `start'
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:478:in `get_response'
        from /usr/local/var/rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:455:in `get'
        from -e:1:in `<main>'

Works in the browser, and I can see in my keychain the Root CA there. Using @mislav's doctor utility, I can see that the Root CA is expired...

ruby doctor.rb api.xively.com                                                                                                                                                                                                                                                      2.1.2
/usr/local/var/rbenv/versions/2.1.2/bin/ruby (2.1.2-p95)
OpenSSL 1.0.1i 6 Aug 2014: /usr/local/etc/openssl
SSL_CERT_DIR=""
SSL_CERT_FILE=""

HEAD https://api.xively.com:443
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

The server presented a certificate that could not be verified:
  subject: /C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
  issuer: /C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
  error code 10: certificate has expired

But this works and isn't expired at all in the browser?!

screen shot 2014-09-12 at 12 19 46 pm

Poking around the OpenSSL formula, I can see the use of the security find-certificate command to retrieve the certs in the keychain. Running the following gives me 2 Root CA's with the same common name:

security find-certificate -a -p -c "GlobalSign Root CA"  /System/Library/Keychains/SystemRootCertificates.keychain
-----BEGIN CERTIFICATE-----
..snip..
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
..snip..
-----END CERTIFICATE-----

2 certs with the same common name? Oh one of them is expired!

After removing the expired Root CA, and reinstalling openssl (so that /usr/local/etc/openssl/cert.pem is regenerated) hitting the above endpoint works! (As well as any other site that has a SSL cert signed by GlobalSign).

So is there a better way to deal with expired Root CAs? Or should there be a check in the formula to deal with expired ones? Looking at the man pages for security I can't find a way to omit expired CA certs.

In any case hopefully this will come up in searches for other people.

adamv commented 10 years ago

Is this specific to Homebrew?

ghost commented 10 years ago

Yes, as the OpenSSL formula pulls CA Certs from the keychain.

jacknagel commented 10 years ago

You can run brew postinstall openssl to regen cert.pem without reinstalling all of openssl.

jconley commented 10 years ago

this is a known openssl bug

jacknagel commented 10 years ago

Given that we lean pretty heavily on Apple to handle certificate management, it's not clear to me that there is anything Homebrew can do here, especially while operating within it's normal bounds (i.e. not doing stuff without the user being explicit). Even if there was some kind of expired certificate check during post-install, it would still be possible to end up with expired certs at a later time and Homebrew wouldn't know about it.

If this is indeed an upstream bug in openssl, then hopefully a fix will materialize in a future release.

Blaisorblade commented 9 years ago

The OpenSSL bug is still stalled, and I ran into this bug (with the same CA) again. My solution was to just erase the expired certificate, as explained in the other issue, though I only guessed it should be safe — so don't use it unless you understand what you're doing (I'm not even entirely sure the hash I used is system-independent, though why not?).

sudo security delete-certificate -Z 2F173F7DE99667AFA57AF80AA2D1B12FAC830338 /System/Library/Keychains/SystemRootCertificates.keychain
brew postinstall openssl
mattheworiordan commented 9 years ago

Thanks @Blaisorblade, your sequence of commands to delete the old cert & update worked for me:

sudo security delete-certificate -Z 2F173F7DE99667AFA57AF80AA2D1B12FAC830338 /System/Library/Keychains/SystemRootCertificates.keychain
brew postinstall openssl