Skip to content

Commit

Permalink
Refactor and simplify SslCertificateManager using .NET 9’s cross-plat…
Browse files Browse the repository at this point in the history
…form X509CertificateLoader.LoadPkcs12FromFile method
  • Loading branch information
tjementum committed Nov 19, 2024
1 parent d0815f3 commit 90afd43
Showing 1 changed file with 12 additions and 66 deletions.
78 changes: 12 additions & 66 deletions application/AppHost/SslCertificateManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Extensions.Configuration;
Expand All @@ -10,10 +9,7 @@ namespace AppHost;

public static class SslCertificateManager
{
public static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

private static string UserSecretsId =>
Assembly.GetEntryAssembly()!.GetCustomAttribute<UserSecretsIdAttribute>()!.UserSecretsId;
private static string UserSecretsId => Assembly.GetEntryAssembly()!.GetCustomAttribute<UserSecretsIdAttribute>()!.UserSecretsId;

public static string CreateSslCertificateIfNotExists(this IDistributedApplicationBuilder builder)
{
Expand All @@ -24,9 +20,13 @@ public static string CreateSslCertificateIfNotExists(this IDistributedApplicatio
?? builder.CreateStablePassword(certificatePasswordKey).Resource.Value;

var certificateLocation = GetCertificateLocation("localhost");
if (!IsValidCertificate(certificatePassword, certificateLocation))
try
{
X509CertificateLoader.LoadPkcs12FromFile(certificateLocation, certificatePassword);
}
catch (CryptographicException)
{
CreateNewSelfSignedDeveloperCertificate(certificatePassword, certificateLocation);
CreateNewSelfSignedDeveloperCertificate(certificateLocation, certificatePassword);
}

return certificatePassword;
Expand All @@ -38,77 +38,23 @@ private static string GetCertificateLocation(string domain)
return $"{userFolder}/.aspnet/dev-certs/https/{domain}.pfx";
}

private static bool IsValidCertificate(string? password, string certificateLocation)
{
if (!File.Exists(certificateLocation))
{
return false;
}

if (IsWindows)
{
try
{
// Try to load the certificate with the provided password
_ = new X509Certificate2(certificateLocation, password);
return true;
}
catch (CryptographicException)
{
// If a CryptographicException is thrown, the password is invalid
// Ignore the exception and return false
}
}
else
{
var certificateValidation = StartProcess(new ProcessStartInfo
{
FileName = "openssl",
Arguments = $"pkcs12 -in {certificateLocation} -passin pass:{password} -nokeys",
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
);

if (certificateValidation.Contains("--BEGIN CERTIFICATE--"))
{
return true;
}
}

Console.WriteLine($"Certificate {certificateLocation} exists, but password {password} was invalid. Creating a new certificate.");
return false;
}

private static void CreateNewSelfSignedDeveloperCertificate(string password, string certificateLocation)
private static void CreateNewSelfSignedDeveloperCertificate(string certificateLocation, string password)
{
if (File.Exists(certificateLocation))
{
Console.WriteLine($"Certificate {certificateLocation} exists, but password {password} was invalid. Creating a new certificate.");

File.Delete(certificateLocation);
}

StartProcess(new ProcessStartInfo
Process.Start(new ProcessStartInfo
{
FileName = "dotnet",

Check warning on line 52 in application/AppHost/SslCertificateManager.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Make sure the "PATH" used to find this command includes only what you intend. (https://rules.sonarsource.com/csharp/RSPEC-4036)

Check warning on line 52 in application/AppHost/SslCertificateManager.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Make sure the "PATH" used to find this command includes only what you intend. (https://rules.sonarsource.com/csharp/RSPEC-4036)

Check warning on line 52 in application/AppHost/SslCertificateManager.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Make sure the "PATH" used to find this command includes only what you intend. (https://rules.sonarsource.com/csharp/RSPEC-4036)

Check warning on line 52 in application/AppHost/SslCertificateManager.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Make sure the "PATH" used to find this command includes only what you intend. (https://rules.sonarsource.com/csharp/RSPEC-4036)
Arguments = $"dev-certs https --trust -ep {certificateLocation} -p {password}",
RedirectStandardOutput = false,
RedirectStandardError = false,
UseShellExecute = false
}
);
}

private static string StartProcess(ProcessStartInfo processStartInfo)
{
var process = Process.Start(processStartInfo)!;

var output = string.Empty;
if (processStartInfo.RedirectStandardOutput) output += process.StandardOutput.ReadToEnd();
if (processStartInfo.RedirectStandardError) output += process.StandardError.ReadToEnd();

process.WaitForExit();

return output;
)!.WaitForExit();
}
}

0 comments on commit 90afd43

Please sign in to comment.