1 use std::fmt::{Debug, Formatter, Result as FormatterResult};
2 use std::marker::PhantomData;
3 use std::ops::Deref;
4 use std::str;
5 
6 use serde::de::{DeserializeOwned, Error as _, Visitor};
7 use serde::{Deserialize, Deserializer, Serialize, Serializer};
8 use thiserror::Error;
9 
10 use super::{
11     JsonWebKey, JsonWebKeyId, JsonWebKeyType, JsonWebKeyUse, JweContentEncryptionAlgorithm,
12     JwsSigningAlgorithm, PrivateSigningKey, SignatureVerificationError, SigningError,
13 };
14 
15 new_type![
16     #[derive(Deserialize, Eq, Hash, Ord, PartialOrd, Serialize)]
17     JsonWebTokenContentType(String)
18 ];
19 
20 new_type![
21     #[derive(Deserialize, Eq, Hash, Ord, PartialOrd, Serialize)]
22     JsonWebTokenType(String)
23 ];
24 
25 #[derive(Clone, Debug, PartialEq)]
26 #[non_exhaustive]
27 pub enum JsonWebTokenAlgorithm<JE, JS, JT>
28 where
29     JE: JweContentEncryptionAlgorithm<JT>,
30     JS: JwsSigningAlgorithm<JT>,
31     JT: JsonWebKeyType,
32 {
33     Encryption(JE),
34     // This is ugly, but we don't expose this module via the public API, so it's fine.
35     Signature(JS, PhantomData<JT>),
36     ///
37     /// No digital signature or MAC performed.
38     ///
39     /// # Security Warning
40     ///
41     /// This algorithm provides no security over the integrity of the JSON Web Token. Clients
42     /// should be careful not to rely on unsigned JWT's for security purposes. See
43     /// [Critical vulnerabilities in JSON Web Token libraries](
44     ///     https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/) for
45     /// further discussion.
46     ///
47     None,
48 }
49 impl<'de, JE, JS, JT> Deserialize<'de> for JsonWebTokenAlgorithm<JE, JS, JT>
50 where
51     JE: JweContentEncryptionAlgorithm<JT>,
52     JS: JwsSigningAlgorithm<JT>,
53     JT: JsonWebKeyType,
54 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,55     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
56     where
57         D: Deserializer<'de>,
58     {
59         let value: serde_json::Value = Deserialize::deserialize(deserializer)?;
60         // TODO: get rid of this clone() (see below)
61         let s: String = serde_json::from_value(value.clone()).map_err(D::Error::custom)?;
62 
63         // NB: These comparisons are case sensitive. Section 4.1.1 of RFC 7515 states: "The "alg"
64         // value is a case-sensitive ASCII string containing a StringOrURI value."
65         if s == "none" {
66             Ok(JsonWebTokenAlgorithm::None)
67         // TODO: Figure out a way to deserialize the enums without giving up ownership
68         } else if let Ok(val) = serde_json::from_value::<JE>(value.clone()) {
69             Ok(JsonWebTokenAlgorithm::Encryption(val))
70         } else if let Ok(val) = serde_json::from_value::<JS>(value) {
71             Ok(JsonWebTokenAlgorithm::Signature(val, PhantomData))
72         } else {
73             Err(D::Error::custom(format!(
74                 "unrecognized JSON Web Algorithm `{}`",
75                 s
76             )))
77         }
78     }
79 }
80 impl<JE, JS, JT> Serialize for JsonWebTokenAlgorithm<JE, JS, JT>
81 where
82     JE: JweContentEncryptionAlgorithm<JT>,
83     JS: JwsSigningAlgorithm<JT>,
84     JT: JsonWebKeyType,
85 {
serialize<SE>(&self, serializer: SE) -> Result<SE::Ok, SE::Error> where SE: Serializer,86     fn serialize<SE>(&self, serializer: SE) -> Result<SE::Ok, SE::Error>
87     where
88         SE: Serializer,
89     {
90         match self {
91             JsonWebTokenAlgorithm::Encryption(ref enc) => enc.serialize(serializer),
92             JsonWebTokenAlgorithm::Signature(ref sig, _) => sig.serialize(serializer),
93             JsonWebTokenAlgorithm::None => serializer.serialize_str("none"),
94         }
95     }
96 }
97 
98 #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
99 pub struct JsonWebTokenHeader<JE, JS, JT>
100 where
101     JE: JweContentEncryptionAlgorithm<JT>,
102     JS: JwsSigningAlgorithm<JT>,
103     JT: JsonWebKeyType,
104 {
105     #[serde(
106         bound = "JE: JweContentEncryptionAlgorithm<JT>, JS: JwsSigningAlgorithm<JT>, JT: JsonWebKeyType"
107     )]
108     pub alg: JsonWebTokenAlgorithm<JE, JS, JT>,
109     // Additional critical header parameters that must be understood by this implementation. Since
110     // we don't understand any such extensions, we reject any JWT with this value present (the
111     // spec specifically prohibits including public (standard) headers in this field).
112     // See https://tools.ietf.org/html/rfc7515#section-4.1.11.
113     #[serde(skip_serializing_if = "Option::is_none")]
114     pub crit: Option<Vec<String>>,
115     #[serde(skip_serializing_if = "Option::is_none")]
116     pub cty: Option<JsonWebTokenContentType>,
117     #[serde(skip_serializing_if = "Option::is_none")]
118     pub kid: Option<JsonWebKeyId>,
119     #[serde(skip_serializing_if = "Option::is_none")]
120     pub typ: Option<JsonWebTokenType>,
121     // Other JOSE header fields are omitted since the OpenID Connect spec specifically says that
122     // the "x5u", "x5c", "jku", "jwk" header parameter fields SHOULD NOT be used.
123     // See http://openid.net/specs/openid-connect-core-1_0-final.html#IDToken.
124     #[serde(skip)]
125     _phantom_jt: PhantomData<JT>,
126 }
127 
128 pub trait JsonWebTokenPayloadSerde<P>: Debug
129 where
130     P: Debug + DeserializeOwned + Serialize,
131 {
deserialize<DE: serde::de::Error>(payload: &[u8]) -> Result<P, DE>132     fn deserialize<DE: serde::de::Error>(payload: &[u8]) -> Result<P, DE>;
serialize(payload: &P) -> Result<String, serde_json::Error>133     fn serialize(payload: &P) -> Result<String, serde_json::Error>;
134 }
135 
136 #[derive(Clone, Debug, PartialEq)]
137 pub struct JsonWebTokenJsonPayloadSerde;
138 impl<P> JsonWebTokenPayloadSerde<P> for JsonWebTokenJsonPayloadSerde
139 where
140     P: Debug + DeserializeOwned + Serialize,
141 {
deserialize<DE: serde::de::Error>(payload: &[u8]) -> Result<P, DE>142     fn deserialize<DE: serde::de::Error>(payload: &[u8]) -> Result<P, DE> {
143         serde_json::from_slice(payload)
144             .map_err(|err| DE::custom(format!("Failed to parse payload JSON: {:?}", err)))
145     }
146 
serialize(payload: &P) -> Result<String, serde_json::Error>147     fn serialize(payload: &P) -> Result<String, serde_json::Error> {
148         serde_json::to_string(payload).map_err(Into::into)
149     }
150 }
151 
152 // Helper trait so that we can get borrowed payload when we have a reference to the JWT and owned
153 // payload when we own the JWT.
154 pub trait JsonWebTokenAccess<JE, JS, JT, P>
155 where
156     JE: JweContentEncryptionAlgorithm<JT>,
157     JS: JwsSigningAlgorithm<JT>,
158     JT: JsonWebKeyType,
159     P: Debug + DeserializeOwned + Serialize,
160 {
161     type ReturnType;
162 
unverified_header(&self) -> &JsonWebTokenHeader<JE, JS, JT>163     fn unverified_header(&self) -> &JsonWebTokenHeader<JE, JS, JT>;
unverified_payload(self) -> Self::ReturnType164     fn unverified_payload(self) -> Self::ReturnType;
unverified_payload_ref(&self) -> &P165     fn unverified_payload_ref(&self) -> &P;
166 
payload<JU, JW>( self, signature_alg: &JS, key: &JW, ) -> Result<Self::ReturnType, SignatureVerificationError> where JU: JsonWebKeyUse, JW: JsonWebKey<JS, JT, JU>167     fn payload<JU, JW>(
168         self,
169         signature_alg: &JS,
170         key: &JW,
171     ) -> Result<Self::ReturnType, SignatureVerificationError>
172     where
173         JU: JsonWebKeyUse,
174         JW: JsonWebKey<JS, JT, JU>;
175 }
176 
177 ///
178 /// Error creating a JSON Web Token.
179 ///
180 #[derive(Debug, Error)]
181 #[non_exhaustive]
182 pub enum JsonWebTokenError {
183     ///
184     /// Failed to serialize JWT.
185     ///
186     #[error("Failed to serialize JWT")]
187     SerializationError(#[source] serde_json::Error),
188     ///
189     /// Failed to sign JWT.
190     ///
191     #[error("Failed to sign JWT")]
192     SigningError(#[source] SigningError),
193 }
194 
195 #[derive(Clone, Debug, PartialEq)]
196 pub struct JsonWebToken<JE, JS, JT, P, S>
197 where
198     JE: JweContentEncryptionAlgorithm<JT>,
199     JS: JwsSigningAlgorithm<JT>,
200     JT: JsonWebKeyType,
201     P: Debug + DeserializeOwned + Serialize,
202     S: JsonWebTokenPayloadSerde<P>,
203 {
204     header: JsonWebTokenHeader<JE, JS, JT>,
205     payload: P,
206     signature: Vec<u8>,
207     signing_input: String,
208     _phantom: PhantomData<S>,
209 }
210 impl<JE, JS, JT, P, S> JsonWebToken<JE, JS, JT, P, S>
211 where
212     JE: JweContentEncryptionAlgorithm<JT>,
213     JS: JwsSigningAlgorithm<JT>,
214     JT: JsonWebKeyType,
215     P: Debug + DeserializeOwned + Serialize,
216     S: JsonWebTokenPayloadSerde<P>,
217 {
new<JU, K, SK>(payload: P, signing_key: &SK, alg: &JS) -> Result<Self, JsonWebTokenError> where JU: JsonWebKeyUse, K: JsonWebKey<JS, JT, JU>, SK: PrivateSigningKey<JS, JT, JU, K>,218     pub fn new<JU, K, SK>(payload: P, signing_key: &SK, alg: &JS) -> Result<Self, JsonWebTokenError>
219     where
220         JU: JsonWebKeyUse,
221         K: JsonWebKey<JS, JT, JU>,
222         SK: PrivateSigningKey<JS, JT, JU, K>,
223     {
224         let header = JsonWebTokenHeader::<JE, _, _> {
225             alg: JsonWebTokenAlgorithm::Signature(alg.clone(), PhantomData),
226             crit: None,
227             cty: None,
228             kid: signing_key.as_verification_key().key_id().cloned(),
229             typ: None,
230             _phantom_jt: PhantomData,
231         };
232 
233         let header_json =
234             serde_json::to_string(&header).map_err(JsonWebTokenError::SerializationError)?;
235         let header_base64 = base64::encode_config(&header_json, base64::URL_SAFE_NO_PAD);
236 
237         let serialized_payload =
238             S::serialize(&payload).map_err(JsonWebTokenError::SerializationError)?;
239         let payload_base64 = base64::encode_config(&serialized_payload, base64::URL_SAFE_NO_PAD);
240 
241         let signing_input = format!("{}.{}", header_base64, payload_base64);
242 
243         let signature = signing_key
244             .sign(alg, signing_input.as_bytes())
245             .map_err(JsonWebTokenError::SigningError)?;
246 
247         Ok(JsonWebToken {
248             header,
249             payload,
250             signature,
251             signing_input,
252             _phantom: PhantomData,
253         })
254     }
255 }
256 // Owned JWT.
257 impl<JE, JS, JT, P, S> JsonWebTokenAccess<JE, JS, JT, P> for JsonWebToken<JE, JS, JT, P, S>
258 where
259     JE: JweContentEncryptionAlgorithm<JT>,
260     JS: JwsSigningAlgorithm<JT>,
261     JT: JsonWebKeyType,
262     P: Debug + DeserializeOwned + Serialize,
263     S: JsonWebTokenPayloadSerde<P>,
264 {
265     type ReturnType = P;
unverified_header(&self) -> &JsonWebTokenHeader<JE, JS, JT>266     fn unverified_header(&self) -> &JsonWebTokenHeader<JE, JS, JT> {
267         &self.header
268     }
unverified_payload(self) -> Self::ReturnType269     fn unverified_payload(self) -> Self::ReturnType {
270         self.payload
271     }
unverified_payload_ref(&self) -> &P272     fn unverified_payload_ref(&self) -> &P {
273         &self.payload
274     }
payload<JU, JW>( self, signature_alg: &JS, key: &JW, ) -> Result<Self::ReturnType, SignatureVerificationError> where JU: JsonWebKeyUse, JW: JsonWebKey<JS, JT, JU>,275     fn payload<JU, JW>(
276         self,
277         signature_alg: &JS,
278         key: &JW,
279     ) -> Result<Self::ReturnType, SignatureVerificationError>
280     where
281         JU: JsonWebKeyUse,
282         JW: JsonWebKey<JS, JT, JU>,
283     {
284         key.verify_signature(
285             signature_alg,
286             self.signing_input.as_bytes(),
287             &self.signature,
288         )?;
289         Ok(self.payload)
290     }
291 }
292 // Borrowed JWT.
293 impl<'a, JE, JS, JT, P, S> JsonWebTokenAccess<JE, JS, JT, P> for &'a JsonWebToken<JE, JS, JT, P, S>
294 where
295     JE: JweContentEncryptionAlgorithm<JT>,
296     JS: JwsSigningAlgorithm<JT>,
297     JT: JsonWebKeyType,
298     P: Debug + DeserializeOwned + Serialize,
299     S: JsonWebTokenPayloadSerde<P>,
300 {
301     type ReturnType = &'a P;
unverified_header(&self) -> &JsonWebTokenHeader<JE, JS, JT>302     fn unverified_header(&self) -> &JsonWebTokenHeader<JE, JS, JT> {
303         &self.header
304     }
unverified_payload(self) -> Self::ReturnType305     fn unverified_payload(self) -> Self::ReturnType {
306         &self.payload
307     }
unverified_payload_ref(&self) -> &P308     fn unverified_payload_ref(&self) -> &P {
309         &self.payload
310     }
payload<JU, JW>( self, signature_alg: &JS, key: &JW, ) -> Result<Self::ReturnType, SignatureVerificationError> where JU: JsonWebKeyUse, JW: JsonWebKey<JS, JT, JU>,311     fn payload<JU, JW>(
312         self,
313         signature_alg: &JS,
314         key: &JW,
315     ) -> Result<Self::ReturnType, SignatureVerificationError>
316     where
317         JU: JsonWebKeyUse,
318         JW: JsonWebKey<JS, JT, JU>,
319     {
320         key.verify_signature(
321             signature_alg,
322             self.signing_input.as_bytes(),
323             &self.signature,
324         )?;
325         Ok(&self.payload)
326     }
327 }
328 impl<'de, JE, JS, JT, P, S> Deserialize<'de> for JsonWebToken<JE, JS, JT, P, S>
329 where
330     JE: JweContentEncryptionAlgorithm<JT>,
331     JS: JwsSigningAlgorithm<JT>,
332     JT: JsonWebKeyType,
333     P: Debug + DeserializeOwned + Serialize,
334     S: JsonWebTokenPayloadSerde<P>,
335 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,336     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
337     where
338         D: Deserializer<'de>,
339     {
340         struct JsonWebTokenVisitor<
341             JE: JweContentEncryptionAlgorithm<JT>,
342             JS: JwsSigningAlgorithm<JT>,
343             JT: JsonWebKeyType,
344             P: Debug + DeserializeOwned + Serialize,
345             S: JsonWebTokenPayloadSerde<P>,
346         >(
347             PhantomData<JE>,
348             PhantomData<JS>,
349             PhantomData<JT>,
350             PhantomData<P>,
351             PhantomData<S>,
352         );
353         impl<'de, JE, JS, JT, P, S> Visitor<'de> for JsonWebTokenVisitor<JE, JS, JT, P, S>
354         where
355             JE: JweContentEncryptionAlgorithm<JT>,
356             JS: JwsSigningAlgorithm<JT>,
357             JT: JsonWebKeyType,
358             P: Debug + DeserializeOwned + Serialize,
359             S: JsonWebTokenPayloadSerde<P>,
360         {
361             type Value = JsonWebToken<JE, JS, JT, P, S>;
362 
363             fn expecting(&self, formatter: &mut Formatter) -> FormatterResult {
364                 formatter.write_str("JsonWebToken")
365             }
366 
367             fn visit_str<DE>(self, v: &str) -> Result<Self::Value, DE>
368             where
369                 DE: serde::de::Error,
370             {
371                 let raw_token = v.to_string();
372                 let header: JsonWebTokenHeader<JE, JS, JT>;
373                 let payload: P;
374                 let signature;
375                 let signing_input;
376 
377                 {
378                     let parts = raw_token.split('.').collect::<Vec<_>>();
379 
380                     // NB: We avoid including the full payload encoding in the error output to avoid
381                     // clients potentially logging sensitive values.
382                     if parts.len() != 3 {
383                         return Err(DE::custom(format!(
384                             "Invalid JSON web token: found {} parts (expected 3)",
385                             parts.len()
386                         )));
387                     }
388 
389                     let header_json =
390                         base64::decode_config(parts[0], crate::core::base64_url_safe_no_pad())
391                             .map_err(|err| {
392                                 DE::custom(format!("Invalid base64url header encoding: {:?}", err))
393                             })?;
394                     header = serde_json::from_slice(&header_json).map_err(|err| {
395                         DE::custom(format!("Failed to parse header JSON: {:?}", err))
396                     })?;
397 
398                     let raw_payload =
399                         base64::decode_config(parts[1], crate::core::base64_url_safe_no_pad())
400                             .map_err(|err| {
401                                 DE::custom(format!("Invalid base64url payload encoding: {:?}", err))
402                             })?;
403                     payload = S::deserialize::<DE>(&raw_payload)?;
404 
405                     signature =
406                         base64::decode_config(parts[2], crate::core::base64_url_safe_no_pad())
407                             .map_err(|err| {
408                                 DE::custom(format!(
409                                     "Invalid base64url signature encoding: {:?}",
410                                     err
411                                 ))
412                             })?;
413 
414                     signing_input = format!("{}.{}", parts[0], parts[1]);
415                 }
416 
417                 Ok(JsonWebToken {
418                     header,
419                     payload,
420                     signature,
421                     signing_input,
422                     _phantom: PhantomData,
423                 })
424             }
425         }
426         deserializer.deserialize_str(JsonWebTokenVisitor(
427             PhantomData,
428             PhantomData,
429             PhantomData,
430             PhantomData,
431             PhantomData,
432         ))
433     }
434 }
435 impl<JE, JS, JT, P, S> Serialize for JsonWebToken<JE, JS, JT, P, S>
436 where
437     JE: JweContentEncryptionAlgorithm<JT>,
438     JS: JwsSigningAlgorithm<JT>,
439     JT: JsonWebKeyType,
440     P: Debug + DeserializeOwned + Serialize,
441     S: JsonWebTokenPayloadSerde<P>,
442 {
serialize<SE>(&self, serializer: SE) -> Result<SE::Ok, SE::Error> where SE: Serializer,443     fn serialize<SE>(&self, serializer: SE) -> Result<SE::Ok, SE::Error>
444     where
445         SE: Serializer,
446     {
447         let signature_base64 = base64::encode_config(&self.signature, base64::URL_SAFE_NO_PAD);
448         serializer.serialize_str(&format!("{}.{}", self.signing_input, signature_base64))
449     }
450 }
451 
452 #[cfg(test)]
453 pub mod tests {
454     use std::marker::PhantomData;
455     use std::string::ToString;
456 
457     use crate::core::{
458         CoreJsonWebKey, CoreJsonWebKeyType, CoreJweContentEncryptionAlgorithm,
459         CoreJwsSigningAlgorithm, CoreRsaPrivateSigningKey,
460     };
461     use crate::JsonWebKeyId;
462 
463     use super::{
464         JsonWebToken, JsonWebTokenAccess, JsonWebTokenAlgorithm, JsonWebTokenJsonPayloadSerde,
465         JsonWebTokenPayloadSerde,
466     };
467 
468     type CoreAlgorithm = JsonWebTokenAlgorithm<
469         CoreJweContentEncryptionAlgorithm,
470         CoreJwsSigningAlgorithm,
471         CoreJsonWebKeyType,
472     >;
473 
474     pub const TEST_JWT: &str =
475         "eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZ\
476          GFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGU\
477          gcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlc\
478          mUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e\
479          5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3l\
480          fWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV\
481          0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41\
482          Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg";
483 
484     const TEST_JWT_PAYLOAD: &str = "It\u{2019}s a dangerous business, Frodo, going out your \
485                                     door. You step onto the road, and if you don't keep your feet, \
486                                     there\u{2019}s no knowing where you might be swept off \
487                                     to.";
488 
489     pub const TEST_RSA_PUB_KEY: &str = "{
490             \"kty\": \"RSA\",
491             \"kid\": \"bilbo.baggins@hobbiton.example\",
492             \"use\": \"sig\",
493             \"n\": \"n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT\
494                      -O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV\
495                      wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-\
496                      oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde\
497                      3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC\
498                      LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g\
499                      HdrNP5zw\",
500             \"e\": \"AQAB\"
501         }";
502 
503     pub const TEST_EC_PUB_KEY_P256: &str = r#"{
504         "kty": "EC",
505         "kid": "bilbo.baggins@hobbiton.example",
506         "use": "sig",
507         "crv": "P-256",
508         "x": "t6PHivOTggpaX9lkMkis2p8kMhy-CktJAFTz6atReZw",
509         "y": "ODobXupKlD0DeM1yRd7bX4XFNBO1HOgCT1UCu0KY3lc"
510     }"#;
511     pub const TEST_EC_PUB_KEY_P384: &str = r#"{
512         "kty": "EC",
513         "kid": "bilbo.baggins@hobbiton.example",
514         "use": "sig",
515         "crv" : "P-384",
516         "x": "9ywsUbxX59kJXFRiWHcx97wRKNiF8Hc9F5wI08n8h2ek_qAl0veEc36k1Qz6KLiL",
517         "y": "6PWlqjRbaV7V8ohDscM243IneuLZmxDGLiGNA1w69fQhEDsvZtKLUQ5KiHLgR3op"
518     }"#;
519 
520     // This is the PEM form of the test private key from:
521     // https://tools.ietf.org/html/rfc7520#section-3.4
522     pub const TEST_RSA_PRIV_KEY: &str = "-----BEGIN RSA PRIVATE KEY-----\n\
523          MIIEowIBAAKCAQEAn4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8/KuKPEHLd4\n\
524          rHVTeT+O+XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz/AJmSCpMaJMRBSFKrKb2wqVwG\n\
525          U/NsYOYL+QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj+oBHqFEHYpP\n\
526          e7Tpe+OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzw\n\
527          OHrtIQbS0FVbb9k3+tVTU4fg/3L/vniUFAKwuCLqKnS2BYwdq/mzSnbLY7h/qixo\n\
528          R7jig3//kRhuaxwUkRz5iaiQkqgc5gHdrNP5zwIDAQABAoIBAG1lAvQfhBUSKPJK\n\
529          Rn4dGbshj7zDSr2FjbQf4pIh/ZNtHk/jtavyO/HomZKV8V0NFExLNi7DUUvvLiW7\n\
530          0PgNYq5MDEjJCtSd10xoHa4QpLvYEZXWO7DQPwCmRofkOutf+NqyDS0QnvFvp2d+\n\
531          Lov6jn5C5yvUFgw6qWiLAPmzMFlkgxbtjFAWMJB0zBMy2BqjntOJ6KnqtYRMQUxw\n\
532          TgXZDF4rhYVKtQVOpfg6hIlsaoPNrF7dofizJ099OOgDmCaEYqM++bUlEHxgrIVk\n\
533          wZz+bg43dfJCocr9O5YX0iXaz3TOT5cpdtYbBX+C/5hwrqBWru4HbD3xz8cY1TnD\n\
534          qQa0M8ECgYEA3Slxg/DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex/fp7AZ/9\n\
535          nRaO7HX/+SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr/WCsmGpeNqQn\n\
536          ev1T7IyEsnh8UMt+n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0kCgYEAuKE2\n\
537          dh+cTf6ERF4k4e/jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR/cu0Dm1MZwW\n\
538          mtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoB\n\
539          vyY898EXvRD+hdqRxHlSqAZ192zB3pVFJ0s7pFcCgYAHw9W9eS8muPYv4ZhDu/fL\n\
540          2vorDmD1JqFcHCxZTOnX1NWWAj5hXzmrU0hvWvFC0P4ixddHf5Nqd6+5E9G3k4E5\n\
541          2IwZCnylu3bqCWNh8pT8T3Gf5FQsfPT5530T2BcsoPhUaeCnP499D+rb2mTnFYeg\n\
542          mnTT1B/Ue8KGLFFfn16GKQKBgAiw5gxnbocpXPaO6/OKxFFZ+6c0OjxfN2PogWce\n\
543          TU/k6ZzmShdaRKwDFXisxRJeNQ5Rx6qgS0jNFtbDhW8E8WFmQ5urCOqIOYk28EBi\n\
544          At4JySm4v+5P7yYBh8B8YD2l9j57z/s8hJAxEbn/q8uHP2ddQqvQKgtsni+pHSk9\n\
545          XGBfAoGBANz4qr10DdM8DHhPrAb2YItvPVz/VwkBd1Vqj8zCpyIEKe/07oKOvjWQ\n\
546          SgkLDH9x2hBgY01SbP43CvPk0V72invu2TGkI/FXwXWJLLG7tDSgw4YyfhrYrHmg\n\
547          1Vre3XB9HH8MYBVB6UIexaAq4xSeoemRKTBesZro7OKjKT8/GmiO\
548          -----END RSA PRIVATE KEY-----";
549 
550     #[test]
test_jwt_algorithm_deserialization()551     fn test_jwt_algorithm_deserialization() {
552         assert_eq!(
553             serde_json::from_str::<CoreAlgorithm>("\"A128CBC-HS256\"")
554                 .expect("failed to deserialize"),
555             JsonWebTokenAlgorithm::Encryption(
556                 CoreJweContentEncryptionAlgorithm::Aes128CbcHmacSha256
557             ),
558         );
559         assert_eq!(
560             serde_json::from_str::<CoreAlgorithm>("\"A128GCM\"").expect("failed to deserialize"),
561             JsonWebTokenAlgorithm::Encryption(CoreJweContentEncryptionAlgorithm::Aes128Gcm),
562         );
563         assert_eq!(
564             serde_json::from_str::<CoreAlgorithm>("\"HS256\"").expect("failed to deserialize"),
565             JsonWebTokenAlgorithm::Signature(CoreJwsSigningAlgorithm::HmacSha256, PhantomData),
566         );
567         assert_eq!(
568             serde_json::from_str::<CoreAlgorithm>("\"RS256\"").expect("failed to deserialize"),
569             JsonWebTokenAlgorithm::Signature(
570                 CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256,
571                 PhantomData,
572             ),
573         );
574         assert_eq!(
575             serde_json::from_str::<CoreAlgorithm>("\"none\"").expect("failed to deserialize"),
576             JsonWebTokenAlgorithm::None,
577         );
578 
579         serde_json::from_str::<CoreAlgorithm>("\"invalid\"")
580             .expect_err("deserialization should have failed");
581     }
582 
583     #[test]
test_jwt_algorithm_serialization()584     fn test_jwt_algorithm_serialization() {
585         assert_eq!(
586             serde_json::to_string::<CoreAlgorithm>(&JsonWebTokenAlgorithm::Encryption(
587                 CoreJweContentEncryptionAlgorithm::Aes128CbcHmacSha256
588             ))
589             .expect("failed to serialize"),
590             "\"A128CBC-HS256\"",
591         );
592         assert_eq!(
593             serde_json::to_string::<CoreAlgorithm>(&JsonWebTokenAlgorithm::Encryption(
594                 CoreJweContentEncryptionAlgorithm::Aes128Gcm
595             ))
596             .expect("failed to serialize"),
597             "\"A128GCM\"",
598         );
599         assert_eq!(
600             serde_json::to_string::<CoreAlgorithm>(&JsonWebTokenAlgorithm::Signature(
601                 CoreJwsSigningAlgorithm::HmacSha256,
602                 PhantomData,
603             ))
604             .expect("failed to serialize"),
605             "\"HS256\"",
606         );
607         assert_eq!(
608             serde_json::to_string::<CoreAlgorithm>(&JsonWebTokenAlgorithm::Signature(
609                 CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256,
610                 PhantomData,
611             ))
612             .expect("failed to serialize"),
613             "\"RS256\"",
614         );
615         assert_eq!(
616             serde_json::to_string::<CoreAlgorithm>(&JsonWebTokenAlgorithm::None)
617                 .expect("failed to serialize"),
618             "\"none\"",
619         );
620     }
621 
622     #[derive(Clone, Debug)]
623     pub struct JsonWebTokenStringPayloadSerde;
624     impl JsonWebTokenPayloadSerde<String> for JsonWebTokenStringPayloadSerde {
deserialize<DE: serde::de::Error>(payload: &[u8]) -> Result<String, DE>625         fn deserialize<DE: serde::de::Error>(payload: &[u8]) -> Result<String, DE> {
626             Ok(String::from_utf8(payload.to_owned()).unwrap())
627         }
serialize(payload: &String) -> Result<String, serde_json::Error>628         fn serialize(payload: &String) -> Result<String, serde_json::Error> {
629             Ok(payload.to_string())
630         }
631     }
632 
633     #[test]
test_jwt_basic()634     fn test_jwt_basic() {
635         fn verify_jwt<A>(jwt_access: A, key: &CoreJsonWebKey, expected_payload: &str)
636         where
637             A: JsonWebTokenAccess<
638                 CoreJweContentEncryptionAlgorithm,
639                 CoreJwsSigningAlgorithm,
640                 CoreJsonWebKeyType,
641                 String,
642             >,
643             A::ReturnType: ToString,
644         {
645             {
646                 let header = jwt_access.unverified_header();
647                 assert_eq!(
648                     header.alg,
649                     JsonWebTokenAlgorithm::Signature(
650                         CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256,
651                         PhantomData,
652                     )
653                 );
654                 assert_eq!(header.crit, None);
655                 assert_eq!(header.cty, None);
656                 assert_eq!(
657                     header.kid,
658                     Some(JsonWebKeyId::new(
659                         "bilbo.baggins@hobbiton.example".to_string()
660                     ))
661                 );
662                 assert_eq!(header.typ, None);
663             }
664             assert_eq!(jwt_access.unverified_payload_ref(), expected_payload);
665 
666             assert_eq!(
667                 jwt_access
668                     .payload(&CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256, key)
669                     .expect("failed to validate payload")
670                     .to_string(),
671                 expected_payload
672             );
673         }
674 
675         let key: CoreJsonWebKey =
676             serde_json::from_str(TEST_RSA_PUB_KEY).expect("deserialization failed");
677 
678         let jwt: JsonWebToken<
679             CoreJweContentEncryptionAlgorithm,
680             CoreJwsSigningAlgorithm,
681             CoreJsonWebKeyType,
682             String,
683             JsonWebTokenStringPayloadSerde,
684         > = serde_json::from_value(serde_json::Value::String(TEST_JWT.to_string()))
685             .expect("failed to deserialize");
686 
687         assert_eq!(
688             serde_json::to_value(&jwt).expect("failed to serialize"),
689             serde_json::Value::String(TEST_JWT.to_string())
690         );
691 
692         verify_jwt(&jwt, &key, TEST_JWT_PAYLOAD);
693         assert_eq!((&jwt).unverified_payload(), TEST_JWT_PAYLOAD);
694 
695         verify_jwt(jwt, &key, TEST_JWT_PAYLOAD);
696     }
697 
698     #[test]
test_new_jwt()699     fn test_new_jwt() {
700         let signing_key = CoreRsaPrivateSigningKey::from_pem(
701             TEST_RSA_PRIV_KEY,
702             Some(JsonWebKeyId::new(
703                 "bilbo.baggins@hobbiton.example".to_string(),
704             )),
705         )
706         .unwrap();
707         let new_jwt = JsonWebToken::<
708             CoreJweContentEncryptionAlgorithm,
709             _,
710             _,
711             _,
712             JsonWebTokenStringPayloadSerde,
713         >::new(
714             TEST_JWT_PAYLOAD.to_owned(),
715             &signing_key,
716             &CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256,
717         )
718         .unwrap();
719         assert_eq!(
720             serde_json::to_value(&new_jwt).expect("failed to serialize"),
721             serde_json::Value::String(TEST_JWT.to_string())
722         );
723     }
724 
725     #[test]
test_invalid_signature()726     fn test_invalid_signature() {
727         let corrupted_jwt_str = TEST_JWT
728             .to_string()
729             .chars()
730             .take(TEST_JWT.len() - 1)
731             .collect::<String>()
732             + "f";
733         let jwt: JsonWebToken<
734             CoreJweContentEncryptionAlgorithm,
735             CoreJwsSigningAlgorithm,
736             CoreJsonWebKeyType,
737             String,
738             JsonWebTokenStringPayloadSerde,
739         > = serde_json::from_value(serde_json::Value::String(corrupted_jwt_str))
740             .expect("failed to deserialize");
741         let key: CoreJsonWebKey =
742             serde_json::from_str(TEST_RSA_PUB_KEY).expect("deserialization failed");
743 
744         // JsonWebTokenAccess for reference.
745         (&jwt)
746             .payload(&CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256, &key)
747             .expect_err("signature verification should have failed");
748 
749         // JsonWebTokenAccess for owned value.
750         jwt.payload(&CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256, &key)
751             .expect_err("signature verification should have failed");
752     }
753 
754     #[test]
test_invalid_deserialization()755     fn test_invalid_deserialization() {
756         #[derive(Debug, Deserialize, Serialize)]
757         struct TestPayload {
758             foo: String,
759         }
760 
761         fn expect_deserialization_err<I: Into<String>>(jwt_str: I, pattern: &str) {
762             let err = serde_json::from_value::<
763                 JsonWebToken<
764                     CoreJweContentEncryptionAlgorithm,
765                     CoreJwsSigningAlgorithm,
766                     CoreJsonWebKeyType,
767                     TestPayload,
768                     JsonWebTokenJsonPayloadSerde,
769                 >,
770             >(serde_json::Value::String(jwt_str.into()))
771             .expect_err("deserialization should have failed");
772 
773             assert!(
774                 err.to_string().contains(pattern),
775                 "Error `{}` must contain string `{}`",
776                 err,
777                 pattern,
778             );
779         }
780 
781         // Too many dots
782         expect_deserialization_err("a.b.c.d", "found 4 parts (expected 3)");
783 
784         // Invalid header base64
785         expect_deserialization_err("a!.b.c", "Invalid base64url header encoding");
786 
787         // Invalid header utf-8 (after base64 decoding)
788         expect_deserialization_err("gA.b.c", "Error(\"expected value\", line: 1, column: 1)");
789 
790         // Invalid header JSON
791         expect_deserialization_err("bm90X2pzb24.b.c", "Failed to parse header JSON");
792 
793         let valid_header =
794             "eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9";
795 
796         // Invalid payload base64
797         expect_deserialization_err(
798             format!("{}.b!.c", valid_header),
799             "Invalid base64url payload encoding",
800         );
801 
802         // Invalid payload utf-8 (after base64 decoding)
803         expect_deserialization_err(
804             format!("{}.gA.c", valid_header),
805             "Error(\"expected value\", line: 1, column: 1)",
806         );
807 
808         // Invalid payload JSON
809         expect_deserialization_err(
810             format!("{}.bm90X2pzb24.c", valid_header),
811             "Failed to parse payload JSON",
812         );
813 
814         let valid_body = "eyJmb28iOiAiYmFyIn0";
815 
816         // Invalid signature base64
817         expect_deserialization_err(
818             format!("{}.{}.c!", valid_header, valid_body),
819             "Invalid base64url signature encoding",
820         );
821 
822         let deserialized = serde_json::from_value::<
823             JsonWebToken<
824                 CoreJweContentEncryptionAlgorithm,
825                 CoreJwsSigningAlgorithm,
826                 CoreJsonWebKeyType,
827                 TestPayload,
828                 JsonWebTokenJsonPayloadSerde,
829             >,
830         >(serde_json::Value::String(format!(
831             "{}.{}.e2FiY30",
832             valid_header, valid_body
833         )))
834         .expect("failed to deserialize");
835         assert_eq!(deserialized.unverified_payload().foo, "bar");
836     }
837 }
838