More refactoring in the crypto mod
This commit is contained in:
parent
1f6d0ffb2c
commit
8e4757cb1d
|
@ -1,17 +1,27 @@
|
|||
use ring::{rand, signature};
|
||||
|
||||
use crate::algorithms::Algorithm;
|
||||
use crate::errors::Result;
|
||||
use crate::pem_decoder::PemEncodedKey;
|
||||
use crate::serialization::b64_encode;
|
||||
use crate::algorithms::Algorithm;
|
||||
|
||||
|
||||
/// Only used internally when validating EC, to map from our enum to the Ring EcdsaVerificationAlgorithm structs.
|
||||
pub(crate) fn alg_to_ec_verification(alg: Algorithm) -> &'static signature::EcdsaVerificationAlgorithm {
|
||||
pub(crate) fn alg_to_ec_verification(
|
||||
alg: Algorithm,
|
||||
) -> &'static signature::EcdsaVerificationAlgorithm {
|
||||
match alg {
|
||||
Algorithm::ES256 => &signature::ECDSA_P256_SHA256_FIXED,
|
||||
Algorithm::ES384 => &signature::ECDSA_P384_SHA384_FIXED,
|
||||
_ => unreachable!("Tried to get EC signature for a non-EC algorithm"),
|
||||
_ => unreachable!("Tried to get EC alg for a non-EC algorithm"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Only used internally when signing EC, to map from our enum to the Ring EcdsaVerificationAlgorithm structs.
|
||||
pub(crate) fn alg_to_ec_signing(alg: Algorithm) -> &'static signature::EcdsaSigningAlgorithm {
|
||||
match alg {
|
||||
Algorithm::ES256 => &signature::ECDSA_P256_SHA256_FIXED_SIGNING,
|
||||
Algorithm::ES384 => &signature::ECDSA_P384_SHA384_FIXED_SIGNING,
|
||||
_ => unreachable!("Tried to get EC alg for a non-EC algorithm"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,19 +27,33 @@ pub fn sign(message: &str, key: &[u8], algorithm: Algorithm) -> Result<String> {
|
|||
Algorithm::HS384 => sign_hmac(hmac::HMAC_SHA384, key, message),
|
||||
Algorithm::HS512 => sign_hmac(hmac::HMAC_SHA512, key, message),
|
||||
|
||||
Algorithm::ES256 => ecdsa::sign(&signature::ECDSA_P256_SHA256_FIXED_SIGNING, key, message),
|
||||
Algorithm::ES384 => ecdsa::sign(&signature::ECDSA_P384_SHA384_FIXED_SIGNING, key, message),
|
||||
Algorithm::ES256 | Algorithm::ES384 => {
|
||||
ecdsa::sign(ecdsa::alg_to_ec_signing(algorithm), key, message)
|
||||
}
|
||||
|
||||
Algorithm::RS256 => rsa::sign(&signature::RSA_PKCS1_SHA256, key, message),
|
||||
Algorithm::RS384 => rsa::sign(&signature::RSA_PKCS1_SHA384, key, message),
|
||||
Algorithm::RS512 => rsa::sign(&signature::RSA_PKCS1_SHA512, key, message),
|
||||
|
||||
Algorithm::PS256 => rsa::sign(&signature::RSA_PSS_SHA256, key, message),
|
||||
Algorithm::PS384 => rsa::sign(&signature::RSA_PSS_SHA384, key, message),
|
||||
Algorithm::PS512 => rsa::sign(&signature::RSA_PSS_SHA512, key, message),
|
||||
Algorithm::RS256
|
||||
| Algorithm::RS384
|
||||
| Algorithm::RS512
|
||||
| Algorithm::PS256
|
||||
| Algorithm::PS384
|
||||
| Algorithm::PS512 => rsa::sign(rsa::alg_to_rsa_signing(algorithm), key, message),
|
||||
}
|
||||
}
|
||||
|
||||
/// See Ring docs for more details
|
||||
fn verify_ring(
|
||||
alg: &'static dyn signature::VerificationAlgorithm,
|
||||
signature: &str,
|
||||
message: &str,
|
||||
key: &[u8],
|
||||
) -> Result<bool> {
|
||||
let signature_bytes = b64_decode(signature)?;
|
||||
let public_key = signature::UnparsedPublicKey::new(alg, key);
|
||||
let res = public_key.verify(message.as_bytes(), &signature_bytes);
|
||||
|
||||
Ok(res.is_ok())
|
||||
}
|
||||
|
||||
/// Compares the signature given with a re-computed signature for HMAC or using the public key
|
||||
/// for RSA/EC.
|
||||
///
|
||||
|
@ -59,31 +73,30 @@ pub fn verify(signature: &str, message: &str, key: &[u8], algorithm: Algorithm)
|
|||
}
|
||||
Algorithm::ES256 | Algorithm::ES384 => {
|
||||
let pem_key = PemEncodedKey::new(key)?;
|
||||
verify_ring(ecdsa::alg_to_ec_verification(algorithm), signature, message, pem_key.as_ec_public_key()?)
|
||||
verify_ring(
|
||||
ecdsa::alg_to_ec_verification(algorithm),
|
||||
signature,
|
||||
message,
|
||||
pem_key.as_ec_public_key()?,
|
||||
)
|
||||
}
|
||||
// only RSAs left
|
||||
_ => {
|
||||
Algorithm::RS256
|
||||
| Algorithm::RS384
|
||||
| Algorithm::RS512
|
||||
| Algorithm::PS256
|
||||
| Algorithm::PS384
|
||||
| Algorithm::PS512 => {
|
||||
let pem_key = PemEncodedKey::new(key)?;
|
||||
verify_ring(rsa::alg_to_rsa_parameters(algorithm), signature, message, pem_key.as_rsa_key()?)
|
||||
},
|
||||
verify_ring(
|
||||
rsa::alg_to_rsa_parameters(algorithm),
|
||||
signature,
|
||||
message,
|
||||
pem_key.as_rsa_key()?,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// See Ring docs for more details
|
||||
fn verify_ring(
|
||||
alg: &'static dyn signature::VerificationAlgorithm,
|
||||
signature: &str,
|
||||
message: &str,
|
||||
key: &[u8],
|
||||
) -> Result<bool> {
|
||||
let signature_bytes = b64_decode(signature)?;
|
||||
let public_key = signature::UnparsedPublicKey::new(alg, key);
|
||||
let res = public_key.verify(message.as_bytes(), &signature_bytes);
|
||||
|
||||
Ok(res.is_ok())
|
||||
}
|
||||
|
||||
/// Verify the signature given using the (n, e) components of a RSA public key.
|
||||
///
|
||||
/// `signature` is the signature part of a jwt (text after the second '.')
|
||||
|
@ -96,5 +109,5 @@ pub fn verify_rsa_components(
|
|||
alg: Algorithm,
|
||||
) -> Result<bool> {
|
||||
let signature_bytes = b64_decode(signature)?;
|
||||
rsa::verify_from_components(&signature_bytes, message, components, alg)
|
||||
rsa::verify_from_components(rsa::alg_to_rsa_parameters(alg), &signature_bytes, message, components)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use ring::{rand, signature};
|
||||
use simple_asn1::BigUint;
|
||||
|
||||
use crate::algorithms::Algorithm;
|
||||
use crate::errors::{ErrorKind, Result};
|
||||
use crate::pem_decoder::PemEncodedKey;
|
||||
use crate::serialization::{b64_encode, b64_decode};
|
||||
use crate::algorithms::Algorithm;
|
||||
|
||||
use crate::serialization::{b64_decode, b64_encode};
|
||||
|
||||
/// Only used internally when validating RSA, to map from our enum to the Ring param structs.
|
||||
pub(crate) fn alg_to_rsa_parameters(alg: Algorithm) -> &'static signature::RsaParameters {
|
||||
|
@ -20,6 +19,18 @@ pub(crate) fn alg_to_rsa_parameters(alg: Algorithm) -> &'static signature::RsaPa
|
|||
}
|
||||
}
|
||||
|
||||
/// Only used internally when signing with RSA, to map from our enum to the Ring signing structs.
|
||||
pub(crate) fn alg_to_rsa_signing(alg: Algorithm) -> &'static dyn signature::RsaEncoding {
|
||||
match alg {
|
||||
Algorithm::RS256 => &signature::RSA_PKCS1_SHA256,
|
||||
Algorithm::RS384 => &signature::RSA_PKCS1_SHA384,
|
||||
Algorithm::RS512 => &signature::RSA_PKCS1_SHA512,
|
||||
Algorithm::PS256 => &signature::RSA_PSS_SHA256,
|
||||
Algorithm::PS384 => &signature::RSA_PSS_SHA384,
|
||||
Algorithm::PS512 => &signature::RSA_PSS_SHA512,
|
||||
_ => unreachable!("Tried to get RSA signature for a non-rsa algorithm"),
|
||||
}
|
||||
}
|
||||
|
||||
/// The actual RSA signing + encoding
|
||||
/// Taken from Ring doc https://briansmith.org/rustdoc/ring/signature/index.html
|
||||
|
@ -42,13 +53,14 @@ pub(crate) fn sign(
|
|||
}
|
||||
|
||||
pub(crate) fn verify_from_components(
|
||||
alg: &'static signature::RsaParameters,
|
||||
signature_bytes: &[u8],
|
||||
message: &str,
|
||||
components: (&str, &str),
|
||||
alg: Algorithm) -> Result<bool> {
|
||||
) -> Result<bool> {
|
||||
let n = BigUint::from_bytes_be(&b64_decode(components.0)?).to_bytes_be();
|
||||
let e = BigUint::from_bytes_be(&b64_decode(components.1)?).to_bytes_be();
|
||||
let pubkey = signature::RsaPublicKeyComponents { n, e };
|
||||
let res = pubkey.verify(alg_to_rsa_parameters(alg), message.as_ref(), &signature_bytes);
|
||||
let res = pubkey.verify(alg, message.as_ref(), &signature_bytes);
|
||||
Ok(res.is_ok())
|
||||
}
|
||||
|
|
|
@ -118,8 +118,8 @@ pub fn dangerous_unsafe_decode<T: DeserializeOwned>(token: &str) -> Result<Token
|
|||
Ok(TokenData { header, claims: decoded_claims })
|
||||
}
|
||||
|
||||
/// Decode a token and return the Header. This is not doing any kind of validation: it is meant to be
|
||||
/// used when you don't know which `alg` the token is using and want to find out.
|
||||
/// Decode a token and return the Header. This is not doing any kind of validation: it only splits
|
||||
/// on the `.` and return the base64 decoded header.
|
||||
///
|
||||
/// If the token has an invalid format, it will return an error.
|
||||
///
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::collections::HashSet;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use serde_json::map::Map;
|
||||
use serde_json::{from_value, Value};
|
||||
|
@ -164,7 +164,7 @@ mod tests {
|
|||
use serde_json::map::Map;
|
||||
use serde_json::to_value;
|
||||
|
||||
use super::{validate, Validation, get_current_timestamp};
|
||||
use super::{get_current_timestamp, validate, Validation};
|
||||
|
||||
use crate::errors::ErrorKind;
|
||||
|
||||
|
|
Loading…
Reference in New Issue