1#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4
5use core::fmt;
6use der::{Decode, Encode};
7use der::referenced::OwnedToRef;
8use sha2::Digest as _;
9
10#[derive(Debug)]
12pub enum Error {
13 Http(String),
15 Parse(String),
17 Verify(String),
19 Digest(String),
21}
22
23impl fmt::Display for Error {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Error::Http(e) => write!(f, "http: {e}"),
27 Error::Parse(e) => write!(f, "parse: {e}"),
28 Error::Verify(e) => write!(f, "verify: {e}"),
29 Error::Digest(e) => write!(f, "digest: {e}"),
30 }
31 }
32}
33
34impl std::error::Error for Error {}
35
36pub struct TsaRequest {
38 pub imprint_alg: &'static str,
40 pub imprint: Vec<u8>,
42 pub policy_oid: Option<String>,
44 pub nonce: [u8; 16],
46 pub cert_req: bool,
48}
49
50#[derive(Clone, Debug)]
52pub struct TsaResponse {
53 pub der: Vec<u8>,
55 pub gen_time_unix: i64,
57 pub serial_hex: String,
59 pub tsa_kid: String,
61}
62
63pub fn request_timestamp(url: &str, req: &TsaRequest) -> Result<TsaResponse, Error> {
65 let der_req = build_timestamp_req_der(req)?;
66 let mut res = ureq::post(url)
67 .content_type("application/timestamp-query")
68 .send(der_req.as_slice())
69 .map_err(|e| Error::Http(e.to_string()))?;
70 let der = res
71 .body_mut()
72 .read_to_vec()
73 .map_err(|e| Error::Http(e.to_string()))?;
74 parse_basic_response(&der)
75}
76
77pub fn verify_token(
79 der: &[u8],
80 expected_alg: &str,
81 expected_imprint: &[u8],
82 expected_nonce: Option<&[u8]>,
83 trust_anchors: &[Vec<u8>],
84) -> Result<TsaResponse, Error> {
85 let tsr = x509_tsp::TimeStampResp::from_der(der).map_err(|e| Error::Parse(e.to_string()))?;
87 let status_val = tsr.status.status as u8;
88 if status_val > 1 {
89 return Err(Error::Verify(format!("status {} not granted", status_val)));
90 }
91 let tst = tsr
92 .time_stamp_token
93 .ok_or_else(|| Error::Parse("missing token".into()))?;
94 let tst_der = tst.to_der().map_err(|e| Error::Parse(e.to_string()))?;
95
96 let sd = cms::content_info::ContentInfo::from_der(&tst_der)
98 .map_err(|e| Error::Parse(format!("cms: {e}")))?;
99 let (tst_info_der, signer_spki, serial_hex, signer_cert, chain) =
100 extract_tstinfo_and_signer_spki(&sd).map_err(|e| Error::Parse(e))?;
101
102 let tsti = x509_tsp::TstInfo::from_der(&tst_info_der).map_err(|e| Error::Parse(e.to_string()))?;
103 verify_message_imprint(&tsti, expected_alg, expected_imprint)?;
104 if let (Some(nonce), Some(exp)) = (tsti.nonce.as_ref(), expected_nonce) {
105 if nonce.as_bytes() != exp {
106 return Err(Error::Verify("nonce mismatch".into()));
107 }
108 }
109
110 verify_eku_and_trust(&signer_cert, &chain, trust_anchors)?;
112 let signer_der = signer_cert.to_der().map_err(|e| Error::Parse(format!("signer der: {e}")))?;
113 verify_cms_signed_attrs(&sd, &signer_der, &signer_spki)?;
114 let tsa_kid = crate::crypto::kid_from_spki_der(&signer_spki);
115 let gen_time_unix = tsti.gen_time.to_unix_duration().as_secs() as i64;
116 Ok(TsaResponse {
117 der: der.to_vec(),
118 gen_time_unix,
119 serial_hex,
120 tsa_kid,
121 })
122}
123
124fn build_timestamp_req_der(req: &TsaRequest) -> Result<Vec<u8>, Error> {
127 use cms::cert::x509::spki::AlgorithmIdentifier;
129 use der::asn1::{Int, OctetString};
130 use der::oid::ObjectIdentifier;
131 use x509_tsp::{MessageImprint, TimeStampReq, TspVersion};
132
133 let alg_oid: ObjectIdentifier = match req.imprint_alg {
134 "sha512" => const_oid::db::rfc5912::ID_SHA_512,
135 "shake256-64" => ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.12"),
137 other => return Err(Error::Digest(other.into())),
138 };
139
140 let alg = AlgorithmIdentifier { oid: alg_oid, parameters: None };
141 let hashed_message = OctetString::new(req.imprint.clone())
142 .map_err(|e| Error::Parse(e.to_string()))?;
143 let imprint = MessageImprint { hash_algorithm: alg, hashed_message };
144 let tsreq = TimeStampReq {
145 version: TspVersion::V1,
146 message_imprint: imprint,
147 req_policy: req.policy_oid.as_deref().and_then(|s| s.parse().ok()),
148 nonce: Some(Int::new(&req.nonce).map_err(|e| Error::Parse(e.to_string()))?),
149 cert_req: req.cert_req,
150 extensions: None,
151 };
152 tsreq
153 .to_der()
154 .map_err(|e| Error::Parse(format!("encode req: {e}")))
155}
156
157fn parse_basic_response(der: &[u8]) -> Result<TsaResponse, Error> {
158 let tsr = x509_tsp::TimeStampResp::from_der(der).map_err(|e| Error::Parse(e.to_string()))?;
159 let status_val = tsr.status.status as u8;
160 if status_val > 1 {
161 return Err(Error::Verify(format!("status {} not granted", status_val)));
162 }
163 let tst = tsr
164 .time_stamp_token
165 .ok_or_else(|| Error::Parse("missing token".into()))?;
166 let tst_der = tst.to_der().map_err(|e| Error::Parse(e.to_string()))?;
167 let sd = cms::content_info::ContentInfo::from_der(&tst_der)
168 .map_err(|e| Error::Parse(format!("cms: {e}")))?;
169 let (tst_info_der, signer_spki, serial_hex, _signer_cert, _chain) =
170 extract_tstinfo_and_signer_spki(&sd).map_err(|e| Error::Parse(e))?;
171 let tsti = x509_tsp::TstInfo::from_der(&tst_info_der).map_err(|e| Error::Parse(e.to_string()))?;
172 let gen_time_unix = tsti.gen_time.to_unix_duration().as_secs() as i64;
173 let tsa_kid = crate::crypto::kid_from_spki_der(&signer_spki);
174 Ok(TsaResponse {
175 der: der.to_vec(),
176 gen_time_unix,
177 serial_hex,
178 tsa_kid,
179 })
180}
181
182fn extract_tstinfo_and_signer_spki(
183 ci: &cms::content_info::ContentInfo,
184) -> Result<(Vec<u8>, Vec<u8>, String, x509_cert::Certificate, Vec<x509_cert::Certificate>), String> {
185 use cms::cert::CertificateChoices;
186 use cms::signed_data::{EncapsulatedContentInfo, SignedData};
187
188 let signed: SignedData = SignedData::from_der(&ci.content.to_der().map_err(|e| e.to_string())?)
190 .map_err(|e| format!("signed_data: {e}"))?;
191 let EncapsulatedContentInfo { econtent, .. } = signed.encap_content_info;
192 let tsti_der_any = econtent.ok_or_else(|| "missing econtent".to_string())?;
193
194 let mut serial_hex = String::new();
196 let mut all = Vec::<x509_cert::Certificate>::new();
197 if let Some(certs) = &signed.certificates {
198 for i in 0..certs.0.len() {
199 let ch = certs.0.get(i).ok_or_else(|| "bad certset".to_string())?;
200 if let CertificateChoices::Certificate(cert) = ch {
201 serial_hex = hex::encode(cert.tbs_certificate.serial_number.as_bytes());
202 all.push(cert.clone());
203 }
204 }
205 }
206 if all.is_empty() {
207 return Err("no certificates present".into());
208 }
209 let signer_cert = all[0].clone();
210 let signer_spki = signer_cert
211 .tbs_certificate
212 .subject_public_key_info
213 .to_der()
214 .map_err(|e| e.to_string())?;
215 Ok((tsti_der_any.value().to_vec(), signer_spki, serial_hex, signer_cert, all))
216}
217
218fn verify_message_imprint(
219 tsti: &x509_tsp::TstInfo,
220 expected_alg: &str,
221 expected_imprint: &[u8],
222) -> Result<(), Error> {
223 let oid = tsti.message_imprint.hash_algorithm.oid;
224 let ok = match expected_alg {
225 "sha512" => oid == const_oid::db::rfc5912::ID_SHA_512,
226 "shake256-64" => oid == const_oid::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.12"),
227 other => return Err(Error::Digest(other.into())),
228 };
229 if !ok {
230 return Err(Error::Verify("hash alg mismatch".into()));
231 }
232 let got = tsti.message_imprint.hashed_message.as_bytes();
233 if got != expected_imprint {
234 return Err(Error::Verify("messageImprint mismatch".into()));
235 }
236 Ok(())
237}
238
239fn verify_cms_signed_attrs(
242 ci: &cms::content_info::ContentInfo,
243 _signer_cert_der: &[u8],
244 spki_der: &[u8],
245) -> Result<(), Error> {
246 let signed_data: cms::signed_data::SignedData = cms::signed_data::SignedData::from_der(
248 &ci.content
249 .to_der()
250 .map_err(|e| Error::Parse(format!("content der: {e}")))?,
251 )
252 .map_err(|e| Error::Parse(format!("signed_data: {e}")))?;
253 let si = signed_data
254 .signer_infos
255 .0
256 .get(0)
257 .ok_or_else(|| Error::Parse("no SignerInfo".into()))?;
258 let attrs = si
259 .signed_attrs
260 .as_ref()
261 .ok_or_else(|| Error::Parse("missing signedAttrs".into()))?;
262 let attrs_der = attrs
263 .to_der()
264 .map_err(|e| Error::Parse(format!("attrs der: {e}")))?;
265 let sig = si.signature.as_bytes();
266
267 let sig_oid = si.signature_algorithm.oid;
269 let dig_oid = si.digest_alg.oid;
270 use pkcs8::spki::SubjectPublicKeyInfoRef;
271
272
273 use ecdsa::signature::Verifier as _;
274 let spki = SubjectPublicKeyInfoRef::try_from(spki_der).map_err(|e| Error::Parse(e.to_string()))?;
275 let spki_alg = spki.algorithm.oid;
276 let spki_key_bytes = spki.subject_public_key.raw_bytes();
277
278 match (spki_alg, sig_oid, dig_oid) {
279 (o, s, d)
281 if o == const_oid::db::rfc5912::ID_EC_PUBLIC_KEY
282 && s == const_oid::db::rfc5912::ECDSA_WITH_SHA_256
283 && d == const_oid::db::rfc5912::ID_SHA_256 =>
284 {
285 let vk = p256::ecdsa::VerifyingKey::from_sec1_bytes(spki_key_bytes)
286 .map_err(|e| Error::Verify(format!("p256 sec1: {e}")))?;
287 let sig = p256::ecdsa::Signature::from_der(sig).map_err(|e| Error::Verify(format!("p256 sig: {e}")))?;
288 vk.verify(&attrs_der, &sig).map_err(|_| Error::Verify("ecdsa p256 sha256".into()))
289 }
290 (o, s, d)
292 if o == const_oid::db::rfc5912::ID_EC_PUBLIC_KEY
293 && s == const_oid::db::rfc5912::ECDSA_WITH_SHA_384
294 && d == const_oid::db::rfc5912::ID_SHA_384 =>
295 {
296 let vk = p384::ecdsa::VerifyingKey::from_sec1_bytes(spki_key_bytes)
297 .map_err(|e| Error::Verify(format!("p384 sec1: {e}")))?;
298 let sig = p384::ecdsa::Signature::from_der(sig).map_err(|e| Error::Verify(format!("p384 sig: {e}")))?;
299 vk.verify(&attrs_der, &sig).map_err(|_| Error::Verify("ecdsa p384 sha384".into()))
300 }
301 (o, s, d)
304 if o == const_oid::db::rfc5912::RSA_ENCRYPTION
305 && s == const_oid::db::rfc5912::ID_RSASSA_PSS =>
306 {
307 use rsa::pss::{Signature as RsaPssSignature, VerifyingKey};
308 use pkcs8::DecodePublicKey;
309 let pk = rsa::RsaPublicKey::from_public_key_der(spki_der)
310 .map_err(|e| Error::Verify(format!("rsa spki: {e}")))?;
311 let rsig = RsaPssSignature::try_from(sig).map_err(|_| Error::Verify("rsa-pss sig parse".into()))?;
312 let ok = if d == const_oid::db::rfc5912::ID_SHA_512 {
313 VerifyingKey::<sha2::Sha512>::new_with_salt_len(pk.clone(), sha2::Sha512::output_size())
314 .verify(&attrs_der, &rsig)
315 .is_ok()
316 } else if d == const_oid::db::rfc5912::ID_SHA_384 {
317 VerifyingKey::<sha2::Sha384>::new_with_salt_len(pk.clone(), sha2::Sha384::output_size())
318 .verify(&attrs_der, &rsig)
319 .is_ok()
320 } else if d == const_oid::db::rfc5912::ID_SHA_256 {
321 VerifyingKey::<sha2::Sha256>::new_with_salt_len(pk.clone(), sha2::Sha256::output_size())
322 .verify(&attrs_der, &rsig)
323 .is_ok()
324 } else {
325 VerifyingKey::<sha2::Sha512>::new_with_salt_len(pk.clone(), sha2::Sha512::output_size())
327 .verify(&attrs_der, &rsig)
328 .is_ok()
329 || VerifyingKey::<sha2::Sha384>::new_with_salt_len(pk.clone(), sha2::Sha384::output_size())
330 .verify(&attrs_der, &rsig)
331 .is_ok()
332 || VerifyingKey::<sha2::Sha256>::new_with_salt_len(pk.clone(), sha2::Sha256::output_size())
333 .verify(&attrs_der, &rsig)
334 .is_ok()
335 };
336 if ok { Ok(()) } else { Err(Error::Verify("rsa-pss verify failed".into())) }
337 }
338 (o, s, d) if o == const_oid::db::rfc5912::RSA_ENCRYPTION && s == const_oid::db::rfc5912::RSA_ENCRYPTION => {
339 use rsa::pkcs1v15::{Signature as RsaSignature, VerifyingKey};
342 use pkcs8::DecodePublicKey;
343 let pk = rsa::RsaPublicKey::from_public_key_der(spki_der)
344 .map_err(|e| Error::Verify(format!("rsa spki: {e}")))?;
345 let rsig = RsaSignature::try_from(sig).map_err(|_| Error::Verify("rsa sig parse".into()))?;
346
347 fn try_rsa<D>(pk: &rsa::RsaPublicKey, msg: &[u8], sig: &RsaSignature) -> bool
349 where
350 D: sha2::digest::Digest + const_oid::AssociatedOid,
351 {
352 let vk = VerifyingKey::<D>::new_unprefixed(pk.clone());
353 vk.verify(msg, sig).is_ok()
354 }
355
356 let ok = if d == const_oid::db::rfc5912::ID_SHA_512 {
357 try_rsa::<sha2::Sha512>(&pk, &attrs_der, &rsig)
358 } else if d == const_oid::db::rfc5912::ID_SHA_384 {
359 try_rsa::<sha2::Sha384>(&pk, &attrs_der, &rsig)
360 } else if d == const_oid::db::rfc5912::ID_SHA_256 {
361 try_rsa::<sha2::Sha256>(&pk, &attrs_der, &rsig)
362 } else {
363 try_rsa::<sha2::Sha512>(&pk, &attrs_der, &rsig)
365 || try_rsa::<sha2::Sha384>(&pk, &attrs_der, &rsig)
366 || try_rsa::<sha2::Sha256>(&pk, &attrs_der, &rsig)
367 };
368 if ok { Ok(()) } else { Err(Error::Verify("rsa pkcs1 verify failed".into())) }
369 }
370 _ => Err(Error::Verify("unsupported CMS algorithm".into())),
373 }
374}
375
376fn verify_eku_and_trust(
377 signer: &x509_cert::Certificate,
378 chain: &[x509_cert::Certificate],
379 trust: &[Vec<u8>],
380) -> Result<(), Error> {
381 use const_oid::db::rfc5280::ID_KP_TIME_STAMPING;
382 use x509_cert::ext::pkix::ExtendedKeyUsage;
383 use const_oid::AssociatedOid as _;
384
385 let mut has_eku = false;
387 if let Some(exts) = signer.tbs_certificate.extensions.as_ref() {
388 for ext in exts {
389 if ext.extn_id == ExtendedKeyUsage::OID {
390 let eku = ExtendedKeyUsage::from_der(ext.extn_value.as_bytes())
391 .map_err(|e| Error::Parse(format!("eku: {e}")))?;
392 if eku.0.iter().any(|oid| *oid == ID_KP_TIME_STAMPING) {
393 has_eku = true;
394 break;
395 }
396 }
397 }
398 }
399 if !has_eku {
401 for c in chain {
402 if let Some(exts) = c.tbs_certificate.extensions.as_ref() {
403 for ext in exts {
404 if ext.extn_id == ExtendedKeyUsage::OID {
405 let eku = ExtendedKeyUsage::from_der(ext.extn_value.as_bytes())
406 .map_err(|e| Error::Parse(format!("eku: {e}")))?;
407 if eku.0.iter().any(|oid| *oid == ID_KP_TIME_STAMPING) {
408 has_eku = true;
409 break;
410 }
411 }
412 }
413 }
414 if has_eku { break; }
415 }
416 }
417 if !has_eku {
418 return Err(Error::Verify("timeStamping EKU not found on signer or issuing CA".into()));
419 }
420
421 let mut trusted_kids = std::collections::BTreeSet::new();
423 let mut trust_certs: Vec<x509_cert::Certificate> = Vec::new();
424 for blob in trust {
425 let kid = if let Ok(cert) = x509_cert::Certificate::from_der(blob) {
427 let spki = cert
428 .tbs_certificate
429 .subject_public_key_info
430 .to_der()
431 .map_err(|e| Error::Parse(format!("spki: {e}")))?;
432 crate::crypto::kid_from_spki_der(&spki)
433 } else {
434 crate::crypto::kid_from_spki_der(blob)
435 };
436 trusted_kids.insert(kid);
437 if let Ok(cert) = x509_cert::Certificate::from_der(blob) {
438 trust_certs.push(cert);
439 }
440 }
441 let signer_spki = signer
442 .tbs_certificate
443 .subject_public_key_info
444 .to_der()
445 .map_err(|e| Error::Parse(format!("spki: {e}")))?;
446 let signer_kid = crate::crypto::kid_from_spki_der(&signer_spki);
447 if trusted_kids.contains(&signer_kid) {
448 return Ok(());
449 }
450 for c in chain {
451 let spki = c
452 .tbs_certificate
453 .subject_public_key_info
454 .to_der()
455 .map_err(|e| Error::Parse(format!("spki: {e}")))?;
456 let kid = crate::crypto::kid_from_spki_der(&spki);
457 if trusted_kids.contains(&kid) {
458 return Ok(());
459 }
460 }
461 if let Some(()) = verify_signer_cert_with_trust(&signer, &trust_certs).ok() {
463 return Ok(());
464 }
465 Err(Error::Verify("TSA chain not anchored in provided trust".into()))
466}
467
468fn verify_signer_cert_with_trust(
469 signer: &x509_cert::Certificate,
470 trust_certs: &[x509_cert::Certificate],
471) -> Result<(), Error> {
472 use const_oid::db::rfc5912 as oids;
473 let sig_oid = signer.signature_algorithm.oid;
475 let tbs_der = signer
476 .tbs_certificate
477 .to_der()
478 .map_err(|e| Error::Parse(format!("tbs der: {e}")))?;
479
480 for issuer in trust_certs {
481 let spki = &issuer.tbs_certificate.subject_public_key_info;
482 if spki.algorithm.oid != oids::ID_EC_PUBLIC_KEY {
484 continue;
485 }
486 let curve = spki
487 .algorithm
488 .owned_to_ref()
489 .parameters_oid()
490 .ok();
491 let pk_bytes = spki
492 .subject_public_key
493 .raw_bytes()
494 .to_vec();
495
496 if sig_oid == oids::ECDSA_WITH_SHA_256 && curve == Some(oids::SECP_256_R_1) {
498 use ecdsa::signature::DigestVerifier;
499 let vk = p256::ecdsa::VerifyingKey::from_sec1_bytes(&pk_bytes)
500 .map_err(|_| Error::Verify("invalid issuer P-256 key".into()))?;
501 let sig_der = signer
502 .signature
503 .as_bytes()
504 .ok_or_else(|| Error::Verify("missing signature bytes".into()))?;
505 let sig = p256::ecdsa::Signature::from_der(sig_der)
506 .map_err(|_| Error::Verify("invalid ECDSA P-256 signature".into()))?;
507 let ok = vk
508 .verify_digest(sha2::Sha256::new().chain_update(&tbs_der), &sig)
509 .is_ok();
510 if ok {
511 return Ok(());
512 }
513 }
514 if sig_oid == oids::ECDSA_WITH_SHA_384 && curve == Some(const_oid::db::rfc5912::SECP_384_R_1) {
516 use ecdsa::signature::DigestVerifier;
517 let vk = p384::ecdsa::VerifyingKey::from_sec1_bytes(&pk_bytes)
518 .map_err(|_| Error::Verify("invalid issuer P-384 key".into()))?;
519 let sig_der = signer
520 .signature
521 .as_bytes()
522 .ok_or_else(|| Error::Verify("missing signature bytes".into()))?;
523 let sig = p384::ecdsa::Signature::from_der(sig_der)
524 .map_err(|_| Error::Verify("invalid ECDSA P-384 signature".into()))?;
525 let ok = vk
526 .verify_digest(sha2::Sha384::new().chain_update(&tbs_der), &sig)
527 .is_ok();
528 if ok {
529 return Ok(());
530 }
531 }
532 }
533 Err(Error::Verify("could not validate signer cert against trust (ECDSA)".into()))
534}