Skip to content

Commit 34b7139

Browse files
feat: Move COSE signing into c2pa_crypto crate (#807)
1 parent 25c89ed commit 34b7139

File tree

16 files changed

+958
-387
lines changed

16 files changed

+958
-387
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ c2pa = { path = "../sdk", version = "0.40.0", features = [
2727
"pdf",
2828
"unstable_api",
2929
] }
30+
c2pa-crypto = { path = "../internal/crypto", version = "0.2.0" }
3031
clap = { version = "4.5.10", features = ["derive", "env"] }
3132
env_logger = "0.11.4"
3233
glob = "0.3.1"

cli/src/callback_signer.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ use std::{
1818

1919
use anyhow::{bail, Context};
2020
use c2pa::{Error, Signer, SigningAlg};
21+
use c2pa_crypto::{
22+
raw_signature::{RawSigner, RawSignerError},
23+
time_stamp::TimeStampProvider,
24+
};
2125

2226
use crate::signer::SignConfig;
2327

@@ -183,6 +187,53 @@ impl Signer for CallbackSigner<'_> {
183187
fn time_authority_url(&self) -> Option<String> {
184188
self.config.tsa_url.clone()
185189
}
190+
191+
fn raw_signer(&self) -> Box<&dyn RawSigner> {
192+
Box::new(self)
193+
}
194+
}
195+
196+
impl RawSigner for CallbackSigner<'_> {
197+
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, RawSignerError> {
198+
self.callback.sign(data).map_err(|e| {
199+
eprintln!("Unable to embed signature into asset. {}", e);
200+
RawSignerError::InternalError(e.to_string())
201+
})
202+
}
203+
204+
fn alg(&self) -> SigningAlg {
205+
self.config.alg
206+
}
207+
208+
fn cert_chain(&self) -> Result<Vec<Vec<u8>>, RawSignerError> {
209+
let cert_contents = std::fs::read(&self.config.sign_cert_path)?;
210+
211+
let mut pems = pem::parse_many(cert_contents).map_err(|_| Error::CoseInvalidCert)?;
212+
// [pem::parse_many] returns an empty vector if you supply invalid contents, like json, for example.
213+
// Check here if the pems vector is empty.
214+
if pems.is_empty() {
215+
return Err(RawSignerError::InvalidSigningCredentials(
216+
"no certificates provided".to_string(),
217+
));
218+
}
219+
220+
let sign_cert = pems
221+
.drain(..)
222+
.map(|p| p.into_contents())
223+
.collect::<Vec<Vec<u8>>>();
224+
225+
Ok(sign_cert)
226+
}
227+
228+
fn reserve_size(&self) -> usize {
229+
self.config.reserve_size
230+
}
231+
}
232+
233+
impl TimeStampProvider for CallbackSigner<'_> {
234+
fn time_stamp_service_url(&self) -> Option<String> {
235+
self.config.tsa_url.clone()
236+
}
186237
}
187238

188239
#[cfg(test)]
@@ -214,7 +265,7 @@ mod test {
214265
let callback = Box::new(mock_callback_signer);
215266
let signer = CallbackSigner::new(callback, config);
216267

217-
assert_eq!(signer.sign(&[]).unwrap(), expected);
268+
assert_eq!(Signer::sign(&signer, &[]).unwrap(), expected);
218269
}
219270

220271
#[test]
@@ -237,7 +288,10 @@ mod test {
237288
let callback = Box::new(mock_callback_signer);
238289
let signer = CallbackSigner::new(callback, config);
239290

240-
assert!(matches!(signer.sign(&[]), Err(Error::EmbeddingError)));
291+
assert!(matches!(
292+
Signer::sign(&signer, &[]),
293+
Err(Error::EmbeddingError)
294+
));
241295
}
242296

243297
#[test]
@@ -291,8 +345,8 @@ mod test {
291345
let callback = Box::<MockSignCallback>::default();
292346
let signer = CallbackSigner::new(callback, esc);
293347

294-
assert_eq!(signer.alg(), expected_alg);
295-
assert_eq!(signer.reserve_size(), expected_reserve_size);
348+
assert_eq!(Signer::alg(&signer), expected_alg);
349+
assert_eq!(Signer::reserve_size(&signer), expected_reserve_size);
296350
}
297351

298352
#[test]

internal/crypto/src/cose/error.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use thiserror::Error;
1515

1616
use crate::{
1717
cose::{CertificateProfileError, CertificateTrustError},
18-
raw_signature::RawSignatureValidationError,
18+
raw_signature::{RawSignatureValidationError, RawSignerError},
1919
time_stamp::TimeStampError,
2020
};
2121

@@ -66,7 +66,15 @@ pub enum CoseError {
6666
#[error(transparent)]
6767
CertificateTrustError(#[from] CertificateTrustError),
6868

69-
/// An error was occurred when interpreting the underlying raw signature.
69+
/// The box size provided for the signature is too small.
70+
#[error("the signature box is too small")]
71+
BoxSizeTooSmall,
72+
73+
/// An error occurred when generating the underlying raw signature.
74+
#[error(transparent)]
75+
RawSignerError(#[from] RawSignerError),
76+
77+
/// An error occurred when interpreting the underlying raw signature.
7078
#[error(transparent)]
7179
RawSignatureValidationError(#[from] RawSignatureValidationError),
7280

internal/crypto/src/cose/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub use error::CoseError;
2929
mod ocsp;
3030
pub use ocsp::{check_ocsp_status, check_ocsp_status_async, OcspFetchPolicy};
3131

32+
mod sign;
33+
pub use sign::{sign, sign_async};
34+
3235
mod sign1;
3336
pub use sign1::{cert_chain_from_sign1, parse_cose_sign1, signing_alg_from_sign1};
3437

0 commit comments

Comments
 (0)