Reputation: 28509
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:
Upvotes: 57
Views: 46853
Reputation: 101
I cant comment on the answer above, so this serves as a comment. @Keith
if the issue is the private key used for the server certificate is missing the private key i hope this explains whats going on.
To combine the public and private keys in the answer above,
cert = RSACertificateExtensions.CopyWithPrivateKey(cert, rsa);
This will bundle the private key with the certificate for exporting to PFX with
File.WriteAllBytes("filename", cert.Export(X509ContentType.Pfx, "passphrase for export"));
for the example provided above.
The method CreateSelfSigned
returns a X509Certificate2
object with the public and private key attached.
Where as when signing against a root, or subordinate
The Create
method will only create the public key component in the X509Certificate2
object.
I think this is because the usual certificate methods would use the CSR to sign against and return the public key for acceptance by the client which would never expose the private key to the signing server.
Upvotes: 8
Reputation: 33256
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:
And then you could write a DER writer/reader, and just emit the bytes for what you want.
Upvotes: 95