@e-sig/core 0.5.1 → 0.7.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 (102) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +92 -0
  3. package/dist/index.d.ts +7 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +7 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/pem-signer.d.ts +26 -5
  8. package/dist/pem-signer.d.ts.map +1 -1
  9. package/dist/pem-signer.js +84 -13
  10. package/dist/pem-signer.js.map +1 -1
  11. package/dist/pq-cert.d.ts +76 -0
  12. package/dist/pq-cert.d.ts.map +1 -0
  13. package/dist/pq-cert.js +295 -0
  14. package/dist/pq-cert.js.map +1 -0
  15. package/dist/pq-embed.d.ts +22 -0
  16. package/dist/pq-embed.d.ts.map +1 -0
  17. package/dist/pq-embed.js +119 -0
  18. package/dist/pq-embed.js.map +1 -0
  19. package/dist/pq-lifecycle.d.ts +59 -0
  20. package/dist/pq-lifecycle.d.ts.map +1 -0
  21. package/dist/pq-lifecycle.js +55 -0
  22. package/dist/pq-lifecycle.js.map +1 -0
  23. package/dist/pq-seal.d.ts +183 -0
  24. package/dist/pq-seal.d.ts.map +1 -0
  25. package/dist/pq-seal.js +345 -0
  26. package/dist/pq-seal.js.map +1 -0
  27. package/dist/pq-verify.d.ts +99 -0
  28. package/dist/pq-verify.d.ts.map +1 -0
  29. package/dist/pq-verify.js +135 -0
  30. package/dist/pq-verify.js.map +1 -0
  31. package/dist/render-pdf.d.ts +5 -5
  32. package/dist/render-pdf.d.ts.map +1 -1
  33. package/dist/render-pdf.js +51 -17
  34. package/dist/render-pdf.js.map +1 -1
  35. package/dist/sign-document.d.ts +16 -0
  36. package/dist/sign-document.d.ts.map +1 -1
  37. package/dist/sign-document.js +10 -0
  38. package/dist/sign-document.js.map +1 -1
  39. package/dist/sign-pdf.d.ts +66 -4
  40. package/dist/sign-pdf.d.ts.map +1 -1
  41. package/dist/sign-pdf.js +51 -2
  42. package/dist/sign-pdf.js.map +1 -1
  43. package/dist/types.d.ts +36 -0
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/vendor/placeholder-plain/LICENSE-signpdf.md +47 -0
  46. package/dist/vendor/placeholder-plain/createBufferPageWithAnnotation.d.ts +6 -0
  47. package/dist/vendor/placeholder-plain/createBufferPageWithAnnotation.d.ts.map +1 -0
  48. package/dist/vendor/placeholder-plain/createBufferPageWithAnnotation.js +38 -0
  49. package/dist/vendor/placeholder-plain/createBufferPageWithAnnotation.js.map +1 -0
  50. package/dist/vendor/placeholder-plain/createBufferRootWithAcroform.d.ts +6 -0
  51. package/dist/vendor/placeholder-plain/createBufferRootWithAcroform.d.ts.map +1 -0
  52. package/dist/vendor/placeholder-plain/createBufferRootWithAcroform.js +15 -0
  53. package/dist/vendor/placeholder-plain/createBufferRootWithAcroform.js.map +1 -0
  54. package/dist/vendor/placeholder-plain/createBufferTrailer.d.ts +4 -0
  55. package/dist/vendor/placeholder-plain/createBufferTrailer.d.ts.map +1 -0
  56. package/dist/vendor/placeholder-plain/createBufferTrailer.js +26 -0
  57. package/dist/vendor/placeholder-plain/createBufferTrailer.js.map +1 -0
  58. package/dist/vendor/placeholder-plain/findObject.d.ts +4 -0
  59. package/dist/vendor/placeholder-plain/findObject.d.ts.map +1 -0
  60. package/dist/vendor/placeholder-plain/findObject.js +18 -0
  61. package/dist/vendor/placeholder-plain/findObject.js.map +1 -0
  62. package/dist/vendor/placeholder-plain/getIndexFromRef.d.ts +4 -0
  63. package/dist/vendor/placeholder-plain/getIndexFromRef.d.ts.map +1 -0
  64. package/dist/vendor/placeholder-plain/getIndexFromRef.js +13 -0
  65. package/dist/vendor/placeholder-plain/getIndexFromRef.js.map +1 -0
  66. package/dist/vendor/placeholder-plain/getPageRef.d.ts +6 -0
  67. package/dist/vendor/placeholder-plain/getPageRef.d.ts.map +1 -0
  68. package/dist/vendor/placeholder-plain/getPageRef.js +18 -0
  69. package/dist/vendor/placeholder-plain/getPageRef.js.map +1 -0
  70. package/dist/vendor/placeholder-plain/getPagesDictionaryRef.d.ts +3 -0
  71. package/dist/vendor/placeholder-plain/getPagesDictionaryRef.d.ts.map +1 -0
  72. package/dist/vendor/placeholder-plain/getPagesDictionaryRef.js +12 -0
  73. package/dist/vendor/placeholder-plain/getPagesDictionaryRef.js.map +1 -0
  74. package/dist/vendor/placeholder-plain/index.d.ts +2 -0
  75. package/dist/vendor/placeholder-plain/index.d.ts.map +1 -0
  76. package/dist/vendor/placeholder-plain/index.js +4 -0
  77. package/dist/vendor/placeholder-plain/index.js.map +1 -0
  78. package/dist/vendor/placeholder-plain/pdfObject.d.ts +13 -0
  79. package/dist/vendor/placeholder-plain/pdfObject.d.ts.map +1 -0
  80. package/dist/vendor/placeholder-plain/pdfObject.js +142 -0
  81. package/dist/vendor/placeholder-plain/pdfObject.js.map +1 -0
  82. package/dist/vendor/placeholder-plain/pdfkitAddPlaceholder.d.ts +49 -0
  83. package/dist/vendor/placeholder-plain/pdfkitAddPlaceholder.d.ts.map +1 -0
  84. package/dist/vendor/placeholder-plain/pdfkitAddPlaceholder.js +115 -0
  85. package/dist/vendor/placeholder-plain/pdfkitAddPlaceholder.js.map +1 -0
  86. package/dist/vendor/placeholder-plain/plainAddPlaceholder.d.ts +41 -0
  87. package/dist/vendor/placeholder-plain/plainAddPlaceholder.d.ts.map +1 -0
  88. package/dist/vendor/placeholder-plain/plainAddPlaceholder.js +95 -0
  89. package/dist/vendor/placeholder-plain/plainAddPlaceholder.js.map +1 -0
  90. package/dist/vendor/placeholder-plain/readPdf.d.ts +20 -0
  91. package/dist/vendor/placeholder-plain/readPdf.d.ts.map +1 -0
  92. package/dist/vendor/placeholder-plain/readPdf.js +47 -0
  93. package/dist/vendor/placeholder-plain/readPdf.js.map +1 -0
  94. package/dist/vendor/placeholder-plain/readRefTable.d.ts +17 -0
  95. package/dist/vendor/placeholder-plain/readRefTable.d.ts.map +1 -0
  96. package/dist/vendor/placeholder-plain/readRefTable.js +84 -0
  97. package/dist/vendor/placeholder-plain/readRefTable.js.map +1 -0
  98. package/dist/vendor/placeholder-plain/xrefToRefMap.d.ts +3 -0
  99. package/dist/vendor/placeholder-plain/xrefToRefMap.d.ts.map +1 -0
  100. package/dist/vendor/placeholder-plain/xrefToRefMap.js +38 -0
  101. package/dist/vendor/placeholder-plain/xrefToRefMap.js.map +1 -0
  102. package/package.json +10 -8
@@ -0,0 +1,183 @@
1
+ import crypto from "node:crypto";
2
+ /** Seal schema version. Bump on any breaking change to the signed payload shape. */
3
+ export declare const PQ_SEAL_VERSION: 1;
4
+ /** Hybrid algorithm identifier embedded in (and bound by) every seal. */
5
+ export declare const PQ_SEAL_ALG: "hybrid-ed25519-ml-dsa-65";
6
+ /** Bundle schema version for the wrapped at-rest key material. */
7
+ declare const PQ_BUNDLE_VERSION: 1;
8
+ /**
9
+ * True if `value` is a structurally well-formed UUAID assertion — the exact rule
10
+ * `buildPqSeal` enforces on input and `verifyPqSealSignatures` enforces on a
11
+ * seal that carries one. This is an envelope check, NOT proof that the
12
+ * identifier resolves, exists, or belongs to the signer.
13
+ *
14
+ * Accepted here does NOT imply accepted by the UUAID registry: the registry
15
+ * additionally enforces semantics this package deliberately does not know
16
+ * (registered subject classes and object types, canonical UUID form). Expect a
17
+ * band of identifiers this will sign and a resolver will still reject.
18
+ */
19
+ export declare function isWellFormedUuaidAssertion(value: unknown): value is string;
20
+ /**
21
+ * The wrappable at-rest key bundle. Persist `wrapPqKeyBundle(bundle, passphrase)`;
22
+ * never store the raw bundle. Compact by design: an Ed25519 PKCS#8 key plus a
23
+ * 32-byte ML-DSA seed (the full 4032-byte ML-DSA secret key is re-derived
24
+ * deterministically via `ml_dsa65.keygen(seed)`).
25
+ */
26
+ export interface PqKeyBundle {
27
+ v: typeof PQ_BUNDLE_VERSION;
28
+ /** base64 PKCS#8 DER of the Ed25519 private key. */
29
+ ed25519Pkcs8: string;
30
+ /** base64 32-byte ML-DSA-65 seed. */
31
+ mldsa65Seed: string;
32
+ }
33
+ /** Public key material derived from a bundle — safe to publish/pin as the signer identity. */
34
+ export interface PqPublicMaterial {
35
+ /** base64 raw 32-byte Ed25519 public key. */
36
+ ed25519: string;
37
+ /** base64 raw 1952-byte ML-DSA-65 public key. */
38
+ mldsa65: string;
39
+ /** SHA-256 hex of the raw ML-DSA-65 public key — the post-quantum identity fingerprint. */
40
+ mldsa65Fpr: string;
41
+ /** Stable 128-bit hex id over both public keys (bound into every seal). */
42
+ keyId: string;
43
+ }
44
+ /** In-memory signing keys, ready to produce seals. Never persisted directly. */
45
+ export interface PqSigningKeys {
46
+ ed25519PrivateKey: crypto.KeyObject;
47
+ ed25519PublicRaw: Uint8Array;
48
+ mldsa65SecretKey: Uint8Array;
49
+ mldsa65PublicKey: Uint8Array;
50
+ }
51
+ /**
52
+ * A hybrid post-quantum seal. The signed payload is every field EXCEPT `sig`,
53
+ * serialized canonically (see `canonicalJson`). `digest` is the SHA-256 (hex) of
54
+ * the first `coveredBytes` bytes of the final document — the PDF-verify layer
55
+ * checks that binding; `verifyPqSealSignatures` only checks the two signatures.
56
+ */
57
+ export interface PqSeal {
58
+ v: typeof PQ_SEAL_VERSION;
59
+ alg: typeof PQ_SEAL_ALG;
60
+ /** Digest algorithm over the covered document bytes. */
61
+ over: "sha256";
62
+ /** SHA-256 hex of the covered document bytes (the first `coveredBytes` bytes). */
63
+ digest: string;
64
+ /** Byte length of the document prefix the digest covers (P0 = rendered PDF pre-seal). */
65
+ coveredBytes: number;
66
+ /** ISO 8601 seal creation time. */
67
+ signedAt: string;
68
+ /** 128-bit hex id over both public keys. */
69
+ keyId: string;
70
+ /**
71
+ * OPTIONAL signer-asserted UUAID (IAASO-0004 attribution). Omitted entirely
72
+ * unless the signer supplies one. Signed like every other payload field, so it
73
+ * is immutable once sealed — but it is a CLAIM by the seal key, not proof of
74
+ * identity: it binds key -> uuaid only. See the identity note at the top of
75
+ * this file before relying on it for attribution.
76
+ */
77
+ uuaid?: string;
78
+ keys: {
79
+ ed25519: string;
80
+ mldsa65: string;
81
+ mldsa65Fpr: string;
82
+ };
83
+ sig: {
84
+ /** base64 Ed25519 signature over canonicalJson(payload). */
85
+ ed25519: string;
86
+ /** base64 ML-DSA-65 signature over canonicalJson(payload). */
87
+ mldsa65: string;
88
+ };
89
+ }
90
+ /** Result of verifying a seal's two signatures (does NOT check document binding). */
91
+ export interface PqSealVerification {
92
+ /** Classical Ed25519 signature valid. */
93
+ ed25519: boolean;
94
+ /** Post-quantum ML-DSA-65 signature valid. */
95
+ mldsa65: boolean;
96
+ /** The embedded `mldsa65Fpr` matches SHA-256(mldsa65 public key). */
97
+ fingerprintOk: boolean;
98
+ /** The embedded `keyId` matches the digest of the two public keys it claims. */
99
+ keyIdOk: boolean;
100
+ /**
101
+ * The seal either asserts no UUAID, or asserts a structurally well-formed one.
102
+ * A seal carrying a malformed `uuaid` is rejected (fail-closed) even though its
103
+ * signatures are intact — a hand-crafted identity field is not something to
104
+ * pass downstream. True does NOT mean the assertion was verified.
105
+ */
106
+ uuaidOk: boolean;
107
+ /** Hybrid verdict: every check passed (both signatures + fingerprint + keyId + uuaid shape). */
108
+ ok: boolean;
109
+ }
110
+ export interface GeneratePqKeyBundleOptions {
111
+ /**
112
+ * 32-byte ML-DSA-65 keygen seed. The same seed always derives the same
113
+ * keypair — supply one for deterministic key provisioning (e.g. from a KMS
114
+ * or sealed secret). Omit for a fresh random seed.
115
+ */
116
+ mldsa65Seed?: Uint8Array;
117
+ /**
118
+ * PKCS#8 DER Ed25519 private key to use instead of generating a fresh one.
119
+ * Together with `mldsa65Seed` this makes the whole bundle deterministic.
120
+ */
121
+ ed25519Pkcs8?: Uint8Array;
122
+ }
123
+ /**
124
+ * Generate a fresh hybrid key bundle plus its derived public material. The bundle
125
+ * is what you wrap + persist; the public material is what you publish/pin as the
126
+ * signer's post-quantum identity. Pass `opts` to provision deterministically
127
+ * from existing key material instead of random generation.
128
+ */
129
+ export declare function generatePqKeyBundle(opts?: GeneratePqKeyBundleOptions): {
130
+ bundle: PqKeyBundle;
131
+ public: PqPublicMaterial;
132
+ };
133
+ /** Rehydrate in-memory signing keys from a bundle (deterministically re-derives the ML-DSA keypair). */
134
+ export declare function loadPqSigningKeys(bundle: PqKeyBundle): PqSigningKeys;
135
+ /** Derive the publishable public material for a set of signing keys. */
136
+ export declare function publicMaterialForKeys(keys: PqSigningKeys): PqPublicMaterial;
137
+ /** AES-256-GCM-wrap a key bundle for persistence. `passphrase` ≥ 24 chars. */
138
+ export declare function wrapPqKeyBundle(bundle: PqKeyBundle, passphrase: string): Uint8Array;
139
+ /** Inverse of `wrapPqKeyBundle`. Throws on wrong passphrase / tampering (auth-tag mismatch). */
140
+ export declare function unwrapPqKeyBundle(blob: Uint8Array, passphrase: string): PqKeyBundle;
141
+ export interface BuildPqSealInput {
142
+ /** SHA-256 hex of the covered document bytes. */
143
+ digestHex: string;
144
+ /** Byte length the digest covers (the document prefix protected by the seal). */
145
+ coveredBytes: number;
146
+ keys: PqSigningKeys;
147
+ /** Seal timestamp. Defaults to now. */
148
+ signedAt?: Date;
149
+ /**
150
+ * OPTIONAL UUAID to assert as the signer identity (IAASO-0004 attribution).
151
+ * Omit — the default — to produce a seal byte-identical to pre-`uuaid` output.
152
+ * Rejected at build time unless structurally well-formed, so a malformed
153
+ * identifier can never be signed into a document. That check is structural
154
+ * only: passing it does not mean the UUAID registry will resolve or accept the
155
+ * identifier (see `isWellFormedUuaidAssertion`).
156
+ */
157
+ uuaid?: string;
158
+ }
159
+ /**
160
+ * Produce a hybrid seal over `digestHex`. Both signatures are computed over the
161
+ * exact same canonical bytes (the seal minus `sig`), binding digest, covered
162
+ * length, public keys, timestamp and keyId under BOTH schemes.
163
+ */
164
+ export declare function buildPqSeal(input: BuildPqSealInput): PqSeal;
165
+ /**
166
+ * Verify a seal's two signatures over its own payload (does NOT bind the seal to a
167
+ * document — the PDF-verify layer checks `digest` against the covered bytes).
168
+ *
169
+ * Fails CLOSED: any malformed field, wrong-length key/signature, or thrown error
170
+ * yields `ok:false` rather than propagating. The hybrid verdict requires BOTH
171
+ * signatures valid AND the ML-DSA fingerprint self-consistent.
172
+ */
173
+ export declare function verifyPqSealSignatures(seal: PqSeal): PqSealVerification;
174
+ /**
175
+ * Deterministic JSON serialization (recursively key-sorted, no insignificant
176
+ * whitespace) used as the signing input. The seal payload contains only strings
177
+ * and safe integers, so this is unambiguous without full RFC 8785 number
178
+ * canonicalization. Both signing and verification serialize the identical field
179
+ * set (payload = seal minus `sig`), so the two sides always agree.
180
+ */
181
+ export declare function canonicalJson(value: unknown): string;
182
+ export {};
183
+ //# sourceMappingURL=pq-seal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pq-seal.d.ts","sourceRoot":"","sources":["../src/pq-seal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,345 @@
1
+ // pq-seal.ts
2
+ //
3
+ // Hybrid post-quantum document seal — Ed25519 (classical) + ML-DSA-65 (FIPS 204,
4
+ // module-lattice, quantum-resistant). This is the cryptographic core of e-sig's
5
+ // post-quantum wedge: every sealed document carries TWO independent signatures
6
+ // over the same payload, and a verifier requires BOTH to pass. If either scheme
7
+ // is ever broken (a CRQC breaks Ed25519, or an unforeseen lattice attack dents
8
+ // ML-DSA), the seal still stands on the other — the belt-and-suspenders
9
+ // migration path NIST/CNSA 2.0 recommends over a hard cutover.
10
+ //
11
+ // The seal is a small canonical-JSON object signed over a SHA-256 digest of the
12
+ // document bytes it covers. It does NOT replace the PDF's PKCS#7/PAdES RSA
13
+ // signature (which stays valid in every PDF reader, including Adobe Acrobat —
14
+ // no mainstream reader validates ML-DSA in PAdES yet, 2026). Instead the seal is
15
+ // embedded in the PDF and the RSA /ByteRange signature is applied on top, so the
16
+ // classical signature cryptographically covers the seal (see sign-pdf.ts).
17
+ //
18
+ // Identity model (v1): raw ML-DSA-65 public key + its SHA-256 fingerprint carried
19
+ // in the seal (the `keyId` / `mldsa65Fpr`), verified TOFU / against-published-key.
20
+ // A self-signed ML-DSA-65 X.509 certificate (RFC 9881 OID 2.16.840.1.101.3.4.3.18)
21
+ // is a deliberate fast-follow, not required to ship the seal.
22
+ //
23
+ // Optional signer-asserted UUAID (`uuaid`): a signer MAY additionally assert the
24
+ // UUAID identity it signs as, for IAASO-0004 (Media Provenance & Attribution)
25
+ // attribution. The field is part of the signed payload, so it is bound under BOTH
26
+ // schemes and cannot be added, removed or swapped on an existing seal.
27
+ //
28
+ // What it proves: the holder of THIS seal key claims to be THAT UUAID.
29
+ // What it does NOT: that the UUAID's owner authorised this document.
30
+ //
31
+ // It is one half of a mutual binding (key -> uuaid). The other half (uuaid -> key,
32
+ // i.e. the UUAID owner authenticating this seal key as theirs) lives in the UUAID
33
+ // registry and is NOT established here. A relying party MUST NOT treat a bare
34
+ // `uuaid` assertion as attribution: unmatched, it is worth exactly the TOFU
35
+ // fingerprint next to it. Absent the second direction, an attacker who can mint
36
+ // any seal can assert any UUAID.
37
+ //
38
+ // Backward compatibility: the field is omitted entirely when not supplied, so
39
+ // seals from callers that never set it are byte-identical to pre-`uuaid` output,
40
+ // and verifiers that predate the field still verify uuaid-bearing seals (the
41
+ // signed payload is reconstructed generically as "the seal minus `sig`"). This is
42
+ // why the field is additive at v1 rather than a version bump: bumping
43
+ // PQ_SEAL_VERSION would break every already-deployed verifier, the added field
44
+ // does not.
45
+ //
46
+ // Algorithm binding: both signatures are computed over the SAME canonical bytes —
47
+ // the seal object minus its `sig` field — so digest, covered length, public keys,
48
+ // timestamp and keyId are all bound together and cannot be swapped independently.
49
+ import crypto from "node:crypto";
50
+ import { ml_dsa65 } from "@noble/post-quantum/ml-dsa.js";
51
+ import { encryptKeyPem, decryptKeyPem } from "./cert-issuer.js";
52
+ // ---------- Constants ----------
53
+ /** Seal schema version. Bump on any breaking change to the signed payload shape. */
54
+ export const PQ_SEAL_VERSION = 1;
55
+ /** Hybrid algorithm identifier embedded in (and bound by) every seal. */
56
+ export const PQ_SEAL_ALG = "hybrid-ed25519-ml-dsa-65";
57
+ /** Bundle schema version for the wrapped at-rest key material. */
58
+ const PQ_BUNDLE_VERSION = 1;
59
+ /**
60
+ * DER SubjectPublicKeyInfo prefix for an Ed25519 key (RFC 8410 §4). A raw 32-byte
61
+ * Ed25519 public key is exactly this 12-byte prefix followed by the key, so we
62
+ * can round-trip raw keys ↔ node KeyObjects without a heavier ASN.1 dependency.
63
+ */
64
+ const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
65
+ // FIPS 204 ML-DSA-65 sizes (raw, unencoded) — asserted defensively at load time.
66
+ const MLDSA65_PUBLIC_LEN = 1952;
67
+ const MLDSA65_SIGNATURE_LEN = 3309;
68
+ const MLDSA65_SEED_LEN = 32;
69
+ const ED25519_RAW_PUBLIC_LEN = 32;
70
+ const ED25519_SIGNATURE_LEN = 64;
71
+ /** Upper bound on an asserted UUAID string — bounds the seal, not the namespace. */
72
+ const UUAID_MAX_LEN = 255;
73
+ /**
74
+ * Structural shape of a UUAID: `uuaid:` followed by three or four
75
+ * `[A-Za-z0-9_-]` segments — covering both the compact profile
76
+ * (`uuaid:foundation:<objectType>:<uuid>`) and the federated profile
77
+ * (`uuaid:<subjectClass>:<jurisdiction>:<authority>:<localId>`).
78
+ *
79
+ * Deliberately structural only. Which subject classes and object types exist is
80
+ * a registry that evolves in the UUAID lane; hard-coding that enum here would
81
+ * make this package reject newly-registered-but-valid identifiers until it is
82
+ * republished, and it would bake another system's policy into a signed wire
83
+ * format. Semantic validation and resolution belong to the UUAID verifier.
84
+ */
85
+ const UUAID_ASSERTION_RE = /^uuaid:[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:[A-Za-z0-9_-]+(?::[A-Za-z0-9_-]+)?$/;
86
+ /**
87
+ * True if `value` is a structurally well-formed UUAID assertion — the exact rule
88
+ * `buildPqSeal` enforces on input and `verifyPqSealSignatures` enforces on a
89
+ * seal that carries one. This is an envelope check, NOT proof that the
90
+ * identifier resolves, exists, or belongs to the signer.
91
+ *
92
+ * Accepted here does NOT imply accepted by the UUAID registry: the registry
93
+ * additionally enforces semantics this package deliberately does not know
94
+ * (registered subject classes and object types, canonical UUID form). Expect a
95
+ * band of identifiers this will sign and a resolver will still reject.
96
+ */
97
+ export function isWellFormedUuaidAssertion(value) {
98
+ return typeof value === "string" && value.length <= UUAID_MAX_LEN && UUAID_ASSERTION_RE.test(value);
99
+ }
100
+ /**
101
+ * Generate a fresh hybrid key bundle plus its derived public material. The bundle
102
+ * is what you wrap + persist; the public material is what you publish/pin as the
103
+ * signer's post-quantum identity. Pass `opts` to provision deterministically
104
+ * from existing key material instead of random generation.
105
+ */
106
+ export function generatePqKeyBundle(opts = {}) {
107
+ let ed25519Pkcs8;
108
+ let ed25519PublicRaw;
109
+ if (opts.ed25519Pkcs8) {
110
+ const privateKey = crypto.createPrivateKey({
111
+ key: Buffer.from(opts.ed25519Pkcs8),
112
+ format: "der",
113
+ type: "pkcs8",
114
+ });
115
+ if (privateKey.asymmetricKeyType !== "ed25519") {
116
+ throw new Error(`generatePqKeyBundle: ed25519Pkcs8 must be an Ed25519 key, got ${privateKey.asymmetricKeyType}`);
117
+ }
118
+ ed25519Pkcs8 = Buffer.from(opts.ed25519Pkcs8);
119
+ ed25519PublicRaw = rawEd25519FromKeyObject(crypto.createPublicKey(privateKey));
120
+ }
121
+ else {
122
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
123
+ ed25519Pkcs8 = privateKey.export({ type: "pkcs8", format: "der" });
124
+ ed25519PublicRaw = rawEd25519FromKeyObject(publicKey);
125
+ }
126
+ if (opts.mldsa65Seed && opts.mldsa65Seed.length !== MLDSA65_SEED_LEN) {
127
+ throw new Error(`generatePqKeyBundle: mldsa65Seed must be ${MLDSA65_SEED_LEN} bytes, got ${opts.mldsa65Seed.length}`);
128
+ }
129
+ const seed = opts.mldsa65Seed ? Buffer.from(opts.mldsa65Seed) : crypto.randomBytes(MLDSA65_SEED_LEN);
130
+ const { publicKey: mldsa65PublicKey } = ml_dsa65.keygen(seed);
131
+ const bundle = {
132
+ v: PQ_BUNDLE_VERSION,
133
+ ed25519Pkcs8: b64(ed25519Pkcs8),
134
+ mldsa65Seed: b64(seed),
135
+ };
136
+ return { bundle, public: publicMaterial(ed25519PublicRaw, mldsa65PublicKey) };
137
+ }
138
+ /** Rehydrate in-memory signing keys from a bundle (deterministically re-derives the ML-DSA keypair). */
139
+ export function loadPqSigningKeys(bundle) {
140
+ if (bundle.v !== PQ_BUNDLE_VERSION) {
141
+ throw new Error(`loadPqSigningKeys: unknown bundle version ${bundle.v}`);
142
+ }
143
+ const ed25519PrivateKey = crypto.createPrivateKey({
144
+ key: Buffer.from(bundle.ed25519Pkcs8, "base64"),
145
+ format: "der",
146
+ type: "pkcs8",
147
+ });
148
+ const ed25519PublicRaw = rawEd25519FromKeyObject(crypto.createPublicKey(ed25519PrivateKey));
149
+ const seed = Buffer.from(bundle.mldsa65Seed, "base64");
150
+ if (seed.length !== MLDSA65_SEED_LEN) {
151
+ throw new Error(`loadPqSigningKeys: ML-DSA seed must be ${MLDSA65_SEED_LEN} bytes, got ${seed.length}`);
152
+ }
153
+ const { publicKey, secretKey } = ml_dsa65.keygen(seed);
154
+ return {
155
+ ed25519PrivateKey,
156
+ ed25519PublicRaw,
157
+ mldsa65SecretKey: secretKey,
158
+ mldsa65PublicKey: publicKey,
159
+ };
160
+ }
161
+ /** Derive the publishable public material for a set of signing keys. */
162
+ export function publicMaterialForKeys(keys) {
163
+ return publicMaterial(keys.ed25519PublicRaw, keys.mldsa65PublicKey);
164
+ }
165
+ // ---------- At-rest wrapping (reuses cert-issuer AES-256-GCM) ----------
166
+ /** AES-256-GCM-wrap a key bundle for persistence. `passphrase` ≥ 24 chars. */
167
+ export function wrapPqKeyBundle(bundle, passphrase) {
168
+ return encryptKeyPem(JSON.stringify(bundle), passphrase);
169
+ }
170
+ /** Inverse of `wrapPqKeyBundle`. Throws on wrong passphrase / tampering (auth-tag mismatch). */
171
+ export function unwrapPqKeyBundle(blob, passphrase) {
172
+ const bundle = JSON.parse(decryptKeyPem(blob, passphrase));
173
+ if (bundle.v !== PQ_BUNDLE_VERSION) {
174
+ throw new Error(`unwrapPqKeyBundle: unknown bundle version ${bundle.v}`);
175
+ }
176
+ return bundle;
177
+ }
178
+ /**
179
+ * Produce a hybrid seal over `digestHex`. Both signatures are computed over the
180
+ * exact same canonical bytes (the seal minus `sig`), binding digest, covered
181
+ * length, public keys, timestamp and keyId under BOTH schemes.
182
+ */
183
+ export function buildPqSeal(input) {
184
+ if (!/^[0-9a-f]{64}$/.test(input.digestHex)) {
185
+ throw new Error("buildPqSeal: digestHex must be 64 lowercase hex chars (SHA-256)");
186
+ }
187
+ if (!Number.isInteger(input.coveredBytes) || input.coveredBytes <= 0) {
188
+ throw new Error("buildPqSeal: coveredBytes must be a positive integer");
189
+ }
190
+ if (input.uuaid !== undefined && !isWellFormedUuaidAssertion(input.uuaid)) {
191
+ throw new Error("buildPqSeal: uuaid must be a well-formed UUAID (uuaid:<3-or-4 segments>) — refusing to sign a malformed identity claim");
192
+ }
193
+ const pub = publicMaterialForKeys(input.keys);
194
+ const payload = {
195
+ v: PQ_SEAL_VERSION,
196
+ alg: PQ_SEAL_ALG,
197
+ over: "sha256",
198
+ digest: input.digestHex,
199
+ coveredBytes: input.coveredBytes,
200
+ signedAt: (input.signedAt ?? new Date()).toISOString(),
201
+ keyId: pub.keyId,
202
+ // Spread-in rather than `uuaid: input.uuaid` so the key is ABSENT (not
203
+ // `undefined`) when unused — canonicalJson would otherwise serialize it and
204
+ // change the signed bytes of every seal that never asked for attribution.
205
+ ...(input.uuaid !== undefined ? { uuaid: input.uuaid } : {}),
206
+ keys: { ed25519: pub.ed25519, mldsa65: pub.mldsa65, mldsa65Fpr: pub.mldsa65Fpr },
207
+ };
208
+ const signingInput = Buffer.from(canonicalJson(payload), "utf8");
209
+ const ed25519Sig = crypto.sign(null, signingInput, input.keys.ed25519PrivateKey);
210
+ const mldsa65Sig = ml_dsa65.sign(signingInput, input.keys.mldsa65SecretKey);
211
+ return { ...payload, sig: { ed25519: b64(ed25519Sig), mldsa65: b64(mldsa65Sig) } };
212
+ }
213
+ /**
214
+ * Verify a seal's two signatures over its own payload (does NOT bind the seal to a
215
+ * document — the PDF-verify layer checks `digest` against the covered bytes).
216
+ *
217
+ * Fails CLOSED: any malformed field, wrong-length key/signature, or thrown error
218
+ * yields `ok:false` rather than propagating. The hybrid verdict requires BOTH
219
+ * signatures valid AND the ML-DSA fingerprint self-consistent.
220
+ */
221
+ export function verifyPqSealSignatures(seal) {
222
+ const fail = {
223
+ ed25519: false,
224
+ mldsa65: false,
225
+ fingerprintOk: false,
226
+ keyIdOk: false,
227
+ uuaidOk: false,
228
+ ok: false,
229
+ };
230
+ try {
231
+ if (seal.v !== PQ_SEAL_VERSION || seal.alg !== PQ_SEAL_ALG || seal.over !== "sha256")
232
+ return fail;
233
+ const ed25519Pub = Buffer.from(seal.keys.ed25519, "base64");
234
+ const mldsa65Pub = Buffer.from(seal.keys.mldsa65, "base64");
235
+ const ed25519Sig = Buffer.from(seal.sig.ed25519, "base64");
236
+ const mldsa65Sig = Buffer.from(seal.sig.mldsa65, "base64");
237
+ if (ed25519Pub.length !== ED25519_RAW_PUBLIC_LEN)
238
+ return fail;
239
+ if (mldsa65Pub.length !== MLDSA65_PUBLIC_LEN)
240
+ return fail;
241
+ if (ed25519Sig.length !== ED25519_SIGNATURE_LEN)
242
+ return fail;
243
+ if (mldsa65Sig.length !== MLDSA65_SIGNATURE_LEN)
244
+ return fail;
245
+ // Reconstruct the exact signed payload: the seal minus `sig`.
246
+ const { sig: _sig, ...payload } = seal;
247
+ void _sig;
248
+ const signingInput = Buffer.from(canonicalJson(payload), "utf8");
249
+ // Self-consistency of the identity fields carried in the (signed) payload:
250
+ // fingerprint over the ML-DSA key, and keyId over BOTH public keys. These
251
+ // don't add trust (the keys are the seal's own), but they make the identity
252
+ // fields the signature commits to actually correspond to the keys present.
253
+ const fingerprintOk = sha256Hex(mldsa65Pub) === seal.keys.mldsa65Fpr;
254
+ const expectedKeyId = crypto
255
+ .createHash("sha256")
256
+ .update(ed25519Pub)
257
+ .update(mldsa65Pub)
258
+ .digest("hex")
259
+ .slice(0, 32);
260
+ const keyIdOk = seal.keyId === expectedKeyId;
261
+ // An absent `uuaid` asserts nothing and is fine; a present one must be
262
+ // structurally sound. Both cases are already covered by the signatures —
263
+ // this only rejects identity fields no honest signer could have produced.
264
+ const uuaidOk = seal.uuaid === undefined || isWellFormedUuaidAssertion(seal.uuaid);
265
+ let ed25519 = false;
266
+ try {
267
+ ed25519 = crypto.verify(null, signingInput, ed25519RawToPublicKey(ed25519Pub), ed25519Sig);
268
+ }
269
+ catch {
270
+ ed25519 = false;
271
+ }
272
+ let mldsa65 = false;
273
+ try {
274
+ mldsa65 = ml_dsa65.verify(mldsa65Sig, signingInput, mldsa65Pub);
275
+ }
276
+ catch {
277
+ mldsa65 = false;
278
+ }
279
+ return {
280
+ ed25519,
281
+ mldsa65,
282
+ fingerprintOk,
283
+ keyIdOk,
284
+ uuaidOk,
285
+ ok: ed25519 && mldsa65 && fingerprintOk && keyIdOk && uuaidOk,
286
+ };
287
+ }
288
+ catch {
289
+ return fail;
290
+ }
291
+ }
292
+ // ---------- Internals ----------
293
+ function publicMaterial(ed25519PublicRaw, mldsa65PublicKey) {
294
+ const ed25519 = b64(ed25519PublicRaw);
295
+ const mldsa65 = b64(mldsa65PublicKey);
296
+ const mldsa65Fpr = sha256Hex(mldsa65PublicKey);
297
+ const keyId = crypto
298
+ .createHash("sha256")
299
+ .update(ed25519PublicRaw)
300
+ .update(mldsa65PublicKey)
301
+ .digest("hex")
302
+ .slice(0, 32);
303
+ return { ed25519, mldsa65, mldsa65Fpr, keyId };
304
+ }
305
+ /** Extract the raw 32-byte Ed25519 public key from a node KeyObject (SPKI tail). */
306
+ function rawEd25519FromKeyObject(pub) {
307
+ const spki = pub.export({ type: "spki", format: "der" });
308
+ return Uint8Array.prototype.slice.call(spki, spki.length - ED25519_RAW_PUBLIC_LEN);
309
+ }
310
+ /** Rebuild a node public KeyObject from a raw 32-byte Ed25519 key. */
311
+ function ed25519RawToPublicKey(raw) {
312
+ if (raw.length !== ED25519_RAW_PUBLIC_LEN) {
313
+ throw new Error(`ed25519 raw public key must be ${ED25519_RAW_PUBLIC_LEN} bytes`);
314
+ }
315
+ return crypto.createPublicKey({
316
+ key: Buffer.concat([ED25519_SPKI_PREFIX, Buffer.from(raw)]),
317
+ format: "der",
318
+ type: "spki",
319
+ });
320
+ }
321
+ function sha256Hex(bytes) {
322
+ return crypto.createHash("sha256").update(bytes).digest("hex");
323
+ }
324
+ function b64(bytes) {
325
+ return Buffer.from(bytes).toString("base64");
326
+ }
327
+ /**
328
+ * Deterministic JSON serialization (recursively key-sorted, no insignificant
329
+ * whitespace) used as the signing input. The seal payload contains only strings
330
+ * and safe integers, so this is unambiguous without full RFC 8785 number
331
+ * canonicalization. Both signing and verification serialize the identical field
332
+ * set (payload = seal minus `sig`), so the two sides always agree.
333
+ */
334
+ export function canonicalJson(value) {
335
+ if (value === null || typeof value !== "object") {
336
+ return JSON.stringify(value);
337
+ }
338
+ if (Array.isArray(value)) {
339
+ return `[${value.map((v) => canonicalJson(v)).join(",")}]`;
340
+ }
341
+ const obj = value;
342
+ const keys = Object.keys(obj).sort();
343
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`).join(",")}}`;
344
+ }
345
+ //# sourceMappingURL=pq-seal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pq-seal.js","sourceRoot":"","sources":["../src/pq-seal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import { type VerifyResult } from "./verify-pdf.js";
2
+ export interface PqSealVerdict {
3
+ /** A seal was found and parsed. */
4
+ present: boolean;
5
+ /** Hybrid verdict: digest binds to the document AND both signatures + fingerprint valid. */
6
+ ok: boolean;
7
+ /** SHA-256 over the covered document prefix equals the seal's `digest`. */
8
+ digestBinds?: boolean;
9
+ /** Classical Ed25519 signature valid. */
10
+ ed25519?: boolean;
11
+ /** Post-quantum ML-DSA-65 signature valid. */
12
+ mldsa65?: boolean;
13
+ /** Embedded ML-DSA fingerprint matches its public key. */
14
+ fingerprintOk?: boolean;
15
+ /** A `signerCert` was supplied AND it is a valid ML-DSA-65 cert for this seal's key. */
16
+ certIdentityOk?: boolean;
17
+ alg?: string;
18
+ keyId?: string;
19
+ /** ML-DSA-65 public-key fingerprint — the post-quantum signer identity to pin. */
20
+ mldsa65Fpr?: string;
21
+ signedAt?: string;
22
+ coveredBytes?: number;
23
+ /**
24
+ * The signer-asserted UUAID carried in the seal, when present (IAASO-0004).
25
+ * ASSERTION, NOT ATTRIBUTION: a valid seal proves the seal key claimed this
26
+ * identity, never that the identity's owner authorised the document. Treat it
27
+ * as attribution only once an independent uuaid -> key direction has been
28
+ * checked (a UUAID-side registration of this seal key). Unmatched, it carries
29
+ * no more weight than `mldsa65Fpr`.
30
+ */
31
+ uuaid?: string;
32
+ /** A `expectedUuaid` was supplied AND the seal asserts exactly that UUAID. */
33
+ uuaidMatches?: boolean;
34
+ failures: string[];
35
+ }
36
+ export interface VerifyPqSealOptions {
37
+ /**
38
+ * Pin the expected post-quantum signer. When set, the seal's ML-DSA-65
39
+ * fingerprint MUST equal this value (case-insensitive hex) or verification
40
+ * fails — this is how a relying party asserts "signed by THIS party" in-band
41
+ * (the raw-key TOFU trust model). Compare against a fingerprint you published
42
+ * or received out-of-band.
43
+ */
44
+ expectedMldsa65Fpr?: string;
45
+ /**
46
+ * A self-signed ML-DSA-65 X.509 certificate (PEM or DER) asserting the signer
47
+ * identity. When set, the cert must be valid AND its public key must be the one
48
+ * that produced the seal — the X.509 upgrade of `expectedMldsa65Fpr`.
49
+ */
50
+ signerCert?: string | Uint8Array;
51
+ /**
52
+ * Pin the expected signer-asserted UUAID. When set, the seal MUST carry
53
+ * exactly this `uuaid` (case-sensitive — UUAID segments are case-preserving)
54
+ * or verification fails.
55
+ *
56
+ * This pins an ASSERTION. It answers "does this seal claim the identity I
57
+ * expected?", not "does that identity vouch for this key?" — the relying party
58
+ * still supplies the trust, exactly as with `expectedMldsa65Fpr`. Pinning a
59
+ * UUAID you obtained from the document itself proves nothing.
60
+ */
61
+ expectedUuaid?: string;
62
+ }
63
+ /**
64
+ * Verify the embedded post-quantum seal against the document bytes. Never throws;
65
+ * a missing or malformed seal returns `{ present:false, ok:false }`. Pass
66
+ * `expectedMldsa65Fpr` to also pin the signer identity.
67
+ */
68
+ export declare function verifyPqSeal(pdf: Buffer, opts?: VerifyPqSealOptions): PqSealVerdict;
69
+ export interface DocumentVerification {
70
+ /**
71
+ * Overall: the classical signature is valid AND, if a post-quantum seal is
72
+ * present, it too is valid and lies within the classically-signed region. A
73
+ * document with no seal is judged on the classical signature alone (backward
74
+ * compatible); callers that REQUIRE post-quantum protection should also assert
75
+ * `postQuantum.present`.
76
+ */
77
+ ok: boolean;
78
+ /** Classical PAdES / PKCS#7 (RSA) verification. */
79
+ classical: VerifyResult;
80
+ /** Post-quantum hybrid seal verification. */
81
+ postQuantum: PqSealVerdict;
82
+ }
83
+ export interface VerifyDocumentOptions extends VerifyPqSealOptions {
84
+ /**
85
+ * Require a valid post-quantum seal. When true, a document without a seal (or
86
+ * with an invalid one) fails overall — use this where post-quantum protection
87
+ * is mandatory, to prevent a silent downgrade to classical-only.
88
+ */
89
+ requirePq?: boolean;
90
+ }
91
+ /**
92
+ * Full document verification: classical PAdES signature + post-quantum hybrid
93
+ * seal. Also asserts that the seal-covered region falls within the RSA-signed
94
+ * prefix, so the classical signature genuinely protects the seal. Pass
95
+ * `requirePq` to reject unsealed documents and `expectedMldsa65Fpr` to pin the
96
+ * post-quantum signer.
97
+ */
98
+ export declare function verifyDocument(pdf: Buffer, opts?: VerifyDocumentOptions): DocumentVerification;
99
+ //# sourceMappingURL=pq-verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pq-verify.d.ts","sourceRoot":"","sources":["../src/pq-verify.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKxE,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,4FAA4F;IAC5F,EAAE,EAAE,OAAO,CAAC;IACZ,2EAA2E;IAC3E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wFAAwF;IACxF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IACjC;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,mBAAwB,GAAG,aAAa,CAgFvF;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,EAAE,EAAE,OAAO,CAAC;IACZ,mDAAmD;IACnD,SAAS,EAAE,YAAY,CAAC;IACxB,6CAA6C;IAC7C,WAAW,EAAE,aAAa,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAsB,SAAQ,mBAAmB;IAChE;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA0B,GAAG,oBAAoB,CA+BlG"}