1use crate::algorithm::store::Store;
2use crate::algorithm::VerifyingAlgorithm;
3use crate::error::Error;
4use crate::header::{Header, JoseHeader};
5use crate::token::{Unverified, Verified};
6use crate::{FromBase64, Token, SEPARATOR};
7
8pub trait VerifyWithKey<T> {
10 fn verify_with_key(self, key: &impl VerifyingAlgorithm) -> Result<T, Error>;
11}
12
13pub trait VerifyWithStore<T> {
15 fn verify_with_store<S, A>(self, store: &S) -> Result<T, Error>
16 where
17 S: Store<Algorithm = A>,
18 A: VerifyingAlgorithm;
19}
20
21impl<'a, H: JoseHeader, C> VerifyWithKey<Token<H, C, Verified>> for Token<H, C, Unverified<'a>> {
22 fn verify_with_key(
23 self,
24 key: &impl VerifyingAlgorithm,
25 ) -> Result<Token<H, C, Verified>, Error> {
26 let header = self.header();
27 let header_algorithm = header.algorithm_type();
28 let key_algorithm = key.algorithm_type();
29 if header_algorithm != key_algorithm {
30 return Err(Error::AlgorithmMismatch(header_algorithm, key_algorithm));
31 }
32
33 let Unverified {
34 header_str,
35 claims_str,
36 signature_str,
37 } = self.signature;
38
39 if key.verify(header_str, claims_str, signature_str)? {
40 Ok(Token {
41 header: self.header,
42 claims: self.claims,
43 signature: Verified,
44 })
45 } else {
46 Err(Error::InvalidSignature)
47 }
48 }
49}
50
51impl<'a, H: JoseHeader, C> VerifyWithStore<Token<H, C, Verified>> for Token<H, C, Unverified<'a>> {
52 fn verify_with_store<S, A>(self, store: &S) -> Result<Token<H, C, Verified>, Error>
53 where
54 S: Store<Algorithm = A>,
55 A: VerifyingAlgorithm,
56 {
57 let header = self.header();
58 let key_id = header.key_id().ok_or(Error::NoKeyId)?;
59 let key = store
60 .get(key_id)
61 .ok_or_else(|| Error::NoKeyWithKeyId(key_id.to_owned()))?;
62
63 self.verify_with_key(key)
64 }
65}
66
67impl<'a, H, C> VerifyWithKey<Token<H, C, Verified>> for &'a str
68where
69 H: FromBase64 + JoseHeader,
70 C: FromBase64,
71{
72 fn verify_with_key(
73 self,
74 key: &impl VerifyingAlgorithm,
75 ) -> Result<Token<H, C, Verified>, Error> {
76 let unverified = Token::parse_unverified(self)?;
77 unverified.verify_with_key(key)
78 }
79}
80
81impl<'a, H, C> VerifyWithStore<Token<H, C, Verified>> for &'a str
82where
83 H: FromBase64 + JoseHeader,
84 C: FromBase64,
85{
86 fn verify_with_store<S, A>(self, store: &S) -> Result<Token<H, C, Verified>, Error>
87 where
88 S: Store<Algorithm = A>,
89 A: VerifyingAlgorithm,
90 {
91 let unverified: Token<H, C, _> = Token::parse_unverified(self)?;
92 unverified.verify_with_store(store)
93 }
94}
95
96impl<'a, C: FromBase64> VerifyWithKey<C> for &'a str {
97 fn verify_with_key(self, key: &impl VerifyingAlgorithm) -> Result<C, Error> {
98 let token: Token<Header, C, _> = self.verify_with_key(key)?;
99 Ok(token.claims)
100 }
101}
102
103impl<'a, C: FromBase64> VerifyWithStore<C> for &'a str {
104 fn verify_with_store<S, A>(self, store: &S) -> Result<C, Error>
105 where
106 S: Store<Algorithm = A>,
107 A: VerifyingAlgorithm,
108 {
109 let token: Token<Header, C, _> = self.verify_with_store(store)?;
110 Ok(token.claims)
111 }
112}
113
114impl<'a, H: FromBase64, C: FromBase64> Token<H, C, Unverified<'a>> {
115 pub fn parse_unverified(token_str: &str) -> Result<Token<H, C, Unverified>, Error> {
117 let [header_str, claims_str, signature_str] = split_components(token_str)?;
118 let header = H::from_base64(header_str)?;
119 let claims = C::from_base64(claims_str)?;
120 let signature = Unverified {
121 header_str,
122 claims_str,
123 signature_str,
124 };
125
126 Ok(Token {
127 header,
128 claims,
129 signature,
130 })
131 }
132}
133
134pub(crate) fn split_components(token: &str) -> Result<[&str; 3], Error> {
135 let mut components = token.split(SEPARATOR);
136 let header = components.next().ok_or(Error::NoHeaderComponent)?;
137 let claims = components.next().ok_or(Error::NoClaimsComponent)?;
138 let signature = components.next().ok_or(Error::NoSignatureComponent)?;
139
140 if components.next().is_some() {
141 return Err(Error::TooManyComponents);
142 }
143
144 Ok([header, claims, signature])
145}
146
147#[cfg(test)]
148mod tests {
149 use std::collections::{BTreeMap, HashMap};
150 use std::iter::FromIterator;
151
152 use hmac::{Hmac, Mac};
153 use serde::Deserialize;
154 use sha2::{Sha256, Sha512};
155
156 use crate::algorithm::VerifyingAlgorithm;
157 use crate::error::Error;
158 use crate::token::verified::{VerifyWithKey, VerifyWithStore};
159
160 #[derive(Debug, Deserialize)]
161 struct Claims {
162 name: String,
163 }
164
165 #[test]
166 #[cfg(feature = "openssl")]
167 pub fn token_can_not_be_verified_with_a_wrong_key() -> Result<(), Error> {
168 use crate::{token::signed::SignWithKey, AlgorithmType, Header, PKeyWithDigest, Token};
169 use openssl::{hash::MessageDigest, pkey::PKey};
170
171 let private_pem = include_bytes!("../../test/rs256-private.pem");
172 let public_pem = include_bytes!("../../test/rs256-public-2.pem");
173
174 let rs256_private_key = PKeyWithDigest {
175 digest: MessageDigest::sha256(),
176 key: PKey::private_key_from_pem(private_pem).unwrap(),
177 };
178 let rs256_public_key = PKeyWithDigest {
179 digest: MessageDigest::sha256(),
180 key: PKey::public_key_from_pem(public_pem).unwrap(),
181 };
182
183 let header = Header {
184 algorithm: AlgorithmType::Rs256,
185 ..Default::default()
186 };
187 let mut claims = BTreeMap::new();
188 claims.insert("sub", "someone");
189
190 let signed_token = Token::new(header, claims).sign_with_key(&rs256_private_key)?;
191 let token_str = signed_token.as_str();
192 let unverified_token: Token<Header, BTreeMap<String, String>, _> =
193 Token::parse_unverified(token_str)?;
194 let verified_token_result = unverified_token.verify_with_key(&rs256_public_key);
195 assert!(verified_token_result.is_err());
196 match verified_token_result.err().unwrap() {
197 Error::InvalidSignature => Ok(()),
198 other => panic!("Wrong error type: {:?}", other),
199 }
200 }
201
202 #[test]
203 pub fn component_errors() {
204 let key: Hmac<Sha256> = Hmac::new_from_slice(b"first").unwrap();
205
206 let no_claims = "header";
207 match VerifyWithKey::<String>::verify_with_key(no_claims, &key) {
208 Err(Error::NoClaimsComponent) => (),
209 Ok(s) => panic!("Verify should not have succeeded with output {:?}", s),
210 x => panic!("Incorrect error type {:?}", x),
211 }
212
213 let no_signature = "header.claims";
214 match VerifyWithKey::<String>::verify_with_key(no_signature, &key) {
215 Err(Error::NoSignatureComponent) => (),
216 Ok(s) => panic!("Verify should not have succeeded with output {:?}", s),
217 x => panic!("Incorrect error type {:?}", x),
218 }
219
220 let too_many = "header.claims.signature.";
221 match VerifyWithKey::<String>::verify_with_key(too_many, &key) {
222 Err(Error::TooManyComponents) => (),
223 Ok(s) => panic!("Verify should not have succeeded with output {:?}", s),
224 x => panic!("Incorrect error type {:?}", x),
225 }
226 }
227
228 fn create_test_data<T>() -> Result<T, Error>
231 where
232 T: FromIterator<(&'static str, Box<dyn VerifyingAlgorithm>)>,
233 {
234 let key1: Hmac<Sha256> = Hmac::new_from_slice(b"first")?;
236 let key2: Hmac<Sha512> = Hmac::new_from_slice(b"second")?;
237
238 let name_to_key_tuples = vec![
239 ("first_key", Box::new(key1) as Box<dyn VerifyingAlgorithm>),
240 ("second_key", Box::new(key2) as Box<dyn VerifyingAlgorithm>),
241 ]
242 .into_iter()
243 .collect();
244
245 Ok(name_to_key_tuples)
246 }
247
248 const JANE_DOE_SECOND_KEY_TOKEN: &str = "eyJhbGciOiJIUzUxMiIsImtpZCI6InNlY29uZF9rZXkifQ.eyJuYW1lIjoiSmFuZSBEb2UifQ.t2ON5s8DDb2hefBIWAe0jaEcp-T7b2Wevmj0kKJ8BFxKNQURHpdh4IA-wbmBmqtiCnqTGoRdqK45hhW0AOtz0A";
251
252 #[test]
253 pub fn verify_claims_with_b_tree_map() -> Result<(), Error> {
254 let key_store: BTreeMap<_, _> = create_test_data()?;
255
256 let claims: Claims = JANE_DOE_SECOND_KEY_TOKEN.verify_with_store(&key_store)?;
257
258 assert_eq!(claims.name, "Jane Doe");
259 Ok(())
260 }
261
262 #[test]
263 pub fn verify_claims_with_hash_map() -> Result<(), Error> {
264 let key_store: HashMap<_, _> = create_test_data()?;
265
266 let claims: Claims = JANE_DOE_SECOND_KEY_TOKEN.verify_with_store(&key_store)?;
267
268 assert_eq!(claims.name, "Jane Doe");
269 Ok(())
270 }
271
272 #[test]
273 pub fn verify_claims_with_missing_key() -> Result<(), Error> {
274 let key_store: BTreeMap<_, _> = create_test_data()?;
275 let missing_key_token = "eyJhbGciOiJIUzUxMiIsImtpZCI6Im1pc3Npbmdfa2V5In0.eyJuYW1lIjoiSmFuZSBEb2UifQ.MC9hmBjv9OABdv5bsjVdwUgPOhvpe6a924KU-U7PjVWF2N-f_HXa1PVWtDVJ-dqt1GKutVwixrz7hgVvE_G5_w";
276
277 let should_fail_claims: Result<Claims, _> = missing_key_token.verify_with_store(&key_store);
278
279 match should_fail_claims {
280 Err(Error::NoKeyWithKeyId(key_id)) => assert_eq!(key_id, "missing_key"),
281 _ => panic!(
282 "Missing key should have triggered specific error but returned {:?}",
283 should_fail_claims
284 ),
285 }
286
287 Ok(())
288 }
289}