91 lines
3.4 KiB
C#
91 lines
3.4 KiB
C#
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;
|
|
}
|
|
}
|
|
|
|
} |