简体   繁体   中英

TLS with client certificate failing handshake

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.

I recieved my client certificate from API developers in format .p12, so I converted it to .crt and added that to keystore with Keytool

This is where you went wrong. Converting it to .crt extracts the public certificate. What you need to do is convert the .p12 file to a java keystore. There are many examples on the net. See this SO answer for how.

To confirm that it's worked, run keytool -list -keystore <yourkeystore>.jks and check that you have a PrivateKeyEntry in there.

While you're checking things, add the -v flag to the keytool -list command and check that the Issuer field is CN=test, O=test because we can see from your log file that your server requires a client certificate to be issued by that authority.

Also check that your JDK is configured with the Unlimited Strength Jurisdiction Policy Files because the cipher you're being asked to use requires it.

From the log, it seems that TLS cipher TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 is invalidated for TLS client. You may need to check which cipher list client supports. If the cipher TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 is not included in the cipher list, you may need to add support for it.

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]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM