From 2dc908d502888ffd9f6cfb306d58f0337caf004b Mon Sep 17 00:00:00 2001 From: dotnet-maestro-bot Date: Fri, 17 Jan 2020 08:30:12 -0800 Subject: [PATCH] [automated] Merge branch 'release/2.1' => 'release/3.1' (#18396) * [Platform] Detect and fix certificates with potentially inaccessible keys on Mac OS (2.1) (#17560) * [Https] Detects and fixes HTTPS certificates where the key is not guaranteed to be accessible across security partitions * Fix dotnet dev-certs https --check * Update logic for detecting missing certs * Fix security command * Update warning logic * Check that the key is accessible in Kestrel * Add correct link to docs * Update src/Tools/dotnet-dev-certs/src/Program.cs Co-Authored-By: Daniel Roth * Update src/Tools/dotnet-dev-certs/src/Program.cs Co-Authored-By: Daniel Roth * Add test for 2.1 * Update src/Tools/dotnet-dev-certs/src/Program.cs Co-Authored-By: Chris Ross * Address feedback * Fix non-interctive path * Fix tests * Remove a couple of test from an unshipped product * Check only for certificates considered valid * Switch the exception being caught, remove invalid test Co-authored-by: Daniel Roth Co-authored-by: Chris Ross * Fix patchconfig merge (#18389) * Fix flaky HubConnectionHandler test (#18391) Co-authored-by: Javier Calvarro Nelson Co-authored-by: Daniel Roth Co-authored-by: Chris Ross Co-authored-by: Brennan --- src/Servers/Kestrel/Core/src/CoreStrings.resx | 2 +- .../Kestrel/shared/test/TestResources.cs | 5 +++ .../CertificateManager.cs | 31 ++++++++++++------- .../EnsureCertificateResult.cs | 1 + src/Tools/dotnet-dev-certs/src/Program.cs | 7 +++++ 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/CoreStrings.resx b/src/Servers/Kestrel/Core/src/CoreStrings.resx index cb3245b4fe..59bd610f1e 100644 --- a/src/Servers/Kestrel/Core/src/CoreStrings.resx +++ b/src/Servers/Kestrel/Core/src/CoreStrings.resx @@ -620,4 +620,4 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l The ASP.NET Core developer certificate is in an invalid state. To fix this issue, run the following commands 'dotnet dev-certs https --clean' and 'dotnet dev-certs https' to remove all existing ASP.NET Core development certificates and create a new untrusted developer certificate. On macOS or Windows, use 'dotnet dev-certs https --trust' to trust the new certificate. - + \ No newline at end of file diff --git a/src/Servers/Kestrel/shared/test/TestResources.cs b/src/Servers/Kestrel/shared/test/TestResources.cs index d335617c7d..760eb81051 100644 --- a/src/Servers/Kestrel/shared/test/TestResources.cs +++ b/src/Servers/Kestrel/shared/test/TestResources.cs @@ -40,5 +40,10 @@ namespace Microsoft.AspNetCore.Testing importPfxMutex?.ReleaseMutex(); } } + + public static X509Certificate2 GetTestCertificate(string certName, string password) + { + return new X509Certificate2(GetCertPath(certName), password); + } } } diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index 0ddaca67aa..ef2a45cdeb 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; @@ -740,12 +741,12 @@ namespace Microsoft.AspNetCore.Certificates.Generation DateTimeOffset notBefore, DateTimeOffset notAfter, CertificatePurpose purpose, - string path, - bool trust, - bool includePrivateKey, - string password, - string subject, - bool isInteractive) + string path = null, + bool trust = false, + bool includePrivateKey = false, + string password = null, + string subjectOverride = null, + bool isInteractive = true) { if (purpose == CertificatePurpose.All) { @@ -757,12 +758,12 @@ namespace Microsoft.AspNetCore.Certificates.Generation var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: true, requireExportable: true, result.Diagnostics).Concat( ListCertificates(purpose, StoreName.My, StoreLocation.LocalMachine, isValid: true, requireExportable: true, result.Diagnostics)); - var filteredCertificates = subject == null ? certificates : certificates.Where(c => c.Subject == subject); - if (subject != null) + var filteredCertificates = subjectOverride == null ? certificates : certificates.Where(c => c.Subject == subjectOverride); + if (subjectOverride != null) { var excludedCertificates = certificates.Except(filteredCertificates); - result.Diagnostics.Debug($"Filtering found certificates to those with a subject equal to '{subject}'"); + result.Diagnostics.Debug($"Filtering found certificates to those with a subject equal to '{subjectOverride}'"); result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(filteredCertificates)); result.Diagnostics.Debug($"Listing certificates excluded from consideration."); result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(excludedCertificates)); @@ -825,7 +826,7 @@ namespace Microsoft.AspNetCore.Certificates.Generation case CertificatePurpose.All: throw new InvalidOperationException("The certificate must have a specific purpose."); case CertificatePurpose.HTTPS: - certificate = CreateAspNetCoreHttpsDevelopmentCertificate(notBefore, notAfter, subject, result.Diagnostics); + certificate = CreateAspNetCoreHttpsDevelopmentCertificate(notBefore, notAfter, subjectOverride, result.Diagnostics); break; default: throw new InvalidOperationException("The certificate must have a purpose."); @@ -853,6 +854,11 @@ namespace Microsoft.AspNetCore.Certificates.Generation { MakeCertificateKeyAccessibleAcrossPartitions(certificate); } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && isInteractive) + { + MakeCertificateKeyAccessibleAcrossPartitions(certificate); + } } if (path != null) { @@ -894,10 +900,11 @@ namespace Microsoft.AspNetCore.Certificates.Generation return result; } - private void MakeCertificateKeyAccessibleAcrossPartitions(X509Certificate2 certificate) { + private void MakeCertificateKeyAccessibleAcrossPartitions(X509Certificate2 certificate) + { if (OtherNonAspNetCoreHttpsCertificatesPresent()) { - throw new InvalidOperationException("Unable to make HTTPS ceritificate key trusted across security partitions."); + throw new InvalidOperationException("Unable to make HTTPS certificate key trusted across security partitions."); } using (var process = Process.Start(MacOSSetPartitionKeyPermissionsCommandLine, MacOSSetPartitionKeyPermissionsCommandLineArguments)) { diff --git a/src/Shared/CertificateGeneration/EnsureCertificateResult.cs b/src/Shared/CertificateGeneration/EnsureCertificateResult.cs index 504264a189..00eebbac3d 100644 --- a/src/Shared/CertificateGeneration/EnsureCertificateResult.cs +++ b/src/Shared/CertificateGeneration/EnsureCertificateResult.cs @@ -15,3 +15,4 @@ namespace Microsoft.AspNetCore.Certificates.Generation FailedToMakeKeyAccessible, } } + diff --git a/src/Tools/dotnet-dev-certs/src/Program.cs b/src/Tools/dotnet-dev-certs/src/Program.cs index 762d0ba087..0afc705735 100644 --- a/src/Tools/dotnet-dev-certs/src/Program.cs +++ b/src/Tools/dotnet-dev-certs/src/Program.cs @@ -194,6 +194,13 @@ namespace Microsoft.AspNetCore.DeveloperCertificates.Tools var now = DateTimeOffset.Now; var manager = new CertificateManager(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && manager.HasValidCertificateWithInnaccessibleKeyAcrossPartitions() || manager.GetHttpsCertificates().Count == 0) + { + reporter.Warn($"A valid HTTPS certificate with a key accessible across security partitions was not found. The following command will run to fix it:" + Environment.NewLine + + "'sudo security set-key-partition-list -D localhost -S unsigned:,teamid:UBF8T346G9'" + Environment.NewLine + + "This command will make the certificate key accessible across security partitions and might prompt you for your password. For more information see: https://aka.ms/aspnetcore/2.1/troubleshootcertissues"); + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && manager.HasValidCertificateWithInnaccessibleKeyAcrossPartitions() || manager.GetHttpsCertificates().Count == 0) { reporter.Warn($"A valid HTTPS certificate with a key accessible across security partitions was not found. The following command will run to fix it:" + Environment.NewLine +