Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate and Sign Certificate Request using pure .net Framework

I am trying to use pure .net code to create a certificate request and create a certificate from the certificate request against an existing CA certificate I have available (either in the Windows Certificate store or as a separate file).

I know that I have the classes X509Certificate and X509Certificate2 available to load certificates and get access to their information, but I don't see any classes or functionality within the System.Security.Cryptography namespace that could be used to create a certificate request or to sign such a certificate request to create a new signed certificate.

And that although the documentation on the System.Security.Cryptography.Pkcs namespace says:

The System.Security.Cryptography.Pkcs namespace provides programming elements for Public Key Cryptography Standards (PKCS), including methods for signing data, exchanging keys, requesting certificates, public key encryption and decryption, and other security functions.

So, how can I create a certificate request and fulfill that request to create a new X509 certificate using only pure .net classes from System.Security.Cryptography?


Note:

  • I don't want to use an external executable like openssl or MakeCert
  • I don't want to use BouncyCastle
  • I don't want to use Windows Certificate Enrollment API
  • I don't want to use the native Win32 API functions
like image 775
NineBerry Avatar asked Jan 10 '18 21:01

NineBerry


1 Answers

Short answer: You can starting in .NET Framework 4.7.2.

This functionality was originally added to .NET Core 2.0 in the form of the CertificateRequest class, which can build a PKCS#10 certification signing request or an X.509 (self-signed or chained) public key certificate.

The classes for that feature were made available in .NET Framework 4.7.2.

using (RSA parent = RSA.Create(4096)) using (RSA rsa = RSA.Create(2048)) {     CertificateRequest parentReq = new CertificateRequest(         "CN=Experimental Issuing Authority",         parent,         HashAlgorithmName.SHA256,         RSASignaturePadding.Pkcs1);      parentReq.CertificateExtensions.Add(         new X509BasicConstraintsExtension(true, false, 0, true));      parentReq.CertificateExtensions.Add(         new X509SubjectKeyIdentifierExtension(parentReq.PublicKey, false));      using (X509Certificate2 parentCert = parentReq.CreateSelfSigned(         DateTimeOffset.UtcNow.AddDays(-45),         DateTimeOffset.UtcNow.AddDays(365)))     {         CertificateRequest req = new CertificateRequest(             "CN=Valid-Looking Timestamp Authority",             rsa,             HashAlgorithmName.SHA256,             RSASignaturePadding.Pkcs1);          req.CertificateExtensions.Add(             new X509BasicConstraintsExtension(false, false, 0, false));          req.CertificateExtensions.Add(             new X509KeyUsageExtension(                 X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation,                 false));          req.CertificateExtensions.Add(             new X509EnhancedKeyUsageExtension(                 new OidCollection                 {                     new Oid("1.3.6.1.5.5.7.3.8")                 },                 true));          req.CertificateExtensions.Add(             new X509SubjectKeyIdentifierExtension(req.PublicKey, false));          using (X509Certificate2 cert = req.Create(             parentCert,             DateTimeOffset.UtcNow.AddDays(-1),             DateTimeOffset.UtcNow.AddDays(90),             new byte[] { 1, 2, 3, 4 }))         {             // Do something with these certs, like export them to PFX,             // or add them to an X509Store, or whatever.         }     } } 

Longer answer if you're stuck on older versions: To accomplish your goal without adding any new P/Invokes, you would need to read and understand the following documents:

  • ITU-T X.680-201508, the ASN.1 language
  • IETF RFC 5280 or ITU-T X.509, the documents that explain the fields in X.509 certificates.
  • IETF RFC 2986, explains the PKCS#10 certification signing request
  • ITU-T X.690, explains the BER encoding family for ASN.1 (including DER) which tells you how to read and write bytes to achieve the semantic meaning from X.509 / PKCS#10.

And then you could write a DER writer/reader, and just emit the bytes for what you want.

like image 185
bartonjs Avatar answered Sep 28 '22 06:09

bartonjs