@awacloud/pdf 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/CHANGELOG.md +609 -0
  2. package/LICENSE +661 -0
  3. package/NOTICE +77 -0
  4. package/README.md +363 -2
  5. package/dist/build/index.js +21 -0
  6. package/dist/build/pdf-full-rw.js +10972 -0
  7. package/dist/build/pdf-full-rw.meta.json +105 -0
  8. package/dist/build/pdf-full-rw.min.js +53 -0
  9. package/dist/build/pdf-full.js +6078 -0
  10. package/dist/build/pdf-full.meta.json +90 -0
  11. package/dist/build/pdf-full.min.js +32 -0
  12. package/dist/build/pdf-large-rw.js +10367 -0
  13. package/dist/build/pdf-large-rw.meta.json +99 -0
  14. package/dist/build/pdf-large-rw.min.js +53 -0
  15. package/dist/build/pdf-large.js +5473 -0
  16. package/dist/build/pdf-large.meta.json +84 -0
  17. package/dist/build/pdf-large.min.js +32 -0
  18. package/dist/build/pdf-legacy-rw.js +12402 -0
  19. package/dist/build/pdf-legacy-rw.meta.json +110 -0
  20. package/dist/build/pdf-legacy-rw.min.js +53 -0
  21. package/dist/build/pdf-legacy.js +7508 -0
  22. package/dist/build/pdf-legacy.meta.json +95 -0
  23. package/dist/build/pdf-legacy.min.js +32 -0
  24. package/dist/build/pdf-rw.js +7578 -0
  25. package/dist/build/pdf-rw.meta.json +77 -0
  26. package/dist/build/pdf-rw.min.js +53 -0
  27. package/dist/build/pdf.js +2684 -0
  28. package/dist/build/pdf.meta.json +62 -0
  29. package/dist/build/pdf.min.js +32 -0
  30. package/dist/standalone/pdf-full-rw.js +16798 -0
  31. package/dist/standalone/pdf-full-rw.meta.json +78 -0
  32. package/dist/standalone/pdf-full-rw.min.js +56 -0
  33. package/dist/standalone/pdf-full.js +11904 -0
  34. package/dist/standalone/pdf-full.meta.json +63 -0
  35. package/dist/standalone/pdf-full.min.js +35 -0
  36. package/dist/standalone/pdf-large-rw.js +16193 -0
  37. package/dist/standalone/pdf-large-rw.meta.json +72 -0
  38. package/dist/standalone/pdf-large-rw.min.js +56 -0
  39. package/dist/standalone/pdf-large.js +11299 -0
  40. package/dist/standalone/pdf-large.meta.json +57 -0
  41. package/dist/standalone/pdf-large.min.js +35 -0
  42. package/dist/standalone/pdf-legacy-rw.js +18228 -0
  43. package/dist/standalone/pdf-legacy-rw.meta.json +83 -0
  44. package/dist/standalone/pdf-legacy-rw.min.js +56 -0
  45. package/dist/standalone/pdf-legacy.js +13334 -0
  46. package/dist/standalone/pdf-legacy.meta.json +68 -0
  47. package/dist/standalone/pdf-legacy.min.js +35 -0
  48. package/dist/standalone/pdf-rw.js +13404 -0
  49. package/dist/standalone/pdf-rw.meta.json +50 -0
  50. package/dist/standalone/pdf-rw.min.js +56 -0
  51. package/dist/standalone/pdf.js +8510 -0
  52. package/dist/standalone/pdf.meta.json +35 -0
  53. package/dist/standalone/pdf.min.js +35 -0
  54. package/docs/README.md +53 -0
  55. package/docs/api/README.md +38 -0
  56. package/docs/api/_shared/README.md +91 -0
  57. package/docs/api/action/README.md +29 -0
  58. package/docs/api/action/action.md +81 -0
  59. package/docs/api/action/goTo.md +66 -0
  60. package/docs/api/action/launch.md +58 -0
  61. package/docs/api/action/named.md +55 -0
  62. package/docs/api/action/uri.md +54 -0
  63. package/docs/api/annot/README.md +53 -0
  64. package/docs/api/annot/annot.md +114 -0
  65. package/docs/api/annot/fileAttach.md +53 -0
  66. package/docs/api/annot/freeText.md +68 -0
  67. package/docs/api/annot/ink.md +69 -0
  68. package/docs/api/annot/link.md +74 -0
  69. package/docs/api/annot/markup.md +83 -0
  70. package/docs/api/annot/popup.md +52 -0
  71. package/docs/api/annot/projection.md +56 -0
  72. package/docs/api/annot/redact.md +67 -0
  73. package/docs/api/annot/square.md +87 -0
  74. package/docs/api/annot/stamp.md +54 -0
  75. package/docs/api/annot/text.md +69 -0
  76. package/docs/api/annot/widget.md +69 -0
  77. package/docs/api/associatedFiles/README.md +9 -0
  78. package/docs/api/associatedFiles/associatedFiles.md +78 -0
  79. package/docs/api/bundles/README.md +68 -0
  80. package/docs/api/bundles/dist-matrix.md +165 -0
  81. package/docs/api/bundles/pdf-full.md +148 -0
  82. package/docs/api/bundles/pdf-large.md +144 -0
  83. package/docs/api/bundles/pdf-legacy.md +169 -0
  84. package/docs/api/content/README.md +29 -0
  85. package/docs/api/content/color.md +99 -0
  86. package/docs/api/content/graphics.md +114 -0
  87. package/docs/api/content/images.md +124 -0
  88. package/docs/api/content/ops.md +100 -0
  89. package/docs/api/content/stream.md +107 -0
  90. package/docs/api/content/text.md +98 -0
  91. package/docs/api/crypto/README.md +29 -0
  92. package/docs/api/crypto/aesGcm.md +72 -0
  93. package/docs/api/crypto/permissions.md +79 -0
  94. package/docs/api/crypto/security.md +98 -0
  95. package/docs/api/crypto/standardV4.md +104 -0
  96. package/docs/api/crypto/standardV5.md +84 -0
  97. package/docs/api/crypto/standardV6.md +93 -0
  98. package/docs/api/destination/README.md +9 -0
  99. package/docs/api/destination/destination.md +79 -0
  100. package/docs/api/document/README.md +29 -0
  101. package/docs/api/document/builder.md +281 -0
  102. package/docs/api/document/catalog.md +98 -0
  103. package/docs/api/document/document.md +187 -0
  104. package/docs/api/document/encryptedWriter.md +149 -0
  105. package/docs/api/document/incrementalWriter.md +148 -0
  106. package/docs/api/document/page.md +99 -0
  107. package/docs/api/document/pages.md +82 -0
  108. package/docs/api/document/resources.md +102 -0
  109. package/docs/api/document/writer.md +157 -0
  110. package/docs/api/document/xrefStreamWriter.md +122 -0
  111. package/docs/api/embedded/README.md +13 -0
  112. package/docs/api/embedded/collection.md +80 -0
  113. package/docs/api/embedded/embeddedFile.md +86 -0
  114. package/docs/api/embedded/fileSpec.md +87 -0
  115. package/docs/api/errors.md +110 -0
  116. package/docs/api/extra/3d-richmedia.md +76 -0
  117. package/docs/api/extra/README.md +99 -0
  118. package/docs/api/extra/annot-extended.md +71 -0
  119. package/docs/api/extra/associated-files.md +70 -0
  120. package/docs/api/extra/ccitt-fax-decoder.md +74 -0
  121. package/docs/api/extra/color-spaces-extended.md +72 -0
  122. package/docs/api/extra/content-ops-extended.md +82 -0
  123. package/docs/api/extra/document-parts.md +69 -0
  124. package/docs/api/extra/embedded-files-portfolio.md +87 -0
  125. package/docs/api/extra/font-cid-typed.md +77 -0
  126. package/docs/api/extra/font-color-tagging.md +76 -0
  127. package/docs/api/extra/form-actions-extended.md +75 -0
  128. package/docs/api/extra/info-dict-deprecated.md +72 -0
  129. package/docs/api/extra/jbig2-read.md +80 -0
  130. package/docs/api/extra/legacy-deprecated-annots.md +89 -0
  131. package/docs/api/extra/legacy-deprecated-filters.md +78 -0
  132. package/docs/api/extra/legacy-rc4-read.md +74 -0
  133. package/docs/api/extra/legacy-xfa-read.md +65 -0
  134. package/docs/api/extra/linearization-write.md +71 -0
  135. package/docs/api/extra/misc.md +93 -0
  136. package/docs/api/extra/optional-content-extended.md +83 -0
  137. package/docs/api/extra/pdf-a-output-intent.md +65 -0
  138. package/docs/api/extra/pdf-sandbox.md +76 -0
  139. package/docs/api/extra/pdf-ua-tagged.md +63 -0
  140. package/docs/api/extra/pdf-x-prepress.md +65 -0
  141. package/docs/api/extra/redaction-iso32005.md +65 -0
  142. package/docs/api/extra/shading-typed.md +73 -0
  143. package/docs/api/extra/sig-aes-gcm.md +69 -0
  144. package/docs/api/extra/sig-pades.md +103 -0
  145. package/docs/api/extra/tagged-pdf-typed.md +78 -0
  146. package/docs/api/extra/transparency-typed.md +74 -0
  147. package/docs/api/extra/well-tagged-pdf.md +61 -0
  148. package/docs/api/extra/xmp-extended.md +65 -0
  149. package/docs/api/font/README.md +25 -0
  150. package/docs/api/font/embed.md +157 -0
  151. package/docs/api/font/encoding.md +95 -0
  152. package/docs/api/font/font.md +97 -0
  153. package/docs/api/font/type3.md +89 -0
  154. package/docs/api/form/README.md +35 -0
  155. package/docs/api/form/acroform.md +88 -0
  156. package/docs/api/form/appearance.md +87 -0
  157. package/docs/api/form/button.md +97 -0
  158. package/docs/api/form/choice.md +96 -0
  159. package/docs/api/form/fieldTree.md +93 -0
  160. package/docs/api/form/signature.md +90 -0
  161. package/docs/api/form/text.md +88 -0
  162. package/docs/api/linearization/README.md +11 -0
  163. package/docs/api/linearization/linearization.md +81 -0
  164. package/docs/api/main.md +116 -0
  165. package/docs/api/metadata/README.md +10 -0
  166. package/docs/api/metadata/info.md +70 -0
  167. package/docs/api/metadata/xmp.md +62 -0
  168. package/docs/api/ocg/README.md +23 -0
  169. package/docs/api/ocg/config.md +95 -0
  170. package/docs/api/ocg/ocg.md +77 -0
  171. package/docs/api/outline/README.md +11 -0
  172. package/docs/api/outline/outline.md +107 -0
  173. package/docs/api/pdf.md +152 -0
  174. package/docs/api/prepress/README.md +10 -0
  175. package/docs/api/prepress/outputIntent.md +79 -0
  176. package/docs/api/prepress/pageBoundary.md +75 -0
  177. package/docs/api/sig/README.md +32 -0
  178. package/docs/api/sig/byteRange.md +120 -0
  179. package/docs/api/sig/certChain.md +84 -0
  180. package/docs/api/sig/dss.md +111 -0
  181. package/docs/api/sig/oids.md +76 -0
  182. package/docs/api/sig/sha1.md +72 -0
  183. package/docs/api/sig/sign.md +317 -0
  184. package/docs/api/sig/signature.md +178 -0
  185. package/docs/api/sig/timestamp.md +84 -0
  186. package/docs/api/syntax/README.md +29 -0
  187. package/docs/api/syntax/crossRefStream.md +115 -0
  188. package/docs/api/syntax/filters/README.md +50 -0
  189. package/docs/api/syntax/filters/ascii85.md +76 -0
  190. package/docs/api/syntax/filters/asciiHex.md +73 -0
  191. package/docs/api/syntax/filters/dispatch.md +125 -0
  192. package/docs/api/syntax/filters/flate.md +134 -0
  193. package/docs/api/syntax/filters/runLength.md +78 -0
  194. package/docs/api/syntax/objStream.md +88 -0
  195. package/docs/api/syntax/parser-obj.md +97 -0
  196. package/docs/api/syntax/parser.md +151 -0
  197. package/docs/api/syntax/serializer.md +109 -0
  198. package/docs/api/syntax/tokenizer.md +104 -0
  199. package/docs/api/syntax/trailer.md +85 -0
  200. package/docs/api/syntax/xref.md +139 -0
  201. package/docs/api/tagged/README.md +25 -0
  202. package/docs/api/tagged/classMap.md +67 -0
  203. package/docs/api/tagged/markedContent.md +62 -0
  204. package/docs/api/tagged/parentTree.md +67 -0
  205. package/docs/api/tagged/roleMap.md +67 -0
  206. package/docs/api/tagged/structElement.md +76 -0
  207. package/docs/api/tagged/structTree.md +75 -0
  208. package/docs/guide/coverage.md +113 -0
  209. package/docs/guide/crypto.md +121 -0
  210. package/docs/guide/extending.md +76 -0
  211. package/docs/guide/getting-started.md +75 -0
  212. package/docs/guide/legacy-1.7.md +42 -0
  213. package/docs/guide/pades-integration.md +579 -0
  214. package/docs/guide/read-pdf.md +89 -0
  215. package/package.json +97 -4
  216. package/src/_shared/index.js +179 -0
  217. package/src/action/action.js +119 -0
  218. package/src/action/goTo.js +89 -0
  219. package/src/action/launch.js +61 -0
  220. package/src/action/named.js +54 -0
  221. package/src/action/uri.js +51 -0
  222. package/src/annot/annot.js +212 -0
  223. package/src/annot/fileAttach.js +55 -0
  224. package/src/annot/freeText.js +82 -0
  225. package/src/annot/ink.js +77 -0
  226. package/src/annot/link.js +77 -0
  227. package/src/annot/markup.js +91 -0
  228. package/src/annot/popup.js +53 -0
  229. package/src/annot/projection.js +52 -0
  230. package/src/annot/redact.js +87 -0
  231. package/src/annot/square.js +132 -0
  232. package/src/annot/stamp.js +48 -0
  233. package/src/annot/text.js +54 -0
  234. package/src/annot/widget.js +61 -0
  235. package/src/associatedFiles/associatedFiles.js +86 -0
  236. package/src/bundles/pdf-full.js +91 -0
  237. package/src/bundles/pdf-large.js +81 -0
  238. package/src/bundles/pdf-legacy.js +107 -0
  239. package/src/content/color.js +114 -0
  240. package/src/content/graphics.js +192 -0
  241. package/src/content/images.js +160 -0
  242. package/src/content/ops.js +137 -0
  243. package/src/content/stream.js +154 -0
  244. package/src/content/text.js +125 -0
  245. package/src/crypto/aesGcm.js +123 -0
  246. package/src/crypto/permissions.js +112 -0
  247. package/src/crypto/security.js +327 -0
  248. package/src/crypto/standardV4.js +443 -0
  249. package/src/crypto/standardV5.js +306 -0
  250. package/src/crypto/standardV6.js +334 -0
  251. package/src/destination/destination.js +183 -0
  252. package/src/document/builder.js +618 -0
  253. package/src/document/catalog.js +100 -0
  254. package/src/document/document.js +472 -0
  255. package/src/document/encryptedWriter.js +554 -0
  256. package/src/document/incrementalWriter.js +514 -0
  257. package/src/document/page.js +131 -0
  258. package/src/document/pages.js +103 -0
  259. package/src/document/resources.js +146 -0
  260. package/src/document/writer.js +211 -0
  261. package/src/document/xrefStreamWriter.js +353 -0
  262. package/src/embedded/collection.js +102 -0
  263. package/src/embedded/embeddedFile.js +99 -0
  264. package/src/embedded/fileSpec.js +137 -0
  265. package/src/errors.js +78 -0
  266. package/src/extra/3d-richmedia.js +171 -0
  267. package/src/extra/annot-extended.js +200 -0
  268. package/src/extra/associated-files.js +131 -0
  269. package/src/extra/ccitt-fax-decoder.js +776 -0
  270. package/src/extra/color-spaces-extended.js +196 -0
  271. package/src/extra/content-ops-extended.js +153 -0
  272. package/src/extra/document-parts.js +149 -0
  273. package/src/extra/embedded-files-portfolio.js +234 -0
  274. package/src/extra/font-cid-typed.js +185 -0
  275. package/src/extra/font-color-tagging.js +144 -0
  276. package/src/extra/form-actions-extended.js +196 -0
  277. package/src/extra/info-dict-deprecated.js +137 -0
  278. package/src/extra/jbig2-read.js +169 -0
  279. package/src/extra/legacy-deprecated-annots.js +198 -0
  280. package/src/extra/legacy-deprecated-filters.js +167 -0
  281. package/src/extra/legacy-rc4-read.js +235 -0
  282. package/src/extra/legacy-xfa-read.js +104 -0
  283. package/src/extra/linearization-write.js +97 -0
  284. package/src/extra/misc.js +217 -0
  285. package/src/extra/optional-content-extended.js +142 -0
  286. package/src/extra/pdf-a-output-intent.js +112 -0
  287. package/src/extra/pdf-sandbox.js +88 -0
  288. package/src/extra/pdf-ua-tagged.js +116 -0
  289. package/src/extra/pdf-x-prepress.js +114 -0
  290. package/src/extra/redaction-iso32005.js +136 -0
  291. package/src/extra/shading-typed.js +222 -0
  292. package/src/extra/sig-aes-gcm.js +135 -0
  293. package/src/extra/sig-pades.js +242 -0
  294. package/src/extra/tagged-pdf-typed.js +203 -0
  295. package/src/extra/transparency-typed.js +135 -0
  296. package/src/extra/well-tagged-pdf.js +138 -0
  297. package/src/extra/xmp-extended.js +190 -0
  298. package/src/font/embed.js +480 -0
  299. package/src/font/encoding.js +92 -0
  300. package/src/font/font.js +101 -0
  301. package/src/font/type3.js +75 -0
  302. package/src/form/acroform.js +94 -0
  303. package/src/form/appearance.js +90 -0
  304. package/src/form/button.js +105 -0
  305. package/src/form/choice.js +152 -0
  306. package/src/form/fieldTree.js +120 -0
  307. package/src/form/signature.js +100 -0
  308. package/src/form/text.js +101 -0
  309. package/src/linearization/linearization.js +107 -0
  310. package/src/main.js +411 -0
  311. package/src/metadata/info.js +87 -0
  312. package/src/metadata/xmp.js +62 -0
  313. package/src/ocg/config.js +156 -0
  314. package/src/ocg/ocg.js +124 -0
  315. package/src/outline/outline.js +157 -0
  316. package/src/pdf.js +133 -0
  317. package/src/prepress/outputIntent.js +118 -0
  318. package/src/prepress/pageBoundary.js +108 -0
  319. package/src/sig/byteRange.js +306 -0
  320. package/src/sig/certChain.js +247 -0
  321. package/src/sig/dss.js +317 -0
  322. package/src/sig/oids.js +157 -0
  323. package/src/sig/sha1.js +142 -0
  324. package/src/sig/sign.js +1899 -0
  325. package/src/sig/signature.js +1441 -0
  326. package/src/sig/timestamp.js +236 -0
  327. package/src/syntax/crossRefStream.js +133 -0
  328. package/src/syntax/filters/ascii85.js +122 -0
  329. package/src/syntax/filters/asciiHex.js +83 -0
  330. package/src/syntax/filters/dispatch.js +176 -0
  331. package/src/syntax/filters/flate.js +316 -0
  332. package/src/syntax/filters/runLength.js +96 -0
  333. package/src/syntax/objStream.js +99 -0
  334. package/src/syntax/parser-obj.js +52 -0
  335. package/src/syntax/parser.js +321 -0
  336. package/src/syntax/serializer.js +221 -0
  337. package/src/syntax/tokenizer.js +290 -0
  338. package/src/syntax/trailer.js +76 -0
  339. package/src/syntax/xref.js +341 -0
  340. package/src/tagged/classMap.js +81 -0
  341. package/src/tagged/markedContent.js +123 -0
  342. package/src/tagged/parentTree.js +126 -0
  343. package/src/tagged/roleMap.js +107 -0
  344. package/src/tagged/structElement.js +138 -0
  345. package/src/tagged/structTree.js +94 -0
@@ -0,0 +1,317 @@
1
+ ---
2
+ module: pdfSign
3
+ category: pdf/sig
4
+ dependencies: [pdfErrors, pdfSigOids, pdfByteRange, pdfDssBuilder, pdfIncrementalWriter, pdfParser, asn1, rsa, ecc, ed25519, sha256, sha384, sha512, bitArray, pdfDocument, pdfSecurity, pdfStandardV4, pdfStandardV5, pdfStandardV6]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfSign
11
+
12
+ > PAdES signature generation (write side) — levels B / T / LT / LTA.
13
+
14
+ **Module** `pdfSign` | **Source** `packages/front/office/pdf/src/sig/sign.js` | **Deps** `pdfErrors`, `pdfSigOids`, `pdfByteRange`, `pdfDssBuilder`, `pdfIncrementalWriter`, `pdfParser`, `asn1`, `rsa`, `ecc`, `ed25519`, `sha256`, `sha384`, `sha512`, `bitArray`, `pdfDocument`, `pdfSecurity`, `pdfStandardV4`, `pdfStandardV5`, `pdfStandardV6` | **Worker-safe** yes
15
+
16
+ Companion of [`pdfSignature`](./signature.md) (verify side). Produces a
17
+ detached PKCS#7/CMS `SignedData` blob and embeds it into a signature
18
+ dictionary whose `/ByteRange` covers the whole document minus the
19
+ whole `/Contents` `<…>` token, delimiters included (ISO 32000-2 §12.8.3.3.1
20
+ — see [`pdfByteRange`](./byteRange.md)); `_emitWithPlaceholder`'s
21
+ `contentsOffset` / `contentsLength` still name the hex-digit span. Algorithms: RSA-PSS, ECDSA (P-256/P-384/P-521),
22
+ Ed25519 — PKCS#1 v1.5 is deliberately refused (fw policy, NIST SP
23
+ 800-131A Rev.2). ECDSA signature values are DER `ECDSA-Sig-Value`
24
+ (RFC 3279 §2.2.3); Ed25519 always uses SHA-512 (RFC 8419 §3.1).
25
+ **Default `subFilter` is `adbe.pkcs7.detached`** — a PAdES
26
+ emitter MUST explicitly pass `subFilter: 'ETSI.CAdES.detached'`.
27
+
28
+ ## PAdES levels
29
+
30
+ | Level | Requires | Behavior |
31
+ |-------|----------|----------|
32
+ | `B` (default) | — | Single embedded signature, `eContentInfo` absent, no `signedAttrs` unless `opts.useSignedAttrs`. |
33
+ | `T` | `opts.tsaSign` callback | Adds `signedAttrs` (contentType, messageDigest, signingTime, ESS `signing-certificate-v2`) and an `unsignedAttrs` RFC 3161 timestamp token. |
34
+ | `LT` | `T` requirements + `pdfDssBuilder`/`pdfDocument` (always present via the registered `modules` deps) | As `T`, then appends a DSS (`/Certs`, `/OCSPs`, `/CRLs`, `/VRI`) and an updated Catalog via an incremental update. |
35
+ | `LTA` | `LT` requirements | As `LT`, then appends a second incremental update carrying a `/DocTimeStamp` (fresh `tsaSign` call over the LT bytes). |
36
+
37
+ Every level signs by **incremental update** (§7.5.6, non-destructive): the
38
+ base bytes are kept verbatim and the signature object is appended through
39
+ [`pdfIncrementalWriter`](../document/incrementalWriter.md). The update section
40
+ therefore takes the form of the base's newest cross-reference section
41
+ (classical table or cross-reference stream), and its `/Root`, `/Info` and
42
+ `/ID` come from the newest-first merged trailer. The signature takes the
43
+ first object number at or past the merged `/Size`, so an object held in an
44
+ object stream is never overwritten. The fixed-width `/ByteRange`
45
+ and `/Contents` placeholders are found inside the signature object from its
46
+ own offset, and they are patched without changing the byte length. `LT`
47
+ adds a second update: the DSS, plus the Catalog re-defined under its own
48
+ number with `/DSS`. The Catalog is resolved through `readDocument` from the
49
+ trailer `/Root`, wherever it lives, including inside an object stream.
50
+ `LTA` adds a third update, the DocTimeStamp, appended the same way
51
+ as the signature. A hybrid-reference base (a classical trailer carrying
52
+ `/XRefStm`) is refused, and nothing is written.
53
+
54
+ The `pdfParser` dependency is no longer read. It keeps its position so that
55
+ code calling the factory with positional arguments still works.
56
+ `pdfDocument` comes next. Every level needs it, because the signature
57
+ field is written from the Catalog and page 1 that `readDocument` resolves.
58
+ `pdfSecurity`, `pdfStandardV4`, `pdfStandardV5` and `pdfStandardV6` are
59
+ appended last. They are read only when the base is encrypted, so a
60
+ hand-wired factory that signs only unencrypted documents may pass `null`
61
+ for them.
62
+
63
+ ## What the update contains
64
+
65
+ ISO 32000-2 §12.7.5.5 makes a signature dictionary the value (`/V`) of a
66
+ signature field (`/FT /Sig`), and §12.8.5.2 says a document timestamp is
67
+ found the same way, by examining signature fields. So the incremental
68
+ update that carries a signature dictionary also carries the field that
69
+ holds it:
70
+
71
+ | Object | Content |
72
+ |--------|---------|
73
+ | Signature dictionary | `/Type /Sig` (`/Type /DocTimeStamp` for the LTA timestamp), `/Filter /Adobe.PPKLite`, `/SubFilter`, `/ByteRange`, `/Contents`. It takes the first object number at or past the merged `/Size`. |
74
+ | Field / widget | One object, the field dictionary merged with its widget annotation (§12.7.4, §12.5.6.19), numbered right after the signature: `/Type /Annot`, `/Subtype /Widget`, `/FT /Sig`, `/T (Signature<n>)`, `/V` → the signature dictionary, `/Rect [0 0 0 0]` (invisible), `/F 132` (Print + Locked), `/P` → page 1. `<n>` is the lowest index no root field of the document already uses, so a second `sign()` writes `Signature2`. |
75
+ | Page 1 | Re-emitted under its own number with the widget appended to `/Annots`. If `/Annots` is an indirect array, that array object is re-emitted instead and the page is not. Page 1 is the first leaf of the page tree. |
76
+ | `/AcroForm` | `/Fields` gets the new field appended, and `/SigFlags` is set to `3` (SignaturesExist + AppendOnly). An indirect `/AcroForm` is re-emitted under its own number. A direct or absent one is written into a re-emission of the Catalog. An indirect `/Fields` array is re-emitted under its own number. |
77
+
78
+ Every entry these objects already had is copied as it is, so existing form
79
+ fields, annotations and `/AcroForm` keys (`/DA`, `/DR`, `/NeedAppearances`
80
+ and so on) are kept. All new objects come before the update's
81
+ cross-reference section, so the `/ByteRange` covers them like every other
82
+ byte. `LT` copies the Catalog, `/AcroForm` included, when it adds `/DSS`.
83
+ `LTA` then appends a second field for its `/DocTimeStamp` in the timestamp's
84
+ own update.
85
+
86
+ ### Ed25519: the ISO/TS 32002 declaration
87
+
88
+ EdDSA signatures come from ISO/TS 32002, which requires "PDF documents
89
+ using enhancements described in this document" to declare it in the
90
+ Catalog (ISO/TS 32002 §4). For `algorithm: 'ed25519'`, at every level and
91
+ with every `subFilter`, the signing update therefore also re-emits the
92
+ Catalog under its own number with:
93
+
94
+ - `/Extensions` holding the prefix `ISO_` → a developer extensions
95
+ dictionary (ISO 32000-2 §7.12.3) with exactly `/Type /DeveloperExtensions`,
96
+ `/BaseVersion /2.0`, `/ExtensionLevel 32002`, `/ExtensionRevision (:2022)`
97
+ and `/URL (https://www.iso.org/standard/45875.html)`;
98
+ - `/Version /2.0` when the document's effective version is below 2.0: the
99
+ Catalog `/Version` name when there is one, else the header version
100
+ (ISO 32000-2 §7.7.2, the entry exists so that an incremental update can
101
+ raise the version; ISO/TS 32002 Table 2 marks EdDSA as PDF 2.x). A PDF 2.0
102
+ document gets no `/Version` entry. A `/Version` that is not a name counts
103
+ as absent.
104
+
105
+ The declaration is merged with what the document already has (ISO 32000-2
106
+ §7.12.2: the value of a prefix is a developer extensions dictionary or an
107
+ array of them):
108
+
109
+ | Existing `/Extensions` | Result |
110
+ |------------------------|--------|
111
+ | absent | `<< /ISO_ ext >>` |
112
+ | present, no `ISO_` | `ISO_` added; the other prefixes (`ADBE_`, …) kept |
113
+ | `ISO_` a dictionary at `/ExtensionLevel 32002` | unchanged — signing an already declared document again adds nothing |
114
+ | `ISO_` a dictionary at another level | `ISO_` becomes the array `[existing ext]` |
115
+ | `ISO_` an array | `ext` appended, unless an element is already at level 32002 |
116
+ | any of these held by an indirect reference | resolved; the merged result is written as a direct dictionary in the Catalog, the referenced object stays in the file, no longer referenced by it |
117
+ | any other shape (`/Extensions 5`, an `ISO_` string, an array element that is not a dictionary) | `pdf/sign/bad-extensions`, nothing written |
118
+
119
+ The Catalog is re-emitted whenever the declaration or the version changes
120
+ it, including when the `/AcroForm` is indirect (otherwise the signature
121
+ field alone does not touch the Catalog); every other Catalog entry is
122
+ copied as it is. The `LT` and `LTA` updates copy the Catalog, so the
123
+ declaration stays in the newest Catalog. ECDSA and RSA-PSS signatures do
124
+ not touch `/Extensions` or `/Version`.
125
+
126
+ **Viewers.** Adobe Acrobat Reader does not validate Ed25519 (EdDSA)
127
+ signatures: it reports an error about the formatting of the signature,
128
+ with or without the declaration, and also on an Ed25519 signature produced
129
+ by OpenSSL (measured 2026-10-05). OpenSSL 3.5 and later verify them
130
+ (`openssl cms -verify`). Use ECDSA P-256 where Acrobat interoperability
131
+ matters — see the [PAdES guide](../../guide/pades-integration.md).
132
+
133
+ ### Encrypted base
134
+
135
+ A base whose trailer carries `/Encrypt` gets the same field, with its
136
+ field name encrypted:
137
+
138
+ - **Password.** `opts.password` is required. It may be the owner or the
139
+ user password, and `''` is a valid empty user password. The document key
140
+ is derived from it through the standard security handler, once per
141
+ `sign()` call and before anything is written.
142
+ - **Permissions.** With the user password, `/P` must grant bit 4 (modify)
143
+ and bit 6 (annotations and form fields), ISO 32000-2 Table 22. The owner
144
+ password is not checked against `/P`.
145
+ - **Supported encryption.** AES only, for both the string and the stream
146
+ crypt filters: V=4 R=4 with `AESV2`, V=5 R=5 and V=5 R=6 with `AESV3`.
147
+ RC4 (V below 4, or a `/V2` crypt filter), AES-GCM (`AESV4`, ISO/TS
148
+ 32003) and any handler other than `/Standard` are refused with a typed
149
+ error. Nothing is ever signed without its field.
150
+ - **What is encrypted.** The new field's `/T` is encrypted with the string
151
+ crypt filter, keyed by the field's own object number, behind a fresh
152
+ 16-byte IV from `opts.randomBytes` (default `crypto.getRandomValues`).
153
+ When the string filter is `Identity`, the name is written in clear.
154
+ The signature dictionary's `/Contents` is never encrypted (ISO 32000-2
155
+ §7.6.2), and `/ByteRange` holds integers. Re-emitted objects (Catalog,
156
+ page 1, `/AcroForm`, `/Fields`) keep their number and generation, so the
157
+ encrypted strings they already held keep their key.
158
+ - **Ed25519 declaration.** The two new strings of the ISO/TS 32002
159
+ dictionary (`/ExtensionRevision`, `/URL`) are encrypted with the string
160
+ crypt filter under the Catalog's object number and generation, each
161
+ behind a fresh IV; names and integers are never encrypted. The strings
162
+ of an indirect `/Extensions` value that is inlined into the Catalog are
163
+ decrypted under their former object and encrypted again under the
164
+ Catalog's, since the V=4 key depends on the object number.
165
+ - **Trailer.** Every incremental update written over an encrypted base
166
+ repeats the base's `/Encrypt` in its trailer or cross-reference stream
167
+ dictionary (ISO 32000-2 §7.5.6).
168
+ - **Levels LT and LTA.** Levels LT and LTA are supported on an encrypted
169
+ base. The DSS certificate, OCSP and CRL streams, any VRI timestamp
170
+ stream and the VRI `/TU` string are encrypted with the document key
171
+ (stream and string crypt filters of the base's `/Encrypt`), as is the
172
+ DocTimeStamp field's `/T`. Each of these strings and streams gets its
173
+ own fresh 16-byte IV from `opts.randomBytes`. The hexadecimal
174
+ `/Contents` of the `/Sig` and `/DocTimeStamp` dictionaries is never
175
+ encrypted (ISO 32000-2 §7.6.2). Every incremental update repeats the
176
+ base's `/Encrypt` (§7.5.6). Copied objects (Catalog, page, AcroForm)
177
+ keep their existing ciphertext under their own object numbers.
178
+
179
+ To pick a field name that is not taken yet, the existing root field names
180
+ are decrypted first.
181
+
182
+ ### Signed attributes
183
+
184
+ When signed attributes are emitted (levels T, LT and LTA, or
185
+ `useSignedAttrs: true`), they are written in DER `SET OF` order. Each
186
+ attribute is encoded first. The encodings are then sorted as unsigned byte
187
+ strings, and an encoding that is a prefix of a longer one sorts first
188
+ (X.690 §11.6). The signature covers these sorted bytes (RFC 5652 §5.4).
189
+ A verifier that re-encodes the attributes before it checks the signature,
190
+ as OpenSSL does for Ed25519, therefore checks the bytes that were signed.
191
+ Signatures written in the earlier fixed order (contentType, messageDigest,
192
+ signingTime, signing-certificate-v2) still verify with `pdfSignature`,
193
+ which checks the attributes as received.
194
+
195
+ ## Resolve
196
+
197
+ ```js
198
+ const s = runtime.resolve('pdfSign');
199
+ // Returns: { sign, _buildPkcs7, _buildSignedAttrs, _sortDerSetOf,
200
+ // _buildUnsignedAttrsTsa, _extractIssuerSerial,
201
+ // _emitWithPlaceholder, _hashBytes, _toDer, HASH_TABLE }
202
+ ```
203
+
204
+ The factory also returns internal helpers with a leading underscore,
205
+ exposed for white-box testing only — prefer `sign` for the stable contract.
206
+
207
+ ## API
208
+
209
+ | Method | Signature | Returns |
210
+ |--------|-----------|---------|
211
+ | `sign` | `(pdfBytes: Uint8Array, opts: SignOpts) => Uint8Array` | The signed PDF bytes: the base kept verbatim plus one incremental update for the signature and its field, then one for the DSS (`LT`/`LTA`) and one for the DocTimeStamp and its field (`LTA`). |
212
+ | `HASH_TABLE` | `{ sha256, sha384, sha512 }` → `{ mod, oid, len }` | The supported digest algorithms, by `opts.hashAlg` name. |
213
+ | `_buildPkcs7` / `_buildSignedAttrs` / `_sortDerSetOf` / `_buildUnsignedAttrsTsa` / `_extractIssuerSerial` / `_emitWithPlaceholder` / `_hashBytes` / `_toDer` | internal helpers | Returned for white-box tests only; not a stable contract — use `sign`. |
214
+
215
+ ### `SignOpts`
216
+
217
+ ```js
218
+ {
219
+ cert: Uint8Array | string, // X.509 DER bytes or PEM string
220
+ privateKey: // algorithm-specific:
221
+ { n, e, d } // RSA-PSS — Uint8Array each
222
+ | { curve, secretKey } // ECDSA — ecc.curves.c256|c384|c521 + ecc.ecdsa.secretKey
223
+ | Uint8Array, // Ed25519 — 64 bytes (seed || pub)
224
+ algorithm: 'rsa-pss' | 'ecdsa' | 'ed25519',
225
+ hashAlg?: 'sha256' | 'sha384' | 'sha512', // default 'sha256'; 'sha512' only (and default) for Ed25519
226
+ level?: 'B' | 'T' | 'LT' | 'LTA', // default 'B'
227
+ subFilter?: string, // default 'adbe.pkcs7.detached'
228
+ useSignedAttrs?: boolean, // default false for level 'B'
229
+ placeholderBytes?: number, // default 8192
230
+ docTimeStamp?: boolean, // internal — DocTimeStamp object emission
231
+ signingTime?: Date,
232
+ tsaSign?: (args: { digest, hashAlg }) => Uint8Array, // required for T/LT/LTA
233
+ dss?: { certs?, ocsps?, crls?, vri?, autoVri?, vriTime? }, // LT/LTA — see pdfDssBuilder
234
+ docTimeStampPlaceholder?: number, // LTA — default = placeholderBytes
235
+ password?: string | Uint8Array, // encrypted base: owner or user password ('' = empty user password)
236
+ randomBytes?: (n: number) => Uint8Array // encrypted base: IV source (field names, DSS strings and streams), default crypto.getRandomValues
237
+ }
238
+ ```
239
+
240
+ ## Examples
241
+
242
+ ### Level B — RSA-PSS, PAdES `SubFilter`
243
+
244
+ ```js
245
+ const s = runtime.resolve('pdfSign');
246
+ const signed = s.sign(pdfBytes, {
247
+ cert, privateKey: { n, e, d },
248
+ algorithm: 'rsa-pss', hashAlg: 'sha256',
249
+ subFilter: 'ETSI.CAdES.detached' // required for PAdES — not the default
250
+ });
251
+ ```
252
+
253
+ ### Level T — with a timestamp authority callback
254
+
255
+ ```js
256
+ const signed = s.sign(pdfBytes, {
257
+ cert, privateKey, algorithm: 'ecdsa',
258
+ level: 'T',
259
+ tsaSign: ({ digest, hashAlg }) => callRealTsa(digest, hashAlg) // returns RFC 3161 TimeStampToken DER
260
+ });
261
+ ```
262
+
263
+ ### Level LTA — full chain with DSS + DocTimeStamp
264
+
265
+ ```js
266
+ const signed = s.sign(pdfBytes, {
267
+ cert, privateKey, algorithm: 'ed25519',
268
+ level: 'LTA',
269
+ tsaSign: myTsaCallback,
270
+ dss: { certs: [leafDer, caDer], ocsps: [ocspDer], autoVri: true }
271
+ });
272
+ ```
273
+
274
+ ## Errors
275
+
276
+ Raised as `ContractError` unless noted.
277
+
278
+ | Code | When |
279
+ |------|------|
280
+ | `pdf/sign/bad-input` | `pdfBytes` not `Uint8Array`, or a cert/privateKey argument neither `Uint8Array` nor PEM string. |
281
+ | `pdf/sign/bad-opts` | `opts` missing or not an object. |
282
+ | `pdf/sign/level-not-implemented` | `opts.level` outside `B`/`T`/`LT`/`LTA`. |
283
+ | `pdf/sign/no-dss-builder` | Level `LT`/`LTA` requested without `pdfDssBuilder` wired. |
284
+ | `pdf/sign/no-document-reader` | Any level requested without `pdfDocument` wired (the signature field needs the Catalog and page 1). |
285
+ | `pdf/sign/no-incremental-writer` | Any level requested without `pdfIncrementalWriter` wired. |
286
+ | `pdf/sign/no-algorithm` | `opts.algorithm` missing. |
287
+ | `pdf/sign/bad-hash-alg` | `opts.hashAlg` outside `sha256`/`sha384`/`sha512`. |
288
+ | `pdf/sign/ed25519-requires-sha512` | `algorithm: 'ed25519'` with an `opts.hashAlg` other than `sha512` (RFC 8419 §3.1); `context.hashAlg` names it. Omit `hashAlg` or pass `'sha512'`. |
289
+ | `pdf/sign/tsa-required-for-level-T` | Level `T`/`LT`/`LTA` without `opts.tsaSign`. |
290
+ | `pdf/sign/tsa-bad-result` / `tsa-bad-result-lta` | `tsaSign` did not return a `Uint8Array`. |
291
+ | `pdf/sign/cert-parse` | Cert DER doesn't parse as a valid X.509 SEQUENCE (issuer/serial extraction). |
292
+ | `pdf/sign/unknown-hash` / `unknown-sigalg` / `unknown-algorithm` | Unsupported `hashAlg`/`signatureAlg`/`algorithm` value reaching the PKCS#7 builder or signer dispatch. |
293
+ | `pdf/sign/no-startxref` / `bad-startxref` | Base `pdfBytes` has no (or an unparsable) `startxref` — required to append the placeholder signature object. |
294
+ | `pdf/sign/no-trailer` | No cross-reference section of the base supplies a usable `/Size` and `/Root`. |
295
+ | `pdf/incremental/hybrid-base` (`RenderError`) | The base is a hybrid-reference file; propagated from `pdfIncrementalWriter`, nothing written. `pdf/incremental/unsupported-base` likewise when `startxref` designates neither a table nor an xref stream. |
296
+ | `pdf/sign/br-placeholder-missing` / `br-overflow` | Internal `/ByteRange` / `/Contents` placeholder location or patching failed (should not occur in practice). |
297
+ | `pdf/sign/no-rsa` / `no-ecc` / `no-ed25519` (`EncryptionError`) | The matching fw crypto primitive (`rsa.pssSign`, `ecc.ecdsa`, `ed25519.sign`) is unavailable. |
298
+ | `pdf/sign/bad-rsa-key` / `bad-ecdsa-key` / `bad-ed25519-key` | `privateKey` shape doesn't match the selected `algorithm`. |
299
+ | `pdf/sign/rsa-failed` / `ed25519-failed` (`EncryptionError`) | The underlying fw signer returned `false`. |
300
+ | `pdf/sign/pkcs7-too-large` | The built PKCS#7 blob exceeds `placeholderBytes`. |
301
+ | `pdf/sign/hex-overflow` / `dts-hex-overflow` | PKCS#7 (or TimeStampToken) hex exceeds the reserved `/Contents` placeholder length. |
302
+ | `pdf/sign/tst-too-large` | LTA `DocTimeStamp` TimeStampToken exceeds its placeholder. |
303
+ | `pdf/sign/bad-extensions` | `algorithm: 'ed25519'` and the Catalog `/Extensions` (or its `ISO_` entry, or an element of an `ISO_` array) is not a dictionary, an array of dictionaries or a reference to one (ISO 32000-2 §7.12). `context: { shape }` names the offending value's type. Nothing is written. |
304
+ | `pdf/sign/catalog-not-found` | The trailer `/Root` does not resolve to a dictionary (signature field, or the LT/LTA Catalog update). |
305
+ | `pdf/sign/no-security-handler` | Encrypted base, and `pdfSecurity`, `pdfStandardV4`, `pdfStandardV5` or `pdfStandardV6` is not wired. |
306
+ | `pdf/sign/encrypted-password-required` | Encrypted base without `opts.password`. Pass `''` for an empty user password. |
307
+ | `pdf/sign/encrypted-bad-password` | `opts.password` is neither the owner nor the user password. The password is not echoed in the error. |
308
+ | `pdf/sign/encrypted-unsupported` | Encryption that cannot be signed: `context.filter` names a handler other than `Standard`; `context.reason` is `'rc4'` (V below 4, or a `/V2` crypt filter), `'aes-gcm'` (`AESV4`) or `'no-id'` (V=4 without a trailer `/ID`); `context.cause` carries the handler's error code for an unreadable or unsupported `/Encrypt`. |
309
+ | `pdf/sign/encrypted-permission-denied` | User password, and `/P` lacks bit 4 or bit 6. `context: { P, required: ['modify', 'annot'] }`. Use the owner password. |
310
+ | `pdf/sign/no-random` (`EncryptionError`) | Encrypted base, and neither `opts.randomBytes` nor `crypto.getRandomValues` is available for the IV. |
311
+
312
+ ## See also
313
+
314
+ - [`pdfSignature`](./signature.md) — verify side (the counterpart this module's output is checked against).
315
+ - [`pdfDssBuilder`](./dss.md) — DSS construction for levels LT/LTA.
316
+ - [`pdfByteRange`](./byteRange.md) · [`pdfTimestamp`](./timestamp.md) · [`pdfCertChain`](./certChain.md)
317
+ - [`pdfIncrementalWriter`](../document/incrementalWriter.md) — underlying append mechanism for every level.
@@ -0,0 +1,178 @@
1
+ ---
2
+ module: pdfSignature
3
+ category: pdf/sig
4
+ dependencies: [pdfErrors, pdfParser, pdfSigOids, asn1, rsa, ecc, ed25519, sha256, sha384, sha512, bitArray]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfSignature
11
+
12
+ > Digital signature handler — ISO 32000-2 §12.8 + ISO TS 32001 (CAdES) + ISO TS 32002 (Ed25519).
13
+
14
+ **Module** `pdfSignature` | **Source** `packages/front/office/pdf/src/sig/signature.js` | **Deps** `pdfErrors`, `pdfParser`, `pdfSigOids`, `asn1`, `rsa`, `ecc`, `ed25519`, `sha256`, `sha384`, `sha512`, `bitArray` | **Worker-safe** yes
15
+
16
+ Typing and end-to-end verification of PDF signatures (detached PKCS#7/CMS). Supported SubFilters: `adbe.pkcs7.detached`, `adbe.pkcs7.sha1` (legacy), `ETSI.CAdES.detached`, `ETSI.RFC3161` (timestamp only), plus Ed25519 (ISO TS 32002). `verifySignature` reconstructs the `/ByteRange`-covered bytes, recomputes the digest, locates the signer's certificate inside the embedded PKCS#7 `SignedData`, and **does dispatch and execute** the public-key check itself (`rsa.pssVerify` / ECDSA / `ed25519.verify` via the internal `verifyPk` dispatcher) — see § *Semantics of `verified` vs `valid` vs `pkVerified`* below. The result's `valid` field is a deprecated alias of `verified`: read `verified`.
17
+
18
+ ## Resolve
19
+
20
+ ```js
21
+ const sig = runtime.resolve('pdfSignature');
22
+ // Returns: { typeSignature, verifySignature, verifyAllSignatures, verifyPk,
23
+ // locatePkcs7, DIGEST_OIDS, SIG_OIDS }
24
+ ```
25
+
26
+ ## API
27
+
28
+ | Method | Signature | Returns |
29
+ |--------|-----------|---------|
30
+ | `typeSignature` | `(dict, refInfo?) => Signature` | Strict typing, §12.8.1 Table 252. |
31
+ | `verifySignature` | `(typedSig, documentBytes, fwBundle?) => VerifyResult` | Full verification — digests `/ByteRange`, locates the signer cert, and runs the public-key check. |
32
+ | `verifyAllSignatures` | `(documentBytes, fwBundle?) => { signatures: VerifyResult[], timestamps: TsVerifyResult[] }` | Scans the raw bytes for every `/Type /Sig` and `/Type /DocTimeStamp` object (across incremental updates) and verifies each. |
33
+ | `verifyPk` | `(args: { algorithm, pubKey, signature, message?, digest?, hashMod?, sLen? }) => { verified: boolean, code?: string, error?: string }` | Public-key verification primitive dispatcher — routes to `rsa.pssVerify` (`'rsa-pss'`), fw's deliberate RSA PKCS#1 v1.5 refusal (`'rsa-v15'`/`'rsa'`), ECDSA (`'ecdsa'`/`'ecc'`) or `ed25519.verify` (`'ed25519'`). For ECDSA, `signature` is the DER `ECDSA-Sig-Value` or the legacy fixed-width raw r‖s (DER tried first; anything else → `pdf/sig/verify-pk/bad-ecdsa-sig`). |
34
+ | `locatePkcs7` | `(blob: Uint8Array, asn1Mod?) => asn1Children \| false` | Decodes the CMS `ContentInfo` → `SignedData` and returns its parsed children (`false` on malformed input). |
35
+
36
+ `DIGEST_OIDS` and `SIG_OIDS` (constants, re-exported from `pdfSigOids`) are also returned for callers that need to map OIDs to algorithm names directly.
37
+
38
+ The factory also returns five internal helpers with a leading underscore
39
+ (`_hashByteRange`, `_scanSignatureObjects`, `_verifyPkcs7Signature`,
40
+ `_verifyTsaSignature`, `_ecdsaSigToRaw`) — exposed for internal reuse/testing, not part of the
41
+ stable public contract; prefer the methods above.
42
+
43
+ ### Shape `Signature`
44
+
45
+ ```js
46
+ {
47
+ kind: 'Sig' | 'DocTimeStamp',
48
+ filter, subFilter, contents: Uint8Array,
49
+ byteRange: [start1, len1, start2, len2],
50
+ reference, cert, name, m, location, reason, contactInfo,
51
+ v, propBuild, propAuthTime, propAuthType,
52
+ raw // the source dict
53
+ }
54
+ ```
55
+
56
+ ## Examples
57
+
58
+ ### Semantics of `verified` vs `valid` vs `pkVerified`
59
+
60
+ `verifySignature(...)` returns:
61
+
62
+ ```js
63
+ {
64
+ verified: true, // public-key check executed AND succeeded
65
+ valid: true, // deprecated alias of verified
66
+ pkVerified: true, // explicit strict-crypto boolean
67
+ errors: [ /* { code, message, context?, cause? } */ ],
68
+ signerCerts: [ /* { der } */ ],
69
+ hashAlg: 'sha256' | 'sha384' | 'sha512' | null,
70
+ signatureAlg:'rsa' | 'rsa-pss' | 'ecc' | 'ed25519' | null,
71
+ computedDigest: Uint8Array | null // digest recomputed over /ByteRange
72
+ }
73
+ ```
74
+
75
+ `valid` is a **deprecated alias of `verified`**: it always carries the same
76
+ value, is kept for compatibility, and will be removed in a future major
77
+ version. Read `verified`. The same holds for the `valid` field of each
78
+ `verifyAllSignatures` entry, signatures and document timestamps alike.
79
+
80
+ `verified` / `pkVerified` are `true` only when the public-key check
81
+ (`verifyPk`, dispatched internally) actually ran and succeeded against the
82
+ signer's certificate SPKI. There is **no** `pdf/sig/pk-verify-not-wired`
83
+ code in this module — the public-key verification path is wired by
84
+ construction; a failed check surfaces a specific `errors[]` record instead
85
+ (e.g. `pdf/sig/pk-verify-failed`, `pdf/sig/rsa-pkcs1v15-deprecated` for the
86
+ deliberately-refused legacy scheme).
87
+
88
+ ### Structural verification + digest
89
+
90
+ ```js
91
+ const sig = runtime.resolve('pdfSignature');
92
+ const typed = sig.typeSignature(sigFieldDict.v);
93
+ const result = sig.verifySignature(typed, documentBytes, fwBundle);
94
+ result.verified; // true when the PK check passed
95
+ result.computedDigest; // Uint8Array — /ByteRange digest
96
+ result.pkVerified; // strict-crypto boolean, same as `verified`
97
+ ```
98
+
99
+ ### Multi-signature + timestamp scan
100
+
101
+ ```js
102
+ const sig = runtime.resolve('pdfSignature');
103
+ const { signatures, timestamps } = sig.verifyAllSignatures(documentBytes, fwBundle);
104
+ signatures.every((s) => s.verified);
105
+ timestamps.every((t) => t.verified);
106
+ ```
107
+
108
+ Each `timestamps[]` entry (`TsVerifyResult`) has this shape:
109
+
110
+ ```js
111
+ {
112
+ objNum, objGen, // the /DocTimeStamp object
113
+ verified: true, // imprint matches AND the gap is exact
114
+ valid: true, // deprecated alias of verified
115
+ kind: 'DocTimeStamp',
116
+ subFilter: 'ETSI.RFC3161' | string | null,
117
+ hashAlg: 'sha256' | 'sha384' | 'sha512' | string | null,
118
+ tstInfo: { hashAlg, imprint, rawSd } | null,
119
+ imprintVerified: true, // messageImprint == /ByteRange digest (imprint outcome alone)
120
+ tsaVerified: false, // TSA signature check — informational
121
+ gapForm: 'token' | 'digits' | null,
122
+ errors: [ /* { code, message, context?, cause? } */ ],
123
+ signerCerts: [ /* the TSA signer certificates, when located */ ]
124
+ }
125
+ ```
126
+
127
+ `gapForm` names the accepted `/ByteRange` gap form, in the vocabulary of
128
+ `pdfByteRange.auditByteRange`: `'token'` when the gap is exactly the whole
129
+ `<…>` token of the `/Contents` value, `'digits'` when it is exactly its hex
130
+ digits, `null` for any other gap. It is present on every entry, failure
131
+ paths included. A non-exact gap adds a
132
+ `pdf/sig/byterange/gap-start-mismatch` / `gap-end-mismatch` record to
133
+ `errors[]` and leaves `verified: false` even when `imprintVerified` is
134
+ `true`; the earlier `pdf/ts/*` failures keep their first error code.
135
+ `signatures[]` entries carry `objNum` / `objGen` plus the `verifySignature`
136
+ result shape above, with no `gapForm` key.
137
+
138
+ ### Inspecting the decoded CMS
139
+
140
+ ```js
141
+ const sd = sig.locatePkcs7(typed.contents);
142
+ // sd is the parsed SignedData children array (ASN.1 nodes), or `false`.
143
+ ```
144
+
145
+ ## Errors
146
+
147
+ | Code | Class | When |
148
+ |------|--------|------|
149
+ | `pdf/sig/not-dict` | `ParseError` | Argument is not a dict. |
150
+ | `pdf/sig/bad-type` | `ParseError` | `/Type` is neither `/Sig` nor `/DocTimeStamp`. |
151
+ | `pdf/sig/missing-filter` | `ParseError` | `/Filter` missing. |
152
+ | `pdf/sig/missing-subfilter` | `ParseError` | `/SubFilter` missing. |
153
+ | `pdf/sig/unknown-subfilter` | `ParseError` | SubFilter outside the supported set. |
154
+ | `pdf/sig/missing-contents` | `ParseError` | `/Contents` missing. |
155
+ | `pdf/sig/missing-byterange` | `ParseError` | `/ByteRange` missing. |
156
+ | `pdf/sig/bad-byterange` | `ParseError` | `/ByteRange` malformed (≠ 4 integers). |
157
+ | `pdf/sig/missing-fw` | `EncryptionError` | fw bundle incomplete for `verifySignature`. |
158
+ | `pdf/sig/byterange/inconsistent` | `ParseError` | ByteRange offsets inconsistent with the document length. |
159
+ | `pdf/sig/pkcs7-malformed` | record `errors[]` | PKCS#7 `SignedData` parse failed. |
160
+ | `pdf/sig/no-signer` / `empty-signers` / `bad-signer` | record `errors[]` | `signerInfos` absent / empty / malformed. |
161
+ | `pdf/sig/unknown-digest` / `unknown-sigalg` | record `errors[]` | digestAlgorithm / signatureAlgorithm OID outside the supported set. |
162
+ | `pdf/sig/no-hash` | record `errors[]` | Hash module unavailable for the resolved `hashAlg`. |
163
+ | `pdf/sig/signer-info-short` / `no-encrypted-digest` | record `errors[]` | SignerInfo ASN.1 shape unexpected. |
164
+ | `pdf/sig/digest-failed` | record `errors[]` | Failed to recompute the `/ByteRange` digest. The record is `{ code, message }`: the underlying error's message is appended to `message`, and no `cause` is attached. |
165
+ | `pdf/sig/signed-attrs-parse-failed` / `digest-not-computed` / `digest-length-mismatch` / `digest-mismatch` / `no-message-digest-attr` | record `errors[]` | `signedAttrs` present but its `messageDigest` attribute fails to parse or match. |
166
+ | `pdf/sig/signer-cert-not-found` | record `errors[]` | No embedded cert matches the SignerInfo's `IssuerAndSerialNumber`. |
167
+ | `pdf/sig/spki-*` (`cert-parse`, `not-found`, `malformed`, `rsa-parse`, `rsa-fields`, `ecc-not-uncompressed`, `ed25519-bad-len`, `unsupported-alg`) | record `errors[]` | SubjectPublicKeyInfo extraction/shape failure. |
168
+ | `pdf/sig/byterange/gap-start-mismatch` / `gap-end-mismatch` | record `errors[]` (`verified: false`) | `/Sig` and `/DocTimeStamp`: the `/ByteRange` gap is neither exactly the hex digits of `/Contents` nor exactly its whole `<…>` token — both forms are accepted, every other gap is refused by `verifySignature` / `verifyAllSignatures` (a `/Sig`) and by `verifyAllSignatures` (a `/DocTimeStamp`, whose `imprintVerified` still reports the imprint outcome alone). The `timestamps[]` entry names the accepted form in `gapForm`. |
169
+ | `pdf/sig/byterange-concat-failed` | record `errors[]` | Failed to extract the ByteRange-covered bytes for the fallback signed-payload path. |
170
+ | `pdf/sig/pk-verify-failed` | record `errors[]` | `verifyPk` ran and returned `verified: false` (see `verifyPk` codes below). |
171
+ | `pdf/sig/verify-pk/bad-args` / `no-alg` / `bad-sig` / `no-message` / `no-hash` / `no-rsa` / `bad-rsa-key` / `no-ecc` / `bad-ecc-key` / `unknown-curve` / `bad-ecc-point` / `bad-ecdsa-sig` / `no-digest` / `no-ed25519` / `bad-ed25519-key` / `unknown-alg` / `throw` | `verifyPk` return `{ code }` | Invalid inputs or dispatch failure inside `verifyPk`. |
172
+ | `pdf/sig/rsa-pkcs1v15-deprecated` | `verifyPk` return `{ code }` | RSA PKCS#1 v1.5 is deliberately refused (NIST SP 800-131A Rev.2) — use RSA-PSS. |
173
+ | `pdf/ts/*` (`empty-contents`, `parse-failed`, `unknown-hash`, `imprint-length-mismatch`, `imprint-mismatch`, `byterange-failed`, `no-ci`, `short-ci`, `no-sd`, `short-sd`, `no-eci`, `no-econtent`, `no-tst`, `short-tstinfo`, `no-imprint`, `tsa-no-sd`, `tsa-throw`) | record `errors[]` | Emitted by `verifyAllSignatures`'s `/DocTimeStamp` branch (RFC 3161 TimeStampToken parsing + TSA signature check). |
174
+
175
+ ## See also
176
+
177
+ - [`pdfByteRange`](./byteRange.md) · [`pdfTimestamp`](./timestamp.md) · [`pdfCertChain`](./certChain.md)
178
+ - [`pdfSignatureField`](../form/signature.md)
@@ -0,0 +1,84 @@
1
+ ---
2
+ module: pdfTimestamp
3
+ category: pdf/sig
4
+ dependencies: [pdfErrors, pdfSigOids, asn1, rsa, ecc, ed25519, sha256, sha384, sha512]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfTimestamp
11
+
12
+ > Document Timestamp + TSA tokens — ISO 32000-2 §12.8.5 / RFC 3161.
13
+
14
+ **Module** `pdfTimestamp` | **Source** `packages/front/office/pdf/src/sig/timestamp.js` | **Deps** `pdfErrors`, `pdfSigOids`, `asn1`, `rsa`, `ecc`, `ed25519`, `sha256`, `sha384`, `sha512` | **Worker-safe** yes
15
+
16
+ Parsing and verification of RFC 3161 Time-Stamp Authority tokens — used either as a standalone document timestamp (`SubFilter = ETSI.RFC3161`) or as an unsigned attribute of a signature for proof of existence. The module extracts `TSTInfo` (genTime, policy, messageImprint, serialNumber) and verifies the TSA signature against the embedded certificate.
17
+
18
+ ## Resolve
19
+
20
+ ```js
21
+ const ts = runtime.resolve('pdfTimestamp');
22
+ // Returns: { parseTimestampToken, verifyTimestamp,
23
+ // extractTimestampFromUnsignedAttrs,
24
+ // OID_TST_INFO, OID_AA_TIMESTAMP }
25
+ ```
26
+
27
+ ## API
28
+
29
+ | Method | Signature | Returns |
30
+ |--------|-----------|---------|
31
+ | `parseTimestampToken` | `(blob: Uint8Array, asn1Mod?) => TstInfo` | Decodes the RFC 3161 ContentInfo. |
32
+ | `verifyTimestamp` | `(blob: Uint8Array, fwBundle?) => VerifyResult` | Cryptographic verification. |
33
+ | `extractTimestampFromUnsignedAttrs` | `(signedAttrs, asn1Mod?) => Uint8Array \| null` | Looks up `id-aa-timeStampToken` (1.2.840.113549.1.9.16.2.14). |
34
+ | `OID_TST_INFO` | `string` (constant) | `id-ct-TSTInfo` OID (1.2.840.113549.1.9.16.1.4), used to validate `encapContentInfo`'s eContentType. |
35
+ | `OID_AA_TIMESTAMP` | `string` (constant) | `id-aa-timeStampToken` OID, used by `extractTimestampFromUnsignedAttrs`. |
36
+
37
+ ### Shape `TstInfo`
38
+
39
+ ```js
40
+ {
41
+ version, policy: oid,
42
+ serialNumber: Uint8Array,
43
+ messageImprint: { hashAlg, hashedMessage: Uint8Array } | null,
44
+ genTime: Date | null,
45
+ nonce?: Uint8Array, tsa?: Uint8Array
46
+ }
47
+ ```
48
+
49
+ ## Examples
50
+
51
+ ### Document timestamp
52
+
53
+ ```js
54
+ const ts = runtime.resolve('pdfTimestamp');
55
+ const result = ts.verifyTimestamp(sig.contents);
56
+ result.valid;
57
+ result.tstInfo.genTime; // Date — proof of existence
58
+ ```
59
+
60
+ ### Timestamp embedded in a signature
61
+
62
+ ```js
63
+ const pk7 = runtime.resolve('pdfSignature').locatePkcs7(sig.contents);
64
+ const tsBytes = ts.extractTimestampFromUnsignedAttrs(pk7.signerInfo.unsignedAttrs);
65
+ if (tsBytes) {
66
+ const tstInfo = ts.parseTimestampToken(tsBytes);
67
+ }
68
+ ```
69
+
70
+ ## Errors
71
+
72
+ | Code | Class | When |
73
+ |------|--------|------|
74
+ | `pdf/ts/bad-input` | `ParseError` | Argument is not a Uint8Array. |
75
+ | `pdf/ts/missing-fw` | `EncryptionError` | fw bundle incomplete. |
76
+ | `pdf/ts/malformed` | `ParseError` | Invalid ASN.1 structure (ContentInfo, SignedData, or top-level TSTInfo). |
77
+ | `pdf/ts/no-econtent` | `ParseError` | `encapContentInfo` has no `eContent`. |
78
+ | `pdf/ts/wrong-econtent` | `ParseError` | eContentType ≠ `id-ct-TSTInfo`. |
79
+ | `pdf/ts/no-tstinfo` | `ParseError` | TSTInfo not found inside eContent. |
80
+ | `pdf/ts/bad-tstinfo` | `ParseError` | Required fields missing or mistyped. |
81
+
82
+ ## See also
83
+
84
+ - [`pdfSignature`](./signature.md) · [`pdfByteRange`](./byteRange.md) · [`pdfCertChain`](./certChain.md)
@@ -0,0 +1,29 @@
1
+ # Syntax — ISO 32000-2 §7.2–§7.5
2
+
3
+ Binary layer: `Uint8Array` → tokens → typed objects → xref table → trailer.
4
+
5
+ | Module | Returns | Deps | Description |
6
+ |--------|---------|------|-------------|
7
+ | [`pdfTokenizer`](./tokenizer.md) | `{ tokenize, lastIndexOfBytes }` | `pdfErrors`, `pdfShared` | Lexer §7.2. |
8
+ | [`pdfParserObj`](./parser-obj.md) | `{ obj, getEntry, isType }` | none | Typed-object builders and reflection helpers. |
9
+ | [`pdfParser`](./parser.md) | `{ tokenize, parseObject, parseIndirect, parseFromBytes, parseIndirectFromBytes, parserLimits, setParserLimits, obj, getEntry, isType }` | `pdfErrors`, `pdfParserObj`, `pdfTokenizer` | Typed objects §7.3. |
10
+ | [`pdfXref`](./xref.md) | `{ locateStartXref, readStartXref, parseXrefTable, parseTrailerDict, readXrefStreamDict, buildXrefStream }` | `pdfErrors`, `pdfTokenizer`, `pdfParser` | Classical table §7.5.4. |
11
+ | [`pdfTrailer`](./trailer.md) | `{ typeTrailer }` | `pdfErrors`, `pdfParserObj` | Typed trailer §7.5.5. |
12
+ | [`pdfSerializer`](./serializer.md) | `{ serializeObject, serializeIndirect, formatReal }` | `pdfErrors` | Object emission §7.3. |
13
+ | [`pdfObjStream`](./objStream.md) | `{ parseObjectStream }` | `pdfErrors`, `pdfParserObj`, `pdfTokenizer`, `pdfParser` | Object streams §7.5.7. |
14
+ | [`pdfCrossRefStream`](./crossRefStream.md) | `{ parseCrossRefStream }` | `pdfErrors`, `pdfParserObj` | Cross-reference streams §7.5.8. |
15
+ | [Filters](./filters/README.md) | `{ decode, encode }` × 4 + dispatch | `pdfErrors`, `zlib` | The `/Filter` chain §7.4. |
16
+
17
+ ## Common pattern
18
+
19
+ ```js
20
+ const tokMod = runtime.resolve('pdfTokenizer');
21
+ const tok = tokMod.tokenize(bytes);
22
+ let t;
23
+ while ((t = tok.next())) { /* … */ }
24
+ ```
25
+
26
+ ## See also
27
+
28
+ - [Document layer](../document/README.md)
29
+ - [Read pipeline](../../guide/read-pdf.md)