Skip to content

Adjusting the default Kestrel development certificate to support WebTransport #42787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
Tracked by #42788
Daniel-Genkin-MS-2 opened this issue Jul 18, 2022 · 7 comments
Closed
1 task done
Tracked by #42788
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI feature-devcerts

Comments

@Daniel-Genkin-MS-2
Copy link
Contributor

Daniel-Genkin-MS-2 commented Jul 18, 2022

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

@blowdart
Copy link
Contributor

What errors are you seeing? HTTP3 doesn't require ECC and switching to ECC would require some investigation wrt iot and more.

@davidfowl
Copy link
Member

Currently we need to use a custom certificate for the WebTransport connection.

Why is this?

@Daniel-Genkin-MS-2
Copy link
Contributor Author

Chromium will just straight up reject the cert
image

@Daniel-Genkin-MS-2
Copy link
Contributor Author

You can see this if you run the interactive sample app in the webtransport pr (#42097) and replace line 17 which is this:
var certificate = GenerateManualCertificate();
with:
var certificate = CertificateLoader.LoadFromStoreCert("localhost", StoreName.My.ToString(), StoreLocation.CurrentUser, false);

@davidfowl
Copy link
Member

I think we need to figure out why. Is it ECC (Elliptic Curve Cryptography) that's making the big difference?

@adityamandaleeka adityamandaleeka added this to the .NET 8 Planning milestone Jul 18, 2022
@Tratcher
Copy link
Member

Tratcher commented Aug 9, 2022

Duplicate of #41762?

@amcasey amcasey added area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI and removed area-runtime labels Jun 2, 2023
@amcasey
Copy link
Member

amcasey commented Feb 14, 2024

Let's track this via #41762.

@amcasey amcasey closed this as completed Feb 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI feature-devcerts
Projects
None yet
Development

No branches or pull requests

7 participants