/
Mutual TLS communication using PKCS11 keystore in java

Mutual TLS communication using PKCS11 keystore in java



Java based application can make use of pkcs11 keystore to store the private keys. The SunPKCS11 provider is added to the list of security providers, to provide pkcs11 interface to applications. Using keytool, private keys can be provisioned into pkcs11 token and later loaded into keystore java object. Create CA store, that can be used as truststore during TLS authentication.  The SSL context will use the keystore for private key and associated certificates. The  truststore will be used for ca certificates, the context will trust. Finally enable client auth  for mutual TLS. 

Static and dynamic way of adding provider

You have the option of adding provider using static or dynamic method. In static method, you will be adding the provider to JRE, so that all application can use it using the getProvider method. You can choose to add dynamically to each application, using addProvider method and tool arguments. In either case,  pkcs11 configuration file is required describing the token.  

Add provider statically to JRE

Open java.security file and add the following line to the list of providers.  Where n is the next provider number in the list.

security.provider.n=sun.security.pkcs11.SunPKCS11 /home/test/pkcs11.cfg

From application, now you can get the  provider

Provider p = Security.getProvider("SunPKCS11-pkcs11Test");

where pkcs11Test is the name specified in the pkcs11.cfg file

Add provider dynamically to each application

 String configName = "/home/test/pkcs11.cfg";

Provider p = new SunPKCS11(configName);

Security.addProvider(p);

Provision the keys on both server and client using the following steps

Create pkcs12 keystore with keys and certificates.

openssl pkcs12 -export -in <ca signed certificate> -inkey <private key> -out store.p12 -name keyimport -CAfile ca.cert -caname tlsca

Import keystore  to pkcs11 token using static provider.

keytool -importkeystore -deststorepass <dest passwd> -destkeystore NONE -srckeystore store.p12 -deststoretype PKCS11 -srcstoretype PKCS12 -srcstorepass <src passwd> -alias keyimport

Import keystore  to pkcs11 token using dynamic provider.

keytool -importkeystore -deststorepass <dest passwd> -destkeystore NONE -srckeystore store.p12 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg /home/test/pkcs11.cfg -deststoretype PKCS11 -srcstoretype PKCS12 -srcstorepass <src passwd> -alias keyimport

Create CA store for truststore

keytool -keystore ca.jks -import -file ca.cert -alias cacert

Get the provider and load the keys

From java application get the provider instance.

Static provider.

Provider p = Security.getProvider("SunPKCS11-pkcs11Test");

where pkcs11Test is the name specified in the pkcs11.cfg file

Dynamic provider.

         String configName = "/home/test/pkcs11.cfg"; 

        Provider p = new SunPKCS11(configName);

        Security.addProvider(p);

Load  keys to keystore.

char[] pin = "<store pass>".toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS11", p);
keyStore.load(null, pin);

Load ca certificates to truststore.

char[] tpin = "<store pass>".toCharArray();

FileInputStream tst = new FileInputStream("/ca.jks");
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(tst, tpin);

TLS context initialization

Initialize key and trust Mangers 

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, pin);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);

Initialize TLS context

SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);


Create server socket and enable client auth 

SSLServerSocketFactory ssf = context.getServerSocketFactory();
SSLServerSocket s = (SSLServerSocket) ssf.createServerSocket(<port>);

s.setNeedClientAuth(true);
SSLSocket c = (SSLSocket) s.accept();

Create client socket 

SSLSocketFactory ssf = context.getSocketFactory();
SSLSocket s = (SSLSocket) ssf.createSocket("<hostname>", <port>);





Related content