1 use ring::constant_time::verify_slices_are_equal;
2 use ring::{hmac, signature};
3
4 use crate::algorithms::Algorithm;
5 use crate::decoding::{DecodingKey, DecodingKeyKind};
6 use crate::encoding::EncodingKey;
7 use crate::errors::Result;
8 use crate::serialization::{b64_decode, b64_encode};
9
10 pub(crate) mod ecdsa;
11 pub(crate) mod rsa;
12
13 /// The actual HS signing + encoding
14 /// Could be in its own file to match RSA/EC but it's 2 lines...
sign_hmac(alg: hmac::Algorithm, key: &[u8], message: &str) -> Result<String>15 pub(crate) fn sign_hmac(alg: hmac::Algorithm, key: &[u8], message: &str) -> Result<String> {
16 let digest = hmac::sign(&hmac::Key::new(alg, key), message.as_bytes());
17 Ok(b64_encode(digest.as_ref()))
18 }
19
20 /// Take the payload of a JWT, sign it using the algorithm given and return
21 /// the base64 url safe encoded of the result.
22 ///
23 /// If you just want to encode a JWT, use `encode` instead.
sign(message: &str, key: &EncodingKey, algorithm: Algorithm) -> Result<String>24 pub fn sign(message: &str, key: &EncodingKey, algorithm: Algorithm) -> Result<String> {
25 match algorithm {
26 Algorithm::HS256 => sign_hmac(hmac::HMAC_SHA256, key.inner(), message),
27 Algorithm::HS384 => sign_hmac(hmac::HMAC_SHA384, key.inner(), message),
28 Algorithm::HS512 => sign_hmac(hmac::HMAC_SHA512, key.inner(), message),
29
30 Algorithm::ES256 | Algorithm::ES384 => {
31 ecdsa::sign(ecdsa::alg_to_ec_signing(algorithm), key.inner(), message)
32 }
33
34 Algorithm::RS256
35 | Algorithm::RS384
36 | Algorithm::RS512
37 | Algorithm::PS256
38 | Algorithm::PS384
39 | Algorithm::PS512 => rsa::sign(rsa::alg_to_rsa_signing(algorithm), key.inner(), message),
40 }
41 }
42
43 /// See Ring docs for more details
verify_ring( alg: &'static dyn signature::VerificationAlgorithm, signature: &str, message: &str, key: &[u8], ) -> Result<bool>44 fn verify_ring(
45 alg: &'static dyn signature::VerificationAlgorithm,
46 signature: &str,
47 message: &str,
48 key: &[u8],
49 ) -> Result<bool> {
50 let signature_bytes = b64_decode(signature)?;
51 let public_key = signature::UnparsedPublicKey::new(alg, key);
52 let res = public_key.verify(message.as_bytes(), &signature_bytes);
53
54 Ok(res.is_ok())
55 }
56
57 /// Compares the signature given with a re-computed signature for HMAC or using the public key
58 /// for RSA/EC.
59 ///
60 /// If you just want to decode a JWT, use `decode` instead.
61 ///
62 /// `signature` is the signature part of a jwt (text after the second '.')
63 ///
64 /// `message` is base64(header) + "." + base64(claims)
verify( signature: &str, message: &str, key: &DecodingKey, algorithm: Algorithm, ) -> Result<bool>65 pub fn verify(
66 signature: &str,
67 message: &str,
68 key: &DecodingKey,
69 algorithm: Algorithm,
70 ) -> Result<bool> {
71 match algorithm {
72 Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => {
73 // we just re-sign the message with the key and compare if they are equal
74 let signed = sign(message, &EncodingKey::from_secret(key.as_bytes()), algorithm)?;
75 Ok(verify_slices_are_equal(signature.as_ref(), signed.as_ref()).is_ok())
76 }
77 Algorithm::ES256 | Algorithm::ES384 => verify_ring(
78 ecdsa::alg_to_ec_verification(algorithm),
79 signature,
80 message,
81 key.as_bytes(),
82 ),
83 Algorithm::RS256
84 | Algorithm::RS384
85 | Algorithm::RS512
86 | Algorithm::PS256
87 | Algorithm::PS384
88 | Algorithm::PS512 => {
89 let alg = rsa::alg_to_rsa_parameters(algorithm);
90 match &key.kind {
91 DecodingKeyKind::SecretOrDer(bytes) => verify_ring(alg, signature, message, bytes),
92 DecodingKeyKind::RsaModulusExponent { n, e } => {
93 rsa::verify_from_components(alg, signature, message, (n, e))
94 }
95 }
96 }
97 }
98 }
99