Search code examples
javasecurityencryptioncryptographydigital-certificate

Generating X509Certificate with BouncyCastle with Java


This is what I have right now to generate a digital certificate. And now I'm able to generate a digital certificate with password protected for private key.

public static void main(String[] args) throws Exception {
    Security.addProvider(new BouncyCastleProvider());
    testKeyStore();
}

public static void testKeyStore() throws Exception {
    try {
        String storeName = "d://suresh_test.cer";
        java.security.KeyPairGenerator keyPairGenerator = KeyPairGenerator
                .getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        X509Certificate trustCert = createCertificate("CN=CA", "CN=CA",
                publicKey, privateKey);
        java.security.cert.Certificate[] outChain = {
                createCertificate("CN=Client", "CN=CA", publicKey,
                        privateKey), trustCert };
        KeyStore outStore = KeyStore.getInstance("PKCS12");
        outStore.load(null, "suresh_".toCharArray());
        outStore.setKeyEntry("mykey", privateKey, "suresh_".toCharArray(),
                outChain);
        OutputStream outputStream = new FileOutputStream(storeName);
        outStore.store(outputStream, "suresh_".toCharArray());
        outputStream.flush();
        outputStream.close();

        KeyStore inStore = KeyStore.getInstance("PKCS12");
        inStore.load(new FileInputStream(storeName),
                "suresh_".toCharArray());
    } catch (Exception e) {
        e.printStackTrace();
        throw new AssertionError(e.getMessage());
    }
}

private static X509Certificate createCertificate(String dn, String issuer,
        PublicKey publicKey, PrivateKey privateKey) throws Exception {
    X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
    certGenerator.setSerialNumber(BigInteger.valueOf(Math.abs(new Random()
            .nextLong())));
    certGenerator.setIssuerDN(new X509Name(dn));
    certGenerator.setSubjectDN(new X509Name(dn));
    certGenerator.setIssuerDN(new X509Name(issuer)); // Set issuer!
    certGenerator.setNotBefore(Calendar.getInstance().getTime());
    certGenerator.setNotAfter(Calendar.getInstance().getTime());
    certGenerator.setPublicKey(publicKey);
    certGenerator.setSignatureAlgorithm("SHA1WithRSAEncryption");
    X509Certificate certificate = (X509Certificate) certGenerator.generate(
            privateKey, "BC");
    return certificate;
}

How to make it Self sign ?

I have no clues.

How can I proceed for that ?

Thanks for any hints.


Solution

  • You had all the code you needed to produce a self-signed certificate. You just needed to ensure your chain contained only one certificate.

    public static void testKeyStore() throws Exception {
      try {
        String storeName = "path/to/store";
        java.security.KeyPairGenerator keyPairGenerator = KeyPairGenerator
            .getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        X509Certificate selfCert = createCertificate("CN=Client", "CN=Client",
            publicKey, privateKey);
    
        // Note: if you just want to store this certificate then write the
        // contents of selfCert.getEncoded() to file
    
        java.security.cert.Certificate[] outChain = { selfCert };
        KeyStore outStore = KeyStore.getInstance("PKCS12");
        outStore.load(null, PASSWORD.toCharArray());
        outStore.setKeyEntry("mykey", privateKey, PASSWORD.toCharArray(),
            outChain);
        OutputStream outputStream = new FileOutputStream(storeName);
        outStore.store(outputStream, PASSWORD.toCharArray());
        outputStream.flush();
        outputStream.close();
    
        KeyStore inStore = KeyStore.getInstance("PKCS12");
        inStore.load(new FileInputStream(storeName), PASSWORD.toCharArray());
      } catch (Exception e) {
        e.printStackTrace();
        throw new AssertionError(e.getMessage());
      }
    }
    

    I would advise you don't throw an AssertionError. This should only be used by Java itself to indicate an assert statement is false.