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 HttpSignatureBase, HttpSignatureHeaders, HttpSignatureHeadersMap, HttpSignatureParams, SigningKey, VerifyingKey,
9};
10use indexmap::{IndexMap, IndexSet};
11use std::future::Future;
12
13type SignatureName = String;
15type KeyId = String;
17
18pub trait MessageSignature {
21 type Error;
22
23 fn has_message_signature(&self) -> bool;
25
26 fn get_key_ids(&self) -> Result<IndexMap<SignatureName, KeyId>, Self::Error>;
28
29 fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error>;
31}
32
33pub trait MessageSignatureReq {
35 type Error;
36 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 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 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 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 fn extract_signatures(&self) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error>;
77}
78
79pub trait MessageSignatureRes {
81 type Error;
82 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 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 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 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 fn extract_signatures<B>(
131 &self,
132 req_for_param: Option<&Request<B>>,
133 ) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error>;
134}
135
136#[cfg(feature = "blocking")]
138pub 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")]
180pub 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
233impl<D> MessageSignature for Request<D>
235where
236 D: Send + Body + Sync,
237{
238 type Error = HyperSigError;
239
240 fn has_message_signature(&self) -> bool {
242 has_message_signature_inner(self.headers())
243 }
244
245 fn get_key_ids(&self) -> HyperSigResult<IndexMap<SignatureName, KeyId>> {
247 let req_or_res = RequestOrResponse::Request(self);
248 get_key_ids_inner(&req_or_res)
249 }
250
251 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 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 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 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
348impl<D> MessageSignature for Response<D>
350where
351 D: Send + Body + Sync,
352{
353 type Error = HyperSigError;
354
355 fn has_message_signature(&self) -> bool {
357 has_message_signature_inner(self.headers())
358 }
359
360 fn get_key_ids(&self) -> Result<IndexMap<SignatureName, KeyId>, Self::Error> {
362 let req_or_res = RequestOrResponse::Response(self);
363 get_key_ids_inner(&req_or_res)
364 }
365
366 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 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 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 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#[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
589fn has_message_signature_inner(headers: &HeaderMap) -> bool {
593 headers.contains_key("signature") && headers.contains_key("signature-input")
594}
595
596fn get_key_ids_inner<B>(req_or_res: &RequestOrResponse<B>) -> HyperSigResult<IndexMap<SignatureName, KeyId>> {
598 let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
599 let res = signature_headers_map
600 .iter()
601 .filter_map(|(name, headers)| headers.signature_params().keyid.clone().map(|key_id| (name.clone(), key_id)))
602 .collect();
603 Ok(res)
604}
605
606fn get_signature_params_inner<B>(
608 req_or_res: &RequestOrResponse<B>,
609) -> HyperSigResult<IndexMap<SignatureName, HttpSignatureParams>> {
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)| (name.clone(), headers.signature_params().clone()))
614 .collect();
615 Ok(res)
616}
617
618fn extract_signatures_inner<B1, B2>(
620 req_or_res: &RequestOrResponse<B1>,
621 req_for_param: Option<&Request<B2>>,
622) -> HyperSigResult<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>> {
623 let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
624 let extracted = signature_headers_map
625 .iter()
626 .filter_map(|(name, headers)| {
627 build_signature_base(req_or_res, headers.signature_params(), req_for_param)
628 .ok()
629 .map(|base| (name.clone(), (base, headers.clone())))
630 })
631 .collect();
632 Ok(extracted)
633}
634
635async fn verify_message_signatures_inner<T>(
637 map_signature_with_base: &IndexMap<String, (HttpSignatureBase, HttpSignatureHeaders)>,
638 key_and_id: &[(&T, Option<&str>)],
639) -> HyperSigResult<Vec<HyperSigResult<SignatureName>>>
640where
641 T: VerifyingKey + Sync,
642{
643 let res_fut = key_and_id.iter().map(|(key, key_id)| {
645 let filtered = if let Some(key_id) = key_id {
646 map_signature_with_base
647 .iter()
648 .filter(|(_, (base, _))| base.keyid() == Some(key_id))
649 .collect::<IndexMap<_, _>>()
650 } else {
651 map_signature_with_base.iter().collect()
652 };
653
654 async move {
656 if filtered.is_empty() {
657 return Err(HyperSigError::NoSignatureHeaders(
658 "No signature as appropriate target for verification".to_string(),
659 ));
660 }
661 let successful_sig_names = filtered
663 .iter()
664 .filter_map(|(&name, (base, headers))| base.verify_signature_headers(*key, headers).ok().map(|_| name.clone()))
665 .collect::<IndexSet<_>>();
666 if !successful_sig_names.is_empty() {
667 Ok(successful_sig_names.first().unwrap().clone())
668 } else {
669 Err(HyperSigError::InvalidSignature(
670 "Invalid signature for the verifying key".to_string(),
671 ))
672 }
673 }
674 });
675 let res = futures::future::join_all(res_fut).await;
676 Ok(res)
677}
678
679enum RequestOrResponse<'a, B> {
683 Request(&'a Request<B>),
684 Response(&'a Response<B>),
685}
686
687impl<B> RequestOrResponse<'_, B> {
688 fn method(&self) -> HyperSigResult<&http::Method> {
689 match self {
690 RequestOrResponse::Request(req) => Ok(req.method()),
691 _ => Err(HyperSigError::InvalidComponentName(
692 "`method` is only for request".to_string(),
693 )),
694 }
695 }
696
697 fn uri(&self) -> HyperSigResult<&http::Uri> {
698 match self {
699 RequestOrResponse::Request(req) => Ok(req.uri()),
700 _ => Err(HyperSigError::InvalidComponentName("`uri` is only for request".to_string())),
701 }
702 }
703
704 fn headers(&self) -> &HeaderMap {
705 match self {
706 RequestOrResponse::Request(req) => req.headers(),
707 RequestOrResponse::Response(res) => res.headers(),
708 }
709 }
710
711 fn status(&self) -> HyperSigResult<http::StatusCode> {
712 match self {
713 RequestOrResponse::Response(res) => Ok(res.status()),
714 _ => Err(HyperSigError::InvalidComponentName(
715 "`status` is only for response".to_string(),
716 )),
717 }
718 }
719}
720
721fn extract_signature_headers_with_name<B>(req_or_res: &RequestOrResponse<B>) -> HyperSigResult<HttpSignatureHeadersMap> {
723 let headers = req_or_res.headers();
724 if !(headers.contains_key("signature-input") && headers.contains_key("signature")) {
725 return Err(HyperSigError::NoSignatureHeaders(
726 "The request does not have signature and signature-input headers".to_string(),
727 ));
728 };
729
730 let signature_input_strings = headers
731 .get_all("signature-input")
732 .iter()
733 .map(|v| v.to_str())
734 .collect::<Result<Vec<_>, _>>()?
735 .join(", ");
736 let signature_strings = headers
737 .get_all("signature")
738 .iter()
739 .map(|v| v.to_str())
740 .collect::<Result<Vec<_>, _>>()?
741 .join(", ");
742
743 let signature_headers = HttpSignatureHeaders::try_parse(&signature_strings, &signature_input_strings)?;
744 Ok(signature_headers)
745}
746
747fn build_signature_base<B1, B2>(
752 req_or_res: &RequestOrResponse<B1>,
753 signature_params: &HttpSignatureParams,
754 req_for_param: Option<&Request<B2>>,
755) -> HyperSigResult<HttpSignatureBase> {
756 let component_lines = signature_params
757 .covered_components
758 .iter()
759 .map(|component_id| {
760 if component_id.params.0.contains(&HttpMessageComponentParam::Req) {
761 if matches!(req_or_res, RequestOrResponse::Request(_)) {
762 return Err(HyperSigError::InvalidComponentParam(
763 "`req` is not allowed in request".to_string(),
764 ));
765 }
766 if req_for_param.is_none() {
767 return Err(HyperSigError::InvalidComponentParam(
768 "`req` is required for the param".to_string(),
769 ));
770 }
771 let req = RequestOrResponse::Request(req_for_param.unwrap());
772 extract_http_message_component(&req, component_id)
773 } else {
774 extract_http_message_component(req_or_res, component_id)
775 }
776 })
777 .collect::<Result<Vec<_>, _>>()?;
778
779 HttpSignatureBase::try_new(&component_lines, signature_params).map_err(|e| e.into())
780}
781
782fn extract_http_field<B>(req_or_res: &RequestOrResponse<B>, id: &HttpMessageComponentId) -> HyperSigResult<HttpMessageComponent> {
784 let HttpMessageComponentName::HttpField(header_name) = &id.name else {
785 return Err(HyperSigError::InvalidComponentName(
786 "invalid http message component name as http field".to_string(),
787 ));
788 };
789 let headers = match req_or_res {
790 RequestOrResponse::Request(req) => req.headers(),
791 RequestOrResponse::Response(res) => res.headers(),
792 };
793
794 let field_values = headers
795 .get_all(header_name)
796 .iter()
797 .map(|v| v.to_str().map(|s| s.to_owned()))
798 .collect::<Result<Vec<_>, _>>()?;
799
800 HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
801}
802
803fn extract_derived_component<B>(
805 req_or_res: &RequestOrResponse<B>,
806 id: &HttpMessageComponentId,
807) -> HyperSigResult<HttpMessageComponent> {
808 let HttpMessageComponentName::Derived(derived_id) = &id.name else {
809 return Err(HyperSigError::InvalidComponentName(
810 "invalid http message component name as derived component".to_string(),
811 ));
812 };
813 if !id.params.0.is_empty()
814 && matches!(req_or_res, RequestOrResponse::Request(_))
815 && !(id.params.0.contains(&HttpMessageComponentParam::Req) && id.params.0.len() == 1)
816 {
817 return Err(HyperSigError::InvalidComponentParam(
818 "derived component does not allow parameters for request".to_string(),
819 ));
820 }
821
822 match req_or_res {
823 RequestOrResponse::Request(_) => {
824 if matches!(derived_id, DerivedComponentName::Status) {
825 return Err(HyperSigError::InvalidComponentName(
826 "`status` is only for response".to_string(),
827 ));
828 }
829 }
830 RequestOrResponse::Response(_) => {
831 if !matches!(derived_id, DerivedComponentName::Status) && !matches!(derived_id, DerivedComponentName::SignatureParams) {
832 return Err(HyperSigError::InvalidComponentName(
833 "Only `status` and `signature-params` are allowed for response".to_string(),
834 ));
835 }
836 }
837 }
838
839 let field_values: Vec<String> = match derived_id {
840 DerivedComponentName::Method => vec![req_or_res.method()?.as_str().to_string()],
841 DerivedComponentName::TargetUri => vec![req_or_res.uri()?.to_string()],
842 DerivedComponentName::Authority => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
843 DerivedComponentName::Scheme => vec![req_or_res.uri()?.scheme_str().unwrap_or("").to_string()],
844 DerivedComponentName::RequestTarget => match *req_or_res.method()? {
845 http::Method::CONNECT => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
846 http::Method::OPTIONS => vec!["*".to_string()],
847 _ => vec![req_or_res
848 .uri()?
849 .path_and_query()
850 .map(|s| s.to_string())
851 .unwrap_or("".to_string())],
852 },
853 DerivedComponentName::Path => vec![{
854 let p = req_or_res.uri()?.path();
855 if p.is_empty() {
856 "/".to_string()
857 } else {
858 p.to_string()
859 }
860 }],
861 DerivedComponentName::Query => vec![req_or_res.uri()?.query().map(|v| format!("?{v}")).unwrap_or("?".to_string())],
862 DerivedComponentName::QueryParam => {
863 let query = req_or_res.uri()?.query().unwrap_or("");
864 query
865 .split('&')
866 .filter(|s| !s.is_empty())
867 .map(|s| s.to_string())
868 .collect::<Vec<_>>()
869 }
870 DerivedComponentName::Status => vec![req_or_res.status()?.as_str().to_string()],
871 DerivedComponentName::SignatureParams => req_or_res
872 .headers()
873 .get_all("signature-input")
874 .iter()
875 .map(|v| v.to_str().unwrap_or("").to_string())
876 .collect::<Vec<_>>(),
877 };
878
879 HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
880}
881
882fn extract_http_message_component<B>(
885 req_or_res: &RequestOrResponse<B>,
886 target_component_id: &HttpMessageComponentId,
887) -> HyperSigResult<HttpMessageComponent> {
888 match &target_component_id.name {
889 HttpMessageComponentName::HttpField(_) => extract_http_field(req_or_res, target_component_id),
890 HttpMessageComponentName::Derived(_) => extract_derived_component(req_or_res, target_component_id),
891 }
892}
893
894#[cfg(test)]
896mod tests {
897
898 use super::{
899 super::{
900 error::HyperDigestError,
901 hyper_content_digest::{RequestContentDigest, ResponseContentDigest},
902 ContentDigestType,
903 },
904 *,
905 };
906 use http_body_util::Full;
907 use httpsig::prelude::{PublicKey, SecretKey, SharedKey};
908
909 type BoxBody = http_body_util::combinators::BoxBody<bytes::Bytes, HyperDigestError>;
910
911 const EDDSA_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
912MC4CAQAwBQYDK2VwBCIEIDSHAE++q1BP7T8tk+mJtS+hLf81B0o6CFyWgucDFN/C
913-----END PRIVATE KEY-----
914"##;
915 const EDDSA_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
916MCowBQYDK2VwAyEA1ixMQcxO46PLlgQfYS46ivFd+n0CcDHSKUnuhm3i1O0=
917-----END PUBLIC KEY-----
918"##;
919 const COVERED_COMPONENTS_REQ: &[&str] = &["@method", "date", "content-type", "content-digest"];
921 const COVERED_COMPONENTS_RES: &[&str] = &["@status", "\"@method\";req", "date", "content-type", "\"content-digest\";req"];
922
923 async fn build_request() -> Request<BoxBody> {
924 let body = Full::new(&b"{\"hello\": \"world\"}"[..]);
925 let req = Request::builder()
926 .method("GET")
927 .uri("https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something")
928 .header("date", "Sun, 09 May 2021 18:30:00 GMT")
929 .header("content-type", "application/json")
930 .header("content-type", "application/json-patch+json")
931 .body(body)
932 .unwrap();
933 req.set_content_digest(&ContentDigestType::Sha256).await.unwrap()
934 }
935
936 async fn build_response() -> Response<BoxBody> {
937 let body = Full::new(&b"{\"hello\": \"world!!\"}"[..]);
938 let res = Response::builder()
939 .status(200)
940 .header("date", "Sun, 09 May 2021 18:30:00 GMT")
941 .header("content-type", "application/json")
942 .header("content-type", "application/json-patch+json")
943 .body(body)
944 .unwrap();
945 res.set_content_digest(&ContentDigestType::Sha256).await.unwrap()
946 }
947
948 fn build_covered_components_req() -> Vec<HttpMessageComponentId> {
949 COVERED_COMPONENTS_REQ
950 .iter()
951 .map(|&s| HttpMessageComponentId::try_from(s).unwrap())
952 .collect()
953 }
954
955 fn build_covered_components_res() -> Vec<HttpMessageComponentId> {
956 COVERED_COMPONENTS_RES
957 .iter()
958 .map(|&s| HttpMessageComponentId::try_from(s).unwrap())
959 .collect()
960 }
961
962 #[tokio::test]
963 async fn test_extract_component_from_request() {
964 let req = build_request().await;
965 let req_or_res = RequestOrResponse::Request(&req);
966
967 let component_id_method = HttpMessageComponentId::try_from("\"@method\"").unwrap();
968 let component = extract_http_message_component(&req_or_res, &component_id_method).unwrap();
969 assert_eq!(component.to_string(), "\"@method\": GET");
970
971 let component_id = HttpMessageComponentId::try_from("\"date\"").unwrap();
972 let component = extract_http_message_component(&req_or_res, &component_id).unwrap();
973 assert_eq!(component.to_string(), "\"date\": Sun, 09 May 2021 18:30:00 GMT");
974
975 let component_id = HttpMessageComponentId::try_from("content-type").unwrap();
976 let component = extract_http_field(&req_or_res, &component_id).unwrap();
977 assert_eq!(
978 component.to_string(),
979 "\"content-type\": application/json, application/json-patch+json"
980 );
981
982 let component_id = HttpMessageComponentId::try_from("content-digest").unwrap();
983 let component = extract_http_message_component(&req_or_res, &component_id).unwrap();
984 assert_eq!(
985 component.to_string(),
986 "\"content-digest\": sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:"
987 );
988 }
989
990 #[tokio::test]
991 async fn test_extract_signature_params_from_request() {
992 let mut req = build_request().await;
993 let headers = req.headers_mut();
994 headers.insert(
995 "signature-input",
996 http::HeaderValue::from_static(r##"sig1=("@method" "@authority")"##),
997 );
998 let component_id = HttpMessageComponentId::try_from("@signature-params").unwrap();
999 let req_or_res = RequestOrResponse::Request(&req);
1000 let component = extract_http_message_component(&req_or_res, &component_id).unwrap();
1001 assert_eq!(component.to_string(), "\"@signature-params\": (\"@method\" \"@authority\")");
1002 assert_eq!(component.value.to_string(), r##"("@method" "@authority")"##);
1003 assert_eq!(component.value.as_field_value(), r##"sig1=("@method" "@authority")"##);
1004 assert_eq!(component.value.as_component_value(), r##"("@method" "@authority")"##);
1005 assert_eq!(component.value.key(), Some("sig1"));
1006 }
1007
1008 #[tokio::test]
1009 async fn test_build_signature_base_from_request() {
1010 let req = build_request().await;
1011
1012 const SIGPARA: &str = r##";created=1704972031;alg="ed25519";keyid="gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=""##;
1013 let values = (r##""@method" "content-type" "date" "content-digest""##, SIGPARA);
1014 let signature_params = HttpSignatureParams::try_from(format!("({}){}", values.0, values.1).as_str()).unwrap();
1015
1016 let req_or_res = RequestOrResponse::Request(&req);
1017 let signature_base = build_signature_base(&req_or_res, &signature_params, None as Option<&Request<()>>).unwrap();
1018 assert_eq!(
1019 signature_base.to_string(),
1020 r##""@method": GET
1021"content-type": application/json, application/json-patch+json
1022"date": Sun, 09 May 2021 18:30:00 GMT
1023"content-digest": sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
1024"@signature-params": ("@method" "content-type" "date" "content-digest");created=1704972031;alg="ed25519";keyid="gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=""##
1025 );
1026 }
1027
1028 #[tokio::test]
1029 async fn test_extract_tuples_from_request() {
1030 let mut req = build_request().await;
1031 let headers = req.headers_mut();
1032 headers.insert(
1033 "signature-input",
1034 http::HeaderValue::from_static(r##"sig11=("@method" "@authority");created=1704972031"##),
1035 );
1036 headers.insert(
1037 "signature",
1038 http::HeaderValue::from_static(
1039 r##"sig11=:wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==:"##,
1040 ),
1041 );
1042
1043 let req_or_res = RequestOrResponse::Request(&req);
1044 let tuples = extract_signature_headers_with_name(&req_or_res).unwrap();
1045 assert_eq!(tuples.len(), 1);
1046 assert_eq!(tuples.get("sig11").unwrap().signature_name(), "sig11");
1047 assert_eq!(
1048 tuples.get("sig11").unwrap().signature_params().to_string(),
1049 r##"("@method" "@authority");created=1704972031"##
1050 );
1051 }
1052
1053 #[tokio::test]
1054 async fn test_set_verify_message_signature_req() {
1055 let mut req = build_request().await;
1056 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1057 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1058 signature_params.set_key_info(&secret_key);
1059
1060 req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1061 let signature_input = req.headers().get("signature-input").unwrap().to_str().unwrap();
1062 assert!(signature_input.starts_with(r##"sig=("@method" "date" "content-type" "content-digest")"##));
1063 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1066 let verification_res = req.verify_message_signature(&public_key, None).await;
1067 assert!(verification_res.is_ok());
1068 }
1069
1070 #[tokio::test]
1071 async fn test_set_verify_message_signature_res() {
1072 let req = build_request().await;
1073 let mut res = build_response().await;
1074
1075 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1076
1077 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_res()).unwrap();
1078 signature_params.set_key_info(&secret_key);
1079 res
1085 .set_message_signature(&signature_params, &secret_key, None, Some(&req))
1086 .await
1087 .unwrap();
1088 let signature_input = res.headers().get("signature-input").unwrap().to_str().unwrap();
1090 assert!(signature_input.starts_with(r##"sig=("@status" "@method";req "date" "content-type" "content-digest";req)"##));
1091 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1094 let verification_res = res.verify_message_signature(&public_key, None, Some(&req)).await;
1095 assert!(verification_res.is_ok());
1096 }
1097
1098 #[tokio::test]
1099 async fn test_expired_signature() {
1100 let mut req = build_request().await;
1101 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1102 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1103 signature_params.set_key_info(&secret_key);
1104 let created = signature_params.created.unwrap();
1105 signature_params.set_expires(created - 1);
1106 assert!(signature_params.is_expired());
1107
1108 req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1109
1110 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1111 let verification_res = req.verify_message_signature(&public_key, None).await;
1112 assert!(verification_res.is_err());
1113 }
1114
1115 #[tokio::test]
1116 async fn test_set_verify_with_signature_name() {
1117 let mut req = build_request().await;
1118 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1119 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1120 signature_params.set_key_info(&secret_key);
1121
1122 req
1123 .set_message_signature(&signature_params, &secret_key, Some("custom_sig_name"))
1124 .await
1125 .unwrap();
1126
1127 let req_or_res = RequestOrResponse::Request(&req);
1128 let signature_headers_map = extract_signature_headers_with_name(&req_or_res).unwrap();
1129 assert_eq!(signature_headers_map.len(), 1);
1130 assert_eq!(signature_headers_map[0].signature_name(), "custom_sig_name");
1131
1132 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1133 let verification_res = req.verify_message_signature(&public_key, None).await;
1134 assert!(verification_res.is_ok());
1135 }
1136
1137 #[tokio::test]
1138 async fn test_set_verify_with_key_id() {
1139 let mut req = build_request().await;
1140 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1141 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1142 signature_params.set_key_info(&secret_key);
1143
1144 req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1145
1146 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1147 let key_id = public_key.key_id();
1148 let verification_res = req.verify_message_signature(&public_key, Some(&key_id)).await;
1149 assert!(verification_res.is_ok());
1150
1151 let verification_res = req.verify_message_signature(&public_key, Some("NotFoundKeyId")).await;
1152 assert!(verification_res.is_err());
1153 }
1154
1155 const HMACSHA256_SECRET_KEY: &str =
1156 r##"uzvJfB4u3N0Jy4T7NZ75MDVcr8zSTInedJtkgcu46YW4XByzNJjxBdtjUkdJPBtbmHhIDi6pcl8jsasjlTMtDQ=="##;
1157
1158 #[tokio::test]
1159 async fn test_set_verify_with_key_id_hmac_sha256() {
1160 let mut req = build_request().await;
1161 let secret_key = SharedKey::from_base64(HMACSHA256_SECRET_KEY).unwrap();
1162 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1163 signature_params.set_key_info(&secret_key);
1164 signature_params.set_random_nonce();
1166
1167 req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1168
1169 let key_id = VerifyingKey::key_id(&secret_key);
1170 let verification_res = req.verify_message_signature(&secret_key, Some(&key_id)).await;
1171 assert!(verification_res.is_ok());
1172
1173 let verification_res = req.verify_message_signature(&secret_key, Some("NotFoundKeyId")).await;
1174 assert!(verification_res.is_err());
1175 }
1176
1177 #[tokio::test]
1178 async fn test_get_key_ids() {
1179 let mut req = build_request().await;
1180 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1181 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1182 signature_params.set_key_info(&secret_key);
1183
1184 req.set_message_signature(&signature_params, &secret_key, None).await.unwrap();
1185 let key_ids = req.get_key_ids().unwrap();
1186 assert_eq!(key_ids.len(), 1);
1187 assert_eq!(key_ids[0], "gjrE7ACMxgzYfFHgabgf4kLTg1eKIdsJ94AiFTFj1is=");
1188 }
1189
1190 const P256_SECERT_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
1191MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgv7zxW56ojrWwmSo1
11924uOdbVhUfj9Jd+5aZIB9u8gtWnihRANCAARGYsMe0CT6pIypwRvoJlLNs4+cTh2K
1193L7fUNb5i6WbKxkpAoO+6T3pMBG5Yw7+8NuGTvvtrZAXduA2giPxQ8zCf
1194-----END PRIVATE KEY-----
1195"##;
1196 const P256_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
1197MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERmLDHtAk+qSMqcEb6CZSzbOPnE4d
1198ii+31DW+YulmysZKQKDvuk96TARuWMO/vDbhk777a2QF3bgNoIj8UPMwnw==
1199-----END PUBLIC KEY-----
1200"##;
1201 #[tokio::test]
1202 async fn test_set_verify_multiple_signatures() {
1203 let mut req = build_request().await;
1204
1205 let secret_key_eddsa = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1206 let mut signature_params_eddsa = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1207 signature_params_eddsa.set_key_info(&secret_key_eddsa);
1208
1209 let secret_key_p256 = SecretKey::from_pem(P256_SECERT_KEY).unwrap();
1210 let mut signature_params_hmac = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1211 signature_params_hmac.set_key_info(&secret_key_p256);
1212
1213 let params_key_name = &[
1214 (&signature_params_eddsa, &secret_key_eddsa, Some("eddsa_sig")),
1215 (&signature_params_hmac, &secret_key_p256, Some("p256_sig")),
1216 ];
1217
1218 req.set_message_signatures(params_key_name).await.unwrap();
1219
1220 let public_key_eddsa = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1221 let public_key_p256 = PublicKey::from_pem(P256_PUBLIC_KEY).unwrap();
1222 let key_id_eddsa = public_key_eddsa.key_id();
1223 let key_id_p256 = public_key_p256.key_id();
1224
1225 let verification_res = req
1226 .verify_message_signatures(&[
1227 (&public_key_eddsa, Some(&key_id_eddsa)),
1228 (&public_key_p256, Some(&key_id_p256)),
1229 ])
1230 .await
1231 .unwrap();
1232
1233 assert!(verification_res.len() == 2 && verification_res.iter().all(|r| r.is_ok()));
1234 assert!(verification_res[0].as_ref().unwrap() == "eddsa_sig");
1235 assert!(verification_res[1].as_ref().unwrap() == "p256_sig");
1236 }
1237
1238 #[cfg(feature = "blocking")]
1239 #[test]
1240 fn test_blocking_set_verify_message_signature_req() {
1241 let mut req = futures::executor::block_on(build_request());
1242 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1243 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_req()).unwrap();
1244 signature_params.set_key_info(&secret_key);
1245
1246 req.set_message_signature_sync(&signature_params, &secret_key, None).unwrap();
1247
1248 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1249 let verification_res = req.verify_message_signature_sync(&public_key, None);
1250 assert!(verification_res.is_ok());
1251 }
1252
1253 #[cfg(feature = "blocking")]
1254 #[test]
1255 fn test_blocking_set_verify_message_signature_res() {
1256 let req = futures::executor::block_on(build_request());
1257 let mut res = futures::executor::block_on(build_response());
1258 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
1259 let mut signature_params = HttpSignatureParams::try_new(&build_covered_components_res()).unwrap();
1260 signature_params.set_key_info(&secret_key);
1261 res
1262 .set_message_signature_sync(&signature_params, &secret_key, None, Some(&req))
1263 .unwrap();
1264
1265 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
1266 let verification_res = res.verify_message_signature_sync(&public_key, None, Some(&req));
1267 assert!(verification_res.is_ok());
1268 }
1269}