| File: Certificates\CertificateHelpers.cs | Web Access |
| Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Certificates.Generation; namespace Aspire.Cli.Certificates; /// <summary> /// Shared helper methods for certificate operations. /// </summary> internal static partial class CertificateHelpers { /// <summary> /// The environment variable name for overriding the dev-certs OpenSSL certificate directory. /// </summary> internal const string DevCertsOpenSslCertDirEnvVar = "DOTNET_DEV_CERTS_OPENSSL_CERTIFICATE_DIRECTORY"; private static readonly string s_defaultDevCertsTrustPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".aspnet", "dev-certs", "trust"); /// <summary> /// Gets the dev-certs trust path, respecting the <c>DOTNET_DEV_CERTS_OPENSSL_CERTIFICATE_DIRECTORY</c> override. /// </summary> internal static string GetDevCertsTrustPath() { var overridePath = Environment.GetEnvironmentVariable(DevCertsOpenSslCertDirEnvVar); return !string.IsNullOrEmpty(overridePath) ? overridePath : s_defaultDevCertsTrustPath; } /// <summary> /// Gets the system certificate directories by querying OpenSSL. Falls back to well-known /// locations (<c>/etc/ssl/certs</c> and <c>/etc/pki/tls/certs</c>) when OpenSSL is unavailable. /// </summary> internal static List<string> GetSystemCertificateDirectories() { var systemCertDirs = new List<string>(); if (TryGetOpenSslDirectory(out var openSslDir)) { var openSslCertsDir = Path.Combine(openSslDir, "certs"); if (Directory.Exists(openSslCertsDir)) { systemCertDirs.Add(openSslCertsDir); } } else { // Fallback to common locations if OpenSSL is not available or fails if (Directory.Exists("/etc/ssl/certs")) { systemCertDirs.Add("/etc/ssl/certs"); } if (Directory.Exists("/etc/pki/tls/certs")) { systemCertDirs.Add("/etc/pki/tls/certs"); } } return systemCertDirs; } /// <summary> /// Determines whether the specified <see cref="EnsureCertificateResult"/> represents a successful trust operation. /// </summary> /// <param name="result">The result to evaluate.</param> /// <returns><see langword="true"/> if the result represents success; otherwise, <see langword="false"/>.</returns> internal static bool IsSuccessfulTrustResult(EnsureCertificateResult result) => result is EnsureCertificateResult.Succeeded or EnsureCertificateResult.ValidCertificatePresent or EnsureCertificateResult.ExistingHttpsCertificateTrusted or EnsureCertificateResult.NewHttpsCertificateTrusted; /// <summary> /// Tries to detect the OpenSSL directory by running 'openssl version -d'. /// Parses the OPENSSLDIR value from the output (e.g. OPENSSLDIR: "/usr/lib/ssl"). /// </summary> /// <param name="openSslDir">The detected OpenSSL directory path if successful.</param> /// <returns><see langword="true"/> if the directory was detected; otherwise, <see langword="false"/>.</returns> internal static bool TryGetOpenSslDirectory([NotNullWhen(true)] out string? openSslDir) { openSslDir = null; try { var processInfo = new ProcessStartInfo("openssl", "version -d") { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(processInfo); if (process is null) { return false; } var stdout = process.StandardOutput.ReadToEnd(); if (!process.WaitForExit(TimeSpan.FromSeconds(5))) { return false; } if (process.ExitCode != 0) { return false; } var match = OpenSslVersionRegex().Match(stdout); if (!match.Success) { return false; } openSslDir = match.Groups[1].Value; return true; } catch { // openssl may not be installed — silently fail return false; } } [GeneratedRegex("OPENSSLDIR:\\s*\"([^\"]+)\"")] internal static partial Regex OpenSslVersionRegex(); }