Add TLS utility classes for certificate loading, peekable stream for TLS detection, token-bucket rate limiter for handshake throttling, and TlsConnectionState for post-handshake info. Add TlsState property to NatsClient. Fix X509Certificate2 constructor usage for .NET 10 compat.
66 lines
2.3 KiB
C#
66 lines
2.3 KiB
C#
using System.Net.Security;
|
|
using System.Security.Authentication;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
namespace NATS.Server.Tls;
|
|
|
|
public static class TlsHelper
|
|
{
|
|
public static X509Certificate2 LoadCertificate(string certPath, string? keyPath)
|
|
{
|
|
if (keyPath != null)
|
|
return X509Certificate2.CreateFromPemFile(certPath, keyPath);
|
|
return X509CertificateLoader.LoadCertificateFromFile(certPath);
|
|
}
|
|
|
|
public static X509Certificate2Collection LoadCaCertificates(string caPath)
|
|
{
|
|
var collection = new X509Certificate2Collection();
|
|
collection.ImportFromPemFile(caPath);
|
|
return collection;
|
|
}
|
|
|
|
public static SslServerAuthenticationOptions BuildServerAuthOptions(NatsOptions opts)
|
|
{
|
|
var cert = LoadCertificate(opts.TlsCert!, opts.TlsKey);
|
|
var authOpts = new SslServerAuthenticationOptions
|
|
{
|
|
ServerCertificate = cert,
|
|
EnabledSslProtocols = opts.TlsMinVersion,
|
|
ClientCertificateRequired = opts.TlsVerify,
|
|
};
|
|
|
|
if (opts.TlsVerify && opts.TlsCaCert != null)
|
|
{
|
|
var caCerts = LoadCaCertificates(opts.TlsCaCert);
|
|
authOpts.RemoteCertificateValidationCallback = (_, cert, chain, errors) =>
|
|
{
|
|
if (cert == null) return false;
|
|
using var chain2 = new X509Chain();
|
|
chain2.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
|
|
foreach (var ca in caCerts)
|
|
chain2.ChainPolicy.CustomTrustStore.Add(ca);
|
|
chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
|
var cert2 = cert as X509Certificate2 ?? X509CertificateLoader.LoadCertificate(cert.GetRawCertData());
|
|
return chain2.Build(cert2);
|
|
};
|
|
}
|
|
|
|
return authOpts;
|
|
}
|
|
|
|
public static string GetCertificateHash(X509Certificate2 cert)
|
|
{
|
|
var spki = cert.PublicKey.ExportSubjectPublicKeyInfo();
|
|
var hash = SHA256.HashData(spki);
|
|
return Convert.ToHexStringLower(hash);
|
|
}
|
|
|
|
public static bool MatchesPinnedCert(X509Certificate2 cert, HashSet<string> pinned)
|
|
{
|
|
var hash = GetCertificateHash(cert);
|
|
return pinned.Contains(hash);
|
|
}
|
|
}
|