use std::io::Cursor;
use c2pa_macros::c2pa_test_async;
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
use wasm_bindgen_test::wasm_bindgen_test;
use crate::{
crypto::raw_signature::SigningAlg,
identity::{x509::X509SignatureVerifier, IdentityAssertion},
status_tracker::{LogKind, StatusTracker},
Reader,
};
#[c2pa_test_async]
async fn malformed_cbor() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/malformed_cbor.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia_err = ia_results[0].as_ref().unwrap_err();
assert_eq!(ia_err.to_string(), "could not decode assertion cawg.identity (version (no version), content type application/json): missing field `signer_payload`");
assert_eq!(status_tracker.logged_items().len(), 1);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert!(log.label.ends_with("/c2pa.assertions/cawg.identity"));
assert_eq!(log.description, "invalid CBOR");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.cbor.invalid"
);
}
#[c2pa_test_async]
async fn extra_fields() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/extra_field.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
dbg!(ia);
let sp = &ia.signer_payload;
assert_eq!(sp.referenced_assertions.len(), 1);
assert_eq!(
sp.referenced_assertions[0].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(sp.sig_type, "cawg.x509.cose".to_owned());
assert_eq!(status_tracker.logged_items().len(), 0);
}
#[c2pa_test_async]
async fn assertion_not_in_claim_v1() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/extra_assertion_claim_v1.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
let sp = &ia.signer_payload;
assert_eq!(sp.referenced_assertions.len(), 2);
assert_eq!(
sp.referenced_assertions[0].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(
sp.referenced_assertions[1].url(),
"self#jumbf=c2pa/urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4/c2pa.assertions/testing.bogus.assertion".to_owned()
);
assert_eq!(sp.sig_type, "cawg.x509.cose".to_owned());
let x509_verifier = X509SignatureVerifier::default();
let sig_info = ia
.validate(
reader.active_manifest().unwrap(),
&mut status_tracker,
&x509_verifier,
)
.await
.unwrap();
assert_eq!(status_tracker.logged_items().len(), 2);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:4baf4dc3-c464-4c70-902b-d28d832a29e3/c2pa.assertions/cawg.identity"
);
assert_eq!(log.description, "referenced assertion not in claim");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.assertion.mismatch"
);
let log = &status_tracker.logged_items()[1];
assert_eq!(log.kind, LogKind::Success);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:4baf4dc3-c464-4c70-902b-d28d832a29e3/c2pa.assertions/cawg.identity"
);
assert_eq!(
log.description,
"signing certificate trusted, found in User trust anchors"
);
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"signingCredential.trusted"
);
let cert_info = &sig_info.cert_info;
assert_eq!(cert_info.alg.unwrap(), SigningAlg::Ed25519);
assert_eq!(
cert_info.issuer_org.as_ref().unwrap(),
"C2PA Test Signing Cert"
);
}
#[c2pa_test_async]
async fn duplicate_assertion_reference() {
let format = "image/jpeg";
let test_image =
include_bytes!("../fixtures/validation_method/duplicate_assertion_reference.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
let sp = &ia.signer_payload;
assert_eq!(sp.referenced_assertions.len(), 2);
assert_eq!(
sp.referenced_assertions[0].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(
sp.referenced_assertions[1].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(sp.sig_type, "cawg.x509.cose".to_owned());
let x509_verifier = X509SignatureVerifier::default();
let sig_info = ia
.validate(
reader.active_manifest().unwrap(),
&mut status_tracker,
&x509_verifier,
)
.await
.unwrap();
assert_eq!(status_tracker.logged_items().len(), 2);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:9b9f27bc-394b-419f-a8d5-81777c9fa76c/c2pa.assertions/cawg.identity"
);
assert_eq!(log.description, "multiple references to same assertion");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.assertion.duplicate"
);
let log = &status_tracker.logged_items()[1];
assert_eq!(log.kind, LogKind::Success);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:9b9f27bc-394b-419f-a8d5-81777c9fa76c/c2pa.assertions/cawg.identity"
);
assert_eq!(
log.description,
"signing certificate trusted, found in User trust anchors"
);
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"signingCredential.trusted"
);
let cert_info = &sig_info.cert_info;
assert_eq!(cert_info.alg.unwrap(), SigningAlg::Ed25519);
assert_eq!(
cert_info.issuer_org.as_ref().unwrap(),
"C2PA Test Signing Cert"
);
}
#[c2pa_test_async]
async fn no_hard_binding() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/no_hard_binding.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
let sp = &ia.signer_payload;
assert!(sp.referenced_assertions.is_empty());
assert_eq!(sp.sig_type, "cawg.x509.cose".to_owned());
let x509_verifier = X509SignatureVerifier::default();
let sig_info = ia
.validate(
reader.active_manifest().unwrap(),
&mut status_tracker,
&x509_verifier,
)
.await
.unwrap();
assert_eq!(status_tracker.logged_items().len(), 2);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:6df39abb-e6b4-49af-a826-ba44b7b248b7/c2pa.assertions/cawg.identity"
);
assert_eq!(log.description, "no hard binding assertion");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.hard_binding_missing"
);
let log = &status_tracker.logged_items()[1];
assert_eq!(log.kind, LogKind::Success);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:6df39abb-e6b4-49af-a826-ba44b7b248b7/c2pa.assertions/cawg.identity"
);
assert_eq!(
log.description,
"signing certificate trusted, found in User trust anchors"
);
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"signingCredential.trusted"
);
let cert_info = &sig_info.cert_info;
assert_eq!(cert_info.alg.unwrap(), SigningAlg::Ed25519);
assert_eq!(
cert_info.issuer_org.as_ref().unwrap(),
"C2PA Test Signing Cert"
);
}
mod invalid_sig_type {
use std::io::Cursor;
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
use wasm_bindgen_test::wasm_bindgen_test;
use super::*;
use crate::{
identity::{
claim_aggregation::IcaSignatureVerifier, x509::X509SignatureVerifier, IdentityAssertion,
},
status_tracker::{LogKind, StatusTracker},
Reader,
};
#[c2pa_test_async]
async fn x509_signature_verifier() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/invalid_sig_type.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
let sp = &ia.signer_payload;
assert_eq!(sp.referenced_assertions.len(), 1);
assert_eq!(
sp.referenced_assertions[0].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(sp.sig_type, "INVALID.identity.naive_credential".to_owned());
let x509_verifier = X509SignatureVerifier::default();
let err = ia
.validate(
reader.active_manifest().unwrap(),
&mut status_tracker,
&x509_verifier,
)
.await
.unwrap_err();
assert_eq!(
err.to_string(),
"unable to parse a signature of type \"INVALID.identity.naive_credential\""
);
assert_eq!(status_tracker.logged_items().len(), 1);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:0f746efd-5e87-43d9-9032-bfc0e2b0e98f/c2pa.assertions/cawg.identity"
);
assert_eq!(log.description, "unsupported signature type");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.sig_type.unknown"
);
}
#[c2pa_test_async]
async fn ica_verifier() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/invalid_sig_type.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
let sp = &ia.signer_payload;
assert_eq!(sp.referenced_assertions.len(), 1);
assert_eq!(
sp.referenced_assertions[0].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(sp.sig_type, "INVALID.identity.naive_credential".to_owned());
let ica_verifier = IcaSignatureVerifier {};
let err = ia
.validate(
reader.active_manifest().unwrap(),
&mut status_tracker,
&ica_verifier,
)
.await
.unwrap_err();
assert_eq!(
err.to_string(),
"unable to parse a signature of type \"INVALID.identity.naive_credential\""
);
assert_eq!(status_tracker.logged_items().len(), 1);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:0f746efd-5e87-43d9-9032-bfc0e2b0e98f/c2pa.assertions/cawg.identity"
);
assert_eq!(log.description, "unsupported signature type");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.sig_type.unknown"
);
}
}
#[c2pa_test_async]
async fn pad1_invalid() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/pad1_invalid.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
let sp = &ia.signer_payload;
assert_eq!(sp.referenced_assertions.len(), 1);
assert_eq!(
sp.referenced_assertions[0].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(sp.sig_type, "cawg.x509.cose".to_owned());
let x509_verifier = X509SignatureVerifier::default();
let sig_info = ia
.validate(
reader.active_manifest().unwrap(),
&mut status_tracker,
&x509_verifier,
)
.await
.unwrap();
assert_eq!(status_tracker.logged_items().len(), 2);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:8d938dd8-d194-4d24-a0bf-55aae143b692/c2pa.assertions/cawg.identity"
);
assert_eq!(log.description, "invalid value in pad fields");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.pad.invalid"
);
let log = &status_tracker.logged_items()[1];
assert_eq!(log.kind, LogKind::Success);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:8d938dd8-d194-4d24-a0bf-55aae143b692/c2pa.assertions/cawg.identity"
);
assert_eq!(
log.description,
"signing certificate trusted, found in User trust anchors"
);
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"signingCredential.trusted"
);
let cert_info = &sig_info.cert_info;
assert_eq!(cert_info.alg.unwrap(), SigningAlg::Ed25519);
assert_eq!(
cert_info.issuer_org.as_ref().unwrap(),
"C2PA Test Signing Cert"
);
}
#[c2pa_test_async]
async fn pad2_invalid() {
let format = "image/jpeg";
let test_image = include_bytes!("../fixtures/validation_method/pad2_invalid.jpg");
let mut test_image = Cursor::new(test_image);
let reader = Reader::default()
.with_stream(format, &mut test_image)
.unwrap();
assert_eq!(reader.validation_status(), None);
let mut status_tracker = StatusTracker::default();
let active_manifest = reader.active_manifest().unwrap();
let ia_results: Vec<Result<IdentityAssertion, crate::Error>> =
IdentityAssertion::from_manifest(active_manifest, &mut status_tracker).collect();
assert_eq!(ia_results.len(), 1);
let ia = ia_results[0].as_ref().unwrap();
let sp = &ia.signer_payload;
assert_eq!(sp.referenced_assertions.len(), 1);
assert_eq!(
sp.referenced_assertions[0].url(),
"self#jumbf=c2pa.assertions/c2pa.hash.data".to_owned()
);
assert_eq!(sp.sig_type, "cawg.x509.cose".to_owned());
let x509_verifier = X509SignatureVerifier::default();
let sig_info = ia
.validate(
reader.active_manifest().unwrap(),
&mut status_tracker,
&x509_verifier,
)
.await
.unwrap();
assert_eq!(status_tracker.logged_items().len(), 2);
let log = &status_tracker.logged_items()[0];
assert_eq!(log.kind, LogKind::Failure);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:d686f86c-63d9-43e9-822c-7789acefe102/c2pa.assertions/cawg.identity"
);
assert_eq!(log.description, "invalid value in pad fields");
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"cawg.identity.pad.invalid"
);
let log = &status_tracker.logged_items()[1];
assert_eq!(log.kind, LogKind::Success);
assert_eq!(
log.label,
"self#jumbf=/c2pa/test:urn:uuid:d686f86c-63d9-43e9-822c-7789acefe102/c2pa.assertions/cawg.identity"
);
assert_eq!(
log.description,
"signing certificate trusted, found in User trust anchors"
);
assert_eq!(
log.validation_status.as_ref().unwrap().as_ref() as &str,
"signingCredential.trusted"
);
let cert_info = &sig_info.cert_info;
assert_eq!(cert_info.alg.unwrap(), SigningAlg::Ed25519);
assert_eq!(
cert_info.issuer_org.as_ref().unwrap(),
"C2PA Test Signing Cert"
);
}