1

I am a newbie to the subject of SSL authontication and Httpclient requests in Java. And I need to perform a secured connection to service provider to be able to fetch some data from service provider api.

Where I am now:

I have made a .jks keystore containing private key and csr request which I have sent to remote service provider. I have got a signed .cer certificate. So far I have tested it in my Postman by exporting private key to a pem file and setting up a client certificate via CRT+KEY+Keypassword in Postman settings. The requests are running just fine. Now, I have to implement this issue using Java and I have already used Apache fluent-hc to send unauthenticated POST requests before. What actions should I take to implement a client certificate secured HTTP request?

Upd. So far I have googled next steps:

I imported my .CER signed cert into existing jks keystore with PrivateKey:

keytool -importcert -file ./signed.cer -keystore trusted.jks -alias mykey

When listing keystore, I get two entries: PrivateKeyEntry and trustedCertEntry

Then I load my keystore from resource:

    public KeyStore loadKeyStore() throws Exception {
    KeyStore keystore = KeyStore.getInstance("JKS");
    try (InputStream is =  new ClassPathResource(authProperties.getKeyStore()
    + ".jks").getInputStream()) {
    keystore.load(is, authProperties.getKeyPass().toCharArray());
    }

    return keystore;
    }

Loading seems to be fine, I test it and get both private key and certificate. But not the certificate chain, not sure if I need it here.

Then I create a SSLContext and load both TrustMaterial and KeyMaterial from the same keystore:

    public SSLContext loadSSLContext() throws Exception {
    return new SSLContextBuilder()
    .loadTrustMaterial(loadKeyStore(), (x509Certificates, s) -> true)
    .loadKeyMaterial(loadKeyStore(), authProperties.getKeyPass().toCharArray())
    .build();
    }

Then, I create a SSLConnectionSocketFactory:

    SSLContext context = loadSSLContext();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(context,
    new NoopHostnameVerifier());

I create a CloseableHttpClient using SSLConnectionSocketFactory:

    CloseableHttpClient httpclient = HttpClients.custom()
    .setSSLSocketFactory(sslsf)
    .build();

And perform a GET request:

    HttpGet request = new HttpGet("/private/openapi");
    HttpResponse httpresponse = httpclient.execute(request);

When running this, I got

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

What could possibly be a cause? I have googled this issue, but it seems that it is mainly corresponds to protocol and cipher suite mismatch. I am not sure, if it is my case or not. Please help, any ideas or links would be highly appriciated! Here is the stacktrace and debug output(please, ignore strange ip adresses):


16:46:08.727 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> CONNECT api.serviceprovider.com:443 HTTP/1.1 16:46:08.727 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Host: api.serviceprovider.com:443 16:46:08.727 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_232) 16:46:08.727 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "CONNECT api.serviceprovider.com:443 HTTP/1.1[\r][\n]" 16:46:08.727 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Host: api.serviceprovider.com:443[\r][\n]" 16:46:08.727 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_232)[\r][\n]" 16:46:08.727 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "[\r][\n]" 16:46:08.878 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 200 Connection established[\r][\n]" 16:46:08.879 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\r][\n]" 16:46:08.880 [main] DEBUG org.apache.http.headers - http-outgoing-0 << HTTP/1.1 200 Connection established 16:46:08.881 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Tunnel to target created. 16:46:08.906 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled protocols: [TLSv1, TLSv1.1, TLSv1.2] 16:46:08.906 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled cipher suites:[TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_EMPTY_RENEGOTIATION_INFO_SCSV] 16:46:08.906 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Starting handshake 16:46:08.997 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Secure session established 16:46:08.997 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - negotiated protocol: TLSv1.2 16:46:08.997 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - negotiated cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 16:46:08.998 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - peer principal: CN=api.serviceprovider.com, OU=IT Department, O=ServiceProv, L=Moscow, C=RU 16:46:08.998 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - peer alternative names: [api.serviceprovider.com, developer.serviceprovider.com] 16:46:08.999 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - issuer principal: CN=Thawte TLS RSA CA G1, OU=www.digicert.com, O=DigiCert Inc, C=US 16:46:08.999 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Executing request GET /private/openapi HTTP/1.1 16:46:08.999 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Target auth state: UNCHALLENGED 16:46:08.999 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> GET /private/openapi HTTP/1.1 16:46:08.999 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Host: api.serviceprovider.com:443 16:46:08.999 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Connection: Keep-Alive 16:46:08.999 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_232) 16:46:08.999 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Accept-Encoding: gzip,deflate 16:46:08.999 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "GET /private/openapi HTTP/1.1[\r][\n]" 16:46:08.999 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Host: api.serviceprovider.com:443[\r][\n]" 16:46:08.999 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]" 16:46:08.999 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_232)[\r][\n]" 16:46:08.999 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]" 16:46:08.999 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "[\r][\n]" 16:46:09.037 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[read] I/O error: Received fatal alert: handshake_failure" 16:46:09.037 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: Close connection 16:46:09.037 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: Shutdown connection 16:46:09.037 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Connection discarded 16:46:09.038 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {tls}->http://x.x.x.120:8080->https://api.serviceprovider.com:443][total kept alive: 0; route allocated: 0 of 2; total allocated: 0 of 20] javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.Alerts.getSSLException(Alerts.java:154) at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2020) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1127) at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:933) at sun.security.ssl.AppInputStream.read(AppInputStream.java:105) at org.apache.http.impl.conn.LoggingInputStream.read(LoggingInputStream.java:84) at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137) at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153) at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56) at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259) at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163) at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273) at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118) at ru.bcs.creditmarkt.delivery.adapter.ServProvAuthTest.testConn(ServProvAuthTest.java:99)

1
  • Could you check and let me know if the subject alternative name within the certificate field contains the host of what you defined within the http get request? The host should be already there o else it will fail during the handshake process.
    – Hakan54
    Commented Dec 25, 2019 at 19:52

1 Answer 1

1

Problem solved. The issue was in jks keystore, not in code. I have imported client cert, but it required a cert chain with root cert too. Once imported the whole chain with client cert it worked.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.