Skip to content
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

Make ALPN configuration easier for use with TlsHandshakeCallbackOptions #31303

Closed
halter73 opened this issue Mar 27, 2021 · 2 comments · Fixed by #34242
Closed

Make ALPN configuration easier for use with TlsHandshakeCallbackOptions #31303

halter73 opened this issue Mar 27, 2021 · 2 comments · Fixed by #34242
Assignees
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions feature-kestrel Needs: Design This issue requires design work before implementating.
Milestone

Comments

@halter73
Copy link
Member

Thanks for adding this. We're using ServerOptionsSelectionCallback and SslStreamCertificateContext to enable hosting thousands of domains and selecting the right ssl certificates with Kestrel. Though X509Certificate2 on Windows does have temporary file creation issues that don't disappear with dispose that we have to deal with.

I had to spend some time to figure this out and to get it working with HTTP/2. Posting some sample code here for the benefit of others trying to use ServerOptionsSelectionCallback, for inclusion in documentation, and if anything with the sample code triggers changes/improvements.

We needed ConfigureAlpn to enable HTTP/2. Maybe this method should be made public in HttpsConnectionMiddleware or called internally in HttpsConnectionMiddleware for us?

Also would be great to have access to ConnectionContext so we can get the connecting ip, listening port, etc. to make certain decisions at this stage or to abort the connection if we didn't find a matching certificate or for any other reasons. If there is a best practice there on how to drop the connection when a matching certificate is not found, would be glad to hear it. Right now, we just return null as the certificate and let Kestrel drop the connection.

listenOptions.UseHttps(ServerOptionsSelectionCallback, state: listenOptions.Protocols);

ValueTask<SslServerAuthenticationOptions> ServerOptionsSelectionCallback(
	SslStream stream,
	SslClientHelloInfo clientHelloInfo,
	object state,
	CancellationToken cancellationToken)
{
	var serverOptions = new SslServerAuthenticationOptions
	{
		EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13,
		CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
		ServerCertificateContext = SslStreamCertificateContext.Create(certificate, intermediateCertificates, offline: true)
	};

	//ConfigureAlpn / Enable Http2
	var httpProtocols = (HttpProtocols)state;
	ConfigureAlpn(serverOptions, httpProtocols);

	return new ValueTask<SslServerAuthenticationOptions>(serverOptions);
}

//Copy of method from:
//https://github.com/dotnet/aspnetcore/blob/main/src/Servers/Kestrel/Core/src/Middleware/HttpsConnectionMiddleware.cs
void ConfigureAlpn(SslServerAuthenticationOptions serverOptions, HttpProtocols httpProtocols)
{
	serverOptions.ApplicationProtocols = new List<SslApplicationProtocol>();

	// This is order sensitive
	if ((httpProtocols & HttpProtocols.Http2) != 0)
	{
		serverOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http2);
		// https://tools.ietf.org/html/rfc7540#section-9.2.1
		serverOptions.AllowRenegotiation = false;
	}

	if ((httpProtocols & HttpProtocols.Http1) != 0)
	{
		serverOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11);
	}
}

Thanks @nitinag for reporting this issue in #25390 (comment).

I think having a public static ConfigureAlpn method like @nitinag suggests is a reasonable approach. It's internal rather than private today so SniOptionsSelector can call it which probably should have been a sign it should be made public in the first place.

My only concern is that people still won't know to call it and therefore unintentionally disable HTTP/2 when trying to write custom SNI logic. API docs can help here, but not everyone reads it.

I wonder if instead we should automatically populate ApplicationProtocols if its null. The question there becomes what if I want to disable ALPN? Is that important? Could that be done with an empty list instead of a null list?

We shouldn't let perfect be the enemy of the good though. If we cannot autopupulate the ALPN list for whatever reason, we should just expose ConfigureAlpn. It shouldn't be necessary for people to copy/paste this code.

@halter73 halter73 added Needs: Design This issue requires design work before implementating. area-servers feature-kestrel labels Mar 27, 2021
@halter73 halter73 added this to the Next sprint planning milestone Mar 27, 2021
@ghost
Copy link

ghost commented Mar 27, 2021

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@halter73 halter73 changed the title Make ALPN configuration easier for Make ALPN configuration easier for use with TlsHandshakeCallbackOptions Jul 9, 2021
@Tratcher Tratcher self-assigned this Jul 9, 2021
@Tratcher
Copy link
Member

Tratcher commented Jul 9, 2021

Also would be great to have access to ConnectionContext so we can get the connecting ip, listening port, etc. to make certain decisions at this stage or to abort the connection if we didn't find a matching certificate or for any other reasons.

This was addressed by #33953. Now we need to sort out ALPN for both overloads.

Tratcher added a commit to Tratcher/aspnetcore that referenced this issue Jul 9, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Aug 17, 2021
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions feature-kestrel Needs: Design This issue requires design work before implementating.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants