Java Two way SSL Client (+ Spring example)

Jun 27, 2020


one and two way ssl

  1. Offline CA Certificate exchange (upload your certificate to server)
  2. Create JKS (Java Key Storage) with keys
  3. Configure http client

Create JKS (Java Key Storage) with keys

Convert the certificate and private key to PKCS 12

openssl pkcs12 -export -in ./{your_cert}.cer -inkey ./{your_key}.key -name {host} -out {output_name}.p12

Import PKCS 12 and CA to keystore

keytool -importkeystore -deststorepass {password} -destkeystore ./{keystore.jks} -srckeystore ./{key.12} -srcstoretype PKCS12
keytool -import -alias bundle -trustcacerts -file ./{your_cert}.cer -keystore {keystore.jks}

Configure http client

At first add org.apache.httpcomponents:httpclient to dependencies:

// gradle
compile group: 'org.apache.httpcomponents', name: 'httpclient'

<!-- maven -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

At second configure requestFactory using key from keystore

@Configuration
public class TwoWaySslConfiguration {
    @Value("classpath:keystore.jks")
    private Resource keyStoreData;

    @Value("${keystore-pwd}")
    private String keyStorePassword;

    @Value("${key-pwd}")
    private String keyPassword;

    @Bean
    @SneakyThrows
    public RestTemplate restTemplate() {
        KeyStore keyStore = KeyStore.getInstance("jks");
        keyStore.load(new BufferedInputStream(keyStoreData.getInputStream()), keyStorePassword.toCharArray());

        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
                new SSLContextBuilder()
                        .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                        .loadKeyMaterial(keyStore, keyPassword.toCharArray()).build()
                , NoopHostnameVerifier.INSTANCE);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(socketFactory)
                .setMaxConnTotal(1)
                .setMaxConnPerRoute(5)
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        requestFactory.setReadTimeout(10000);
        requestFactory.setConnectionRequestTimeout(10000);

        return new RestTemplate(requestFactory);
    }
}

So you can use RestTemplate as standard rest client for Spring or just use requestFactory.

*Advice: use secret store instead share credentials in your jar

You can use Vault by HashiCorp if you want to provide right credential strategy.


Author Mark Andreev

Machine Learning Engineer