@freedomofpress/sigstore-browser 0.1.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.
- package/.github/workflows/conformance.yml +29 -0
- package/.github/workflows/publish.yml +45 -0
- package/README.md +10 -0
- package/dist/asn1/error.d.ts +5 -0
- package/dist/asn1/error.d.ts.map +1 -0
- package/dist/asn1/error.js +20 -0
- package/dist/asn1/error.js.map +1 -0
- package/dist/asn1/index.d.ts +2 -0
- package/dist/asn1/index.d.ts.map +1 -0
- package/dist/asn1/index.js +17 -0
- package/dist/asn1/index.js.map +1 -0
- package/dist/asn1/length.d.ts +4 -0
- package/dist/asn1/length.d.ts.map +1 -0
- package/dist/asn1/length.js +59 -0
- package/dist/asn1/length.js.map +1 -0
- package/dist/asn1/obj.d.ts +15 -0
- package/dist/asn1/obj.d.ts.map +1 -0
- package/dist/asn1/obj.js +153 -0
- package/dist/asn1/obj.js.map +1 -0
- package/dist/asn1/parse.d.ts +7 -0
- package/dist/asn1/parse.d.ts.map +1 -0
- package/dist/asn1/parse.js +118 -0
- package/dist/asn1/parse.js.map +1 -0
- package/dist/asn1/tag.d.ts +17 -0
- package/dist/asn1/tag.d.ts.map +1 -0
- package/dist/asn1/tag.js +86 -0
- package/dist/asn1/tag.js.map +1 -0
- package/dist/bundle.d.ts +87 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +2 -0
- package/dist/bundle.js.map +1 -0
- package/dist/canonicalize.d.ts +2 -0
- package/dist/canonicalize.d.ts.map +1 -0
- package/dist/canonicalize.js +64 -0
- package/dist/canonicalize.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +217 -0
- package/dist/cli.js.map +1 -0
- package/dist/crypto.d.ts +5 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +260 -0
- package/dist/crypto.js.map +1 -0
- package/dist/dsse.d.ts +2 -0
- package/dist/dsse.d.ts.map +1 -0
- package/dist/dsse.js +42 -0
- package/dist/dsse.js.map +1 -0
- package/dist/encoding.d.ts +17 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +112 -0
- package/dist/encoding.js.map +1 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +79 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +104 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +26 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/oid.d.ts +5 -0
- package/dist/oid.d.ts.map +1 -0
- package/dist/oid.js +25 -0
- package/dist/oid.js.map +1 -0
- package/dist/pem.d.ts +3 -0
- package/dist/pem.d.ts.map +1 -0
- package/dist/pem.js +41 -0
- package/dist/pem.js.map +1 -0
- package/dist/rfc3161/error.d.ts +3 -0
- package/dist/rfc3161/error.d.ts.map +1 -0
- package/dist/rfc3161/error.js +18 -0
- package/dist/rfc3161/error.js.map +1 -0
- package/dist/rfc3161/index.d.ts +2 -0
- package/dist/rfc3161/index.d.ts.map +1 -0
- package/dist/rfc3161/index.js +17 -0
- package/dist/rfc3161/index.js.map +1 -0
- package/dist/rfc3161/timestamp.d.ts +36 -0
- package/dist/rfc3161/timestamp.d.ts.map +1 -0
- package/dist/rfc3161/timestamp.js +203 -0
- package/dist/rfc3161/timestamp.js.map +1 -0
- package/dist/rfc3161/tstinfo.d.ts +13 -0
- package/dist/rfc3161/tstinfo.d.ts.map +1 -0
- package/dist/rfc3161/tstinfo.js +47 -0
- package/dist/rfc3161/tstinfo.js.map +1 -0
- package/dist/sigstore.d.ts +33 -0
- package/dist/sigstore.d.ts.map +1 -0
- package/dist/sigstore.js +531 -0
- package/dist/sigstore.js.map +1 -0
- package/dist/stream.d.ts +22 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +114 -0
- package/dist/stream.js.map +1 -0
- package/dist/timestamp/tsa.d.ts +24 -0
- package/dist/timestamp/tsa.d.ts.map +1 -0
- package/dist/timestamp/tsa.js +150 -0
- package/dist/timestamp/tsa.js.map +1 -0
- package/dist/tlog/body.d.ts +8 -0
- package/dist/tlog/body.d.ts.map +1 -0
- package/dist/tlog/body.js +45 -0
- package/dist/tlog/body.js.map +1 -0
- package/dist/tlog/checkpoint.d.ts +23 -0
- package/dist/tlog/checkpoint.d.ts.map +1 -0
- package/dist/tlog/checkpoint.js +187 -0
- package/dist/tlog/checkpoint.js.map +1 -0
- package/dist/tlog/dsse.d.ts +4 -0
- package/dist/tlog/dsse.d.ts.map +1 -0
- package/dist/tlog/dsse.js +85 -0
- package/dist/tlog/dsse.js.map +1 -0
- package/dist/tlog/hashedrekord.d.ts +4 -0
- package/dist/tlog/hashedrekord.d.ts.map +1 -0
- package/dist/tlog/hashedrekord.js +63 -0
- package/dist/tlog/hashedrekord.js.map +1 -0
- package/dist/tlog/intoto.d.ts +4 -0
- package/dist/tlog/intoto.d.ts.map +1 -0
- package/dist/tlog/intoto.js +50 -0
- package/dist/tlog/intoto.js.map +1 -0
- package/dist/tlog/merkle.d.ts +3 -0
- package/dist/tlog/merkle.d.ts.map +1 -0
- package/dist/tlog/merkle.js +112 -0
- package/dist/tlog/merkle.js.map +1 -0
- package/dist/trust/tuf-root.json +1 -0
- package/dist/trust/tuf.d.ts +95 -0
- package/dist/trust/tuf.d.ts.map +1 -0
- package/dist/trust/tuf.js +150 -0
- package/dist/trust/tuf.js.map +1 -0
- package/dist/x509/cert.d.ts +52 -0
- package/dist/x509/cert.d.ts.map +1 -0
- package/dist/x509/cert.js +256 -0
- package/dist/x509/cert.js.map +1 -0
- package/dist/x509/chain.d.ts +20 -0
- package/dist/x509/chain.d.ts.map +1 -0
- package/dist/x509/chain.js +141 -0
- package/dist/x509/chain.js.map +1 -0
- package/dist/x509/ext.d.ts +48 -0
- package/dist/x509/ext.d.ts.map +1 -0
- package/dist/x509/ext.js +164 -0
- package/dist/x509/ext.js.map +1 -0
- package/dist/x509/index.d.ts +4 -0
- package/dist/x509/index.d.ts.map +1 -0
- package/dist/x509/index.js +19 -0
- package/dist/x509/index.js.map +1 -0
- package/dist/x509/sct.d.ts +25 -0
- package/dist/x509/sct.d.ts.map +1 -0
- package/dist/x509/sct.js +123 -0
- package/dist/x509/sct.js.map +1 -0
- package/eslint.config.mjs +31 -0
- package/package.json +39 -0
- package/src/asn1/error.ts +18 -0
- package/src/asn1/index.ts +16 -0
- package/src/asn1/length.ts +71 -0
- package/src/asn1/obj.ts +184 -0
- package/src/asn1/parse.ts +146 -0
- package/src/asn1/tag.ts +105 -0
- package/src/bundle.ts +99 -0
- package/src/canonicalize.ts +61 -0
- package/src/cli.ts +285 -0
- package/src/crypto.ts +310 -0
- package/src/dsse.ts +49 -0
- package/src/encoding.ts +141 -0
- package/src/errors.ts +82 -0
- package/src/index.browser.test.ts +219 -0
- package/src/index.ts +14 -0
- package/src/interfaces.ts +118 -0
- package/src/oid.ts +28 -0
- package/src/pem.ts +48 -0
- package/src/rfc3161/error.ts +16 -0
- package/src/rfc3161/index.ts +17 -0
- package/src/rfc3161/timestamp.ts +270 -0
- package/src/rfc3161/tstinfo.ts +80 -0
- package/src/sigstore.ts +728 -0
- package/src/stream.ts +141 -0
- package/src/timestamp/tsa.ts +205 -0
- package/src/tlog/body.ts +65 -0
- package/src/tlog/checkpoint.ts +248 -0
- package/src/tlog/dsse.ts +147 -0
- package/src/tlog/hashedrekord.ts +130 -0
- package/src/tlog/intoto.ts +102 -0
- package/src/tlog/merkle.ts +152 -0
- package/src/trust/README.md +38 -0
- package/src/trust/tuf-root.json +1 -0
- package/src/trust/tuf.ts +223 -0
- package/src/types/tuf-browser.d.ts +13 -0
- package/src/x509/cert.ts +319 -0
- package/src/x509/chain.ts +212 -0
- package/src/x509/ext.ts +212 -0
- package/src/x509/index.ts +19 -0
- package/src/x509/sct.ts +154 -0
- package/tsconfig.json +18 -0
- package/vite.config.playwright.ts +26 -0
- package/vite.config.ts +18 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* DSSE transparency log entry verification
|
|
3
|
+
*
|
|
4
|
+
* Based on sigstore-js:
|
|
5
|
+
* https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/tlog/dsse.ts
|
|
6
|
+
*
|
|
7
|
+
* Key differences from sigstore-js:
|
|
8
|
+
* - Browser-compatible: uses Uint8Array instead of Buffer for binary data
|
|
9
|
+
* - Direct bundle field comparison instead of SignatureContent abstraction
|
|
10
|
+
* - Uses crypto.subtle.digest for hash computation instead of Node.js crypto
|
|
11
|
+
* - Adds verifyDSSE002Body() - new functionality (reference only supports v0.0.1)
|
|
12
|
+
*/
|
|
13
|
+
import { base64ToUint8Array, hexToUint8Array, toArrayBuffer, uint8ArrayEqual } from "../encoding.js";
|
|
14
|
+
import { HashAlgorithms } from "../interfaces.js";
|
|
15
|
+
export async function verifyDSSEBody(entry, bundle) {
|
|
16
|
+
const dsseEntry = entry;
|
|
17
|
+
switch (dsseEntry.apiVersion) {
|
|
18
|
+
case "0.0.1":
|
|
19
|
+
return verifyDSSE001Body(dsseEntry, bundle);
|
|
20
|
+
case "0.0.2":
|
|
21
|
+
return verifyDSSE002Body(dsseEntry, bundle);
|
|
22
|
+
default:
|
|
23
|
+
throw new Error(`Unsupported dsse version: ${dsseEntry.apiVersion}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function verifyDSSE001Body(entry, bundle) {
|
|
27
|
+
if (!bundle.dsseEnvelope) {
|
|
28
|
+
throw new Error("Bundle missing dsseEnvelope for DSSE entry");
|
|
29
|
+
}
|
|
30
|
+
if (!entry.spec.signatures || entry.spec.signatures.length !== 1) {
|
|
31
|
+
throw new Error("DSSE entry must have exactly one signature");
|
|
32
|
+
}
|
|
33
|
+
const tlogSig = entry.spec.signatures[0].signature;
|
|
34
|
+
const tlogSigBytes = base64ToUint8Array(tlogSig);
|
|
35
|
+
if (bundle.dsseEnvelope.signatures.length === 0) {
|
|
36
|
+
throw new Error("Bundle DSSE envelope missing signatures");
|
|
37
|
+
}
|
|
38
|
+
const bundleSigBytes = base64ToUint8Array(bundle.dsseEnvelope.signatures[0].sig);
|
|
39
|
+
if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {
|
|
40
|
+
throw new Error("DSSE signature mismatch between TLog entry and bundle");
|
|
41
|
+
}
|
|
42
|
+
const tlogHash = entry.spec.payloadHash?.value || "";
|
|
43
|
+
if (!tlogHash) {
|
|
44
|
+
throw new Error("DSSE entry missing payloadHash");
|
|
45
|
+
}
|
|
46
|
+
const tlogHashBytes = hexToUint8Array(tlogHash);
|
|
47
|
+
const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
|
|
48
|
+
const bundleHashBytes = new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(payloadBytes)));
|
|
49
|
+
if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
|
|
50
|
+
throw new Error("DSSE payload hash mismatch between TLog entry and bundle");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// New functionality for DSSE v0.0.2 (not in sigstore-js reference, which only supports v0.0.1)
|
|
54
|
+
async function verifyDSSE002Body(entry, bundle) {
|
|
55
|
+
if (!bundle.dsseEnvelope) {
|
|
56
|
+
throw new Error("Bundle missing dsseEnvelope for DSSE v0.0.2 entry");
|
|
57
|
+
}
|
|
58
|
+
const spec = entry.spec.dsseV002;
|
|
59
|
+
if (!spec) {
|
|
60
|
+
throw new Error("DSSE v0.0.2 entry missing dsseV002 spec");
|
|
61
|
+
}
|
|
62
|
+
if (!spec.signatures || spec.signatures.length !== 1) {
|
|
63
|
+
throw new Error("DSSE v0.0.2 entry must have exactly one signature");
|
|
64
|
+
}
|
|
65
|
+
const tlogSig = spec.signatures[0].content;
|
|
66
|
+
const tlogSigBytes = base64ToUint8Array(tlogSig);
|
|
67
|
+
if (bundle.dsseEnvelope.signatures.length === 0) {
|
|
68
|
+
throw new Error("Bundle DSSE envelope missing signatures");
|
|
69
|
+
}
|
|
70
|
+
const bundleSigBytes = base64ToUint8Array(bundle.dsseEnvelope.signatures[0].sig);
|
|
71
|
+
if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {
|
|
72
|
+
throw new Error("DSSE signature mismatch between TLog entry and bundle (v0.0.2)");
|
|
73
|
+
}
|
|
74
|
+
const tlogHash = spec.payloadHash?.digest || "";
|
|
75
|
+
if (!tlogHash) {
|
|
76
|
+
throw new Error("DSSE v0.0.2 entry missing payloadHash");
|
|
77
|
+
}
|
|
78
|
+
const tlogHashBytes = base64ToUint8Array(tlogHash);
|
|
79
|
+
const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
|
|
80
|
+
const bundleHashBytes = new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(payloadBytes)));
|
|
81
|
+
if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
|
|
82
|
+
throw new Error("DSSE payload hash mismatch between TLog entry and bundle (v0.0.2)");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=dsse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dsse.js","sourceRoot":"","sources":["../../src/tlog/dsse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashedrekord.d.ts","sourceRoot":"","sources":["../../src/tlog/hashedrekord.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAwC5C,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC,CAaf"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* HashedRekord transparency log entry verification
|
|
3
|
+
*
|
|
4
|
+
* Based on sigstore-js:
|
|
5
|
+
* https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/tlog/hashedrekord.ts
|
|
6
|
+
*
|
|
7
|
+
* Key differences from sigstore-js:
|
|
8
|
+
* - Browser-compatible: uses Uint8Array instead of Buffer for binary data
|
|
9
|
+
* - Direct bundle field comparison instead of SignatureContent abstraction
|
|
10
|
+
* - Adds verifyHashedRekordV002Body() - new functionality (reference only supports v0.0.1)
|
|
11
|
+
*/
|
|
12
|
+
import { base64ToUint8Array, hexToUint8Array, uint8ArrayEqual } from "../encoding.js";
|
|
13
|
+
export async function verifyHashedRekordBody(entry, bundle) {
|
|
14
|
+
const hashedRekordEntry = entry;
|
|
15
|
+
switch (hashedRekordEntry.apiVersion) {
|
|
16
|
+
case "0.0.1":
|
|
17
|
+
return verifyHashedRekordV001Body(hashedRekordEntry, bundle);
|
|
18
|
+
case "0.0.2":
|
|
19
|
+
return verifyHashedRekordV002Body(hashedRekordEntry, bundle);
|
|
20
|
+
default:
|
|
21
|
+
throw new Error(`Unsupported hashedrekord version: ${hashedRekordEntry.apiVersion}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function verifyHashedRekordV001Body(entry, bundle) {
|
|
25
|
+
const spec = entry.spec;
|
|
26
|
+
if (!bundle.messageSignature) {
|
|
27
|
+
throw new Error("Bundle missing messageSignature for hashedrekord entry");
|
|
28
|
+
}
|
|
29
|
+
const tlogSig = spec.signature.content || "";
|
|
30
|
+
const tlogSigBytes = base64ToUint8Array(tlogSig);
|
|
31
|
+
const bundleSigBytes = base64ToUint8Array(bundle.messageSignature.signature);
|
|
32
|
+
if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {
|
|
33
|
+
throw new Error("Signature mismatch between TLog entry and bundle");
|
|
34
|
+
}
|
|
35
|
+
const tlogDigest = spec.data.hash?.value || "";
|
|
36
|
+
const tlogDigestBytes = hexToUint8Array(tlogDigest);
|
|
37
|
+
const bundleDigestBytes = base64ToUint8Array(bundle.messageSignature.messageDigest.digest);
|
|
38
|
+
if (!uint8ArrayEqual(tlogDigestBytes, bundleDigestBytes)) {
|
|
39
|
+
throw new Error("Digest mismatch between TLog entry and bundle");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// New functionality for HashedRekord v0.0.2 (not in sigstore-js reference, which only supports v0.0.1)
|
|
43
|
+
function verifyHashedRekordV002Body(entry, bundle) {
|
|
44
|
+
const spec = entry.spec.hashedRekordV002;
|
|
45
|
+
if (!bundle.messageSignature) {
|
|
46
|
+
throw new Error("Bundle missing messageSignature for hashedrekord v0.0.2 entry");
|
|
47
|
+
}
|
|
48
|
+
// NOTE: HashedRekord v0.0.2 uses single base64 encoding (unlike intoto which is double-encoded)
|
|
49
|
+
// Verified against Sigstore conformance test suite bundles
|
|
50
|
+
const tlogSig = spec.signature.content || "";
|
|
51
|
+
const tlogSigBytes = base64ToUint8Array(tlogSig);
|
|
52
|
+
const bundleSigBytes = base64ToUint8Array(bundle.messageSignature.signature);
|
|
53
|
+
if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {
|
|
54
|
+
throw new Error("Signature mismatch between TLog entry and bundle (v0.0.2)");
|
|
55
|
+
}
|
|
56
|
+
const tlogDigest = spec.data.digest || "";
|
|
57
|
+
const tlogDigestBytes = base64ToUint8Array(tlogDigest);
|
|
58
|
+
const bundleDigestBytes = base64ToUint8Array(bundle.messageSignature.messageDigest.digest);
|
|
59
|
+
if (!uint8ArrayEqual(tlogDigestBytes, bundleDigestBytes)) {
|
|
60
|
+
throw new Error("Digest mismatch between TLog entry and bundle (v0.0.2)");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=hashedrekord.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashedrekord.js","sourceRoot":"","sources":["../../src/tlog/hashedrekord.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intoto.d.ts","sourceRoot":"","sources":["../../src/tlog/intoto.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAiC5C,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC,CAkDf"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Intoto transparency log entry verification
|
|
3
|
+
*
|
|
4
|
+
* Based on sigstore-js:
|
|
5
|
+
* https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/tlog/intoto.ts
|
|
6
|
+
*
|
|
7
|
+
* Key differences from sigstore-js:
|
|
8
|
+
* - Browser-compatible: uses Uint8Array instead of Buffer for binary data
|
|
9
|
+
* - Direct bundle field comparison instead of SignatureContent abstraction
|
|
10
|
+
* - Uses crypto.subtle.digest for hash computation instead of Node.js crypto
|
|
11
|
+
*/
|
|
12
|
+
import { base64Decode, base64ToUint8Array, hexToUint8Array, toArrayBuffer, uint8ArrayEqual } from "../encoding.js";
|
|
13
|
+
import { HashAlgorithms } from "../interfaces.js";
|
|
14
|
+
export async function verifyIntotoBody(entry, bundle) {
|
|
15
|
+
const intotoEntry = entry;
|
|
16
|
+
if (intotoEntry.apiVersion !== "0.0.2") {
|
|
17
|
+
throw new Error(`Unsupported intoto version: ${intotoEntry.apiVersion}`);
|
|
18
|
+
}
|
|
19
|
+
if (!bundle.dsseEnvelope) {
|
|
20
|
+
throw new Error("Bundle missing dsseEnvelope for intoto entry");
|
|
21
|
+
}
|
|
22
|
+
const tlogEnvelope = intotoEntry.spec.content.envelope;
|
|
23
|
+
if (!tlogEnvelope.signatures || tlogEnvelope.signatures.length !== 1) {
|
|
24
|
+
throw new Error("Intoto entry must have exactly one signature");
|
|
25
|
+
}
|
|
26
|
+
// The signature in the intoto tlog entry is double-base64-encoded:
|
|
27
|
+
// 1. Raw signature bytes are base64-encoded (normal)
|
|
28
|
+
// 2. That base64 string is base64-encoded again (for storage in JSON)
|
|
29
|
+
// So we decode twice: base64 -> string -> base64 -> bytes
|
|
30
|
+
const tlogSigBase64 = tlogEnvelope.signatures[0].sig;
|
|
31
|
+
const tlogSigDecoded = base64Decode(tlogSigBase64); // First decode: base64 -> UTF-8 string (which contains base64)
|
|
32
|
+
const tlogSigBytes = base64ToUint8Array(tlogSigDecoded); // Second decode: base64 string -> raw bytes
|
|
33
|
+
if (bundle.dsseEnvelope.signatures.length === 0) {
|
|
34
|
+
throw new Error("Bundle DSSE envelope missing signatures");
|
|
35
|
+
}
|
|
36
|
+
const bundleSigBytes = base64ToUint8Array(bundle.dsseEnvelope.signatures[0].sig);
|
|
37
|
+
if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {
|
|
38
|
+
throw new Error("Intoto signature mismatch between TLog entry and bundle");
|
|
39
|
+
}
|
|
40
|
+
if (intotoEntry.spec.content.payloadHash) {
|
|
41
|
+
const tlogHash = intotoEntry.spec.content.payloadHash.value;
|
|
42
|
+
const tlogHashBytes = hexToUint8Array(tlogHash);
|
|
43
|
+
const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
|
|
44
|
+
const bundleHashBytes = new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(payloadBytes)));
|
|
45
|
+
if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
|
|
46
|
+
throw new Error("Intoto payload hash mismatch between TLog entry and bundle");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=intoto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intoto.js","sourceRoot":"","sources":["../../src/tlog/intoto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACnH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAmClD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAiB,EACjB,MAAsB;IAEtB,MAAM,WAAW,GAAG,KAAoB,CAAC;IAEzC,IAAI,WAAW,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,+BAA+B,WAAW,CAAC,UAAU,EAAE,CACxD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IAEvD,IAAI,CAAC,YAAY,CAAC,UAAU,IAAI,YAAY,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,mEAAmE;IACnE,qDAAqD;IACrD,sEAAsE;IACtE,0DAA0D;IAC1D,MAAM,aAAa,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACrD,MAAM,cAAc,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,+DAA+D;IACnH,MAAM,YAAY,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAAC,4CAA4C;IAErG,IAAI,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,cAAc,GAAG,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEjF,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,cAAc,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC;QAC5D,MAAM,aAAa,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAEhD,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACrE,MAAM,eAAe,GAAG,IAAI,UAAU,CACpC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC,CAC/E,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,aAAa,EAAE,eAAe,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merkle.d.ts","sourceRoot":"","sources":["../../src/tlog/merkle.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK9C,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Adapted from sigstore-js for browser compatibility:
|
|
3
|
+
https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/timestamp/merkle.ts
|
|
4
|
+
|
|
5
|
+
Key differences:
|
|
6
|
+
- Uses Uint8Array instead of Buffer
|
|
7
|
+
- Uses async Web Crypto API (crypto.subtle.digest) instead of sync Node.js crypto
|
|
8
|
+
- Base64 decoding via custom base64ToUint8Array instead of Buffer.from
|
|
9
|
+
- Custom uint8ArrayEqual instead of crypto.bufferEqual
|
|
10
|
+
*/
|
|
11
|
+
import { base64ToUint8Array, toArrayBuffer, uint8ArrayEqual } from "../encoding.js";
|
|
12
|
+
import { HashAlgorithms } from "../interfaces.js";
|
|
13
|
+
const RFC6962_LEAF_HASH_PREFIX = new Uint8Array([0x00]);
|
|
14
|
+
const RFC6962_NODE_HASH_PREFIX = new Uint8Array([0x01]);
|
|
15
|
+
export async function verifyMerkleInclusion(entry) {
|
|
16
|
+
if (!entry.inclusionProof) {
|
|
17
|
+
throw new Error("Missing inclusion proof");
|
|
18
|
+
}
|
|
19
|
+
const inclusionProof = entry.inclusionProof;
|
|
20
|
+
const logIndex = BigInt(inclusionProof.logIndex);
|
|
21
|
+
const treeSize = BigInt(inclusionProof.treeSize);
|
|
22
|
+
if (logIndex < 0n || logIndex >= treeSize) {
|
|
23
|
+
throw new Error(`Invalid log index: ${logIndex}`);
|
|
24
|
+
}
|
|
25
|
+
// Figure out which subset of hashes corresponds to the inner and border
|
|
26
|
+
// nodes
|
|
27
|
+
const { inner, border } = decompInclProof(logIndex, treeSize);
|
|
28
|
+
if (inclusionProof.hashes.length !== inner + border) {
|
|
29
|
+
throw new Error("Invalid hash count in inclusion proof");
|
|
30
|
+
}
|
|
31
|
+
const innerHashes = inclusionProof.hashes
|
|
32
|
+
.slice(0, inner)
|
|
33
|
+
.map((h) => base64ToUint8Array(h));
|
|
34
|
+
const borderHashes = inclusionProof.hashes
|
|
35
|
+
.slice(inner)
|
|
36
|
+
.map((h) => base64ToUint8Array(h));
|
|
37
|
+
// The entry's hash is the leaf hash
|
|
38
|
+
const leafHash = await hashLeaf(base64ToUint8Array(entry.canonicalizedBody));
|
|
39
|
+
// Chain the hashes belonging to the inner and border portions
|
|
40
|
+
const calculatedHash = await chainBorderRight(await chainInner(leafHash, innerHashes, logIndex), borderHashes);
|
|
41
|
+
const rootHash = base64ToUint8Array(inclusionProof.rootHash);
|
|
42
|
+
// Calculated hash should match the root hash in the inclusion proof
|
|
43
|
+
if (!uint8ArrayEqual(calculatedHash, rootHash)) {
|
|
44
|
+
throw new Error("Calculated root hash does not match inclusion proof");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Breaks down inclusion proof for a leaf at the specified index in a tree of
|
|
48
|
+
// the specified size. The split point is where paths to the index leaf and
|
|
49
|
+
// the (size - 1) leaf diverge. Returns lengths of the bottom and upper proof
|
|
50
|
+
// parts.
|
|
51
|
+
function decompInclProof(index, size) {
|
|
52
|
+
const inner = innerProofSize(index, size);
|
|
53
|
+
const border = onesCount(index >> BigInt(inner));
|
|
54
|
+
return { inner, border };
|
|
55
|
+
}
|
|
56
|
+
// Computes a subtree hash for a node on or below the tree's right border.
|
|
57
|
+
// Assumes the provided proof hashes are ordered from lower to higher levels
|
|
58
|
+
// and seed is the initial hash of the node specified by the index.
|
|
59
|
+
async function chainInner(seed, hashes, index) {
|
|
60
|
+
let acc = seed;
|
|
61
|
+
for (let i = 0; i < hashes.length; i++) {
|
|
62
|
+
const h = hashes[i];
|
|
63
|
+
if ((index >> BigInt(i)) & BigInt(1)) {
|
|
64
|
+
acc = await hashChildren(h, acc);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
acc = await hashChildren(acc, h);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return acc;
|
|
71
|
+
}
|
|
72
|
+
// Computes a subtree hash for nodes along the tree's right border.
|
|
73
|
+
async function chainBorderRight(seed, hashes) {
|
|
74
|
+
let acc = seed;
|
|
75
|
+
for (const h of hashes) {
|
|
76
|
+
acc = await hashChildren(h, acc);
|
|
77
|
+
}
|
|
78
|
+
return acc;
|
|
79
|
+
}
|
|
80
|
+
function innerProofSize(index, size) {
|
|
81
|
+
return bitLength(index ^ (size - BigInt(1)));
|
|
82
|
+
}
|
|
83
|
+
// Counts the number of ones in the binary representation of the given number.
|
|
84
|
+
// https://en.wikipedia.org/wiki/Hamming_weight
|
|
85
|
+
function onesCount(num) {
|
|
86
|
+
return num.toString(2).split("1").length - 1;
|
|
87
|
+
}
|
|
88
|
+
// Returns the number of bits necessary to represent an integer in binary.
|
|
89
|
+
function bitLength(n) {
|
|
90
|
+
if (n === 0n) {
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
return n.toString(2).length;
|
|
94
|
+
}
|
|
95
|
+
// Hashing logic according to RFC6962.
|
|
96
|
+
// https://datatracker.ietf.org/doc/html/rfc6962#section-2
|
|
97
|
+
async function hashChildren(left, right) {
|
|
98
|
+
const data = new Uint8Array(RFC6962_NODE_HASH_PREFIX.length + left.length + right.length);
|
|
99
|
+
data.set(RFC6962_NODE_HASH_PREFIX, 0);
|
|
100
|
+
data.set(left, RFC6962_NODE_HASH_PREFIX.length);
|
|
101
|
+
data.set(right, RFC6962_NODE_HASH_PREFIX.length + left.length);
|
|
102
|
+
const hash = await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(data));
|
|
103
|
+
return new Uint8Array(hash);
|
|
104
|
+
}
|
|
105
|
+
async function hashLeaf(leaf) {
|
|
106
|
+
const data = new Uint8Array(RFC6962_LEAF_HASH_PREFIX.length + leaf.length);
|
|
107
|
+
data.set(RFC6962_LEAF_HASH_PREFIX, 0);
|
|
108
|
+
data.set(leaf, RFC6962_LEAF_HASH_PREFIX.length);
|
|
109
|
+
const hash = await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(data));
|
|
110
|
+
return new Uint8Array(hash);
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=merkle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merkle.js","sourceRoot":"","sources":["../../src/tlog/merkle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"ewogInNpZ25hdHVyZXMiOiBbCiAgewogICAia2V5aWQiOiAiNmYyNjAwODlkNTkyM2RhZjIwMTY2Y2E2NTdjNTQzYWY2MTgzNDZhYjk3MTg4NGE5OTk2MmIwMTk4OGJiZTBjMyIsCiAgICJzaWciOiAiIgogIH0sCiAgewogICAia2V5aWQiOiAiZTcxYTU0ZDU0MzgzNWJhODZhZGFkOTQ2MDM3OWM3NjQxZmI4NzI2ZDE2NGVhNzY2ODAxYTFjNTIyYWJhN2VhMiIsCiAgICJzaWciOiAiMzA0NTAyMjEwMGJiZGRkNDY0ZjgwNjZjZWI4OGJhNzg3Mzc1YzEyY2Q2MzMwNjgwZTA4YzI5MTA3MDNlNjUzOGM3MWNjNzlhZDIwMjIwNTE5MGIwNmU0NTM3ZmU5NjFiM2VmODFmZTY4ZWRjZDAwODljMTlmOTE5YWZlZDQyM2I5YWFmZDcwMDY0MTE1MyIKICB9LAogIHsKICAgImtleWlkIjogIjIyZjRjYWVjNmQ4ZTZmOTU1NWFmNjZiM2Q0YzNjYjA2YTNiYjIzZmRjN2UzOWM5MTZjNjFmNDYyZTZmNTJiMDYiLAogICAic2lnIjogIjMwNDQwMjIwNjkzMDZjZDUyNTdmNzMyYTc0MGMxYWZlNjBhOGU0MzNjNWRlNThlYWZlYWRiZTk5YzMzNmM5YzcxZDE5OGNmODAyMjAwZDc3Mzk1M2FlN2RiYzQ4ZDNlNWJhZDlhNmY2NGJhZmZmMTk2YjdlMmFkNGE1MmExOTUxOTM2N2Q0N2RjMDQyIgogIH0sCiAgewogICAia2V5aWQiOiAiNjE2NDM4MzgxMjViNDQwYjQwZGI2OTQyZjVjYjVhMzFjMGRjMDQzNjgzMTZlYjJhYWE1OGI5NTkwNGE1ODIyMiIsCiAgICJzaWciOiAiMzA0NDAyMjA0ZDIxYTJlYzgwZGY2NmU2MWY2ZmUyOTEyOTUxZGM0N2RmODM2MDM2ZjhjMGFiMTA4MTZkMzc1ZTcxZGJmNzllMDIyMDU0N2FkY2UxYWZkZjA0ZTY3OTRlZmEyMDNkZDUyNjRjNmY3ZTBlZjc4ZTU3ZmU5MzRiMGQyNmNiOTk0ZWVjNzYiCiAgfSwKICB7CiAgICJrZXlpZCI6ICJhNjg3ZTViZjRmYWI4MmIwZWU1OGQ0NmUwNWM5NTM1MTQ1YTJjOWFmYjQ1OGY0M2Q0MmI0NWNhMGZkY2UyYTcwIiwKICAgInNpZyI6ICIzMDQ1MDIyMDYwODI2NDk2NTU3MTQ0ZWIxNjQ5ODkzZWQ1ZjZmNGVhNTQ1MzZmZWIwY2E4MmY4Yjg5YWU2NDFiZTM5NzQzZTUwMjIxMDBhZDcxMThiNWU5ZDQ4MzczMjYyMDZlNDEyZmM2ZGEyOTk5OTI1ZDExMDMyOGE3YzE2NmIwNmM2MjQzMzZjOTNmIgogIH0sCiAgewogICAia2V5aWQiOiAiMTgzZTY0ZjM3NjcwZGMxM2NhMGQyODk5NWEzMDUzZjM3NDA5NTRkZGNlNDQzMjFhNDFlNDY1MzRjZjQ0ZTYzMiIsCiAgICJzaWciOiAiMzA0NjAyMjEwMGQ4MTc5NDM5YzJlNzNlYjBjMTczM2FiZWU3ZmFmODMyZGNhZWE3MjYzZWRjYjQ5MTk4OTFjM2EyNDdmMDU5MjMwMjIxMDBlMWE0MzdlMDc5N2U4MDNmOWI3MmRjOWQyZDkyMTU1YjBhMjI3MGMyNGVmZGQ1ZjRiM2E1ZDhmMGIwZjQzMWE3IgogIH0KIF0sCiAic2lnbmVkIjogewogICJfdHlwZSI6ICJyb290IiwKICAiY29uc2lzdGVudF9zbmFwc2hvdCI6IHRydWUsCiAgImV4cGlyZXMiOiAiMjAyNi0wMS0yMlQxMzowNTo1OVoiLAogICJrZXlzIjogewogICAiMGM4NzQzMmMzYmYwOWZkOTkxODlmZGMzMmZhNWVhZWRmNGU0YTVmYWM3YmFiNzNmYTA0YTJlMGZjNjRhZjZmNSI6IHsKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dHlwZSI6ICJlY2RzYSIsCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRVdSaUdyNStqKzNKNVNzSCtadHI1bkUySDJ3TzdcbkJWK25PM3M5M2dMY2ExOHFUT3pIWTFvV3lBR0R5a01Tc0dUVUJTdDlEK0FuMEtmS3NEMm1mU000MlE9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iCiAgICB9LAogICAgInNjaGVtZSI6ICJlY2RzYS1zaGEyLW5pc3RwMjU2IiwKICAgICJ4LXR1Zi1vbi1jaS1vbmxpbmUtdXJpIjogImdjcGttczpwcm9qZWN0cy9zaWdzdG9yZS1yb290LXNpZ25pbmcvbG9jYXRpb25zL2dsb2JhbC9rZXlSaW5ncy9yb290L2NyeXB0b0tleXMvdGltZXN0YW1wL2NyeXB0b0tleVZlcnNpb25zLzEiCiAgIH0sCiAgICIxODNlNjRmMzc2NzBkYzEzY2EwZDI4OTk1YTMwNTNmMzc0MDk1NGRkY2U0NDMyMWE0MWU0NjUzNGNmNDRlNjMyIjogewogICAgImtleXR5cGUiOiAiZWNkc2EiLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogIi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVNeHBQT0pDSVo1b3RHNDEwNmZHSnNlRVFpM1Y5XG5wa01ZUTR1eVY5VGoxTTdXSFhJeUxHK2prZnZ1RzBnbFExSlpiUlpaQlYzZ0FSNHNvamRHSElTZW93PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIgogICAgfSwKICAgICJzY2hlbWUiOiAiZWNkc2Etc2hhMi1uaXN0cDI1NiIsCiAgICAieC10dWYtb24tY2kta2V5b3duZXIiOiAiQGxhbmNlIgogICB9LAogICAiMjJmNGNhZWM2ZDhlNmY5NTU1YWY2NmIzZDRjM2NiMDZhM2JiMjNmZGM3ZTM5YzkxNmM2MWY0NjJlNmY1MmIwNiI6IHsKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dHlwZSI6ICJlY2RzYSIsCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXpCelZPbUhDUG9qTVZMU0kzNjRXaWlWOE5QckRcbjZJZ1J4Vmxpc2t6L3YreTNKRVI1bWNWR2NPTmxpRGNXTUM1SjJsZkhtalBOUGhiNEg3eG04THpmU0E9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iCiAgICB9LAogICAgInNjaGVtZSI6ICJlY2RzYS1zaGEyLW5pc3RwMjU2IiwKICAgICJ4LXR1Zi1vbi1jaS1rZXlvd25lciI6ICJAc2FudGlhZ290b3JyZXMiCiAgIH0sCiAgICI2MTY0MzgzODEyNWI0NDBiNDBkYjY5NDJmNWNiNWEzMWMwZGMwNDM2ODMxNmViMmFhYTU4Yjk1OTA0YTU4MjIyIjogewogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl0eXBlIjogImVjZHNhIiwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICItLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLVxuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFaW5pa1NzQVFtWWtOZUg1ZVlxL0NuSXpMYWFjT1xueGxTYWF3UURPd3FLeS90Q3F4cTV4eFBTSmMyMUs0V0loczlHeU9rS2Z6dWVZM0dJTHpjTUpaNGNXdz09XG4tLS0tLUVORCBQVUJMSUMgS0VZLS0tLS1cbiIKICAgIH0sCiAgICAic2NoZW1lIjogImVjZHNhLXNoYTItbmlzdHAyNTYiLAogICAgIngtdHVmLW9uLWNpLWtleW93bmVyIjogIkBib2JjYWxsYXdheSIKICAgfSwKICAgImE2ODdlNWJmNGZhYjgyYjBlZTU4ZDQ2ZTA1Yzk1MzUxNDVhMmM5YWZiNDU4ZjQzZDQyYjQ1Y2EwZmRjZTJhNzAiOiB7CiAgICAia2V5aWRfaGFzaF9hbGdvcml0aG1zIjogWwogICAgICJzaGEyNTYiLAogICAgICJzaGE1MTIiCiAgICBdLAogICAgImtleXR5cGUiOiAiZWNkc2EiLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogIi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUwZ2hyaDkyTHcxWXIzaWRHVjVXcUN0TURCOEN4XG4rRDhoZEM0dzJaTE5JcGxWUm9WR0xza1lhM2doZU15T2ppSjhrUGkxNWFRMi8vN1Arb2o3VXZKUEd3PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIgogICAgfSwKICAgICJzY2hlbWUiOiAiZWNkc2Etc2hhMi1uaXN0cDI1NiIsCiAgICAieC10dWYtb24tY2kta2V5b3duZXIiOiAiQGpvc2h1YWdsIgogICB9LAogICAiZTcxYTU0ZDU0MzgzNWJhODZhZGFkOTQ2MDM3OWM3NjQxZmI4NzI2ZDE2NGVhNzY2ODAxYTFjNTIyYWJhN2VhMiI6IHsKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dHlwZSI6ICJlY2RzYSIsCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRUVYc3ozU1pYRmI4ak1WNDJqNnBKbHlqYmpSOEtcbk4zQndvY2V4cTZMTUliNXFzV0tPUXZMTjE2TlVlZkxjNEhzd09vdW1Sc1ZWYWFqU3BRUzZmb2JrUnc9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iCiAgICB9LAogICAgInNjaGVtZSI6ICJlY2RzYS1zaGEyLW5pc3RwMjU2IiwKICAgICJ4LXR1Zi1vbi1jaS1rZXlvd25lciI6ICJAbW5tNjc4IgogICB9CiAgfSwKICAicm9sZXMiOiB7CiAgICJyb290IjogewogICAgImtleWlkcyI6IFsKICAgICAiZTcxYTU0ZDU0MzgzNWJhODZhZGFkOTQ2MDM3OWM3NjQxZmI4NzI2ZDE2NGVhNzY2ODAxYTFjNTIyYWJhN2VhMiIsCiAgICAgIjIyZjRjYWVjNmQ4ZTZmOTU1NWFmNjZiM2Q0YzNjYjA2YTNiYjIzZmRjN2UzOWM5MTZjNjFmNDYyZTZmNTJiMDYiLAogICAgICI2MTY0MzgzODEyNWI0NDBiNDBkYjY5NDJmNWNiNWEzMWMwZGMwNDM2ODMxNmViMmFhYTU4Yjk1OTA0YTU4MjIyIiwKICAgICAiYTY4N2U1YmY0ZmFiODJiMGVlNThkNDZlMDVjOTUzNTE0NWEyYzlhZmI0NThmNDNkNDJiNDVjYTBmZGNlMmE3MCIsCiAgICAgIjE4M2U2NGYzNzY3MGRjMTNjYTBkMjg5OTVhMzA1M2YzNzQwOTU0ZGRjZTQ0MzIxYTQxZTQ2NTM0Y2Y0NGU2MzIiCiAgICBdLAogICAgInRocmVzaG9sZCI6IDMKICAgfSwKICAgInNuYXBzaG90IjogewogICAgImtleWlkcyI6IFsKICAgICAiMGM4NzQzMmMzYmYwOWZkOTkxODlmZGMzMmZhNWVhZWRmNGU0YTVmYWM3YmFiNzNmYTA0YTJlMGZjNjRhZjZmNSIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMSwKICAgICJ4LXR1Zi1vbi1jaS1leHBpcnktcGVyaW9kIjogMzY1MCwKICAgICJ4LXR1Zi1vbi1jaS1zaWduaW5nLXBlcmlvZCI6IDM2NQogICB9LAogICAidGFyZ2V0cyI6IHsKICAgICJrZXlpZHMiOiBbCiAgICAgImU3MWE1NGQ1NDM4MzViYTg2YWRhZDk0NjAzNzljNzY0MWZiODcyNmQxNjRlYTc2NjgwMWExYzUyMmFiYTdlYTIiLAogICAgICIyMmY0Y2FlYzZkOGU2Zjk1NTVhZjY2YjNkNGMzY2IwNmEzYmIyM2ZkYzdlMzljOTE2YzYxZjQ2MmU2ZjUyYjA2IiwKICAgICAiNjE2NDM4MzgxMjViNDQwYjQwZGI2OTQyZjVjYjVhMzFjMGRjMDQzNjgzMTZlYjJhYWE1OGI5NTkwNGE1ODIyMiIsCiAgICAgImE2ODdlNWJmNGZhYjgyYjBlZTU4ZDQ2ZTA1Yzk1MzUxNDVhMmM5YWZiNDU4ZjQzZDQyYjQ1Y2EwZmRjZTJhNzAiLAogICAgICIxODNlNjRmMzc2NzBkYzEzY2EwZDI4OTk1YTMwNTNmMzc0MDk1NGRkY2U0NDMyMWE0MWU0NjUzNGNmNDRlNjMyIgogICAgXSwKICAgICJ0aHJlc2hvbGQiOiAzCiAgIH0sCiAgICJ0aW1lc3RhbXAiOiB7CiAgICAia2V5aWRzIjogWwogICAgICIwYzg3NDMyYzNiZjA5ZmQ5OTE4OWZkYzMyZmE1ZWFlZGY0ZTRhNWZhYzdiYWI3M2ZhMDRhMmUwZmM2NGFmNmY1IgogICAgXSwKICAgICJ0aHJlc2hvbGQiOiAxLAogICAgIngtdHVmLW9uLWNpLWV4cGlyeS1wZXJpb2QiOiA3LAogICAgIngtdHVmLW9uLWNpLXNpZ25pbmctcGVyaW9kIjogNgogICB9CiAgfSwKICAic3BlY192ZXJzaW9uIjogIjEuMCIsCiAgInZlcnNpb24iOiAxMywKICAieC10dWYtb24tY2ktZXhwaXJ5LXBlcmlvZCI6IDE5NywKICAieC10dWYtb24tY2ktc2lnbmluZy1wZXJpb2QiOiA0NgogfQp9"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { TrustedRoot } from "../interfaces.js";
|
|
2
|
+
/**
|
|
3
|
+
* Options for TrustedRootProvider configuration
|
|
4
|
+
*/
|
|
5
|
+
export interface TrustedRootProviderOptions {
|
|
6
|
+
/**
|
|
7
|
+
* TUF repository URL for metadata
|
|
8
|
+
* Default: Sigstore production TUF repository
|
|
9
|
+
*/
|
|
10
|
+
metadataUrl?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Target base URL for fetching target files
|
|
13
|
+
* If not specified, uses the same as metadataUrl
|
|
14
|
+
*/
|
|
15
|
+
targetBaseUrl?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Initial root metadata (1.root.json content)
|
|
18
|
+
* If not provided, will use embedded default
|
|
19
|
+
*/
|
|
20
|
+
initialRoot?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Namespace for TUF cache storage
|
|
23
|
+
* Default: 'sigstore-browser'
|
|
24
|
+
*/
|
|
25
|
+
namespace?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Name of the trusted root target file
|
|
28
|
+
* Default: 'trusted_root.json'
|
|
29
|
+
*/
|
|
30
|
+
trustedRootTarget?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Cache TTL in milliseconds
|
|
33
|
+
* Default: 1 hour (3600000 ms)
|
|
34
|
+
*/
|
|
35
|
+
cacheTTL?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Provides Sigstore trusted root via TUF for secure updates
|
|
39
|
+
*
|
|
40
|
+
* This class manages fetching and caching of Sigstore trusted root metadata
|
|
41
|
+
* using The Update Framework (TUF) for secure, verified updates.
|
|
42
|
+
*
|
|
43
|
+
* Example usage:
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const provider = new TrustedRootProvider();
|
|
46
|
+
* const trustedRoot = await provider.getTrustedRoot();
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare class TrustedRootProvider {
|
|
50
|
+
private metadataUrl;
|
|
51
|
+
private targetBaseUrl?;
|
|
52
|
+
private initialRoot?;
|
|
53
|
+
private namespace;
|
|
54
|
+
private trustedRootTarget;
|
|
55
|
+
private cacheTTL;
|
|
56
|
+
private tufClient?;
|
|
57
|
+
private cachedRoot?;
|
|
58
|
+
private cacheTimestamp?;
|
|
59
|
+
constructor(options?: TrustedRootProviderOptions);
|
|
60
|
+
/**
|
|
61
|
+
* Initialize the TUF client
|
|
62
|
+
* Lazy initialization to avoid loading TUF client until needed
|
|
63
|
+
*/
|
|
64
|
+
private initTUFClient;
|
|
65
|
+
/**
|
|
66
|
+
* Get the default embedded root metadata
|
|
67
|
+
* Returns the TUF root.json that bootstraps the TUF client
|
|
68
|
+
*/
|
|
69
|
+
private getDefaultRoot;
|
|
70
|
+
/**
|
|
71
|
+
* Check if cached trusted root is still valid
|
|
72
|
+
*/
|
|
73
|
+
private isCacheValid;
|
|
74
|
+
/**
|
|
75
|
+
* Get the Sigstore trusted root metadata
|
|
76
|
+
* Uses TUF to securely fetch and verify the trusted root
|
|
77
|
+
*
|
|
78
|
+
* @returns Promise<TrustedRoot> The verified trusted root metadata
|
|
79
|
+
* @throws Error if TUF verification fails or root cannot be fetched
|
|
80
|
+
*/
|
|
81
|
+
getTrustedRoot(): Promise<TrustedRoot>;
|
|
82
|
+
/**
|
|
83
|
+
* Manually refresh the trusted root from TUF
|
|
84
|
+
* Bypasses cache and forces a fresh fetch
|
|
85
|
+
*
|
|
86
|
+
* @returns Promise<TrustedRoot> The updated trusted root metadata
|
|
87
|
+
*/
|
|
88
|
+
refreshTrustedRoot(): Promise<TrustedRoot>;
|
|
89
|
+
/**
|
|
90
|
+
* Clear the cached trusted root
|
|
91
|
+
* Next call to getTrustedRoot() will fetch fresh data
|
|
92
|
+
*/
|
|
93
|
+
clearCache(): void;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=tuf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tuf.d.ts","sourceRoot":"","sources":["../../src/trust/tuf.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAYD;;;;;;;;;;;GAWG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,UAAU,CAAC,CAAc;IACjC,OAAO,CAAC,cAAc,CAAC,CAAS;gBAEpB,OAAO,GAAE,0BAA+B;IAUpD;;;OAGG;YACW,aAAa;IAwB3B;;;OAGG;YACW,cAAc;IAY5B;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAsC5C;;;;;OAKG;IACG,kBAAkB,IAAI,OAAO,CAAC,WAAW,CAAC;IAShD;;;OAGG;IACH,UAAU,IAAI,IAAI;CAInB"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* TUF (The Update Framework) integration for trusted root management
|
|
3
|
+
*
|
|
4
|
+
* Provides secure updates for Sigstore trusted root metadata using TUF.
|
|
5
|
+
* Uses tuf-browser for browser-compatible TUF client functionality.
|
|
6
|
+
*
|
|
7
|
+
* Reference: https://github.com/freedomofpress/tuf-browser
|
|
8
|
+
*/
|
|
9
|
+
import { Uint8ArrayToString } from "../encoding.js";
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration for Sigstore production TUF repository
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_CONFIG = {
|
|
14
|
+
metadataUrl: 'https://tuf-repo-cdn.sigstore.dev/',
|
|
15
|
+
namespace: 'sigstore-browser',
|
|
16
|
+
trustedRootTarget: 'trusted_root.json',
|
|
17
|
+
cacheTTL: 3600000, // 1 hour
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Provides Sigstore trusted root via TUF for secure updates
|
|
21
|
+
*
|
|
22
|
+
* This class manages fetching and caching of Sigstore trusted root metadata
|
|
23
|
+
* using The Update Framework (TUF) for secure, verified updates.
|
|
24
|
+
*
|
|
25
|
+
* Example usage:
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const provider = new TrustedRootProvider();
|
|
28
|
+
* const trustedRoot = await provider.getTrustedRoot();
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export class TrustedRootProvider {
|
|
32
|
+
metadataUrl;
|
|
33
|
+
targetBaseUrl;
|
|
34
|
+
initialRoot;
|
|
35
|
+
namespace;
|
|
36
|
+
trustedRootTarget;
|
|
37
|
+
cacheTTL;
|
|
38
|
+
tufClient;
|
|
39
|
+
cachedRoot;
|
|
40
|
+
cacheTimestamp;
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
const metadataUrl = options.metadataUrl || DEFAULT_CONFIG.metadataUrl;
|
|
43
|
+
this.metadataUrl = metadataUrl.endsWith('/') ? metadataUrl : `${metadataUrl}/`;
|
|
44
|
+
this.targetBaseUrl = options.targetBaseUrl || this.metadataUrl;
|
|
45
|
+
this.initialRoot = options.initialRoot;
|
|
46
|
+
this.namespace = options.namespace || DEFAULT_CONFIG.namespace;
|
|
47
|
+
this.trustedRootTarget = options.trustedRootTarget || DEFAULT_CONFIG.trustedRootTarget;
|
|
48
|
+
this.cacheTTL = options.cacheTTL ?? DEFAULT_CONFIG.cacheTTL;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the TUF client
|
|
52
|
+
* Lazy initialization to avoid loading TUF client until needed
|
|
53
|
+
*/
|
|
54
|
+
async initTUFClient() {
|
|
55
|
+
if (this.tufClient) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const { TUFClient } = await import('tuf-browser/dist/tuf.js');
|
|
60
|
+
// Get initial root metadata
|
|
61
|
+
const rootMetadata = this.initialRoot || await this.getDefaultRoot();
|
|
62
|
+
this.tufClient = new TUFClient(this.metadataUrl, rootMetadata, this.namespace, this.targetBaseUrl);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw new Error(`Failed to initialize TUF client: ${error instanceof Error ? error.message : String(error)}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get the default embedded root metadata
|
|
70
|
+
* Returns the TUF root.json that bootstraps the TUF client
|
|
71
|
+
*/
|
|
72
|
+
async getDefaultRoot() {
|
|
73
|
+
// Import the embedded TUF root metadata (base64-encoded 1.root.json as JSON string)
|
|
74
|
+
// This is the root of trust for TUF, not to be confused with the Sigstore trusted root
|
|
75
|
+
const tufRootModule = await import('./tuf-root.json', { with: { type: 'json' } });
|
|
76
|
+
const tufRootBase64 = tufRootModule.default;
|
|
77
|
+
// Decode from base64 to get the actual root.json content
|
|
78
|
+
const decoder = new TextDecoder();
|
|
79
|
+
const rootBytes = Uint8Array.from(atob(tufRootBase64), c => c.charCodeAt(0));
|
|
80
|
+
return decoder.decode(rootBytes);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if cached trusted root is still valid
|
|
84
|
+
*/
|
|
85
|
+
isCacheValid() {
|
|
86
|
+
if (!this.cachedRoot || !this.cacheTimestamp) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
return (now - this.cacheTimestamp) < this.cacheTTL;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get the Sigstore trusted root metadata
|
|
94
|
+
* Uses TUF to securely fetch and verify the trusted root
|
|
95
|
+
*
|
|
96
|
+
* @returns Promise<TrustedRoot> The verified trusted root metadata
|
|
97
|
+
* @throws Error if TUF verification fails or root cannot be fetched
|
|
98
|
+
*/
|
|
99
|
+
async getTrustedRoot() {
|
|
100
|
+
// Return cached root if still valid
|
|
101
|
+
if (this.isCacheValid() && this.cachedRoot) {
|
|
102
|
+
return this.cachedRoot;
|
|
103
|
+
}
|
|
104
|
+
// Initialize TUF client if needed
|
|
105
|
+
await this.initTUFClient();
|
|
106
|
+
if (!this.tufClient) {
|
|
107
|
+
throw new Error('TUF client not initialized');
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
// Update TUF metadata (root, timestamp, snapshot, targets)
|
|
111
|
+
// This must be called before getTarget() to populate the metadata cache
|
|
112
|
+
await this.tufClient.updateTUF();
|
|
113
|
+
// Fetch the trusted root target via TUF
|
|
114
|
+
// TUF will handle all verification (signatures, rollback protection, etc.)
|
|
115
|
+
const trustedRootBytes = await this.tufClient.getTarget(this.trustedRootTarget);
|
|
116
|
+
// Parse the trusted root JSON
|
|
117
|
+
const trustedRootJson = Uint8ArrayToString(trustedRootBytes);
|
|
118
|
+
const trustedRoot = JSON.parse(trustedRootJson);
|
|
119
|
+
// Cache the result
|
|
120
|
+
this.cachedRoot = trustedRoot;
|
|
121
|
+
this.cacheTimestamp = Date.now();
|
|
122
|
+
return trustedRoot;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
throw new Error(`Failed to fetch trusted root via TUF: ${error instanceof Error ? error.message : String(error)}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Manually refresh the trusted root from TUF
|
|
130
|
+
* Bypasses cache and forces a fresh fetch
|
|
131
|
+
*
|
|
132
|
+
* @returns Promise<TrustedRoot> The updated trusted root metadata
|
|
133
|
+
*/
|
|
134
|
+
async refreshTrustedRoot() {
|
|
135
|
+
// Clear cache
|
|
136
|
+
this.cachedRoot = undefined;
|
|
137
|
+
this.cacheTimestamp = undefined;
|
|
138
|
+
// Fetch fresh root
|
|
139
|
+
return await this.getTrustedRoot();
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Clear the cached trusted root
|
|
143
|
+
* Next call to getTrustedRoot() will fetch fresh data
|
|
144
|
+
*/
|
|
145
|
+
clearCache() {
|
|
146
|
+
this.cachedRoot = undefined;
|
|
147
|
+
this.cacheTimestamp = undefined;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=tuf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tuf.js","sourceRoot":"","sources":["../../src/trust/tuf.ts"],"names":[],"mappings":"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"}
|