jwt_next/algorithm/rust_crypto/
asymmetric.rs

1use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
2use crate::error::Error;
3use crate::SEPARATOR;
4
5use base64::Engine;
6use digest::Digest;
7use p256::pkcs8::{DecodePrivateKey, DecodePublicKey};
8use rsa::pkcs1::DecodeRsaPrivateKey;
9use rsa::{RsaPrivateKey, RsaPublicKey};
10use signature::{DigestSigner, DigestVerifier, SignatureEncoding};
11
12#[derive(Clone, Debug)]
13pub enum VerifyingKey {
14    RS256(Box<rsa::pkcs1v15::VerifyingKey<sha2::Sha256>>),
15    RS384(Box<rsa::pkcs1v15::VerifyingKey<sha2::Sha384>>),
16    RS512(Box<rsa::pkcs1v15::VerifyingKey<sha2::Sha512>>),
17    EC256(Box<p256::ecdsa::VerifyingKey>),
18    EC384(Box<p384::ecdsa::VerifyingKey>),
19}
20
21impl VerifyingKey {
22    pub fn from_ec256(key: p256::PublicKey) -> Self {
23        Self::EC256(p256::ecdsa::VerifyingKey::from(key).into())
24    }
25
26    pub fn from_ec384(key: p384::PublicKey) -> Self {
27        Self::EC384(p384::ecdsa::VerifyingKey::from(key).into())
28    }
29
30    pub fn from_rsa256(key: RsaPublicKey) -> Self {
31        Self::RS256(rsa::pkcs1v15::VerifyingKey::new(key).into())
32    }
33
34    pub fn from_rsa384(key: RsaPublicKey) -> Self {
35        Self::RS384(rsa::pkcs1v15::VerifyingKey::new(key).into())
36    }
37
38    pub fn from_rsa512(key: RsaPublicKey) -> Self {
39        Self::RS512(rsa::pkcs1v15::VerifyingKey::new(key).into())
40    }
41}
42
43#[derive(Clone, Debug)]
44pub enum SigningKey {
45    RS256(Box<rsa::pkcs1v15::SigningKey<sha2::Sha256>>),
46    RS384(Box<rsa::pkcs1v15::SigningKey<sha2::Sha384>>),
47    RS512(Box<rsa::pkcs1v15::SigningKey<sha2::Sha512>>),
48    EC256(Box<p256::ecdsa::SigningKey>),
49    EC384(Box<p384::ecdsa::SigningKey>),
50}
51
52impl SigningKey {
53    pub fn from_ec256(key: p256::SecretKey) -> Self {
54        Self::EC256(p256::ecdsa::SigningKey::from(key).into())
55    }
56
57    pub fn from_ec384(key: p384::SecretKey) -> Self {
58        Self::EC384(p384::ecdsa::SigningKey::from(key).into())
59    }
60
61    pub fn from_rsa256(key: RsaPrivateKey) -> Self {
62        Self::RS256(rsa::pkcs1v15::SigningKey::new(key).into())
63    }
64
65    pub fn from_rsa384(key: RsaPrivateKey) -> Self {
66        Self::RS384(rsa::pkcs1v15::SigningKey::new(key).into())
67    }
68
69    pub fn from_rsa512(key: RsaPrivateKey) -> Self {
70        Self::RS512(rsa::pkcs1v15::SigningKey::new(key).into())
71    }
72}
73
74pub use ::{digest, ecdsa, p256, rsa, signature};
75
76#[derive(Clone, Debug)]
77pub enum PublicKey {
78    RSA(Box<RsaPublicKey>),
79    EC256(Box<p256::PublicKey>),
80    EC384(Box<p384::PublicKey>),
81}
82
83impl PublicKey {
84    pub fn from_pem_bytes(encoded: &[u8]) -> Result<Self, Error> {
85        Self::from_pem(std::str::from_utf8(encoded).map_err(|_| Error::InvalidKey)?)
86    }
87
88    pub fn from_pem(encoded: &str) -> Result<Self, Error> {
89        if let Ok(ec) = encoded.parse::<p384::PublicKey>() {
90            Ok(PublicKey::EC384(ec.into()))
91        } else if let Ok(ec) = encoded.parse::<p256::PublicKey>() {
92            Ok(PublicKey::EC256(ec.into()))
93        } else if let Ok(rsa) = rsa::RsaPublicKey::from_public_key_pem(encoded) {
94            Ok(PublicKey::RSA(rsa.into()))
95        } else {
96            Err(Error::InvalidKey)
97        }
98    }
99
100    pub fn into_rsa(self) -> Result<RsaPublicKey, Self> {
101        match self {
102            PublicKey::RSA(rsa) => Ok(*rsa),
103            _ => Err(self),
104        }
105    }
106
107    pub fn into_ec256(self) -> Result<p256::PublicKey, Self> {
108        match self {
109            PublicKey::EC256(ec) => Ok(*ec),
110            _ => Err(self),
111        }
112    }
113
114    pub fn into_ec384(self) -> Result<p384::PublicKey, Self> {
115        match self {
116            PublicKey::EC384(ec) => Ok(*ec),
117            _ => Err(self),
118        }
119    }
120}
121
122#[derive(Clone, Debug)]
123pub enum PrivateKey {
124    RSA(Box<RsaPrivateKey>),
125    EC256(Box<p256::SecretKey>),
126    EC384(Box<p384::SecretKey>),
127}
128
129impl PrivateKey {
130    pub fn from_pem_bytes(encoded: &[u8]) -> Result<Self, Error> {
131        Self::from_pem(std::str::from_utf8(encoded).map_err(|_| Error::InvalidKey)?)
132    }
133
134    pub fn from_pem(pem: &str) -> Result<Self, Error> {
135        if let Ok(ec) = pem.parse::<p384::SecretKey>() {
136            Ok(PrivateKey::EC384(ec.into()))
137        } else if let Ok(ec) = pem.parse::<p256::SecretKey>() {
138            Ok(PrivateKey::EC256(ec.into()))
139        } else if let Ok(rsa) = rsa::RsaPrivateKey::from_pkcs8_pem(pem) {
140            Ok(PrivateKey::RSA(rsa.into()))
141        } else if let Ok(rsa) = rsa::RsaPrivateKey::from_pkcs1_pem(pem) {
142            Ok(PrivateKey::RSA(rsa.into()))
143        } else {
144            Err(Error::InvalidKey)
145        }
146    }
147
148    pub fn into_rsa(self) -> Result<RsaPrivateKey, Self> {
149        match self {
150            PrivateKey::RSA(rsa) => Ok(*rsa),
151            _ => Err(self),
152        }
153    }
154
155    pub fn into_ec256(self) -> Result<p256::SecretKey, Self> {
156        match self {
157            PrivateKey::EC256(ec) => Ok(*ec),
158            _ => Err(self),
159        }
160    }
161
162    pub fn into_ec384(self) -> Result<p384::SecretKey, Self> {
163        match self {
164            PrivateKey::EC384(ec) => Ok(*ec),
165            _ => Err(self),
166        }
167    }
168}
169
170pub struct AsymmetricKeyWithDigest<K> {
171    key: K,
172}
173
174impl<K> AsymmetricKeyWithDigest<K> {
175    pub fn new(key: K) -> Self {
176        Self { key }
177    }
178}
179
180impl SigningAlgorithm for AsymmetricKeyWithDigest<SigningKey> {
181    fn algorithm_type(&self) -> AlgorithmType {
182        match self.key {
183            SigningKey::RS256(_) => AlgorithmType::Rs256,
184            SigningKey::RS384(_) => AlgorithmType::Rs384,
185            SigningKey::RS512(_) => AlgorithmType::Rs512,
186            SigningKey::EC256(_) => AlgorithmType::Es256,
187            SigningKey::EC384(_) => AlgorithmType::Es384,
188        }
189    }
190
191    fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
192        macro_rules! short_hand {
193            ($key:ident, $hash:ty, $sig:ty) => {
194                let mut digest = <$hash>::new();
195
196                digest.update(header.as_bytes());
197                digest.update(SEPARATOR.as_bytes());
198                digest.update(claims.as_bytes());
199
200                let signed: $sig = $key.try_sign_digest(digest)?;
201
202                return Ok(
203                    base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(signed.to_bytes())
204                );
205            };
206        }
207
208        match &self.key {
209            SigningKey::RS256(key) => {
210                short_hand!(key, sha2::Sha256, rsa::pkcs1v15::Signature);
211            }
212            SigningKey::RS384(key) => {
213                short_hand!(key, sha2::Sha384, rsa::pkcs1v15::Signature);
214            }
215            SigningKey::RS512(key) => {
216                short_hand!(key, sha2::Sha512, rsa::pkcs1v15::Signature);
217            }
218            SigningKey::EC256(key) => {
219                short_hand!(key, sha2::Sha256, p256::ecdsa::Signature);
220            }
221            SigningKey::EC384(key) => {
222                short_hand!(key, sha2::Sha384, p384::ecdsa::Signature);
223            }
224        }
225    }
226}
227
228impl VerifyingAlgorithm for AsymmetricKeyWithDigest<VerifyingKey> {
229    fn algorithm_type(&self) -> AlgorithmType {
230        match self.key {
231            VerifyingKey::RS256(_) => AlgorithmType::Rs256,
232            VerifyingKey::RS384(_) => AlgorithmType::Rs384,
233            VerifyingKey::RS512(_) => AlgorithmType::Rs512,
234            VerifyingKey::EC256(_) => AlgorithmType::Es256,
235            VerifyingKey::EC384(_) => AlgorithmType::Es384,
236        }
237    }
238
239    fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
240        macro_rules! short_hand {
241            ($key:ident, $hash:ty, $sig:ty) => {
242                let mut digest = <$hash>::new();
243
244                digest.update(header.as_bytes());
245                digest.update(SEPARATOR.as_bytes());
246                digest.update(claims.as_bytes());
247
248                let signature = <$sig>::try_from(signature).map_err(|_| Error::InvalidSignature)?;
249
250                return Ok($key.verify_digest(digest, &signature).is_ok());
251            };
252        }
253
254        match &self.key {
255            VerifyingKey::RS256(key) => {
256                short_hand!(key, sha2::Sha256, rsa::pkcs1v15::Signature);
257            }
258            VerifyingKey::RS384(key) => {
259                short_hand!(key, sha2::Sha384, rsa::pkcs1v15::Signature);
260            }
261            VerifyingKey::RS512(key) => {
262                short_hand!(key, sha2::Sha512, rsa::pkcs1v15::Signature);
263            }
264            VerifyingKey::EC256(key) => {
265                short_hand!(key, sha2::Sha256, p256::ecdsa::Signature);
266            }
267            VerifyingKey::EC384(key) => {
268                short_hand!(key, sha2::Sha384, p384::ecdsa::Signature);
269            }
270        }
271    }
272}
273
274#[cfg(test)]
275mod tests {
276    use super::*;
277
278    use crate::algorithm::AlgorithmType::*;
279    use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
280    use crate::error::Error;
281    use crate::header::PrecomputedAlgorithmOnlyHeader as AlgOnly;
282    use crate::ToBase64;
283
284    // {"sub":"1234567890","name":"John Doe","admin":true}
285    const CLAIMS: &str = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
286
287    const RS256_SIGNATURE: &str =
288    "cQsAHF2jHvPGFP5zTD8BgoJrnzEx6JNQCpupebWLFnOc2r_punDDTylI6Ia4JZNkvy2dQP-7W-DEbFQ3oaarHsDndqUgwf9iYlDQxz4Rr2nEZX1FX0-FMEgFPeQpdwveCgjtTYUbVy37ijUySN_rW-xZTrsh_Ug-ica8t-zHRIw";
289
290    const PREGENERATED_ES256_SIGNATURE: &str =
291        "6SgeIURSNz_qFcxsKQOWZmi_ALiBctj_ZINvce4AOa-OQn9QI6lh8P78FTZx5LQtOleF3XeBlGIAdYms_VPecA";
292
293    #[test]
294    fn rs256_sign() -> Result<(), Error> {
295        let key = PrivateKey::from_pem_bytes(include_bytes!("../../../test/rs256-private.pem"))?;
296        let signer = AsymmetricKeyWithDigest::new(SigningKey::from_rsa256(key.into_rsa().unwrap()));
297        let result = signer.sign(&AlgOnly(Rs256).to_base64()?, CLAIMS)?;
298        assert_eq!(result, RS256_SIGNATURE);
299        Ok(())
300    }
301
302    #[test]
303    fn rs256_verify() -> Result<(), Error> {
304        let key = PublicKey::from_pem_bytes(include_bytes!("../../../test/rs256-public.pem"))?;
305        let verifier =
306            AsymmetricKeyWithDigest::new(VerifyingKey::from_rsa256(key.into_rsa().unwrap()));
307        assert!(
308            verifier.verify(&AlgOnly(Rs256).to_base64()?, CLAIMS, RS256_SIGNATURE)?,
309            "signature should be valid"
310        );
311        Ok(())
312    }
313
314    #[test]
315    fn es256_sign() -> Result<(), Error> {
316        let key = PrivateKey::from_pem_bytes(include_bytes!("../../../test/es256-private.pem"))?;
317        let signer =
318            AsymmetricKeyWithDigest::new(SigningKey::from_ec256(key.into_ec256().unwrap()));
319        let signature = signer.sign(&AlgOnly(Es256).to_base64()?, CLAIMS)?;
320
321        let key = PublicKey::from_pem_bytes(include_bytes!("../../../test/es256-public.pem"))?;
322        let verifier =
323            AsymmetricKeyWithDigest::new(VerifyingKey::from_ec256(key.into_ec256().unwrap()));
324        assert!(
325            verifier.verify(&AlgOnly(Es256).to_base64()?, CLAIMS, &signature)?,
326            "signature should be valid"
327        );
328        Ok(())
329    }
330
331    #[test]
332    fn es256_verify() -> Result<(), Error> {
333        let key = PublicKey::from_pem_bytes(include_bytes!("../../../test/es256-public.pem"))?;
334        let verifier =
335            AsymmetricKeyWithDigest::new(VerifyingKey::from_ec256(key.into_ec256().unwrap()));
336        assert!(
337            verifier.verify(
338                &AlgOnly(Es256).to_base64()?,
339                CLAIMS,
340                PREGENERATED_ES256_SIGNATURE
341            )?,
342            "signature should be valid"
343        );
344
345        Ok(())
346    }
347
348    #[test]
349    fn genric_public_key_parse() -> Result<(), Error> {
350        match PublicKey::from_pem_bytes(include_bytes!("../../../test/rs256-public.pem")) {
351            Ok(PublicKey::RSA(_)) => {}
352            _ => panic!("invalid rsa key"),
353        }
354
355        match PublicKey::from_pem_bytes(include_bytes!("../../../test/es256-public.pem")) {
356            Ok(PublicKey::EC256(_)) => {}
357            _ => panic!("invalid ec key"),
358        }
359
360        Ok(())
361    }
362
363    #[test]
364    fn genric_private_key_parse() -> Result<(), Error> {
365        match PrivateKey::from_pem_bytes(include_bytes!("../../../test/rs256-private.pem")) {
366            Ok(PrivateKey::RSA(_)) => {}
367            _ => panic!("invalid rsa key"),
368        }
369
370        match PrivateKey::from_pem_bytes(include_bytes!("../../../test/es256-private.pem")) {
371            Ok(PrivateKey::EC256(_)) => {}
372            _ => panic!("invalid ec key"),
373        }
374
375        Ok(())
376    }
377}