Sunday 16 October 2016

Create Version 3, X.509 certificate hierarchy in java using bouncy castle API.

In this article I am going to talk about creating SSL certificates in java program using bouncy castle API.

Bouncy castle is a lightweight cryptography API. It is implementation of Java Cryptography Extension(JCE) and the Java Cryptography Architecture.(JCA).

I will create very basic certificates which contains only necessary properties.You can explore the API for more operations and properties you can apply to a certificate.

Please import below dependency in your code.
   
     <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->  
     <dependency>  
       <groupId>org.bouncycastle</groupId>  
       <artifactId>bcpkix-jdk15on</artifactId>  
       <version>1.55</version>  
     </dependency>  
     <!-- https://mvnrepository.com/artifact/joda-time/joda-time -->  
     <dependency>  
       <groupId>joda-time</groupId>  
       <artifactId>joda-time</artifactId>  
       <version>2.9.4</version>  
     </dependency>  


I am performing below steps in the code:
Steps:
1) Creating a self signed root certificate.
2) Creating an intermediate certificate signed by root certificate created in step 1.
3) Creating an end user certificate signed by intermediate certificate created in step 2.

Code:
 import org.bouncycastle.asn1.x500.X500Name;  
 import org.bouncycastle.asn1.x509.BasicConstraints;  
 import org.bouncycastle.asn1.x509.Extension;  
 import org.bouncycastle.asn1.x509.KeyUsage;  
 import org.bouncycastle.cert.X509v3CertificateBuilder;  
 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;  
 import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;  
 import org.bouncycastle.jce.provider.BouncyCastleProvider;  
 import org.bouncycastle.operator.OperatorCreationException;  
 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;  
 import org.joda.time.DateTime;  
   
 import java.io.FileOutputStream;  
 import java.io.IOException;  
 import java.math.BigInteger;  
 import java.security.*;  
 import java.security.cert.CertificateEncodingException;  
 import java.security.cert.CertificateException;  
 import java.security.cert.X509Certificate;  
 import java.util.Random;  
   
   
 public class App {  
   
   public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, OperatorCreationException, InvalidKeyException, NoSuchProviderException, SignatureException, UnrecoverableKeyException {  
     Security.addProvider(new BouncyCastleProvider());  
   
     // Create self signed Root CA certificate  
     KeyPair rootCAKeyPair = generateKeyPair();  
     X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(  
         new X500Name("CN=rootCA"), // issuer authority  
         BigInteger.valueOf(new Random().nextInt()), //serial number of certificate  
         DateTime.now().toDate(), // start of validity  
         new DateTime(2025, 12, 31, 0, 0, 0, 0).toDate(), //end of certificate validity  
         new X500Name("CN=rootCA"), // subject name of certificate  
         rootCAKeyPair.getPublic()); // public key of certificate  
     // key usage restrictions  
     builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));  
     builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));  
     X509Certificate rootCA = new JcaX509CertificateConverter().getCertificate(builder  
         .build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").  
             build(rootCAKeyPair.getPrivate()))); // private key of signing authority , here it is self signed  
     saveToFile(rootCA, "D:\\rootCA.cer");  
   
   
     //create Intermediate CA cert signed by Root CA  
     KeyPair intermedCAKeyPair = generateKeyPair();  
     builder = new JcaX509v3CertificateBuilder(  
         rootCA, // here rootCA is issuer authority  
         BigInteger.valueOf(new Random().nextInt()), DateTime.now().toDate(),  
         new DateTime(2025, 12, 31, 0, 0, 0, 0).toDate(),  
         new X500Name("CN=IntermedCA"), intermedCAKeyPair.getPublic());  
     builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));  
     builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));  
     X509Certificate intermedCA = new JcaX509CertificateConverter().getCertificate(builder  
         .build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").  
             build(rootCAKeyPair.getPrivate())));// private key of signing authority , here it is signed by rootCA  
     saveToFile(intermedCA, "D:\\intermedCA.cer");  
   
     //create end user cert signed by Intermediate CA  
     KeyPair endUserCertKeyPair = generateKeyPair();  
     builder = new JcaX509v3CertificateBuilder(  
         intermedCA, //here intermedCA is issuer authority  
         BigInteger.valueOf(new Random().nextInt()), DateTime.now().toDate(),  
         new DateTime(2025, 12, 31, 0, 0, 0, 0).toDate(),  
         new X500Name("CN=endUserCert"), endUserCertKeyPair.getPublic());  
     builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature));  
     builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));  
     X509Certificate endUserCert = new JcaX509CertificateConverter().getCertificate(builder  
         .build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").  
             build(intermedCAKeyPair.getPrivate())));// private key of signing authority , here it is signed by intermedCA  
     saveToFile(endUserCert, "D:\\endUserCert.cer");  
   }  
   
   private static KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {  
     KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");  
     kpGen.initialize(2048, new SecureRandom());  
     return kpGen.generateKeyPair();  
   }  
   
   private static void saveToFile(X509Certificate certificate, String filePath) throws IOException, CertificateEncodingException {  
     FileOutputStream fileOutputStream = new FileOutputStream(filePath);  
     fileOutputStream.write(certificate.getEncoded());  
     fileOutputStream.flush();  
     fileOutputStream.close();  
   }  
   
 }  
   


Here you can see, for rootCA I am using its own private key to sign the certificate. For intermedCA I am using rootCA private key for signing. For end user certificate I am using IntermedCA private key for signing.
In real life also you can see a chain of certificate similar to this. Open any certificate of HTTPS connection from browser and observe the certificate chain and properties of each certificate.

"SHA256withRSA" is a signature algorithm I am using it for signing the certificates.
In keyUsage "keyCertSign" restricts the certificate usage only for signing other certificates. While "digitalSignature" usage needed for SSL client , our web browser, for example which uses that certificate for entity authentication and data origin authentication with integrity.

The "true" flag in BasicConstraints mark the certificate as a CA certificate which can sign other certificates. "false" flag mark the certificate as end entity of the certificate chain.

As an out come of this program you will have 3 certificates in the specified file path.





Now open the rootCA first:


























You can see certificate not trusted message. So lets add this certificate in trusted root certificate store

1) Click on "Install certificate" button.
2) select "Local Machine" , click next
3) select second option of "place all certificates in the following store"
4) Browse and select "Trusted Root Certification Authority"
5) Click "Next" than click "Finish".
6) Import successful.


Same thing perform for "Intermed CA" certificate , with only change in step 4: Browse and select "Intermediate Certification Authority".

Now close the certificate and reopen it.
Lets examine each certificate now:

1) RootCA



              




2)Intermed CA
























3) End user certificate






















































There are other ways to create certificates and certificate chain. For e.g:  java "keytool" command or using tool like "keystore explorer"....
But Many times you have situation where you have to do certificate operations from program only.
So this will be very helpful at that time.

In next article I will post more on the topic of certificates and the operations you can perform using bouncy castle from java program.

Please post your comments and doubts!!!


3 comments:

  1. How do i create clientKey.der file along with endusercert file

    ReplyDelete
  2. if i had any money i'd donate it all to you.
    Thank you so much!

    ReplyDelete