jwt/token/
verified.rs

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
8/// Allow objects to be verified with a key.
9pub trait VerifyWithKey<T> {
10    fn verify_with_key(self, key: &impl VerifyingAlgorithm) -> Result<T, Error>;
11}
12
13/// Allow objects to be verified with a store.
14pub 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    /// Not recommended. Parse the header and claims without checking the validity of the signature.
116    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    // Test stores
229
230    fn create_test_data<T>() -> Result<T, Error>
231    where
232        T: FromIterator<(&'static str, Box<dyn VerifyingAlgorithm>)>,
233    {
234        // Test two different algorithms in the same store
235        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    // Header   {"alg":"HS512","kid":"second_key"}
249    // Claims   {"name":"Jane Doe"}
250    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}