use async_trait::async_trait;
use bcder::{encode::Values, OctetString};
use c2pa_raw_crypto::oids::SHA256_OID;
use rand::RngExt;
use sha2::{Digest, Sha256};
use crate::{
context::Context,
crypto::{asn1::rfc3161::TimeStampReq, time_stamp::TimeStampError},
maybe_send_sync::MaybeSync,
};
fn raw_crypto_oid_to_bcder_oid(oid: &c2pa_raw_crypto::Oid) -> bcder::Oid {
bcder::Oid(bytes::Bytes::copy_from_slice(oid.as_bytes()))
}
pub trait TimeStampProvider {
fn time_stamp_service_url(&self) -> Option<String> {
None
}
fn time_stamp_request_headers(&self) -> Option<Vec<(String, String)>> {
None
}
fn time_stamp_request_body(&self, message: &[u8]) -> Result<Vec<u8>, TimeStampError> {
default_rfc3161_message(message)
}
fn send_time_stamp_request(&self, message: &[u8]) -> Option<Result<Vec<u8>, TimeStampError>> {
if let Some(url) = self.time_stamp_service_url() {
if let Ok(body) = self.time_stamp_request_body(message) {
let headers: Option<Vec<(String, String)>> = self.time_stamp_request_headers();
let context = Context::new();
return Some(super::http_request::default_rfc3161_request(
&url, headers, &body, message, &context,
));
}
}
None
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait AsyncTimeStampProvider: MaybeSync {
fn time_stamp_service_url(&self) -> Option<String> {
None
}
fn time_stamp_request_headers(&self) -> Option<Vec<(String, String)>> {
None
}
fn time_stamp_request_body(&self, message: &[u8]) -> Result<Vec<u8>, TimeStampError> {
default_rfc3161_message(message)
}
async fn send_time_stamp_request(
&self,
message: &[u8],
) -> Option<Result<Vec<u8>, TimeStampError>> {
if let Some(url) = self.time_stamp_service_url() {
if let Ok(body) = self.time_stamp_request_body(message) {
let headers: Option<Vec<(String, String)>> = self.time_stamp_request_headers();
let context = Context::new();
return Some(
super::http_request::default_rfc3161_request_async(
&url, headers, &body, message, &context,
)
.await,
);
}
}
None
}
}
pub fn default_rfc3161_message(data: &[u8]) -> Result<Vec<u8>, TimeStampError> {
let mut hasher = Sha256::new();
hasher.update(data);
let digest = hasher.finalize();
let mut random = [0u8; 8];
rand::rng().fill(&mut random);
let sha256_oid = raw_crypto_oid_to_bcder_oid(&SHA256_OID);
let request = TimeStampReq {
version: bcder::Integer::from(1_u8),
message_imprint: crate::crypto::asn1::rfc3161::MessageImprint {
hash_algorithm: crate::crypto::asn1::AlgorithmIdentifier {
algorithm: sha256_oid,
},
hashed_message: OctetString::new(bytes::Bytes::copy_from_slice(&digest)),
},
req_policy: None,
nonce: Some(bcder::Integer::from(u64::from_le_bytes(random))),
cert_req: Some(true),
extensions: None,
};
let mut body = Vec::<u8>::new();
request
.encode_ref()
.write_encoded(bcder::Mode::Der, &mut body)?;
Ok(body)
}