Saturday, August 23, 2014

Signing Certificate Signing Request (CSR) using bouncycastle 1.49

Digital Certificates are used to used to prove the ownership of public keys in the Public Key Infrastructure. It usually consist of the details of the Subject (The entity to whom the certificate is issued), the details of the Issuer by whom the certificate is signed (Usually a Certificate Authority (CA), can be the subject itself in case of self signed certificates), the public key, a serial number and optionally some other properties.

To get the public key signed, the subject first create a Certificate Signing Request (CSR), Which contains the public key and the details of the subject such as Distinguished Name (DN), Organization (O), Organization Unit (OU), State (ST), Country(C). The CA then verify these details and sign (or reject) the request.

If you are using Java to sign a certificate, you can use Bouncy Castle to sign the CSRs programmatically. Following code will explain how it can be done with bouncycastle 1.49.
In order to use bouncycastle, you need to add the bcprov and bcpkix jars to the classpath which can be downloaded from [1] and add the bouncycastle provider as,

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

We'll begin by creating a PKCS10CertificationRequest object from the CSR

encodedCsr = "....." //The PEM encoded CSR's text content
PEMParser pemParser = new PEMParser(new InputStreamReader(new ByteArrayInputStream(encodedCsr.getBytes())));
PKCS10CertificationRequest request = (PKCS10CertificationRequest) pemParser.readObject();

Then sign the above created PKCS10CertificationRequest as follows,

try {
            int validity = 365; //No of days the certificate should be valid
            String serialNo = ...; // a unique number
            privateKey = ...; // The CA's private key
            caCert = ...; //The CA's certificate as a X509Certificate
            Date issuedDate = new Date();
            Date expiryDate = new Date(System.currentTimeMillis() + validity * MILLIS_PER_DAY); //MILLIS_PER_DAY=86400000l
            JcaPKCS10CertificationRequest jcaRequest = new JcaPKCS10CertificationRequest(request);
            X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(caCert,
                    new BigInteger(serialNo), issuedDate, expiryDate, jcaRequest.getSubject(), jcaRequest.getPublicKey());
            JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
            certificateBuilder.addExtension(Extension.authorityKeyIdentifier, false,
                    .addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(jcaRequest
                    .addExtension(Extension.basicConstraints, true, new BasicConstraints(0))
                    .addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage
                    .addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));
            ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privateKey);

            //Add the CRL endpoint
            DistributionPointName crlEp = new DistributionPointName(new GeneralNames(new GeneralName(GeneralName
                    .uniformResourceIdentifier, CA_CRL_ENDPOINT_URL)));
            DistributionPoint disPoint = new DistributionPoint(crlEp, null, null);
            certificateBuilder.addExtension(Extension.cRLDistributionPoints, false,
                    new CRLDistPoint(new DistributionPoint[]{disPoint}));

            //Add the OCSP endpoint
            AccessDescription ocsp = new AccessDescription(AccessDescription.id_ad_ocsp,
                    new GeneralName(GeneralName.uniformResourceIdentifier, CA_OCSP_ENDPOINT_URL)
            ASN1EncodableVector authInfoAccessASN = new ASN1EncodableVector();
            certificateBuilder.addExtension(Extension.authorityInfoAccess, false, new DERSequence(authInfoAccessASN));
            X509Certificate signedCert = new JcaX509CertificateConverter().setProvider("BC").getCertificate
        } catch (Exception e) {
            throw new CaException("Error in signing the certificate", e);