jws/
combine.rs

1///! Combine multiple verifiers.
2
3use crate::{Error, JsonObject, Result, Verifier};
4
5#[derive(Clone, Debug)]
6pub struct OrVerifier<Left, Right> {
7	pub left  : Left,
8	pub right : Right,
9}
10
11#[derive(Clone, Debug)]
12pub struct AndVerifier<Left, Right> {
13	pub left  : Left,
14	pub right : Right,
15}
16
17/// Verifier that accepts messages if they are accepted by one of the wrapped verifiers.
18impl<Left, Right> OrVerifier<Left, Right> {
19	pub fn new(left: Left, right: Right) -> Self {
20		Self{left, right}
21	}
22
23	pub fn into_inner(self) -> (Left, Right) {
24		(self.left, self.right)
25	}
26
27	pub fn left(&self) -> &Left {
28		&self.left
29	}
30
31	pub fn right(&self) -> &Right {
32		&self.right
33	}
34}
35
36/// Verifier that accepts messages if they are accepted by both of the wrapped verifiers.
37impl<Left, Right> AndVerifier<Left, Right> {
38	pub fn new(left: Left, right: Right) -> Self {
39		Self{left, right}
40	}
41
42	pub fn into_inner(self) -> (Left, Right) {
43		(self.left, self.right)
44	}
45
46	pub fn left(&self) -> &Left {
47		&self.left
48	}
49
50	pub fn right(&self) -> &Right {
51		&self.right
52	}
53}
54
55impl<Left: Verifier, Right: Verifier> Verifier for OrVerifier<Left, Right> {
56	fn verify(&self, protected_header: Option<&JsonObject>, unprotected_header: Option<&JsonObject>, encoded_header: &[u8], encoded_payload: &[u8], signature: &[u8]) -> Result<()> {
57		// Try verifier Left first.
58		let error_a = match self.left.verify(protected_header, unprotected_header, encoded_header, encoded_payload, signature) {
59			Ok(()) => return Ok(()),
60			Err(x) => x,
61		};
62
63		// Also try verifier Right if Left didn't succeed.
64		let error_b = match self.right.verify(protected_header, unprotected_header, encoded_header, encoded_payload, signature) {
65			Ok(()) => return Ok(()),
66			Err(x) => x,
67		};
68
69		// Favor errors that aren't UnsupportedMacAlgorithm as returned error.
70		Err(match (error_a.kind(), error_b.kind()) {
71			(_, Error::UnsupportedMacAlgorithm) => error_a,
72			(Error::UnsupportedMacAlgorithm, _) => error_b,
73			(_, _)                              => error_a
74		})
75	}
76}
77
78impl<Left: Verifier, Right: Verifier> Verifier for AndVerifier<Left, Right> {
79	fn verify(&self, protected_header: Option<&JsonObject>, unprotected_header: Option<&JsonObject>, encoded_header: &[u8], encoded_payload: &[u8], signature: &[u8]) -> Result<()> {
80		// Try verifier Left and Right in order, pass all errors up.
81		self.left.verify(protected_header, unprotected_header, encoded_header, encoded_payload, signature)?;
82		self.right.verify(protected_header, unprotected_header, encoded_header, encoded_payload, signature)?;
83		Ok(())
84	}
85}
86
87#[cfg(test)]
88mod test {
89	use super::*;
90	use crate::{compact, json_object};
91	use crate::hmac::{HmacVerifier, Hs256Signer};
92
93	use assert2::assert;
94
95	#[test]
96	fn test_encode_sign_hmac_sha2() {
97		let header = json_object!{"typ": "JWT"};
98		let signed = compact::encode_sign(header, b"foo", &Hs256Signer::new(b"secretkey")).expect("sign HS256 failed");
99
100		let verifier_wrong = HmacVerifier::new(b"wrong-key");
101		let verifier_right = HmacVerifier::new(b"secretkey");
102
103		let wrong_or_right  = verifier_wrong.clone().or(verifier_right.clone());
104		let wrong_or_wrong  = verifier_wrong.clone().or(verifier_wrong.clone());
105		let wrong_and_right = verifier_wrong.clone().and(verifier_right.clone());
106		let right_and_right = verifier_right.clone().and(verifier_right.clone());
107
108		// Make sure the verifiers work as expected.
109		assert!(let Ok(_) = compact::decode_verify(signed.as_bytes(), &verifier_right));
110		assert!(let Ok(_) = compact::decode_verify(signed.as_bytes(), &wrong_or_right));
111		assert!(let Ok(_) = compact::decode_verify(signed.as_bytes(), &right_and_right));
112
113		assert!(let Err(Error { kind: Error::InvalidSignature, .. }) = compact::decode_verify(signed.as_bytes(), &verifier_wrong));
114		assert!(let Err(Error { kind: Error::InvalidSignature, .. }) = compact::decode_verify(signed.as_bytes(), &wrong_or_wrong));
115		assert!(let Err(Error { kind: Error::InvalidSignature, .. }) = compact::decode_verify(signed.as_bytes(), &wrong_and_right));
116	}
117}