Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.0] Add support for trusting dev certs on linux #57108

Merged
merged 5 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/ProjectTemplates/Shared/DevelopmentCertificate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private static string EnsureDevelopmentCertificates(string certificatePath, stri
var manager = CertificateManager.Instance;
var certificate = manager.CreateAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1));
var certificateThumbprint = certificate.Thumbprint;
CertificateManager.ExportCertificate(certificate, path: certificatePath, includePrivateKey: true, certificatePassword, CertificateKeyExportFormat.Pfx);
manager.ExportCertificate(certificate, path: certificatePath, includePrivateKey: true, certificatePassword, CertificateKeyExportFormat.Pfx);

return certificateThumbprint;
}
Expand Down
3 changes: 3 additions & 0 deletions src/Servers/Kestrel/Core/src/Internal/LoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ internal static partial class LoggerExtensions

[LoggerMessage(8, LogLevel.Warning, "The ASP.NET Core developer certificate is not trusted. For information about trusting the ASP.NET Core developer certificate, see https://aka.ms/aspnet/https-trust-dev-cert.", EventName = "DeveloperCertificateNotTrusted")]
public static partial void DeveloperCertificateNotTrusted(this ILogger<KestrelServer> logger);

[LoggerMessage(9, LogLevel.Warning, "The ASP.NET Core developer certificate is only trusted by some clients. For information about trusting the ASP.NET Core developer certificate, see https://aka.ms/aspnet/https-trust-dev-cert", EventName = "DeveloperCertificatePartiallyTrusted")]
public static partial void DeveloperCertificatePartiallyTrusted(this ILogger<KestrelServer> logger);
}
25 changes: 18 additions & 7 deletions src/Servers/Kestrel/Core/src/KestrelServerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,23 +385,34 @@ internal void Serialize(Utf8JsonWriter writer)
return null;
}

var status = CertificateManager.Instance.CheckCertificateState(cert, interactive: false);
var status = CertificateManager.Instance.CheckCertificateState(cert);
if (!status.Success)
{
// Display a warning indicating to the user that a prompt might appear and provide instructions on what to do in that
// case. The underlying implementation of this check is specific to Mac OS and is handled within CheckCertificateState.
// Kestrel must NEVER cause a UI prompt on a production system. We only attempt this here because Mac OS is not supported
// in production.
// Failure is only possible on MacOS and indicates that, if there is a dev cert, it must be from
// a dotnet version prior to 7.0 - newer versions store it in such a way that this check succeeds.
// (Success does not mean that the dev cert has been trusted).
// In practice, success.FailureMessage will always be MacOSCertificateManager.InvalidCertificateState.
// Basically, we're just going to encourage the user to generate and trust the dev cert. We support
// these older certificates not by accepting them as-is, but by modernizing them when dev-certs is run.
// If we detect an issue here, we can avoid a UI prompt below.
Debug.Assert(status.FailureMessage != null, "Status with a failure result must have a message.");
logger.DeveloperCertificateFirstRun(status.FailureMessage);

// Prevent binding to HTTPS if the certificate is not valid (avoid the prompt)
return null;
}

if (!CertificateManager.Instance.IsTrusted(cert))
// On MacOS, this may cause a UI prompt, since it requires accessing the keychain. Kestrel must NEVER
// cause a UI prompt on a production system. We only attempt this here because MacOS is not supported
// in production.
switch (CertificateManager.Instance.GetTrustLevel(cert))
{
logger.DeveloperCertificateNotTrusted();
case CertificateManager.TrustLevel.Partial:
logger.DeveloperCertificatePartiallyTrusted();
break;
case CertificateManager.TrustLevel.None:
logger.DeveloperCertificateNotTrusted();
break;
}

return cert;
Expand Down
16 changes: 2 additions & 14 deletions src/Servers/Kestrel/Core/src/TlsConfigurationLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,20 +176,8 @@ public ListenOptions UseHttpsWithSni(

private static bool IsDevelopmentCertificate(X509Certificate2 certificate)
{
if (!string.Equals(certificate.Subject, "CN=localhost", StringComparison.Ordinal))
{
return false;
}

foreach (var ext in certificate.Extensions)
{
if (string.Equals(ext.Oid?.Value, CertificateManager.AspNetHttpsOid, StringComparison.Ordinal))
{
return true;
}
}

return false;
return string.Equals(certificate.Subject, CertificateManager.LocalhostHttpsDistinguishedName, StringComparison.Ordinal) &&
CertificateManager.IsHttpsDevelopmentCertificate(certificate);
}

private static bool TryGetCertificatePath(string applicationName, [NotNullWhen(true)] out string? path)
Expand Down
Loading
Loading