@freedomofpress/sigstore-browser 0.1.17 → 0.2.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/README.md +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/sigstore.d.ts +2 -0
- package/dist/sigstore.js +6 -4
- package/dist/sigstore.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ const verifier = new SigstoreVerifier({
|
|
|
66
66
|
|
|
67
67
|
Thresholds must be non-negative safe integers. Authorities without `operator` metadata can satisfy a threshold of one, but never add to the count of named operators. Thresholds above one require that many distinct, explicitly named operators.
|
|
68
68
|
|
|
69
|
-
When `isDigestOnly` is `true`, supply exactly 32 bytes containing the artifact's SHA-256 digest
|
|
69
|
+
When `isDigestOnly` is `true`, supply exactly 32 bytes containing the artifact's SHA-256 digest and construct the verifier with `verifyDigest: verifySignatureOverDigest` from `@freedomofpress/crypto-browser/noble`. Verifiers that always have the artifact can leave it out, and their bundles do not carry `@noble/curves`.
|
|
70
70
|
|
|
71
71
|
## What Gets Verified
|
|
72
72
|
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createHash, webcrypto } from "node:crypto";
|
|
|
3
3
|
import { access, readFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { base64ToUint8Array, hexToUint8Array, Uint8ArrayToHex, Uint8ArrayToString, } from "@freedomofpress/crypto-browser";
|
|
6
|
+
import { verifySignatureOverDigest } from "@freedomofpress/crypto-browser/noble";
|
|
6
7
|
import { SigstoreVerifier } from "./sigstore.js";
|
|
7
8
|
import { TrustedRootProvider } from "./trust/tuf.js";
|
|
8
9
|
// Ensure the global Web Crypto implementation is available when running under Node.js
|
|
@@ -150,7 +151,8 @@ async function verifyBundle(options) {
|
|
|
150
151
|
loadBundle(options.bundlePath),
|
|
151
152
|
resolveArtifact(options.artifactInput),
|
|
152
153
|
]);
|
|
153
|
-
|
|
154
|
+
// The conformance suite may hand us only a digest.
|
|
155
|
+
const verifier = new SigstoreVerifier({ verifyDigest: verifySignatureOverDigest });
|
|
154
156
|
await verifier.loadSigstoreRoot(trustedRoot);
|
|
155
157
|
// Extract and verify the artifact digest from the bundle
|
|
156
158
|
let bundleDigestHex;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { createHash, webcrypto } from \"node:crypto\";\nimport { access, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n base64ToUint8Array,\n hexToUint8Array,\n Uint8ArrayToHex,\n Uint8ArrayToString,\n} from \"@freedomofpress/crypto-browser\";\n\nimport { SigstoreBundle } from \"./bundle.js\";\nimport { TrustedRoot } from \"./interfaces.js\";\nimport { SigstoreVerifier } from \"./sigstore.js\";\nimport { TrustedRootProvider } from \"./trust/tuf.js\";\n\n// Ensure the global Web Crypto implementation is available when running under Node.js\nif (typeof globalThis.crypto === \"undefined\") {\n globalThis.crypto = webcrypto as unknown as Crypto;\n}\n\ninterface CLIOptions {\n bundlePath: string;\n certificateIdentity: string;\n certificateOidcIssuer: string;\n trustedRootPath: string | undefined;\n artifactInput: string;\n}\n\ntype ArtifactInput =\n | { type: \"file\"; path: string; data: Uint8Array; digestHex: string }\n | { type: \"digest\"; digestHex: string };\n\nconst USAGE = `Usage: sigstore-browser verify-bundle [--staging] --bundle FILE --certificate-identity IDENTITY --certificate-oidc-issuer URL [--trusted-root FILE] FILE_OR_DIGEST`;\n\nfunction printUsage(): void {\n console.error(USAGE);\n}\n\nfunction parseArgs(argv: string[]): CLIOptions {\n const options: Partial<CLIOptions> = {};\n let command: string | undefined;\n let artifactInput: string | undefined;\n\n for (let i = 0; i < argv.length; i++) {\n const current = argv[i];\n\n if (current === \"--help\" || current === \"-h\") {\n printUsage();\n process.exit(0);\n }\n\n if (current.startsWith(\"--\")) {\n const [name, providedValue] = current.split(\"=\", 2);\n\n switch (name) {\n case \"--bundle\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --bundle\");\n }\n options.bundlePath = value;\n break;\n }\n case \"--certificate-identity\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --certificate-identity\");\n }\n options.certificateIdentity = value;\n break;\n }\n case \"--certificate-oidc-issuer\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --certificate-oidc-issuer\");\n }\n options.certificateOidcIssuer = value;\n break;\n }\n case \"--trusted-root\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --trusted-root\");\n }\n options.trustedRootPath = value;\n break;\n }\n default:\n throw new Error(`Unknown option: ${name}`);\n }\n\n continue;\n }\n\n if (!command) {\n command = current;\n continue;\n }\n\n if (!artifactInput) {\n artifactInput = current;\n continue;\n }\n\n throw new Error(`Unexpected argument: ${current}`);\n }\n\n if (command !== \"verify-bundle\") {\n throw new Error(\"No command provided. Expected 'verify-bundle'.\");\n }\n\n if (!artifactInput) {\n throw new Error(\"Missing FILE_OR_DIGEST argument.\");\n }\n\n if (!options.bundlePath) {\n throw new Error(\"Missing required option --bundle\");\n }\n\n if (!options.certificateIdentity) {\n throw new Error(\"Missing required option --certificate-identity\");\n }\n\n if (!options.certificateOidcIssuer) {\n throw new Error(\"Missing required option --certificate-oidc-issuer\");\n }\n\n return {\n bundlePath: options.bundlePath,\n certificateIdentity: options.certificateIdentity,\n certificateOidcIssuer: options.certificateOidcIssuer,\n trustedRootPath: options.trustedRootPath,\n artifactInput,\n };\n}\n\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveArtifact(input: string): Promise<ArtifactInput> {\n const digestPrefix = \"sha256:\";\n\n if (\n input.startsWith(digestPrefix) &&\n input.length === digestPrefix.length + 64 &&\n /^[0-9a-fA-F]+$/.test(input.slice(digestPrefix.length)) &&\n !(await fileExists(input))\n ) {\n return {\n type: \"digest\",\n digestHex: input.slice(digestPrefix.length).toLowerCase(),\n };\n }\n\n const resolvedPath = path.resolve(input);\n const artifactBuffer = await readFile(resolvedPath);\n const digestHex = createHash(\"sha256\").update(artifactBuffer).digest(\"hex\");\n\n return {\n type: \"file\",\n path: resolvedPath,\n data: new Uint8Array(artifactBuffer),\n digestHex,\n };\n}\n\nasync function loadTrustedRoot(\n pathInput: string | undefined,\n): Promise<TrustedRoot> {\n if (!pathInput) {\n // Use TUF to fetch the latest trusted root (matches sigstore-js behavior)\n const tufProvider = new TrustedRootProvider({\n metadataUrl: \"https://tuf-repo-cdn.sigstore.dev/\",\n targetBaseUrl: \"https://tuf-repo-cdn.sigstore.dev/targets/\",\n });\n return await tufProvider.getTrustedRoot();\n }\n const resolvedPath = path.resolve(pathInput);\n const raw = await readFile(resolvedPath, \"utf8\");\n return JSON.parse(raw) as TrustedRoot;\n}\n\nasync function loadBundle(bundlePath: string): Promise<SigstoreBundle> {\n const resolved = path.resolve(bundlePath);\n const raw = await readFile(resolved, \"utf8\");\n return JSON.parse(raw) as SigstoreBundle;\n}\n\nasync function verifyBundle(options: CLIOptions): Promise<void> {\n const [trustedRoot, bundle, artifact] = await Promise.all([\n loadTrustedRoot(options.trustedRootPath),\n loadBundle(options.bundlePath),\n resolveArtifact(options.artifactInput),\n ]);\n\n const verifier = new SigstoreVerifier();\n await verifier.loadSigstoreRoot(trustedRoot);\n\n // Extract and verify the artifact digest from the bundle\n let bundleDigestHex: string;\n let bundleDigestBytes: Uint8Array;\n\n if (bundle.messageSignature) {\n // Regular bundle: digest is in messageSignature\n if (bundle.messageSignature.messageDigest.algorithm !== \"SHA2_256\") {\n throw new Error(\n `Unsupported message digest algorithm: ${bundle.messageSignature.messageDigest.algorithm}`,\n );\n }\n\n bundleDigestBytes = base64ToUint8Array(\n bundle.messageSignature.messageDigest.digest,\n );\n bundleDigestHex = Uint8ArrayToHex(bundleDigestBytes).toLowerCase();\n } else if (bundle.dsseEnvelope) {\n // DSSE bundle: digest is in the in-toto statement payload\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const payload = JSON.parse(Uint8ArrayToString(payloadBytes));\n\n if (!payload.subject || payload.subject.length === 0) {\n throw new Error(\"DSSE payload has no subject\");\n }\n\n // Find matching subject by comparing artifact digest with all subjects\n let matchedSubject = null;\n for (const subject of payload.subject) {\n const subjectDigest = subject.digest?.[\"sha256\"];\n if (subjectDigest && artifact.digestHex === subjectDigest.toLowerCase()) {\n matchedSubject = subject;\n break;\n }\n }\n\n if (!matchedSubject) {\n throw new Error(\n `Artifact digest ${artifact.digestHex} does not match any subject in DSSE payload`\n );\n }\n\n bundleDigestHex = matchedSubject.digest[\"sha256\"].toLowerCase();\n\n // Convert hex digest to bytes for verification target\n bundleDigestBytes = hexToUint8Array(bundleDigestHex);\n } else {\n throw new Error(\"Bundle does not contain a message signature or DSSE envelope\");\n }\n\n // For non-DSSE bundles, verify the digest matches\n if (bundle.messageSignature && artifact.digestHex !== bundleDigestHex) {\n throw new Error(\n \"Artifact digest does not match the digest embedded in the bundle.\",\n );\n }\n\n const verificationTarget =\n artifact.type === \"file\" ? artifact.data : bundleDigestBytes;\n const isDigestOnly = artifact.type === \"digest\";\n\n await verifier.verifyArtifact(\n options.certificateIdentity,\n options.certificateOidcIssuer,\n bundle,\n verificationTarget,\n isDigestOnly,\n );\n}\n\nasync function main(): Promise<void> {\n try {\n const options = parseArgs(process.argv.slice(2));\n await verifyBundle(options);\n console.log(\"Bundle verification succeeded.\");\n } catch (error) {\n if (error instanceof Error) {\n console.error(error.message);\n } else {\n console.error(error);\n }\n process.exitCode = 1;\n }\n}\n\nawait main();\n"]}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAIjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,sFAAsF;AACtF,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;IAC7C,UAAU,CAAC,MAAM,GAAG,SAA8B,CAAC;AACrD,CAAC;AAcD,MAAM,KAAK,GAAG,oKAAoK,CAAC;AAEnL,SAAS,UAAU;IACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,IAAI,OAA2B,CAAC;IAChC,IAAI,aAAiC,CAAC;IAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAExB,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YAC7C,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAEpD,QAAQ,IAAI,EAAE,CAAC;gBACb,KAAK,UAAU,CAAC,CAAC,CAAC;oBAChB,MAAM,KAAK,GAAG,aAAa,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzC,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;oBAChD,CAAC;oBACD,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC;oBAC3B,MAAM;gBACR,CAAC;gBACD,KAAK,wBAAwB,CAAC,CAAC,CAAC;oBAC9B,MAAM,KAAK,GAAG,aAAa,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzC,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;oBAC9D,CAAC;oBACD,OAAO,CAAC,mBAAmB,GAAG,KAAK,CAAC;oBACpC,MAAM;gBACR,CAAC;gBACD,KAAK,2BAA2B,CAAC,CAAC,CAAC;oBACjC,MAAM,KAAK,GAAG,aAAa,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzC,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;oBACjE,CAAC;oBACD,OAAO,CAAC,qBAAqB,GAAG,KAAK,CAAC;oBACtC,MAAM;gBACR,CAAC;gBACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;oBACtB,MAAM,KAAK,GAAG,aAAa,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzC,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;oBACtD,CAAC;oBACD,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC;oBAChC,MAAM;gBACR,CAAC;gBACD;oBACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;YAC/C,CAAC;YAED,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,OAAO,CAAC;YAClB,SAAS;QACX,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,aAAa,GAAG,OAAO,CAAC;YACxB,SAAS;QACX,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,OAAO,KAAK,eAAe,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;QAChD,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;QACpD,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,aAAa;KACd,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,KAAa;IAC1C,MAAM,YAAY,GAAG,SAAS,CAAC;IAE/B,IACE,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC;QAC9B,KAAK,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM,GAAG,EAAE;QACzC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACvD,CAAC,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC,EAC1B,CAAC;QACD,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;SAC1D,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE5E,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,IAAI,UAAU,CAAC,cAAc,CAAC;QACpC,SAAS;KACV,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,SAA6B;IAE7B,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,0EAA0E;QAC1E,MAAM,WAAW,GAAG,IAAI,mBAAmB,CAAC;YAC1C,WAAW,EAAE,oCAAoC;YACjD,aAAa,EAAE,4CAA4C;SAC5D,CAAC,CAAC;QACH,OAAO,MAAM,WAAW,CAAC,cAAc,EAAE,CAAC;IAC5C,CAAC;IACD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,UAAkB;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,OAAmB;IAC7C,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACxD,eAAe,CAAC,OAAO,CAAC,eAAe,CAAC;QACxC,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC;QAC9B,eAAe,CAAC,OAAO,CAAC,aAAa,CAAC;KACvC,CAAC,CAAC;IAEH,mDAAmD;IACnD,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,EAAE,YAAY,EAAE,yBAAyB,EAAE,CAAC,CAAC;IACnF,MAAM,QAAQ,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAE7C,yDAAyD;IACzD,IAAI,eAAuB,CAAC;IAC5B,IAAI,iBAA6B,CAAC;IAElC,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC5B,gDAAgD;QAChD,IAAI,MAAM,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CACb,yCAAyC,MAAM,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,EAAE,CAC3F,CAAC;QACJ,CAAC;QAED,iBAAiB,GAAG,kBAAkB,CACpC,MAAM,CAAC,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAC7C,CAAC;QACF,eAAe,GAAG,eAAe,CAAC,iBAAiB,CAAC,CAAC,WAAW,EAAE,CAAC;IACrE,CAAC;SAAM,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QAC/B,0DAA0D;QAC1D,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC;QAE7D,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QAED,uEAAuE;QACvE,IAAI,cAAc,GAAG,IAAI,CAAC;QAC1B,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACtC,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,aAAa,IAAI,QAAQ,CAAC,SAAS,KAAK,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxE,cAAc,GAAG,OAAO,CAAC;gBACzB,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,mBAAmB,QAAQ,CAAC,SAAS,6CAA6C,CACnF,CAAC;QACJ,CAAC;QAED,eAAe,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAEhE,sDAAsD;QACtD,iBAAiB,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,kDAAkD;IAClD,IAAI,MAAM,CAAC,gBAAgB,IAAI,QAAQ,CAAC,SAAS,KAAK,eAAe,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CACb,mEAAmE,CACpE,CAAC;IACJ,CAAC;IAED,MAAM,kBAAkB,GACtB,QAAQ,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAC/D,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC;IAEhD,MAAM,QAAQ,CAAC,cAAc,CAC3B,OAAO,CAAC,mBAAmB,EAC3B,OAAO,CAAC,qBAAqB,EAC7B,MAAM,EACN,kBAAkB,EAClB,YAAY,CACb,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,IAAI,EAAE,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { createHash, webcrypto } from \"node:crypto\";\nimport { access, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n base64ToUint8Array,\n hexToUint8Array,\n Uint8ArrayToHex,\n Uint8ArrayToString,\n} from \"@freedomofpress/crypto-browser\";\nimport { verifySignatureOverDigest } from \"@freedomofpress/crypto-browser/noble\";\n\nimport { SigstoreBundle } from \"./bundle.js\";\nimport { TrustedRoot } from \"./interfaces.js\";\nimport { SigstoreVerifier } from \"./sigstore.js\";\nimport { TrustedRootProvider } from \"./trust/tuf.js\";\n\n// Ensure the global Web Crypto implementation is available when running under Node.js\nif (typeof globalThis.crypto === \"undefined\") {\n globalThis.crypto = webcrypto as unknown as Crypto;\n}\n\ninterface CLIOptions {\n bundlePath: string;\n certificateIdentity: string;\n certificateOidcIssuer: string;\n trustedRootPath: string | undefined;\n artifactInput: string;\n}\n\ntype ArtifactInput =\n | { type: \"file\"; path: string; data: Uint8Array; digestHex: string }\n | { type: \"digest\"; digestHex: string };\n\nconst USAGE = `Usage: sigstore-browser verify-bundle [--staging] --bundle FILE --certificate-identity IDENTITY --certificate-oidc-issuer URL [--trusted-root FILE] FILE_OR_DIGEST`;\n\nfunction printUsage(): void {\n console.error(USAGE);\n}\n\nfunction parseArgs(argv: string[]): CLIOptions {\n const options: Partial<CLIOptions> = {};\n let command: string | undefined;\n let artifactInput: string | undefined;\n\n for (let i = 0; i < argv.length; i++) {\n const current = argv[i];\n\n if (current === \"--help\" || current === \"-h\") {\n printUsage();\n process.exit(0);\n }\n\n if (current.startsWith(\"--\")) {\n const [name, providedValue] = current.split(\"=\", 2);\n\n switch (name) {\n case \"--bundle\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --bundle\");\n }\n options.bundlePath = value;\n break;\n }\n case \"--certificate-identity\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --certificate-identity\");\n }\n options.certificateIdentity = value;\n break;\n }\n case \"--certificate-oidc-issuer\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --certificate-oidc-issuer\");\n }\n options.certificateOidcIssuer = value;\n break;\n }\n case \"--trusted-root\": {\n const value = providedValue ?? argv[++i];\n if (!value) {\n throw new Error(\"Missing value for --trusted-root\");\n }\n options.trustedRootPath = value;\n break;\n }\n default:\n throw new Error(`Unknown option: ${name}`);\n }\n\n continue;\n }\n\n if (!command) {\n command = current;\n continue;\n }\n\n if (!artifactInput) {\n artifactInput = current;\n continue;\n }\n\n throw new Error(`Unexpected argument: ${current}`);\n }\n\n if (command !== \"verify-bundle\") {\n throw new Error(\"No command provided. Expected 'verify-bundle'.\");\n }\n\n if (!artifactInput) {\n throw new Error(\"Missing FILE_OR_DIGEST argument.\");\n }\n\n if (!options.bundlePath) {\n throw new Error(\"Missing required option --bundle\");\n }\n\n if (!options.certificateIdentity) {\n throw new Error(\"Missing required option --certificate-identity\");\n }\n\n if (!options.certificateOidcIssuer) {\n throw new Error(\"Missing required option --certificate-oidc-issuer\");\n }\n\n return {\n bundlePath: options.bundlePath,\n certificateIdentity: options.certificateIdentity,\n certificateOidcIssuer: options.certificateOidcIssuer,\n trustedRootPath: options.trustedRootPath,\n artifactInput,\n };\n}\n\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveArtifact(input: string): Promise<ArtifactInput> {\n const digestPrefix = \"sha256:\";\n\n if (\n input.startsWith(digestPrefix) &&\n input.length === digestPrefix.length + 64 &&\n /^[0-9a-fA-F]+$/.test(input.slice(digestPrefix.length)) &&\n !(await fileExists(input))\n ) {\n return {\n type: \"digest\",\n digestHex: input.slice(digestPrefix.length).toLowerCase(),\n };\n }\n\n const resolvedPath = path.resolve(input);\n const artifactBuffer = await readFile(resolvedPath);\n const digestHex = createHash(\"sha256\").update(artifactBuffer).digest(\"hex\");\n\n return {\n type: \"file\",\n path: resolvedPath,\n data: new Uint8Array(artifactBuffer),\n digestHex,\n };\n}\n\nasync function loadTrustedRoot(\n pathInput: string | undefined,\n): Promise<TrustedRoot> {\n if (!pathInput) {\n // Use TUF to fetch the latest trusted root (matches sigstore-js behavior)\n const tufProvider = new TrustedRootProvider({\n metadataUrl: \"https://tuf-repo-cdn.sigstore.dev/\",\n targetBaseUrl: \"https://tuf-repo-cdn.sigstore.dev/targets/\",\n });\n return await tufProvider.getTrustedRoot();\n }\n const resolvedPath = path.resolve(pathInput);\n const raw = await readFile(resolvedPath, \"utf8\");\n return JSON.parse(raw) as TrustedRoot;\n}\n\nasync function loadBundle(bundlePath: string): Promise<SigstoreBundle> {\n const resolved = path.resolve(bundlePath);\n const raw = await readFile(resolved, \"utf8\");\n return JSON.parse(raw) as SigstoreBundle;\n}\n\nasync function verifyBundle(options: CLIOptions): Promise<void> {\n const [trustedRoot, bundle, artifact] = await Promise.all([\n loadTrustedRoot(options.trustedRootPath),\n loadBundle(options.bundlePath),\n resolveArtifact(options.artifactInput),\n ]);\n\n // The conformance suite may hand us only a digest.\n const verifier = new SigstoreVerifier({ verifyDigest: verifySignatureOverDigest });\n await verifier.loadSigstoreRoot(trustedRoot);\n\n // Extract and verify the artifact digest from the bundle\n let bundleDigestHex: string;\n let bundleDigestBytes: Uint8Array;\n\n if (bundle.messageSignature) {\n // Regular bundle: digest is in messageSignature\n if (bundle.messageSignature.messageDigest.algorithm !== \"SHA2_256\") {\n throw new Error(\n `Unsupported message digest algorithm: ${bundle.messageSignature.messageDigest.algorithm}`,\n );\n }\n\n bundleDigestBytes = base64ToUint8Array(\n bundle.messageSignature.messageDigest.digest,\n );\n bundleDigestHex = Uint8ArrayToHex(bundleDigestBytes).toLowerCase();\n } else if (bundle.dsseEnvelope) {\n // DSSE bundle: digest is in the in-toto statement payload\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const payload = JSON.parse(Uint8ArrayToString(payloadBytes));\n\n if (!payload.subject || payload.subject.length === 0) {\n throw new Error(\"DSSE payload has no subject\");\n }\n\n // Find matching subject by comparing artifact digest with all subjects\n let matchedSubject = null;\n for (const subject of payload.subject) {\n const subjectDigest = subject.digest?.[\"sha256\"];\n if (subjectDigest && artifact.digestHex === subjectDigest.toLowerCase()) {\n matchedSubject = subject;\n break;\n }\n }\n\n if (!matchedSubject) {\n throw new Error(\n `Artifact digest ${artifact.digestHex} does not match any subject in DSSE payload`\n );\n }\n\n bundleDigestHex = matchedSubject.digest[\"sha256\"].toLowerCase();\n\n // Convert hex digest to bytes for verification target\n bundleDigestBytes = hexToUint8Array(bundleDigestHex);\n } else {\n throw new Error(\"Bundle does not contain a message signature or DSSE envelope\");\n }\n\n // For non-DSSE bundles, verify the digest matches\n if (bundle.messageSignature && artifact.digestHex !== bundleDigestHex) {\n throw new Error(\n \"Artifact digest does not match the digest embedded in the bundle.\",\n );\n }\n\n const verificationTarget =\n artifact.type === \"file\" ? artifact.data : bundleDigestBytes;\n const isDigestOnly = artifact.type === \"digest\";\n\n await verifier.verifyArtifact(\n options.certificateIdentity,\n options.certificateOidcIssuer,\n bundle,\n verificationTarget,\n isDigestOnly,\n );\n}\n\nasync function main(): Promise<void> {\n try {\n const options = parseArgs(process.argv.slice(2));\n await verifyBundle(options);\n console.log(\"Bundle verification succeeded.\");\n } catch (error) {\n if (error instanceof Error) {\n console.error(error.message);\n } else {\n console.error(error);\n }\n process.exitCode = 1;\n }\n}\n\nawait main();\n"]}
|
package/dist/sigstore.d.ts
CHANGED
|
@@ -7,11 +7,13 @@ export interface SigstoreVerifierOptions {
|
|
|
7
7
|
tlogThreshold?: number;
|
|
8
8
|
ctlogThreshold?: number;
|
|
9
9
|
tsaThreshold?: number;
|
|
10
|
+
verifyDigest?: (key: CryptoKey, digest: Uint8Array, signature: Uint8Array) => Promise<boolean>;
|
|
10
11
|
}
|
|
11
12
|
export declare class SigstoreVerifier {
|
|
12
13
|
private root;
|
|
13
14
|
private rawRoot;
|
|
14
15
|
private options;
|
|
16
|
+
private verifyDigest;
|
|
15
17
|
constructor(options?: SigstoreVerifierOptions);
|
|
16
18
|
loadLog(logs: RawLogs): Promise<RekorKeyInfo[]>;
|
|
17
19
|
loadCTLogs(ctlogs: RawLogs): Promise<CTLog[]>;
|
package/dist/sigstore.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { base64ToUint8Array, ByteStream, canonicalizeJCS, importKey, sha256, stringToUint8Array, uint8ArrayEqual, Uint8ArrayToHex, Uint8ArrayToString, verifySignature
|
|
1
|
+
import { base64ToUint8Array, ByteStream, canonicalizeJCS, importKey, sha256, stringToUint8Array, uint8ArrayEqual, Uint8ArrayToHex, Uint8ArrayToString, verifySignature } from "@freedomofpress/crypto-browser";
|
|
2
2
|
import { assertBundle } from "./bundle.js";
|
|
3
3
|
import { preAuthEncoding } from "./dsse.js";
|
|
4
4
|
import { parseValidityPeriod, SigstoreRoots, } from "./interfaces.js";
|
|
@@ -48,6 +48,7 @@ export class SigstoreVerifier {
|
|
|
48
48
|
constructor(options = {}) {
|
|
49
49
|
this.root = undefined;
|
|
50
50
|
this.rawRoot = undefined;
|
|
51
|
+
this.verifyDigest = options.verifyDigest;
|
|
51
52
|
this.options = {
|
|
52
53
|
tlogThreshold: options.tlogThreshold ?? 1,
|
|
53
54
|
ctlogThreshold: options.ctlogThreshold ?? 1,
|
|
@@ -375,9 +376,10 @@ export class SigstoreVerifier {
|
|
|
375
376
|
}
|
|
376
377
|
const publicKey = await signingCert.publicKeyObj;
|
|
377
378
|
if (isDigestOnly) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
379
|
+
if (!this.verifyDigest) {
|
|
380
|
+
throw new Error("Digest-only verification needs the verifyDigest option");
|
|
381
|
+
}
|
|
382
|
+
const verified = await this.verifyDigest(publicKey, data, signature);
|
|
381
383
|
if (!verified) {
|
|
382
384
|
throw new Error("Error verifying signature over digest");
|
|
383
385
|
}
|
package/dist/sigstore.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sigstore.js","sourceRoot":"","sources":["../src/sigstore.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToUint8Array, ByteStream, canonicalizeJCS, importKey, sha256, stringToUint8Array, uint8ArrayEqual, Uint8ArrayToHex, Uint8ArrayToString, verifySignature, verifySignatureOverDigest } from \"@freedomofpress/crypto-browser\";\n\nimport { assertBundle, SigstoreBundle, TLogEntry } from \"./bundle.js\";\nimport { preAuthEncoding } from \"./dsse.js\";\nimport {\n CertAuthority,\n CTLog,\n parseValidityPeriod,\n RawCAs,\n RawLogs,\n RekorKeyInfo,\n Sigstore,\n SigstoreRoots,\n TrustedRoot,\n} from \"./interfaces.js\";\nimport type { VerificationPolicy } from \"./policy.js\";\nimport { AllOf, AnyOf, Identity, OIDCIssuer, OIDCIssuerV2 } from \"./policy.js\";\nimport { verifyBundleTimestamp } from \"./timestamp/tsa.js\";\nimport { verifyTLogBody } from \"./tlog/body.js\";\nimport { verifyCheckpoint } from \"./tlog/checkpoint.js\";\nimport { verifyMerkleInclusion } from \"./tlog/merkle.js\";\nimport { TrustedRootProvider } from \"./trust/tuf.js\";\nimport {\n CertificateChainVerifier,\n EXTENSION_OID_SCT,\n X509Certificate,\n X509SCTExtension,\n} from \"./x509/index.js\";\n\nconst MEDIA_TYPE_BASE = \"application/vnd.dev.sigstore.bundle\";\n// Upper bounds on in-toto subjects and digests, matching sigstore-go.\nconst MAX_SUBJECTS = 1024;\nconst MAX_SUBJECT_DIGESTS = 32;\n\n// Unknown operators can satisfy threshold one, but add no independence to named operators.\nfunction countOperators(operators: Set<string>): number {\n if (operators.size === 0) return 0;\n return Math.max(1, operators.size - (operators.has(\"\") ? 1 : 0));\n}\n\n/**\n * Extract bundle version from mediaType string\n * Reference: https://github.com/sigstore/sigstore-go/blob/main/pkg/bundle/bundle.go#L159-L177\n */\nfunction getBundleVersion(mediaType: string): string {\n switch (mediaType) {\n case `${MEDIA_TYPE_BASE}+json;version=0.1`:\n return \"0.1\";\n case `${MEDIA_TYPE_BASE}+json;version=0.2`:\n return \"0.2\";\n case `${MEDIA_TYPE_BASE}+json;version=0.3`:\n return \"0.3\";\n }\n\n // New format: \"application/vnd.dev.sigstore.bundle.v0.3+json\"\n if (mediaType.startsWith(`${MEDIA_TYPE_BASE}.v`) && mediaType.endsWith(\"+json\")) {\n const version = mediaType\n .replace(`${MEDIA_TYPE_BASE}.v`, \"\")\n .replace(\"+json\", \"\");\n // Only the versions this verifier implements are accepted.\n if (/^0\\.[123]$/.test(version)) {\n return version;\n }\n }\n\n throw new Error(`Unsupported bundle media type: ${mediaType}`);\n}\n\nexport interface SigstoreVerifierOptions {\n tlogThreshold?: number;\n ctlogThreshold?: number;\n tsaThreshold?: number;\n}\n\nexport class SigstoreVerifier {\n private root: Sigstore | undefined;\n private rawRoot: TrustedRoot | undefined;\n private options: Required<SigstoreVerifierOptions>;\n\n constructor(options: SigstoreVerifierOptions = {}) {\n this.root = undefined;\n this.rawRoot = undefined;\n this.options = {\n tlogThreshold: options.tlogThreshold ?? 1,\n ctlogThreshold: options.ctlogThreshold ?? 1,\n tsaThreshold: options.tsaThreshold ?? 0,\n };\n for (const [name, threshold] of Object.entries(this.options)) {\n if (!Number.isSafeInteger(threshold) || threshold < 0) {\n throw new Error(`${name} must be a non-negative safe integer`);\n }\n }\n }\n\n // Loads every Rekor key; entries select theirs by log ID and SETs are checked against its validity window.\n async loadLog(logs: RawLogs): Promise<RekorKeyInfo[]> {\n return Promise.all(\n logs.map(async (log) => ({\n publicKey: await importKey(\n log.publicKey.keyDetails,\n log.publicKey.keyDetails,\n log.publicKey.rawBytes,\n ),\n logId: base64ToUint8Array(log.logId.keyId),\n hashAlgorithm: log.hashAlgorithm,\n // Empty means unknown; countOperators never adds it to the named operator count.\n operator: log.operator || \"\",\n validFor: parseValidityPeriod(log.publicKey.validFor),\n })),\n );\n }\n\n // Loads every CT log; SCTs select their log by ID and are checked against its validity window.\n async loadCTLogs(ctlogs: RawLogs): Promise<CTLog[]> {\n if (ctlogs.length === 0) {\n throw new Error(\"Could not find any CT logs in sigstore root.\");\n }\n return Promise.all(\n ctlogs.map(async (log) => ({\n logID: base64ToUint8Array(log.logId.keyId),\n publicKey: await importKey(\n log.publicKey.keyDetails,\n log.publicKey.keyDetails,\n log.publicKey.rawBytes,\n ),\n operator: log.operator || \"\",\n validFor: parseValidityPeriod(log.publicKey.validFor),\n })),\n );\n }\n\n // Adapted from https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/key/certificate.ts#L22-L53\n // Verifies that the leaf certificate chains to a trusted CA and is valid at the given timestamp.\n // Differences from sigstore-js:\n // - This is async (uses await) because our CertificateChainVerifier.verify() is async\n // - sigstore-js filters CAs using filterCertAuthorities() before calling this function,\n // we do the timestamp filtering inline within this function\n async verifyCertificateChain(\n timestamp: Date,\n leaf: X509Certificate,\n certificateAuthorities: CertAuthority[]\n ): Promise<X509Certificate[]> {\n let lastError: unknown;\n\n for (const ca of certificateAuthorities) {\n // Check if this CA is valid for the given timestamp\n if (timestamp < ca.validFor.start || timestamp > ca.validFor.end) {\n continue;\n }\n\n try {\n const verifier = new CertificateChainVerifier({\n trustedCerts: ca.certChain,\n untrustedCert: leaf,\n timestamp,\n });\n return await verifier.verify();\n } catch (err) {\n lastError = err;\n }\n }\n\n throw new Error(`Failed to verify certificate chain: ${lastError instanceof Error ? lastError.message : 'No valid CAs found'}`);\n }\n\n // Loads every Fulcio CA; verifyCertificateChain() selects CAs by the observer timestamp.\n loadCA(cas: RawCAs): CertAuthority[] {\n return cas\n .filter((ca) => ca.certChain.certificates.length > 0)\n .map((ca) => ({\n certChain: ca.certChain.certificates.map((cert) =>\n X509Certificate.parse(base64ToUint8Array(cert.rawBytes)),\n ),\n validFor: parseValidityPeriod(ca.validFor),\n }));\n }\n\n async loadSigstoreRoot(rawRoot: TrustedRoot) {\n rawRoot.timestampAuthorities?.forEach((authority) =>\n parseValidityPeriod(authority.validFor),\n );\n const root = {\n rekor: await this.loadLog(rawRoot[SigstoreRoots.tlogs]),\n ctlogs: await this.loadCTLogs(rawRoot[SigstoreRoots.ctlogs]),\n certificateAuthorities: this.loadCA(rawRoot[SigstoreRoots.certificateAuthorities]),\n };\n this.rawRoot = rawRoot;\n this.root = root;\n }\n\n /**\n * Load Sigstore trusted root via TUF\n * Uses The Update Framework for secure, verified updates of trusted root metadata\n *\n * @param tufProvider Optional TrustedRootProvider instance. If not provided, uses default Sigstore TUF repository\n */\n async loadSigstoreRootWithTUF(tufProvider?: TrustedRootProvider): Promise<void> {\n const provider = tufProvider || new TrustedRootProvider();\n const trustedRoot = await provider.getTrustedRoot();\n await this.loadSigstoreRoot(trustedRoot);\n }\n\n // Adapted from https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/key/sct.ts\n // Key differences:\n // - Adds duplicate SCT detection (not in reference)\n // - Inline CT log filtering by logID and validity period (reference uses filterTLogAuthorities)\n // - Returns the distinct operators of the logs whose SCTs verified, for threshold checking\n async verifySCT(\n cert: X509Certificate,\n issuer: X509Certificate,\n ctlogs: CTLog[],\n ): Promise<Set<string>> {\n let extSCT: X509SCTExtension | undefined;\n\n // Verifying the SCT requires that we remove the SCT extension and\n // re-encode the TBS structure to DER -- this value is part of the data\n // over which the signature is calculated. Since this is a destructive action\n // we create a copy of the certificate so we can remove the SCT extension\n // without affecting the original certificate.\n const clone = cert.clone();\n\n // Intentionally not using the findExtension method here because we want to\n // remove the the SCT extension from the certificate before calculating the\n // PreCert structure\n for (let i = 0; i < clone.extensions.length; i++) {\n const ext = clone.extensions[i];\n\n if (ext.subs[0].toOID() === EXTENSION_OID_SCT) {\n extSCT = new X509SCTExtension(ext);\n\n // Remove the extension from the certificate\n clone.extensions.splice(i, 1);\n break;\n }\n }\n\n // No SCT extension found - fail verification\n if (!extSCT) {\n throw new Error(\"Certificate is missing required SCT extension\");\n }\n\n // Found an SCT extension but it has no SCTs - fail verification\n if (extSCT.signedCertificateTimestamps.length === 0) {\n throw new Error(\"SCT extension is present but contains no SCTs\");\n }\n\n // Check for duplicate SCTs (same log ID)\n const seenLogIds = new Set<string>();\n for (const sct of extSCT.signedCertificateTimestamps) {\n const logIdHex = Uint8ArrayToHex(sct.logID);\n if (seenLogIds.has(logIdHex)) {\n throw new Error(`Duplicate SCT found for log ID: ${logIdHex}`);\n }\n seenLogIds.add(logIdHex);\n }\n\n // Construct the PreCert structure\n // https://www.rfc-editor.org/rfc/rfc6962#section-3.2\n const preCert = new ByteStream();\n\n // Calculate hash of the issuer's public key\n const issuerId = await sha256(issuer.publicKey);\n preCert.appendView(issuerId);\n\n // Re-encodes the certificate to DER after removing the SCT extension\n const tbs = clone.tbsCertificate.toDER();\n preCert.appendUint24(tbs.length);\n preCert.appendView(tbs);\n\n // Calculate and return the verification results for each SCT\n // Unlike sigstore-go which counts verified SCTs and checks threshold at the end,\n // sigstore-js throws immediately if any SCT fails verification\n const operators = new Set<string>();\n\n for (const sct of extSCT.signedCertificateTimestamps) {\n // Find the CT log that matches this SCT's log ID and is valid for the SCT datetime\n const validCTLogs = ctlogs.filter((log) => {\n // Check if log IDs match\n if (!uint8ArrayEqual(log.logID, sct.logID)) return false;\n // Check that the SCT datetime is within the log's validity period\n return log.validFor.start <= sct.datetime && sct.datetime <= log.validFor.end;\n });\n\n // See if the SCT is valid for any of the CT logs\n const verified = await (async () => {\n for (const log of validCTLogs) {\n try {\n if (await sct.verify(preCert.buffer, log.publicKey)) {\n return log;\n }\n } catch {\n // Continue trying other logs\n }\n }\n return undefined;\n })();\n\n if (!verified) {\n throw new Error(\"SCT verification failed\");\n }\n\n operators.add(verified.operator);\n }\n\n return operators;\n }\n\n // Verifies the signed entry timestamp and returns the integrated time it binds.\n private async verifySET(entry: TLogEntry, promise: string, log: RekorKeyInfo): Promise<Date> {\n const integratedTime = Number(entry.integratedTime);\n const integratedDate = new Date(integratedTime * 1000);\n if (integratedDate < log.validFor.start || integratedDate > log.validFor.end) {\n throw new Error(\"Rekor key was not valid at the integrated time.\");\n }\n const signed = stringToUint8Array(\n canonicalizeJCS({\n body: entry.canonicalizedBody,\n integratedTime,\n logIndex: Number(entry.logIndex),\n logID: Uint8ArrayToHex(log.logId),\n }),\n );\n if (!(await verifySignature(log.publicKey, signed, base64ToUint8Array(promise), log.hashAlgorithm))) {\n throw new Error(\"Failed to verify the inclusion promise in the provided bundle.\");\n }\n return integratedDate;\n }\n\n // Fully verifies every entry from a trusted log and returns the SET-bound integrated times.\n // Entries from unknown logs are ignored; the threshold counts distinct log operators that verified.\n private async verifyTlogEntries(\n cert: X509Certificate,\n bundle: SigstoreBundle,\n rekor: RekorKeyInfo[],\n ): Promise<Date[]> {\n const entries = bundle.verificationMaterial.tlogEntries;\n // Only v0.1 bundles may rely on an inclusion promise alone.\n const requireProof = getBundleVersion(bundle.mediaType) !== \"0.1\";\n const operators = new Set<string>();\n const integratedTimes: Date[] = [];\n\n for (const entry of entries) {\n const logId = base64ToUint8Array(entry.logId.keyId);\n const log = rekor.find((l) => uint8ArrayEqual(l.logId, logId));\n if (!log) continue;\n\n const promise = entry.inclusionPromise?.signedEntryTimestamp;\n if (!entry.inclusionProof && (requireProof || !promise)) {\n throw new Error(\"Transparency log entry requires an inclusion proof.\");\n }\n if (promise) {\n integratedTimes.push(await this.verifySET(entry, promise, log));\n }\n if (entry.inclusionProof) {\n await verifyMerkleInclusion(entry);\n await verifyCheckpoint(entry, log);\n }\n if (entry.integratedTime && !cert.validForDate(new Date(Number(entry.integratedTime) * 1000))) {\n throw new Error(\"Artifact signing was logged outside of the certificate validity.\");\n }\n await verifyTLogBody(entry, bundle, cert);\n operators.add(log.operator);\n }\n\n const verifiedOperators = countOperators(operators);\n if (verifiedOperators < this.options.tlogThreshold) {\n throw new Error(`Not enough verified transparency logs: ${verifiedOperators} < ${this.options.tlogThreshold}`);\n }\n return integratedTimes;\n }\n\n // Shared checks: policy, transparency log, timestamps, chain at every observer time, SCTs.\n // Returns the signing certificate and the bundle's signature.\n private async verifyBundle(\n bundle: SigstoreBundle,\n policy: VerificationPolicy,\n ): Promise<{ signingCert: X509Certificate; signature: Uint8Array }> {\n assertBundle(bundle);\n if (!this.root || !this.rawRoot) {\n throw new Error(\"Sigstore root is undefined\");\n }\n\n const cert = bundle.verificationMaterial.certificate ||\n bundle.verificationMaterial.x509CertificateChain?.certificates[0];\n if (!cert) {\n throw new Error(\"No certificate found in bundle\");\n }\n const signingCert = X509Certificate.parse(base64ToUint8Array(cert.rawBytes));\n const signature = base64ToUint8Array(\n bundle.messageSignature ? bundle.messageSignature.signature : bundle.dsseEnvelope.signatures[0].sig,\n );\n\n await policy.verify(signingCert);\n\n // Observer timestamps come from SET-bound integrated times and verified RFC 3161 timestamps.\n // Rekor v2 entries carry no integrated time, so they need a TSA timestamp to be anchored at all.\n const integratedTimes = await this.verifyTlogEntries(signingCert, bundle, this.root.rekor);\n const timestamps = await verifyBundleTimestamp(\n bundle.verificationMaterial.timestampVerificationData,\n signature,\n this.rawRoot.timestampAuthorities || [],\n );\n const tsaOperators = countOperators(new Set(timestamps.map((t) => t.operator)));\n if (tsaOperators < this.options.tsaThreshold) {\n throw new Error(`Not enough verified TSA operators: ${tsaOperators} < ${this.options.tsaThreshold}`);\n }\n const observerTimes = [...integratedTimes, ...timestamps.map((t) => t.signingTime)];\n if (observerTimes.length === 0) {\n throw new Error(\"No verified observer timestamp anchors the signature in time.\");\n }\n\n // The CA window and the whole chain are checked at every observer time, never at the leaf's own notBefore.\n let certPath: X509Certificate[] = [];\n for (const ts of observerTimes) {\n certPath = await this.verifyCertificateChain(ts, signingCert, this.root.certificateAuthorities);\n }\n const issuerCert = certPath.length > 1 ? certPath[1] : certPath[0];\n const ctOperators = countOperators(await this.verifySCT(signingCert, issuerCert, this.root.ctlogs));\n if (ctOperators < this.options.ctlogThreshold) {\n throw new Error(`Not enough verified CT log operators: ${ctOperators} < ${this.options.ctlogThreshold}`);\n }\n\n return { signingCert, signature };\n }\n\n public async verifyArtifactPolicy(\n policy: VerificationPolicy,\n bundle: SigstoreBundle,\n data: Uint8Array,\n isDigestOnly: boolean = false,\n ): Promise<boolean> {\n if (isDigestOnly && data.byteLength !== 32) {\n throw new Error(\"SHA-256 digest must be exactly 32 bytes\");\n }\n const { signingCert, signature } = await this.verifyBundle(bundle, policy);\n\n // # 7 Revocation *skipping* not really a thing (unsurprisingly)\n\n // # 8 verify the signed data\n if (bundle.dsseEnvelope) {\n // Only in-toto statements are understood; other payload types must not be read as one.\n if (bundle.dsseEnvelope.payloadType !== \"application/vnd.in-toto+json\") {\n throw new Error(`Unsupported DSSE payload type: ${bundle.dsseEnvelope.payloadType}`);\n }\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const payload = JSON.parse(Uint8ArrayToString(payloadBytes));\n\n // Verify the artifact digest matches a subject in the in-toto statement\n if (!Array.isArray(payload?.subject) || payload.subject.length === 0 || payload.subject.length > MAX_SUBJECTS) {\n throw new Error(`DSSE payload must have between 1 and ${MAX_SUBJECTS} subjects`);\n }\n // Compute or extract the artifact digest\n let artifactDigest: string;\n if (isDigestOnly) {\n // data is already the digest bytes\n artifactDigest = Uint8ArrayToHex(data);\n } else {\n // data is the file content, compute the digest\n artifactDigest = Uint8ArrayToHex(await sha256(data));\n }\n\n // Every subject must carry a bounded digest map; any one of them may match the artifact.\n let matchedSubject = false;\n for (const subject of payload.subject) {\n const digests = subject?.digest;\n if (!digests || typeof digests !== \"object\" || Array.isArray(digests) || Object.keys(digests).length > MAX_SUBJECT_DIGESTS) {\n throw new Error(`Invalid DSSE subject digest map (maximum ${MAX_SUBJECT_DIGESTS} digests)`);\n }\n matchedSubject ||= typeof digests.sha256 === \"string\" && artifactDigest === digests.sha256.toLowerCase();\n }\n\n if (!matchedSubject) {\n throw new Error(\n `Artifact digest ${artifactDigest} does not match any subject in DSSE payload`\n );\n }\n\n // Create PAE (Pre-Authentication Encoding) for signature verification\n const pae = preAuthEncoding(bundle.dsseEnvelope.payloadType, payloadBytes);\n\n const publicKey = await signingCert.publicKeyObj;\n const verified = await verifySignature(publicKey, pae, signature);\n if (!verified) {\n throw new Error(\"DSSE signature verification failed\");\n }\n } else {\n // The bundle's message digest must be the digest of the artifact being verified.\n const { messageDigest } = bundle.messageSignature;\n const digest = isDigestOnly ? data : await sha256(data);\n if (messageDigest.algorithm !== \"SHA2_256\" || !uint8ArrayEqual(digest, base64ToUint8Array(messageDigest.digest))) {\n throw new Error(\"Artifact digest does not match the bundle message digest\");\n }\n const publicKey = await signingCert.publicKeyObj;\n\n if (isDigestOnly) {\n // For hashedrekord bundles, verify signature over the digest directly.\n // Uses the same elliptic.js workaround as sigstore-js conformance CLI.\n const verified = await verifySignatureOverDigest(publicKey, data, signature);\n if (!verified) {\n throw new Error(\"Error verifying signature over digest\");\n }\n } else {\n // For regular bundles, verify the signature over the artifact data\n const verified = await verifySignature(publicKey, data, signature);\n if (!verified) {\n const keyAlg = publicKey.algorithm.name || 'unknown';\n throw new Error(`Error verifying artifact signature. Key algorithm: ${keyAlg}, Data length: ${data.length}, Signature length: ${signature.length}`);\n }\n }\n }\n\n return true;\n }\n\npublic async verifyArtifact(\n identity: string,\n issuer: string,\n bundle: SigstoreBundle,\n data: Uint8Array,\n isDigestOnly: boolean = false,\n): Promise<boolean> {\n\n const policy = new AllOf([\n new Identity({ identity }),\n new AnyOf([\n new OIDCIssuerV2(issuer),\n new OIDCIssuer(issuer),\n ]),\n ]);\n\n return this.verifyArtifactPolicy(\n policy,\n bundle,\n data,\n isDigestOnly,\n );\n}\n\n \n\n /**\n * Verify a DSSE bundle using a verification policy.\n * This matches sigstore-python's verify_dsse API.\n *\n * Reference: https://github.com/sigstore/sigstore-python/blob/main/sigstore/verify/verifier.py#L388\n *\n * Unlike verify_artifact which verifies an artifact against a bundle,\n * this method verifies the DSSE envelope itself and returns the payload.\n * The caller is responsible for checking that the payload matches their\n * expected artifact (e.g., by checking subjects in an in-toto statement).\n *\n * @param bundle - The Sigstore bundle containing the DSSE envelope\n * @param policy - A verification policy to apply to the signing certificate\n * @returns The payload type and payload bytes from the verified envelope\n */\n public async verifyDsse(\n bundle: SigstoreBundle,\n policy: VerificationPolicy,\n ): Promise<{ payloadType: string; payload: Uint8Array }> {\n const { signingCert, signature } = await this.verifyBundle(bundle, policy);\n if (!bundle.dsseEnvelope) {\n throw new Error(\"Bundle does not contain a DSSE envelope\");\n }\n\n // (7) Verify the DSSE envelope signature\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const pae = preAuthEncoding(bundle.dsseEnvelope.payloadType, payloadBytes);\n\n const publicKey = await signingCert.publicKeyObj;\n const verified = await verifySignature(publicKey, pae, signature);\n if (!verified) {\n throw new Error(\"DSSE signature verification failed\");\n }\n\n // (8) Every entry MUST be of type \"dsse\" for DSSE verification\n for (const entry of bundle.verificationMaterial.tlogEntries) {\n if (entry.kindVersion.kind !== \"dsse\") {\n throw new Error(`Expected entry type dsse, got ${entry.kindVersion.kind}`);\n }\n }\n\n // Return the verified payload\n return {\n payloadType: bundle.dsseEnvelope.payloadType,\n payload: payloadBytes,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sigstore.js","sourceRoot":"","sources":["../src/sigstore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAE/M,OAAO,EAAE,YAAY,EAA6B,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAGL,mBAAmB,EAKnB,aAAa,GAEd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,eAAe,GAAG,qCAAqC,CAAC;AAC9D,sEAAsE;AACtE,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,2FAA2F;AAC3F,SAAS,cAAc,CAAC,SAAsB;IAC5C,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACnC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,SAAiB;IACzC,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,GAAG,eAAe,mBAAmB;YACxC,OAAO,KAAK,CAAC;QACf,KAAK,GAAG,eAAe,mBAAmB;YACxC,OAAO,KAAK,CAAC;QACf,KAAK,GAAG,eAAe,mBAAmB;YACxC,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,8DAA8D;IAC9D,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,eAAe,IAAI,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAChF,MAAM,OAAO,GAAG,SAAS;aACtB,OAAO,CAAC,GAAG,eAAe,IAAI,EAAE,EAAE,CAAC;aACnC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACxB,2DAA2D;QAC3D,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,kCAAkC,SAAS,EAAE,CAAC,CAAC;AACjE,CAAC;AAUD,MAAM,OAAO,gBAAgB;IAM3B,YAAY,UAAmC,EAAE;QAC/C,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG;YACb,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,CAAC;YACzC,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC;YAC3C,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,CAAC;SACxC,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;gBACtD,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,sCAAsC,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;IACH,CAAC;IAED,2GAA2G;IAC3G,KAAK,CAAC,OAAO,CAAC,IAAa;QACzB,OAAO,OAAO,CAAC,GAAG,CAChB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACvB,SAAS,EAAE,MAAM,SAAS,CACxB,GAAG,CAAC,SAAS,CAAC,UAAU,EACxB,GAAG,CAAC,SAAS,CAAC,UAAU,EACxB,GAAG,CAAC,SAAS,CAAC,QAAQ,CACvB;YACD,KAAK,EAAE,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;YAC1C,aAAa,EAAE,GAAG,CAAC,aAAa;YAChC,iFAAiF;YACjF,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,QAAQ,EAAE,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC;SACtD,CAAC,CAAC,CACJ,CAAC;IACJ,CAAC;IAED,+FAA+F;IAC/F,KAAK,CAAC,UAAU,CAAC,MAAe;QAC9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAChB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;YAC1C,SAAS,EAAE,MAAM,SAAS,CACxB,GAAG,CAAC,SAAS,CAAC,UAAU,EACxB,GAAG,CAAC,SAAS,CAAC,UAAU,EACxB,GAAG,CAAC,SAAS,CAAC,QAAQ,CACvB;YACD,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,QAAQ,EAAE,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC;SACtD,CAAC,CAAC,CACJ,CAAC;IACJ,CAAC;IAED,gHAAgH;IAChH,iGAAiG;IACjG,gCAAgC;IAChC,sFAAsF;IACtF,wFAAwF;IACxF,8DAA8D;IAC9D,KAAK,CAAC,sBAAsB,CAC1B,SAAe,EACf,IAAqB,EACrB,sBAAuC;QAEvC,IAAI,SAAkB,CAAC;QAEvB,KAAK,MAAM,EAAE,IAAI,sBAAsB,EAAE,CAAC;YACxC,oDAAoD;YACpD,IAAI,SAAS,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,IAAI,SAAS,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;gBACjE,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;oBAC5C,YAAY,EAAE,EAAE,CAAC,SAAS;oBAC1B,aAAa,EAAE,IAAI;oBACnB,SAAS;iBACV,CAAC,CAAC;gBACH,OAAO,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;YACjC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,SAAS,GAAG,GAAG,CAAC;YAClB,CAAC;QACH,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,uCAAuC,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAClI,CAAC;IAED,yFAAyF;IACzF,MAAM,CAAC,GAAW;QAChB,OAAO,GAAG;aACP,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;aACpD,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACZ,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAChD,eAAe,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CACzD;YACD,QAAQ,EAAE,mBAAmB,CAAC,EAAE,CAAC,QAAQ,CAAC;SAC3C,CAAC,CAAC,CAAC;IACR,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,OAAoB;QACzC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAClD,mBAAmB,CAAC,SAAS,CAAC,QAAQ,CAAC,CACxC,CAAC;QACF,MAAM,IAAI,GAAG;YACX,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACvD,MAAM,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAC5D,sBAAsB,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;SACnF,CAAC;QACF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,uBAAuB,CAAC,WAAiC;QAC7D,MAAM,QAAQ,GAAG,WAAW,IAAI,IAAI,mBAAmB,EAAE,CAAC;QAC1D,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,cAAc,EAAE,CAAC;QACpD,MAAM,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,gGAAgG;IAChG,mBAAmB;IACnB,oDAAoD;IACpD,gGAAgG;IAChG,2FAA2F;IAC3F,KAAK,CAAC,SAAS,CACb,IAAqB,EACrB,MAAuB,EACvB,MAAe;QAEf,IAAI,MAAoC,CAAC;QAEzC,kEAAkE;QAClE,uEAAuE;QACvE,6EAA6E;QAC7E,yEAAyE;QACzE,8CAA8C;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAE3B,2EAA2E;QAC3E,2EAA2E;QAC3E,oBAAoB;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAEhC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,iBAAiB,EAAE,CAAC;gBAC9C,MAAM,GAAG,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC;gBAEnC,4CAA4C;gBAC5C,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC9B,MAAM;YACR,CAAC;QACH,CAAC;QAED,6CAA6C;QAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,gEAAgE;QAChE,IAAI,MAAM,CAAC,2BAA2B,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,yCAAyC;QACzC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;QACrC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,2BAA2B,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;YACjE,CAAC;YACD,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;QAED,kCAAkC;QAClC,qDAAqD;QACrD,MAAM,OAAO,GAAG,IAAI,UAAU,EAAE,CAAC;QAEjC,4CAA4C;QAC5C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAE7B,qEAAqE;QACrE,MAAM,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QACzC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAExB,6DAA6D;QAC7D,iFAAiF;QACjF,+DAA+D;QAC/D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QAEpC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,2BAA2B,EAAE,CAAC;YACrD,mFAAmF;YACnF,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxC,yBAAyB;gBACzB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC;oBAAE,OAAO,KAAK,CAAC;gBACzD,kEAAkE;gBAClE,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAChF,CAAC,CAAC,CAAC;YAEH,iDAAiD;YACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE;gBACjC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;oBAC9B,IAAI,CAAC;wBACH,IAAI,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;4BACpD,OAAO,GAAG,CAAC;wBACb,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,6BAA6B;oBAC/B,CAAC;gBACH,CAAC;gBACD,OAAO,SAAS,CAAC;YACnB,CAAC,CAAC,EAAE,CAAC;YAEL,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC;YAED,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,gFAAgF;IACxE,KAAK,CAAC,SAAS,CAAC,KAAgB,EAAE,OAAe,EAAE,GAAiB;QAC1E,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACpD,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QACvD,IAAI,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,MAAM,GAAG,kBAAkB,CAC/B,eAAe,CAAC;YACd,IAAI,EAAE,KAAK,CAAC,iBAAiB;YAC7B,cAAc;YACd,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YAChC,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;SAClC,CAAC,CACH,CAAC;QACF,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;YACpG,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,4FAA4F;IAC5F,oGAAoG;IAC5F,KAAK,CAAC,iBAAiB,CAC7B,IAAqB,EACrB,MAAsB,EACtB,KAAqB;QAErB,MAAM,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAC,WAAW,CAAC;QACxD,4DAA4D;QAC5D,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,CAAC;QAClE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QACpC,MAAM,eAAe,GAAW,EAAE,CAAC;QAEnC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACpD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;YAC/D,IAAI,CAAC,GAAG;gBAAE,SAAS;YAEnB,MAAM,OAAO,GAAG,KAAK,CAAC,gBAAgB,EAAE,oBAAoB,CAAC;YAC7D,IAAI,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACzE,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,eAAe,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAClE,CAAC;YACD,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;gBACzB,MAAM,qBAAqB,CAAC,KAAK,CAAC,CAAC;gBACnC,MAAM,gBAAgB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACrC,CAAC;YACD,IAAI,KAAK,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC9F,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;YACtF,CAAC;YACD,MAAM,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YAC1C,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QAED,MAAM,iBAAiB,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,0CAA0C,iBAAiB,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;QACjH,CAAC;QACD,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,2FAA2F;IAC3F,8DAA8D;IACtD,KAAK,CAAC,YAAY,CACxB,MAAsB,EACtB,MAA0B;QAE1B,YAAY,CAAC,MAAM,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,oBAAoB,CAAC,WAAW;YAClD,MAAM,CAAC,oBAAoB,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7E,MAAM,SAAS,GAAG,kBAAkB,CAClC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CACpG,CAAC;QAEF,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEjC,6FAA6F;QAC7F,iGAAiG;QACjG,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3F,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAC5C,MAAM,CAAC,oBAAoB,CAAC,yBAAyB,EACrD,SAAS,EACT,IAAI,CAAC,OAAO,CAAC,oBAAoB,IAAI,EAAE,CACxC,CAAC;QACF,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAChF,IAAI,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,sCAAsC,YAAY,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;QACvG,CAAC;QACD,MAAM,aAAa,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;QACpF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACnF,CAAC;QAED,2GAA2G;QAC3G,IAAI,QAAQ,GAAsB,EAAE,CAAC;QACrC,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;YAC/B,QAAQ,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAClG,CAAC;QACD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnE,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACpG,IAAI,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,yCAAyC,WAAW,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;QAC3G,CAAC;QAED,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;IACpC,CAAC;IAEM,KAAK,CAAC,oBAAoB,CAC/B,MAA0B,EAC1B,MAAsB,EACtB,IAAgB,EAChB,eAAwB,KAAK;QAE7B,IAAI,YAAY,IAAI,IAAI,CAAC,UAAU,KAAK,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAE3E,gEAAgE;QAEhE,6BAA6B;QAC7B,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,uFAAuF;YACvF,IAAI,MAAM,CAAC,YAAY,CAAC,WAAW,KAAK,8BAA8B,EAAE,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;YACvF,CAAC;YACD,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YACrE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC;YAE7D,wEAAwE;YACxE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;gBAC9G,MAAM,IAAI,KAAK,CAAC,wCAAwC,YAAY,WAAW,CAAC,CAAC;YACnF,CAAC;YACD,yCAAyC;YACzC,IAAI,cAAsB,CAAC;YAC3B,IAAI,YAAY,EAAE,CAAC;gBACjB,mCAAmC;gBACnC,cAAc,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,+CAA+C;gBAC/C,cAAc,GAAG,eAAe,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACvD,CAAC;YAED,yFAAyF;YACzF,IAAI,cAAc,GAAG,KAAK,CAAC;YAC3B,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,OAAO,EAAE,MAAM,CAAC;gBAChC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;oBAC3H,MAAM,IAAI,KAAK,CAAC,4CAA4C,mBAAmB,WAAW,CAAC,CAAC;gBAC9F,CAAC;gBACD,cAAc,KAAd,cAAc,GAAK,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,EAAC;YAC3G,CAAC;YAED,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CACb,mBAAmB,cAAc,6CAA6C,CAC/E,CAAC;YACJ,CAAC;YAED,sEAAsE;YACtE,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;YAE3E,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;YACjD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,iFAAiF;YACjF,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC,gBAAgB,CAAC;YAClD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,aAAa,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,kBAAkB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBACjH,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;YAC9E,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;YAEjD,IAAI,YAAY,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;oBACvB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;gBAC5E,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;gBACrE,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,mEAAmE;gBACnE,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;gBACnE,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC;oBACrD,MAAM,IAAI,KAAK,CAAC,sDAAsD,MAAM,kBAAkB,IAAI,CAAC,MAAM,uBAAuB,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;gBACtJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAEI,KAAK,CAAC,cAAc,CACzB,QAAgB,EAChB,MAAc,EACd,MAAsB,EACtB,IAAgB,EAChB,eAAwB,KAAK;QAG7B,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC;YACvB,IAAI,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC;gBACR,IAAI,YAAY,CAAC,MAAM,CAAC;gBACxB,IAAI,UAAU,CAAC,MAAM,CAAC;aACvB,CAAC;SACH,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,oBAAoB,CAC9B,MAAM,EACN,MAAM,EACN,IAAI,EACJ,YAAY,CACb,CAAC;IACJ,CAAC;IAIC;;;;;;;;;;;;;;OAcG;IACI,KAAK,CAAC,UAAU,CACrB,MAAsB,EACtB,MAA0B;QAE1B,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QAED,yCAAyC;QACzC,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACrE,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAE3E,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;QACjD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,+DAA+D;QAC/D,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,CAAC;YAC5D,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACtC,MAAM,IAAI,KAAK,CAAC,iCAAiC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7E,CAAC;QACH,CAAC;QAED,8BAA8B;QAC9B,OAAO;YACL,WAAW,EAAE,MAAM,CAAC,YAAY,CAAC,WAAW;YAC5C,OAAO,EAAE,YAAY;SACtB,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { base64ToUint8Array, ByteStream, canonicalizeJCS, importKey, sha256, stringToUint8Array, uint8ArrayEqual, Uint8ArrayToHex, Uint8ArrayToString, verifySignature } from \"@freedomofpress/crypto-browser\";\n\nimport { assertBundle, SigstoreBundle, TLogEntry } from \"./bundle.js\";\nimport { preAuthEncoding } from \"./dsse.js\";\nimport {\n CertAuthority,\n CTLog,\n parseValidityPeriod,\n RawCAs,\n RawLogs,\n RekorKeyInfo,\n Sigstore,\n SigstoreRoots,\n TrustedRoot,\n} from \"./interfaces.js\";\nimport type { VerificationPolicy } from \"./policy.js\";\nimport { AllOf, AnyOf, Identity, OIDCIssuer, OIDCIssuerV2 } from \"./policy.js\";\nimport { verifyBundleTimestamp } from \"./timestamp/tsa.js\";\nimport { verifyTLogBody } from \"./tlog/body.js\";\nimport { verifyCheckpoint } from \"./tlog/checkpoint.js\";\nimport { verifyMerkleInclusion } from \"./tlog/merkle.js\";\nimport { TrustedRootProvider } from \"./trust/tuf.js\";\nimport {\n CertificateChainVerifier,\n EXTENSION_OID_SCT,\n X509Certificate,\n X509SCTExtension,\n} from \"./x509/index.js\";\n\nconst MEDIA_TYPE_BASE = \"application/vnd.dev.sigstore.bundle\";\n// Upper bounds on in-toto subjects and digests, matching sigstore-go.\nconst MAX_SUBJECTS = 1024;\nconst MAX_SUBJECT_DIGESTS = 32;\n\n// Unknown operators can satisfy threshold one, but add no independence to named operators.\nfunction countOperators(operators: Set<string>): number {\n if (operators.size === 0) return 0;\n return Math.max(1, operators.size - (operators.has(\"\") ? 1 : 0));\n}\n\n/**\n * Extract bundle version from mediaType string\n * Reference: https://github.com/sigstore/sigstore-go/blob/main/pkg/bundle/bundle.go#L159-L177\n */\nfunction getBundleVersion(mediaType: string): string {\n switch (mediaType) {\n case `${MEDIA_TYPE_BASE}+json;version=0.1`:\n return \"0.1\";\n case `${MEDIA_TYPE_BASE}+json;version=0.2`:\n return \"0.2\";\n case `${MEDIA_TYPE_BASE}+json;version=0.3`:\n return \"0.3\";\n }\n\n // New format: \"application/vnd.dev.sigstore.bundle.v0.3+json\"\n if (mediaType.startsWith(`${MEDIA_TYPE_BASE}.v`) && mediaType.endsWith(\"+json\")) {\n const version = mediaType\n .replace(`${MEDIA_TYPE_BASE}.v`, \"\")\n .replace(\"+json\", \"\");\n // Only the versions this verifier implements are accepted.\n if (/^0\\.[123]$/.test(version)) {\n return version;\n }\n }\n\n throw new Error(`Unsupported bundle media type: ${mediaType}`);\n}\n\nexport interface SigstoreVerifierOptions {\n tlogThreshold?: number;\n ctlogThreshold?: number;\n tsaThreshold?: number;\n // Needed only for digest-only verification: verifySignatureOverDigest from \"@freedomofpress/crypto-browser/noble\".\n verifyDigest?: (key: CryptoKey, digest: Uint8Array, signature: Uint8Array) => Promise<boolean>;\n}\n\nexport class SigstoreVerifier {\n private root: Sigstore | undefined;\n private rawRoot: TrustedRoot | undefined;\n private options: Required<Omit<SigstoreVerifierOptions, \"verifyDigest\">>;\n private verifyDigest: SigstoreVerifierOptions[\"verifyDigest\"];\n\n constructor(options: SigstoreVerifierOptions = {}) {\n this.root = undefined;\n this.rawRoot = undefined;\n this.verifyDigest = options.verifyDigest;\n this.options = {\n tlogThreshold: options.tlogThreshold ?? 1,\n ctlogThreshold: options.ctlogThreshold ?? 1,\n tsaThreshold: options.tsaThreshold ?? 0,\n };\n for (const [name, threshold] of Object.entries(this.options)) {\n if (!Number.isSafeInteger(threshold) || threshold < 0) {\n throw new Error(`${name} must be a non-negative safe integer`);\n }\n }\n }\n\n // Loads every Rekor key; entries select theirs by log ID and SETs are checked against its validity window.\n async loadLog(logs: RawLogs): Promise<RekorKeyInfo[]> {\n return Promise.all(\n logs.map(async (log) => ({\n publicKey: await importKey(\n log.publicKey.keyDetails,\n log.publicKey.keyDetails,\n log.publicKey.rawBytes,\n ),\n logId: base64ToUint8Array(log.logId.keyId),\n hashAlgorithm: log.hashAlgorithm,\n // Empty means unknown; countOperators never adds it to the named operator count.\n operator: log.operator || \"\",\n validFor: parseValidityPeriod(log.publicKey.validFor),\n })),\n );\n }\n\n // Loads every CT log; SCTs select their log by ID and are checked against its validity window.\n async loadCTLogs(ctlogs: RawLogs): Promise<CTLog[]> {\n if (ctlogs.length === 0) {\n throw new Error(\"Could not find any CT logs in sigstore root.\");\n }\n return Promise.all(\n ctlogs.map(async (log) => ({\n logID: base64ToUint8Array(log.logId.keyId),\n publicKey: await importKey(\n log.publicKey.keyDetails,\n log.publicKey.keyDetails,\n log.publicKey.rawBytes,\n ),\n operator: log.operator || \"\",\n validFor: parseValidityPeriod(log.publicKey.validFor),\n })),\n );\n }\n\n // Adapted from https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/key/certificate.ts#L22-L53\n // Verifies that the leaf certificate chains to a trusted CA and is valid at the given timestamp.\n // Differences from sigstore-js:\n // - This is async (uses await) because our CertificateChainVerifier.verify() is async\n // - sigstore-js filters CAs using filterCertAuthorities() before calling this function,\n // we do the timestamp filtering inline within this function\n async verifyCertificateChain(\n timestamp: Date,\n leaf: X509Certificate,\n certificateAuthorities: CertAuthority[]\n ): Promise<X509Certificate[]> {\n let lastError: unknown;\n\n for (const ca of certificateAuthorities) {\n // Check if this CA is valid for the given timestamp\n if (timestamp < ca.validFor.start || timestamp > ca.validFor.end) {\n continue;\n }\n\n try {\n const verifier = new CertificateChainVerifier({\n trustedCerts: ca.certChain,\n untrustedCert: leaf,\n timestamp,\n });\n return await verifier.verify();\n } catch (err) {\n lastError = err;\n }\n }\n\n throw new Error(`Failed to verify certificate chain: ${lastError instanceof Error ? lastError.message : 'No valid CAs found'}`);\n }\n\n // Loads every Fulcio CA; verifyCertificateChain() selects CAs by the observer timestamp.\n loadCA(cas: RawCAs): CertAuthority[] {\n return cas\n .filter((ca) => ca.certChain.certificates.length > 0)\n .map((ca) => ({\n certChain: ca.certChain.certificates.map((cert) =>\n X509Certificate.parse(base64ToUint8Array(cert.rawBytes)),\n ),\n validFor: parseValidityPeriod(ca.validFor),\n }));\n }\n\n async loadSigstoreRoot(rawRoot: TrustedRoot) {\n rawRoot.timestampAuthorities?.forEach((authority) =>\n parseValidityPeriod(authority.validFor),\n );\n const root = {\n rekor: await this.loadLog(rawRoot[SigstoreRoots.tlogs]),\n ctlogs: await this.loadCTLogs(rawRoot[SigstoreRoots.ctlogs]),\n certificateAuthorities: this.loadCA(rawRoot[SigstoreRoots.certificateAuthorities]),\n };\n this.rawRoot = rawRoot;\n this.root = root;\n }\n\n /**\n * Load Sigstore trusted root via TUF\n * Uses The Update Framework for secure, verified updates of trusted root metadata\n *\n * @param tufProvider Optional TrustedRootProvider instance. If not provided, uses default Sigstore TUF repository\n */\n async loadSigstoreRootWithTUF(tufProvider?: TrustedRootProvider): Promise<void> {\n const provider = tufProvider || new TrustedRootProvider();\n const trustedRoot = await provider.getTrustedRoot();\n await this.loadSigstoreRoot(trustedRoot);\n }\n\n // Adapted from https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/key/sct.ts\n // Key differences:\n // - Adds duplicate SCT detection (not in reference)\n // - Inline CT log filtering by logID and validity period (reference uses filterTLogAuthorities)\n // - Returns the distinct operators of the logs whose SCTs verified, for threshold checking\n async verifySCT(\n cert: X509Certificate,\n issuer: X509Certificate,\n ctlogs: CTLog[],\n ): Promise<Set<string>> {\n let extSCT: X509SCTExtension | undefined;\n\n // Verifying the SCT requires that we remove the SCT extension and\n // re-encode the TBS structure to DER -- this value is part of the data\n // over which the signature is calculated. Since this is a destructive action\n // we create a copy of the certificate so we can remove the SCT extension\n // without affecting the original certificate.\n const clone = cert.clone();\n\n // Intentionally not using the findExtension method here because we want to\n // remove the the SCT extension from the certificate before calculating the\n // PreCert structure\n for (let i = 0; i < clone.extensions.length; i++) {\n const ext = clone.extensions[i];\n\n if (ext.subs[0].toOID() === EXTENSION_OID_SCT) {\n extSCT = new X509SCTExtension(ext);\n\n // Remove the extension from the certificate\n clone.extensions.splice(i, 1);\n break;\n }\n }\n\n // No SCT extension found - fail verification\n if (!extSCT) {\n throw new Error(\"Certificate is missing required SCT extension\");\n }\n\n // Found an SCT extension but it has no SCTs - fail verification\n if (extSCT.signedCertificateTimestamps.length === 0) {\n throw new Error(\"SCT extension is present but contains no SCTs\");\n }\n\n // Check for duplicate SCTs (same log ID)\n const seenLogIds = new Set<string>();\n for (const sct of extSCT.signedCertificateTimestamps) {\n const logIdHex = Uint8ArrayToHex(sct.logID);\n if (seenLogIds.has(logIdHex)) {\n throw new Error(`Duplicate SCT found for log ID: ${logIdHex}`);\n }\n seenLogIds.add(logIdHex);\n }\n\n // Construct the PreCert structure\n // https://www.rfc-editor.org/rfc/rfc6962#section-3.2\n const preCert = new ByteStream();\n\n // Calculate hash of the issuer's public key\n const issuerId = await sha256(issuer.publicKey);\n preCert.appendView(issuerId);\n\n // Re-encodes the certificate to DER after removing the SCT extension\n const tbs = clone.tbsCertificate.toDER();\n preCert.appendUint24(tbs.length);\n preCert.appendView(tbs);\n\n // Calculate and return the verification results for each SCT\n // Unlike sigstore-go which counts verified SCTs and checks threshold at the end,\n // sigstore-js throws immediately if any SCT fails verification\n const operators = new Set<string>();\n\n for (const sct of extSCT.signedCertificateTimestamps) {\n // Find the CT log that matches this SCT's log ID and is valid for the SCT datetime\n const validCTLogs = ctlogs.filter((log) => {\n // Check if log IDs match\n if (!uint8ArrayEqual(log.logID, sct.logID)) return false;\n // Check that the SCT datetime is within the log's validity period\n return log.validFor.start <= sct.datetime && sct.datetime <= log.validFor.end;\n });\n\n // See if the SCT is valid for any of the CT logs\n const verified = await (async () => {\n for (const log of validCTLogs) {\n try {\n if (await sct.verify(preCert.buffer, log.publicKey)) {\n return log;\n }\n } catch {\n // Continue trying other logs\n }\n }\n return undefined;\n })();\n\n if (!verified) {\n throw new Error(\"SCT verification failed\");\n }\n\n operators.add(verified.operator);\n }\n\n return operators;\n }\n\n // Verifies the signed entry timestamp and returns the integrated time it binds.\n private async verifySET(entry: TLogEntry, promise: string, log: RekorKeyInfo): Promise<Date> {\n const integratedTime = Number(entry.integratedTime);\n const integratedDate = new Date(integratedTime * 1000);\n if (integratedDate < log.validFor.start || integratedDate > log.validFor.end) {\n throw new Error(\"Rekor key was not valid at the integrated time.\");\n }\n const signed = stringToUint8Array(\n canonicalizeJCS({\n body: entry.canonicalizedBody,\n integratedTime,\n logIndex: Number(entry.logIndex),\n logID: Uint8ArrayToHex(log.logId),\n }),\n );\n if (!(await verifySignature(log.publicKey, signed, base64ToUint8Array(promise), log.hashAlgorithm))) {\n throw new Error(\"Failed to verify the inclusion promise in the provided bundle.\");\n }\n return integratedDate;\n }\n\n // Fully verifies every entry from a trusted log and returns the SET-bound integrated times.\n // Entries from unknown logs are ignored; the threshold counts distinct log operators that verified.\n private async verifyTlogEntries(\n cert: X509Certificate,\n bundle: SigstoreBundle,\n rekor: RekorKeyInfo[],\n ): Promise<Date[]> {\n const entries = bundle.verificationMaterial.tlogEntries;\n // Only v0.1 bundles may rely on an inclusion promise alone.\n const requireProof = getBundleVersion(bundle.mediaType) !== \"0.1\";\n const operators = new Set<string>();\n const integratedTimes: Date[] = [];\n\n for (const entry of entries) {\n const logId = base64ToUint8Array(entry.logId.keyId);\n const log = rekor.find((l) => uint8ArrayEqual(l.logId, logId));\n if (!log) continue;\n\n const promise = entry.inclusionPromise?.signedEntryTimestamp;\n if (!entry.inclusionProof && (requireProof || !promise)) {\n throw new Error(\"Transparency log entry requires an inclusion proof.\");\n }\n if (promise) {\n integratedTimes.push(await this.verifySET(entry, promise, log));\n }\n if (entry.inclusionProof) {\n await verifyMerkleInclusion(entry);\n await verifyCheckpoint(entry, log);\n }\n if (entry.integratedTime && !cert.validForDate(new Date(Number(entry.integratedTime) * 1000))) {\n throw new Error(\"Artifact signing was logged outside of the certificate validity.\");\n }\n await verifyTLogBody(entry, bundle, cert);\n operators.add(log.operator);\n }\n\n const verifiedOperators = countOperators(operators);\n if (verifiedOperators < this.options.tlogThreshold) {\n throw new Error(`Not enough verified transparency logs: ${verifiedOperators} < ${this.options.tlogThreshold}`);\n }\n return integratedTimes;\n }\n\n // Shared checks: policy, transparency log, timestamps, chain at every observer time, SCTs.\n // Returns the signing certificate and the bundle's signature.\n private async verifyBundle(\n bundle: SigstoreBundle,\n policy: VerificationPolicy,\n ): Promise<{ signingCert: X509Certificate; signature: Uint8Array }> {\n assertBundle(bundle);\n if (!this.root || !this.rawRoot) {\n throw new Error(\"Sigstore root is undefined\");\n }\n\n const cert = bundle.verificationMaterial.certificate ||\n bundle.verificationMaterial.x509CertificateChain?.certificates[0];\n if (!cert) {\n throw new Error(\"No certificate found in bundle\");\n }\n const signingCert = X509Certificate.parse(base64ToUint8Array(cert.rawBytes));\n const signature = base64ToUint8Array(\n bundle.messageSignature ? bundle.messageSignature.signature : bundle.dsseEnvelope.signatures[0].sig,\n );\n\n await policy.verify(signingCert);\n\n // Observer timestamps come from SET-bound integrated times and verified RFC 3161 timestamps.\n // Rekor v2 entries carry no integrated time, so they need a TSA timestamp to be anchored at all.\n const integratedTimes = await this.verifyTlogEntries(signingCert, bundle, this.root.rekor);\n const timestamps = await verifyBundleTimestamp(\n bundle.verificationMaterial.timestampVerificationData,\n signature,\n this.rawRoot.timestampAuthorities || [],\n );\n const tsaOperators = countOperators(new Set(timestamps.map((t) => t.operator)));\n if (tsaOperators < this.options.tsaThreshold) {\n throw new Error(`Not enough verified TSA operators: ${tsaOperators} < ${this.options.tsaThreshold}`);\n }\n const observerTimes = [...integratedTimes, ...timestamps.map((t) => t.signingTime)];\n if (observerTimes.length === 0) {\n throw new Error(\"No verified observer timestamp anchors the signature in time.\");\n }\n\n // The CA window and the whole chain are checked at every observer time, never at the leaf's own notBefore.\n let certPath: X509Certificate[] = [];\n for (const ts of observerTimes) {\n certPath = await this.verifyCertificateChain(ts, signingCert, this.root.certificateAuthorities);\n }\n const issuerCert = certPath.length > 1 ? certPath[1] : certPath[0];\n const ctOperators = countOperators(await this.verifySCT(signingCert, issuerCert, this.root.ctlogs));\n if (ctOperators < this.options.ctlogThreshold) {\n throw new Error(`Not enough verified CT log operators: ${ctOperators} < ${this.options.ctlogThreshold}`);\n }\n\n return { signingCert, signature };\n }\n\n public async verifyArtifactPolicy(\n policy: VerificationPolicy,\n bundle: SigstoreBundle,\n data: Uint8Array,\n isDigestOnly: boolean = false,\n ): Promise<boolean> {\n if (isDigestOnly && data.byteLength !== 32) {\n throw new Error(\"SHA-256 digest must be exactly 32 bytes\");\n }\n const { signingCert, signature } = await this.verifyBundle(bundle, policy);\n\n // # 7 Revocation *skipping* not really a thing (unsurprisingly)\n\n // # 8 verify the signed data\n if (bundle.dsseEnvelope) {\n // Only in-toto statements are understood; other payload types must not be read as one.\n if (bundle.dsseEnvelope.payloadType !== \"application/vnd.in-toto+json\") {\n throw new Error(`Unsupported DSSE payload type: ${bundle.dsseEnvelope.payloadType}`);\n }\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const payload = JSON.parse(Uint8ArrayToString(payloadBytes));\n\n // Verify the artifact digest matches a subject in the in-toto statement\n if (!Array.isArray(payload?.subject) || payload.subject.length === 0 || payload.subject.length > MAX_SUBJECTS) {\n throw new Error(`DSSE payload must have between 1 and ${MAX_SUBJECTS} subjects`);\n }\n // Compute or extract the artifact digest\n let artifactDigest: string;\n if (isDigestOnly) {\n // data is already the digest bytes\n artifactDigest = Uint8ArrayToHex(data);\n } else {\n // data is the file content, compute the digest\n artifactDigest = Uint8ArrayToHex(await sha256(data));\n }\n\n // Every subject must carry a bounded digest map; any one of them may match the artifact.\n let matchedSubject = false;\n for (const subject of payload.subject) {\n const digests = subject?.digest;\n if (!digests || typeof digests !== \"object\" || Array.isArray(digests) || Object.keys(digests).length > MAX_SUBJECT_DIGESTS) {\n throw new Error(`Invalid DSSE subject digest map (maximum ${MAX_SUBJECT_DIGESTS} digests)`);\n }\n matchedSubject ||= typeof digests.sha256 === \"string\" && artifactDigest === digests.sha256.toLowerCase();\n }\n\n if (!matchedSubject) {\n throw new Error(\n `Artifact digest ${artifactDigest} does not match any subject in DSSE payload`\n );\n }\n\n // Create PAE (Pre-Authentication Encoding) for signature verification\n const pae = preAuthEncoding(bundle.dsseEnvelope.payloadType, payloadBytes);\n\n const publicKey = await signingCert.publicKeyObj;\n const verified = await verifySignature(publicKey, pae, signature);\n if (!verified) {\n throw new Error(\"DSSE signature verification failed\");\n }\n } else {\n // The bundle's message digest must be the digest of the artifact being verified.\n const { messageDigest } = bundle.messageSignature;\n const digest = isDigestOnly ? data : await sha256(data);\n if (messageDigest.algorithm !== \"SHA2_256\" || !uint8ArrayEqual(digest, base64ToUint8Array(messageDigest.digest))) {\n throw new Error(\"Artifact digest does not match the bundle message digest\");\n }\n const publicKey = await signingCert.publicKeyObj;\n\n if (isDigestOnly) {\n if (!this.verifyDigest) {\n throw new Error(\"Digest-only verification needs the verifyDigest option\");\n }\n const verified = await this.verifyDigest(publicKey, data, signature);\n if (!verified) {\n throw new Error(\"Error verifying signature over digest\");\n }\n } else {\n // For regular bundles, verify the signature over the artifact data\n const verified = await verifySignature(publicKey, data, signature);\n if (!verified) {\n const keyAlg = publicKey.algorithm.name || 'unknown';\n throw new Error(`Error verifying artifact signature. Key algorithm: ${keyAlg}, Data length: ${data.length}, Signature length: ${signature.length}`);\n }\n }\n }\n\n return true;\n }\n\npublic async verifyArtifact(\n identity: string,\n issuer: string,\n bundle: SigstoreBundle,\n data: Uint8Array,\n isDigestOnly: boolean = false,\n): Promise<boolean> {\n\n const policy = new AllOf([\n new Identity({ identity }),\n new AnyOf([\n new OIDCIssuerV2(issuer),\n new OIDCIssuer(issuer),\n ]),\n ]);\n\n return this.verifyArtifactPolicy(\n policy,\n bundle,\n data,\n isDigestOnly,\n );\n}\n\n \n\n /**\n * Verify a DSSE bundle using a verification policy.\n * This matches sigstore-python's verify_dsse API.\n *\n * Reference: https://github.com/sigstore/sigstore-python/blob/main/sigstore/verify/verifier.py#L388\n *\n * Unlike verify_artifact which verifies an artifact against a bundle,\n * this method verifies the DSSE envelope itself and returns the payload.\n * The caller is responsible for checking that the payload matches their\n * expected artifact (e.g., by checking subjects in an in-toto statement).\n *\n * @param bundle - The Sigstore bundle containing the DSSE envelope\n * @param policy - A verification policy to apply to the signing certificate\n * @returns The payload type and payload bytes from the verified envelope\n */\n public async verifyDsse(\n bundle: SigstoreBundle,\n policy: VerificationPolicy,\n ): Promise<{ payloadType: string; payload: Uint8Array }> {\n const { signingCert, signature } = await this.verifyBundle(bundle, policy);\n if (!bundle.dsseEnvelope) {\n throw new Error(\"Bundle does not contain a DSSE envelope\");\n }\n\n // (7) Verify the DSSE envelope signature\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const pae = preAuthEncoding(bundle.dsseEnvelope.payloadType, payloadBytes);\n\n const publicKey = await signingCert.publicKeyObj;\n const verified = await verifySignature(publicKey, pae, signature);\n if (!verified) {\n throw new Error(\"DSSE signature verification failed\");\n }\n\n // (8) Every entry MUST be of type \"dsse\" for DSSE verification\n for (const entry of bundle.verificationMaterial.tlogEntries) {\n if (entry.kindVersion.kind !== \"dsse\") {\n throw new Error(`Expected entry type dsse, got ${entry.kindVersion.kind}`);\n }\n }\n\n // Return the verified payload\n return {\n payloadType: bundle.dsseEnvelope.payloadType,\n payload: payloadBytes,\n };\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freedomofpress/sigstore-browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A minimal browser-only Sigstore verification library.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"vitest": "^5.0.5"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@freedomofpress/crypto-browser": "^0.
|
|
52
|
-
"@freedomofpress/tuf-browser": "^0.
|
|
51
|
+
"@freedomofpress/crypto-browser": "^0.3.0",
|
|
52
|
+
"@freedomofpress/tuf-browser": "^0.3.0"
|
|
53
53
|
}
|
|
54
54
|
}
|