feat(c2pa): custom continuity method support in manifest-box validation#54
Open
valentinamgiusti wants to merge 12 commits into
Open
feat(c2pa): custom continuity method support in manifest-box validation#54valentinamgiusti wants to merge 12 commits into
valentinamgiusti wants to merge 12 commits into
Conversation
valentinamgiusti
force-pushed
the
c2pa-custom-continuity
branch
3 times, most recently
from
July 17, 2026 15:41
22b821b to
9e4300c
Compare
valentinamgiusti
force-pushed
the
c2pa-merkle-validation
branch
from
July 17, 2026 15:41
6acec11 to
5fd7854
Compare
valentinamgiusti
force-pushed
the
c2pa-custom-continuity
branch
from
July 20, 2026 14:23
9e4300c to
52f82f4
Compare
valentinamgiusti
force-pushed
the
c2pa-merkle-validation
branch
from
July 20, 2026 14:27
31a2ac5 to
838effc
Compare
valentinamgiusti
force-pushed
the
c2pa-custom-continuity
branch
6 times, most recently
from
July 21, 2026 16:39
78f3bd9 to
b93e9de
Compare
Signed-off-by: Valentina <valentina.giusti@qualabs.com>
…dation Signed-off-by: Valentina <valentina.giusti@qualabs.com>
Signed-off-by: Valentina <valentina.giusti@qualabs.com>
Signed-off-by: Valentina <valentina.giusti@qualabs.com>
Signed-off-by: Valentina <valentina.giusti@qualabs.com>
CONTINUITY_METHOD_INVALID's description was stale: a broken c2pa.manifestId chain or a failed custom validator report SEGMENT_INVALID, not this code. Fix the table and note SEGMENT_INVALID's continuity-related sources too. Also move this PR's changelog entries from the 1.1.0 section (cut by streaming-video-technology-alliance#378's release commit) to Unreleased, since streaming-video-technology-alliance#378 may publish before this merges. Addresses review feedback on streaming-video-technology-alliance#379. Signed-off-by: Valentina <valentina.giusti@qualabs.com>
The existing custom-method tests patch a signed fixture in place, which breaks its hashedURI binding and always adds assertion.hashedURI.mismatch; none of them can reach isValid: true. Build an unsigned segment with its own matching c2pa.livevideo.segment and c2pa.hash.bmff.v3 assertions instead, so a registered validator can be exercised on a genuinely clean happy path. Addresses review feedback on streaming-video-technology-alliance#379. Signed-off-by: Valentina <valentina.giusti@qualabs.com>
valentinamgiusti
force-pushed
the
c2pa-custom-continuity
branch
from
July 21, 2026 17:46
15db728 to
b367fec
Compare
…echnology-alliance#387) Bump @microsoft/api-extractor 7.53.1 -> 7.58.12 (drops lodash entirely, pins patched minimatch 10.2.3) and eslint-plugin-tsdoc 0.4.0 -> 0.5.2 (moves to @microsoft/tsdoc-config 0.18.1 with patched ajv). All other fixes are lockfile-only updates within existing semver ranges. Fixes Dependabot alerts (all development-scope, package-lock.json): - js-yaml 4.1.0 -> 4.3.0 (streaming-video-technology-alliance#72 high, streaming-video-technology-alliance#69 medium, #31 medium) - brace-expansion 1.1.12 -> 1.1.16, 2.0.2 -> 2.1.2 (streaming-video-technology-alliance#70, streaming-video-technology-alliance#71 high) - ws 7.5.10 -> 7.5.13 (streaming-video-technology-alliance#66 high) - markdown-it 14.1.0 -> 14.3.0 (streaming-video-technology-alliance#65 medium) - lodash removed from tree (streaming-video-technology-alliance#63 high, streaming-video-technology-alliance#62 medium, #34 medium) - defu 6.1.4 -> 6.1.7 (streaming-video-technology-alliance#61 high) - picomatch 2.3.1 -> 2.3.2, 4.0.3 -> 4.0.5 (streaming-video-technology-alliance#58, streaming-video-technology-alliance#56 medium) - flatted 3.3.3 -> 3.4.2 (#54 high) - minimatch 3.1.2 -> 3.1.5, 9.0.5 -> 9.0.9, 10.0.3 -> 10.2.3 (#51, #49, #46 high) - rollup 4.52.5 -> 4.62.2 (#48 high) - koa 2.16.3 -> 2.16.4 (#47 high) - min-document 2.19.0 -> 2.19.2 (#29 low) Also clears remaining npm audit findings not yet surfaced as alerts: ajv ReDoS (GHSA-2g4f-4pwh-qvx6), diff DoS (GHSA-73rr-hh4g-fpgx), yaml stack overflow (GHSA-48c2-rrv3-qjmp). npm audit now reports 0 vulnerabilities. Signed-off-by: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…logy-alliance#378) * refactor(c2pa): extract shared exclusion parsing and uuid helpers Move parseExclusions to bmff/, and toUint8Array, asInteger, matchesUuid, JUMBF_UUID to utils so upcoming Merkle validation can reuse them. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * feat(c2pa): add VOD Merkle segment validation validateC2paMerkleSegment verifies fragmented MP4 media segments against the init manifest merkle maps (C2PA §15.12.2 / §18.6): parses the auxiliary uuid box (spec 2.4 and c2pa-rs formats), recomputes the leaf hash, walks the Merkle proof, and enforces location continuity via caller-held state. Adds status codes assertion.bmffHash.malformed / .mismatch. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * feat(c2pa): extract merkle maps in init segment validation validateC2paInitSegment reads the merkle field of the c2pa.hash.bmff.v3 assertion, validates each entry's initHash binding against the raw init bytes, and returns the maps as merkleMaps. VOD Merkle streams no longer report SESSIONKEY_INVALID. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * chore(c2pa): release 1.1.0 Changelog, version bump, and API report for VOD Merkle validation. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * docs(c2pa): shorten merkle validation comments Signed-off-by: Valentina <valentina.giusti@qualabs.com> * refactor(c2pa): move merkle map extraction to the merkle module Signed-off-by: Valentina <valentina.giusti@qualabs.com> * docs(c2pa): tighten validateC2paMerkleSegment doc comment Signed-off-by: Valentina <valentina.giusti@qualabs.com> * fix(c2pa): bound merkle proof path to the committed row and reject unconsumed hashes Bound the proof path against the committed manifest row instead of the full tree depth, and reject inputs that leave unconsumed proof hashes. Addresses review feedback on streaming-video-technology-alliance#378/streaming-video-technology-alliance#379. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * fix(c2pa): stop advancing merkle location state on discontinuity Only advance per-track location state when the location continuity check also passes, not just the Merkle proof. Addresses review feedback on streaming-video-technology-alliance#379. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * fix(c2pa): parse the spec-defined merkle auxiliary box format only Per §A.5.1.2/A.5.4.1.4, the auxiliary 'uuid' C2PA box for merkle data is the same ContentProvenanceBox used for the manifest box (version/ flags + null-terminated box_purpose + raw data), not a second box type with a bare CBOR map. Remove the fabricated MERKLE_AUX_UUID and its bare-CBOR-map parser, and the invented integer-key path in bmff-merkle-map (the CDDL only defines string keys). Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * fix(c2pa): tolerate fixed-size padding after the merkle CBOR item §A.5.4.1.4 requires padding auxiliary uuid boxes to a fixed size when a Merkle tree has more than one. cbor-x's decode() throws on trailing bytes, so a spec-conforming padded box was flagged malformed. Decode via decodeMultiple and stop after the first item instead. Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * fix(c2pa): flag malformed BMFF hash when merkle initHash or alg is missing Per the merkle-map CDDL, initHash is required for fragmented assets (the only case validateMerkleMaps handles), and alg has no default when absent from both the entry and the enclosing assertion. Both were previously tolerated silently: a missing initHash left the init segment unbound, and a missing alg defaulted to SHA-256. Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * refactor(c2pa): export and reuse BmffHashExclusion in MerkleMap BmffHashExclusion/BmffHashConstraint were already @public but not exported from the barrel, so MerkleMap.exclusions duplicated their shape inline. Export them and reuse the type to avoid drift. No runtime or shape change. Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * docs(c2pa): document merkle location state and its status code reuse Rename MerkleSegmentState.lastLocation to lastLocations (it's a map of per-track locations) and document the uniqueId:localId key format and the leniency on the first location seen per track. Also document that VOD Merkle reuses livevideo.assertion.invalid for per-track location discontinuity, which its §19.7.2 doc comment didn't cover. Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * docs(c2pa): fix BMFF hash status code citation and document them C2PA 2.3, which this package targets, has no Annex D — the failure code table lives at §15.2.2.3. Fix the citation on both BMFF hash codes, add them to results-and-error-codes.md, and note the SESSIONKEY_INVALID behavior change for VOD Merkle streams. Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * refactor(c2pa): require non-empty merkleMaps instead of returning null The only caller of this validator (SegmentRouter in the toolkit) already gates on merkleMaps.length > 0 before invoking it, so the null return for the empty case was dead weight at every call site. Document the precondition instead. Addresses review feedback on streaming-video-technology-alliance#378. BREAKING CHANGE: validateC2paMerkleSegment no longer returns null. Callers that branched on a null result should remove that check. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * fix(c2pa): resync merkle continuity after a proof-verified gap Freezing the location baseline on any discontinuity (to stop a replay from laundering itself as the new baseline) had a worse side effect: one out-of-order or dropped segment left every later segment flagged relative to a stale baseline for the rest of the session, even when those later segments were sequential among themselves. Advance the baseline on any segment whose Merkle proof verifies, discontinuous or not — it's genuinely signed content, so a forward gap resyncs immediately instead of cascading. A replayed/reordered segment is still flagged invalid at the point it occurs. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * refactor(c2pa): remove dead malformed-flag plumbing in aux box extraction readAuxPayload can only return a payload or 'other' since 5046af2 removed the bare-CBOR-map parser that used to signal 'malformed'; the flag was always false. Simplify extractMerkleAuxBoxes to return just the payloads array, and note the unplumbed claim-level alg fallback in validateMerkleMaps. Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * Update CHANGELOG with version 1.1.0 details Removed unreleased version section and added details for version 1.1.0. Signed-off-by: Casey Occhialini <1508707+littlespex@users.noreply.github.com> * chore(c2pa): revert manual version bump Version bumps go through a separate release script, not feature PRs. Addresses review feedback on streaming-video-technology-alliance#378/streaming-video-technology-alliance#379. Signed-off-by: Valentina <valentina.giusti@qualabs.com> * docs(c2pa): add VOD Merkle validation guide The README still described only the two segment-level validation methods and didn't link a dedicated guide for VOD Merkle, unlike VSI and Manifest Box. Add docs/merkle-validation.md following the same structure, and update the README's method list and doc links. Addresses review feedback on streaming-video-technology-alliance#378. Signed-off-by: Valentina <valentina.giusti@qualabs.com> --------- Signed-off-by: Valentina <valentina.giusti@qualabs.com> Signed-off-by: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Co-authored-by: Casey Occhialini <1508707+littlespex@users.noreply.github.com>
Signed-off-by: Casey Occhialini <1508707+littlespex@users.noreply.github.com>
…lback (streaming-video-technology-alliance#388) Fixes all five open code scanning alerts: - isCmcdCustomKey (alert #7): the ambiguous pattern /^[a-zA-Z0-9-.]+-[a-zA-Z0-9-.]+$/ backtracked quadratically on inputs like '---...-!'. Replaced with a single unambiguous character-class regex plus an interior-hyphen index check. Behavior is unchanged (verified by exhaustive sweep over all strings up to length 5). - iso8601DurationToNumber (alerts #4-6): the unanchored /([.,\d]+)H/ patterns rescanned from every start position, going quadratic on long digit/comma runs. Each pattern now requires a run boundary via a (?:^|[^.,\d]) prefix, which pins matches to the start of a number run and keeps scanning linear. Matches and captures are unchanged. - uuid (alert #3): the final fallback derived UUIDs from Math.random. It now uses crypto.getRandomValues with RFC 4122 version/variant bits, formatted through the existing arrayBufferToUuid helper. The blob URL trick remains as the last resort and Math.random is gone. This also fixes the fallback in Node, where blob URLs contain no slash and the previous code returned the whole blob: URL. Adversarial inputs of 50k characters drop from 4.7s / 14.2s to under 2ms, scaling linearly (10M chars in ~40ms). Signed-off-by: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds support for implementer-defined continuity methods (C2PA §19.3.2) in
validateC2paManifestBoxSegment:livevideo.continuityMethod.unsupportedstatus code, emitted alongside the spec-mandatedcontinuityMethod.invalid(§19.7.2) so consumers can distinguish an unverifiable custom method from a broken chain.continuityValidator: { method, validate }to register a validator for a custom method. The callback receives the decodedc2pa.livevideo.segmentassertion (with its method-specific fields) and the parsed manifest. The built-inc2pa.manifestIdmethod cannot be overridden.Motivated by third-party PSM streams (e.g. EZDRM's
com.ezdrm.anchor-chain) that validate as broken chain with no way to tell why.Stacked on #53: depends on its shared exclusion-parsing refactor. Changelog entries added to the 1.1.0 section alongside VOD Merkle.