diff --git a/examples/auth0.rs b/examples/auth0.rs index 040301a0..2964c3a3 100644 --- a/examples/auth0.rs +++ b/examples/auth0.rs @@ -1,8 +1,9 @@ /// Example for the backend to backend implementation use std::collections::HashMap; +use std::str::FromStr; use jsonwebtoken::jwk::AlgorithmParameters; -use jsonwebtoken::{decode, decode_header, jwk, DecodingKey, Validation}; +use jsonwebtoken::{decode, decode_header, jwk, Algorithm, DecodingKey, Validation}; const TOKEN: &str = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjFaNTdkX2k3VEU2S1RZNTdwS3pEeSJ9.eyJpc3MiOiJodHRwczovL2Rldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20vIiwic3ViIjoiNDNxbW44c281R3VFU0U1N0Fkb3BhN09jYTZXeVNidmRAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZGV2LWR1enlheWs0LmV1LmF1dGgwLmNvbS9hcGkvdjIvIiwiaWF0IjoxNjIzNTg1MzAxLCJleHAiOjE2MjM2NzE3MDEsImF6cCI6IjQzcW1uOHNvNUd1RVNFNTdBZG9wYTdPY2E2V3lTYnZkIiwic2NvcGUiOiJyZWFkOnVzZXJzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.0MpewU1GgvRqn4F8fK_-Eu70cUgWA5JJrdbJhkCPCxXP-8WwfI-qx1ZQg2a7nbjXICYAEl-Z6z4opgy-H5fn35wGP0wywDqZpqL35IPqx6d0wRvpPMjJM75zVXuIjk7cEhDr2kaf1LOY9auWUwGzPiDB_wM-R0uvUMeRPMfrHaVN73xhAuQWVjCRBHvNscYS5-i6qBQKDMsql87dwR72DgHzMlaC8NnaGREBC-xiSamesqhKPVyGzSkFSaF3ZKpGrSDapqmHkNW9RDBE3GQ9OHM33vzUdVKOjU1g9Leb9PDt0o1U4p3NQoGJPShQ6zgWSUEaqvUZTfkbpD_DoYDRxA"; const JWKS_REPLY: &str = r#" @@ -21,7 +22,11 @@ fn main() -> Result<(), Box> { match &j.algorithm { AlgorithmParameters::RSA(rsa) => { let decoding_key = DecodingKey::from_rsa_components(&rsa.n, &rsa.e).unwrap(); - let mut validation = Validation::new(j.common.algorithm.unwrap()); + + let mut validation = Validation::new( + Algorithm::from_str(j.common.key_algorithm.unwrap().to_string().as_str()) + .unwrap(), + ); validation.validate_exp = false; let decoded_token = decode::>(TOKEN, &decoding_key, &validation) diff --git a/src/algorithms.rs b/src/algorithms.rs index 06ad34a0..22782c75 100644 --- a/src/algorithms.rs +++ b/src/algorithms.rs @@ -84,6 +84,8 @@ impl Algorithm { #[cfg(test)] mod tests { + use crate::jwk::KeyAlgorithm; + use super::*; #[test] diff --git a/src/jwk.rs b/src/jwk.rs index 4ae1f02e..a5432f3a 100644 --- a/src/jwk.rs +++ b/src/jwk.rs @@ -1,11 +1,15 @@ #![allow(missing_docs)] -//! This crate contains types only for working JWK and JWK Sets -//! This is only meant to be used to deal with public JWK, not generate ones. -//! Most of the code in this file is taken from https://github.com/lawliet89/biscuit but -//! tweaked to remove the private bits as it's not the goal for this crate currently. -use crate::Algorithm; +///! This crate contains types only for working JWK and JWK Sets +///! This is only meant to be used to deal with public JWK, not generate ones. +///! Most of the code in this file is taken from https://github.com/lawliet89/biscuit but +/// tweaked to remove the private bits as it's not the goal for this crate currently. +///! +use crate::{ + errors::{self, Error, ErrorKind}, + Algorithm, +}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use std::fmt; +use std::{fmt, str::FromStr}; /// The intended usage of the public `KeyType`. This enum is serialized `untagged` #[derive(Clone, Debug, Eq, PartialEq, Hash)] @@ -141,6 +145,87 @@ impl<'de> Deserialize<'de> for KeyOperations { } } +/// The algorithms of the keys +#[allow(non_camel_case_types, clippy::upper_case_acronyms)] +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)] +pub enum KeyAlgorithm { + /// HMAC using SHA-256 + HS256, + /// HMAC using SHA-384 + HS384, + /// HMAC using SHA-512 + HS512, + + /// ECDSA using SHA-256 + ES256, + /// ECDSA using SHA-384 + ES384, + + /// RSASSA-PKCS1-v1_5 using SHA-256 + RS256, + /// RSASSA-PKCS1-v1_5 using SHA-384 + 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, + + /// Edwards-curve Digital Signature Algorithm (EdDSA) + EdDSA, + + /// RSAES-PKCS1-V1_5 + RSA1_5, + + /// RSAES-OAEP using SHA-1 + #[serde(rename = "RSA-OAEP")] + RSA_OAEP, + + /// RSAES-OAEP-256 using SHA-2 + #[serde(rename = "RSA-OAEP-256")] + RSA_OAEP_256, +} + +impl FromStr for KeyAlgorithm { + type Err = Error; + fn from_str(s: &str) -> errors::Result { + match s { + "HS256" => Ok(KeyAlgorithm::HS256), + "HS384" => Ok(KeyAlgorithm::HS384), + "HS512" => Ok(KeyAlgorithm::HS512), + "ES256" => Ok(KeyAlgorithm::ES256), + "ES384" => Ok(KeyAlgorithm::ES384), + "RS256" => Ok(KeyAlgorithm::RS256), + "RS384" => Ok(KeyAlgorithm::RS384), + "PS256" => Ok(KeyAlgorithm::PS256), + "PS384" => Ok(KeyAlgorithm::PS384), + "PS512" => Ok(KeyAlgorithm::PS512), + "RS512" => Ok(KeyAlgorithm::RS512), + "EdDSA" => Ok(KeyAlgorithm::EdDSA), + "RSA1_5" => Ok(KeyAlgorithm::RSA1_5), + "RSA-OAEP" => Ok(KeyAlgorithm::RSA_OAEP), + "RSA-OAEP-256" => Ok(KeyAlgorithm::RSA_OAEP_256), + _ => Err(ErrorKind::InvalidAlgorithmName.into()), + } + } +} + +impl fmt::Display for KeyAlgorithm { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl KeyAlgorithm { + fn to_algorithm(self) -> errors::Result { + Algorithm::from_str(self.to_string().as_str()) + } +} + /// Common JWK parameters #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default, Hash)] pub struct CommonParameters { @@ -158,9 +243,9 @@ pub struct CommonParameters { #[serde(rename = "key_ops", skip_serializing_if = "Option::is_none", default)] pub key_operations: Option>, - /// The algorithm intended for use with the key + /// The algorithm keys intended for use with the key. #[serde(rename = "alg", skip_serializing_if = "Option::is_none", default)] - pub algorithm: Option, + pub key_algorithm: Option, /// The case sensitive Key ID for the key #[serde(rename = "kid", skip_serializing_if = "Option::is_none", default)] @@ -326,6 +411,13 @@ pub struct Jwk { pub algorithm: AlgorithmParameters, } +impl Jwk { + /// Find whether the Algorithm is implmented and supported + pub fn is_supported(&self) -> bool { + self.common.key_algorithm.unwrap().to_algorithm().is_ok() + } +} + /// A JWK set #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct JwkSet { @@ -366,7 +458,9 @@ mod tests { assert_eq!(set.keys.len(), 1); let key = &set.keys[0]; assert_eq!(key.common.key_id, Some("abc123".to_string())); - assert_eq!(key.common.algorithm, Some(Algorithm::HS256)); + let algorithm = key.common.key_algorithm.unwrap().to_algorithm().unwrap(); + assert_eq!(algorithm, Algorithm::HS256); + match &key.algorithm { AlgorithmParameters::OctetKey(key) => { assert_eq!(key.key_type, OctetKeyType::Octet);