5

I'm totally new to crypto/certs and trying to generate a certificate using the Bouncy Castle libraries. Looking at some of their sample code, this is what I have so far:

package crypto;

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.X509v1CertificateBuilder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v1CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Properties;


public class App {

    private static final int VALIDITY_PERIOD = 7 * 24 * 60 * 60 * 1000; // one week

    public static void main (String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        KeyPair keyPair = generateRSAKeyPair();
        X509Certificate rootCert = buildRootCert(keyPair);
        buildEndEntityCert(keyPair.getPublic(), keyPair.getPrivate(), rootCert);
    }

    /**
     * Create a random 2048 bit RSA key pair
     */
    public static KeyPair generateRSAKeyPair() throws Exception {
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
        kpGen.initialize(2048, new SecureRandom());

        return kpGen.generateKeyPair();
    }

    /**
     * Build a sample V1 certificate to use as a CA root certificate
     */
    public static X509Certificate buildRootCert(KeyPair keyPair)
            throws Exception
    {
        X509v1CertificateBuilder certBldr = new JcaX509v1CertificateBuilder(
                new X500Name("CN=Test Root Certificate"),
                BigInteger.valueOf(1),
                new Date(System.currentTimeMillis()),
                new Date(System.currentTimeMillis() + VALIDITY_PERIOD),
                new X500Name("CN=Test Root Certificate"),
                keyPair.getPublic());

        ContentSigner signer = new JcaContentSignerBuilder("SHA1WithRSA").setProvider("BC").build(keyPair.getPrivate());

        return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBldr.build(signer));
    }

    /**
     * Build a sample V3 certificate to use as an end entity certificate
     */
    public static X509Certificate buildEndEntityCert(PublicKey entityKey, PrivateKey caKey, X509Certificate caCert)
            throws Exception
    {

        X509v3CertificateBuilder certBldr = new JcaX509v3CertificateBuilder(
                caCert.getSubjectX500Principal(),
                BigInteger.valueOf(1),
                new Date(System.currentTimeMillis()),
                new Date(System.currentTimeMillis() + VALIDITY_PERIOD),
                new X500Principal("CN=Test End Entity Certificate"),
                entityKey);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

        certBldr.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert))
                .addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(entityKey))
                .addExtension(Extension.basicConstraints, true, new BasicConstraints(false))
                .addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));

        ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(caKey);

        return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBldr.build(signer));
    }
}

My pom has the various Bouncy Castle libs and latest itext:

<dependencies>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.56</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.47</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcmail-jdk15</artifactId>
            <version>1.46</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-ext-jdk15on</artifactId>
            <version>1.55</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpg-jdk15on</artifactId>
            <version>1.56</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-debug-jdk15on</artifactId>
            <version>1.55</version>
        </dependency>
        <dependency>
            <groupId>commons-configuration</groupId>
            <artifactId>commons-configuration</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.11</version>
        </dependency>

But I'm getting this error:

Exception in thread "main" java.lang.NoSuchMethodError: org.bouncycastle.asn1.ASN1Integer.<init>(I)V
    at org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder.createPSSParams(Unknown Source)
    at org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder.<clinit>(Unknown Source)
    at org.bouncycastle.operator.jcajce.JcaContentSignerBuilder.<init>(Unknown Source)
    at crypto.App.buildRootCert(App.java:62)
    at crypto.App.main(App.java:34)

Process finished with exit code 1

Does anyone know why?

Crystal
  • 28,460
  • 62
  • 219
  • 393

1 Answers1

12

It happens because of different versions being used (1.56 and 1.46). After version 1.47, many parts of the API have changed.

I could run your code changing my pom.xml to use only version 1.56:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.56</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcmail-jdk15on</artifactId>
    <version>1.56</version>
</dependency>

That's the minimal set of libs to run the code in your question. Of course if your application needs to use other libs (bcpg, bcprov-ext and so on), you can include them accordingly (but I suggest you to choose versions >= 1.55, to avoid these mixed versions issues)

Note: bcmail depends on bcpkix and bcprov, so actually only bcmail is needed in pom.xml

  • Ya that wasn't intentional. I don't really know much about this crypto space and looking at different SO posts, i didn't even know there were other libs to pull in for this sample code to work. Do you recommend any crypto tutorials to get started for using Java to create certs, keys like you would using openssl. (i thought this was useful to understand, but only if it was in java code instd of keytool: https://sites.google.com/site/ddmwsst/create-your-own-certificate-and-ca) – Crystal May 09 '17 at 20:26
  • For certificates creation/manipulation, I believe **bcprov** and **bcmail** are enough (as it is in the answer), I've never needed to use **bcpg**, **bcprov-ext** and others. Tutorials: I'd suggest [java security guide](http://docs.oracle.com/javase/8/docs/technotes/guides/security), specially the **Public Key Infrastructure** chapters. Bouncycastle also has a [doc page](http://www.bouncycastle.org/documentation.html) but I think it could be better. –  May 09 '17 at 21:07
  • For something more conceptual and less java-specific, you could google for Public Key Infrastructure - [wikipedia has a good article](https://en.wikipedia.org/wiki/Public_key_infrastructure). For normative (very technical and boring document), take a look at the [RFC 5280](https://tools.ietf.org/html/rfc5280) –  May 09 '17 at 21:09