2
votes

The webserver updated its SSL cert to a new verisign signed cert and my java app can no longer connect.

I am using java 5 with a date on the cert file Nov 2006 in /usr/java/jre/lib/security

I get

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1518)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:174)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:168)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:848)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:106)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:818)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1030)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1057)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1041)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:402)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:170)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)

How do I install a new key supplied by the server?

From a different java instance I get

Certificate chain received from eservices3.bus.att.com - 135.38.253.93 was not trusted causing SSL handshake failure.

I assume that it is from the same root problem.

Update Before the remote server was updated this worked with our standard java install. I didn't have to install any certs to get this to work last time around.

2
You probably had to install the server's (original) certificate in your Java client in the first place. Simply repeat that step for the new certificate.AbdullahC

2 Answers

12
votes

Java tries to validate the certificate by following the chain of certificates presented by the server, until it finds one it trusts (i.e. one that's present in your cacerts file).

We can verify the chain manually using the OpenSSL command line tools:

simon@lucifer:~$ openssl s_client -connect eservices3.bus.att.com:443
<snipped>
---
Certificate chain
 0 s:/C=US/ST=Georgia/L=Alpharetta/O=ATT Services, Inc./OU=ATTIT/CN=eservices3.bus.att.com
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Secure Server CA - G3
---

Now, here's the problem: the issuer (line beginning i:) "VeriSign Class 3 Secure Server CA - G3" is an intermediate certificate, not a root. The AT&T server is misconfigured, and should be sending both its own certificate ("eservices3.bus.att.com") and the intermediate, so that Java can verify the chain all the way to the root.

To illustrate another way, the chain should look like this:

1) VeriSign Class 3 Public Primary Certification Authority - G5 (root)
                               ^
                               | signed by
                               |
2)          VeriSign Class 3 Secure Server CA - G3      (intermediate)
                               ^
                               | signed by
                               |
3)                 eservices3.bus.att.com                     (server)
  • the root (1) is in cacerts - ok
  • the server certificate (3) is presented during the SSL handshake - ok
  • but: Java has no knowledge of the intermediate (2) - so can't verify the chain end-to-end

To fix this, you can either:

  • ask AT&T to fix the server so it sends both the server and intermediate cert during the handshake, or
  • import the intermediate cert into Java's keystore

The first solution is preferable, since it helps everyone (not just you) and is slightly less risky (you might not notice if the intermediate cert became compromised).

If you want to import the cert as a temporary measure, grab it from VeriSign's support pages (it's "Secondary SSL Intermediate CA Certificate"), then:

simon@lucifer:~$ keytool -importcert -alias some_alias_of_your_choosing \
                    -file intermediate_cert_path.crt \
                    -keystore your_cacerts_path
Enter keystore password:  *****
Certificate was added to keystore

To remove the cert (once AT&T get their act together):

simon@lucifer:~$ keytool -delete -alias same_alias_as_before \
                    -keystore your_cacerts_path
0
votes

It sounds as though your server (or application, but more likely the server) doesn't trust the root certificate that verisign has issued this new certificate from. Once you trust that cert, you'll trust all the certs chained to it.

The verisign root CAs can be found at the below link:

http://www.verisign.com/support/roots.html