use async_trait::async_trait;
use bcder::{encode::Values, OctetString};
use rand::{thread_rng, Rng};
use x509_certificate::DigestAlgorithm;
use crate::{asn1::rfc3161::TimeStampReq, time_stamp::TimeStampError};
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)
}
#[allow(unused_variables)] fn send_time_stamp_request(&self, message: &[u8]) -> Option<Result<Vec<u8>, TimeStampError>> {
#[cfg(not(target_arch = "wasm32"))]
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,
));
}
}
None
}
}
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
pub trait AsyncTimeStampProvider: Sync {
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)
}
#[allow(unused_variables)] async fn send_time_stamp_request(
&self,
message: &[u8],
) -> Option<Result<Vec<u8>, TimeStampError>> {
#[cfg(not(target_arch = "wasm32"))]
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_async(
&url, headers, &body, message,
)
.await,
);
}
}
None
}
}
#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
pub trait AsyncTimeStampProvider {
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)
}
#[allow(unused_variables)] async fn send_time_stamp_request(
&self,
message: &[u8],
) -> Option<Result<Vec<u8>, TimeStampError>> {
#[cfg(not(target_arch = "wasm32"))]
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_async(
&url, headers, &body, message,
)
.await,
);
}
}
None
}
}
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();
request
.encode_ref()
.write_encoded(bcder::Mode::Der, &mut body)?;
Ok(body)
}
fn time_stamp_message_http(
message: &[u8],
digest_algorithm: DigestAlgorithm,
) -> Result<TimeStampReq, TimeStampError> {
let mut h = digest_algorithm.digester();
h.update(message);
let digest = h.finish();
let mut random = [0u8; 8];
thread_rng().try_fill(&mut random).map_err(|_| {
TimeStampError::InternalError("Unable to generate random number".to_string())
})?;
let request = TimeStampReq {
version: bcder::Integer::from(1_u8),
message_imprint: crate::asn1::rfc3161::MessageImprint {
hash_algorithm: digest_algorithm.into(),
hashed_message: OctetString::new(bytes::Bytes::copy_from_slice(digest.as_ref())),
},
req_policy: None,
nonce: Some(bcder::Integer::from(u64::from_le_bytes(random))),
cert_req: Some(true),
extensions: None,
};
Ok(request)
}