usertrust 1.4.0 → 2.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 (133) hide show
  1. package/README.md +17 -1
  2. package/dist/anomaly/detector.d.ts.map +1 -1
  3. package/dist/anomaly/detector.js +36 -11
  4. package/dist/anomaly/detector.js.map +1 -1
  5. package/dist/anomaly/index.d.ts +2 -2
  6. package/dist/anomaly/index.d.ts.map +1 -1
  7. package/dist/anomaly/index.js +1 -1
  8. package/dist/anomaly/index.js.map +1 -1
  9. package/dist/anomaly/signals/spend-velocity.d.ts +39 -12
  10. package/dist/anomaly/signals/spend-velocity.d.ts.map +1 -1
  11. package/dist/anomaly/signals/spend-velocity.js +66 -43
  12. package/dist/anomaly/signals/spend-velocity.js.map +1 -1
  13. package/dist/anomaly/signals/token-rate.d.ts +33 -13
  14. package/dist/anomaly/signals/token-rate.d.ts.map +1 -1
  15. package/dist/anomaly/signals/token-rate.js +124 -38
  16. package/dist/anomaly/signals/token-rate.js.map +1 -1
  17. package/dist/anomaly/types.d.ts +28 -6
  18. package/dist/anomaly/types.d.ts.map +1 -1
  19. package/dist/audit/anchor-doctor.d.ts +42 -0
  20. package/dist/audit/anchor-doctor.d.ts.map +1 -0
  21. package/dist/audit/anchor-doctor.js +285 -0
  22. package/dist/audit/anchor-doctor.js.map +1 -0
  23. package/dist/audit/anchor-verify.d.ts +229 -0
  24. package/dist/audit/anchor-verify.d.ts.map +1 -0
  25. package/dist/audit/anchor-verify.js +809 -0
  26. package/dist/audit/anchor-verify.js.map +1 -0
  27. package/dist/audit/anchor.d.ts +177 -0
  28. package/dist/audit/anchor.d.ts.map +1 -0
  29. package/dist/audit/anchor.js +922 -0
  30. package/dist/audit/anchor.js.map +1 -0
  31. package/dist/audit/canonical.js +1 -1
  32. package/dist/audit/canonical.js.map +1 -1
  33. package/dist/audit/chain.d.ts.map +1 -1
  34. package/dist/audit/chain.js +21 -7
  35. package/dist/audit/chain.js.map +1 -1
  36. package/dist/audit/read.d.ts +19 -0
  37. package/dist/audit/read.d.ts.map +1 -0
  38. package/dist/audit/read.js +94 -0
  39. package/dist/audit/read.js.map +1 -0
  40. package/dist/audit/rekor-verify.d.ts +116 -0
  41. package/dist/audit/rekor-verify.d.ts.map +1 -0
  42. package/dist/audit/rekor-verify.js +533 -0
  43. package/dist/audit/rekor-verify.js.map +1 -0
  44. package/dist/audit/rekor.d.ts +71 -0
  45. package/dist/audit/rekor.d.ts.map +1 -0
  46. package/dist/audit/rekor.js +556 -0
  47. package/dist/audit/rekor.js.map +1 -0
  48. package/dist/audit/rotation.js +1 -1
  49. package/dist/audit/rotation.js.map +1 -1
  50. package/dist/audit/sigv4.d.ts +44 -0
  51. package/dist/audit/sigv4.d.ts.map +1 -0
  52. package/dist/audit/sigv4.js +134 -0
  53. package/dist/audit/sigv4.js.map +1 -0
  54. package/dist/audit/verify.d.ts +78 -0
  55. package/dist/audit/verify.d.ts.map +1 -1
  56. package/dist/audit/verify.js +195 -1
  57. package/dist/audit/verify.js.map +1 -1
  58. package/dist/cli/anchor.d.ts +3 -0
  59. package/dist/cli/anchor.d.ts.map +1 -0
  60. package/dist/cli/anchor.js +626 -0
  61. package/dist/cli/anchor.js.map +1 -0
  62. package/dist/cli/completions.js +1 -1
  63. package/dist/cli/export.d.ts +3 -0
  64. package/dist/cli/export.d.ts.map +1 -0
  65. package/dist/cli/export.js +58 -0
  66. package/dist/cli/export.js.map +1 -0
  67. package/dist/cli/health.js.map +1 -1
  68. package/dist/cli/init.d.ts.map +1 -1
  69. package/dist/cli/init.js +99 -2
  70. package/dist/cli/init.js.map +1 -1
  71. package/dist/cli/inspect.d.ts.map +1 -1
  72. package/dist/cli/inspect.js +4 -34
  73. package/dist/cli/inspect.js.map +1 -1
  74. package/dist/cli/main.d.ts +2 -2
  75. package/dist/cli/main.d.ts.map +1 -1
  76. package/dist/cli/main.js +20 -1
  77. package/dist/cli/main.js.map +1 -1
  78. package/dist/cli/pricing.js +1 -1
  79. package/dist/cli/pricing.js.map +1 -1
  80. package/dist/cli/ui.d.ts +3 -0
  81. package/dist/cli/ui.d.ts.map +1 -0
  82. package/dist/cli/ui.js +35 -0
  83. package/dist/cli/ui.js.map +1 -0
  84. package/dist/cli/verify.d.ts.map +1 -1
  85. package/dist/cli/verify.js +342 -3
  86. package/dist/cli/verify.js.map +1 -1
  87. package/dist/config.d.ts.map +1 -1
  88. package/dist/config.js.map +1 -1
  89. package/dist/detect.d.ts +71 -16
  90. package/dist/detect.d.ts.map +1 -1
  91. package/dist/detect.js +141 -6
  92. package/dist/detect.js.map +1 -1
  93. package/dist/export/markdown.d.ts +12 -0
  94. package/dist/export/markdown.d.ts.map +1 -0
  95. package/dist/export/markdown.js +142 -0
  96. package/dist/export/markdown.js.map +1 -0
  97. package/dist/govern.d.ts +67 -3
  98. package/dist/govern.d.ts.map +1 -1
  99. package/dist/govern.js +1011 -219
  100. package/dist/govern.js.map +1 -1
  101. package/dist/headless.d.ts +41 -2
  102. package/dist/headless.d.ts.map +1 -1
  103. package/dist/headless.js +58 -7
  104. package/dist/headless.js.map +1 -1
  105. package/dist/index.d.ts +33 -25
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +30 -23
  108. package/dist/index.js.map +1 -1
  109. package/dist/ledger/client.d.ts.map +1 -1
  110. package/dist/ledger/client.js +57 -46
  111. package/dist/ledger/client.js.map +1 -1
  112. package/dist/ledger/engine.d.ts.map +1 -1
  113. package/dist/ledger/engine.js +22 -13
  114. package/dist/ledger/engine.js.map +1 -1
  115. package/dist/ledger/pricing.d.ts +54 -0
  116. package/dist/ledger/pricing.d.ts.map +1 -1
  117. package/dist/ledger/pricing.js +128 -8
  118. package/dist/ledger/pricing.js.map +1 -1
  119. package/dist/shared/types.d.ts +154 -340
  120. package/dist/shared/types.d.ts.map +1 -1
  121. package/dist/shared/types.js +67 -17
  122. package/dist/shared/types.js.map +1 -1
  123. package/dist/snapshot/checkpoint.d.ts.map +1 -1
  124. package/dist/snapshot/checkpoint.js +20 -2
  125. package/dist/snapshot/checkpoint.js.map +1 -1
  126. package/dist/streaming.d.ts +13 -3
  127. package/dist/streaming.d.ts.map +1 -1
  128. package/dist/streaming.js +88 -30
  129. package/dist/streaming.js.map +1 -1
  130. package/dist/supply-chain/sign.d.ts.map +1 -1
  131. package/dist/supply-chain/sign.js +3 -0
  132. package/dist/supply-chain/sign.js.map +1 -1
  133. package/package.json +6 -4
@@ -0,0 +1,533 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 Usertools, Inc.
3
+ /**
4
+ * Rekor Transparency-Log Receipt Verification — Zero-dependency standalone
5
+ *
6
+ * INTENTIONAL DUPLICATION: this file exists byte-for-byte in BOTH
7
+ * packages/verify/src/rekor-verify.ts and
8
+ * packages/core/src/audit/rekor-verify.ts — here even the import paths match,
9
+ * since the module's only sibling import is anchor-verify.js. The parity test
10
+ * pins the two together; any change must land in both packages.
11
+ *
12
+ * A receipt is EVIDENCE SUPPLIED BY THE PARTY UNDER AUDIT: it proves nothing on
13
+ * its own, and every field in it is attacker-shaped. What verification
14
+ * establishes, end to end, is a single chain of bindings:
15
+ *
16
+ * our signed anchor record -> the bytes the log stored -> that entry's
17
+ * position in a tree -> a checkpoint over that tree -> a log key the AUDITOR
18
+ * pinned (never one the receipt names).
19
+ *
20
+ * Break any link and the receipt is worthless, so each is checked in order and
21
+ * the first failure is fatal (fail-closed). Rekor data deliberately lives in
22
+ * SEPARATE receipt files: the anchor record schema is frozen, and a
23
+ * transparency log must never become a field inside the thing it witnesses.
24
+ *
25
+ * Offline scope: a verified receipt proves the entry was included in the log
26
+ * under a pinned key. WHEN it was included is a separate, weaker claim:
27
+ * `integratedTime` is covered by no signature of its own, so it counts as
28
+ * attested only when the log's signed entry timestamp (SET) over it verifies
29
+ * under the same pinned keyring — otherwise the receipt proves inclusion and
30
+ * says nothing about time. Neither claim proves the log's current head is
31
+ * consistent with that checkpoint; that needs a witness/consistency query,
32
+ * which stays out of the zero-dependency verifier by design.
33
+ */
34
+ import { createHash } from "node:crypto";
35
+ import { anchorPayloadHash, publicKeyFromPem, verifySignatureRaw, } from "./anchor-verify.js";
36
+ // ── Constants ──
37
+ /**
38
+ * The rekor.sigstore.dev v1 log key, as served by
39
+ * https://rekor.sigstore.dev/api/v1/log/publicKey — ECDSA P-256, SPKI sha256
40
+ * c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d (the log's
41
+ * published logID). This is DATA, not a dependency, and it is not a blanket
42
+ * trust root: it is consulted ONLY for receipts whose log URL host IS
43
+ * rekor.sigstore.dev. Any other log must be pinned by the operator with
44
+ * --rekor-pubkey.
45
+ */
46
+ export const REKOR_PROD_PUBKEY_PEM = `-----BEGIN PUBLIC KEY-----
47
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwr
48
+ kBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==
49
+ -----END PUBLIC KEY-----
50
+ `;
51
+ /** The one host the embedded key above is allowed to speak for. */
52
+ const REKOR_PROD_HOST = "rekor.sigstore.dev";
53
+ const ERR = "rekor-receipt-invalid";
54
+ // Caps on untrusted input. A receipt is a small artifact; anything near these
55
+ // bounds is an attempt to make the verifier do work, not to prove inclusion.
56
+ const MAX_RECEIPT_BYTES = 256 * 1024;
57
+ const MAX_ENTRY_BODY_BYTES = 64 * 1024;
58
+ const MAX_CHECKPOINT_BYTES = 8 * 1024;
59
+ const MAX_INCLUSION_PATH = 64;
60
+ const MAX_PEM_BYTES = 16 * 1024;
61
+ const MAX_SET_BYTES = 1024;
62
+ /**
63
+ * Exclusive upper bound on integratedTime, in SECONDS: `* 1000` must stay
64
+ * inside the ±8.64e15 ms ECMAScript Date range, or every downstream
65
+ * `new Date(ms).toISOString()` throws RangeError on attacker-chosen input.
66
+ */
67
+ const MAX_INTEGRATED_TIME = 8_640_000_000_000;
68
+ const HEX64 = /^[0-9a-f]{64}$/;
69
+ const BASE64 = /^[A-Za-z0-9+/]*={0,2}$/;
70
+ const UINT = /^(0|[1-9][0-9]*)$/;
71
+ // Matching control characters is the entire point here — they are what gets
72
+ // removed from anything echoed back to a terminal.
73
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping them is the intent
74
+ const CONTROL_CHARS = /[\x00-\x1f\x7f]/g;
75
+ const LEAF_PREFIX = Buffer.from([0x00]);
76
+ const NODE_PREFIX = Buffer.from([0x01]);
77
+ const RECEIPT_KEYS = new Set(["v", "vaultId", "anchorSeq", "artifactHash", "entryBody", "log"]);
78
+ const LOG_KEYS = new Set([
79
+ "url",
80
+ "logIndex",
81
+ "treeSize",
82
+ "rootHash",
83
+ "hashes",
84
+ "checkpoint",
85
+ "integratedTime",
86
+ "signedEntryTimestamp",
87
+ "logID",
88
+ ]);
89
+ // ── Small helpers ──
90
+ /**
91
+ * Untrusted values are never echoed whole into an error string. Control
92
+ * characters are stripped BEFORE truncation, because these strings are printed
93
+ * to a terminal: an escape sequence or a bare CR inside a field name would let
94
+ * the party under audit repaint the line its own verdict is printed on, and
95
+ * truncating first would leave a half-consumed escape behind.
96
+ */
97
+ function clip(value) {
98
+ const scrubbed = value.replace(CONTROL_CHARS, "");
99
+ return scrubbed.length <= 80 ? scrubbed : `${scrubbed.slice(0, 80)}...`;
100
+ }
101
+ function asObject(value) {
102
+ return value !== null && typeof value === "object" && !Array.isArray(value)
103
+ ? value
104
+ : null;
105
+ }
106
+ function isSafeIntAtLeast(value, min) {
107
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= min;
108
+ }
109
+ /** Lowercased host (INCLUDING port) of an http(s) URL, or null. */
110
+ function logHost(url) {
111
+ let parsed;
112
+ try {
113
+ parsed = new URL(url);
114
+ }
115
+ catch {
116
+ return null;
117
+ }
118
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:")
119
+ return null;
120
+ return parsed.host.toLowerCase();
121
+ }
122
+ function nodeHash(left, right) {
123
+ return createHash("sha256").update(NODE_PREFIX).update(left).update(right).digest();
124
+ }
125
+ /**
126
+ * Sorted-key JSON of a FLAT object of strings and safe integers — the exact
127
+ * bytes a Rekor SET is computed over. Over this charset (base64, lowercase hex,
128
+ * integers) it is byte-identical to RFC 8785 JCS; a general JCS implementation
129
+ * would buy nothing here and cost the verifier its zero-dependency property.
130
+ */
131
+ function sortedKeyStringify(value) {
132
+ const fields = Object.keys(value)
133
+ .sort()
134
+ .map((key) => `${JSON.stringify(key)}:${JSON.stringify(value[key])}`);
135
+ return `{${fields.join(",")}}`;
136
+ }
137
+ // ── Signed notes (checkpoints) ──
138
+ /**
139
+ * Parse a signed note:
140
+ * <origin>\n<treeSize>\n<base64 rootHash>\n\n— <keyname> <base64 sig>\n...
141
+ * Strictly LF-only and strictly this shape — a note is a signed artifact, so
142
+ * accepting variants would mean verifying a signature over bytes we did not
143
+ * actually parse. The signature payload is `4-byte keyhint || DER signature`;
144
+ * the hint identifies which key the log used and is ADVISORY only, because the
145
+ * auditor pins the key out-of-band. Only its 4 bytes are skipped.
146
+ *
147
+ * ONE OR MORE signature lines are accepted: a production checkpoint is signed by
148
+ * the log and co-signed by its witnesses, and every line must still be
149
+ * well-formed. Which of them (if any) speaks for the auditor is decided later,
150
+ * against the pinned keyring — never here.
151
+ */
152
+ export function parseSignedNote(note) {
153
+ if (note.length === 0 || Buffer.byteLength(note, "utf8") > MAX_CHECKPOINT_BYTES)
154
+ return null;
155
+ if (note.includes("\r"))
156
+ return null;
157
+ const lines = note.split("\n");
158
+ if (lines.length > 5 && lines[lines.length - 1] === "")
159
+ lines.pop();
160
+ if (lines.length < 5)
161
+ return null;
162
+ const origin = lines[0];
163
+ const sizeLine = lines[1];
164
+ const rootB64 = lines[2];
165
+ if (origin.length === 0 || lines[3] !== "")
166
+ return null;
167
+ if (!UINT.test(sizeLine))
168
+ return null;
169
+ const treeSize = Number(sizeLine);
170
+ if (!Number.isSafeInteger(treeSize))
171
+ return null;
172
+ if (!BASE64.test(rootB64))
173
+ return null;
174
+ const root = Buffer.from(rootB64, "base64");
175
+ if (root.length !== 32)
176
+ return null;
177
+ const sigs = [];
178
+ for (const line of lines.slice(4)) {
179
+ const parts = line.split(" ");
180
+ if (parts.length !== 3 || parts[0] !== "—" || parts[1].length === 0)
181
+ return null;
182
+ const sigField = parts[2];
183
+ if (!BASE64.test(sigField))
184
+ return null;
185
+ const raw = Buffer.from(sigField, "base64");
186
+ if (raw.length <= 4)
187
+ return null;
188
+ sigs.push(raw.subarray(4));
189
+ }
190
+ return {
191
+ origin,
192
+ treeSize,
193
+ rootHashHex: root.toString("hex"),
194
+ body: `${origin}\n${sizeLine}\n${rootB64}\n`,
195
+ sigs,
196
+ };
197
+ }
198
+ /**
199
+ * Does a checkpoint's signed origin name the host the receipt says it came from?
200
+ * A production Rekor checkpoint's origin is `"<host> - <treeID>"`, while the
201
+ * signed-note format also permits the bare host; both identify the same log, so
202
+ * only the part before the first " - " is compared. The comparison stays exact
203
+ * on that part — a suffix rule would let evil.example.org.attacker.net pass.
204
+ */
205
+ function originNamesHost(origin, host) {
206
+ const separator = origin.indexOf(" - ");
207
+ const named = separator === -1 ? origin : origin.slice(0, separator);
208
+ return named.toLowerCase() === host;
209
+ }
210
+ // ── RFC 9162 inclusion ──
211
+ /**
212
+ * RFC 9162 §2.1.3.2 inclusion verification: walk the audit path from the leaf
213
+ * to the root, deciding sibling order from the leaf index rather than from any
214
+ * hint the proof supplies. `fn`/`sn` track the leaf's and the last leaf's
215
+ * positions within the current subtree; the right-shift after a left-sibling
216
+ * merge is what makes right-edge (incomplete) subtrees come out correct.
217
+ *
218
+ * Never throws: malformed hex, out-of-range indices, and over-long paths are
219
+ * rejections, because this runs on attacker-supplied input.
220
+ */
221
+ export function verifyIndexInclusion(leafHex, index, treeSize, pathHex, rootHex) {
222
+ if (!Number.isSafeInteger(index) || !Number.isSafeInteger(treeSize))
223
+ return false;
224
+ if (index < 0 || treeSize < 1 || index >= treeSize)
225
+ return false;
226
+ if (!HEX64.test(leafHex) || !HEX64.test(rootHex))
227
+ return false;
228
+ if (pathHex.length > MAX_INCLUSION_PATH)
229
+ return false;
230
+ let fn = index;
231
+ let sn = treeSize - 1;
232
+ let r = Buffer.from(leafHex, "hex");
233
+ for (const pHex of pathHex) {
234
+ if (!HEX64.test(pHex))
235
+ return false;
236
+ if (sn === 0)
237
+ return false;
238
+ const p = Buffer.from(pHex, "hex");
239
+ if (fn % 2 === 1 || fn === sn) {
240
+ r = nodeHash(p, r);
241
+ // LSB(fn) not set (the fn === sn right-edge case): shift both equally
242
+ // until LSB(fn) is set or fn is 0.
243
+ while (fn % 2 === 0 && fn !== 0) {
244
+ fn = Math.floor(fn / 2);
245
+ sn = Math.floor(sn / 2);
246
+ }
247
+ }
248
+ else {
249
+ r = nodeHash(r, p);
250
+ }
251
+ fn = Math.floor(fn / 2);
252
+ sn = Math.floor(sn / 2);
253
+ }
254
+ return sn === 0 && r.toString("hex") === rootHex;
255
+ }
256
+ // ── Strict receipt parsing ──
257
+ /**
258
+ * Strict parse of one receipt. Unknown fields, wrong types, and range
259
+ * violations are all rejected before any crypto runs — the same fail-closed
260
+ * posture as parseAnchorRecord, for the same reason: a field the verifier
261
+ * silently ignores is a field an attacker can use.
262
+ */
263
+ export function parseRekorReceipt(raw) {
264
+ const bad = (message) => ({
265
+ receipt: null,
266
+ error: `${ERR}: ${message}`,
267
+ });
268
+ if (Buffer.byteLength(raw, "utf8") > MAX_RECEIPT_BYTES)
269
+ return bad("receipt exceeds 256 KiB");
270
+ let parsed;
271
+ try {
272
+ parsed = JSON.parse(raw);
273
+ }
274
+ catch {
275
+ return bad("not valid JSON");
276
+ }
277
+ const obj = asObject(parsed);
278
+ if (obj === null)
279
+ return bad("not an object");
280
+ for (const key of Object.keys(obj)) {
281
+ if (!RECEIPT_KEYS.has(key))
282
+ return bad(`unknown field "${clip(key)}"`);
283
+ }
284
+ if (obj.v !== 1)
285
+ return bad("unsupported version");
286
+ if (typeof obj.vaultId !== "string" || obj.vaultId.length === 0)
287
+ return bad("missing vaultId");
288
+ if (!isSafeIntAtLeast(obj.anchorSeq, 1)) {
289
+ return bad("anchorSeq must be a safe integer >= 1");
290
+ }
291
+ if (typeof obj.artifactHash !== "string" || !HEX64.test(obj.artifactHash)) {
292
+ return bad("artifactHash must be 64 lowercase hex characters");
293
+ }
294
+ if (typeof obj.entryBody !== "string" || obj.entryBody.length === 0) {
295
+ return bad("missing entryBody");
296
+ }
297
+ if (!BASE64.test(obj.entryBody))
298
+ return bad("entryBody must be base64");
299
+ if (Buffer.from(obj.entryBody, "base64").length > MAX_ENTRY_BODY_BYTES) {
300
+ return bad("entryBody exceeds 64 KiB decoded");
301
+ }
302
+ const log = asObject(obj.log);
303
+ if (log === null)
304
+ return bad("log must be an object");
305
+ for (const key of Object.keys(log)) {
306
+ if (!LOG_KEYS.has(key))
307
+ return bad(`unknown log field "${clip(key)}"`);
308
+ }
309
+ if (typeof log.url !== "string" || logHost(log.url) === null) {
310
+ return bad("log.url must be an http(s) URL");
311
+ }
312
+ if (!isSafeIntAtLeast(log.logIndex, 0))
313
+ return bad("log.logIndex must be a safe integer >= 0");
314
+ if (!isSafeIntAtLeast(log.treeSize, 1))
315
+ return bad("log.treeSize must be a safe integer >= 1");
316
+ if (log.logIndex >= log.treeSize)
317
+ return bad("log.logIndex must be < log.treeSize");
318
+ if (typeof log.rootHash !== "string" || !HEX64.test(log.rootHash)) {
319
+ return bad("log.rootHash must be 64 lowercase hex characters");
320
+ }
321
+ if (!Array.isArray(log.hashes) || log.hashes.length > MAX_INCLUSION_PATH) {
322
+ return bad(`log.hashes must be an array of at most ${MAX_INCLUSION_PATH} hashes`);
323
+ }
324
+ for (const h of log.hashes) {
325
+ if (typeof h !== "string" || !HEX64.test(h)) {
326
+ return bad("log.hashes entries must be 64 lowercase hex characters");
327
+ }
328
+ }
329
+ if (typeof log.checkpoint !== "string" ||
330
+ log.checkpoint.length === 0 ||
331
+ Buffer.byteLength(log.checkpoint, "utf8") > MAX_CHECKPOINT_BYTES) {
332
+ return bad("log.checkpoint must be a non-empty string of at most 8 KiB");
333
+ }
334
+ // Bounded in SECONDS so `integratedTime * 1000` cannot leave the Date range
335
+ // and turn a printed verdict into a RangeError on attacker-chosen input.
336
+ if (!isSafeIntAtLeast(log.integratedTime, 1) || log.integratedTime >= MAX_INTEGRATED_TIME) {
337
+ return bad(`log.integratedTime must be a safe integer > 0 and < ${MAX_INTEGRATED_TIME}`);
338
+ }
339
+ if (log.logID !== undefined && (typeof log.logID !== "string" || !HEX64.test(log.logID))) {
340
+ return bad("log.logID must be 64 lowercase hex characters");
341
+ }
342
+ if (log.signedEntryTimestamp !== undefined) {
343
+ if (typeof log.signedEntryTimestamp !== "string" ||
344
+ log.signedEntryTimestamp.length === 0 ||
345
+ !BASE64.test(log.signedEntryTimestamp) ||
346
+ Buffer.byteLength(log.signedEntryTimestamp, "utf8") > MAX_SET_BYTES) {
347
+ return bad("log.signedEntryTimestamp must be base64 of at most 1 KiB");
348
+ }
349
+ // The logID is part of the payload the SET signs, so a SET without one
350
+ // is unverifiable by construction — and unverifiable supplied evidence
351
+ // is a rejection, never a receipt that quietly proves less than it looks.
352
+ if (log.logID === undefined) {
353
+ return bad("log.signedEntryTimestamp requires log.logID");
354
+ }
355
+ }
356
+ return { receipt: obj, error: null };
357
+ }
358
+ // ── Entry binding ──
359
+ /**
360
+ * The logged entry must commit to OUR artifact AND OUR signature. Without the
361
+ * signature binding, anyone could log the (public) payload hash of someone
362
+ * else's anchor and present the resulting receipt as their own.
363
+ */
364
+ function checkHashedRekordEntry(entryBytes, artifactHash, recordSigBase64) {
365
+ if (entryBytes.length === 0)
366
+ return "entryBody decodes to no bytes";
367
+ if (entryBytes.length > MAX_ENTRY_BODY_BYTES)
368
+ return "entryBody exceeds 64 KiB decoded";
369
+ let parsed;
370
+ try {
371
+ parsed = JSON.parse(entryBytes.toString("utf8"));
372
+ }
373
+ catch {
374
+ return "entryBody is not valid JSON";
375
+ }
376
+ const entry = asObject(parsed);
377
+ if (entry === null)
378
+ return "entryBody is not a JSON object";
379
+ if (entry.kind !== "hashedrekord")
380
+ return "entryBody kind is not hashedrekord";
381
+ const spec = asObject(entry.spec);
382
+ if (spec === null)
383
+ return "entryBody spec is missing";
384
+ const hash = asObject(asObject(spec.data)?.hash);
385
+ if (hash === null)
386
+ return "entryBody spec.data.hash is missing";
387
+ if (hash.algorithm !== "sha256")
388
+ return "entryBody spec.data.hash.algorithm is not sha256";
389
+ if (hash.value !== artifactHash) {
390
+ return "entryBody spec.data.hash.value does not match the receipt artifactHash";
391
+ }
392
+ const signature = asObject(spec.signature);
393
+ if (signature === null || typeof signature.content !== "string") {
394
+ return "entryBody spec.signature.content is missing";
395
+ }
396
+ // Compare DECODED bytes: base64 spelling is not canonical, so string
397
+ // equality would reject honest receipts and is not what "same signature"
398
+ // means.
399
+ const logged = Buffer.from(signature.content, "base64");
400
+ const ours = Buffer.from(recordSigBase64, "base64");
401
+ if (ours.length === 0 || !logged.equals(ours)) {
402
+ return "entryBody spec.signature.content is not the anchor record signature";
403
+ }
404
+ return null;
405
+ }
406
+ /**
407
+ * Which key(s) may speak for this log. Supplying no key is only meaningful for
408
+ * the one log whose key ships with the verifier; for anything else, an unpinned
409
+ * receipt would be self-certifying, so it is refused rather than trusted.
410
+ *
411
+ * A caller who supplied material that ALL got discarded (empty file, oversized
412
+ * blob) is not a caller who supplied nothing: silently falling back to the
413
+ * embedded key there would verify a rekor.sigstore.dev receipt under a key the
414
+ * auditor never chose, and pass a merge gate the auditor thought they had
415
+ * pinned. Discarded-everything is refused instead.
416
+ */
417
+ function resolveLogKeyring(host, logPubkeysPem) {
418
+ const supplied = logPubkeysPem.filter((pem) => pem.length > 0 && Buffer.byteLength(pem, "utf8") <= MAX_PEM_BYTES);
419
+ if (supplied.length > 0)
420
+ return { keys: supplied, error: null };
421
+ if (logPubkeysPem.length > 0) {
422
+ return {
423
+ keys: [],
424
+ error: "supplied --rekor-pubkey material is empty or invalid — refusing to fall back to the embedded key",
425
+ };
426
+ }
427
+ if (host === REKOR_PROD_HOST)
428
+ return { keys: [REKOR_PROD_PUBKEY_PEM], error: null };
429
+ return {
430
+ keys: [],
431
+ error: `custom log requires --rekor-pubkey (no pinned key for log host ${clip(host)})`,
432
+ };
433
+ }
434
+ // ── Receipt verification ──
435
+ /**
436
+ * Verify one receipt against the anchor record it claims to witness, under a
437
+ * caller-pinned keyring (any key in the ring may verify the checkpoint).
438
+ *
439
+ * The order below is the binding chain, and it is deliberate: cheap identity
440
+ * and hash checks first, then the entry decode, then the inclusion walk, and
441
+ * only then the signatures — so a receipt for the wrong record can never cost
442
+ * an ECDSA verification, and a failure always names the earliest broken link.
443
+ * `ok` is the INCLUSION verdict; `attestedTimeMs` is the strictly weaker time
444
+ * claim, and only a verifying signed entry timestamp produces it.
445
+ */
446
+ export function verifyRekorReceipt(receipt, record, logPubkeysPem) {
447
+ const errors = [];
448
+ const fail = (message) => {
449
+ errors.push(`${ERR}: ${message}`);
450
+ return { ok: false, attestedTimeMs: null, errors };
451
+ };
452
+ // 1 — the receipt must name THIS record.
453
+ if (receipt.vaultId !== record.vaultId || receipt.anchorSeq !== record.anchorSeq) {
454
+ return fail(`record mismatch: receipt claims vault ${clip(receipt.vaultId)} anchorSeq ${receipt.anchorSeq}`);
455
+ }
456
+ // 2 — and must carry that record's signing-payload hash.
457
+ const payloadHash = anchorPayloadHash(record);
458
+ if (receipt.artifactHash !== payloadHash) {
459
+ return fail("artifactHash is not the anchor payload hash of this record");
460
+ }
461
+ // 3 — the bytes the log stored must commit to the artifact and our signature.
462
+ const entryBytes = Buffer.from(receipt.entryBody, "base64");
463
+ const entryError = checkHashedRekordEntry(entryBytes, payloadHash, record.sig);
464
+ if (entryError !== null)
465
+ return fail(entryError);
466
+ // 4/5 — sha256(0x00 || stored bytes) must sit at logIndex under log.rootHash.
467
+ const leafHex = createHash("sha256").update(LEAF_PREFIX).update(entryBytes).digest("hex");
468
+ if (!verifyIndexInclusion(leafHex, receipt.log.logIndex, receipt.log.treeSize, receipt.log.hashes, receipt.log.rootHash)) {
469
+ return fail(`inclusion proof does not reconstruct log.rootHash from logIndex ${receipt.log.logIndex} of ${receipt.log.treeSize}`);
470
+ }
471
+ // 6 — the checkpoint must be this log's, at this size, over this root.
472
+ const host = logHost(receipt.log.url);
473
+ if (host === null)
474
+ return fail("log.url is not an http(s) URL");
475
+ const note = parseSignedNote(receipt.log.checkpoint);
476
+ if (note === null)
477
+ return fail("log.checkpoint is not a parseable signed note");
478
+ if (!originNamesHost(note.origin, host)) {
479
+ return fail(`log.checkpoint origin ${clip(note.origin)} is not the log.url host ${clip(host)}`);
480
+ }
481
+ if (note.treeSize !== receipt.log.treeSize) {
482
+ return fail(`log.checkpoint treeSize ${note.treeSize} does not match log.treeSize ${receipt.log.treeSize}`);
483
+ }
484
+ if (note.rootHashHex !== receipt.log.rootHash) {
485
+ return fail("log.checkpoint root hash does not match log.rootHash");
486
+ }
487
+ // 7 — and must be signed by a key the AUDITOR pinned. A co-signed checkpoint
488
+ // carries one signature per witness, and the auditor pins only the parties
489
+ // they trust: ONE line verifying under ONE pinned key is the whole claim.
490
+ const keyring = resolveLogKeyring(host, logPubkeysPem);
491
+ if (keyring.error !== null)
492
+ return fail(keyring.error);
493
+ const sigsBase64 = note.sigs.map((sig) => sig.toString("base64"));
494
+ const signed = keyring.keys.some((pem) => {
495
+ const key = publicKeyFromPem(pem);
496
+ if (key === null)
497
+ return false;
498
+ return sigsBase64.some((sig) => verifySignatureRaw("ecdsa-p256", note.body, key, sig));
499
+ });
500
+ if (!signed) {
501
+ return fail("log.checkpoint signature does not verify under any pinned log public key");
502
+ }
503
+ // 8 — inclusion holds. TIME is a separate claim: the checkpoint signs the
504
+ // tree, not when this entry entered it, so integratedTime is worth exactly
505
+ // as much as the signed entry timestamp over it. No SET (or no logID to
506
+ // build its payload from) means an honest "included, time unknown" — the
507
+ // caller then falls back to the operator-claimed timestamp knowing it is
508
+ // operator-claimed. A SET that is PRESENT and does not verify is different
509
+ // in kind: supplied evidence that fails is a forgery attempt, not an
510
+ // absence, so it fails the whole receipt closed.
511
+ const set = receipt.log.signedEntryTimestamp;
512
+ const logID = receipt.log.logID;
513
+ if (set === undefined || logID === undefined) {
514
+ return { ok: true, attestedTimeMs: null, errors };
515
+ }
516
+ const setPayload = sortedKeyStringify({
517
+ body: receipt.entryBody,
518
+ integratedTime: receipt.log.integratedTime,
519
+ logID,
520
+ logIndex: receipt.log.logIndex,
521
+ });
522
+ const setSigned = keyring.keys.some((pem) => {
523
+ const key = publicKeyFromPem(pem);
524
+ if (key === null)
525
+ return false;
526
+ return verifySignatureRaw("ecdsa-p256", setPayload, key, set);
527
+ });
528
+ if (!setSigned)
529
+ return fail("signedEntryTimestamp does not verify");
530
+ // 9 — every link held AND the log signed the time, so it is witness-attested.
531
+ return { ok: true, attestedTimeMs: receipt.log.integratedTime * 1000, errors };
532
+ }
533
+ //# sourceMappingURL=rekor-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rekor-verify.js","sourceRoot":"","sources":["../../src/audit/rekor-verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { type AnchorSink } from "./anchor.js";
2
+ import { type AnchorRecord } from "./anchor-verify.js";
3
+ export declare const DEFAULT_REKOR_URL = "https://rekor.sigstore.dev";
4
+ /**
5
+ * Injectable HTTP transport — the sinks' only impure edge. Structurally
6
+ * identical to anchor-doctor's, so a caller may share one transport across
7
+ * both without either module importing the other.
8
+ */
9
+ export type HttpTransport = (opts: {
10
+ method: string;
11
+ url: string;
12
+ headers: Record<string, string>;
13
+ body: Buffer;
14
+ }) => Promise<{
15
+ status: number;
16
+ body: string;
17
+ headers?: Record<string, string>;
18
+ }>;
19
+ export interface S3SinkConfig {
20
+ bucket: string;
21
+ region: string;
22
+ prefix?: string;
23
+ endpoint?: string;
24
+ }
25
+ /**
26
+ * Endpoint rule for BOTH sinks. Plaintext is refused off-loopback: for S3,
27
+ * SigV4 authenticates the request but does not encrypt it, so an http endpoint
28
+ * on the network would put the credential-bearing headers on the wire; for
29
+ * Rekor, an http log URL lets anyone on the path answer for the witness — and
30
+ * a sink that accepts a forged 201 files forged evidence. Loopback is allowed
31
+ * for dev MinIO/LocalStack and local log instances.
32
+ */
33
+ export declare function parseEndpoint(endpoint: string, sinkName?: string): URL;
34
+ /**
35
+ * PUT one canonical record per object, keyed by vault and anchorSeq. Immutability
36
+ * is the STORE's job (Object Lock retention / a deny-delete bucket policy);
37
+ * `usertrust anchor doctor` reports whether this identity's permissions match
38
+ * that intent.
39
+ */
40
+ export declare function s3Sink(cfg: S3SinkConfig, transport?: HttpTransport): AnchorSink;
41
+ /**
42
+ * The hashedrekord entry we PROPOSE for a record: the anchor payload hash as the
43
+ * artifact, the record's Ed25519 signature, and the vault's public key. The log
44
+ * stores its own serialization of this; the receipt carries the log's bytes, so
45
+ * these are the bytes we sign nothing over and merely offer.
46
+ */
47
+ export declare function buildHashedRekordEntry(record: AnchorRecord, publicKeySpkiBase64: string): string;
48
+ /**
49
+ * `<seq12>.<8 hex of sha256(log url)>.json` — one receipt per (anchor, LOG).
50
+ * Keying by anchorSeq alone made two rekor sinks silently overwrite each
51
+ * other's evidence: the second witness's receipt replaced the first's, and the
52
+ * operator ended up with fewer independent attestations than they configured.
53
+ * Readers glob `*.json` in this directory, so pre-existing `<seq12>.json`
54
+ * receipts keep being found.
55
+ */
56
+ export declare function rekorReceiptPath(rootDir: string, anchorSeq: number, logUrl: string): string;
57
+ /**
58
+ * Publish a record's payload hash to a Rekor transparency log and persist the
59
+ * inclusion receipt next to the mirror.
60
+ *
61
+ * A 409 means the log already holds an entry for this proposal, which happens
62
+ * on exactly one honest path: a crash between writing the receipt and clearing
63
+ * the outbox, so the emitter redelivers a record that IS already witnessed.
64
+ * That case is resolved from the receipt we already hold — never from the 409
65
+ * itself, which carries no evidence. A 409 with no such receipt is a duplicate
66
+ * we cannot account for, and fabricating one from a Location header would mean
67
+ * filing evidence about bytes we never saw (delta D1), so it rejects and the
68
+ * outbox keeps the record for a human.
69
+ */
70
+ export declare function rekorSink(rootDir: string, url?: string, transport?: HttpTransport): AnchorSink;
71
+ //# sourceMappingURL=rekor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rekor.d.ts","sourceRoot":"","sources":["../../src/audit/rekor.ts"],"names":[],"mappings":"AA2CA,OAAO,EAAuB,KAAK,UAAU,EAAkC,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,KAAK,YAAY,EAAqB,MAAM,oBAAoB,CAAC;AAK1E,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;AAe9D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACb,KAAK,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAElF,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAwCD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,GAAG,CAczE;AAyBD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,GAAE,aAA6B,GAAG,UAAU,CA0C9F;AAkBD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAchG;AA4ID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG3F;AA8GD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAA0B,EAC/B,SAAS,GAAE,aAA6B,GACtC,UAAU,CAwEZ"}