using System.Security.Cryptography.X509Certificates; namespace StellaOps.Router.Transport.Tls; /// /// Utility class for loading certificates from various sources. /// public static class CertificateLoader { /// /// Loads a server certificate from the options. /// /// The TLS transport options. /// The loaded certificate. /// Thrown when no certificate is configured. public static X509Certificate2 LoadServerCertificate(TlsTransportOptions options) { // Direct certificate object takes precedence if (options.ServerCertificate is not null) { return options.ServerCertificate; } // Load from path if (string.IsNullOrEmpty(options.ServerCertificatePath)) { throw new InvalidOperationException("Server certificate is not configured"); } return LoadCertificateFromPath( options.ServerCertificatePath, options.ServerCertificateKeyPath, options.ServerCertificatePassword); } /// /// Loads a client certificate from the options. /// /// The TLS transport options. /// The loaded certificate, or null if not configured. public static X509Certificate2? LoadClientCertificate(TlsTransportOptions options) { // Direct certificate object takes precedence if (options.ClientCertificate is not null) { return options.ClientCertificate; } // Load from path if (string.IsNullOrEmpty(options.ClientCertificatePath)) { return null; } return LoadCertificateFromPath( options.ClientCertificatePath, options.ClientCertificateKeyPath, options.ClientCertificatePassword); } /// /// Loads a certificate from a file path. /// /// The certificate path (PEM or PFX). /// The private key path (optional, for PEM). /// The password (optional, for PFX). /// The loaded certificate. public static X509Certificate2 LoadCertificateFromPath( string certPath, string? keyPath = null, string? password = null) { var extension = Path.GetExtension(certPath).ToLowerInvariant(); return extension switch { ".pfx" or ".p12" => LoadPfxCertificate(certPath, password), ".pem" or ".crt" or ".cer" => LoadPemCertificate(certPath, keyPath), _ => throw new InvalidOperationException($"Unsupported certificate format: {extension}") }; } private static X509Certificate2 LoadPfxCertificate(string pfxPath, string? password) { return X509CertificateLoader.LoadPkcs12FromFile( pfxPath, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); } private static X509Certificate2 LoadPemCertificate(string certPath, string? keyPath) { var certPem = File.ReadAllText(certPath); if (string.IsNullOrEmpty(keyPath)) { // Assume the key is in the same file return X509Certificate2.CreateFromPem(certPem); } var keyPem = File.ReadAllText(keyPath); return X509Certificate2.CreateFromPem(certPem, keyPem); } }