use base64ct::{Base64, Base64UrlUnpadded, Encoding};
use sha2::{Digest, Sha256};
use crate::{digest::DigestAlgorithm, error::AdesError, signer::Signer, tsp::TspClient};
use super::sign::{assemble_jws, sign_inner};
#[cfg(feature = "tsp")]
pub fn sign_t<S>(data: &[u8], signer: &S, tsa: &TspClient) -> Result<Vec<u8>, AdesError>
where
S: Signer,
S::Error: std::error::Error + Send + Sync + 'static,
{
let c = sign_inner(data, signer)?;
let unprotected = timestamp_unprotected(&c.sig_b64url, tsa)?;
Ok(assemble_jws(
&c.header_b64url,
&c.payload_b64url,
&c.sig_b64url,
&unprotected,
))
}
#[cfg(all(feature = "tsp", feature = "ocsp"))]
pub fn sign_lt<S>(
data: &[u8],
signer: &S,
tsa: &TspClient,
ocsp: &crate::ocsp::OcspClient,
) -> Result<Vec<u8>, AdesError>
where
S: Signer,
S::Error: std::error::Error + Send + Sync + 'static,
{
let c = sign_inner(data, signer)?;
let cert = signer.certificate();
let ocsp_resp = match ocsp.raw_response(cert, cert) {
Ok(resp) => Some(resp),
Err(AdesError::Ocsp(_)) => None,
Err(e) => return Err(e),
};
let unprotected = match ocsp_resp {
Some(ocsp_bytes) => {
let tst_entry = tst_etsi_u_entry(&c.sig_b64url, tsa)?;
let rvals_json = format!(
r#"{{"rVals":{{"ocspVals":["{}"]}}}}"#,
Base64::encode_string(&ocsp_bytes)
);
let rvals_entry = Base64UrlUnpadded::encode_string(rvals_json.as_bytes());
format!(r#"{{"etsiU":["{tst_entry}","{rvals_entry}"]}}"#)
}
None => timestamp_unprotected(&c.sig_b64url, tsa)?,
};
Ok(assemble_jws(
&c.header_b64url,
&c.payload_b64url,
&c.sig_b64url,
&unprotected,
))
}
#[cfg(feature = "tsp")]
fn tst_etsi_u_entry(sig_b64url: &str, tsa: &TspClient) -> Result<String, AdesError> {
let imprint = Sha256::digest(sig_b64url.as_bytes());
let tsr = tsa.timestamp(&imprint, DigestAlgorithm::Sha256)?;
let tsr_b64 = Base64::encode_string(&tsr);
let sig_tst_json = format!(r#"{{"sigTst":{{"tstTokens":[{{"val":"{tsr_b64}"}}]}}}}"#);
Ok(Base64UrlUnpadded::encode_string(sig_tst_json.as_bytes()))
}
#[cfg(feature = "tsp")]
fn timestamp_unprotected(sig_b64url: &str, tsa: &TspClient) -> Result<String, AdesError> {
let entry = tst_etsi_u_entry(sig_b64url, tsa)?;
Ok(format!(r#"{{"etsiU":["{entry}"]}}"#))
}