Aller au contenu

PD-282 — Specification Review

Story : PD-282 — ProofEnvelope auto-vérifiable : scellement HSM global et matériel eIDAS/OCSP embarqué
Auditeur : Claude (Opus 4.6)
Date : 2026-03-02
Documents analysés :
- PD-282-specification.md
- PD-282-tests.md


Synthèse

Gravité Nombre
Bloquant 3
Majeur 9
Mineur 6
Total 18

Constats détaillés


AMB-01 — Liste de patterns anti-secrets extensible sans gouvernance

Type : Ambiguïté
Référence : Spec §4 INV-282-06
Description : L'invariant qualifie la liste de patterns interdits de « minimaux » (privateKey, secretKey, sessionToken, hmacSecret, dek). Le terme « minimaux » implique que la liste peut être étendue, mais aucun mécanisme de gouvernance n'est défini : qui ajoute un pattern, quand, avec quel processus de validation, et quel impact sur les enveloppes déjà scellées avec l'ancienne liste.
Impact : Un implémenteur ne peut pas déterminer le contrat exact. Deux implémentations pourraient diverger sur la liste effective. L'extension non gouvernée pourrait invalider des flux de production.
Gravité : Majeur

AMB-02 — Rôle respectif de envelopeSeal.certificateChain vs verificationMaterial.*CertificateChain

Type : Ambiguïté
Référence : Spec §5.1.1 (certificateChain[]) et §5.1.2 (tsaCertificateChain[], eidasCertificateChain[])
Description : La spec définit trois tableaux de chaînes de certificats sans expliciter leur rôle fonctionnel respectif. Le lecteur doit inférer que `envelopeSeal.certificateChain` sert à vérifier le sceau global, `tsaCertificateChain` à vérifier le token TSA (PD-81), et `eidasCertificateChain` les signatures eIDAS. Aucune section ne contractualise cette sémantique.
Impact : Un implémenteur ou vérificateur tiers pourrait confondre les chaînes, utiliser la mauvaise chaîne pour une vérification donnée, ou considérer certaines chaînes comme redondantes.
Gravité : Majeur

AMB-03 — Format « base64-DER » vs « base64-DER-OCSP » non distingué

Type : Ambiguïté
Référence : Spec §5.1.1 (certificateChain[]) et §5.1.2 (ocspResponses[].response)
Description : Deux labels de format sont utilisés — « base64-DER » pour les certificats et « base64-DER-OCSP » pour les réponses OCSP — mais la regex de validation est identique (`^[A-Za-z0-9+/]+={0,2}$`). Le spec ne définit pas si « base64-DER-OCSP » désigne un encodage distinct (DER d'un OCSPResponse ASN.1) ou une simple convention de nommage.
Impact : Sans distinction formelle, un implémenteur pourrait accepter un certificat DER comme réponse OCSP (ou inversement) si seule la regex est vérifiée.
Gravité : Mineur

AMB-04 — « Mécanisme de réconciliation existant » non référencé

Type : Ambiguïté
Référence : Spec §5.5 Atomicité multi-composant
Description : Le scénario crash post-commit mentionne un « rattrapage asynchrone par mécanisme de réconciliation existant » sans référence à un PD, un module, ou une documentation. Ce mécanisme est présenté comme un fait acquis mais aucun contrat ne permet de vérifier son existence ou sa compatibilité avec les invariants PD-282.
Impact : Si le mécanisme n'existe pas ou n'est pas compatible avec l'immutabilité PD-282, le comportement post-crash est indéfini.
Gravité : Majeur

AMB-05 — Ordre temporel implicite : verificationMaterial avant calcul du sceau

Type : Ambiguïté
Référence : Spec §4 INV-282-02 + §5.1.1 + §5.1.2
Description : Le sceau couvre l'enveloppe complète hors `envelopeSeal` (INV-282-02). `verificationMaterial` fait partie du contenu scellé. Cela implique que `verificationMaterial` (OCSP, chaînes, timestamps) DOIT être assemblé AVANT le calcul du sceau. Cet ordonnancement temporel est une contrainte d'implémentation critique jamais explicitée.
Impact : Un implémenteur pourrait tenter de sceller d'abord puis ajouter le verificationMaterial, produisant un sceau qui ne couvre pas le matériel de vérification.
Gravité : Majeur

AMB-06 — « Policy dégradée » non formellement équivalente à OCSP_UNAVAILABLE

Type : Ambiguïté
Référence : Spec §5.1.2 (ocspResponses, comportement si invalide)
Description : Le tableau de format indique « si vide: autorisé uniquement avec policy dégradée ». Le terme « policy dégradée » n'est pas défini ; il faut croiser avec ERR-05 et l'enum `validationPolicy` pour comprendre qu'il désigne `OCSP_UNAVAILABLE`. L'enum n'a que deux valeurs, donc l'équivalence est déductible, mais le contrat devrait être explicite.
Impact : Mineur en l'état (deux valeurs d'enum), mais risque d'ambiguïté si l'enum est étendue.
Gravité : Mineur

AMB-07 — Absence de distinction « champ absent » vs « tableau vide » pour ocspResponses

Type : Ambiguïté
Référence : Spec §5.1.2 (ocspResponses) + Tests §7 TC-NEG-06
Description : La spec distingue « absent » (rejet) de « vide » (autorisé avec OCSP_UNAVAILABLE). Cependant, TC-NEG-06 dit « ocspResponses absent → Rejet finalisation » sans préciser que « absent » signifie « clé JSON manquante » et non « tableau vide [] ». La distinction est structurellement critique (schema validation vs business logic) mais implicite.
Impact : Un implémenteur de tests pourrait tester le mauvais cas (tableau vide au lieu de clé absente, ou inversement).
Gravité : Mineur

CTR-01 — Exigence de monitoring déclarée hors périmètre mais formulée comme obligatoire

Type : Contradiction
Référence : Spec §6 ERR-05 (note)
Description : La note ERR-05 déclare qu'« un mécanisme de monitoring DOIT alerter si le taux d'enveloppes avec OCSP_UNAVAILABLE dépasse 10% sur 1h », puis affirme que ce mécanisme est « hors périmètre fonctionnel de PD-282 » tout en stipulant qu'il « DOIT être implémenté dans l'infrastructure de monitoring existante ». Un DOIT hors périmètre est une contradiction : soit c'est dans le périmètre (et un invariant manque), soit c'est une recommandation (et « DOIT » est inapproprié).
Impact : Aucune story ne porte ce requirement. Risque d'oubli ou de contestation lors de l'implémentation.
Gravité : Majeur

CTR-02 — Stockage des nouveaux champs vs « Aucune migration DDL applicable »

Type : Contradiction
Référence : Spec §5.6 + §5.1.1 + §5.1.2
Description : La spec introduit deux structures de données (`envelopeSeal`, `verificationMaterial`) avec des contrats de format détaillés, puis déclare « Aucune stratégie de migration DDL applicable ». Le modèle de stockage n'est pas précisé. Si ces champs sont dans une colonne `jsonb` existante, aucun DDL n'est requis. Si une colonne ou table dédiée est nécessaire, la mention §5.6 est fausse. L'absence de précision rend le contrat invérifiable.
Impact : Un implémenteur ne peut pas déterminer si un DDL est attendu ou interdit.
Gravité : Mineur

IST-01 — Mode B (vérification online publique) sans test nominal positif

Type : Incohérence Spec↔Tests
Référence : Spec §2 (Inclus), §3 (Définitions Mode B) / Tests (absent)
Description : La spec inclut explicitement la « Vérification tierce en mode online public (sans service ProbatioVault) » et définit Mode B (blockchain/OCSP/CRL publics). TC-NOM-04 couvre uniquement Mode A (air-gapped). TC-ERR-08 couvre l'échec dans les deux modes. Aucun test nominal ne vérifie le chemin positif Mode B.
Impact : Mode B est contractualisé en périmètre mais n'a aucune preuve de conformité positive.
Gravité : Bloquant

IST-02 — TC-NOM-08 (atomicité) non rattaché à un invariant

Type : Incohérence Spec↔Tests
Référence : Tests §3 TC-NOM-08 / Tests §2 Matrice de couverture
Description : TC-NOM-08 teste les scénarios crash pre/post-commit (§5.5) mais n'apparaît pas dans la matrice de couverture §2 car aucun invariant ne couvre l'atomicité. Le test existe mais n'est formellement rattaché à aucun invariant ni critère d'acceptation.
Impact : Un audit de couverture basé sur la matrice conclura que l'atomicité n'est pas testée, alors qu'un test existe. Traçabilité incomplète.
Gravité : Mineur

IST-03 — Normalisation certSerialNumber non testée

Type : Incohérence Spec↔Tests
Référence : Spec §5.1.2 (règle de normalisation certSerialNumber) / Tests (absent)
Description : La spec contractualise une normalisation uppercase à l'ingestion pour `certSerialNumber` (case-insensitive acceptée en entrée, uppercase stocké). Aucun test ne vérifie : (a) qu'une entrée en minuscules/mixte est acceptée, (b) que la forme normalisée est persistée, (c) que les comparaisons utilisent la forme normalisée.
Impact : La normalisation pourrait ne pas être implémentée sans détection par la suite de tests.
Gravité : Majeur

IST-04 — Pas de test négatif pour producedAt > validationTimestamp

Type : Incohérence Spec↔Tests
Référence : Spec CA-05 / Tests §3 TC-NOM-03 (THEN clause)
Description : TC-NOM-03 vérifie que `producedAt <= validationTimestamp` en cas nominal. Mais aucun test ne spécifie le comportement lorsque cette condition est violée (producedAt dans le futur par rapport à validationTimestamp). La spec ne définit pas si c'est un rejet, un warning, ou un état accepté.
Impact : Comportement indéfini en cas d'incohérence temporelle OCSP. Un implémenteur pourrait accepter silencieusement des snapshots OCSP postérieurs au scellement.
Gravité : Majeur

IST-05 — Comportement à la finalisation si OCSP status = « revoked » non spécifié ni testé

Type : Incohérence Spec↔Tests
Référence : Spec §5.1.2 (ocspResponses[].status enum good|revoked|unknown) / Tests (absent)
Description : La spec définit l'enum `status` incluant `revoked` comme valeur valide, mais ne spécifie pas le comportement métier lorsque le statut OCSP d'un certificat de la chaîne est « revoked » au moment de la finalisation. Aucun test ne couvre ce cas. L'enveloppe pourrait être scellée avec un certificat révoqué sans alerte ni rejet.
Impact : Une enveloppe scellée contenant un statut OCSP « revoked » aurait une force probante contestable devant un auditeur ou tribunal (certificat de confiance révoqué au moment de la preuve).
Gravité : Bloquant

IST-06 — Pas de test pour substitution inter-enveloppes de composants internes

Type : Incohérence Spec↔Tests
Référence : Spec §4 INV-282-01 (justification « Empêche substitution de composants valides inter-enveloppes ») / Tests §7 TC-NEG-09
Description : TC-NEG-09 teste la copie de `envelopeSeal` d'une enveloppe vers une autre. Mais INV-282-01 mentionne la substitution de « composants » (pluriel). Aucun test ne vérifie la substitution d'un composant interne (ex : remplacement du `verificationMaterial` d'une enveloppe par celui d'une autre, le seal restant celui de l'enveloppe originale). Ce cas est couvert architecturalement (le seal protège le contenu) mais sans test explicite.
Impact : La justification d'INV-282-01 invoque un scénario d'attaque sans test dédié couvrant la substitution de composants internes.
Gravité : Mineur

HD-01 — signedAt exclu du sceau : horodatage de scellement falsifiable

Type : Hypothèse dangereuse
Référence : Spec §5.1.1 (envelopeSeal.signedAt) + §4 INV-282-02
Description : `signedAt` est un champ de `envelopeSeal`, qui est exclu intégralement du calcul du sceau (INV-282-02). Contrairement à `algorithm` (implicitement lié par la vérification cryptographique), `kid` (lié par la lookup de clé), et `certificateChain` (liée par la correspondance clé publique), `signedAt` n'a aucune liaison implicite ni explicite avec le sceau. Un attaquant avec accès en écriture au stockage peut modifier `signedAt` sans invalider la vérification.
Impact : Dans un contexte de conformité légale (eIDAS), l'horodatage de scellement est un élément probatoire. Sa falsification sans détection compromet la chronologie des preuves. Le `validationTimestamp` (dans verificationMaterial, protégé par le sceau) subsiste comme ancrage temporel, mais la divergence non détectable entre `signedAt` et `validationTimestamp` crée une incohérence exploitable.
Gravité : Bloquant

HD-02 — Déterminisme JCS après aller-retour base de données (jsonb)

Type : Hypothèse dangereuse
Référence : Spec §4 INV-282-02 + §10.1 (PostgreSQL jsonb)
Description : Le sceau est calculé sur la canonicalisation JCS (RFC 8785) du contenu. PostgreSQL `jsonb` normalise les valeurs JSON à l'ingestion (réordonnancement des clés, normalisation des nombres). Si le contenu est persisté en jsonb puis relu pour vérification, la forme sérialisée pourrait différer de celle utilisée au moment du scellement (par exemple, un nombre `1.0` sérialisé comme `1` par PostgreSQL). La spec ne précise pas si le sceau est calculé sur la représentation pre-persistance ou post-round-trip.
Impact : Vérification échouant sur des enveloppes intactes (faux négatif) si la canonicalisation diffère après round-trip.
Gravité : Majeur

HD-03 — Finalisation concurrente sur la même enveloppe UNSEALED

Type : Hypothèse dangereuse
Référence : Spec §5.4 (machine à états) + §5.5 (atomicité)
Description : La spec contractualise UNSEALED → SEALED comme autorisée et l'atomicité ACID du commit. Cependant, elle ne traite pas la concurrence : deux requêtes simultanées de finalisation sur la même enveloppe UNSEALED. L'atomicité ACID garantit l'isolation transactionnelle au niveau base, mais sans verrou applicatif explicite (SELECT FOR UPDATE, optimistic locking), une race condition pourrait produire deux tentatives de scellement dont une échouerait de manière non contractualisée.
Impact : Comportement d'erreur non spécifié en cas de concurrence. Un double scellement ou une erreur technique non métier pourrait se produire.
Gravité : Majeur

RSC-01 — Absence de statut OCSP pour le certificat de scellement propre

Type : Risque sécu/conformité
Référence : Spec §5.1.2 (verificationMaterial) + §5.1.1 (envelopeSeal.certificateChain)
Description : Le `verificationMaterial` contient des réponses OCSP pour les chaînes TSA et eIDAS, mais aucune réponse OCSP pour le certificat de scellement ProbatioVault (issu de `envelopeSeal.certificateChain`). En Mode A (air-gapped), un vérificateur tiers ne peut pas établir que le certificat de scellement n'était pas révoqué au moment de la génération. Le processus de révocation des clés HSM est explicitement hors périmètre (§2 Exclu), mais l'absence de preuve de non-révocation du certificat de scellement dans l'enveloppe elle-même est un trou d'auditabilité.
Impact : Force probante contestable si le certificat de scellement est ultérieurement révoqué : aucune preuve embarquée n'atteste de sa validité au moment T.
Gravité : Majeur

Récapitulatif par gravité

Bloquants (3)

ID Type Référence Résumé
IST-01 Incohérence Spec↔Tests Mode B Aucun test nominal positif pour Mode B (périmètre contractualisé)
IST-05 Incohérence Spec↔Tests OCSP status=revoked Comportement non spécifié ni testé si certificat révoqué à la finalisation
HD-01 Hypothèse dangereuse signedAt Horodatage de scellement falsifiable (exclu du sceau, aucune liaison implicite)

Majeurs (9)

ID Type Référence Résumé
AMB-01 Ambiguïté INV-282-06 Liste patterns anti-secrets extensible sans gouvernance
AMB-02 Ambiguïté certificateChain[] Rôles des trois chaînes de certificats non différenciés
AMB-04 Ambiguïté §5.5 Mécanisme de réconciliation existant non référencé
AMB-05 Ambiguïté §5.2 Ordre temporel assembly verificationMaterial vs sceau implicite
CTR-01 Contradiction ERR-05 note Exigence monitoring DOIT mais hors périmètre
IST-03 Incohérence Spec↔Tests certSerialNumber Normalisation uppercase contractualisée mais non testée
IST-04 Incohérence Spec↔Tests producedAt Pas de test négatif si producedAt > validationTimestamp
HD-02 Hypothèse dangereuse JCS + jsonb Déterminisme canonicalisation après round-trip PostgreSQL
HD-03 Hypothèse dangereuse concurrence Finalisation concurrente non contractualisée
RSC-01 Risque sécu/conformité OCSP sealing cert Pas de preuve de non-révocation du certificat de scellement

Mineurs (6)

ID Type Référence Résumé
AMB-03 Ambiguïté base64-DER-OCSP Label de format non défini
AMB-06 Ambiguïté policy dégradée Terme non formellement équivalent à OCSP_UNAVAILABLE
AMB-07 Ambiguïté ocspResponses absent vs vide Distinction structurelle implicite
CTR-02 Contradiction §5.6 Modèle de stockage des nouveaux champs non précisé
IST-02 Incohérence Spec↔Tests TC-NOM-08 Test atomicité non rattaché à un invariant dans la matrice
IST-06 Incohérence Spec↔Tests INV-282-01 Substitution composants internes non testée explicitement