Why are there no extensions in the CertificateExtensions property of CertificateRequest?

84 views Asked by At

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.

1

There are 1 answers

1
vitkuz573 On BEST ANSWER

A bit non-obvious to me, but you should have loaded the CSR with the CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions parameter.