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);
}
}