Scenario 10.4: Hybrid TLS

Category: TLS/mTLS
Complexity: ⭐⭐⭐⭐⭐ (Very High)
Prerequisites: OpenSSL 3.6+, PQ certificates
Estimated Time: 45-60 Minutes


Description

This scenario describes Hybrid TLS - the combination of classical and Post-Quantum algorithms in the TLS handshake for maximum security during the transition phase.

Hybrid Approaches:

  • Hybrid Key Exchange - X25519 + ML-KEM-768
  • Hybrid Signature - ECDSA + ML-DSA-65
  • Dual Certificates - Classical + PQ certificate

Why Hybrid? If one algorithm is broken (classical by quantum computers, PQ by new attacks), the connection remains secure through the other.


TLS 1.3 Hybrid Key Exchange

sequenceDiagram participant Client participant Server Client->>Server: ClientHello + key_share(X25519 + ML-KEM-768) Server->>Client: ServerHello + key_share(X25519 + ML-KEM-768) Note over Client,Server: Combine both shared secrets Client->>Server: Finished Server->>Client: Finished Note over Client,Server: Hybrid-secured connection


Code Example: Hybrid TLS with OpenSSL 3.6

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Runtime.InteropServices;
 
// OpenSSL 3.6 Hybrid Groups for Key Exchange
public static class HybridTlsConfig
{
    // Hybrid Key Exchange Groups (OpenSSL 3.6+)
    public const string HYBRID_X25519_MLKEM768 = "x25519_mlkem768";
    public const string HYBRID_SECP384R1_MLKEM768 = "secp384r1_mlkem768";
    public const string HYBRID_SECP256R1_MLKEM512 = "secp256r1_mlkem512";
 
    [DllImport("libssl")]
    private static extern int SSL_CTX_set1_groups_list(IntPtr ctx, string groups);
 
    public static void ConfigureHybridKeyExchange(IntPtr sslContext)
    {
        // Configure hybrid groups (preference order)
        var groups = $"{HYBRID_X25519_MLKEM768}:{HYBRID_SECP384R1_MLKEM768}:X25519:secp384r1";
 
        int result = SSL_CTX_set1_groups_list(sslContext, groups);
        if (result != 1)
        {
            throw new CryptographicException("Failed to configure hybrid key exchange");
        }
    }
}

ASP.NET Core Hybrid TLS Server

using Microsoft.AspNetCore.Server.Kestrel.Core;
using System.Security.Authentication;
 
var builder = WebApplication.CreateBuilder(args);
 
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(443, listenOptions =>
    {
        listenOptions.UseHttps(httpsOptions =>
        {
            // Hybrid certificate (ML-DSA + ECDSA)
            httpsOptions.ServerCertificate = LoadHybridCertificate();
 
            // Enforce TLS 1.3 (prerequisite for hybrid)
            httpsOptions.SslProtocols = SslProtocols.Tls13;
 
            // OpenSSL configuration for hybrid key exchange
            httpsOptions.OnAuthenticate = (context, sslOptions) =>
            {
                // Cipher suites for TLS 1.3
                sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(new[]
                {
                    TlsCipherSuite.TLS_AES_256_GCM_SHA384,
                    TlsCipherSuite.TLS_CHACHA20_POLY1305_SHA256
                });
 
                // Application-Layer Protocol Negotiation
                sslOptions.ApplicationProtocols = new List<SslApplicationProtocol>
                {
                    SslApplicationProtocol.Http2,
                    SslApplicationProtocol.Http11
                };
            };
        });
 
        listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
    });
});
 
X509Certificate2 LoadHybridCertificate()
{
    using var ctx = PqCryptoContext.Initialize();
 
    // Dual certificate with both algorithms
    var cert = ctx.LoadCertificateWithPrivateKey(
        "server-hybrid.crt.pem",
        "server-hybrid.key.pem",
        "Password!"
    );
 
    return cert;
}

Create Hybrid Certificate

public class HybridCertificateBuilder
{
    public X509Certificate2 CreateHybridServerCertificate(
        X509Certificate2 caCert,
        AsymmetricAlgorithm caKey,
        string[] dnsNames)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Dual Key: ECDSA + ML-DSA
        using var ecdsaKey = ECDsa.Create(ECCurve.NamedCurves.nistP384);
        using var mlDsaKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
        var dn = new DnBuilder()
            .AddCN(dnsNames[0])
            .AddO("Example GmbH")
            .Build();
 
        // CSR with both keys
        var csr = ctx.CreateHybridCertificateRequest(
            classicalKey: ecdsaKey,
            pqKey: mlDsaKey,
            subject: dn,
            extensions: new ExtBuilder()
                .SubjectAlternativeName(dnsNames.Select(d => $"dns:{d}").ToArray())
                .Build()
        );
 
        // Issue hybrid certificate
        var cert = ctx.IssueHybridCertificate(
            csr,
            issuerCert: caCert,
            issuerKey: caKey,
            validDays: 365,
            extensions: new ExtBuilder()
                .BasicConstraints(ca: false, critical: true)
                .KeyUsage(KeyUsageFlags.DigitalSignature | KeyUsageFlags.KeyEncipherment)
                .ExtendedKeyUsage(ExtKeyUsage.ServerAuth)
                .SubjectKeyIdentifier(mlDsaKey.PublicKey)
                .AuthorityKeyIdentifier(caCert)
                // Hybrid-specific extension
                .AddCustomExtension(
                    oid: "1.3.6.1.4.1.99999.1.1",  // Example OID
                    critical: false,
                    value: "hybrid:ecdsa-p384+ml-dsa-65"
                )
                .Build()
        );
 
        return cert;
    }
}

Nginx with OpenSSL 3.6 Hybrid

server {
    listen 443 ssl http2;
    server_name www.example.com;
 
    # Hybrid certificate
    ssl_certificate     /etc/nginx/ssl/server-hybrid-chain.pem;
    ssl_certificate_key /etc/nginx/ssl/server-hybrid.key.pem;
 
    # TLS 1.3 only
    ssl_protocols TLSv1.3;
 
    # Hybrid Key Exchange Groups (OpenSSL 3.6+)
    ssl_ecdh_curve x25519_mlkem768:secp384r1_mlkem768:X25519:secp384r1;
 
    # Signature Algorithms (Hybrid)
    ssl_conf_command SignatureAlgorithms ed25519:ecdsa_secp384r1_sha384:mldsa65:hybrid_mldsa65_ecdsa_p384;
 
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
 
    location / {
        proxy_pass http://backend:8080;
    }
}

Hybrid Client Configuration

public HttpClient CreateHybridTlsClient()
{
    var handler = new SocketsHttpHandler
    {
        SslOptions = new SslClientAuthenticationOptions
        {
            EnabledSslProtocols = SslProtocols.Tls13,
 
            // Cipher suites (TLS 1.3 default good)
            CipherSuitesPolicy = new CipherSuitesPolicy(new[]
            {
                TlsCipherSuite.TLS_AES_256_GCM_SHA384,
                TlsCipherSuite.TLS_CHACHA20_POLY1305_SHA256
            }),
 
            RemoteCertificateValidationCallback = (sender, certificate, chain, errors) =>
            {
                if (errors != SslPolicyErrors.None)
                {
                    Console.WriteLine($"TLS Error: {errors}");
                    return false;
                }
 
                // Verify hybrid signature
                if (certificate is X509Certificate2 cert2)
                {
                    var algorithm = cert2.SignatureAlgorithm.FriendlyName;
                    Console.WriteLine($"Server Signature Algorithm: {algorithm}");
 
                    // Check if PQ algorithm is used
                    if (!algorithm.Contains("ML-DSA") && !algorithm.Contains("hybrid"))
                    {
                        Console.WriteLine("WARNING: Server is not using PQ certificate");
                    }
                }
 
                return true;
            }
        }
    };
 
    return new HttpClient(handler);
}

Fallback Strategy

public class HybridTlsClientWithFallback
{
    public async Task<HttpResponseMessage> GetWithFallback(string url)
    {
        // Attempt 1: Hybrid TLS
        try
        {
            using var hybridClient = CreateHybridTlsClient();
            return await hybridClient.GetAsync(url);
        }
        catch (AuthenticationException ex) when (IsHybridNotSupported(ex))
        {
            Console.WriteLine("Hybrid TLS not supported, falling back to classic...");
        }
 
        // Fallback: Classic TLS 1.3
        using var classicClient = CreateClassicTlsClient();
        return await classicClient.GetAsync(url);
    }
 
    private bool IsHybridNotSupported(Exception ex)
    {
        return ex.Message.Contains("no common signature algorithm") ||
               ex.Message.Contains("unsupported group");
    }
 
    private HttpClient CreateClassicTlsClient()
    {
        var handler = new HttpClientHandler
        {
            SslProtocols = SslProtocols.Tls13
        };
        return new HttpClient(handler);
    }
}

Compatibility Matrix

Component Hybrid Key Exchange Hybrid Signature
OpenSSL 3.6+
BoringSSL ✅ (experimental)
Windows SChannel ❌ (not yet)
NSS (Firefox) ✅ (ML-KEM)
.NET 9+ ✅ (with OpenSSL)

Industry-Specific Hybrid Requirements

Industry Timeline Requirement
BSI TR-02102 From 2025 Hybrid recommended
NIST From 2024 ML-KEM for key exchange
Financial (PCI) 2025-2027 PQ migration roadmap
Government From 2025 Hybrid mandatory (US NSA CNSA 2.0)

Relationship Scenario Description
Prerequisite 10.1 TLS Server Basic setup
Prerequisite 10.3 mTLS Deployment mTLS infrastructure
Related 7.2 Key Encapsulation ML-KEM
Related Algorithms PQ fundamentals

« ← 10.3 mTLS Deployment | ↑ TLS Overview | → All Scenarios »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: on 2026/01/30 at 06:51 AM