<?xml version="1.0" encoding="utf-8"?>
<rfcdesc title="Post-Quantum Traditional (PQ/T) Hybrid Key Agreement Mechanisms for TLS 1.3" num="10024" status="standards" wg="tls">
  <authors><author>K. Kwiatkowski (PQShield)</author><author>P. Kampanakis (AWS)</author><author>B. E. Westerbaan (Cloudflare)</author><author>D. Stebila (University of Waterloo)</author></authors>
  <rfcdate><month>August</month><year>2026</year></rfcdate>
  <date>2026-08-20</date>
<content>
  <p>On met du <wikipedia name="Cryptographie
  post-quantique">post-quantique</wikipedia> partout en ce moment. Ce
  court <wikipedia name="Request for comments">RFC</wikipedia>
  normalise l'utilisation de clés hybrides (post-quantiques et
  traditionnelles) dans les <wikipedia name="Échange de clé">échanges de clés</wikipedia> de
  <wikipedia name="Transport Layer Security">TLS</wikipedia>.</p>
  <p>Les trois mécanismes normalisés dans ce <wikipedia name="Request
  for comments">RFC</wikipedia> utilisent tous
  <wikipedia xml:lang="en" name="Kyber">ML-KEM</wikipedia>, qui est normalisé dans <link
  url="https://csrc.nist.gov/pubs/fips/203/final">FIPS-203</link>. ML-KEM
  repose sur <wikipedia name="Réseau (géométrie)">les réseaux euclidiens</wikipedia> et les
  experts en <wikipedia>cryptographie</wikipedia> ne sont pas sûrs à
  100 % de sa sécurité. Dans le doute, il est donc recommandé de
  l'utiliser combiné avec un algorithme traditionnel, comme décrit
  dans le <rfc num="9954"
  local="true"/>. Ainsi, on est protégé à la fois contre les futurs
  CRQC (<foreign>Cryptographically-Relevant Quantum
  Computer</foreign>) et contre la <wikipedia>cryptanalyse</wikipedia>
  plus classique. Les principes de cette méthode hybride sont décrits
  en détail dans le <rfc num="9794" local="true"/> et le <rfc
  num="9954" local="true"/> déjà
  cité.</p>
  <p>Les trois mécanismes d'<link local="echange-cles">échange de clés</link> pour <wikipedia
  name="Transport Layer Security">TLS</wikipedia> normalisés ici (et
  qui sont appelés « groupes » pour des raisons historiques) sont :
  <enum>
    <item>X25519MLKEM768, qui combine l'algorithme traditionnel
    <wikipedia name="Cryptographie sur les courbes elliptiques">à
    courbes elliptiques</wikipedia> X25519 (<rfc num="7748"
    local="true"/>) avec ML-KEM, et qui est le mécanisme recommandé.</item>
    <item>SecP256r1MLKEM768, qui combine SecP256 (norme <link
    url="https://csrc.nist.gov/pubs/fips/186-5/final">FIPS-186</link>,
    donc une courbe elliptique différente, la P256) avec ML-KEM, et
    qui a l'avantage ou l'inconvénient de n'utiliser que des
    algorithmes <wikipedia name="National Institute of Standards and
    Technology">NIST</wikipedia>.</item>
    <item>SecP384MLKEM1024, proche du précédent mais avec des clés
    plus longues et une courbe elliptique différente, avec normalement
    davantage de sécurité.</item>
  </enum>
  Pour les trois mécanismes traditionnels, avec des courbes
  elliptiques, l'algorithme <wikipedia name="Échange de clés
  Diffie-Hellman basé sur les courbes elliptiques">ECDH</wikipedia>
  est utilisé.</p>
  <p>Pour réaliser l'<wikipedia name="Échange de clé">échange de clés</wikipedia> au début
  d'une session <wikipedia name="Transport Layer
  Security">TLS</wikipedia>, on fait tourner le mécanisme traditionnel
  <emphasis>et</emphasis> le post-quantique, et on concatène les deux
  clés. (Oui, je simplifie, que les experts en cryptographie
  m'excusent, la sortie d'ECDH utilisée n'est pas vraiment la clé.) On
  notera que, pour X25519MLKEM768, la clé faite via ML-KEM fait 1 184
  octets et celle d'ECDH seulement 32 octets ; c'est un problème avec
  beaucoup d'algorithmes post-quantiques, dont les clés et les
  signatures sont très longues. (Et, oui, on n'utilise pas directement
  ces « clés » mais un dérivé.)</p>
  <p>Si on se soucie de conformité plutôt que de sécurité, on lira
  avec bonheur la section 5 du RFC, qui décrit en détail la conformité
  de ce RFC avec les règles <wikipedia name="Federal Information Processing Standard">FIPS</wikipedia> (c'est surtout
  utile si vous travaillez pour le gouvernement étatsunien).</p>
  <p>Et si vous vous intéressez aux débats sur la sécurité de ML-KEM
  et sur le concept même d'hybride, parmi les nombreux articles
  publiés, je vous recommande <link
  url="https://keymaterial.net/2025/11/27/ml-kem-mythbusting/">celui
  de Sophie Schmieg</link>.</p>
  <p>Les trois mécanismes d'échange de clés ont été <link
  url="https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8">ajoutés
  au registre IANA</link>, avec respectivement les numéros 4588, 4587
  et 4589.</p>
  <p>Voici, vus par <wikipedia name="Mozilla
  Firefox">Firefox</wikipedia> (« Outils de développement Web » puis
  « Réseau » puis « Sécurité », tout au bout), les algorithmes
  cryptographiques utilisés avec un serveur <wikipedia name="HyperText
  Transfer Protocol Secure">HTTPS</wikipedia> qui accepte un des
  mécanismes de notre RFC. Il y a en tout trois éléments à la liste
  car il faut trois choses pour faire du TLS :
  <enum>
    <item>Un algorithme d'échange de clés (c'est le sujet de ce RFC),
    ici mlkem768x25519 (X25519MLKEM768 dans le RFC, c'est aussi ce
    qu'afficherait <wikipedia name="Google Chrome">Chrome</wikipedia>),</item>
    <item>Un algorithme d'<wikipedia>authentification</wikipedia> via
    une <wikipedia name="Signature numérique">signature</wikipedia>, ici RSA-PSS-SHA256 (c'est
    l'algorithme que vous trouverez dans le
    <wikipedia name="Certificat électronique">certificat</wikipedia>),</item>
    <item>Un algorithme pour le <wikipedia name="Cryptographie symétrique">chiffrement
    symétrique</wikipedia>, une fois que les clés de session auront
    été échangées, ici <wikipedia name="Salsa20" anchor="ChaCha">ChaCha20</wikipedia> avec
    <wikipedia xml:lang="en">Poly1305</wikipedia>.</item>
  </enum>
  Seul le premier des trois cités inclut du post-quantique. RSA
  pourrait faire l'échange de clés (une des parties génère une clé de
  session et la chiffre avec RSA avant de l'envoyer) et la signature
  mais ML-KEM ne sait faire que l'échange de clés.
  <image name="firefox-pq-2.png"/></p>
  <p>À part Firefox, <wikipedia name="Google Chrome">Chrome</wikipedia> gère ces nouveaux
  mécanismes (qui sont déjà dans plusieurs
  <wikipedia name="Bibliothèque logicielle">bibliothèques</wikipedia> de cryptographie, cf. par
  exemple <link
  url="https://developers.cloudflare.com/ssl/post-quantum-cryptography/pqc-support/">la
  liste de Cloudflare</link>), ainsi que des hébergeurs comme
  <wikipedia>Cloudflare</wikipedia> ou
  <wikipedia name="Amazon Web Services">AWS</wikipedia>. Voici une connexion vue par Chrome :
  <image name="chrome-pq.png"/></p>
  <p>Jouons un peu avec <wikipedia>OpenSSL</wikipedia> maintenant. On
  va utiliser la version qui est dans <wikipedia>Debian</wikipedia>
  stable. D'abord, créons un certificat pour <wikipedia name="Elliptic
  curve digital signature algorithm">ECDSA</wikipedia> :
  <code>
% openssl version
OpenSSL 3.5.4 30 Sep 2025 (Library: OpenSSL 3.5.4 30 Sep 2025)

% openssl ecparam -out server.pem -name prime256v1 -genkey

% openssl req -new -key server.pem  -nodes -out server.csr
…
Country Name (2 letter code) [AU]:FR
…

% openssl x509 -in server.csr -out server.crt -req -signkey server.pem -days 2001
Certificate request self-signature ok
subject=C=FR…
  </code>
  Maintenant qu'on a le certificat, lançons le serveur en lui disant
  qu'on accepte d'échanger les clés en X25519MLKEM768 (et qu'on écoute
  sur le <wikipedia name="Port (logiciel)">port</wikipedia> 12345) :
  <code>
% openssl s_server -tls1_3 -groups X25519MLKEM768 -accept 12345 -cert server.crt -key server.pem 
  </code>
  Firefox va pouvoir s'y connecter et affichera :
  <code>
Version du protocole :	"TLSv1.3"
Suite de chiffrement :	"TLS_AES_128_GCM_SHA256"
Groupe d’échange de clés :	"mlkem768x25519"
Algorithme de signature :	"ECDSA-P256-SHA256"  
  </code>
  Le serveur OpenSSL annonce quant à lui :
  <code>
Shared ciphers:TLS_AES_128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA
Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA1:RSA+SHA1
Shared Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512
Supported groups: X25519MLKEM768:x25519:secp256r1:secp384r1:secp521r1:ffdhe2048:ffdhe3072
Shared groups: X25519MLKEM768
CIPHER is TLS_AES_128_GCM_SHA256
 </code>  
  À noter que si on avait lancé le serveur avec <computer>-groups
  MLKEM768</computer>, Firefox ne pouvait se connecter (<foreign>no
  suitable key share</foreign>) puisqu'il ne gère pas ML-KEM seul,
  uniquement dans un contexte hybride (ML-KEM et ECDH-X25519). L'usage
  de ML-KEM seul est décrit dans l'<foreign><wikipedia xml:lang="en" name="Internet Draft">Internet
  draft</wikipedia></foreign> <computer><link
  url="https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/">draft-ietf-tls-mlkem</link></computer>. Et
  si vous voulez connaitre tous les mécanismes d'échange de clés de
  votre installation d'OpenSSL :
  <code>
% openssl list -kem-algorithms 
  { 1.2.840.113549.1.1.1, 2.5.8.1.1, RSA, rsaEncryption } @ default
  { 1.2.840.10045.2.1, EC, id-ecPublicKey } @ default
  { 1.3.101.110, X25519 } @ default
  { 1.3.101.111, X448 } @ default
  { 2.16.840.1.101.3.4.4.1, id-alg-ml-kem-512, ML-KEM-512, MLKEM512 } @ default
  { 2.16.840.1.101.3.4.4.2, id-alg-ml-kem-768, ML-KEM-768, MLKEM768 } @ default
  { 2.16.840.1.101.3.4.4.3, id-alg-ml-kem-1024, ML-KEM-1024, MLKEM1024 } @ default
  X25519MLKEM768 @ default
  X448MLKEM1024 @ default
  SecP256r1MLKEM768 @ default
  SecP384r1MLKEM1024 @ default
  </code>
  (Pour ceux de signature, c'est <computer>openssl list
  -signature-algorithms</computer> et, logiquement, on n'y trouve pas ML-KEM.)</p>
  <p>Et dans <wikipedia>curl</wikipedia> ? Je n'ai pas testé mais
  <link url="https://github.com/curl/everything-curl/blob/master/usingcurl/tls/post-quantum.md">normalement ceci marche</link> :
  <code>
curl -v --curves X25519MLKEM768 https://example.com
  </code>
  </p>
  </content>
</rfcdesc>
