C2PA Rust Library

repository·main·Indexed 18 days ago

https://github.com/contentauth/c2pa-rs

A core component of the Content Authenticity Initiative (CAI) SDK for certifying the source and history (provenance) of media content. It implements C2PA and CAWG identity assertion specifications, providing capabilities for creating, signing, parsing, and embedding manifests into supported file formats. The project includes the c2pa crate, a C-compatible FFI (c2pa-c-ffi) for cross-language integration, and the c2patool command line utility.

Tokens
64.7K
Snippets
178
Records
269
Agent score
61%

What's inside c2pa-rs

  1. Overview of C2PA Rust library features

    main

    The c2pa crate implements a subset of the C2PA technical specification and the CAWG identity assertion specification. Key capabilities include:

    • Claims and Manifests: Create and sign C2PA claims and manifests.
    • Identity Assertions: Create, sign, and validate CAWG identity assertions within manifests.
    • Embedding: Embed manifests into supported file formats.
    • Parsing: Parse and validate existing manifests within supported file formats.
    • C API Support: Provides a C FFI (c2pa-c-ffi) for integration with C or other C-interfacing languages.
  2. Use the C2PA C API for cross-language integration

    main

    The c2pa_c_ffi package provides a C-compatible interface for the C2PA Rust library. This allows you to integrate content authenticity features into applications written in C, or any language capable of interfacing with C libraries (such as Python, Swift, or C++).

    Dynamic library binaries are exported for Linux, macOS, and Windows. Consumers can use this API by following standard linking procedures for C-based libraries without needing knowledge of Rust.

  3. What is the Context API and how does it work?

    main

    The Context structure is the central configuration hub for the C2PA Rust library. It encapsulates three main components:

    1. Settings: Configuration options for verification, signing, network policies, builder behavior, etc.
    2. HTTP resolvers: Customizable sync and async HTTP clients used for fetching remote manifests.
    3. Signers: Cryptographic signers used to sign manifests (these are automatically created from the provided settings).

    Context is thread-safe and can be shared across your application using Arc<Context>. It is designed to replace the older thread-local Settings pattern, providing explicit dependency management and better testability.

  4. What is weak binding in C2PA?

    main

    Weak binding occurs when the C2PA claim contains a generated instanceID UUID that is not corroborated by any data within the asset itself.

    This happens in two scenarios:

    1. Caller-owns-write: The asset is finalized, has no InstanceID, and the SDK is not allowed to write to it.
    2. Sidecar: The SDK does not modify the asset, and the source asset lacks an InstanceID.

    In these cases, the link between the claim and the asset exists only by convention. To avoid weak binding, ensure the asset has a valid xmpMM:InstanceID before signing.

  5. What is redaction in C2PA

    main

    Redaction is the process of removing an assertion from a prior manifest in the C2PA claim chain. This is typically used for privacy (e.g., removing GPS coordinates) or metadata cleanup.

    When an assertion is redacted, its JUMBF box is replaced with a zero-filled placeholder. This allows verifiers to distinguish between an intentional removal and data corruption.

    Tip: To replace a metadata field instead of just removing it, redact the existing assertion and add a new one with the updated values in the same manifest.

  6. Understand cryptographic library selection for Signing and Validation

    main

    The c2pa crate selects different underlying cryptographic libraries based on the target platform and enabled feature flags. This affects which SigningAlg variants are available and how they are implemented.

    Signing

    When performing signing operations, the implementation depends on whether you are using the default (OpenSSL), the rust_native_crypto feature, or targeting WASM.

    Validation

    When validating signatures, the implementation depends on whether you are using the default (OpenSSL) or the rust_native_crypto feature/WASM.

    Note: es512 signing is not supported in WASM environments.

    | C2PA `SigningAlg` | Default (*) | `feature = "rust_native_crypto"` (*) | WASM |
    | --- | --- | --- | --- |
    | `es256` | OpenSSL | `p256` | `p256` |
    | `es384` | OpenSSL | `p384` | `p384` |
    | `es512` | OpenSSL | OpenSSL | ❌ |
    | `ed25519` | OpenSSL | `ed25519-dalek` | `ed25519-dalek` |
    | `ps256` | OpenSSL | `rsa` | `rsa` |
    | `ps384` | OpenSSL | `rsa` | `rsa` |
    | `ps512` | OpenSSL | `rsa` | `rsa` |
  7. Understand the relationship between Source, Parent, and Ingredient assets

    main

    In C2PA workflows, it is important to distinguish between different asset roles:

    • Parent asset: An asset that contains a manifest store.
    • Parent ingredient: A hashed and validated version of a parent asset, used to represent its contribution to a new asset.
    • Source asset: The asset that is actually hashed and signed. This might be a rendition (e.g., an exported JPEG) from an editing application that did not preserve the original manifest.
    • Signed output: The final product, consisting of the source asset and a new manifest store that includes the parent ingredient.

    If a source asset has a manifest store but no parent ingredient is defined, the SDK will attempt to generate a parent ingredient from the parent asset.

  8. Optional Asset Handler traits

    main

    Beyond the mandatory traits, handlers can implement several optional traits to provide advanced capabilities:

    AssetPatch

    Used for in-place binary patching. This optimizes manifest updates by patching bytes in-place without rewriting the whole file. This only works when the new store is the same size as the existing one.

    pub trait AssetPatch {
        fn patch_cai_store(&self, asset_path: &Path, store_bytes: &[u8]) -> Result<()>;
    }

    RemoteRefEmbed

    Used for embedding remote manifest reference URLs into the asset's XMP metadata.

    pub trait RemoteRefEmbed {
        fn embed_reference(&self, asset_path: &Path, embed_ref: RemoteRefEmbedType) -> Result<()>;
        fn embed_reference_to_stream(
            &self,
            source_stream: &mut dyn CAIRead,
            output_stream: &mut dyn CAIReadWrite,
            embed_ref: RemoteRefEmbedType,
        ) -> Result<()>;
    }

    AssetBoxHash

    Used for box hash support. It generates a BoxMap describing all hashable regions in the file for c2pa.hash.boxes assertions.

    pub trait AssetBoxHash {
        fn get_box_map(&self, input_stream: &mut dyn CAIRead) -> Result<Vec<BoxMap>>;
    }

    ComposedManifestRef

    Used for pre-composed manifest wrapping. It wraps raw manifest store bytes into the format-specific container structure (e.g., JPEG XT headers for JPEG, or a caBX chunk for PNG).

    pub trait ComposedManifestRef {
        fn compose_manifest(&self, manifest_data: &[u8], format: &str) -> Result<Vec<u8>>;
    }
    NOTE

    When ComposedManifestRef is used, the asset handler is not performing the manifest embedding; the API provides a composed manifest ready for direct insertion.

  9. How the deprecation and removal process works

    main

    When an API is replaced, the SDK follows a three-stage process to ensure developers have time to migrate:

    1. Stage 1: Deprecation notice: The item is marked as deprecated in the source code with a message pointing to a replacement. This is delivered in a minor release.
    2. Stage 2: Grace period: The deprecated API remains functional. The minimum grace periods are:
      • Pre-1.0: 60 days
      • Post-1.0: 90 days
    3. Stage 3: Removal: The item is removed from the API.
      • Post-1.0: Removed in the next major release.
      • Pre-1.0: Removed in the next 0.x.0 release.

    Note: Deprecations are only issued once a replacement is available. In cases of serious security vulnerabilities, the grace period may be bypassed.

  10. How FLAC C2PA manifest storage is implemented

    main

    C2PA-RS implements manifest storage for FLAC files by embedding the manifest within an optional ID3v2 tag prepended to the FLAC stream.

    According to the C2PA specification, the manifest is stored as the Encapsulated object data of a General Encapsulated Object (GEOB).

    Key Technical Details:

    • MIME Type: The GEOB must use the JUMBF media type: application/c2pa. The implementation also supports the deprecated application/x-c2pa-manifest-store for reading.
    • File Layout: The file structure follows [optional ID3v2][fLaC stream].
    • Detection Logic:
      • If the first 3 bytes are ID3, an ID3v2 tag is present. The implementation reads the ID3 header to determine size and treats the remainder as the FLAC stream.
      • If the first 4 bytes are fLaC, the file is treated as a pure FLAC stream without an ID3 block.
    • Writing Behavior: When writing a manifest, the FLAC stream itself is not modified; instead, an ID3 block containing the GEOB frame is added or replaced at the beginning of the file.
  11. Understand InstanceID behavior when the caller owns the write

    main

    If the asset is already finalized before the SDK is invoked (the SDK reads but does not write), the SDK cannot modify the asset's XMP. The behavior is fixed:

    • If the source has an InstanceID: The SDK uses the existing InstanceID in the C2PA claim. No XMP is written.
    • If the source has no InstanceID: The SDK generates a UUID for the claim only. Because the SDK cannot write to the asset, the binding between the claim and the asset is weak.

    In this mode, the caller is responsible for ensuring the asset's InstanceID is correct before invoking the SDK.

  12. Understand the Context API for configuration

    main

    The library uses a Context structure to manage configuration for C2PA operations. This replaces the older global Settings pattern and provides several advantages:

    • Thread-safety: Context is Send + Sync, meaning it can be safely shared across multiple threads using Arc<Context>.
    • Isolation: You can instantiate multiple Context instances, each with its own unique configuration, rather than relying on a single global state.
    • Compatibility: Existing JSON or TOML settings files remain compatible with the Context API.
    • Automatic Signer Management: Signers are automatically created from the provided settings when required by an operation.