Aller au contenu

PD-39 — Retour d'Expérience (REX)

Date : 2025-12-23 User Story : Intégration TSA RFC 3161 par Batch Cryptographique


1. Résumé exécutif

Objectif : Implémenter un système d'horodatage probatoire par batch cryptographique, conforme RFC 3161 et eIDAS, avec preuves d'inclusion Merkle (RFC 9162) et horloge de référence NTS authentifiée.

Résultat : Infrastructure de base livrée (batch, scellement, Merkle, preuves d'inclusion, attestations NTS). Les composants de communication QTSA externe (TsaClientService, TstValidatorService, TrustedListService) sont définis en interfaces mais non implémentés.

Verdict : ✅ ACCEPTÉ — Les écarts bloquants E-01 (WORM) et E-02 (NTS fail-closed) ont été résolus. L'architecture est prête pour l'intégration QTSA externe.


2. Points fluides

  • Architecture modulaire claire : 41 fichiers source organisés en constants/, dto/, entities/, enums/, guards/, interfaces/, processors/, services/, utils/
  • Entités TypeORM complètes : TimestampBatch, BatchItem, BatchSeal, TimestampToken, ClockAttestation avec relations FK correctes
  • MerkleService RFC 6962 : Implémentation conforme avec préfixes 0x00/0x01, tri lexicographique, sérialisation reproductible
  • Preuves d'inclusion RFC 9162 : Format InclusionProofDataV2 avec chemin d'audit L/R
  • Intégration HSM existant (PD-36) : Réutilisation de HsmService pour signatures ECDSA P-384
  • Tests unitaires solides : 307 tests passants, 15 suites de tests couvrant tous les services implémentés
  • DTOs avec validation : class-validator avec regex sur les hashes SHA-256

3. Points difficiles

Obstacle Contexte Résolution
WORM protection DB L'invariant 10 (immuabilité post-conservation) n'était pas garanti au niveau base de données. Le guard API seul était insuffisant. Migration 1733900001000-AddWormProtection.ts ajoutant triggers INSERT/UPDATE/DELETE + event trigger DDL
NTS fail-closed ReferenceClockService lisait observe.json sans vérifier l'authentification NTS effective. Mode permissif par défaut. Ajout de getAuthenticatedTimeStrict() avec vérification UID/permissions + exigence nts_ke_established=true sur sources
Absence de client NTS Node.js Aucune bibliothèque NTS viable en JavaScript/TypeScript Architecture ntpd-rs (démon Rust externe) disciplinant l'horloge système, lecture via observe.json
Complexité ASN.1/RFC 3161 Parsing et validation des structures TST complexes Interfaces définies (ITstValidatorService), implémentation différée
Trusted Lists ETSI Parsing XML volumineux, vérification signatures LOTL/TL nationales Interface prévue, implémentation différée

4. Hypothèses révélées tardivement

Hypothèse Découverte Impact
ntpd-rs doit être installé et configuré L'architecture suppose un démon externe opérationnel avec permissions correctes sur observe.json Documentation déploiement nécessaire, dépendance infra
HSM doit avoir clés pré-provisionnées Labels tsa-batch-seal-key et tsa-clock-attestation-key requis Procédure de provisionnement HSM à documenter
URIs ETSI en HTTP obligatoire Les identifiants http://uri.etsi.org/TrstSvc/... doivent rester HTTP pour compatibilité Trusted Lists Commentaires NOSONAR ajoutés, documentation ETSI TS 119 612 référencée
PostgreSQL event triggers requis Protection DDL contre DROP TRIGGER nécessite event_trigger (superuser) Contrainte d'installation, migration spécifique

5. Invariants complexes

Invariant Difficulté Mécanisme final
#5 — Batch scellé avant horodatage Transition d'état atomique + empêcher extension Statut SEALED + signature HSM + guard API + triggers DB
#8/#9 — Horloge de référence authentifiée Pas de lib NTS Node.js, validation temps authentifié ntpd-rs externe + observe.json + attestations signées HSM
#10 — Éléments immuables Protection multi-couches contre modification Triggers DB (DML) + event trigger (DDL) + RLS + audit PD-17
#6 — Structure déterministe Reproductibilité parfaite de l'arbre Merkle Tri lexicographique strict + préfixes RFC 6962 + sérialisation canonique

6. Dette technique

Élément Description Criticité Ticket suggéré
TsaClientService Client HTTP RFC 3161 non implémenté Élevée PD-39-B
TstValidatorService Validation complète TST (ASN.1, signature, chaîne) non implémentée Élevée PD-39-B
TrustedListService Parsing EU LOTL/TL nationales non implémenté Élevée PD-39-C
QtsaQualificationService Vérification qualification eIDAS non implémentée Élevée PD-39-C
RevocationService CRL/OCSP non implémenté Moyenne PD-39-D
Couverture TSA 23% Tests d'intégration incomplets (services stub) Moyenne Continu
verifyCompleteProof hardcodé tstValid: true en attendant TstValidatorService Faible PD-39-B

7. Risques résiduels

Risque Probabilité Impact Mitigation actuelle Action requise
ntpd-rs non démarré Faible Bloquant Fail-closed, rejet opérations Health check démarrage applicatif
observe.json permissions incorrectes Faible Bloquant Vérification UID/GID/mode Documentation déploiement
HSM indisponible Faible Bloquant Rejet scellement Circuit breaker + alerting
Aucune QTSA configurée Certain (actuel) Bloquant horodatage Interfaces prêtes Implémentation PD-39-B
Trusted List expirée N/A (non implémenté) N/A Implémentation PD-39-C

8. Améliorations processus

Suggestion Justification
Identifier les dépendances infra en amont ntpd-rs et HSM requis dès le début, non découverts initialement
Valider les invariants de sécurité en revue d'architecture E-01 et E-02 auraient pu être identifiés avant implémentation
Découper les US volumineuses PD-39 couvre 10+ services, livraison incrémentale préférable
Définir les interfaces avant implémentation Les interfaces QTSA/TL ont facilité le découpage
Documenter les URIs ETSI dès la spec Évite confusion HTTP vs HTTPS tardive

9. Enseignements clés

  1. Fail-closed par défaut : Tout mécanisme de sécurité probatoire doit rejeter en cas de doute. Le mode permissif initial de l'horloge NTS a causé l'écart E-02.

  2. La protection API est insuffisante : Les guards NestJS protègent les endpoints mais pas la base de données. L'immuabilité probatoire exige des contrôles au niveau DB (triggers, RLS).

  3. Les démons externes sont acceptables : L'absence de bibliothèque NTS Node.js a conduit à utiliser ntpd-rs. Cette architecture découplée fonctionne bien si correctement documentée.

  4. Les standards ETSI utilisent HTTP pour les URIs : Les identifiants ne sont pas des URLs à appeler mais des chaînes de comparaison. Documentation et commentaires NOSONAR essentiels.

  5. Livrer l'infrastructure avant l'intégration externe : L'approche "entities + services internes + interfaces QTSA" permet de valider l'architecture avant la complexité ASN.1/TL.


Fin du retour d'expérience PD-39.