users@jersey.java.net

[Jersey] TLS client authentication issue.

From: John MacAuley <john_at_blackacorn.ca>
Date: Fri, 6 Mar 2015 00:05:03 -0500

Peoples,

I need some help. I have spent a few days trying to solve my issue but have just not been able to do it. You may remember me asking this question last month. I have tried a bunch of different changes to the following initialization, including overriding the key and trust store managers with no resolution. I upgraded to Jersey 2.16 today to see if that would help and it didn't. Getting close to tossing Jersey out all together. I am using the ApacheConnectorProvider for chunked POST support (httpcomponents 4.4).

The scenario is simple. My client is issuing a POST via TLSv1 to my application fronted by Apache httpd (mod_proxy). We are enforcing client authentication. The initial unprotected handshake works fine with the TLS session getting established. When httpd determines that the POST is to the protected URL corresponding to the application, it initiates renegotiation so that it can force client authentication. Negotiation proceeds without an issue until the server sends the "CertificateRequest" with the list of signing CA from which it will accept a client certificate. I can see my self-signed certificate in the list, but the client does not respond with the certificate, but instead fails the handshake. I have reproduced the problem with CA signed certificates as well so I do not believe it is due to the self-signed certificate.

This worked previously with HttpUrlConnection and all I needed to do was configure the key and trust stores on the command line.

Here is the client initialization code on my most recent attempt:

        ClientConfig clientConfig = new ClientConfig();

        // We want to use the Apache connector for chunk POST support.
        clientConfig.connectorProvider(new ApacheConnectorProvider());

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setDefaultMaxPerRoute(10);
        connectionManager.setMaxTotal(80);
        clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);

        clientConfig.register(new MoxyXmlFeature());
        clientConfig.register(new LoggingFilter(java.util.logging.Logger.getGlobal(), true));
        clientConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.CHUNKED);

        // Apache specific configuration.
        RequestConfig.Builder custom = RequestConfig.custom();
        custom.setExpectContinueEnabled(true);
        custom.setRelativeRedirectsAllowed(true);
        custom.setRedirectsEnabled(true);
        clientConfig.property(ApacheClientProperties.REQUEST_CONFIG, custom.build());
        
        // Set up the key and trust stores.
        SslConfigurator sslConfig = SslConfigurator.newInstance()
            .trustStoreFile("truststore.jks")
            .trustStorePassword("changeit")
            .keyStoreFile("keystore.jks")
            .keyPassword("changeit");
        SSLContext sslContext = sslConfig.createSSLContext();

        // Build the client.
        client = ClientBuilder.newBuilder().sslContext(sslContext).withConfig(clientConfig).build();

Thanks for the help!

John