PD-282 - ProofEnvelope auto-verifiable : scellement HSM global et materiel eIDAS/OCSP embarque¶
1. Objectif¶
La User Story PD-282 contractualise la production d'une ProofEnvelope auto-verifiable par un tiers, sans dependance aux services ProbatioVault, via :
- un scellement cryptographique global de l'enveloppe (
envelopeSeal) couvrant l'integralite du contenu canonicalise (JCS RFC 8785) ; - l'inclusion d'un materiel de verification offline (
verificationMaterial) comprenant chaines de certificats et snapshots OCSP au moment de generation ; - la garantie qu'une modification d'un octet invalide la verification ;
- la compatibilite avec l'immutabilite persistee (PD-272) et le modele d'etats de reference (PD-280), sans contournement des invariants existants.
2. Perimetre / Hors perimetre¶
Inclus¶
- Generation d'un champ
envelopeSealpour chaque enveloppe finalisee. - Couverture de signature sur l'enveloppe complete hors champ
envelopeSeal. - Inclusion de
verificationMaterialavectsaCertificateChain,eidasCertificateChain,ocspResponses,validationTimestamp,validationPolicy. - Verification tierce en mode offline strict (air-gapped) et mode online public (sans service ProbatioVault).
- Compatibilite de verification apres rotation de cle via
kid+ chaine de certificats embarquee. - Regles de rejet explicites en cas de format invalide ou donnees manquantes.
Exclu¶
- Outil CLI public package (hors script de preuve interne).
- Evolution UI/front.
- Refonte du mecanisme d'ancrage blockchain existant.
- Processus de revocation de cles HSM compromises.
- Migration vers formats CAdES/XAdES/PAdES.
- LTV (re-horodatage periodique long terme ETSI).
- Changement de schema d'etat global si PD-280 non disponible (compatibilite API uniquement).
3. Definitions¶
ProofEnvelope: structure JSON probante contenant preuves cryptographiques et metadonnees.JCS: JSON Canonicalization Scheme (RFC 8785), serialisation deterministe.envelopeSeal: sceau global HSM de l'enveloppe.verificationMaterial: materiaux cryptographiques necessaires a la verification autonome.GENERATION_TIME_SNAPSHOT: politique attestant l'etat de non-revocation au moment T de generation.Mode A: verification offline stricte sans reseau.Mode B: verification online publique (blockchain/OCSP/CRL publics), sans dependance ProbatioVault.Etat terminal: etat sans transition sortante autorisee.- Token TSA (RFC 3161) : produit par PD-81 (LegalCompositeProof) et partie integrante de la
ProofEnvelope.tsaCertificateChainpermet la verification de ce token TSA existant.
4. Invariants (non negociables)¶
| ID | Regle | Justification |
|---|---|---|
| INV-282-01 | Toute enveloppe finalisee DOIT contenir envelopeSeal valide cryptographiquement. | Empeche substitution de composants valides inter-enveloppes. |
| INV-282-02 | Le calcul du sceau DOIT exclure strictement le champ envelopeSeal avant canonicalisation JCS. | Evite auto-reference et non-determinisme. |
| INV-282-03 | Toute modification d'un octet du payload signe (enveloppe hors envelopeSeal) DOIT rendre la verification invalide. Note de justification : signedAt n'est pas inclus dans ce perimetre car son ancrage temporel est assure par validationTimestamp (inclus dans le hash) et par le token TSA PD-81. | Integrite bout-en-bout du perimetre signe. |
| INV-282-04 | verificationMaterial DOIT etre suffisant pour verification Mode A (hors ancrage blockchain). | Auto-verifiabilite tierce sans service PV. |
| INV-282-05 | validationPolicy DOIT etre explicite et presente dans l'enveloppe. | Interpretation probatoire non ambigue. |
| INV-282-06 | L'enveloppe DOIT passer une verification heuristique anti-secrets basee sur une liste de patterns interdits connus ; toute detection entraine rejet. Patterns interdits minimaux : privateKey, secretKey, sessionToken, hmacSecret, dek. | Confidentialite et conformite. |
| INV-282-07 | Invariant crypto-proof : tout artefact crypto temporaire (cle/fragment/DEK/ReKey) est chiffre au repos (AES-256-GCM ou envelope HSM). | Exigence constitutionnelle domaine crypto. |
| INV-282-08 | Une enveloppe scellee est immuable : toute tentative de mutation post-persistance est interdite. | Non-regression et force probante. |
| INV-282-09 | Etat SEALED est terminal : SEALED -> * : INTERDITE (etat terminal). | Coherence machine a etats. |
| INV-282-10 | Transition retour SEALED -> UNSEALED : INTERDITE. | Interdit downgrade post-scellement. |
| INV-282-11 | La verification d'enveloppes historiques DOIT rester possible apres rotation de cle via kid + chaine embarquee. | Perennite des preuves. |
| INV-282-12 | Toute regle de format/longueur invalide entraine un rejet explicite de finalisation. | Contrat testable, aucune hypothese implicite. |
5. Flux nominaux¶
5.1 Modele de donnees contractuel (format unique de reference)¶
5.1.1 envelopeSeal¶
| Champ | Format/encodage | Taille | Caracteres / casse | Regex | Comportement si invalide |
|---|---|---|---|---|---|
algorithm | chaine ASCII | valeur fixe | case-sensitive | ^ECDSA-P384-SHA3-384$ | rejet finalisation |
signature | base64url (RFC 4648 URL-safe, sans =) | 80..200 caracteres | [A-Za-z0-9_-] case-sensitive | ^[A-Za-z0-9_-]{80,200}$ | rejet finalisation |
kid | ASCII printable | 3..128 caracteres | case-sensitive | ^[A-Za-z0-9._:-]{3,128}$ | rejet finalisation |
signedAt | RFC3339 UTC millisecondes (YYYY-MM-DDTHH:mm:ss.SSSZ) | 24 caracteres | case-sensitive | ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$ | rejet finalisation |
certificateChain[] | tableau base64-DER | 1..10 elements ; chaque element 1..16384 caracteres | base64 case-sensitive | ^[A-Za-z0-9+/]+={0,2}$ | rejet finalisation |
5.1.2 verificationMaterial¶
| Champ | Format/encodage | Taille | Caracteres / casse | Regex | Comportement si invalide |
|---|---|---|---|---|---|
tsaCertificateChain[] | tableau base64-DER | 1..10 elements | base64 case-sensitive | ^[A-Za-z0-9+/]+={0,2}$ | rejet finalisation |
eidasCertificateChain[] | tableau base64-DER | 1..10 elements | base64 case-sensitive | ^[A-Za-z0-9+/]+={0,2}$ | rejet finalisation |
ocspResponses[] | tableau d'objets OCSP | 0..20 elements | - | - | si absent: rejet; si vide: autorise uniquement avec policy degradee |
ocspResponses[].certSerialNumber | hex sans prefixe | 2..64 caracteres | [0-9A-F], case-insensitive acceptee a l'entree puis normalisation uppercase | ^[0-9A-Fa-f]{2,64}$ | rejet finalisation |
ocspResponses[].response | base64-DER-OCSP | 1..32768 caracteres | base64 case-sensitive | ^[A-Za-z0-9+/]+={0,2}$ | rejet finalisation |
ocspResponses[].producedAt | RFC3339 UTC millisecondes | 24 caracteres | case-sensitive | ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$ | rejet finalisation |
ocspResponses[].status | enum | good\|revoked\|unknown | lowercase | ^(good|revoked|unknown)$ | rejet finalisation. Si status=revoked : rejet de finalisation (certificat revoque, cf. ERR-09). |
validationTimestamp | RFC3339 UTC millisecondes | 24 caracteres | case-sensitive | ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$ | rejet finalisation |
validationPolicy | enum | GENERATION_TIME_SNAPSHOT\|OCSP_UNAVAILABLE | uppercase + _ | ^(GENERATION_TIME_SNAPSHOT|OCSP_UNAVAILABLE)$ | rejet finalisation |
Regle de normalisation certSerialNumber : la normalisation uppercase est appliquee a l'ingestion (avant stockage). Toute comparaison se fait sur la forme normalisee.
Regle d'unicite de definition : les formats ci-dessus sont la reference unique ; toute autre section s'y refere sans redefinition.
5.2 Parametres numeriques contractuels¶
| Parametre | Defaut | Bornes min/max | Unite | Contexte / percentile | Hors bornes |
|---|---|---|---|---|---|
| Latence scellement complet | 500 | min 1 / max 5000 | ms | P95, environnement backend de reference a preciser | non-conformite perf; alerte qualite |
| Timeout OCSP par requete | 2000 | min 100 / max 10000 | ms | P95 | clamp configuration; puis policy degradee si timeout |
| Nombre reponses OCSP | 2 | min 0 / max 20 | elements | par enveloppe | >max: rejet finalisation |
| Taille overhead envelope | 17 | min 0 / max 64 | KB | P95 payload API | >max: non-conformite perf/taille |
5.3 SLA temporels¶
- Aucune transition temporelle metier de type TTL/expiration/delai de validite d'etat n'est introduite par PD-282.
- Les horodatages
signedAt,producedAt,validationTimestampsont des preuves temporelles, pas des timers d'expiration d'etat. - Mention obligatoire :
Aucune transition temporelle identifiee.
5.4 Machine d'etats UNSEALED/SEALED¶
| Etat source | Etat cible | Persiste en base | Regle |
|---|---|---|---|
UNSEALED | SEALED | Oui (INSERT) | AUTORISEE uniquement via construction en memoire puis insertion atomique |
UNSEALED | UNSEALED | Non | NON PERTINENTE EN BASE (etat transitoire memoire uniquement) |
SEALED | SEALED | Non (UPDATE) | INTERDITE en base (pas de double ecriture) |
SEALED | UNSEALED | Non | INTERDITE |
UNSEALEDest un etat transitoire en memoire au niveau service; il n'est jamais persiste danslegal_composite_proof.- La persistance est atomique en INSERT direct
SEALED(payload complet incluantenvelope_seal), sans sequence INSERT puis UPDATE. - La testabilite de la transition
UNSEALED -> SEALEDest portee par les tests service (unitaires) sur la construction en memoire et la validation du payload final. - La base de donnees ne teste pas une transition
UNSEALED -> SEALEDpar UPDATE, car ce chemin n'existe pas par design. - Justification architecturale: le trigger d'immutabilite PD-272 bloque tout
UPDATEsurlegal_composite_proof; le pattern INSERT-only est donc la seule option compatible sans modifier ce trigger.
5.5 Atomicite multi-composant¶
- INSERT/UPDATE base probatoire : synchrone transactionnel (ACID).
- Verifications asynchrones externes eventuelles (hors transaction DB) : idempotentes et retry-safe.
- Crash pre-commit : rollback total, aucun artefact persistant.
- Crash post-commit : etat DB autoritatif, rattrapage asynchrone par mecanisme de reconciliation existant.
- Aucun contournement d'immutabilite autorise.
5.6 Strategie de migration DDL¶
| Element | Specification |
|---|---|
| Migration DDL requise | ALTER TABLE legal_composite_proof ADD COLUMN envelope_seal JSONB NULL; |
| Nature du changement | Ajout de colonne uniquement |
| Colonnes existantes | Aucune colonne existante n'est modifiee (pas de changement type/contrainte/nom) |
| Backfill | Aucun backfill obligatoire (NULL autorise pour l'historique) |
| Compatibilite trigger PD-272 | Le trigger d'immutabilite existant couvre automatiquement la nouvelle colonne: tout UPDATE reste interdit, y compris sur envelope_seal |
| Mode d'ecriture cible | Maintien du pattern INSERT atomique en etat SEALED (aucune ecriture en deux temps) |
5.7 Contraintes inter-modules¶
- Aucune route d'un autre module n'est explicitement protegee/modifiee par cette story.
- Le token TSA (RFC 3161) est produit par PD-81 (LegalCompositeProof) et fait partie integrante de la
ProofEnvelope. tsaCertificateChainest requis pour verifier ce token TSA existant.- Mention obligatoire :
Aucune contrainte inter-module de routage applicable.
5bis. Diagrammes¶
5bis.1 Machine d'etats UNSEALED / SEALED¶
stateDiagram-v2
direction LR
state "UNSEALED\n(transitoire memoire)" as UNSEALED
state "SEALED\n(persiste, terminal)" as SEALED
[*] --> UNSEALED : Construction en memoire
UNSEALED --> SEALED : INSERT atomique\n(payload complet + envelopeSeal)
SEALED --> [*]
note right of SEALED
Etat terminal (INV-282-09)
Aucune transition sortante autorisee
UPDATE/DELETE interdit (trigger PD-272)
end note
note left of UNSEALED
Jamais persiste en base
Etat transitoire service uniquement
end note Transitions interdites (INV-282-09, INV-282-10) :
| Transition | Statut | Justification |
|---|---|---|
SEALED -> SEALED | INTERDITE | Pas de double ecriture (trigger PD-272 bloque UPDATE) |
SEALED -> UNSEALED | INTERDITE | Downgrade post-scellement interdit (INV-282-10) |
SEALED -> * | INTERDITE | Etat terminal, aucune transition sortante (INV-282-09) |
UNSEALED -> UNSEALED | NON PERTINENTE | Etat transitoire memoire uniquement, pas de persistance |
5bis.2 Flux de scellement (generation de l'enveloppe)¶
sequenceDiagram
participant S as ProofEnvelopeService
participant V as ValidationService
participant OCSP as Repondeur OCSP
participant HSM as CloudHSM (PKCS#11)
participant DB as PostgreSQL<br/>(legal_composite_proof)
Note over S: Etat UNSEALED (memoire)
S->>S: Assembler ProofEnvelope<br/>(preuves + metadonnees)
S->>S: Scan heuristique anti-secrets<br/>(INV-282-06 : patterns interdits)
alt Pattern interdit detecte
S-->>S: REJET finalisation (ERR-06)
end
S->>V: Demander verificationMaterial
V->>OCSP: Requete OCSP par certificat<br/>(timeout contractuel <= 10000ms)
alt OCSP disponible
OCSP-->>V: OCSPResponse (status: good/revoked/unknown)
alt status = revoked
V-->>S: REJET finalisation (ERR-09)
else status = good | unknown
V->>V: Assembler ocspResponses[]<br/>+ producedAt + certSerialNumber (normalize uppercase)
V->>V: validationPolicy = GENERATION_TIME_SNAPSHOT
end
else OCSP indisponible (timeout ERR-05)
V->>V: ocspResponses = []
V->>V: validationPolicy = OCSP_UNAVAILABLE
end
V->>V: Assembler tsaCertificateChain[]<br/>+ eidasCertificateChain[]<br/>+ validationTimestamp (RFC3339 UTC ms)
V-->>S: verificationMaterial complet (INV-282-04)
S->>S: Inserer verificationMaterial<br/>dans ProofEnvelope
S->>S: Exclure champ envelopeSeal (INV-282-02)
S->>S: Canonicaliser JCS (RFC 8785)
alt Echec canonicalisation
S-->>S: REJET finalisation (ERR-02)
end
S->>S: Hash SHA3-384 du payload canonicalise
S->>HSM: Sign CKM_ECDSA(hash, kid)<br/>algorithme = ECDSA-P384-SHA3-384
alt Signature echoue
HSM-->>S: Erreur (ERR-03)
else Signature OK
HSM-->>S: signature (raw ECDSA, base64url)
end
S->>S: Assembler envelopeSeal :<br/>algorithm + signature + kid<br/>+ signedAt + certificateChain[]
S->>S: Valider formats contractuels<br/>(regex §5.1, INV-282-12)
alt Format invalide
S-->>S: REJET finalisation (ERR-06)
end
Note over S: Transition UNSEALED -> SEALED
S->>DB: INSERT atomique<br/>(payload complet avec envelope_seal JSONB)
Note over DB: Trigger PD-272 :<br/>tout UPDATE futur interdit
Note over S: Etat SEALED (terminal, INV-282-09) 5bis.3 Flux de verification tierce (Mode A offline / Mode B online)¶
sequenceDiagram
participant T as Verificateur tiers
participant E as ProofEnvelope (document)
participant TS as Trust-store local (H-01)
participant BC as Blockchain publique<br/>(Mode B uniquement)
T->>E: Extraire envelopeSeal + verificationMaterial
T->>T: Verifier validationPolicy<br/>(GENERATION_TIME_SNAPSHOT | OCSP_UNAVAILABLE)
T->>T: Extraire payload = enveloppe SANS envelopeSeal (INV-282-02)
T->>T: Canonicaliser JCS (RFC 8785)
T->>T: Hash SHA3-384 du payload canonicalise
T->>T: crypto.verify(null, hash, publicKey, signature)<br/>(raw ECDSA — pas de createVerify)
Note over T: INV-282-03 : toute modification<br/>d'un octet invalide la verification
alt Signature invalide
T-->>T: ECHEC verification (ERR-03)
end
T->>E: Extraire certificateChain[] (envelopeSeal)<br/>+ eidasCertificateChain[]
T->>TS: Verifier chaine jusqu'a ancre de confiance
alt Chaine non verifiable
T-->>T: ECHEC verification (ERR-08)
end
T->>E: Extraire kid (envelopeSeal)
T->>T: Identifier cle via kid + chaine embarquee<br/>(INV-282-11 : rotation de cle)
alt validationPolicy = GENERATION_TIME_SNAPSHOT
T->>E: Extraire ocspResponses[]
T->>T: Verifier OCSP status pour chaque certificat
T->>T: Confirmer producedAt <= validationTimestamp
else validationPolicy = OCSP_UNAVAILABLE
T->>T: Accepter sans OCSP<br/>(policy degradee documentee)
end
T->>E: Extraire tsaCertificateChain[]
T->>T: Verifier token TSA (RFC 3161, PD-81)<br/>via chaine TSA embarquee
opt Mode B uniquement
T->>BC: Verifier ancrage blockchain<br/>(hors perimetre INV-282-04)
end
T->>T: Verification complete : VALIDE 6. Cas d'erreur¶
| ID | Cas | Reponse attendue |
|---|---|---|
| ERR-01 | envelopeSeal manquant sur enveloppe finalisee | Echec validation, statut non conforme |
| ERR-02 | Echec canonicalisation JCS | Rejet finalisation, erreur metier explicite |
| ERR-03 | Signature invalide ou algorithme non conforme | Rejet finalisation |
| ERR-04 | verificationMaterial incomplet (chaines/champs requis absents) | Rejet finalisation |
| ERR-05 | OCSP indisponible (timeout) | Finalisation autorisee seulement avec validationPolicy=OCSP_UNAVAILABLE et ocspResponses=[] |
| ERR-06 | Format invalide (regex/longueur/casse contractuelle) | Rejet finalisation |
| ERR-07 | Tentative de mutation post-scellement | Refus strict (immutabilite) |
| ERR-08 | Chaine cert non verifiable jusqu'a ancre de confiance | Verification tierce echoue (mode A/B) |
| ERR-09 | OCSP status=revoked detecte | Rejet finalisation (certificat revoque) |
Note ERR-05 (garde-fou exploitation) : un mecanisme de monitoring doit alerter si le taux d'enveloppes generees avec OCSP_UNAVAILABLE depasse 10% sur une fenetre glissante de 1 heure. Ce mecanisme est hors perimetre fonctionnel de PD-282 mais DOIT etre implemente dans l'infrastructure de monitoring existante.
7. Criteres d'acceptation (testables)¶
| ID | Critere | Observable |
|---|---|---|
| CA-01 | Toute enveloppe finalisee contient envelopeSeal valide | Verification cryptographique OK |
| CA-02 | Recalcul JCS + hash + verify ECDSA reussit sur enveloppe intacte | Resultat valid=true |
| CA-03 | Mutation 1 octet invalide le sceau | Resultat valid=false |
| CA-04 | verificationMaterial contient tous champs requis | Schema/contrat valide |
| CA-05 | OCSP snapshot au moment T est inclus si disponible | ocspResponses[].producedAt <= validationTimestamp |
| CA-06 | Aucun secret crypto en clair selon controle heuristique par patterns interdits | Scan/controle de contenu sans pattern interdit |
| CA-07 | Mutation post-persistance interdite | tentative UPDATE/DELETE refusee |
| CA-08 | Verification mode A reussit sans reseau ProbatioVault, sous reserve que le trust-store du verificateur contienne la racine de confiance (cf. H-01). | execution air-gapped positive |
| CA-09 | Verification historique apres rotation de cle reste possible | enveloppe ancienne toujours verifiable |
| CA-10 | validationPolicy explicite et conforme enum | valeur acceptee uniquement dans enum |
| CA-11 | Etat terminal documente : SEALED -> * interdit | tests de transitions refusees |
| CA-12 | Parametres numeriques respectent bornes contractuelles | tests de config/hors bornes conformes |
8. Scenarios de test (Given / When / Then)¶
- T-01 Integrite nominale
- Given une enveloppe complete non scellee valide
- When le sceau est produit puis verifie
-
Then la verification cryptographique reussit
-
T-02 Alteration post-scellement
- Given une enveloppe scellee valide
- When un octet quelconque est modifie
-
Then la verification echoue
-
T-03 Materiel eIDAS complet
- Given une generation nominale avec OCSP disponible
- When l'enveloppe est finalisee
-
Then
verificationMaterialcontient chaines + OCSP + timestamp + policyGENERATION_TIME_SNAPSHOT -
T-04 OCSP indisponible
- Given repondeur OCSP indisponible jusqu'au timeout contractuel
- When l'enveloppe est finalisee en mode degrade autorise
-
Then
ocspResponses=[]etvalidationPolicy=OCSP_UNAVAILABLE -
T-05 Immutabilite
- Given une enveloppe
SEALED - When une mutation est demandee
-
Then la transition est refusee (
SEALED -> *interdit) -
T-06 Rotation cle
- Given une enveloppe signee avec un
kidhistorique - When la cle courante a change
- Then la verification de l'enveloppe historique reste valide via chaine embarquee
9. Hypotheses explicites¶
| ID | Hypothese | Impact si faux |
|---|---|---|
| H-01 | La racine de confiance necessaire a la validation cert est disponible cote verificateur | Mode A peut echouer malgre enveloppe correcte |
| H-02 | Le modele PD-280 n'impose pas de transition contradictoire avec SEALED terminal | Revision de la machine a etats requise |
| H-03 | La finalisation peut porter une policy degradee OCSP_UNAVAILABLE | Sinon generation doit etre bloquante |
| H-04 | Les sources cert/OCSP utilisees sont juridiquement recevables pour le contexte eIDAS cible | Risque de non-conformite legale |
| H-05 | Les bornes perf sont mesurees sur un environnement de reference defini | Sans reference, critere perf contestable |
10. Contraintes techniques (stack) et points a clarifier¶
10.1 Contraintes techniques confirmees (projet cible)¶
- Projet cible presume :
ProbatioVault-backend. - Stack contractuelle :
NestJS + TypeORM + PostgreSQL. - Formats d'artefacts : JSON (
jsonb), certificats DER encodes base64, timestamps RFC3339 UTC. - Toute mention de stack non conforme (ex. Spring Boot, Swift/SwiftUI) est interdite.
10.2 Points a clarifier¶
| ID | Point a clarifier | Donnee manquante / decision attendue |
|---|---|---|
| Q-02 | Environnement de reference perf | hote cible (CPU/RAM/reseau) pour valider P95 |
| Q-04 | Jeu exact d'etats metier final PD-280 | confirmer alignement UNSEALED/SEALED avec etats globaux |
| Q-05 | Inclusion root CA dans chaines | obligatoire ou optionnelle selon politique trust-store cible |
References¶
- Epic : Pas d'epic parent (story independante, labels: crypto, legal-compliance, rfc-pv-proof)
- JIRA :
PD-282 - Repos concernes :
ProbatioVault-backend - Documents associes :
- RFC
PV-PROOF-001 v1.1.0 (2026-03-01) - PD-81 (LegalCompositeProof)
- PD-272 (immutability trigger)
- PD-280 (modele d'etats PENDING/INDETERMINATE)