Jan 31, 2010

How to generate Self-Signed Certificates programmatically ?

The most common approach of generating a self-signed certificate is using the Java Keytool. But there may be situations where the requirement is to generate self-signed certificates programmatically.

It is possible to do this by programmatically invoking the keytool(using Runtime.exec) which is not a very promising approach. And also it is possible to use the Sun's proprietary classes used inside the Keytool to do this. But there is no documented API on these classes.

One clean approach of programmatically generating these self-signed certificates is through the Bouncy Castle API. I will walk you through the important steps of the above process.

To start with this, you need to have the Bouncy Castle jar in your classpath.(You can download it from here)

First you need to generate a key pair. We are using "RSA" public-key cryptography algorithm and a key size of 1024.

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair KPair = keyPairGenerator.generateKeyPair();

Then instantiate an X.509 cert. generator.
X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();

Now start creating the certificate. Serial number, issuer, validity period and Subject are set here.
v3CertGen.setSerialNumber(BigInteger.valueOf(new SecureRandom().nextInt()));
        v3CertGen.setIssuerDN(new X509Principal("CN=" + domainName + ", OU=None, O=None L=None, C=None"));
        v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
        v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365*10)));
        v3CertGen.setSubjectDN(new X509Principal("CN=" + domainName + ", OU=None, O=None L=None, C=None"));

Then set the public key of the key pair and the signing algorithm to the cert generator.
v3CertGen.setPublicKey(KPair.getPublic());
v3CertGen.setSignatureAlgorithm("MD5WithRSAEncryption"); 

Now you can generate the certificate.
X509Certificate PKCertificate = v3CertGen.generateX509Certificate(KPair.getPrivate());

And store it in a file.
FileOutputStream fos = new FileOutputStream("/path/to/testCert.cert");
fos.write(PKCertificate.getEncoded());
fos.close();

You can view this cert using the keytool.
keytool -printcert -file /path/to/cert

Upto now we have created a key-pair and generated a X.509 certificate which contains the public key. Now we have to import the generated private key to a key store. Importing the private key to a key store is straight forward.

Load the key store to memory.

KeyStore privateKS = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("/path/to/sample-key-store.jks");
privateKS.load(fis, "keyStorePass".toCharArray());

Import the private key to the key store.

privateKS.setKeyEntry("sample.alias", KPair.getPrivate(),
                   new char[]{'e', 'n', 't', 'r', 'y', 'p', 'a', 's', 's'},
                   new java.security.cert.Certificate[]{PKCertificate});

Write the key store back to disk.

privateKS.store( new FileOutputStream(keystoreFile), "keyStorePass".toCharArray());

You can try this with different parameters like key sizes, signing algorithms, etc.