using System; using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace ln.http; public class TlsListener : Listener { private CertificateStore _certificateStore; public X509Certificate DefaultCertificate { get; set; } public TlsListener(HttpRouter httpRouter, CertificateStore certificateStore) :this(httpRouter, null, certificateStore){} public TlsListener(HttpRouter httpRouter, IPAddress bind, int port, CertificateStore certificateStore) :this(httpRouter, new IPEndPoint(bind, port), certificateStore){} public TlsListener(HttpRouter httpRouter, IPEndPoint bind, CertificateStore certificateStore) : this(httpRouter, bind, certificateStore, null) { } public TlsListener(HttpRouter httpRouter, IPEndPoint bind, CertificateStore certificateStore, X509Certificate defaultCertificate) :base(httpRouter, bind) { _certificateStore = certificateStore; DefaultCertificate = defaultCertificate; if (DefaultCertificate is null) { if (_certificateStore.TryGetCertificate("localhost", out defaultCertificate)) DefaultCertificate = defaultCertificate; } } protected override void Accepted(Socket connectedSocket, Stream connectionStream) { SslStream sslStream = new SslStream(connectionStream, false, null, CertificateSelectionCallback); try { sslStream.AuthenticateAsServer(DefaultCertificate); // ToDo: Check for correct ALPN protocol identifier base.Accepted(connectedSocket, sslStream); } catch (Exception e) { } finally { sslStream?.Dispose(); } } private X509Certificate CertificateSelectionCallback(object sender, string targethost, X509CertificateCollection localcertificates, X509Certificate? remotecertificate, string[] acceptableissuers) { if (!_certificateStore.TryGetCertificate(targethost, out X509Certificate certificate)) return null; return certificate; } private X509Certificate2 buildSelfSignedServerCertificate() { SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddIpAddress(LocalEndpoint.Address); sanBuilder.AddDnsName(Environment.MachineName); X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN={LocalEndpoint.Address.ToString()}"); using (RSA rsa = RSA.Create(4096)) { var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1); request.CertificateExtensions.Add( new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature , false)); request.CertificateExtensions.Add( new X509EnhancedKeyUsageExtension( new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false)); request.CertificateExtensions.Add(sanBuilder.Build()); var certificate= request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650))); return certificate; } } }