feat: add TlsHelper, PeekableStream, and TlsRateLimiter
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.
This commit is contained in:
65
src/NATS.Server/Tls/TlsHelper.cs
Normal file
65
src/NATS.Server/Tls/TlsHelper.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user