| File: DirectTlsEndpointOptions.cs | Web Access |
| Project: src\aspnetcore\src\Servers\Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj (Microsoft.AspNetCore.Server.Kestrel.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; using System.Diagnostics.CodeAnalysis; using System.Net.Security; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Https; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.DirectTls; /// <summary> /// Per-endpoint TLS configuration for an endpoint served by the DirectTls transport. /// </summary> /// <remarks> /// DirectTls is TLS-only: every endpoint served by this transport terminates TLS, so a server certificate /// (either <see cref="ServerCertificate"/> or <see cref="ServerCertificateSelector"/>) is required. /// </remarks> [Experimental("ASPNETCORE_DIRECTTLS_001", UrlFormat = "https://aka.ms/aspnetcore/directtls")] public sealed class DirectTlsEndpointOptions { /// <summary> /// The server certificate presented during the TLS handshake. Used when /// <see cref="ServerCertificateSelector"/> is not set or returns <see langword="null"/>. /// </summary> public X509Certificate2? ServerCertificate { get; set; } /// <summary> /// A callback that selects the server certificate based on the connection and the SNI host name parsed /// from the ClientHello. When set, it is invoked once per connection before the certificate is installed; /// returning <see langword="null"/> falls back to <see cref="ServerCertificate"/>. /// </summary> /// <remarks> /// The first argument is the <see cref="ConnectionContext"/> for the connection being negotiated (already /// allocated so it carries the same connection id that will later serve the request); the second is the /// requested SNI host name, or <see langword="null"/> when the client did not send one. /// <para> /// This callback runs synchronously on the epoll worker thread that owns the connection and must not block. /// A blocking or long-running callback stalls the handshake and I/O of every connection assigned to that worker. /// </para> /// </remarks> public Func<ConnectionContext?, string?, X509Certificate2?>? ServerCertificateSelector { get; set; } /// <summary> /// The allowable TLS protocol versions. <see cref="SslProtocols.None"/> (the default) lets the operating /// system choose an appropriate default set. /// </summary> public SslProtocols SslProtocols { get; set; } = SslProtocols.None; /// <summary> /// Whether a client certificate is requested and/or required during the handshake (mutual TLS). /// </summary> /// <remarks> /// Defaults to <see cref="ClientCertificateMode.NoCertificate"/>. /// <see cref="ClientCertificateMode.DelayCertificate"/> is not supported (see https://github.com/dotnet/aspnetcore/issues/67915) /// </remarks> public ClientCertificateMode ClientCertificateMode { get; set; } = ClientCertificateMode.NoCertificate; /// <summary> /// A callback used to validate a client certificate when <see cref="ClientCertificateMode"/> requests one. /// Return <see langword="true"/> to accept the certificate. When not set, a certificate is accepted only /// when it produced no <see cref="SslPolicyErrors"/>. /// </summary> /// <remarks> /// This callback runs synchronously on the epoll worker thread that owns the connection and must not block. /// A blocking or long-running callback stalls the handshake and I/O of every connection assigned to that worker. /// </remarks> public Func<X509Certificate2, X509Chain?, SslPolicyErrors, bool>? ClientCertificateValidation { get; set; } /// <summary> /// An optional callback invoked with the raw ClientHello record bytes as soon as they are parsed, before /// the handshake completes. /// </summary> /// <remarks> /// The <see cref="ReadOnlySequence{T}"/> is only valid for the duration of the callback; copy the bytes /// (for example with <c>ToArray()</c>) if they must outlive the call. The first argument is the /// <see cref="ConnectionContext"/> for the connection being negotiated. /// <para> /// This callback runs synchronously on the epoll worker thread that owns the connection and must not block. /// A blocking or long-running callback stalls the handshake and I/O of every connection assigned to that worker. /// </para> /// </remarks> public Action<ConnectionContext, ReadOnlySequence<byte>>? TlsClientHelloBytesCallback { get; set; } /// <summary> /// Overrides the transport-wide worker count (<c>DirectTlsTransportOptions.WorkerCount</c>) for this /// endpoint. When <see langword="null"/> (the default), the transport-wide worker count is used. /// </summary> /// <remarks> /// Each DirectTls endpoint runs its own pool of worker threads, so a server's total thread count is the sum /// of every bound endpoint's worker count. Set this on individual endpoints to bound threads when hosting /// several DirectTls endpoints — for example, a low-traffic management port can use far fewer workers than a /// public HTTPS port. Must be greater than zero when set. /// </remarks> public int? WorkerCount { get; set { if (value is <= 0) { throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(WorkerCount)} must be greater than zero when set."); } field = value; } } /// <summary> /// The maximum amount of time allowed for the TLS handshake to complete on a connection to this endpoint. /// A connection whose handshake does not finish within this window is dropped. Defaults to 10 seconds. /// Set to <see cref="Timeout.InfiniteTimeSpan"/> to disable the timeout; any other non-positive value is rejected. /// </summary> /// <remarks> /// This bounds slow or stalled handshakes — for example a client that opens a connection and then dribbles /// the ClientHello one byte at a time — which would otherwise keep a file descriptor and its native TLS /// session pinned to a worker indefinitely. It mirrors <see cref="HttpsConnectionAdapterOptions.HandshakeTimeout"/>, /// which provides the same protection for the <see cref="SslStream"/>-based HTTPS middleware, and shares its /// 10-second default. /// </remarks> public TimeSpan HandshakeTimeout { get; set { if (value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveTimeSpanRequired); } field = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue; } } = HttpsConnectionAdapterOptions.DefaultHandshakeTimeout; /// <summary> /// The HTTP protocols (ALPN) advertised for this endpoint, /// sourced from <see cref="ListenOptions.Protocols"/> after the endpoint has been configured. /// </summary> internal HttpProtocols HttpProtocols { get; set; } = HttpProtocols.Http1AndHttp2; }