Henric
Henric

Reputation: 802

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;
}

Upvotes: 4

Views: 2133

Answers (2)

Gru97
Gru97

Reputation: 591

I came across this question from a dotnet community and I post it here, it might be helpful.

You can generate an X509 Certificate using a PKCS10CertificationRequest and the private key, but it will be a self-signed certificate and might not be validated by the system you want to prove your identity to (it's for testing purpose only). Here is the code to generate an in .Net using Bouncy Castle:

public X509Certificate2 GenerateSelfSignedCertificate(Pkcs10CertificationRequest pkcsRequest)
{

    var privateKeyPemReader = new PemReader(File.OpenText("path to file"));
    var rsaPrivateKey = DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)privateKeyPemReader.ReadObject());

    // Specify the subject name
    string subjectName = pkcsRequest.GetCertificationRequestInfo().Subject.ToString();

    // Create a certificate request
    var request = new CertificateRequest($"CN={subjectName}", rsaPrivateKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

    // Add extensions to the request
    request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));

    // Create a self-signed certificate
    var certificate = request.CreateSelfSigned(DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddYears(10));

    // Return the certificate
    return new X509Certificate2(certificate.Export(X509ContentType.Cert));
}

For understanding the difference between a PKCS10CertificationRequest and an X509 Certificate please refer to these specifications:

PKCS10 Spec

X.509 Spec

In short, a PKCS10CertificationRequest is a request for obtaining certificate from a CA containing information like public key and subject. CA will issue and sign the certificate which will be of type X509 certificate and that will prove the certificate owner's identity to other systems.

Upvotes: 0

Jcs
Jcs

Reputation: 13709

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)

Upvotes: 3

Related Questions