Skip to content

API Proposal: Expose TLS client hello message #60805

@DeagleGross

Description

@DeagleGross

Is there an existing issue for this?

  • I have searched the existing issues

Intro

We need to add implementation at least for HTTP.SYS / Kestrel servers. Based on SslStream API Proposal for Kestrel support (dotnet/runtime proposal), it seems more likely that a callback will be introduced there (something like SslServerAuthenticationOptions.ClientHelloBytesCallback).

Or we can just support it in aspnetcore directly similarly to how YARP has already done it (see TlsFilter middleware).

Proposed API

Kestrel

Exposing a separate extension on ListenOptionsHttpsExtensions or on a new type ListenOptionsTlsExtensions works for Kestrel

namespace Microsoft.AspNetCore.Hosting
{
  public static class ListenOptionsHttpsExtensions
  {
+   public static ListenOptions ConfigureTlsClientHelloCallback(this ListenOptions listenOptions, Action<ConnectionContext, ReadOnlySequence<byte>> tlsClientHelloCallback);  // has info about connection; has the tls client hello bytes
  }

+ public static class ListenOptionsTlsExtensions
+  {
+   public static ListenOptions ConfigureTlsClientHelloCallback(this ListenOptions listenOptions, Action<ConnectionContext, ReadOnlySequence<byte>> tlsClientHelloCallback);  // has info about connection; has the tls client hello bytes
+  }
}

Kestrel Usage:

options.ListenAnyIP(443, listenOptions =>
{
   listenOptions.ConfigureTlsClientHelloCallback((connectionContext, tlsClientHelloBytes) => {
       // do whatever with tlsClientHelloBytes
   });
});

Implementation of such a kind would be reading every packet, then if it appears to start with TLS client hello header, then we would try to identify the length of it, read needed data, and then invoke a callback. Later we would be able to even add an overload to provide a parsed TLS client hello message in a strictly typed way (like TlsFrameInfo)

This also helps user to associate the tls client hello with a specific connection (ConnectionContext parameter).

ReadOnlySequence<byte> should be chosen instead of ReadOnlySpan<byte> because tls info can come in different segments, and it will not be a contiguous memory then (see TlsFilter's if (!buffer.IsSingleSegment))

Http.Sys

In order to align the implementation for different servers, I am proposing to add a similar callback to HttpSysOptions

namespace Microsoft.AspNetCore.Server.HttpSys;

public class HttpSysOptions
{
+   Action<IFeatureCollection, ReadOnlySpan<byte>> ClientHelloBytesCallback { get; set; }
}

Http.sys Usage:

options.ClientHelloBytesCallback = (requestFeature, bytes)=>
{
       // do whatever with tlsClientHelloBytes
});

HTTP.SYS API would have same idea, but different implementation: a) having a callback in a different options class and b) having an IFeatureCollection instead of ConnectionContext (there is none yet for HTTP.SYS). That would also give full control to the user to lookup to any feature collection or even set their own feature for future call rejection for instance.

Other considered designs (and why they are not chosen)

Middleware

Adding a separate middleware on top of IApplicationBuilder.Run() will not fulfil the need, since such a middleware is terminal (runs after the internal ASP.NET middleware chain including SslStream one):

        app.Run(async (HttpContext httpContext) =>
        {
            var transportFeature = httpContext.Features.Get<IConnectionTransportFeature>();
            var pipeReader = transportFeature.Transport.Input;

            // imagine here we get the buffer for the TLS Client Hello message
            var bytes = await pipeReader.ReadAsync();
            var tlsCLientHelloMessage = bytes.Buffer.FirstSpan;

            tlsClientHelloCallback(httpContext, tlsCLientHelloMessage); // invoking, so users can do whatever
        });

Exposing bytes field on the ITlsHandshakeFeature (or similar)

This is considered a non-performant API for both servers due to increasing a memory footprint significantly (see dotnet/runtime#113729 (comment)):

public interface ITlsHandshakeFeature
{
  public byte[] TlsClientHelloMessageBytes { get; }
}

Is your feature request related to a problem? Please describe the problem.

The intention here is to have an API to access a TLS client hello message in a format of raw bytes (in example byte[]). In such a way users can analyze it and make whatever decision they want to.

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-httpsys

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions