Skip to content

Commit

Permalink
fix: Remove c2pa::Signer dependency on `c2pa_crypto::TimeStampProvi…
Browse files Browse the repository at this point in the history
…der` (#718)

This causes problems with UniFFI bindings that can't be addressed.
  • Loading branch information
scouten-adobe authored Dec 6, 2024
1 parent a254623 commit f110ea8
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 142 deletions.
4 changes: 3 additions & 1 deletion internal/crypto/src/time_stamp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ pub use error::TimeStampError;

#[cfg(not(target_arch = "wasm32"))]
mod http_request;
#[cfg(not(target_arch = "wasm32"))]
pub use http_request::{default_rfc3161_request, default_rfc3161_request_async};

mod provider;
pub use provider::{AsyncTimeStampProvider, TimeStampProvider};
pub use provider::{default_rfc3161_message, AsyncTimeStampProvider, TimeStampProvider};

mod response;

Expand Down
5 changes: 4 additions & 1 deletion internal/crypto/src/time_stamp/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ pub trait AsyncTimeStampProvider {
}
}

fn default_rfc3161_message(data: &[u8]) -> Result<Vec<u8>, TimeStampError> {
/// Create an [RFC 3161] time stamp request message for a given piece of data.
///
/// [RFC 3161]: https://datatracker.ietf.org/doc/html/rfc3161
pub fn default_rfc3161_message(data: &[u8]) -> Result<Vec<u8>, TimeStampError> {
let request = time_stamp_message_http(data, DigestAlgorithm::Sha256)?;

let mut body = Vec::<u8>::new();
Expand Down
15 changes: 3 additions & 12 deletions sdk/src/callback_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,13 @@ impl Signer for CallbackSigner {
fn reserve_size(&self) -> usize {
self.reserve_size
}
}

impl TimeStampProvider for CallbackSigner {
fn time_stamp_service_url(&self) -> Option<String> {
fn time_authority_url(&self) -> Option<String> {
self.tsa_url.clone()
}
}

use async_trait::async_trait;
use c2pa_crypto::time_stamp::{AsyncTimeStampProvider, TimeStampProvider};

#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
Expand All @@ -187,19 +184,13 @@ impl AsyncSigner for CallbackSigner {
fn reserve_size(&self) -> usize {
self.reserve_size
}
}

#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl AsyncTimeStampProvider for CallbackSigner {
fn time_stamp_service_url(&self) -> Option<String> {
fn time_authority_url(&self) -> Option<String> {
self.tsa_url.clone()
}

#[cfg(target_arch = "wasm32")]
async fn send_time_stamp_request(
&self,
_message: &[u8],
) -> Option<std::result::Result<Vec<u8>, c2pa_crypto::time_stamp::TimeStampError>> {
async fn send_timestamp_request(&self, _message: &[u8]) -> Option<Result<Vec<u8>>> {
None
}
}
9 changes: 1 addition & 8 deletions sdk/src/cose_sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,6 @@ fn pad_cose_sig(sign1: &mut CoseSign1, end_size: usize) -> Result<Vec<u8>> {
mod tests {
#![allow(clippy::unwrap_used)]

use c2pa_crypto::time_stamp::{TimeStampError, TimeStampProvider};

use super::sign_claim;
use crate::{claim::Claim, utils::test::temp_signer};

Expand Down Expand Up @@ -428,13 +426,8 @@ mod tests {
fn reserve_size(&self) -> usize {
1024
}
}

impl TimeStampProvider for BogusSigner {
fn send_time_stamp_request(
&self,
_message: &[u8],
) -> Option<Result<Vec<u8>, TimeStampError>> {
fn send_timestamp_request(&self, _message: &[u8]) -> Option<crate::error::Result<Vec<u8>>> {
Some(Ok(Vec::new()))
}
}
Expand Down
2 changes: 0 additions & 2 deletions sdk/src/cose_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1504,8 +1504,6 @@ pub mod tests {
}
}

impl c2pa_crypto::time_stamp::TimeStampProvider for OcspSigner {}

let ocsp_signer = OcspSigner {
signer: Box::new(signer),
ocsp_rsp: ocsp_rsp_data.to_vec(),
Expand Down
12 changes: 5 additions & 7 deletions sdk/src/openssl/ec_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// specific language governing permissions and limitations under
// each license.

use c2pa_crypto::{openssl::OpenSslMutex, time_stamp::TimeStampProvider, SigningAlg};
use c2pa_crypto::{openssl::OpenSslMutex, SigningAlg};
use openssl::{
ec::EcKey,
hash::MessageDigest,
Expand Down Expand Up @@ -107,14 +107,12 @@ impl Signer for EcSigner {
Ok(certs)
}

fn reserve_size(&self) -> usize {
1024 + self.certs_size + self.timestamp_size // the Cose_Sign1 contains complete certs and timestamps so account for size
fn time_authority_url(&self) -> Option<String> {
self.tsa_url.clone()
}
}

impl TimeStampProvider for EcSigner {
fn time_stamp_service_url(&self) -> Option<String> {
self.tsa_url.clone()
fn reserve_size(&self) -> usize {
1024 + self.certs_size + self.timestamp_size // the Cose_Sign1 contains complete certs and timestamps so account for size
}
}

Expand Down
12 changes: 5 additions & 7 deletions sdk/src/openssl/ed_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// specific language governing permissions and limitations under
// each license.

use c2pa_crypto::{openssl::OpenSslMutex, time_stamp::TimeStampProvider, SigningAlg};
use c2pa_crypto::{openssl::OpenSslMutex, SigningAlg};
use openssl::{
pkey::{PKey, Private},
x509::X509,
Expand Down Expand Up @@ -97,14 +97,12 @@ impl Signer for EdSigner {
Ok(certs)
}

fn reserve_size(&self) -> usize {
1024 + self.certs_size + self.timestamp_size // the Cose_Sign1 contains complete certs and timestamps so account for size
fn time_authority_url(&self) -> Option<String> {
self.tsa_url.clone()
}
}

impl TimeStampProvider for EdSigner {
fn time_stamp_service_url(&self) -> Option<String> {
self.tsa_url.clone()
fn reserve_size(&self) -> usize {
1024 + self.certs_size + self.timestamp_size // the Cose_Sign1 contains complete certs and timestamps so account for size
}
}

Expand Down
15 changes: 5 additions & 10 deletions sdk/src/openssl/temp_signer_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl AsyncSignerAdapter {
alg,
certs: signer.certs().unwrap_or_default(),
reserve_size: signer.reserve_size(),
tsa_url: signer.time_stamp_service_url(),
tsa_url: signer.time_authority_url(),
ocsp_val: signer.ocsp_val(),
}
}
Expand Down Expand Up @@ -91,16 +91,11 @@ impl crate::AsyncSigner for AsyncSignerAdapter {
self.reserve_size
}

async fn ocsp_val(&self) -> Option<Vec<u8>> {
self.ocsp_val.clone()
fn time_authority_url(&self) -> Option<String> {
self.tsa_url.clone()
}
}

#[cfg(test)]
#[cfg(feature = "openssl_sign")]
#[async_trait::async_trait]
impl c2pa_crypto::time_stamp::AsyncTimeStampProvider for AsyncSignerAdapter {
fn time_stamp_service_url(&self) -> Option<String> {
self.tsa_url.clone()
async fn ocsp_val(&self) -> Option<Vec<u8>> {
self.ocsp_val.clone()
}
}
155 changes: 122 additions & 33 deletions sdk/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@
// specific language governing permissions and limitations under
// each license.

use c2pa_crypto::{
time_stamp::{AsyncTimeStampProvider, TimeStampError, TimeStampProvider},
SigningAlg,
};
use async_trait::async_trait;
use c2pa_crypto::SigningAlg;

use crate::{DynamicAssertion, Result};

/// The `Signer` trait generates a cryptographic signature over a byte array.
///
/// This trait exists to allow the signature mechanism to be extended.
pub trait Signer: TimeStampProvider {
pub trait Signer {
/// Returns a new byte array which is a signature over the original.
fn sign(&self, data: &[u8]) -> Result<Vec<u8>>;

Expand All @@ -35,6 +34,46 @@ pub trait Signer: TimeStampProvider {
/// than this value.
fn reserve_size(&self) -> usize;

/// URL for time authority to time stamp the signature
fn time_authority_url(&self) -> Option<String> {
None
}

/// Additional request headers to pass to the time stamp authority.
///
/// IMPORTANT: You should not include the "Content-type" header here.
/// That is provided by default.
fn timestamp_request_headers(&self) -> Option<Vec<(String, String)>> {
None
}

fn timestamp_request_body(&self, message: &[u8]) -> Result<Vec<u8>> {
c2pa_crypto::time_stamp::default_rfc3161_message(message).map_err(|e| e.into())
}

/// Request RFC 3161 timestamp to be included in the manifest data
/// structure.
///
/// `message` is a preliminary hash of the claim
///
/// The default implementation will send the request to the URL
/// provided by [`Self::time_authority_url()`], if any.
#[allow(unused)] // message not used on WASM
fn send_timestamp_request(&self, message: &[u8]) -> Option<Result<Vec<u8>>> {
#[cfg(not(target_arch = "wasm32"))]
if let Some(url) = self.time_authority_url() {
if let Ok(body) = self.timestamp_request_body(message) {
let headers: Option<Vec<(String, String)>> = self.timestamp_request_headers();
return Some(
c2pa_crypto::time_stamp::default_rfc3161_request(&url, headers, &body, message)
.map_err(|e| e.into()),
);
}
}

None
}

/// OCSP response for the signing cert if available
/// This is the only C2PA supported cert revocation method.
/// By pre-querying the value for a your signing cert the value can
Expand Down Expand Up @@ -85,16 +124,14 @@ pub(crate) trait ConfigurableSigner: Signer + Sized {
) -> Result<Self>;
}

use async_trait::async_trait;

/// The `AsyncSigner` trait generates a cryptographic signature over a byte array.
///
/// This trait exists to allow the signature mechanism to be extended.
///
/// Use this when the implementation is asynchronous.
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
pub trait AsyncSigner: Sync + AsyncTimeStampProvider {
pub trait AsyncSigner: Sync {
/// Returns a new byte array which is a signature over the original.
async fn sign(&self, data: Vec<u8>) -> Result<Vec<u8>>;

Expand All @@ -109,6 +146,49 @@ pub trait AsyncSigner: Sync + AsyncTimeStampProvider {
/// than this value.
fn reserve_size(&self) -> usize;

/// URL for time authority to time stamp the signature
fn time_authority_url(&self) -> Option<String> {
None
}

/// Additional request headers to pass to the time stamp authority.
///
/// IMPORTANT: You should not include the "Content-type" header here.
/// That is provided by default.
fn timestamp_request_headers(&self) -> Option<Vec<(String, String)>> {
None
}

fn timestamp_request_body(&self, message: &[u8]) -> Result<Vec<u8>> {
c2pa_crypto::time_stamp::default_rfc3161_message(message).map_err(|e| e.into())
}

/// Request RFC 3161 timestamp to be included in the manifest data
/// structure.
///
/// `message` is a preliminary hash of the claim
///
/// The default implementation will send the request to the URL
/// provided by [`Self::time_authority_url()`], if any.
async fn send_timestamp_request(&self, message: &[u8]) -> Option<Result<Vec<u8>>> {
// NOTE: This is currently synchronous, but may become
// async in the future.
if let Some(url) = self.time_authority_url() {
if let Ok(body) = self.timestamp_request_body(message) {
let headers: Option<Vec<(String, String)>> = self.timestamp_request_headers();
return Some(
c2pa_crypto::time_stamp::default_rfc3161_request_async(
&url, headers, &body, message,
)
.await
.map_err(|e| e.into()),
);
}
}

None
}

/// OCSP response for the signing cert if available
/// This is the only C2PA supported cert revocation method.
/// By pre-querying the value for a your signing cert the value can
Expand All @@ -131,9 +211,14 @@ pub trait AsyncSigner: Sync + AsyncTimeStampProvider {
}
}

/// The `AsyncSigner` trait generates a cryptographic signature over a byte array.
///
/// This trait exists to allow the signature mechanism to be extended.
///
/// Use this when the implementation is asynchronous.
#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
pub trait AsyncSigner: AsyncTimeStampProvider {
pub trait AsyncSigner {
/// Returns a new byte array which is a signature over the original.
async fn sign(&self, data: Vec<u8>) -> Result<Vec<u8>>;

Expand All @@ -148,6 +233,34 @@ pub trait AsyncSigner: AsyncTimeStampProvider {
/// than this value.
fn reserve_size(&self) -> usize;

/// URL for time authority to time stamp the signature
fn time_authority_url(&self) -> Option<String> {
None
}

/// Additional request headers to pass to the time stamp authority.
///
/// IMPORTANT: You should not include the "Content-type" header here.
/// That is provided by default.
fn timestamp_request_headers(&self) -> Option<Vec<(String, String)>> {
None
}

fn timestamp_request_body(&self, message: &[u8]) -> Result<Vec<u8>> {
c2pa_crypto::time_stamp::default_rfc3161_message(message).map_err(|e| e.into())
}

/// Request RFC 3161 timestamp to be included in the manifest data
/// structure.
///
/// `message` is a preliminary hash of the claim
///
/// The default implementation will send the request to the URL
/// provided by [`Self::time_authority_url()`], if any.
async fn send_timestamp_request(&self, _message: &[u8]) -> Option<Result<Vec<u8>>> {
None
}

/// OCSP response for the signing cert if available
/// This is the only C2PA supported cert revocation method.
/// By pre-querying the value for a your signing cert the value can
Expand Down Expand Up @@ -216,27 +329,3 @@ impl Signer for Box<dyn Signer + Send + Sync> {
(**self).dynamic_assertions()
}
}

impl TimeStampProvider for Box<dyn Signer + Send + Sync> {
fn time_stamp_service_url(&self) -> Option<String> {
(**self).time_stamp_service_url()
}

fn time_stamp_request_headers(&self) -> Option<Vec<(String, String)>> {
(**self).time_stamp_request_headers()
}

fn time_stamp_request_body(
&self,
message: &[u8],
) -> std::result::Result<Vec<u8>, TimeStampError> {
(**self).time_stamp_request_body(message)
}

fn send_time_stamp_request(
&self,
message: &[u8],
) -> Option<std::result::Result<Vec<u8>, TimeStampError>> {
(**self).send_time_stamp_request(message)
}
}
Loading

0 comments on commit f110ea8

Please sign in to comment.