Question

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.

Was it helpful?

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.

OTHER TIPS

After spending the weekend to port our BC version from 143 to 154, I am posting lessions learnt, hoping it would save some time for someone in the future.

1) The PKI eXtention API from BC has been moved to its own jar. I was breaking my head to find PemParser in bcprov-jdk15on-154.jar. The implementation for PemParser is in bcpkix-jdk15on-154.jar. Needless to say the pkix jar depends on core bc jar.

2) The PEMReader class is not available in latest 154 version. This has been replaced by PemParser.

3) Reading a public certificate from file on disk:

Security.addProvider(new BouncyCastleProvider());
File file = new File("c:/mycert.crt");
X509Certificate cert = null;
PEMParser pemParser = new PEMParser(new FileReader(file));
Object object = pemParser.readObject();
if (object instanceof X509CertificateHolder) {
    X509CertificateHolder holder = (X509CertificateHolder)object;
    cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(holder);
}
if (cert == null) {
    throw new Exception("mycert.crt" + " doesn't contain X509Certificate!");
}
return cert;
//If you need publicKey use cert.getPublicKey() method.

4) Reading a password protected private key from disk:

Security.addProvider(new BouncyCastleProvider());
KeyPair keyPair = null;
File file = new File("c:/myprivate.key");
PEMParser pemParser = new PEMParser(new FileReader(file));
Object object = pemParser.readObject();
if (object instanceof PEMEncryptedKeyPair) {
    JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
    PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) object;
    PEMDecryptorProvider decProv =
            new JcePEMDecryptorProviderBuilder().build("strongpasswordfor_myprivate.key".toCharArray());
    keyPair = converter.getKeyPair(ckp.decryptKeyPair(decProv));
}
return keyPair;
//Once we have the keypair, we can get keyPair.getPrivate() [PrivateKey.class] 
//or keyPair.getPublic() [PublicKey.class]  

5) Reading a string based certificate, this is typically the case when we want to do SSL mutual auth, and have webserver forward the client certificate to the application server in the Http Request Header:

Security.addProvider(new BouncyCastleProvider());
X509Certificate cert = null;
    String myClientCert = "-----BEGIN CERTIFICATE----- CERTCONTENTS -----END CERTIFICATE-----"
    String cert1 = myClientCert.replaceAll("-----BEGIN CERTIFICATE-----", "").replaceAll("-----END CERTIFICATE-----", "").replaceAll(" ", System.lineSeparator());
    int ind = cert1.lastIndexOf(System.lineSeparator());
    cert1 = new StringBuilder(cert1).replace(ind, ind + System.lineSeparator().length(), "").toString();
    cert1 = BEGIN_CERT  + cert1 + END_CERT;
    PEMParser pemParser = new PEMParser(new StringReader(cert1));
    Object object = pemParser.readObject();
    if (object instanceof X509CertificateHolder) {
        X509CertificateHolder holder = (X509CertificateHolder)object;
        cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(holder);
    }
    return cert;

6) Needless to say, add error handling, exception management & cleanup to your taste.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top