@svta/cml-c2pa 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/C2paAssertion.ts","../src/C2paSignatureInfo.ts","../src/C2paManifest.ts","../src/C2paStatusCode.ts","../src/cose/CoseKeyJwk.ts","../src/LiveVideoStatusCode.ts","../src/init/InitSegmentValidation.ts","../src/init/validateC2paInitSegment.ts","../src/vsi/SequenceState.ts","../src/segment/SegmentValidation.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/ManifestBoxValidation.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/C2paAssertion.ts","../src/C2paSignatureInfo.ts","../src/C2paManifest.ts","../src/C2paStatusCode.ts","../src/cose/CoseKeyJwk.ts","../src/LiveVideoStatusCode.ts","../src/init/InitSegmentValidation.ts","../src/init/validateC2paInitSegment.ts","../src/vsi/SequenceState.ts","../src/segment/SegmentValidation.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/ManifestBoxValidation.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -56,7 +56,7 @@ function toUint8Array$1(value) {
56
56
  * @example
57
57
  * {@includeCode ../../test/cose/decodeCoseSign1.test.ts#example}
58
58
  *
59
- * @public
59
+ * @internal
60
60
  */
61
61
  function decodeCoseSign1(coseBytes) {
62
62
  try {
@@ -389,7 +389,7 @@ function findRDNValue(issuerValue, targetOID) {
389
389
  * @example
390
390
  * {@includeCode ../../test/x509/extractCertificateInfo.test.ts#example}
391
391
  *
392
- * @public
392
+ * @internal
393
393
  */
394
394
  function extractCertificateInfo(certDER) {
395
395
  try {
@@ -735,7 +735,7 @@ function buildHashInput(bytes, exclusions, offsetPrefixSize) {
735
735
  * @example
736
736
  * {@includeCode ../../test/bmff/computeBmffHash.test.ts#example}
737
737
  *
738
- * @public
738
+ * @internal
739
739
  */
740
740
  async function computeBmffHash(segmentBytes, options) {
741
741
  const exclusions = options?.exclusions ?? [];
@@ -1944,25 +1944,29 @@ function parseBmffHashAssertion(assertions) {
1944
1944
  }
1945
1945
  function parseManifest(bytes) {
1946
1946
  try {
1947
- const { manifest } = readC2paManifest(bytes);
1947
+ const internalData = readC2paManifest(bytes);
1948
+ const { manifest } = internalData;
1948
1949
  if (!manifest) return {
1949
1950
  manifest: null,
1950
1951
  issuer: null,
1951
1952
  liveVideo: null,
1952
- bmff: EMPTY_BMFF_HASH
1953
+ bmff: EMPTY_BMFF_HASH,
1954
+ internalData: null
1953
1955
  };
1954
1956
  return {
1955
1957
  manifest,
1956
1958
  issuer: manifest.signatureInfo?.issuer ?? null,
1957
1959
  liveVideo: parseLiveVideoAssertion(manifest.assertions),
1958
- bmff: parseBmffHashAssertion(manifest.assertions)
1960
+ bmff: parseBmffHashAssertion(manifest.assertions),
1961
+ internalData
1959
1962
  };
1960
1963
  } catch {
1961
1964
  return {
1962
1965
  manifest: null,
1963
1966
  issuer: null,
1964
1967
  liveVideo: null,
1965
- bmff: EMPTY_BMFF_HASH
1968
+ bmff: EMPTY_BMFF_HASH,
1969
+ internalData: null
1966
1970
  };
1967
1971
  }
1968
1972
  }
@@ -2004,7 +2008,7 @@ function collectErrorCodes(hasManifest, hasLiveVideo, streamIdValid, sequenceNum
2004
2008
  * @public
2005
2009
  */
2006
2010
  async function validateC2paManifestBoxSegment(bytes, lastManifestId, state) {
2007
- const { manifest, issuer, liveVideo, bmff } = parseManifest(bytes);
2011
+ const { manifest, issuer, liveVideo, bmff, internalData } = parseManifest(bytes);
2008
2012
  const sequenceNumber = liveVideo?.sequenceNumber ?? null;
2009
2013
  const previousManifestId = liveVideo?.previousManifestId ?? null;
2010
2014
  const streamId = liveVideo?.streamId ?? null;
@@ -2016,7 +2020,9 @@ async function validateC2paManifestBoxSegment(bytes, lastManifestId, state) {
2016
2020
  exclusions: bmff.exclusions,
2017
2021
  alg: bmff.alg ?? void 0
2018
2022
  });
2019
- const errorCodes = [...collectErrorCodes(manifest !== null, liveVideo !== null, streamIdValid, sequenceNumberValid, bmffHashMatches, continuityMethod, previousManifestId, lastManifestId)];
2023
+ const liveVideoCodes = collectErrorCodes(manifest !== null, liveVideo !== null, streamIdValid, sequenceNumberValid, bmffHashMatches, continuityMethod, previousManifestId, lastManifestId);
2024
+ const integrityCodes = internalData ? await validateManifestIntegrity(internalData, internalData.signatureBytes ? extractCertificateFromSignatureBytes(internalData.signatureBytes) : null) : [];
2025
+ const errorCodes = [...liveVideoCodes, ...integrityCodes];
2020
2026
  const currentManifestId = manifest?.instanceId ?? null;
2021
2027
  return {
2022
2028
  result: {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["coseGet","toUint8Array","protectedHeader: CoseHeader","TEXT_DECODER","HEX_TABLE: readonly string[]","C2PA_MANIFEST_UUID: readonly number[]","JUMBF_UUID: readonly number[]","TEXT_DECODER","notBefore: string | null","assertions: InternalAssertionData[]","data: unknown","refs: ClaimAssertionRef[]","claimData: Record<string, unknown> | null","claimCborBytes: Uint8Array | null","internalAssertions: InternalAssertionData[]","signatureBytes: Uint8Array | null","assertions: C2paAssertion[]","codes: C2paStatusCode[]","codes: C2paStatusCode[]","CURVE_COMPONENT_BYTES: Record<string, number>","RSA_PSS_SALT_LENGTH: Record<string, number>","codes: C2paStatusCode[]","Code","EC_CURVE_NAMES: Record<number, string>","OKP_CURVE_NAMES: Record<number, string>","BMFF_HASH_ASSERTION_LABEL","EMPTY_BMFF_HASH: BmffHashFields","constraints: BmffHashConstraint[]","exclusions: BmffHashExclusion[]","errorCodes: (LiveVideoStatusCode | C2paStatusCode)[]"],"sources":["../src/LiveVideoStatusCode.ts","../src/cose/decodeCoseSign1.ts","../src/jumbf/parseJumbfBoxes.ts","../src/jumbf/parseJumbfLabel.ts","../src/utils.ts","../src/x509/asn1.ts","../src/x509/extractCertificateInfo.ts","../src/readC2paManifest.ts","../src/extractManifestCertificate.ts","../src/bmff/shouldExcludeBox.ts","../src/bmff/computeBmffHash.ts","../src/bmff/validateBmffHash.ts","../src/C2paStatusCode.ts","../src/claim/validateActionIngredients.ts","../src/claim/validateAssertionHashes.ts","../src/cose/constants.ts","../src/cose/resolveAlgorithmFromCoseAlg.ts","../src/cose/buildSigStructure.ts","../src/cose/verifyCoseSign1.ts","../src/x509/extractCertificateSpki.ts","../src/x509/normalizeRsaPssSpki.ts","../src/claim/verifyClaimSignature.ts","../src/claim/validateManifestIntegrity.ts","../src/cose/convertCoseKeyToJwk.ts","../src/cose/resolveImportAlgorithm.ts","../src/cose/verifySignerBinding.ts","../src/init/validateC2paInitSegment.ts","../src/emsg/extractVsiEmsgBox.ts","../src/vsi/decodeVsiMap.ts","../src/vsi/createSequenceState.ts","../src/vsi/SequenceState.ts","../src/vsi/validateSequenceNumber.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts"],"sourcesContent":["import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA failure status codes for live video validation,\n * as defined in the C2PA specification section 19.7.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_live_video_validation_process | C2PA Spec §19.7}\n *\n * @enum\n *\n * @public\n */\nexport const LiveVideoStatusCode = {\n\t/** Init segment contains an `mdat` box (§19.7.1) */\n\tINIT_INVALID: 'livevideo.init.invalid',\n\t/** C2PA Manifest Box failed standard validation (§19.7.1) */\n\tMANIFEST_INVALID: 'livevideo.manifest.invalid',\n\t/** Segment structure invalid: missing Manifest Box/emsg, signature/hash/key failure (§19.7) */\n\tSEGMENT_INVALID: 'livevideo.segment.invalid',\n\t/** Live video assertion field invalid: sequenceNumber or streamId mismatch (§19.7.2) */\n\tASSERTION_INVALID: 'livevideo.assertion.invalid',\n\t/** continuityMethod absent, unsupported, or companion fields incorrect (§19.7.2) */\n\tCONTINUITY_METHOD_INVALID: 'livevideo.continuityMethod.invalid',\n\t/** Session key invalid: signerBinding failed or required fields absent (§19.7.3) */\n\tSESSIONKEY_INVALID: 'livevideo.sessionkey.invalid',\n} as const\n\n/**\n * Union type of all {@link (LiveVideoStatusCode:variable)} values.\n *\n * @public\n */\nexport type LiveVideoStatusCode = ValueOf<typeof LiveVideoStatusCode>\n","import { decode } from 'cbor-x/decode'\nimport type { CoseSign1 } from './CoseSign1.ts'\n\nconst COSE_SIGN1_TAG_SINGLE_BYTE = 0xd2\nconst COSE_SIGN1_TAG_TWO_BYTE_FIRST = 0xd8\nconst COSE_SIGN1_TAG_TWO_BYTE_SECOND = 0x12\nconst COSE_SIGN1_ARRAY_LENGTH = 4\nconst COSE_KEY_KID = 4\nconst COSE_KEY_ALG = 1\n\ntype CoseHeader = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(header: CoseHeader, key: number): unknown {\n\tif (header instanceof Map) return header.get(key)\n\treturn (header as Record<number | string, unknown>)[key]\n}\n\nfunction stripCoseTag(bytes: Uint8Array): Uint8Array {\n\tif (bytes[0] === COSE_SIGN1_TAG_SINGLE_BYTE) return bytes.subarray(1)\n\tif (bytes[0] === COSE_SIGN1_TAG_TWO_BYTE_FIRST && bytes[1] === COSE_SIGN1_TAG_TWO_BYTE_SECOND) return bytes.subarray(2)\n\treturn bytes\n}\n\nfunction toUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tthrow new Error(`Expected Uint8Array or number[], got ${typeof value}`)\n}\n\n/**\n * Decodes a `COSE_Sign1` structure from raw bytes (RFC 9052).\n *\n * Handles CBOR tag 18 in both single-byte (0xD2) and two-byte (0xD8 0x12) form.\n *\n * @param coseBytes - Raw COSE_Sign1 bytes, optionally prefixed with CBOR tag 18\n * @returns The decoded COSE_Sign1 structure\n * @throws If the bytes do not represent a valid COSE_Sign1 structure\n *\n * @example\n * {@includeCode ../../test/cose/decodeCoseSign1.test.ts#example}\n *\n * @public\n */\nexport function decodeCoseSign1(coseBytes: Uint8Array): CoseSign1 {\n\ttry {\n\t\tconst stripped = stripCoseTag(coseBytes)\n\t\tconst coseArray = decode(stripped) as unknown\n\n\t\tif (!Array.isArray(coseArray) || coseArray.length !== COSE_SIGN1_ARRAY_LENGTH) {\n\t\t\tthrow new Error('Invalid COSE_Sign1 structure: expected array with 4 elements')\n\t\t}\n\n\t\tconst [protectedRaw, unprotectedRaw, payloadRaw, signatureRaw] = coseArray as unknown[]\n\n\t\tconst protectedBytes = toUint8Array(protectedRaw)\n\t\tlet protectedHeader: CoseHeader = {}\n\t\tif (protectedBytes.length > 0) {\n\t\t\tprotectedHeader = decode(protectedBytes) as CoseHeader\n\t\t}\n\n\t\tconst unprotectedHeader = (unprotectedRaw ?? {}) as CoseHeader\n\t\tconst kidRaw = coseGet(protectedHeader, COSE_KEY_KID) ?? coseGet(unprotectedHeader, COSE_KEY_KID) ?? null\n\t\tconst kid = kidRaw != null ? toUint8Array(kidRaw) : null\n\t\tconst alg = (coseGet(protectedHeader, COSE_KEY_ALG) ?? coseGet(unprotectedHeader, COSE_KEY_ALG) ?? null) as number | null\n\n\t\treturn {\n\t\t\tprotectedBytes,\n\t\t\tprotectedHeader: protectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tunprotectedHeader: unprotectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tpayload: payloadRaw == null ? null : toUint8Array(payloadRaw),\n\t\t\tsignature: toUint8Array(signatureRaw),\n\t\t\tkid,\n\t\t\talg,\n\t\t}\n\t}\n\tcatch (error) {\n\t\tthrow new Error(`Failed to decode COSE_Sign1: ${(error as Error).message}`)\n\t}\n}\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { JumbfBox } from './JumbfBox.ts'\n\n/**\n * Parses JUMBF boxes (ISO 19566-5) from raw bytes.\n *\n * JUMBF boxes share the same 4-byte size + 4-byte type structure as ISO BMFF boxes,\n * so they can be parsed with the same reader.\n *\n * @param bytes - Raw bytes containing JUMBF box content\n * @returns Array of parsed JUMBF boxes with their payloads\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfBoxes.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfBoxes(bytes: Uint8Array): JumbfBox[] {\n\treturn readIsoBoxes(bytes).map(box => ({\n\t\ttype: box.type,\n\t\tdata: box.view.readData(box.view.bytesRemaining),\n\t}))\n}\n","const TEXT_DECODER = new TextDecoder()\nconst JUMD_UUID_SIZE = 16\nconst JUMD_TOGGLES_OFFSET = 16\nconst JUMD_LABEL_START = 17\nconst LABEL_FLAG_MASK = 0x03\nconst LABEL_FLAG_EXPECTED = 0x03\n\n/**\n * Extracts the label from a JUMBF Description Box (`jumd`) data payload.\n *\n * The `jumd` format is: 16-byte UUID + 1-byte toggles + null-terminated label string.\n * A label is only present when bits 0 and 1 of the toggles byte are both set.\n *\n * @param jumdData - Raw bytes of the `jumd` box data (payload after the box header)\n * @returns The label string, or `null` if no label is present\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfLabel.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfLabel(jumdData: Uint8Array): string | null {\n\tif (jumdData.length < JUMD_UUID_SIZE + 1) return null\n\n\tconst toggles = jumdData[JUMD_TOGGLES_OFFSET]\n\tif ((toggles & LABEL_FLAG_MASK) !== LABEL_FLAG_EXPECTED) return null\n\n\tlet end = JUMD_LABEL_START\n\twhile (end < jumdData.length && jumdData[end] !== 0) end++\n\tif (end >= jumdData.length) return null\n\n\treturn TEXT_DECODER.decode(jumdData.subarray(JUMD_LABEL_START, end))\n}\n","import type { IsoBoxReadView, ParsedIsoBox } from '@svta/cml-iso-bmff'\n\nconst MILLISECONDS_PER_SECOND = 1000\nconst SHA_ALGORITHM_PATTERN = /^sha(\\d+)$/i\n\n/**\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * Defaults to `'SHA-256'` when no algorithm is provided.\n *\n * @internal\n */\nexport function normalizeAlgorithmName(rawAlg?: string): string {\n\treturn (rawAlg ?? 'SHA-256').replace(SHA_ALGORITHM_PATTERN, 'SHA-$1')\n}\n\nconst HEX_TABLE: readonly string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\n/**\n * Converts a Uint8Array to a lowercase hex string.\n *\n * @internal\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n\tlet hex = ''\n\tfor (const byte of bytes) hex += HEX_TABLE[byte]\n\treturn hex\n}\n\n/**\n * Checks whether a session key has expired based on its creation time\n * and validity period.\n *\n * @param createdAt - ISO 8601 date string when the key was created\n * @param validityPeriodSeconds - Validity duration in seconds\n * @param now - Current time (defaults to `new Date()`, injectable for testing)\n * @returns `true` if the key has expired\n *\n * @internal\n */\nexport function isKeyExpired(createdAt: string, validityPeriodSeconds: number, now: Date = new Date()): boolean {\n\tconst createdAtMs = new Date(createdAt).getTime()\n\tif (Number.isNaN(createdAtMs)) return true\n\tconst validityEnd = new Date(createdAtMs + validityPeriodSeconds * MILLISECONDS_PER_SECOND)\n\treturn now > validityEnd\n}\n\n/**\n * Constant-time comparison of two hash byte arrays.\n *\n * @internal\n */\nexport function hashesEqual(a: Uint8Array, b: Uint8Array): boolean {\n\tif (a.length !== b.length) return false\n\tlet diff = 0\n\tfor (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]\n\treturn diff === 0\n}\n\n// C2PA manifest store UUID per C2PA specification\nconst C2PA_MANIFEST_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1a, 0x96, 0x4f, 0x32,\n\t0xa0, 0xf6, 0xf3, 0xec, 0xf9, 0x6c, 0x10, 0xea,\n]\n\n// JUMBF UUID per ISO 19566-5 (used by c2pa-rs and other JUMBF-compliant tools)\nconst JUMBF_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1b, 0x0e, 0x48, 0x3c,\n\t0x92, 0x97, 0x58, 0x28, 0x87, 0x7e, 0xc4, 0x81,\n]\n\nfunction matchesUuid(usertype: readonly number[], expected: readonly number[]): boolean {\n\treturn usertype.length === expected.length && expected.every((b, i) => b === usertype[i])\n}\n\nfunction isC2paUuid(usertype: readonly number[]): boolean {\n\treturn matchesUuid(usertype, C2PA_MANIFEST_UUID) || matchesUuid(usertype, JUMBF_UUID)\n}\n\n/**\n * A parsed ISO BMFF box with a UUID type.\n *\n * `ParsedIsoBox` does not include 'uuid' in its type union because UUID boxes\n * are not part of the standard `IsoBoxMap`. This type represents the structural\n * shape needed to work with UUID boxes at runtime.\n *\n * @internal\n */\nexport type UuidParsedBox = {\n\ttype: string\n\tusertype?: number[]\n\tview: IsoBoxReadView\n\tsize: number\n}\n\n/**\n * Finds the C2PA UUID box in a list of parsed ISO BMFF boxes.\n *\n * Matches against both the C2PA manifest store UUID and the JUMBF UUID\n * (ISO 19566-5), as different tools use different UUIDs.\n *\n * @internal\n */\nexport function findC2paUuidBox(boxes: ParsedIsoBox[]): UuidParsedBox | undefined {\n\treturn (boxes as UuidParsedBox[]).find(\n\t\tbox => box.type === 'uuid' && isC2paUuid(box.usertype ?? []),\n\t)\n}\n\nconst FULLBOX_HEADER_SIZE = 4\nconst AUX_UUID_OFFSET_SIZE = 8\n\n/**\n * Strips the JUMBF UUID box prefix (fullbox header, purpose string, aux offset)\n * to return only the JUMBF manifest data.\n *\n * Structure per ISO 19566-5 / C2PA BMFF storage:\n * version(1) + flags(3) + purpose(null-terminated) + aux_offset(8) + JUMBF data\n *\n * Returns `null` if the payload does not contain a valid JUMBF UUID prefix.\n *\n * @internal\n */\nexport function stripJumbfUuidPrefix(payload: Uint8Array): Uint8Array | null {\n\tif (payload.length < FULLBOX_HEADER_SIZE) return null\n\n\tlet offset = FULLBOX_HEADER_SIZE\n\t// Skip null-terminated purpose string (e.g. \"manifest\\0\")\n\twhile (offset < payload.length && payload[offset] !== 0) offset++\n\tif (offset >= payload.length) return null\n\toffset++ // skip the null terminator\n\toffset += AUX_UUID_OFFSET_SIZE\n\tif (offset > payload.length) return null\n\treturn payload.subarray(offset)\n}\n","/**\n * Minimal ASN.1 DER parsing helpers for X.509 certificate navigation.\n *\n * @internal\n */\n\nexport const ASN1_TAG_INTEGER = 0x02\nexport const ASN1_TAG_OBJECT_IDENTIFIER = 0x06\nexport const ASN1_TAG_SEQUENCE = 0x30\nexport const ASN1_TAG_SET = 0x31\nexport const ASN1_TAG_UTC_TIME = 0x17\nexport const ASN1_TAG_GENERALIZED_TIME = 0x18\nexport const ASN1_TAG_CONTEXT_0 = 0xa0\nconst ASN1_LONG_FORM_FLAG = 0x80\nconst ASN1_LONG_FORM_MASK = 0x7f\n\nexport type Asn1Element = {\n\treadonly tag: number\n\treadonly value: Uint8Array\n\treadonly totalSize: number\n}\n\nexport function readLength(bytes: Uint8Array, offset: number): { length: number; bytesRead: number } {\n\tif (offset >= bytes.length) return { length: 0, bytesRead: 0 }\n\tconst first = bytes[offset] ?? 0\n\tif (first < ASN1_LONG_FORM_FLAG) return { length: first, bytesRead: 1 }\n\tconst count = first & ASN1_LONG_FORM_MASK\n\tlet length = 0\n\tfor (let i = 0; i < count; i++) {\n\t\tlength = (length << 8) | (bytes[offset + 1 + i] ?? 0)\n\t}\n\treturn { length, bytesRead: 1 + count }\n}\n\nexport function readElement(bytes: Uint8Array, offset: number): Asn1Element | null {\n\tif (offset + 2 > bytes.length) return null\n\tconst tag = bytes[offset] ?? 0\n\tconst { length, bytesRead } = readLength(bytes, offset + 1)\n\tconst headerSize = 1 + bytesRead\n\tconst valueEnd = offset + headerSize + length\n\tif (valueEnd > bytes.length) return null\n\treturn {\n\t\ttag,\n\t\tvalue: bytes.subarray(offset + headerSize, valueEnd),\n\t\ttotalSize: headerSize + length,\n\t}\n}\n\n/**\n * Reads an ASN.1 element and returns its full DER encoding (tag + length + value).\n *\n * @internal\n */\nexport function readElementRaw(bytes: Uint8Array, offset: number): Uint8Array | null {\n\tconst el = readElement(bytes, offset)\n\tif (!el) return null\n\treturn bytes.subarray(offset, offset + el.totalSize)\n}\n","const TEXT_DECODER = new TextDecoder()\n\nimport type { CertificateInfo } from './CertificateInfo.ts'\nimport {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_GENERALIZED_TIME,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_OBJECT_IDENTIFIER,\n\tASN1_TAG_SEQUENCE,\n\tASN1_TAG_SET,\n\tASN1_TAG_UTC_TIME,\n\treadElement,\n\ttype Asn1Element,\n} from './asn1.ts'\n\nconst OID_COMMON_NAME = new Uint8Array([0x55, 0x04, 0x03])\nconst OID_ORG_NAME = new Uint8Array([0x55, 0x04, 0x0a])\n\nfunction matchesOID(value: Uint8Array, oid: Uint8Array): boolean {\n\tif (value.length < oid.length) return false\n\tfor (let i = 0; i < oid.length; i++) {\n\t\tif (value[i] !== oid[i]) return false\n\t}\n\treturn true\n}\n\nfunction parseTime(element: Asn1Element): string | null {\n\tconst text = TEXT_DECODER.decode(element.value)\n\tif (element.tag === ASN1_TAG_UTC_TIME) {\n\t\tconst yy = parseInt(text.substring(0, 2), 10)\n\t\tconst year = yy >= 50 ? 1900 + yy : 2000 + yy\n\t\treturn `${year}-${text.substring(2, 4)}-${text.substring(4, 6)}T${text.substring(6, 8)}:${text.substring(8, 10)}:${text.substring(10, 12)}Z`\n\t}\n\tif (element.tag === ASN1_TAG_GENERALIZED_TIME) {\n\t\treturn `${text.substring(0, 4)}-${text.substring(4, 6)}-${text.substring(6, 8)}T${text.substring(8, 10)}:${text.substring(10, 12)}:${text.substring(12, 14)}Z`\n\t}\n\treturn null\n}\n\nfunction findOidValueInSequence(seqValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tconst oidEl = readElement(seqValue, 0)\n\tif (!oidEl || oidEl.tag !== ASN1_TAG_OBJECT_IDENTIFIER) return null\n\tif (!matchesOID(oidEl.value, targetOID)) return null\n\n\tconst valEl = readElement(seqValue, oidEl.totalSize)\n\treturn valEl ? TEXT_DECODER.decode(valEl.value) : null\n}\n\nfunction findRDNValue(issuerValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tlet offset = 0\n\twhile (offset < issuerValue.length) {\n\t\tconst setEl = readElement(issuerValue, offset)\n\t\tif (!setEl || setEl.tag !== ASN1_TAG_SET) break\n\n\t\tlet setOffset = 0\n\t\twhile (setOffset < setEl.value.length) {\n\t\t\tconst seqEl = readElement(setEl.value, setOffset)\n\t\t\tif (!seqEl || seqEl.tag !== ASN1_TAG_SEQUENCE) break\n\n\t\t\tconst found = findOidValueInSequence(seqEl.value, targetOID)\n\t\t\tif (found) return found\n\n\t\t\tsetOffset += seqEl.totalSize\n\t\t}\n\t\toffset += setEl.totalSize\n\t}\n\treturn null\n}\n\n/**\n * Extracts the issuer name and `notBefore` date from a DER-encoded X.509 certificate.\n *\n * Uses a minimal ASN.1 parser that handles the subset of DER structures found in\n * typical C2PA signing certificates. Extracts the issuer Common Name (OID 2.5.4.3)\n * or Organization Name (OID 2.5.4.10) as a fallback, and the `notBefore` validity date.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Certificate information, or `null` if parsing fails\n *\n * @example\n * {@includeCode ../../test/x509/extractCertificateInfo.test.ts#example}\n *\n * @public\n */\nexport function extractCertificateInfo(certDER: Uint8Array): CertificateInfo | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// Optional version field (context tag [0])\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// Serial number\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// Signature algorithm\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// Issuer\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\tconst issuer =\n\t\t\tfindRDNValue(el.value, OID_COMMON_NAME) ??\n\t\t\tfindRDNValue(el.value, OID_ORG_NAME) ??\n\t\t\t'Unknown Issuer'\n\t\toffset += el.totalSize\n\n\t\t// Validity\n\t\tel = readElement(tbs.value, offset)\n\t\tlet notBefore: string | null = null\n\t\tif (el && el.tag === ASN1_TAG_SEQUENCE) {\n\t\t\tconst timeEl = readElement(el.value, 0)\n\t\t\tif (timeEl) notBefore = parseTime(timeEl)\n\t\t}\n\n\t\treturn { issuer, notBefore }\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","const TEXT_DECODER = new TextDecoder()\n\nimport { readIsoBoxes, type ParsedIsoBox } from '@svta/cml-iso-bmff'\nimport { decode } from 'cbor-x/decode'\nimport type { C2paAssertion } from './C2paAssertion.ts'\nimport type { C2paManifest } from './C2paManifest.ts'\nimport type { ClaimAssertionRef } from './claim/ClaimAssertionRef.ts'\nimport type { InternalAssertionData, InternalManifestData } from './claim/InternalManifestData.ts'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport { extractCertificateInfo } from './x509/extractCertificateInfo.ts'\n\n\nconst MAX_JUMBF_NESTING_DEPTH = 20\nconst X5CHAIN_HEADER_LABEL = 33\n\nfunction resolveManifestBoxes(jumbfBoxes: JumbfBox[], depth = 0): JumbfBox[] {\n\tif (depth >= MAX_JUMBF_NESTING_DEPTH) return jumbfBoxes\n\n\t// Skip jumd description boxes — they contain labels, not manifest content\n\tconst contentBoxes = jumbfBoxes.filter(b => b.type !== 'jumd')\n\n\t// Single jumb wrapping — unwrap one level and recurse\n\t// This handles: store jumb → manifest jumb → claim/assertions/signature\n\tconst firstBox = contentBoxes[0]\n\tif (contentBoxes.length === 1 && firstBox?.type === 'jumb') {\n\t\treturn resolveManifestBoxes(parseJumbfBoxes(firstBox.data), depth + 1)\n\t}\n\n\treturn jumbfBoxes\n}\n\nfunction extractManifestLabel(jumbfBoxes: JumbfBox[]): string | null {\n\t// Navigate: store jumb → manifest jumb → jumd label\n\tfor (const box of jumbfBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tfor (const child of inner) {\n\t\t\tif (child.type !== 'jumb') continue\n\t\t\tconst childInner = parseJumbfBoxes(child.data)\n\t\t\tconst jumd = childInner.find(b => b.type === 'jumd')\n\t\t\tif (jumd) {\n\t\t\t\tconst label = parseJumbfLabel(jumd.data)\n\t\t\t\tif (label) return label\n\t\t\t}\n\t\t}\n\t}\n\treturn null\n}\n\nfunction parseAssertionsInternal(assertionStoreBoxes: JumbfBox[]): InternalAssertionData[] {\n\tconst assertions: InternalAssertionData[] = []\n\n\tfor (const box of assertionStoreBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tconst contentBox = inner.find(\n\t\t\tb => b.type === 'cbor' || b.type === 'json' || b.type === 'jumc' || b.type === 'jp2c' || b.type === 'bidb',\n\t\t)\n\n\t\tlet data: unknown = null\n\t\tif (contentBox) {\n\t\t\tif (contentBox.type === 'cbor') {\n\t\t\t\ttry { data = decode(contentBox.data) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse if (contentBox.type === 'json') {\n\t\t\t\ttry { data = JSON.parse(TEXT_DECODER.decode(contentBox.data)) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdata = contentBox.data\n\t\t\t}\n\t\t}\n\n\t\tassertions.push({ label, data, rawBoxPayload: box.data })\n\t}\n\n\treturn assertions\n}\n\nfunction parseSignatureInfo(signatureBytes: Uint8Array | null): { issuer: string | null; certNotBefore: string | null } {\n\tif (!signatureBytes) return { issuer: null, certNotBefore: null }\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_HEADER_LABEL] ?? cose.unprotectedHeader[X5CHAIN_HEADER_LABEL]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return { issuer: null, certNotBefore: null }\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\tif (!(certDER instanceof Uint8Array)) return { issuer: null, certNotBefore: null }\n\n\t\tconst certInfo = extractCertificateInfo(certDER)\n\t\treturn { issuer: certInfo?.issuer ?? null, certNotBefore: certInfo?.notBefore ?? null }\n\t} catch {\n\t\t// signature parsing failed — continue without signature info\n\t\treturn { issuer: null, certNotBefore: null }\n\t}\n}\n\nfunction extractClaimAssertionRefs(claimData: Record<string, unknown>): ClaimAssertionRef[] {\n\tconst created = claimData['created_assertions'] as unknown[] | undefined\n\tconst gathered = claimData['gathered_assertions'] as unknown[] | undefined\n\tconst v1 = claimData['assertions'] as unknown[] | undefined\n\n\tconst sources = [...(created ?? []), ...(gathered ?? []), ...(v1 ?? [])]\n\tconst refs: ClaimAssertionRef[] = []\n\n\tfor (const entry of sources) {\n\t\tif (!entry || typeof entry !== 'object') continue\n\t\tconst e = entry as Record<string, unknown>\n\t\tconst url = e['url'] as string | undefined\n\t\tconst hash = e['hash']\n\t\tif (!url || !hash) continue\n\n\t\trefs.push({\n\t\t\turl,\n\t\t\thash: hash instanceof Uint8Array ? hash : new Uint8Array(hash as number[]),\n\t\t\talg: (e['alg'] as string | undefined) ?? null,\n\t\t})\n\t}\n\n\treturn refs\n}\n\n/**\n * Reads a C2PA manifest from raw BMFF bytes.\n *\n * Locates the C2PA UUID box (`d8fec3d6-1a96-4f32-a0f6-f3ecf96c10ea`), navigates\n * the JUMBF manifest store structure (ISO 19566-5), and returns the parsed active\n * manifest with its claims, assertions, and signature information.\n *\n * This function performs structural parsing only. It does not verify the\n * cryptographic signature of the claim.\n *\n * @param bytes - Raw BMFF bytes (e.g. an MP4 init segment or media segment)\n * @param preParsedBoxes - Optional pre-parsed ISO boxes to avoid redundant parsing\n * @returns The parsed manifest data including claim, assertions, and signature bytes\n * @throws If no C2PA UUID box is found, or the JUMBF structure is invalid\n *\n * @example\n * {@includeCode ../test/readC2paManifest.test.ts#example}\n *\n * @internal\n */\nexport function readC2paManifest(bytes: Uint8Array, preParsedBoxes?: ParsedIsoBox[]): InternalManifestData {\n\tconst boxes = preParsedBoxes ?? readIsoBoxes(bytes)\n\tconst uuidBox = findC2paUuidBox(boxes)\n\n\tif (!uuidBox) {\n\t\tthrow new Error('No C2PA UUID box found in the provided bytes')\n\t}\n\n\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\tif (!jumbfPayload) {\n\t\tthrow new Error('Invalid JUMBF UUID prefix in C2PA box')\n\t}\n\tconst jumbfBoxes = parseJumbfBoxes(jumbfPayload)\n\n\tif (jumbfBoxes.length === 0) {\n\t\tthrow new Error('No JUMBF boxes found in C2PA UUID box')\n\t}\n\n\tconst manifestLabel = extractManifestLabel(jumbfBoxes)\n\tconst manifestBoxes = resolveManifestBoxes(jumbfBoxes)\n\n\tlet claimData: Record<string, unknown> | null = null\n\tlet claimCborBytes: Uint8Array | null = null\n\tlet internalAssertions: InternalAssertionData[] = []\n\tlet signatureBytes: Uint8Array | null = null\n\n\tfor (const box of manifestBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tif (label === 'c2pa.claim' || label === 'c2pa.claim.v2') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor')\n\t\t\tif (contentBox) {\n\t\t\t\tclaimCborBytes = contentBox.data\n\t\t\t\ttry { claimData = decode(contentBox.data) as Record<string, unknown> } catch { /* malformed claim — continue */ }\n\t\t\t}\n\t\t}\n\t\telse if (label === 'c2pa.assertions') {\n\t\t\tinternalAssertions = parseAssertionsInternal(inner)\n\t\t}\n\t\telse if (label === 'c2pa.signature') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\tif (contentBox) signatureBytes = contentBox.data\n\t\t}\n\t}\n\n\tconst { issuer, certNotBefore } = parseSignatureInfo(signatureBytes)\n\n\tconst instanceId = (claimData?.['instanceID'] ?? claimData?.['instance_id'] ?? null) as string | null\n\tconst claimGenerator = (claimData?.['claim_generator'] ?? claimData?.['claimGenerator'] ?? null) as string | null\n\tconst resolvedLabel =\n\t\tmanifestLabel ??\n\t\t(claimData?.['dc:title'] as string | undefined) ??\n\t\t(claimData?.['title'] as string | undefined) ??\n\t\tinstanceId ??\n\t\t'unknown'\n\n\tconst claimAssertionRefs = claimData ? extractClaimAssertionRefs(claimData) : []\n\n\tconst assertions: C2paAssertion[] = internalAssertions.map(a => ({ label: a.label, data: a.data }))\n\n\tconst manifest: C2paManifest = {\n\t\tlabel: resolvedLabel,\n\t\tinstanceId,\n\t\tclaimGenerator,\n\t\tsignatureInfo: { issuer, certNotBefore },\n\t\tassertions,\n\t}\n\n\treturn {\n\t\tmanifest,\n\t\tclaimAssertionRefs,\n\t\tclaimCborBytes,\n\t\tsignatureBytes,\n\t\tassertions: internalAssertions,\n\t}\n}\n\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\n\nconst C2PA_SIGNATURE_LABEL = 'c2pa.signature'\nconst X5CHAIN_COSE_HEADER = 33\n\n/**\n * Extracts the end-entity certificate from raw COSE_Sign1 signature bytes.\n *\n * @internal\n */\nexport function extractCertificateFromSignatureBytes(signatureBytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_COSE_HEADER] ??\n\t\t\tcose.unprotectedHeader[X5CHAIN_COSE_HEADER]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return null\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\treturn certDER instanceof Uint8Array ? certDER : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction findSignatureContentBytes(boxes: JumbfBox[]): Uint8Array | null {\n\tfor (const box of boxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\n\t\tif (jumd && parseJumbfLabel(jumd.data) === C2PA_SIGNATURE_LABEL) {\n\t\t\tconst content = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\treturn content?.data ?? null\n\t\t}\n\n\t\tconst nested = findSignatureContentBytes(inner)\n\t\tif (nested) return nested\n\t}\n\treturn null\n}\n\n/**\n * Extracts the end-entity certificate (DER-encoded) from the C2PA claim signature\n * embedded in a BMFF file.\n *\n * Navigates the JUMBF structure inside the C2PA UUID box to locate the\n * `c2pa.signature` entry, decodes the `COSE_Sign1`, and returns the first\n * certificate from the `x5chain` (COSE protected header label 33).\n *\n * @param mp4Bytes - Raw BMFF bytes (e.g. an MP4 init segment)\n * @returns DER-encoded certificate bytes, or `null` if not found or on any error\n *\n * @example\n * {@includeCode ../test/c2pa/extractManifestCertificate.test.ts#example}\n *\n * @internal\n */\nexport function extractManifestCertificate(mp4Bytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst boxes = readIsoBoxes(mp4Bytes)\n\t\tconst uuidBox = findC2paUuidBox(boxes)\n\t\tif (!uuidBox) return null\n\n\t\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\t\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\t\tif (!jumbfPayload) return null\n\t\tconst signatureBytes = findSignatureContentBytes(parseJumbfBoxes(jumbfPayload))\n\t\tif (!signatureBytes) return null\n\n\t\treturn extractCertificateFromSignatureBytes(signatureBytes)\n\t} catch {\n\t\treturn null\n\t}\n}\n","import type { BmffHashConstraint, BmffHashExclusion } from './BmffHashExclusion.ts'\n\nfunction bytesMatchAt(boxData: Uint8Array, offset: number, expected: Uint8Array | readonly number[]): boolean {\n\tconst bytes = expected instanceof Uint8Array ? expected : new Uint8Array(expected as number[])\n\tif (offset + bytes.length > boxData.length) return false\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (boxData[offset + i] !== bytes[i]) return false\n\t}\n\treturn true\n}\n\nfunction constraintMatches(boxData: Uint8Array, constraint: BmffHashConstraint): boolean {\n\treturn bytesMatchAt(boxData, constraint.offset, constraint.value)\n}\n\n/**\n * Returns `true` if the given BMFF box should be excluded from the\n * C2PA content hash, based on the provided exclusion list.\n *\n * Exclusions use C2PA xpath notation (e.g. `/emsg`, `/moof/traf`).\n * Optional `data` constraints narrow the match to specific box content by byte offset.\n *\n * @param boxType - Four-character box type code (e.g. `'emsg'`, `'moof'`)\n * @param boxData - Full box bytes including the 8-byte size+type header\n * @param exclusions - Exclusion list from the C2PA `c2pa.hash.bmff.v3` assertion\n * @returns `true` if the box should be excluded from the hash input\n *\n * @example\n * {@includeCode ../../test/bmff/shouldExcludeBox.test.ts#example}\n *\n * @public\n */\nexport function shouldExcludeBox(\n\tboxType: string,\n\tboxData: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n): boolean {\n\tfor (const exclusion of exclusions) {\n\t\tif (!exclusion.xpath) continue\n\t\tconst xpathMatchesType = exclusion.xpath === `/${boxType}` || exclusion.xpath.startsWith(`/${boxType}/`)\n\t\tif (!xpathMatchesType) continue\n\t\tconst { data } = exclusion\n\t\tif (!data || data.length === 0) return true\n\t\tif (data.every(constraint => constraintMatches(boxData, constraint))) return true\n\t}\n\treturn false\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { shouldExcludeBox } from './shouldExcludeBox.ts'\n\nconst MINIMUM_BOX_SIZE = 8 // size(4) + type(4)\nconst BOX_TYPE_OFFSET = 4\nconst DEFAULT_HASH_ALG = 'SHA-256'\n\n/**\n * Options for BMFF content hash computation.\n *\n * @public\n */\nexport type BmffHashOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n\t/** `8` for offset-prefix mode, `0` (default) for no prefix. */\n\treadonly offsetPrefixSize?: number\n}\n\nfunction readBoxType(bytes: Uint8Array, offset: number): string {\n\treturn String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3])\n}\n\nfunction writeUint64BigEndian(bytes: Uint8Array, value: number): void {\n\tnew DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).setBigUint64(0, BigInt(value), false)\n}\n\nfunction buildHashInput(\n\tbytes: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n\toffsetPrefixSize: number,\n): Uint8Array {\n\tif (offsetPrefixSize !== 0 && offsetPrefixSize !== 8) {\n\t\tthrow new Error(`offsetPrefixSize must be 0 or 8, got ${offsetPrefixSize}`)\n\t}\n\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t// First pass: calculate total size\n\tlet totalLength = 0\n\tlet offset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\ttotalLength += offsetPrefixSize + boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\t// Second pass: write directly into pre-sized buffer\n\tconst hashInput = new Uint8Array(totalLength)\n\tlet writeOffset = 0\n\toffset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\tif (offsetPrefixSize > 0) {\n\t\t\t\twriteUint64BigEndian(hashInput.subarray(writeOffset, writeOffset + offsetPrefixSize), offset)\n\t\t\t\twriteOffset += offsetPrefixSize\n\t\t\t}\n\t\t\thashInput.set(boxData, writeOffset)\n\t\t\twriteOffset += boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\treturn hashInput\n}\n\n/**\n * Computes the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Iterates through top-level BMFF boxes, excludes those matching the exclusion list,\n * concatenates the remaining box bytes (optionally prefixed with each box's file offset),\n * and returns the WebCrypto digest.\n *\n * @param segmentBytes - Raw segment bytes to hash\n * @param options - Hash options (exclusions, algorithm, offset prefix size)\n * @returns The computed hash bytes\n *\n * @example\n * {@includeCode ../../test/bmff/computeBmffHash.test.ts#example}\n *\n * @public\n */\nexport async function computeBmffHash(segmentBytes: Uint8Array, options?: BmffHashOptions): Promise<Uint8Array> {\n\tconst exclusions = options?.exclusions ?? []\n\tconst alg = options?.alg ?? DEFAULT_HASH_ALG\n\tconst offsetPrefixSize = options?.offsetPrefixSize ?? 0\n\n\tconst hashInput = buildHashInput(segmentBytes, exclusions, offsetPrefixSize)\n\tconst hashBuffer = await crypto.subtle.digest(alg, hashInput)\n\treturn new Uint8Array(hashBuffer)\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { computeBmffHash } from './computeBmffHash.ts'\nimport { hashesEqual } from '../utils.ts'\n\nconst OFFSET_PREFIX_SIZES_TO_TRY = [8, 0] as const\n\n/**\n * Options for BMFF hash validation.\n *\n * @public\n */\nexport type BmffHashValidationOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n}\n\n/**\n * Validates the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Tries both offset-prefix modes — 8-byte file offset prefix and no prefix — to handle\n * inter-signer interoperability until a standard signaling mechanism is defined in the spec.\n *\n * Use {@link computeBmffHash} directly when the offset prefix size is known.\n *\n * @param segmentBytes - Raw segment bytes to validate\n * @param expectedHash - Expected hash bytes from the VSI CBOR map\n * @param options - Validation options (exclusions, algorithm)\n * @returns `true` if the computed hash matches the expected hash in either offset mode\n *\n * @example\n * {@includeCode ../../test/bmff/validateBmffHash.test.ts#example}\n *\n * @public\n */\nexport async function validateBmffHash(\n\tsegmentBytes: Uint8Array,\n\texpectedHash: Uint8Array,\n\toptions?: BmffHashValidationOptions,\n): Promise<boolean> {\n\tfor (const offsetPrefixSize of OFFSET_PREFIX_SIZES_TO_TRY) {\n\t\tconst hash = await computeBmffHash(segmentBytes, { ...options, offsetPrefixSize })\n\t\tif (hashesEqual(hash, expectedHash)) return true\n\t}\n\treturn false\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA validation status codes for manifest integrity checks,\n * as defined in the C2PA specification chapters 15 and 18.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_claim_validation | C2PA Spec §15.10.3}\n *\n * @enum\n *\n * @public\n */\nexport const C2paStatusCode = {\n\t/** Assertion hash does not match the hashed URI in the claim (§15.10.3.1) */\n\tASSERTION_HASHEDURI_MISMATCH: 'assertion.hashedURI.mismatch',\n\t/** An assertion referenced in the claim is missing from the assertion store (§15.10.3.1) */\n\tASSERTION_MISSING: 'assertion.missing',\n\t/** An action requiring an ingredient reference does not have one (§18.15.4.7) */\n\tASSERTION_ACTION_INGREDIENT_MISMATCH: 'assertion.action.ingredientMismatch',\n\t/** Claim signature verification failed (§15.7) */\n\tCLAIM_SIGNATURE_MISMATCH: 'claim.signature.mismatch',\n} as const\n\n/**\n * Union type of all {@link (C2paStatusCode:variable)} values.\n *\n * @public\n */\nexport type C2paStatusCode = ValueOf<typeof C2paStatusCode>\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\n\nconst ACTIONS_LABELS = new Set(['c2pa.actions', 'c2pa.actions.v2'])\nconst ACTIONS_REQUIRING_INGREDIENTS = new Set(['c2pa.opened', 'c2pa.placed', 'c2pa.removed'])\n\n/**\n * Validates action ingredient references per C2PA §18.15.4.7.\n *\n * For any `c2pa.actions` or `c2pa.actions.v2` assertion, actions with type\n * `c2pa.opened`, `c2pa.placed`, or `c2pa.removed` must include a\n * `parameters.ingredients` field. Reports `assertion.action.ingredientMismatch`\n * if any such action is missing the required field.\n *\n * @param assertions - Parsed assertions (label + decoded data)\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport function validateActionIngredients(\n\tassertions: readonly { readonly label: string; readonly data: unknown }[],\n): readonly C2paStatusCode[] {\n\tconst codes: C2paStatusCode[] = []\n\n\tfor (const assertion of assertions) {\n\t\tif (!ACTIONS_LABELS.has(assertion.label)) continue\n\n\t\tconst data = assertion.data as Record<string, unknown> | null\n\t\tif (!data) continue\n\n\t\tconst actions = data['actions'] as unknown[] | undefined\n\t\tif (!Array.isArray(actions)) continue\n\n\t\tfor (const action of actions) {\n\t\t\tif (!action || typeof action !== 'object') continue\n\t\t\tconst record = action as Record<string, unknown>\n\t\t\tconst actionType = record['action'] as string | undefined\n\t\t\tif (!actionType || !ACTIONS_REQUIRING_INGREDIENTS.has(actionType)) continue\n\n\t\t\tconst parameters = record['parameters'] as Record<string, unknown> | undefined\n\t\t\tconst ingredients = parameters?.['ingredients']\n\n\t\t\tif (!Array.isArray(ingredients) || ingredients.length === 0) {\n\t\t\t\tcodes.push(C2paStatusCode.ASSERTION_ACTION_INGREDIENT_MISMATCH)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn codes\n}\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { hashesEqual, normalizeAlgorithmName } from '../utils.ts'\nimport type { ClaimAssertionRef } from './ClaimAssertionRef.ts'\nimport type { InternalAssertionData } from './InternalManifestData.ts'\n\n/**\n * Extracts the assertion label from a JUMBF URI.\n *\n * Handles both absolute (`self#jumbf=/c2pa/<manifest>/c2pa.assertions/<label>`)\n * and relative URI forms by returning the last path segment.\n */\nfunction extractLabelFromUrl(url: string): string {\n\tconst fragmentIndex = url.indexOf('#jumbf=')\n\tconst path = fragmentIndex >= 0 ? url.substring(fragmentIndex + 7) : url\n\tconst lastSlash = path.lastIndexOf('/')\n\treturn lastSlash >= 0 ? path.substring(lastSlash + 1) : path\n}\n\n/**\n * Validates assertion hashes and presence per C2PA §15.10.3.1.\n *\n * For each assertion referenced in the claim's hashed URI list:\n * - Checks that the assertion exists in the assertion store (`assertion.missing`)\n * - Recomputes the hash of the raw JUMBF box payload and compares it to the\n * expected hash from the claim (`assertion.hashedURI.mismatch`)\n *\n * @param claimRefs - Hashed URI references from the claim\n * @param assertions - Parsed assertions with preserved raw box payloads\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport async function validateAssertionHashes(\n\tclaimRefs: readonly ClaimAssertionRef[],\n\tassertions: readonly InternalAssertionData[],\n): Promise<readonly C2paStatusCode[]> {\n\tif (claimRefs.length === 0) return []\n\n\tconst assertionsByLabel = new Map<string, InternalAssertionData>()\n\tfor (const assertion of assertions) {\n\t\tassertionsByLabel.set(assertion.label, assertion)\n\t}\n\n\tconst codes: C2paStatusCode[] = []\n\n\tconst hashChecks = claimRefs.map(async (ref) => {\n\t\tconst label = extractLabelFromUrl(ref.url)\n\t\tconst assertion = assertionsByLabel.get(label)\n\n\t\tif (!assertion) {\n\t\t\treturn C2paStatusCode.ASSERTION_MISSING\n\t\t}\n\n\t\tconst alg = ref.alg ? normalizeAlgorithmName(ref.alg) : 'SHA-256'\n\t\tconst computedHash = new Uint8Array(\n\t\t\tawait crypto.subtle.digest(alg, assertion.rawBoxPayload),\n\t\t)\n\n\t\tif (!hashesEqual(computedHash, ref.hash)) {\n\t\t\treturn C2paStatusCode.ASSERTION_HASHEDURI_MISMATCH\n\t\t}\n\n\t\treturn null\n\t})\n\n\tconst results = await Promise.all(hashChecks)\n\tfor (const result of results) {\n\t\tif (result) codes.push(result)\n\t}\n\n\treturn codes\n}\n","// WebCrypto algorithm names\nexport const ECDSA_ALGORITHM = 'ECDSA'\nexport const ED25519_ALGORITHM = 'Ed25519'\nexport const RSA_PSS_ALGORITHM = 'RSA-PSS'\n\n// Named curves\nexport const CURVE_P256 = 'P-256'\nexport const CURVE_P384 = 'P-384'\nexport const CURVE_P521 = 'P-521'\n\n// Hash algorithms\nexport const HASH_SHA256 = 'SHA-256'\nexport const HASH_SHA384 = 'SHA-384'\nexport const HASH_SHA512 = 'SHA-512'\n","import {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst COSE_ALG_ES256 = -7\nconst COSE_ALG_ES384 = -35\nconst COSE_ALG_ES512 = -36\nconst COSE_ALG_EDDSA = -8\nconst COSE_ALG_PS256 = -37\nconst COSE_ALG_PS384 = -38\nconst COSE_ALG_PS512 = -39\n\ntype CoseAlgorithm = AlgorithmIdentifier | EcKeyImportParams | RsaHashedImportParams\n\nconst COSE_ALGORITHM_MAP = new Map<number, CoseAlgorithm>([\n\t[COSE_ALG_ES256, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P256 }],\n\t[COSE_ALG_ES384, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P384 }],\n\t[COSE_ALG_ES512, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P521 }],\n\t[COSE_ALG_EDDSA, { name: ED25519_ALGORITHM }],\n\t[COSE_ALG_PS256, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA256 } }],\n\t[COSE_ALG_PS384, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA384 } }],\n\t[COSE_ALG_PS512, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA512 } }],\n])\n\n/**\n * Maps a COSE algorithm number (from a COSE_Sign1 protected header) to the\n * WebCrypto algorithm identifier needed for `crypto.subtle.importKey('spki', ...)`.\n *\n * @param coseAlg - COSE algorithm identifier (e.g. -7 for ES256)\n * @returns WebCrypto algorithm identifier\n * @throws If the COSE algorithm is not supported\n *\n * @internal\n */\nexport function resolveAlgorithmFromCoseAlg(coseAlg: number): CoseAlgorithm {\n\tconst algorithm = COSE_ALGORITHM_MAP.get(coseAlg)\n\tif (!algorithm) {\n\t\tthrow new Error(`Unsupported COSE algorithm: ${coseAlg}`)\n\t}\n\treturn algorithm\n}\n","const CBOR_ARRAY_FOUR_ITEMS = 0x84\nconst CBOR_TEXT_MAJOR_TYPE_BASE = 0x60\nconst CBOR_BYTES_MAJOR_TYPE_BASE = 0x40\nconst CBOR_UINT8_LENGTH_INDICATOR = 0x58\nconst CBOR_UINT16_LENGTH_INDICATOR = 0x59\nconst CBOR_UINT32_LENGTH_INDICATOR = 0x5a\nconst CBOR_INLINE_MAX = 23\nconst CBOR_UINT8_MAX = 255\nconst CBOR_UINT16_MAX = 65535\nconst COSE_SIG1_CONTEXT_BYTES = new TextEncoder().encode('Signature1')\n\nfunction byteStringHeaderSize(length: number): number {\n\tif (length <= CBOR_INLINE_MAX) return 1\n\tif (length <= CBOR_UINT8_MAX) return 2\n\tif (length <= CBOR_UINT16_MAX) return 3\n\treturn 5\n}\n\nfunction writeByteStringHeader(output: Uint8Array, offset: number, length: number): number {\n\tif (length <= CBOR_INLINE_MAX) {\n\t\toutput[offset++] = CBOR_BYTES_MAJOR_TYPE_BASE + length\n\t} else if (length <= CBOR_UINT8_MAX) {\n\t\toutput[offset++] = CBOR_UINT8_LENGTH_INDICATOR\n\t\toutput[offset++] = length\n\t} else if (length <= CBOR_UINT16_MAX) {\n\t\toutput[offset++] = CBOR_UINT16_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t} else {\n\t\toutput[offset++] = CBOR_UINT32_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >>> 24) & 0xff\n\t\toutput[offset++] = (length >>> 16) & 0xff\n\t\toutput[offset++] = (length >>> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t}\n\treturn offset\n}\n\n/**\n * Builds the COSE `Sig_Structure` (ToBeSigned) bytes for a `COSE_Sign1` structure (RFC 9052 §4.4).\n *\n * The resulting bytes are the direct input to signature creation or verification via WebCrypto.\n *\n * @param protectedBytes - Serialized protected header (CBOR-encoded byte string)\n * @param payload - Payload bytes\n * @param externalAad - External additional authenticated data (default: empty)\n * @returns CBOR-encoded `Sig_Structure` array ready for signing or verification\n *\n * @example\n * {@includeCode ../../test/cose/buildSigStructure.test.ts#example}\n *\n * @public\n */\nexport function buildSigStructure(\n\tprotectedBytes: Uint8Array,\n\tpayload: Uint8Array,\n\texternalAad: Uint8Array = new Uint8Array(0),\n): Uint8Array {\n\tconst totalLength =\n\t\t1 // array header\n\t\t+ 1 + COSE_SIG1_CONTEXT_BYTES.length // context string (length < 24, fits inline)\n\t\t+ byteStringHeaderSize(protectedBytes.length) + protectedBytes.length\n\t\t+ byteStringHeaderSize(externalAad.length) + externalAad.length\n\t\t+ byteStringHeaderSize(payload.length) + payload.length\n\n\tconst result = new Uint8Array(totalLength)\n\tlet offset = 0\n\n\tresult[offset++] = CBOR_ARRAY_FOUR_ITEMS\n\tresult[offset++] = CBOR_TEXT_MAJOR_TYPE_BASE + COSE_SIG1_CONTEXT_BYTES.length\n\tresult.set(COSE_SIG1_CONTEXT_BYTES, offset)\n\toffset += COSE_SIG1_CONTEXT_BYTES.length\n\n\toffset = writeByteStringHeader(result, offset, protectedBytes.length)\n\tresult.set(protectedBytes, offset)\n\toffset += protectedBytes.length\n\n\toffset = writeByteStringHeader(result, offset, externalAad.length)\n\tresult.set(externalAad, offset)\n\toffset += externalAad.length\n\n\toffset = writeByteStringHeader(result, offset, payload.length)\n\tresult.set(payload, offset)\n\n\treturn result\n}\n","import type { CoseSign1 } from './CoseSign1.ts'\nimport { buildSigStructure } from './buildSigStructure.ts'\nimport {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst DER_SEQUENCE_TAG = 0x30\nconst DER_INTEGER_TAG = 0x02\n\nconst CURVE_COMPONENT_BYTES: Record<string, number> = { [CURVE_P256]: 32, [CURVE_P384]: 48, [CURVE_P521]: 66 }\n\ntype EcKeyAlgorithm = KeyAlgorithm & { readonly namedCurve: string }\ntype RsaHashedKeyAlgorithm = KeyAlgorithm & { readonly hash: { readonly name: string } }\n\nconst RSA_PSS_SALT_LENGTH: Record<string, number> = {\n\t[HASH_SHA256]: 32,\n\t[HASH_SHA384]: 48,\n\t[HASH_SHA512]: 64,\n}\n\nfunction getComponentSize(publicKey: CryptoKey): number {\n\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\tconst size = CURVE_COMPONENT_BYTES[curve]\n\tif (!size) throw new Error(`Unsupported EC curve: ${curve}`)\n\treturn size\n}\n\nfunction isDerEncoded(signature: Uint8Array, expectedRawLength: number): boolean {\n\treturn signature.length !== expectedRawLength && signature.length > 2 && signature[0] === DER_SEQUENCE_TAG\n}\n\nfunction parseDerLength(der: Uint8Array, offset: number): { length: number; nextOffset: number } {\n\tif (offset >= der.length) throw new Error('DER signature: truncated length')\n\tconst firstByte = der[offset]\n\tif ((firstByte & 0x80) === 0) {\n\t\treturn { length: firstByte, nextOffset: offset + 1 }\n\t}\n\tconst numBytes = firstByte & 0x7f\n\tif (numBytes === 0 || offset + numBytes >= der.length) throw new Error('DER signature: invalid long-form length')\n\tlet length = 0\n\tfor (let i = 1; i <= numBytes; i++) {\n\t\tlength = (length << 8) | der[offset + i]\n\t}\n\treturn { length, nextOffset: offset + 1 + numBytes }\n}\n\nfunction extractDerInteger(\n\tder: Uint8Array,\n\toffset: number,\n): { value: Uint8Array; nextOffset: number } {\n\tif (der[offset] !== DER_INTEGER_TAG) throw new Error('DER signature: expected INTEGER tag')\n\tconst { length, nextOffset: valueStart } = parseDerLength(der, offset + 1)\n\tlet start = valueStart\n\tlet remaining = length\n\tif (remaining > 0 && der[start] === 0x00) {\n\t\tstart++\n\t\tremaining--\n\t}\n\treturn { value: der.slice(start, start + remaining), nextOffset: valueStart + length }\n}\n\nfunction derToRawEcdsaSignature(der: Uint8Array, componentSize: number): Uint8Array {\n\tif (der[0] !== DER_SEQUENCE_TAG) throw new Error('DER signature: expected SEQUENCE tag')\n\tconst { nextOffset: contentStart } = parseDerLength(der, 1)\n\tconst rResult = extractDerInteger(der, contentStart)\n\tconst sResult = extractDerInteger(der, rResult.nextOffset)\n\n\tconst rawLength = componentSize * 2\n\tconst raw = new Uint8Array(rawLength)\n\traw.set(rResult.value, componentSize - rResult.value.length)\n\traw.set(sResult.value, rawLength - sResult.value.length)\n\treturn raw\n}\n\nfunction resolveVerifyAlgorithm(publicKey: CryptoKey) {\n\tconst { name } = publicKey.algorithm\n\tif (name === ED25519_ALGORITHM) return { name: ED25519_ALGORITHM }\n\tif (name === ECDSA_ALGORITHM) {\n\t\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\t\tconst hash = curve === CURVE_P384 ? HASH_SHA384 : curve === CURVE_P521 ? HASH_SHA512 : HASH_SHA256\n\t\treturn { name: ECDSA_ALGORITHM, hash: { name: hash } }\n\t}\n\tif (name === RSA_PSS_ALGORITHM) {\n\t\tconst hashName = (publicKey.algorithm as RsaHashedKeyAlgorithm).hash.name\n\t\treturn { name: RSA_PSS_ALGORITHM, saltLength: RSA_PSS_SALT_LENGTH[hashName] ?? 32 }\n\t}\n\tthrow new Error(`Unsupported public key algorithm: ${name}`)\n}\n\nfunction normalizeSignature(signature: Uint8Array, publicKey: CryptoKey): Uint8Array {\n\tif (publicKey.algorithm.name !== ECDSA_ALGORITHM) return signature\n\tconst componentSize = getComponentSize(publicKey)\n\tif (isDerEncoded(signature, componentSize * 2)) {\n\t\treturn derToRawEcdsaSignature(signature, componentSize)\n\t}\n\treturn signature\n}\n\n/**\n * Verifies a `COSE_Sign1` signature using a provided `CryptoKey` (RFC 9052 §4.4).\n *\n * Builds the `Sig_Structure` from the protected header and payload, normalizes\n * DER-encoded ECDSA signatures to raw format if needed, and delegates\n * verification to the WebCrypto API.\n *\n * Supports `ECDSA` (P-256, P-384, P-521), `Ed25519`, and `RSA-PSS` (PS256, PS384, PS512) keys.\n *\n * @param coseSign1 - Decoded COSE_Sign1 structure (from {@link decodeCoseSign1})\n * @param payload - Payload bytes to verify. May differ from `coseSign1.payload` for detached payloads.\n * @param publicKey - Imported public key for verification\n * @returns `true` if the signature is valid\n * @throws If the key algorithm is not supported\n *\n * @example\n * {@includeCode ../../test/cose/verifyCoseSign1.test.ts#example}\n *\n * @public\n */\nexport async function verifyCoseSign1(\n\tcoseSign1: CoseSign1,\n\tpayload: Uint8Array,\n\tpublicKey: CryptoKey,\n): Promise<boolean> {\n\tconst sigStructure = buildSigStructure(coseSign1.protectedBytes, payload)\n\tconst algorithm = resolveVerifyAlgorithm(publicKey)\n\tconst signature = normalizeSignature(coseSign1.signature, publicKey)\n\treturn crypto.subtle.verify(algorithm, publicKey, signature, sigStructure)\n}\n","import {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_SEQUENCE,\n\treadElement,\n\treadElementRaw,\n} from './asn1.ts'\n\n/**\n * Extracts the SubjectPublicKeyInfo (SPKI) DER bytes from an X.509 DER certificate.\n *\n * Navigates the TBSCertificate structure to reach the 7th field\n * (SubjectPublicKeyInfo), skipping version, serialNumber, signatureAlgorithm,\n * issuer, validity, and subject.\n *\n * The returned bytes can be imported directly via\n * `crypto.subtle.importKey('spki', ...)`.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Full DER encoding of the SubjectPublicKeyInfo, or `null` on parse failure\n *\n * @internal\n */\nexport function extractCertificateSpki(certDER: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// 1. Optional version [0]\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// 2. Serial number (INTEGER)\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// 3. Signature algorithm (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 4. Issuer (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 5. Validity (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 6. Subject (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 7. SubjectPublicKeyInfo (SEQUENCE) — return full DER encoding\n\t\treturn readElementRaw(tbs.value, offset)\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","import { readElement, ASN1_TAG_SEQUENCE } from './asn1.ts'\n\n// OID 1.2.840.113549.1.1.10 (rsassaPss)\nconst OID_RSASSA_PSS = new Uint8Array([0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a])\n\n// AlgorithmIdentifier for rsaEncryption (OID 1.2.840.113549.1.1.1) with NULL params\n// SEQUENCE { OID rsaEncryption, NULL }\nconst RSA_ENCRYPTION_ALGORITHM_ID = new Uint8Array([\n\t0x30, 0x0d, // SEQUENCE, 13 bytes\n\t0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, // OID rsaEncryption\n\t0x05, 0x00, // NULL\n])\n\nfunction containsRsaPssOid(bytes: Uint8Array): boolean {\n\tif (bytes.length < OID_RSASSA_PSS.length) return false\n\touter: for (let i = 0; i <= bytes.length - OID_RSASSA_PSS.length; i++) {\n\t\tfor (let j = 0; j < OID_RSASSA_PSS.length; j++) {\n\t\t\tif (bytes[i + j] !== OID_RSASSA_PSS[j]) continue outer\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\n/**\n * Normalizes an SPKI that uses the `rsassaPss` OID (1.2.840.113549.1.1.10) to\n * use the generic `rsaEncryption` OID (1.2.840.113549.1.1.1) instead.\n *\n * WebCrypto's `importKey('spki', ...)` with `{ name: 'RSA-PSS' }` expects the\n * SPKI to use the generic `rsaEncryption` OID. Certificates signed with\n * RSASSA-PSS often embed the PSS-specific OID and parameters, which causes\n * `DataError` on import.\n *\n * If the SPKI does not use `rsassaPss`, it is returned unchanged.\n *\n * @internal\n */\nexport function normalizeRsaPssSpki(spkiBytes: Uint8Array): Uint8Array {\n\tif (!containsRsaPssOid(spkiBytes)) return spkiBytes\n\n\t// Parse outer SEQUENCE\n\tconst outer = readElement(spkiBytes, 0)\n\tif (!outer || outer.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// First child: AlgorithmIdentifier SEQUENCE\n\tconst algId = readElement(outer.value, 0)\n\tif (!algId || algId.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// Second child: BIT STRING with the public key\n\tconst publicKeyBitString = outer.value.subarray(algId.totalSize)\n\n\t// Build new SPKI: RSA_ENCRYPTION_ALGORITHM_ID + original BIT STRING\n\tconst innerLength = RSA_ENCRYPTION_ALGORITHM_ID.length + publicKeyBitString.length\n\tconst headerBytes = encodeDerLength(innerLength)\n\tconst result = new Uint8Array(1 + headerBytes.length + innerLength)\n\tlet offset = 0\n\tresult[offset++] = ASN1_TAG_SEQUENCE\n\tresult.set(headerBytes, offset)\n\toffset += headerBytes.length\n\tresult.set(RSA_ENCRYPTION_ALGORITHM_ID, offset)\n\toffset += RSA_ENCRYPTION_ALGORITHM_ID.length\n\tresult.set(publicKeyBitString, offset)\n\n\treturn result\n}\n\nfunction encodeDerLength(length: number): Uint8Array {\n\tif (length < 0x80) return new Uint8Array([length])\n\tif (length <= 0xff) return new Uint8Array([0x81, length])\n\tif (length <= 0xffff) return new Uint8Array([0x82, (length >> 8) & 0xff, length & 0xff])\n\treturn new Uint8Array([0x83, (length >> 16) & 0xff, (length >> 8) & 0xff, length & 0xff])\n}\n","import { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { resolveAlgorithmFromCoseAlg } from '../cose/resolveAlgorithmFromCoseAlg.ts'\nimport { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { extractCertificateSpki } from '../x509/extractCertificateSpki.ts'\nimport { normalizeRsaPssSpki } from '../x509/normalizeRsaPssSpki.ts'\n\n/**\n * Verifies the claim signature of a C2PA manifest per §15.7.\n *\n * The `c2pa.signature` JUMBF box contains a `COSE_Sign1` structure whose payload\n * is the claim CBOR bytes. This function verifies the signature against the\n * public key extracted from the end-entity certificate in the `x5chain` header.\n *\n * @param signatureBytes - Raw COSE_Sign1 bytes from the `c2pa.signature` box\n * @param claimCborBytes - Raw CBOR bytes of the claim content box\n * @param certificateDER - DER-encoded end-entity X.509 certificate\n * @returns `true` if the signature is valid\n *\n * @internal\n */\nexport async function verifyClaimSignature(\n\tsignatureBytes: Uint8Array,\n\tclaimCborBytes: Uint8Array,\n\tcertificateDER: Uint8Array,\n): Promise<boolean> {\n\ttry {\n\t\tconst coseSign1 = decodeCoseSign1(signatureBytes)\n\n\t\tconst rawSpki = extractCertificateSpki(certificateDER)\n\t\tif (!rawSpki) return false\n\t\tconst spkiBytes = normalizeRsaPssSpki(rawSpki)\n\n\t\tif (coseSign1.alg == null) return false\n\n\t\tconst importAlgorithm = resolveAlgorithmFromCoseAlg(coseSign1.alg)\n\n\t\tconst publicKey = await crypto.subtle.importKey(\n\t\t\t'spki',\n\t\t\tnew Uint8Array(spkiBytes) as BufferSource,\n\t\t\timportAlgorithm,\n\t\t\ttrue,\n\t\t\t['verify'],\n\t\t)\n\n\t\treturn verifyCoseSign1(coseSign1, claimCborBytes, publicKey)\n\t}\n\tcatch {\n\t\treturn false\n\t}\n}\n","import type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { C2paStatusCode as Code } from '../C2paStatusCode.ts'\nimport type { InternalManifestData } from './InternalManifestData.ts'\nimport { validateActionIngredients } from './validateActionIngredients.ts'\nimport { validateAssertionHashes } from './validateAssertionHashes.ts'\nimport { verifyClaimSignature } from './verifyClaimSignature.ts'\n\n/**\n * Validates the integrity of a C2PA manifest per Chapter 15 and Chapter 18.\n *\n * Runs four validation checks in parallel where possible:\n * 1. Assertion hash verification (§15.10.3.1)\n * 2. Missing assertion detection (§15.10.3.1)\n * 3. Action ingredient validation (§18.15.4.7)\n * 4. Claim signature verification (§15.7)\n *\n * @param internal - Enriched manifest data with raw assertion bytes and claim references\n * @param certificateDER - DER-encoded end-entity certificate, or `null` to skip signature check\n * @returns Array of C2PA status codes for any failures found (empty if all pass)\n *\n * @internal\n */\nexport async function validateManifestIntegrity(\n\tinternal: InternalManifestData,\n\tcertificateDER: Uint8Array | null,\n): Promise<readonly C2paStatusCode[]> {\n\tconst { signatureBytes, claimCborBytes } = internal\n\n\tconst [assertionHashCodes, signatureValid] = await Promise.all([\n\t\tvalidateAssertionHashes(internal.claimAssertionRefs, internal.assertions),\n\t\tsignatureBytes && claimCborBytes && certificateDER\n\t\t\t? verifyClaimSignature(signatureBytes, claimCborBytes, certificateDER)\n\t\t\t: Promise.resolve(true),\n\t])\n\n\tconst actionCodes = validateActionIngredients(internal.assertions)\n\n\tconst codes: C2paStatusCode[] = [...assertionHashCodes, ...actionCodes]\n\n\tif (!signatureValid) {\n\t\tcodes.push(Code.CLAIM_SIGNATURE_MISMATCH)\n\t}\n\n\treturn codes\n}\n","import type { CoseKeyJwk } from './CoseKeyJwk.ts'\n\n// IANA COSE Key Types (RFC 9053)\nconst OKP_KEY_TYPE = 1\nconst EC2_KEY_TYPE = 2\n\n// IANA COSE Elliptic Curves\nconst EC_CURVE_NAMES: Record<number, string> = { 1: 'P-256', 2: 'P-384', 3: 'P-521' }\nconst OKP_CURVE_NAMES: Record<number, string> = { 4: 'X25519', 5: 'X448', 6: 'Ed25519', 7: 'Ed448' }\n\ntype CoseKeyLike = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(key: CoseKeyLike, intKey: number): unknown {\n\tif (key instanceof Map) return key.get(intKey)\n\treturn (key as Record<number | string, unknown>)[intKey]\n}\n\nfunction toBase64Url(value: unknown): string {\n\tconst bytes = value instanceof Uint8Array ? value : new Uint8Array(value as number[])\n\tlet binary = ''\n\tfor (const byte of bytes) binary += String.fromCharCode(byte)\n\treturn btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\n/**\n * Converts a COSE public key (RFC 9052 / IANA COSE Key registry) to JWK format.\n *\n * Supports EC2 keys (P-256, P-384, P-521) and OKP keys (Ed25519, Ed448, X25519, X448).\n * Input may be a `Map\\<number, unknown\\>` (from CBOR decoders like cbor-x) or a plain\n * object with integer keys.\n *\n * @param coseKey - COSE key structure as decoded from a C2PA `c2pa.session-keys` assertion\n * @returns JWK representation of the public key\n * @throws If the key type or curve is not supported\n *\n * @example\n * {@includeCode ../../test/cose/convertCoseKeyToJwk.test.ts#example}\n *\n * @public\n */\nexport function convertCoseKeyToJwk(coseKey: unknown): CoseKeyJwk {\n\tconst key = coseKey as CoseKeyLike\n\tconst kty = coseGet(key, 1)\n\tconst crv = coseGet(key, -1) as number\n\tconst x = coseGet(key, -2)\n\n\tif (kty === EC2_KEY_TYPE) {\n\t\tconst curveName = EC_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported EC curve: ${crv}`)\n\t\tconst y = coseGet(key, -3)\n\t\tif (!(x instanceof Uint8Array)) throw new Error('EC2 key missing or invalid x coordinate')\n\t\tif (!(y instanceof Uint8Array)) throw new Error('EC2 key missing or invalid y coordinate')\n\t\treturn { kty: 'EC', crv: curveName, x: toBase64Url(x), y: toBase64Url(y) }\n\t}\n\n\tif (kty === OKP_KEY_TYPE) {\n\t\tconst curveName = OKP_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported OKP curve: ${crv}`)\n\t\treturn { kty: 'OKP', crv: curveName, x: toBase64Url(x) }\n\t}\n\n\tthrow new Error(`Unsupported COSE key type: ${kty}`)\n}\n","import { ECDSA_ALGORITHM } from './constants.ts'\n\nconst KEY_TYPE_OKP = 'OKP'\n\nexport function resolveImportAlgorithm(jwk: { kty: string; crv: string }): AlgorithmIdentifier | EcKeyImportParams {\n\treturn jwk.kty === KEY_TYPE_OKP ? { name: jwk.crv } : { name: ECDSA_ALGORITHM, namedCurve: jwk.crv }\n}\n","import { encode } from 'cbor-x/encode'\nimport { convertCoseKeyToJwk } from './convertCoseKeyToJwk.ts'\nimport { decodeCoseSign1 } from './decodeCoseSign1.ts'\nimport { resolveImportAlgorithm } from './resolveImportAlgorithm.ts'\nimport { verifyCoseSign1 } from './verifyCoseSign1.ts'\n\n/**\n * Verifies a C2PA signer binding — a `COSE_Sign1` structure that proves\n * a session key was authorized by the content signer (C2PA spec §18.25.2).\n *\n * The `Sig_Structure` payload is `CBOR(bstr(signerCertBytes))` per the C2PA spec.\n * DER-encoded ECDSA signatures are automatically normalized to raw format.\n *\n * @param signerBindingBytes - Raw `COSE_Sign1` bytes of the signer binding\n * @param sessionCoseKey - COSE public key from the `c2pa.session-keys` assertion\n * @param signerCertBytes - DER-encoded end-entity certificate (from `x5chain`)\n * @returns `true` if the signer binding signature is valid\n * @throws If the COSE key type is not supported or decoding fails\n *\n * @example\n * {@includeCode ../../test/cose/verifySignerBinding.test.ts#example}\n *\n * @public\n */\nexport async function verifySignerBinding(\n\tsignerBindingBytes: Uint8Array,\n\tsessionCoseKey: unknown,\n\tsignerCertBytes: Uint8Array,\n): Promise<boolean> {\n\tconst coseSign1 = decodeCoseSign1(signerBindingBytes)\n\tconst jwk = convertCoseKeyToJwk(sessionCoseKey)\n\tconst publicKey = await crypto.subtle.importKey('jwk', jwk as JsonWebKey, resolveImportAlgorithm(jwk), false, ['verify'])\n\t// Signer binding payload = CBOR(bstr(cert)) per C2PA spec §18.25.2\n\tconst cborCertPayload = encode(signerCertBytes) as Uint8Array\n\treturn verifyCoseSign1(coseSign1, cborCertPayload, publicKey)\n}\n","import { decode } from 'cbor-x/decode'\nimport { encode } from 'cbor-x/encode'\nimport { findIsoBox, readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { extractCertificateFromSignatureBytes } from '../extractManifestCertificate.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { validateManifestIntegrity } from '../claim/validateManifestIntegrity.ts'\nimport { convertCoseKeyToJwk } from '../cose/convertCoseKeyToJwk.ts'\nimport { verifySignerBinding } from '../cose/verifySignerBinding.ts'\nimport type { InitSegmentValidation, ValidatedSessionKey } from './InitSegmentValidation.ts'\nimport { bytesToHex, isKeyExpired, normalizeAlgorithmName } from '../utils.ts'\n\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst SESSION_KEYS_ASSERTION_LABEL = 'c2pa.session-keys'\nconst COSE_KEY_ID_LABEL = 2\n\n// cbor-x represents CBOR tagged values in multiple ways depending on version/config:\n// - { tag: number, value: unknown } (structured)\n// - Tag class instance with constructor name 'Tag'\n// - { '@@TAGGED@@': [tag, value] } (internal key)\nconst CBOR_TAGGED_KEY = '@@TAGGED@@'\n\nfunction extractCborTaggedValue(value: unknown): unknown | null {\n\tif (typeof value !== 'object' || value === null) return null\n\tconst obj = value as Record<string, unknown>\n\tif (typeof obj['tag'] === 'number' && 'value' in obj) return obj['value']\n\tconst tagged = obj[CBOR_TAGGED_KEY]\n\tif (Array.isArray(tagged) && tagged.length === 2) return tagged[1]\n\treturn null\n}\n\nfunction normalizeToUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tif (extractCborTaggedValue(value) !== null) return encode(value) as Uint8Array\n\tthrow new Error('Cannot convert value to Uint8Array')\n}\n\nfunction ensureDecodedCbor(value: unknown): unknown {\n\tif (value instanceof Uint8Array) return decode(value)\n\tif (Array.isArray(value) && value.length > 0 && typeof (value as number[])[0] === 'number') {\n\t\treturn decode(new Uint8Array(value as number[]))\n\t}\n\treturn value\n}\n\nfunction parseCreatedAt(value: unknown): string | null {\n\tconst resolved = extractCborTaggedValue(value) ?? value\n\tif (typeof resolved === 'string') return resolved\n\tif (resolved instanceof Date) return resolved.toISOString()\n\treturn null\n}\n\nfunction extractKidHex(keyData: Record<string, unknown>, coseKey: unknown): string | null {\n\tconst kid = keyData['kid']\n\tif (kid instanceof Uint8Array) return bytesToHex(kid)\n\tif (typeof kid === 'string') return kid\n\tif (Array.isArray(kid) && kid.length > 0) return bytesToHex(new Uint8Array(kid as number[]))\n\n\t// Fallback: COSE key field 2 is the key ID per RFC 9052\n\tconst coseKeyLike = coseKey as Map<number, unknown> | Record<number, unknown>\n\tconst coseKid = coseKeyLike instanceof Map ? coseKeyLike.get(COSE_KEY_ID_LABEL) : coseKeyLike[COSE_KEY_ID_LABEL]\n\tif (coseKid instanceof Uint8Array) return bytesToHex(coseKid)\n\tif (Array.isArray(coseKid) && coseKid.length > 0) {\n\t\treturn bytesToHex(new Uint8Array(coseKid as number[]))\n\t}\n\n\treturn null\n}\n\nfunction extractKeyArray(data: unknown): unknown[] {\n\tif (Array.isArray(data)) return data\n\tif (typeof data === 'object' && data !== null) {\n\t\tconst obj = data as Record<string, unknown>\n\t\tconst keys = obj['keys'] ?? obj['sessionKeys']\n\t\tif (Array.isArray(keys)) return keys\n\t\tif (typeof keys === 'object' && keys !== null) {\n\t\t\tconst nested = (keys as Record<string, unknown>)['keys']\n\t\t\tif (Array.isArray(nested)) return nested\n\t\t}\n\t}\n\treturn []\n}\n\nasync function validateBmffHashAssertion(\n\tbytes: Uint8Array,\n\tassertion: C2paAssertion | null,\n): Promise<boolean> {\n\tif (!assertion) return true\n\tconst data = assertion.data as Record<string, unknown>\n\tconst rawHash = data['hash'] ?? data['value']\n\tif (!rawHash) return true\n\tconst expectedHash =\n\t\trawHash instanceof Uint8Array ? rawHash : new Uint8Array(rawHash as number[])\n\tconst alg = normalizeAlgorithmName(data['alg'] as string | undefined)\n\tconst exclusions = (data['exclusions'] as BmffHashExclusion[] | undefined) ?? []\n\treturn validateBmffHash(bytes, expectedHash, { exclusions, alg })\n}\n\ntype SessionKeyFields = {\n\tminSequenceNumber: number\n\tvalidityPeriod: number\n\tcreatedAt: string\n\tkid: string\n\tcoseKey: unknown\n\tsignerBindingBytes: Uint8Array\n}\n\nfunction extractSessionKeyFields(entry: unknown): SessionKeyFields | null {\n\tconst keyData = entry as Record<string, unknown>\n\n\tconst minSequenceNumber = keyData['minSequenceNumber']\n\tconst validityPeriod = keyData['validityPeriod']\n\tconst createdAt = parseCreatedAt(keyData['createdAt'])\n\n\tif (minSequenceNumber == null || validityPeriod == null || !createdAt) return null\n\n\tconst isNotYetActive = new Date() < new Date(createdAt)\n\tif (isNotYetActive || isKeyExpired(createdAt, Number(validityPeriod))) return null\n\n\tconst coseKey = ensureDecodedCbor(keyData['key'])\n\tconst kid = extractKidHex(keyData, coseKey)\n\tif (!kid) return null\n\n\tconst signerBindingRaw = keyData['signerBinding']\n\tif (!signerBindingRaw) return null\n\n\ttry {\n\t\treturn {\n\t\t\tminSequenceNumber: Number(minSequenceNumber),\n\t\t\tvalidityPeriod: Number(validityPeriod),\n\t\t\tcreatedAt,\n\t\t\tkid,\n\t\t\tcoseKey,\n\t\t\tsignerBindingBytes: normalizeToUint8Array(signerBindingRaw),\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function verifyAndConvertKey(\n\tfields: SessionKeyFields,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst isBindingValid = await verifySignerBinding(fields.signerBindingBytes, fields.coseKey, certificate)\n\tif (!isBindingValid) return null\n\n\ttry {\n\t\tconst jwk = convertCoseKeyToJwk(fields.coseKey)\n\t\treturn {\n\t\t\tkid: fields.kid,\n\t\t\tjwk,\n\t\t\tminSequenceNumber: fields.minSequenceNumber,\n\t\t\tvalidityPeriod: fields.validityPeriod,\n\t\t\tcreatedAt: fields.createdAt,\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function validateSingleSessionKey(\n\tentry: unknown,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst fields = extractSessionKeyFields(entry)\n\tif (!fields) return null\n\treturn verifyAndConvertKey(fields, certificate)\n}\n\nasync function validateSessionKeys(\n\tassertion: C2paAssertion,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey[]> {\n\tconst keyEntries = extractKeyArray(ensureDecodedCbor(assertion.data))\n\tconst results = await Promise.all(\n\t\tkeyEntries.map(entry => validateSingleSessionKey(entry, certificate)),\n\t)\n\treturn results.filter((key): key is ValidatedSessionKey => key !== null)\n}\n\n/**\n * Validates a C2PA init segment: parses the manifest, extracts and verifies\n * the certificate, validates the BMFF hard binding hash, verifies all\n * session keys from the `c2pa.session-keys` assertion, and performs\n * manifest integrity checks (assertion hashes, missing assertions,\n * action ingredients, and claim signature verification).\n *\n * Only session keys with a valid signer binding and an unexpired validity period\n * are included in the result.\n *\n * @param bytes - Raw init segment bytes\n * @returns Structured validation result (with `INIT_INVALID` error code if `mdat` box is present)\n * @throws If no C2PA UUID box is found\n *\n * @example\n * {@includeCode ../../test/init/validateC2paInitSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paInitSegment(bytes: Uint8Array): Promise<InitSegmentValidation> {\n\tconst boxes = readIsoBoxes(bytes)\n\tif (findIsoBox(boxes, box => box.type === 'mdat')) {\n\t\treturn {\n\t\t\tmanifest: null,\n\t\t\tcertificate: null,\n\t\t\tmanifestId: null,\n\t\t\tsessionKeys: [],\n\t\t\tisValid: false,\n\t\t\terrorCodes: [LiveVideoStatusCode.INIT_INVALID],\n\t\t}\n\t}\n\n\tconst internalData = readC2paManifest(bytes, boxes)\n\tconst { manifest } = internalData\n\tconst certificate = internalData.signatureBytes\n\t\t? extractCertificateFromSignatureBytes(internalData.signatureBytes)\n\t\t: null\n\n\tconst bmffHashAssertion =\n\t\tmanifest.assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL) ?? null\n\tconst bmffHashValid = await validateBmffHashAssertion(bytes, bmffHashAssertion)\n\n\tconst sessionKeysAssertion = manifest.assertions.find(\n\t\ta => a.label === SESSION_KEYS_ASSERTION_LABEL,\n\t)\n\tconst sessionKeys =\n\t\tsessionKeysAssertion && certificate\n\t\t\t? await validateSessionKeys(sessionKeysAssertion, certificate)\n\t\t\t: []\n\n\tconst integrityCodes = await validateManifestIntegrity(internalData, certificate)\n\n\tconst codes = new Set<LiveVideoStatusCode | C2paStatusCode>()\n\tif (!bmffHashValid) codes.add(LiveVideoStatusCode.INIT_INVALID)\n\tif (sessionKeys.length === 0) codes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\tfor (const code of integrityCodes) codes.add(code)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tmanifest,\n\t\tcertificate,\n\t\tmanifestId: manifest.instanceId,\n\t\tsessionKeys,\n\t\tisValid: errorCodes.length === 0,\n\t\terrorCodes,\n\t}\n}\n","import { readEmsg, readIsoBoxes, type EventMessageBox } from '@svta/cml-iso-bmff'\n\nconst EMSG_BOX_TYPE = 'emsg'\nconst VSI_SCHEME_URI = 'urn:c2pa:verifiable-segment-info'\nconst EMSG_READER_CONFIG = { readers: { emsg: readEmsg } }\n\n/**\n * Finds and parses the first C2PA Verifiable Segment Info (VSI) EMSG box\n * in a DASH segment, identified by scheme URI `urn:c2pa:verifiable-segment-info`.\n *\n * @param segmentBytes - Raw DASH segment bytes\n * @returns The parsed VSI EMSG box, or `null` if not found\n *\n * @example\n * {@includeCode ../../test/emsg/extractVsiEmsgBox.test.ts#example}\n *\n * @internal\n */\nexport function extractVsiEmsgBox(segmentBytes: Uint8Array): EventMessageBox | null {\n\tfor (const box of readIsoBoxes(segmentBytes, EMSG_READER_CONFIG)) {\n\t\tif (box.type !== EMSG_BOX_TYPE) continue\n\t\tconst emsg = box as EventMessageBox\n\t\tif (emsg.schemeIdUri === VSI_SCHEME_URI) return emsg\n\t}\n\treturn null\n}\n","import { decode } from 'cbor-x/decode'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { normalizeAlgorithmName } from '../utils.ts'\nimport type { VsiMap } from './VsiMap.ts'\n\n\n/**\n * Decodes a C2PA Verifiable Segment Info (VSI) CBOR map from raw bytes.\n *\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * @param vsiCborBytes - Raw CBOR-encoded VSI map bytes from the EMSG `messageData`\n * @returns The decoded VSI map\n * @throws If the bytes are not a valid VSI CBOR map\n *\n * @example\n * {@includeCode ../../test/vsi/decodeVsiMap.test.ts#example}\n *\n * @internal\n */\nexport function decodeVsiMap(vsiCborBytes: Uint8Array): VsiMap {\n\tconst raw = decode(vsiCborBytes) as Record<string, unknown>\n\n\tif (typeof raw !== 'object' || raw === null) {\n\t\tthrow new Error('VSI map must be a CBOR map')\n\t}\n\n\tconst sequenceNumber = raw['sequenceNumber']\n\tif (typeof sequenceNumber !== 'number') throw new Error('VSI map missing or invalid sequenceNumber')\n\n\tconst bmffHashRaw = raw['bmffHash'] as Record<string, unknown> | undefined\n\tif (!bmffHashRaw || typeof bmffHashRaw !== 'object') throw new Error('VSI map missing bmffHash')\n\n\tconst hash = bmffHashRaw['hash']\n\tif (!(hash instanceof Uint8Array)) throw new Error('VSI map bmffHash.hash must be a Uint8Array')\n\n\tconst exclusions = bmffHashRaw['exclusions']\n\tif (exclusions !== undefined && !Array.isArray(exclusions)) throw new Error('VSI map bmffHash.exclusions must be an array')\n\n\tconst manifestId = raw['manifestId']\n\tif (typeof manifestId !== 'string') throw new Error('VSI map missing or invalid manifestId')\n\n\tconst alg = normalizeAlgorithmName(bmffHashRaw['alg'] as string | undefined)\n\n\treturn {\n\t\tsequenceNumber,\n\t\tbmffHash: {\n\t\t\thash,\n\t\t\talg,\n\t\t\texclusions: (exclusions as BmffHashExclusion[] | undefined) ?? [],\n\t\t},\n\t\tmanifestId,\n\t}\n}\n","import type { SequenceState } from './SequenceState.ts'\n\n/**\n * Creates the initial (empty) sequence state for a new stream.\n *\n * @returns A {@link SequenceState} with no history\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function createSequenceState(): SequenceState {\n\treturn { lastSequenceNumber: null, seenSequences: new Set() }\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * State and result types for monotonic sequence number validation\n * per C2PA Live Streaming Specification §18.4.\n *\n * @public\n */\n\n/**\n * Immutable state snapshot for a single stream's sequence number history.\n *\n * Pass to {@link validateC2paSegment} via the `sequenceState` parameter.\n *\n * @public\n */\nexport type SequenceState = {\n\treadonly lastSequenceNumber: number | null\n\treadonly seenSequences: ReadonlySet<number>\n}\n\n/**\n * Reason codes for sequence number validation outcomes.\n *\n * @see {@link SequenceValidationResult}\n *\n * @enum\n *\n * @public\n */\nexport const SequenceValidationReason = {\n\t/** Sequence number is the next expected value */\n\tVALID: 'valid',\n\t/** Sequence number was already seen */\n\tDUPLICATE: 'duplicate',\n\t/** One or more sequence numbers were skipped */\n\tGAP_DETECTED: 'gap_detected',\n\t/** Sequence number is less than the last seen */\n\tOUT_OF_ORDER: 'out_of_order',\n\t/** Below the session key's minSequenceNumber */\n\tSEQUENCE_NUMBER_BELOW_MINIMUM: 'sequence_number_below_minimum',\n} as const\n\n/**\n * Union type of all {@link (SequenceValidationReason:variable)} values.\n *\n * @public\n */\nexport type SequenceValidationReason = ValueOf<typeof SequenceValidationReason>\n\n/**\n * Result of validating a single sequence number against the current stream state.\n *\n * Discriminated on `reason` — narrow to `'gap_detected'` to access\n * `missingFrom` / `missingTo`.\n *\n * @public\n */\nexport type SequenceValidationResult =\n\t| { readonly isValid: true; readonly reason: typeof SequenceValidationReason.VALID }\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason:\n\t\t\t\t| typeof SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM\n\t\t\t\t| typeof SequenceValidationReason.DUPLICATE\n\t\t\t\t| typeof SequenceValidationReason.OUT_OF_ORDER\n\t\t}\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason: typeof SequenceValidationReason.GAP_DETECTED\n\t\t\treadonly missingFrom: number\n\t\t\treadonly missingTo: number\n\t\t}\n","import { SequenceValidationReason } from './SequenceState.ts'\nimport type { SequenceState, SequenceValidationResult } from './SequenceState.ts'\n\nconst SEEN_SEQUENCES_WINDOW_SIZE = 32\n\nfunction pruneSeenSequences(seen: Set<number>, lastSequenceNumber: number): Set<number> {\n\tif (seen.size <= SEEN_SEQUENCES_WINDOW_SIZE) return seen\n\tconst threshold = lastSequenceNumber - SEEN_SEQUENCES_WINDOW_SIZE\n\tconst pruned = new Set<number>()\n\tfor (const seq of seen) {\n\t\tif (seq >= threshold) pruned.add(seq)\n\t}\n\treturn pruned\n}\n\n/**\n * Validates a segment's sequence number against the current stream state\n * per C2PA Live Streaming Specification §18.4.\n *\n * This function is **pure and stateless** — it returns both the validation\n * result and the next state. The caller is responsible for persisting\n * `nextState` between calls.\n *\n * Detects: `duplicate`, `out_of_order`, `gap_detected`, and\n * `sequence_number_below_minimum`.\n *\n * Internally uses a sliding window of the last 32 sequence numbers\n * to bound memory usage during long-running streams.\n *\n * @param state - Current stream state (from {@link createSequenceState} or previous `nextState`)\n * @param sequenceNumber - Sequence number from the segment's VSI map\n * @param minSequenceNumber - Minimum accepted sequence number (from the session key, default 0)\n * @returns Validation result and the updated state to persist\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function validateSequenceNumber(\n\tstate: SequenceState,\n\tsequenceNumber: number,\n\tminSequenceNumber: number,\n): { readonly result: SequenceValidationResult; readonly nextState: SequenceState } {\n\tif (sequenceNumber < minSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tif (state.seenSequences.has(sequenceNumber)) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.DUPLICATE },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tconst nextSeenSequences = new Set(state.seenSequences)\n\tnextSeenSequences.add(sequenceNumber)\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber < state.lastSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.OUT_OF_ORDER },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: state.lastSequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, state.lastSequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber > state.lastSequenceNumber + 1) {\n\t\tconst missingFrom = state.lastSequenceNumber + 1\n\t\tconst missingTo = sequenceNumber - 1\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.GAP_DETECTED, missingFrom, missingTo },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tresult: { isValid: true, reason: SequenceValidationReason.VALID },\n\t\tnextState: {\n\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t},\n\t}\n}\n","import { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { extractVsiEmsgBox } from '../emsg/extractVsiEmsgBox.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { decodeVsiMap } from '../vsi/decodeVsiMap.ts'\nimport type { SequenceState } from '../vsi/SequenceState.ts'\nimport { createSequenceState } from '../vsi/createSequenceState.ts'\nimport { validateSequenceNumber } from '../vsi/validateSequenceNumber.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { ValidatedSessionKey } from '../init/InitSegmentValidation.ts'\nimport { resolveImportAlgorithm } from '../cose/resolveImportAlgorithm.ts'\nimport { bytesToHex, isKeyExpired } from '../utils.ts'\nimport type { SegmentValidationResult } from './SegmentValidation.ts'\n\nfunction findSessionKey(sessionKeys: readonly ValidatedSessionKey[], kidHex: string | null): ValidatedSessionKey | null {\n\tif (!kidHex || sessionKeys.length === 0) return null\n\treturn sessionKeys.find(k => k.kid === kidHex) ?? null\n}\n\n/**\n * Validates a C2PA live stream segment using the VSI/EMSG method (§19.7.3).\n *\n * Extracts the EMSG box, decodes the COSE_Sign1 and VSI map, matches the\n * session key by kid, then performs all cryptographic checks: signature\n * verification, BMFF content hash, sequence number floor, and key validity.\n *\n * Returns `null` if the segment does not contain a C2PA EMSG box.\n *\n * @param segmentBytes - Raw segment bytes\n * @param sessionKeys - Available session keys from the init segment\n * @param sequenceState - Current sequence state for this stream\n * @returns Validation result and updated sequence state, or `null` if no C2PA EMSG box\n *\n * @example\n * {@includeCode ../../test/segment/validateC2paSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paSegment(\n\tsegmentBytes: Uint8Array,\n\tsessionKeys: readonly ValidatedSessionKey[],\n\tsequenceState: SequenceState = createSequenceState(),\n): Promise<{ readonly result: SegmentValidationResult; readonly nextSequenceState: SequenceState } | null> {\n\tconst emsgBox = extractVsiEmsgBox(segmentBytes)\n\tif (!emsgBox) return null\n\n\tconst coseSign1 = decodeCoseSign1(emsgBox.messageData)\n\tconst { payload } = coseSign1\n\tif (!payload) throw new Error('COSE_Sign1 payload is empty — cannot decode VSI map')\n\tconst vsi = decodeVsiMap(payload)\n\n\tconst kidHex = coseSign1.kid ? bytesToHex(coseSign1.kid) : null\n\tconst sessionKey = findSessionKey(sessionKeys, kidHex)\n\tconst bmffHashHex = bytesToHex(vsi.bmffHash.hash)\n\tconst minSequenceNumber = sessionKey?.minSequenceNumber ?? 0\n\n\tconst { result: sequenceResult, nextState: nextSequenceState } = validateSequenceNumber(\n\t\tsequenceState,\n\t\tvsi.sequenceNumber,\n\t\tminSequenceNumber,\n\t)\n\n\tconst baseFields = {\n\t\tsequenceNumber: vsi.sequenceNumber,\n\t\tmanifestId: vsi.manifestId,\n\t\tbmffHashHex,\n\t\tkidHex,\n\t\tsequenceResult,\n\t}\n\n\tif (!sessionKey) {\n\t\treturn {\n\t\t\tresult: {\n\t\t\t\t...baseFields,\n\t\t\t\tisValid: false,\n\t\t\t\terrorCodes: [LiveVideoStatusCode.SEGMENT_INVALID],\n\t\t\t},\n\t\t\tnextSequenceState,\n\t\t}\n\t}\n\n\tconst algorithm = resolveImportAlgorithm(sessionKey.jwk)\n\tconst publicKey = await crypto.subtle.importKey(\n\t\t'jwk',\n\t\tsessionKey.jwk as JsonWebKey,\n\t\talgorithm,\n\t\tfalse,\n\t\t['verify'],\n\t)\n\n\tconst [signatureValid, hashValid] = await Promise.all([\n\t\tverifyCoseSign1(coseSign1, payload, publicKey),\n\t\tvalidateBmffHash(segmentBytes, vsi.bmffHash.hash, {\n\t\t\texclusions: vsi.bmffHash.exclusions,\n\t\t\talg: vsi.bmffHash.alg,\n\t\t}),\n\t])\n\n\tconst sequenceAboveMin = vsi.sequenceNumber >= sessionKey.minSequenceNumber\n\t// §19.7.3 requires comparing against the segment's presentation time, but the\n\t// VSI map does not carry it. We compare against `now` as an approximation,\n\t// which is accurate for live streams validated in real time.\n\tconst keyExpired = isKeyExpired(sessionKey.createdAt, sessionKey.validityPeriod)\n\n\tconst codes = new Set<LiveVideoStatusCode>()\n\tif (!signatureValid || !hashValid || !sequenceAboveMin) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\tif (!sequenceResult.isValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (keyExpired) codes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tresult: { ...baseFields, isValid: errorCodes.length === 0, errorCodes },\n\t\tnextSequenceState,\n\t}\n}\n","import type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paManifest } from '../C2paManifest.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { bytesToHex, normalizeAlgorithmName } from '../utils.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { BmffHashConstraint, BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport type { ManifestBoxValidationResult, ManifestBoxValidationState } from './ManifestBoxValidation.ts'\n\nconst LIVE_VIDEO_ASSERTION_LABEL = 'c2pa.livevideo.segment'\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst MANIFEST_ID_PREFIX_PATTERN = /^(xmp:iid:|urn:uuid:)/i\nconst CONTINUITY_METHOD_MANIFEST_ID = 'c2pa.manifestId'\nconst SUPPORTED_CONTINUITY_METHODS = new Set([CONTINUITY_METHOD_MANIFEST_ID])\n\nfunction normalizeManifestId(id: string | null): string | null {\n\tif (!id) return null\n\treturn id.replace(MANIFEST_ID_PREFIX_PATTERN, '').toLowerCase()\n}\n\nfunction extractAssertionData(data: unknown): Record<string, unknown> | null {\n\tif (data !== null && typeof data === 'object' && !Array.isArray(data)) {\n\t\treturn data as Record<string, unknown>\n\t}\n\treturn null\n}\n\nfunction toUint8Array(value: unknown): Uint8Array | null {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\treturn null\n}\n\n// --- Live video assertion parsing ---\n\ntype LiveVideoFields = {\n\tsequenceNumber: number | null\n\tpreviousManifestId: string | null\n\tstreamId: string | null\n\tcontinuityMethod: string | null\n}\n\nfunction parseLiveVideoAssertion(assertions: readonly C2paAssertion[]): LiveVideoFields | null {\n\tconst assertion = assertions.find(a => a.label === LIVE_VIDEO_ASSERTION_LABEL)\n\tif (!assertion) return null\n\n\tconst data = extractAssertionData(assertion.data)\n\tconst rawSeq = data?.['sequenceNumber']\n\tconst rawPrev = data?.['previousManifestId']\n\tconst rawStreamId = data?.['streamId']\n\tconst rawContinuity = data?.['continuityMethod']\n\n\treturn {\n\t\tsequenceNumber: typeof rawSeq === 'number' ? rawSeq : null,\n\t\tpreviousManifestId: typeof rawPrev === 'string' ? rawPrev : null,\n\t\tstreamId: typeof rawStreamId === 'string' ? rawStreamId : null,\n\t\tcontinuityMethod: typeof rawContinuity === 'string' ? rawContinuity : null,\n\t}\n}\n\n// --- BMFF hash assertion parsing ---\n\ntype BmffHashFields = {\n\thashBytes: Uint8Array | null\n\thashHex: string | null\n\texclusions: readonly BmffHashExclusion[]\n\talg: string | null\n}\n\nconst EMPTY_BMFF_HASH: BmffHashFields = { hashBytes: null, hashHex: null, exclusions: [], alg: null }\n\nfunction parseConstraints(rawConstraints: unknown): BmffHashConstraint[] {\n\tif (!Array.isArray(rawConstraints)) return []\n\n\tconst constraints: BmffHashConstraint[] = []\n\tfor (const c of rawConstraints) {\n\t\tif (!c || typeof c !== 'object') continue\n\t\tconst record = c as Record<string, unknown>\n\t\tif (typeof record['offset'] !== 'number') continue\n\t\tconst value = toUint8Array(record['value'])\n\t\tif (value) constraints.push({ offset: record['offset'], value })\n\t}\n\treturn constraints\n}\n\nfunction parseExclusions(rawExclusions: unknown): BmffHashExclusion[] {\n\tif (!Array.isArray(rawExclusions)) return []\n\n\tconst exclusions: BmffHashExclusion[] = []\n\tfor (const exc of rawExclusions) {\n\t\tif (!exc || typeof exc !== 'object') continue\n\t\tconst record = exc as Record<string, unknown>\n\t\tif (typeof record['xpath'] !== 'string') continue\n\n\t\tconst constraints = parseConstraints(record['data'])\n\t\texclusions.push(constraints.length > 0 ? { xpath: record['xpath'], data: constraints } : { xpath: record['xpath'] })\n\t}\n\treturn exclusions\n}\n\nfunction parseBmffHashAssertion(assertions: readonly C2paAssertion[]): BmffHashFields {\n\tconst assertion = assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL)\n\tif (!assertion) return EMPTY_BMFF_HASH\n\n\tconst data = extractAssertionData(assertion.data)\n\tif (!data) return EMPTY_BMFF_HASH\n\n\tconst hashBytes = toUint8Array(data['hash'] ?? data['value'])\n\tconst hashHex = hashBytes ? bytesToHex(hashBytes) : null\n\tconst exclusions = parseExclusions(data['exclusions'])\n\tconst alg = typeof data['alg'] === 'string' ? normalizeAlgorithmName(data['alg']) : null\n\treturn { hashBytes, hashHex, exclusions, alg }\n}\n\n// --- Manifest parsing ---\n\ntype ParsedManifest = {\n\tmanifest: C2paManifest | null\n\tissuer: string | null\n\tliveVideo: LiveVideoFields | null\n\tbmff: BmffHashFields\n}\n\nfunction parseManifest(bytes: Uint8Array): ParsedManifest {\n\ttry {\n\t\tconst { manifest } = readC2paManifest(bytes)\n\t\tif (!manifest) return { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH }\n\n\t\treturn {\n\t\t\tmanifest,\n\t\t\tissuer: manifest.signatureInfo?.issuer ?? null,\n\t\t\tliveVideo: parseLiveVideoAssertion(manifest.assertions),\n\t\t\tbmff: parseBmffHashAssertion(manifest.assertions),\n\t\t}\n\t} catch {\n\t\treturn { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH }\n\t}\n}\n\n// --- Validation ---\n\nfunction collectErrorCodes(\n\thasManifest: boolean,\n\thasLiveVideo: boolean,\n\tstreamIdValid: boolean,\n\tsequenceNumberValid: boolean,\n\tbmffHashMatches: boolean,\n\tcontinuityMethod: string | null,\n\tpreviousManifestId: string | null,\n\tlastManifestId: string | null,\n): readonly LiveVideoStatusCode[] {\n\tconst codes = new Set<LiveVideoStatusCode>()\n\n\tif (!hasManifest) codes.add(LiveVideoStatusCode.MANIFEST_INVALID)\n\tif (!hasLiveVideo) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!streamIdValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!sequenceNumberValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!bmffHashMatches) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\n\tif (!continuityMethod) {\n\t\tcodes.add(LiveVideoStatusCode.CONTINUITY_METHOD_INVALID)\n\t} else if (!SUPPORTED_CONTINUITY_METHODS.has(continuityMethod)) {\n\t\tcodes.add(LiveVideoStatusCode.CONTINUITY_METHOD_INVALID)\n\t} else if (continuityMethod === CONTINUITY_METHOD_MANIFEST_ID) {\n\t\tif (!previousManifestId) {\n\t\t\tcodes.add(LiveVideoStatusCode.CONTINUITY_METHOD_INVALID)\n\t\t} else if (lastManifestId && normalizeManifestId(previousManifestId) !== normalizeManifestId(lastManifestId)) {\n\t\t\tcodes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\t\t}\n\t}\n\n\treturn [...codes]\n}\n\n/**\n * Validates a C2PA manifest-box live stream segment.\n *\n * Parses the C2PA manifest embedded in the segment and validates per §19.7.1 and §19.7.2.\n * Recomputes the `c2pa.hash.bmff.v3` content hash from the raw segment bytes and compares\n * it against the expected hash in the manifest assertion. Checks live-video assertions\n * (sequenceNumber, streamId, continuityMethod) and manifest-ID chain continuity.\n *\n * This function is **pure** — it does not access any external state. The\n * caller is responsible for persisting `nextManifestId` and `nextState`\n * between calls.\n *\n * @param bytes - Raw segment bytes\n * @param lastManifestId - Manifest ID from the previous segment, or null for the first segment\n * @param state - Optional state from the previous segment for streamId/sequenceNumber checks\n * @returns Validation result, the manifest ID, and state to persist for the next call\n *\n * @example\n * {@includeCode ../../test/manifestbox/validateC2paManifestBoxSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paManifestBoxSegment(\n\tbytes: Uint8Array,\n\tlastManifestId: string | null,\n\tstate?: ManifestBoxValidationState,\n): Promise<{\n\treadonly result: ManifestBoxValidationResult\n\treadonly nextManifestId: string | null\n\treadonly nextState: ManifestBoxValidationState\n}> {\n\tconst { manifest, issuer, liveVideo, bmff } = parseManifest(bytes)\n\n\tconst sequenceNumber = liveVideo?.sequenceNumber ?? null\n\tconst previousManifestId = liveVideo?.previousManifestId ?? null\n\tconst streamId = liveVideo?.streamId ?? null\n\tconst continuityMethod = liveVideo?.continuityMethod ?? null\n\n\tconst streamIdValid = state?.lastStreamId == null || streamId === state.lastStreamId\n\tconst sequenceNumberValid =\n\t\tstate?.lastSequenceNumber == null ||\n\t\t(sequenceNumber !== null && sequenceNumber > state.lastSequenceNumber)\n\n\tlet bmffHashMatches = true\n\tif (bmff.hashBytes !== null) {\n\t\tbmffHashMatches = await validateBmffHash(bytes, bmff.hashBytes, {\n\t\t\texclusions: bmff.exclusions,\n\t\t\talg: bmff.alg ?? undefined,\n\t\t})\n\t}\n\n\tconst liveVideoCodes = collectErrorCodes(\n\t\tmanifest !== null, liveVideo !== null,\n\t\tstreamIdValid, sequenceNumberValid, bmffHashMatches,\n\t\tcontinuityMethod, previousManifestId, lastManifestId,\n\t)\n\n\tconst errorCodes: (LiveVideoStatusCode | C2paStatusCode)[] = [...liveVideoCodes]\n\n\tconst currentManifestId = manifest?.instanceId ?? null\n\n\treturn {\n\t\tresult: {\n\t\t\tmanifest: manifest ?? null,\n\t\t\tissuer,\n\t\t\tsequenceNumber,\n\t\t\tpreviousManifestId,\n\t\t\tstreamId,\n\t\t\tcontinuityMethod,\n\t\t\tbmffHashHex: bmff.hashHex,\n\t\t\tisValid: errorCodes.length === 0,\n\t\t\terrorCodes,\n\t\t},\n\t\tnextManifestId: currentManifestId ?? lastManifestId,\n\t\tnextState: {\n\t\t\tlastStreamId: streamId ?? state?.lastStreamId,\n\t\t\tlastSequenceNumber: sequenceNumber ?? state?.lastSequenceNumber,\n\t\t},\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["coseGet","toUint8Array","protectedHeader: CoseHeader","TEXT_DECODER","HEX_TABLE: readonly string[]","C2PA_MANIFEST_UUID: readonly number[]","JUMBF_UUID: readonly number[]","TEXT_DECODER","notBefore: string | null","assertions: InternalAssertionData[]","data: unknown","refs: ClaimAssertionRef[]","claimData: Record<string, unknown> | null","claimCborBytes: Uint8Array | null","internalAssertions: InternalAssertionData[]","signatureBytes: Uint8Array | null","assertions: C2paAssertion[]","codes: C2paStatusCode[]","codes: C2paStatusCode[]","CURVE_COMPONENT_BYTES: Record<string, number>","RSA_PSS_SALT_LENGTH: Record<string, number>","codes: C2paStatusCode[]","Code","EC_CURVE_NAMES: Record<number, string>","OKP_CURVE_NAMES: Record<number, string>","BMFF_HASH_ASSERTION_LABEL","EMPTY_BMFF_HASH: BmffHashFields","constraints: BmffHashConstraint[]","exclusions: BmffHashExclusion[]","integrityCodes: readonly C2paStatusCode[]","errorCodes: (LiveVideoStatusCode | C2paStatusCode)[]"],"sources":["../src/LiveVideoStatusCode.ts","../src/cose/decodeCoseSign1.ts","../src/jumbf/parseJumbfBoxes.ts","../src/jumbf/parseJumbfLabel.ts","../src/utils.ts","../src/x509/asn1.ts","../src/x509/extractCertificateInfo.ts","../src/readC2paManifest.ts","../src/extractManifestCertificate.ts","../src/bmff/shouldExcludeBox.ts","../src/bmff/computeBmffHash.ts","../src/bmff/validateBmffHash.ts","../src/C2paStatusCode.ts","../src/claim/validateActionIngredients.ts","../src/claim/validateAssertionHashes.ts","../src/cose/constants.ts","../src/cose/resolveAlgorithmFromCoseAlg.ts","../src/cose/buildSigStructure.ts","../src/cose/verifyCoseSign1.ts","../src/x509/extractCertificateSpki.ts","../src/x509/normalizeRsaPssSpki.ts","../src/claim/verifyClaimSignature.ts","../src/claim/validateManifestIntegrity.ts","../src/cose/convertCoseKeyToJwk.ts","../src/cose/resolveImportAlgorithm.ts","../src/cose/verifySignerBinding.ts","../src/init/validateC2paInitSegment.ts","../src/emsg/extractVsiEmsgBox.ts","../src/vsi/decodeVsiMap.ts","../src/vsi/createSequenceState.ts","../src/vsi/SequenceState.ts","../src/vsi/validateSequenceNumber.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts"],"sourcesContent":["import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA failure status codes for live video validation,\n * as defined in the C2PA specification section 19.7.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_live_video_validation_process | C2PA Spec §19.7}\n *\n * @enum\n *\n * @public\n */\nexport const LiveVideoStatusCode = {\n\t/** Init segment contains an `mdat` box (§19.7.1) */\n\tINIT_INVALID: 'livevideo.init.invalid',\n\t/** C2PA Manifest Box failed standard validation (§19.7.1) */\n\tMANIFEST_INVALID: 'livevideo.manifest.invalid',\n\t/** Segment structure invalid: missing Manifest Box/emsg, signature/hash/key failure (§19.7) */\n\tSEGMENT_INVALID: 'livevideo.segment.invalid',\n\t/** Live video assertion field invalid: sequenceNumber or streamId mismatch (§19.7.2) */\n\tASSERTION_INVALID: 'livevideo.assertion.invalid',\n\t/** continuityMethod absent, unsupported, or companion fields incorrect (§19.7.2) */\n\tCONTINUITY_METHOD_INVALID: 'livevideo.continuityMethod.invalid',\n\t/** Session key invalid: signerBinding failed or required fields absent (§19.7.3) */\n\tSESSIONKEY_INVALID: 'livevideo.sessionkey.invalid',\n} as const\n\n/**\n * Union type of all {@link (LiveVideoStatusCode:variable)} values.\n *\n * @public\n */\nexport type LiveVideoStatusCode = ValueOf<typeof LiveVideoStatusCode>\n","import { decode } from 'cbor-x/decode'\nimport type { CoseSign1 } from './CoseSign1.ts'\n\nconst COSE_SIGN1_TAG_SINGLE_BYTE = 0xd2\nconst COSE_SIGN1_TAG_TWO_BYTE_FIRST = 0xd8\nconst COSE_SIGN1_TAG_TWO_BYTE_SECOND = 0x12\nconst COSE_SIGN1_ARRAY_LENGTH = 4\nconst COSE_KEY_KID = 4\nconst COSE_KEY_ALG = 1\n\ntype CoseHeader = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(header: CoseHeader, key: number): unknown {\n\tif (header instanceof Map) return header.get(key)\n\treturn (header as Record<number | string, unknown>)[key]\n}\n\nfunction stripCoseTag(bytes: Uint8Array): Uint8Array {\n\tif (bytes[0] === COSE_SIGN1_TAG_SINGLE_BYTE) return bytes.subarray(1)\n\tif (bytes[0] === COSE_SIGN1_TAG_TWO_BYTE_FIRST && bytes[1] === COSE_SIGN1_TAG_TWO_BYTE_SECOND) return bytes.subarray(2)\n\treturn bytes\n}\n\nfunction toUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tthrow new Error(`Expected Uint8Array or number[], got ${typeof value}`)\n}\n\n/**\n * Decodes a `COSE_Sign1` structure from raw bytes (RFC 9052).\n *\n * Handles CBOR tag 18 in both single-byte (0xD2) and two-byte (0xD8 0x12) form.\n *\n * @param coseBytes - Raw COSE_Sign1 bytes, optionally prefixed with CBOR tag 18\n * @returns The decoded COSE_Sign1 structure\n * @throws If the bytes do not represent a valid COSE_Sign1 structure\n *\n * @example\n * {@includeCode ../../test/cose/decodeCoseSign1.test.ts#example}\n *\n * @internal\n */\nexport function decodeCoseSign1(coseBytes: Uint8Array): CoseSign1 {\n\ttry {\n\t\tconst stripped = stripCoseTag(coseBytes)\n\t\tconst coseArray = decode(stripped) as unknown\n\n\t\tif (!Array.isArray(coseArray) || coseArray.length !== COSE_SIGN1_ARRAY_LENGTH) {\n\t\t\tthrow new Error('Invalid COSE_Sign1 structure: expected array with 4 elements')\n\t\t}\n\n\t\tconst [protectedRaw, unprotectedRaw, payloadRaw, signatureRaw] = coseArray as unknown[]\n\n\t\tconst protectedBytes = toUint8Array(protectedRaw)\n\t\tlet protectedHeader: CoseHeader = {}\n\t\tif (protectedBytes.length > 0) {\n\t\t\tprotectedHeader = decode(protectedBytes) as CoseHeader\n\t\t}\n\n\t\tconst unprotectedHeader = (unprotectedRaw ?? {}) as CoseHeader\n\t\tconst kidRaw = coseGet(protectedHeader, COSE_KEY_KID) ?? coseGet(unprotectedHeader, COSE_KEY_KID) ?? null\n\t\tconst kid = kidRaw != null ? toUint8Array(kidRaw) : null\n\t\tconst alg = (coseGet(protectedHeader, COSE_KEY_ALG) ?? coseGet(unprotectedHeader, COSE_KEY_ALG) ?? null) as number | null\n\n\t\treturn {\n\t\t\tprotectedBytes,\n\t\t\tprotectedHeader: protectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tunprotectedHeader: unprotectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tpayload: payloadRaw == null ? null : toUint8Array(payloadRaw),\n\t\t\tsignature: toUint8Array(signatureRaw),\n\t\t\tkid,\n\t\t\talg,\n\t\t}\n\t}\n\tcatch (error) {\n\t\tthrow new Error(`Failed to decode COSE_Sign1: ${(error as Error).message}`)\n\t}\n}\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { JumbfBox } from './JumbfBox.ts'\n\n/**\n * Parses JUMBF boxes (ISO 19566-5) from raw bytes.\n *\n * JUMBF boxes share the same 4-byte size + 4-byte type structure as ISO BMFF boxes,\n * so they can be parsed with the same reader.\n *\n * @param bytes - Raw bytes containing JUMBF box content\n * @returns Array of parsed JUMBF boxes with their payloads\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfBoxes.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfBoxes(bytes: Uint8Array): JumbfBox[] {\n\treturn readIsoBoxes(bytes).map(box => ({\n\t\ttype: box.type,\n\t\tdata: box.view.readData(box.view.bytesRemaining),\n\t}))\n}\n","const TEXT_DECODER = new TextDecoder()\nconst JUMD_UUID_SIZE = 16\nconst JUMD_TOGGLES_OFFSET = 16\nconst JUMD_LABEL_START = 17\nconst LABEL_FLAG_MASK = 0x03\nconst LABEL_FLAG_EXPECTED = 0x03\n\n/**\n * Extracts the label from a JUMBF Description Box (`jumd`) data payload.\n *\n * The `jumd` format is: 16-byte UUID + 1-byte toggles + null-terminated label string.\n * A label is only present when bits 0 and 1 of the toggles byte are both set.\n *\n * @param jumdData - Raw bytes of the `jumd` box data (payload after the box header)\n * @returns The label string, or `null` if no label is present\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfLabel.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfLabel(jumdData: Uint8Array): string | null {\n\tif (jumdData.length < JUMD_UUID_SIZE + 1) return null\n\n\tconst toggles = jumdData[JUMD_TOGGLES_OFFSET]\n\tif ((toggles & LABEL_FLAG_MASK) !== LABEL_FLAG_EXPECTED) return null\n\n\tlet end = JUMD_LABEL_START\n\twhile (end < jumdData.length && jumdData[end] !== 0) end++\n\tif (end >= jumdData.length) return null\n\n\treturn TEXT_DECODER.decode(jumdData.subarray(JUMD_LABEL_START, end))\n}\n","import type { IsoBoxReadView, ParsedIsoBox } from '@svta/cml-iso-bmff'\n\nconst MILLISECONDS_PER_SECOND = 1000\nconst SHA_ALGORITHM_PATTERN = /^sha(\\d+)$/i\n\n/**\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * Defaults to `'SHA-256'` when no algorithm is provided.\n *\n * @internal\n */\nexport function normalizeAlgorithmName(rawAlg?: string): string {\n\treturn (rawAlg ?? 'SHA-256').replace(SHA_ALGORITHM_PATTERN, 'SHA-$1')\n}\n\nconst HEX_TABLE: readonly string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\n/**\n * Converts a Uint8Array to a lowercase hex string.\n *\n * @internal\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n\tlet hex = ''\n\tfor (const byte of bytes) hex += HEX_TABLE[byte]\n\treturn hex\n}\n\n/**\n * Checks whether a session key has expired based on its creation time\n * and validity period.\n *\n * @param createdAt - ISO 8601 date string when the key was created\n * @param validityPeriodSeconds - Validity duration in seconds\n * @param now - Current time (defaults to `new Date()`, injectable for testing)\n * @returns `true` if the key has expired\n *\n * @internal\n */\nexport function isKeyExpired(createdAt: string, validityPeriodSeconds: number, now: Date = new Date()): boolean {\n\tconst createdAtMs = new Date(createdAt).getTime()\n\tif (Number.isNaN(createdAtMs)) return true\n\tconst validityEnd = new Date(createdAtMs + validityPeriodSeconds * MILLISECONDS_PER_SECOND)\n\treturn now > validityEnd\n}\n\n/**\n * Constant-time comparison of two hash byte arrays.\n *\n * @internal\n */\nexport function hashesEqual(a: Uint8Array, b: Uint8Array): boolean {\n\tif (a.length !== b.length) return false\n\tlet diff = 0\n\tfor (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]\n\treturn diff === 0\n}\n\n// C2PA manifest store UUID per C2PA specification\nconst C2PA_MANIFEST_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1a, 0x96, 0x4f, 0x32,\n\t0xa0, 0xf6, 0xf3, 0xec, 0xf9, 0x6c, 0x10, 0xea,\n]\n\n// JUMBF UUID per ISO 19566-5 (used by c2pa-rs and other JUMBF-compliant tools)\nconst JUMBF_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1b, 0x0e, 0x48, 0x3c,\n\t0x92, 0x97, 0x58, 0x28, 0x87, 0x7e, 0xc4, 0x81,\n]\n\nfunction matchesUuid(usertype: readonly number[], expected: readonly number[]): boolean {\n\treturn usertype.length === expected.length && expected.every((b, i) => b === usertype[i])\n}\n\nfunction isC2paUuid(usertype: readonly number[]): boolean {\n\treturn matchesUuid(usertype, C2PA_MANIFEST_UUID) || matchesUuid(usertype, JUMBF_UUID)\n}\n\n/**\n * A parsed ISO BMFF box with a UUID type.\n *\n * `ParsedIsoBox` does not include 'uuid' in its type union because UUID boxes\n * are not part of the standard `IsoBoxMap`. This type represents the structural\n * shape needed to work with UUID boxes at runtime.\n *\n * @internal\n */\nexport type UuidParsedBox = {\n\ttype: string\n\tusertype?: number[]\n\tview: IsoBoxReadView\n\tsize: number\n}\n\n/**\n * Finds the C2PA UUID box in a list of parsed ISO BMFF boxes.\n *\n * Matches against both the C2PA manifest store UUID and the JUMBF UUID\n * (ISO 19566-5), as different tools use different UUIDs.\n *\n * @internal\n */\nexport function findC2paUuidBox(boxes: ParsedIsoBox[]): UuidParsedBox | undefined {\n\treturn (boxes as UuidParsedBox[]).find(\n\t\tbox => box.type === 'uuid' && isC2paUuid(box.usertype ?? []),\n\t)\n}\n\nconst FULLBOX_HEADER_SIZE = 4\nconst AUX_UUID_OFFSET_SIZE = 8\n\n/**\n * Strips the JUMBF UUID box prefix (fullbox header, purpose string, aux offset)\n * to return only the JUMBF manifest data.\n *\n * Structure per ISO 19566-5 / C2PA BMFF storage:\n * version(1) + flags(3) + purpose(null-terminated) + aux_offset(8) + JUMBF data\n *\n * Returns `null` if the payload does not contain a valid JUMBF UUID prefix.\n *\n * @internal\n */\nexport function stripJumbfUuidPrefix(payload: Uint8Array): Uint8Array | null {\n\tif (payload.length < FULLBOX_HEADER_SIZE) return null\n\n\tlet offset = FULLBOX_HEADER_SIZE\n\t// Skip null-terminated purpose string (e.g. \"manifest\\0\")\n\twhile (offset < payload.length && payload[offset] !== 0) offset++\n\tif (offset >= payload.length) return null\n\toffset++ // skip the null terminator\n\toffset += AUX_UUID_OFFSET_SIZE\n\tif (offset > payload.length) return null\n\treturn payload.subarray(offset)\n}\n","/**\n * Minimal ASN.1 DER parsing helpers for X.509 certificate navigation.\n *\n * @internal\n */\n\nexport const ASN1_TAG_INTEGER = 0x02\nexport const ASN1_TAG_OBJECT_IDENTIFIER = 0x06\nexport const ASN1_TAG_SEQUENCE = 0x30\nexport const ASN1_TAG_SET = 0x31\nexport const ASN1_TAG_UTC_TIME = 0x17\nexport const ASN1_TAG_GENERALIZED_TIME = 0x18\nexport const ASN1_TAG_CONTEXT_0 = 0xa0\nconst ASN1_LONG_FORM_FLAG = 0x80\nconst ASN1_LONG_FORM_MASK = 0x7f\n\nexport type Asn1Element = {\n\treadonly tag: number\n\treadonly value: Uint8Array\n\treadonly totalSize: number\n}\n\nexport function readLength(bytes: Uint8Array, offset: number): { length: number; bytesRead: number } {\n\tif (offset >= bytes.length) return { length: 0, bytesRead: 0 }\n\tconst first = bytes[offset] ?? 0\n\tif (first < ASN1_LONG_FORM_FLAG) return { length: first, bytesRead: 1 }\n\tconst count = first & ASN1_LONG_FORM_MASK\n\tlet length = 0\n\tfor (let i = 0; i < count; i++) {\n\t\tlength = (length << 8) | (bytes[offset + 1 + i] ?? 0)\n\t}\n\treturn { length, bytesRead: 1 + count }\n}\n\nexport function readElement(bytes: Uint8Array, offset: number): Asn1Element | null {\n\tif (offset + 2 > bytes.length) return null\n\tconst tag = bytes[offset] ?? 0\n\tconst { length, bytesRead } = readLength(bytes, offset + 1)\n\tconst headerSize = 1 + bytesRead\n\tconst valueEnd = offset + headerSize + length\n\tif (valueEnd > bytes.length) return null\n\treturn {\n\t\ttag,\n\t\tvalue: bytes.subarray(offset + headerSize, valueEnd),\n\t\ttotalSize: headerSize + length,\n\t}\n}\n\n/**\n * Reads an ASN.1 element and returns its full DER encoding (tag + length + value).\n *\n * @internal\n */\nexport function readElementRaw(bytes: Uint8Array, offset: number): Uint8Array | null {\n\tconst el = readElement(bytes, offset)\n\tif (!el) return null\n\treturn bytes.subarray(offset, offset + el.totalSize)\n}\n","const TEXT_DECODER = new TextDecoder()\n\nimport type { CertificateInfo } from './CertificateInfo.ts'\nimport {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_GENERALIZED_TIME,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_OBJECT_IDENTIFIER,\n\tASN1_TAG_SEQUENCE,\n\tASN1_TAG_SET,\n\tASN1_TAG_UTC_TIME,\n\treadElement,\n\ttype Asn1Element,\n} from './asn1.ts'\n\nconst OID_COMMON_NAME = new Uint8Array([0x55, 0x04, 0x03])\nconst OID_ORG_NAME = new Uint8Array([0x55, 0x04, 0x0a])\n\nfunction matchesOID(value: Uint8Array, oid: Uint8Array): boolean {\n\tif (value.length < oid.length) return false\n\tfor (let i = 0; i < oid.length; i++) {\n\t\tif (value[i] !== oid[i]) return false\n\t}\n\treturn true\n}\n\nfunction parseTime(element: Asn1Element): string | null {\n\tconst text = TEXT_DECODER.decode(element.value)\n\tif (element.tag === ASN1_TAG_UTC_TIME) {\n\t\tconst yy = parseInt(text.substring(0, 2), 10)\n\t\tconst year = yy >= 50 ? 1900 + yy : 2000 + yy\n\t\treturn `${year}-${text.substring(2, 4)}-${text.substring(4, 6)}T${text.substring(6, 8)}:${text.substring(8, 10)}:${text.substring(10, 12)}Z`\n\t}\n\tif (element.tag === ASN1_TAG_GENERALIZED_TIME) {\n\t\treturn `${text.substring(0, 4)}-${text.substring(4, 6)}-${text.substring(6, 8)}T${text.substring(8, 10)}:${text.substring(10, 12)}:${text.substring(12, 14)}Z`\n\t}\n\treturn null\n}\n\nfunction findOidValueInSequence(seqValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tconst oidEl = readElement(seqValue, 0)\n\tif (!oidEl || oidEl.tag !== ASN1_TAG_OBJECT_IDENTIFIER) return null\n\tif (!matchesOID(oidEl.value, targetOID)) return null\n\n\tconst valEl = readElement(seqValue, oidEl.totalSize)\n\treturn valEl ? TEXT_DECODER.decode(valEl.value) : null\n}\n\nfunction findRDNValue(issuerValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tlet offset = 0\n\twhile (offset < issuerValue.length) {\n\t\tconst setEl = readElement(issuerValue, offset)\n\t\tif (!setEl || setEl.tag !== ASN1_TAG_SET) break\n\n\t\tlet setOffset = 0\n\t\twhile (setOffset < setEl.value.length) {\n\t\t\tconst seqEl = readElement(setEl.value, setOffset)\n\t\t\tif (!seqEl || seqEl.tag !== ASN1_TAG_SEQUENCE) break\n\n\t\t\tconst found = findOidValueInSequence(seqEl.value, targetOID)\n\t\t\tif (found) return found\n\n\t\t\tsetOffset += seqEl.totalSize\n\t\t}\n\t\toffset += setEl.totalSize\n\t}\n\treturn null\n}\n\n/**\n * Extracts the issuer name and `notBefore` date from a DER-encoded X.509 certificate.\n *\n * Uses a minimal ASN.1 parser that handles the subset of DER structures found in\n * typical C2PA signing certificates. Extracts the issuer Common Name (OID 2.5.4.3)\n * or Organization Name (OID 2.5.4.10) as a fallback, and the `notBefore` validity date.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Certificate information, or `null` if parsing fails\n *\n * @example\n * {@includeCode ../../test/x509/extractCertificateInfo.test.ts#example}\n *\n * @internal\n */\nexport function extractCertificateInfo(certDER: Uint8Array): CertificateInfo | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// Optional version field (context tag [0])\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// Serial number\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// Signature algorithm\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// Issuer\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\tconst issuer =\n\t\t\tfindRDNValue(el.value, OID_COMMON_NAME) ??\n\t\t\tfindRDNValue(el.value, OID_ORG_NAME) ??\n\t\t\t'Unknown Issuer'\n\t\toffset += el.totalSize\n\n\t\t// Validity\n\t\tel = readElement(tbs.value, offset)\n\t\tlet notBefore: string | null = null\n\t\tif (el && el.tag === ASN1_TAG_SEQUENCE) {\n\t\t\tconst timeEl = readElement(el.value, 0)\n\t\t\tif (timeEl) notBefore = parseTime(timeEl)\n\t\t}\n\n\t\treturn { issuer, notBefore }\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","const TEXT_DECODER = new TextDecoder()\n\nimport { readIsoBoxes, type ParsedIsoBox } from '@svta/cml-iso-bmff'\nimport { decode } from 'cbor-x/decode'\nimport type { C2paAssertion } from './C2paAssertion.ts'\nimport type { C2paManifest } from './C2paManifest.ts'\nimport type { ClaimAssertionRef } from './claim/ClaimAssertionRef.ts'\nimport type { InternalAssertionData, InternalManifestData } from './claim/InternalManifestData.ts'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport { extractCertificateInfo } from './x509/extractCertificateInfo.ts'\n\n\nconst MAX_JUMBF_NESTING_DEPTH = 20\nconst X5CHAIN_HEADER_LABEL = 33\n\nfunction resolveManifestBoxes(jumbfBoxes: JumbfBox[], depth = 0): JumbfBox[] {\n\tif (depth >= MAX_JUMBF_NESTING_DEPTH) return jumbfBoxes\n\n\t// Skip jumd description boxes — they contain labels, not manifest content\n\tconst contentBoxes = jumbfBoxes.filter(b => b.type !== 'jumd')\n\n\t// Single jumb wrapping — unwrap one level and recurse\n\t// This handles: store jumb → manifest jumb → claim/assertions/signature\n\tconst firstBox = contentBoxes[0]\n\tif (contentBoxes.length === 1 && firstBox?.type === 'jumb') {\n\t\treturn resolveManifestBoxes(parseJumbfBoxes(firstBox.data), depth + 1)\n\t}\n\n\treturn jumbfBoxes\n}\n\nfunction extractManifestLabel(jumbfBoxes: JumbfBox[]): string | null {\n\t// Navigate: store jumb → manifest jumb → jumd label\n\tfor (const box of jumbfBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tfor (const child of inner) {\n\t\t\tif (child.type !== 'jumb') continue\n\t\t\tconst childInner = parseJumbfBoxes(child.data)\n\t\t\tconst jumd = childInner.find(b => b.type === 'jumd')\n\t\t\tif (jumd) {\n\t\t\t\tconst label = parseJumbfLabel(jumd.data)\n\t\t\t\tif (label) return label\n\t\t\t}\n\t\t}\n\t}\n\treturn null\n}\n\nfunction parseAssertionsInternal(assertionStoreBoxes: JumbfBox[]): InternalAssertionData[] {\n\tconst assertions: InternalAssertionData[] = []\n\n\tfor (const box of assertionStoreBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tconst contentBox = inner.find(\n\t\t\tb => b.type === 'cbor' || b.type === 'json' || b.type === 'jumc' || b.type === 'jp2c' || b.type === 'bidb',\n\t\t)\n\n\t\tlet data: unknown = null\n\t\tif (contentBox) {\n\t\t\tif (contentBox.type === 'cbor') {\n\t\t\t\ttry { data = decode(contentBox.data) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse if (contentBox.type === 'json') {\n\t\t\t\ttry { data = JSON.parse(TEXT_DECODER.decode(contentBox.data)) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdata = contentBox.data\n\t\t\t}\n\t\t}\n\n\t\tassertions.push({ label, data, rawBoxPayload: box.data })\n\t}\n\n\treturn assertions\n}\n\nfunction parseSignatureInfo(signatureBytes: Uint8Array | null): { issuer: string | null; certNotBefore: string | null } {\n\tif (!signatureBytes) return { issuer: null, certNotBefore: null }\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_HEADER_LABEL] ?? cose.unprotectedHeader[X5CHAIN_HEADER_LABEL]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return { issuer: null, certNotBefore: null }\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\tif (!(certDER instanceof Uint8Array)) return { issuer: null, certNotBefore: null }\n\n\t\tconst certInfo = extractCertificateInfo(certDER)\n\t\treturn { issuer: certInfo?.issuer ?? null, certNotBefore: certInfo?.notBefore ?? null }\n\t} catch {\n\t\t// signature parsing failed — continue without signature info\n\t\treturn { issuer: null, certNotBefore: null }\n\t}\n}\n\nfunction extractClaimAssertionRefs(claimData: Record<string, unknown>): ClaimAssertionRef[] {\n\tconst created = claimData['created_assertions'] as unknown[] | undefined\n\tconst gathered = claimData['gathered_assertions'] as unknown[] | undefined\n\tconst v1 = claimData['assertions'] as unknown[] | undefined\n\n\tconst sources = [...(created ?? []), ...(gathered ?? []), ...(v1 ?? [])]\n\tconst refs: ClaimAssertionRef[] = []\n\n\tfor (const entry of sources) {\n\t\tif (!entry || typeof entry !== 'object') continue\n\t\tconst e = entry as Record<string, unknown>\n\t\tconst url = e['url'] as string | undefined\n\t\tconst hash = e['hash']\n\t\tif (!url || !hash) continue\n\n\t\trefs.push({\n\t\t\turl,\n\t\t\thash: hash instanceof Uint8Array ? hash : new Uint8Array(hash as number[]),\n\t\t\talg: (e['alg'] as string | undefined) ?? null,\n\t\t})\n\t}\n\n\treturn refs\n}\n\n/**\n * Reads a C2PA manifest from raw BMFF bytes.\n *\n * Locates the C2PA UUID box (`d8fec3d6-1a96-4f32-a0f6-f3ecf96c10ea`), navigates\n * the JUMBF manifest store structure (ISO 19566-5), and returns the parsed active\n * manifest with its claims, assertions, and signature information.\n *\n * This function performs structural parsing only. It does not verify the\n * cryptographic signature of the claim.\n *\n * @param bytes - Raw BMFF bytes (e.g. an MP4 init segment or media segment)\n * @param preParsedBoxes - Optional pre-parsed ISO boxes to avoid redundant parsing\n * @returns The parsed manifest data including claim, assertions, and signature bytes\n * @throws If no C2PA UUID box is found, or the JUMBF structure is invalid\n *\n * @example\n * {@includeCode ../test/readC2paManifest.test.ts#example}\n *\n * @internal\n */\nexport function readC2paManifest(bytes: Uint8Array, preParsedBoxes?: ParsedIsoBox[]): InternalManifestData {\n\tconst boxes = preParsedBoxes ?? readIsoBoxes(bytes)\n\tconst uuidBox = findC2paUuidBox(boxes)\n\n\tif (!uuidBox) {\n\t\tthrow new Error('No C2PA UUID box found in the provided bytes')\n\t}\n\n\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\tif (!jumbfPayload) {\n\t\tthrow new Error('Invalid JUMBF UUID prefix in C2PA box')\n\t}\n\tconst jumbfBoxes = parseJumbfBoxes(jumbfPayload)\n\n\tif (jumbfBoxes.length === 0) {\n\t\tthrow new Error('No JUMBF boxes found in C2PA UUID box')\n\t}\n\n\tconst manifestLabel = extractManifestLabel(jumbfBoxes)\n\tconst manifestBoxes = resolveManifestBoxes(jumbfBoxes)\n\n\tlet claimData: Record<string, unknown> | null = null\n\tlet claimCborBytes: Uint8Array | null = null\n\tlet internalAssertions: InternalAssertionData[] = []\n\tlet signatureBytes: Uint8Array | null = null\n\n\tfor (const box of manifestBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tif (label === 'c2pa.claim' || label === 'c2pa.claim.v2') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor')\n\t\t\tif (contentBox) {\n\t\t\t\tclaimCborBytes = contentBox.data\n\t\t\t\ttry { claimData = decode(contentBox.data) as Record<string, unknown> } catch { /* malformed claim — continue */ }\n\t\t\t}\n\t\t}\n\t\telse if (label === 'c2pa.assertions') {\n\t\t\tinternalAssertions = parseAssertionsInternal(inner)\n\t\t}\n\t\telse if (label === 'c2pa.signature') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\tif (contentBox) signatureBytes = contentBox.data\n\t\t}\n\t}\n\n\tconst { issuer, certNotBefore } = parseSignatureInfo(signatureBytes)\n\n\tconst instanceId = (claimData?.['instanceID'] ?? claimData?.['instance_id'] ?? null) as string | null\n\tconst claimGenerator = (claimData?.['claim_generator'] ?? claimData?.['claimGenerator'] ?? null) as string | null\n\tconst resolvedLabel =\n\t\tmanifestLabel ??\n\t\t(claimData?.['dc:title'] as string | undefined) ??\n\t\t(claimData?.['title'] as string | undefined) ??\n\t\tinstanceId ??\n\t\t'unknown'\n\n\tconst claimAssertionRefs = claimData ? extractClaimAssertionRefs(claimData) : []\n\n\tconst assertions: C2paAssertion[] = internalAssertions.map(a => ({ label: a.label, data: a.data }))\n\n\tconst manifest: C2paManifest = {\n\t\tlabel: resolvedLabel,\n\t\tinstanceId,\n\t\tclaimGenerator,\n\t\tsignatureInfo: { issuer, certNotBefore },\n\t\tassertions,\n\t}\n\n\treturn {\n\t\tmanifest,\n\t\tclaimAssertionRefs,\n\t\tclaimCborBytes,\n\t\tsignatureBytes,\n\t\tassertions: internalAssertions,\n\t}\n}\n\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\n\nconst C2PA_SIGNATURE_LABEL = 'c2pa.signature'\nconst X5CHAIN_COSE_HEADER = 33\n\n/**\n * Extracts the end-entity certificate from raw COSE_Sign1 signature bytes.\n *\n * @internal\n */\nexport function extractCertificateFromSignatureBytes(signatureBytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_COSE_HEADER] ??\n\t\t\tcose.unprotectedHeader[X5CHAIN_COSE_HEADER]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return null\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\treturn certDER instanceof Uint8Array ? certDER : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction findSignatureContentBytes(boxes: JumbfBox[]): Uint8Array | null {\n\tfor (const box of boxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\n\t\tif (jumd && parseJumbfLabel(jumd.data) === C2PA_SIGNATURE_LABEL) {\n\t\t\tconst content = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\treturn content?.data ?? null\n\t\t}\n\n\t\tconst nested = findSignatureContentBytes(inner)\n\t\tif (nested) return nested\n\t}\n\treturn null\n}\n\n/**\n * Extracts the end-entity certificate (DER-encoded) from the C2PA claim signature\n * embedded in a BMFF file.\n *\n * Navigates the JUMBF structure inside the C2PA UUID box to locate the\n * `c2pa.signature` entry, decodes the `COSE_Sign1`, and returns the first\n * certificate from the `x5chain` (COSE protected header label 33).\n *\n * @param mp4Bytes - Raw BMFF bytes (e.g. an MP4 init segment)\n * @returns DER-encoded certificate bytes, or `null` if not found or on any error\n *\n * @example\n * {@includeCode ../test/c2pa/extractManifestCertificate.test.ts#example}\n *\n * @internal\n */\nexport function extractManifestCertificate(mp4Bytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst boxes = readIsoBoxes(mp4Bytes)\n\t\tconst uuidBox = findC2paUuidBox(boxes)\n\t\tif (!uuidBox) return null\n\n\t\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\t\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\t\tif (!jumbfPayload) return null\n\t\tconst signatureBytes = findSignatureContentBytes(parseJumbfBoxes(jumbfPayload))\n\t\tif (!signatureBytes) return null\n\n\t\treturn extractCertificateFromSignatureBytes(signatureBytes)\n\t} catch {\n\t\treturn null\n\t}\n}\n","import type { BmffHashConstraint, BmffHashExclusion } from './BmffHashExclusion.ts'\n\nfunction bytesMatchAt(boxData: Uint8Array, offset: number, expected: Uint8Array | readonly number[]): boolean {\n\tconst bytes = expected instanceof Uint8Array ? expected : new Uint8Array(expected as number[])\n\tif (offset + bytes.length > boxData.length) return false\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (boxData[offset + i] !== bytes[i]) return false\n\t}\n\treturn true\n}\n\nfunction constraintMatches(boxData: Uint8Array, constraint: BmffHashConstraint): boolean {\n\treturn bytesMatchAt(boxData, constraint.offset, constraint.value)\n}\n\n/**\n * Returns `true` if the given BMFF box should be excluded from the\n * C2PA content hash, based on the provided exclusion list.\n *\n * Exclusions use C2PA xpath notation (e.g. `/emsg`, `/moof/traf`).\n * Optional `data` constraints narrow the match to specific box content by byte offset.\n *\n * @param boxType - Four-character box type code (e.g. `'emsg'`, `'moof'`)\n * @param boxData - Full box bytes including the 8-byte size+type header\n * @param exclusions - Exclusion list from the C2PA `c2pa.hash.bmff.v3` assertion\n * @returns `true` if the box should be excluded from the hash input\n *\n * @example\n * {@includeCode ../../test/bmff/shouldExcludeBox.test.ts#example}\n *\n * @public\n */\nexport function shouldExcludeBox(\n\tboxType: string,\n\tboxData: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n): boolean {\n\tfor (const exclusion of exclusions) {\n\t\tif (!exclusion.xpath) continue\n\t\tconst xpathMatchesType = exclusion.xpath === `/${boxType}` || exclusion.xpath.startsWith(`/${boxType}/`)\n\t\tif (!xpathMatchesType) continue\n\t\tconst { data } = exclusion\n\t\tif (!data || data.length === 0) return true\n\t\tif (data.every(constraint => constraintMatches(boxData, constraint))) return true\n\t}\n\treturn false\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { shouldExcludeBox } from './shouldExcludeBox.ts'\n\nconst MINIMUM_BOX_SIZE = 8 // size(4) + type(4)\nconst BOX_TYPE_OFFSET = 4\nconst DEFAULT_HASH_ALG = 'SHA-256'\n\n/**\n * Options for BMFF content hash computation.\n *\n * @internal\n */\nexport type BmffHashOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n\t/** `8` for offset-prefix mode, `0` (default) for no prefix. */\n\treadonly offsetPrefixSize?: number\n}\n\nfunction readBoxType(bytes: Uint8Array, offset: number): string {\n\treturn String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3])\n}\n\nfunction writeUint64BigEndian(bytes: Uint8Array, value: number): void {\n\tnew DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).setBigUint64(0, BigInt(value), false)\n}\n\nfunction buildHashInput(\n\tbytes: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n\toffsetPrefixSize: number,\n): Uint8Array {\n\tif (offsetPrefixSize !== 0 && offsetPrefixSize !== 8) {\n\t\tthrow new Error(`offsetPrefixSize must be 0 or 8, got ${offsetPrefixSize}`)\n\t}\n\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t// First pass: calculate total size\n\tlet totalLength = 0\n\tlet offset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\ttotalLength += offsetPrefixSize + boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\t// Second pass: write directly into pre-sized buffer\n\tconst hashInput = new Uint8Array(totalLength)\n\tlet writeOffset = 0\n\toffset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\tif (offsetPrefixSize > 0) {\n\t\t\t\twriteUint64BigEndian(hashInput.subarray(writeOffset, writeOffset + offsetPrefixSize), offset)\n\t\t\t\twriteOffset += offsetPrefixSize\n\t\t\t}\n\t\t\thashInput.set(boxData, writeOffset)\n\t\t\twriteOffset += boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\treturn hashInput\n}\n\n/**\n * Computes the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Iterates through top-level BMFF boxes, excludes those matching the exclusion list,\n * concatenates the remaining box bytes (optionally prefixed with each box's file offset),\n * and returns the WebCrypto digest.\n *\n * @param segmentBytes - Raw segment bytes to hash\n * @param options - Hash options (exclusions, algorithm, offset prefix size)\n * @returns The computed hash bytes\n *\n * @example\n * {@includeCode ../../test/bmff/computeBmffHash.test.ts#example}\n *\n * @internal\n */\nexport async function computeBmffHash(segmentBytes: Uint8Array, options?: BmffHashOptions): Promise<Uint8Array> {\n\tconst exclusions = options?.exclusions ?? []\n\tconst alg = options?.alg ?? DEFAULT_HASH_ALG\n\tconst offsetPrefixSize = options?.offsetPrefixSize ?? 0\n\n\tconst hashInput = buildHashInput(segmentBytes, exclusions, offsetPrefixSize)\n\tconst hashBuffer = await crypto.subtle.digest(alg, hashInput)\n\treturn new Uint8Array(hashBuffer)\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { computeBmffHash } from './computeBmffHash.ts'\nimport { hashesEqual } from '../utils.ts'\n\nconst OFFSET_PREFIX_SIZES_TO_TRY = [8, 0] as const\n\n/**\n * Options for BMFF hash validation.\n *\n * @public\n */\nexport type BmffHashValidationOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n}\n\n/**\n * Validates the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Tries both offset-prefix modes — 8-byte file offset prefix and no prefix — to handle\n * inter-signer interoperability until a standard signaling mechanism is defined in the spec.\n *\n * Use {@link computeBmffHash} directly when the offset prefix size is known.\n *\n * @param segmentBytes - Raw segment bytes to validate\n * @param expectedHash - Expected hash bytes from the VSI CBOR map\n * @param options - Validation options (exclusions, algorithm)\n * @returns `true` if the computed hash matches the expected hash in either offset mode\n *\n * @example\n * {@includeCode ../../test/bmff/validateBmffHash.test.ts#example}\n *\n * @public\n */\nexport async function validateBmffHash(\n\tsegmentBytes: Uint8Array,\n\texpectedHash: Uint8Array,\n\toptions?: BmffHashValidationOptions,\n): Promise<boolean> {\n\tfor (const offsetPrefixSize of OFFSET_PREFIX_SIZES_TO_TRY) {\n\t\tconst hash = await computeBmffHash(segmentBytes, { ...options, offsetPrefixSize })\n\t\tif (hashesEqual(hash, expectedHash)) return true\n\t}\n\treturn false\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA validation status codes for manifest integrity checks,\n * as defined in the C2PA specification chapters 15 and 18.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_claim_validation | C2PA Spec §15.10.3}\n *\n * @enum\n *\n * @public\n */\nexport const C2paStatusCode = {\n\t/** Assertion hash does not match the hashed URI in the claim (§15.10.3.1) */\n\tASSERTION_HASHEDURI_MISMATCH: 'assertion.hashedURI.mismatch',\n\t/** An assertion referenced in the claim is missing from the assertion store (§15.10.3.1) */\n\tASSERTION_MISSING: 'assertion.missing',\n\t/** An action requiring an ingredient reference does not have one (§18.15.4.7) */\n\tASSERTION_ACTION_INGREDIENT_MISMATCH: 'assertion.action.ingredientMismatch',\n\t/** Claim signature verification failed (§15.7) */\n\tCLAIM_SIGNATURE_MISMATCH: 'claim.signature.mismatch',\n} as const\n\n/**\n * Union type of all {@link (C2paStatusCode:variable)} values.\n *\n * @public\n */\nexport type C2paStatusCode = ValueOf<typeof C2paStatusCode>\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\n\nconst ACTIONS_LABELS = new Set(['c2pa.actions', 'c2pa.actions.v2'])\nconst ACTIONS_REQUIRING_INGREDIENTS = new Set(['c2pa.opened', 'c2pa.placed', 'c2pa.removed'])\n\n/**\n * Validates action ingredient references per C2PA §18.15.4.7.\n *\n * For any `c2pa.actions` or `c2pa.actions.v2` assertion, actions with type\n * `c2pa.opened`, `c2pa.placed`, or `c2pa.removed` must include a\n * `parameters.ingredients` field. Reports `assertion.action.ingredientMismatch`\n * if any such action is missing the required field.\n *\n * @param assertions - Parsed assertions (label + decoded data)\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport function validateActionIngredients(\n\tassertions: readonly { readonly label: string; readonly data: unknown }[],\n): readonly C2paStatusCode[] {\n\tconst codes: C2paStatusCode[] = []\n\n\tfor (const assertion of assertions) {\n\t\tif (!ACTIONS_LABELS.has(assertion.label)) continue\n\n\t\tconst data = assertion.data as Record<string, unknown> | null\n\t\tif (!data) continue\n\n\t\tconst actions = data['actions'] as unknown[] | undefined\n\t\tif (!Array.isArray(actions)) continue\n\n\t\tfor (const action of actions) {\n\t\t\tif (!action || typeof action !== 'object') continue\n\t\t\tconst record = action as Record<string, unknown>\n\t\t\tconst actionType = record['action'] as string | undefined\n\t\t\tif (!actionType || !ACTIONS_REQUIRING_INGREDIENTS.has(actionType)) continue\n\n\t\t\tconst parameters = record['parameters'] as Record<string, unknown> | undefined\n\t\t\tconst ingredients = parameters?.['ingredients']\n\n\t\t\tif (!Array.isArray(ingredients) || ingredients.length === 0) {\n\t\t\t\tcodes.push(C2paStatusCode.ASSERTION_ACTION_INGREDIENT_MISMATCH)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn codes\n}\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { hashesEqual, normalizeAlgorithmName } from '../utils.ts'\nimport type { ClaimAssertionRef } from './ClaimAssertionRef.ts'\nimport type { InternalAssertionData } from './InternalManifestData.ts'\n\n/**\n * Extracts the assertion label from a JUMBF URI.\n *\n * Handles both absolute (`self#jumbf=/c2pa/<manifest>/c2pa.assertions/<label>`)\n * and relative URI forms by returning the last path segment.\n */\nfunction extractLabelFromUrl(url: string): string {\n\tconst fragmentIndex = url.indexOf('#jumbf=')\n\tconst path = fragmentIndex >= 0 ? url.substring(fragmentIndex + 7) : url\n\tconst lastSlash = path.lastIndexOf('/')\n\treturn lastSlash >= 0 ? path.substring(lastSlash + 1) : path\n}\n\n/**\n * Validates assertion hashes and presence per C2PA §15.10.3.1.\n *\n * For each assertion referenced in the claim's hashed URI list:\n * - Checks that the assertion exists in the assertion store (`assertion.missing`)\n * - Recomputes the hash of the raw JUMBF box payload and compares it to the\n * expected hash from the claim (`assertion.hashedURI.mismatch`)\n *\n * @param claimRefs - Hashed URI references from the claim\n * @param assertions - Parsed assertions with preserved raw box payloads\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport async function validateAssertionHashes(\n\tclaimRefs: readonly ClaimAssertionRef[],\n\tassertions: readonly InternalAssertionData[],\n): Promise<readonly C2paStatusCode[]> {\n\tif (claimRefs.length === 0) return []\n\n\tconst assertionsByLabel = new Map<string, InternalAssertionData>()\n\tfor (const assertion of assertions) {\n\t\tassertionsByLabel.set(assertion.label, assertion)\n\t}\n\n\tconst codes: C2paStatusCode[] = []\n\n\tconst hashChecks = claimRefs.map(async (ref) => {\n\t\tconst label = extractLabelFromUrl(ref.url)\n\t\tconst assertion = assertionsByLabel.get(label)\n\n\t\tif (!assertion) {\n\t\t\treturn C2paStatusCode.ASSERTION_MISSING\n\t\t}\n\n\t\tconst alg = ref.alg ? normalizeAlgorithmName(ref.alg) : 'SHA-256'\n\t\tconst computedHash = new Uint8Array(\n\t\t\tawait crypto.subtle.digest(alg, assertion.rawBoxPayload),\n\t\t)\n\n\t\tif (!hashesEqual(computedHash, ref.hash)) {\n\t\t\treturn C2paStatusCode.ASSERTION_HASHEDURI_MISMATCH\n\t\t}\n\n\t\treturn null\n\t})\n\n\tconst results = await Promise.all(hashChecks)\n\tfor (const result of results) {\n\t\tif (result) codes.push(result)\n\t}\n\n\treturn codes\n}\n","// WebCrypto algorithm names\nexport const ECDSA_ALGORITHM = 'ECDSA'\nexport const ED25519_ALGORITHM = 'Ed25519'\nexport const RSA_PSS_ALGORITHM = 'RSA-PSS'\n\n// Named curves\nexport const CURVE_P256 = 'P-256'\nexport const CURVE_P384 = 'P-384'\nexport const CURVE_P521 = 'P-521'\n\n// Hash algorithms\nexport const HASH_SHA256 = 'SHA-256'\nexport const HASH_SHA384 = 'SHA-384'\nexport const HASH_SHA512 = 'SHA-512'\n","import {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst COSE_ALG_ES256 = -7\nconst COSE_ALG_ES384 = -35\nconst COSE_ALG_ES512 = -36\nconst COSE_ALG_EDDSA = -8\nconst COSE_ALG_PS256 = -37\nconst COSE_ALG_PS384 = -38\nconst COSE_ALG_PS512 = -39\n\ntype CoseAlgorithm = AlgorithmIdentifier | EcKeyImportParams | RsaHashedImportParams\n\nconst COSE_ALGORITHM_MAP = new Map<number, CoseAlgorithm>([\n\t[COSE_ALG_ES256, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P256 }],\n\t[COSE_ALG_ES384, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P384 }],\n\t[COSE_ALG_ES512, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P521 }],\n\t[COSE_ALG_EDDSA, { name: ED25519_ALGORITHM }],\n\t[COSE_ALG_PS256, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA256 } }],\n\t[COSE_ALG_PS384, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA384 } }],\n\t[COSE_ALG_PS512, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA512 } }],\n])\n\n/**\n * Maps a COSE algorithm number (from a COSE_Sign1 protected header) to the\n * WebCrypto algorithm identifier needed for `crypto.subtle.importKey('spki', ...)`.\n *\n * @param coseAlg - COSE algorithm identifier (e.g. -7 for ES256)\n * @returns WebCrypto algorithm identifier\n * @throws If the COSE algorithm is not supported\n *\n * @internal\n */\nexport function resolveAlgorithmFromCoseAlg(coseAlg: number): CoseAlgorithm {\n\tconst algorithm = COSE_ALGORITHM_MAP.get(coseAlg)\n\tif (!algorithm) {\n\t\tthrow new Error(`Unsupported COSE algorithm: ${coseAlg}`)\n\t}\n\treturn algorithm\n}\n","const CBOR_ARRAY_FOUR_ITEMS = 0x84\nconst CBOR_TEXT_MAJOR_TYPE_BASE = 0x60\nconst CBOR_BYTES_MAJOR_TYPE_BASE = 0x40\nconst CBOR_UINT8_LENGTH_INDICATOR = 0x58\nconst CBOR_UINT16_LENGTH_INDICATOR = 0x59\nconst CBOR_UINT32_LENGTH_INDICATOR = 0x5a\nconst CBOR_INLINE_MAX = 23\nconst CBOR_UINT8_MAX = 255\nconst CBOR_UINT16_MAX = 65535\nconst COSE_SIG1_CONTEXT_BYTES = new TextEncoder().encode('Signature1')\n\nfunction byteStringHeaderSize(length: number): number {\n\tif (length <= CBOR_INLINE_MAX) return 1\n\tif (length <= CBOR_UINT8_MAX) return 2\n\tif (length <= CBOR_UINT16_MAX) return 3\n\treturn 5\n}\n\nfunction writeByteStringHeader(output: Uint8Array, offset: number, length: number): number {\n\tif (length <= CBOR_INLINE_MAX) {\n\t\toutput[offset++] = CBOR_BYTES_MAJOR_TYPE_BASE + length\n\t} else if (length <= CBOR_UINT8_MAX) {\n\t\toutput[offset++] = CBOR_UINT8_LENGTH_INDICATOR\n\t\toutput[offset++] = length\n\t} else if (length <= CBOR_UINT16_MAX) {\n\t\toutput[offset++] = CBOR_UINT16_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t} else {\n\t\toutput[offset++] = CBOR_UINT32_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >>> 24) & 0xff\n\t\toutput[offset++] = (length >>> 16) & 0xff\n\t\toutput[offset++] = (length >>> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t}\n\treturn offset\n}\n\n/**\n * Builds the COSE `Sig_Structure` (ToBeSigned) bytes for a `COSE_Sign1` structure (RFC 9052 §4.4).\n *\n * The resulting bytes are the direct input to signature creation or verification via WebCrypto.\n *\n * @param protectedBytes - Serialized protected header (CBOR-encoded byte string)\n * @param payload - Payload bytes\n * @param externalAad - External additional authenticated data (default: empty)\n * @returns CBOR-encoded `Sig_Structure` array ready for signing or verification\n *\n * @example\n * {@includeCode ../../test/cose/buildSigStructure.test.ts#example}\n *\n * @public\n */\nexport function buildSigStructure(\n\tprotectedBytes: Uint8Array,\n\tpayload: Uint8Array,\n\texternalAad: Uint8Array = new Uint8Array(0),\n): Uint8Array {\n\tconst totalLength =\n\t\t1 // array header\n\t\t+ 1 + COSE_SIG1_CONTEXT_BYTES.length // context string (length < 24, fits inline)\n\t\t+ byteStringHeaderSize(protectedBytes.length) + protectedBytes.length\n\t\t+ byteStringHeaderSize(externalAad.length) + externalAad.length\n\t\t+ byteStringHeaderSize(payload.length) + payload.length\n\n\tconst result = new Uint8Array(totalLength)\n\tlet offset = 0\n\n\tresult[offset++] = CBOR_ARRAY_FOUR_ITEMS\n\tresult[offset++] = CBOR_TEXT_MAJOR_TYPE_BASE + COSE_SIG1_CONTEXT_BYTES.length\n\tresult.set(COSE_SIG1_CONTEXT_BYTES, offset)\n\toffset += COSE_SIG1_CONTEXT_BYTES.length\n\n\toffset = writeByteStringHeader(result, offset, protectedBytes.length)\n\tresult.set(protectedBytes, offset)\n\toffset += protectedBytes.length\n\n\toffset = writeByteStringHeader(result, offset, externalAad.length)\n\tresult.set(externalAad, offset)\n\toffset += externalAad.length\n\n\toffset = writeByteStringHeader(result, offset, payload.length)\n\tresult.set(payload, offset)\n\n\treturn result\n}\n","import type { CoseSign1 } from './CoseSign1.ts'\nimport { buildSigStructure } from './buildSigStructure.ts'\nimport {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst DER_SEQUENCE_TAG = 0x30\nconst DER_INTEGER_TAG = 0x02\n\nconst CURVE_COMPONENT_BYTES: Record<string, number> = { [CURVE_P256]: 32, [CURVE_P384]: 48, [CURVE_P521]: 66 }\n\ntype EcKeyAlgorithm = KeyAlgorithm & { readonly namedCurve: string }\ntype RsaHashedKeyAlgorithm = KeyAlgorithm & { readonly hash: { readonly name: string } }\n\nconst RSA_PSS_SALT_LENGTH: Record<string, number> = {\n\t[HASH_SHA256]: 32,\n\t[HASH_SHA384]: 48,\n\t[HASH_SHA512]: 64,\n}\n\nfunction getComponentSize(publicKey: CryptoKey): number {\n\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\tconst size = CURVE_COMPONENT_BYTES[curve]\n\tif (!size) throw new Error(`Unsupported EC curve: ${curve}`)\n\treturn size\n}\n\nfunction isDerEncoded(signature: Uint8Array, expectedRawLength: number): boolean {\n\treturn signature.length !== expectedRawLength && signature.length > 2 && signature[0] === DER_SEQUENCE_TAG\n}\n\nfunction parseDerLength(der: Uint8Array, offset: number): { length: number; nextOffset: number } {\n\tif (offset >= der.length) throw new Error('DER signature: truncated length')\n\tconst firstByte = der[offset]\n\tif ((firstByte & 0x80) === 0) {\n\t\treturn { length: firstByte, nextOffset: offset + 1 }\n\t}\n\tconst numBytes = firstByte & 0x7f\n\tif (numBytes === 0 || offset + numBytes >= der.length) throw new Error('DER signature: invalid long-form length')\n\tlet length = 0\n\tfor (let i = 1; i <= numBytes; i++) {\n\t\tlength = (length << 8) | der[offset + i]\n\t}\n\treturn { length, nextOffset: offset + 1 + numBytes }\n}\n\nfunction extractDerInteger(\n\tder: Uint8Array,\n\toffset: number,\n): { value: Uint8Array; nextOffset: number } {\n\tif (der[offset] !== DER_INTEGER_TAG) throw new Error('DER signature: expected INTEGER tag')\n\tconst { length, nextOffset: valueStart } = parseDerLength(der, offset + 1)\n\tlet start = valueStart\n\tlet remaining = length\n\tif (remaining > 0 && der[start] === 0x00) {\n\t\tstart++\n\t\tremaining--\n\t}\n\treturn { value: der.slice(start, start + remaining), nextOffset: valueStart + length }\n}\n\nfunction derToRawEcdsaSignature(der: Uint8Array, componentSize: number): Uint8Array {\n\tif (der[0] !== DER_SEQUENCE_TAG) throw new Error('DER signature: expected SEQUENCE tag')\n\tconst { nextOffset: contentStart } = parseDerLength(der, 1)\n\tconst rResult = extractDerInteger(der, contentStart)\n\tconst sResult = extractDerInteger(der, rResult.nextOffset)\n\n\tconst rawLength = componentSize * 2\n\tconst raw = new Uint8Array(rawLength)\n\traw.set(rResult.value, componentSize - rResult.value.length)\n\traw.set(sResult.value, rawLength - sResult.value.length)\n\treturn raw\n}\n\nfunction resolveVerifyAlgorithm(publicKey: CryptoKey) {\n\tconst { name } = publicKey.algorithm\n\tif (name === ED25519_ALGORITHM) return { name: ED25519_ALGORITHM }\n\tif (name === ECDSA_ALGORITHM) {\n\t\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\t\tconst hash = curve === CURVE_P384 ? HASH_SHA384 : curve === CURVE_P521 ? HASH_SHA512 : HASH_SHA256\n\t\treturn { name: ECDSA_ALGORITHM, hash: { name: hash } }\n\t}\n\tif (name === RSA_PSS_ALGORITHM) {\n\t\tconst hashName = (publicKey.algorithm as RsaHashedKeyAlgorithm).hash.name\n\t\treturn { name: RSA_PSS_ALGORITHM, saltLength: RSA_PSS_SALT_LENGTH[hashName] ?? 32 }\n\t}\n\tthrow new Error(`Unsupported public key algorithm: ${name}`)\n}\n\nfunction normalizeSignature(signature: Uint8Array, publicKey: CryptoKey): Uint8Array {\n\tif (publicKey.algorithm.name !== ECDSA_ALGORITHM) return signature\n\tconst componentSize = getComponentSize(publicKey)\n\tif (isDerEncoded(signature, componentSize * 2)) {\n\t\treturn derToRawEcdsaSignature(signature, componentSize)\n\t}\n\treturn signature\n}\n\n/**\n * Verifies a `COSE_Sign1` signature using a provided `CryptoKey` (RFC 9052 §4.4).\n *\n * Builds the `Sig_Structure` from the protected header and payload, normalizes\n * DER-encoded ECDSA signatures to raw format if needed, and delegates\n * verification to the WebCrypto API.\n *\n * Supports `ECDSA` (P-256, P-384, P-521), `Ed25519`, and `RSA-PSS` (PS256, PS384, PS512) keys.\n *\n * @param coseSign1 - Decoded COSE_Sign1 structure (from {@link decodeCoseSign1})\n * @param payload - Payload bytes to verify. May differ from `coseSign1.payload` for detached payloads.\n * @param publicKey - Imported public key for verification\n * @returns `true` if the signature is valid\n * @throws If the key algorithm is not supported\n *\n * @example\n * {@includeCode ../../test/cose/verifyCoseSign1.test.ts#example}\n *\n * @public\n */\nexport async function verifyCoseSign1(\n\tcoseSign1: CoseSign1,\n\tpayload: Uint8Array,\n\tpublicKey: CryptoKey,\n): Promise<boolean> {\n\tconst sigStructure = buildSigStructure(coseSign1.protectedBytes, payload)\n\tconst algorithm = resolveVerifyAlgorithm(publicKey)\n\tconst signature = normalizeSignature(coseSign1.signature, publicKey)\n\treturn crypto.subtle.verify(algorithm, publicKey, signature, sigStructure)\n}\n","import {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_SEQUENCE,\n\treadElement,\n\treadElementRaw,\n} from './asn1.ts'\n\n/**\n * Extracts the SubjectPublicKeyInfo (SPKI) DER bytes from an X.509 DER certificate.\n *\n * Navigates the TBSCertificate structure to reach the 7th field\n * (SubjectPublicKeyInfo), skipping version, serialNumber, signatureAlgorithm,\n * issuer, validity, and subject.\n *\n * The returned bytes can be imported directly via\n * `crypto.subtle.importKey('spki', ...)`.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Full DER encoding of the SubjectPublicKeyInfo, or `null` on parse failure\n *\n * @internal\n */\nexport function extractCertificateSpki(certDER: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// 1. Optional version [0]\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// 2. Serial number (INTEGER)\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// 3. Signature algorithm (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 4. Issuer (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 5. Validity (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 6. Subject (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 7. SubjectPublicKeyInfo (SEQUENCE) — return full DER encoding\n\t\treturn readElementRaw(tbs.value, offset)\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","import { readElement, ASN1_TAG_SEQUENCE } from './asn1.ts'\n\n// OID 1.2.840.113549.1.1.10 (rsassaPss)\nconst OID_RSASSA_PSS = new Uint8Array([0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a])\n\n// AlgorithmIdentifier for rsaEncryption (OID 1.2.840.113549.1.1.1) with NULL params\n// SEQUENCE { OID rsaEncryption, NULL }\nconst RSA_ENCRYPTION_ALGORITHM_ID = new Uint8Array([\n\t0x30, 0x0d, // SEQUENCE, 13 bytes\n\t0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, // OID rsaEncryption\n\t0x05, 0x00, // NULL\n])\n\nfunction containsRsaPssOid(bytes: Uint8Array): boolean {\n\tif (bytes.length < OID_RSASSA_PSS.length) return false\n\touter: for (let i = 0; i <= bytes.length - OID_RSASSA_PSS.length; i++) {\n\t\tfor (let j = 0; j < OID_RSASSA_PSS.length; j++) {\n\t\t\tif (bytes[i + j] !== OID_RSASSA_PSS[j]) continue outer\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\n/**\n * Normalizes an SPKI that uses the `rsassaPss` OID (1.2.840.113549.1.1.10) to\n * use the generic `rsaEncryption` OID (1.2.840.113549.1.1.1) instead.\n *\n * WebCrypto's `importKey('spki', ...)` with `{ name: 'RSA-PSS' }` expects the\n * SPKI to use the generic `rsaEncryption` OID. Certificates signed with\n * RSASSA-PSS often embed the PSS-specific OID and parameters, which causes\n * `DataError` on import.\n *\n * If the SPKI does not use `rsassaPss`, it is returned unchanged.\n *\n * @internal\n */\nexport function normalizeRsaPssSpki(spkiBytes: Uint8Array): Uint8Array {\n\tif (!containsRsaPssOid(spkiBytes)) return spkiBytes\n\n\t// Parse outer SEQUENCE\n\tconst outer = readElement(spkiBytes, 0)\n\tif (!outer || outer.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// First child: AlgorithmIdentifier SEQUENCE\n\tconst algId = readElement(outer.value, 0)\n\tif (!algId || algId.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// Second child: BIT STRING with the public key\n\tconst publicKeyBitString = outer.value.subarray(algId.totalSize)\n\n\t// Build new SPKI: RSA_ENCRYPTION_ALGORITHM_ID + original BIT STRING\n\tconst innerLength = RSA_ENCRYPTION_ALGORITHM_ID.length + publicKeyBitString.length\n\tconst headerBytes = encodeDerLength(innerLength)\n\tconst result = new Uint8Array(1 + headerBytes.length + innerLength)\n\tlet offset = 0\n\tresult[offset++] = ASN1_TAG_SEQUENCE\n\tresult.set(headerBytes, offset)\n\toffset += headerBytes.length\n\tresult.set(RSA_ENCRYPTION_ALGORITHM_ID, offset)\n\toffset += RSA_ENCRYPTION_ALGORITHM_ID.length\n\tresult.set(publicKeyBitString, offset)\n\n\treturn result\n}\n\nfunction encodeDerLength(length: number): Uint8Array {\n\tif (length < 0x80) return new Uint8Array([length])\n\tif (length <= 0xff) return new Uint8Array([0x81, length])\n\tif (length <= 0xffff) return new Uint8Array([0x82, (length >> 8) & 0xff, length & 0xff])\n\treturn new Uint8Array([0x83, (length >> 16) & 0xff, (length >> 8) & 0xff, length & 0xff])\n}\n","import { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { resolveAlgorithmFromCoseAlg } from '../cose/resolveAlgorithmFromCoseAlg.ts'\nimport { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { extractCertificateSpki } from '../x509/extractCertificateSpki.ts'\nimport { normalizeRsaPssSpki } from '../x509/normalizeRsaPssSpki.ts'\n\n/**\n * Verifies the claim signature of a C2PA manifest per §15.7.\n *\n * The `c2pa.signature` JUMBF box contains a `COSE_Sign1` structure whose payload\n * is the claim CBOR bytes. This function verifies the signature against the\n * public key extracted from the end-entity certificate in the `x5chain` header.\n *\n * @param signatureBytes - Raw COSE_Sign1 bytes from the `c2pa.signature` box\n * @param claimCborBytes - Raw CBOR bytes of the claim content box\n * @param certificateDER - DER-encoded end-entity X.509 certificate\n * @returns `true` if the signature is valid\n *\n * @internal\n */\nexport async function verifyClaimSignature(\n\tsignatureBytes: Uint8Array,\n\tclaimCborBytes: Uint8Array,\n\tcertificateDER: Uint8Array,\n): Promise<boolean> {\n\ttry {\n\t\tconst coseSign1 = decodeCoseSign1(signatureBytes)\n\n\t\tconst rawSpki = extractCertificateSpki(certificateDER)\n\t\tif (!rawSpki) return false\n\t\tconst spkiBytes = normalizeRsaPssSpki(rawSpki)\n\n\t\tif (coseSign1.alg == null) return false\n\n\t\tconst importAlgorithm = resolveAlgorithmFromCoseAlg(coseSign1.alg)\n\n\t\tconst publicKey = await crypto.subtle.importKey(\n\t\t\t'spki',\n\t\t\tnew Uint8Array(spkiBytes) as BufferSource,\n\t\t\timportAlgorithm,\n\t\t\ttrue,\n\t\t\t['verify'],\n\t\t)\n\n\t\treturn verifyCoseSign1(coseSign1, claimCborBytes, publicKey)\n\t}\n\tcatch {\n\t\treturn false\n\t}\n}\n","import type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { C2paStatusCode as Code } from '../C2paStatusCode.ts'\nimport type { InternalManifestData } from './InternalManifestData.ts'\nimport { validateActionIngredients } from './validateActionIngredients.ts'\nimport { validateAssertionHashes } from './validateAssertionHashes.ts'\nimport { verifyClaimSignature } from './verifyClaimSignature.ts'\n\n/**\n * Validates the integrity of a C2PA manifest per Chapter 15 and Chapter 18.\n *\n * Runs four validation checks in parallel where possible:\n * 1. Assertion hash verification (§15.10.3.1)\n * 2. Missing assertion detection (§15.10.3.1)\n * 3. Action ingredient validation (§18.15.4.7)\n * 4. Claim signature verification (§15.7)\n *\n * @param internal - Enriched manifest data with raw assertion bytes and claim references\n * @param certificateDER - DER-encoded end-entity certificate, or `null` to skip signature check\n * @returns Array of C2PA status codes for any failures found (empty if all pass)\n *\n * @internal\n */\nexport async function validateManifestIntegrity(\n\tinternal: InternalManifestData,\n\tcertificateDER: Uint8Array | null,\n): Promise<readonly C2paStatusCode[]> {\n\tconst { signatureBytes, claimCborBytes } = internal\n\n\tconst [assertionHashCodes, signatureValid] = await Promise.all([\n\t\tvalidateAssertionHashes(internal.claimAssertionRefs, internal.assertions),\n\t\tsignatureBytes && claimCborBytes && certificateDER\n\t\t\t? verifyClaimSignature(signatureBytes, claimCborBytes, certificateDER)\n\t\t\t: Promise.resolve(true),\n\t])\n\n\tconst actionCodes = validateActionIngredients(internal.assertions)\n\n\tconst codes: C2paStatusCode[] = [...assertionHashCodes, ...actionCodes]\n\n\tif (!signatureValid) {\n\t\tcodes.push(Code.CLAIM_SIGNATURE_MISMATCH)\n\t}\n\n\treturn codes\n}\n","import type { CoseKeyJwk } from './CoseKeyJwk.ts'\n\n// IANA COSE Key Types (RFC 9053)\nconst OKP_KEY_TYPE = 1\nconst EC2_KEY_TYPE = 2\n\n// IANA COSE Elliptic Curves\nconst EC_CURVE_NAMES: Record<number, string> = { 1: 'P-256', 2: 'P-384', 3: 'P-521' }\nconst OKP_CURVE_NAMES: Record<number, string> = { 4: 'X25519', 5: 'X448', 6: 'Ed25519', 7: 'Ed448' }\n\ntype CoseKeyLike = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(key: CoseKeyLike, intKey: number): unknown {\n\tif (key instanceof Map) return key.get(intKey)\n\treturn (key as Record<number | string, unknown>)[intKey]\n}\n\nfunction toBase64Url(value: unknown): string {\n\tconst bytes = value instanceof Uint8Array ? value : new Uint8Array(value as number[])\n\tlet binary = ''\n\tfor (const byte of bytes) binary += String.fromCharCode(byte)\n\treturn btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\n/**\n * Converts a COSE public key (RFC 9052 / IANA COSE Key registry) to JWK format.\n *\n * Supports EC2 keys (P-256, P-384, P-521) and OKP keys (Ed25519, Ed448, X25519, X448).\n * Input may be a `Map\\<number, unknown\\>` (from CBOR decoders like cbor-x) or a plain\n * object with integer keys.\n *\n * @param coseKey - COSE key structure as decoded from a C2PA `c2pa.session-keys` assertion\n * @returns JWK representation of the public key\n * @throws If the key type or curve is not supported\n *\n * @example\n * {@includeCode ../../test/cose/convertCoseKeyToJwk.test.ts#example}\n *\n * @public\n */\nexport function convertCoseKeyToJwk(coseKey: unknown): CoseKeyJwk {\n\tconst key = coseKey as CoseKeyLike\n\tconst kty = coseGet(key, 1)\n\tconst crv = coseGet(key, -1) as number\n\tconst x = coseGet(key, -2)\n\n\tif (kty === EC2_KEY_TYPE) {\n\t\tconst curveName = EC_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported EC curve: ${crv}`)\n\t\tconst y = coseGet(key, -3)\n\t\tif (!(x instanceof Uint8Array)) throw new Error('EC2 key missing or invalid x coordinate')\n\t\tif (!(y instanceof Uint8Array)) throw new Error('EC2 key missing or invalid y coordinate')\n\t\treturn { kty: 'EC', crv: curveName, x: toBase64Url(x), y: toBase64Url(y) }\n\t}\n\n\tif (kty === OKP_KEY_TYPE) {\n\t\tconst curveName = OKP_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported OKP curve: ${crv}`)\n\t\treturn { kty: 'OKP', crv: curveName, x: toBase64Url(x) }\n\t}\n\n\tthrow new Error(`Unsupported COSE key type: ${kty}`)\n}\n","import { ECDSA_ALGORITHM } from './constants.ts'\n\nconst KEY_TYPE_OKP = 'OKP'\n\nexport function resolveImportAlgorithm(jwk: { kty: string; crv: string }): AlgorithmIdentifier | EcKeyImportParams {\n\treturn jwk.kty === KEY_TYPE_OKP ? { name: jwk.crv } : { name: ECDSA_ALGORITHM, namedCurve: jwk.crv }\n}\n","import { encode } from 'cbor-x/encode'\nimport { convertCoseKeyToJwk } from './convertCoseKeyToJwk.ts'\nimport { decodeCoseSign1 } from './decodeCoseSign1.ts'\nimport { resolveImportAlgorithm } from './resolveImportAlgorithm.ts'\nimport { verifyCoseSign1 } from './verifyCoseSign1.ts'\n\n/**\n * Verifies a C2PA signer binding — a `COSE_Sign1` structure that proves\n * a session key was authorized by the content signer (C2PA spec §18.25.2).\n *\n * The `Sig_Structure` payload is `CBOR(bstr(signerCertBytes))` per the C2PA spec.\n * DER-encoded ECDSA signatures are automatically normalized to raw format.\n *\n * @param signerBindingBytes - Raw `COSE_Sign1` bytes of the signer binding\n * @param sessionCoseKey - COSE public key from the `c2pa.session-keys` assertion\n * @param signerCertBytes - DER-encoded end-entity certificate (from `x5chain`)\n * @returns `true` if the signer binding signature is valid\n * @throws If the COSE key type is not supported or decoding fails\n *\n * @example\n * {@includeCode ../../test/cose/verifySignerBinding.test.ts#example}\n *\n * @public\n */\nexport async function verifySignerBinding(\n\tsignerBindingBytes: Uint8Array,\n\tsessionCoseKey: unknown,\n\tsignerCertBytes: Uint8Array,\n): Promise<boolean> {\n\tconst coseSign1 = decodeCoseSign1(signerBindingBytes)\n\tconst jwk = convertCoseKeyToJwk(sessionCoseKey)\n\tconst publicKey = await crypto.subtle.importKey('jwk', jwk as JsonWebKey, resolveImportAlgorithm(jwk), false, ['verify'])\n\t// Signer binding payload = CBOR(bstr(cert)) per C2PA spec §18.25.2\n\tconst cborCertPayload = encode(signerCertBytes) as Uint8Array\n\treturn verifyCoseSign1(coseSign1, cborCertPayload, publicKey)\n}\n","import { decode } from 'cbor-x/decode'\nimport { encode } from 'cbor-x/encode'\nimport { findIsoBox, readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { extractCertificateFromSignatureBytes } from '../extractManifestCertificate.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { validateManifestIntegrity } from '../claim/validateManifestIntegrity.ts'\nimport { convertCoseKeyToJwk } from '../cose/convertCoseKeyToJwk.ts'\nimport { verifySignerBinding } from '../cose/verifySignerBinding.ts'\nimport type { InitSegmentValidation, ValidatedSessionKey } from './InitSegmentValidation.ts'\nimport { bytesToHex, isKeyExpired, normalizeAlgorithmName } from '../utils.ts'\n\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst SESSION_KEYS_ASSERTION_LABEL = 'c2pa.session-keys'\nconst COSE_KEY_ID_LABEL = 2\n\n// cbor-x represents CBOR tagged values in multiple ways depending on version/config:\n// - { tag: number, value: unknown } (structured)\n// - Tag class instance with constructor name 'Tag'\n// - { '@@TAGGED@@': [tag, value] } (internal key)\nconst CBOR_TAGGED_KEY = '@@TAGGED@@'\n\nfunction extractCborTaggedValue(value: unknown): unknown | null {\n\tif (typeof value !== 'object' || value === null) return null\n\tconst obj = value as Record<string, unknown>\n\tif (typeof obj['tag'] === 'number' && 'value' in obj) return obj['value']\n\tconst tagged = obj[CBOR_TAGGED_KEY]\n\tif (Array.isArray(tagged) && tagged.length === 2) return tagged[1]\n\treturn null\n}\n\nfunction normalizeToUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tif (extractCborTaggedValue(value) !== null) return encode(value) as Uint8Array\n\tthrow new Error('Cannot convert value to Uint8Array')\n}\n\nfunction ensureDecodedCbor(value: unknown): unknown {\n\tif (value instanceof Uint8Array) return decode(value)\n\tif (Array.isArray(value) && value.length > 0 && typeof (value as number[])[0] === 'number') {\n\t\treturn decode(new Uint8Array(value as number[]))\n\t}\n\treturn value\n}\n\nfunction parseCreatedAt(value: unknown): string | null {\n\tconst resolved = extractCborTaggedValue(value) ?? value\n\tif (typeof resolved === 'string') return resolved\n\tif (resolved instanceof Date) return resolved.toISOString()\n\treturn null\n}\n\nfunction extractKidHex(keyData: Record<string, unknown>, coseKey: unknown): string | null {\n\tconst kid = keyData['kid']\n\tif (kid instanceof Uint8Array) return bytesToHex(kid)\n\tif (typeof kid === 'string') return kid\n\tif (Array.isArray(kid) && kid.length > 0) return bytesToHex(new Uint8Array(kid as number[]))\n\n\t// Fallback: COSE key field 2 is the key ID per RFC 9052\n\tconst coseKeyLike = coseKey as Map<number, unknown> | Record<number, unknown>\n\tconst coseKid = coseKeyLike instanceof Map ? coseKeyLike.get(COSE_KEY_ID_LABEL) : coseKeyLike[COSE_KEY_ID_LABEL]\n\tif (coseKid instanceof Uint8Array) return bytesToHex(coseKid)\n\tif (Array.isArray(coseKid) && coseKid.length > 0) {\n\t\treturn bytesToHex(new Uint8Array(coseKid as number[]))\n\t}\n\n\treturn null\n}\n\nfunction extractKeyArray(data: unknown): unknown[] {\n\tif (Array.isArray(data)) return data\n\tif (typeof data === 'object' && data !== null) {\n\t\tconst obj = data as Record<string, unknown>\n\t\tconst keys = obj['keys'] ?? obj['sessionKeys']\n\t\tif (Array.isArray(keys)) return keys\n\t\tif (typeof keys === 'object' && keys !== null) {\n\t\t\tconst nested = (keys as Record<string, unknown>)['keys']\n\t\t\tif (Array.isArray(nested)) return nested\n\t\t}\n\t}\n\treturn []\n}\n\nasync function validateBmffHashAssertion(\n\tbytes: Uint8Array,\n\tassertion: C2paAssertion | null,\n): Promise<boolean> {\n\tif (!assertion) return true\n\tconst data = assertion.data as Record<string, unknown>\n\tconst rawHash = data['hash'] ?? data['value']\n\tif (!rawHash) return true\n\tconst expectedHash =\n\t\trawHash instanceof Uint8Array ? rawHash : new Uint8Array(rawHash as number[])\n\tconst alg = normalizeAlgorithmName(data['alg'] as string | undefined)\n\tconst exclusions = (data['exclusions'] as BmffHashExclusion[] | undefined) ?? []\n\treturn validateBmffHash(bytes, expectedHash, { exclusions, alg })\n}\n\ntype SessionKeyFields = {\n\tminSequenceNumber: number\n\tvalidityPeriod: number\n\tcreatedAt: string\n\tkid: string\n\tcoseKey: unknown\n\tsignerBindingBytes: Uint8Array\n}\n\nfunction extractSessionKeyFields(entry: unknown): SessionKeyFields | null {\n\tconst keyData = entry as Record<string, unknown>\n\n\tconst minSequenceNumber = keyData['minSequenceNumber']\n\tconst validityPeriod = keyData['validityPeriod']\n\tconst createdAt = parseCreatedAt(keyData['createdAt'])\n\n\tif (minSequenceNumber == null || validityPeriod == null || !createdAt) return null\n\n\tconst isNotYetActive = new Date() < new Date(createdAt)\n\tif (isNotYetActive || isKeyExpired(createdAt, Number(validityPeriod))) return null\n\n\tconst coseKey = ensureDecodedCbor(keyData['key'])\n\tconst kid = extractKidHex(keyData, coseKey)\n\tif (!kid) return null\n\n\tconst signerBindingRaw = keyData['signerBinding']\n\tif (!signerBindingRaw) return null\n\n\ttry {\n\t\treturn {\n\t\t\tminSequenceNumber: Number(minSequenceNumber),\n\t\t\tvalidityPeriod: Number(validityPeriod),\n\t\t\tcreatedAt,\n\t\t\tkid,\n\t\t\tcoseKey,\n\t\t\tsignerBindingBytes: normalizeToUint8Array(signerBindingRaw),\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function verifyAndConvertKey(\n\tfields: SessionKeyFields,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst isBindingValid = await verifySignerBinding(fields.signerBindingBytes, fields.coseKey, certificate)\n\tif (!isBindingValid) return null\n\n\ttry {\n\t\tconst jwk = convertCoseKeyToJwk(fields.coseKey)\n\t\treturn {\n\t\t\tkid: fields.kid,\n\t\t\tjwk,\n\t\t\tminSequenceNumber: fields.minSequenceNumber,\n\t\t\tvalidityPeriod: fields.validityPeriod,\n\t\t\tcreatedAt: fields.createdAt,\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function validateSingleSessionKey(\n\tentry: unknown,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst fields = extractSessionKeyFields(entry)\n\tif (!fields) return null\n\treturn verifyAndConvertKey(fields, certificate)\n}\n\nasync function validateSessionKeys(\n\tassertion: C2paAssertion,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey[]> {\n\tconst keyEntries = extractKeyArray(ensureDecodedCbor(assertion.data))\n\tconst results = await Promise.all(\n\t\tkeyEntries.map(entry => validateSingleSessionKey(entry, certificate)),\n\t)\n\treturn results.filter((key): key is ValidatedSessionKey => key !== null)\n}\n\n/**\n * Validates a C2PA init segment: parses the manifest, extracts and verifies\n * the certificate, validates the BMFF hard binding hash, verifies all\n * session keys from the `c2pa.session-keys` assertion, and performs\n * manifest integrity checks (assertion hashes, missing assertions,\n * action ingredients, and claim signature verification).\n *\n * Only session keys with a valid signer binding and an unexpired validity period\n * are included in the result.\n *\n * @param bytes - Raw init segment bytes\n * @returns Structured validation result (with `INIT_INVALID` error code if `mdat` box is present)\n * @throws If no C2PA UUID box is found\n *\n * @example\n * {@includeCode ../../test/init/validateC2paInitSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paInitSegment(bytes: Uint8Array): Promise<InitSegmentValidation> {\n\tconst boxes = readIsoBoxes(bytes)\n\tif (findIsoBox(boxes, box => box.type === 'mdat')) {\n\t\treturn {\n\t\t\tmanifest: null,\n\t\t\tcertificate: null,\n\t\t\tmanifestId: null,\n\t\t\tsessionKeys: [],\n\t\t\tisValid: false,\n\t\t\terrorCodes: [LiveVideoStatusCode.INIT_INVALID],\n\t\t}\n\t}\n\n\tconst internalData = readC2paManifest(bytes, boxes)\n\tconst { manifest } = internalData\n\tconst certificate = internalData.signatureBytes\n\t\t? extractCertificateFromSignatureBytes(internalData.signatureBytes)\n\t\t: null\n\n\tconst bmffHashAssertion =\n\t\tmanifest.assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL) ?? null\n\tconst bmffHashValid = await validateBmffHashAssertion(bytes, bmffHashAssertion)\n\n\tconst sessionKeysAssertion = manifest.assertions.find(\n\t\ta => a.label === SESSION_KEYS_ASSERTION_LABEL,\n\t)\n\tconst sessionKeys =\n\t\tsessionKeysAssertion && certificate\n\t\t\t? await validateSessionKeys(sessionKeysAssertion, certificate)\n\t\t\t: []\n\n\tconst integrityCodes = await validateManifestIntegrity(internalData, certificate)\n\n\tconst codes = new Set<LiveVideoStatusCode | C2paStatusCode>()\n\tif (!bmffHashValid) codes.add(LiveVideoStatusCode.INIT_INVALID)\n\tif (sessionKeys.length === 0) codes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\tfor (const code of integrityCodes) codes.add(code)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tmanifest,\n\t\tcertificate,\n\t\tmanifestId: manifest.instanceId,\n\t\tsessionKeys,\n\t\tisValid: errorCodes.length === 0,\n\t\terrorCodes,\n\t}\n}\n","import { readEmsg, readIsoBoxes, type EventMessageBox } from '@svta/cml-iso-bmff'\n\nconst EMSG_BOX_TYPE = 'emsg'\nconst VSI_SCHEME_URI = 'urn:c2pa:verifiable-segment-info'\nconst EMSG_READER_CONFIG = { readers: { emsg: readEmsg } }\n\n/**\n * Finds and parses the first C2PA Verifiable Segment Info (VSI) EMSG box\n * in a DASH segment, identified by scheme URI `urn:c2pa:verifiable-segment-info`.\n *\n * @param segmentBytes - Raw DASH segment bytes\n * @returns The parsed VSI EMSG box, or `null` if not found\n *\n * @example\n * {@includeCode ../../test/emsg/extractVsiEmsgBox.test.ts#example}\n *\n * @internal\n */\nexport function extractVsiEmsgBox(segmentBytes: Uint8Array): EventMessageBox | null {\n\tfor (const box of readIsoBoxes(segmentBytes, EMSG_READER_CONFIG)) {\n\t\tif (box.type !== EMSG_BOX_TYPE) continue\n\t\tconst emsg = box as EventMessageBox\n\t\tif (emsg.schemeIdUri === VSI_SCHEME_URI) return emsg\n\t}\n\treturn null\n}\n","import { decode } from 'cbor-x/decode'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { normalizeAlgorithmName } from '../utils.ts'\nimport type { VsiMap } from './VsiMap.ts'\n\n\n/**\n * Decodes a C2PA Verifiable Segment Info (VSI) CBOR map from raw bytes.\n *\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * @param vsiCborBytes - Raw CBOR-encoded VSI map bytes from the EMSG `messageData`\n * @returns The decoded VSI map\n * @throws If the bytes are not a valid VSI CBOR map\n *\n * @example\n * {@includeCode ../../test/vsi/decodeVsiMap.test.ts#example}\n *\n * @internal\n */\nexport function decodeVsiMap(vsiCborBytes: Uint8Array): VsiMap {\n\tconst raw = decode(vsiCborBytes) as Record<string, unknown>\n\n\tif (typeof raw !== 'object' || raw === null) {\n\t\tthrow new Error('VSI map must be a CBOR map')\n\t}\n\n\tconst sequenceNumber = raw['sequenceNumber']\n\tif (typeof sequenceNumber !== 'number') throw new Error('VSI map missing or invalid sequenceNumber')\n\n\tconst bmffHashRaw = raw['bmffHash'] as Record<string, unknown> | undefined\n\tif (!bmffHashRaw || typeof bmffHashRaw !== 'object') throw new Error('VSI map missing bmffHash')\n\n\tconst hash = bmffHashRaw['hash']\n\tif (!(hash instanceof Uint8Array)) throw new Error('VSI map bmffHash.hash must be a Uint8Array')\n\n\tconst exclusions = bmffHashRaw['exclusions']\n\tif (exclusions !== undefined && !Array.isArray(exclusions)) throw new Error('VSI map bmffHash.exclusions must be an array')\n\n\tconst manifestId = raw['manifestId']\n\tif (typeof manifestId !== 'string') throw new Error('VSI map missing or invalid manifestId')\n\n\tconst alg = normalizeAlgorithmName(bmffHashRaw['alg'] as string | undefined)\n\n\treturn {\n\t\tsequenceNumber,\n\t\tbmffHash: {\n\t\t\thash,\n\t\t\talg,\n\t\t\texclusions: (exclusions as BmffHashExclusion[] | undefined) ?? [],\n\t\t},\n\t\tmanifestId,\n\t}\n}\n","import type { SequenceState } from './SequenceState.ts'\n\n/**\n * Creates the initial (empty) sequence state for a new stream.\n *\n * @returns A {@link SequenceState} with no history\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function createSequenceState(): SequenceState {\n\treturn { lastSequenceNumber: null, seenSequences: new Set() }\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * State and result types for monotonic sequence number validation\n * per C2PA Live Streaming Specification §18.4.\n *\n * @public\n */\n\n/**\n * Immutable state snapshot for a single stream's sequence number history.\n *\n * Pass to {@link validateC2paSegment} via the `sequenceState` parameter.\n *\n * @public\n */\nexport type SequenceState = {\n\treadonly lastSequenceNumber: number | null\n\treadonly seenSequences: ReadonlySet<number>\n}\n\n/**\n * Reason codes for sequence number validation outcomes.\n *\n * @see {@link SequenceValidationResult}\n *\n * @enum\n *\n * @public\n */\nexport const SequenceValidationReason = {\n\t/** Sequence number is the next expected value */\n\tVALID: 'valid',\n\t/** Sequence number was already seen */\n\tDUPLICATE: 'duplicate',\n\t/** One or more sequence numbers were skipped */\n\tGAP_DETECTED: 'gap_detected',\n\t/** Sequence number is less than the last seen */\n\tOUT_OF_ORDER: 'out_of_order',\n\t/** Below the session key's minSequenceNumber */\n\tSEQUENCE_NUMBER_BELOW_MINIMUM: 'sequence_number_below_minimum',\n} as const\n\n/**\n * Union type of all {@link (SequenceValidationReason:variable)} values.\n *\n * @public\n */\nexport type SequenceValidationReason = ValueOf<typeof SequenceValidationReason>\n\n/**\n * Result of validating a single sequence number against the current stream state.\n *\n * Discriminated on `reason` — narrow to `'gap_detected'` to access\n * `missingFrom` / `missingTo`.\n *\n * @public\n */\nexport type SequenceValidationResult =\n\t| { readonly isValid: true; readonly reason: typeof SequenceValidationReason.VALID }\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason:\n\t\t\t\t| typeof SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM\n\t\t\t\t| typeof SequenceValidationReason.DUPLICATE\n\t\t\t\t| typeof SequenceValidationReason.OUT_OF_ORDER\n\t\t}\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason: typeof SequenceValidationReason.GAP_DETECTED\n\t\t\treadonly missingFrom: number\n\t\t\treadonly missingTo: number\n\t\t}\n","import { SequenceValidationReason } from './SequenceState.ts'\nimport type { SequenceState, SequenceValidationResult } from './SequenceState.ts'\n\nconst SEEN_SEQUENCES_WINDOW_SIZE = 32\n\nfunction pruneSeenSequences(seen: Set<number>, lastSequenceNumber: number): Set<number> {\n\tif (seen.size <= SEEN_SEQUENCES_WINDOW_SIZE) return seen\n\tconst threshold = lastSequenceNumber - SEEN_SEQUENCES_WINDOW_SIZE\n\tconst pruned = new Set<number>()\n\tfor (const seq of seen) {\n\t\tif (seq >= threshold) pruned.add(seq)\n\t}\n\treturn pruned\n}\n\n/**\n * Validates a segment's sequence number against the current stream state\n * per C2PA Live Streaming Specification §18.4.\n *\n * This function is **pure and stateless** — it returns both the validation\n * result and the next state. The caller is responsible for persisting\n * `nextState` between calls.\n *\n * Detects: `duplicate`, `out_of_order`, `gap_detected`, and\n * `sequence_number_below_minimum`.\n *\n * Internally uses a sliding window of the last 32 sequence numbers\n * to bound memory usage during long-running streams.\n *\n * @param state - Current stream state (from {@link createSequenceState} or previous `nextState`)\n * @param sequenceNumber - Sequence number from the segment's VSI map\n * @param minSequenceNumber - Minimum accepted sequence number (from the session key, default 0)\n * @returns Validation result and the updated state to persist\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function validateSequenceNumber(\n\tstate: SequenceState,\n\tsequenceNumber: number,\n\tminSequenceNumber: number,\n): { readonly result: SequenceValidationResult; readonly nextState: SequenceState } {\n\tif (sequenceNumber < minSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tif (state.seenSequences.has(sequenceNumber)) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.DUPLICATE },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tconst nextSeenSequences = new Set(state.seenSequences)\n\tnextSeenSequences.add(sequenceNumber)\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber < state.lastSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.OUT_OF_ORDER },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: state.lastSequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, state.lastSequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber > state.lastSequenceNumber + 1) {\n\t\tconst missingFrom = state.lastSequenceNumber + 1\n\t\tconst missingTo = sequenceNumber - 1\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.GAP_DETECTED, missingFrom, missingTo },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tresult: { isValid: true, reason: SequenceValidationReason.VALID },\n\t\tnextState: {\n\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t},\n\t}\n}\n","import { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { extractVsiEmsgBox } from '../emsg/extractVsiEmsgBox.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { decodeVsiMap } from '../vsi/decodeVsiMap.ts'\nimport type { SequenceState } from '../vsi/SequenceState.ts'\nimport { createSequenceState } from '../vsi/createSequenceState.ts'\nimport { validateSequenceNumber } from '../vsi/validateSequenceNumber.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { ValidatedSessionKey } from '../init/InitSegmentValidation.ts'\nimport { resolveImportAlgorithm } from '../cose/resolveImportAlgorithm.ts'\nimport { bytesToHex, isKeyExpired } from '../utils.ts'\nimport type { SegmentValidationResult } from './SegmentValidation.ts'\n\nfunction findSessionKey(sessionKeys: readonly ValidatedSessionKey[], kidHex: string | null): ValidatedSessionKey | null {\n\tif (!kidHex || sessionKeys.length === 0) return null\n\treturn sessionKeys.find(k => k.kid === kidHex) ?? null\n}\n\n/**\n * Validates a C2PA live stream segment using the VSI/EMSG method (§19.7.3).\n *\n * Extracts the EMSG box, decodes the COSE_Sign1 and VSI map, matches the\n * session key by kid, then performs all cryptographic checks: signature\n * verification, BMFF content hash, sequence number floor, and key validity.\n *\n * Returns `null` if the segment does not contain a C2PA EMSG box.\n *\n * @param segmentBytes - Raw segment bytes\n * @param sessionKeys - Available session keys from the init segment\n * @param sequenceState - Current sequence state for this stream\n * @returns Validation result and updated sequence state, or `null` if no C2PA EMSG box\n *\n * @example\n * {@includeCode ../../test/segment/validateC2paSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paSegment(\n\tsegmentBytes: Uint8Array,\n\tsessionKeys: readonly ValidatedSessionKey[],\n\tsequenceState: SequenceState = createSequenceState(),\n): Promise<{ readonly result: SegmentValidationResult; readonly nextSequenceState: SequenceState } | null> {\n\tconst emsgBox = extractVsiEmsgBox(segmentBytes)\n\tif (!emsgBox) return null\n\n\tconst coseSign1 = decodeCoseSign1(emsgBox.messageData)\n\tconst { payload } = coseSign1\n\tif (!payload) throw new Error('COSE_Sign1 payload is empty — cannot decode VSI map')\n\tconst vsi = decodeVsiMap(payload)\n\n\tconst kidHex = coseSign1.kid ? bytesToHex(coseSign1.kid) : null\n\tconst sessionKey = findSessionKey(sessionKeys, kidHex)\n\tconst bmffHashHex = bytesToHex(vsi.bmffHash.hash)\n\tconst minSequenceNumber = sessionKey?.minSequenceNumber ?? 0\n\n\tconst { result: sequenceResult, nextState: nextSequenceState } = validateSequenceNumber(\n\t\tsequenceState,\n\t\tvsi.sequenceNumber,\n\t\tminSequenceNumber,\n\t)\n\n\tconst baseFields = {\n\t\tsequenceNumber: vsi.sequenceNumber,\n\t\tmanifestId: vsi.manifestId,\n\t\tbmffHashHex,\n\t\tkidHex,\n\t\tsequenceResult,\n\t}\n\n\tif (!sessionKey) {\n\t\treturn {\n\t\t\tresult: {\n\t\t\t\t...baseFields,\n\t\t\t\tisValid: false,\n\t\t\t\terrorCodes: [LiveVideoStatusCode.SEGMENT_INVALID],\n\t\t\t},\n\t\t\tnextSequenceState,\n\t\t}\n\t}\n\n\tconst algorithm = resolveImportAlgorithm(sessionKey.jwk)\n\tconst publicKey = await crypto.subtle.importKey(\n\t\t'jwk',\n\t\tsessionKey.jwk as JsonWebKey,\n\t\talgorithm,\n\t\tfalse,\n\t\t['verify'],\n\t)\n\n\tconst [signatureValid, hashValid] = await Promise.all([\n\t\tverifyCoseSign1(coseSign1, payload, publicKey),\n\t\tvalidateBmffHash(segmentBytes, vsi.bmffHash.hash, {\n\t\t\texclusions: vsi.bmffHash.exclusions,\n\t\t\talg: vsi.bmffHash.alg,\n\t\t}),\n\t])\n\n\tconst sequenceAboveMin = vsi.sequenceNumber >= sessionKey.minSequenceNumber\n\t// §19.7.3 requires comparing against the segment's presentation time, but the\n\t// VSI map does not carry it. We compare against `now` as an approximation,\n\t// which is accurate for live streams validated in real time.\n\tconst keyExpired = isKeyExpired(sessionKey.createdAt, sessionKey.validityPeriod)\n\n\tconst codes = new Set<LiveVideoStatusCode>()\n\tif (!signatureValid || !hashValid || !sequenceAboveMin) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\tif (!sequenceResult.isValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (keyExpired) codes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tresult: { ...baseFields, isValid: errorCodes.length === 0, errorCodes },\n\t\tnextSequenceState,\n\t}\n}\n","import type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paManifest } from '../C2paManifest.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { bytesToHex, normalizeAlgorithmName } from '../utils.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { BmffHashConstraint, BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport type { InternalManifestData } from '../claim/InternalManifestData.ts'\nimport { validateManifestIntegrity } from '../claim/validateManifestIntegrity.ts'\nimport { extractCertificateFromSignatureBytes } from '../extractManifestCertificate.ts'\nimport type { ManifestBoxValidationResult, ManifestBoxValidationState } from './ManifestBoxValidation.ts'\n\nconst LIVE_VIDEO_ASSERTION_LABEL = 'c2pa.livevideo.segment'\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst MANIFEST_ID_PREFIX_PATTERN = /^(xmp:iid:|urn:uuid:)/i\nconst CONTINUITY_METHOD_MANIFEST_ID = 'c2pa.manifestId'\nconst SUPPORTED_CONTINUITY_METHODS = new Set([CONTINUITY_METHOD_MANIFEST_ID])\n\nfunction normalizeManifestId(id: string | null): string | null {\n\tif (!id) return null\n\treturn id.replace(MANIFEST_ID_PREFIX_PATTERN, '').toLowerCase()\n}\n\nfunction extractAssertionData(data: unknown): Record<string, unknown> | null {\n\tif (data !== null && typeof data === 'object' && !Array.isArray(data)) {\n\t\treturn data as Record<string, unknown>\n\t}\n\treturn null\n}\n\nfunction toUint8Array(value: unknown): Uint8Array | null {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\treturn null\n}\n\n// --- Live video assertion parsing ---\n\ntype LiveVideoFields = {\n\tsequenceNumber: number | null\n\tpreviousManifestId: string | null\n\tstreamId: string | null\n\tcontinuityMethod: string | null\n}\n\nfunction parseLiveVideoAssertion(assertions: readonly C2paAssertion[]): LiveVideoFields | null {\n\tconst assertion = assertions.find(a => a.label === LIVE_VIDEO_ASSERTION_LABEL)\n\tif (!assertion) return null\n\n\tconst data = extractAssertionData(assertion.data)\n\tconst rawSeq = data?.['sequenceNumber']\n\tconst rawPrev = data?.['previousManifestId']\n\tconst rawStreamId = data?.['streamId']\n\tconst rawContinuity = data?.['continuityMethod']\n\n\treturn {\n\t\tsequenceNumber: typeof rawSeq === 'number' ? rawSeq : null,\n\t\tpreviousManifestId: typeof rawPrev === 'string' ? rawPrev : null,\n\t\tstreamId: typeof rawStreamId === 'string' ? rawStreamId : null,\n\t\tcontinuityMethod: typeof rawContinuity === 'string' ? rawContinuity : null,\n\t}\n}\n\n// --- BMFF hash assertion parsing ---\n\ntype BmffHashFields = {\n\thashBytes: Uint8Array | null\n\thashHex: string | null\n\texclusions: readonly BmffHashExclusion[]\n\talg: string | null\n}\n\nconst EMPTY_BMFF_HASH: BmffHashFields = { hashBytes: null, hashHex: null, exclusions: [], alg: null }\n\nfunction parseConstraints(rawConstraints: unknown): BmffHashConstraint[] {\n\tif (!Array.isArray(rawConstraints)) return []\n\n\tconst constraints: BmffHashConstraint[] = []\n\tfor (const c of rawConstraints) {\n\t\tif (!c || typeof c !== 'object') continue\n\t\tconst record = c as Record<string, unknown>\n\t\tif (typeof record['offset'] !== 'number') continue\n\t\tconst value = toUint8Array(record['value'])\n\t\tif (value) constraints.push({ offset: record['offset'], value })\n\t}\n\treturn constraints\n}\n\nfunction parseExclusions(rawExclusions: unknown): BmffHashExclusion[] {\n\tif (!Array.isArray(rawExclusions)) return []\n\n\tconst exclusions: BmffHashExclusion[] = []\n\tfor (const exc of rawExclusions) {\n\t\tif (!exc || typeof exc !== 'object') continue\n\t\tconst record = exc as Record<string, unknown>\n\t\tif (typeof record['xpath'] !== 'string') continue\n\n\t\tconst constraints = parseConstraints(record['data'])\n\t\texclusions.push(constraints.length > 0 ? { xpath: record['xpath'], data: constraints } : { xpath: record['xpath'] })\n\t}\n\treturn exclusions\n}\n\nfunction parseBmffHashAssertion(assertions: readonly C2paAssertion[]): BmffHashFields {\n\tconst assertion = assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL)\n\tif (!assertion) return EMPTY_BMFF_HASH\n\n\tconst data = extractAssertionData(assertion.data)\n\tif (!data) return EMPTY_BMFF_HASH\n\n\tconst hashBytes = toUint8Array(data['hash'] ?? data['value'])\n\tconst hashHex = hashBytes ? bytesToHex(hashBytes) : null\n\tconst exclusions = parseExclusions(data['exclusions'])\n\tconst alg = typeof data['alg'] === 'string' ? normalizeAlgorithmName(data['alg']) : null\n\treturn { hashBytes, hashHex, exclusions, alg }\n}\n\n// --- Manifest parsing ---\n\ntype ParsedManifest = {\n\tmanifest: C2paManifest | null\n\tissuer: string | null\n\tliveVideo: LiveVideoFields | null\n\tbmff: BmffHashFields\n\tinternalData: InternalManifestData | null\n}\n\nfunction parseManifest(bytes: Uint8Array): ParsedManifest {\n\ttry {\n\t\tconst internalData = readC2paManifest(bytes)\n\t\tconst { manifest } = internalData\n\t\tif (!manifest) return { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH, internalData: null }\n\n\t\treturn {\n\t\t\tmanifest,\n\t\t\tissuer: manifest.signatureInfo?.issuer ?? null,\n\t\t\tliveVideo: parseLiveVideoAssertion(manifest.assertions),\n\t\t\tbmff: parseBmffHashAssertion(manifest.assertions),\n\t\t\tinternalData,\n\t\t}\n\t} catch {\n\t\treturn { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH, internalData: null }\n\t}\n}\n\n// --- Validation ---\n\nfunction collectErrorCodes(\n\thasManifest: boolean,\n\thasLiveVideo: boolean,\n\tstreamIdValid: boolean,\n\tsequenceNumberValid: boolean,\n\tbmffHashMatches: boolean,\n\tcontinuityMethod: string | null,\n\tpreviousManifestId: string | null,\n\tlastManifestId: string | null,\n): readonly LiveVideoStatusCode[] {\n\tconst codes = new Set<LiveVideoStatusCode>()\n\n\tif (!hasManifest) codes.add(LiveVideoStatusCode.MANIFEST_INVALID)\n\tif (!hasLiveVideo) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!streamIdValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!sequenceNumberValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!bmffHashMatches) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\n\tif (!continuityMethod) {\n\t\tcodes.add(LiveVideoStatusCode.CONTINUITY_METHOD_INVALID)\n\t} else if (!SUPPORTED_CONTINUITY_METHODS.has(continuityMethod)) {\n\t\tcodes.add(LiveVideoStatusCode.CONTINUITY_METHOD_INVALID)\n\t} else if (continuityMethod === CONTINUITY_METHOD_MANIFEST_ID) {\n\t\tif (!previousManifestId) {\n\t\t\tcodes.add(LiveVideoStatusCode.CONTINUITY_METHOD_INVALID)\n\t\t} else if (lastManifestId && normalizeManifestId(previousManifestId) !== normalizeManifestId(lastManifestId)) {\n\t\t\tcodes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\t\t}\n\t}\n\n\treturn [...codes]\n}\n\n/**\n * Validates a C2PA manifest-box live stream segment.\n *\n * Parses the C2PA manifest embedded in the segment and validates per §19.7.1 and §19.7.2.\n * Recomputes the `c2pa.hash.bmff.v3` content hash from the raw segment bytes and compares\n * it against the expected hash in the manifest assertion. Checks live-video assertions\n * (sequenceNumber, streamId, continuityMethod) and manifest-ID chain continuity.\n *\n * This function is **pure** — it does not access any external state. The\n * caller is responsible for persisting `nextManifestId` and `nextState`\n * between calls.\n *\n * @param bytes - Raw segment bytes\n * @param lastManifestId - Manifest ID from the previous segment, or null for the first segment\n * @param state - Optional state from the previous segment for streamId/sequenceNumber checks\n * @returns Validation result, the manifest ID, and state to persist for the next call\n *\n * @example\n * {@includeCode ../../test/manifestbox/validateC2paManifestBoxSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paManifestBoxSegment(\n\tbytes: Uint8Array,\n\tlastManifestId: string | null,\n\tstate?: ManifestBoxValidationState,\n): Promise<{\n\treadonly result: ManifestBoxValidationResult\n\treadonly nextManifestId: string | null\n\treadonly nextState: ManifestBoxValidationState\n}> {\n\tconst { manifest, issuer, liveVideo, bmff, internalData } = parseManifest(bytes)\n\n\tconst sequenceNumber = liveVideo?.sequenceNumber ?? null\n\tconst previousManifestId = liveVideo?.previousManifestId ?? null\n\tconst streamId = liveVideo?.streamId ?? null\n\tconst continuityMethod = liveVideo?.continuityMethod ?? null\n\n\tconst streamIdValid = state?.lastStreamId == null || streamId === state.lastStreamId\n\tconst sequenceNumberValid =\n\t\tstate?.lastSequenceNumber == null ||\n\t\t(sequenceNumber !== null && sequenceNumber > state.lastSequenceNumber)\n\n\tlet bmffHashMatches = true\n\tif (bmff.hashBytes !== null) {\n\t\tbmffHashMatches = await validateBmffHash(bytes, bmff.hashBytes, {\n\t\t\texclusions: bmff.exclusions,\n\t\t\talg: bmff.alg ?? undefined,\n\t\t})\n\t}\n\n\tconst liveVideoCodes = collectErrorCodes(\n\t\tmanifest !== null, liveVideo !== null,\n\t\tstreamIdValid, sequenceNumberValid, bmffHashMatches,\n\t\tcontinuityMethod, previousManifestId, lastManifestId,\n\t)\n\n\tconst integrityCodes: readonly C2paStatusCode[] = internalData\n\t\t? await validateManifestIntegrity(\n\t\t\tinternalData,\n\t\t\tinternalData.signatureBytes ? extractCertificateFromSignatureBytes(internalData.signatureBytes) : null,\n\t\t)\n\t\t: []\n\n\tconst errorCodes: (LiveVideoStatusCode | C2paStatusCode)[] = [...liveVideoCodes, ...integrityCodes]\n\n\tconst currentManifestId = manifest?.instanceId ?? null\n\n\treturn {\n\t\tresult: {\n\t\t\tmanifest: manifest ?? null,\n\t\t\tissuer,\n\t\t\tsequenceNumber,\n\t\t\tpreviousManifestId,\n\t\t\tstreamId,\n\t\t\tcontinuityMethod,\n\t\t\tbmffHashHex: bmff.hashHex,\n\t\t\tisValid: errorCodes.length === 0,\n\t\t\terrorCodes,\n\t\t},\n\t\tnextManifestId: currentManifestId ?? lastManifestId,\n\t\tnextState: {\n\t\t\tlastStreamId: streamId ?? state?.lastStreamId,\n\t\t\tlastSequenceNumber: sequenceNumber ?? state?.lastSequenceNumber,\n\t\t},\n\t}\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svta/cml-c2pa",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "C2PA (Coalition for Content Provenance and Authenticity) live video validation for BMFF/MP4 containers",
5
5
  "license": "Apache-2.0",
6
6
  "authors": [
@@ -20,6 +20,7 @@
20
20
  "publishConfig": {
21
21
  "access": "public",
22
22
  "registry": "https://registry.npmjs.org",
23
+ "provenance": true,
23
24
  "scope": "svta"
24
25
  },
25
26
  "files": [