Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Aspire.Hosting/Dcp/DcpHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ internal async Task EnsureDevelopmentCertificateTrustAsync(CancellationToken can
try
{
// Check and warn if the developer certificate is not trusted
if (_developerCertificateService.TrustCertificate && _developerCertificateService.Certificates.Count > 0 && !DeveloperCertificateService.IsCertificateTrusted(_fileSystemService, _developerCertificateService.Certificates.First()))
if (_developerCertificateService.TrustCertificate && _developerCertificateService.Certificates.Count > 0 && !await DeveloperCertificateService.IsCertificateTrustedAsync(_fileSystemService, _developerCertificateService.Certificates.First(), cancellationToken).ConfigureAwait(false))
{
var trustLocation = "your project folder";
var appHostDirectory = _configuration["AppHost:Directory"];
Expand Down
35 changes: 11 additions & 24 deletions src/Aspire.Hosting/DeveloperCertificateService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.Dcp.Process;
using Aspire.Hosting.Utils;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;

namespace Aspire.Hosting;
Expand Down Expand Up @@ -112,14 +112,14 @@ public DeveloperCertificateService(ILogger<DeveloperCertificateService> logger,
/// <inheritdoc />
public bool UseForHttps { get; }

internal static bool IsCertificateTrusted(IFileSystemService fileSystemService, X509Certificate2 certificate)
internal static async Task<bool> IsCertificateTrustedAsync(IFileSystemService fileSystemService, X509Certificate2 certificate, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(certificate);

if (OperatingSystem.IsMacOS())
{
// On MacOS we have to verify against the Keychain
return IsCertificateTrustedInMacOsKeychain(fileSystemService, certificate);
return await IsCertificateTrustedInMacOsKeychainAsync(fileSystemService, certificate, cancellationToken).ConfigureAwait(false);
}

try
Expand Down Expand Up @@ -150,7 +150,7 @@ internal static bool IsCertificateTrusted(IFileSystemService fileSystemService,

// Use the same approach as `dotnet dev-certs` to check if the certificate is trusted in the macOS keychain
// See: https://github.com/dotnet/aspnetcore/blob/2a88012113497bac5056548f16d810738b069198/src/Shared/CertificateGeneration/MacOSCertificateManager.cs#L36-L37
private static bool IsCertificateTrustedInMacOsKeychain(IFileSystemService fileSystemService, X509Certificate2 certificate)
private static async Task<bool> IsCertificateTrustedInMacOsKeychainAsync(IFileSystemService fileSystemService, X509Certificate2 certificate, CancellationToken cancellationToken)
{
try
{
Expand All @@ -159,31 +159,18 @@ private static bool IsCertificateTrustedInMacOsKeychain(IFileSystemService fileS

File.WriteAllBytes(certPath, certificate.Export(X509ContentType.Cert));

var startInfo = new ProcessStartInfo
var processSpec = new ProcessSpec("security")
{
FileName = "security",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
Arguments = $"verify-cert -p basic -p ssl -c {certPath}",
ThrowOnNonZeroReturnCode = false
};

startInfo.ArgumentList.Add("verify-cert");
startInfo.ArgumentList.Add("-p");
startInfo.ArgumentList.Add("basic");
startInfo.ArgumentList.Add("-p");
startInfo.ArgumentList.Add("ssl");
startInfo.ArgumentList.Add("-c");
startInfo.ArgumentList.Add(certPath);

using var process = Process.Start(startInfo);
if (process is null)
var (task, processDisposable) = ProcessUtil.Run(processSpec);
await using (processDisposable.ConfigureAwait(false))
{
return false;
var result = await task.WaitAsync(cancellationToken).ConfigureAwait(false);
return result.ExitCode == 0;
}

process.WaitForExit();
return process.ExitCode == 0;
}
catch
{
Expand Down
Loading