Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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’OpenSSHssh-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éseaufuzzing 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-keysign si la clé CA est privilégiée, [ADR-108] §5), fait sérialiser le to-be-signed par air-ssh-proto, le fait signer par air-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 (CLI air-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 un principal = le compte visé et la fenêtre de validité est ouverte. Côté client, air-ssh pré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.