I am confused as to where exactly I need to include client certificate. Now, my first issue is that I don't trust the server. I tried using default Java keystore file (cacerts) which has both Thawte and Digicert in it, and those are the root authorities of the server I'm trying to communicate with. I set that cacerts file as keystore using System.setProperty("javax.net.ssl.keyStore", "...")
, it didn't work, I set it as truststore, it didn't work. I still got
unable to find valid certification path to requested target
So I sorted that out temporarily by using AlwaysTrustSSLConnectionFactory()
.
Now the issue is that the server doesn't trust me. I have a client certificate and I tried adding it to both keystore and truststore, but regardless of what I do, after ServerHelloDone I get
Warning: no suitable certificate found - continuing without client authentication
in Java's SSL debug messages and a handshake failure after secret and key messages. Here is the end of my log:
http-bio-8080-exec-3, WRITE: TLSv1.2 Handshake, length = 40
http-bio-8080-exec-3, READ: TLSv1.2 Alert, length = 2
http-bio-8080-exec-3, RECV TLSv1.2 ALERT: fatal, handshake_failure
%% Invalidated: [Session-7, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384]
http-bio-8080-exec-3, called closeSocket()
http-bio-8080-exec-3, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)
Here is my current code:
System.setProperty("javax.net.ssl.keyStore", "C:/Users/Lovro/Desktop/certs/api/keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass");
URL url = new URL(urlRequest);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(new AlwaysTrustSSLContextFactory());
conn.connect();
I recieved my client certificate from API developers in format .p12
, so I converted it to .crt
and added that to keystore with Keytool. Does anyone know what could be the issue and is my handshake failing because I have not included client certificate properly or if I didn't add it to keystore properly? As far as I understand, truststore needs to contain public keys of trusted root authorities and keystore should have my client certificate. Is this correct? How do I achieve this?
Any suggestion is welcome, I am new to TLS/HTTPS and have no idea what am I doing.
Postman
and it works. The certificate is valid. – lovrodoejavax.net.ssl.keyStore
. If p12 does not work either, get the CA list sent by the server and compare it to the issuer of the p12 certificate – pedrofb