Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/Shared/CertificateGeneration/CertificateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using System.Formats.Asn1;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
Expand All @@ -19,16 +20,16 @@ namespace Microsoft.AspNetCore.Certificates.Generation;

internal abstract class CertificateManager
{
internal const int CurrentAspNetCoreCertificateVersion = 4;
internal const int CurrentMinimumAspNetCoreCertificateVersion = 4;
internal const int CurrentAspNetCoreCertificateVersion = 5;
internal const int CurrentMinimumAspNetCoreCertificateVersion = 5;
Comment on lines +22 to +23
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to state this out loud so we're all clear, I believe this means that after getting this change in a patch on a dev machine, ASP.NET Core apps will now require version 5 of the cert to be present. However it won't be created/installed until something forces the SDK first-run experience to run (e.g. running a dotnet command) or dotnet dev-certs https is run explicitly. I think this is what we want TBC, but want to ensure we're all on the same page.


// OID used for HTTPS certs
internal const string AspNetHttpsOid = "1.3.6.1.4.1.311.84.1.1";
internal const string AspNetHttpsOidFriendlyName = "ASP.NET Core HTTPS development certificate";

private const string ServerAuthenticationEnhancedKeyUsageOid = "1.3.6.1.5.5.7.3.1";
private const string ServerAuthenticationEnhancedKeyUsageOidFriendlyName = "Server Authentication";

// dns names of the host from a container
private const string LocalhostDockerHttpsDnsName = "host.docker.internal";
private const string ContainersDockerHttpsDnsName = "host.containers.internal";
Expand Down Expand Up @@ -828,6 +829,20 @@ internal static X509Certificate2 CreateSelfSignedCertificate(
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;

Expand Down
Loading