"DOC PAdES-B-LT format + year-9 LTV re-stamping — extend B-T signatures with validation data + re-timestamp before signature/TS authority expires"
§1 — Description (BCP-14 normative)
The DOC service MUST ship LTV extension at services/doc/src/ltv/ extending B-T signatures to B-LT format and re-stamping at year-9, embedding fresh validation data, immutable audit, 4 memory audit kinds.
- MUST validate
ltv_operationagainst closed enum per DEC-1802.
- MUST validate
ltv_statusagainst closed enum per DEC-1803.
- MUST extend B-T → B-LT at
extender.rs::extend(signature)per DEC-1800:
- Fetch cert chain from signature.
- Fetch OCSP/CRL responses for each cert at signature time.
- Embed validation data into PDF (PAdES VRI dictionary) per ETSI EN 319 142-1.
- Re-fetch fresh timestamp per DEC-1804.
- MUST schedule year-9 re-stamping per DEC-1801 — TASK-MCP-007 cron monthly, scans all
doc_documentswith signatures aged ≥9 years.
- MUST never alter the original signature bytes per DEC-1804 — only embed additional validation data + add new timestamp layer.
- MUST define table at migration
0011: ``sql CREATE TABLE doc_ltv_operations ( operation_id UUID PRIMARY KEY, tenant_id UUID NOT NULL, document_id UUID NOT NULL, operation TEXT NOT NULL CHECK (operation IN ('extend_bt_to_blt','restamp_blt')), signature_source TEXT NOT NULL, -- 'qtsp' | 'aatl' | 'vn_ca' | 'imported' original_sig_age_days INT NOT NULL, status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','completed','failed','deferred')), new_validation_data_added BYTEA, new_timestamp_token BYTEA, failure_reason TEXT, trace_id CHAR(32), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), completed_at TIMESTAMPTZ ); CREATE INDEX ltv_ops_doc_idx ON doc_ltv_operations(tenant_id, document_id, created_at DESC); ALTER TABLE doc_ltv_operations ENABLE ROW LEVEL SECURITY; CREATE POLICY ltv_ops_rls ON doc_ltv_operations USING (tenant_id = current_setting('auth.tenant_id')::uuid) WITH CHECK (tenant_id = current_setting('auth.tenant_id')::uuid); REVOKE UPDATE, DELETE ON doc_ltv_operations FROM cyberos_app; GRANT UPDATE (status, new_validation_data_added, new_timestamp_token, failure_reason, completed_at) ON doc_ltv_operations TO cyberos_app;``
- MUST expose endpoints: ``
text POST /v1/doc/documents/{id}/ltv/extend (manual extend B-T → B-LT) POST /v1/doc/documents/{id}/ltv/restamp (manual re-stamp) GET /v1/doc/documents/{id}/ltv/operations``
- MUST emit 4 memory audit kinds per DEC-1805. PII per TASK-MEMORY-111: validation data + TS token hashed.
- MUST thread trace_id from cron / manual → fetcher → writer → audit.
- MUST NOT alter original signature per DEC-1804.
- MUST NOT skip validation data fetch before re-stamp per DEC-1800.
§2 — Why this design
Why LTV (DEC-1800)? Without embedded validation data, signature verification requires reaching OCSP/CRL/cert chain online — services may be gone in 10 years.
Why year-9 (DEC-1801)? Most TS authority certs valid 10 years; re-stamp at year-9 gives buffer.
Why fresh timestamp on re-stamp (DEC-1804)? Re-stamping with expired TS = ineffective; must use active TS authority.
Why preserve original signature (DEC-1804)? Tamper-evident — any modification = legal invalidation. We only add new layers.
§3 — API contract
POST /v1/doc/documents/{id}/ltv/extend
POST /v1/doc/documents/{id}/ltv/restamp
GET /v1/doc/documents/{id}/ltv/operations
Sample operation:
{
"operation_id": "uuid",
"operation": "extend_bt_to_blt",
"signature_source": "aatl",
"original_sig_age_days": 30,
"status": "completed",
"new_validation_data_size_bytes": 8192,
"new_timestamp_authority": "TSA-DigiCert"
}
§4 — Acceptance criteria
- B-T extended to B-LT correctly. 2. Year-9 cron scans all sigs. 3. OCSP/CRL responses embedded. 4. Cert chain embedded. 5. Fresh TS token added. 6. Original signature preserved (byte-identical). 7. ltv_operation enum cardinality 2. 8. ltv_status enum cardinality 4. 9. PAdES VRI dictionary present after extend. 10. 4 memory audit kinds emitted. 11. PII scrubbed (validation data + TS token SHA256). 12. RLS denies cross-tenant. 13. Trace_id preserved. 14. Append-only operations table via REVOKE except status cols. 15. Failure → status=failed; retry. 16. TS authority down → status=deferred; retry next cron. 17. Idempotent (multiple extends OK; each adds layer). 18. Verifiable in Adobe Reader after extend. 19. Composes with TASK-DOC-002/003/004 sigs. 20. OCSP fetch fallback to CRL on failure.
§5 — Verification
#[tokio::test]
async fn extend_adds_vri_to_pdf() {
let ctx = TestContext::with_b_t_signed_pdf().await;
let op = ctx.extend_ltv(ctx.doc_id).await;
assert_eq!(op.status, "completed");
let pdf = ctx.fetch_pdf(ctx.doc_id).await;
assert!(ctx.parse_pades(pdf).has_vri_dictionary());
}
#[tokio::test]
async fn original_signature_preserved() {
let ctx = TestContext::with_b_t_signed_pdf().await;
let original_sig_bytes = ctx.extract_signature_bytes(ctx.doc_id).await;
ctx.extend_ltv(ctx.doc_id).await;
let post_extend_sig = ctx.extract_signature_bytes(ctx.doc_id).await;
assert_eq!(original_sig_bytes, post_extend_sig);
}
#[tokio::test]
async fn year_9_cron_picks_up_aging_sigs() {
let ctx = TestContext::with_sig_age_3300_days().await;
ctx.run_ltv_cron().await;
let op = ctx.fetch_latest_op(ctx.doc_id).await;
assert_eq!(op.operation, "restamp_blt");
}
// 5.4..5.10
§7 — Dependencies
Upstream: TASK-DOC-002. Cross-module: TASK-DOC-003 (AATL composability), TASK-DOC-004 (VN CA composability), TASK-DOC-001 (PDF storage), TASK-MCP-007 (cron), TASK-MEMORY-111 (PII).
§10 — Failure modes
| Failure | Detection | Outcome | Recovery |
|---|---|---|---|
| OCSP unreachable | retry, fallback CRL | sev-2 audit | inherent |
| TS authority down | mark deferred | retry next cron | inherent |
| Cert chain unfetchable | error | failed; sev-1 | manual intervention |
| PDF malformed | parse err | failed; sev-2 | manual review |
| Cron skipped | next run catches | inherent | inherent |
| Sig already B-LT | skip extend | no-op | inherent |
| Year-9 false positive | date math check | inherent | inherent |
| VRI dictionary write fail | rollback | failed | retry |
| Cross-tenant scan | RLS | 0 rows | inherent |
| Multiple cron instances | per-tenant queue | one at a time | inherent |
§11 — Implementation notes
- §11.1 PAdES VRI = Validation Related Info dictionary; appended to PDF, indexed by signature SubFilter.
- §11.2 OCSP fetch via signer cert AIA extension; CRL fetch via cert CDP extension; cache 24h.
- §11.3 TS authority: rotate per partner (DigiCert, GlobalSign, FreeTSA fallback for non-tenant-bound).
- §11.4 memory audit body: doc_id, operation, signature_source, status; validation data SHA256.
- §11.5 Cron: monthly scan
SELECT doc_id WHERE last_ltv_op IS NULL OR last_ltv_op.created_at < now() - interval '9 years'.
End of TASK-DOC-011 spec.