ADR-109 — Certificats SSH (utilisateur + hôte) et autorité de certification : format wire couche 2, CA orchestrée, révocation
Statut : Accepté (2026-07-26, décision BDFL). RFC de direction
(ADR-015).
S’appuie sur ADR-108
(air-keystore : matériel de clé, magasin scellé, révocation, face air-keysign),
ADR-091 (motif réseau sans-IO — cœur pur fuzzable),
ADR-093 (transport SSH-2, air-ssh-proto),
ADR-094 (userauth publickey), ADR-034
(air-crypto = primitives pures), ADR-029
(nommage), ADR-089 (SecurityManager
politique).
Compagnon d’ [ADR-108] : celui-là détient le matériel de clé ; celui-ci définit le
format de certificat et l’orchestration CA/vérification.
Catégorie : Architecture couche 2 (capacité air-ssh-proto) + orchestration.
Vague 1 #2 du triage des écarts OpenSSH.
Contexte
Les certificats SSH sont le levier de flotte majeur manquant. Avec des clés brutes,
autoriser un utilisateur exige de distribuer sa clé publique sur chaque hôte
(authorized_keys), et faire confiance à un hôte exige un known_hosts par client
(TOFU). Les certificats remplacent cela par une autorité de certification (CA) :
on fait confiance à une clé CA, et tout ce qu’elle signe (certificats utilisateur
et hôte) est accepté — avec durée de vie courte, principaux (principals) explicites,
options et révocation.
[ADR-108] a posé le matériel : air-keystore détient la clé CA, le magasin des CA de
confiance, et la révocation. Il manque deux choses, que cet ADR tranche : (1) le
format wire du certificat et sa vérification ; (2) l’orchestration d’émission
et de vérification, dans le respect strict du layering.
Directive BDFL (2026-07-26). « Il faut de l’interop avec OpenSSH. » Et, en cadrage d’[ADR-108] : « le format wire des certificats = couche 2 (air-ssh-proto), pas un manager L1 ; la CA = orchestration keystore(clé CA) + crypto(signature) + proto(format), pas un monolithe. »
Décision
1. Le format de certificat vit dans air-ssh-proto (couche 2), sans-IO
Le codec de certificat SSH — encodage/décodage du blob, sérialisation de la partie
à signer (to-be-signed), et vérification de la signature contre une clé CA — est
une capacité de air-ssh-proto (couche 2), pas du keystore. Il suit le motif
sans-IO ([ADR-091]) : cœur pur, déterministe, fuzzable, sans I/O propre. La
vérification de signature appelle air-crypto (Ed25519 verify, primitive pure). Le
certificat couvre les champs standard : nonce, clé publique certifiée, serial, type
(utilisateur ou hôte), key id, principals valides (utilisateurs ou noms
d’hôte), valid after/valid before, options critiques, extensions, clé de
signature (CA) et signature.
2. Interop OpenSSH + moderne-only
Le format est celui d’OpenSSH — ssh-ed25519-cert-v01@openssh.com — pour interop
réelle (certs émis/lus par l’écosystème). Conformément à la doctrine publickey Ed25519
moderne-only ([ADR-094]), seuls les certificats Ed25519 sont supportés (pas de
RSA/ECDSA-cert). Le parseur accepte des données externes du réseau ⇒ fuzzing
obligatoire (cargo-fuzz), parsing schema-first, zéro unwrap, slicing borné
(Principe 3). Les options critiques inconnues provoquent un rejet (fail-closed,
conforme à la spec des certs) ; les extensions inconnues sont ignorées.
3. La CA est une orchestration, pas un composant — et le layering est strict
Trois responsabilités, trois emplacements :
air-keystore(couche 1) — détient la clé CA privée (matériel + cycle de vie), le magasin des CA de confiance (clés publiques CA acceptées par un serveur/client), et la liste de révocation (§4). Aucune connaissance du format wire.air-ssh-proto(couche 2) — construit la partie à signer et assemble/vérifie le certificat (format).- Orchestration d’émission (couche 2) — une fonction qui : prend la clé CA via le
keystore (ou via
air-keysignsi la clé CA est privilégiée, [ADR-108] §5), fait sérialiser le to-be-signed parair-ssh-proto, le fait signer parair-crypto, puis assemble le certificat. Elle vit en couche 2 (elle dépend de proto et du keystore) — jamais en couche 1 (le keystore L1 ne peut pas dépendre de proto L2). L’outil qui l’expose (CLIair-keystore cert issue) est reporté en vague 2.
La vérification (un serveur/client valide un certificat présenté) est consommée par
air-sshd/air-ssh (couche 2) : air-ssh-proto vérifie la signature contre la CA ; le
keystore fournit la CA de confiance et l’état de révocation ; la politique
(quels principals/options accepter) relève à terme du SecurityManager ([ADR-089]).
4. Révocation
La liste de révocation (KRL — clés et/ou certificats révoqués, par serial ou par
clé) est stockée et interrogée dans air-keystore ([ADR-108] : revocation), avec
interop du format KRL OpenSSH. La vérification d’un certificat présenté consulte :
signature CA valide et non expiré et principal correspondant et non révoqué
et options critiques toutes comprises. Toute étape en échec ⇒ rejet.
5. Types utilisateur et hôte
- Certificat utilisateur — remplace la distribution d’
authorized_keys: le serveur accepte toute clé utilisateur portant un certificat d’une CA de confiance, dont unprincipal= le compte visé et la fenêtre de validité est ouverte. Côté client,air-sshprésente le certificat (réutilise keystore/CA + codec ; décision du bloc client d’origine). - Certificat hôte — remplace le TOFU
known_hosts: le client fait confiance à une CA d’hôtes ; tout hôte présentant un certificat hôte valide (principal = nom d’hôte) est accepté sans première-vue. Débloque le flux de provisioning « air-desktop-host » (image first-boot dont l’identité est vérifiable par certificat court) — dont le processus fait l’objet d’un ADR séparé ; celui-ci en fournit le mécanisme.
Conséquences
Positives.
- Gestion de flotte à l’échelle : une CA de confiance remplace la distribution N×M de clés et le TOFU ; durées de vie courtes + révocation = posture bien plus sûre.
- Layering propre : format en couche 2 (sans-IO, fuzzable), matériel en couche 1, orchestration en couche 2 — aucune inversion, cohérent [ADR-108].
- Interop OpenSSH : certs émis/consommés par l’écosystème ; migration douce.
- Débloque hostbased/provisioning (ADR ultérieurs) et le cert client (bloc client).
- Moderne-only : une seule famille (Ed25519-cert), surface minimale.
Négatives / coûts assumés.
- Surface d’attaque du parseur de certificats (entrée réseau pré-auth) ⇒ fuzz + schema-first obligatoires ; fail-closed sur options critiques inconnues. Risque borné, pas nul.
- Gestion de la CA = responsabilité opérationnelle : compromission de la clé CA =
compromission de la flotte ⇒ la clé CA gagne à être privilégiée (
air-keysign) et hors-ligne autant que possible. Documenté, à durcir. - Complexité de vérification (signature + expiry + principal + révocation + options) : chaque condition est un test ; l’oubli d’une = trou. Couverture 100 % + cas négatifs exhaustifs (Principe 1).
Mise en œuvre (référence, hors décision). Incréments : (a) codec + vérification de
certificat dans air-ssh-proto (sans-IO) + fuzz ; (b) magasin CA de confiance + KRL dans
air-keystore ([ADR-108]) ; (c) orchestration d’émission (couche 2) ; (d) vérification
câblée dans le userauth d’air-sshd ([ADR-094]) et la présentation côté air-ssh ;
(e) CLI cert issue|inspect|verify|revoke = vague 2. Non engagés par cet ADR ; il en
fixe les décisions normatives.
Alternatives rejetées
Aucune alternative n’a été consignée lors de l’instruction.