@freedomofpress/sigstore-browser 0.1.16 → 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/dsse.js +4 -9
- package/dist/dsse.js.map +1 -1
- package/dist/rfc3161/timestamp.js +3 -3
- package/dist/rfc3161/timestamp.js.map +1 -1
- package/dist/rfc3161/tstinfo.js +2 -3
- package/dist/rfc3161/tstinfo.js.map +1 -1
- package/dist/sigstore.d.ts +2 -0
- package/dist/sigstore.js +9 -10
- package/dist/sigstore.js.map +1 -1
- package/dist/tlog/dsse.js +3 -4
- package/dist/tlog/dsse.js.map +1 -1
- package/dist/tlog/intoto.js +2 -3
- package/dist/tlog/intoto.js.map +1 -1
- package/dist/tlog/merkle.js +8 -102
- package/dist/tlog/merkle.js.map +1 -1
- package/dist/trust/tuf.js +2 -5
- package/dist/trust/tuf.js.map +1 -1
- package/dist/x509/cert.js +2 -2
- package/dist/x509/cert.js.map +1 -1
- package/package.json +4 -4
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":"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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\";\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/dsse.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { concatBytes, stringToUint8Array } from "@freedomofpress/crypto-browser";
|
|
1
2
|
/*
|
|
2
3
|
Copyright 2023 The Sigstore Authors.
|
|
3
4
|
|
|
@@ -23,20 +24,14 @@ export function preAuthEncoding(payloadType, payload) {
|
|
|
23
24
|
payload.length,
|
|
24
25
|
"",
|
|
25
26
|
].join(" ");
|
|
26
|
-
// DSSE
|
|
27
|
-
|
|
28
|
-
const encoder = new TextEncoder();
|
|
29
|
-
const prefixBuffer = encoder.encode(prefix);
|
|
27
|
+
// DSSE requires an ASCII prefix.
|
|
28
|
+
const prefixBuffer = stringToUint8Array(prefix);
|
|
30
29
|
// Verify all characters are ASCII (< 128)
|
|
31
30
|
for (let i = 0; i < prefixBuffer.length; i++) {
|
|
32
31
|
if (prefixBuffer[i] > 127) {
|
|
33
32
|
throw new Error(`Invalid non-ASCII character in PAE prefix at position ${i}`);
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
const combinedArray = new Uint8Array(prefixBuffer.length + payload.length);
|
|
38
|
-
combinedArray.set(prefixBuffer, 0);
|
|
39
|
-
combinedArray.set(payload, prefixBuffer.length);
|
|
40
|
-
return combinedArray;
|
|
35
|
+
return concatBytes(prefixBuffer, payload);
|
|
41
36
|
}
|
|
42
37
|
//# sourceMappingURL=dsse.js.map
|
package/dist/dsse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dsse.js","sourceRoot":"","sources":["../src/dsse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;EAcE;AACF,MAAM,UAAU,GAAG,QAAQ,CAAC;AAE5B,mCAAmC;AACnC,MAAM,UAAU,eAAe,CAC7B,WAAmB,EACnB,OAAmB;IAEnB,MAAM,MAAM,GAAG;QACb,UAAU;QACV,WAAW,CAAC,MAAM;QAClB,WAAW;QACX,OAAO,CAAC,MAAM;QACd,EAAE;KACH,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,
|
|
1
|
+
{"version":3,"file":"dsse.js","sourceRoot":"","sources":["../src/dsse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACjF;;;;;;;;;;;;;;EAcE;AACF,MAAM,UAAU,GAAG,QAAQ,CAAC;AAE5B,mCAAmC;AACnC,MAAM,UAAU,eAAe,CAC7B,WAAmB,EACnB,OAAmB;IAEnB,MAAM,MAAM,GAAG;QACb,UAAU;QACV,WAAW,CAAC,MAAM;QAClB,WAAW;QACX,OAAO,CAAC,MAAM;QACd,EAAE;KACH,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,iCAAiC;IACjC,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAEhD,0CAA0C;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { concatBytes, stringToUint8Array } from \"@freedomofpress/crypto-browser\";\n/*\nCopyright 2023 The Sigstore Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nconst PAE_PREFIX = \"DSSEv1\";\n\n// DSSE Pre-Authentication Encoding\nexport function preAuthEncoding(\n payloadType: string,\n payload: Uint8Array,\n): Uint8Array {\n const prefix = [\n PAE_PREFIX,\n payloadType.length,\n payloadType,\n payload.length,\n \"\",\n ].join(\" \");\n\n // DSSE requires an ASCII prefix.\n const prefixBuffer = stringToUint8Array(prefix);\n\n // Verify all characters are ASCII (< 128)\n for (let i = 0; i < prefixBuffer.length; i++) {\n if (prefixBuffer[i] > 127) {\n throw new Error(`Invalid non-ASCII character in PAE prefix at position ${i}`);\n }\n }\n\n return concatBytes(prefixBuffer, payload);\n}\n"]}
|
|
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { ASN1Obj, uint8ArrayEqual, verifySignature } from "@freedomofpress/crypto-browser";
|
|
16
|
+
import { ASN1Obj, digest, uint8ArrayEqual, verifySignature } from "@freedomofpress/crypto-browser";
|
|
17
17
|
import { HashAlgorithms } from "../interfaces.js";
|
|
18
18
|
import { ECDSA_SIGNATURE_ALGOS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from "../oid.js";
|
|
19
19
|
import { RFC3161TimestampVerificationError } from "./error.js";
|
|
@@ -93,9 +93,9 @@ export class RFC3161Timestamp {
|
|
|
93
93
|
const hashAlgName = hashAlg === "sha256" ? HashAlgorithms.SHA256 :
|
|
94
94
|
hashAlg === "sha384" ? HashAlgorithms.SHA384 :
|
|
95
95
|
hashAlg === "sha512" ? HashAlgorithms.SHA512 : hashAlg;
|
|
96
|
-
const tstInfoDigest = await
|
|
96
|
+
const tstInfoDigest = await digest(hashAlgName, this.tstInfo.raw);
|
|
97
97
|
const expectedDigest = this.messageDigestAttributeObj.subs[1].subs[0].value;
|
|
98
|
-
if (!uint8ArrayEqual(
|
|
98
|
+
if (!uint8ArrayEqual(tstInfoDigest, expectedDigest)) {
|
|
99
99
|
throw new RFC3161TimestampVerificationError("signed data does not match tstInfo");
|
|
100
100
|
}
|
|
101
101
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timestamp.js","sourceRoot":"","sources":["../../src/rfc3161/timestamp.ts"],"names":[],"mappings":"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","sourcesContent":["/*\nCopyright 2023 The Sigstore Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport { ASN1Obj, uint8ArrayEqual, verifySignature } from \"@freedomofpress/crypto-browser\";\n\nimport { HashAlgorithms } from \"../interfaces.js\";\nimport { ECDSA_SIGNATURE_ALGOS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from \"../oid.js\";\nimport { RFC3161TimestampVerificationError } from \"./error.js\";\nimport { TSTInfo } from \"./tstinfo.js\";\n\nconst OID_PKCS9_CONTENT_TYPE_SIGNED_DATA = \"1.2.840.113549.1.7.2\";\nconst OID_PKCS9_CONTENT_TYPE_TSTINFO = \"1.2.840.113549.1.9.16.1.4\";\nconst OID_PKCS9_MESSAGE_DIGEST_KEY = \"1.2.840.113549.1.9.4\";\n\nexport class RFC3161Timestamp {\n public root: ASN1Obj;\n\n constructor(asn1: ASN1Obj) {\n this.root = asn1;\n }\n\n public static parse(der: Uint8Array): RFC3161Timestamp {\n const asn1 = ASN1Obj.parseBuffer(der);\n return new RFC3161Timestamp(asn1);\n }\n\n get status(): bigint {\n return this.pkiStatusInfoObj.subs[0].toInteger();\n }\n\n get contentType(): string {\n return this.contentTypeObj.toOID();\n }\n\n get eContentType(): string {\n return this.eContentTypeObj.toOID();\n }\n\n get signingTime(): Date {\n return this.tstInfo.genTime;\n }\n\n get signerIssuer(): Uint8Array {\n return this.signerSidObj.subs[0].value;\n }\n\n get signerSerialNumber(): Uint8Array {\n return this.signerSidObj.subs[1].value;\n }\n\n get signerDigestAlgorithm(): string {\n const oid = this.signerDigestAlgorithmObj.subs[0].toOID();\n const algo = SHA2_HASH_ALGOS[oid];\n if (!algo) {\n throw new Error(`Unknown digest algorithm OID: ${oid}`);\n }\n return algo;\n }\n\n get signatureAlgorithm(): string {\n const oid = this.signatureAlgorithmObj.subs[0].toOID();\n const algo = ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid];\n return algo;\n }\n\n get signatureValue(): Uint8Array {\n return this.signatureValueObj.value;\n }\n\n get tstInfo(): TSTInfo {\n // Need to unpack tstInfo from an OCTET STRING\n return new TSTInfo(this.eContentObj.subs[0].subs[0]);\n }\n\n public async verify(data: Uint8Array, publicKey: CryptoKey): Promise<void> {\n if (!this.timeStampTokenObj) {\n throw new RFC3161TimestampVerificationError(\"timeStampToken is missing\");\n }\n\n // Check for expected ContentInfo content type\n if (this.contentType !== OID_PKCS9_CONTENT_TYPE_SIGNED_DATA) {\n throw new RFC3161TimestampVerificationError(\n `incorrect content type: ${this.contentType}`,\n );\n }\n\n // Check for expected encapsulated content type\n if (this.eContentType !== OID_PKCS9_CONTENT_TYPE_TSTINFO) {\n throw new RFC3161TimestampVerificationError(\n `incorrect encapsulated content type: ${this.eContentType}`,\n );\n }\n\n // Check that the tstInfo references the correct artifact\n await this.tstInfo.verify(data);\n // Check that the signed message digest matches the tstInfo\n await this.verifyMessageDigest();\n // Check that the signature is valid for the signed attributes\n await this.verifySignature(publicKey);\n }\n\n private async verifyMessageDigest(): Promise<void> {\n // Check that the tstInfo matches the signed data\n const hashAlg = this.signerDigestAlgorithm;\n\n // Convert hash algorithm name to the format expected by WebCrypto\n const hashAlgName = hashAlg === \"sha256\" ? HashAlgorithms.SHA256 :\n hashAlg === \"sha384\" ? HashAlgorithms.SHA384 :\n hashAlg === \"sha512\" ? HashAlgorithms.SHA512 : hashAlg;\n\n const tstInfoDigest = await crypto.subtle.digest(\n hashAlgName,\n this.tstInfo.raw as BufferSource,\n );\n const expectedDigest = this.messageDigestAttributeObj.subs[1].subs[0].value;\n\n if (!uint8ArrayEqual(new Uint8Array(tstInfoDigest), expectedDigest)) {\n throw new RFC3161TimestampVerificationError(\n \"signed data does not match tstInfo\",\n );\n }\n }\n\n private async verifySignature(key: CryptoKey): Promise<void> {\n // Encode the signed attributes for verification\n const signedAttrs = this.signedAttrsObj.toDER();\n signedAttrs[0] = 0x31; // Change context-specific tag to SET\n\n const oid = this.signatureAlgorithmObj.subs[0].toOID();\n // Try both ECDSA and RSA signature algorithms\n const algo = ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid];\n\n if (!algo) {\n throw new RFC3161TimestampVerificationError(\n `Unsupported signature algorithm OID: ${oid}`,\n );\n }\n\n // Check that the signature is valid for the signed attributes\n const verified = await verifySignature(\n key,\n signedAttrs,\n this.signatureValue,\n algo,\n );\n\n if (!verified) {\n throw new RFC3161TimestampVerificationError(\n \"signature verification failed\",\n );\n }\n }\n\n // https://www.rfc-editor.org/rfc/rfc3161#section-2.4.2\n private get pkiStatusInfoObj(): ASN1Obj {\n // pkiStatusInfo is the first element of the timestamp response sequence\n return this.root.subs[0];\n }\n\n // https://www.rfc-editor.org/rfc/rfc3161#section-2.4.2\n private get timeStampTokenObj(): ASN1Obj {\n // timeStampToken is the first element of the timestamp response sequence\n return this.root.subs[1];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-3\n private get contentTypeObj(): ASN1Obj {\n return this.timeStampTokenObj.subs[0];\n }\n // https://www.rfc-editor.org/rfc/rfc5652#section-3\n private get signedDataObj(): ASN1Obj {\n const obj = this.timeStampTokenObj.subs.find((sub) =>\n sub.tag.isContextSpecific(0x00),\n );\n if (!obj) {\n throw new RFC3161TimestampVerificationError(\n \"Missing timeStampTokenObj sub.\",\n );\n }\n return obj.subs[0];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.1\n private get encapContentInfoObj(): ASN1Obj {\n return this.signedDataObj.subs[2];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.1\n private get signerInfosObj(): ASN1Obj {\n // SignerInfos is the last element of the signed data sequence\n const sd = this.signedDataObj;\n return sd.subs[sd.subs.length - 1];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5652#section-5.1\n private get signerInfoObj(): ASN1Obj {\n // Only supporting one signer\n return this.signerInfosObj.subs[0];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.2\n private get eContentTypeObj(): ASN1Obj {\n return this.encapContentInfoObj.subs[0];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.2\n private get eContentObj(): ASN1Obj {\n return this.encapContentInfoObj.subs[1];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signedAttrsObj(): ASN1Obj {\n const signedAttrs = this.signerInfoObj.subs.find((sub) =>\n sub.tag.isContextSpecific(0x00),\n );\n if (!signedAttrs) {\n throw new RFC3161TimestampVerificationError(\"Missing signedAttrsObj.\");\n }\n return signedAttrs;\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get messageDigestAttributeObj(): ASN1Obj {\n const messageDigest = this.signedAttrsObj.subs.find(\n (sub) =>\n sub.subs[0].tag.isOID() &&\n sub.subs[0].toOID() === OID_PKCS9_MESSAGE_DIGEST_KEY,\n );\n if (!messageDigest) {\n throw new RFC3161TimestampVerificationError(\"Missing messageDigest.\");\n }\n return messageDigest;\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signerSidObj(): ASN1Obj {\n return this.signerInfoObj.subs[1];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signerDigestAlgorithmObj(): ASN1Obj {\n // Signature is the 2nd element of the signerInfoObj object\n return this.signerInfoObj.subs[2];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signatureAlgorithmObj(): ASN1Obj {\n // Signature is the 4th element of the signerInfoObj object\n return this.signerInfoObj.subs[4];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signatureValueObj(): ASN1Obj {\n // Signature is the 6th element of the signerInfoObj object\n return this.signerInfoObj.subs[5];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"timestamp.js","sourceRoot":"","sources":["../../src/rfc3161/timestamp.ts"],"names":[],"mappings":"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","sourcesContent":["/*\nCopyright 2023 The Sigstore Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport { ASN1Obj, digest, uint8ArrayEqual, verifySignature } from \"@freedomofpress/crypto-browser\";\n\nimport { HashAlgorithms } from \"../interfaces.js\";\nimport { ECDSA_SIGNATURE_ALGOS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from \"../oid.js\";\nimport { RFC3161TimestampVerificationError } from \"./error.js\";\nimport { TSTInfo } from \"./tstinfo.js\";\n\nconst OID_PKCS9_CONTENT_TYPE_SIGNED_DATA = \"1.2.840.113549.1.7.2\";\nconst OID_PKCS9_CONTENT_TYPE_TSTINFO = \"1.2.840.113549.1.9.16.1.4\";\nconst OID_PKCS9_MESSAGE_DIGEST_KEY = \"1.2.840.113549.1.9.4\";\n\nexport class RFC3161Timestamp {\n public root: ASN1Obj;\n\n constructor(asn1: ASN1Obj) {\n this.root = asn1;\n }\n\n public static parse(der: Uint8Array): RFC3161Timestamp {\n const asn1 = ASN1Obj.parseBuffer(der);\n return new RFC3161Timestamp(asn1);\n }\n\n get status(): bigint {\n return this.pkiStatusInfoObj.subs[0].toInteger();\n }\n\n get contentType(): string {\n return this.contentTypeObj.toOID();\n }\n\n get eContentType(): string {\n return this.eContentTypeObj.toOID();\n }\n\n get signingTime(): Date {\n return this.tstInfo.genTime;\n }\n\n get signerIssuer(): Uint8Array {\n return this.signerSidObj.subs[0].value;\n }\n\n get signerSerialNumber(): Uint8Array {\n return this.signerSidObj.subs[1].value;\n }\n\n get signerDigestAlgorithm(): string {\n const oid = this.signerDigestAlgorithmObj.subs[0].toOID();\n const algo = SHA2_HASH_ALGOS[oid];\n if (!algo) {\n throw new Error(`Unknown digest algorithm OID: ${oid}`);\n }\n return algo;\n }\n\n get signatureAlgorithm(): string {\n const oid = this.signatureAlgorithmObj.subs[0].toOID();\n const algo = ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid];\n return algo;\n }\n\n get signatureValue(): Uint8Array {\n return this.signatureValueObj.value;\n }\n\n get tstInfo(): TSTInfo {\n // Need to unpack tstInfo from an OCTET STRING\n return new TSTInfo(this.eContentObj.subs[0].subs[0]);\n }\n\n public async verify(data: Uint8Array, publicKey: CryptoKey): Promise<void> {\n if (!this.timeStampTokenObj) {\n throw new RFC3161TimestampVerificationError(\"timeStampToken is missing\");\n }\n\n // Check for expected ContentInfo content type\n if (this.contentType !== OID_PKCS9_CONTENT_TYPE_SIGNED_DATA) {\n throw new RFC3161TimestampVerificationError(\n `incorrect content type: ${this.contentType}`,\n );\n }\n\n // Check for expected encapsulated content type\n if (this.eContentType !== OID_PKCS9_CONTENT_TYPE_TSTINFO) {\n throw new RFC3161TimestampVerificationError(\n `incorrect encapsulated content type: ${this.eContentType}`,\n );\n }\n\n // Check that the tstInfo references the correct artifact\n await this.tstInfo.verify(data);\n // Check that the signed message digest matches the tstInfo\n await this.verifyMessageDigest();\n // Check that the signature is valid for the signed attributes\n await this.verifySignature(publicKey);\n }\n\n private async verifyMessageDigest(): Promise<void> {\n // Check that the tstInfo matches the signed data\n const hashAlg = this.signerDigestAlgorithm;\n\n // Convert hash algorithm name to the format expected by WebCrypto\n const hashAlgName = hashAlg === \"sha256\" ? HashAlgorithms.SHA256 :\n hashAlg === \"sha384\" ? HashAlgorithms.SHA384 :\n hashAlg === \"sha512\" ? HashAlgorithms.SHA512 : hashAlg;\n\n const tstInfoDigest = await digest(hashAlgName, this.tstInfo.raw);\n const expectedDigest = this.messageDigestAttributeObj.subs[1].subs[0].value;\n\n if (!uint8ArrayEqual(tstInfoDigest, expectedDigest)) {\n throw new RFC3161TimestampVerificationError(\n \"signed data does not match tstInfo\",\n );\n }\n }\n\n private async verifySignature(key: CryptoKey): Promise<void> {\n // Encode the signed attributes for verification\n const signedAttrs = this.signedAttrsObj.toDER();\n signedAttrs[0] = 0x31; // Change context-specific tag to SET\n\n const oid = this.signatureAlgorithmObj.subs[0].toOID();\n // Try both ECDSA and RSA signature algorithms\n const algo = ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid];\n\n if (!algo) {\n throw new RFC3161TimestampVerificationError(\n `Unsupported signature algorithm OID: ${oid}`,\n );\n }\n\n // Check that the signature is valid for the signed attributes\n const verified = await verifySignature(\n key,\n signedAttrs,\n this.signatureValue,\n algo,\n );\n\n if (!verified) {\n throw new RFC3161TimestampVerificationError(\n \"signature verification failed\",\n );\n }\n }\n\n // https://www.rfc-editor.org/rfc/rfc3161#section-2.4.2\n private get pkiStatusInfoObj(): ASN1Obj {\n // pkiStatusInfo is the first element of the timestamp response sequence\n return this.root.subs[0];\n }\n\n // https://www.rfc-editor.org/rfc/rfc3161#section-2.4.2\n private get timeStampTokenObj(): ASN1Obj {\n // timeStampToken is the first element of the timestamp response sequence\n return this.root.subs[1];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-3\n private get contentTypeObj(): ASN1Obj {\n return this.timeStampTokenObj.subs[0];\n }\n // https://www.rfc-editor.org/rfc/rfc5652#section-3\n private get signedDataObj(): ASN1Obj {\n const obj = this.timeStampTokenObj.subs.find((sub) =>\n sub.tag.isContextSpecific(0x00),\n );\n if (!obj) {\n throw new RFC3161TimestampVerificationError(\n \"Missing timeStampTokenObj sub.\",\n );\n }\n return obj.subs[0];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.1\n private get encapContentInfoObj(): ASN1Obj {\n return this.signedDataObj.subs[2];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.1\n private get signerInfosObj(): ASN1Obj {\n // SignerInfos is the last element of the signed data sequence\n const sd = this.signedDataObj;\n return sd.subs[sd.subs.length - 1];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5652#section-5.1\n private get signerInfoObj(): ASN1Obj {\n // Only supporting one signer\n return this.signerInfosObj.subs[0];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.2\n private get eContentTypeObj(): ASN1Obj {\n return this.encapContentInfoObj.subs[0];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.2\n private get eContentObj(): ASN1Obj {\n return this.encapContentInfoObj.subs[1];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signedAttrsObj(): ASN1Obj {\n const signedAttrs = this.signerInfoObj.subs.find((sub) =>\n sub.tag.isContextSpecific(0x00),\n );\n if (!signedAttrs) {\n throw new RFC3161TimestampVerificationError(\"Missing signedAttrsObj.\");\n }\n return signedAttrs;\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get messageDigestAttributeObj(): ASN1Obj {\n const messageDigest = this.signedAttrsObj.subs.find(\n (sub) =>\n sub.subs[0].tag.isOID() &&\n sub.subs[0].toOID() === OID_PKCS9_MESSAGE_DIGEST_KEY,\n );\n if (!messageDigest) {\n throw new RFC3161TimestampVerificationError(\"Missing messageDigest.\");\n }\n return messageDigest;\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signerSidObj(): ASN1Obj {\n return this.signerInfoObj.subs[1];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signerDigestAlgorithmObj(): ASN1Obj {\n // Signature is the 2nd element of the signerInfoObj object\n return this.signerInfoObj.subs[2];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signatureAlgorithmObj(): ASN1Obj {\n // Signature is the 4th element of the signerInfoObj object\n return this.signerInfoObj.subs[4];\n }\n\n // https://datatracker.ietf.org/doc/html/rfc5652#section-5.3\n private get signatureValueObj(): ASN1Obj {\n // Signature is the 6th element of the signerInfoObj object\n return this.signerInfoObj.subs[5];\n }\n}\n"]}
|
package/dist/rfc3161/tstinfo.js
CHANGED
|
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { uint8ArrayEqual } from "@freedomofpress/crypto-browser";
|
|
16
|
+
import { digest, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
|
|
17
17
|
import { HashAlgorithms } from "../interfaces.js";
|
|
18
18
|
import { SHA2_HASH_ALGOS } from "../oid.js";
|
|
19
19
|
import { RFC3161TimestampVerificationError } from "./error.js";
|
|
@@ -47,8 +47,7 @@ export class TSTInfo {
|
|
|
47
47
|
const hashAlgName = hashAlg === "sha256" ? HashAlgorithms.SHA256 :
|
|
48
48
|
hashAlg === "sha384" ? HashAlgorithms.SHA384 :
|
|
49
49
|
hashAlg === "sha512" ? HashAlgorithms.SHA512 : hashAlg;
|
|
50
|
-
|
|
51
|
-
if (!uint8ArrayEqual(new Uint8Array(digest), this.messageImprintHashedMessage)) {
|
|
50
|
+
if (!uint8ArrayEqual(await digest(hashAlgName, data), this.messageImprintHashedMessage)) {
|
|
52
51
|
throw new RFC3161TimestampVerificationError("message imprint does not match artifact");
|
|
53
52
|
}
|
|
54
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tstinfo.js","sourceRoot":"","sources":["../../src/rfc3161/tstinfo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;EAcE;AACF,OAAO,EAAW,eAAe,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"tstinfo.js","sourceRoot":"","sources":["../../src/rfc3161/tstinfo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;EAcE;AACF,OAAO,EAAW,MAAM,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAElF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,iCAAiC,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,OAAO,OAAO;IAGlB,YAAY,IAAa;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IACvC,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACpC,CAAC;IAED,IAAI,2BAA2B;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,+CAA+C,GAAG,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,2BAA2B;QAC7B,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9C,CAAC;IAED,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,IAAgB;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,2BAA2B,CAAC;QAEjD,kEAAkE;QAClE,MAAM,WAAW,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAC/C,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;gBAC9C,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAE1E,IAAI,CAAC,eAAe,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,2BAA2B,CAAC,EAAE,CAAC;YACxF,MAAM,IAAI,iCAAiC,CACzC,yCAAyC,CAC1C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,IAAY,iBAAiB;QAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;CACF","sourcesContent":["/*\nCopyright 2023 The Sigstore Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport { ASN1Obj, digest, uint8ArrayEqual } from \"@freedomofpress/crypto-browser\";\n\nimport { HashAlgorithms } from \"../interfaces.js\";\nimport { SHA2_HASH_ALGOS } from \"../oid.js\";\nimport { RFC3161TimestampVerificationError } from \"./error.js\";\n\nexport class TSTInfo {\n public root: ASN1Obj;\n\n constructor(asn1: ASN1Obj) {\n this.root = asn1;\n }\n\n get version(): bigint {\n return this.root.subs[0].toInteger();\n }\n\n get genTime(): Date {\n return this.root.subs[4].toDate();\n }\n\n get messageImprintHashAlgorithm(): string {\n const oid = this.messageImprintObj.subs[0].subs[0].toOID();\n const algo = SHA2_HASH_ALGOS[oid];\n if (!algo) {\n throw new Error(`Unknown message imprint hash algorithm OID: ${oid}`);\n }\n return algo;\n }\n\n get messageImprintHashedMessage(): Uint8Array {\n return this.messageImprintObj.subs[1].value;\n }\n\n get raw(): Uint8Array {\n return this.root.toDER();\n }\n\n public async verify(data: Uint8Array): Promise<void> {\n const hashAlg = this.messageImprintHashAlgorithm;\n\n // Convert hash algorithm name to the format expected by WebCrypto\n const hashAlgName = hashAlg === \"sha256\" ? HashAlgorithms.SHA256 :\n hashAlg === \"sha384\" ? HashAlgorithms.SHA384 :\n hashAlg === \"sha512\" ? HashAlgorithms.SHA512 : hashAlg;\n\n if (!uint8ArrayEqual(await digest(hashAlgName, data), this.messageImprintHashedMessage)) {\n throw new RFC3161TimestampVerificationError(\n \"message imprint does not match artifact\",\n );\n }\n }\n\n // https://www.rfc-editor.org/rfc/rfc3161#section-2.4.2\n private get messageImprintObj(): ASN1Obj {\n return this.root.subs[2];\n }\n}\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,7 +1,6 @@
|
|
|
1
|
-
import { base64ToUint8Array, ByteStream, canonicalizeJCS, importKey, 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
|
-
import { HashAlgorithms } from "./interfaces.js";
|
|
5
4
|
import { parseValidityPeriod, SigstoreRoots, } from "./interfaces.js";
|
|
6
5
|
import { AllOf, AnyOf, Identity, OIDCIssuer, OIDCIssuerV2 } from "./policy.js";
|
|
7
6
|
import { verifyBundleTimestamp } from "./timestamp/tsa.js";
|
|
@@ -49,6 +48,7 @@ export class SigstoreVerifier {
|
|
|
49
48
|
constructor(options = {}) {
|
|
50
49
|
this.root = undefined;
|
|
51
50
|
this.rawRoot = undefined;
|
|
51
|
+
this.verifyDigest = options.verifyDigest;
|
|
52
52
|
this.options = {
|
|
53
53
|
tlogThreshold: options.tlogThreshold ?? 1,
|
|
54
54
|
ctlogThreshold: options.ctlogThreshold ?? 1,
|
|
@@ -186,7 +186,7 @@ export class SigstoreVerifier {
|
|
|
186
186
|
// https://www.rfc-editor.org/rfc/rfc6962#section-3.2
|
|
187
187
|
const preCert = new ByteStream();
|
|
188
188
|
// Calculate hash of the issuer's public key
|
|
189
|
-
const issuerId =
|
|
189
|
+
const issuerId = await sha256(issuer.publicKey);
|
|
190
190
|
preCert.appendView(issuerId);
|
|
191
191
|
// Re-encodes the certificate to DER after removing the SCT extension
|
|
192
192
|
const tbs = clone.tbsCertificate.toDER();
|
|
@@ -345,7 +345,7 @@ export class SigstoreVerifier {
|
|
|
345
345
|
}
|
|
346
346
|
else {
|
|
347
347
|
// data is the file content, compute the digest
|
|
348
|
-
artifactDigest = Uint8ArrayToHex(
|
|
348
|
+
artifactDigest = Uint8ArrayToHex(await sha256(data));
|
|
349
349
|
}
|
|
350
350
|
// Every subject must carry a bounded digest map; any one of them may match the artifact.
|
|
351
351
|
let matchedSubject = false;
|
|
@@ -370,17 +370,16 @@ export class SigstoreVerifier {
|
|
|
370
370
|
else {
|
|
371
371
|
// The bundle's message digest must be the digest of the artifact being verified.
|
|
372
372
|
const { messageDigest } = bundle.messageSignature;
|
|
373
|
-
const digest = isDigestOnly
|
|
374
|
-
? data
|
|
375
|
-
: new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, data));
|
|
373
|
+
const digest = isDigestOnly ? data : await sha256(data);
|
|
376
374
|
if (messageDigest.algorithm !== "SHA2_256" || !uint8ArrayEqual(digest, base64ToUint8Array(messageDigest.digest))) {
|
|
377
375
|
throw new Error("Artifact digest does not match the bundle message digest");
|
|
378
376
|
}
|
|
379
377
|
const publicKey = await signingCert.publicKeyObj;
|
|
380
378
|
if (isDigestOnly) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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);
|
|
384
383
|
if (!verified) {
|
|
385
384
|
throw new Error("Error verifying signature over digest");
|
|
386
385
|
}
|
package/dist/sigstore.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sigstore.js","sourceRoot":"","sources":["../src/sigstore.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,yBAAyB,GAC1B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,YAAY,EAA6B,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,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;AAQD,MAAM,OAAO,gBAAgB;IAK3B,YAAY,UAAmC,EAAE;QAC/C,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACzB,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,IAAI,UAAU,CAC7B,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,SAAyB,CAAC,CACpF,CAAC;QACF,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,CAC9B,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,IAAoB,CAAC,CAAC,CACxF,CAAC;YACJ,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;gBACzB,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,IAAoB,CAAC,CAAC,CAAC;YAC5F,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,uEAAuE;gBACvE,uEAAuE;gBACvE,MAAM,QAAQ,GAAG,MAAM,yBAAyB,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;gBAC7E,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 {\n base64ToUint8Array,\n ByteStream,\n canonicalizeJCS,\n importKey,\n stringToUint8Array,\n uint8ArrayEqual,\n Uint8ArrayToHex,\n Uint8ArrayToString,\n verifySignature,\n verifySignatureOverDigest,\n} from \"@freedomofpress/crypto-browser\";\n\nimport { assertBundle, SigstoreBundle, TLogEntry } from \"./bundle.js\";\nimport { preAuthEncoding } from \"./dsse.js\";\nimport { HashAlgorithms } from \"./interfaces.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 = new Uint8Array(\n await crypto.subtle.digest(HashAlgorithms.SHA256, issuer.publicKey as BufferSource),\n );\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(\n new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, data as BufferSource))\n );\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\n ? data\n : new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, data as BufferSource));\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":"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","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/dist/tlog/dsse.js
CHANGED
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
* Key differences from sigstore-js:
|
|
8
8
|
* - Browser-compatible: uses Uint8Array instead of Buffer for binary data
|
|
9
9
|
* - Direct bundle field comparison instead of SignatureContent abstraction
|
|
10
|
-
* - Uses crypto.subtle.digest for hash computation instead of Node.js crypto
|
|
11
10
|
* - Adds verifyDSSE002Body() - new functionality (reference only supports v0.0.1)
|
|
12
11
|
*/
|
|
13
|
-
import { base64ToUint8Array, hexToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
|
|
12
|
+
import { base64ToUint8Array, digest, hexToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
|
|
14
13
|
import { getHashAlgorithm } from "../interfaces.js";
|
|
15
14
|
import { assertLoggedCertificate } from "./body.js";
|
|
16
15
|
export async function verifyDSSEBody(entry, bundle, cert) {
|
|
@@ -47,7 +46,7 @@ async function verifyDSSE001Body(entry, bundle, cert) {
|
|
|
47
46
|
const hashAlg = getHashAlgorithm(entry.spec.payloadHash.algorithm);
|
|
48
47
|
const tlogHashBytes = hexToUint8Array(entry.spec.payloadHash.value);
|
|
49
48
|
const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
|
|
50
|
-
const bundleHashBytes =
|
|
49
|
+
const bundleHashBytes = await digest(hashAlg, payloadBytes);
|
|
51
50
|
if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
|
|
52
51
|
throw new Error("DSSE payload hash mismatch between TLog entry and bundle");
|
|
53
52
|
}
|
|
@@ -83,7 +82,7 @@ async function verifyDSSE002Body(entry, bundle, cert) {
|
|
|
83
82
|
const hashAlg = getHashAlgorithm(spec.payloadHash.algorithm);
|
|
84
83
|
const tlogHashBytes = base64ToUint8Array(spec.payloadHash.digest);
|
|
85
84
|
const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
|
|
86
|
-
const bundleHashBytes =
|
|
85
|
+
const bundleHashBytes = await digest(hashAlg, payloadBytes);
|
|
87
86
|
if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
|
|
88
87
|
throw new Error("DSSE payload hash mismatch between TLog entry and bundle (v0.0.2)");
|
|
89
88
|
}
|
package/dist/tlog/dsse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dsse.js","sourceRoot":"","sources":["../../src/tlog/dsse.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dsse.js","sourceRoot":"","sources":["../../src/tlog/dsse.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * DSSE transparency log entry verification\n *\n * Based on sigstore-js:\n * https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/tlog/dsse.ts\n *\n * Key differences from sigstore-js:\n * - Browser-compatible: uses Uint8Array instead of Buffer for binary data\n * - Direct bundle field comparison instead of SignatureContent abstraction\n * - Adds verifyDSSE002Body() - new functionality (reference only supports v0.0.1)\n */\n\nimport { base64ToUint8Array, digest, hexToUint8Array, uint8ArrayEqual } from \"@freedomofpress/crypto-browser\";\n\nimport type { SigstoreBundle } from \"../bundle.js\";\nimport { getHashAlgorithm } from \"../interfaces.js\";\nimport type { X509Certificate } from \"../x509/cert.js\";\nimport { assertLoggedCertificate, type RekorEntry } from \"./body.js\";\n\n// Shape of the Rekor v2 dsse_v002 entry spec, validated field by field below.\ntype DsseV002Spec = {\n payloadHash?: { algorithm?: string; digest?: string };\n signatures?: { content?: string; verifier?: { x509Certificate?: { rawBytes?: string } } }[];\n};\n\ninterface DSSESpec {\n signatures?: Array<{\n signature: string;\n verifier?: string;\n keyid?: string;\n }>;\n payloadHash?: {\n algorithm: string;\n value: string;\n };\n envelopeHash?: {\n algorithm: string;\n value: string;\n };\n}\n\ninterface DSSEEntry extends RekorEntry {\n apiVersion: \"0.0.1\" | \"0.0.2\";\n kind: \"dsse\";\n spec: DSSESpec;\n}\n\nexport async function verifyDSSEBody(\n entry: RekorEntry,\n bundle: SigstoreBundle,\n cert: X509Certificate,\n): Promise<void> {\n const dsseEntry = entry as DSSEEntry;\n\n switch (dsseEntry.apiVersion) {\n case \"0.0.1\":\n return verifyDSSE001Body(dsseEntry, bundle, cert);\n case \"0.0.2\":\n return verifyDSSE002Body(dsseEntry, bundle, cert);\n default:\n throw new Error(\n `Unsupported dsse version: ${dsseEntry.apiVersion}`\n );\n }\n}\n\nasync function verifyDSSE001Body(\n entry: DSSEEntry,\n bundle: SigstoreBundle,\n cert: X509Certificate,\n): Promise<void> {\n if (!bundle.dsseEnvelope) {\n throw new Error(\"Bundle missing dsseEnvelope for DSSE entry\");\n }\n\n if (!entry.spec.signatures || entry.spec.signatures.length !== 1) {\n throw new Error(\"DSSE entry must have exactly one signature\");\n }\n assertLoggedCertificate(cert, entry.spec.signatures[0].verifier, true);\n\n const tlogSig = entry.spec.signatures[0].signature;\n const tlogSigBytes = base64ToUint8Array(tlogSig);\n\n if (bundle.dsseEnvelope.signatures.length === 0) {\n throw new Error(\"Bundle DSSE envelope missing signatures\");\n }\n\n const bundleSigBytes = base64ToUint8Array(bundle.dsseEnvelope.signatures[0].sig);\n\n if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {\n throw new Error(\"DSSE signature mismatch between TLog entry and bundle\");\n }\n\n if (!entry.spec.payloadHash?.value || !entry.spec.payloadHash?.algorithm) {\n throw new Error(\"DSSE entry missing payloadHash or algorithm\");\n }\n\n const hashAlg = getHashAlgorithm(entry.spec.payloadHash.algorithm);\n const tlogHashBytes = hexToUint8Array(entry.spec.payloadHash.value);\n\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const bundleHashBytes = await digest(hashAlg, payloadBytes);\n\n if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {\n throw new Error(\"DSSE payload hash mismatch between TLog entry and bundle\");\n }\n}\n\n// New functionality for DSSE v0.0.2 (not in sigstore-js reference, which only supports v0.0.1)\nasync function verifyDSSE002Body(\n entry: DSSEEntry,\n bundle: SigstoreBundle,\n cert: X509Certificate,\n): Promise<void> {\n if (!bundle.dsseEnvelope) {\n throw new Error(\"Bundle missing dsseEnvelope for DSSE v0.0.2 entry\");\n }\n\n const spec = (entry.spec as { dsseV002?: DsseV002Spec }).dsseV002;\n if (!spec) {\n throw new Error(\"DSSE v0.0.2 entry missing dsseV002 spec\");\n }\n\n if (!spec.signatures || spec.signatures.length !== 1) {\n throw new Error(\"DSSE v0.0.2 entry must have exactly one signature\");\n }\n assertLoggedCertificate(cert, spec.signatures[0].verifier?.x509Certificate?.rawBytes, false);\n\n const tlogSig = spec.signatures[0].content;\n if (typeof tlogSig !== \"string\") {\n throw new Error(\"DSSE v0.0.2 entry signature missing content\");\n }\n const tlogSigBytes = base64ToUint8Array(tlogSig);\n\n if (bundle.dsseEnvelope.signatures.length === 0) {\n throw new Error(\"Bundle DSSE envelope missing signatures\");\n }\n\n const bundleSigBytes = base64ToUint8Array(bundle.dsseEnvelope.signatures[0].sig);\n\n if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {\n throw new Error(\"DSSE signature mismatch between TLog entry and bundle (v0.0.2)\");\n }\n\n if (!spec.payloadHash?.digest || !spec.payloadHash?.algorithm) {\n throw new Error(\"DSSE v0.0.2 entry missing payloadHash or algorithm\");\n }\n\n const hashAlg = getHashAlgorithm(spec.payloadHash.algorithm);\n const tlogHashBytes = base64ToUint8Array(spec.payloadHash.digest);\n\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const bundleHashBytes = await digest(hashAlg, payloadBytes);\n\n if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {\n throw new Error(\"DSSE payload hash mismatch between TLog entry and bundle (v0.0.2)\");\n }\n}\n"]}
|
package/dist/tlog/intoto.js
CHANGED
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
* Key differences from sigstore-js:
|
|
8
8
|
* - Browser-compatible: uses Uint8Array instead of Buffer for binary data
|
|
9
9
|
* - Direct bundle field comparison instead of SignatureContent abstraction
|
|
10
|
-
* - Uses crypto.subtle.digest for hash computation instead of Node.js crypto
|
|
11
10
|
*/
|
|
12
|
-
import { base64Decode, base64ToUint8Array, hexToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
|
|
11
|
+
import { base64Decode, base64ToUint8Array, digest, hexToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
|
|
13
12
|
import { getHashAlgorithm } from "../interfaces.js";
|
|
14
13
|
import { assertLoggedCertificate } from "./body.js";
|
|
15
14
|
export async function verifyIntotoBody(entry, bundle, cert) {
|
|
@@ -46,7 +45,7 @@ export async function verifyIntotoBody(entry, bundle, cert) {
|
|
|
46
45
|
const hashAlg = getHashAlgorithm(intotoEntry.spec.content.payloadHash.algorithm);
|
|
47
46
|
const tlogHashBytes = hexToUint8Array(intotoEntry.spec.content.payloadHash.value);
|
|
48
47
|
const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
|
|
49
|
-
const bundleHashBytes =
|
|
48
|
+
const bundleHashBytes = await digest(hashAlg, payloadBytes);
|
|
50
49
|
if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
|
|
51
50
|
throw new Error("Intoto payload hash mismatch between TLog entry and bundle");
|
|
52
51
|
}
|
package/dist/tlog/intoto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intoto.js","sourceRoot":"","sources":["../../src/tlog/intoto.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"intoto.js","sourceRoot":"","sources":["../../src/tlog/intoto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAG5H,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,EAAE,uBAAuB,EAAmB,MAAM,WAAW,CAAC;AAiCrE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAiB,EACjB,MAAsB,EACtB,IAAqB;IAErB,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;IACD,uBAAuB,CAAC,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAE1E,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,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACjF,MAAM,aAAa,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAElF,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACrE,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAE5D,IAAI,CAAC,eAAe,CAAC,aAAa,EAAE,eAAe,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["/*\n * Intoto transparency log entry verification\n *\n * Based on sigstore-js:\n * https://github.com/sigstore/sigstore-js/blob/main/packages/verify/src/tlog/intoto.ts\n *\n * Key differences from sigstore-js:\n * - Browser-compatible: uses Uint8Array instead of Buffer for binary data\n * - Direct bundle field comparison instead of SignatureContent abstraction\n */\n\nimport { base64Decode, base64ToUint8Array, digest, hexToUint8Array, uint8ArrayEqual } from \"@freedomofpress/crypto-browser\";\n\nimport type { SigstoreBundle } from \"../bundle.js\";\nimport { getHashAlgorithm } from \"../interfaces.js\";\nimport type { X509Certificate } from \"../x509/cert.js\";\nimport { assertLoggedCertificate, type RekorEntry } from \"./body.js\";\n\ninterface IntotoEnvelope {\n payload: string;\n payloadType: string;\n signatures: Array<{\n keyid?: string;\n sig: string;\n publicKey?: string;\n }>;\n}\n\ninterface IntotoSpec {\n content: {\n envelope: IntotoEnvelope;\n hash?: {\n algorithm: string;\n value: string;\n };\n payloadHash?: {\n algorithm: string;\n value: string;\n };\n };\n publicKey?: string;\n}\n\ninterface IntotoEntry extends RekorEntry {\n apiVersion: \"0.0.2\";\n kind: \"intoto\";\n spec: IntotoSpec;\n}\n\nexport async function verifyIntotoBody(\n entry: RekorEntry,\n bundle: SigstoreBundle,\n cert: X509Certificate,\n): Promise<void> {\n const intotoEntry = entry as IntotoEntry;\n\n if (intotoEntry.apiVersion !== \"0.0.2\") {\n throw new Error(\n `Unsupported intoto version: ${intotoEntry.apiVersion}`\n );\n }\n\n if (!bundle.dsseEnvelope) {\n throw new Error(\"Bundle missing dsseEnvelope for intoto entry\");\n }\n\n const tlogEnvelope = intotoEntry.spec.content.envelope;\n\n if (!tlogEnvelope.signatures || tlogEnvelope.signatures.length !== 1) {\n throw new Error(\"Intoto entry must have exactly one signature\");\n }\n assertLoggedCertificate(cert, tlogEnvelope.signatures[0].publicKey, true);\n\n // The signature in the intoto tlog entry is double-base64-encoded:\n // 1. Raw signature bytes are base64-encoded (normal)\n // 2. That base64 string is base64-encoded again (for storage in JSON)\n // So we decode twice: base64 -> string -> base64 -> bytes\n const tlogSigBase64 = tlogEnvelope.signatures[0].sig;\n const tlogSigDecoded = base64Decode(tlogSigBase64); // First decode: base64 -> UTF-8 string (which contains base64)\n const tlogSigBytes = base64ToUint8Array(tlogSigDecoded); // Second decode: base64 string -> raw bytes\n\n if (bundle.dsseEnvelope.signatures.length === 0) {\n throw new Error(\"Bundle DSSE envelope missing signatures\");\n }\n\n const bundleSigBytes = base64ToUint8Array(bundle.dsseEnvelope.signatures[0].sig);\n\n if (!uint8ArrayEqual(tlogSigBytes, bundleSigBytes)) {\n throw new Error(\"Intoto signature mismatch between TLog entry and bundle\");\n }\n\n if (intotoEntry.spec.content.payloadHash) {\n if (!intotoEntry.spec.content.payloadHash.algorithm) {\n throw new Error(\"Intoto entry missing payloadHash algorithm\");\n }\n\n const hashAlg = getHashAlgorithm(intotoEntry.spec.content.payloadHash.algorithm);\n const tlogHashBytes = hexToUint8Array(intotoEntry.spec.content.payloadHash.value);\n\n const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);\n const bundleHashBytes = await digest(hashAlg, payloadBytes);\n\n if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {\n throw new Error(\"Intoto payload hash mismatch between TLog entry and bundle\");\n }\n }\n}\n"]}
|
package/dist/tlog/merkle.js
CHANGED
|
@@ -1,112 +1,18 @@
|
|
|
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
|
-
- uint8ArrayEqual from crypto-browser instead of Node.js crypto.timingSafeEqual
|
|
10
|
-
*/
|
|
11
|
-
import { base64ToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
|
|
12
|
-
import { HashAlgorithms } from "../interfaces.js";
|
|
13
|
-
const RFC6962_LEAF_HASH_PREFIX = new Uint8Array([0x00]);
|
|
14
|
-
const RFC6962_NODE_HASH_PREFIX = new Uint8Array([0x01]);
|
|
1
|
+
import { base64ToUint8Array, hashLeaf, verifyInclusionProof } from "@freedomofpress/crypto-browser";
|
|
15
2
|
export async function verifyMerkleInclusion(entry) {
|
|
16
3
|
if (!entry.inclusionProof) {
|
|
17
4
|
throw new Error("Missing inclusion proof");
|
|
18
5
|
}
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
23
|
-
throw new Error(`Invalid log index: ${logIndex}`);
|
|
6
|
+
const proof = entry.inclusionProof;
|
|
7
|
+
const index = Number(proof.logIndex);
|
|
8
|
+
const size = Number(proof.treeSize);
|
|
9
|
+
if (!Number.isSafeInteger(index) || !Number.isSafeInteger(size) || index < 0 || index >= size) {
|
|
10
|
+
throw new Error(`Invalid log index: ${proof.logIndex}`);
|
|
24
11
|
}
|
|
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
12
|
const leafHash = await hashLeaf(base64ToUint8Array(entry.canonicalizedBody));
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const rootHash = base64ToUint8Array(inclusionProof.rootHash);
|
|
42
|
-
// Calculated hash should match the root hash in the inclusion proof
|
|
43
|
-
if (!uint8ArrayEqual(calculatedHash, rootHash)) {
|
|
13
|
+
const ok = await verifyInclusionProof(leafHash, index, size, base64ToUint8Array(proof.rootHash), proof.hashes.map(base64ToUint8Array));
|
|
14
|
+
if (!ok) {
|
|
44
15
|
throw new Error("Calculated root hash does not match inclusion proof");
|
|
45
16
|
}
|
|
46
17
|
}
|
|
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, 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, data);
|
|
110
|
-
return new Uint8Array(hash);
|
|
111
|
-
}
|
|
112
18
|
//# sourceMappingURL=merkle.js.map
|
package/dist/tlog/merkle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merkle.js","sourceRoot":"","sources":["../../src/tlog/merkle.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"merkle.js","sourceRoot":"","sources":["../../src/tlog/merkle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAIpG,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAgB;IAC1D,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAC9F,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC7E,MAAM,EAAE,GAAG,MAAM,oBAAoB,CACnC,QAAQ,EACR,KAAK,EACL,IAAI,EACJ,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAClC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CACrC,CAAC;IACF,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;AACH,CAAC","sourcesContent":["import { base64ToUint8Array, hashLeaf, verifyInclusionProof } from \"@freedomofpress/crypto-browser\";\n\nimport type { TLogEntry } from \"../bundle.js\";\n\nexport async function verifyMerkleInclusion(entry: TLogEntry): Promise<void> {\n if (!entry.inclusionProof) {\n throw new Error(\"Missing inclusion proof\");\n }\n const proof = entry.inclusionProof;\n const index = Number(proof.logIndex);\n const size = Number(proof.treeSize);\n if (!Number.isSafeInteger(index) || !Number.isSafeInteger(size) || index < 0 || index >= size) {\n throw new Error(`Invalid log index: ${proof.logIndex}`);\n }\n const leafHash = await hashLeaf(base64ToUint8Array(entry.canonicalizedBody));\n const ok = await verifyInclusionProof(\n leafHash,\n index,\n size,\n base64ToUint8Array(proof.rootHash),\n proof.hashes.map(base64ToUint8Array),\n );\n if (!ok) {\n throw new Error(\"Calculated root hash does not match inclusion proof\");\n }\n}\n"]}
|
package/dist/trust/tuf.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reference: https://github.com/freedomofpress/tuf-browser
|
|
8
8
|
*/
|
|
9
|
-
import { Uint8ArrayToString } from "@freedomofpress/crypto-browser";
|
|
9
|
+
import { base64Decode, Uint8ArrayToString } from "@freedomofpress/crypto-browser";
|
|
10
10
|
/**
|
|
11
11
|
* Default configuration for Sigstore production TUF repository
|
|
12
12
|
*/
|
|
@@ -67,10 +67,7 @@ export class TrustedRootProvider {
|
|
|
67
67
|
// Import the embedded TUF root metadata (base64-encoded 1.root.json as string)
|
|
68
68
|
// This is the root of trust for TUF, not to be confused with the Sigstore trusted root
|
|
69
69
|
const { default: tufRootBase64 } = await import('./tuf-root.js');
|
|
70
|
-
|
|
71
|
-
const decoder = new TextDecoder();
|
|
72
|
-
const rootBytes = Uint8Array.from(atob(tufRootBase64), c => c.charCodeAt(0));
|
|
73
|
-
return decoder.decode(rootBytes);
|
|
70
|
+
return base64Decode(tufRootBase64);
|
|
74
71
|
}
|
|
75
72
|
/**
|
|
76
73
|
* Check if cached trusted root is still valid
|
package/dist/trust/tuf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tuf.js","sourceRoot":"","sources":["../../src/trust/tuf.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * TUF (The Update Framework) integration for trusted root management\n *\n * Provides secure updates for Sigstore trusted root metadata using TUF.\n * Uses tuf-browser for browser-compatible TUF client functionality.\n *\n * Reference: https://github.com/freedomofpress/tuf-browser\n */\n\nimport { Uint8ArrayToString } from \"@freedomofpress/crypto-browser\";\nimport type { TUFClient } from \"@freedomofpress/tuf-browser\";\n\nimport { TrustedRoot } from \"../interfaces.js\";\n\n/**\n * Options for TrustedRootProvider configuration\n */\nexport interface TrustedRootProviderOptions {\n /**\n * TUF repository URL for metadata\n * Default: Sigstore production TUF repository\n */\n metadataUrl?: string;\n\n /**\n * Target base URL for fetching target files\n * If not specified, uses the same as metadataUrl\n */\n targetBaseUrl?: string;\n\n /**\n * Initial root metadata (1.root.json content)\n * If not provided, will use embedded default\n */\n initialRoot?: string;\n\n /**\n * Namespace for TUF cache storage\n * Default: 'tuf-cache'\n */\n namespace?: string;\n\n /**\n * Name of the trusted root target file\n * Default: 'trusted_root.json'\n */\n trustedRootTarget?: string;\n\n /**\n * Cache TTL in milliseconds\n * Default: 1 hour (3600000 ms)\n */\n cacheTTL?: number;\n\n /**\n * Disable persistent caching (use in-memory only)\n * Default: false\n */\n disableCache?: boolean;\n}\n\n/**\n * Default configuration for Sigstore production TUF repository\n */\nconst DEFAULT_CONFIG = {\n metadataUrl: 'https://tuf-repo-cdn.sigstore.dev/',\n targetBaseUrl: 'https://tuf-repo-cdn.sigstore.dev/targets/',\n namespace: 'tuf-cache',\n trustedRootTarget: 'trusted_root.json',\n cacheTTL: 3600000, // 1 hour\n};\n\n/**\n * Provides Sigstore trusted root via TUF for secure updates\n *\n * This class manages fetching and caching of Sigstore trusted root metadata\n * using The Update Framework (TUF) for secure, verified updates.\n *\n * Example usage:\n * ```typescript\n * const provider = new TrustedRootProvider();\n * const trustedRoot = await provider.getTrustedRoot();\n * ```\n */\nexport class TrustedRootProvider {\n private metadataUrl: string;\n private targetBaseUrl?: string;\n private initialRoot?: string;\n private namespace: string;\n private trustedRootTarget: string;\n private cacheTTL: number;\n private disableCache: boolean;\n\n private tufClient?: TUFClient;\n private cachedRoot?: TrustedRoot;\n private cacheTimestamp?: number;\n\n constructor(options: TrustedRootProviderOptions = {}) {\n const metadataUrl = options.metadataUrl || DEFAULT_CONFIG.metadataUrl;\n this.metadataUrl = metadataUrl.endsWith('/') ? metadataUrl : `${metadataUrl}/`;\n const targetBaseUrl = options.targetBaseUrl || DEFAULT_CONFIG.targetBaseUrl;\n this.targetBaseUrl = targetBaseUrl.endsWith('/') ? targetBaseUrl : `${targetBaseUrl}/`;\n this.initialRoot = options.initialRoot;\n this.namespace = options.namespace || DEFAULT_CONFIG.namespace;\n this.trustedRootTarget = options.trustedRootTarget || DEFAULT_CONFIG.trustedRootTarget;\n this.cacheTTL = options.cacheTTL ?? DEFAULT_CONFIG.cacheTTL;\n this.disableCache = options.disableCache ?? false;\n }\n\n /**\n * Initialize the TUF client\n * Lazy initialization to avoid loading TUF client until needed\n */\n private async initTUFClient(): Promise<void> {\n if (this.tufClient) {\n return;\n }\n\n try {\n const { TUFClient } = await import('@freedomofpress/tuf-browser');\n\n // Get initial root metadata\n const rootMetadata = this.initialRoot || await this.getDefaultRoot();\n\n this.tufClient = new TUFClient(\n this.metadataUrl,\n rootMetadata,\n this.namespace,\n this.targetBaseUrl,\n { disableCache: this.disableCache }\n );\n } catch (error) {\n throw new Error(\n `Failed to initialize TUF client: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Get the default embedded root metadata\n * Returns the TUF root.json that bootstraps the TUF client\n */\n private async getDefaultRoot(): Promise<string> {\n // Import the embedded TUF root metadata (base64-encoded 1.root.json as string)\n // This is the root of trust for TUF, not to be confused with the Sigstore trusted root\n const { default: tufRootBase64 } = await import('./tuf-root.js');\n\n // Decode from base64 to get the actual root.json content\n const decoder = new TextDecoder();\n const rootBytes = Uint8Array.from(atob(tufRootBase64), c => c.charCodeAt(0));\n return decoder.decode(rootBytes);\n }\n\n /**\n * Check if cached trusted root is still valid\n */\n private isCacheValid(): boolean {\n if (!this.cachedRoot || !this.cacheTimestamp) {\n return false;\n }\n\n const now = Date.now();\n return (now - this.cacheTimestamp) < this.cacheTTL;\n }\n\n /**\n * Get the Sigstore trusted root metadata\n * Uses TUF to securely fetch and verify the trusted root\n *\n * @returns Promise<TrustedRoot> The verified trusted root metadata\n * @throws Error if TUF verification fails or root cannot be fetched\n */\n async getTrustedRoot(): Promise<TrustedRoot> {\n // Return cached root if still valid\n if (this.isCacheValid() && this.cachedRoot) {\n return this.cachedRoot;\n }\n\n // Initialize TUF client if needed\n await this.initTUFClient();\n\n if (!this.tufClient) {\n throw new Error('TUF client not initialized');\n }\n\n try {\n // Update TUF metadata (root, timestamp, snapshot, targets)\n // This must be called before getTarget() to populate the metadata cache\n await this.tufClient.updateTUF();\n\n // Fetch the trusted root target via TUF\n // TUF will handle all verification (signatures, rollback protection, etc.)\n const trustedRootBuffer = await this.tufClient.getTarget(this.trustedRootTarget);\n\n // Parse the trusted root JSON\n const trustedRootJson = Uint8ArrayToString(new Uint8Array(trustedRootBuffer));\n const trustedRoot = JSON.parse(trustedRootJson) as TrustedRoot;\n\n // Cache the result\n this.cachedRoot = trustedRoot;\n this.cacheTimestamp = Date.now();\n\n return trustedRoot;\n } catch (error) {\n throw new Error(\n `Failed to fetch trusted root via TUF: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Manually refresh the trusted root from TUF\n * Bypasses cache and forces a fresh fetch\n *\n * @returns Promise<TrustedRoot> The updated trusted root metadata\n */\n async refreshTrustedRoot(): Promise<TrustedRoot> {\n // Clear cache\n this.cachedRoot = undefined;\n this.cacheTimestamp = undefined;\n\n // Fetch fresh root\n return await this.getTrustedRoot();\n }\n\n /**\n * Clear the cached trusted root\n * Next call to getTrustedRoot() will fetch fresh data\n */\n clearCache(): void {\n this.cachedRoot = undefined;\n this.cacheTimestamp = undefined;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tuf.js","sourceRoot":"","sources":["../../src/trust/tuf.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * TUF (The Update Framework) integration for trusted root management\n *\n * Provides secure updates for Sigstore trusted root metadata using TUF.\n * Uses tuf-browser for browser-compatible TUF client functionality.\n *\n * Reference: https://github.com/freedomofpress/tuf-browser\n */\n\nimport { base64Decode, Uint8ArrayToString } from \"@freedomofpress/crypto-browser\";\nimport type { TUFClient } from \"@freedomofpress/tuf-browser\";\n\nimport { TrustedRoot } from \"../interfaces.js\";\n\n/**\n * Options for TrustedRootProvider configuration\n */\nexport interface TrustedRootProviderOptions {\n /**\n * TUF repository URL for metadata\n * Default: Sigstore production TUF repository\n */\n metadataUrl?: string;\n\n /**\n * Target base URL for fetching target files\n * If not specified, uses the same as metadataUrl\n */\n targetBaseUrl?: string;\n\n /**\n * Initial root metadata (1.root.json content)\n * If not provided, will use embedded default\n */\n initialRoot?: string;\n\n /**\n * Namespace for TUF cache storage\n * Default: 'tuf-cache'\n */\n namespace?: string;\n\n /**\n * Name of the trusted root target file\n * Default: 'trusted_root.json'\n */\n trustedRootTarget?: string;\n\n /**\n * Cache TTL in milliseconds\n * Default: 1 hour (3600000 ms)\n */\n cacheTTL?: number;\n\n /**\n * Disable persistent caching (use in-memory only)\n * Default: false\n */\n disableCache?: boolean;\n}\n\n/**\n * Default configuration for Sigstore production TUF repository\n */\nconst DEFAULT_CONFIG = {\n metadataUrl: 'https://tuf-repo-cdn.sigstore.dev/',\n targetBaseUrl: 'https://tuf-repo-cdn.sigstore.dev/targets/',\n namespace: 'tuf-cache',\n trustedRootTarget: 'trusted_root.json',\n cacheTTL: 3600000, // 1 hour\n};\n\n/**\n * Provides Sigstore trusted root via TUF for secure updates\n *\n * This class manages fetching and caching of Sigstore trusted root metadata\n * using The Update Framework (TUF) for secure, verified updates.\n *\n * Example usage:\n * ```typescript\n * const provider = new TrustedRootProvider();\n * const trustedRoot = await provider.getTrustedRoot();\n * ```\n */\nexport class TrustedRootProvider {\n private metadataUrl: string;\n private targetBaseUrl?: string;\n private initialRoot?: string;\n private namespace: string;\n private trustedRootTarget: string;\n private cacheTTL: number;\n private disableCache: boolean;\n\n private tufClient?: TUFClient;\n private cachedRoot?: TrustedRoot;\n private cacheTimestamp?: number;\n\n constructor(options: TrustedRootProviderOptions = {}) {\n const metadataUrl = options.metadataUrl || DEFAULT_CONFIG.metadataUrl;\n this.metadataUrl = metadataUrl.endsWith('/') ? metadataUrl : `${metadataUrl}/`;\n const targetBaseUrl = options.targetBaseUrl || DEFAULT_CONFIG.targetBaseUrl;\n this.targetBaseUrl = targetBaseUrl.endsWith('/') ? targetBaseUrl : `${targetBaseUrl}/`;\n this.initialRoot = options.initialRoot;\n this.namespace = options.namespace || DEFAULT_CONFIG.namespace;\n this.trustedRootTarget = options.trustedRootTarget || DEFAULT_CONFIG.trustedRootTarget;\n this.cacheTTL = options.cacheTTL ?? DEFAULT_CONFIG.cacheTTL;\n this.disableCache = options.disableCache ?? false;\n }\n\n /**\n * Initialize the TUF client\n * Lazy initialization to avoid loading TUF client until needed\n */\n private async initTUFClient(): Promise<void> {\n if (this.tufClient) {\n return;\n }\n\n try {\n const { TUFClient } = await import('@freedomofpress/tuf-browser');\n\n // Get initial root metadata\n const rootMetadata = this.initialRoot || await this.getDefaultRoot();\n\n this.tufClient = new TUFClient(\n this.metadataUrl,\n rootMetadata,\n this.namespace,\n this.targetBaseUrl,\n { disableCache: this.disableCache }\n );\n } catch (error) {\n throw new Error(\n `Failed to initialize TUF client: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Get the default embedded root metadata\n * Returns the TUF root.json that bootstraps the TUF client\n */\n private async getDefaultRoot(): Promise<string> {\n // Import the embedded TUF root metadata (base64-encoded 1.root.json as string)\n // This is the root of trust for TUF, not to be confused with the Sigstore trusted root\n const { default: tufRootBase64 } = await import('./tuf-root.js');\n\n return base64Decode(tufRootBase64);\n }\n\n /**\n * Check if cached trusted root is still valid\n */\n private isCacheValid(): boolean {\n if (!this.cachedRoot || !this.cacheTimestamp) {\n return false;\n }\n\n const now = Date.now();\n return (now - this.cacheTimestamp) < this.cacheTTL;\n }\n\n /**\n * Get the Sigstore trusted root metadata\n * Uses TUF to securely fetch and verify the trusted root\n *\n * @returns Promise<TrustedRoot> The verified trusted root metadata\n * @throws Error if TUF verification fails or root cannot be fetched\n */\n async getTrustedRoot(): Promise<TrustedRoot> {\n // Return cached root if still valid\n if (this.isCacheValid() && this.cachedRoot) {\n return this.cachedRoot;\n }\n\n // Initialize TUF client if needed\n await this.initTUFClient();\n\n if (!this.tufClient) {\n throw new Error('TUF client not initialized');\n }\n\n try {\n // Update TUF metadata (root, timestamp, snapshot, targets)\n // This must be called before getTarget() to populate the metadata cache\n await this.tufClient.updateTUF();\n\n // Fetch the trusted root target via TUF\n // TUF will handle all verification (signatures, rollback protection, etc.)\n const trustedRootBuffer = await this.tufClient.getTarget(this.trustedRootTarget);\n\n // Parse the trusted root JSON\n const trustedRootJson = Uint8ArrayToString(new Uint8Array(trustedRootBuffer));\n const trustedRoot = JSON.parse(trustedRootJson) as TrustedRoot;\n\n // Cache the result\n this.cachedRoot = trustedRoot;\n this.cacheTimestamp = Date.now();\n\n return trustedRoot;\n } catch (error) {\n throw new Error(\n `Failed to fetch trusted root via TUF: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Manually refresh the trusted root from TUF\n * Bypasses cache and forces a fresh fetch\n *\n * @returns Promise<TrustedRoot> The updated trusted root metadata\n */\n async refreshTrustedRoot(): Promise<TrustedRoot> {\n // Clear cache\n this.cachedRoot = undefined;\n this.cacheTimestamp = undefined;\n\n // Fetch fresh root\n return await this.getTrustedRoot();\n }\n\n /**\n * Clear the cached trusted root\n * Next call to getTrustedRoot() will fetch fresh data\n */\n clearCache(): void {\n this.cachedRoot = undefined;\n this.cacheTimestamp = undefined;\n }\n}\n"]}
|
package/dist/x509/cert.js
CHANGED
|
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { ASN1Obj, importKey, toDER, uint8ArrayEqual, Uint8ArrayToBase64,
|
|
16
|
+
import { ASN1Obj, importKey, toDER, uint8ArrayEqual, Uint8ArrayToBase64, Uint8ArrayToString, verifySignature } from "@freedomofpress/crypto-browser";
|
|
17
17
|
import { KeyTypes } from "../interfaces.js";
|
|
18
18
|
import { DEFAULT_HASH_ALGORITHM, ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, OID_RSASSA_PSS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from "../oid.js";
|
|
19
19
|
import { X509AuthorityKeyIDExtension, X509BasicConstraintsExtension, X509BuildConfigDigestExtension, X509BuildConfigURIExtension, X509BuildSignerDigestExtension, X509BuildSignerURIExtension, X509BuildTriggerExtension, X509Extension, X509FulcioIssuerV1, X509FulcioIssuerV2, X509GitHubWorkflowNameExtension, X509GitHubWorkflowRefExtension, X509GitHubWorkflowRepositoryExtension, X509GitHubWorkflowSHAExtension, X509GitHubWorkflowTriggerExtension, X509KeyUsageExtension, X509RunInvocationURIExtension, X509RunnerEnvironmentExtension, X509SCTExtension, X509SourceRepositoryDigestExtension, X509SourceRepositoryIdentifierExtension, X509SourceRepositoryOwnerIdentifierExtension, X509SourceRepositoryOwnerURIExtension, X509SourceRepositoryRefExtension, X509SourceRepositoryURIExtension, X509SourceRepositoryVisibilityExtension, X509SubjectAlternativeNameExtension, X509SubjectKeyIDExtension, } from "./ext.js";
|
|
@@ -426,7 +426,7 @@ export class X509Certificate {
|
|
|
426
426
|
const oid = oidObj.toOID();
|
|
427
427
|
const attrName = DN_OID_TO_NAME[oid];
|
|
428
428
|
if (attrName) {
|
|
429
|
-
const value =
|
|
429
|
+
const value = Uint8ArrayToString(valueObj.value);
|
|
430
430
|
result.set(attrName, value);
|
|
431
431
|
}
|
|
432
432
|
}
|
package/dist/x509/cert.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cert.js","sourceRoot":"","sources":["../../src/x509/cert.ts"],"names":[],"mappings":"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","sourcesContent":["/*\nCopyright 2023 The Sigstore Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport {\n ASN1Obj,\n importKey,\n toDER,\n uint8ArrayEqual,\n Uint8ArrayToBase64,\n verifySignature,\n} from \"@freedomofpress/crypto-browser\";\n\nimport { KeyTypes } from \"../interfaces.js\";\nimport { DEFAULT_HASH_ALGORITHM, ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, OID_RSASSA_PSS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from \"../oid.js\";\nimport {\n X509AuthorityKeyIDExtension,\n X509BasicConstraintsExtension,\n X509BuildConfigDigestExtension,\n X509BuildConfigURIExtension,\n X509BuildSignerDigestExtension,\n X509BuildSignerURIExtension,\n X509BuildTriggerExtension,\n X509Extension,\n X509FulcioIssuerV1,\n X509FulcioIssuerV2,\n X509GitHubWorkflowNameExtension,\n X509GitHubWorkflowRefExtension,\n X509GitHubWorkflowRepositoryExtension,\n X509GitHubWorkflowSHAExtension,\n X509GitHubWorkflowTriggerExtension,\n X509KeyUsageExtension,\n X509RunInvocationURIExtension,\n X509RunnerEnvironmentExtension,\n X509SCTExtension,\n X509SourceRepositoryDigestExtension,\n X509SourceRepositoryIdentifierExtension,\n X509SourceRepositoryOwnerIdentifierExtension,\n X509SourceRepositoryOwnerURIExtension,\n X509SourceRepositoryRefExtension,\n X509SourceRepositoryURIExtension,\n X509SourceRepositoryVisibilityExtension,\n X509SubjectAlternativeNameExtension,\n X509SubjectKeyIDExtension,\n} from \"./ext.js\";\n\n// Standard X.509 extension OIDs\nconst EXTENSION_OID_SUBJECT_KEY_ID = \"2.5.29.14\";\nconst EXTENSION_OID_KEY_USAGE = \"2.5.29.15\";\nconst EXTENSION_OID_SUBJECT_ALT_NAME = \"2.5.29.17\";\nconst EXTENSION_OID_BASIC_CONSTRAINTS = \"2.5.29.19\";\nconst EXTENSION_OID_AUTHORITY_KEY_ID = \"2.5.29.35\";\n\n// CT Log SCT extension OID\nexport const EXTENSION_OID_SCT = \"1.3.6.1.4.1.11129.2.4.2\";\n\n// Distinguished Name attribute OIDs (X.500)\nconst DN_OID_COMMON_NAME = \"2.5.4.3\";\nconst DN_OID_COUNTRY = \"2.5.4.6\";\nconst DN_OID_LOCALITY = \"2.5.4.7\";\nconst DN_OID_STATE = \"2.5.4.8\";\nconst DN_OID_ORGANIZATION = \"2.5.4.10\";\nconst DN_OID_ORGANIZATIONAL_UNIT = \"2.5.4.11\";\n\nconst DN_OID_TO_NAME: Record<string, string> = {\n [DN_OID_COMMON_NAME]: \"CN\",\n [DN_OID_COUNTRY]: \"C\",\n [DN_OID_LOCALITY]: \"L\",\n [DN_OID_STATE]: \"ST\",\n [DN_OID_ORGANIZATION]: \"O\",\n [DN_OID_ORGANIZATIONAL_UNIT]: \"OU\",\n};\n\n// Fulcio extension OIDs\n// https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md\nexport const EXTENSION_OID_FULCIO_ISSUER_V1 = \"1.3.6.1.4.1.57264.1.1\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_TRIGGER = \"1.3.6.1.4.1.57264.1.2\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_SHA = \"1.3.6.1.4.1.57264.1.3\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_NAME = \"1.3.6.1.4.1.57264.1.4\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_REPOSITORY = \"1.3.6.1.4.1.57264.1.5\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_REF = \"1.3.6.1.4.1.57264.1.6\";\nexport const EXTENSION_OID_OTHERNAME = \"1.3.6.1.4.1.57264.1.7\";\nexport const EXTENSION_OID_FULCIO_ISSUER_V2 = \"1.3.6.1.4.1.57264.1.8\";\nexport const EXTENSION_OID_BUILD_SIGNER_URI = \"1.3.6.1.4.1.57264.1.9\";\nexport const EXTENSION_OID_BUILD_SIGNER_DIGEST = \"1.3.6.1.4.1.57264.1.10\";\nexport const EXTENSION_OID_RUNNER_ENVIRONMENT = \"1.3.6.1.4.1.57264.1.11\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_URI = \"1.3.6.1.4.1.57264.1.12\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_DIGEST = \"1.3.6.1.4.1.57264.1.13\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_REF = \"1.3.6.1.4.1.57264.1.14\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_IDENTIFIER = \"1.3.6.1.4.1.57264.1.15\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_OWNER_URI = \"1.3.6.1.4.1.57264.1.16\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_OWNER_IDENTIFIER = \"1.3.6.1.4.1.57264.1.17\";\nexport const EXTENSION_OID_BUILD_CONFIG_URI = \"1.3.6.1.4.1.57264.1.18\";\nexport const EXTENSION_OID_BUILD_CONFIG_DIGEST = \"1.3.6.1.4.1.57264.1.19\";\nexport const EXTENSION_OID_BUILD_TRIGGER = \"1.3.6.1.4.1.57264.1.20\";\nexport const EXTENSION_OID_RUN_INVOCATION_URI = \"1.3.6.1.4.1.57264.1.21\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_VISIBILITY = \"1.3.6.1.4.1.57264.1.22\";\n\nexport class X509Certificate {\n public root: ASN1Obj;\n\n constructor(asn1: ASN1Obj) {\n this.root = asn1;\n }\n\n public static parse(cert: Uint8Array | string): X509Certificate {\n const der = typeof cert === \"string\" ? toDER(cert) : cert;\n const asn1 = ASN1Obj.parseBuffer(der);\n return new X509Certificate(asn1);\n }\n\n get tbsCertificate(): ASN1Obj {\n return this.tbsCertificateObj;\n }\n\n get version(): string {\n // version number is the first element of the version context specific tag\n const ver = this.versionObj.subs[0].toInteger();\n return `v${(ver + BigInt(1)).toString()}`;\n }\n\n get serialNumber(): Uint8Array {\n return this.serialNumberObj.value;\n }\n\n get notBefore(): Date {\n // notBefore is the first element of the validity sequence\n return this.validityObj.subs[0].toDate();\n }\n\n get notAfter(): Date {\n // notAfter is the second element of the validity sequence\n return this.validityObj.subs[1].toDate();\n }\n\n get issuer(): Uint8Array {\n return this.issuerObj.value;\n }\n\n get subject(): Uint8Array {\n return this.subjectObj.value;\n }\n\n /**\n * Returns the issuer distinguished name as a Map of attribute names to values.\n * Common attributes: CN (Common Name), O (Organization), L (Locality),\n * ST (State), C (Country), OU (Organizational Unit)\n */\n get issuerDN(): Map<string, string> {\n return this.parseDistinguishedName(this.issuerObj);\n }\n\n /**\n * Returns the subject distinguished name as a Map of attribute names to values.\n * Common attributes: CN (Common Name), O (Organization), L (Locality),\n * ST (State), C (Country), OU (Organizational Unit)\n */\n get subjectDN(): Map<string, string> {\n return this.parseDistinguishedName(this.subjectObj);\n }\n\n get publicKey(): Uint8Array {\n return this.subjectPublicKeyInfoObj.toDER();\n }\n\n /**\n * Import the public key with a specific hash algorithm and signature scheme for RSA keys.\n * For ECDSA keys, both parameters are ignored.\n * @param hashAlg - Hash algorithm (e.g., \"sha384\") for RSA keys\n * @param usePss - If true, import as RSA-PSS key; if false, import as PKCS#1 v1.5\n */\n public async getPublicKeyObj(hashAlg?: string, usePss?: boolean): Promise<CryptoKey> {\n const publicKey = this.subjectPublicKeyInfoObj.toDER();\n const spki = ASN1Obj.parseBuffer(publicKey);\n const algorithmOID = spki.subs[0].subs[0].toOID();\n\n // RSA key (OID 1.2.840.113549.1.1.1) or RSA-PSS key (OID 1.2.840.113549.1.1.10)\n const isRsaKey = algorithmOID === \"1.2.840.113549.1.1.1\";\n const isRsaPssKey = algorithmOID === OID_RSASSA_PSS;\n\n if (isRsaPssKey) {\n // WebCrypto doesn't support importing keys with id-RSASSA-PSS OID, only rsaEncryption\n throw new Error(\n \"RSA-PSS public keys (id-RSASSA-PSS OID) are not supported by WebCrypto. \" +\n \"Only certificates with standard RSA keys (rsaEncryption OID) signed using RSA-PSS are supported.\"\n );\n }\n\n if (isRsaKey) {\n const hash = hashAlg || DEFAULT_HASH_ALGORITHM;\n // crypto-browser extracts hash from scheme and uses PSS unless \"PKCS1\" is present\n const scheme = usePss ? hash : `PKCS1_${hash}`;\n return importKey(KeyTypes.RSA, scheme, Uint8ArrayToBase64(publicKey));\n } else {\n // ECDSA key - the curve OID is in the second element\n const curveOID = spki.subs[0].subs[1]?.toOID();\n const curve = ECDSA_CURVE_NAMES[curveOID];\n if (!curve) {\n throw new Error(`Unknown ECDSA curve OID: ${curveOID}`);\n }\n return importKey(KeyTypes.Ecdsa, curve, Uint8ArrayToBase64(publicKey));\n }\n }\n\n get publicKeyObj(): Promise<CryptoKey> {\n return this.getPublicKeyObj();\n }\n\n get signatureAlgorithm(): string {\n const oid: string = this.signatureAlgorithmObj.subs[0].toOID();\n return ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid] || this.parseRsaPssHashAlgorithm();\n }\n\n get signatureAlgorithmOid(): string {\n return this.signatureAlgorithmObj.subs[0].toOID();\n }\n\n /**\n * Parse hash algorithm from RSA-PSS signature algorithm parameters.\n * RSA-PSS parameters are: SEQUENCE { hashAlgorithm, maskGenAlgorithm, saltLength, trailerField }\n */\n private parseRsaPssHashAlgorithm(): string {\n const sigAlgOid = this.signatureAlgorithmObj.subs[0].toOID();\n if (sigAlgOid !== OID_RSASSA_PSS) {\n return \"\";\n }\n\n // RSA-PSS has parameters in the second element of the signature algorithm sequence\n const params = this.signatureAlgorithmObj.subs[1];\n if (!params || params.subs.length === 0) {\n return DEFAULT_HASH_ALGORITHM;\n }\n\n // First element is hashAlgorithm [0] EXPLICIT\n const hashAlgWrapper = params.subs[0];\n if (hashAlgWrapper && hashAlgWrapper.subs.length > 0) {\n // The wrapper contains a SEQUENCE with the hash algorithm OID\n const hashAlgSeq = hashAlgWrapper.subs[0];\n if (hashAlgSeq && hashAlgSeq.subs.length > 0) {\n const hashOid = hashAlgSeq.subs[0].toOID();\n return SHA2_HASH_ALGOS[hashOid] || DEFAULT_HASH_ALGORITHM;\n }\n }\n\n return DEFAULT_HASH_ALGORITHM;\n }\n\n get signatureValue(): Uint8Array {\n // Signature value is a bit string, so we need to skip the first byte\n return this.signatureValueObj.value.subarray(1);\n }\n\n get subjectAltName(): string | undefined {\n const ext = this.extSubjectAltName;\n return ext?.uri || ext?.rfc822Name;\n }\n\n get extensions(): ASN1Obj[] {\n // The extension list is the first (and only) element of the extensions\n // context specific tag\n const extSeq = this.extensionsObj?.subs[0];\n return extSeq?.subs || /* istanbul ignore next */ [];\n }\n\n get extKeyUsage(): X509KeyUsageExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_KEY_USAGE);\n return ext ? new X509KeyUsageExtension(ext) : undefined;\n }\n\n get extBasicConstraints(): X509BasicConstraintsExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BASIC_CONSTRAINTS);\n return ext ? new X509BasicConstraintsExtension(ext) : undefined;\n }\n\n get extSubjectAltName(): X509SubjectAlternativeNameExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SUBJECT_ALT_NAME);\n return ext ? new X509SubjectAlternativeNameExtension(ext) : undefined;\n }\n\n get extAuthorityKeyID(): X509AuthorityKeyIDExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_AUTHORITY_KEY_ID);\n return ext ? new X509AuthorityKeyIDExtension(ext) : undefined;\n }\n\n get extSubjectKeyID(): X509SubjectKeyIDExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SUBJECT_KEY_ID);\n return ext\n ? new X509SubjectKeyIDExtension(ext)\n : /* istanbul ignore next */ undefined;\n }\n\n get extSCT(): X509SCTExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SCT);\n return ext ? new X509SCTExtension(ext) : undefined;\n }\n\n get extFulcioIssuerV1(): X509FulcioIssuerV1 | undefined {\n const ext = this.findExtension(EXTENSION_OID_FULCIO_ISSUER_V1);\n return ext ? new X509FulcioIssuerV1(ext) : undefined;\n }\n\n get extFulcioIssuerV2(): X509FulcioIssuerV2 | undefined {\n const ext = this.findExtension(EXTENSION_OID_FULCIO_ISSUER_V2);\n return ext ? new X509FulcioIssuerV2(ext) : undefined;\n }\n\n get extGitHubWorkflowTrigger(): X509GitHubWorkflowTriggerExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_TRIGGER);\n return ext ? new X509GitHubWorkflowTriggerExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowSHA(): X509GitHubWorkflowSHAExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_SHA);\n return ext ? new X509GitHubWorkflowSHAExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowName(): X509GitHubWorkflowNameExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_NAME);\n return ext ? new X509GitHubWorkflowNameExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowRepository(): X509GitHubWorkflowRepositoryExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_REPOSITORY);\n return ext ? new X509GitHubWorkflowRepositoryExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowRef(): X509GitHubWorkflowRefExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_REF);\n return ext ? new X509GitHubWorkflowRefExtension(ext) : undefined;\n }\n\n get extBuildSignerURI(): X509BuildSignerURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_SIGNER_URI);\n return ext ? new X509BuildSignerURIExtension(ext) : undefined;\n }\n\n get extBuildSignerDigest(): X509BuildSignerDigestExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_SIGNER_DIGEST);\n return ext ? new X509BuildSignerDigestExtension(ext) : undefined;\n }\n\n get extRunnerEnvironment(): X509RunnerEnvironmentExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_RUNNER_ENVIRONMENT);\n return ext ? new X509RunnerEnvironmentExtension(ext) : undefined;\n }\n\n get extSourceRepositoryURI(): X509SourceRepositoryURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_URI);\n return ext ? new X509SourceRepositoryURIExtension(ext) : undefined;\n }\n\n get extSourceRepositoryDigest(): X509SourceRepositoryDigestExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_DIGEST);\n return ext ? new X509SourceRepositoryDigestExtension(ext) : undefined;\n }\n\n get extSourceRepositoryRef(): X509SourceRepositoryRefExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_REF);\n return ext ? new X509SourceRepositoryRefExtension(ext) : undefined;\n }\n\n get extSourceRepositoryIdentifier(): X509SourceRepositoryIdentifierExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_IDENTIFIER);\n return ext ? new X509SourceRepositoryIdentifierExtension(ext) : undefined;\n }\n\n get extSourceRepositoryOwnerURI(): X509SourceRepositoryOwnerURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_OWNER_URI);\n return ext ? new X509SourceRepositoryOwnerURIExtension(ext) : undefined;\n }\n\n get extSourceRepositoryOwnerIdentifier(): X509SourceRepositoryOwnerIdentifierExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_OWNER_IDENTIFIER);\n return ext ? new X509SourceRepositoryOwnerIdentifierExtension(ext) : undefined;\n }\n\n get extBuildConfigURI(): X509BuildConfigURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_CONFIG_URI);\n return ext ? new X509BuildConfigURIExtension(ext) : undefined;\n }\n\n get extBuildConfigDigest(): X509BuildConfigDigestExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_CONFIG_DIGEST);\n return ext ? new X509BuildConfigDigestExtension(ext) : undefined;\n }\n\n get extBuildTrigger(): X509BuildTriggerExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_TRIGGER);\n return ext ? new X509BuildTriggerExtension(ext) : undefined;\n }\n\n get extRunInvocationURI(): X509RunInvocationURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_RUN_INVOCATION_URI);\n return ext ? new X509RunInvocationURIExtension(ext) : undefined;\n }\n\n get extSourceRepositoryVisibility(): X509SourceRepositoryVisibilityExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_VISIBILITY);\n return ext ? new X509SourceRepositoryVisibilityExtension(ext) : undefined;\n }\n\n get isCA(): boolean {\n const ca = this.extBasicConstraints?.isCA || false;\n\n // If the KeyUsage extension is present, keyCertSign must be set\n if (this.extKeyUsage) {\n return ca && this.extKeyUsage.keyCertSign;\n }\n\n return ca;\n }\n\n public extension(oid: string): X509Extension | undefined {\n const ext = this.findExtension(oid);\n return ext ? new X509Extension(ext) : undefined;\n }\n\n public async verify(issuerCertificate?: X509Certificate): Promise<boolean> {\n // Extract the hash algorithm from this certificate's signature algorithm\n const sigAlgOID = this.signatureAlgorithmOid;\n const isRsaPss = sigAlgOID === OID_RSASSA_PSS;\n\n // Get hash algorithm - for RSA-PSS, parse from parameters; otherwise lookup in tables\n const hashAlg = isRsaPss\n ? this.parseRsaPssHashAlgorithm()\n : (RSA_SIGNATURE_ALGOS[sigAlgOID] || ECDSA_SIGNATURE_ALGOS[sigAlgOID]);\n\n // Use the issuer's public key if provided, otherwise use the subject's (for self-signed certs)\n // Import with the correct hash algorithm and key type for this certificate's signature\n const publicKeyObj = issuerCertificate\n ? await issuerCertificate.getPublicKeyObj(hashAlg, isRsaPss)\n : await this.getPublicKeyObj(hashAlg, isRsaPss);\n\n return await verifySignature(\n publicKeyObj,\n this.tbsCertificate.toDER(),\n this.signatureValue,\n this.signatureAlgorithm,\n );\n }\n\n public validForDate(date: Date): boolean {\n return this.notBefore <= date && date <= this.notAfter;\n }\n\n public equals(other: X509Certificate): boolean {\n return uint8ArrayEqual(this.root.toDER(), other.root.toDER());\n }\n\n // Creates a copy of the certificate with a new buffer\n public clone(): X509Certificate {\n const der = this.root.toDER();\n const clone = new Uint8Array(der);\n return X509Certificate.parse(clone);\n }\n\n private findExtension(oid: string): ASN1Obj | undefined {\n // Find the extension with the given OID. The OID will always be the first\n // element of the extension sequence\n return this.extensions.find((ext) => ext.subs[0].toOID() === oid);\n }\n\n /////////////////////////////////////////////////////////////////////////////\n // The following properties use the documented x509 structure to locate the\n // desired ASN.1 object\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.1\n private get tbsCertificateObj(): ASN1Obj {\n // tbsCertificate is the first element of the certificate sequence\n return this.root.subs[0];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2\n private get signatureAlgorithmObj(): ASN1Obj {\n // signatureAlgorithm is the second element of the certificate sequence\n return this.root.subs[1];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.3\n private get signatureValueObj(): ASN1Obj {\n // signatureValue is the third element of the certificate sequence\n return this.root.subs[2];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.1\n private get versionObj(): ASN1Obj {\n // version is the first element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[0];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.2\n private get serialNumberObj(): ASN1Obj {\n // serialNumber is the second element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[1];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.4\n private get issuerObj(): ASN1Obj {\n // issuer is the fourth element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[3];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5\n private get validityObj(): ASN1Obj {\n // version is the fifth element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[4];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.6\n private get subjectObj(): ASN1Obj {\n // subject is the sixth element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[5];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7\n private get subjectPublicKeyInfoObj(): ASN1Obj {\n // subjectPublicKeyInfo is the seventh element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[6];\n }\n\n // Extensions can't be located by index because their position varies. Instead,\n // we need to find the extensions context specific tag\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.9\n private get extensionsObj(): ASN1Obj | undefined {\n return this.tbsCertificateObj.subs.find((sub) =>\n sub.tag.isContextSpecific(0x03),\n );\n }\n\n // Parse a Distinguished Name (issuer or subject) ASN1Obj into a Map\n // DN structure: SEQUENCE of SET of SEQUENCE (AttributeTypeAndValue)\n // Each AttributeTypeAndValue is [OID, value]\n private parseDistinguishedName(dnObj: ASN1Obj): Map<string, string> {\n const result = new Map<string, string>();\n\n // Iterate over RDNs (RelativeDistinguishedName - each is a SET)\n for (const rdn of dnObj.subs) {\n // Each RDN contains one or more AttributeTypeAndValue (SEQUENCE)\n for (const atv of rdn.subs) {\n if (atv.subs.length >= 2) {\n const oidObj = atv.subs[0];\n const valueObj = atv.subs[1];\n\n if (oidObj.tag.isOID()) {\n const oid = oidObj.toOID();\n const attrName = DN_OID_TO_NAME[oid];\n if (attrName) {\n const value = new TextDecoder().decode(valueObj.value);\n result.set(attrName, value);\n }\n }\n }\n }\n }\n\n return result;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cert.js","sourceRoot":"","sources":["../../src/x509/cert.ts"],"names":[],"mappings":"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","sourcesContent":["/*\nCopyright 2023 The Sigstore Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport { ASN1Obj, importKey, toDER, uint8ArrayEqual, Uint8ArrayToBase64, Uint8ArrayToString, verifySignature } from \"@freedomofpress/crypto-browser\";\n\nimport { KeyTypes } from \"../interfaces.js\";\nimport { DEFAULT_HASH_ALGORITHM, ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, OID_RSASSA_PSS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from \"../oid.js\";\nimport {\n X509AuthorityKeyIDExtension,\n X509BasicConstraintsExtension,\n X509BuildConfigDigestExtension,\n X509BuildConfigURIExtension,\n X509BuildSignerDigestExtension,\n X509BuildSignerURIExtension,\n X509BuildTriggerExtension,\n X509Extension,\n X509FulcioIssuerV1,\n X509FulcioIssuerV2,\n X509GitHubWorkflowNameExtension,\n X509GitHubWorkflowRefExtension,\n X509GitHubWorkflowRepositoryExtension,\n X509GitHubWorkflowSHAExtension,\n X509GitHubWorkflowTriggerExtension,\n X509KeyUsageExtension,\n X509RunInvocationURIExtension,\n X509RunnerEnvironmentExtension,\n X509SCTExtension,\n X509SourceRepositoryDigestExtension,\n X509SourceRepositoryIdentifierExtension,\n X509SourceRepositoryOwnerIdentifierExtension,\n X509SourceRepositoryOwnerURIExtension,\n X509SourceRepositoryRefExtension,\n X509SourceRepositoryURIExtension,\n X509SourceRepositoryVisibilityExtension,\n X509SubjectAlternativeNameExtension,\n X509SubjectKeyIDExtension,\n} from \"./ext.js\";\n\n// Standard X.509 extension OIDs\nconst EXTENSION_OID_SUBJECT_KEY_ID = \"2.5.29.14\";\nconst EXTENSION_OID_KEY_USAGE = \"2.5.29.15\";\nconst EXTENSION_OID_SUBJECT_ALT_NAME = \"2.5.29.17\";\nconst EXTENSION_OID_BASIC_CONSTRAINTS = \"2.5.29.19\";\nconst EXTENSION_OID_AUTHORITY_KEY_ID = \"2.5.29.35\";\n\n// CT Log SCT extension OID\nexport const EXTENSION_OID_SCT = \"1.3.6.1.4.1.11129.2.4.2\";\n\n// Distinguished Name attribute OIDs (X.500)\nconst DN_OID_COMMON_NAME = \"2.5.4.3\";\nconst DN_OID_COUNTRY = \"2.5.4.6\";\nconst DN_OID_LOCALITY = \"2.5.4.7\";\nconst DN_OID_STATE = \"2.5.4.8\";\nconst DN_OID_ORGANIZATION = \"2.5.4.10\";\nconst DN_OID_ORGANIZATIONAL_UNIT = \"2.5.4.11\";\n\nconst DN_OID_TO_NAME: Record<string, string> = {\n [DN_OID_COMMON_NAME]: \"CN\",\n [DN_OID_COUNTRY]: \"C\",\n [DN_OID_LOCALITY]: \"L\",\n [DN_OID_STATE]: \"ST\",\n [DN_OID_ORGANIZATION]: \"O\",\n [DN_OID_ORGANIZATIONAL_UNIT]: \"OU\",\n};\n\n// Fulcio extension OIDs\n// https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md\nexport const EXTENSION_OID_FULCIO_ISSUER_V1 = \"1.3.6.1.4.1.57264.1.1\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_TRIGGER = \"1.3.6.1.4.1.57264.1.2\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_SHA = \"1.3.6.1.4.1.57264.1.3\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_NAME = \"1.3.6.1.4.1.57264.1.4\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_REPOSITORY = \"1.3.6.1.4.1.57264.1.5\";\nexport const EXTENSION_OID_GITHUB_WORKFLOW_REF = \"1.3.6.1.4.1.57264.1.6\";\nexport const EXTENSION_OID_OTHERNAME = \"1.3.6.1.4.1.57264.1.7\";\nexport const EXTENSION_OID_FULCIO_ISSUER_V2 = \"1.3.6.1.4.1.57264.1.8\";\nexport const EXTENSION_OID_BUILD_SIGNER_URI = \"1.3.6.1.4.1.57264.1.9\";\nexport const EXTENSION_OID_BUILD_SIGNER_DIGEST = \"1.3.6.1.4.1.57264.1.10\";\nexport const EXTENSION_OID_RUNNER_ENVIRONMENT = \"1.3.6.1.4.1.57264.1.11\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_URI = \"1.3.6.1.4.1.57264.1.12\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_DIGEST = \"1.3.6.1.4.1.57264.1.13\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_REF = \"1.3.6.1.4.1.57264.1.14\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_IDENTIFIER = \"1.3.6.1.4.1.57264.1.15\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_OWNER_URI = \"1.3.6.1.4.1.57264.1.16\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_OWNER_IDENTIFIER = \"1.3.6.1.4.1.57264.1.17\";\nexport const EXTENSION_OID_BUILD_CONFIG_URI = \"1.3.6.1.4.1.57264.1.18\";\nexport const EXTENSION_OID_BUILD_CONFIG_DIGEST = \"1.3.6.1.4.1.57264.1.19\";\nexport const EXTENSION_OID_BUILD_TRIGGER = \"1.3.6.1.4.1.57264.1.20\";\nexport const EXTENSION_OID_RUN_INVOCATION_URI = \"1.3.6.1.4.1.57264.1.21\";\nexport const EXTENSION_OID_SOURCE_REPOSITORY_VISIBILITY = \"1.3.6.1.4.1.57264.1.22\";\n\nexport class X509Certificate {\n public root: ASN1Obj;\n\n constructor(asn1: ASN1Obj) {\n this.root = asn1;\n }\n\n public static parse(cert: Uint8Array | string): X509Certificate {\n const der = typeof cert === \"string\" ? toDER(cert) : cert;\n const asn1 = ASN1Obj.parseBuffer(der);\n return new X509Certificate(asn1);\n }\n\n get tbsCertificate(): ASN1Obj {\n return this.tbsCertificateObj;\n }\n\n get version(): string {\n // version number is the first element of the version context specific tag\n const ver = this.versionObj.subs[0].toInteger();\n return `v${(ver + BigInt(1)).toString()}`;\n }\n\n get serialNumber(): Uint8Array {\n return this.serialNumberObj.value;\n }\n\n get notBefore(): Date {\n // notBefore is the first element of the validity sequence\n return this.validityObj.subs[0].toDate();\n }\n\n get notAfter(): Date {\n // notAfter is the second element of the validity sequence\n return this.validityObj.subs[1].toDate();\n }\n\n get issuer(): Uint8Array {\n return this.issuerObj.value;\n }\n\n get subject(): Uint8Array {\n return this.subjectObj.value;\n }\n\n /**\n * Returns the issuer distinguished name as a Map of attribute names to values.\n * Common attributes: CN (Common Name), O (Organization), L (Locality),\n * ST (State), C (Country), OU (Organizational Unit)\n */\n get issuerDN(): Map<string, string> {\n return this.parseDistinguishedName(this.issuerObj);\n }\n\n /**\n * Returns the subject distinguished name as a Map of attribute names to values.\n * Common attributes: CN (Common Name), O (Organization), L (Locality),\n * ST (State), C (Country), OU (Organizational Unit)\n */\n get subjectDN(): Map<string, string> {\n return this.parseDistinguishedName(this.subjectObj);\n }\n\n get publicKey(): Uint8Array {\n return this.subjectPublicKeyInfoObj.toDER();\n }\n\n /**\n * Import the public key with a specific hash algorithm and signature scheme for RSA keys.\n * For ECDSA keys, both parameters are ignored.\n * @param hashAlg - Hash algorithm (e.g., \"sha384\") for RSA keys\n * @param usePss - If true, import as RSA-PSS key; if false, import as PKCS#1 v1.5\n */\n public async getPublicKeyObj(hashAlg?: string, usePss?: boolean): Promise<CryptoKey> {\n const publicKey = this.subjectPublicKeyInfoObj.toDER();\n const spki = ASN1Obj.parseBuffer(publicKey);\n const algorithmOID = spki.subs[0].subs[0].toOID();\n\n // RSA key (OID 1.2.840.113549.1.1.1) or RSA-PSS key (OID 1.2.840.113549.1.1.10)\n const isRsaKey = algorithmOID === \"1.2.840.113549.1.1.1\";\n const isRsaPssKey = algorithmOID === OID_RSASSA_PSS;\n\n if (isRsaPssKey) {\n // WebCrypto doesn't support importing keys with id-RSASSA-PSS OID, only rsaEncryption\n throw new Error(\n \"RSA-PSS public keys (id-RSASSA-PSS OID) are not supported by WebCrypto. \" +\n \"Only certificates with standard RSA keys (rsaEncryption OID) signed using RSA-PSS are supported.\"\n );\n }\n\n if (isRsaKey) {\n const hash = hashAlg || DEFAULT_HASH_ALGORITHM;\n // crypto-browser extracts hash from scheme and uses PSS unless \"PKCS1\" is present\n const scheme = usePss ? hash : `PKCS1_${hash}`;\n return importKey(KeyTypes.RSA, scheme, Uint8ArrayToBase64(publicKey));\n } else {\n // ECDSA key - the curve OID is in the second element\n const curveOID = spki.subs[0].subs[1]?.toOID();\n const curve = ECDSA_CURVE_NAMES[curveOID];\n if (!curve) {\n throw new Error(`Unknown ECDSA curve OID: ${curveOID}`);\n }\n return importKey(KeyTypes.Ecdsa, curve, Uint8ArrayToBase64(publicKey));\n }\n }\n\n get publicKeyObj(): Promise<CryptoKey> {\n return this.getPublicKeyObj();\n }\n\n get signatureAlgorithm(): string {\n const oid: string = this.signatureAlgorithmObj.subs[0].toOID();\n return ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid] || this.parseRsaPssHashAlgorithm();\n }\n\n get signatureAlgorithmOid(): string {\n return this.signatureAlgorithmObj.subs[0].toOID();\n }\n\n /**\n * Parse hash algorithm from RSA-PSS signature algorithm parameters.\n * RSA-PSS parameters are: SEQUENCE { hashAlgorithm, maskGenAlgorithm, saltLength, trailerField }\n */\n private parseRsaPssHashAlgorithm(): string {\n const sigAlgOid = this.signatureAlgorithmObj.subs[0].toOID();\n if (sigAlgOid !== OID_RSASSA_PSS) {\n return \"\";\n }\n\n // RSA-PSS has parameters in the second element of the signature algorithm sequence\n const params = this.signatureAlgorithmObj.subs[1];\n if (!params || params.subs.length === 0) {\n return DEFAULT_HASH_ALGORITHM;\n }\n\n // First element is hashAlgorithm [0] EXPLICIT\n const hashAlgWrapper = params.subs[0];\n if (hashAlgWrapper && hashAlgWrapper.subs.length > 0) {\n // The wrapper contains a SEQUENCE with the hash algorithm OID\n const hashAlgSeq = hashAlgWrapper.subs[0];\n if (hashAlgSeq && hashAlgSeq.subs.length > 0) {\n const hashOid = hashAlgSeq.subs[0].toOID();\n return SHA2_HASH_ALGOS[hashOid] || DEFAULT_HASH_ALGORITHM;\n }\n }\n\n return DEFAULT_HASH_ALGORITHM;\n }\n\n get signatureValue(): Uint8Array {\n // Signature value is a bit string, so we need to skip the first byte\n return this.signatureValueObj.value.subarray(1);\n }\n\n get subjectAltName(): string | undefined {\n const ext = this.extSubjectAltName;\n return ext?.uri || ext?.rfc822Name;\n }\n\n get extensions(): ASN1Obj[] {\n // The extension list is the first (and only) element of the extensions\n // context specific tag\n const extSeq = this.extensionsObj?.subs[0];\n return extSeq?.subs || /* istanbul ignore next */ [];\n }\n\n get extKeyUsage(): X509KeyUsageExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_KEY_USAGE);\n return ext ? new X509KeyUsageExtension(ext) : undefined;\n }\n\n get extBasicConstraints(): X509BasicConstraintsExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BASIC_CONSTRAINTS);\n return ext ? new X509BasicConstraintsExtension(ext) : undefined;\n }\n\n get extSubjectAltName(): X509SubjectAlternativeNameExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SUBJECT_ALT_NAME);\n return ext ? new X509SubjectAlternativeNameExtension(ext) : undefined;\n }\n\n get extAuthorityKeyID(): X509AuthorityKeyIDExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_AUTHORITY_KEY_ID);\n return ext ? new X509AuthorityKeyIDExtension(ext) : undefined;\n }\n\n get extSubjectKeyID(): X509SubjectKeyIDExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SUBJECT_KEY_ID);\n return ext\n ? new X509SubjectKeyIDExtension(ext)\n : /* istanbul ignore next */ undefined;\n }\n\n get extSCT(): X509SCTExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SCT);\n return ext ? new X509SCTExtension(ext) : undefined;\n }\n\n get extFulcioIssuerV1(): X509FulcioIssuerV1 | undefined {\n const ext = this.findExtension(EXTENSION_OID_FULCIO_ISSUER_V1);\n return ext ? new X509FulcioIssuerV1(ext) : undefined;\n }\n\n get extFulcioIssuerV2(): X509FulcioIssuerV2 | undefined {\n const ext = this.findExtension(EXTENSION_OID_FULCIO_ISSUER_V2);\n return ext ? new X509FulcioIssuerV2(ext) : undefined;\n }\n\n get extGitHubWorkflowTrigger(): X509GitHubWorkflowTriggerExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_TRIGGER);\n return ext ? new X509GitHubWorkflowTriggerExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowSHA(): X509GitHubWorkflowSHAExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_SHA);\n return ext ? new X509GitHubWorkflowSHAExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowName(): X509GitHubWorkflowNameExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_NAME);\n return ext ? new X509GitHubWorkflowNameExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowRepository(): X509GitHubWorkflowRepositoryExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_REPOSITORY);\n return ext ? new X509GitHubWorkflowRepositoryExtension(ext) : undefined;\n }\n\n get extGitHubWorkflowRef(): X509GitHubWorkflowRefExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_REF);\n return ext ? new X509GitHubWorkflowRefExtension(ext) : undefined;\n }\n\n get extBuildSignerURI(): X509BuildSignerURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_SIGNER_URI);\n return ext ? new X509BuildSignerURIExtension(ext) : undefined;\n }\n\n get extBuildSignerDigest(): X509BuildSignerDigestExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_SIGNER_DIGEST);\n return ext ? new X509BuildSignerDigestExtension(ext) : undefined;\n }\n\n get extRunnerEnvironment(): X509RunnerEnvironmentExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_RUNNER_ENVIRONMENT);\n return ext ? new X509RunnerEnvironmentExtension(ext) : undefined;\n }\n\n get extSourceRepositoryURI(): X509SourceRepositoryURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_URI);\n return ext ? new X509SourceRepositoryURIExtension(ext) : undefined;\n }\n\n get extSourceRepositoryDigest(): X509SourceRepositoryDigestExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_DIGEST);\n return ext ? new X509SourceRepositoryDigestExtension(ext) : undefined;\n }\n\n get extSourceRepositoryRef(): X509SourceRepositoryRefExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_REF);\n return ext ? new X509SourceRepositoryRefExtension(ext) : undefined;\n }\n\n get extSourceRepositoryIdentifier(): X509SourceRepositoryIdentifierExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_IDENTIFIER);\n return ext ? new X509SourceRepositoryIdentifierExtension(ext) : undefined;\n }\n\n get extSourceRepositoryOwnerURI(): X509SourceRepositoryOwnerURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_OWNER_URI);\n return ext ? new X509SourceRepositoryOwnerURIExtension(ext) : undefined;\n }\n\n get extSourceRepositoryOwnerIdentifier(): X509SourceRepositoryOwnerIdentifierExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_OWNER_IDENTIFIER);\n return ext ? new X509SourceRepositoryOwnerIdentifierExtension(ext) : undefined;\n }\n\n get extBuildConfigURI(): X509BuildConfigURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_CONFIG_URI);\n return ext ? new X509BuildConfigURIExtension(ext) : undefined;\n }\n\n get extBuildConfigDigest(): X509BuildConfigDigestExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_CONFIG_DIGEST);\n return ext ? new X509BuildConfigDigestExtension(ext) : undefined;\n }\n\n get extBuildTrigger(): X509BuildTriggerExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_BUILD_TRIGGER);\n return ext ? new X509BuildTriggerExtension(ext) : undefined;\n }\n\n get extRunInvocationURI(): X509RunInvocationURIExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_RUN_INVOCATION_URI);\n return ext ? new X509RunInvocationURIExtension(ext) : undefined;\n }\n\n get extSourceRepositoryVisibility(): X509SourceRepositoryVisibilityExtension | undefined {\n const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_VISIBILITY);\n return ext ? new X509SourceRepositoryVisibilityExtension(ext) : undefined;\n }\n\n get isCA(): boolean {\n const ca = this.extBasicConstraints?.isCA || false;\n\n // If the KeyUsage extension is present, keyCertSign must be set\n if (this.extKeyUsage) {\n return ca && this.extKeyUsage.keyCertSign;\n }\n\n return ca;\n }\n\n public extension(oid: string): X509Extension | undefined {\n const ext = this.findExtension(oid);\n return ext ? new X509Extension(ext) : undefined;\n }\n\n public async verify(issuerCertificate?: X509Certificate): Promise<boolean> {\n // Extract the hash algorithm from this certificate's signature algorithm\n const sigAlgOID = this.signatureAlgorithmOid;\n const isRsaPss = sigAlgOID === OID_RSASSA_PSS;\n\n // Get hash algorithm - for RSA-PSS, parse from parameters; otherwise lookup in tables\n const hashAlg = isRsaPss\n ? this.parseRsaPssHashAlgorithm()\n : (RSA_SIGNATURE_ALGOS[sigAlgOID] || ECDSA_SIGNATURE_ALGOS[sigAlgOID]);\n\n // Use the issuer's public key if provided, otherwise use the subject's (for self-signed certs)\n // Import with the correct hash algorithm and key type for this certificate's signature\n const publicKeyObj = issuerCertificate\n ? await issuerCertificate.getPublicKeyObj(hashAlg, isRsaPss)\n : await this.getPublicKeyObj(hashAlg, isRsaPss);\n\n return await verifySignature(\n publicKeyObj,\n this.tbsCertificate.toDER(),\n this.signatureValue,\n this.signatureAlgorithm,\n );\n }\n\n public validForDate(date: Date): boolean {\n return this.notBefore <= date && date <= this.notAfter;\n }\n\n public equals(other: X509Certificate): boolean {\n return uint8ArrayEqual(this.root.toDER(), other.root.toDER());\n }\n\n // Creates a copy of the certificate with a new buffer\n public clone(): X509Certificate {\n const der = this.root.toDER();\n const clone = new Uint8Array(der);\n return X509Certificate.parse(clone);\n }\n\n private findExtension(oid: string): ASN1Obj | undefined {\n // Find the extension with the given OID. The OID will always be the first\n // element of the extension sequence\n return this.extensions.find((ext) => ext.subs[0].toOID() === oid);\n }\n\n /////////////////////////////////////////////////////////////////////////////\n // The following properties use the documented x509 structure to locate the\n // desired ASN.1 object\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.1\n private get tbsCertificateObj(): ASN1Obj {\n // tbsCertificate is the first element of the certificate sequence\n return this.root.subs[0];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2\n private get signatureAlgorithmObj(): ASN1Obj {\n // signatureAlgorithm is the second element of the certificate sequence\n return this.root.subs[1];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.3\n private get signatureValueObj(): ASN1Obj {\n // signatureValue is the third element of the certificate sequence\n return this.root.subs[2];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.1\n private get versionObj(): ASN1Obj {\n // version is the first element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[0];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.2\n private get serialNumberObj(): ASN1Obj {\n // serialNumber is the second element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[1];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.4\n private get issuerObj(): ASN1Obj {\n // issuer is the fourth element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[3];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5\n private get validityObj(): ASN1Obj {\n // version is the fifth element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[4];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.6\n private get subjectObj(): ASN1Obj {\n // subject is the sixth element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[5];\n }\n\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7\n private get subjectPublicKeyInfoObj(): ASN1Obj {\n // subjectPublicKeyInfo is the seventh element of the tbsCertificate sequence\n return this.tbsCertificateObj.subs[6];\n }\n\n // Extensions can't be located by index because their position varies. Instead,\n // we need to find the extensions context specific tag\n // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.9\n private get extensionsObj(): ASN1Obj | undefined {\n return this.tbsCertificateObj.subs.find((sub) =>\n sub.tag.isContextSpecific(0x03),\n );\n }\n\n // Parse a Distinguished Name (issuer or subject) ASN1Obj into a Map\n // DN structure: SEQUENCE of SET of SEQUENCE (AttributeTypeAndValue)\n // Each AttributeTypeAndValue is [OID, value]\n private parseDistinguishedName(dnObj: ASN1Obj): Map<string, string> {\n const result = new Map<string, string>();\n\n // Iterate over RDNs (RelativeDistinguishedName - each is a SET)\n for (const rdn of dnObj.subs) {\n // Each RDN contains one or more AttributeTypeAndValue (SEQUENCE)\n for (const atv of rdn.subs) {\n if (atv.subs.length >= 2) {\n const oidObj = atv.subs[0];\n const valueObj = atv.subs[1];\n\n if (oidObj.tag.isOID()) {\n const oid = oidObj.toOID();\n const attrName = DN_OID_TO_NAME[oid];\n if (attrName) {\n const value = Uint8ArrayToString(valueObj.value);\n result.set(attrName, value);\n }\n }\n }\n }\n }\n\n return result;\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",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"@vitest/coverage-v8": "^5.0.5",
|
|
44
44
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
45
45
|
"playwright": "^1.57.0",
|
|
46
|
-
"typescript": "^
|
|
46
|
+
"typescript": "^6.0.3",
|
|
47
47
|
"typescript-eslint": "^8.37.0",
|
|
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
|
}
|