Repository: dotnet/aspnetcore
File: src/Shared/CertificateGeneration/CertificateManager.cs (C#)

Code before:
                throw new InvalidOperationException("Invalid location.");
        }
    }

    internal abstract CheckCertificateStateResult CheckCertificateState(X509Certificate2 candidate);

    internal abstract void CorrectCertificateState(X509Certificate2 candidate);

    internal static X509Certificate2 CreateSelfSignedCertificate(
        X500DistinguishedName subject,
        IEnumerable<X509Extension> extensions,
        DateTimeOffset notBefore,
        DateTimeOffset notAfter)
    {
        using var key = CreateKeyMaterial(RSAMinimumKeySizeInBits);

        var request = new CertificateRequest(subject, key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        foreach (var extension in extensions)
        {
            request.CertificateExtensions.Add(extension);
        }

        // Only add the SKI and AKI extensions if neither is already present.
        // OpenSSL needs these to correctly identify the trust chain for a private key. If multiple certificates don't have a subject key identifier and share the same subject,
        // the wrong certificate can be chosen for the trust chain, leading to validation errors.
        if (!request.CertificateExtensions.OfType<X509SubjectKeyIdentifierExtension>().Any() && !request.CertificateExtensions.OfType<X509AuthorityKeyIdentifierExtension>().Any())
        {
            // RFC 5280 section 4.2.1.2
            var subjectKeyIdentifier = new X509SubjectKeyIdentifierExtension(new PublicKey(key), critical: false);
            // RFC 5280 section 4.2.1.1
            var authorityKeyIdentifier = X509AuthorityKeyIdentifierExtension.CreateFromSubjectKeyIdentifier(subjectKeyIdentifier);

            request.CertificateExtensions.Add(subjectKeyIdentifier);
            request.CertificateExtensions.Add(authorityKeyIdentifier);
        }

        var result = request.CreateSelfSigned(notBefore, notAfter);
        return result;

        static RSA CreateKeyMaterial(int minimumKeySize)
        {
            var rsa = RSA.Create(minimumKeySize);
            if (rsa.KeySize < minimumKeySize)
            {
                throw new InvalidOperationException($"Failed to create a key with a size of {minimumKeySize} bits");
            }

            return rsa;
        }
    }


Review comment (suggestion):
This isn't _quite_ right, because someone could include `X509Extension` without specializing it to the types listed.

If you want to be defensive against them being added, you need to check something more like

```suggestion
        if (request.CertificateExtensions.Count(ext => ext.Oid.Value is "2.5.29.14" or "2.5.29.35") == 0)
```

And, of course, I feel compelled to ask "can you add a test for this?"

Code after:
                RemoveCertificateFromUserStore(certificate);
                break;
            default:
                throw new InvalidOperationException("Invalid location.");
        }
    }

    internal abstract CheckCertificateStateResult CheckCertificateState(X509Certificate2 candidate);

    internal abstract void CorrectCertificateState(X509Certificate2 candidate);

    internal static X509Certificate2 CreateSelfSignedCertificate(
        X500DistinguishedName subject,
        IEnumerable<X509Extension> extensions,
        DateTimeOffset notBefore,
        DateTimeOffset notAfter)
    {
        using var key = CreateKeyMaterial(RSAMinimumKeySizeInBits);

        var request = new CertificateRequest(subject, key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        foreach (var extension in extensions)
        {
            request.CertificateExtensions.Add(extension);
        }

        // Only add the SKI and AKI extensions if neither is already present.
        // OpenSSL needs these to correctly identify the trust chain for a private key. If multiple certificates don't have a subject key identifier and share the same subject,
        // the wrong certificate can be chosen for the trust chain, leading to validation errors.
        if (!request.CertificateExtensions.Any(ext => ext.Oid?.Value is SubjectKeyIdentifierOid or AuthorityKeyIdentifierOid))
        {
            // RFC 5280 section 4.2.1.2
            var subjectKeyIdentifier = new X509SubjectKeyIdentifierExtension(request.PublicKey, X509SubjectKeyIdentifierHashAlgorithm.Sha256, critical: false);
            // RFC 5280 section 4.2.1.1
            var authorityKeyIdentifier = X509AuthorityKeyIdentifierExtension.CreateFromSubjectKeyIdentifier(subjectKeyIdentifier);

            request.CertificateExtensions.Add(subjectKeyIdentifier);
            request.CertificateExtensions.Add(authorityKeyIdentifier);
        }

        var result = request.CreateSelfSigned(notBefore, notAfter);
        return result;

        static RSA CreateKeyMaterial(int minimumKeySize)
        {
            var rsa = RSA.Create(minimumKeySize);
            if (rsa.KeySize < minimumKeySize)
            {
                throw new InvalidOperationException($"Failed to create a key with a size of {minimumKeySize} bits");
            }

            return rsa;