Files
git.stella-ops.org/src/__Libraries/StellaOps.Router.Transport.Tls/CertificateLoader.cs
StellaOps Bot 6a299d231f
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Add unit tests for Router configuration and transport layers
- Implemented tests for RouterConfig, RoutingOptions, StaticInstanceConfig, and RouterConfigOptions to ensure default values are set correctly.
- Added tests for RouterConfigProvider to validate configurations and ensure defaults are returned when no file is specified.
- Created tests for ConfigValidationResult to check success and error scenarios.
- Developed tests for ServiceCollectionExtensions to verify service registration for RouterConfig.
- Introduced UdpTransportTests to validate serialization, connection, request-response, and error handling in UDP transport.
- Added scripts for signing authority gaps and hashing DevPortal SDK snippets.
2025-12-05 08:01:47 +02:00

105 lines
3.6 KiB
C#

using System.Security.Cryptography.X509Certificates;
namespace StellaOps.Router.Transport.Tls;
/// <summary>
/// Utility class for loading certificates from various sources.
/// </summary>
public static class CertificateLoader
{
/// <summary>
/// Loads a server certificate from the options.
/// </summary>
/// <param name="options">The TLS transport options.</param>
/// <returns>The loaded certificate.</returns>
/// <exception cref="InvalidOperationException">Thrown when no certificate is configured.</exception>
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);
}
/// <summary>
/// Loads a client certificate from the options.
/// </summary>
/// <param name="options">The TLS transport options.</param>
/// <returns>The loaded certificate, or null if not configured.</returns>
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);
}
/// <summary>
/// Loads a certificate from a file path.
/// </summary>
/// <param name="certPath">The certificate path (PEM or PFX).</param>
/// <param name="keyPath">The private key path (optional, for PEM).</param>
/// <param name="password">The password (optional, for PFX).</param>
/// <returns>The loaded certificate.</returns>
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);
}
}