1use crate::http_uri_ext::HttpUriExt as _;
10use http::{Response, Uri};
11use hyper::header::ETAG;
12use p256::ecdsa::DerSignature;
13use p256::ecdsa::signature::Verifier as _;
14use rand::{Rng, rng};
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16use sha2::{Digest, Sha256, digest};
17use std::{collections::HashMap, convert::TryInto, fmt, fmt::Debug};
18
19#[derive(Debug, thiserror::Error)]
21pub enum CupDecorationError {
22 #[error("could not serialize request.")]
23 SerializationError(#[from] serde_json::Error),
24 #[error("could not parse existing URI.")]
25 ParseError(#[from] http::uri::InvalidUri),
26 #[error("could not append query parameter.")]
27 AppendQueryParameterError(#[from] crate::http_uri_ext::Error),
28}
29
30#[derive(Debug, thiserror::Error)]
32pub enum CupVerificationError {
33 #[error("etag header missing.")]
34 EtagHeaderMissing,
35 #[error("etag header is not a string.")]
36 EtagNotString(hyper::header::ToStrError),
37 #[error("etag header is malformed.")]
38 EtagMalformed,
39 #[error("etag header's request hash is malformed.")]
40 RequestHashMalformed,
41 #[error("etag header's request hash doesn't match.")]
42 RequestHashMismatch,
43 #[error("etag header's signature is malformed.")]
44 SignatureMalformed,
45 #[error("specified public key ID not found in internal map.")]
46 SpecifiedPublicKeyIdMissing,
47 #[error("could not verify etag header's signature.")]
48 SignatureError(#[from] ecdsa::Error),
49}
50
51pub type PublicKeyId = u64;
54pub type PublicKey = p256::ecdsa::VerifyingKey;
55
56fn from_pem<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
57where
58 D: Deserializer<'de>,
59{
60 use serde::de;
61 let s = String::deserialize(deserializer)?;
62 s.parse().map_err(de::Error::custom)
63}
64
65fn to_pem<S>(public_key: &PublicKey, serializer: S) -> Result<S::Ok, S::Error>
66where
67 S: Serializer,
68{
69 use pkcs8::EncodePublicKey;
70 use serde::ser;
71 serializer.serialize_str(
72 &elliptic_curve::PublicKey::from(public_key)
73 .to_public_key_pem(pkcs8::LineEnding::LF)
74 .map_err(ser::Error::custom)?,
75 )
76}
77
78#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
79pub struct PublicKeyAndId {
80 #[serde(deserialize_with = "from_pem", serialize_with = "to_pem")]
81 pub key: PublicKey,
82 pub id: PublicKeyId,
83}
84
85#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
86pub struct PublicKeys {
87 pub latest: PublicKeyAndId,
89 pub historical: Vec<PublicKeyAndId>,
91}
92
93#[derive(PartialEq, Eq, Debug, Copy, Clone)]
94pub struct Nonce([u8; 32]);
95
96impl From<[u8; 32]> for Nonce {
97 fn from(array: [u8; 32]) -> Self {
98 Nonce(array)
99 }
100}
101impl From<&[u8; 32]> for Nonce {
102 fn from(array: &[u8; 32]) -> Self {
103 Nonce(*array)
104 }
105}
106
107#[allow(clippy::from_over_into)]
108impl Into<[u8; 32]> for Nonce {
109 fn into(self) -> [u8; 32] {
110 self.0
111 }
112}
113
114impl Default for Nonce {
115 fn default() -> Self {
116 Self::new()
117 }
118}
119
120impl Nonce {
121 pub fn new() -> Nonce {
122 let mut nonce_bits = [0_u8; 32];
123 rng().fill(&mut nonce_bits[..]);
124 Nonce(nonce_bits)
125 }
126}
127
128impl fmt::Display for Nonce {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "{}", hex::encode(self.0))
131 }
132}
133
134#[derive(Clone, Debug, PartialEq, Eq)]
139pub struct RequestMetadata {
140 pub request_body: Vec<u8>,
141 pub public_key_id: PublicKeyId,
142 pub nonce: Nonce,
143}
144
145pub trait CupRequest {
148 fn get_uri(&self) -> &str;
150 fn set_uri(&mut self, uri: String);
152 fn get_serialized_body(&self) -> serde_json::Result<Vec<u8>>;
154}
155
156pub trait Cupv2RequestHandler {
159 fn decorate_request(
163 &self,
164 request: &mut impl CupRequest,
165 ) -> Result<RequestMetadata, CupDecorationError>;
166
167 fn verify_response(
170 &self,
171 request_metadata: &RequestMetadata,
172 resp: &Response<Vec<u8>>,
173 public_key_id: PublicKeyId,
174 ) -> Result<DerSignature, CupVerificationError>;
175}
176
177pub trait Cupv2Verifier {
179 fn verify_response_with_signature(
182 &self,
183 ecdsa_signature: &DerSignature,
184 request_body: &[u8],
185 response_body: &[u8],
186 public_key_id: PublicKeyId,
187 nonce: &Nonce,
188 ) -> Result<(), CupVerificationError>;
189}
190
191pub trait Cupv2Handler: Cupv2RequestHandler + Cupv2Verifier {}
192
193impl<T> Cupv2Handler for T where T: Cupv2RequestHandler + Cupv2Verifier {}
194
195#[derive(Debug)]
197pub struct StandardCupv2Handler {
198 parameters_by_id: HashMap<PublicKeyId, PublicKey>,
201 latest_public_key_id: PublicKeyId,
202}
203
204impl StandardCupv2Handler {
205 pub fn new(public_keys: &PublicKeys) -> Self {
207 Self {
208 parameters_by_id: std::iter::once(&public_keys.latest)
209 .chain(&public_keys.historical)
210 .map(|k| (k.id, k.key))
211 .collect(),
212 latest_public_key_id: public_keys.latest.id,
213 }
214 }
215}
216
217impl Cupv2RequestHandler for StandardCupv2Handler {
218 fn decorate_request(
219 &self,
220 request: &mut impl CupRequest,
221 ) -> Result<RequestMetadata, CupDecorationError> {
222 let public_key_id: PublicKeyId = self.latest_public_key_id;
230
231 let nonce = Nonce::new();
232
233 let uri: Uri = request.get_uri().parse()?;
234 let uri = uri.append_query_parameter("cup2key", &format!("{public_key_id}:{nonce}"))?;
235 request.set_uri(uri.to_string());
236
237 Ok(RequestMetadata { request_body: request.get_serialized_body()?, public_key_id, nonce })
238 }
239
240 fn verify_response(
241 &self,
242 request_metadata: &RequestMetadata,
243 resp: &Response<Vec<u8>>,
244 public_key_id: PublicKeyId,
245 ) -> Result<DerSignature, CupVerificationError> {
246 let etag_header = resp
262 .headers()
263 .get(ETAG)
264 .ok_or(CupVerificationError::EtagHeaderMissing)?
265 .to_str()
266 .map_err(CupVerificationError::EtagNotString)
267 .map(parse_etag)?;
268
269 let (encoded_signature, hex_hash): (&str, &str) =
270 etag_header.split_once(':').ok_or(CupVerificationError::EtagMalformed)?;
271
272 let actual_hash =
273 &hex::decode(hex_hash).map_err(|_| CupVerificationError::RequestHashMalformed)?;
274
275 let request_body_hash = Sha256::digest(&request_metadata.request_body);
276 if *request_body_hash != *actual_hash {
277 return Err(CupVerificationError::RequestHashMismatch);
278 }
279
280 let signature = DerSignature::from_bytes(
281 &hex::decode(encoded_signature)
282 .map_err(|_| CupVerificationError::SignatureMalformed)?,
283 )?;
284
285 let () = self.verify_response_with_signature(
286 &signature,
287 &request_metadata.request_body,
288 resp.body(),
289 public_key_id,
290 &request_metadata.nonce,
291 )?;
292
293 Ok(signature)
294 }
295}
296
297pub fn make_transaction_hash(
298 request_body: &[u8],
299 response_body: &[u8],
300 public_key_id: PublicKeyId,
301 nonce: &Nonce,
302) -> digest::Output<Sha256> {
303 let request_hash = Sha256::digest(request_body);
304 let response_hash = Sha256::digest(response_body);
305 let cup2_urlparam = format!("{public_key_id}:{nonce}");
306
307 let mut hasher = Sha256::new();
308 hasher.update(request_hash);
309 hasher.update(response_hash);
310 hasher.update(cup2_urlparam);
311 hasher.finalize()
312}
313
314impl Cupv2Verifier for StandardCupv2Handler {
315 fn verify_response_with_signature(
316 &self,
317 ecdsa_signature: &DerSignature,
318 request_body: &[u8],
319 response_body: &[u8],
320 public_key_id: PublicKeyId,
321 nonce: &Nonce,
322 ) -> Result<(), CupVerificationError> {
323 let transaction_hash =
324 make_transaction_hash(request_body, response_body, public_key_id, nonce);
325
326 let public_key: &PublicKey = self
327 .parameters_by_id
328 .get(&public_key_id)
329 .ok_or(CupVerificationError::SpecifiedPublicKeyIdMissing)?;
330 let der_signature: ecdsa::der::Signature<p256::NistP256> =
334 ecdsa_signature.as_ref().try_into()?;
335 let signature: ecdsa::Signature<p256::NistP256> = der_signature.try_into()?;
337 Ok(public_key.verify(&transaction_hash, &signature)?)
338 }
339}
340
341fn parse_etag(etag: &str) -> &str {
342 match etag.as_bytes() {
347 [b'W', b'/', b'\"', inner @ .., b'\"'] => unsafe { std::str::from_utf8_unchecked(inner) },
353 [b'\"', inner @ .., b'\"'] => unsafe { std::str::from_utf8_unchecked(inner) },
355 _ => etag,
357 }
358}
359
360pub mod test_support {
361 use super::*;
362 use crate::{
363 protocol::request::{Request, RequestWrapper},
364 request_builder::Intermediate,
365 };
366 use p256::ecdsa::SigningKey;
367 use std::{convert::TryInto, str::FromStr};
368
369 pub const RAW_PRIVATE_KEY_FOR_TEST: &str = include_str!("testing_keys/test_private_key.pem");
370 pub const RAW_PUBLIC_KEY_FOR_TEST: &str = include_str!("testing_keys/test_public_key.pem");
371
372 pub fn make_default_public_key_id_for_test() -> PublicKeyId {
373 123456789.try_into().unwrap()
374 }
375 pub fn make_default_private_key_for_test() -> SigningKey {
376 SigningKey::from_str(RAW_PRIVATE_KEY_FOR_TEST).unwrap()
377 }
378 pub fn make_default_public_key_for_test() -> PublicKey {
379 PublicKey::from_str(RAW_PUBLIC_KEY_FOR_TEST).unwrap()
380 }
381
382 pub fn make_keys_for_test() -> (SigningKey, PublicKey) {
383 (make_default_private_key_for_test(), make_default_public_key_for_test())
384 }
385
386 pub fn make_public_keys_for_test(
387 public_key_id: PublicKeyId,
388 public_key: PublicKey,
389 ) -> PublicKeys {
390 PublicKeys {
391 latest: PublicKeyAndId { id: public_key_id, key: public_key },
392 historical: vec![],
393 }
394 }
395
396 pub fn make_default_public_keys_for_test() -> PublicKeys {
397 let (_priv_key, public_key) = make_keys_for_test();
398 make_public_keys_for_test(make_default_public_key_id_for_test(), public_key)
399 }
400
401 pub fn make_default_json_public_keys_for_test() -> serde_json::Value {
402 serde_json::json!({
403 "latest": {
404 "id": make_default_public_key_id_for_test(),
405 "key": RAW_PUBLIC_KEY_FOR_TEST,
406 },
407 "historical": []
408 })
409 }
410 pub fn make_cup_handler_for_test() -> StandardCupv2Handler {
411 let (_signing_key, public_key) = make_keys_for_test();
412 let public_keys =
413 make_public_keys_for_test(make_default_public_key_id_for_test(), public_key);
414 StandardCupv2Handler::new(&public_keys)
415 }
416
417 pub fn make_expected_signature_for_test(
418 signing_key: &SigningKey,
419 request_metadata: &RequestMetadata,
420 response_body: &[u8],
421 ) -> Vec<u8> {
422 use signature::Signer;
423 let transaction_hash = make_transaction_hash(
424 &request_metadata.request_body,
425 response_body,
426 request_metadata.public_key_id,
427 &request_metadata.nonce,
428 );
429 let sig: ecdsa::Signature<p256::NistP256> = signing_key.sign(&transaction_hash);
430 sig.to_der().as_bytes().to_vec()
431 }
432
433 pub struct MockCupv2Handler {
435 decoration_error: fn() -> Option<CupDecorationError>,
436 verification_error: fn() -> Option<CupVerificationError>,
437 }
438 impl MockCupv2Handler {
439 pub fn new() -> MockCupv2Handler {
440 MockCupv2Handler {
441 decoration_error: || None::<CupDecorationError>,
442 verification_error: || None::<CupVerificationError>,
443 }
444 }
445 pub fn set_decoration_error(
446 mut self,
447 e: fn() -> Option<CupDecorationError>,
448 ) -> MockCupv2Handler {
449 self.decoration_error = e;
450 self
451 }
452 pub fn set_verification_error(
453 mut self,
454 e: fn() -> Option<CupVerificationError>,
455 ) -> MockCupv2Handler {
456 self.verification_error = e;
457 self
458 }
459 }
460
461 impl Default for MockCupv2Handler {
462 fn default() -> Self {
463 Self::new()
464 }
465 }
466
467 impl Cupv2RequestHandler for MockCupv2Handler {
468 fn decorate_request(
469 &self,
470 _request: &mut impl CupRequest,
471 ) -> Result<RequestMetadata, CupDecorationError> {
472 match (self.decoration_error)() {
473 Some(e) => Err(e),
474 None => Ok(RequestMetadata {
475 request_body: vec![],
476 public_key_id: 0.try_into().unwrap(),
477 nonce: [0u8; 32].into(),
478 }),
479 }
480 }
481
482 fn verify_response(
483 &self,
484 request_metadata: &RequestMetadata,
485 resp: &Response<Vec<u8>>,
486 public_key_id: PublicKeyId,
487 ) -> Result<DerSignature, CupVerificationError> {
488 use p256::elliptic_curve::Generate as _;
489 let signing_key = SigningKey::generate();
490 let signature = DerSignature::from_bytes(&make_expected_signature_for_test(
491 &signing_key,
492 request_metadata,
493 resp.body(),
494 ))
495 .unwrap();
496 let () = self.verify_response_with_signature(
497 &signature,
498 &request_metadata.request_body,
499 resp.body(),
500 public_key_id,
501 &request_metadata.nonce,
502 )?;
503 Ok(signature)
504 }
505 }
506
507 impl Cupv2Verifier for MockCupv2Handler {
508 fn verify_response_with_signature(
509 &self,
510 _ecdsa_signature: &DerSignature,
511 _request_body: &[u8],
512 _response_body: &[u8],
513 _public_key_id: PublicKeyId,
514 _nonce: &Nonce,
515 ) -> Result<(), CupVerificationError> {
516 match (self.verification_error)() {
517 Some(e) => Err(e),
518 None => Ok(()),
519 }
520 }
521 }
522
523 pub fn make_standard_intermediate_for_test(request: Request) -> Intermediate {
524 Intermediate {
525 uri: "http://fuchsia.dev".to_string(),
526 headers: [].into(),
527 body: RequestWrapper { request },
528 }
529 }
530}
531
532#[cfg(test)]
533mod tests {
534 use super::*;
535 use crate::{
536 protocol::request::{Request, RequestWrapper},
537 request_builder::Intermediate,
538 };
539 use assert_matches::assert_matches;
540 use p256::ecdsa::SigningKey;
541 use url::Url;
542
543 impl PartialEq for CupVerificationError {
545 fn eq(&self, other: &Self) -> bool {
546 format!("{self:?}") == format!("{other:?}")
547 }
548 }
549
550 #[test]
551 fn test_standard_cup_handler_decorate() -> Result<(), anyhow::Error> {
552 let (_, public_key) = test_support::make_keys_for_test();
553 let public_key_id: PublicKeyId = 42.try_into()?;
554 let public_keys = test_support::make_public_keys_for_test(public_key_id, public_key);
555 let cup_handler = StandardCupv2Handler::new(&public_keys);
556
557 let mut intermediate =
558 test_support::make_standard_intermediate_for_test(Request::default());
559
560 let request_metadata = cup_handler.decorate_request(&mut intermediate)?;
561
562 let cup2key_value: String = Url::parse(&intermediate.uri)?
564 .query_pairs()
565 .find_map(|(k, v)| if k == "cup2key" { Some(v) } else { None })
566 .unwrap()
567 .to_string();
568
569 let (public_key_decimal, nonce_hex) = cup2key_value.split_once(':').unwrap();
570 assert_eq!(public_key_decimal, public_key_id.to_string());
571 assert_eq!(nonce_hex, request_metadata.nonce.to_string());
572 assert_ne!(request_metadata.nonce, [0_u8; 32].into());
574
575 Ok(())
576 }
577
578 #[test]
579 fn test_standard_cup_handler_decorate_ipv6_link_local() -> Result<(), anyhow::Error> {
580 let (_, public_key) = test_support::make_keys_for_test();
581 let public_key_id: PublicKeyId = 42.try_into()?;
582 let public_keys = test_support::make_public_keys_for_test(public_key_id, public_key);
583 let cup_handler = StandardCupv2Handler::new(&public_keys);
584
585 let mut intermediate = Intermediate {
586 uri: "http://[::1%eth0]".to_string(),
587 headers: [].into(),
588 body: RequestWrapper { request: Request::default() },
589 };
590
591 let request_metadata = cup_handler.decorate_request(&mut intermediate)?;
592
593 assert_eq!(
594 intermediate.uri,
595 format!("http://[::1%eth0]/?cup2key={}:{}", public_key_id, request_metadata.nonce,)
596 );
597
598 assert_ne!(request_metadata.nonce, [0_u8; 32].into());
600
601 Ok(())
602 }
603
604 #[test]
605 fn test_verify_response_missing_etag_header() -> Result<(), anyhow::Error> {
606 let (_, public_key) = test_support::make_keys_for_test();
607 let public_key_id: PublicKeyId = 12345.try_into()?;
608 let public_keys = test_support::make_public_keys_for_test(public_key_id, public_key);
609 let cup_handler = StandardCupv2Handler::new(&public_keys);
610
611 let mut intermediate =
612 test_support::make_standard_intermediate_for_test(Request::default());
613 let request_metadata = cup_handler.decorate_request(&mut intermediate)?;
614
615 let response: Response<Vec<u8>> =
617 hyper::Response::builder().status(200).body("foo".as_bytes().to_vec())?;
618
619 assert_matches!(
620 cup_handler.verify_response(&request_metadata, &response, public_key_id),
621 Err(CupVerificationError::EtagHeaderMissing)
622 );
623 Ok(())
624 }
625
626 #[test]
627 fn test_verify_response_malformed_etag_header() -> Result<(), anyhow::Error> {
628 let (_, public_key) = test_support::make_keys_for_test();
629 let public_key_id: PublicKeyId = 12345.try_into()?;
630 let public_keys = test_support::make_public_keys_for_test(public_key_id, public_key);
631 let cup_handler = StandardCupv2Handler::new(&public_keys);
632
633 let mut intermediate =
634 test_support::make_standard_intermediate_for_test(Request::default());
635 let request_metadata = cup_handler.decorate_request(&mut intermediate)?;
636
637 let response: Response<Vec<u8>> = hyper::Response::builder()
638 .status(200)
639 .header(ETAG, "\u{FEFF}")
640 .body("foo".as_bytes().to_vec())?;
641
642 assert_matches!(
643 cup_handler.verify_response(&request_metadata, &response, public_key_id),
644 Err(CupVerificationError::EtagNotString(_))
645 );
646 Ok(())
647 }
648
649 #[test]
650 fn test_verify_cached_signature_against_message() -> Result<(), anyhow::Error> {
651 let (priv_key, public_key) = test_support::make_keys_for_test();
652 let response_body = "bar";
653 let correct_public_key_id: PublicKeyId = 24682468.try_into()?;
654 let wrong_public_key_id: PublicKeyId = 12341234.try_into()?;
655
656 let public_keys =
657 test_support::make_public_keys_for_test(correct_public_key_id, public_key);
658 let cup_handler = StandardCupv2Handler::new(&public_keys);
659 let mut intermediate =
660 test_support::make_standard_intermediate_for_test(Request::default());
661 let request_metadata = cup_handler.decorate_request(&mut intermediate)?;
662 let expected_request_metadata = RequestMetadata {
663 request_body: intermediate.serialize_body()?,
664 public_key_id: correct_public_key_id,
665 nonce: request_metadata.nonce,
666 };
667
668 let expected_hash = Sha256::digest(&request_metadata.request_body);
669
670 let expected_hash_hex: String = hex::encode(expected_hash);
671 let expected_signature = hex::encode(test_support::make_expected_signature_for_test(
672 &priv_key,
673 &expected_request_metadata,
674 response_body.as_bytes(),
675 ));
676
677 for (etag, public_key_id, expected_err) in [
678 ("bar", correct_public_key_id, Some(CupVerificationError::EtagMalformed)),
680 ("foo:bar", correct_public_key_id, Some(CupVerificationError::RequestHashMalformed)),
682 (
684 &format!("foo:{}", hex::encode([1; 32])),
685 correct_public_key_id,
686 Some(CupVerificationError::RequestHashMismatch),
687 ),
688 (
691 &format!("foo:{expected_hash_hex}"),
692 correct_public_key_id,
693 Some(CupVerificationError::SignatureMalformed),
694 ),
695 (
698 &format!("{}:{}", hex::encode([1; 64]), expected_hash_hex),
699 correct_public_key_id,
700 Some(CupVerificationError::SignatureError(ecdsa::Error::new())),
701 ),
702 (
704 &format!("{expected_signature}:{expected_hash_hex}",),
705 wrong_public_key_id,
706 Some(CupVerificationError::SpecifiedPublicKeyIdMissing),
707 ),
708 (&format!("{expected_signature}:{expected_hash_hex}",), correct_public_key_id, None),
710 ] {
711 let response: Response<Vec<u8>> = hyper::Response::builder()
712 .status(200)
713 .header(ETAG, etag)
714 .body(response_body.as_bytes().to_vec())?;
715 let actual_err =
716 cup_handler.verify_response(&request_metadata, &response, public_key_id).err();
717 assert_eq!(
718 actual_err, expected_err,
719 "Received error {actual_err:?}, expected error {expected_err:?}"
720 );
721 }
722
723 Ok(())
724 }
725
726 fn make_verify_response_arguments(
730 request_handler: &impl Cupv2RequestHandler,
731 private_key: SigningKey,
732 response_body: &str,
733 ) -> Result<(RequestMetadata, Response<Vec<u8>>), anyhow::Error> {
734 let mut intermediate =
735 test_support::make_standard_intermediate_for_test(Request::default());
736 let request_metadata = request_handler.decorate_request(&mut intermediate)?;
737
738 let signature = hex::encode(test_support::make_expected_signature_for_test(
739 &private_key,
740 &request_metadata,
741 response_body.as_bytes(),
742 ));
743
744 let etag = &format!(
745 "{}:{}",
746 signature,
747 hex::encode(Sha256::digest(&request_metadata.request_body))
748 );
749
750 let response: Response<Vec<u8>> = hyper::Response::builder()
751 .status(200)
752 .header(ETAG, etag)
753 .body(response_body.as_bytes().to_vec())?;
754 Ok((request_metadata, response))
755 }
756
757 #[test]
758 fn test_historical_verification() -> Result<(), anyhow::Error> {
759 let (private_key_a, public_key_a) = test_support::make_keys_for_test();
760 let public_key_id_a: PublicKeyId = 24682468.try_into()?;
761 let response_body_a = "foo";
762
763 let public_keys = PublicKeys {
764 latest: PublicKeyAndId { id: public_key_id_a, key: public_key_a },
765 historical: vec![],
766 };
767 let mut cup_handler = StandardCupv2Handler::new(&public_keys);
768 let (request_metadata_a, response_a) =
769 make_verify_response_arguments(&cup_handler, private_key_a, response_body_a)?;
770 assert_matches!(
771 cup_handler.verify_response(&request_metadata_a, &response_a, public_key_id_a),
772 Ok(_)
773 );
774
775 let (private_key_b, public_key_b) = test_support::make_keys_for_test();
777 let public_key_id_b: PublicKeyId = 12341234.try_into()?;
778 let response_body_b = "bar";
779
780 let public_keys = PublicKeys {
782 latest: PublicKeyAndId { id: public_key_id_b, key: public_key_b },
783 historical: vec![PublicKeyAndId { id: public_key_id_a, key: public_key_a }],
784 };
785 cup_handler = StandardCupv2Handler::new(&public_keys);
786
787 let (request_metadata_b, response_b) =
788 make_verify_response_arguments(&cup_handler, private_key_b, response_body_b)?;
789 assert_matches!(
791 cup_handler.verify_response(&request_metadata_b, &response_b, public_key_id_b),
792 Ok(_)
793 );
794
795 assert_matches!(
797 cup_handler.verify_response(&request_metadata_a, &response_a, public_key_id_a),
798 Ok(_)
799 );
800
801 assert!(
804 cup_handler.verify_response(&request_metadata_a, &response_a, public_key_id_b).is_err()
805 );
806 assert!(
807 cup_handler.verify_response(&request_metadata_a, &response_b, public_key_id_a).is_err()
808 );
809 assert!(
810 cup_handler.verify_response(&request_metadata_b, &response_a, public_key_id_a).is_err()
811 );
812
813 Ok(())
814 }
815
816 #[test]
817 fn test_deserialize_public_keys() {
818 let public_key_and_id: PublicKeyAndId = serde_json::from_value(serde_json::json!(
819 {
820 "id": 123,
821 "key": test_support::RAW_PUBLIC_KEY_FOR_TEST,
822 }
823 ))
824 .unwrap();
825
826 assert_eq!(public_key_and_id.key, test_support::make_default_public_key_for_test());
827 }
828
829 #[test]
830 fn test_publickeys_roundtrip() {
831 let public_keys = test_support::make_default_public_keys_for_test();
834 let public_keys_serialized = serde_json::to_string(&public_keys).unwrap();
835 let public_keys_reconstituted = serde_json::from_str(&public_keys_serialized).unwrap();
836 assert_eq!(public_keys, public_keys_reconstituted);
837 }
838
839 #[test]
840 fn test_parse_etag() {
841 assert_eq!(parse_etag("W/\"foo\""), "foo");
843 assert_eq!(parse_etag("W/\"thing-\"with\"-quotes\""), "thing-\"with\"-quotes");
844 assert_eq!(parse_etag("W/\"\""), "");
845 assert_eq!(parse_etag("\"foo\""), "foo");
847 assert_eq!(parse_etag("\"thing-\"with\"-quotes\""), "thing-\"with\"-quotes",);
848 assert_eq!(parse_etag("\"\""), "");
849 for v in ["foo", "1", "W", "W\"", "W/\"", "W/", "w/\"bar\"", "W/'bar'", ""] {
851 assert_eq!(parse_etag(v), v);
853 }
854 }
855}