1use std::collections::HashMap;
2use std::sync::Arc;
3use std::time::{Duration, SystemTime};
4
5use anyhow::Context as _;
6use ferron_common::logging::LogMessage;
7use hyper::Request;
8use hyper_util::client::legacy::Client;
9use hyper_util::rt::TokioExecutor;
10use num_bigint::BigInt;
11use rasn::prelude::*;
12use rasn_ocsp::BasicOcspResponse;
13use rasn_ocsp::{CertId, OcspRequest, OcspResponse, OcspResponseStatus, Request as OcspInnerRequest, TbsRequest};
14use rustls::client::WebPkiServerVerifier;
15use rustls::server::{ClientHello, ResolvesServerCert};
16use rustls::sign::CertifiedKey;
17use rustls_pki_types::CertificateDer;
18use rustls_platform_verifier::BuilderVerifierExt;
19use sha1::{Digest, Sha1};
20use sha2::Sha256;
21use std::ops::Deref;
22use tokio::sync::RwLock;
23use tokio_util::sync::CancellationToken;
24use x509_parser::prelude::*;
25
26type OcspCache = Arc<RwLock<HashMap<Vec<u8>, Option<Arc<CertifiedKey>>>>>;
27
28#[derive(Debug)]
29pub struct OcspStapler {
30 inner: Arc<dyn ResolvesServerCert>,
31 cache: OcspCache,
32 sender: async_channel::Sender<CertifiedKey>,
33 cancel_token: CancellationToken,
34}
35
36impl OcspStapler {
37 pub fn new(
38 inner: Arc<dyn ResolvesServerCert>,
39 runtime: &tokio::runtime::Runtime,
40 logging_tx: Vec<async_channel::Sender<LogMessage>>,
41 ) -> Self {
42 let (sender, receiver) = async_channel::unbounded();
43 let cache = Arc::new(RwLock::new(HashMap::new()));
44 let cancel_token = CancellationToken::new();
45
46 let stapler = Self {
47 inner,
48 cache,
49 sender,
50 cancel_token: cancel_token.clone(),
51 };
52
53 runtime.spawn(background_ocsp_task(
54 receiver,
55 stapler.cache.clone(),
56 cancel_token,
57 logging_tx,
58 ));
59
60 stapler
61 }
62
63 pub fn preload(&self, key: Arc<CertifiedKey>) {
64 if !key.cert.is_empty() {
65 let _ = self.sender.send_blocking((*key).clone());
67 }
68 }
69
70 pub async fn stop(&self) {
71 self.cancel_token.cancel();
72 }
73}
74
75impl ResolvesServerCert for OcspStapler {
76 fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
77 let original_key = self.inner.resolve(client_hello)?;
78 if let Some(leaf) = original_key.cert.first() {
79 #[cfg(any(feature = "runtime-vibeio", feature = "runtime-monoio"))]
83 let cache = self.cache.blocking_read();
84 #[cfg(feature = "runtime-tokio")]
85 let cache = futures_executor::block_on(async { self.cache.read().await });
86
87 if let Some(cached_key_option) = cache.get(&leaf.to_vec()) {
88 if let Some(cached_key) = cached_key_option.as_ref() {
89 if cached_key.ocsp.is_some() {
93 return Some(cached_key.clone());
94 }
95 }
96 } else {
98 let _ = self.sender.send_blocking((*original_key).clone());
100 }
101 }
102 Some(original_key)
103 }
104}
105
106async fn background_ocsp_task(
107 receiver: async_channel::Receiver<CertifiedKey>,
108 cache: OcspCache,
109 cancel_token: CancellationToken,
110 logging_tx: Vec<async_channel::Sender<LogMessage>>,
111) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
112 let mut next_updates: HashMap<Vec<u8>, SystemTime> = HashMap::new();
114 let mut known_certs: HashMap<Vec<u8>, CertifiedKey> = HashMap::new();
116
117 let tls_config_builder =
119 match rustls::ClientConfig::builder_with_provider(rustls::crypto::aws_lc_rs::default_provider().into())
120 .with_safe_default_protocol_versions()
121 {
122 Ok(builder) => builder,
123 Err(e) => {
124 for tx in &logging_tx {
125 let _ = tx
126 .send(LogMessage::new(
127 format!("Failed to create TLS config builder for OCSP stapling: {e}"),
128 true,
129 ))
130 .await;
131 }
132 return Err(e.into());
133 }
134 };
135 let https_connector = hyper_rustls::HttpsConnectorBuilder::new()
136 .with_tls_config(
137 (if let Ok(client_config) = BuilderVerifierExt::with_platform_verifier(tls_config_builder.clone()) {
138 client_config
139 } else {
140 tls_config_builder.with_webpki_verifier(
141 match WebPkiServerVerifier::builder(Arc::new(rustls::RootCertStore {
142 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
143 }))
144 .build()
145 {
146 Ok(verifier) => verifier,
147 Err(e) => {
148 for tx in &logging_tx {
149 let _ = tx
150 .send(LogMessage::new(
151 format!("Failed to create TLS verifier for OCSP stapling: {e}"),
152 true,
153 ))
154 .await;
155 }
156 return Err(e.into());
157 }
158 },
159 )
160 })
161 .with_no_client_auth(),
162 )
163 .https_or_http()
164 .enable_http1()
165 .build();
166
167 let client =
168 Client::builder(TokioExecutor::new()).build::<_, http_body_util::Full<hyper::body::Bytes>>(https_connector);
169
170 loop {
171 let mut sleep_duration = Duration::from_secs(60); let now = SystemTime::now();
175 for next_update in next_updates.values() {
176 if let Ok(duration) = next_update.duration_since(now) {
177 if duration < sleep_duration {
178 sleep_duration = duration;
179 }
180 } else {
181 sleep_duration = Duration::from_secs(1);
183 }
184 }
185
186 let received_certified_key = tokio::select! {
187 _ = cancel_token.cancelled() => Err(anyhow::anyhow!("Cancelled"))?,
188 _ = tokio::time::sleep(sleep_duration) => None,
189 res = receiver.recv() => match res {
190 Ok(chain) => Some(chain),
191 Err(e) => Err(e)?, }
193 };
194
195 if let Some(certified_key) = received_certified_key {
196 let chain = &certified_key.cert;
197 if let Some(leaf) = chain.first() {
198 let key = leaf.to_vec();
199 if !known_certs.contains_key(&key) {
200 known_certs.insert(key.clone(), certified_key);
201 next_updates.insert(key, SystemTime::now());
203 }
204 }
205 }
206
207 let now = SystemTime::now();
209 let mut updates_to_fetch = Vec::new();
210 for (key, next_update) in &next_updates {
211 if *next_update <= now {
212 updates_to_fetch.push(key.clone());
213 }
214 }
215
216 for key in updates_to_fetch {
217 if let Some(certified_key) = known_certs.get(&key) {
218 match fetch_ocsp_response(&client, &certified_key.cert).await {
219 Ok(Some((response, next_update_time))) => {
220 let mut new_certified_key = certified_key.clone();
221 new_certified_key.ocsp = Some(response.clone());
222 cache
223 .write()
224 .await
225 .insert(certified_key.cert[0].to_vec(), Some(Arc::new(new_certified_key)));
226 next_updates.insert(key, next_update_time);
227 }
228 Ok(None) => {
229 cache.write().await.insert(certified_key.cert[0].to_vec(), None);
231 next_updates.remove(&key);
232 }
233 Err(e) => {
234 for tx in &logging_tx {
236 let _ = tx.send(LogMessage::new(format!("OCSP fetch failed: {e}"), true)).await;
237 }
238 next_updates.insert(key, now + Duration::from_secs(rand::random_range(100..=500)));
240 continue;
241 }
242 };
243 }
244 }
245 }
246}
247
248async fn fetch_ocsp_response(
249 client: &Client<
250 hyper_rustls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>,
251 http_body_util::Full<hyper::body::Bytes>,
252 >,
253 chain: &[CertificateDer<'_>],
254) -> anyhow::Result<Option<(Vec<u8>, SystemTime)>> {
255 let response = fetch_ocsp_response_inner(client, chain, true).await;
257
258 if response.is_ok() {
260 return response;
261 }
262
263 let should_try_sha1 = match &response {
265 Err(e) => should_try_sha1_for_error(e),
266 _ => false,
267 };
268
269 if should_try_sha1 {
270 if let Ok(sha1_response) = fetch_ocsp_response_inner(client, chain, false).await {
271 return Ok(sha1_response);
272 }
273 }
274
275 response
277}
278
279async fn fetch_ocsp_response_inner(
280 client: &Client<
281 hyper_rustls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>,
282 http_body_util::Full<hyper::body::Bytes>,
283 >,
284 chain: &[CertificateDer<'_>],
285 use_sha256: bool,
286) -> anyhow::Result<Option<(Vec<u8>, SystemTime)>> {
287 if chain.len() < 2 {
288 return Ok(None);
289 }
290
291 let leaf = &chain[0];
292 let issuer = &chain[1];
293
294 let (_, leaf_cert) =
295 X509Certificate::from_der(leaf).map_err(|e| anyhow::anyhow!("Failed to parse leaf cert: {e}"))?;
296 let (_, issuer_cert) =
297 X509Certificate::from_der(issuer).map_err(|e| anyhow::anyhow!("Failed to parse issuer cert: {e}"))?;
298
299 let Some(ocsp_url) = extract_ocsp_url(&leaf_cert) else {
300 return Ok(None);
301 };
302
303 let req_der = create_ocsp_request(&leaf_cert, &issuer_cert, use_sha256)?;
304
305 let req = Request::builder()
306 .method("POST")
307 .uri(&ocsp_url)
308 .header("Content-Type", "application/ocsp-request")
309 .body(http_body_util::Full::new(hyper::body::Bytes::from(req_der)))
310 .with_context(|| format!("Failed to build OCSP request for {ocsp_url}"))?;
311
312 let res = client.request(req).await?;
313 if !res.status().is_success() {
314 return Err(anyhow::anyhow!(
315 "OCSP request failed with status {} for URL: {ocsp_url}",
316 res.status()
317 ));
318 }
319
320 use http_body_util::BodyExt;
321 let body_bytes = res.collect().await?.to_bytes();
322 let response_der = body_bytes.to_vec();
323
324 let response: OcspResponse =
326 rasn::der::decode(&response_der).map_err(|e| anyhow::anyhow!("Failed to decode OCSP response: {e}"))?;
327
328 if response.status != OcspResponseStatus::Successful {
329 return Err(anyhow::anyhow!(
330 "OCSP response status unsuccessful: {}",
331 response.status.identifier()
332 ));
333 }
334
335 let response_bytes = response
336 .bytes
337 .ok_or_else(|| anyhow::anyhow!("No response bytes in OCSP response"))?;
338
339 if response_bytes.r#type
340 != ObjectIdentifier::new(vec![1, 3, 6, 1, 5, 5, 7, 48, 1, 1])
341 .ok_or_else(|| anyhow::anyhow!("Invalid OCSP basic response OID"))?
342 {
343 return Err(anyhow::anyhow!("Unsupported OCSP response type"));
344 }
345
346 let basic_response: BasicOcspResponse = rasn::der::decode(&response_bytes.response)
347 .map_err(|e| anyhow::anyhow!("Failed to decode BasicOcspResponse: {e}"))?;
348
349 verify_ocsp_signature_with_certs_field(&basic_response, &issuer_cert)?;
351
352 let mut min_next_update: Option<SystemTime> = None;
354 for single_res in basic_response.tbs_response_data.responses {
355 verify_single_res(&single_res, &leaf_cert, &issuer_cert)?;
356
357 let next_update = single_res.next_update.map(SystemTime::from);
358 if let Some(mut nu) = next_update {
359 let this_update = SystemTime::from(single_res.this_update);
361 let validity = nu
362 .duration_since(this_update)
363 .unwrap_or_else(|_| Duration::from_secs(0));
364 let margin = validity / 4 + Duration::from_secs(rand::random_range(0..=300));
365
366 if nu.checked_sub(margin).unwrap_or(nu) > SystemTime::now() {
367 nu = nu.checked_sub(margin).unwrap_or(nu);
368 }
369
370 min_next_update = Some(match min_next_update {
371 Some(min) if nu < min => nu,
372 None => nu,
373 _ => min_next_update.ok_or(anyhow::anyhow!("Failed to compute next update"))?,
374 });
375 }
376 }
377
378 let next_update = min_next_update.unwrap_or_else(|| SystemTime::now() + Duration::from_secs(300));
379 Ok(Some((response_der, next_update)))
380}
381
382fn extract_ocsp_url(cert: &X509Certificate) -> Option<String> {
383 for ext in cert.extensions() {
384 if let x509_parser::extensions::ParsedExtension::AuthorityInfoAccess(aia) = ext.parsed_extension() {
385 for access_desc in &aia.accessdescs {
386 if access_desc.access_method == x509_parser::oid_registry::OID_PKIX_ACCESS_DESCRIPTOR_OCSP {
387 if let x509_parser::extensions::GeneralName::URI(uri) = access_desc.access_location {
388 return Some(uri.to_string());
389 }
390 }
391 }
392 }
393 }
394 None
395}
396
397fn create_ocsp_request(leaf: &X509Certificate, issuer: &X509Certificate, use_sha256: bool) -> anyhow::Result<Vec<u8>> {
398 let issuer_name_hash = if use_sha256 {
400 let mut sha256 = Sha256::new();
401 sha256.update(issuer.subject().as_raw());
402 sha256.finalize().to_vec()
403 } else {
404 let mut sha1 = Sha1::new();
405 sha1.update(issuer.subject().as_raw());
406 sha1.finalize().to_vec()
407 };
408
409 let spki = issuer.public_key();
413 let pub_key_bytes = &spki.subject_public_key.data;
415 let issuer_key_hash = if use_sha256 {
416 let mut sha256 = Sha256::new();
417 sha256.update(pub_key_bytes);
418 sha256.finalize().to_vec()
419 } else {
420 let mut sha1 = Sha1::new();
421 sha1.update(pub_key_bytes);
422 sha1.finalize().to_vec()
423 };
424
425 let serial_number = &leaf.tbs_certificate.serial;
427 let serial_int = rasn::types::Integer::from(num_bigint::BigInt::from_biguint(
430 num_bigint::Sign::Plus,
431 serial_number.to_owned(),
432 ));
433
434 let cert_id = CertId {
435 hash_algorithm: rasn_pkix::AlgorithmIdentifier {
436 algorithm: if use_sha256 {
437 rasn::types::Oid::JOINT_ISO_ITU_T_COUNTRY_US_ORGANIZATION_GOV_CSOR_NIST_ALGORITHMS_HASH_SHA256.to_owned()
438 } else {
439 rasn::types::Oid::ISO_IDENTIFIED_ORGANISATION_OIW_SECSIG_ALGORITHM_SHA1.to_owned()
440 },
441 parameters: None,
442 },
443 issuer_name_hash: rasn::types::OctetString::from(issuer_name_hash),
444 issuer_key_hash: rasn::types::OctetString::from(issuer_key_hash),
445 serial_number: serial_int,
446 };
447
448 let req = OcspRequest {
449 tbs_request: TbsRequest {
450 version: rasn::types::Integer::from(0), requestor_name: None,
452 request_list: vec![OcspInnerRequest {
453 req_cert: cert_id,
454 single_request_extensions: None,
455 }],
456 request_extensions: None,
457 },
458 optional_signature: None,
459 };
460
461 rasn::der::encode(&req).map_err(|e| anyhow::anyhow!(e))
462}
463
464fn verify_ocsp_signature(basic_response: &BasicOcspResponse, issuer_cert: &X509Certificate) -> anyhow::Result<()> {
469 let spki = issuer_cert.public_key();
470 let alg: &dyn aws_lc_rs::signature::VerificationAlgorithm =
471 match *basic_response.signature_algorithm.algorithm.deref().deref() {
472 [1, 2, 840, 113549, 1, 1, 11] => &aws_lc_rs::signature::RSA_PKCS1_2048_8192_SHA256,
474 [1, 2, 840, 113549, 1, 1, 12] => &aws_lc_rs::signature::RSA_PKCS1_2048_8192_SHA384,
475 [1, 2, 840, 113549, 1, 1, 13] => &aws_lc_rs::signature::RSA_PKCS1_2048_8192_SHA512,
476 [1, 2, 840, 113549, 1, 1, 5] => &aws_lc_rs::signature::RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
477
478 [1, 3, 101, 112] => &aws_lc_rs::signature::ED25519,
480
481 [1, 2, 840, 10045, 4, 3, algo] => {
483 let curve_oid: Option<ObjectIdentifier> = issuer_cert
485 .public_key()
486 .algorithm
487 .parameters
488 .as_ref()
489 .and_then(|v| rasn::der::decode::<ObjectIdentifier>(v.as_bytes()).ok());
490 let curve_oid_u32: Option<&[u32]> = curve_oid.as_deref().map(|oid| oid.as_ref());
491 match (curve_oid_u32, algo) {
492 (Some([1, 2, 840, 10045, 3, 1, 7]), 2) => &aws_lc_rs::signature::ECDSA_P256_SHA256_ASN1,
494 (Some([1, 2, 840, 10045, 3, 1, 7]), 3) => &aws_lc_rs::signature::ECDSA_P256_SHA384_ASN1,
495 (Some([1, 2, 840, 10045, 3, 1, 7]), 4) => &aws_lc_rs::signature::ECDSA_P256_SHA512_ASN1,
496
497 (Some([1, 3, 132, 0, 34]), 2) => &aws_lc_rs::signature::ECDSA_P384_SHA256_ASN1,
499 (Some([1, 3, 132, 0, 34]), 3) => &aws_lc_rs::signature::ECDSA_P384_SHA384_ASN1,
500 (Some([1, 3, 132, 0, 34]), 4) => &aws_lc_rs::signature::ECDSA_P384_SHA512_ASN1,
501
502 (Some([1, 3, 132, 0, 35]), 2) => &aws_lc_rs::signature::ECDSA_P521_SHA256_ASN1,
504 (Some([1, 3, 132, 0, 35]), 3) => &aws_lc_rs::signature::ECDSA_P521_SHA384_ASN1,
505 (Some([1, 3, 132, 0, 35]), 4) => &aws_lc_rs::signature::ECDSA_P521_SHA512_ASN1,
506
507 (Some([1, 3, 132, 0, 10]), 2) => &aws_lc_rs::signature::ECDSA_P256K1_SHA256_ASN1,
509
510 _ => {
511 return Err(anyhow::anyhow!(
512 "Unsupported OCSP signature algorithm OID: {}",
513 basic_response.signature_algorithm.algorithm
514 ))
515 }
516 }
517 }
518
519 _ => {
520 return Err(anyhow::anyhow!(
521 "Unsupported OCSP signature algorithm OID: {}",
522 basic_response.signature_algorithm.algorithm
523 ))
524 }
525 };
526
527 let signature = basic_response.signature.as_raw_slice();
528
529 alg
530 .verify_sig(
531 spki.subject_public_key.data.as_ref(),
532 &rasn::der::encode(&basic_response.tbs_response_data)
533 .map_err(|e| anyhow::anyhow!("OCSP response signature verification failed: {e}"))?,
534 signature,
535 )
536 .map_err(|_| anyhow::anyhow!("OCSP response signature verification failed"))?;
537
538 Ok(())
539}
540
541fn verify_ocsp_signature_with_certs_field(
542 basic_response: &BasicOcspResponse,
543 issuer_cert: &X509Certificate,
544) -> anyhow::Result<()> {
545 let Err(mut last_error) = verify_ocsp_signature(basic_response, issuer_cert) else {
546 return Ok(());
547 };
548
549 if let Some(ref certs) = basic_response.certs {
550 for cert in certs {
551 let Ok(cert_der) = rasn::der::encode(cert) else {
554 continue;
555 };
556 let Ok((_, parsed_cert)) = X509Certificate::from_der(&cert_der) else {
557 continue;
558 };
559
560 if parsed_cert.tbs_certificate.issuer != *issuer_cert.subject() {
562 continue;
564 }
565
566 if !parsed_cert.extensions().iter().any(|e| {
567 let parsed = e.parsed_extension();
568 match parsed {
569 ParsedExtension::ExtendedKeyUsage(eku) => eku.ocsp_signing,
570 _ => false,
571 }
572 }) {
573 continue;
575 }
576
577 let Err(new_last_error) = verify_ocsp_signature(basic_response, &parsed_cert) else {
578 return Ok(());
579 };
580 last_error = new_last_error;
581 }
582 }
583
584 Err(last_error)
585}
586
587fn hash_oid(data: impl AsRef<[u8]>, oid: ObjectIdentifier) -> anyhow::Result<Vec<u8>> {
588 let mut ctx =
589 if oid == *rasn::types::Oid::JOINT_ISO_ITU_T_COUNTRY_US_ORGANIZATION_GOV_CSOR_NIST_ALGORITHMS_HASH_SHA256 {
590 aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256)
591 } else if oid == *rasn::types::Oid::JOINT_ISO_ITU_T_COUNTRY_US_ORGANIZATION_GOV_CSOR_NIST_ALGORITHMS_HASH_SHA384 {
592 aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA384)
593 } else if oid == *rasn::types::Oid::JOINT_ISO_ITU_T_COUNTRY_US_ORGANIZATION_GOV_CSOR_NIST_ALGORITHMS_HASH_SHA512 {
594 aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA512)
595 } else if oid == *rasn::types::Oid::ISO_IDENTIFIED_ORGANISATION_OIW_SECSIG_ALGORITHM_SHA1 {
596 aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA1_FOR_LEGACY_USE_ONLY)
597 } else {
598 return Err(anyhow::anyhow!(
599 "Unsupported hash algorithm OID in OCSP response: {}",
600 oid
601 ));
602 };
603 ctx.update(data.as_ref());
604 Ok(ctx.finish().as_ref().to_vec())
605}
606
607fn should_try_sha1_for_error(err: &anyhow::Error) -> bool {
608 let e_message = err.to_string();
609 e_message.contains("OCSP request failed with status")
610 || e_message.contains("Failed to decode OCSP response")
611 || e_message.contains("OCSP response status unsuccessful")
612}
613
614fn verify_single_res(
615 single_res: &rasn_ocsp::SingleResponse,
616 leaf_cert: &X509Certificate,
617 issuer_cert: &X509Certificate,
618) -> anyhow::Result<()> {
619 if single_res.cert_id.issuer_name_hash.as_ref()
621 != hash_oid(
622 issuer_cert.subject().as_raw(),
623 single_res.cert_id.hash_algorithm.algorithm.clone(),
624 )?
625 {
626 return Err(anyhow::anyhow!("Issuer name hash mismatch in OCSP response"));
627 }
628
629 if single_res.cert_id.issuer_key_hash.as_ref()
631 != hash_oid(
632 issuer_cert.public_key().subject_public_key.data.as_ref(),
633 single_res.cert_id.hash_algorithm.algorithm.clone(),
634 )?
635 {
636 return Err(anyhow::anyhow!("Issuer key hash mismatch in OCSP response"));
637 }
638
639 let serial_number = &leaf_cert.tbs_certificate.serial;
641 let serial_int = BigInt::from_biguint(num_bigint::Sign::Plus, serial_number.to_owned());
642 if single_res.cert_id.serial_number != rasn::types::Integer::from(serial_int) {
643 return Err(anyhow::anyhow!("Serial number mismatch in OCSP response"));
644 }
645
646 let now_with_skew = SystemTime::now() + Duration::from_secs(60);
649 let now = SystemTime::now();
650 let this_update_st = SystemTime::from(single_res.this_update);
651 if this_update_st > now_with_skew || single_res.next_update.map(SystemTime::from).is_some_and(|nu| nu < now) {
652 return Err(anyhow::anyhow!("OCSP response is not current"));
653 }
654
655 Ok(())
656}
657
658#[cfg(test)]
659mod tests {
660 use super::*;
661 use anyhow::anyhow;
662 use sha1::Sha1 as TestSha1;
663 use sha2::{Digest as Sha2Digest, Sha256 as TestSha256};
664
665 #[test]
666 fn test_should_try_sha1_for_error() {
667 let e1 = anyhow!("OCSP request failed with status 500 for URL");
668 assert!(super::should_try_sha1_for_error(&e1));
669
670 let e2 = anyhow!("Failed to decode OCSP response: malformed");
671 assert!(super::should_try_sha1_for_error(&e2));
672
673 let e3 = anyhow!("OCSP response status unsuccessful: 3");
674 assert!(super::should_try_sha1_for_error(&e3));
675
676 let e4 = anyhow!("network down");
677 assert!(!super::should_try_sha1_for_error(&e4));
678 }
679
680 #[test]
681 fn test_hash_oid_sha256_and_sha1() {
682 let data = b"abc";
683
684 let oid_sha256 = rasn::types::Oid::JOINT_ISO_ITU_T_COUNTRY_US_ORGANIZATION_GOV_CSOR_NIST_ALGORITHMS_HASH_SHA256;
686 let got = hash_oid(data.as_ref(), oid_sha256.into()).expect("hash_oid sha256 failed");
687 let mut hasher = TestSha256::new();
688 hasher.update(data);
689 let expected = hasher.finalize().to_vec();
690 assert_eq!(got, expected);
691
692 let oid_sha1 = rasn::types::Oid::ISO_IDENTIFIED_ORGANISATION_OIW_SECSIG_ALGORITHM_SHA1;
694 let got1 = hash_oid(data.as_ref(), oid_sha1.into()).expect("hash_oid sha1 failed");
695 let mut hasher1 = TestSha1::new();
696 hasher1.update(data);
697 let expected1 = hasher1.finalize().to_vec();
698 assert_eq!(got1, expected1);
699 }
700}