I'm adding a SAN extension to my CSR
public CertificateRequest GenerateCSR(string subjectName, List<string> ipAddresses, out RSA rsaKeyPair)
{
if (ipAddresses == null)
{
throw new ArgumentNullException(nameof(ipAddresses));
}
_logger.LogInformation("Starting CSR generation for subject: {SubjectName}", subjectName);
rsaKeyPair = RSA.Create(2048);
_logger.LogDebug("RSA key pair generated successfully with key size {KeySize}.", rsaKeyPair.KeySize);
var subject = new X500DistinguishedName(subjectName);
var csr = new CertificateRequest(subject, rsaKeyPair, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
_logger.LogDebug("CSR Subject: {CSRSubject}", csr.SubjectName.Name);
var sanBuilder = new SubjectAlternativeNameBuilder();
foreach (var ipAddress in ipAddresses)
{
sanBuilder.AddIpAddress(IPAddress.Parse(ipAddress));
}
var sanExtension = sanBuilder.Build();
csr.CertificateExtensions.Add(sanExtension);
_logger.LogDebug("Added Subject Alternative Name extension with {SANCount} IP addresses.", ipAddresses.Count);
foreach (var extension in csr.CertificateExtensions)
{
var asnData = new AsnEncodedData(extension.Oid, extension.RawData);
var formattedData = asnData.Format(true);
_logger.LogDebug("CSR Extension: {ExtensionOid} - {ExtensionFriendlyName} - {ExtensionFormattedData}", extension.Oid?.Value ?? "Unknown", extension.Oid?.FriendlyName ?? "Unknown", formattedData);
}
_logger.LogInformation("CSR generated successfully for subject: {SubjectName}.", subjectName);
return csr;
}
What logs and OpenSSL successfully notify about it.
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
IP Address:192.168.5.122
Then I pass the CSR through SignalR to the server and it generates a certificate and signs it with the key of the internal CA
public X509Certificate2 GenerateCertificateFromCSR(byte[] csrBytes)
{
if (csrBytes == null)
{
throw new ArgumentNullException(nameof(csrBytes));
}
var csr = CertificateRequest.LoadSigningRequest(csrBytes, HashAlgorithmName.SHA256);
using var caCertificate = new X509Certificate2(_settings.PfxPath, _settings.PfxPassword);
var subjectName = new X500DistinguishedName(caCertificate.SubjectName);
var signatureGenerator = X509SignatureGenerator.CreateForRSA(caCertificate.GetRSAPrivateKey(), RSASignaturePadding.Pkcs1);
var notBefore = DateTimeOffset.UtcNow;
var notAfter = DateTimeOffset.UtcNow.AddYears(1);
var serialNumber = GenerateSerialNumber();
var certificate = csr.Create(subjectName, signatureGenerator, notBefore, notAfter, serialNumber);
foreach (var extension in csr.CertificateExtensions)
{
var asnData = new AsnEncodedData(extension.Oid, extension.RawData);
var formattedData = asnData.Format(true);
_logger.LogDebug("CSR Extension: {ExtensionOid} - {ExtensionFriendlyName} - {ExtensionFormattedData}", extension.Oid?.Value ?? "Unknown", extension.Oid?.FriendlyName ?? "Unknown", formattedData);
certificate.Extensions.Add(extension);
}
return certificate;
}
But there is no message in the logs when adding extensions and the extensions are not in the final certificate. At the same time, the certificate itself is correct. How can this be?
Don't suggest using BouncyCastle, on the contrary I am trying to move away from using it.
A bit non-obvious to me, but you should have loaded the CSR with the
CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions
parameter.