Aller au contenu

Expression de besoin — PD-282

ProofEnvelope : scellement HSM (PROOF-14) + matériel de validation eIDAS (PROOF-05b)

Champ Valeur
Story PD-282
Titre ProofEnvelope : scellement HSM (PROOF-14) + matériel validation eIDAS (PROOF-05b)
Labels crypto, legal-compliance, rfc-pv-proof
Priorité Medium
Auteur Claude (orchestrateur IA)
Date 2026-03-02
Version 1.0
RFC de référence PV-PROOF-001 v1.1.0 (2026-03-01)

1. Contexte et problématique

ProbatioVault génère des preuves numériques probantes sous forme de ProofEnvelopes — des structures JSON signées contenant l'ensemble des éléments cryptographiques attestant de l'intégrité, de l'horodatage et de l'authenticité d'un document ou d'un événement.

Aujourd'hui, la vérification d'une ProofEnvelope nécessite un accès aux services internes de ProbatioVault : le service HSM pour la validation de signature, le service TSA pour la vérification de l'horodatage, et le service de vérification de certificats pour la chaîne de confiance eIDAS. Cette dépendance pose trois problèmes majeurs :

Problème 1 — Absence de scellement global. Chaque composant de la preuve (hash documentaire, signature HSM, jeton TSA, preuve Merkle) est vérifié indépendamment, mais il n'existe pas de sceau cryptographique couvrant l'enveloppe dans son ensemble. Un attaquant pourrait théoriquement substituer un composant valide par un autre composant valide provenant d'une enveloppe différente, sans que la vérification unitaire ne détecte l'incohérence.

Problème 2 — Impossibilité de vérification autonome. Un tiers (auditeur judiciaire, expert technique, juge) souhaitant vérifier la validité d'une preuve doit interroger les services ProbatioVault. En cas d'indisponibilité de la plateforme, de litige commercial, ou de procédure contradictoire, cette dépendance invalide de facto la valeur probante de l'enveloppe.

Problème 3 — Absence de preuve de non-révocation au moment T. Les certificats eIDAS et HSM peuvent être révoqués après la génération de la preuve. Sans snapshot des réponses OCSP et des chaînes de certificats au moment de la génération, un tiers ne peut pas distinguer une preuve générée avant la révocation d'une preuve générée après.

La RFC PV-PROOF-001 v1.1.0 répond à ces trois problèmes via deux mécanismes complémentaires : PROOF-14 (scellement HSM de l'enveloppe complète) et PROOF-05b (inclusion du matériel de vérification eIDAS).


2. Objectif

Rendre chaque ProofEnvelope auto-vérifiable : un tiers disposant uniquement du fichier JSON de l'enveloppe et d'un outil cryptographique standard (OpenSSL, Bouncy Castle, ou équivalent) doit pouvoir vérifier l'intégrité et l'authenticité de la preuve sans aucune connexion aux services ProbatioVault.

Concrètement, cette story doit :

  1. Sceller chaque ProofEnvelope finalisée avec une signature HSM ECDSA P-384 couvrant l'intégralité du contenu canonicalisé (JCS) de l'enveloppe.
  2. Inclure dans l'enveloppe tout le matériel cryptographique nécessaire à la vérification offline : chaîne de certificats TSA, chaîne de certificats eIDAS, réponses OCSP capturées au moment T, et horodatage de validation.
  3. Garantir que toute modification, même d'un seul octet, du contenu de l'enveloppe invalide le sceau.
  4. Préserver la compatibilité avec le trigger d'immutabilité PostgreSQL (PD-272) et le modèle d'états PENDING/INDETERMINATE (PD-280).

3. Périmètre fonctionnel

3.1. Lot 1 — MUST-HAVE (livré dans PD-282)

PROOF-14 : Scellement HSM de l'enveloppe

Le scellement consiste à produire un champ envelopeSeal ajouté à la ProofEnvelope après la persistance de tous les autres champs. Le processus est le suivant :

  1. Canonicalisation JCS : L'enveloppe complète (sans le champ envelopeSeal) est sérialisée en JSON Canonicalization Scheme (RFC 8785) via le JsonCanonicalizeService existant.
  2. Hachage SHA3-384 : Le contenu canonicalisé est haché avec SHA3-384 (famille SHA-3, résistante aux attaques par extension de longueur).
  3. Signature ECDSA P-384 : Le hash est signé par le HSM via le HsmService existant, avec la clé de scellement identifiée par son kid (Key ID).
  4. Construction du champ envelopeSeal :
{
  "envelopeSeal": {
    "algorithm": "ECDSA-P384-SHA3-384",
    "signature": "<base64url>",
    "kid": "pv-master-signing-2026",
    "signedAt": "2026-03-02T14:30:00.000Z",
    "certificateChain": ["<base64-DER-cert-1>", "<base64-DER-cert-2>"]
  }
}
  1. Persistance : L'enveloppe complète (avec envelopeSeal) est persistée. Le trigger d'immutabilité (PD-272) bloque toute modification ultérieure.

Le certificateChain dans le sceau contient la chaîne complète de la clé HSM de scellement, permettant au tiers de vérifier la signature sans interroger ProbatioVault.

PROOF-05b : Matériel de vérification eIDAS

Un nouveau champ verificationMaterial est ajouté à la ProofEnvelope, contenant :

{
  "verificationMaterial": {
    "tsaCertificateChain": ["<base64-DER>", "..."],
    "eidasCertificateChain": ["<base64-DER>", "..."],
    "ocspResponses": [
      {
        "certSerialNumber": "...",
        "response": "<base64-DER-OCSP>",
        "producedAt": "2026-03-02T14:29:58.000Z",
        "status": "good"
      }
    ],
    "validationTimestamp": "2026-03-02T14:30:00.000Z",
    "validationPolicy": "GENERATION_TIME_SNAPSHOT"
  }
}

Les OCSP responses sont capturées au moment de la génération de la preuve et incluses en tant que snapshots. Elles attestent que les certificats n'étaient pas révoqués à l'instant T de génération. La politique de validation est explicite : GENERATION_TIME_SNAPSHOT signifie que le matériel reflète l'état des certificats au moment de la génération, pas au moment de la vérification.

3.2. Lot 2 — Découplable (story séparée si PD-280 non mergé)

PENDING explicite

Le modèle d'états de PD-280 introduit un état PENDING explicite pour les ProofEnvelopes en cours de constitution (avant finalisation). Ce lot inclut :

  • Mapping de l'absence de sceau (envelopeSeal === null) vers l'état PENDING.
  • Exposition de l'état via l'API REST.
  • Règle de compatibilité formelle : si PD-280 n'est pas mergé, null == PENDING est traité côté API uniquement sans colonne BDD dédiée.

Recommandation PO : découpler ce lot si PD-280 n'est pas prêt au moment de l'implémentation. Le scellement et le matériel de vérification sont indépendants du modèle d'états.


4. Modes de vérification

L'enveloppe scellée doit supporter deux modes de vérification par un tiers, correspondant à deux niveaux d'exigence.

4.1. Mode A — Offline strict (air-gapped)

Le vérificateur dispose uniquement du fichier JSON de la ProofEnvelope. Aucune connexion réseau n'est requise.

Étapes de vérification :

  1. Extraction du champ envelopeSeal : Le vérificateur isole le sceau et reconstitue le contenu de l'enveloppe sans ce champ.
  2. Canonicalisation JCS : Le contenu reconstitué est sérialisé en JCS (RFC 8785). Le vérificateur utilise une implémentation JCS locale (disponible dans toutes les langues majeures).
  3. Hachage SHA3-384 : Le contenu canonicalisé est haché.
  4. Vérification de signature ECDSA : Le hash est vérifié contre la signature du sceau, en utilisant la clé publique extraite du certificateChain inclus dans le sceau.
  5. Validation de la chaîne de certificats : Le vérificateur remonte la chaîne jusqu'à une racine de confiance (CA eIDAS). Les certificats intermédiaires sont inclus dans l'enveloppe.
  6. Vérification OCSP : Les réponses OCSP incluses dans verificationMaterial attestent de la non-révocation des certificats au moment T. Le vérificateur vérifie la signature de chaque réponse OCSP.
  7. Vérifications internes : Hash documentaire, signature HSM du document, jeton TSA, preuve Merkle vers la racine — chaque composant est vérifié avec les clés et certificats inclus dans l'enveloppe.

Limites du mode A : La vérification blockchain (ancrage Merkle root) n'est pas possible en mode air-gapped. Le vérificateur peut vérifier la cohérence interne (document hash -> Merkle tree -> root), mais pas que la root a été effectivement ancrée on-chain.

4.2. Mode B — Indépendant de PV mais online public

Le vérificateur dispose du fichier JSON et d'un accès internet public (sans accès aux services ProbatioVault).

Étapes supplémentaires par rapport au mode A :

  1. Vérification blockchain : Le vérificateur interroge un noeud public ou un explorer blockchain pour confirmer que la Merkle root déclarée dans l'enveloppe a été effectivement ancrée on-chain à l'horodatage attendu.
  2. Vérification OCSP live (optionnelle) : Le vérificateur peut interroger le répondeur OCSP de la CA pour obtenir le statut actuel des certificats, en complément du snapshot inclus dans l'enveloppe.
  3. Vérification CRL (optionnelle) : Le vérificateur peut télécharger la CRL courante de la CA pour une vérification exhaustive.

Ce mode ne dépend pas de ProbatioVault : toutes les sources consultées (nodes blockchain, répondeurs OCSP, CRL Distribution Points) sont des services publics opérés par des tiers de confiance.


5. Contraintes techniques

5.1. HSM

Paramètre Valeur
Algorithme ECDSA
Courbe P-384 (secp384r1)
Hash SHA3-384
Format signature DER-encoded, exposé en base64url
Key ID Champ kid dans le sceau
Labels production Préfixe pv-master-*
Labels test Préfixe pv-test-*
Rotation Le kid + certificateChain permettent au tiers de retrouver la clé publique historique

La rotation de clé HSM ne doit pas invalider les enveloppes existantes. Chaque enveloppe porte son propre kid et sa propre chaîne de certificats, rendant la vérification indépendante de l'état courant du HSM.

5.2. eIDAS et TSA

Paramètre Valeur
Politique de validation GENERATION_TIME_SNAPSHOT — snapshot au moment T
OCSP Réponses capturées à la génération, incluses en DER
Chaînes de certificats TSA + eIDAS, format DER encodé en base64
CRL Non incluse (trop volumineuse). OCSP suffit pour le mode offline

L'inclusion des OCSP responses est suffisante pour le mode offline. Les CRL sont disponibles en mode B via les CRL Distribution Points encodés dans les certificats.

5.3. Canonicalisation

La canonicalisation JCS (RFC 8785) est le standard choisi pour la sérialisation déterministe du JSON. Le JsonCanonicalizeService existant implémente déjà cette norme. Points d'attention :

  • L'enveloppe est canonicalisée sans le champ envelopeSeal (ce champ est exclu avant la canonicalisation, puis ajouté après).
  • L'ordre d'exclusion doit être déterministe : supprimer la clé envelopeSeal du dictionnaire avant la canonicalisation.
  • Les nombres flottants suivent la norme IEEE 754 avec la sérialisation ECMAScript.

5.4. Latence et performance

Paramètre Contrainte
Moment du scellement Synchrone, post-persist dans generateProof()
Appels HSM 1 signature par enveloppe (le scellement)
Appels OCSP N appels (1 par certificat dans les chaînes TSA + eIDAS)
Latence cible < 500ms pour le scellement complet (HSM + OCSP)
Parallélisation Les appels OCSP peuvent être parallélisés

Le scellement est synchrone : generateProof() ne retourne pas tant que le sceau n'est pas persisté. Le trigger d'immutabilité (PD-272) s'applique immédiatement après.

5.5. Taille de l'enveloppe

L'inclusion des chaînes de certificats et des réponses OCSP augmente la taille de l'enveloppe. Estimation :

Composant Taille estimée
Chaîne certificats TSA ~3-5 KB (2-3 certs)
Chaîne certificats eIDAS ~3-5 KB (2-3 certs)
Chaîne certificats HSM ~2-3 KB (1-2 certs)
Réponses OCSP ~2-4 KB (2-4 réponses)
Signature sceau ~96 bytes (P-384)
Total overhead ~10-17 KB

Cet overhead est acceptable pour des enveloppes dont la taille typique est de 5-50 KB. La taille totale reste largement en dessous des limites PostgreSQL (jsonb supporte jusqu'à 255 MB) et des seuils de transfert API.


6. Critères d'acceptation

Critères fonctionnels (Jira)

ID Critère Lot
CA-01 Toute ProofEnvelope finalisée possède un champ envelopeSeal avec une signature HSM valide 1
CA-02 La vérification par un tiers (recalcul JCS + SHA3-384 + ECDSA verify P-384) réussit 1
CA-03 La modification d'un seul octet de l'enveloppe provoque l'échec de la vérification du sceau 1
CA-04 verificationMaterial inclut tsaCertificateChain, eidasCertificateChain, ocspResponses, validationTimestamp 1
CA-05 Les réponses OCSP sont capturées au moment de la génération (snapshot à l'instant T) 1
CA-06 Aucun secret cryptographique dans l'enveloppe (clés privées, tokens de session HSM) 1
CA-07 Le trigger d'immutabilité bloque toujours UPDATE/DELETE après persistance 1
CA-08 Pipeline CI vert (lint + tests + Sonar QG) 1

Critères de vérification (ajoutés)

ID Critère Lot
CA-09 Mode A (offline) : un script de vérification autonome valide l'enveloppe sans connexion réseau, en utilisant uniquement les données incluses dans le JSON 1
CA-10 Mode A (offline) : la chaîne de certificats HSM incluse dans envelopeSeal.certificateChain remonte jusqu'à une racine de confiance 1
CA-11 Mode B (online public) : la Merkle root déclarée dans l'enveloppe est retrouvable sur un explorer blockchain public 2*
CA-12 Rotation de clé HSM : une enveloppe scellée avec une clé historique (kid antérieur) reste vérifiable après rotation 1
CA-13 La politique de validation GENERATION_TIME_SNAPSHOT est explicitement déclarée dans verificationMaterial.validationPolicy 1

*CA-11 dépend de l'infrastructure blockchain existante et peut être vérifié indépendamment.


7. Dépendances et prérequis

Dépendances internes

Story Composant Statut Impact
PD-81 LegalCompositeProof Livré Structure de base de la ProofEnvelope
PD-272 Immutability trigger Livré Le trigger doit couvrir l'enveloppe avec sceau
PD-280 PENDING/INDETERMINATE En cours Lot 2 dépend de ce modèle d'états

Briques existantes réutilisées

Service Usage dans PD-282
JsonCanonicalizeService Canonicalisation JCS de l'enveloppe avant hachage
HsmService Signature ECDSA P-384 du hash de l'enveloppe
TsaClientService Récupération de la chaîne de certificats TSA
SignatureVerificationService Vérification locale (tests + mode A)

Prérequis techniques

  1. Le HsmService doit exposer une méthode de signature avec retour du kid et de la chaîne de certificats associée. Si cette méthode n'existe pas, elle doit être ajoutée dans le cadre de PD-282.
  2. Le TsaClientService doit permettre la récupération de la chaîne de certificats TSA. Si seul le jeton TSA est retourné aujourd'hui, l'extraction de la chaîne doit être ajoutée.
  3. Un mécanisme d'appel OCSP doit être disponible (via un OcspClientService existant ou à créer). Les répondeurs OCSP sont identifiés via l'extension AIA (Authority Information Access) des certificats.

8. Hors périmètre

Les éléments suivants sont explicitement exclus de PD-282 :

  1. Outil CLI de vérification : Un outil de vérification packagé pour les tiers (CLI, bibliothèque, application web) n'est pas dans le périmètre. Seul un script de test interne démontrant la faisabilité du mode A est requis (CA-09).
  2. Interface utilisateur : Aucune modification de l'application front-end. Le scellement est un processus backend transparent.
  3. Ancrage blockchain : Le mécanisme d'ancrage de la Merkle root on-chain est un processus existant. PD-282 ne modifie pas ce processus.
  4. Révocation de clé HSM : La procédure de révocation d'une clé HSM compromise (re-scellement des enveloppes, notification des tiers) est un sujet distinct.
  5. Format de preuve alternatif : Pas de génération en format standard (CAdES, XAdES, PAdES). Le format est le JSON natif ProbatioVault.
  6. Validation LTV (Long-Term Validation) : L'archivage long terme avec re-horodatage périodique (norme ETSI EN 319 122) n'est pas couvert. Le GENERATION_TIME_SNAPSHOT est suffisant pour la validité initiale.
  7. Gestion du Lot 2 (PENDING explicite) si PD-280 n'est pas mergé : sera traité dans une story dédiée.

9. Risques identifiés

# Risque Probabilité Impact Mitigation
R1 PD-280 non mergé au moment de l'implémentation Moyenne Faible Lot 2 découplé. Lot 1 est indépendant du modèle d'états
R2 Latence OCSP excessive (répondeurs externes lents) Moyenne Moyen Parallélisation des appels OCSP. Timeout avec fallback graceful (inclure un champ ocspUnavailable: true si timeout)
R3 Taille d'enveloppe trop importante pour certains cas d'usage Faible Faible Overhead estimé ~10-17 KB, acceptable. Monitoring à mettre en place
R4 Changement de format JCS entre versions de la bibliothèque Faible Élevé Verrouiller la version de la bibliothèque JCS. Tests de non-régression sur la canonicalisation
R5 Répondeur OCSP indisponible au moment de la génération Faible Moyen Stratégie dégradée : générer l'enveloppe avec ocspResponses: [] et validationPolicy: "OCSP_UNAVAILABLE". Le scellement reste valide, mais le mode A perd la preuve de non-révocation
R6 Incompatibilité trigger immutabilité avec le scellement post-persist Faible Élevé Le scellement doit être fait AVANT le trigger, ou le trigger doit autoriser l'ajout du sceau comme opération atomique unique post-INSERT
R7 Clé HSM de scellement différente de la clé de signature documentaire Faible Faible Clarifier dans la spécification si la même clé ou deux clés distinctes sont utilisées. Deux clés recommandées (séparation des responsabilités)

Le risque R6 est critique : il faut vérifier que le trigger d'immutabilité de PD-272 permet l'ajout du champ envelopeSeal après l'INSERT initial. Si le trigger bloque tout UPDATE, le scellement doit être intégré dans la même transaction que l'INSERT (INSERT de l'enveloppe complète avec sceau). Cela implique que le scellement se fasse AVANT la persistance, pas après.


10. Questions ouvertes restantes

# Question Impact Proposition
Q1 Le trigger d'immutabilité PD-272 autorise-t-il un UPDATE pour ajouter envelopeSeal post-INSERT, ou faut-il insérer l'enveloppe complète (avec sceau) en une seule opération ? Architecture Vérifier le code du trigger. Si blocage total, sceller avant INSERT dans la même transaction
Q2 Le HsmService expose-t-il déjà le kid et la chaîne de certificats associée lors d'une signature, ou faut-il enrichir l'interface ? Implémentation Auditer l'interface existante du HsmService. Enrichir si nécessaire
Q3 Faut-il utiliser la même clé HSM pour le scellement de l'enveloppe et pour la signature du document, ou deux clés distinctes ? Sécurité Deux clés distinctes recommandées (séparation des responsabilités : pv-master-signing-* pour documents, pv-master-sealing-* pour enveloppes)
Q4 Quel comportement en cas d'indisponibilité du répondeur OCSP : bloquer la génération ou générer avec matériel incomplet ? Disponibilité Générer avec matériel incomplet + flag explicite ocspUnavailable. La preuve reste scellée, seule la preuve de non-révocation est absente
Q5 Le OcspClientService existe-t-il ou doit-il être créé dans le cadre de PD-282 ? Implémentation Vérifier l'existant. Si absent, créer un service minimal (requête HTTP vers le répondeur OCSP identifié par l'extension AIA du certificat)
Q6 Faut-il inclure les certificats racine (root CA) dans les chaînes, ou s'arrêter aux intermédiaires (le tiers fournit sa propre trust store) ? Interopérabilité Inclure la chaîne complète jusqu'à la racine. Le tiers peut ignorer la racine s'il a sa propre trust store, mais l'inclusion facilite la vérification autonome

Annexe A — Flux de scellement (séquence simplifiée)

generateProof()
  ├── 1. Assembler ProofEnvelope (hash doc, signature HSM doc, TSA token, Merkle proof)
  ├── 2. Capturer le matériel de vérification
  │     ├── Récupérer tsaCertificateChain via TsaClientService
  │     ├── Récupérer eidasCertificateChain
  │     ├── Appeler OCSP pour chaque certificat (parallélisé)
  │     └── Construire verificationMaterial { chains, ocspResponses, validationTimestamp, policy }
  ├── 3. Ajouter verificationMaterial à l'enveloppe
  ├── 4. Sceller l'enveloppe
  │     ├── Exclure le champ envelopeSeal (absent à ce stade)
  │     ├── Canonicaliser (JCS / RFC 8785)
  │     ├── Hasher (SHA3-384)
  │     ├── Signer via HsmService (ECDSA P-384)
  │     └── Construire envelopeSeal { algorithm, signature, kid, signedAt, certificateChain }
  ├── 5. Ajouter envelopeSeal à l'enveloppe
  ├── 6. Persister (INSERT atomique — trigger immutabilité actif)
  └── 7. Retourner ProofEnvelope complète

Annexe B — Invariants RFC applicables

Invariant Nom Description
INV-11 EnvelopeSealValid Le sceau de l'enveloppe doit être cryptographiquement valide. Vérifié par recalcul JCS + SHA3-384 + ECDSA verify avec la clé publique du certificat identifié par kid
INV-12 OfflineVerificationMaterialSufficient Le matériel de vérification doit être suffisant pour une validation offline. Vérifié par la présence et la validité de : tsaCertificateChain, eidasCertificateChain, ocspResponses, validationTimestamp