Chrome and other browsers are phasing out SSL certificates
that are implemented using the weak SHA-1 hash
. As a result, SSL certificate authorities, like GoDaddy are also phasing out SHA-1 in favor of SHA-2. GoDaddy is one of the largest providers, at about 13% of all SSL certificates
This means that GoDaddy had to switch to their SHA-2 root certificate and get it installed in all the major browsers, OSs, and other important clients. For some reason, it wasn’t installed in some versions of Oracle’s Java 7 or 8. Apple-released versions of Java do seem to have the root certificate, and as of July 2014, it was added to recent versions of Java 8.
The upshot of this is that new server certificates that are signed with GoDaddy’s SHA-2 root certificate (hash: 47 BE AB C9 22 EA E8 0E 78 78 34 62 A7 9F 45 C2 54 FD E6 8B) aren’t trusted, and so you’ll get unexpected exceptions in Java code that encounter them:
SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
There are a number of bad
solutions to this:
- Don’t just disable SSL certificate chain checking. That defeats the purpose of the whole public key infrastructure that SSL is based on: It opens you to a man-in-the-middle attack.
- Don’t just add the GoDaddy root certificate to your local keychain That solves the problem for one client, but doesn’t solve the problem generally.
- Don’t just downgrade to a SHA-1 certificate (as the top-rated Google / Stack Overflow result would suggest). SHA-1 is being deprecated because it’s insecure, so you shouldn’t use it. Furthermore, you will have to change back to SHA-2 eventually, and in the mean time, your web site will be marked as untrusted. Then your SHA-2 certificate will stop working for legacy Java clients that already shipped without the new root cert.
Fortunately, there is a solution that uses SHA-2, so it’s forward-compatible, and it works for any client. GoDaddy’s head of their SSL division outlined the approach, but unfortunately it’s buried in a comment on a related page:
“Install the GoDaddy G1 to G2 Cross certificate in your certificate bundle file along with the intermediate certificate. This allows our SHA-2 certificates to be trusted by any client that recognizes our SHA-1 roots.” The comment is a little vague and hard to find, so here’s what to do:
Get the gdroot-g2_cross.crt crossover certificate from GoDaddy’s repository and install it in your certificate chain.
So instead of your chain looking like this:
It should look like this:
- Go Daddy Root Certificate Authority – G2: (SHA-2) – Hash 47 BE AB C9 22 EA E8 0E 78 78 34 62 A7 9F 45 C2 54 FD E6 8B. This is the root certificate that’s built into most systems (e.g. Chrome) but not built into Java.
- Go Daddy Secure Certificate Authority – G2: (SHA-2) – Hash 27 AC 93 69 FA F2 52 07 BB 26 27 CE FA CC BE 4E F9 C3 19 B8
- Your SHA2 certificate
- Go Daddy Class 2 Certification Authority: (SHA-1) – Hash 27 96 BA E6 3F 18 01 E2 77 26 1B A0 D7 77 70 02 8F 20 EE E4. This is the old root certificate that’s built into most systems, including java. It’s really no concern that the signature on this one is SHA-1 since the entire certificate is included directly in the client.
- Go Daddy Root Certificate Authority – G2: (SHA-2) – Hash 34 0B 28 80 F4 46 FC C0 4E 59 ED 33 F5 2B 3D 08 D6 24 29 64. This is the so-called “GoDaddy G1 to G2 Cross Certificate”.
- Go Daddy Secure Certificate Authority – G2: (SHA-2) – Hash 27 AC 93 69 FA F2 52 07 BB 26 27 CE FA CC BE 4E F9 C3 19 B8. This is the same intermediate certificate as above.
- Your SHA-2 Certificate
That’s it! Now your certificate has two potential trust chains, and the client will choose the right one. All of the certs except for the root are SHA-2 signed, so the chain is as strong as SHA-2. Much thanks to Kirk Peterson
for the analysis to find this problem and solution, and to GoDaddy’s Wayne Thayer
for posting the comment that summarized the solution.