feat: Support CAWG callback signing via c_ffi#2118
Merged
Conversation
Replace AsyncRawSigner with AsyncSigner throughout AsyncX509CredentialHolder and AsyncIdentityAssertionSigner, using AsyncSignerWrapper from cose_sign.rs to bridge into the COSE signing path. Rename from_async_raw_signer to from_async_signer. Simplify test setup to use async_test_signer() directly. Apply the same treatment to the sync side: replace hardcoded Box<dyn Signer + Send + Sync> with BoxedSigner in X509CredentialHolder, IdentityAssertionSigner, and IdentityAssertionBuilder, fixing WASM build failures. Add cfg-conditional Send/Sync handling to IdentityAssertionBuilder matching the pattern used by its async counterpart. Add IdentityAssertionSigner::from_cawg_x509 as a convenience constructor for combining a C2PA signer with a CAWG X.509 identity assertion signer. Add c2pa_create_cawg_signer( takes C2paSigner pointers plus null-terminated arrays for referenced_assertions and roles, delegating to from_cawg_x509." Expose SignerWrapper and AsyncSignerWrapper as pub(crate) for use across the crate.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2118 +/- ##
==========================================
- Coverage 78.44% 78.33% -0.12%
==========================================
Files 177 176 -1
Lines 45503 45725 +222
==========================================
+ Hits 35695 35818 +123
- Misses 9808 9907 +99 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Merging this PR will not alter performance
Comparing Footnotes
|
…_cawg_x509 → with_x509_identity Remove CAWG-specific naming from the C and Rust identity signer APIs Replace read_null_terminated_cstr_array with safer cstr_array_or_return_null! macro that enforces a max length and errors on invalid UTF-8 Add unit tests for with_x509_identity (Rust) and c2pa_identity_signer_create (C FFI)
Contributor
|
This PR contains breaking changes. Are downstream SDKs affected by changes? Given it's the C FFI. I would think so? |
tmathern
reviewed
May 8, 2026
tmathern
approved these changes
May 8, 2026
Remove the CLI-local CallbackSigner, CallbackSignerConfig, and ExternalProcessRunner in favour of c2pa::CallbackSigner from the SDK. The subprocess invocation logic is now a closure inside make_subprocess_signer, and the CAWG identity signer path now correctly reads the signing cert from cawg_x509_signer settings rather than always falling back to the C2PA manifest's sign_cert.
… signer tests c2patool can now act as its own subprocess signer via C2PATOOL_SIGN_MODE (set automatically by --signer-path/--identity-signer-path). Supports c2pa, cawg, and fail modes; both signer paths fall back to baked-in test certs when none are configured. Restores and adds integration tests for subprocess signing, CAWG identity signing, not-found errors, and signer failures using C2PATOOL_FORCE_SIGN_MODE.
…RawSigner-only - Reverts changed to the Identity RawSigner - Add OwnedSignerWrapper to signer.rs (BoxedSigner → RawSigner adapter, inverse of RawSignerWrapper) - Make CawgX509IdentitySigner pub(crate) with two constructors: from_settings (builds RawSigner from cert/key bytes eagerly) and from_signer (wraps a BoxedSigner via OwnedSignerWrapper); both store the identity signer as Arc<dyn RawSigner + Send + Sync> so dynamic_assertions() clones the Arc instead of rebuilding each call - Add ArcRawSigner adapter to delegate through the Arc - Add public create_signer::from_x509_identity as the c2pa-layer entry point for combined C2PA + X.509 identity signing - Update c2pa C FFI and c2patool CLI to use create_signer::from_x509_identity
Introduce a --signer-info protocol: before signing, c2patool calls the subprocess with --signer-info and expects a JSON response containing alg, sign_cert, and optionally tsa_url and reserve_size. The signer is the only party that knows its maximum signature size, so reserve_size now flows from the signer rather than from a --reserve-size CLI flag. - Add reserve_size: Option<usize> to SignerInfo; signer declares it via --signer-info, c2patool sets it on CallbackSigner - Hide --reserve-size (deprecated); signer-provided value takes precedence - Add compat_mode: only pass --alg/--reserve-size to subprocess when cert/alg came from settings (legacy path); new --signer-info signers receive neither - Add hidden test-signer subcommand as a test double (replaces C2PATOOL_SIGN_MODE env var); supports --signer-info and --fail - Add cli/docs/signing.md covering the full signing protocol, both subprocess and settings-only paths, and how to write your own signer - Fix Settings::from_file deprecation in signer.rs - Update integration tests for new error messages and subcommand protocol
scouten-adobe
approved these changes
May 15, 2026
cawg callback unit tests also remove perf from make test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replace AsyncRawSigner with AsyncSigner throughout AsyncX509CredentialHolder and AsyncIdentityAssertionSigner, using AsyncSignerWrapper from cose_sign.rs to bridge into the COSE signing path. Rename from_async_raw_signer to from_async_signer. Simplify test setup to use async_test_signer() directly.
Apply the same treatment to the sync side: replace hardcoded Box<dyn Signer + Send + Sync> with BoxedSigner in X509CredentialHolder, IdentityAssertionSigner, and IdentityAssertionBuilder, fixing WASM build failures. Add cfg-conditional Send/Sync handling to IdentityAssertionBuilder matching the pattern used by its async counterpart.
Add IdentityAssertionSigner::from_cawg_x509 as a convenience constructor for combining a C2PA signer with a CAWG X.509 identity assertion signer.
Add c2pa_create_cawg_signer(
takes C2paSigner pointers plus null-terminated arrays for referenced_assertions and roles, delegating to from_cawg_x509."
Expose SignerWrapper and
AsyncSignerWrapper as pub(crate) for use across the crate.