Résumé
- ALPN transporte une offre ordonnée d’identifiants opaques et permet au serveur de retenir une valeur commune. Cette sélection régit les données applicatives de la connexion TLS concernée, pas une autre liaison ni une propriété durable du service.
- Un proxy de terminaison prend deux rôles : serveur en aval, nouveau client en amont. HTTP/2 en aval et HTTP/1.1 en amont peuvent être simultanément corrects ; les deux négociations exigent des preuves distinctes.
- Le registre IANA, la configuration et un rappel installé décrivent des possibilités. La preuve d’exécution associe offre, sélection ou alerte, rappel invoqué, fin de négociation et démarrage applicatif à un identifiant de connexion.
L’incident n’était pas la conversion de protocole
Sur la première liaison, tout était cohérent. ClientHello annonçait deux protocoles. En TLS 1.3, EncryptedExtensions retenait h2, puis Finished authentifiait la transcription. Les préfaces HTTP/2 et les SETTINGS confirmaient le démarrage effectif.
L’origine n’était pourtant pas la paire de cette connexion. Le point de présence avait déchiffré le trafic, puis ouvert une nouvelle liaison avec d’autres clés et une autre politique. En amont, http/1.1 pouvait être choisi, ou ALPN être absent et le proxy appliquer un repli explicite.
La conversion peut être une architecture saine. L’erreur vient du modèle d’observation qui a supprimé l’identifiant aval, le point de terminaison et l’identifiant amont avant d’écrire h2 dans la fiche de l’origine. Une vérité locale est devenue une affirmation topologique sans preuve.
Des octets exacts, pas des étiquettes souples
L’IANA attribue la valeur 16 à application_layer_protocol_negotiation. RFC 7301 décrit chaque nom de protocole comme une chaîne opaque de 1 à 255 octets, précédée de sa longueur. Une entrée vide ou tronquée est invalide.
Une interface ne doit donc ni changer la casse, ni raccourcir, ni rapprocher des valeurs semblables. HTTP/2 sur TLS porte exactement h2, soit deux octets. RFC 9113 interdit h2c dans l’offre ou la sélection ALPN sur TLS.
L’ordre du client exprime sa préférence, mais le serveur choisit dans l’intersection selon sa politique. Voir h2 en première position ne prouve pas qu’il a été retenu. Voir h2 dans un fichier de configuration ne prouve pas que le contexte appliqué à cette connexion l’a utilisé.
Sans valeur commune, RFC 7301 impose l’alerte fatale no_application_protocol. RFC 9325 soutient ce comportement strict contre la confusion inter-protocoles. Un serveur ne peut pas répondre avec une valeur non offerte puis prétendre avoir négocié.
Une chaîne de preuves, palier par palier
La sélection est définitive pour les données de la même connexion. Après avoir choisi h2, un serveur ne peut pas interpréter ce flux en HTTP/1.1. Pour HTTP/2, la préface de connexion et SETTINGS apportent une confirmation après TLS.
Il faut conserver plusieurs résultats : l’offre émise, la valeur répondue, l’authentification de la négociation par Finished, la préface comprise, puis l’échange applicatif. Une capture de ClientHello n’est pas une négociation terminée. Un ALPN réussi sans préface valide n’est pas un service HTTP/2 fonctionnel.
Cette portée ne s’étend pas dans le temps. RFC 9113 avertit qu’un support passé n’est pas un indicateur fort pour une prochaine connexion : instances, configuration et réseau évoluent. Le bon sujet de preuve reste la connexion.
Deux connexions, deux autorités
Le proxy est serveur TLS vis-à-vis du navigateur et client TLS vis-à-vis de l’origine. Chaque rôle produit sa propre offre, sa propre sélection, ses alertes et sa version de politique.
La documentation Envoy matérialise ce choix. Une grappe amont peut reprendre explicitement le protocole aval, négocier indépendamment HTTP/1.1 ou HTTP/2 par ALPN, ou revenir à HTTP/1.1 si ALPN manque en amont. La continuité n’est donc pas une propriété implicite : c’est un comportement configuré puis observé.
Un tunnel est encore un autre cas. L’intermédiaire peut n’être qu’un relais d’octets et ne jamais connaître la sélection TLS intérieure. Le champ HTTP défini par RFC 7639 peut annoncer les protocoles prévus dans CONNECT, mais une intention ne vaut pas négociation intérieure accomplie.
Le journal doit garder deux tuples — aval et amont — reliés par un événement nommé de terminaison, traduction ou tunnel. Cette relation n’autorise pas la fusion de leurs protocoles.
Les pièges d’une preuve réduite à la configuration
Dans OpenSSL, une liste client de longueur nulle supprime l’extension ALPN. Si ClientHello ne propose rien, le rappel de sélection du serveur n’est pas appelé. « Rappel installé » et « rappel exécuté » sont deux états.
Le rappel servername s’exécute d’abord et peut remplacer SSL_CTX; ALPN utilise ensuite le contexte obtenu. Un inventaire global peut donc ne pas correspondre à la politique du nom virtuel qui a réellement servi la connexion.
La valeur retournée doit provenir du vecteur client. SSL_get0_alpn_selected livre un pointeur emprunté, non terminé par NUL, avec une longueur explicite. Le traiter comme une chaîne ordinaire peut tronquer ou altérer l’identifiant.
Le test négatif le plus parlant concerne SSL_select_next_proto. Sans recouvrement, l’aide place tout de même la première valeur client dans la sortie et renvoie OPENSSL_NPN_NO_OVERLAP. OpenSSL exige que la sortie soit ignorée pour ALPN. Journaliser avant d’examiner le code de retour fabrique une sélection inexistante.
Il faut aussi distinguer absence, encodage invalide, aucun recouvrement, NOACK sans sélection, échec du rappel et sélection réussie. Un seul booléen efface l’origine de l’échec.
Reprise et données précoces ne changent pas le propriétaire
RFC 7301 fait d’ALPN une propriété de connexion, non de session. Lors d’une reprise, les anciennes valeurs sont sans effet ; les nouveaux messages de négociation décident.
Un ticket émis pendant une période où h2 était actif ne garantit donc rien sur une instance ou une génération ultérieure. Copier l’ancienne valeur dans la nouvelle ligne de télémétrie crée une capacité fantôme.
Pour TLS 1.3, la PSK associe des paramètres aux données 0-RTT, dont ALPN. Le serveur ne peut accepter ces données que si la nouvelle sélection correspond. Si elles sont refusées et que le protocole final diffère, l’application peut devoir reconstruire le message.
RFC 9846 interdit ainsi à la couche TLS de renvoyer automatiquement les données précoces lorsque l’ALPN final n’est pas identique. Seule l’application connaît l’encodage et la sémantique nécessaires.
Choisir un protocole ne vérifie ni l’identité ni le droit
ALPN répond à la question « comment parler sur cette connexion ». La validation du certificat et la correspondance d’identité de service répondent à « avec qui ». L’autorisation applicative répond ensuite à « pour quelle action ».
HTTP/3 illustre cette séparation : h3 est normalement choisi pendant TLS sur QUIC, mais RFC 9114 exige aussi un certificat acceptable pour l’origine de l’URI. Une sélection h3 valide ne rend pas autoritaire un serveur dont l’identité échoue.
L’IANA fournit enfin un vocabulaire interopérable, pas une carte de déploiement. Une entrée enregistrée, du code compilé ou une configuration disponible ne prouvent ni offre ni sélection. Le dernier mot appartient à la connexion exécutée et à l’analyseur applicatif qui a réellement démarré.
Épreuves négatives à conserver
Faire proposer h2,http/1.1, puis laisser le serveur préférer http/1.1 : le journal doit retenir la sélection, pas la première offre. Répondre avec une valeur absente de l’offre doit interrompre la négociation.
Envoyer un ClientHello sans ALPN et confirmer que le rappel ne s’exécute pas. Produire séparément no_application_protocol et un NOACK volontaire. Déclencher le piège OPENSSL_NPN_NO_OVERLAP sans laisser sa sortie devenir une sélection.
Changer SSL_CTX pendant le traitement du nom de serveur et attribuer le résultat à la bonne génération. Négocier h2 en aval et HTTP/1.1 en amont, avec deux identifiants de connexion. Reprendre une session après changement de politique sans copier l’ancienne valeur. Refuser des données précoces lorsque l’ALPN final change.
Enfin, réussir ALPN tout en échouant l’identité du certificat, puis réussir les deux tout en refusant l’action. Si ces résultats restent séparés, le système respecte enfin l’autorité limitée de chaque couche.
Sources
- https://www.rfc-editor.org/rfc/rfc7301.html
- https://www.rfc-editor.org/rfc/rfc9846.html
- https://www.rfc-editor.org/rfc/rfc9113.html
- https://www.rfc-editor.org/rfc/rfc9114.html
- https://www.rfc-editor.org/rfc/rfc9001.html
- https://www.rfc-editor.org/rfc/rfc9525.html
- https://www.rfc-editor.org/rfc/rfc9325.html
- https://www.rfc-editor.org/rfc/rfc7639.html
- https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
- https://docs.openssl.org/3.6/man3/SSL_CTX_set_alpn_select_cb/
- https://www.gnutls.org/manual/html_node/Application-Layer-Protocol-Negotiation-_0028ALPN_0029.html
- https://boringssl.googlesource.com/boringssl/+/HEAD/include/openssl/ssl.h
- https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/upstreams/http/v3/http_protocol_options.proto.html
- https://heng.lu/running-code-primary-the-patch-needed-to-preserve-the-internet-original-design/
Briefing des membres
Contexte approfondi du profil
Connectez-vous avec le bon niveau d'adhésion pour débloquer le briefing complet et les notes de source.
Réservé à Strategic Circle
Strategic Circle
Ouvert à tous les lecteurs. Débloquez les briefings de profil après adhésion et connexion.
Rejoindre Strategic CircleRéservé aux membres de Leadership Alliance
Leadership Alliance
Réservé aux propriétaires et dirigeants qualifiés d'actifs IP ; connectez-vous pour débloquer les briefings Alliance.
Rejoindre Leadership Alliance
