In your .NET web application, web API, or HTTP client, for each request, you can know, just by reading a header, what key exchange group is negotiated. Based on this, you know if PQC is used in the request, which means you're protected against attacks from quantum computers. Supports both server-side (web APIs/applications) and client-side (HttpClient) scenarios.
$ dotnet add package ConnectingApps.PqcTracerTrace if your web requests are quantum-proof.
Quantum computers pose an existential threat to current encryption. Algorithms like RSA and elliptic-curve cryptography (used in today's TLS connections) can be broken by sufficiently powerful quantum computers using Shor's algorithm. This means data encrypted today could be harvested and decrypted in the future—a threat known as "harvest now, decrypt later".
To protect against this, the industry is transitioning to Post-Quantum Cryptography (PQC). ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism), formerly known as Kyber, is one of the algorithms standardized by NIST for quantum-resistant key exchange. When you see MLKEM in your TLS negotiation (e.g., X25519MLKEM768), your connection is using a hybrid key exchange that combines classical and post-quantum algorithms—making it resistant to both current and future quantum attacks.
You need to know which of your connections are already quantum-safe. PqcTracer makes this visible for both incoming and outgoing HTTPS traffic.
Install the NuGet package from nuget.org/packages/ConnectingApps.PqcTracer:
dotnet add package ConnectingApps.PqcTracerPqcTracer provides two extension methods you need to call:
| Method | Purpose |
|---|---|
TraceTlsConnection() | Configures Kestrel to capture TLS negotiation details (key exchange group & cipher suite) |
UseTlsTraceHeaders() | Adds middleware that exposes the captured info as response headers |
Here's a complete Program.cs showing how to integrate PqcTracer:
using ConnectingApps.PqcTracer;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.WebHost.TraceTlsConnection();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var app = builder.Build();
app.UseTlsTraceHeaders();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
public partial class Program { }After integrating PqcTracer, every HTTPS response includes two headers:
X-Tls-Cipher: TLS_AES_256_GCM_SHA384
X-Tls-Group: X25519MLKEM768
X-Tls-Group: The key exchange algorithm used. If it contains MLKEM, your connection is quantum-resistant.X-Tls-Cipher: The symmetric cipher suite negotiated for the session.PqcTracer can also trace TLS details for outgoing HTTPS requests made via HttpClient. There are two ways to use this functionality:
Use TlsTracingHandler directly when creating your HttpClient:
using ConnectingApps.PqcTracer;
using var handler = new TlsTracingHandler();
using var client = new HttpClient(handler);
try
{
using var response = await client.GetAsync("https://www.google.com");
response.EnsureSuccessStatusCode();
var trace = response.GetTlsTrace();
if (trace != null)
{
Console.WriteLine($"Negotiated Group: {trace.Group}");
Console.WriteLine($"Cipher Suite: {trace.CipherSuite}");
}
else
{
Console.WriteLine("TLS Trace not found.");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}Register HttpClient via dependency injection and use the AddTlsTracing() extension method:
using ConnectingApps.PqcTracer;
using Microsoft.Extensions.DependencyInjection;
// Register the HttpClient via DI
var services = new ServiceCollection();
services.AddHttpClient("GoogleClient").AddTlsTracing();
var serviceProvider = services.BuildServiceProvider();
// Resolve IHttpClientFactory from the service provider
var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
// Create the client using the factory
using var client = httpClientFactory.CreateClient("GoogleClient");
try
{
using var response = await client.GetAsync("https://www.google.com");
response.EnsureSuccessStatusCode();
var trace = response.GetTlsTrace();
if (trace != null)
{
Console.WriteLine($"Negotiated Group: {trace.Group}");
Console.WriteLine($"Cipher Suite: {trace.CipherSuite}");
}
else
{
Console.WriteLine("TLS Trace not found.");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}Both approaches produce the same output. The DI approach is recommended for production applications as it integrates better with ASP.NET Core's service container and enables features like named/typed clients, policies, and lifetime management.
Example Output (on a system with OpenSSL 3.0, which lacks PQC support):
Negotiated Group: x25519
Cipher Suite: TLS_AES_256_GCM_SHA384
Note: The output shows
x25519instead ofX25519MLKEM768because OpenSSL 3.0 does not support ML-KEM. You need OpenSSL 3.5.0 or later for post-quantum key exchange.
⚠️ Linux Only: PqcTracer currently only works on Linux. It uses P/Invoke calls to
libssl.so.3(OpenSSL 3.x) to query the negotiated TLS group directly from the SSL context.
For PQC support (ML-KEM), you need OpenSSL 3.5.0 or later installed on your system.
TraceTlsConnection() hooks into Kestrel's TLS authentication callback to intercept the SslStream after handshake completionSSL_ctrl to get the negotiated group ID, then converts it to a human-readable name using SSL_group_to_nameUseTlsTraceHeaders() middleware reads these values and adds them to every HTTP responseTlsTracingHandler implements a custom ConnectCallback for SocketsHttpHandlerSslStream using the same OpenSSL P/Invoke callsHttpRequestMessage.Options dictionaryGetTlsTrace() extension method retrieves the trace from the responseThis project is licensed under the GPL-3.0 License. See the LICENSE file for details.
Built by Connecting Apps and QuantumSafeAudit.com