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¶
-
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.
-
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).
-
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.
-
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.
-
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.