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
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…