burnledger 0.2.1

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 (115) hide show
  1. package/README.md +182 -0
  2. package/dist/cjs/cli.d.ts +16 -0
  3. package/dist/cjs/cli.d.ts.map +1 -0
  4. package/dist/cjs/cli.js +168 -0
  5. package/dist/cjs/cli.js.map +1 -0
  6. package/dist/cjs/client.d.ts +116 -0
  7. package/dist/cjs/client.d.ts.map +1 -0
  8. package/dist/cjs/client.js +353 -0
  9. package/dist/cjs/client.js.map +1 -0
  10. package/dist/cjs/crypto-browser.d.ts +7 -0
  11. package/dist/cjs/crypto-browser.d.ts.map +1 -0
  12. package/dist/cjs/crypto-browser.js +37 -0
  13. package/dist/cjs/crypto-browser.js.map +1 -0
  14. package/dist/cjs/crypto-node.d.ts +4 -0
  15. package/dist/cjs/crypto-node.d.ts.map +1 -0
  16. package/dist/cjs/crypto-node.js +30 -0
  17. package/dist/cjs/crypto-node.js.map +1 -0
  18. package/dist/cjs/crypto.d.ts +6 -0
  19. package/dist/cjs/crypto.d.ts.map +1 -0
  20. package/dist/cjs/crypto.js +4 -0
  21. package/dist/cjs/crypto.js.map +1 -0
  22. package/dist/cjs/errors.d.ts +76 -0
  23. package/dist/cjs/errors.d.ts.map +1 -0
  24. package/dist/cjs/errors.js +119 -0
  25. package/dist/cjs/errors.js.map +1 -0
  26. package/dist/cjs/http.d.ts +35 -0
  27. package/dist/cjs/http.d.ts.map +1 -0
  28. package/dist/cjs/http.js +160 -0
  29. package/dist/cjs/http.js.map +1 -0
  30. package/dist/cjs/index.browser.d.ts +31 -0
  31. package/dist/cjs/index.browser.d.ts.map +1 -0
  32. package/dist/cjs/index.browser.js +54 -0
  33. package/dist/cjs/index.browser.js.map +1 -0
  34. package/dist/cjs/index.d.ts +26 -0
  35. package/dist/cjs/index.d.ts.map +1 -0
  36. package/dist/cjs/index.js +50 -0
  37. package/dist/cjs/index.js.map +1 -0
  38. package/dist/cjs/keys.d.ts +12 -0
  39. package/dist/cjs/keys.d.ts.map +1 -0
  40. package/dist/cjs/keys.js +17 -0
  41. package/dist/cjs/keys.js.map +1 -0
  42. package/dist/cjs/models.d.ts +197 -0
  43. package/dist/cjs/models.d.ts.map +1 -0
  44. package/dist/cjs/models.js +246 -0
  45. package/dist/cjs/models.js.map +1 -0
  46. package/dist/cjs/package.json +1 -0
  47. package/dist/cjs/pagination.d.ts +21 -0
  48. package/dist/cjs/pagination.d.ts.map +1 -0
  49. package/dist/cjs/pagination.js +50 -0
  50. package/dist/cjs/pagination.js.map +1 -0
  51. package/dist/cjs/verify.d.ts +50 -0
  52. package/dist/cjs/verify.d.ts.map +1 -0
  53. package/dist/cjs/verify.js +500 -0
  54. package/dist/cjs/verify.js.map +1 -0
  55. package/dist/cjs/webhooks.d.ts +36 -0
  56. package/dist/cjs/webhooks.d.ts.map +1 -0
  57. package/dist/cjs/webhooks.js +71 -0
  58. package/dist/cjs/webhooks.js.map +1 -0
  59. package/dist/esm/cli.d.ts +16 -0
  60. package/dist/esm/cli.d.ts.map +1 -0
  61. package/dist/esm/cli.js +164 -0
  62. package/dist/esm/cli.js.map +1 -0
  63. package/dist/esm/client.d.ts +116 -0
  64. package/dist/esm/client.d.ts.map +1 -0
  65. package/dist/esm/client.js +316 -0
  66. package/dist/esm/client.js.map +1 -0
  67. package/dist/esm/crypto-browser.d.ts +7 -0
  68. package/dist/esm/crypto-browser.d.ts.map +1 -0
  69. package/dist/esm/crypto-browser.js +34 -0
  70. package/dist/esm/crypto-browser.js.map +1 -0
  71. package/dist/esm/crypto-node.d.ts +4 -0
  72. package/dist/esm/crypto-node.d.ts.map +1 -0
  73. package/dist/esm/crypto-node.js +27 -0
  74. package/dist/esm/crypto-node.js.map +1 -0
  75. package/dist/esm/crypto.d.ts +6 -0
  76. package/dist/esm/crypto.d.ts.map +1 -0
  77. package/dist/esm/crypto.js +3 -0
  78. package/dist/esm/crypto.js.map +1 -0
  79. package/dist/esm/errors.d.ts +76 -0
  80. package/dist/esm/errors.d.ts.map +1 -0
  81. package/dist/esm/errors.js +105 -0
  82. package/dist/esm/errors.js.map +1 -0
  83. package/dist/esm/http.d.ts +35 -0
  84. package/dist/esm/http.d.ts.map +1 -0
  85. package/dist/esm/http.js +156 -0
  86. package/dist/esm/http.js.map +1 -0
  87. package/dist/esm/index.browser.d.ts +31 -0
  88. package/dist/esm/index.browser.d.ts.map +1 -0
  89. package/dist/esm/index.browser.js +31 -0
  90. package/dist/esm/index.browser.js.map +1 -0
  91. package/dist/esm/index.d.ts +26 -0
  92. package/dist/esm/index.d.ts.map +1 -0
  93. package/dist/esm/index.js +26 -0
  94. package/dist/esm/index.js.map +1 -0
  95. package/dist/esm/keys.d.ts +12 -0
  96. package/dist/esm/keys.d.ts.map +1 -0
  97. package/dist/esm/keys.js +14 -0
  98. package/dist/esm/keys.js.map +1 -0
  99. package/dist/esm/models.d.ts +197 -0
  100. package/dist/esm/models.d.ts.map +1 -0
  101. package/dist/esm/models.js +226 -0
  102. package/dist/esm/models.js.map +1 -0
  103. package/dist/esm/pagination.d.ts +21 -0
  104. package/dist/esm/pagination.d.ts.map +1 -0
  105. package/dist/esm/pagination.js +46 -0
  106. package/dist/esm/pagination.js.map +1 -0
  107. package/dist/esm/verify.d.ts +50 -0
  108. package/dist/esm/verify.d.ts.map +1 -0
  109. package/dist/esm/verify.js +491 -0
  110. package/dist/esm/verify.js.map +1 -0
  111. package/dist/esm/webhooks.d.ts +36 -0
  112. package/dist/esm/webhooks.d.ts.map +1 -0
  113. package/dist/esm/webhooks.js +67 -0
  114. package/dist/esm/webhooks.js.map +1 -0
  115. package/package.json +65 -0
@@ -0,0 +1,500 @@
1
+ "use strict";
2
+ /** Offline certificate and transparency verification.
3
+ *
4
+ * Ports the Go signing payload builders (core/payload.go) and Merkle tree
5
+ * verification (core/merkle.go) to TypeScript. All crypto is delegated to
6
+ * a CryptoOps provider (Node or browser).
7
+ *
8
+ * Critical encoding details:
9
+ * - Go's json.Marshal encodes []byte as base64, [N]byte as number arrays.
10
+ * - The payload builders normalize both formats to lowercase hex strings.
11
+ * - Timestamps in payloads use second-precision UTC: "YYYY-MM-DDTHH:MM:SSZ".
12
+ * - RFC 8785 canonical JSON: sorted keys recursively, no whitespace.
13
+ * - Transparency leaf = SHA-256(0x00 || issuanceBytes(cert)), NOT the
14
+ * certificate signing payload. issuanceBytes reconstructs json.Marshal
15
+ * output at issuance time (transparency_status=PENDING, no transparency).
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.hexToBytes = hexToBytes;
19
+ exports.bytesToHex = bytesToHex;
20
+ exports.publicKeyFromHex = publicKeyFromHex;
21
+ exports.verifyCertificate = verifyCertificate;
22
+ exports.verifyTransparency = verifyTransparency;
23
+ exports.issuanceBytes = issuanceBytes;
24
+ exports.verifyConsistency = verifyConsistency;
25
+ const errors_js_1 = require("./errors.js");
26
+ // ---------------------------------------------------------------------------
27
+ // Pure byte helpers (no Buffer, no node:crypto)
28
+ // ---------------------------------------------------------------------------
29
+ const HEX_CHARS = "0123456789abcdef";
30
+ // Signing-format v2 domain-separation tags (CR-H01). Must match the
31
+ // source-of-truth const block in Go's core/payload.go byte-for-byte.
32
+ const PAYLOAD_TYPE_ATTESTATION = "burnledger.attestation.v2";
33
+ const PAYLOAD_TYPE_VERIFICATION = "burnledger.verification.v2";
34
+ const PAYLOAD_TYPE_CERTIFICATE = "burnledger.certificate.v2";
35
+ const PAYLOAD_TYPE_TREE_HEAD = "burnledger.sth.v2";
36
+ function hexToBytes(hex) {
37
+ const len = hex.length >>> 1;
38
+ const out = new Uint8Array(len);
39
+ for (let i = 0; i < len; i++) {
40
+ const hi = hex.charCodeAt(i * 2);
41
+ const lo = hex.charCodeAt(i * 2 + 1);
42
+ out[i] = (unhex(hi) << 4) | unhex(lo);
43
+ }
44
+ return out;
45
+ }
46
+ function unhex(c) {
47
+ // 0-9
48
+ if (c >= 48 && c <= 57)
49
+ return c - 48;
50
+ // a-f
51
+ if (c >= 97 && c <= 102)
52
+ return c - 87;
53
+ // A-F
54
+ if (c >= 65 && c <= 70)
55
+ return c - 55;
56
+ return 0;
57
+ }
58
+ function bytesToHex(bytes) {
59
+ let out = "";
60
+ for (let i = 0; i < bytes.length; i++) {
61
+ const b = bytes[i];
62
+ out += HEX_CHARS[b >>> 4];
63
+ out += HEX_CHARS[b & 0x0f];
64
+ }
65
+ return out;
66
+ }
67
+ function concatBytes(a, b) {
68
+ const out = new Uint8Array(a.length + b.length);
69
+ out.set(a, 0);
70
+ out.set(b, a.length);
71
+ return out;
72
+ }
73
+ function bytesEqual(a, b) {
74
+ if (a.length !== b.length)
75
+ return false;
76
+ for (let i = 0; i < a.length; i++) {
77
+ if (a[i] !== b[i])
78
+ return false;
79
+ }
80
+ return true;
81
+ }
82
+ function base64ToBytes(b64) {
83
+ // Use atob for universal browser+node compatibility.
84
+ // Node 18+ has atob globally; browsers always have it.
85
+ const bin = atob(b64);
86
+ const out = new Uint8Array(bin.length);
87
+ for (let i = 0; i < bin.length; i++) {
88
+ out[i] = bin.charCodeAt(i);
89
+ }
90
+ return out;
91
+ }
92
+ function textToBytes(s) {
93
+ return new TextEncoder().encode(s);
94
+ }
95
+ async function publicKeyFromHex(crypto, hexKey, opts) {
96
+ const raw = hexToBytes(hexKey);
97
+ if (raw.length !== 32) {
98
+ throw new errors_js_1.VerificationError(`public key must be 32 bytes, got ${raw.length}`);
99
+ }
100
+ const hash = await crypto.sha256(raw);
101
+ const keyId = "dp_k_" + bytesToHex(hash);
102
+ return { keyBytes: raw, keyId, revoked: opts?.revoked ?? false };
103
+ }
104
+ /** Verify all signatures on a deletion certificate offline. */
105
+ async function verifyCertificate(crypto, certificate, publicKeys) {
106
+ const issuer = certificate.issuer;
107
+ const keyId = issuer.key_id;
108
+ const pki = publicKeys.get(keyId);
109
+ if (pki === undefined)
110
+ throw new errors_js_1.VerificationError(`unknown issuer key: ${keyId}`);
111
+ if (pki.revoked)
112
+ throw new errors_js_1.VerificationError(`issuer key is revoked: ${keyId}`);
113
+ // 1. Attestation signature
114
+ const att = certificate.attestation;
115
+ const attPayload = buildAttestationPayload(certificate.subject, att);
116
+ const attSig = decodeSignature(att.attestation_signature);
117
+ if (!(await crypto.ed25519Verify(pki.keyBytes, attPayload, attSig))) {
118
+ throw new errors_js_1.VerificationError("attestation signature is invalid");
119
+ }
120
+ // 2. Verification signature
121
+ const ver = certificate.verification;
122
+ const verPayload = buildVerificationPayload(certificate.attestation_id, ver);
123
+ const verSig = decodeSignature(ver.verification_signature);
124
+ if (!(await crypto.ed25519Verify(pki.keyBytes, verPayload, verSig))) {
125
+ throw new errors_js_1.VerificationError("verification signature is invalid");
126
+ }
127
+ // 3. Certificate signature
128
+ const certPayload = buildCertificatePayload(certificate);
129
+ const certSig = decodeSignature(certificate.certificate_signature);
130
+ if (!(await crypto.ed25519Verify(pki.keyBytes, certPayload, certSig))) {
131
+ throw new errors_js_1.VerificationError("certificate signature is invalid");
132
+ }
133
+ // 4. Now that every signature is verified (so these fields are trustworthy),
134
+ // reject certificates that are validly signed but are NOT proof of deletion.
135
+ // Mirrors core/verify.go steps 3 and 6 — without these the SDK would accept
136
+ // a revoked certificate, or one attesting data that is still present, as VALID.
137
+ if (certificate.status === "REVOKED") {
138
+ throw new errors_js_1.VerificationError("certificate has been revoked");
139
+ }
140
+ for (const s of ver.systems ?? []) {
141
+ const recordCount = s.record_count;
142
+ if (recordCount !== 0) {
143
+ throw new errors_js_1.VerificationError(`data still present: system "${s.system_name}" reports ${recordCount} record(s)`);
144
+ }
145
+ }
146
+ return "VALID";
147
+ }
148
+ /** Verify the transparency proof embedded in a certificate. */
149
+ async function verifyTransparency(crypto, certificate, publicKeys) {
150
+ const transparency = certificate.transparency;
151
+ if (transparency == null) {
152
+ return "NOT_AVAILABLE";
153
+ }
154
+ const sth = transparency.signed_tree_head;
155
+ const issuer = certificate.issuer;
156
+ const keyId = issuer.key_id;
157
+ const pki = publicKeys.get(keyId);
158
+ if (pki === undefined)
159
+ throw new errors_js_1.VerificationError(`unknown issuer key: ${keyId}`);
160
+ if (pki.revoked)
161
+ throw new errors_js_1.VerificationError(`issuer key is revoked: ${keyId}`);
162
+ // 1. Tree head signature
163
+ const headPayload = buildTreeHeadPayload(sth);
164
+ const headSig = decodeSignature(sth.signature);
165
+ if (!(await crypto.ed25519Verify(pki.keyBytes, headPayload, headSig))) {
166
+ throw new errors_js_1.VerificationError("tree head signature is invalid");
167
+ }
168
+ // 2. Merkle inclusion proof — leaf is hash of issuance-time certificate JSON,
169
+ // NOT the canonical signing payload. Matches Go's core.IssuanceBytes(cert).
170
+ const issuanceData = issuanceBytes(certificate);
171
+ const leaf = await hashLeaf(crypto, issuanceData);
172
+ const proofHashes = (transparency.inclusion_proof ?? []).map((h) => decodeBytes(h));
173
+ const root = decodeBytes(sth.root_hash);
174
+ const index = transparency.entry_index;
175
+ const treeSize = sth.tree_size;
176
+ if (!(await verifyInclusion(crypto, leaf, index, treeSize, proofHashes, root))) {
177
+ throw new errors_js_1.VerificationError("merkle inclusion proof is invalid");
178
+ }
179
+ return "INCLUDED";
180
+ }
181
+ // ---------------------------------------------------------------------------
182
+ // Issuance bytes — matches Go's core.IssuanceBytes(cert)
183
+ // ---------------------------------------------------------------------------
184
+ /** Reconstruct the certificate JSON as it existed at issuance time.
185
+ *
186
+ * At issuance: transparency_status = "PENDING", transparency = nil (omitted).
187
+ * The leaf preimage is the RFC 8785 canonical JSON of that form — exactly
188
+ * Go's `CanonicalJSON(json.Marshal(cert))` in core.IssuanceBytes. It MUST be
189
+ * canonicalized (sorted keys, recursively), not serialized in insertion order:
190
+ * Go's struct field order is not alphabetical, so insertion-order stringify
191
+ * produces a different leaf hash and every genuine certificate fails inclusion
192
+ * verification (#C-01).
193
+ */
194
+ function issuanceBytes(certificate) {
195
+ const clone = JSON.parse(JSON.stringify(certificate));
196
+ clone.transparency_status = "PENDING";
197
+ delete clone.transparency;
198
+ return canonicalJson(clone);
199
+ }
200
+ // ---------------------------------------------------------------------------
201
+ // RFC 8785 Canonical JSON
202
+ // ---------------------------------------------------------------------------
203
+ function canonicalJson(obj) {
204
+ return textToBytes(canonicalStringify(obj));
205
+ }
206
+ function canonicalStringify(val) {
207
+ if (val === null || val === undefined)
208
+ return "null";
209
+ if (typeof val === "boolean")
210
+ return val ? "true" : "false";
211
+ if (typeof val === "number")
212
+ return JSON.stringify(val);
213
+ if (typeof val === "string")
214
+ return JSON.stringify(val);
215
+ if (Array.isArray(val)) {
216
+ return "[" + val.map(canonicalStringify).join(",") + "]";
217
+ }
218
+ if (typeof val === "object") {
219
+ const obj = val;
220
+ const keys = Object.keys(obj).sort();
221
+ const pairs = keys.map((k) => JSON.stringify(k) + ":" + canonicalStringify(obj[k]));
222
+ return "{" + pairs.join(",") + "}";
223
+ }
224
+ return JSON.stringify(val);
225
+ }
226
+ // ---------------------------------------------------------------------------
227
+ // Byte encoding helpers
228
+ // ---------------------------------------------------------------------------
229
+ /** Convert a byte field to lowercase hex. Handles:
230
+ * - hex string (from hand-crafted test data)
231
+ * - base64 string (from Go's json.Marshal of []byte slices)
232
+ * - number[] (from Go's json.Marshal of [N]byte fixed arrays)
233
+ */
234
+ function toHex(value) {
235
+ if (Array.isArray(value)) {
236
+ return bytesToHex(new Uint8Array(value));
237
+ }
238
+ const str = value;
239
+ if (/^[0-9a-fA-F]+$/.test(str) && str.length % 2 === 0) {
240
+ return str.toLowerCase();
241
+ }
242
+ return bytesToHex(base64ToBytes(str));
243
+ }
244
+ /** Decode a signature field to raw bytes. Same format handling as toHex. */
245
+ function decodeSignature(value) {
246
+ if (Array.isArray(value)) {
247
+ return new Uint8Array(value);
248
+ }
249
+ const str = value;
250
+ if (/^[0-9a-fA-F]+$/.test(str)) {
251
+ const raw = hexToBytes(str);
252
+ if (raw.length === 64)
253
+ return raw;
254
+ }
255
+ return base64ToBytes(str);
256
+ }
257
+ /** Decode a hash/bytes field to raw bytes. Same format handling as toHex. */
258
+ function decodeBytes(value) {
259
+ if (Array.isArray(value)) {
260
+ return new Uint8Array(value);
261
+ }
262
+ const str = value;
263
+ if (/^[0-9a-fA-F]+$/.test(str) && str.length % 2 === 0) {
264
+ return hexToBytes(str);
265
+ }
266
+ return base64ToBytes(str);
267
+ }
268
+ function formatTimestamp(ts) {
269
+ // Strip fractional seconds, normalize to YYYY-MM-DDTHH:MM:SSZ
270
+ let s = ts;
271
+ const dotIdx = s.indexOf(".");
272
+ if (dotIdx !== -1) {
273
+ // Find the end of fractional seconds (Z, +, or end)
274
+ let endIdx = s.length;
275
+ for (let i = dotIdx + 1; i < s.length; i++) {
276
+ if (s[i] === "Z" || s[i] === "+" || s[i] === "-") {
277
+ endIdx = i;
278
+ break;
279
+ }
280
+ }
281
+ s = s.slice(0, dotIdx) + s.slice(endIdx);
282
+ }
283
+ if (s.endsWith("Z"))
284
+ return s;
285
+ // Strip timezone offset
286
+ const plusIdx = s.indexOf("+");
287
+ if (plusIdx !== -1) {
288
+ s = s.slice(0, plusIdx);
289
+ }
290
+ return s + "Z";
291
+ }
292
+ // ---------------------------------------------------------------------------
293
+ // Payload builders — exact ports of core/payload.go
294
+ // ---------------------------------------------------------------------------
295
+ function buildAttestationPayload(subject, att) {
296
+ const attestedAt = formatTimestamp(att.attested_at);
297
+ const systems = att.systems.map((s) => ({
298
+ canonical_version: s.canonical_version ?? null,
299
+ connector_type: s.connector_type,
300
+ hash_scope: s.hash_scope,
301
+ merkle_root: s.merkle_root
302
+ ? toHex(s.merkle_root)
303
+ : null,
304
+ observed_at: attestedAt,
305
+ record_count: s.record_count,
306
+ system_name: s.system_name,
307
+ }));
308
+ const payload = {
309
+ attested_at: attestedAt,
310
+ payload_type: PAYLOAD_TYPE_ATTESTATION,
311
+ proof_mode: att.proof_mode,
312
+ subject_hash: toHex(subject.identifier_hash),
313
+ systems,
314
+ };
315
+ return canonicalJson(payload);
316
+ }
317
+ function buildVerificationPayload(attestationId, ver) {
318
+ const verifiedAt = formatTimestamp(ver.verified_at);
319
+ const systems = ver.systems.map((s) => ({
320
+ observed_at: verifiedAt,
321
+ record_count: s.record_count,
322
+ system_name: s.system_name,
323
+ }));
324
+ const payload = {
325
+ attestation_id: attestationId,
326
+ payload_type: PAYLOAD_TYPE_VERIFICATION,
327
+ systems,
328
+ verified_at: verifiedAt,
329
+ };
330
+ return canonicalJson(payload);
331
+ }
332
+ function buildCertificatePayload(cert) {
333
+ const att = cert.attestation;
334
+ const ver = cert.verification;
335
+ const issuer = cert.issuer;
336
+ const subject = cert.subject;
337
+ // Attestation systems — uses "system_name" field name
338
+ const attSystems = att.systems.map((s) => ({
339
+ canonical_version: s.canonical_version ?? null,
340
+ connector_type: s.connector_type,
341
+ hash_scope: s.hash_scope,
342
+ merkle_root: s.merkle_root
343
+ ? toHex(s.merkle_root)
344
+ : null,
345
+ record_count: s.record_count,
346
+ system_name: s.system_name,
347
+ }));
348
+ const attObj = {
349
+ attestation_signature: toHex(att.attestation_signature),
350
+ attested_at: formatTimestamp(att.attested_at),
351
+ proof_mode: att.proof_mode,
352
+ systems: attSystems,
353
+ };
354
+ // Verification systems
355
+ const verSystems = ver.systems.map((s) => ({
356
+ connector_type: s.connector_type,
357
+ record_count: s.record_count,
358
+ system_name: s.system_name,
359
+ }));
360
+ const verObj = {
361
+ systems: verSystems,
362
+ verification_signature: toHex(ver.verification_signature),
363
+ verified_at: formatTimestamp(ver.verified_at),
364
+ };
365
+ const issuerObj = {
366
+ key_id: issuer.key_id,
367
+ name: issuer.name,
368
+ public_key: toHex(issuer.public_key),
369
+ };
370
+ const subjectObj = {
371
+ identifier_hash: toHex(subject.identifier_hash),
372
+ identifier_type_hint: subject.identifier_type_hint,
373
+ };
374
+ // Revocation
375
+ let revocation = null;
376
+ const rev = cert.revocation;
377
+ if (rev != null) {
378
+ revocation = {
379
+ reason: rev.reason,
380
+ replacement_certificate_id: rev.replacement_certificate_id ?? null,
381
+ revoked_at: formatTimestamp(rev.revoked_at),
382
+ };
383
+ }
384
+ const payload = {
385
+ attestation: attObj,
386
+ attestation_id: cert.attestation_id,
387
+ certificate_format_version: cert.certificate_format_version,
388
+ certificate_id: cert.certificate_id,
389
+ issued_at: formatTimestamp(cert.issued_at),
390
+ issuer: issuerObj,
391
+ payload_type: PAYLOAD_TYPE_CERTIFICATE,
392
+ revocation,
393
+ status: cert.status,
394
+ subject: subjectObj,
395
+ verification: verObj,
396
+ };
397
+ return canonicalJson(payload);
398
+ }
399
+ function buildTreeHeadPayload(head) {
400
+ const payload = {
401
+ payload_type: PAYLOAD_TYPE_TREE_HEAD,
402
+ root_hash: toHex(head.root_hash),
403
+ timestamp: formatTimestamp(head.timestamp),
404
+ tree_size: head.tree_size,
405
+ };
406
+ return canonicalJson(payload);
407
+ }
408
+ // ---------------------------------------------------------------------------
409
+ // Merkle tree (RFC 6962) — ports of core/merkle.go
410
+ // ---------------------------------------------------------------------------
411
+ async function hashLeaf(crypto, data) {
412
+ return crypto.sha256(concatBytes(new Uint8Array([0x00]), data));
413
+ }
414
+ async function hashNode(crypto, left, right) {
415
+ const prefix = new Uint8Array([0x01]);
416
+ return crypto.sha256(concatBytes(prefix, concatBytes(left, right)));
417
+ }
418
+ function splitPoint(n) {
419
+ let k = 1;
420
+ while (k * 2 < n) {
421
+ k *= 2;
422
+ }
423
+ return k;
424
+ }
425
+ async function verifyInclusion(crypto, leaf, index, size, proof, root) {
426
+ if (size === 0 || index >= size)
427
+ return false;
428
+ if (size === 1)
429
+ return proof.length === 0 && bytesEqual(leaf, root);
430
+ const [computed, consumed] = await chainInclusion(crypto, leaf, index, size, proof);
431
+ return consumed === proof.length && bytesEqual(computed, root);
432
+ }
433
+ async function chainInclusion(crypto, leaf, index, n, proof) {
434
+ if (n === 1)
435
+ return [leaf, 0];
436
+ const k = splitPoint(n);
437
+ if (index < k) {
438
+ const [inner, used] = await chainInclusion(crypto, leaf, index, k, proof);
439
+ if (used >= proof.length)
440
+ return [inner, used + 1];
441
+ return [await hashNode(crypto, inner, proof[used]), used + 1];
442
+ }
443
+ const [inner, used] = await chainInclusion(crypto, leaf, index - k, n - k, proof);
444
+ if (used >= proof.length)
445
+ return [inner, used + 1];
446
+ return [await hashNode(crypto, proof[used], inner), used + 1];
447
+ }
448
+ function isPow2(n) {
449
+ return n > 0 && (n & (n - 1)) === 0;
450
+ }
451
+ /** Verify a Merkle consistency proof (RFC 6962 Section 2.1.4).
452
+ *
453
+ * Port of Go's VerifyConsistency / Python's _verify_consistency.
454
+ */
455
+ async function verifyConsistency(crypto, oldSize, newSize, oldRoot, newRoot, proof) {
456
+ if (oldSize === 0 || newSize === 0 || oldSize > newSize)
457
+ return false;
458
+ if (oldSize === newSize) {
459
+ return proof.length === 0 && bytesEqual(oldRoot, newRoot);
460
+ }
461
+ let pIdx = 0;
462
+ let fr;
463
+ let sr;
464
+ if (isPow2(oldSize)) {
465
+ fr = oldRoot;
466
+ sr = oldRoot;
467
+ }
468
+ else {
469
+ if (pIdx >= proof.length)
470
+ return false;
471
+ fr = proof[pIdx];
472
+ sr = proof[pIdx];
473
+ pIdx++;
474
+ }
475
+ let fn = oldSize - 1;
476
+ let sn = newSize - 1;
477
+ while ((fn & 1) === 1) {
478
+ fn >>= 1;
479
+ sn >>= 1;
480
+ }
481
+ while (pIdx < proof.length) {
482
+ const c = proof[pIdx];
483
+ pIdx++;
484
+ if ((fn & 1) === 1 || fn === sn) {
485
+ fr = await hashNode(crypto, c, fr);
486
+ sr = await hashNode(crypto, c, sr);
487
+ while (fn !== 0 && (fn & 1) === 0) {
488
+ fn >>= 1;
489
+ sn >>= 1;
490
+ }
491
+ }
492
+ else {
493
+ sr = await hashNode(crypto, sr, c);
494
+ }
495
+ fn >>= 1;
496
+ sn >>= 1;
497
+ }
498
+ return sn === 0 && bytesEqual(fr, oldRoot) && bytesEqual(sr, newRoot);
499
+ }
500
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /** Webhook signature verification for incoming BurnLedger events.
2
+ *
3
+ * The server signs webhook payloads with HMAC-SHA256 using the webhook secret.
4
+ * The signature is sent in the X-BurnLedger-Signature header as a hex string,
5
+ * and the timestamp in the X-BurnLedger-Timestamp header as an RFC3339 string.
6
+ *
7
+ * CR-M01: the signed preimage is `timestamp + "." + body`, where `timestamp` is
8
+ * the exact RFC3339 string from the X-BurnLedger-Timestamp header. Binding the
9
+ * timestamp into the MAC prevents a captured delivery from being replayed under
10
+ * a different timestamp. Receivers MUST also verify the timestamp is fresh (see
11
+ * isTimestampFresh) — the signature proves authenticity, freshness prevents
12
+ * replay of an old-but-validly-signed delivery.
13
+ *
14
+ * Node-only — webhooks are received server-side.
15
+ */
16
+ /**
17
+ * Verify that a webhook payload was signed by the expected secret.
18
+ *
19
+ * @param secret The webhook secret (raw UTF-8, as returned by the API)
20
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
21
+ * @param body The raw request body bytes
22
+ * @param signature The hex-encoded HMAC-SHA256 signature from the X-BurnLedger-Signature header
23
+ * @returns true if the signature is valid
24
+ */
25
+ export declare function verifyWebhookSignature(secret: string, timestamp: string, body: Uint8Array | string, signature: string): boolean;
26
+ /**
27
+ * Verify that the webhook timestamp is within an acceptable freshness window.
28
+ * Receivers MUST call this (in addition to verifyWebhookSignature) to prevent
29
+ * replay of an old-but-validly-signed delivery.
30
+ *
31
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
32
+ * @param toleranceSeconds Maximum accepted age/skew in seconds (default 300)
33
+ * @returns true if the timestamp parses and is within +/- tolerance of now
34
+ */
35
+ export declare function isTimestampFresh(timestamp: string, toleranceSeconds?: number): boolean;
36
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,GAAG,MAAM,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAwBT;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,gBAAgB,GAAE,MAAY,GAC7B,OAAO,CAKT"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /** Webhook signature verification for incoming BurnLedger events.
3
+ *
4
+ * The server signs webhook payloads with HMAC-SHA256 using the webhook secret.
5
+ * The signature is sent in the X-BurnLedger-Signature header as a hex string,
6
+ * and the timestamp in the X-BurnLedger-Timestamp header as an RFC3339 string.
7
+ *
8
+ * CR-M01: the signed preimage is `timestamp + "." + body`, where `timestamp` is
9
+ * the exact RFC3339 string from the X-BurnLedger-Timestamp header. Binding the
10
+ * timestamp into the MAC prevents a captured delivery from being replayed under
11
+ * a different timestamp. Receivers MUST also verify the timestamp is fresh (see
12
+ * isTimestampFresh) — the signature proves authenticity, freshness prevents
13
+ * replay of an old-but-validly-signed delivery.
14
+ *
15
+ * Node-only — webhooks are received server-side.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.verifyWebhookSignature = verifyWebhookSignature;
19
+ exports.isTimestampFresh = isTimestampFresh;
20
+ const node_crypto_1 = require("node:crypto");
21
+ /**
22
+ * Verify that a webhook payload was signed by the expected secret.
23
+ *
24
+ * @param secret The webhook secret (raw UTF-8, as returned by the API)
25
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
26
+ * @param body The raw request body bytes
27
+ * @param signature The hex-encoded HMAC-SHA256 signature from the X-BurnLedger-Signature header
28
+ * @returns true if the signature is valid
29
+ */
30
+ function verifyWebhookSignature(secret, timestamp, body, signature) {
31
+ if (secret.length === 0)
32
+ return false;
33
+ if (timestamp.length === 0)
34
+ return false;
35
+ if (signature.length === 0)
36
+ return false;
37
+ // Preimage: timestamp + "." + body. An RFC3339 timestamp never contains a
38
+ // ".", so the field boundary is unambiguous.
39
+ const bodyBytes = typeof body === "string" ? Buffer.from(body, "utf-8") : Buffer.from(body);
40
+ const expected = (0, node_crypto_1.createHmac)("sha256", secret)
41
+ .update(Buffer.from(`${timestamp}.`, "utf-8"))
42
+ .update(bodyBytes)
43
+ .digest();
44
+ let received;
45
+ try {
46
+ received = Buffer.from(signature, "hex");
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ if (received.length !== expected.length)
52
+ return false;
53
+ return (0, node_crypto_1.timingSafeEqual)(expected, received);
54
+ }
55
+ /**
56
+ * Verify that the webhook timestamp is within an acceptable freshness window.
57
+ * Receivers MUST call this (in addition to verifyWebhookSignature) to prevent
58
+ * replay of an old-but-validly-signed delivery.
59
+ *
60
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
61
+ * @param toleranceSeconds Maximum accepted age/skew in seconds (default 300)
62
+ * @returns true if the timestamp parses and is within +/- tolerance of now
63
+ */
64
+ function isTimestampFresh(timestamp, toleranceSeconds = 300) {
65
+ const parsed = Date.parse(timestamp);
66
+ if (Number.isNaN(parsed))
67
+ return false;
68
+ const ageSeconds = Math.abs(Date.now() - parsed) / 1000;
69
+ return ageSeconds <= toleranceSeconds;
70
+ }
71
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AAaH,wDA6BC;AAWD,4CAQC;AA3DD,6CAA0D;AAE1D;;;;;;;;GAQG;AACH,SAAgB,sBAAsB,CACpC,MAAc,EACd,SAAiB,EACjB,IAAyB,EACzB,SAAiB;IAEjB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEzC,0EAA0E;IAC1E,6CAA6C;IAC7C,MAAM,SAAS,GACb,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,IAAA,wBAAU,EAAC,QAAQ,EAAE,MAAM,CAAC;SAC1C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,EAAE,OAAO,CAAC,CAAC;SAC7C,MAAM,CAAC,SAAS,CAAC;SACjB,MAAM,EAAE,CAAC;IAEZ,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAEtD,OAAO,IAAA,6BAAe,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,gBAAgB,CAC9B,SAAiB,EACjB,mBAA2B,GAAG;IAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IACxD,OAAO,UAAU,IAAI,gBAAgB,CAAC;AACxC,CAAC"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /** burnledger check — offline certificate verification.
3
+ * Exit codes: 0=valid, 1=invalid, 2=usage error */
4
+ type Cert = Record<string, unknown>;
5
+ /** The pass/fail decision behind the exit code. A signature failure, a
6
+ * transparency FAILURE (thrown, not NOT_AVAILABLE), or an online-confirmed
7
+ * revocation all make the certificate invalid. Exported for testing. */
8
+ export declare function certVerdict(sigResult: string, transparencyFailed: boolean, online: boolean, revocation: {
9
+ status: string;
10
+ } | undefined): boolean;
11
+ export declare function formatOutput(cert: Cert, sigResult: string, transparency: string, transparencyFailed: boolean, revocation: {
12
+ status: string;
13
+ reason?: string;
14
+ } | undefined, online: boolean): string;
15
+ export {};
16
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AACA;mDACmD;AAQnD,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAiEpC;;wEAEwE;AACxE,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,OAAO,EAC3B,MAAM,EAAE,OAAO,EACf,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACzC,OAAO,CAMT;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAChF,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,GAC3E,MAAM,CAmCR"}