0

We are using java client(openJDK 1.8.0) to call an api that needs mutual authentication. For this we are using java standard JKS file as a keystore and truststore (same file for containing both trustcerts and identity certs/privatekey). Sample java we are using to test is as below ::

KeyStore clientKeyStore = KeyStore.getInstance("JKS");
            clientKeyStore.load(new FileInputStream("./client.keystore"),
                    password.toCharArray());

            // create a client connection manager to use in creating httpclients
            PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();


            SSLContext sslContext = SSLContextBuilder.create()
                    .loadKeyMaterial(clientKeyStore, password.toCharArray())
                    .loadTrustMaterial(clientKeyStore, null).build();

            // create the client based on the manager, and use it to make the call
            CloseableHttpClient httpClient = HttpClientBuilder.create()
                    .setConnectionManager(mgr)
                    .setSslcontext(sslContext)
                    .setSSLHostnameVerifier(new NoopHostnameVerifier())
                    .build();


            HttpPost httppost = new HttpPost("https://someUrl");

            String params = "";
            StringEntity param = new StringEntity(params);
            httppost.setEntity(param);
            System.out.println("Sending request...............");
            HttpResponse response = httpClient.execute(httppost);

During SSL handshake as a last step of "serverhello", server is requesting client's identity by issuing "certificaterequest" - please find below request ::

    *** CertificateRequest
Cert Types: RSA, ECDSA, DSS
Supported Signature Algorithms: SHA512withRSA, Unknown (hash:0x6, signature:0x2), SHA512withECDSA, SHA384withRSA, Unknown (hash:0x5, signature:0x2), SHA384withECDSA, SHA256withRSA, SHA256withDSA, SHA256withECDSA, SHA224withRSA, SHA224withDSA, SHA224withECDSA, SHA1withRSA, SHA1withDSA, SHA1withECDSA
Cert Authorities:
<CN=Intermediate CA, OU=ourCA.com, O=ourCA Inc, C=US>

Right after this, we are seeing below lines indicating java's keyManager is not able to find anything signed with the same signer.

*** ServerHelloDone
[read] MD5 and SHA1 hashes:  len = 4
0000: 0E 00 00 00                                        ....
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
***

We have validated that the certificate is present in the keystore and its a valid certificate( by opening it in windows box, it wont open if its invalid cert). So our keystore has an chain : myIdentity >> signed by Intermediate CA >>signed by Root CA

A few things we have tried(without any luck) is :

  • Tried overriding keystoremanager to return a hardcoded alias ie alias of the certificate in keystore.jks
  • Tried splitting identity certs and CA certs in two separate files ie separate keystore.jks and truststore.jks

Its worth sharing that the same connectivity works well if we are using cURL. In case of cURL, we have to pass client certificate explicitly as an argument ( cURL has no concept of keystore) and we are using linux default keystore (/etc/pki/tls/certs/ca-bundle.crt)

curl -vvv GET https://api.someone.com/some/path -E /home/certificates/client.test.pem --key /home/certificates/client.test.key

I am not sure what other details can add value but I'll be happy to share all the possible details needed ( except my private key :-P )

buch11
  • 872
  • 3
  • 13
  • 29

1 Answers1

0

I had the same problem as you described. The issue I had was that I loaded the keystore in Java using:

System.setProperty("javax.net.ssl.keyStore", "/path/key.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass");

When the server requested a ClientCertificate all a got was:

*** CertificateRequest 
Cert Types: RSA, DSS Supported Signature Algorithms: SHA512withRSA, SHA512withECDSA, SHA384withRSA, SHA384withECDSA, SHA256withRSA, SHA256withECDSA, Unknown (hash:0x4,signature:0x2), SHA224withRSA, SHA224withECDSA, Unknown (hash:0x3,signature:0x2), SHA1withRSA, SHA1withECDSA, SHA1withDSA 
Cert Authorities: 
&ltCN=HB Internal Issuing CA, DC=domainx, DC=hb, DC=bis>
*** ServerHelloDone 
Warning: no suitable certificate found - continuing without client authentication

The solution for this was to load the keystore in a different way as described by: Java SSLHandshakeException "no cipher suites in common"

Basically what I did was to change how I created the SSLContext:

From:

System.setProperty("javax.net.ssl.keyStore", "/path/key.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass");

System.setProperty("javax.net.ssl.trustStore", "/path/trust.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

SSLContext c = SSLContext.getInstance("TLSv1.2");
c.init(null, null, null);

To:

// instantiate a KeyStore with type JKS
KeyStore ks = KeyStore.getInstance("JKS");

// load the contents of the KeyStore
final char[] keyPasswd = "pass".toCharArray();
ks.load(new FileInputStream("/path/key.jks"), keyPasswd);

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

keyManagerFactory.init(ks, keyPasswd);

SSLContext c = SSLContext.getInstance("TLSv1.2");
c.init(keyManagerFactory.getKeyManagers(), null, null);

and the result then was:

*** CertificateRequest
Cert Types: RSA, DSS
Supported Signature Algorithms: SHA512withRSA, SHA512withECDSA, SHA384withRSA, SHA384withECDSA, SHA256withRSA, SHA256withECDSA, Unknown (hash:0x4, signature:0x2), SHA224withRSA, SHA224withECDSA, Unknown (hash:0x3, signature:0x2), SHA1withRSA, SHA1withECDSA, SHA1withDSA
Cert Authorities:
&ltCN=HB Internal Issuing CA, DC=domainx, DC=hb, DC=bis>
*** ServerHelloDone
matching alias: ibmwebspheremq01
Martin.k
  • 1
  • 1