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
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_alg_key_ids(&self) -> Result<IndexMap<SignatureName, (Option<AlgorithmName>, Option<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_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 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_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 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_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 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
620fn 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
632fn 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
649async 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 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 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 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
693enum 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
735fn 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
761fn 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
796fn 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
817fn 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
896fn 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#[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 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 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 res
1099 .set_message_signature(&signature_params, &secret_key, None, Some(&req))
1100 .await
1101 .unwrap();
1102 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 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 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}