Skip to content

fix(oe-ca-core,oe-conformance,oe-tsa-core): expiration de la clé TSU, contrôlée à chaque signature - #80

Merged
PhilippeVienne merged 1 commit into
devfrom
fix/tsu-key-expiry
Sep 30, 2026
Merged

PhilippeVienne merged 1 commit into
devfrom
fix/tsu-key-expiry

Conversation

@PhilippeVienne

Copy link
Copy Markdown
Contributor

Remplace #54, fermée par GitHub à la suppression de sa branche de base (pile) après la fusion de #76 (ex-#53). Même contenu, rebasé sur dev ; base : dev.

Objet

Constat T-3 de l'audit de préparation eIDAS/WebTrust du 2026-09-25
(docs/AUDIT_2026_09_25.md, EN 319 421 TIS-7.6.7-01/-02/-04/-05/-06,
TIS-7.7.1-09) : la clé de signature d'une TSU n'avait aucune date
d'expiration propre — un processus de longue durée pouvait signer
indéfiniment avec la même clé, y compris au-delà de l'expiration du
certificat lui-même.

Décisions prises avec l'utilisateur avant d'écrire :

  • Certificat tsa_signer : 1 an → 2 ans. Clé : private_key_validity
    = 1 an (plus courte que le certificat, exigence shall).
  • Extension posée et vérifiée à chaque signature, pas seulement
    déclarative : Authority::timestamp refuse (systemFailure) une fois la
    clé expirée, à chaque appel, pas qu'au démarrage.

x509_cert::ext::pkix::PrivateKeyUsagePeriod existe déjà dans la
bibliothèque (pas de DER à la main comme pour #53/T-1) :
oe-ca-core::extensions::private_key_usage_period la pose (non critique,
recommandation RFC 5280), oe_conformance::check_tsu_certificate (le
Profile::check de tsa_signer, donc appelé par Issuer::issue avant tout
enregistrement) exige sa présence et que son notAfter précède celui du
certificat, et oe-tsa-core::Authority met en cache cette date à la
construction pour la revérifier à chaque signature.

Fixture tests/fixtures/tsa/tsu-cert.pem régénérée avec cette extension
(openssl req -addext ne la connaît pas par son nom — donnée en DER brut,
voir tests/fixtures/tsa/README.md pour la commande complète et comment
recalculer la valeur).

Empilée sur #53 (T-1) : mêmes fichiers oe-tsa-core/src/lib.rs.
Base : fix/tsa-gen-time-fraction (#53), pas dev.

Vérifications

  • cargo fmt --check : silencieux.
  • cargo clippy --workspace --all-targets -- -D warnings : silencieux, sur
    toolchain 1.97 (local) et 1.98.1 (CI).
  • cargo test --workspace (avec OE_CASTORE_TEST_DSN) : tout au vert.
  • cargo audit --ignore RUSTSEC-2023-0071 : aucune vulnérabilité.
  • oe-conformance/tests/tsu_certificate.rs (nouveaux tests, émission réelle
    via Issuer::issue, pas de DER construit à la main) : l'émission est
    refusée sans privateKeyUsagePeriod, et refusée quand la clé dépasse la
    validité du certificat.
  • oe-tsa-core/tests/end_to_end.rs (nouveau test) : passé l'expiration de
    la clé (mais avant celle du certificat), l'horodatage est refusé et
    aucune signature n'a lieu (compteur d'appels au signeur, pas
    seulement une erreur rendue après coup). Mutation : en retirant le
    contrôle, ce test échoue bien.

Revue humaine obligatoire

Voir PROVENANCE.md. Chaque case est cochée par le
contributeur humain qui valide la PR, après l'avoir fait lui-même.

  • Revue d'architecture validée par l'humain
  • Code relu et tests unitaires/intégration vérifiés localement
  • Absence de dépendances tierces incompatibles avec la double licence EUPL-1.2 / AGPL-3.0 (make licenses)
  • Validation de l'apport intellectuel et de la paternité humaine sur la modification

Assistance par IA

  • Cette PR a été produite avec l'assistance de Claude Code : les commits concernés portent la remorque Co-authored-by: Claude <noreply@anthropic.com>, auteur et committer restent humains, et scripts/provenance.py archive a été lancé
  • Cette PR a été écrite sans assistance par IA

… contrôlée à chaque signature

Constat T-3 de l'audit du 2026-09-25 (EN 319 421 TIS-7.6.7-01/-02/-04/-05/-06,
TIS-7.7.1-09) : la clé de signature d'une TSU n'avait pas de date d'expiration
propre, et rien n'empêchait un processus de longue durée de signer au-delà de
l'expiration du certificat lui-même. Norme : la clé doit expirer avant le
certificat, l'extension privateKeyUsagePeriod doit le porter, et le système
doit refuser toute signature une fois cette date atteinte.

oe-ca-core :
- profile::tsa_signer() porte maintenant private_key_validity (1 an), et
  validity passe à 2 ans (au lieu d'1 an) pour que la clé ait vraiment un
  cycle de vie plus court que le certificat qui la porte.
- extensions::private_key_usage_period pose l'extension (non critique,
  comme le recommande RFC 5280), via x509_cert::ext::pkix::PrivateKeyUsagePeriod
  (déjà fourni par la bibliothèque, pas d'encodage DER à la main ici).

oe-conformance : check_tsu_certificate (Profile::check de tsa_signer, donc
appelé par Issuer::issue avant tout enregistrement) exige désormais cette
extension et vérifie que son notAfter précède celui du certificat. Nouvelle
fonction publique tsu_private_key_not_after, réutilisée par oe-tsa-core.

oe-tsa-core : Authority met en cache la date d'expiration de la clé à la
construction, et Authority::timestamp la recontrôle à *chaque* appel, avant
la signature — un processus démarré avant l'expiration continue de la
refuser correctement une fois la date dépassée, pas seulement au démarrage.

Fixture tests/fixtures/tsa/tsu-cert.pem régénérée avec privateKeyUsagePeriod
(openssl req -addext ne connaît pas cette extension par son nom : donnée en
DER brut, voir tests/fixtures/tsa/README.md).

- oe-conformance : deux nouveaux tests bout-en-bout (émission réelle via
  Issuer::issue) prouvant le refus d'émission sans l'extension, et quand la
  clé dépasse la validité du certificat.
- oe-tsa-core : nouveau test bout-en-bout prouvant qu'aucune signature n'a
  lieu une fois la clé expirée (compteur d'appels au signeur, pas seulement
  une erreur rendue). Testé par mutation.

Co-authored-by: Claude <noreply@anthropic.com>
@PhilippeVienne
PhilippeVienne merged commit 484f233 into dev Sep 30, 2026
17 checks passed
@PhilippeVienne
PhilippeVienne deleted the fix/tsu-key-expiry branch September 30, 2026 15:06
PhilippeVienne added a commit that referenced this pull request Oct 1, 2026
…a matrice (#84)

Les correctifs de l'audit du 2026-09-25 sont tous sur dev (#52 à #59, via
#76, #80, #82) : la matrice le dit, avec pour chaque ligne repassée en
« couvert » une preuve de mise en service (règle D-2, #79) — pas seulement
un test de bibliothèque.

- bin/tsa-server/tests/serve.rs, le test du binaire, prouve désormais aussi :
  le refus de démarrer quand OPENEIDAS_ACCURACY ne couvre pas la dérive
  tolérée (T-1), le refus d'émettre avec une clé TSU expirée mais un
  certificat encore valide (T-3), la fraction de seconde de genTime (T-1),
  et le journal du jeton relu (série, empreinte soumise, état de l'horloge :
  J-3), en relisant audit-monitor.log après un horodatage réel.
- Le job de démonstration Helm/kind interroge le répondeur OCSP pour un
  numéro jamais émis et exige `unknown` (O-1).
- C-1 : preuve par les tests du binaire ca-server (ARL et certificat de la
  racine servis aux adresses gravées) ; R-2 : étape Helm qui refuse
  l'approbation automatique en production ; R-1 : actions signées relayées
  par ra-console et revue de la voie de secours, toutes deux testées sur les
  binaires.
- Restent en écart, cible resserrée : l'authentification multifacteur
  (GEN-6.5.5-04 : la voie de secours CLI n'a pas de second facteur, son
  contrôle compensatoire — RBAC de l'hôte, trace non authentifiée, revue —
  est nommé dans le mécanisme, décision de l'utilisateur), la durée de
  conservation côté tsa-server (§7.10) et la nouvelle bi-clé à chaque
  renouvellement TSU (TIS-7.6.7). docs/ARCHITECTURE.md décrit le journal
  tel qu'il est.

Bilan : 23 couvertes, 1 implémentée, 10 écarts, 2 hors périmètre (avant :
17 / 1 / 16 / 2). docs/CONFORMITE-ETSI.md régénéré.

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant