Closed
Description
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
Currently we need to use a custom certificate for the WebTransport connection. It would be great to have the default Kestrel certificate work with WebTransport to avoid this. It would make development easier and smoother.
Current setup
var builder = WebApplication.CreateBuilder(args);
// generate a certificate and hash to be shared with the client
var certificate = GenerateManualCertificate();
var hash = SHA256.HashData(certificate.RawData);
var certStr = Convert.ToBase64String(hash);
// configure the ports
builder.WebHost.ConfigureKestrel((context, options) =>
{
// webtransport configured port
options.Listen(IPAddress.Any, 5002, listenOptions =>
{
listenOptions.UseHttps(certificate);
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
});
});
// Adapted from: https://github.com/wegylexy/webtransport
// We will need to eventually merge this with existing Kestrel certificate generation
// tracked in issue #41762
static X509Certificate2 GenerateManualCertificate()
{
X509Certificate2 cert;
var store = new X509Store("KestrelWebTransportCertificates", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
if (store.Certificates.Count > 0)
{
cert = store.Certificates[^1];
// rotate key after it expires
if (DateTime.Parse(cert.GetExpirationDateString(), null) >= DateTimeOffset.UtcNow)
{
store.Close();
return cert;
}
}
// generate a new cert
var now = DateTimeOffset.UtcNow;
SubjectAlternativeNameBuilder sanBuilder = new();
sanBuilder.AddDnsName("localhost");
using var ec = ECDsa.Create(ECCurve.NamedCurves.nistP256);
CertificateRequest req = new("CN=localhost", ec, HashAlgorithmName.SHA256);
// Adds purpose
req.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection
{
new("1.3.6.1.5.5.7.3.1") // serverAuth
}, false));
// Adds usage
req.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, false));
// Adds subject alternate names
req.CertificateExtensions.Add(sanBuilder.Build());
// Sign
using var crt = req.CreateSelfSigned(now, now.AddDays(14)); // 14 days is the max duration of a certificate for this
cert = new(crt.Export(X509ContentType.Pfx));
// Save
store.Add(cert);
store.Close();
return cert;
}
Describe the solution you'd like
var builder = WebApplication.CreateBuilder(args);
// configure the ports
builder.WebHost.ConfigureKestrel((context, options) =>
{
// webtransport configured port
options.Listen(IPAddress.Any, 5002, listenOptions =>
{
listenOptions.UseHttps();
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
listenOptions.IsWebTransportPort = true; // switches to the webtransport-compatible cert (Could be cool if this wasn't even necessary).
Console.WriteLine(listenOptions.certHash); // prints the hash so that the user can paste it into the JS API or inject into their client side code.
});
});
Additional context
No response