1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//! PDF `/Sig` annotation writer — round 30.
//!
//! Symmetric encoder side of the round-27 / round-21 reader. Given a
//! [`oxideav_scene::Scene`] and a [`Signer`] implementation, emits a
//! signed PDF whose AcroForm `/Fields` contains a `/FT /Sig` field whose
//! `/V` points at a signature dictionary carrying the `/ByteRange`
//! placeholders and the PKCS#7 / CMS `SignedData` blob.
//!
//! # ISO references
//!
//! * **ISO 32000-1 §12.7.4.5** — Signature fields (`/FT /Sig`).
//! * **ISO 32000-1 §12.8.1** — Signature dictionaries (`/Type /Sig`,
//! `/Filter /Adobe.PPKLite`, `/SubFilter /adbe.pkcs7.detached`,
//! `/ByteRange [a b c d]`, `/Contents <…hex…>`).
//! * **RFC 5652 §5** — CMS `SignedData` ContentInfo (the bytes that go
//! into `/Contents`).
//! * **RFC 5652 §5.4** — `SignedAttributes` re-tagging from `[0]
//! IMPLICIT` to universal SET for hashing.
//! * **RFC 5652 §11.2** — `messageDigest` signed-attribute.
//!
//! # The byte-range placeholder pattern
//!
//! Per §12.8.1.1, `/ByteRange` covers the entire PDF *except* the bytes
//! between `<` and `>` of `/Contents`. So the encoder:
//!
//! 1. Writes the PDF body up to and including the `<` of `/Contents`.
//! 2. Reserves a fixed-width run of `0` bytes (the placeholder for the
//! hex-encoded signature blob).
//! 3. Writes the closing `>`, the rest of the dictionary, the xref,
//! the trailer, and `%%EOF`.
//! 4. Patches `/ByteRange` in place (the four 10-digit slots reserved
//! earlier) with the actual offsets.
//! 5. Hashes the bytes named by `/ByteRange`, signs the hash, wraps
//! the signature into a CMS `SignedData` ContentInfo, hex-encodes
//! the blob, and overwrites the `0…0` run from step 2 with the hex
//! digits (length-preserving — the budget is reserved generously
//! enough that any RSA-2048 / ECDSA-P256 SHA-256 SignedData fits).
//!
//! Because the bytes between `<` and `>` are *excluded* from
//! `/ByteRange`, step 5's overwrite does not invalidate the hash
//! computed in step 4 — the byte-stable property is what makes this
//! pattern work.
pub use ;
pub use ;