diff --git a/README.md b/README.md index 41aa215..b11ce26 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,9 @@ This library currently supports the following: - RS256 - RS384 - RS512 +- PS256 +- PS384 +- PS512 - ES256 - ES384 diff --git a/examples/custom_header.rs b/examples/custom_header.rs index cdcf38b..d4c94da 100644 --- a/examples/custom_header.rs +++ b/examples/custom_header.rs @@ -3,7 +3,7 @@ extern crate jsonwebtoken as jwt; extern crate serde_derive; use jwt::errors::ErrorKind; -use jwt::{decode, encode, Algorithm, Header, Validation, Key}; +use jwt::{decode, encode, Algorithm, Header, Key, Validation}; #[derive(Debug, Serialize, Deserialize)] struct Claims { diff --git a/examples/validation.rs b/examples/validation.rs index 71c95b5..552eef0 100644 --- a/examples/validation.rs +++ b/examples/validation.rs @@ -3,7 +3,7 @@ extern crate jsonwebtoken as jwt; extern crate serde_derive; use jwt::errors::ErrorKind; -use jwt::{decode, encode, Header, Validation, Key}; +use jwt::{decode, encode, Header, Key, Validation}; #[derive(Debug, Serialize, Deserialize)] struct Claims { diff --git a/src/algorithms.rs b/src/algorithms.rs index 0e172f3..a7f8589 100644 --- a/src/algorithms.rs +++ b/src/algorithms.rs @@ -22,6 +22,13 @@ pub enum Algorithm { RS384, /// RSASSA-PKCS1-v1_5 using SHA-512 RS512, + + /// RSASSA-PSS using SHA-256 + PS256, + /// RSASSA-PSS using SHA-384 + PS384, + /// RSASSA-PSS using SHA-512 + PS512, } impl Default for Algorithm { @@ -41,6 +48,9 @@ impl FromStr for Algorithm { "ES384" => Ok(Algorithm::ES384), "RS256" => Ok(Algorithm::RS256), "RS384" => Ok(Algorithm::RS384), + "PS256" => Ok(Algorithm::PS256), + "PS384" => Ok(Algorithm::PS384), + "PS512" => Ok(Algorithm::PS512), "RS512" => Ok(Algorithm::RS512), _ => Err(new_error(ErrorKind::InvalidAlgorithmName)), } diff --git a/src/crypto.rs b/src/crypto.rs index 741585c..588980a 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -34,7 +34,6 @@ fn sign_ecdsa( return Err(new_error(ErrorKind::InvalidKeyFormat)); } }; - let rng = rand::SystemRandom::new(); let sig = signing_key.sign(&rng, untrusted::Input::from(signing_input.as_bytes()))?; Ok(base64::encode_config(&sig, base64::URL_SAFE_NO_PAD)) @@ -83,6 +82,10 @@ pub fn sign(signing_input: &str, key: Key, algorithm: Algorithm) -> Result sign_rsa(&signature::RSA_PKCS1_SHA256, key, signing_input), Algorithm::RS384 => sign_rsa(&signature::RSA_PKCS1_SHA384, key, signing_input), Algorithm::RS512 => sign_rsa(&signature::RSA_PKCS1_SHA512, key, signing_input), + + Algorithm::PS256 => sign_rsa(&signature::RSA_PSS_SHA256, key, signing_input), + Algorithm::PS384 => sign_rsa(&signature::RSA_PSS_SHA384, key, signing_input), + Algorithm::PS512 => sign_rsa(&signature::RSA_PSS_SHA512, key, signing_input), } } @@ -144,44 +147,38 @@ fn verify_ring_rsa( pub fn verify( signature: &str, signing_input: &str, - public_key: Key, + key: Key, algorithm: Algorithm, ) -> Result { match algorithm { Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => { // we just re-sign the data with the key and compare if they are equal - let signed = sign(signing_input, public_key, algorithm)?; + let signed = sign(signing_input, key, algorithm)?; Ok(verify_slices_are_equal(signature.as_ref(), signed.as_ref()).is_ok()) } - Algorithm::ES256 => verify_ring_es( - &signature::ECDSA_P256_SHA256_FIXED, - signature, - signing_input, - public_key, - ), - Algorithm::ES384 => verify_ring_es( - &signature::ECDSA_P384_SHA384_FIXED, - signature, - signing_input, - public_key, - ), - Algorithm::RS256 => verify_ring_rsa( - &signature::RSA_PKCS1_2048_8192_SHA256, - signature, - signing_input, - public_key, - ), - Algorithm::RS384 => verify_ring_rsa( - &signature::RSA_PKCS1_2048_8192_SHA384, - signature, - signing_input, - public_key, - ), - Algorithm::RS512 => verify_ring_rsa( - &signature::RSA_PKCS1_2048_8192_SHA512, - signature, - signing_input, - public_key, - ), + Algorithm::ES256 => { + verify_ring_es(&signature::ECDSA_P256_SHA256_FIXED, signature, signing_input, key) + } + Algorithm::ES384 => { + verify_ring_es(&signature::ECDSA_P384_SHA384_FIXED, signature, signing_input, key) + } + Algorithm::RS256 => { + verify_ring_rsa(&signature::RSA_PKCS1_2048_8192_SHA256, signature, signing_input, key) + } + Algorithm::RS384 => { + verify_ring_rsa(&signature::RSA_PKCS1_2048_8192_SHA384, signature, signing_input, key) + } + Algorithm::RS512 => { + verify_ring_rsa(&signature::RSA_PKCS1_2048_8192_SHA512, signature, signing_input, key) + } + Algorithm::PS256 => { + verify_ring_rsa(&signature::RSA_PSS_2048_8192_SHA256, signature, signing_input, key) + } + Algorithm::PS384 => { + verify_ring_rsa(&signature::RSA_PSS_2048_8192_SHA384, signature, signing_input, key) + } + Algorithm::PS512 => { + verify_ring_rsa(&signature::RSA_PSS_2048_8192_SHA512, signature, signing_input, key) + } } } diff --git a/src/errors.rs b/src/errors.rs index d05a0ee..317a5cb 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -99,7 +99,7 @@ impl StdError for Error { } } - fn cause(&self) -> Option<&StdError> { + fn cause(&self) -> Option<&dyn StdError> { match *self.0 { ErrorKind::InvalidToken => None, ErrorKind::InvalidSignature => None, diff --git a/tests/ecdsa.rs b/tests/ecdsa.rs index c11c0fd..4df1dab 100644 --- a/tests/ecdsa.rs +++ b/tests/ecdsa.rs @@ -4,7 +4,7 @@ extern crate serde_derive; extern crate chrono; use chrono::Utc; -use jsonwebtoken::{decode, encode, sign, verify, Algorithm, Key, Header, Validation}; +use jsonwebtoken::{decode, encode, sign, verify, Algorithm, Header, Key, Validation}; #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] struct Claims { @@ -33,7 +33,8 @@ fn round_trip_claim() { let token = encode(&Header::new(Algorithm::ES256), &my_claims, Key::Pkcs8(&privkey[..])).unwrap(); let pubkey = include_bytes!("public_ecdsa_key.pk8"); - let token_data = decode::(&token, Key::Pkcs8(pubkey), &Validation::new(Algorithm::ES256)).unwrap(); + let token_data = + decode::(&token, Key::Pkcs8(pubkey), &Validation::new(Algorithm::ES256)).unwrap(); assert_eq!(my_claims, token_data.claims); assert!(token_data.header.kid.is_none()); } diff --git a/tests/lib.rs b/tests/lib.rs index 6a4e328..b91f318 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -41,7 +41,8 @@ fn encode_with_custom_header() { let mut header = Header::default(); header.kid = Some("kid".to_string()); let token = encode(&header, &my_claims, Key::Hmac(b"secret")).unwrap(); - let token_data = decode::(&token, Key::Hmac(b"secret"), &Validation::default()).unwrap(); + let token_data = + decode::(&token, Key::Hmac(b"secret"), &Validation::default()).unwrap(); assert_eq!(my_claims, token_data.claims); assert_eq!("kid", token_data.header.kid.unwrap()); } @@ -54,7 +55,8 @@ fn round_trip_claim() { exp: Utc::now().timestamp() + 10000, }; let token = encode(&Header::default(), &my_claims, Key::Hmac(b"secret")).unwrap(); - let token_data = decode::(&token, Key::Hmac(b"secret"), &Validation::default()).unwrap(); + let token_data = + decode::(&token, Key::Hmac(b"secret"), &Validation::default()).unwrap(); assert_eq!(my_claims, token_data.claims); assert!(token_data.header.kid.is_none()); } @@ -166,5 +168,8 @@ fn generate_algorithm_enum_from_str() { assert!(Algorithm::from_str("RS256").is_ok()); assert!(Algorithm::from_str("RS384").is_ok()); assert!(Algorithm::from_str("RS512").is_ok()); + assert!(Algorithm::from_str("PS256").is_ok()); + assert!(Algorithm::from_str("PS384").is_ok()); + assert!(Algorithm::from_str("PS512").is_ok()); assert!(Algorithm::from_str("").is_err()); } diff --git a/tests/rsa.rs b/tests/rsa.rs index 20ee7f7..b64f4c7 100644 --- a/tests/rsa.rs +++ b/tests/rsa.rs @@ -4,7 +4,16 @@ extern crate serde_derive; extern crate chrono; use chrono::Utc; -use jsonwebtoken::{decode, encode, sign, verify, Algorithm, Key, Header, Validation}; +use jsonwebtoken::{decode, encode, sign, verify, Algorithm, Header, Key, Validation}; + +const RSA_ALGORITHMS: &[Algorithm] = &[ + Algorithm::RS256, + Algorithm::RS384, + Algorithm::RS512, + Algorithm::PS256, + Algorithm::PS384, + Algorithm::PS512, +]; #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] struct Claims { @@ -16,11 +25,13 @@ struct Claims { #[test] fn round_trip_sign_verification() { let privkey = include_bytes!("private_rsa_key.der"); - let encrypted = sign("hello world", Key::Der(&privkey[..]), Algorithm::RS256).unwrap(); - let is_valid = - verify(&encrypted, "hello world", Key::Der(include_bytes!("public_rsa_key.der")), Algorithm::RS256) - .unwrap(); - assert!(is_valid); + for &alg in RSA_ALGORITHMS { + let encrypted = sign("hello world", Key::Der(&privkey[..]), alg).unwrap(); + let is_valid = + verify(&encrypted, "hello world", Key::Der(include_bytes!("public_rsa_key.der")), alg) + .unwrap(); + assert!(is_valid); + } } #[test] @@ -31,16 +42,18 @@ fn round_trip_claim() { exp: Utc::now().timestamp() + 10000, }; let privkey = include_bytes!("private_rsa_key.der"); - let token = - encode(&Header::new(Algorithm::RS256), &my_claims, Key::Der(&privkey[..])).unwrap(); - let token_data = decode::( - &token, - Key::Der(include_bytes!("public_rsa_key.der")), - &Validation::new(Algorithm::RS256), - ) - .unwrap(); - assert_eq!(my_claims, token_data.claims); - assert!(token_data.header.kid.is_none()); + + for &alg in RSA_ALGORITHMS { + let token = encode(&Header::new(alg), &my_claims, Key::Der(&privkey[..])).unwrap(); + let token_data = decode::( + &token, + Key::Der(include_bytes!("public_rsa_key.der")), + &Validation::new(alg), + ) + .unwrap(); + assert_eq!(my_claims, token_data.claims); + assert!(token_data.header.kid.is_none()); + } } #[test]