@svta/cml-c2pa 1.4.0 → 1.4.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.
- package/dist/index.d.ts +248 -250
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +85 -106
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts.map
CHANGED
|
@@ -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/bmff/BmffHashExclusion.ts","../src/merkle/MerkleSegmentValidation.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","../src/merkle/validateC2paMerkleSegment.ts"],"
|
|
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/bmff/BmffHashExclusion.ts","../src/merkle/MerkleSegmentValidation.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","../src/merkle/validateC2paMerkleSegment.ts"],"mappings":";;;;;;;KAKY;WACF;WACA;;;;;;;;;KCFE;WACF;WACA;;;;;;;;;KCCE;WACF;WACA;WACA;WACA,eAAe;WACf,qBAAqB;;;;;;;;;;;;;;qBCDlB;;WAEZ;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;;;;;;YAQW,iBAAiB,eAAe;;;;;;;;;KCxChC;WACF;WACA;WACA;WACA;;;;;;;;;;;;;;qBCEG;;WAEZ;;WAEA;;WAEA;;;;;;WAMA;;WAEA;;WAEA;;WAEA;;;;;;;YAQW,sBAAsB,eAAe;;;;;;;;;KChCrC;WACF;WACA,OAAO;;;;;;;;;;;KAYL;WACF;WACA,gBAAgB;;;;;;;;;KCbd;WACF;WACA;WACA;WACA,iBAAiB;WACjB,UAAU;WACV;WACA,qBAAqB;WACrB;;;;;;;;;;;;;KAcE;WACF,eAAe;;;;;;;KAQb;WACF;WACA;WACA;WACA,sBAAsB,sBAAsB;;;;;;;;;;;;KC9B1C;WACF;WACA,KAAK;WACL;WACA;WACA;;;;;;;;;KAUE;WACF,UAAU;WACV,aAAa;WACb;WACA,sBAAsB;WACtB,qBAAqB;WACrB;WACA,sBAAsB,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBCiKhC,wBAAwB,OAAO,aAAa,QAAQ;;;;;;;;;;;;;;;;KCrL9D;WACF;WACA,eAAe;;;;;;;;;;;qBAYZ;;WAEZ;;WAEA;;WAEA;;WAEA;;WAEA;;;;;;;YAQW,2BAA2B,eAAe;;;;;;;;;KAU1C;WACE;WAAwB,eAAe,yBAAyB;;WAElE;WACA,eACC,yBAAyB,uCACzB,yBAAyB,mBACzB,yBAAyB;;WAG1B;WACA,eAAe,yBAAyB;WACxC;WACA;;;;;;;;;;;KC7DA;WACF;WACA;WACA;WACA;WACA,gBAAgB;WAChB;WACA,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;wBCwBT,oBACrB,cAAc,YACd,sBAAsB,uBACtB,gBAAe,gBACb;WAAmB,QAAQ;WAAkC,mBAAmB;;;;;;;;;;;KClCvE;WACF,UAAU;WACV;;WAEA,aAAa;WACb;WACA;WACA;WACA;WACA;WACA;WACA,sBAAsB,sBAAsB;;;;;;;KAQ1C,kCACX,oBAAoB,SAAS,0BAC7B,UAAU,2BACI;;;;;;KAOH;WACF;aACC;aACA,UAAU;;;;;;;;;;;KAYT;WACF;WACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBCwIY,+BACrB,OAAO,YACP,+BACA,QAAQ,4BACR,UAAU,+BACR;WACO,QAAQ;WACR;WACA,WAAW;;;;;;;;;;;;;;;;;;wBCWC,0BACrB,cAAc,YACd,qBAAqB,aACrB,QAAQ,qBACN;WACO,QAAQ;WACR,WAAW"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { findIsoBox, readEmsg, readIsoBoxes } from "@svta/cml-iso-bmff";
|
|
2
|
-
|
|
3
2
|
//#region src/cbor/readCborItem.ts
|
|
4
3
|
const TEXT_DECODER$4 = /* @__PURE__ */ new TextDecoder("utf-8", { ignoreBOM: true });
|
|
5
4
|
const MAJOR_UINT = 0;
|
|
@@ -218,7 +217,6 @@ function decodeCbor(bytes) {
|
|
|
218
217
|
if (item.end !== bytes.length) throw new RangeError("Trailing bytes after CBOR data item");
|
|
219
218
|
return item.value;
|
|
220
219
|
}
|
|
221
|
-
|
|
222
220
|
//#endregion
|
|
223
221
|
//#region src/LiveVideoStatusCode.ts
|
|
224
222
|
/**
|
|
@@ -232,15 +230,25 @@ function decodeCbor(bytes) {
|
|
|
232
230
|
* @public
|
|
233
231
|
*/
|
|
234
232
|
const LiveVideoStatusCode = {
|
|
233
|
+
/** Init segment contains an `mdat` box (§19.7.1) */
|
|
235
234
|
INIT_INVALID: "livevideo.init.invalid",
|
|
235
|
+
/** C2PA Manifest Box failed standard validation (§19.7.1) */
|
|
236
236
|
MANIFEST_INVALID: "livevideo.manifest.invalid",
|
|
237
|
+
/** Segment invalid: missing Manifest Box/emsg, signature/hash/key failure, or session key outside its validity period (§19.7) */
|
|
237
238
|
SEGMENT_INVALID: "livevideo.segment.invalid",
|
|
239
|
+
/**
|
|
240
|
+
* Live video assertion field invalid: sequenceNumber or streamId mismatch
|
|
241
|
+
* (§19.7.2). Also reused for VOD Merkle per-track location discontinuity
|
|
242
|
+
* (§15.12.2), which has no dedicated code.
|
|
243
|
+
*/
|
|
238
244
|
ASSERTION_INVALID: "livevideo.assertion.invalid",
|
|
245
|
+
/** continuityMethod absent, unsupported, or companion fields incorrect (§19.7.2) */
|
|
239
246
|
CONTINUITY_METHOD_INVALID: "livevideo.continuityMethod.invalid",
|
|
247
|
+
/** Custom continuityMethod with no registered validator (§19.7.2) */
|
|
240
248
|
CONTINUITY_METHOD_UNSUPPORTED: "livevideo.continuityMethod.unsupported",
|
|
249
|
+
/** Session key invalid: signerBinding failed or required fields absent (§19.7.3) */
|
|
241
250
|
SESSIONKEY_INVALID: "livevideo.sessionkey.invalid"
|
|
242
251
|
};
|
|
243
|
-
|
|
244
252
|
//#endregion
|
|
245
253
|
//#region src/cbor/projectCborTags.ts
|
|
246
254
|
const TAG_DATE_TIME_STRING = 0;
|
|
@@ -288,7 +296,6 @@ function projectCborTags(value) {
|
|
|
288
296
|
}
|
|
289
297
|
return value;
|
|
290
298
|
}
|
|
291
|
-
|
|
292
299
|
//#endregion
|
|
293
300
|
//#region src/C2paStatusCode.ts
|
|
294
301
|
/**
|
|
@@ -302,21 +309,33 @@ function projectCborTags(value) {
|
|
|
302
309
|
* @public
|
|
303
310
|
*/
|
|
304
311
|
const C2paStatusCode = {
|
|
312
|
+
/** Assertion hash does not match the hashed URI in the claim (§15.10.3.1) */
|
|
305
313
|
ASSERTION_HASHEDURI_MISMATCH: "assertion.hashedURI.mismatch",
|
|
314
|
+
/** The assertion store has no box for a claim reference, or more than one box for its label (§8.4.1, §15.10.3.1) */
|
|
306
315
|
ASSERTION_MISSING: "assertion.missing",
|
|
316
|
+
/** The manifest has more than one hard binding assertion (§9.1, §15.10.1.2) */
|
|
307
317
|
ASSERTION_MULTIPLE_HARD_BINDINGS: "assertion.multipleHardBindings",
|
|
318
|
+
/** The assertion store holds an assertion that the claim does not reference (§15.10.3.1) */
|
|
308
319
|
ASSERTION_UNDECLARED: "assertion.undeclared",
|
|
320
|
+
/** An action requiring an ingredient reference does not have one (§18.15.4.7) */
|
|
309
321
|
ASSERTION_ACTION_INGREDIENT_MISMATCH: "assertion.action.ingredientMismatch",
|
|
322
|
+
/** Claim signature verification failed, or the signature carries no certificate (§15.7) */
|
|
310
323
|
CLAIM_SIGNATURE_MISMATCH: "claimSignature.mismatch",
|
|
324
|
+
/** The manifest has no `c2pa.signature` box, so the claim signature cannot be found (§15.7) */
|
|
311
325
|
CLAIM_SIGNATURE_MISSING: "claimSignature.missing",
|
|
326
|
+
/** The manifest has no claim box (§15.6.1) */
|
|
312
327
|
CLAIM_MISSING: "claim.missing",
|
|
328
|
+
/** The claim box holds CBOR that does not decode (§15.6.2) */
|
|
313
329
|
CLAIM_CBOR_INVALID: "claim.cbor.invalid",
|
|
330
|
+
/** The claim box holds CBOR that is not a map (§15.6.2). The library does not check the fields of the claim. */
|
|
314
331
|
CLAIM_MALFORMED: "claim.malformed",
|
|
332
|
+
/** The manifest has more than one claim box (§15.6.1) */
|
|
315
333
|
CLAIM_MULTIPLE: "claim.multiple",
|
|
334
|
+
/** BMFF hash assertion or Merkle structure is malformed (§15.2.2.3) */
|
|
316
335
|
ASSERTION_BMFFHASH_MALFORMED: "assertion.bmffHash.malformed",
|
|
336
|
+
/** BMFF content hash does not match the committed value (§15.2.2.3) */
|
|
317
337
|
ASSERTION_BMFFHASH_MISMATCH: "assertion.bmffHash.mismatch"
|
|
318
338
|
};
|
|
319
|
-
|
|
320
339
|
//#endregion
|
|
321
340
|
//#region src/cose/decodeCoseSign1.ts
|
|
322
341
|
const COSE_SIGN1_TAG = 18;
|
|
@@ -368,7 +387,6 @@ function decodeCoseSign1(coseBytes) {
|
|
|
368
387
|
throw new Error(`Failed to decode COSE_Sign1: ${error.message}`);
|
|
369
388
|
}
|
|
370
389
|
}
|
|
371
|
-
|
|
372
390
|
//#endregion
|
|
373
391
|
//#region src/jumbf/parseJumbfBoxes.ts
|
|
374
392
|
/**
|
|
@@ -391,11 +409,9 @@ function parseJumbfBoxes(bytes) {
|
|
|
391
409
|
data: box.view.readData(box.view.bytesRemaining)
|
|
392
410
|
}));
|
|
393
411
|
}
|
|
394
|
-
|
|
395
412
|
//#endregion
|
|
396
413
|
//#region src/jumbf/parseJumbfLabel.ts
|
|
397
414
|
const TEXT_DECODER$3 = /* @__PURE__ */ new TextDecoder();
|
|
398
|
-
const JUMD_UUID_SIZE = 16;
|
|
399
415
|
const JUMD_TOGGLES_OFFSET = 16;
|
|
400
416
|
const JUMD_LABEL_START = 17;
|
|
401
417
|
const LABEL_FLAG_MASK = 3;
|
|
@@ -415,14 +431,13 @@ const LABEL_FLAG_EXPECTED = 3;
|
|
|
415
431
|
* @internal
|
|
416
432
|
*/
|
|
417
433
|
function parseJumbfLabel(jumdData) {
|
|
418
|
-
if (jumdData.length <
|
|
434
|
+
if (jumdData.length < 17) return null;
|
|
419
435
|
if ((jumdData[JUMD_TOGGLES_OFFSET] & LABEL_FLAG_MASK) !== LABEL_FLAG_EXPECTED) return null;
|
|
420
436
|
let end = JUMD_LABEL_START;
|
|
421
437
|
while (end < jumdData.length && jumdData[end] !== 0) end++;
|
|
422
438
|
if (end >= jumdData.length) return null;
|
|
423
439
|
return TEXT_DECODER$3.decode(jumdData.subarray(JUMD_LABEL_START, end));
|
|
424
440
|
}
|
|
425
|
-
|
|
426
441
|
//#endregion
|
|
427
442
|
//#region src/utils.ts
|
|
428
443
|
const MILLISECONDS_PER_SECOND = 1e3;
|
|
@@ -572,21 +587,8 @@ function stripJumbfUuidPrefix(payload) {
|
|
|
572
587
|
if (!prefix || prefix.rest.length < AUX_UUID_OFFSET_SIZE) return null;
|
|
573
588
|
return prefix.rest.subarray(AUX_UUID_OFFSET_SIZE);
|
|
574
589
|
}
|
|
575
|
-
|
|
576
590
|
//#endregion
|
|
577
591
|
//#region src/x509/asn1.ts
|
|
578
|
-
/**
|
|
579
|
-
* Minimal ASN.1 DER parsing helpers for X.509 certificate navigation.
|
|
580
|
-
*
|
|
581
|
-
* @internal
|
|
582
|
-
*/
|
|
583
|
-
const ASN1_TAG_INTEGER = 2;
|
|
584
|
-
const ASN1_TAG_OBJECT_IDENTIFIER = 6;
|
|
585
|
-
const ASN1_TAG_SEQUENCE = 48;
|
|
586
|
-
const ASN1_TAG_SET = 49;
|
|
587
|
-
const ASN1_TAG_UTC_TIME = 23;
|
|
588
|
-
const ASN1_TAG_GENERALIZED_TIME = 24;
|
|
589
|
-
const ASN1_TAG_CONTEXT_0 = 160;
|
|
590
592
|
const ASN1_LONG_FORM_FLAG = 128;
|
|
591
593
|
const ASN1_LONG_FORM_MASK = 127;
|
|
592
594
|
function readLength(bytes, offset) {
|
|
@@ -630,7 +632,6 @@ function readElementRaw(bytes, offset) {
|
|
|
630
632
|
if (!el) return null;
|
|
631
633
|
return bytes.subarray(offset, offset + el.totalSize);
|
|
632
634
|
}
|
|
633
|
-
|
|
634
635
|
//#endregion
|
|
635
636
|
//#region src/x509/extractCertificateInfo.ts
|
|
636
637
|
const TEXT_DECODER$1 = /* @__PURE__ */ new TextDecoder();
|
|
@@ -651,16 +652,16 @@ function matchesOID(value, oid) {
|
|
|
651
652
|
}
|
|
652
653
|
function parseTime(element) {
|
|
653
654
|
const text = TEXT_DECODER$1.decode(element.value);
|
|
654
|
-
if (element.tag ===
|
|
655
|
+
if (element.tag === 23) {
|
|
655
656
|
const yy = parseInt(text.substring(0, 2), 10);
|
|
656
657
|
return `${yy >= 50 ? 1900 + yy : 2e3 + yy}-${text.substring(2, 4)}-${text.substring(4, 6)}T${text.substring(6, 8)}:${text.substring(8, 10)}:${text.substring(10, 12)}Z`;
|
|
657
658
|
}
|
|
658
|
-
if (element.tag ===
|
|
659
|
+
if (element.tag === 24) return `${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`;
|
|
659
660
|
return null;
|
|
660
661
|
}
|
|
661
662
|
function findOidValueInSequence(seqValue, targetOID) {
|
|
662
663
|
const oidEl = readElement(seqValue, 0);
|
|
663
|
-
if (!oidEl || oidEl.tag !==
|
|
664
|
+
if (!oidEl || oidEl.tag !== 6) return null;
|
|
664
665
|
if (!matchesOID(oidEl.value, targetOID)) return null;
|
|
665
666
|
const valEl = readElement(seqValue, oidEl.totalSize);
|
|
666
667
|
return valEl ? TEXT_DECODER$1.decode(valEl.value) : null;
|
|
@@ -669,11 +670,11 @@ function findRDNValue(issuerValue, targetOID) {
|
|
|
669
670
|
let offset = 0;
|
|
670
671
|
while (offset < issuerValue.length) {
|
|
671
672
|
const setEl = readElement(issuerValue, offset);
|
|
672
|
-
if (!setEl || setEl.tag !==
|
|
673
|
+
if (!setEl || setEl.tag !== 49) break;
|
|
673
674
|
let setOffset = 0;
|
|
674
675
|
while (setOffset < setEl.value.length) {
|
|
675
676
|
const seqEl = readElement(setEl.value, setOffset);
|
|
676
|
-
if (!seqEl || seqEl.tag !==
|
|
677
|
+
if (!seqEl || seqEl.tag !== 48) break;
|
|
677
678
|
const found = findOidValueInSequence(seqEl.value, targetOID);
|
|
678
679
|
if (found) return found;
|
|
679
680
|
setOffset += seqEl.totalSize;
|
|
@@ -700,29 +701,29 @@ function findRDNValue(issuerValue, targetOID) {
|
|
|
700
701
|
function extractCertificateInfo(certDER) {
|
|
701
702
|
try {
|
|
702
703
|
const cert = readElement(certDER, 0);
|
|
703
|
-
if (!cert || cert.tag !==
|
|
704
|
+
if (!cert || cert.tag !== 48) return null;
|
|
704
705
|
const tbs = readElement(cert.value, 0);
|
|
705
|
-
if (!tbs || tbs.tag !==
|
|
706
|
+
if (!tbs || tbs.tag !== 48) return null;
|
|
706
707
|
let offset = 0;
|
|
707
708
|
let el = readElement(tbs.value, offset);
|
|
708
709
|
if (!el) return null;
|
|
709
|
-
if (el.tag ===
|
|
710
|
+
if (el.tag === 160) {
|
|
710
711
|
offset += el.totalSize;
|
|
711
712
|
el = readElement(tbs.value, offset);
|
|
712
713
|
if (!el) return null;
|
|
713
714
|
}
|
|
714
|
-
if (el.tag !==
|
|
715
|
+
if (el.tag !== 2) return null;
|
|
715
716
|
offset += el.totalSize;
|
|
716
717
|
el = readElement(tbs.value, offset);
|
|
717
|
-
if (!el || el.tag !==
|
|
718
|
+
if (!el || el.tag !== 48) return null;
|
|
718
719
|
offset += el.totalSize;
|
|
719
720
|
el = readElement(tbs.value, offset);
|
|
720
|
-
if (!el || el.tag !==
|
|
721
|
+
if (!el || el.tag !== 48) return null;
|
|
721
722
|
const issuer = findRDNValue(el.value, OID_COMMON_NAME) ?? findRDNValue(el.value, OID_ORG_NAME) ?? "Unknown Issuer";
|
|
722
723
|
offset += el.totalSize;
|
|
723
724
|
el = readElement(tbs.value, offset);
|
|
724
725
|
let notBefore = null;
|
|
725
|
-
if (el && el.tag ===
|
|
726
|
+
if (el && el.tag === 48) {
|
|
726
727
|
const timeEl = readElement(el.value, 0);
|
|
727
728
|
if (timeEl) notBefore = parseTime(timeEl);
|
|
728
729
|
}
|
|
@@ -734,7 +735,6 @@ function extractCertificateInfo(certDER) {
|
|
|
734
735
|
return null;
|
|
735
736
|
}
|
|
736
737
|
}
|
|
737
|
-
|
|
738
738
|
//#endregion
|
|
739
739
|
//#region src/readC2paManifest.ts
|
|
740
740
|
const TEXT_DECODER = /* @__PURE__ */ new TextDecoder();
|
|
@@ -774,18 +774,20 @@ function parseAssertionsInternal(assertionStoreBoxes) {
|
|
|
774
774
|
const contentBox = inner.find((b) => b.type === "cbor" || b.type === "json" || b.type === "jumc" || b.type === "jp2c" || b.type === "bidb");
|
|
775
775
|
let data = null;
|
|
776
776
|
let taggedData;
|
|
777
|
-
if (contentBox)
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
777
|
+
if (contentBox) {
|
|
778
|
+
if (contentBox.type === "cbor") try {
|
|
779
|
+
taggedData = decodeCbor(contentBox.data);
|
|
780
|
+
data = projectCborTags(taggedData);
|
|
781
|
+
} catch {
|
|
782
|
+
data = contentBox.data;
|
|
783
|
+
}
|
|
784
|
+
else if (contentBox.type === "json") try {
|
|
785
|
+
data = JSON.parse(TEXT_DECODER.decode(contentBox.data));
|
|
786
|
+
} catch {
|
|
787
|
+
data = contentBox.data;
|
|
788
|
+
}
|
|
789
|
+
else data = contentBox.data;
|
|
787
790
|
}
|
|
788
|
-
else data = contentBox.data;
|
|
789
791
|
assertions.push({
|
|
790
792
|
label,
|
|
791
793
|
data,
|
|
@@ -861,7 +863,7 @@ function extractClaimAssertionRefs(claimData) {
|
|
|
861
863
|
if (!url || hash == null) continue;
|
|
862
864
|
refs.push({
|
|
863
865
|
url,
|
|
864
|
-
hash: hash instanceof Uint8Array ? hash : new Uint8Array(0),
|
|
866
|
+
hash: hash instanceof Uint8Array ? hash : /* @__PURE__ */ new Uint8Array(0),
|
|
865
867
|
alg: e["alg"] ?? null
|
|
866
868
|
});
|
|
867
869
|
}
|
|
@@ -963,7 +965,6 @@ function readC2paManifest(bytes, preParsedBoxes) {
|
|
|
963
965
|
assertions: internalAssertions
|
|
964
966
|
};
|
|
965
967
|
}
|
|
966
|
-
|
|
967
968
|
//#endregion
|
|
968
969
|
//#region src/bmff/shouldExcludeBox.ts
|
|
969
970
|
function bytesMatchAt(boxData, offset, expected) {
|
|
@@ -1002,7 +1003,6 @@ function shouldExcludeBox(boxType, boxData, exclusions) {
|
|
|
1002
1003
|
}
|
|
1003
1004
|
return false;
|
|
1004
1005
|
}
|
|
1005
|
-
|
|
1006
1006
|
//#endregion
|
|
1007
1007
|
//#region src/bmff/computeBmffHash.ts
|
|
1008
1008
|
const MINIMUM_BOX_SIZE = 8;
|
|
@@ -1068,7 +1068,6 @@ async function computeBmffHash(segmentBytes, options) {
|
|
|
1068
1068
|
const hashBuffer = await crypto.subtle.digest(alg, hashInput);
|
|
1069
1069
|
return new Uint8Array(hashBuffer);
|
|
1070
1070
|
}
|
|
1071
|
-
|
|
1072
1071
|
//#endregion
|
|
1073
1072
|
//#region src/bmff/parseExclusions.ts
|
|
1074
1073
|
function isMap(value) {
|
|
@@ -1117,7 +1116,6 @@ function parseExclusions(rawExclusions) {
|
|
|
1117
1116
|
}
|
|
1118
1117
|
return exclusions;
|
|
1119
1118
|
}
|
|
1120
|
-
|
|
1121
1119
|
//#endregion
|
|
1122
1120
|
//#region src/extractManifestCertificate.ts
|
|
1123
1121
|
const X5CHAIN_COSE_HEADER = 33;
|
|
@@ -1137,11 +1135,10 @@ function extractCertificateFromSignatureBytes(signatureBytes) {
|
|
|
1137
1135
|
return null;
|
|
1138
1136
|
}
|
|
1139
1137
|
}
|
|
1140
|
-
|
|
1141
1138
|
//#endregion
|
|
1142
1139
|
//#region src/claim/validateActionIngredients.ts
|
|
1143
|
-
const ACTIONS_LABELS = new Set(["c2pa.actions", "c2pa.actions.v2"]);
|
|
1144
|
-
const ACTIONS_REQUIRING_INGREDIENTS = new Set([
|
|
1140
|
+
const ACTIONS_LABELS = /* @__PURE__ */ new Set(["c2pa.actions", "c2pa.actions.v2"]);
|
|
1141
|
+
const ACTIONS_REQUIRING_INGREDIENTS = /* @__PURE__ */ new Set([
|
|
1145
1142
|
"c2pa.opened",
|
|
1146
1143
|
"c2pa.placed",
|
|
1147
1144
|
"c2pa.removed"
|
|
@@ -1178,7 +1175,6 @@ function validateActionIngredients(assertions) {
|
|
|
1178
1175
|
}
|
|
1179
1176
|
return codes;
|
|
1180
1177
|
}
|
|
1181
|
-
|
|
1182
1178
|
//#endregion
|
|
1183
1179
|
//#region src/claim/validateAssertionHashes.ts
|
|
1184
1180
|
/**
|
|
@@ -1255,7 +1251,6 @@ async function validateAssertionHashes(claimRefs, assertions) {
|
|
|
1255
1251
|
verified
|
|
1256
1252
|
};
|
|
1257
1253
|
}
|
|
1258
|
-
|
|
1259
1254
|
//#endregion
|
|
1260
1255
|
//#region src/cose/constants.ts
|
|
1261
1256
|
const ECDSA_ALGORITHM = "ECDSA";
|
|
@@ -1267,10 +1262,9 @@ const CURVE_P521 = "P-521";
|
|
|
1267
1262
|
const HASH_SHA256 = "SHA-256";
|
|
1268
1263
|
const HASH_SHA384 = "SHA-384";
|
|
1269
1264
|
const HASH_SHA512 = "SHA-512";
|
|
1270
|
-
|
|
1271
1265
|
//#endregion
|
|
1272
1266
|
//#region src/cose/resolveAlgorithmFromCoseAlg.ts
|
|
1273
|
-
const COSE_ALGORITHM_MAP = new Map([
|
|
1267
|
+
const COSE_ALGORITHM_MAP = /* @__PURE__ */ new Map([
|
|
1274
1268
|
[-7, {
|
|
1275
1269
|
name: ECDSA_ALGORITHM,
|
|
1276
1270
|
namedCurve: CURVE_P256
|
|
@@ -1312,7 +1306,6 @@ function resolveAlgorithmFromCoseAlg(coseAlg) {
|
|
|
1312
1306
|
if (!algorithm) throw new Error(`Unsupported COSE algorithm: ${coseAlg}`);
|
|
1313
1307
|
return algorithm;
|
|
1314
1308
|
}
|
|
1315
|
-
|
|
1316
1309
|
//#endregion
|
|
1317
1310
|
//#region src/cose/buildSigStructure.ts
|
|
1318
1311
|
const CBOR_ARRAY_FOUR_ITEMS = 132;
|
|
@@ -1364,7 +1357,7 @@ function writeByteStringHeader(output, offset, length) {
|
|
|
1364
1357
|
*
|
|
1365
1358
|
* @public
|
|
1366
1359
|
*/
|
|
1367
|
-
function buildSigStructure(protectedBytes, payload, externalAad = new Uint8Array(0)) {
|
|
1360
|
+
function buildSigStructure(protectedBytes, payload, externalAad = /* @__PURE__ */ new Uint8Array(0)) {
|
|
1368
1361
|
const totalLength = 2 + COSE_SIG1_CONTEXT_BYTES.length + byteStringHeaderSize(protectedBytes.length) + protectedBytes.length + byteStringHeaderSize(externalAad.length) + externalAad.length + byteStringHeaderSize(payload.length) + payload.length;
|
|
1369
1362
|
const result = new Uint8Array(totalLength);
|
|
1370
1363
|
let offset = 0;
|
|
@@ -1395,7 +1388,6 @@ function encodeCborByteString(bytes) {
|
|
|
1395
1388
|
result.set(bytes, writeByteStringHeader(result, 0, bytes.length));
|
|
1396
1389
|
return result;
|
|
1397
1390
|
}
|
|
1398
|
-
|
|
1399
1391
|
//#endregion
|
|
1400
1392
|
//#region src/cose/verifyCoseSign1.ts
|
|
1401
1393
|
const DER_SEQUENCE_TAG = 48;
|
|
@@ -1462,22 +1454,25 @@ function derToRawEcdsaSignature(der, componentSize) {
|
|
|
1462
1454
|
}
|
|
1463
1455
|
function resolveVerifyAlgorithm(publicKey) {
|
|
1464
1456
|
const { name } = publicKey.algorithm;
|
|
1465
|
-
if (name ===
|
|
1466
|
-
if (name ===
|
|
1457
|
+
if (name === "Ed25519") return { name: ED25519_ALGORITHM };
|
|
1458
|
+
if (name === "ECDSA") {
|
|
1467
1459
|
const curve = publicKey.algorithm.namedCurve;
|
|
1468
1460
|
return {
|
|
1469
1461
|
name: ECDSA_ALGORITHM,
|
|
1470
|
-
hash: { name: curve ===
|
|
1462
|
+
hash: { name: curve === "P-384" ? HASH_SHA384 : curve === "P-521" ? HASH_SHA512 : HASH_SHA256 }
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
if (name === "RSA-PSS") {
|
|
1466
|
+
const hashName = publicKey.algorithm.hash.name;
|
|
1467
|
+
return {
|
|
1468
|
+
name: RSA_PSS_ALGORITHM,
|
|
1469
|
+
saltLength: RSA_PSS_SALT_LENGTH[hashName] ?? 32
|
|
1471
1470
|
};
|
|
1472
1471
|
}
|
|
1473
|
-
if (name === RSA_PSS_ALGORITHM) return {
|
|
1474
|
-
name: RSA_PSS_ALGORITHM,
|
|
1475
|
-
saltLength: RSA_PSS_SALT_LENGTH[publicKey.algorithm.hash.name] ?? 32
|
|
1476
|
-
};
|
|
1477
1472
|
throw new Error(`Unsupported public key algorithm: ${name}`);
|
|
1478
1473
|
}
|
|
1479
1474
|
function normalizeSignature(signature, publicKey) {
|
|
1480
|
-
if (publicKey.algorithm.name !==
|
|
1475
|
+
if (publicKey.algorithm.name !== "ECDSA") return signature;
|
|
1481
1476
|
const componentSize = getComponentSize(publicKey);
|
|
1482
1477
|
if (isDerEncoded(signature, componentSize * 2)) return derToRawEcdsaSignature(signature, componentSize);
|
|
1483
1478
|
return signature;
|
|
@@ -1508,7 +1503,6 @@ async function verifyCoseSign1(coseSign1, payload, publicKey) {
|
|
|
1508
1503
|
const signature = normalizeSignature(coseSign1.signature, publicKey);
|
|
1509
1504
|
return crypto.subtle.verify(algorithm, publicKey, signature, sigStructure);
|
|
1510
1505
|
}
|
|
1511
|
-
|
|
1512
1506
|
//#endregion
|
|
1513
1507
|
//#region src/x509/extractCertificateSpki.ts
|
|
1514
1508
|
/**
|
|
@@ -1529,37 +1523,36 @@ async function verifyCoseSign1(coseSign1, payload, publicKey) {
|
|
|
1529
1523
|
function extractCertificateSpki(certDER) {
|
|
1530
1524
|
try {
|
|
1531
1525
|
const cert = readElement(certDER, 0);
|
|
1532
|
-
if (!cert || cert.tag !==
|
|
1526
|
+
if (!cert || cert.tag !== 48) return null;
|
|
1533
1527
|
const tbs = readElement(cert.value, 0);
|
|
1534
|
-
if (!tbs || tbs.tag !==
|
|
1528
|
+
if (!tbs || tbs.tag !== 48) return null;
|
|
1535
1529
|
let offset = 0;
|
|
1536
1530
|
let el = readElement(tbs.value, offset);
|
|
1537
1531
|
if (!el) return null;
|
|
1538
|
-
if (el.tag ===
|
|
1532
|
+
if (el.tag === 160) {
|
|
1539
1533
|
offset += el.totalSize;
|
|
1540
1534
|
el = readElement(tbs.value, offset);
|
|
1541
1535
|
if (!el) return null;
|
|
1542
1536
|
}
|
|
1543
|
-
if (el.tag !==
|
|
1537
|
+
if (el.tag !== 2) return null;
|
|
1544
1538
|
offset += el.totalSize;
|
|
1545
1539
|
el = readElement(tbs.value, offset);
|
|
1546
|
-
if (!el || el.tag !==
|
|
1540
|
+
if (!el || el.tag !== 48) return null;
|
|
1547
1541
|
offset += el.totalSize;
|
|
1548
1542
|
el = readElement(tbs.value, offset);
|
|
1549
|
-
if (!el || el.tag !==
|
|
1543
|
+
if (!el || el.tag !== 48) return null;
|
|
1550
1544
|
offset += el.totalSize;
|
|
1551
1545
|
el = readElement(tbs.value, offset);
|
|
1552
|
-
if (!el || el.tag !==
|
|
1546
|
+
if (!el || el.tag !== 48) return null;
|
|
1553
1547
|
offset += el.totalSize;
|
|
1554
1548
|
el = readElement(tbs.value, offset);
|
|
1555
|
-
if (!el || el.tag !==
|
|
1549
|
+
if (!el || el.tag !== 48) return null;
|
|
1556
1550
|
offset += el.totalSize;
|
|
1557
1551
|
return readElementRaw(tbs.value, offset);
|
|
1558
1552
|
} catch {
|
|
1559
1553
|
return null;
|
|
1560
1554
|
}
|
|
1561
1555
|
}
|
|
1562
|
-
|
|
1563
1556
|
//#endregion
|
|
1564
1557
|
//#region src/x509/normalizeRsaPssSpki.ts
|
|
1565
1558
|
const OID_RSASSA_PSS = /* @__PURE__ */ new Uint8Array([
|
|
@@ -1616,15 +1609,15 @@ function containsRsaPssOid(bytes) {
|
|
|
1616
1609
|
function normalizeRsaPssSpki(spkiBytes) {
|
|
1617
1610
|
if (!containsRsaPssOid(spkiBytes)) return spkiBytes;
|
|
1618
1611
|
const outer = readElement(spkiBytes, 0);
|
|
1619
|
-
if (!outer || outer.tag !==
|
|
1612
|
+
if (!outer || outer.tag !== 48) return spkiBytes;
|
|
1620
1613
|
const algId = readElement(outer.value, 0);
|
|
1621
|
-
if (!algId || algId.tag !==
|
|
1614
|
+
if (!algId || algId.tag !== 48) return spkiBytes;
|
|
1622
1615
|
const publicKeyBitString = outer.value.subarray(algId.totalSize);
|
|
1623
1616
|
const innerLength = RSA_ENCRYPTION_ALGORITHM_ID.length + publicKeyBitString.length;
|
|
1624
1617
|
const headerBytes = encodeDerLength(innerLength);
|
|
1625
1618
|
const result = new Uint8Array(1 + headerBytes.length + innerLength);
|
|
1626
1619
|
let offset = 0;
|
|
1627
|
-
result[offset++] =
|
|
1620
|
+
result[offset++] = 48;
|
|
1628
1621
|
result.set(headerBytes, offset);
|
|
1629
1622
|
offset += headerBytes.length;
|
|
1630
1623
|
result.set(RSA_ENCRYPTION_ALGORITHM_ID, offset);
|
|
@@ -1647,7 +1640,6 @@ function encodeDerLength(length) {
|
|
|
1647
1640
|
length & 255
|
|
1648
1641
|
]);
|
|
1649
1642
|
}
|
|
1650
|
-
|
|
1651
1643
|
//#endregion
|
|
1652
1644
|
//#region src/claim/verifyClaimSignature.ts
|
|
1653
1645
|
/**
|
|
@@ -1677,7 +1669,6 @@ async function verifyClaimSignature(signatureBytes, claimCborBytes, certificateD
|
|
|
1677
1669
|
return false;
|
|
1678
1670
|
}
|
|
1679
1671
|
}
|
|
1680
|
-
|
|
1681
1672
|
//#endregion
|
|
1682
1673
|
//#region src/claim/validateManifestIntegrity.ts
|
|
1683
1674
|
const HARD_BINDING_LABELS = /* @__PURE__ */ new Set([
|
|
@@ -1753,7 +1744,6 @@ async function validateManifestIntegrity(internal) {
|
|
|
1753
1744
|
verifiedAssertions: assertionHashes.verified
|
|
1754
1745
|
};
|
|
1755
1746
|
}
|
|
1756
|
-
|
|
1757
1747
|
//#endregion
|
|
1758
1748
|
//#region src/cose/convertCoseKeyToJwk.ts
|
|
1759
1749
|
const OKP_KEY_TYPE = 1;
|
|
@@ -1819,7 +1809,6 @@ function convertCoseKeyToJwk(coseKey) {
|
|
|
1819
1809
|
}
|
|
1820
1810
|
throw new Error(`Unsupported COSE key type: ${kty}`);
|
|
1821
1811
|
}
|
|
1822
|
-
|
|
1823
1812
|
//#endregion
|
|
1824
1813
|
//#region src/cose/resolveImportAlgorithm.ts
|
|
1825
1814
|
const KEY_TYPE_OKP = "OKP";
|
|
@@ -1829,7 +1818,6 @@ function resolveImportAlgorithm(jwk) {
|
|
|
1829
1818
|
namedCurve: jwk.crv
|
|
1830
1819
|
};
|
|
1831
1820
|
}
|
|
1832
|
-
|
|
1833
1821
|
//#endregion
|
|
1834
1822
|
//#region src/cose/verifySignerBinding.ts
|
|
1835
1823
|
async function verifyPayload(coseSign1, payload, publicKey) {
|
|
@@ -1864,7 +1852,6 @@ async function verifySignerBinding(signerBindingBytes, sessionCoseKey, signerCer
|
|
|
1864
1852
|
if (await verifyPayload(coseSign1, signerCertBytes, publicKey)) return true;
|
|
1865
1853
|
return verifyPayload(coseSign1, encodeCborByteString(signerCertBytes), publicKey);
|
|
1866
1854
|
}
|
|
1867
|
-
|
|
1868
1855
|
//#endregion
|
|
1869
1856
|
//#region src/merkle/validateMerkleMaps.ts
|
|
1870
1857
|
function parseMerkleRow(rawHashes) {
|
|
@@ -1938,7 +1925,6 @@ async function validateMerkleMaps(bytes, assertion, codes) {
|
|
|
1938
1925
|
}
|
|
1939
1926
|
return merkleMaps;
|
|
1940
1927
|
}
|
|
1941
|
-
|
|
1942
1928
|
//#endregion
|
|
1943
1929
|
//#region src/init/validateC2paInitSegment.ts
|
|
1944
1930
|
const BMFF_HASH_ASSERTION_LABEL$1 = "c2pa.hash.bmff.v3";
|
|
@@ -2112,7 +2098,6 @@ async function validateC2paInitSegment(bytes) {
|
|
|
2112
2098
|
errorCodes
|
|
2113
2099
|
};
|
|
2114
2100
|
}
|
|
2115
|
-
|
|
2116
2101
|
//#endregion
|
|
2117
2102
|
//#region src/emsg/extractVsiEmsgBox.ts
|
|
2118
2103
|
const EMSG_BOX_TYPE = "emsg";
|
|
@@ -2138,7 +2123,6 @@ function extractVsiEmsgBox(segmentBytes) {
|
|
|
2138
2123
|
}
|
|
2139
2124
|
return null;
|
|
2140
2125
|
}
|
|
2141
|
-
|
|
2142
2126
|
//#endregion
|
|
2143
2127
|
//#region src/vsi/decodeVsiMap.ts
|
|
2144
2128
|
/**
|
|
@@ -2160,10 +2144,7 @@ function decodeVsiMap(vsiCborBytes) {
|
|
|
2160
2144
|
if (typeof raw !== "object" || raw === null) throw new Error("VSI map must be a CBOR map");
|
|
2161
2145
|
const rawSequenceNumber = raw["sequenceNumber"];
|
|
2162
2146
|
const sequenceNumber = asUnsignedInteger(rawSequenceNumber);
|
|
2163
|
-
if (sequenceNumber === null) {
|
|
2164
|
-
const received = typeof rawSequenceNumber === "number" || typeof rawSequenceNumber === "bigint" ? String(rawSequenceNumber) : typeof rawSequenceNumber;
|
|
2165
|
-
throw new Error(`VSI map sequenceNumber must be an unsigned integer up to ${Number.MAX_SAFE_INTEGER}, got ${received}`);
|
|
2166
|
-
}
|
|
2147
|
+
if (sequenceNumber === null) throw new Error(`VSI map sequenceNumber must be an unsigned integer up to ${Number.MAX_SAFE_INTEGER}, got ${typeof rawSequenceNumber === "number" || typeof rawSequenceNumber === "bigint" ? String(rawSequenceNumber) : typeof rawSequenceNumber}`);
|
|
2167
2148
|
const bmffHashRaw = raw["bmffHash"];
|
|
2168
2149
|
if (!bmffHashRaw || typeof bmffHashRaw !== "object") throw new Error("VSI map missing bmffHash");
|
|
2169
2150
|
const hash = bmffHashRaw["hash"];
|
|
@@ -2182,7 +2163,6 @@ function decodeVsiMap(vsiCborBytes) {
|
|
|
2182
2163
|
manifestId
|
|
2183
2164
|
};
|
|
2184
2165
|
}
|
|
2185
|
-
|
|
2186
2166
|
//#endregion
|
|
2187
2167
|
//#region src/vsi/createSequenceState.ts
|
|
2188
2168
|
/**
|
|
@@ -2201,7 +2181,6 @@ function createSequenceState() {
|
|
|
2201
2181
|
seenSequences: /* @__PURE__ */ new Set()
|
|
2202
2182
|
};
|
|
2203
2183
|
}
|
|
2204
|
-
|
|
2205
2184
|
//#endregion
|
|
2206
2185
|
//#region src/vsi/SequenceState.ts
|
|
2207
2186
|
/**
|
|
@@ -2214,13 +2193,17 @@ function createSequenceState() {
|
|
|
2214
2193
|
* @public
|
|
2215
2194
|
*/
|
|
2216
2195
|
const SequenceValidationReason = {
|
|
2196
|
+
/** Sequence number is the next expected value */
|
|
2217
2197
|
VALID: "valid",
|
|
2198
|
+
/** Sequence number was already seen */
|
|
2218
2199
|
DUPLICATE: "duplicate",
|
|
2200
|
+
/** One or more sequence numbers were skipped */
|
|
2219
2201
|
GAP_DETECTED: "gap_detected",
|
|
2202
|
+
/** Sequence number is less than the last seen */
|
|
2220
2203
|
OUT_OF_ORDER: "out_of_order",
|
|
2204
|
+
/** Below the session key's minSequenceNumber */
|
|
2221
2205
|
SEQUENCE_NUMBER_BELOW_MINIMUM: "sequence_number_below_minimum"
|
|
2222
2206
|
};
|
|
2223
|
-
|
|
2224
2207
|
//#endregion
|
|
2225
2208
|
//#region src/vsi/validateSequenceNumber.ts
|
|
2226
2209
|
const SEEN_SEQUENCES_WINDOW_SIZE = 32;
|
|
@@ -2309,7 +2292,6 @@ function validateSequenceNumber(state, sequenceNumber, minSequenceNumber) {
|
|
|
2309
2292
|
}
|
|
2310
2293
|
};
|
|
2311
2294
|
}
|
|
2312
|
-
|
|
2313
2295
|
//#endregion
|
|
2314
2296
|
//#region src/bmff/validateBmffHash.ts
|
|
2315
2297
|
const OFFSET_PREFIX_SIZES_TO_TRY = [8, 0];
|
|
@@ -2339,7 +2321,6 @@ async function validateBmffHash(segmentBytes, expectedHash, options) {
|
|
|
2339
2321
|
}), expectedHash)) return true;
|
|
2340
2322
|
return false;
|
|
2341
2323
|
}
|
|
2342
|
-
|
|
2343
2324
|
//#endregion
|
|
2344
2325
|
//#region src/segment/validateC2paSegment.ts
|
|
2345
2326
|
function findSessionKey(sessionKeys, kidHex) {
|
|
@@ -2418,7 +2399,6 @@ async function validateC2paSegment(segmentBytes, sessionKeys, sequenceState = cr
|
|
|
2418
2399
|
nextSequenceState: authentic ? nextSequenceState : sequenceState
|
|
2419
2400
|
};
|
|
2420
2401
|
}
|
|
2421
|
-
|
|
2422
2402
|
//#endregion
|
|
2423
2403
|
//#region src/manifestbox/validateC2paManifestBoxSegment.ts
|
|
2424
2404
|
const LIVE_VIDEO_ASSERTION_LABEL = "c2pa.livevideo.segment";
|
|
@@ -2566,7 +2546,7 @@ async function validateC2paManifestBoxSegment(bytes, lastManifestId, state, opti
|
|
|
2566
2546
|
offsetPrefixSize: 8
|
|
2567
2547
|
}), bmff.hashBytes);
|
|
2568
2548
|
const continuityCodes = await validateContinuity(manifest, liveVideo, lastManifestId, options);
|
|
2569
|
-
const liveVideoCodes = [
|
|
2549
|
+
const liveVideoCodes = [.../* @__PURE__ */ new Set([...collectErrorCodes(manifest !== null, liveVideo !== null, streamIdValid, sequenceNumberValid, bmffHashMatches), ...continuityCodes])];
|
|
2570
2550
|
const integrityCodes = integrity?.codes ?? [];
|
|
2571
2551
|
const errorCodes = [...liveVideoCodes, ...integrityCodes];
|
|
2572
2552
|
if (bmff.malformed) errorCodes.push(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED);
|
|
@@ -2592,7 +2572,6 @@ async function validateC2paManifestBoxSegment(bytes, lastManifestId, state, opti
|
|
|
2592
2572
|
} : state ?? {}
|
|
2593
2573
|
};
|
|
2594
2574
|
}
|
|
2595
|
-
|
|
2596
2575
|
//#endregion
|
|
2597
2576
|
//#region src/merkle/validateC2paMerkleSegment.ts
|
|
2598
2577
|
const MERKLE_BOX_PURPOSE = "merkle";
|
|
@@ -2764,7 +2743,7 @@ async function validateC2paMerkleSegment(segmentBytes, merkleMaps, state) {
|
|
|
2764
2743
|
nextState: { lastLocations: nextLocations }
|
|
2765
2744
|
};
|
|
2766
2745
|
}
|
|
2767
|
-
|
|
2768
2746
|
//#endregion
|
|
2769
2747
|
export { C2paStatusCode, LiveVideoStatusCode, SequenceValidationReason, validateC2paInitSegment, validateC2paManifestBoxSegment, validateC2paMerkleSegment, validateC2paSegment };
|
|
2748
|
+
|
|
2770
2749
|
//# sourceMappingURL=index.js.map
|