Mutual SSL
Before diving into Mutual SSL, it’s essential to first understand SSL. SSL (Secure Socket Layer) is a protocol used to verify that a client is accessing the correct server resource. This verification relies on widely-used cryptographic utility known as digital certificates.
How does a Digital Certificate work?
As part of their identity, any party can hold a private and public key pair. The private key is kept secret, while the public key can be shared openly. If party ‘A’ signs a message with their private key, the message’s origin (whether it was generated by ‘A’ or not) can be verified by anyone using ‘A’s public key.
Standard SSL
This flow is used in standard SSL, where when a client attempts to access a website, the server provides a digital signature of its certificate. The client can easily verify this using the server’s public key, ensuring it is accessing the correct website or server. In practice, client browsers don’t hold public keys or certificates directly. Instead, Certificate Authorities (CAs) act as trusted intermediaries to facilitate this verification process.
Mutual SSL
Building on the concept of basic SSL, Mutual SSL extends verification to both the client and the server. The verification and exchange process can be summarized in these steps:
- The client accesses a website.
- The server sends a digitally signed certificate.
- The client verifies it using the Certificate Authority (CA) or the server’s public key.
- The client then shares its own digitally signed certificate.
- The server verifies the client’s certificate.
- If all handshakes are completed, the SSL verification is considered complete.
If you’re looking to enable Mutual SSL (MSSL) in any programming language, the core process remains the same: creating an SSLContext
and loading the necessary key materials.
Below are some Java code snippets I’ve used on the client side to enable Mutual SSL.
You can use keystores to store the certificates and private keys.
private SslContext createSSSLContext(){
SslContext sslContext;
try{
sslContext = SslContextBuilder.forClient()
.keyManager(getKeyManagerFactory()).trustManager(getTrustManagerFactory()).build()
}
catch(Exception e){
throw new RuntimeException("Error creating SSL Context");
}
}
private KeyManagerFactory getKeyManagerFactory() throws NoSuchAlorithmExceotion, CertificateException,IoException, KeysStoreException{
KeyStore keyStoreInstance = KeyStore.getInstance("jks");
KeyStoreInstance.load(getClass()).getClassLoader().getResorceAsStream(keyStore),keyStorePassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStoreInstance,keyStorePassword.toCharArray());
return keyManagerFactory;
}
private TrustManagerFactory getTrustManagerFactory() throws NoSuchAlorithmExceotion, CertificateException,IoException, KeysStoreException{
KeyStore trustStoreInstance = KeyStore.getInstance("jks");
KeyStoreInstance.load(getClass()).getClassLoader().getResorceAsStream(trustStore),trustStorePassword.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(trustStoreInstance,trustStorePassword.toCharArray());
return trustManagerFactory;
}
You can use this SSL context created and set in any rest/web client object to enable mutual SSL.
- A keystore is used to store your own key materials, while a truststore is used to store the public key materials of other parties. However, it’s possible to store both in a single JKS (Java KeyStore) file if needed.
- Load store paths and passwords from env/config.
Thanks for reading :)