use async_trait::async_trait;
use bcder::{encode::Values, OctetString};
use rand::{thread_rng, Rng};
use sha2::{Digest, Sha256};
use crate::{
crypto::{
asn1::rfc3161::TimeStampReq,
raw_signature::oids::{ans1_oid_bcder_oid, SHA256_OID},
time_stamp::TimeStampError,
},
http::SyncGenericResolver,
maybe_send_sync::MaybeSync,
};
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();
return Some(super::http_request::default_rfc3161_request(
&url,
headers,
&body,
message,
&SyncGenericResolver::with_redirects().unwrap_or_default(),
));
}
}
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) {
use crate::http::AsyncGenericResolver;
let headers: Option<Vec<(String, String)>> = self.time_stamp_request_headers();
return Some(
super::http_request::default_rfc3161_request_async(
&url,
headers,
&body,
message,
&AsyncGenericResolver::with_redirects().unwrap_or_default(),
)
.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];
thread_rng().try_fill(&mut random).map_err(|_| {
TimeStampError::InternalError("Unable to generate random number".to_string())
})?;
let sha256_oid = ans1_oid_bcder_oid(&SHA256_OID)
.ok_or_else(|| TimeStampError::InternalError("Invalid SHA-256 OID".to_string()))?;
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)
}