In previous post, we have explained how to create a certificate chain in Java. After generating the chain, we need to store it somewhere so that it can be used later when we are doing the actual SSL communication, either in a key store or trust store. This post will show you how to store the private key and its associated certificate chain in a keystore file.
There are different types of keystore in Java, in this post, we will choose the JKS to demonstrate how to store the certificate chain. When storing a private key entry into a keystore, we need to store its associated certificate chain as well. Usually we need to give the entry an alias to identify the entry. Below is the code snippet to store an entry into a keystore:
KeyStore keyStore=KeyStore.getInstance("jks"); keyStore.load(null,null); keyStore.setKeyEntry(alias, key, password, chain); keyStore.store(new FileOutputStream(keystore),password);
First, we will load an empty keystore, if you already have a keystore, can replace:
keyStore.load(null,null);
with
keyStore.load(new FileInputStream(keystore),password);
After loading the keystore, we can set the entry by calling setKeyEntry and pass the alias, private key, key protection password and the associated certificate chain. Then we call keyStore.store() to store the entry. Note in some hardware keystore, we no need to call keyStore.store() method to save the keystore, the setKeyEntry() will automatically put the entry onto the hardware.
We can retrieve the certificate chain from the keystore by calling
keyStore.getCertificateChain() method with the specified alias.
Certificate[] certs=keyStore.getCertificateChain(alias);
Below is a workable program which demonstrate how to store and retrieve the certificate chain.
import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.Key; import java.security.KeyStore; import java.security.Principal; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; //import javax.security.cert.Certificate; import sun.security.x509.BasicConstraintsExtension; import sun.security.x509.CertAndKeyGen; import sun.security.x509.CertificateExtensions; import sun.security.x509.CertificateIssuerName; import sun.security.x509.X500Name; import sun.security.x509.X509CertImpl; import sun.security.x509.X509CertInfo; public class CertificateChainGeneration { public static void main(String[] args){ try{ //Generate ROOT certificate CertAndKeyGen keyGen=new CertAndKeyGen("RSA","SHA1WithRSA",null); keyGen.generate(1024); PrivateKey rootPrivateKey=keyGen.getPrivateKey(); X509Certificate rootCertificate = keyGen.getSelfCertificate(new X500Name("CN=ROOT"), (long) 365 * 24 * 60 * 60); //Generate intermediate certificate CertAndKeyGen keyGen1=new CertAndKeyGen("RSA","SHA1WithRSA",null); keyGen1.generate(1024); PrivateKey middlePrivateKey=keyGen1.getPrivateKey(); X509Certificate middleCertificate = keyGen1.getSelfCertificate(new X500Name("CN=MIDDLE"), (long) 365 * 24 * 60 * 60); //Generate leaf certificate CertAndKeyGen keyGen2=new CertAndKeyGen("RSA","SHA1WithRSA",null); keyGen2.generate(1024); PrivateKey topPrivateKey=keyGen2.getPrivateKey(); X509Certificate topCertificate = keyGen2.getSelfCertificate(new X500Name("CN=TOP"), (long) 365 * 24 * 60 * 60); rootCertificate = createSignedCertificate(rootCertificate,rootCertificate,rootPrivateKey); middleCertificate = createSignedCertificate(middleCertificate,rootCertificate,rootPrivateKey); topCertificate = createSignedCertificate(topCertificate,middleCertificate,middlePrivateKey); X509Certificate[] chain = new X509Certificate[3]; chain[0]=topCertificate; chain[1]=middleCertificate; chain[2]=rootCertificate; String alias = "mykey"; char[] password = "password".toCharArray(); String keystore = "testkeys.jks"; //Store the certificate chain storeKeyAndCertificateChain(alias, password, keystore, topPrivateKey, chain); //Reload the keystore and display key and certificate chain info loadAndDisplayChain(alias, password, keystore); //Clear the keystore clearKeyStore(alias, password, keystore); }catch(Exception ex){ ex.printStackTrace(); } } private static void storeKeyAndCertificateChain(String alias, char[] password, String keystore, Key key, X509Certificate[] chain) throws Exception{ KeyStore keyStore=KeyStore.getInstance("jks"); keyStore.load(null,null); keyStore.setKeyEntry(alias, key, password, chain); keyStore.store(new FileOutputStream(keystore),password); } private static void loadAndDisplayChain(String alias,char[] password, String keystore) throws Exception{ //Reload the keystore KeyStore keyStore=KeyStore.getInstance("jks"); keyStore.load(new FileInputStream(keystore),password); Key key=keyStore.getKey(alias, password); if(key instanceof PrivateKey){ System.out.println("Get private key : "); System.out.println(key.toString()); Certificate[] certs=keyStore.getCertificateChain(alias); System.out.println("Certificate chain length : "+certs.length); for(Certificate cert:certs){ System.out.println(cert.toString()); } }else{ System.out.println("Key is not private key"); } } private static void clearKeyStore(String alias,char[] password, String keystore) throws Exception{ KeyStore keyStore=KeyStore.getInstance("jks"); keyStore.load(new FileInputStream(keystore),password); keyStore.deleteEntry(alias); keyStore.store(new FileOutputStream(keystore),password); } private static X509Certificate createSignedCertificate(X509Certificate cetrificate,X509Certificate issuerCertificate,PrivateKey issuerPrivateKey){ try{ Principal issuer = issuerCertificate.getSubjectDN(); String issuerSigAlg = issuerCertificate.getSigAlgName(); byte[] inCertBytes = cetrificate.getTBSCertificate(); X509CertInfo info = new X509CertInfo(inCertBytes); info.set(X509CertInfo.ISSUER, new CertificateIssuerName((X500Name) issuer)); //No need to add the BasicContraint for leaf cert if(!cetrificate.getSubjectDN().getName().equals("CN=TOP")){ CertificateExtensions exts=new CertificateExtensions(); BasicConstraintsExtension bce = new BasicConstraintsExtension(true, -1); exts.set(BasicConstraintsExtension.NAME,new BasicConstraintsExtension(false, bce.getExtensionValue())); info.set(X509CertInfo.EXTENSIONS, exts); } X509CertImpl outCert = new X509CertImpl(info); outCert.sign(issuerPrivateKey, issuerSigAlg); return outCert; }catch(Exception ex){ ex.printStackTrace(); } return null; } }
We will cover different extensions of certificate in future post.
the above code give that error to me when i run this on java netbeans.
java.security.cert.CertificateException: Issuer class type invalid.
at sun.security.x509.X509CertInfo.setIssuer(X509CertInfo.java:860)
at sun.security.x509.X509CertInfo.set(X509CertInfo.java:403)
at certchain.CertificateChainGeneration.createSignedCertificate(CertificateChainGeneration.java:123)
at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:56)
java.lang.NullPointerException
at certchain.CertificateChainGeneration.createSignedCertificate(CertificateChainGeneration.java:118)
at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:57)
java.lang.NullPointerException
at certchain.CertificateChainGeneration.createSignedCertificate(CertificateChainGeneration.java:118)
at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:58)
java.lang.NullPointerException
at sun.security.provider.JavaKeyStore.engineStore(JavaKeyStore.java:577)
at sun.security.provider.JavaKeyStore$JKS.engineStore(JavaKeyStore.java:56)
at sun.security.provider.KeyStoreDelegator.engineStore(KeyStoreDelegator.java:195)
at sun.security.provider.JavaKeyStore$DualFormatJKS.engineStore(JavaKeyStore.java:70)
at java.security.KeyStore.store(KeyStore.java:1377)
at certchain.CertificateChainGeneration.storeKeyAndCertificateChain(CertificateChainGeneration.java:85)
at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:70)