Reputation: 1969
I'm trying to implement a MTLS communication for a Java client application with a Nginx server. Both the server and client are configured with self generated key pairs. Server public certificate is added to the client trustore and the client's public certificate is provided to the nginx server through the ssl_client_certificate
config. Below is the server config at nginx.
server {
listen 443 ssl;
server_name myserver.io;
ssl_certificate certs/server.crt;
ssl_certificate_key certs/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_client_certificate certs/client.cer;
ssl_verify_client optional;
location / {
if ($ssl_client_verify != SUCCESS) {
return 403;
}
}
}
The java client uses Apache httpcore
, httpclient
and httpasyncclient
dependencies. Below is a cleaned code snippet I'm using to obtain the client connection.
public static CloseableHttpAsyncClient getClient() throws Exception {
// Create pooling connection.
ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor();
PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor);
connectionManager.setMaxTotal(20);
connectionManager.setDefaultMaxPerRoute(20);
// Create request configuration.
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(300).setConnectionRequestTimeout(300)
.setSocketTimeout(300).setRedirectsEnabled(false)
.setRelativeRedirectsAllowed(false)
.build();
// Create client builder.
HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClients.custom().setDefaultRequestConfig(config);
// Construct and set SSL context.
// Here keystore and truststore are "java.security.KeyStore" objects.
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keystore, "mypass".toCharArray(), (aliases, socket) - > "mtlsserver")
.loadTrustMaterial(truststore, null)
.build();
httpClientBuilder.setSSLContext(sslContext);
httpClientBuilder.setSSLHostnameVerifier(new DefaultHostnameVerifier());
httpClientBuilder.setConnectionManager(connectionManager);
client = httpClientBuilder.build();
client.start();
return client;
}
When running this code, server returns a 403
response indicating not establishing a mtls connection. However the mtls connection works fine when above httpClientBuilder.setConnectionManager(connectionManager);
line is removed.
During the ssl handshake, it seems that the client doesn't send any certificates to the server when using it with a connection pool (by setting the connection manager). It sends the correct certificate from the keystore when using a single connection (without the pool).
I'm trying to understand what's happening here and how to resolve this. Any help would be appreciated.
Upvotes: 0
Views: 365
Reputation: 1969
It looks like MTLS doesn't work in Apache Client 4 library when it's configured with a connection pool. However I was able to get this into working by upgrading my code to work with Apache Core 5 and Client 5 libraries.
A sample code can be extracted from the "Apache HttpClient 5.x migration guide".
Upvotes: 0