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_bases = params_key_name
290      .iter()
291      .map(|(params, key, name)| {
292        build_signature_base(&req_or_res, params, None as Option<&Request<()>>).map(|base| (base, *key, *name))
293      })
294      .collect::<Result<Vec<_>, _>>()?;
295    let vec_signature_headers = futures::future::join_all(
296      vec_signature_bases
297        .into_iter()
298        .map(|(base, key, name)| async move { base.build_signature_headers(key, name) }),
299    )
300    .await
301    .into_iter()
302    .collect::<Result<Vec<_>, _>>()?;
303    vec_signature_headers.iter().try_for_each(|headers| {
304      self
305        .headers_mut()
306        .append("signature-input", headers.signature_input_header_value().parse()?);
307      self
308        .headers_mut()
309        .append("signature", headers.signature_header_value().parse()?);
310      Ok(()) as Result<(), HyperSigError>
311    })
312  }
313
314  /// Verify the http message signature with given verifying key if the request has signature and signature-input headers
315  /// Return Ok(()) if the signature is valid.
316  /// 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.
317  /// If key_id is given, it is used to match the key id in signature params
318  async fn verify_message_signature<T>(&self, verifying_key: &T, key_id: Option<&str>) -> HyperSigResult<SignatureName>
319  where
320    Self: Sized,
321    T: VerifyingKey + Sync,
322  {
323    self
324      .verify_message_signatures(&[(verifying_key, key_id)])
325      .await?
326      .pop()
327      .unwrap()
328  }
329
330  async fn verify_message_signatures<T>(
331    &self,
332    key_and_id: &[(&T, Option<&str>)],
333  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
334  where
335    Self: Sized,
336    T: VerifyingKey + Sync,
337  {
338    if !self.has_message_signature() {
339      return Err(HyperSigError::NoSignatureHeaders(
340        "The request does not have signature and signature-input headers".to_string(),
341      ));
342    }
343    let map_signature_with_base = self.extract_signatures()?;
344    verify_message_signatures_inner(&map_signature_with_base, key_and_id).await
345  }
346
347  /// Extract all signature bases contained in the request headers
348  fn extract_signatures(&self) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error> {
349    let req_or_res = RequestOrResponse::Request(self);
350    extract_signatures_inner(&req_or_res, None as Option<&Request<()>>)
351  }
352}
353
354/* --------------------------------------- */
355impl<D> MessageSignature for Response<D>
356where
357  D: Send + Body + Sync,
358{
359  type Error = HyperSigError;
360
361  /// Check if the response has signature and signature-input headers
362  fn has_message_signature(&self) -> bool {
363    has_message_signature_inner(self.headers())
364  }
365
366  /// Extract all key ids for signature bases contained in the response headers
367  fn get_alg_key_ids(&self) -> Result<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>, Self::Error> {
368    let req_or_res = RequestOrResponse::Response(self);
369    get_alg_key_ids_inner(&req_or_res)
370  }
371
372  /// Extract all signature params used to generate signature bases contained in the response headers
373  fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error> {
374    let req_or_res = RequestOrResponse::Response(self);
375    get_signature_params_inner(&req_or_res)
376  }
377}
378
379impl<D> MessageSignatureRes for Response<D>
380where
381  D: Send + Body + Sync,
382{
383  type Error = HyperSigError;
384
385  /// Set the http message signature from given http signature params and signing key
386  async fn set_message_signature<T, B>(
387    &mut self,
388    signature_params: &HttpSignatureParams,
389    signing_key: &T,
390    signature_name: Option<&str>,
391    req_for_param: Option<&Request<B>>,
392  ) -> Result<(), Self::Error>
393  where
394    Self: Sized,
395    T: SigningKey + Sync,
396    B: Sync,
397  {
398    self
399      .set_message_signatures(&[(signature_params, signing_key, signature_name)], req_for_param)
400      .await
401  }
402
403  async fn set_message_signatures<T, B>(
404    &mut self,
405    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
406    req_for_param: Option<&Request<B>>,
407  ) -> Result<(), Self::Error>
408  where
409    Self: Sized,
410    T: SigningKey + Sync,
411  {
412    let req_or_res = RequestOrResponse::Response(self);
413
414    let vec_signature_bases = params_key_name
415      .iter()
416      .map(|(params, key, name)| build_signature_base(&req_or_res, params, req_for_param).map(|base| (base, *key, *name)))
417      .collect::<Result<Vec<_>, _>>()?;
418    let vec_signature_headers = futures::future::join_all(
419      vec_signature_bases
420        .into_iter()
421        .map(|(base, key, name)| async move { base.build_signature_headers(key, name) }),
422    )
423    .await
424    .into_iter()
425    .collect::<Result<Vec<_>, _>>()?;
426
427    vec_signature_headers.iter().try_for_each(|headers| {
428      self
429        .headers_mut()
430        .append("signature-input", headers.signature_input_header_value().parse()?);
431      self
432        .headers_mut()
433        .append("signature", headers.signature_header_value().parse()?);
434      Ok(()) as Result<(), HyperSigError>
435    })
436  }
437
438  /// Verify the http message signature with given verifying key if the response has signature and signature-input headers
439  /// Return Ok(()) if the signature is valid.
440  /// 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.
441  /// If key_id is given, it is used to match the key id in signature params
442  async fn verify_message_signature<T, B>(
443    &self,
444    verifying_key: &T,
445    key_id: Option<&str>,
446    req_for_param: Option<&Request<B>>,
447  ) -> Result<SignatureName, Self::Error>
448  where
449    Self: Sized,
450    T: VerifyingKey + Sync,
451    B: Sync,
452  {
453    self
454      .verify_message_signatures(&[(verifying_key, key_id)], req_for_param)
455      .await?
456      .pop()
457      .unwrap()
458  }
459
460  async fn verify_message_signatures<T, B>(
461    &self,
462    key_and_id: &[(&T, Option<&str>)],
463    req_for_param: Option<&Request<B>>,
464  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
465  where
466    Self: Sized,
467    T: VerifyingKey + Sync,
468  {
469    if !self.has_message_signature() {
470      return Err(HyperSigError::NoSignatureHeaders(
471        "The response does not have signature and signature-input headers".to_string(),
472      ));
473    }
474    let map_signature_with_base = self.extract_signatures(req_for_param)?;
475    verify_message_signatures_inner(&map_signature_with_base, key_and_id).await
476  }
477
478  /// Extract all signature bases contained in the response headers
479  fn extract_signatures<B>(
480    &self,
481    req_for_param: Option<&Request<B>>,
482  ) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error> {
483    let req_or_res = RequestOrResponse::Response(self);
484    extract_signatures_inner(&req_or_res, req_for_param)
485  }
486}
487
488/* --------------------------------------- */
489#[cfg(feature = "blocking")]
490impl<D> MessageSignatureReqSync for Request<D>
491where
492  D: Send + Body + Sync,
493{
494  fn set_message_signature_sync<T>(
495    &mut self,
496    signature_params: &HttpSignatureParams,
497    signing_key: &T,
498    signature_name: Option<&str>,
499  ) -> Result<(), Self::Error>
500  where
501    Self: Sized,
502    T: SigningKey + Sync,
503  {
504    futures::executor::block_on(self.set_message_signature(signature_params, signing_key, signature_name))
505  }
506
507  fn set_message_signatures_sync<T>(
508    &mut self,
509    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
510  ) -> Result<(), Self::Error>
511  where
512    Self: Sized,
513    T: SigningKey + Sync,
514  {
515    futures::executor::block_on(self.set_message_signatures(params_key_name))
516  }
517
518  fn verify_message_signature_sync<T>(&self, verifying_key: &T, key_id: Option<&str>) -> Result<SignatureName, Self::Error>
519  where
520    Self: Sized,
521    T: VerifyingKey + Sync,
522  {
523    futures::executor::block_on(self.verify_message_signature(verifying_key, key_id))
524  }
525
526  fn verify_message_signatures_sync<T>(
527    &self,
528    key_and_id: &[(&T, Option<&str>)],
529  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
530  where
531    Self: Sized,
532    T: VerifyingKey + Sync,
533  {
534    futures::executor::block_on(self.verify_message_signatures(key_and_id))
535  }
536}
537
538#[cfg(feature = "blocking")]
539impl<D> MessageSignatureResSync for Response<D>
540where
541  D: Send + Body + Sync,
542{
543  fn set_message_signature_sync<T, B>(
544    &mut self,
545    signature_params: &HttpSignatureParams,
546    signing_key: &T,
547    signature_name: Option<&str>,
548    req_for_param: Option<&Request<B>>,
549  ) -> Result<(), Self::Error>
550  where
551    Self: Sized,
552    T: SigningKey + Sync,
553    B: Sync,
554  {
555    futures::executor::block_on(self.set_message_signature(signature_params, signing_key, signature_name, req_for_param))
556  }
557
558  fn set_message_signatures_sync<T, B>(
559    &mut self,
560    params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
561    req_for_param: Option<&Request<B>>,
562  ) -> Result<(), Self::Error>
563  where
564    Self: Sized,
565    T: SigningKey + Sync,
566    B: Sync,
567  {
568    futures::executor::block_on(self.set_message_signatures(params_key_name, req_for_param))
569  }
570
571  fn verify_message_signature_sync<T, B>(
572    &self,
573    verifying_key: &T,
574    key_id: Option<&str>,
575    req_for_param: Option<&Request<B>>,
576  ) -> Result<SignatureName, Self::Error>
577  where
578    Self: Sized,
579    T: VerifyingKey + Sync,
580    B: Sync,
581  {
582    futures::executor::block_on(self.verify_message_signature(verifying_key, key_id, req_for_param))
583  }
584
585  fn verify_message_signatures_sync<T, B>(
586    &self,
587    key_and_id: &[(&T, Option<&str>)],
588    req_for_param: Option<&Request<B>>,
589  ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
590  where
591    Self: Sized,
592    T: VerifyingKey + Sync,
593    B: Sync,
594  {
595    futures::executor::block_on(self.verify_message_signatures(key_and_id, req_for_param))
596  }
597}
598
599/* --------------------------------------- */
600// inner functions
601/// has message signature inner function
602fn has_message_signature_inner(headers: &HeaderMap) -> bool {
603  headers.contains_key("signature") && headers.contains_key("signature-input")
604}
605
606/// get key ids inner function
607fn get_alg_key_ids_inner<B>(
608  req_or_res: &RequestOrResponse<B>,
609) -> HyperSigResult<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>> {
610  let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
611  let res = signature_headers_map
612    .iter()
613    .map(|(name, headers)| {
614      // Unknown or unsupported algorithm strings are mapped to None
615      let alg = headers
616        .signature_params()
617        .alg
618        .clone()
619        .map(|a| AlgorithmName::from_str(&a))
620        .transpose()
621        .ok()
622        .flatten();
623      let key_id = headers.signature_params().keyid.clone();
624      (name.clone(), (alg, key_id))
625    })
626    .collect();
627  Ok(res)
628}
629
630/// get signature params inner function
631fn get_signature_params_inner<B>(
632  req_or_res: &RequestOrResponse<B>,
633) -> HyperSigResult<IndexMap<SignatureName, HttpSignatureParams>> {
634  let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
635  let res = signature_headers_map
636    .iter()
637    .map(|(name, headers)| (name.clone(), headers.signature_params().clone()))
638    .collect();
639  Ok(res)
640}
641
642/// extract signatures inner function
643fn extract_signatures_inner<B1, B2>(
644  req_or_res: &RequestOrResponse<B1>,
645  req_for_param: Option<&Request<B2>>,
646) -> HyperSigResult<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>> {
647  let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
648  let extracted = signature_headers_map
649    .iter()
650    .filter_map(|(name, headers)| {
651      build_signature_base(req_or_res, headers.signature_params(), req_for_param)
652        .ok()
653        .map(|base| (name.clone(), (base, headers.clone())))
654    })
655    .collect();
656  Ok(extracted)
657}
658
659/// Verify multiple signatures inner function
660async fn verify_message_signatures_inner<T>(
661  map_signature_with_base: &IndexMap<String, (HttpSignatureBase, HttpSignatureHeaders)>,
662  key_and_id: &[(&T, Option<&str>)],
663) -> HyperSigResult<Vec<HyperSigResult<SignatureName>>>
664where
665  T: VerifyingKey + Sync,
666{
667  // verify for each key_and_id tuple
668  let res_fut = key_and_id.iter().map(|(key, key_id)| {
669    let filtered = if let Some(key_id) = key_id {
670      map_signature_with_base
671        .iter()
672        .filter(|(_, (base, _))| base.keyid() == Some(key_id))
673        .collect::<IndexMap<_, _>>()
674    } else {
675      map_signature_with_base.iter().collect()
676    };
677
678    // check if any one of the signature headers is valid in async manner
679    async move {
680      if filtered.is_empty() {
681        return Err(HyperSigError::NoSignatureHeaders(
682          "No signature as appropriate target for verification".to_string(),
683        ));
684      }
685      // check if any one of the signature headers is valid
686      let successful_sig_names = filtered
687        .iter()
688        .filter_map(|(&name, (base, headers))| base.verify_signature_headers(*key, headers).ok().map(|_| name.clone()))
689        .collect::<IndexSet<_>>();
690      if !successful_sig_names.is_empty() {
691        Ok(successful_sig_names.first().unwrap().clone())
692      } else {
693        Err(HyperSigError::InvalidSignature(
694          "Invalid signature for the verifying key".to_string(),
695        ))
696      }
697    }
698  });
699  let res = futures::future::join_all(res_fut).await;
700  Ok(res)
701}
702
703/* --------------------------------------- */
704
705/// A type to represent either http request or response
706enum RequestOrResponse<'a, B> {
707  Request(&'a Request<B>),
708  Response(&'a Response<B>),
709}
710
711impl<B> RequestOrResponse<'_, B> {
712  fn method(&self) -> HyperSigResult<&http::Method> {
713    match self {
714      RequestOrResponse::Request(req) => Ok(req.method()),
715      _ => Err(HyperSigError::InvalidComponentName(
716        "`method` is only for request".to_string(),
717      )),
718    }
719  }
720
721  fn uri(&self) -> HyperSigResult<&http::Uri> {
722    match self {
723      RequestOrResponse::Request(req) => Ok(req.uri()),
724      _ => Err(HyperSigError::InvalidComponentName("`uri` is only for request".to_string())),
725    }
726  }
727
728  fn headers(&self) -> &HeaderMap {
729    match self {
730      RequestOrResponse::Request(req) => req.headers(),
731      RequestOrResponse::Response(res) => res.headers(),
732    }
733  }
734
735  fn status(&self) -> HyperSigResult<http::StatusCode> {
736    match self {
737      RequestOrResponse::Response(res) => Ok(res.status()),
738      _ => Err(HyperSigError::InvalidComponentName(
739        "`status` is only for response".to_string(),
740      )),
741    }
742  }
743}
744
745/// Extract signature and signature-input with signature-name indication from http request and response
746fn extract_signature_headers_with_name<B>(req_or_res: &RequestOrResponse<B>) -> HyperSigResult<HttpSignatureHeadersMap> {
747  let headers = req_or_res.headers();
748  if !(headers.contains_key("signature-input") && headers.contains_key("signature")) {
749    return Err(HyperSigError::NoSignatureHeaders(
750      "The request does not have signature and signature-input headers".to_string(),
751    ));
752  };
753
754  let signature_input_strings = headers
755    .get_all("signature-input")
756    .iter()
757    .map(|v| v.to_str())
758    .collect::<Result<Vec<_>, _>>()?
759    .join(", ");
760  let signature_strings = headers
761    .get_all("signature")
762    .iter()
763    .map(|v| v.to_str())
764    .collect::<Result<Vec<_>, _>>()?
765    .join(", ");
766
767  let signature_headers = HttpSignatureHeaders::try_parse(&signature_strings, &signature_input_strings)?;
768  Ok(signature_headers)
769}
770
771/// Build signature base from hyper http request/response and signature params
772/// - req_or_res: the hyper http request or response
773/// - signature_params: the http signature params
774/// - req_for_param: corresponding request to be considered in the signature base in response
775fn build_signature_base<B1, B2>(
776  req_or_res: &RequestOrResponse<B1>,
777  signature_params: &HttpSignatureParams,
778  req_for_param: Option<&Request<B2>>,
779) -> HyperSigResult<HttpSignatureBase> {
780  let component_lines = signature_params
781    .covered_components
782    .iter()
783    .map(|component_id| {
784      if component_id.params.0.contains(&HttpMessageComponentParam::Req) {
785        if matches!(req_or_res, RequestOrResponse::Request(_)) {
786          return Err(HyperSigError::InvalidComponentParam(
787            "`req` is not allowed in request".to_string(),
788          ));
789        }
790        if req_for_param.is_none() {
791          return Err(HyperSigError::InvalidComponentParam(
792            "`req` is required for the param".to_string(),
793          ));
794        }
795        let req = RequestOrResponse::Request(req_for_param.unwrap());
796        extract_http_message_component(&req, component_id)
797      } else {
798        extract_http_message_component(req_or_res, component_id)
799      }
800    })
801    .collect::<Result<Vec<_>, _>>()?;
802
803  HttpSignatureBase::try_new(&component_lines, signature_params).map_err(|e| e.into())
804}
805
806/// Extract http field from hyper http request/response
807fn extract_http_field<B>(req_or_res: &RequestOrResponse<B>, id: &HttpMessageComponentId) -> HyperSigResult<HttpMessageComponent> {
808  let HttpMessageComponentName::HttpField(header_name) = &id.name else {
809    return Err(HyperSigError::InvalidComponentName(
810      "invalid http message component name as http field".to_string(),
811    ));
812  };
813  let headers = match req_or_res {
814    RequestOrResponse::Request(req) => req.headers(),
815    RequestOrResponse::Response(res) => res.headers(),
816  };
817
818  let field_values = headers
819    .get_all(header_name)
820    .iter()
821    .map(|v| v.to_str().map(|s| s.to_owned()))
822    .collect::<Result<Vec<_>, _>>()?;
823
824  HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
825}
826
827/// Extract derived component from hyper http request/response
828fn extract_derived_component<B>(
829  req_or_res: &RequestOrResponse<B>,
830  id: &HttpMessageComponentId,
831) -> HyperSigResult<HttpMessageComponent> {
832  let HttpMessageComponentName::Derived(derived_id) = &id.name else {
833    return Err(HyperSigError::InvalidComponentName(
834      "invalid http message component name as derived component".to_string(),
835    ));
836  };
837  // Validate parameters allowed on derived components (RFC 9421).
838  // - `name`: only valid on `@query-param`
839  // - `req`: only valid on response messages (to reference request-derived components, §2.4)
840  // - `sf`, `key`, `bs`, `tr`: only valid on HTTP field components, not derived components
841  id.params.0.iter().try_for_each(|param| match param {
842    HttpMessageComponentParam::Name(_) if matches!(derived_id, DerivedComponentName::QueryParam) => Ok(()),
843    HttpMessageComponentParam::Name(_) => Err(HyperSigError::InvalidComponentParam(
844      "`name` parameter is only allowed for `@query-param`".to_string(),
845    )),
846    // `req` is only meaningful in response signatures (RFC 9421 §2.4).
847    // `build_signature_base` already validates this and re-dispatches extraction against the
848    // original request, so `req_or_res` here should always be `Request`.
849    // Guard against misuse by callers that bypass `build_signature_base`.
850    HttpMessageComponentParam::Req if matches!(req_or_res, RequestOrResponse::Request(_)) => Ok(()),
851    HttpMessageComponentParam::Req => Err(HyperSigError::InvalidComponentParam(
852      "`req`-tagged component must be extracted from the source request".to_string(),
853    )),
854    _ => Err(HyperSigError::InvalidComponentParam(format!(
855      "parameter `{}` is not allowed on derived components",
856      String::from(param.clone())
857    ))),
858  })?;
859
860  match req_or_res {
861    RequestOrResponse::Request(_) => {
862      if matches!(derived_id, DerivedComponentName::Status) {
863        return Err(HyperSigError::InvalidComponentName(
864          "`status` is only for response".to_string(),
865        ));
866      }
867    }
868    RequestOrResponse::Response(_) => {
869      let has_req = id.params.0.contains(&HttpMessageComponentParam::Req);
870      // Response messages can use `@status` and `@signature-params` directly,
871      // or any request-derived component with the `req` parameter (RFC 9421 §2.4).
872      if !matches!(derived_id, DerivedComponentName::Status)
873        && !matches!(derived_id, DerivedComponentName::SignatureParams)
874        && !has_req
875      {
876        return Err(HyperSigError::InvalidComponentName(
877          "derived components other than `@status` and `@signature-params` require `req` parameter for response".to_string(),
878        ));
879      }
880      // `@status` must not have `req` parameter
881      if matches!(derived_id, DerivedComponentName::Status) && has_req {
882        return Err(HyperSigError::InvalidComponentParam(
883          "`@status` does not accept `req` parameter".to_string(),
884        ));
885      }
886    }
887  }
888
889  let field_values: Vec<String> = match derived_id {
890    DerivedComponentName::Method => vec![req_or_res.method()?.as_str().to_string()],
891    DerivedComponentName::TargetUri => vec![req_or_res.uri()?.to_string()],
892    DerivedComponentName::Authority => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
893    DerivedComponentName::Scheme => vec![req_or_res.uri()?.scheme_str().unwrap_or("").to_string()],
894    DerivedComponentName::RequestTarget => match *req_or_res.method()? {
895      http::Method::CONNECT => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
896      http::Method::OPTIONS => vec!["*".to_string()],
897      _ => vec![req_or_res
898        .uri()?
899        .path_and_query()
900        .map(|s| s.to_string())
901        .unwrap_or("".to_string())],
902    },
903    DerivedComponentName::Path => vec![{
904      let p = req_or_res.uri()?.path();
905      if p.is_empty() {
906        "/".to_string()
907      } else {
908        p.to_string()
909      }
910    }],
911    DerivedComponentName::Query => vec![req_or_res.uri()?.query().map(|v| format!("?{v}")).unwrap_or("?".to_string())],
912    DerivedComponentName::QueryParam => {
913      let query = req_or_res.uri()?.query().unwrap_or("");
914      query
915        .split('&')
916        .filter(|s| !s.is_empty())
917        .map(|s| s.to_string())
918        .collect::<Vec<_>>()
919    }
920    DerivedComponentName::Status => vec![req_or_res.status()?.as_str().to_string()],
921    DerivedComponentName::SignatureParams => req_or_res
922      .headers()
923      .get_all("signature-input")
924      .iter()
925      .map(|v| v.to_str().unwrap_or("").to_string())
926      .collect::<Vec<_>>(),
927  };
928
929  HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
930}
931
932/* --------------------------------------- */
933/// Extract http message component from hyper http request
934fn extract_http_message_component<B>(
935  req_or_res: &RequestOrResponse<B>,
936  target_component_id: &HttpMessageComponentId,
937) -> HyperSigResult<HttpMessageComponent> {
938  match &target_component_id.name {
939    HttpMessageComponentName::HttpField(_) => extract_http_field(req_or_res, target_component_id),
940    HttpMessageComponentName::Derived(_) => extract_derived_component(req_or_res, target_component_id),
941  }
942}
943
944/* --------------------------------------- */
945#[cfg(test)]
946#[path = "hyper_http_tests.rs"]
947mod tests;