How to configure apache httpclient 4.5+ SSLContext to use mutual TLS authentication with a self signed certificate?

I am trying to configure a CloseableHttpClient from httpclient 4.5 with mutual TLS authentication. The server certificate is self-signed. Here is the code I use (inpired by various StackOverflow posts):

KeyStore trustStore = KeyStore.getInstance("pkcs12");
try (InputStream fis = new FileInputStream(ssl_cert_file)) {
    trustStore.load(fis, password.toCharArray());
}
SSLContext sslContext = SSLContexts.custom()
        .loadKeyMaterial(trustStore, password.toCharArray(), (map, socket) -> "client")
        .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
        .build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,  new DefaultHostnameVerifier());
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("https", socketFactory).build();
connectionManager = new PoolingHttpClientConnectionManager(registry);

I Got

sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

Which looks like that the CA certificate I provide is not used I think. Any idea of what could be wrong ?


The CA's certificate, client's certificate and client's private key are in a pkcs12 file generated with

openssl pkcs12 -export -in client-cert.pem -inkey private/client-key.pem -certfile cacert.pem -name "client" -out client-cert.p12

I tried openssl s_client to check the certificate return the expected output (it does). I suspect the problem is coming from my code rather than the client-cert.p12 file.

openssl s_client -connect host:port -tls1 -cert client-cert.pem -key private/client-key.pem -CAfile cacert.pem

Upvotes: 2

Views: 3010

Answers (1)

As pointed by @Gimby The problem was my CA's certificate was not recognized as a TrustCertEntry in my keystore.

My workaround is to generate a jks file just for the CA's certificate:

keytool -import -alias client -file cacert.pem -storetype JKS -keystore cacert.jks

Build a KeyStore object from it and use it for SSLContext.loadTrustMaterial.

Upvotes: 2

Related Questions