ASP.NET, Kestrel and Schannel GA with TLS 1.3 Post-Quantum Cryptography
Before diving into the main content of this post, there’s an essential update you should know about:
My colleague, Aabha Thipsay has shared an update regarding her June post on Post-Quantum Cryptography (PQC) in Windows. Hybrid TLS, which employs ML-KEM key exchange groups, is now generally available in Windows 11 and Windows Server 2025. This enhancement allows TLS connections to merge traditional and post-quantum key establishment methods, ensuring cryptographic flexibility and safeguarding against future quantum-based attacks.
For further details, feel free to check the update here.
All organisations must upgrade to TLS 1.3 to effectively support post-quantum cryptography for their network data.
Older versions of TLS, like 1.0, 1.1, and even 1.2, neither support nor will they support PQC. TLS 1.0 and 1.1 have already been deprecated, and TLS 1.2 is not far behind.
Moreover, TLS 1.0 and 1.1 are officially deprecated by the IETF as per RFC 8996.
When it comes to securing data during transmission, TLS is the most widely used technology, almost exclusively used to authenticate servers (and optionally clients), while providing encryption and ensuring the integrity of network traffic.
Honestly, SSH comes in a distant second place.
The real beauty of TLS lies in its crypto-agility (which you can learn more about in my previous post here). This flexibility permits a server and client to negotiate a mutually preferred ciphersuite.
To clarify, this blog post will primarily discuss Windows, but I plan to write a follow-up regarding Linux, OpenSSL, and nginx as well. If you’re looking for more technical detail and aren’t concerned about understanding how TLS incorporates PQC and crypto-agility, feel free to skip ahead to the section titled ‘ASP.NET and Kestrel’ where I explain using hybrid TLS 1.3 with ASP.NET and the Kestrel web server.
Going forward, when I mention TLS, I will be referring to TLS 1.3 and its later versions.
The diagram and text below clarify how TLS negotiates a mutually accepted ciphersuite, thus supporting crypto-agility.
Initially, the client (like a web browser) sends a list of supported ciphersuites to the server in a message called ClientHello. This is the first message dispatched by the client during a TLS negotiation.
The server then chooses which ciphersuite to utilise and relays this back in the ServerHello message.
Notably, both the client and server include TLS_AES_256_GCM_SHA384 in their lists, and since it appears first in the server’s preference, the server selects it, even though TLS_AES_128_GCM_SHA256 was listed first by the client.
According to RFC 8446, “The Transport Layer Security (TLS) Protocol Version 1.3” §4.1.1, the choice of ciphersuite is left to the server. The order of the client’s list serves as a suggestion, but many production servers typically overlook this and prefer their own list, picking the first match they find.
If the client and server’s ciphersuite lists do not match at all, generally, the server will send a handshake_failure alert and close the connection.
TLS 1.3 has significantly simplified ciphersuite names compared to previous versions. In TLS 1.2 and earlier, each single ciphersuite name bundled multiple considerations: key exchange algorithm, authentication method, bulk encryption procedure, and hashing function, making them harder to understand and rigid.
TLS 1.3 has refined this model, focusing the ciphersuite on only the symmetric encryption and hashing components—for instance, TLS_AES_256_GCM_SHA384.
Key exchange is negotiated separately through supported_groups and key_share TLS extensions, while authentication is managed via the signature_algorithms TLS extension.
This separation is crucial as it simplifies the protocol’s development, allowing for the introduction of new key exchange mechanisms—such as post-quantum or hybrid methods—without needing to overhaul the entire ciphersuite architecture.
From a PQC standpoint, the ciphersuites utilised by TLS 1.3 remain largely unchanged; it’s the supported groups that matter most. In TLS 1.3, the ClientHello message employs supported_groups, key_share, and signature_algorithms extensions to incorporate PQC algorithms. I’ll keep things light to avoid overwhelming details!
When using hybrid techniques (i.e., PQC plus classical cryptography), the supported_groups and key_share data formats might resemble the following:
The supported_groups order suggests preference, with the most commonly used hybrids (PQC plus classical) listed first, followed by classical groups as a fallback for servers that don’t yet support PQC. As an optimisation, the client also includes a key_share for its preferred choice in the ClientHello—essentially its actual ephemeral public keys—so if the server accepts that group, the handshake is completed in one trip instead of triggering a HelloRetryRequest and another round.
In this instance, the client indicates, “I prefer using hybrid crypto but can fall back to either X25519 or secp256r1 if necessary.” Furthermore, it doesn’t just state this; it proactively sends a key_share, pre-generating and attaching the ephemeral public keys for its top pick (X25519MLKEM768), thus facilitating a one-trip handshake if the server agrees. The fallback options are noted but not pre-calculated, meaning reverting to one of these choices will incur extra time.
The key_share dimensions in the diagram indicate that hybrid is merely two key exchanges merged: the client’s 1216-byte share consists of a 32-byte X25519 public key and a 1184-byte ML-KEM-768 key. The server’s response has a different size as the ML-KEM half presents a ciphertext rather than a matching public key.
It is the server’s responsibility to determine which algorithms to employ, while the client communicates its capabilities via the ClientHello message.
A quick note: the term “group” isn’t arbitrary; it stems from the underlying mathematics (elliptic-curve groups, finite-field multiplicative groups). It’s precise but can be obscure to those unfamiliar with group theory! However, ML-KEM isn’t based on any group; its security relies, in part, on lattice structures, but let’s not get sidetracked!
Now, let’s transition to the core topic—ASP.NET, Kestrel, and PQC.
ASP.NET is Microsoft’s open-source web framework used for creating web applications, APIs, and real-time services on .NET.
Kestrel is a cross-platform, high-performance HTTP[S] server that comes with .NET to manage raw TCP connections and HTTP protocol processes.
ASP.NET and Kestrel work together since Kestrel is the default in-process server that listens for, and manages, HTTP requests directed to ASP.NET.
Here’s a basic example of C# Kestrel code that listens for HTTPS connections:
using System.Net;
using Microsoft.AspNetCore.Connections.Features;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(o => o.ListenAnyIP(8443, l => l.UseHttps()));
var app = builder.Build();
app.MapGet("https://techcommunity.microsoft.com/", (HttpContext ctx) =>
{
var tls = ctx.Features.Get();
return Results.Json(new
{
Timestamp = DateTime.UtcNow,
Protocol = tls?.Protocol.ToString() ?? "Unknown",
CipherSuite = tls?.NegotiatedCipherSuite?.ToString() ?? "Unknown"
});
});
app.Run();This code is well-structured as it doesn’t make assumptions about the TLS version, ciphersuites, or groups. Instead, these configurations are handled outside the application in some form of setup.
In contrast, the anti-pattern for the above code is as follows:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(o => o.ListenAnyIP(8443, l => l.UseHttps(h =>
{
h.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
h.OnAuthenticate = (_, sslOptions) =>
{
sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(new[]
{
TlsCipherSuite.TLS_AES_256_GCM_SHA384,
TlsCipherSuite.TLS_AES_128_GCM_SHA256,
TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
});
};
})));
var app = builder.Build();
This code is NOT crypto-agile and should be deemed an anti-pattern because it hardcodes cryptographic details like TLS versions and ciphersuites, necessitating code changes whenever these configurations need an update. It also won’t guarantee a PQC connection negotiation.
Note: CipherSuitesPolicy is exclusive to Linux. On Windows or macOS, this constructor will trigger a PlatformNotSupportedException—ciphersuites on those platforms are dictated by the OS (SChannel on Windows). However, the TLS protocol restrictions are platform-agnostic.
And now, let’s dive into SChannel!
Windows leverages a component called schannel.dll for TLS communications. As of July 14th, 2026, schannel is now GA with PQC support, as highlighted in Aabha’s recent update.
While this version supports TLS hybrid groups, note that the PQC groups aren’t enabled by default, so you’ll need to configure them yourself.
There are three primary methods to set up schannel:
- Modify the Registry directly
- Use Group Policy
- Employ PowerShell cmdlets
We’ll focus on the third method, yet ultimately, all approaches directly or indirectly modify the Registry.
For a reference on various PowerShell TLS cmdlets, please check this site.
The Get-TlsCipherSuite command displays all supported ciphersuites, regardless of the TLS protocol version. You can disable a ciphersuite using the Disable-TlsCipherSuite command.
What we really aim to do is set a group for PQC, for which we can use the following command:
Enable-TlsEccCurve -Name "X25519_MLKEM768" -Position 0The -position option is vital as it places the hybrid group at the top of the preferred group list. Failing to do so could prevent you from negotiating the hybrid PQC group.
You can verify the setting with the Get-TlsEccCurve command, as shown below:
x25519_mlkem768
curve25519
NistP256
NistP384Now that we’ve established the group, let’s run the server code and connect using a browser such as Edge or Chrome. You can view the connection details under Developer Tools à Security.
This section will display the protocol version (TLS 1.3), the group (X25519MLKEM768), and the ciphersuite (AES_256_GCM).
Additionally, you can use OpenSSL as a client to check the group:
openssl s_client -connect 127.0.0.1:8443 -tls1_3 -brief
Connecting to 127.0.0.1
depth=0 CN=localhost
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=localhost
Hash used: SHA256
Signature type: rsa_pss_rsae_sha256
Negotiated TLS1.3 group: X25519MLKEM768
It’s essential to point out that while the key negotiation process used post-quantum cryptography, the server authentication leveraged a traditional certificate. This design choice addresses an immediate need for encrypted data transmission to counter harvest-now, decrypt-later attacks, where an adversary captures traffic today, hoping to decrypt it years down the line when quantum computing evolves. Authentication represents a different risk; an attacker would need a quantum computer active during the live session to forge a certificate, rather than years later. Therefore, the priority is to secure confidentiality first, through PQC key exchanges, addressing the more pressing threat while the broader ecosystem transitions to PQC certificates.
Post-quantum TLS 1.3 is no longer just theory—you can experiment with it on Windows today. By upgrading your services to TLS 1.3, eliminating hard-coded cryptographic choices in your application code, and allowing SChannel to negotiate hybrid groups like X25519MLKEM768, you can start testing how ASP.NET and Kestrel perform in a quantum-resistant setting. If you build or manage services on Windows, now is the perfect time to grab the latest Windows Insider or preview build, activate the hybrid TLS group, run your Kestrel workloads, and examine the negotiated connections. The best way to prepare for post-quantum cryptography is to start testing it today.
As always, I want to extend a huge thank you to everyone who reviewed drafts of this post and offered valuable input and suggestions.
Aabha Thipsay – Windows Security
Jessica Krynitsky – Windows Security
Andrei Popov – Windows Security
Barry Dorrans – .NET Security
Jeremy Barton – .NET Security
Raul Garcia – Microsoft Crypto Board
Share this content:
Discover more from Qureshi
Subscribe to get the latest posts sent to your email.