Java 7 (acting as client) SSL handshake failure with keystore and truststore that worked in Java 6
Asked Answered
S

1

14

I'm doing a JBoss AS 5.1 to 7.4, and Java 6 to 7 migration, and get a handshake failure.

The keystore and truststore are the ones we have been using successfully for ages with Java 6.

I've written some tests to narrow the problem down, it's definitely not JBoss but rather Java 7.

With SSL logging turned on, I get this:

17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) %% Invalidated:  [Session-2, SSL_RSA_WITH_RC4_128_SHA]
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, SEND TLSv1 ALERT:  fatal, description = certificate_unknown
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, WRITE: TLSv1 Alert, length = 2
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, called closeSocket()
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, handling exception: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, called close()
17:44:30,042 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, called closeInternal(true)

There are some threads touching upon this (or a similar) problem, where people are suggesting to recreate certs or truststores with different params. I'd rather not go down this route, since I've recently without success tried to create more such keystores and truststores for different accounts of the same webservice.

Since we have been using these old (keystore and truststore) in production with Java 6, I'd like to keep them if at all possible.

It appears the problem may be caused by Java 7 being more tight regarding the checking of truststore certificate chain?

Is it possible to set some flags to relax the checking, make it behave like Java 6?

A thing I'm not 100% sure about is how to interpret the failure message: I think it's telling me that it's my machine (not the remove server), which isn't satisfied that the remote machine is safe. Is that correct?

Any help/ideas appreciated!

==========================================================

As suggested, have added PEM (with chain), exported from firefox when accessing the WS URL, to the truststore. This doesn't make it handshake, but slightly changes the failure.

***
%% Invalidated:  [Session-1, SSL_RSA_WITH_RC4_128_SHA]
main, SEND TLSv1 ALERT:  fatal, description = certificate_unknown
main, WRITE: TLSv1 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 01 00 02 02 2E                               .......
main, called closeSocket()
main, handling exception: 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
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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)

==============================================================

Also, as suggested in other threads, I've written another test that uses a TrustManager that does not validate certificate chains, and ran this with my original truststore.

This test is able to connect, and thus shows that my machine's validating of the remote machine is the only problem, and that my keystore is fine.

However, I can't use this approach for our actual webservice client, since that uses the Sun RPC lib, and connecting happens somewhere deep inside their code, so I can't touch it.

Saddlebow answered 11/8, 2014 at 10:40 Comment(2)
Please edit your question and include the output of openssl s_client -connect <server>:<port>.Messier
Possibly related: JDK-7018897 : CertPath validation cannot handle self-signed cert with bad KeyUsage.Messier
B
13

First, yes, the exception says the Java SSL module in your machine doesn't trust the proof of identity (certificate) received from the server.

Yes, Java 7 does stricter checking. There may be more, but the one I'm sure of is that it doesn't allow the validity period of a child cert to end after the parent/CA cert (or begin before, but in practice that doesn't happen). See PKIX Path does not chain with any of the trust anchors error in Windows Environment which says it is a bug and will be fixed.

To check: if the server is a webserver, you could access any (harmless) page with a browser and use that to look at the cert chain. Otherwise, run openssl s_client -connect $host:443 -showcerts and once it connects enter EOF (Unix ^D, Windows ^Z), then put each ----BEGIN CERT... to -----END CERT... block in a different file and run openssl x509 -noout -subject -issuer -startdate -enddate on each in order.

To fix: if this is the problem, there doesn't seem to be any way to turn it off directly, except by turning off all cert checking (and thus losing some of the security of SSL), but adding the server entity cert to your truststore should work because then Java doesn't verify the chain. (You don't need to remove what's already there, just use an alias that isn't already in use.) Good luck.

Burstone answered 11/8, 2014 at 13:24 Comment(4)
When I access the webservice URL in Firefox, in Page Info, Website Identity, I can view the site's certificate, and export it. Is this the "server entity cert" which you refer to? Firefox lets me export it as X.509 PEM, X.509 PEM with chain, X.509 DER, X.509 PKCS#7, X.509 PKCS#7 with chain. Do the options yield the same result after transformation, or is it important to avoid a particular format to avoid information loss? Is it important to export "with chain" or should it be without?Saddlebow
Regarding the link where it's suggested some of the checking detail is a bug, and is fixed in Java 8, I've downloaded the latest Java 8 that's available from webup8 ppa for Ubuntu, and get the exact same failure that it shows in Java 7.Saddlebow
@stupor Yes, the cert shown first by a browser (or at the bottom if you tab to the full chain) is the server cert, and if you trust that directly Java will avoid the bug. keytool can read either X.509PEM or X.509DER. keytool can also read PKCS#7chain in other cases, but you don't want chain here because a trustedCert entry uses only a single cert. #23775155 says "expected release Date Oct 2014" and 8u20 definitely isn't out yet; 8u11 (security) was released by Oracle in July.Burstone
When I first tried to add the server entity cert to the truststore, it appeared not to help. However, in the meantime the WS operator reluctantly provided us with more info, including the crucial fact that they have multiple copies of the web service on different sub domains, which are backed by different certs. When I tried out the suggestions some weeks ago, they failed because I was mixing sub domains. I now tried again, adding the entity cert to the truststore solves the problem! Thank you Dave!Saddlebow

© 2022 - 2024 — McMap. All rights reserved.