use async_trait::async_trait;
use crate::{
crypto::{
cose::{sign_async, TimeStampStorage},
raw_signature::AsyncRawSigner,
},
identity::{
builder::{AsyncCredentialHolder, IdentityBuilderError},
SignerPayload,
},
};
#[cfg(not(target_arch = "wasm32"))]
pub struct AsyncX509CredentialHolder(Box<dyn AsyncRawSigner + Send + Sync + 'static>);
#[cfg(target_arch = "wasm32")]
pub struct AsyncX509CredentialHolder(Box<dyn AsyncRawSigner + 'static>);
impl AsyncX509CredentialHolder {
#[cfg(not(target_arch = "wasm32"))]
pub fn from_async_raw_signer(signer: Box<dyn AsyncRawSigner + Send + Sync + 'static>) -> Self {
Self(signer)
}
#[cfg(target_arch = "wasm32")]
pub fn from_async_raw_signer(signer: Box<dyn AsyncRawSigner + 'static>) -> Self {
Self(signer)
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl AsyncCredentialHolder for AsyncX509CredentialHolder {
fn sig_type(&self) -> &'static str {
super::CAWG_X509_SIG_TYPE
}
fn reserve_size(&self) -> usize {
self.0.reserve_size()
}
async fn sign(&self, signer_payload: &SignerPayload) -> Result<Vec<u8>, IdentityBuilderError> {
let mut sp_cbor: Vec<u8> = vec![];
c2pa_cbor::to_writer(&mut sp_cbor, signer_payload)
.map_err(|e| IdentityBuilderError::CborGenerationError(e.to_string()))?;
Ok(sign_async(
self.0.as_ref(),
&sp_cbor,
None,
TimeStampStorage::V2_sigTst2_CTT,
)
.await
.map_err(|e| IdentityBuilderError::SignerError(e.to_string()))?)
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::panic)]
#![allow(clippy::unwrap_used)]
use std::io::{Cursor, Seek};
use c2pa_macros::c2pa_test_async;
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
use wasm_bindgen_test::wasm_bindgen_test;
use crate::{
crypto::{cose::Verifier, raw_signature},
identity::{
builder::{AsyncIdentityAssertionBuilder, AsyncIdentityAssertionSigner},
tests::fixtures::{cert_chain_and_private_key_for_alg, manifest_json, parent_json},
x509::{AsyncX509CredentialHolder, X509SignatureVerifier},
IdentityAssertion,
},
status_tracker::StatusTracker,
Builder, Reader, SigningAlg,
};
const TEST_IMAGE: &[u8] = include_bytes!("../../../tests/fixtures/CA.jpg");
const TEST_THUMBNAIL: &[u8] = include_bytes!("../../../tests/fixtures/thumbnail.jpg");
#[c2pa_test_async]
async fn simple_case_async() {
let settings = crate::settings::Settings::default()
.with_value("core.decode_identity_assertions", false)
.unwrap();
let context = crate::Context::new()
.with_settings(settings)
.unwrap()
.into_shared();
let format = "image/jpeg";
let mut source = Cursor::new(TEST_IMAGE);
let mut dest = Cursor::new(Vec::new());
let mut builder = Builder::from_shared_context(&context)
.with_definition(manifest_json())
.unwrap();
builder
.add_ingredient_from_stream(parent_json(), format, &mut source)
.unwrap();
builder
.add_resource("thumbnail.jpg", Cursor::new(TEST_THUMBNAIL))
.unwrap();
let mut c2pa_signer =
AsyncIdentityAssertionSigner::from_test_credentials(SigningAlg::Ps256);
let (cawg_cert_chain, cawg_private_key) =
cert_chain_and_private_key_for_alg(SigningAlg::Ed25519);
let cawg_raw_signer = raw_signature::async_signer_from_cert_chain_and_private_key(
&cawg_cert_chain,
&cawg_private_key,
SigningAlg::Ed25519,
None,
)
.unwrap();
let x509_holder = AsyncX509CredentialHolder::from_async_raw_signer(cawg_raw_signer);
let iab = AsyncIdentityAssertionBuilder::for_credential_holder(x509_holder);
c2pa_signer.add_identity_assertion(iab);
builder
.sign_async(&c2pa_signer, format, &mut source, &mut dest)
.await
.unwrap();
dest.rewind().unwrap();
let manifest_store = Reader::from_shared_context(&context)
.with_stream_async(format, &mut dest)
.await
.unwrap();
assert_eq!(manifest_store.validation_status(), None);
let manifest = manifest_store.active_manifest().unwrap();
let mut st = StatusTracker::default();
let mut ia_iter = IdentityAssertion::from_manifest(manifest, &mut st);
let ia = ia_iter.next().unwrap().unwrap();
assert!(ia_iter.next().is_none());
drop(ia_iter);
let x509_verifier = X509SignatureVerifier {
cose_verifier: Verifier::IgnoreProfileAndTrustPolicy,
};
let sig_info = ia
.validate(manifest, &mut st, &x509_verifier)
.await
.unwrap();
let cert_info = &sig_info.cert_info;
assert_eq!(cert_info.alg.unwrap(), SigningAlg::Ed25519);
assert_eq!(
cert_info.issuer_org.as_ref().unwrap(),
"C2PA Test Signing Cert"
);
}
}