Add versioning to dotnet-dev-certs (#10908)

This commit is contained in:
Justin Kotalik 2019-06-05 22:04:27 -07:00 committed by GitHub
parent 5b56de966e
commit fdba8a91f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 190 additions and 242 deletions

View File

@ -42,6 +42,10 @@ namespace Microsoft.AspNetCore.Certificates.Generation
private static readonly string MacOSTrustCertificateCommandLineArguments = "security add-trusted-cert -d -r trustRoot -k " + MacOSSystemKeyChain + " ";
private const int UserCancelledErrorCode = 1223;
// 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<X509Certificate2> ListCertificates(
CertificatePurpose purpose,
StoreName storeName,
@ -83,7 +87,8 @@ namespace Microsoft.AspNetCore.Certificates.Generation
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);
@ -117,6 +122,25 @@ namespace Microsoft.AspNetCore.Certificates.Generation
bool HasOid(X509Certificate2 certificate, string oid) =>
certificate.Extensions.OfType<X509Extension>()
.Any(e => string.Equals(oid, e.Oid.Value, StringComparison.Ordinal));
bool MatchesVersion(X509Certificate2 c)
{
var byteArray = c.Extensions.OfType<X509Extension>()
.Where(e => string.Equals(AspNetHttpsOid, e.Oid.Value, StringComparison.Ordinal))
.Single()
.RawData;
if ((byteArray.Length == AspNetHttpsOidFriendlyName.Length && byteArray[0] == (byte)'A') || byteArray.Length == 0)
{
// No Version set, default to 0
return 0 >= AspNetHttpsCertificateVersion;
}
else
{
// Version is in the only byte of the byte array.
return byteArray[0] >= AspNetHttpsCertificateVersion;
}
}
#if !XPLAT
bool IsExportable(X509Certificate2 c) =>
((c.GetRSAPrivateKey() is RSACryptoServiceProvider rsaPrivateKey &&
@ -171,10 +195,22 @@ namespace Microsoft.AspNetCore.Certificates.Generation
pathLengthConstraint: 0,
critical: true);
byte[] bytePayload;
if (AspNetHttpsCertificateVersion != 0)
{
bytePayload = new byte[1];
bytePayload[0] = (byte)AspNetHttpsCertificateVersion;
}
else
{
bytePayload = Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName);
}
var aspNetHttpsExtension = new X509Extension(
new AsnEncodedData(
new Oid(AspNetHttpsOid, AspNetHttpsOidFriendlyName),
Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName)),
bytePayload),
critical: false);
extensions.Add(basicConstraints);
@ -633,7 +669,7 @@ namespace Microsoft.AspNetCore.Certificates.Generation
}
}
public EnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate(
public DetailedEnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate(
DateTimeOffset notBefore,
DateTimeOffset notAfter,
string path = null,
@ -645,109 +681,7 @@ namespace Microsoft.AspNetCore.Certificates.Generation
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,

View File

@ -7,17 +7,20 @@ using System.Linq;
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;
namespace Microsoft.AspNetCore.Certificates.Generation.Tests
{
public class CertificateManagerTests
public class CertificateManagerTests : IClassFixture<CertFixture>
{
public CertificateManagerTests(ITestOutputHelper output)
private CertFixture _fixture;
private CertificateManager _manager => _fixture.Manager;
public CertificateManagerTests(ITestOutputHelper output, CertFixture fixture)
{
_fixture = fixture;
Output = output;
}
@ -25,122 +28,31 @@ namespace Microsoft.AspNetCore.Certificates.Generation.Tests
public ITestOutputHelper Output { get; }
[Fact(Skip = "True")]
[ConditionalFact]
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")]
public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates()
{
try
{
// Arrange
_fixture.CleanupCertificates();
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
// 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);
// 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<X509Extension>(),
e => e is X509BasicConstraintsExtension basicConstraints &&
basicConstraints.Critical == true &&
basicConstraints.CertificateAuthority == false &&
basicConstraints.HasPathLengthConstraint == false &&
basicConstraints.PathLengthConstraint == 0);
Assert.Contains(
httpsCertificate.Extensions.OfType<X509Extension>(),
e => e is X509KeyUsageExtension keyUsage &&
keyUsage.Critical == true &&
keyUsage.KeyUsages == (X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature));
Assert.Contains(
httpsCertificate.Extensions.OfType<X509Extension>(),
e => e is X509EnhancedKeyUsageExtension enhancedKeyUsage &&
enhancedKeyUsage.Critical == true &&
enhancedKeyUsage.EnhancedKeyUsages.OfType<Oid>().Single() is Oid keyUsage &&
keyUsage.Value == "1.3.6.1.5.5.7.3.1");
// Subject alternative name
Assert.Contains(
httpsCertificate.Extensions.OfType<X509Extension>(),
e => e.Critical == true &&
e.Oid.Value == "2.5.29.17");
// ASP.NET HTTPS Development certificate extension
Assert.Contains(
httpsCertificate.Extensions.OfType<X509Extension>(),
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");
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);
var result = _manager.EnsureAspNetCoreHttpsDevelopmentCertificate(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));
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);
@ -182,7 +94,7 @@ namespace Microsoft.AspNetCore.Certificates.Generation.Tests
httpsCertificate.Extensions.OfType<X509Extension>(),
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");
e.RawData[0] == _manager.AspNetHttpsCertificateVersion);
Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString());
@ -211,32 +123,27 @@ namespace Microsoft.AspNetCore.Certificates.Generation.Tests
}
}
[Fact(Skip = "true")]
[ConditionalFact]
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")]
public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates()
{
// 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);
}
_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);
Assert.Equal(EnsureCertificateResult.ValidCertificatePresent, result.ResultCode);
Assert.True(File.Exists(CertificateName));
var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName), certificatePassword);
@ -247,39 +154,125 @@ namespace Microsoft.AspNetCore.Certificates.Generation.Tests
Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString());
}
[Fact(Skip = "Requires user interaction")]
public void EnsureAspNetCoreHttpsDevelopmentCertificate_ReturnsCorrectResult_WhenUserCancelsTrustStepOnWindows()
[ConditionalFact]
[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);
var trustFailed = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject);
_manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject);
Assert.Equal(EnsureCertificateResult.UserCancelledTrustStep, trustFailed);
_manager.AspNetHttpsCertificateVersion = 2;
var httpsCertificateList = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true);
Assert.Empty(httpsCertificateList);
}
[ConditionalFact]
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")]
public void EnsureCreateHttpsCertificate_ReturnsExpiredCertificateForEmptyVersionField()
{
_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 = 1;
var httpsCertificateList = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true);
Assert.Empty(httpsCertificateList);
}
[ConditionalFact]
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")]
public void EnsureCreateHttpsCertificate_ReturnsValidIfVersionIsZero()
{
_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);
var httpsCertificateList = _manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true);
Assert.NotEmpty(httpsCertificateList);
}
[ConditionalFact]
[SkipOnHelix("https://github.com/aspnet/AspNetCore/issues/6721")]
public void EnsureCreateHttpsCertificate_ReturnValidIfCertIsNewer()
{
_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 = 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()
{
_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);
Assert.Equal(EnsureCertificateResult.UserCancelledTrustStep, trustFailed.ResultCode);
}
[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));
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.Root, 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))
{
Manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject);
}
}
}

View File

@ -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

View File

@ -81,6 +81,7 @@ namespace Microsoft.AspNetCore.DeveloperCertificates.Tools
(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 @@ namespace Microsoft.AspNetCore.DeveloperCertificates.Tools
}
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 @@ namespace Microsoft.AspNetCore.DeveloperCertificates.Tools
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 @@ namespace Microsoft.AspNetCore.DeveloperCertificates.Tools
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 @@ namespace Microsoft.AspNetCore.DeveloperCertificates.Tools
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.");