0

I connect to REST webservice running on server using Apache HttpClientBuilder. The client must send a certificate to validate and the server certificate is added in truststore in the client side. I specify with options -Djavax.net.ssl.keyStore , -Djavax.net.ssl.trustStore.

However I get below error, any clues? I'm not sure SSL handshake is successful, but there seems to ServerHelloDone and Found Certificate in logs.

Code

HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet("https://testmachine.com/retrieve/path");

// add request header
request.addHeader(Constants.HTTP_HEADER_ACCEPT, Constants.MEDIA_TYPE_JSON);

// request to SERVER
HttpResponse response = client.execute(request);

LOGS

[write] MD5 and SHA1 hashes:  len = 16
0000: 14 ........g...oJ..v...
Padded plaintext before ENCRYPTION:  len = 32
0000: 14.......
0010: 5A.......
main, WRITE: TLSv1 Handshake, length = 32
main, waiting for close_notify or alert: state 3
main, Exception while waiting for close java.net.SocketException: Software caused connection abort: recv failed
main, handling exception: java.net.SocketException: Software caused connection abort: recv failed
%% Invalidated:  [Session-3, SSL_RSA_WITH_RC4_128_MD5]
main, SEND TLSv1 ALERT:  fatal, description = unexpected_message
Padded plaintext before ENCRYPTION:  len = 18
0000: 02 .....@.y..A.
0010: 31 8F                                              1.
main, WRITE: TLSv1 Alert, length = 18
main, Exception sending alert: java.net.SocketException: Software caused connection abort: socket write error
main, called closeSocket()
main, called close()
main, called closeInternal(true)
Apr 18, 2016 1:52:17 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (java.net.SocketException) caught when processing request to {s}->https://testmachine.com:443: Software caused connection abort: recv failed
Apr 18, 2016 1:52:17 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request to {s}->https://testmachine.com:443
Allow unsafe renegotiation: true
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
%% No cached client session
*** ClientHello, TLSv1
ulab
  • 1,079
  • 3
  • 15
  • 45

1 Answers1

0

It looks like keystore is not read from the logs. I susupect that it is because my certificate inside the keystore is ".p12" format and has its own password. So I had to explicitly load the keystore and truststore and build SSLContext to make it working.

One important thing to note is that the privateKeyPassword you will have to supply the certificate password (and not the keystore password that is to protect the key entry).

 .loadKeyMaterial(keyStore, privateKeyPassword.toCharArray())   

Here is some part of code that explains that.

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    FileInputStream keyStream = new FileInputStream(keystoreFile);
    try {
        keyStore.load(keyStream, keystorePassword.toCharArray());
    } catch (Exception ex) {
        System.err.println("Failed to load keystore: " + ex.toString());
        return;
    } finally {
        try {
            keyStream.close();
        } catch (Exception ignore) {
        }
    }

    // load keystore and truststore
    SSLContext sslcontext = SSLContexts.custom()
            .loadTrustMaterial(truststoreFile, truststorePassword.toCharArray(),
                    new TrustSelfSignedStrategy())
                    .loadKeyMaterial(keyStore, privateKeyPassword.toCharArray())        
                    .build();

    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslcontext,
            new String[] { "TLSv1" },
            null,
            SSLConnectionSocketFactory.getDefaultHostnameVerifier());

    CloseableHttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(sslsf)
            .build();
ulab
  • 1,079
  • 3
  • 15
  • 45