From 35a3c0b5e5be4bf5a3241ae90f769955fc1c8eee Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 4 Jun 2019 19:29:56 -0700 Subject: [PATCH 01/13] Initial work --- .../CertificateManager.cs | 24 ++++++++++- .../test/CertificateManagerTests.cs | 40 ++++++++++++++++++- src/Tools/README.md | 3 ++ src/Tools/Tools.sln | 18 +++++++++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index 78ea93398cf4..ea02f6d84655 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -41,6 +41,7 @@ internal class CertificateManager private const string MacOSTrustCertificateCommandLine = "sudo"; private static readonly string MacOSTrustCertificateCommandLineArguments = "security add-trusted-cert -d -r trustRoot -k " + MacOSSystemKeyChain + " "; private const int UserCancelledErrorCode = 1223; + private const byte AspNetHttpsVersion = 1; // TODO make this public somehow public IList ListCertificates( CertificatePurpose purpose, @@ -83,7 +84,8 @@ public IList ListCertificates( var validCertificates = matchingCertificates .Where(c => c.NotBefore <= now && now <= c.NotAfter && - (!requireExportable || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || IsExportable(c))) + (!requireExportable || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || IsExportable(c)) + && MatchesVersion(c)) .ToArray(); var invalidCertificates = matchingCertificates.Except(validCertificates); @@ -135,6 +137,16 @@ bool IsExportable(X509Certificate2 c) => #endif } + private bool MatchesVersion(X509Certificate2 c) + { + // TODO this may not be correct + // todo save GetByteCount as a field + var byteArray = c.Extensions[AspNetHttpsOidFriendlyName].RawData; + var length = Encoding.ASCII.GetByteCount(AspNetHttpsOidFriendlyName); + var version = byteArray[length]; + return version == AspNetHttpsVersion; + } + private static void DisposeCertificates(IEnumerable disposables) { foreach (var disposable in disposables) @@ -171,10 +183,18 @@ public X509Certificate2 CreateAspNetCoreHttpsDevelopmentCertificate(DateTimeOffs pathLengthConstraint: 0, critical: true); + // Add a version here + var byteCount = Encoding.ASCII.GetByteCount(AspNetHttpsOidFriendlyName); + + var bytePayload = new byte[byteCount + 1]; + Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName, bytePayload); + + bytePayload[byteCount] = AspNetHttpsVersion; var aspNetHttpsExtension = new X509Extension( new AsnEncodedData( new Oid(AspNetHttpsOid, AspNetHttpsOidFriendlyName), - Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName)), + bytePayload + ), critical: false); extensions.Add(basicConstraints); diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index b5cf8cfaa2e6..c04e85ced4d2 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -25,7 +25,7 @@ public CertificateManagerTests(ITestOutputHelper output) public ITestOutputHelper Output { get; } - [Fact(Skip = "True")] + [Fact] public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates() { try @@ -95,7 +95,7 @@ public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttps httpsCertificate.Extensions.OfType(), e => e.Critical == false && e.Oid.Value == "1.3.6.1.4.1.311.84.1.1" && - Encoding.ASCII.GetString(e.RawData) == "ASP.NET Core HTTPS development certificate"); + Encoding.ASCII.GetString(e.RawData).StartsWith("ASP.NET Core HTTPS development certificate")); Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); @@ -247,6 +247,42 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); } + [Fact(Skip = "true")] + public void EnsureCreateHttpsCertificate_ShowsExpiredCertificateIfVersionIsIncorrect() + { + // Arrange + const string CertificateName = nameof(EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates) + ".pfx"; + var certificatePassword = Guid.NewGuid().ToString(); + + var manager = new CertificateManager(); + + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); + } + + DateTimeOffset now = DateTimeOffset.UtcNow; + now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); + manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + + var httpsCertificate = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Single(c => c.Subject == TestCertificateSubject); + + // Act + var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, includePrivateKey: true, password: certificatePassword, subject: TestCertificateSubject); + + // Assert + Assert.Equal(EnsureCertificateResult.ValidCertificatePresent, result); + Assert.True(File.Exists(CertificateName)); + + var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName), certificatePassword); + Assert.NotNull(exportedCertificate); + Assert.True(exportedCertificate.HasPrivateKey); + + + Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); + } + [Fact(Skip = "Requires user interaction")] public void EnsureAspNetCoreHttpsDevelopmentCertificate_ReturnsCorrectResult_WhenUserCancelsTrustStepOnWindows() { diff --git a/src/Tools/README.md b/src/Tools/README.md index e13c6ec6e383..7a999d1107cd 100644 --- a/src/Tools/README.md +++ b/src/Tools/README.md @@ -30,3 +30,6 @@ Add `--help` to see more details. For example, ``` dotnet watch --help ``` + +To test any of these projects, do the following: + diff --git a/src/Tools/Tools.sln b/src/Tools/Tools.sln index a2e245206749..77867dcf593c 100644 --- a/src/Tools/Tools.sln +++ b/src/Tools/Tools.sln @@ -7,6 +7,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-watch", "dotnet-watc EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-watch.Tests", "dotnet-watch\test\dotnet-watch.Tests.csproj", "{63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-dev-certs", "dotnet-dev-certs\src\dotnet-dev-certs.csproj", "{0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DeveloperCertificates.XPlat", "FirstRunCertGenerator\src\Microsoft.AspNetCore.DeveloperCertificates.XPlat.csproj", "{7BBDBDA2-299F-4C36-8338-23C525901DE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DeveloperCertificates.XPlat.Tests", "FirstRunCertGenerator\test\Microsoft.AspNetCore.DeveloperCertificates.XPlat.Tests.csproj", "{1EC6FA27-40A5-433F-8CA1-636E7ED8863E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +27,18 @@ Global {63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}.Debug|Any CPU.Build.0 = Debug|Any CPU {63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}.Release|Any CPU.ActiveCfg = Release|Any CPU {63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}.Release|Any CPU.Build.0 = Release|Any CPU + {0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Release|Any CPU.Build.0 = Release|Any CPU + {7BBDBDA2-299F-4C36-8338-23C525901DE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BBDBDA2-299F-4C36-8338-23C525901DE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BBDBDA2-299F-4C36-8338-23C525901DE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BBDBDA2-299F-4C36-8338-23C525901DE0}.Release|Any CPU.Build.0 = Release|Any CPU + {1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 7f87ebd022df60e44e3e9904505ffbcc7bf54963 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 09:58:32 -0700 Subject: [PATCH 02/13] Fix checks and port some deleted code back --- .../CertificateManager.cs | 156 ++++------------ .../test/CertificateManagerTests.cs | 170 +++++++----------- src/Tools/dotnet-dev-certs/src/Program.cs | 15 +- 3 files changed, 108 insertions(+), 233 deletions(-) diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index ea02f6d84655..e59e823ac852 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -18,6 +18,7 @@ internal class CertificateManager { public const string AspNetHttpsOid = "1.3.6.1.4.1.311.84.1.1"; public const string AspNetHttpsOidFriendlyName = "ASP.NET Core HTTPS development certificate"; + private const int AspNetHttpsOidFriendlyNameLength = 42; private const string ServerAuthenticationEnhancedKeyUsageOid = "1.3.6.1.5.5.7.3.1"; private const string ServerAuthenticationEnhancedKeyUsageOidFriendlyName = "Server Authentication"; @@ -41,7 +42,10 @@ internal class CertificateManager private const string MacOSTrustCertificateCommandLine = "sudo"; private static readonly string MacOSTrustCertificateCommandLineArguments = "security add-trusted-cert -d -r trustRoot -k " + MacOSSystemKeyChain + " "; private const int UserCancelledErrorCode = 1223; - private const byte AspNetHttpsVersion = 1; // TODO make this public somehow + + // Setting to 0 means we don't append the version byte, + // which is what all machines currently have. + public int AspNetHttpsCertificateVersion { get; set; } = 1; public IList ListCertificates( CertificatePurpose purpose, @@ -119,6 +123,21 @@ public IList ListCertificates( bool HasOid(X509Certificate2 certificate, string oid) => certificate.Extensions.OfType() .Any(e => string.Equals(oid, e.Oid.Value, StringComparison.Ordinal)); + + bool MatchesVersion(X509Certificate2 c) + { + var byteArray = c.Extensions.OfType().Where(e => string.Equals(AspNetHttpsOid, e.Oid.Value, StringComparison.Ordinal)).Single().RawData; + if (byteArray.Length == AspNetHttpsOidFriendlyNameLength) + { + // No Version set, default to null/0 + return 0 >= AspNetHttpsCertificateVersion; + } + else + { + // Version is in the last byte of the byte array. + return byteArray[AspNetHttpsOidFriendlyNameLength] >= AspNetHttpsCertificateVersion; + } + } #if !XPLAT bool IsExportable(X509Certificate2 c) => ((c.GetRSAPrivateKey() is RSACryptoServiceProvider rsaPrivateKey && @@ -137,16 +156,6 @@ bool IsExportable(X509Certificate2 c) => #endif } - private bool MatchesVersion(X509Certificate2 c) - { - // TODO this may not be correct - // todo save GetByteCount as a field - var byteArray = c.Extensions[AspNetHttpsOidFriendlyName].RawData; - var length = Encoding.ASCII.GetByteCount(AspNetHttpsOidFriendlyName); - var version = byteArray[length]; - return version == AspNetHttpsVersion; - } - private static void DisposeCertificates(IEnumerable disposables) { foreach (var disposable in disposables) @@ -183,18 +192,23 @@ public X509Certificate2 CreateAspNetCoreHttpsDevelopmentCertificate(DateTimeOffs pathLengthConstraint: 0, critical: true); - // Add a version here - var byteCount = Encoding.ASCII.GetByteCount(AspNetHttpsOidFriendlyName); + byte[] bytePayload; - var bytePayload = new byte[byteCount + 1]; - Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName, bytePayload); + if (AspNetHttpsCertificateVersion != 0) + { + bytePayload = new byte[AspNetHttpsOidFriendlyNameLength + 1]; + Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName, bytePayload); + bytePayload[AspNetHttpsOidFriendlyNameLength] = (byte)AspNetHttpsCertificateVersion; + } + else + { + bytePayload = Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName); + } - bytePayload[byteCount] = AspNetHttpsVersion; var aspNetHttpsExtension = new X509Extension( new AsnEncodedData( new Oid(AspNetHttpsOid, AspNetHttpsOidFriendlyName), - bytePayload - ), + bytePayload), critical: false); extensions.Add(basicConstraints); @@ -653,7 +667,7 @@ private static void RemoveCertificateFromKeyChain(string keyChain, X509Certifica } } - public EnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate( + public DetailedEnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate( DateTimeOffset notBefore, DateTimeOffset notAfter, string path = null, @@ -665,109 +679,7 @@ public EnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate( return EnsureValidCertificateExists(notBefore, notAfter, CertificatePurpose.HTTPS, path, trust, includePrivateKey, password, subject); } - public EnsureCertificateResult EnsureValidCertificateExists( - DateTimeOffset notBefore, - DateTimeOffset notAfter, - CertificatePurpose purpose, - string path = null, - bool trust = false, - bool includePrivateKey = false, - string password = null, - string subjectOverride = null) - { - if (purpose == CertificatePurpose.All) - { - throw new ArgumentException("The certificate must have a specific purpose."); - } - - var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: true).Concat( - ListCertificates(purpose, StoreName.My, StoreLocation.LocalMachine, isValid: true)); - - certificates = subjectOverride == null ? certificates : certificates.Where(c => c.Subject == subjectOverride); - - var result = EnsureCertificateResult.Succeeded; - - X509Certificate2 certificate = null; - if (certificates.Count() > 0) - { - certificate = certificates.FirstOrDefault(); - result = EnsureCertificateResult.ValidCertificatePresent; - } - else - { - try - { - switch (purpose) - { - case CertificatePurpose.All: - throw new InvalidOperationException("The certificate must have a specific purpose."); - case CertificatePurpose.HTTPS: - certificate = CreateAspNetCoreHttpsDevelopmentCertificate(notBefore, notAfter, subjectOverride); - break; - default: - throw new InvalidOperationException("The certificate must have a purpose."); - } - } - catch - { - return EnsureCertificateResult.ErrorCreatingTheCertificate; - } - - try - { - certificate = SaveCertificateInStore(certificate, StoreName.My, StoreLocation.CurrentUser); - } - catch - { - return EnsureCertificateResult.ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore; - } - } - if (path != null) - { - try - { - ExportCertificate(certificate, path, includePrivateKey, password); - } - catch - { - return EnsureCertificateResult.ErrorExportingTheCertificate; - } - } - - if ((RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) && trust) - { - try - { - TrustCertificate(certificate); - } - catch (UserCancelledTrustException) - { - return EnsureCertificateResult.UserCancelledTrustStep; - } - catch - { - return EnsureCertificateResult.FailedToTrustTheCertificate; - } - } - - return result; - } - - // This is just to avoid breaking changes across repos. - // Will be renamed back to EnsureAspNetCoreHttpsDevelopmentCertificate once updates are made elsewhere. - public DetailedEnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate2( - DateTimeOffset notBefore, - DateTimeOffset notAfter, - string path = null, - bool trust = false, - bool includePrivateKey = false, - string password = null, - string subject = LocalhostHttpsDistinguishedName) - { - return EnsureValidCertificateExists2(notBefore, notAfter, CertificatePurpose.HTTPS, path, trust, includePrivateKey, password, subject); - } - - public DetailedEnsureCertificateResult EnsureValidCertificateExists2( + public DetailedEnsureCertificateResult EnsureValidCertificateExists( DateTimeOffset notBefore, DateTimeOffset notAfter, CertificatePurpose purpose, diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index c04e85ced4d2..a392f2b91f59 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -8,7 +8,6 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; -using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -45,95 +44,8 @@ public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttps now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, subject: TestCertificateSubject); - // Assert - Assert.Equal(EnsureCertificateResult.Succeeded, result); - Assert.True(File.Exists(CertificateName)); - - var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName)); - Assert.NotNull(exportedCertificate); - Assert.False(exportedCertificate.HasPrivateKey); - - var httpsCertificates = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false); - var httpsCertificate = Assert.Single(httpsCertificates, c => c.Subject == TestCertificateSubject); - Assert.True(httpsCertificate.HasPrivateKey); - Assert.Equal(TestCertificateSubject, httpsCertificate.Subject); - Assert.Equal(TestCertificateSubject, httpsCertificate.Issuer); - Assert.Equal("sha256RSA", httpsCertificate.SignatureAlgorithm.FriendlyName); - Assert.Equal("1.2.840.113549.1.1.11", httpsCertificate.SignatureAlgorithm.Value); - - Assert.Equal(now.LocalDateTime, httpsCertificate.NotBefore); - Assert.Equal(now.AddYears(1).LocalDateTime, httpsCertificate.NotAfter); - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509BasicConstraintsExtension basicConstraints && - basicConstraints.Critical == true && - basicConstraints.CertificateAuthority == false && - basicConstraints.HasPathLengthConstraint == false && - basicConstraints.PathLengthConstraint == 0); - - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509KeyUsageExtension keyUsage && - keyUsage.Critical == true && - keyUsage.KeyUsages == (X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature)); - - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509EnhancedKeyUsageExtension enhancedKeyUsage && - enhancedKeyUsage.Critical == true && - enhancedKeyUsage.EnhancedKeyUsages.OfType().Single() is Oid keyUsage && - keyUsage.Value == "1.3.6.1.5.5.7.3.1"); - - // Subject alternative name - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e.Critical == true && - e.Oid.Value == "2.5.29.17"); - - // ASP.NET HTTPS Development certificate extension - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e.Critical == false && - e.Oid.Value == "1.3.6.1.4.1.311.84.1.1" && - Encoding.ASCII.GetString(e.RawData).StartsWith("ASP.NET Core HTTPS development certificate")); - - Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); - - } - catch (Exception e) - { - Output.WriteLine(e.Message); - ListCertificates(Output); - throw; - } - } - - [ConditionalFact] - [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] - public void EnsureCreateHttpsCertificate2_CreatesACertificate_WhenThereAreNoHttpsCertificates() - { - try - { - // Arrange - const string CertificateName = nameof(EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates) + ".cer"; - var manager = new CertificateManager(); - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } - - // Act - DateTimeOffset now = DateTimeOffset.UtcNow; - now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate2(now, now.AddYears(1), CertificateName, trust: false, subject: TestCertificateSubject); - // Assert Assert.Equal(EnsureCertificateResult.Succeeded, result.ResultCode); - Assert.NotNull(result.Diagnostics); - Assert.NotEmpty(result.Diagnostics.Messages); - Assert.Empty(result.Diagnostics.Exceptions); - Assert.True(File.Exists(CertificateName)); var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName)); @@ -182,7 +94,7 @@ public void EnsureCreateHttpsCertificate2_CreatesACertificate_WhenThereAreNoHttp httpsCertificate.Extensions.OfType(), e => e.Critical == false && e.Oid.Value == "1.3.6.1.4.1.311.84.1.1" && - Encoding.ASCII.GetString(e.RawData) == "ASP.NET Core HTTPS development certificate"); + Encoding.ASCII.GetString(e.RawData).StartsWith("ASP.NET Core HTTPS development certificate")); Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); @@ -236,7 +148,7 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, includePrivateKey: true, password: certificatePassword, subject: TestCertificateSubject); // Assert - Assert.Equal(EnsureCertificateResult.ValidCertificatePresent, result); + Assert.Equal(EnsureCertificateResult.ValidCertificatePresent, result.ResultCode); Assert.True(File.Exists(CertificateName)); var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName), certificatePassword); @@ -247,13 +159,30 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); } - [Fact(Skip = "true")] - public void EnsureCreateHttpsCertificate_ShowsExpiredCertificateIfVersionIsIncorrect() + [Fact] + public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsIncorrect() { - // Arrange - const string CertificateName = nameof(EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates) + ".pfx"; - var certificatePassword = Guid.NewGuid().ToString(); + var manager = new CertificateManager(); + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); + } + + DateTimeOffset now = DateTimeOffset.UtcNow; + now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); + manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + + manager.AspNetHttpsCertificateVersion = 2; + + var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + Assert.Empty(httpsCertificateList); + } + + [Fact] + public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersionField() + { var manager = new CertificateManager(); manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); @@ -264,23 +193,54 @@ public void EnsureCreateHttpsCertificate_ShowsExpiredCertificateIfVersionIsIncor DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); + manager.AspNetHttpsCertificateVersion = 0; manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); - var httpsCertificate = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Single(c => c.Subject == TestCertificateSubject); + manager.AspNetHttpsCertificateVersion = 1; - // Act - var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, includePrivateKey: true, password: certificatePassword, subject: TestCertificateSubject); + var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + Assert.Empty(httpsCertificateList); + } - // Assert - Assert.Equal(EnsureCertificateResult.ValidCertificatePresent, result); - Assert.True(File.Exists(CertificateName)); + [Fact] + public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() + { + var manager = new CertificateManager(); - var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName), certificatePassword); - Assert.NotNull(exportedCertificate); - Assert.True(exportedCertificate.HasPrivateKey); + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); + } + + DateTimeOffset now = DateTimeOffset.UtcNow; + now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); + manager.AspNetHttpsCertificateVersion = 0; + manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + Assert.NotEmpty(httpsCertificateList); + } - Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); + [Fact] + public void EnsureCreateHttpsCertificate_ReturnValidIfCertIsNewer() + { + var manager = new CertificateManager(); + + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); + } + + DateTimeOffset now = DateTimeOffset.UtcNow; + now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); + manager.AspNetHttpsCertificateVersion = 2; + manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + + manager.AspNetHttpsCertificateVersion = 1; + var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + Assert.NotEmpty(httpsCertificateList); } [Fact(Skip = "Requires user interaction")] diff --git a/src/Tools/dotnet-dev-certs/src/Program.cs b/src/Tools/dotnet-dev-certs/src/Program.cs index 170e11b09d95..3854c4c59c42 100644 --- a/src/Tools/dotnet-dev-certs/src/Program.cs +++ b/src/Tools/dotnet-dev-certs/src/Program.cs @@ -81,6 +81,7 @@ public static int Main(string[] args) (check.HasValue() && (exportPath.HasValue() || password.HasValue() || clean.HasValue()))) { reporter.Error(@"Incompatible set of flags. Sample usages +'dotnet dev-certs https' 'dotnet dev-certs https --clean' 'dotnet dev-certs https --check --trust' 'dotnet dev-certs https -ep ./certificate.pfx -p password --trust'"); @@ -133,7 +134,7 @@ private static int CleanHttpsCertificates(IReporter reporter) } manager.CleanupHttpsCertificates(); - reporter.Verbose("HTTPS development certificates successfully removed from the machine."); + reporter.Output("HTTPS development certificates successfully removed from the machine."); return Success; } catch(Exception e) @@ -152,12 +153,12 @@ private static int CheckHttpsCertificate(CommandOption trust, IReporter reporter var certificates = certificateManager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); if (certificates.Count == 0) { - reporter.Verbose("No valid certificate found."); + reporter.Output("No valid certificate found."); return ErrorNoValidCertificateFound; } else { - reporter.Verbose("A valid certificate was found."); + reporter.Output("A valid certificate was found."); } if (trust != null && trust.HasValue()) @@ -166,13 +167,13 @@ private static int CheckHttpsCertificate(CommandOption trust, IReporter reporter var trustedCertificates = certificateManager.ListCertificates(CertificatePurpose.HTTPS, store, StoreLocation.CurrentUser, isValid: true); if (!certificates.Any(c => certificateManager.IsTrusted(c))) { - reporter.Verbose($@"The following certificates were found, but none of them is trusted: + reporter.Output($@"The following certificates were found, but none of them is trusted: {string.Join(Environment.NewLine, certificates.Select(c => $"{c.Subject} - {c.Thumbprint}"))}"); return ErrorCertificateNotTrusted; } else { - reporter.Verbose("A trusted certificate was found."); + reporter.Output("A trusted certificate was found."); } } @@ -207,7 +208,9 @@ private static int EnsureHttpsCertificate(CommandOption exportPath, CommandOptio password.HasValue(), password.Value()); - switch (result) + reporter.Verbose(string.Join(Environment.NewLine, result.Diagnostics.Messages)); + + switch (result.ResultCode) { case EnsureCertificateResult.Succeeded: reporter.Output("The HTTPS developer certificate was generated successfully."); From 807360e2ee61775e12784d6d7e1fc97726d767ab Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 10:17:27 -0700 Subject: [PATCH 03/13] make it so it builds --- .../test/CertificateManagerTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index a392f2b91f59..4eee9952f12e 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -24,7 +24,7 @@ public CertificateManagerTests(ITestOutputHelper output) public ITestOutputHelper Output { get; } - [Fact] + [Fact(Skip = "true")] public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates() { try @@ -159,7 +159,7 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); } - [Fact] + [Fact(Skip = "true")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsIncorrect() { var manager = new CertificateManager(); @@ -180,7 +180,7 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsInc Assert.Empty(httpsCertificateList); } - [Fact] + [Fact(Skip = "true")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersionField() { var manager = new CertificateManager(); @@ -202,7 +202,7 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersio Assert.Empty(httpsCertificateList); } - [Fact] + [Fact(Skip = "true")] public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() { var manager = new CertificateManager(); @@ -222,7 +222,7 @@ public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() Assert.NotEmpty(httpsCertificateList); } - [Fact] + [Fact(Skip = "true")] public void EnsureCreateHttpsCertificate_ReturnValidIfCertIsNewer() { var manager = new CertificateManager(); @@ -258,7 +258,7 @@ public void EnsureAspNetCoreHttpsDevelopmentCertificate_ReturnsCorrectResult_Whe now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); var trustFailed = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject); - Assert.Equal(EnsureCertificateResult.UserCancelledTrustStep, trustFailed); + Assert.Equal(EnsureCertificateResult.UserCancelledTrustStep, trustFailed.ResultCode); } [Fact(Skip = "Requires user interaction")] From 3fa40e80970cb5e61c34ca71d75e89ccf656bed3 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 10:51:05 -0700 Subject: [PATCH 04/13] Feedback: --- src/Tools/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Tools/README.md b/src/Tools/README.md index 7a999d1107cd..e13c6ec6e383 100644 --- a/src/Tools/README.md +++ b/src/Tools/README.md @@ -30,6 +30,3 @@ Add `--help` to see more details. For example, ``` dotnet watch --help ``` - -To test any of these projects, do the following: - From bda214f9dff2fedcb422fa00e37ab3465f996907 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 10:57:43 -0700 Subject: [PATCH 05/13] Nit --- src/Shared/CertificateGeneration/CertificateManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index e59e823ac852..e65550970f38 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -126,10 +126,13 @@ bool HasOid(X509Certificate2 certificate, string oid) => bool MatchesVersion(X509Certificate2 c) { - var byteArray = c.Extensions.OfType().Where(e => string.Equals(AspNetHttpsOid, e.Oid.Value, StringComparison.Ordinal)).Single().RawData; + var byteArray = c.Extensions.OfType() + .Where(e => string.Equals(AspNetHttpsOid, e.Oid.Value, StringComparison.Ordinal)) + .Single() + .RawData; if (byteArray.Length == AspNetHttpsOidFriendlyNameLength) { - // No Version set, default to null/0 + // No Version set, default to 0 return 0 >= AspNetHttpsCertificateVersion; } else From 2b4b47228fb028a58fd740fdb8b9d30640e3819a Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 11:33:45 -0700 Subject: [PATCH 06/13] nit --- src/Shared/CertificateGeneration/CertificateManager.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index e65550970f38..19d134d0c642 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -127,9 +127,10 @@ bool HasOid(X509Certificate2 certificate, string oid) => bool MatchesVersion(X509Certificate2 c) { var byteArray = c.Extensions.OfType() - .Where(e => string.Equals(AspNetHttpsOid, e.Oid.Value, StringComparison.Ordinal)) - .Single() - .RawData; + .Where(e => string.Equals(AspNetHttpsOid, e.Oid.Value, StringComparison.Ordinal)) + .Single() + .RawData; + if (byteArray.Length == AspNetHttpsOidFriendlyNameLength) { // No Version set, default to 0 From bebfafe6e738ec1eef667bfaaf658cf8b9be0922 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 14:28:30 -0700 Subject: [PATCH 07/13] Feedback --- .../CertificateGeneration/CertificateManager.cs | 10 ++++------ .../test/CertificateManagerTests.cs | 14 +++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index 19d134d0c642..7a82d963e0d5 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -18,7 +18,6 @@ internal class CertificateManager { public const string AspNetHttpsOid = "1.3.6.1.4.1.311.84.1.1"; public const string AspNetHttpsOidFriendlyName = "ASP.NET Core HTTPS development certificate"; - private const int AspNetHttpsOidFriendlyNameLength = 42; private const string ServerAuthenticationEnhancedKeyUsageOid = "1.3.6.1.5.5.7.3.1"; private const string ServerAuthenticationEnhancedKeyUsageOidFriendlyName = "Server Authentication"; @@ -131,7 +130,7 @@ bool MatchesVersion(X509Certificate2 c) .Single() .RawData; - if (byteArray.Length == AspNetHttpsOidFriendlyNameLength) + if (byteArray.Length == AspNetHttpsOidFriendlyName.Length || byteArray.Length == 0) { // No Version set, default to 0 return 0 >= AspNetHttpsCertificateVersion; @@ -139,7 +138,7 @@ bool MatchesVersion(X509Certificate2 c) else { // Version is in the last byte of the byte array. - return byteArray[AspNetHttpsOidFriendlyNameLength] >= AspNetHttpsCertificateVersion; + return byteArray[0] >= AspNetHttpsCertificateVersion; } } #if !XPLAT @@ -200,9 +199,8 @@ public X509Certificate2 CreateAspNetCoreHttpsDevelopmentCertificate(DateTimeOffs if (AspNetHttpsCertificateVersion != 0) { - bytePayload = new byte[AspNetHttpsOidFriendlyNameLength + 1]; - Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName, bytePayload); - bytePayload[AspNetHttpsOidFriendlyNameLength] = (byte)AspNetHttpsCertificateVersion; + bytePayload = new byte[1]; + bytePayload[0] = (byte)AspNetHttpsCertificateVersion; } else { diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index 4eee9952f12e..d828f0c97018 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -24,7 +24,7 @@ public CertificateManagerTests(ITestOutputHelper output) public ITestOutputHelper Output { get; } - [Fact(Skip = "true")] + [Fact(Skip = "Modifies global machine state")] public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates() { try @@ -94,7 +94,7 @@ public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttps httpsCertificate.Extensions.OfType(), e => e.Critical == false && e.Oid.Value == "1.3.6.1.4.1.311.84.1.1" && - Encoding.ASCII.GetString(e.RawData).StartsWith("ASP.NET Core HTTPS development certificate")); + e.RawData[0] == manager.AspNetHttpsCertificateVersion); Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); @@ -123,7 +123,7 @@ private void ListCertificates(ITestOutputHelper output) } } - [Fact(Skip = "true")] + [Fact(Skip = "Modifies global machine state")] public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates() { // Arrange @@ -159,7 +159,7 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); } - [Fact(Skip = "true")] + [Fact(Skip = "Modifies global machine state")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsIncorrect() { var manager = new CertificateManager(); @@ -180,7 +180,7 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsInc Assert.Empty(httpsCertificateList); } - [Fact(Skip = "true")] + [Fact(Skip = "Modifies global machine state")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersionField() { var manager = new CertificateManager(); @@ -202,7 +202,7 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersio Assert.Empty(httpsCertificateList); } - [Fact(Skip = "true")] + [Fact(Skip = "Modifies global machine state")] public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() { var manager = new CertificateManager(); @@ -222,7 +222,7 @@ public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() Assert.NotEmpty(httpsCertificateList); } - [Fact(Skip = "true")] + [Fact(Skip = "Modifies global machine state")] public void EnsureCreateHttpsCertificate_ReturnValidIfCertIsNewer() { var manager = new CertificateManager(); From 3686ddac6c14bd1847b41219f7b7efaea833ea75 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 14:37:23 -0700 Subject: [PATCH 08/13] Update CertificateManager.cs --- src/Shared/CertificateGeneration/CertificateManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index 7a82d963e0d5..562c813c3148 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -137,7 +137,7 @@ bool MatchesVersion(X509Certificate2 c) } else { - // Version is in the last byte of the byte array. + // Version is in the only byte of the byte array. return byteArray[0] >= AspNetHttpsCertificateVersion; } } From 7d6f60838202eba0e6d6ade2b3ea4f1792a68e90 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 14:52:42 -0700 Subject: [PATCH 09/13] Enable tests on non-helix workloads --- .../test/CertificateManagerTests.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index d828f0c97018..0c8fd1b94250 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -8,6 +8,7 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -24,7 +25,8 @@ public CertificateManagerTests(ITestOutputHelper output) public ITestOutputHelper Output { get; } - [Fact(Skip = "Modifies global machine state")] + [Fact] + [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates() { try @@ -123,7 +125,8 @@ private void ListCertificates(ITestOutputHelper output) } } - [Fact(Skip = "Modifies global machine state")] + [Fact] + [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates() { // Arrange @@ -159,7 +162,8 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); } - [Fact(Skip = "Modifies global machine state")] + [Fact] + [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsIncorrect() { var manager = new CertificateManager(); @@ -180,7 +184,8 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsInc Assert.Empty(httpsCertificateList); } - [Fact(Skip = "Modifies global machine state")] + [Fact] + [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersionField() { var manager = new CertificateManager(); @@ -202,7 +207,8 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersio Assert.Empty(httpsCertificateList); } - [Fact(Skip = "Modifies global machine state")] + [Fact] + [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() { var manager = new CertificateManager(); @@ -222,7 +228,8 @@ public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() Assert.NotEmpty(httpsCertificateList); } - [Fact(Skip = "Modifies global machine state")] + [Fact] + [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnValidIfCertIsNewer() { var manager = new CertificateManager(); From 419f93783bced3488e1dab84d687ed071b3de9d3 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 15:04:30 -0700 Subject: [PATCH 10/13] Update src/Shared/CertificateGeneration/CertificateManager.cs Co-Authored-By: Andrew Stanton-Nurse --- src/Shared/CertificateGeneration/CertificateManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs index 562c813c3148..14d26abbcdf8 100644 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ b/src/Shared/CertificateGeneration/CertificateManager.cs @@ -130,7 +130,7 @@ bool MatchesVersion(X509Certificate2 c) .Single() .RawData; - if (byteArray.Length == AspNetHttpsOidFriendlyName.Length || byteArray.Length == 0) + if ((byteArray.Length == AspNetHttpsOidFriendlyName.Length && byteArray[0] == (byte)'A') || byteArray.Length == 0) { // No Version set, default to 0 return 0 >= AspNetHttpsCertificateVersion; From 83f9a3fae911cad154e4121d2659f49e39a61830 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 16:27:22 -0700 Subject: [PATCH 11/13] Fixture --- .../test/CertificateManagerTests.cs | 147 ++++++++---------- 1 file changed, 69 insertions(+), 78 deletions(-) diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index 0c8fd1b94250..b82c59aef25b 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -14,10 +14,14 @@ namespace Microsoft.AspNetCore.Certificates.Generation.Tests { - public class CertificateManagerTests + public class CertificateManagerTests : IClassFixture { - public CertificateManagerTests(ITestOutputHelper output) + private CertFixture _fixture; + private CertificateManager _manager => _fixture.Manager; + + public CertificateManagerTests(ITestOutputHelper output, CertFixture fixture) { + _fixture = fixture; Output = output; } @@ -32,19 +36,14 @@ public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttps try { // Arrange - const string CertificateName = nameof(EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates) + ".cer"; - var manager = new CertificateManager(); + _fixture.CleanupCertificates(); - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } + const string CertificateName = nameof(EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates) + ".cer"; - // Act + // Act DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, subject: TestCertificateSubject); + var result = _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, subject: TestCertificateSubject); // Assert Assert.Equal(EnsureCertificateResult.Succeeded, result.ResultCode); @@ -54,7 +53,7 @@ public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttps Assert.NotNull(exportedCertificate); Assert.False(exportedCertificate.HasPrivateKey); - var httpsCertificates = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false); + var httpsCertificates = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false); var httpsCertificate = Assert.Single(httpsCertificates, c => c.Subject == TestCertificateSubject); Assert.True(httpsCertificate.HasPrivateKey); Assert.Equal(TestCertificateSubject, httpsCertificate.Subject); @@ -96,7 +95,7 @@ public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttps httpsCertificate.Extensions.OfType(), e => e.Critical == false && e.Oid.Value == "1.3.6.1.4.1.311.84.1.1" && - e.RawData[0] == manager.AspNetHttpsCertificateVersion); + e.RawData[0] == _manager.AspNetHttpsCertificateVersion); Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); @@ -133,22 +132,16 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn const string CertificateName = nameof(EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates) + ".pfx"; var certificatePassword = Guid.NewGuid().ToString(); - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } + _fixture.CleanupCertificates(); DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); - var httpsCertificate = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Single(c => c.Subject == TestCertificateSubject); + var httpsCertificate = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Single(c => c.Subject == TestCertificateSubject); // Act - var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, includePrivateKey: true, password: certificatePassword, subject: TestCertificateSubject); + var result = _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, includePrivateKey: true, password: certificatePassword, subject: TestCertificateSubject); // Assert Assert.Equal(EnsureCertificateResult.ValidCertificatePresent, result.ResultCode); @@ -166,21 +159,15 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsIncorrect() { - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } + _fixture.CleanupCertificates(); DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); - manager.AspNetHttpsCertificateVersion = 2; + _manager.AspNetHttpsCertificateVersion = 2; - var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + var httpsCertificateList = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); Assert.Empty(httpsCertificateList); } @@ -188,22 +175,16 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsInc [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersionField() { - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } + _fixture.CleanupCertificates(); DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.AspNetHttpsCertificateVersion = 0; - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + _manager.AspNetHttpsCertificateVersion = 0; + _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); - manager.AspNetHttpsCertificateVersion = 1; + _manager.AspNetHttpsCertificateVersion = 1; - var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + var httpsCertificateList = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); Assert.Empty(httpsCertificateList); } @@ -211,20 +192,14 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersio [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() { - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } + _fixture.CleanupCertificates(); DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.AspNetHttpsCertificateVersion = 0; - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + _manager.AspNetHttpsCertificateVersion = 0; + _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); - var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + var httpsCertificateList = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); Assert.NotEmpty(httpsCertificateList); } @@ -232,38 +207,26 @@ public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnValidIfCertIsNewer() { - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } + _fixture.CleanupCertificates(); DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.AspNetHttpsCertificateVersion = 2; - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); + _manager.AspNetHttpsCertificateVersion = 2; + _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); - manager.AspNetHttpsCertificateVersion = 1; - var httpsCertificateList = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + _manager.AspNetHttpsCertificateVersion = 1; + var httpsCertificateList = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); Assert.NotEmpty(httpsCertificateList); } [Fact(Skip = "Requires user interaction")] public void EnsureAspNetCoreHttpsDevelopmentCertificate_ReturnsCorrectResult_WhenUserCancelsTrustStepOnWindows() { - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } + _fixture.CleanupCertificates(); DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - var trustFailed = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject); + var trustFailed = _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject); Assert.Equal(EnsureCertificateResult.UserCancelledTrustStep, trustFailed.ResultCode); } @@ -271,18 +234,46 @@ public void EnsureAspNetCoreHttpsDevelopmentCertificate_ReturnsCorrectResult_Whe [Fact(Skip = "Requires user interaction")] public void EnsureAspNetCoreHttpsDevelopmentCertificate_CanRemoveCertificates() { - var manager = new CertificateManager(); + _fixture.CleanupCertificates(); DateTimeOffset now = DateTimeOffset.UtcNow; now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject); + _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject); + + _manager.CleanupHttpsCertificates(TestCertificateSubject); - manager.CleanupHttpsCertificates(TestCertificateSubject); + Assert.Empty(_manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Where(c => c.Subject == TestCertificateSubject)); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Assert.Empty(_manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, isValid: false).Where(c => c.Subject == TestCertificateSubject)); + } + } + } - Assert.Empty(manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Where(c => c.Subject == TestCertificateSubject)); + public class CertFixture : IDisposable + { + public const string TestCertificateSubject = "CN=aspnet.test"; + + public CertFixture() + { + Manager = new CertificateManager(); + + CleanupCertificates(); + } + + internal CertificateManager Manager { get; set; } + + public void Dispose() + { + CleanupCertificates(); + } + + internal void CleanupCertificates() + { + Manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - Assert.Empty(manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, isValid: false).Where(c => c.Subject == TestCertificateSubject)); + Manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); } } } From 9a7be152bb21baf866112d517a138bb9aabbdc7a Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 16:27:29 -0700 Subject: [PATCH 12/13] nit --- src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index b82c59aef25b..dac0e2d5ccf3 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -7,7 +7,6 @@ using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using System.Text; using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; From 8671d2151a0c0eb3ba2bdf6819deebe4edb99053 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 5 Jun 2019 18:15:02 -0700 Subject: [PATCH 13/13] Update CertificateManagerTests.cs --- .../test/CertificateManagerTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs index dac0e2d5ccf3..843f4ad377ae 100644 --- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs +++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs @@ -28,7 +28,7 @@ public CertificateManagerTests(ITestOutputHelper output, CertFixture fixture) public ITestOutputHelper Output { get; } - [Fact] + [ConditionalFact] [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates() { @@ -123,7 +123,7 @@ private void ListCertificates(ITestOutputHelper output) } } - [Fact] + [ConditionalFact] [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates() { @@ -154,7 +154,7 @@ public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAn Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); } - [Fact] + [ConditionalFact] [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsIncorrect() { @@ -170,7 +170,7 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateIfVersionIsInc Assert.Empty(httpsCertificateList); } - [Fact] + [ConditionalFact] [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersionField() { @@ -187,7 +187,7 @@ public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersio Assert.Empty(httpsCertificateList); } - [Fact] + [ConditionalFact] [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() { @@ -202,7 +202,7 @@ public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero() Assert.NotEmpty(httpsCertificateList); } - [Fact] + [ConditionalFact] [SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")] public void EnsureCreateHttpsCertificate_ReturnValidIfCertIsNewer() {