Skip to content
ecdsa.com

Generate a CSR · .NET

How to generate a CSR for an EC P-256 key with SANs in C#

In C#, System.Security.Cryptography.X509Certificates.CertificateRequest generates a CSR without any package: create it from a subject name and an ECDsa P-256 key, add a SubjectAlternativeNameBuilder extension, and call CreateSigningRequestPem. The run writes key.pem and csr.pem and decodes the CSR with OpenSSL.

Tested with .NET 10.0.402 (SDK, System.Security.Cryptography.X509Certificates.CertificateRequest).

app.cs — P-256 key and CSR with two SANs (a .NET 10 file-based app)
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
// The name string is read most-specific first (as .NET prints names), so CN comes first
var request = new CertificateRequest(
"CN=api.example.com, O=Example Corp, C=US", key, HashAlgorithmName.SHA256);
var san = new SubjectAlternativeNameBuilder();
san.AddDnsName("api.example.com");
san.AddDnsName("www.example.com");
request.CertificateExtensions.Add(san.Build());
// PKCS#10, signed with the request's own key (ecdsa-with-SHA256)
File.WriteAllText("csr.pem", request.CreateSigningRequestPem());
File.WriteAllText("key.pem", key.ExportPkcs8PrivateKeyPem());

How it works

  1. ECDsa.Create(ECCurve.NamedCurves.nistP256) creates the key.
  2. new CertificateRequest(name, key, HashAlgorithmName.SHA256) fixes the subject and the signature algorithm (ecdsa-with-SHA256).
  3. SubjectAlternativeNameBuilder with AddDnsName builds the SAN extension; extensions added to CertificateExtensions go into the CSR's extensionRequest.
  4. CreateSigningRequestPem() (.NET 7+) returns the PEM, and ExportPkcs8PrivateKeyPem() the key.

Gotchas

  • The name string is read most-specific first, as .NET prints names: "C=US, O=Example Corp, CN=api.example.com" produces a subject in reverse order (CN first in the DER). Write "CN=…, O=…, C=US". X500DistinguishedNameBuilder follows the same convention — components added C, O, CN also end up reversed.
  • CreateSigningRequest() returns DER bytes; CAs and ACME clients usually want the PEM from CreateSigningRequestPem().
  • ExportPkcs8PrivateKeyPem() writes the key unencrypted; ExportEncryptedPkcs8PrivateKeyPem(password, …) protects it with a password.
  • CertificateRequest can also sign certificates (CreateSelfSigned, Create), but the CSR itself carries only what you add — key usages and validity are chosen by the CA.

Related recipes