Skip to content

Commit f1b19d0

Browse files
feat: Add CAWG validation to Reader (#1370)
Co-authored-by: Gavin Peacock <[email protected]>
1 parent abaf71f commit f1b19d0

File tree

11 files changed

+166
-46
lines changed

11 files changed

+166
-46
lines changed

cawgi.jpg

136 KB
Loading

sdk/examples/cawg_identity.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ mod cawg {
2929
crypto::raw_signature,
3030
identity::{
3131
builder::{AsyncIdentityAssertionBuilder, AsyncIdentityAssertionSigner},
32-
validator::CawgValidator,
3332
x509::AsyncX509CredentialHolder,
3433
},
3534
AsyncSigner, Builder, Reader, SigningAlg,
@@ -125,10 +124,7 @@ mod cawg {
125124

126125
builder.sign_file_async(&signer, source, &dest).await?;
127126

128-
let mut reader = Reader::from_file(dest)?;
129-
130-
reader.post_validate_async(&CawgValidator {}).await?;
131-
127+
let reader = Reader::from_file_async(dest).await?;
132128
println!("{reader}");
133129
Ok(())
134130
}

sdk/src/identity/identity_assertion/assertion.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,15 @@ pub struct IdentityAssertion {
7171
pub(crate) label: Option<String>,
7272
}
7373

74+
#[allow(unused)] // TEMPORARY while considering API simplification
7475
impl IdentityAssertion {
7576
/// Find the `IdentityAssertion`s that may be present in a given
7677
/// [`Manifest`].
7778
///
7879
/// Iterator returns a [`Result`] because each assertion may fail to parse.
7980
///
8081
/// Aside from CBOR parsing, no further validation is performed.
81-
pub fn from_manifest<'a>(
82+
pub(crate) fn from_manifest<'a>(
8283
manifest: &'a Manifest,
8384
status_tracker: &'a mut StatusTracker,
8485
) -> impl Iterator<Item = Result<Self, crate::Error>> + use<'a> {
@@ -93,6 +94,11 @@ impl IdentityAssertion {
9394
ia.label = Some(to_assertion_uri(manifest_label, a.label()));
9495
}
9596
}
97+
// TO DO: Add error readout if the proposed new setting resulted
98+
// in this assertion being parsed and converted to JSON. This function
99+
// has become incompatible with the now-default behavior to validate
100+
// identity assertions during parsing. This applies only if this API
101+
// becomes public again.
96102
(a.label().to_owned(), ia)
97103
})
98104
.inspect(|(label, r)| {
@@ -120,7 +126,7 @@ impl IdentityAssertion {
120126
/// of the identity assertion.
121127
///
122128
/// [`validate`]: Self::validate
123-
pub async fn to_summary<SV: SignatureVerifier>(
129+
pub(crate) async fn to_summary<SV: SignatureVerifier>(
124130
&self,
125131
manifest: &Manifest,
126132
status_tracker: &mut StatusTracker,
@@ -161,7 +167,7 @@ impl IdentityAssertion {
161167
}
162168

163169
/// Summarize all of the identity assertions found for a [`Manifest`].
164-
pub async fn summarize_all<SV: SignatureVerifier>(
170+
pub(crate) async fn summarize_all<SV: SignatureVerifier>(
165171
manifest: &Manifest,
166172
status_tracker: &mut StatusTracker,
167173
verifier: &SV,
@@ -210,7 +216,7 @@ impl IdentityAssertion {
210216
}
211217

212218
/// Summarize all of the identity assertions found for a [`Reader`].
213-
pub async fn summarize_from_reader<SV: SignatureVerifier>(
219+
pub(crate) async fn summarize_from_reader<SV: SignatureVerifier>(
214220
reader: &Reader,
215221
status_tracker: &mut StatusTracker,
216222
verifier: &SV,
@@ -243,7 +249,7 @@ impl IdentityAssertion {
243249
/// be derived from the signature. This is the [`SignatureVerifier::Output`]
244250
/// type which typically describes the named actor, but may also contain
245251
/// information about the time of signing or the credential's source.
246-
pub async fn validate<SV: SignatureVerifier>(
252+
pub(crate) async fn validate<SV: SignatureVerifier>(
247253
&self,
248254
manifest: &Manifest,
249255
status_tracker: &mut StatusTracker,
@@ -285,7 +291,7 @@ impl IdentityAssertion {
285291
/// be derived from the signature. This is the [`SignatureVerifier::Output`]
286292
/// type which typically describes the named actor, but may also contain
287293
/// information about the time of signing or the credential's source.
288-
pub async fn validate_partial_claim(
294+
pub(crate) async fn validate_partial_claim(
289295
&self,
290296
partial_claim: &PartialClaim,
291297
status_tracker: &mut StatusTracker,

sdk/src/identity/validator.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ mod tests {
6161
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
6262
use wasm_bindgen_test::wasm_bindgen_test;
6363

64-
use super::*;
6564
use crate::{Reader, ValidationState};
6665

6766
const CONNECTED_IDENTITIES_VALID: &[u8] =
@@ -78,9 +77,13 @@ mod tests {
7877
crate::settings::set_settings_value("verify.verify_trust", false).unwrap();
7978

8079
let mut stream = Cursor::new(CONNECTED_IDENTITIES_VALID);
81-
let mut reader = Reader::from_stream("image/jpeg", &mut stream).unwrap();
82-
reader.post_validate_async(&CawgValidator {}).await.unwrap();
80+
81+
let reader = Reader::from_stream_async("image/jpeg", &mut stream)
82+
.await
83+
.unwrap();
84+
8385
//println!("validation results: {}", reader);
86+
8487
assert_eq!(
8588
reader
8689
.validation_results()
@@ -100,9 +103,13 @@ mod tests {
100103
crate::settings::set_settings_value("verify.verify_trust", false).unwrap();
101104

102105
let mut stream = Cursor::new(MULTIPLE_IDENTITIES_VALID);
103-
let mut reader = Reader::from_stream("image/jpeg", &mut stream).unwrap();
104-
reader.post_validate_async(&CawgValidator {}).await.unwrap();
106+
107+
let reader = Reader::from_stream_async("image/jpeg", &mut stream)
108+
.await
109+
.unwrap();
110+
105111
println!("validation results: {reader}");
112+
106113
assert_eq!(
107114
reader
108115
.validation_results()
@@ -116,10 +123,13 @@ mod tests {
116123
}
117124

118125
#[c2pa_test_async]
119-
async fn test_post_validate_with_hard_binding_missing() {
126+
async fn test_cawg_validate_with_hard_binding_missing() {
120127
let mut stream = Cursor::new(NO_HARD_BINDING);
121-
let mut reader = Reader::from_stream("image/jpeg", &mut stream).unwrap();
122-
reader.post_validate_async(&CawgValidator {}).await.unwrap();
128+
129+
let reader = Reader::from_stream_async("image/jpeg", &mut stream)
130+
.await
131+
.unwrap();
132+
123133
assert_eq!(
124134
reader
125135
.validation_results()

sdk/src/identity/x509/async_x509_credential_holder.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ mod tests {
116116
x509::{AsyncX509CredentialHolder, X509SignatureVerifier},
117117
IdentityAssertion,
118118
},
119+
settings::{get_settings_value, set_settings_value},
119120
status_tracker::StatusTracker,
120121
Builder, Reader, SigningAlg,
121122
};
@@ -125,6 +126,11 @@ mod tests {
125126

126127
#[c2pa_test_async]
127128
async fn simple_case_async() {
129+
let old_decode_identity_assertions =
130+
get_settings_value::<bool>("core.decode_identity_assertions").unwrap_or_default();
131+
132+
set_settings_value("core.decode_identity_assertions", false).unwrap();
133+
128134
let format = "image/jpeg";
129135
let mut source = Cursor::new(TEST_IMAGE);
130136
let mut dest = Cursor::new(Vec::new());
@@ -164,7 +170,7 @@ mod tests {
164170
// Read back the Manifest that was generated.
165171
dest.rewind().unwrap();
166172

167-
let manifest_store = Reader::from_stream(format, &mut dest).unwrap();
173+
let manifest_store = Reader::from_stream_async(format, &mut dest).await.unwrap();
168174
assert_eq!(manifest_store.validation_status(), None);
169175

170176
let manifest = manifest_store.active_manifest().unwrap();
@@ -194,5 +200,10 @@ mod tests {
194200
);
195201

196202
// TO DO: Not sure what to check from COSE_Sign1.
203+
set_settings_value(
204+
"core.decode_identity_assertions",
205+
old_decode_identity_assertions,
206+
)
207+
.unwrap();
197208
}
198209
}

sdk/src/identity/x509/x509_credential_holder.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ mod tests {
8888
x509::{X509CredentialHolder, X509SignatureVerifier},
8989
IdentityAssertion,
9090
},
91+
settings::{get_settings_value, set_settings_value},
9192
status_tracker::StatusTracker,
9293
Builder, Reader, SigningAlg,
9394
};
@@ -97,6 +98,11 @@ mod tests {
9798

9899
#[c2pa_test_async]
99100
async fn simple_case() {
101+
let old_decode_identity_assertions =
102+
get_settings_value::<bool>("core.decode_identity_assertions").unwrap_or_default();
103+
104+
set_settings_value("core.decode_identity_assertions", false).unwrap();
105+
100106
let format = "image/jpeg";
101107
let mut source = Cursor::new(TEST_IMAGE);
102108
let mut dest = Cursor::new(Vec::new());
@@ -164,5 +170,11 @@ mod tests {
164170
);
165171

166172
// TO DO: Not sure what to check from COSE_Sign1.
173+
174+
set_settings_value(
175+
"core.decode_identity_assertions",
176+
old_decode_identity_assertions,
177+
)
178+
.unwrap();
167179
}
168180
}

sdk/src/manifest.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@ use crate::{
3030
crypto::raw_signature::SigningAlg,
3131
error::{Error, Result},
3232
hashed_uri::HashedUri,
33+
identity::IdentityAssertion,
3334
ingredient::Ingredient,
3435
jumbf::labels::{to_absolute_uri, to_assertion_uri},
3536
manifest_assertion::ManifestAssertion,
3637
resource_store::{mime_from_uri, skip_serializing_resources, ResourceRef, ResourceStore},
38+
settings::get_settings_value,
39+
status_tracker::StatusTracker,
3740
store::Store,
3841
ClaimGeneratorInfo, ManifestAssertionKind,
3942
};
@@ -350,6 +353,7 @@ impl Manifest {
350353
store: &Store,
351354
manifest_label: &str,
352355
options: &mut StoreOptions,
356+
validation_log: &mut StatusTracker,
353357
) -> Result<Self> {
354358
let claim = store
355359
.get_claim(manifest_label)
@@ -434,6 +438,9 @@ impl Manifest {
434438
})
435439
.collect();
436440

441+
let decode_identity_assertions =
442+
get_settings_value::<bool>("core.decode_identity_assertions").unwrap_or_default();
443+
437444
for assertion in claim.assertions() {
438445
let claim_assertion = match store
439446
.get_claim_assertion_from_uri(&to_absolute_uri(claim.label(), &assertion.url()))
@@ -535,6 +542,45 @@ impl Manifest {
535542
.set_instance(claim_assertion.instance());
536543
manifest.assertions.push(manifest_assertion);
537544
}
545+
label
546+
if decode_identity_assertions
547+
&& (label == "cawg.identity" || label.starts_with("cawg.identity__")) =>
548+
{
549+
let value = assertion.as_json_object()?;
550+
let mut ma = ManifestAssertion::new(label.to_string(), value)
551+
.set_instance(claim_assertion.instance());
552+
553+
let mut partial_claim = crate::dynamic_assertion::PartialClaim::default();
554+
for a in claim.assertions() {
555+
partial_claim.add_assertion(a);
556+
}
557+
558+
let uri = to_assertion_uri(manifest_label, label);
559+
validation_log.push_current_uri(&uri);
560+
let value: Option<serde_json::Value> = if _sync {
561+
crate::log_item!(
562+
uri,
563+
"decoding identity assertions not supported in sync",
564+
"from_store - validating cawg.identity"
565+
)
566+
.validation_status("cawg.validation_skipped")
567+
.informational(validation_log);
568+
None
569+
} else {
570+
let identity_assertion: IdentityAssertion = ma.to_assertion()?;
571+
identity_assertion
572+
.validate_partial_claim(&partial_claim, validation_log)
573+
.await
574+
.ok()
575+
};
576+
if let Some(v) = value {
577+
//debug!("cawg.identity validation returned: {v}");
578+
ma = ManifestAssertion::new(label.to_string(), v)
579+
.set_instance(claim_assertion.instance());
580+
}
581+
validation_log.pop_current_uri();
582+
manifest.assertions.push(ma);
583+
}
538584
_ => {
539585
// inject assertions for all other assertions
540586
match assertion.decode_data() {

sdk/src/manifest_store_report.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ impl ManifestReport {
147147

148148
json = b64_tag(json, "hash");
149149
json = omit_tag(json, "pad");
150+
json = omit_tag(json, "pad1");
150151

151152
json
152153
}

0 commit comments

Comments
 (0)