Aller au contenu

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 envelopeSeal pour chaque enveloppe finalisee.
  • Couverture de signature sur l'enveloppe complete hors champ envelopeSeal.
  • Inclusion de verificationMaterial avec tsaCertificateChain, 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. tsaCertificateChain permet 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, validationTimestamp sont 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
  • UNSEALED est un etat transitoire en memoire au niveau service; il n'est jamais persiste dans legal_composite_proof.
  • La persistance est atomique en INSERT direct SEALED (payload complet incluant envelope_seal), sans sequence INSERT puis UPDATE.
  • La testabilite de la transition UNSEALED -> SEALED est 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 -> SEALED par UPDATE, car ce chemin n'existe pas par design.
  • Justification architecturale: le trigger d'immutabilite PD-272 bloque tout UPDATE sur legal_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.
  • tsaCertificateChain est 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 verificationMaterial contient chaines + OCSP + timestamp + policy GENERATION_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=[] et validationPolicy=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 kid historique
  • 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)