diff --git a/Library/Sources/Manifest/AssertionDefinition.swift b/Library/Sources/Manifest/AssertionDefinition.swift index 52b5596..c17938c 100644 --- a/Library/Sources/Manifest/AssertionDefinition.swift +++ b/Library/Sources/Manifest/AssertionDefinition.swift @@ -17,7 +17,7 @@ import Foundation /// - SeeAlso: [AssertionDefinition Reference](https://opensource.contentauthenticity.org/docs/manifest/json-ref/manifest-definition-schema#assertiondefinition) /// The standard C2PA assertions are currently available: -/// - SeeAlso: [C2PA Specification: Standard C2PA Assertion Summary](https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_standard_c2pa_assertion_summary) +/// - SeeAlso: [C2PA Specification: Standard C2PA Assertion Summary](https://spec.c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_standard_c2pa_assertion_summary) /// But only `actions` is actually implemented! public enum AssertionDefinition: Codable, Equatable { @@ -30,7 +30,11 @@ public enum AssertionDefinition: Codable, Equatable { /// - SeeAlso: [Actions Reference](https://opensource.contentauthenticity.org/docs/manifest/writing/assertions-actions#actions) case actions(actions: [Action]) + /// - SeeAlso: [Actions Reference](https://opensource.contentauthenticity.org/docs/manifest/writing/assertions-actions#actions) + case actionsV2(actions: [Action]) + case assertionMetadata + case alternativeContentRepresentation case assetRef case assetType case bmffBasedHash @@ -40,9 +44,11 @@ public enum AssertionDefinition: Codable, Equatable { case dataHash case depthmap case embeddedData + case externalReference case fontInfo case generalBoxHash case ingredient + case ingredientV3 case metadata case multiAssetHash case softBinding @@ -61,9 +67,17 @@ public enum AssertionDefinition: Codable, Equatable { self = .actions(actions: actions["actions"] ?? []) + case .actionsV2: + let actions = try container.decode([String: [Action]].self, forKey: .data) + + self = .actionsV2(actions: actions["actions"] ?? []) + case .assertionMetadata: self = .assertionMetadata + case .alternativeContentRepresentation: + self = .alternativeContentRepresentation + case .assetRef: self = .assetRef @@ -91,6 +105,9 @@ public enum AssertionDefinition: Codable, Equatable { case .embeddedData: self = .embeddedData + case .externalReference: + self = .externalReference + case .fontInfo: self = .fontInfo @@ -100,6 +117,9 @@ public enum AssertionDefinition: Codable, Equatable { case .ingredient: self = .ingredient + case .ingredientV3: + self = .ingredientV3 + case .metadata: self = .metadata @@ -128,9 +148,16 @@ public enum AssertionDefinition: Codable, Equatable { try container.encode(StandardAssertionLabel.actions, forKey: .label) try container.encode(["actions": actions], forKey: .data) + case .actionsV2(let actions): + try container.encode(StandardAssertionLabel.actionsV2, forKey: .label) + try container.encode(["actions": actions], forKey: .data) + case .assertionMetadata: try container.encode(StandardAssertionLabel.assertionMetadata, forKey: .label) + case .alternativeContentRepresentation: + try container.encode(StandardAssertionLabel.alternativeContentRepresentation, forKey: .label) + case .assetRef: try container.encode(StandardAssertionLabel.assetRef, forKey: .label) @@ -158,6 +185,9 @@ public enum AssertionDefinition: Codable, Equatable { case .embeddedData: try container.encode(StandardAssertionLabel.embeddedData, forKey: .label) + case .externalReference: + try container.encode(StandardAssertionLabel.externalReference, forKey: .label) + case .fontInfo: try container.encode(StandardAssertionLabel.fontInfo, forKey: .label) @@ -167,6 +197,9 @@ public enum AssertionDefinition: Codable, Equatable { case .ingredient: try container.encode(StandardAssertionLabel.ingredient, forKey: .label) + case .ingredientV3: + try container.encode(StandardAssertionLabel.ingredientV3, forKey: .label) + case .metadata: try container.encode(StandardAssertionLabel.metadata, forKey: .label) diff --git a/Library/Sources/Manifest/HashedUri.swift b/Library/Sources/Manifest/HashedUri.swift index 3522f5e..69c4ad1 100644 --- a/Library/Sources/Manifest/HashedUri.swift +++ b/Library/Sources/Manifest/HashedUri.swift @@ -14,7 +14,7 @@ import Foundation /// A HashedUri provides a reference to content available within the same manifest store. This is described in §8.3, URI References of the C2PA Technical Specification. -/// - SeeAlso: [C2PA Specification: URI References](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_uri_references) +/// - SeeAlso: [C2PA Specification: URI References](https://spec.c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_uri_references) /// - SeeAlso: [HashedUri Reference](https://opensource.contentauthenticity.org/docs/manifest/json-ref/manifest-definition-schema/#hasheduri) open class HashedUri: UriOrResource { diff --git a/Library/Sources/Manifest/PredefinedAction.swift b/Library/Sources/Manifest/PredefinedAction.swift index 4de0c7a..b105163 100644 --- a/Library/Sources/Manifest/PredefinedAction.swift +++ b/Library/Sources/Manifest/PredefinedAction.swift @@ -13,7 +13,7 @@ import Foundation -/// - SeeAlso: [C2PA Specification: Actions](https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_actions) +/// - SeeAlso: [C2PA Specification: Actions](https://spec.c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_actions) public enum PredefinedAction: String, Codable { /// (visible) Textual content was inserted into the asset, such as on a text layer or as a caption. @@ -25,6 +25,9 @@ public enum PredefinedAction: String, Codable { /// Reduced or increased playback speed of a video or audio track case changedSpeed = "c2pa.changedSpeed" + /// The asset was captured from a camera or recording device. + case captured = "c2pa.captured" + /// [DEPRECATED] Changes to tone, saturation, etc. @available(*, deprecated) case colorAdjustments = "c2pa.color_adjustments" @@ -83,6 +86,9 @@ public enum PredefinedAction: String, Codable { /// Changes to either content dimensions, its file size or both case resized = "c2pa.resized" + /// Content was segmented into multiple parts or clips. + case segmented = "c2pa.segmented" + /// A conversion of one encoding to another, including resolution scaling, bitrate adjustment and encoding format change. This action is considered as a non-editorial transformation of the parentOf ingredient. case transcoded = "c2pa.transcoded" @@ -97,4 +103,16 @@ public enum PredefinedAction: String, Codable { /// An invisible watermark was inserted into the digital content for the purpose of creating a soft binding. case watermarked = "c2pa.watermarked" + + /// Content was compressed using a compression algorithm. + case compressed = "c2pa.compressed" + + /// Content was decompressed from a compressed representation. + case decompressed = "c2pa.decompressed" + + /// Content was converted between stereo and another channel configuration. + case stereoConverted = "c2pa.stereoConverted" + + /// Content was generated or synthesized using automated or algorithmic means (e.g., generative AI). + case synthesized = "c2pa.synthesized" } diff --git a/Library/Sources/Manifest/StandardAssertionLabel.swift b/Library/Sources/Manifest/StandardAssertionLabel.swift index 1a07e2a..4e02949 100644 --- a/Library/Sources/Manifest/StandardAssertionLabel.swift +++ b/Library/Sources/Manifest/StandardAssertionLabel.swift @@ -14,46 +14,78 @@ import Foundation /// The standard C2PA assertions. -/// - SeeAlso: [C2PA Specification: Standard C2PA Assertion Summary](https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_standard_c2pa_assertion_summary) +/// - SeeAlso: [C2PA Specification: Standard C2PA Assertion Summary](https://spec.c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_standard_c2pa_assertion_summary) public enum StandardAssertionLabel: String, Codable { + /// Describes actions performed on the asset. case actions = "c2pa.actions" + /// Version 2 of the actions assertion schema. + case actionsV2 = "c2pa.actions.v2" + + /// Metadata about another assertion. case assertionMetadata = "c2pa.assertion.metadata" + /// Provides an alternate representation of the content (for example an EXIF preservation image). + case alternativeContentRepresentation = "c2pa.alternative-content-representation" + + /// Reference to a location where the asset may be obtained. case assetRef = "c2pa.asset-ref" + /// Describes the media type and classification of the asset. case assetType = "c2pa.asset-type.v2" + /// Hash of a BMFF-based asset structure. case bmffBasedHash = "c2pa.hash.bmff.v3" + /// Information about the certificate used for signing. case certificateStatus = "c2pa.certificate-status" + /// Reference to externally stored assertion data. case cloudData = "c2pa.cloud-data" + /// Hash of a collection of assets. case collectionDataHash = "c2pa.hash.collection.data" + /// Hash of byte ranges of the asset. case dataHash = "c2pa.hash.data" + /// Google depth map metadata assertion. case depthmap = "c2pa.depthmap.GDepth" + /// Embedded binary data such as images, prompts, or other files. case embeddedData = "c2pa.embedded-data" + /// Reference to an externally stored assertion. + case externalReference = "c2pa.external-reference" + + /// Font metadata describing fonts used in the asset. case fontInfo = "font.info" + /// Hash of specific boxes in a container format. case generalBoxHash = "c2pa.hash.boxes" + /// Ingredient describing an input asset used to create the current asset. case ingredient = "c2pa.ingredient" + /// Version 3 of the ingredient assertion. + case ingredientV3 = "c2pa.ingredient.v3" + + /// Structured metadata about the asset (for example EXIF or IPTC). case metadata = "c2pa.metadata" + /// Hash referencing multiple assets. case multiAssetHash = "c2pa.hash.multi-asset" + /// Soft binding information between content and manifest. case softBinding = "c2pa.soft-binding" + /// Thumbnail representing the asset at claim creation. case thumbnailClaim = "c2pa.thumbnail.claim" + /// Thumbnail representing an imported ingredient. case thumbnailIngredient = "c2pa.thumbnail.ingredient" + /// Signed timestamp token associated with the claim. case timeStamps = "c2pa.time-stamp" } diff --git a/Library/Sources/Manifest/ValidationStatusCode.swift b/Library/Sources/Manifest/ValidationStatusCode.swift index 97fc479..aedf5e3 100644 --- a/Library/Sources/Manifest/ValidationStatusCode.swift +++ b/Library/Sources/Manifest/ValidationStatusCode.swift @@ -13,18 +13,29 @@ import Foundation -/// - SeeAlso: [C2PA Specification: returning_validation_results](https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_returning_validation_results) +/// - SeeAlso: [C2PA Specification: returning_validation_results](https://spec.c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_returning_validation_results) public enum ValidationStatusCode: String, Codable { + // MARK: - Success codes + /// The claim signature referenced in the ingredient’s claim validated. case claimSignatureValidated = "claimSignature.validated" + /// The claim signature was created within the validity window of the signing certificate. + case claimSignatureInsideValidity = "claimSignature.insideValidity" + /// The signing credential is listed on the validator’s trust list. case signingCredentialTrusted = "signingCredential.trusted" + /// The signing credential was checked via OCSP and was not revoked. + case signingCredentialOCSPNotRevoked = "signingCredential.ocsp.notRevoked" + /// The time-stamp credential is listed on the validator’s trust list. case timeStampTrusted = "timeStamp.trusted" + /// The time-stamp token was successfully validated. + case timeStampValidated = "timeStamp.validated" + /// The hash of the the referenced assertion in the ingredient’s manifest matches the corresponding hash in the assertion’s hashed URI in the claim. case assertionHashedUriMatch = "assertion.hashedURI.match" @@ -34,9 +45,54 @@ public enum ValidationStatusCode: String, Codable { /// Hash of a box-based asset matches the hash declared in the BMFF hash assertion. case assertionBmffHashMatch = "assertion.bmffHash.match" + /// Hash of the specified boxes matches the hash declared in the boxes hash assertion. + case assertionBoxesHashMatch = "assertion.boxesHash.match" + + /// Hash of a collection of assets matches the value declared in the collection hash assertion. + case assertionCollectionHashMatch = "assertion.collectionHash.match" + + /// The alternative content representation assertion hash matched the expected value. + case assertionAlternativeContentRepresentationMatch = "assertion.alternativeContentRepresentation.match" + + /// Hash of multiple referenced assets matches the hash declared in the multi-asset hash assertion. + case assertionMultiAssetHashMatch = "assertion.multiAssetHash.match" + /// A non-embedded (remote) assertion was accessible at the time of validation. case assertionAccessible = "assertion.accessible" + /// The claim signature referenced by an ingredient validated successfully. + case ingredientClaimSignatureValidated = "ingredient.claimSignature.validated" + + /// The ingredient’s manifest validated successfully. + case ingredientManifestValidated = "ingredient.manifest.validated" + + + // MARK: - Informational codes + + /// The algorithm used is deprecated but still recognized by the validator. + case algorithmDeprecated = "algorithm.deprecated" + + /// A BMFF hash assertion contained additional exclusions that were ignored during validation. + case assertionBmffHashAdditionalExclusionsPresent = "assertion.bmffHash.additionalExclusionsPresent" + + /// A boxes hash assertion contained additional exclusions that were ignored during validation. + case assertionBoxesHashAdditionalExclusionsPresent = "assertion.boxesHash.additionalExclusionsPresent" + + /// A data hash assertion contained additional exclusions that were ignored during validation. + case assertionDataHashAdditionalExclusionsPresent = "assertion.dataHash.additionalExclusionsPresent" + + /// The provenance of an ingredient could not be determined. + case ingredientUnknownProvenance = "ingredient.unknownProvenance" + + /// The OCSP responder for the signing credential could not be reached. + case signingCredentialOCSPInaccessible = "signingCredential.ocsp.inaccessible" + + /// OCSP checking for the signing credential was skipped. + case signingCredentialOCSPSkipped = "signingCredential.ocsp.skipped" + + + // MARK: - Failure codes + /// The referenced claim in the ingredient’s manifest cannot be found. case claimMissing = "claim.missing" @@ -55,6 +111,9 @@ public enum ValidationStatusCode: String, Codable { /// The claim signature referenced in the ingredient’s claim failed to validate. case claimSignatureMismatch = "claimSignature.mismatch" + /// The claim signature timestamp is outside the validity window of the signing certificate. + case claimSignatureOutsideValidity = "claimSignature.outsideValidity" + /// The manifest has more than one ingredient whose relationship is parentOf. case manifestMultipleParents = "manifest.multipleParents" @@ -118,6 +177,15 @@ public enum ValidationStatusCode: String, Codable { /// An update manifest contains a cloud data assertion referencing an actions assertion. case assertionCloudDataActions = "assertion.cloud-data.actions" + /// More than one hard binding assertion was present when only one is permitted. + case assertionMultipleHardBindings = "assertion.multipleHardBindings" + + /// An assertion contained metadata that is not permitted by the specification. + case assertionMetadataDisallowed = "assertion.metadata.disallowed" + + /// A timestamp assertion is malformed or cannot be parsed. + case assertionTimestampMalformed = "assertion.timestamp.malformed" + /// The value of an alg header, or other header that specifies an algorithm used to compute the value of another field, is unknown or unsupported. case algorithmUnsupported = "algorithm.unsupported" }