1111// specific language governing permissions and limitations under
1212// each license.
1313
14+ use std:: collections:: HashSet ;
15+
1416#[ cfg( feature = "json_schema" ) ]
1517use schemars:: JsonSchema ;
1618use serde:: { Deserialize , Serialize } ;
@@ -21,30 +23,48 @@ use crate::{
2123 jumbf:: labels:: manifest_label_from_uri,
2224 status_tracker:: { LogKind , StatusTracker } ,
2325 store:: Store ,
24- validation_status:: { log_kind, ValidationStatus } ,
26+ validation_status:: { self , log_kind, ValidationStatus } ,
2527} ;
2628
29+ /// Represents the levels of assurance a manifest store achives when evaluated against the C2PA
30+ /// specifications structural, cryptographic, and trust requirements.
31+ ///
32+ /// See [§14.3. Validation states].
33+ ///
34+ /// [§14.3. Validation states]: https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_validation_states
2735#[ derive( Copy , Clone , Debug , PartialEq , Eq , Serialize , Deserialize ) ]
2836#[ cfg_attr( feature = "json_schema" , derive( JsonSchema ) ) ]
29- /// Indicates if the manifest store is valid and trusted.
30- ///
31- /// The Trusted state implies the manifest store is valid and the active signature is trusted.
3237pub enum ValidationState {
33- /// Errors were found in the manifest store.
38+ /// The manifest store fails to meet [ValidationState::WellFormed] requirements, meaning it cannot
39+ /// even be parsed or its basic structure is non-compliant.
40+ ///
41+ /// This case may also occur if validation is disabled in the SDK.
3442 Invalid ,
35- /// No errors were found in validation, but the active signature is not trusted.
43+ /// The manifest store is well-formed and the cryptographic integrity checks succeed.
44+ ///
45+ /// See [§14.3.5. Valid Manifest].
46+ ///
47+ /// [§14.3.5. Valid Manifest]: https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_valid_manifest
3648 Valid ,
37- /// The manifest store is valid and the active signature is trusted.
49+ /// The manifest store is valid and signed by a certificate that chains up to a trusted root or known
50+ /// authority in the trust list.
51+ ///
52+ /// See [§14.3.6. Trusted Manifest].
53+ ///
54+ /// [§14.3.6. Trusted Manifest]: https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_trusted_manifest
3855 Trusted ,
3956}
4057
58+ /// Contains a set of success, informational, and failure validation status codes.
4159#[ derive( Clone , Serialize , Default , Deserialize , Debug , PartialEq , Eq ) ]
4260#[ cfg_attr( feature = "json_schema" , derive( JsonSchema ) ) ]
43- /// Contains a set of success, informational, and failure validation status codes.
4461pub struct StatusCodes {
45- pub success : Vec < ValidationStatus > , // an array of validation success codes. May be empty.
46- pub informational : Vec < ValidationStatus > , // an array of validation informational codes. May be empty.
47- pub failure : Vec < ValidationStatus > , // an array of validation failure codes. May be empty.
62+ /// An array of validation success codes. May be empty.
63+ pub success : Vec < ValidationStatus > ,
64+ /// An array of validation informational codes. May be empty.
65+ pub informational : Vec < ValidationStatus > ,
66+ // An array of validation failure codes. May be empty.
67+ pub failure : Vec < ValidationStatus > ,
4868}
4969
5070impl StatusCodes {
@@ -85,18 +105,22 @@ impl StatusCodes {
85105 }
86106}
87107
88- #[ derive( Clone , Serialize , Default , Deserialize , Debug , PartialEq , Eq ) ]
89- #[ cfg_attr( feature = "json_schema" , derive( JsonSchema ) ) ]
90108/// A map of validation results for a manifest store.
91109///
92110/// The map contains the validation results for the active manifest and any ingredient deltas.
93111/// It is normal for there to be many
112+ #[ derive( Clone , Serialize , Default , Deserialize , Debug , PartialEq , Eq ) ]
113+ #[ cfg_attr( feature = "json_schema" , derive( JsonSchema ) ) ]
94114pub struct ValidationResults {
115+ /// Validation status codes for the ingredient's active manifest. Present if ingredient is a C2PA
116+ /// asset. Not present if the ingredient is not a C2PA asset.
95117 #[ serde( rename = "activeManifest" , skip_serializing_if = "Option::is_none" ) ]
96- active_manifest : Option < StatusCodes > , // Validation status codes for the ingredient's active manifest. Present if ingredient is a C2PA asset. Not present if the ingredient is not a C2PA asset.
118+ active_manifest : Option < StatusCodes > ,
97119
120+ /// List of any changes/deltas between the current and previous validation results for each ingredient's
121+ /// manifest. Present if the the ingredient is a C2PA asset.
98122 #[ serde( rename = "ingredientDeltas" , skip_serializing_if = "Option::is_none" ) ]
99- ingredient_deltas : Option < Vec < IngredientDeltaValidationResult > > , // List of any changes/deltas between the current and previous validation results for each ingredient's manifest. Present if the the ingredient is a C2PA asset.
123+ ingredient_deltas : Option < Vec < IngredientDeltaValidationResult > > ,
100124}
101125
102126impl ValidationResults {
@@ -180,29 +204,43 @@ impl ValidationResults {
180204 }
181205
182206 /// Returns the [ValidationState] of the manifest store based on the validation results.
207+ ///
208+ /// See [§14.3. Validation states].
209+ ///
210+ /// [§14.3. Validation states]: https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_validation_states
183211 pub fn validation_state ( & self ) -> ValidationState {
184- let mut is_trusted = true ; // Assume the state is trusted until proven otherwise
185212 if let Some ( active_manifest) = self . active_manifest . as_ref ( ) {
186- if !active_manifest. failure ( ) . is_empty ( ) {
187- return ValidationState :: Invalid ;
188- }
189- // There must be a trusted credential in the active manifest for the state to be trusted
190- is_trusted = active_manifest. success ( ) . iter ( ) . any ( |status| {
191- status. code ( ) == crate :: validation_status:: SIGNING_CREDENTIAL_TRUSTED
213+ let success_codes: HashSet < & str > = active_manifest
214+ . success ( )
215+ . iter ( )
216+ . map ( |status| status. code ( ) )
217+ . collect ( ) ;
218+ let failure_codes = active_manifest. failure ( ) ;
219+ let ingredient_failure = self . ingredient_deltas . as_ref ( ) . is_some_and ( |deltas| {
220+ deltas
221+ . iter ( )
222+ . any ( |idv| !idv. validation_deltas ( ) . failure ( ) . is_empty ( ) )
192223 } ) ;
193- }
194- if let Some ( ingredient_deltas) = self . ingredient_deltas . as_ref ( ) {
195- for idv in ingredient_deltas. iter ( ) {
196- if !idv. validation_deltas ( ) . failure ( ) . is_empty ( ) {
197- return ValidationState :: Invalid ;
198- }
224+
225+ // https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_valid_manifest
226+ let is_valid = success_codes. contains ( validation_status:: CLAIM_SIGNATURE_VALIDATED )
227+ && success_codes. contains ( validation_status:: CLAIM_SIGNATURE_INSIDE_VALIDITY )
228+ && failure_codes. is_empty ( )
229+ && !ingredient_failure;
230+
231+ // https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_trusted_manifest
232+ let is_trusted = success_codes. contains ( validation_status:: SIGNING_CREDENTIAL_TRUSTED )
233+ && failure_codes. is_empty ( )
234+ && is_valid;
235+
236+ if is_trusted {
237+ return ValidationState :: Trusted ;
238+ } else if is_valid {
239+ return ValidationState :: Valid ;
199240 }
200241 }
201- if is_trusted {
202- ValidationState :: Trusted
203- } else {
204- ValidationState :: Valid
205- }
242+
243+ ValidationState :: Invalid
206244 }
207245
208246 /// Returns a list of all validation errors in [ValidationResults].
0 commit comments