4

I have a problem verifying Verisign certificate when trying to connect with HttpsURLConnection to our backend.

Current certification chain: $openssl s_client -connect host:443

0 s:/C=AT/ST=xxx/L=xxx/O=xxx/CN=host
   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 International Server CA - G3

1 s:/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 International Server CA - G3
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Auth
ority - G5

2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Auth
ority - G5
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority

3 s:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority

I'm pretty sure i have downloaded and added all certificates into KeyStore, but i still get exception : "javax.net.ssl.SSLException: Not trusted server certificate" and the cause is java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: TrustAnchor found but certificate validation failed.

My code for obtaining the connection:

String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("verisign_0", getVerisign0());
keyStore.setCertificateEntry("verisign_1", getVerisign1());
keyStore.setCertificateEntry("verisign_2", getVerisign2());
keyStore.setCertificateEntry("verisign_3", getVerisign3());

String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
return urlConnection;

issue is happening, when connection.connect() is called. All getVerisign() methods returns correct certificates. Is there a step I have forgotten? Maybe a special order in which the certificates should be added?

Just to clarify, I have used exactly this technique with swisssign certificates and it worked. I'm facing this issue because some of Android 2.1, 2.2 devices does not have some root certificates. Thanks in advance.

StackTrace:

[0] = {java.lang.StackTraceElement@830078967208}"org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)"
[1] = {java.lang.StackTraceElement@830078967584}"org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)"
[2] = {java.lang.StackTraceElement@830078967960}"org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.getSecureSocket(HttpConnection.java:168)"
[3] = {java.lang.StackTraceElement@830078968368}"org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:399)"
[4] = {java.lang.StackTraceElement@830078968816}"org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:147)"
ibecar
  • 415
  • 3
  • 10
  • Is the certificate expired or the CLR/OCSP URL not reachable (or even revoked)? – Philip Helger May 16 '13 at 12:19
  • This is just a tip for you to try out. I recently did an app which needed to communicate with server through HTTPS, it was all working well with HttpsURLConnection class in versions under 4 but in all other it returned not trusted. Our certificate is Thawte issued. Only solution and after all searching through forums and topics was to go with SSLSocket. Why did this worked and other solution did not I didn't found any logical answer. Hope this helps and enjoy your work. – Marko Lazić May 15 '13 at 00:35
  • Sorry for delayed comment, but I was out of town. In case someone is struggling with simillar issues: As I cannot install certificates on every device that installs our App, I am will have to use both device's internal trustStore and my own trustStore with my certificates (these will be used if the first trustStore returns exception). [reference](http://nelenkov.blogspot.sk/2011/12/using-custom-certificate-trust-store-on.html) – ibecar May 20 '13 at 19:50

2 Answers2

2

Without further code I can not tell but, I can see you loading the Trusted Certs, but where are you loading your own Keystore? If it is in other code, I can not tell.

Also what happens when you try using an external Truststore e.g. $JAVA_HOME/jre/lib/security/cacerts

Assuming you really want to use a dynamic trust store (usually they are pretty static), have a look at

http://jcalcote.wordpress.com/2010/06/22/managing-a-dynamic-java-trust-store/

Scary Wombat
  • 44,617
  • 6
  • 35
  • 64
2

As said before, the TrustStore inside the JVM is static, once initialized, certificates cannot be appended to it (as I observed with a similar problem). The simple solution is to add your certificates to the default one : $JAVA_HOME/jre/lib/security/cacerts

Or try to include your TrustStore initialization code into a static {} block to initialize it sooner and get a chance to bypass the default behavior.

You can also use a custom file KeysStore and ask the jvm to use it with the -Djavax.net.ssl.keyStore* parameters.

gma
  • 2,563
  • 15
  • 14