Search code examples
androidbouncycastlex509csr

Convert PKCS10CertificationRequest to X509 certificate


I wonder if it is possible to convert a PKCS10CertificationRequest into a X509 Certificate using Bouncy Castle?

Similar to X509_REQ_to_X509 in openssl.

This is how I create the request:

public static PKCS10CertificationRequest generateCSRFile(KeyPair keyPair, KeyUsage keyUsage) throws IOException, OperatorCreationException {
    String principal = "CA=" getCA();

    AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(keyPair.getPrivate().getEncoded());
    AlgorithmIdentifier signatureAlgorithm = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WITHRSA");
    AlgorithmIdentifier digestAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find("SHA-1");
    ContentSigner signer = new BcRSAContentSignerBuilder(signatureAlgorithm, digestAlgorithm).build(privateKey);

    PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name(principal), keyPair.getPublic());
    ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
    extensionsGenerator.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(true));
    extensionsGenerator.addExtension(X509Extension.keyUsage, true, keyUsage);
    csrBuilder.addAttribute(PKCSObjectIdentifiers.x509Certificate, extensionsGenerator.generate());
    PKCS10CertificationRequest csr = csrBuilder.build(signer);
    return csr;
}

Solution

  • I'm far from being an OpenSSL specialist but according to some documentation I found:

    X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey) creates an X509 certificate with subject and issuer the same as the subject in the request r, with validity days, and pkey used to sign it (with md5 as the digest).

    Here is an equivalent with Bouncycastle:

    public X509Certificate x509ReqToX509(PKCS10CertificationRequest csr, int days, PrivateKey pKey) 
    {
      Date notBefore = new Date();
      Calendar cal = Calendar.getInstance();
      cal.add(Calendar.DATE, days);
      Date notAfter = cal.getTime();
      BigInteger serialNumber = generateCertSerialNumber(); // No implemented here
    
      X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
    
      certGen.setSerialNumber(serialNumber);
      certGen.setIssuerDN(csr.getCertificationRequestInfo().getSubject());
      certGen.setSubjectDN(csr.getCertificationRequestInfo().getSubject());
      certGen.setNotBefore(notBefore);
      certGen.setNotAfter(notAfter);
      certGen.setPublicKey(csr.getPublicKey());
      certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
    
      return certGen.generate(pKey, "BC");
    }
    

    Note that:

    1. I replaced MD5 by SHA-256 in the signature algorithm.
    2. Depending on the certificate aim this short code sample may need some update (for instance, adding some mandatory extension)