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