Skip to main content

httpsig_hyper/
hyper_http.rs

1use crate::error::{HyperSigError, HyperSigResult};
2use http::{HeaderMap, Request, Response};
3use http_body::Body;
4use httpsig::prelude::{
5  message_component::{
6    DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam,
7  },
8  AlgorithmName, HttpSignatureBase, HttpSignatureHeaders, HttpSignatureHeadersMap, HttpSignatureParams, SigningKey, VerifyingKey,
9};
10use indexmap::{IndexMap, IndexSet};
11use std::{future::Future, str::FromStr};
12
13/// A type alias for the signature name
14type SignatureName = String;
15/// A type alias for the key id in base 64
16type KeyId = String;
17
18/* --------------------------------------- */
19/// A trait about the http message signature common to both request and response
20pub trait MessageSignature {
21  type Error;
22
23  /// Check if the request has signature and signature-input headers
24  fn has_message_signature(&self) -> bool;
25
26  /// Extract all key ids for signature bases contained in the request headers
27  fn get_alg_key_ids(&self) -> Result<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>, Self::Error>;
28
29  /// Extract all signature params used to generate signature bases contained in the request headers
30  fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error>;
31}
32
33/// A trait about http message signature for request
34pub trait MessageSignatureReq {
35  type Error;
36  /// Set the http message signature from given http signature params and signing key
37  fn set_message_signature<T>(
38    &mut self,
39    signature_params: &HttpSignatureParams,
40    signing_key: &T,
41    signature_name: Option<&str>,
42  ) -> impl Future<Output = Result<(), Self::Error>> + Send
43  where
44    Self: Sized,
45    T: SigningKey + Sync;
46
47  /// Set the http message signatures from given tuples of (http signature params, signing key, name)
48  fn set_message_signatures<T>(
49    &mut self,
50    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
51  ) -> impl Future<Output = Result<(), Self::Error>> + Send
52  where
53    Self: Sized,
54    T: SigningKey + Sync;
55
56  /// Verify the http message signature with given verifying key if the request has signature and signature-input headers
57  fn verify_message_signature<T>(
58    &self,
59    verifying_key: &T,
60    key_id: Option<&str>,
61  ) -> impl Future<Output = Result<SignatureName, Self::Error>> + Send
62  where
63    Self: Sized,
64    T: VerifyingKey + Sync;
65
66  /// Verify multiple signatures at once
67  fn verify_message_signatures<T>(
68    &self,
69    key_and_id: &[(&T, Option<&str>)],
70  ) -> impl Future<Output = Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>> + Send
71  where
72    Self: Sized,
73    T: VerifyingKey + Sync;
74
75  /// Extract all signature bases contained in the request headers
76  fn extract_signatures(&self) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error>;
77}
78
79/// A trait about http message signature for response
80pub trait MessageSignatureRes {
81  type Error;
82  /// Set the http message signature from given http signature params and signing key
83  fn set_message_signature<T, B>(
84    &mut self,
85    signature_params: &HttpSignatureParams,
86    signing_key: &T,
87    signature_name: Option<&str>,
88    req_for_param: Option<&Request<B>>,
89  ) -> impl Future<Output = Result<(), Self::Error>> + Send
90  where
91    Self: Sized,
92    T: SigningKey + Sync,
93    B: Sync;
94
95  /// Set the http message signatures from given tuples of (http signature params, signing key, name)
96  fn set_message_signatures<T, B>(
97    &mut self,
98    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
99    req_for_param: Option<&Request<B>>,
100  ) -> impl Future<Output = Result<(), Self::Error>> + Send
101  where
102    Self: Sized,
103    T: SigningKey + Sync,
104    B: Sync;
105
106  /// Verify the http message signature with given verifying key if the request has signature and signature-input headers
107  fn verify_message_signature<T, B>(
108    &self,
109    verifying_key: &T,
110    key_id: Option<&str>,
111    req_for_param: Option<&Request<B>>,
112  ) -> impl Future<Output = Result<SignatureName, Self::Error>> + Send
113  where
114    Self: Sized,
115    T: VerifyingKey + Sync,
116    B: Sync;
117
118  /// Verify multiple signatures at once
119  fn verify_message_signatures<T, B>(
120    &self,
121    key_and_id: &[(&T, Option<&str>)],
122    req_for_param: Option<&Request<B>>,
123  ) -> impl Future<Output = Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>> + Send
124  where
125    Self: Sized,
126    T: VerifyingKey + Sync,
127    B: Sync;
128
129  /// Extract all signature bases contained in the request headers
130  fn extract_signatures<B>(
131    &self,
132    req_for_param: Option<&Request<B>>,
133  ) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error>;
134}
135
136/* --------------------------------------- */
137#[cfg(feature = "blocking")]
138/// Synchronous counterpart of [`MessageSignatureReq`].
139///
140/// Every method delegates to the corresponding async method via `futures::executor::block_on`.
141///
142/// # Panics
143///
144/// All methods will panic if called from within an async runtime (e.g. a `tokio` task).
145/// Use the async [`MessageSignatureReq`] methods instead when you are already in an async context.
146pub trait MessageSignatureReqSync: MessageSignatureReq {
147  fn set_message_signature_sync<T>(
148    &mut self,
149    signature_params: &HttpSignatureParams,
150    signing_key: &T,
151    signature_name: Option<&str>,
152  ) -> Result<(), Self::Error>
153  where
154    Self: Sized,
155    T: SigningKey + Sync;
156
157  fn set_message_signatures_sync<T>(
158    &mut self,
159    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
160  ) -> Result<(), Self::Error>
161  where
162    Self: Sized,
163    T: SigningKey + Sync;
164
165  fn verify_message_signature_sync<T>(&self, verifying_key: &T, key_id: Option<&str>) -> Result<SignatureName, Self::Error>
166  where
167    Self: Sized,
168    T: VerifyingKey + Sync;
169
170  fn verify_message_signatures_sync<T>(
171    &self,
172    key_and_id: &[(&T, Option<&str>)],
173  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
174  where
175    Self: Sized,
176    T: VerifyingKey + Sync;
177}
178
179#[cfg(feature = "blocking")]
180/// Synchronous counterpart of [`MessageSignatureRes`].
181///
182/// Every method delegates to the corresponding async method via `futures::executor::block_on`.
183///
184/// # Panics
185///
186/// All methods will panic if called from within an async runtime (e.g. a `tokio` task).
187/// Use the async [`MessageSignatureRes`] methods instead when you are already in an async context.
188pub trait MessageSignatureResSync: MessageSignatureRes {
189  fn set_message_signature_sync<T, B>(
190    &mut self,
191    signature_params: &HttpSignatureParams,
192    signing_key: &T,
193    signature_name: Option<&str>,
194    req_for_param: Option<&Request<B>>,
195  ) -> Result<(), Self::Error>
196  where
197    Self: Sized,
198    T: SigningKey + Sync,
199    B: Sync;
200
201  fn set_message_signatures_sync<T, B>(
202    &mut self,
203    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
204    req_for_param: Option<&Request<B>>,
205  ) -> Result<(), Self::Error>
206  where
207    Self: Sized,
208    T: SigningKey + Sync,
209    B: Sync;
210
211  fn verify_message_signature_sync<T, B>(
212    &self,
213    verifying_key: &T,
214    key_id: Option<&str>,
215    req_for_param: Option<&Request<B>>,
216  ) -> Result<SignatureName, Self::Error>
217  where
218    Self: Sized,
219    T: VerifyingKey + Sync,
220    B: Sync;
221
222  fn verify_message_signatures_sync<T, B>(
223    &self,
224    key_and_id: &[(&T, Option<&str>)],
225    req_for_param: Option<&Request<B>>,
226  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
227  where
228    Self: Sized,
229    T: VerifyingKey + Sync,
230    B: Sync;
231}
232
233/* --------------------------------------- */
234impl<D> MessageSignature for Request<D>
235where
236  D: Send + Body + Sync,
237{
238  type Error = HyperSigError;
239
240  /// Check if the request has signature and signature-input headers
241  fn has_message_signature(&self) -> bool {
242    has_message_signature_inner(self.headers())
243  }
244
245  /// Extract all signature bases contained in the request headers
246  fn get_alg_key_ids(&self) -> HyperSigResult<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>> {
247    let req_or_res = RequestOrResponse::Request(self);
248    get_alg_key_ids_inner(&req_or_res)
249  }
250
251  /// Extract all signature params used to generate signature bases contained in the request headers
252  fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error> {
253    let req_or_res = RequestOrResponse::Request(self);
254    get_signature_params_inner(&req_or_res)
255  }
256}
257
258impl<D> MessageSignatureReq for Request<D>
259where
260  D: Send + Body + Sync,
261{
262  type Error = HyperSigError;
263
264  /// Set the http message signature from given http signature params and signing key
265  async fn set_message_signature<T>(
266    &mut self,
267    signature_params: &HttpSignatureParams,
268    signing_key: &T,
269    signature_name: Option<&str>,
270  ) -> HyperSigResult<()>
271  where
272    Self: Sized,
273    T: SigningKey + Sync,
274  {
275    self
276      .set_message_signatures(&[(signature_params, signing_key, signature_name)])
277      .await
278  }
279
280  async fn set_message_signatures<T>(
281    &mut self,
282    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
283  ) -> Result<(), Self::Error>
284  where
285    Self: Sized,
286    T: SigningKey + Sync,
287  {
288    let req_or_res = RequestOrResponse::Request(self);
289    let vec_signature_headers_fut = params_key_name.iter().flat_map(|(params, key, name)| {
290      build_signature_base(&req_or_res, params, None as Option<&Request<()>>)
291        .map(|base| async move { base.build_signature_headers(*key, *name) })
292    });
293    let vec_signature_headers = futures::future::join_all(vec_signature_headers_fut)
294      .await
295      .into_iter()
296      .collect::<Result<Vec<_>, _>>()?;
297    vec_signature_headers.iter().try_for_each(|headers| {
298      self
299        .headers_mut()
300        .append("signature-input", headers.signature_input_header_value().parse()?);
301      self
302        .headers_mut()
303        .append("signature", headers.signature_header_value().parse()?);
304      Ok(()) as Result<(), HyperSigError>
305    })
306  }
307
308  /// Verify the http message signature with given verifying key if the request has signature and signature-input headers
309  /// Return Ok(()) if the signature is valid.
310  /// If invalid for the given key or error occurs (like the case where the request does not have signature and/or signature-input headers), return Err.
311  /// If key_id is given, it is used to match the key id in signature params
312  async fn verify_message_signature<T>(&self, verifying_key: &T, key_id: Option<&str>) -> HyperSigResult<SignatureName>
313  where
314    Self: Sized,
315    T: VerifyingKey + Sync,
316  {
317    self
318      .verify_message_signatures(&[(verifying_key, key_id)])
319      .await?
320      .pop()
321      .unwrap()
322  }
323
324  async fn verify_message_signatures<T>(
325    &self,
326    key_and_id: &[(&T, Option<&str>)],
327  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
328  where
329    Self: Sized,
330    T: VerifyingKey + Sync,
331  {
332    if !self.has_message_signature() {
333      return Err(HyperSigError::NoSignatureHeaders(
334        "The request does not have signature and signature-input headers".to_string(),
335      ));
336    }
337    let map_signature_with_base = self.extract_signatures()?;
338    verify_message_signatures_inner(&map_signature_with_base, key_and_id).await
339  }
340
341  /// Extract all signature bases contained in the request headers
342  fn extract_signatures(&self) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error> {
343    let req_or_res = RequestOrResponse::Request(self);
344    extract_signatures_inner(&req_or_res, None as Option<&Request<()>>)
345  }
346}
347
348/* --------------------------------------- */
349impl<D> MessageSignature for Response<D>
350where
351  D: Send + Body + Sync,
352{
353  type Error = HyperSigError;
354
355  /// Check if the response has signature and signature-input headers
356  fn has_message_signature(&self) -> bool {
357    has_message_signature_inner(self.headers())
358  }
359
360  /// Extract all key ids for signature bases contained in the response headers
361  fn get_alg_key_ids(&self) -> Result<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>, Self::Error> {
362    let req_or_res = RequestOrResponse::Response(self);
363    get_alg_key_ids_inner(&req_or_res)
364  }
365
366  /// Extract all signature params used to generate signature bases contained in the response headers
367  fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error> {
368    let req_or_res = RequestOrResponse::Response(self);
369    get_signature_params_inner(&req_or_res)
370  }
371}
372
373impl<D> MessageSignatureRes for Response<D>
374where
375  D: Send + Body + Sync,
376{
377  type Error = HyperSigError;
378
379  /// Set the http message signature from given http signature params and signing key
380  async fn set_message_signature<T, B>(
381    &mut self,
382    signature_params: &HttpSignatureParams,
383    signing_key: &T,
384    signature_name: Option<&str>,
385    req_for_param: Option<&Request<B>>,
386  ) -> Result<(), Self::Error>
387  where
388    Self: Sized,
389    T: SigningKey + Sync,
390    B: Sync,
391  {
392    self
393      .set_message_signatures(&[(signature_params, signing_key, signature_name)], req_for_param)
394      .await
395  }
396
397  async fn set_message_signatures<T, B>(
398    &mut self,
399    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
400    req_for_param: Option<&Request<B>>,
401  ) -> Result<(), Self::Error>
402  where
403    Self: Sized,
404    T: SigningKey + Sync,
405  {
406    let req_or_res = RequestOrResponse::Response(self);
407
408    let vec_signature_headers_fut = params_key_name.iter().flat_map(|(params, key, name)| {
409      build_signature_base(&req_or_res, params, req_for_param)
410        .map(|base| async move { base.build_signature_headers(*key, *name) })
411    });
412    let vec_signature_headers = futures::future::join_all(vec_signature_headers_fut)
413      .await
414      .into_iter()
415      .collect::<Result<Vec<_>, _>>()?;
416
417    vec_signature_headers.iter().try_for_each(|headers| {
418      self
419        .headers_mut()
420        .append("signature-input", headers.signature_input_header_value().parse()?);
421      self
422        .headers_mut()
423        .append("signature", headers.signature_header_value().parse()?);
424      Ok(()) as Result<(), HyperSigError>
425    })
426  }
427
428  /// Verify the http message signature with given verifying key if the response has signature and signature-input headers
429  /// Return Ok(()) if the signature is valid.
430  /// If invalid for the given key or error occurs (like the case where the request does not have signature and/or signature-input headers), return Err.
431  /// If key_id is given, it is used to match the key id in signature params
432  async fn verify_message_signature<T, B>(
433    &self,
434    verifying_key: &T,
435    key_id: Option<&str>,
436    req_for_param: Option<&Request<B>>,
437  ) -> Result<SignatureName, Self::Error>
438  where
439    Self: Sized,
440    T: VerifyingKey + Sync,
441    B: Sync,
442  {
443    self
444      .verify_message_signatures(&[(verifying_key, key_id)], req_for_param)
445      .await?
446      .pop()
447      .unwrap()
448  }
449
450  async fn verify_message_signatures<T, B>(
451    &self,
452    key_and_id: &[(&T, Option<&str>)],
453    req_for_param: Option<&Request<B>>,
454  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
455  where
456    Self: Sized,
457    T: VerifyingKey + Sync,
458  {
459    if !self.has_message_signature() {
460      return Err(HyperSigError::NoSignatureHeaders(
461        "The response does not have signature and signature-input headers".to_string(),
462      ));
463    }
464    let map_signature_with_base = self.extract_signatures(req_for_param)?;
465    verify_message_signatures_inner(&map_signature_with_base, key_and_id).await
466  }
467
468  /// Extract all signature bases contained in the response headers
469  fn extract_signatures<B>(
470    &self,
471    req_for_param: Option<&Request<B>>,
472  ) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error> {
473    let req_or_res = RequestOrResponse::Response(self);
474    extract_signatures_inner(&req_or_res, req_for_param)
475  }
476}
477
478/* --------------------------------------- */
479#[cfg(feature = "blocking")]
480impl<D> MessageSignatureReqSync for Request<D>
481where
482  D: Send + Body + Sync,
483{
484  fn set_message_signature_sync<T>(
485    &mut self,
486    signature_params: &HttpSignatureParams,
487    signing_key: &T,
488    signature_name: Option<&str>,
489  ) -> Result<(), Self::Error>
490  where
491    Self: Sized,
492    T: SigningKey + Sync,
493  {
494    futures::executor::block_on(self.set_message_signature(signature_params, signing_key, signature_name))
495  }
496
497  fn set_message_signatures_sync<T>(
498    &mut self,
499    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
500  ) -> Result<(), Self::Error>
501  where
502    Self: Sized,
503    T: SigningKey + Sync,
504  {
505    futures::executor::block_on(self.set_message_signatures(params_key_name))
506  }
507
508  fn verify_message_signature_sync<T>(&self, verifying_key: &T, key_id: Option<&str>) -> Result<SignatureName, Self::Error>
509  where
510    Self: Sized,
511    T: VerifyingKey + Sync,
512  {
513    futures::executor::block_on(self.verify_message_signature(verifying_key, key_id))
514  }
515
516  fn verify_message_signatures_sync<T>(
517    &self,
518    key_and_id: &[(&T, Option<&str>)],
519  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
520  where
521    Self: Sized,
522    T: VerifyingKey + Sync,
523  {
524    futures::executor::block_on(self.verify_message_signatures(key_and_id))
525  }
526}
527
528#[cfg(feature = "blocking")]
529impl<D> MessageSignatureResSync for Response<D>
530where
531  D: Send + Body + Sync,
532{
533  fn set_message_signature_sync<T, B>(
534    &mut self,
535    signature_params: &HttpSignatureParams,
536    signing_key: &T,
537    signature_name: Option<&str>,
538    req_for_param: Option<&Request<B>>,
539  ) -> Result<(), Self::Error>
540  where
541    Self: Sized,
542    T: SigningKey + Sync,
543    B: Sync,
544  {
545    futures::executor::block_on(self.set_message_signature(signature_params, signing_key, signature_name, req_for_param))
546  }
547
548  fn set_message_signatures_sync<T, B>(
549    &mut self,
550    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
551    req_for_param: Option<&Request<B>>,
552  ) -> Result<(), Self::Error>
553  where
554    Self: Sized,
555    T: SigningKey + Sync,
556    B: Sync,
557  {
558    futures::executor::block_on(self.set_message_signatures(params_key_name, req_for_param))
559  }
560
561  fn verify_message_signature_sync<T, B>(
562    &self,
563    verifying_key: &T,
564    key_id: Option<&str>,
565    req_for_param: Option<&Request<B>>,
566  ) -> Result<SignatureName, Self::Error>
567  where
568    Self: Sized,
569    T: VerifyingKey + Sync,
570    B: Sync,
571  {
572    futures::executor::block_on(self.verify_message_signature(verifying_key, key_id, req_for_param))
573  }
574
575  fn verify_message_signatures_sync<T, B>(
576    &self,
577    key_and_id: &[(&T, Option<&str>)],
578    req_for_param: Option<&Request<B>>,
579  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
580  where
581    Self: Sized,
582    T: VerifyingKey + Sync,
583    B: Sync,
584  {
585    futures::executor::block_on(self.verify_message_signatures(key_and_id, req_for_param))
586  }
587}
588
589/* --------------------------------------- */
590// inner functions
591/// has message signature inner function
592fn has_message_signature_inner(headers: &HeaderMap) -> bool {
593  headers.contains_key("signature") && headers.contains_key("signature-input")
594}
595
596/// get key ids inner function
597fn get_alg_key_ids_inner<B>(
598  req_or_res: &RequestOrResponse<B>,
599) -> HyperSigResult<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>> {
600  let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
601  let res = signature_headers_map
602    .iter()
603    .map(|(name, headers)| {
604      // Unknown or unsupported algorithm strings are mapped to None
605      let alg = headers
606        .signature_params()
607        .alg
608        .clone()
609        .map(|a| AlgorithmName::from_str(&a))
610        .transpose()
611        .ok()
612        .flatten();
613      let key_id = headers.signature_params().keyid.clone();
614      (name.clone(), (alg, key_id))
615    })
616    .collect();
617  Ok(res)
618}
619
620/// get signature params inner function
621fn get_signature_params_inner<B>(
622  req_or_res: &RequestOrResponse<B>,
623) -> HyperSigResult<IndexMap<SignatureName, HttpSignatureParams>> {
624  let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
625  let res = signature_headers_map
626    .iter()
627    .map(|(name, headers)| (name.clone(), headers.signature_params().clone()))
628    .collect();
629  Ok(res)
630}
631
632/// extract signatures inner function
633fn extract_signatures_inner<B1, B2>(
634  req_or_res: &RequestOrResponse<B1>,
635  req_for_param: Option<&Request<B2>>,
636) -> HyperSigResult<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>> {
637  let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
638  let extracted = signature_headers_map
639    .iter()
640    .filter_map(|(name, headers)| {
641      build_signature_base(req_or_res, headers.signature_params(), req_for_param)
642        .ok()
643        .map(|base| (name.clone(), (base, headers.clone())))
644    })
645    .collect();
646  Ok(extracted)
647}
648
649/// Verify multiple signatures inner function
650async fn verify_message_signatures_inner<T>(
651  map_signature_with_base: &IndexMap<String, (HttpSignatureBase, HttpSignatureHeaders)>,
652  key_and_id: &[(&T, Option<&str>)],
653) -> HyperSigResult<Vec<HyperSigResult<SignatureName>>>
654where
655  T: VerifyingKey + Sync,
656{
657  // verify for each key_and_id tuple
658  let res_fut = key_and_id.iter().map(|(key, key_id)| {
659    let filtered = if let Some(key_id) = key_id {
660      map_signature_with_base
661        .iter()
662        .filter(|(_, (base, _))| base.keyid() == Some(key_id))
663        .collect::<IndexMap<_, _>>()
664    } else {
665      map_signature_with_base.iter().collect()
666    };
667
668    // check if any one of the signature headers is valid in async manner
669    async move {
670      if filtered.is_empty() {
671        return Err(HyperSigError::NoSignatureHeaders(
672          "No signature as appropriate target for verification".to_string(),
673        ));
674      }
675      // check if any one of the signature headers is valid
676      let successful_sig_names = filtered
677        .iter()
678        .filter_map(|(&name, (base, headers))| base.verify_signature_headers(*key, headers).ok().map(|_| name.clone()))
679        .collect::<IndexSet<_>>();
680      if !successful_sig_names.is_empty() {
681        Ok(successful_sig_names.first().unwrap().clone())
682      } else {
683        Err(HyperSigError::InvalidSignature(
684          "Invalid signature for the verifying key".to_string(),
685        ))
686      }
687    }
688  });
689  let res = futures::future::join_all(res_fut).await;
690  Ok(res)
691}
692
693/* --------------------------------------- */
694
695/// A type to represent either http request or response
696enum RequestOrResponse<'a, B> {
697  Request(&'a Request<B>),
698  Response(&'a Response<B>),
699}
700
701impl<B> RequestOrResponse<'_, B> {
702  fn method(&self) -> HyperSigResult<&http::Method> {
703    match self {
704      RequestOrResponse::Request(req) => Ok(req.method()),
705      _ => Err(HyperSigError::InvalidComponentName(
706        "`method` is only for request".to_string(),
707      )),
708    }
709  }
710
711  fn uri(&self) -> HyperSigResult<&http::Uri> {
712    match self {
713      RequestOrResponse::Request(req) => Ok(req.uri()),
714      _ => Err(HyperSigError::InvalidComponentName("`uri` is only for request".to_string())),
715    }
716  }
717
718  fn headers(&self) -> &HeaderMap {
719    match self {
720      RequestOrResponse::Request(req) => req.headers(),
721      RequestOrResponse::Response(res) => res.headers(),
722    }
723  }
724
725  fn status(&self) -> HyperSigResult<http::StatusCode> {
726    match self {
727      RequestOrResponse::Response(res) => Ok(res.status()),
728      _ => Err(HyperSigError::InvalidComponentName(
729        "`status` is only for response".to_string(),
730      )),
731    }
732  }
733}
734
735/// Extract signature and signature-input with signature-name indication from http request and response
736fn extract_signature_headers_with_name<B>(req_or_res: &RequestOrResponse<B>) -> HyperSigResult<HttpSignatureHeadersMap> {
737  let headers = req_or_res.headers();
738  if !(headers.contains_key("signature-input") && headers.contains_key("signature")) {
739    return Err(HyperSigError::NoSignatureHeaders(
740      "The request does not have signature and signature-input headers".to_string(),
741    ));
742  };
743
744  let signature_input_strings = headers
745    .get_all("signature-input")
746    .iter()
747    .map(|v| v.to_str())
748    .collect::<Result<Vec<_>, _>>()?
749    .join(", ");
750  let signature_strings = headers
751    .get_all("signature")
752    .iter()
753    .map(|v| v.to_str())
754    .collect::<Result<Vec<_>, _>>()?
755    .join(", ");
756
757  let signature_headers = HttpSignatureHeaders::try_parse(&signature_strings, &signature_input_strings)?;
758  Ok(signature_headers)
759}
760
761/// Build signature base from hyper http request/response and signature params
762/// - req_or_res: the hyper http request or response
763/// - signature_params: the http signature params
764/// - req_for_param: corresponding request to be considered in the signature base in response
765fn build_signature_base<B1, B2>(
766  req_or_res: &RequestOrResponse<B1>,
767  signature_params: &HttpSignatureParams,
768  req_for_param: Option<&Request<B2>>,
769) -> HyperSigResult<HttpSignatureBase> {
770  let component_lines = signature_params
771    .covered_components
772    .iter()
773    .map(|component_id| {
774      if component_id.params.0.contains(&HttpMessageComponentParam::Req) {
775        if matches!(req_or_res, RequestOrResponse::Request(_)) {
776          return Err(HyperSigError::InvalidComponentParam(
777            "`req` is not allowed in request".to_string(),
778          ));
779        }
780        if req_for_param.is_none() {
781          return Err(HyperSigError::InvalidComponentParam(
782            "`req` is required for the param".to_string(),
783          ));
784        }
785        let req = RequestOrResponse::Request(req_for_param.unwrap());
786        extract_http_message_component(&req, component_id)
787      } else {
788        extract_http_message_component(req_or_res, component_id)
789      }
790    })
791    .collect::<Result<Vec<_>, _>>()?;
792
793  HttpSignatureBase::try_new(&component_lines, signature_params).map_err(|e| e.into())
794}
795
796/// Extract http field from hyper http request/response
797fn extract_http_field<B>(req_or_res: &RequestOrResponse<B>, id: &HttpMessageComponentId) -> HyperSigResult<HttpMessageComponent> {
798  let HttpMessageComponentName::HttpField(header_name) = &id.name else {
799    return Err(HyperSigError::InvalidComponentName(
800      "invalid http message component name as http field".to_string(),
801    ));
802  };
803  let headers = match req_or_res {
804    RequestOrResponse::Request(req) => req.headers(),
805    RequestOrResponse::Response(res) => res.headers(),
806  };
807
808  let field_values = headers
809    .get_all(header_name)
810    .iter()
811    .map(|v| v.to_str().map(|s| s.to_owned()))
812    .collect::<Result<Vec<_>, _>>()?;
813
814  HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
815}
816
817/// Extract derived component from hyper http request/response
818fn extract_derived_component<B>(
819  req_or_res: &RequestOrResponse<B>,
820  id: &HttpMessageComponentId,
821) -> HyperSigResult<HttpMessageComponent> {
822  let HttpMessageComponentName::Derived(derived_id) = &id.name else {
823    return Err(HyperSigError::InvalidComponentName(
824      "invalid http message component name as derived component".to_string(),
825    ));
826  };
827  if !id.params.0.is_empty()
828    && matches!(req_or_res, RequestOrResponse::Request(_))
829    && !(id.params.0.contains(&HttpMessageComponentParam::Req) && id.params.0.len() == 1)
830  {
831    return Err(HyperSigError::InvalidComponentParam(
832      "derived component does not allow parameters for request".to_string(),
833    ));
834  }
835
836  match req_or_res {
837    RequestOrResponse::Request(_) => {
838      if matches!(derived_id, DerivedComponentName::Status) {
839        return Err(HyperSigError::InvalidComponentName(
840          "`status` is only for response".to_string(),
841        ));
842      }
843    }
844    RequestOrResponse::Response(_) => {
845      if !matches!(derived_id, DerivedComponentName::Status) && !matches!(derived_id, DerivedComponentName::SignatureParams) {
846        return Err(HyperSigError::InvalidComponentName(
847          "Only `status` and `signature-params` are allowed for response".to_string(),
848        ));
849      }
850    }
851  }
852
853  let field_values: Vec<String> = match derived_id {
854    DerivedComponentName::Method => vec![req_or_res.method()?.as_str().to_string()],
855    DerivedComponentName::TargetUri => vec![req_or_res.uri()?.to_string()],
856    DerivedComponentName::Authority => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
857    DerivedComponentName::Scheme => vec![req_or_res.uri()?.scheme_str().unwrap_or("").to_string()],
858    DerivedComponentName::RequestTarget => match *req_or_res.method()? {
859      http::Method::CONNECT => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
860      http::Method::OPTIONS => vec!["*".to_string()],
861      _ => vec![req_or_res
862        .uri()?
863        .path_and_query()
864        .map(|s| s.to_string())
865        .unwrap_or("".to_string())],
866    },
867    DerivedComponentName::Path => vec![{
868      let p = req_or_res.uri()?.path();
869      if p.is_empty() {
870        "/".to_string()
871      } else {
872        p.to_string()
873      }
874    }],
875    DerivedComponentName::Query => vec![req_or_res.uri()?.query().map(|v| format!("?{v}")).unwrap_or("?".to_string())],
876    DerivedComponentName::QueryParam => {
877      let query = req_or_res.uri()?.query().unwrap_or("");
878      query
879        .split('&')
880        .filter(|s| !s.is_empty())
881        .map(|s| s.to_string())
882        .collect::<Vec<_>>()
883    }
884    DerivedComponentName::Status => vec![req_or_res.status()?.as_str().to_string()],
885    DerivedComponentName::SignatureParams => req_or_res
886      .headers()
887      .get_all("signature-input")
888      .iter()
889      .map(|v| v.to_str().unwrap_or("").to_string())
890      .collect::<Vec<_>>(),
891  };
892
893  HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
894}
895
896/* --------------------------------------- */
897/// Extract http message component from hyper http request
898fn extract_http_message_component<B>(
899  req_or_res: &RequestOrResponse<B>,
900  target_component_id: &HttpMessageComponentId,
901) -> HyperSigResult<HttpMessageComponent> {
902  match &target_component_id.name {
903    HttpMessageComponentName::HttpField(_) => extract_http_field(req_or_res, target_component_id),
904    HttpMessageComponentName::Derived(_) => extract_derived_component(req_or_res, target_component_id),
905  }
906}
907
908/* --------------------------------------- */
909#[cfg(test)]
910mod tests {
911
912  use super::{
913    super::{
914      error::HyperDigestError,
915      hyper_content_digest::{RequestContentDigest, ResponseContentDigest},
916      ContentDigestType,
917    },
918    *,
919  };
920  use http_body_util::Full;
921  use httpsig::prelude::{AlgorithmName, PublicKey, SecretKey, SharedKey};
922
923  type BoxBody = http_body_util::combinators::BoxBody<bytes::Bytes, HyperDigestError>;
924
925  const EDDSA_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
926MC4CAQAwBQYDK2VwBCIEIDSHAE++q1BP7T8tk+mJtS+hLf81B0o6CFyWgucDFN/C
927-----END PRIVATE KEY-----
928"##;
929  const EDDSA_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
930MCowBQYDK2VwAyEA1ixMQcxO46PLlgQfYS46ivFd+n0CcDHSKUnuhm3i1O0=
931-----END PUBLIC KEY-----
932"##;
933  // const EDDSA_KEY_ID: &str = "gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=";
934  const COVERED_COMPONENTS_REQ: &[&str] = &["@method", "date", "content-type", "content-digest"];
935  const COVERED_COMPONENTS_RES: &[&str] = &["@status", "\"@method\";req", "date", "content-type", "\"content-digest\";req"];
936
937  async fn build_request() -> Request<BoxBody> {
938    let body = Full::new(&b"{\"hello\": \"world\"}"[..]);
939    let req = Request::builder()
940      .method("GET")
941      .uri("https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something")
942      .header("date", "Sun, 09 May 2021 18:30:00 GMT")
943      .header("content-type", "application/json")
944      .header("content-type", "application/json-patch+json")
945      .body(body)
946      .unwrap();
947    req.set_content_digest(&ContentDigestType::Sha256).await.unwrap()
948  }
949
950  async fn build_response() -> Response<BoxBody> {
951    let body = Full::new(&b"{\"hello\": \"world!!\"}"[..]);
952    let res = Response::builder()
953      .status(200)
954      .header("date", "Sun, 09 May 2021 18:30:00 GMT")
955      .header("content-type", "application/json")
956      .header("content-type", "application/json-patch+json")
957      .body(body)
958      .unwrap();
959    res.set_content_digest(&ContentDigestType::Sha256).await.unwrap()
960  }
961
962  fn build_covered_components_req() -> Vec<HttpMessageComponentId> {
963    COVERED_COMPONENTS_REQ
964      .iter()
965      .map(|&s| HttpMessageComponentId::try_from(s).unwrap())
966      .collect()
967  }
968
969  fn build_covered_components_res() -> Vec<HttpMessageComponentId> {
970    COVERED_COMPONENTS_RES
971      .iter()
972      .map(|&s| HttpMessageComponentId::try_from(s).unwrap())
973      .collect()
974  }
975
976  #[tokio::test]
977  async fn test_extract_component_from_request() {
978    let req = build_request().await;
979    let req_or_res = RequestOrResponse::Request(&req);
980
981    let component_id_method = HttpMessageComponentId::try_from("\"@method\"").unwrap();
982    let component = extract_http_message_component(&req_or_res, &component_id_method).unwrap();
983    assert_eq!(component.to_string(), "\"@method\": GET");
984
985    let component_id = HttpMessageComponentId::try_from("\"date\"").unwrap();
986    let component = extract_http_message_component(&req_or_res, &component_id).unwrap();
987    assert_eq!(component.to_string(), "\"date\": Sun, 09 May 2021 18:30:00 GMT");
988
989    let component_id = HttpMessageComponentId::try_from("content-type").unwrap();
990    let component = extract_http_field(&req_or_res, &component_id).unwrap();
991    assert_eq!(
992      component.to_string(),
993      "\"content-type\": application/json, application/json-patch+json"
994    );
995
996    let component_id = HttpMessageComponentId::try_from("content-digest").unwrap();
997    let component = extract_http_message_component(&req_or_res, &component_id).unwrap();
998    assert_eq!(
999      component.to_string(),
1000      "\"content-digest\": sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:"
1001    );
1002  }
1003
1004  #[tokio::test]
1005  async fn test_extract_signature_params_from_request() {
1006    let mut req = build_request().await;
1007    let headers = req.headers_mut();
1008    headers.insert(
1009      "signature-input",
1010      http::HeaderValue::from_static(r##"sig1=("@method" "@authority")"##),
1011    );
1012    let component_id = HttpMessageComponentId::try_from("@signature-params").unwrap();
1013    let req_or_res = RequestOrResponse::Request(&req);
1014    let component = extract_http_message_component(&req_or_res, &component_id).unwrap();
1015    assert_eq!(component.to_string(), "\"@signature-params\": (\"@method\" \"@authority\")");
1016    assert_eq!(component.value.to_string(), r##"("@method" "@authority")"##);
1017    assert_eq!(component.value.as_field_value(), r##"sig1=("@method" "@authority")"##);
1018    assert_eq!(component.value.as_component_value(), r##"("@method" "@authority")"##);
1019    assert_eq!(component.value.key(), Some("sig1"));
1020  }
1021
1022  #[tokio::test]
1023  async fn test_build_signature_base_from_request() {
1024    let req = build_request().await;
1025
1026    const SIGPARA: &str = r##";created=1704972031;alg="ed25519";keyid="gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=""##;
1027    let values = (r##""@method" "content-type" "date" "content-digest""##, SIGPARA);
1028    let signature_params = HttpSignatureParams::try_from(format!("({}){}", values.0, values.1).as_str()).unwrap();
1029
1030    let req_or_res = RequestOrResponse::Request(&req);
1031    let signature_base = build_signature_base(&req_or_res, &signature_params, None as Option<&Request<()>>).unwrap();
1032    assert_eq!(
1033      signature_base.to_string(),
1034      r##""@method": GET
1035"content-type": application/json, application/json-patch+json
1036"date": Sun, 09 May 2021 18:30:00 GMT
1037"content-digest": sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
1038"@signature-params": ("@method" "content-type" "date" "content-digest");created=1704972031;alg="ed25519";keyid="gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=""##
1039    );
1040  }
1041
1042  #[tokio::test]
1043  async fn test_extract_tuples_from_request() {
1044    let mut req = build_request().await;
1045    let headers = req.headers_mut();
1046    headers.insert(
1047      "signature-input",
1048      http::HeaderValue::from_static(r##"sig11=("@method" "@authority");created=1704972031"##),
1049    );
1050    headers.insert(
1051      "signature",
1052      http::HeaderValue::from_static(
1053        r##"sig11=:wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==:"##,
1054      ),
1055    );
1056
1057    let req_or_res = RequestOrResponse::Request(&req);
1058    let tuples = extract_signature_headers_with_name(&req_or_res).unwrap();
1059    assert_eq!(tuples.len(), 1);
1060    assert_eq!(tuples.get("sig11").unwrap().signature_name(), "sig11");
1061    assert_eq!(
1062      tuples.get("sig11").unwrap().signature_params().to_string(),
1063      r##"("@method" "@authority");created=1704972031"##
1064    );
1065  }
1066
1067  #[tokio::test]
1068  async fn test_set_verify_message_signature_req() {
1069    let mut req = build_request().await;
1070    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1071    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1072    signature_params.set_key_info(&secret_key);
1073
1074    req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1075    let signature_input = req.headers().get("signature-input").unwrap().to_str().unwrap();
1076    assert!(signature_input.starts_with(r##"sig=("@method" "date" "content-type" "content-digest")"##));
1077    // let signature = req.headers().get("signature").unwrap().to_str().unwrap();
1078
1079    let public_key = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1080    let verification_res = req.verify_message_signature(&public_key, None).await;
1081    assert!(verification_res.is_ok());
1082  }
1083
1084  #[tokio::test]
1085  async fn test_set_verify_message_signature_res() {
1086    let req = build_request().await;
1087    let mut res = build_response().await;
1088
1089    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1090
1091    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_res()).unwrap();
1092    signature_params.set_key_info(&secret_key);
1093    // let req_or_res = RequestOrResponse::Response(&res);
1094    // let base = build_signature_base(&req_or_res, &signature_params, Some(&req));
1095    // println!("{}", base.unwrap());
1096    // // println!("{:#?}", req);
1097
1098    res
1099      .set_message_signature(&signature_params, &secret_key, None, Some(&req))
1100      .await
1101      .unwrap();
1102    // println!("{:#?}", res.headers());
1103    let signature_input = res.headers().get("signature-input").unwrap().to_str().unwrap();
1104    assert!(signature_input.starts_with(r##"sig=("@status" "@method";req "date" "content-type" "content-digest";req)"##));
1105    // let signature = req.headers().get("signature").unwrap().to_str().unwrap();
1106
1107    let public_key = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1108    let verification_res = res.verify_message_signature(&public_key, None, Some(&req)).await;
1109    assert!(verification_res.is_ok());
1110  }
1111
1112  #[tokio::test]
1113  async fn test_expired_signature() {
1114    let mut req = build_request().await;
1115    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1116    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1117    signature_params.set_key_info(&secret_key);
1118    let created = signature_params.created.unwrap();
1119    signature_params.set_expires(created - 1);
1120    assert!(signature_params.is_expired());
1121
1122    req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1123
1124    let public_key = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1125    let verification_res = req.verify_message_signature(&public_key, None).await;
1126    assert!(verification_res.is_err());
1127  }
1128
1129  #[tokio::test]
1130  async fn test_set_verify_with_signature_name() {
1131    let mut req = build_request().await;
1132    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1133    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1134    signature_params.set_key_info(&secret_key);
1135
1136    req
1137      .set_message_signature(&signature_params, &secret_key, Some("custom_sig_name"))
1138      .await
1139      .unwrap();
1140
1141    let req_or_res = RequestOrResponse::Request(&req);
1142    let signature_headers_map = extract_signature_headers_with_name(&req_or_res).unwrap();
1143    assert_eq!(signature_headers_map.len(), 1);
1144    assert_eq!(signature_headers_map[0].signature_name(), "custom_sig_name");
1145
1146    let public_key = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1147    let verification_res = req.verify_message_signature(&public_key, None).await;
1148    assert!(verification_res.is_ok());
1149  }
1150
1151  #[tokio::test]
1152  async fn test_set_verify_with_key_id() {
1153    let mut req = build_request().await;
1154    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1155    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1156    signature_params.set_key_info(&secret_key);
1157
1158    req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1159
1160    let public_key = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1161    let key_id = public_key.key_id();
1162    let verification_res = req.verify_message_signature(&public_key, Some(&key_id)).await;
1163    assert!(verification_res.is_ok());
1164
1165    let verification_res = req.verify_message_signature(&public_key, Some("NotFoundKeyId")).await;
1166    assert!(verification_res.is_err());
1167  }
1168
1169  const HMACSHA256_SECRET_KEY: &str =
1170    r##"uzvJfB4u3N0Jy4T7NZ75MDVcr8zSTInedJtkgcu46YW4XByzNJjxBdtjUkdJPBtbmHhIDi6pcl8jsasjlTMtDQ=="##;
1171
1172  #[tokio::test]
1173  async fn test_set_verify_with_key_id_hmac_sha256() {
1174    let mut req = build_request().await;
1175    let secret_key = SharedKey::from_base64(&AlgorithmName::HmacSha256, HMACSHA256_SECRET_KEY).unwrap();
1176    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1177    signature_params.set_key_info(&secret_key);
1178    // Random nonce is highly recommended for HMAC
1179    signature_params.set_random_nonce();
1180
1181    req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1182
1183    let org_key_id = VerifyingKey::key_id(&secret_key);
1184    let (alg, key_id) = req.get_alg_key_ids().unwrap().into_iter().next().unwrap().1;
1185    let alg = alg.unwrap();
1186    let key_id = key_id.unwrap();
1187    assert_eq!(org_key_id, key_id);
1188    let verification_key = SharedKey::from_base64(&alg, HMACSHA256_SECRET_KEY).unwrap();
1189    let verification_res = req.verify_message_signature(&verification_key, Some(&key_id)).await;
1190    assert!(verification_res.is_ok());
1191
1192    let verification_res = req.verify_message_signature(&verification_key, Some("NotFoundKeyId")).await;
1193    assert!(verification_res.is_err());
1194  }
1195
1196  #[tokio::test]
1197  async fn test_get_alg_key_ids() {
1198    let mut req = build_request().await;
1199    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1200    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1201    signature_params.set_key_info(&secret_key);
1202
1203    req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1204    let key_ids = req.get_alg_key_ids().unwrap();
1205    assert_eq!(key_ids.len(), 1);
1206    assert_eq!(key_ids[0].0.as_ref().unwrap(), &AlgorithmName::Ed25519);
1207    assert_eq!(key_ids[0].1.as_ref().unwrap(), "gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=");
1208  }
1209
1210  const P256_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
1211MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgv7zxW56ojrWwmSo1
12124uOdbVhUfj9Jd+5aZIB9u8gtWnihRANCAARGYsMe0CT6pIypwRvoJlLNs4+cTh2K
1213L7fUNb5i6WbKxkpAoO+6T3pMBG5Yw7+8NuGTvvtrZAXduA2giPxQ8zCf
1214-----END PRIVATE KEY-----
1215"##;
1216  const P256_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
1217MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERmLDHtAk+qSMqcEb6CZSzbOPnE4d
1218ii+31DW+YulmysZKQKDvuk96TARuWMO/vDbhk777a2QF3bgNoIj8UPMwnw==
1219-----END PUBLIC KEY-----
1220"##;
1221  #[tokio::test]
1222  async fn test_set_verify_multiple_signatures() {
1223    let mut req = build_request().await;
1224
1225    let secret_key_eddsa = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1226    let mut signature_params_eddsa = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1227    signature_params_eddsa.set_key_info(&secret_key_eddsa);
1228
1229    let secret_key_p256 = SecretKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_SECRET_KEY).unwrap();
1230    let mut signature_params_hmac = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1231    signature_params_hmac.set_key_info(&secret_key_p256);
1232
1233    let params_key_name = &[
1234      (&signature_params_eddsa, &secret_key_eddsa, Some("eddsa_sig")),
1235      (&signature_params_hmac, &secret_key_p256, Some("p256_sig")),
1236    ];
1237
1238    req.set_message_signatures(params_key_name).await.unwrap();
1239
1240    let public_key_eddsa = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1241    let public_key_p256 = PublicKey::from_pem(&AlgorithmName::EcdsaP256Sha256, P256_PUBLIC_KEY).unwrap();
1242    let key_id_eddsa = public_key_eddsa.key_id();
1243    let key_id_p256 = public_key_p256.key_id();
1244
1245    let verification_res = req
1246      .verify_message_signatures(&[
1247        (&public_key_eddsa, Some(&key_id_eddsa)),
1248        (&public_key_p256, Some(&key_id_p256)),
1249      ])
1250      .await
1251      .unwrap();
1252
1253    assert!(verification_res.len() == 2 && verification_res.iter().all(|r| r.is_ok()));
1254    assert!(verification_res[0].as_ref().unwrap() == "eddsa_sig");
1255    assert!(verification_res[1].as_ref().unwrap() == "p256_sig");
1256  }
1257
1258  #[cfg(feature = "blocking")]
1259  #[test]
1260  fn test_blocking_set_verify_message_signature_req() {
1261    let mut req = futures::executor::block_on(build_request());
1262    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1263    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1264    signature_params.set_key_info(&secret_key);
1265
1266    req.set_message_signature_sync(&signature_params, &secret_key, None).unwrap();
1267
1268    let public_key = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1269    let verification_res = req.verify_message_signature_sync(&public_key, None);
1270    assert!(verification_res.is_ok());
1271  }
1272
1273  #[cfg(feature = "blocking")]
1274  #[test]
1275  fn test_blocking_set_verify_message_signature_res() {
1276    let req = futures::executor::block_on(build_request());
1277    let mut res = futures::executor::block_on(build_response());
1278    let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
1279    let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_res()).unwrap();
1280    signature_params.set_key_info(&secret_key);
1281    res
1282      .set_message_signature_sync(&signature_params, &secret_key, None, Some(&req))
1283      .unwrap();
1284
1285    let public_key = PublicKey::from_pem(&AlgorithmName::Ed25519, EDDSA_PUBLIC_KEY).unwrap();
1286    let verification_res = res.verify_message_signature_sync(&public_key, None, Some(&req));
1287    assert!(verification_res.is_ok());
1288  }
1289}