Skip to content

Kestrel HTTP3 endpoint validate server name for client certificate by default #61767

Open
@PetSerAl

Description

@PetSerAl

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Kestrel HTTP3 endpoint validate server name for client certificate by default.

Expected Behavior

Default behavior for HTTP3 endpoint should match default behavior for HTTP2 endpoint, where server name is not validated for client certificates.

Steps To Reproduce

using System;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var certificateServerLocalhost = X509CertificateLoader.LoadPkcs12(
    Convert.FromBase64String(
        "MIIDrwIBAzCCA2sGCSqGSIb3DQEHAaCCA1wEggNYMIIDVDCCAW0GCSqGSIb3DQEHAaCCAV4EggFaMIIBVjCCAVIGCyqGSIb3DQEM"
            + "CgECoIHMMIHJMBwGCiqGSIb3DQEMAQMwDgQIad3vtjT4Dl0CAgfQBIGo6KjHd77pQmovty/084x1hiAASWOykB98Ae/UVnk2LpyP"
            + "fMa0CBf9ftYrZoRBxAVCxV69cji5ORmtAHeY4KnUC/YTpNtUSxQMwL+kzs1VVuAn97xlChlwT/Ja8I+nP/SZxqFkAubFSevVICtb"
            + "Ab/AQ2Fm2kc99Cxf3T3w1UXwztrEAia//16oW+lCoJgAWNsmRzDdSyr0DbHKyE0e5+lPYHHe1KI4btQsMXQwEwYJKoZIhvcNAQkV"
            + "MQYEBAEAAAAwXQYJKwYBBAGCNxEBMVAeTgBNAGkAYwByAG8AcwBvAGYAdAAgAFMAbwBmAHQAdwBhAHIAZQAgAEsAZQB5ACAAUwB0"
            + "AG8AcgBhAGcAZQAgAFAAcgBvAHYAaQBkAGUAcjCCAd8GCSqGSIb3DQEHBqCCAdAwggHMAgEAMIIBxQYJKoZIhvcNAQcBMBwGCiqG"
            + "SIb3DQEMAQMwDgQI7CXlOm9fD2gCAgfQgIIBmFjiicG1YQPZbwMya27wyyhreSnznp/WLfycwsa2ssATFgRXssUw49gHs4ZDMqQO"
            + "5y57e4VJoJ4nAb3yQn9HuCqiwv0UJcFc2B70JuRWpWv/TAWgoLuPeeHtOCeBRvhuGW56xkNqiMk/aOQSuOYxKtXhwymY83kZ/g8T"
            + "3uNGRwOkqwzhfrN0vadkBBZmJJ2m7W8cDsWdfFhlFWhN6U9MQK0NnvCqCs9M/jrSfCe103pZb6GiXz6ybW+Ihk/5G5G85DFO2oI/"
            + "Jt++aOBegU+RuyIqsQAhbN13gX0roo5RF5TpQ94QMgxFo46i+Szg0osXggK+unEmCj4xLQ1bTreOaQaSW7RYb1sjm2JbkR66BB7Y"
            + "8YaLZZ79tbQfmzrXiorvOQKkPkDx9qGCRyMluD2kAZ6c5O0X14dc1Bo/RiBHXCpRlJP6tPD1RAF2qwCFtAT3x0/GJyVeAgSfsTvx"
            + "PU6Gv2gFNBtrhnxdhYVTEdDV2w8avJntBdGjO9FQRYhxHXx//RFYeY0CshPQ1lW8TYIxf96KqOWmSGm1TjA7MB8wBwYFKw4DAhoE"
            + "FBBrIxe8fGOgQiTnPTaTYR3QcUwzBBQVujtIjom0GFjf6v9B+43uzBgyLgICB9A="
    ),
    null
);
using var certificateClient = X509CertificateLoader.LoadPkcs12(
    Convert.FromBase64String(
        "MIIDfwIBAzCCAzsGCSqGSIb3DQEHAaCCAywEggMoMIIDJDCCAW0GCSqGSIb3DQEHAaCCAV4EggFaMIIBVjCCAVIGCyqGSIb3DQEM"
            + "CgECoIHMMIHJMBwGCiqGSIb3DQEMAQMwDgQILlG/36k1fsECAgfQBIGoErtgM6e3Bml4MkwYRvULjwbzguW/VJyCbdk78PcVRVls"
            + "uWVMn6k28gubNFF1mjBw9rZzUD5LYF6mNzVbQMhKbaKDDgzqRf0Gp/rs7oE8s+3Mxa+AJHgdid8ir8FtPcKdQixARRsa/5xgTgS6"
            + "OygWxTDvgfNIToZAIwufEMVkZccm5AYxWsa1mBpU577BYhood7ndlhxf1y77/W+P/8cIrLv3YM7b61uWMXQwEwYJKoZIhvcNAQkV"
            + "MQYEBAEAAAAwXQYJKwYBBAGCNxEBMVAeTgBNAGkAYwByAG8AcwBvAGYAdAAgAFMAbwBmAHQAdwBhAHIAZQAgAEsAZQB5ACAAUwB0"
            + "AG8AcgBhAGcAZQAgAFAAcgBvAHYAaQBkAGUAcjCCAa8GCSqGSIb3DQEHBqCCAaAwggGcAgEAMIIBlQYJKoZIhvcNAQcBMBwGCiqG"
            + "SIb3DQEMAQMwDgQIZj+k/x/0j9QCAgfQgIIBaD7nXwkkq8wWxJAWwqcWmZbpeeGyn2dFr/BgvhW09E6pPtkArJPpcOQjCR8vfMKu"
            + "RtyrkJXHCGhQm/1WhszAKJN7KkKECBWUt++a0h+YkPoaHYyQvy7oZKZ0udD3F3YNAplSB4E05BYF3d3w6PZXuMU/A8t1hLVaP+j6"
            + "2t0q324JvUVmTzQcJ8pOqocSGgUB9T0U5aWj2keJSDM6L4vz3Kkm8YCUEna/QBfp81vVbg6zYXF2BhmRD9Uc/7T9CjoC7aIpRoYT"
            + "Ey8CqxEaMrqq82+f4iSrKY+UmtxCtmVp8SCFcLqz9jTn7aUqwNn9SVRLMMmDSxXaEkRg8NFRPdnepkrF5h2EeIB4Gt+6BzWGbDOV"
            + "Yl8ioGYAS71GKKXNl4snh1woX5AQKVdaM/xohLPd8CiqYE4a8vSP1SSC/s3ttSVKfe3e/ONCV7WxshpYObQW2NAzNH/yi+OdLSY6"
            + "btoeRCkTiF8eulpwNjA7MB8wBwYFKw4DAhoEFL8/AatGW+KGBiEA4LplXG61rBNCBBR7tTmVo7NJZsX91Ysbc4PxyRznUwICB9A="
    ),
    null
);
using var certificateClientLocalhost = X509CertificateLoader.LoadPkcs12(
    Convert.FromBase64String(
        "MIIDrwIBAzCCA2sGCSqGSIb3DQEHAaCCA1wEggNYMIIDVDCCAW0GCSqGSIb3DQEHAaCCAV4EggFaMIIBVjCCAVIGCyqGSIb3DQEM"
            + "CgECoIHMMIHJMBwGCiqGSIb3DQEMAQMwDgQIKi5n+9Fb2WwCAgfQBIGoEVZtJPlK2py4NO64buCWJiaZkGl1TTkXRUy4yvMTD5GQ"
            + "+v4Qmh3NXF7qtZoElQoA+UexWIyOgkNOdc0q8nPeTwlB9M6WAT8zLltc4u2YJRYABDyqxFHFVMrXyslj1TOogX55GTiXSaVO0D2m"
            + "sARHHI90Qjuf27sxMtBC+1VmpSBEhGZtMO14CHIpz5qRGyigTf/OC7xnpJ95poEKfUh4XdwCbijvot8lMXQwEwYJKoZIhvcNAQkV"
            + "MQYEBAEAAAAwXQYJKwYBBAGCNxEBMVAeTgBNAGkAYwByAG8AcwBvAGYAdAAgAFMAbwBmAHQAdwBhAHIAZQAgAEsAZQB5ACAAUwB0"
            + "AG8AcgBhAGcAZQAgAFAAcgBvAHYAaQBkAGUAcjCCAd8GCSqGSIb3DQEHBqCCAdAwggHMAgEAMIIBxQYJKoZIhvcNAQcBMBwGCiqG"
            + "SIb3DQEMAQMwDgQI3BQzuM21QesCAgfQgIIBmOSvMKdfwj/aVxsahOwtYAUGcpbYCT0SXXEfPy6iLblXBUWHx9Le8xKMpach2lgh"
            + "gcrJ3R2wT8vsREu4l4UT8cqJkl68B3OUhgPfuvso9iVfMgz/To+Sj5i0H4oMGq90cmdqO7bEp0ZOrRu/JNPRqZ1ghVDrnCQYOQ3m"
            + "3gApTnVQaHpDHSY+Nl3ZDy6DnBNZH4NHBqt8KqsKOWwVEtYFfb66Hi9WQBUP3wu8hiNxE+HuYOhdw00Gz1wneYn9xCKqgRKUyOKR"
            + "C0VG7MdWW7RqBK50DvFGGbQcb6ADCUdr8LqtuNqCklfoBd1NG2NOlYzdBQ93w0KMqV5Hd2SyFi+ZEOEjrwYuchk9AxolkVUNbUze"
            + "Y/O8+T30cR022jUi8YliugEhHm0l4huvyjN0M8mQF9dWcq4PxQ/7NUY9CXjXmp5ZLonbavk6iY5nytMaFUnhh3XtRYH6tJLQRZUV"
            + "4p0icUQhWh0g/aTnnSTzSXpOd5td6Mb0khwq+FfGAgrJWGp+LKYTPA6sag5lNpUMqqjYIosnJKQolBS6ADA7MB8wBwYFKw4DAhoE"
            + "FADCiRACrrpEnRFNC09caBMryMWwBBTHIA1DiU5Ni6bAxQ7YglL8CtieBwICB9A="
    ),
    null
);

var builder = WebApplication.CreateEmptyBuilder(new());
builder.WebHost.UseKestrel();
builder
    .Services.AddOptions<KestrelServerOptions>()
    .Configure(kestrelOptions =>
    {
        kestrelOptions.ConfigureHttpsDefaults(httpsOptions =>
        {
            httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
            httpsOptions.ServerCertificate = certificateServerLocalhost;
            httpsOptions.ClientCertificateValidation = (certificate, chain, errors) =>
            {
                Console.WriteLine($"{certificate.Subject} -> {errors}");
                return true;
            };
        });
        kestrelOptions.ListenLocalhost(
            12345,
            listenOptions =>
            {
                listenOptions.Protocols = HttpProtocols.Http2 | HttpProtocols.Http3;
                listenOptions.UseHttps();
            }
        );
    });
builder.Services.AddRouting();
using var app = builder.Build();
app.MapGet("/", (HttpRequest request) => request.Protocol);
await app.StartAsync();

using (
    HttpClient httpClient = new(
        new SocketsHttpHandler()
        {
            SslOptions =
            {
                ClientCertificateContext = SslStreamCertificateContext.Create(
                    certificateClient,
                    null,
                    true
                ),
                RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true,
            },
        }
    )
)
{
    Console.WriteLine(
        await (
            await httpClient.SendAsync(
                new(HttpMethod.Get, "https://localhost:12345")
                {
                    Version = new(2, 0),
                    VersionPolicy = HttpVersionPolicy.RequestVersionExact,
                }
            )
        ).Content.ReadAsStringAsync()
    );
    Console.WriteLine(
        await (
            await httpClient.SendAsync(
                new(HttpMethod.Get, "https://localhost:12345")
                {
                    Version = new(3, 0),
                    VersionPolicy = HttpVersionPolicy.RequestVersionExact,
                }
            )
        ).Content.ReadAsStringAsync()
    );
}
using (
    HttpClient httpClient = new(
        new SocketsHttpHandler()
        {
            SslOptions =
            {
                ClientCertificateContext = SslStreamCertificateContext.Create(
                    certificateClientLocalhost,
                    null,
                    true
                ),
                RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true,
            },
        }
    )
)
{
    Console.WriteLine(
        await (
            await httpClient.SendAsync(
                new(HttpMethod.Get, "https://localhost:12345")
                {
                    Version = new(2, 0),
                    VersionPolicy = HttpVersionPolicy.RequestVersionExact,
                }
            )
        ).Content.ReadAsStringAsync()
    );
    Console.WriteLine(
        await (
            await httpClient.SendAsync(
                new(HttpMethod.Get, "https://localhost:12345")
                {
                    Version = new(3, 0),
                    VersionPolicy = HttpVersionPolicy.RequestVersionExact,
                }
            )
        ).Content.ReadAsStringAsync()
    );
}

await app.StopAsync();
await app.WaitForShutdownAsync();

Output:

CN=Client -> RemoteCertificateChainErrors
HTTP/2
CN=Client -> RemoteCertificateNameMismatch, RemoteCertificateChainErrors
HTTP/3
CN=Client localhost -> RemoteCertificateChainErrors
HTTP/2
CN=Client localhost -> RemoteCertificateChainErrors
HTTP/3

Expected output:

CN=Client -> RemoteCertificateChainErrors
HTTP/2
CN=Client -> RemoteCertificateChainErrors
HTTP/3
CN=Client localhost -> RemoteCertificateChainErrors
HTTP/2
CN=Client localhost -> RemoteCertificateChainErrors
HTTP/3

Exceptions (if any)

No response

.NET Version

9.0.203

Anything else?

.NET SDK:
 Version:           9.0.203
 Commit:            dc7acfa194
 Workload version:  9.0.200-manifests.9df47798
 MSBuild version:   17.13.20+a4ef1e90f

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.26100
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\9.0.203\

Host:
  Version:      9.0.4
  Architecture: x64
  Commit:       f57e6dc747

.NET SDKs installed:
  9.0.203 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 9.0.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 9.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 9.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-kestrel

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions