Last active
April 5, 2024 16:28
-
-
Save rohanag12/07ab7eb22556244e9698 to your computer and use it in GitHub Desktop.
Create an SslSocketFactory using PEM encrypted certificate files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Utility class to read encrypted PEM files and generate a | |
* SSL Socket Factory based on the provided certificates. | |
* The original code is by Sharon Asher (link below). I have modified | |
* it to use a newer version of the BouncyCastle Library (v1.52) | |
* | |
* Reference - https://gist.github.com/sharonbn/4104301" | |
*/ | |
import org.bouncycastle.cert.X509CertificateHolder; | |
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; | |
import org.bouncycastle.jce.provider.BouncyCastleProvider; | |
import org.bouncycastle.openssl.PEMDecryptorProvider; | |
import org.bouncycastle.openssl.PEMEncryptedKeyPair; | |
import org.bouncycastle.openssl.PEMKeyPair; | |
import org.bouncycastle.openssl.PEMParser; | |
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; | |
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; | |
import javax.net.ssl.KeyManagerFactory; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.SSLSocketFactory; | |
import javax.net.ssl.TrustManagerFactory; | |
import java.io.FileReader; | |
import java.security.KeyPair; | |
import java.security.KeyStore; | |
import java.security.Security; | |
import java.security.cert.Certificate; | |
import java.security.cert.X509Certificate; | |
public class SslUtil { | |
public static SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile, final String keyFile, | |
final String password) { | |
try { | |
/** | |
* Add BouncyCastle as a Security Provider | |
*/ | |
Security.addProvider(new BouncyCastleProvider()); | |
JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter().setProvider("BC"); | |
/** | |
* Load Certificate Authority (CA) certificate | |
*/ | |
PEMParser reader = new PEMParser(new FileReader(caCrtFile)); | |
X509CertificateHolder caCertHolder = (X509CertificateHolder) reader.readObject(); | |
reader.close(); | |
X509Certificate caCert = certificateConverter.getCertificate(caCertHolder); | |
/** | |
* Load client certificate | |
*/ | |
reader = new PEMParser(new FileReader(crtFile)); | |
X509CertificateHolder certHolder = (X509CertificateHolder) reader.readObject(); | |
reader.close(); | |
X509Certificate cert = certificateConverter.getCertificate(certHolder); | |
/** | |
* Load client private key | |
*/ | |
reader = new PEMParser(new FileReader(keyFile)); | |
Object keyObject = reader.readObject(); | |
reader.close(); | |
PEMDecryptorProvider provider = new JcePEMDecryptorProviderBuilder().build(password.toCharArray()); | |
JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC"); | |
KeyPair key; | |
if (keyObject instanceof PEMEncryptedKeyPair) { | |
key = keyConverter.getKeyPair(((PEMEncryptedKeyPair) keyObject).decryptKeyPair(provider)); | |
} else { | |
key = keyConverter.getKeyPair((PEMKeyPair) keyObject); | |
} | |
/** | |
* CA certificate is used to authenticate server | |
*/ | |
KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | |
caKeyStore.load(null, null); | |
caKeyStore.setCertificateEntry("ca-certificate", caCert); | |
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( | |
TrustManagerFactory.getDefaultAlgorithm()); | |
trustManagerFactory.init(caKeyStore); | |
/** | |
* Client key and certificates are sent to server so it can authenticate the client | |
*/ | |
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | |
clientKeyStore.load(null, null); | |
clientKeyStore.setCertificateEntry("certificate", cert); | |
clientKeyStore.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), | |
new Certificate[]{cert}); | |
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( | |
KeyManagerFactory.getDefaultAlgorithm()); | |
keyManagerFactory.init(clientKeyStore, password.toCharArray()); | |
/** | |
* Create SSL socket factory | |
*/ | |
SSLContext context = SSLContext.getInstance("TLSv1.2"); | |
context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); | |
/** | |
* Return the newly created socket factory object | |
*/ | |
return context.getSocketFactory(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
return null; | |
} | |
} |
I have added support for server hostname ignore in the following updated code. Also it works with latest BouncyCastle version 1.68.
This will also support for client and server certificate verification as well only server certificate for clients who doesn't have client certs but only have rootCA using which server certs were signed.
https://gist.github.com/saumilsdk/1e17e30e33d0a18f44ce4e2b5841b281
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello Guyz, I am connecting to server using server CA, Client CA & Private key, where all three are .pem files. But for private key there is no password, so am using random password. After connecting to server at handshake I am getting error like : fatal error Handshake failure.
WRITE: TLSv1.2 Handshake, length = 40
SwingWorker-pool-1-thread-1, READ: TLSv1.2 Alert, length = 2
SwingWorker-pool-1-thread-1, RECV TLSv1.2 ALERT: fatal, handshake_failure
%% Invalidated: [Session-1, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384]
SwingWorker-pool-1-thread-1, called closeSocket()
SwingWorker-pool-1-thread-1, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Can any one guide please?