Dieses Blog durchsuchen

Mittwoch, 8. Juli 2020

Understanding Java Keystores for private key authentication

When your application needs to communicate over https (SSL) a KeyStore and a TrustStore may be involved.

The TrustStore usually holds the public keys of the servers that the client wants to establish a connection to. This store is located in the [jdk_home]\lib\security\cacerts file.

Usually it is sufficient to import a server certificate into this file in order to trust the issuing server with the help of the keytool command.

A KeyStore on the other hand usually holds private keys that can be used for authentication. The file is often in the PKCS12 format and has the file ending "pfx".

There are two ways to configure a TrustStore and a KeyStore. The easiest way is to use these JVM parameters:

 a) by configuration

-Djavax.net.ssl.keyStore=/var/datamyKeyStore.pfx
-Djavax.net.ssl.keyStorePassword=myPassword
-Djavax.net.ssl.trustStore=/java/jdk11/lib/security/cacerts
-Djavax.net.ssl.trustStorePassword=changeit

 Obviously these variables need to be evaluated when connecting to a server. The apache http client (https://hc.apache.org/httpcomponents-client-5.0.x/index.html) and the jax-rs jersey client (https://mvnrepository.com/artifact/com.sun.jersey/jersey-client) do not read values from these variables. Therefore a different approach is necessary:

 b) programmatically load the TrustStore and KeyStore

This example uses the popular Apache HttpClient.
The following code shows how a SSL context is created with a truststore and a keystore which is needed when creating the client:

private SSLContext getSslContext() throws Exception {
    //load truststore (cacerts file)
    KeyStore serverKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
    serverKeystore.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());
    TrustManagerFactory serverTrustManager = TrustManagerFactory.getInstance("X509");
    serverTrustManager.init(serverKeystore);
    //load keystore (pfx file)
    KeyStore userKeystore = KeyStore.getInstance("JKS");
    userKeystore.load(new FileInputStream(keystorePath), keyStorePassword.toCharArray());
    KeyManagerFactory userKeyFactory =
            KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    userKeyFactory.init(userKeystore, keyStorePassword.toCharArray());
    SSLContext sslContext = SSLContext.getInstance("TLS");
    //init the SSL context with truststore and keystore
    sslContext.init(userKeyFactory.getKeyManagers(),
            serverTrustManager.getTrustManagers(), null);
    return sslContext;
}

This HttpClient is then created on basis of the SSLContext:

private CloseableHttpClient secureConnection() throws Exception {
    SSLContext sslContext = getSslContext();
    SSLConnectionSocketFactory sslConSocFactory = new SSLConnectionSocketFactory(sslContext);
    CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslConSocFactory).build();
    return (httpclient);
}

Finally the client can be used to perform a https request with private key authentication:

private void performRequest(String url) throws Exception {
    CloseableHttpClient closeableHttpClient = secureConnection();
    HttpHead httpHead = new HttpHead(url);
    CloseableHttpResponse response = closeableHttpClient.execute(httpHead);
}

Keine Kommentare:

Kommentar posten