1use crate::api::model::{SigningAlgorithm, SigningKeyLength};
5use crate::model::claims::JWTClaims;
6use jwt_simple::algorithms::{
7 ECDSAP256KeyPairLike, ECDSAP384KeyPairLike, ES256KeyPair, ES384KeyPair, HS256Key, HS384Key,
8 HS512Key, MACLike, RS256KeyPair, RS384KeyPair, RS512KeyPair, RSAKeyPairLike,
9};
10use jwt_simple::reexports::{anyhow, rand};
11use p256::ecdsa::signature::RandomizedDigestSigner;
12
13#[non_exhaustive]
14#[derive(Debug, thiserror::Error)]
15pub enum GeneratorError {
17 #[error("Invalid algorithm {0:?}")]
18 InvalidAlgorithm(String),
20
21 #[error("Error generating the jwt: {0}.")]
22 SigningError(anyhow::Error),
24
25 #[error("Error parsing key: {0}. Key must be provided in pkcs#8 format.")]
26 KeyParsing(anyhow::Error),
28
29 #[error("Error serializing values: {0}.")]
30 Serialization(#[from] serde_json::Error),
32}
33
34trait JwtAlgorithm {
35 fn alg(&self) -> &'static str;
36 fn sign(&self, message: &str) -> Result<Vec<u8>, GeneratorError>;
37
38 fn jwt(&self, claims: JWTClaims) -> Result<String, GeneratorError> {
39 let mut claims = claims;
40 claims.headers.insert("alg".to_string(), self.alg().into());
41 claims.headers.insert("typ".to_string(), "JWT".into());
42 let headers = base64(serde_json::to_vec(&claims.headers)?);
43 let body = base64(serde_json::to_vec(&claims.claims)?);
44
45 let message = format!("{headers}.{body}");
46
47 let signature = base64(self.sign(message.as_str())?);
48
49 Ok(format!("{message}.{signature}"))
50 }
51}
52
53fn base64<D: AsRef<[u8]>>(data: D) -> String {
54 base64::encode_config(data.as_ref(), base64::URL_SAFE_NO_PAD)
55}
56
57macro_rules! jwt_rsa {
58 ($type_name:ty) => {
59 impl JwtAlgorithm for $type_name {
60 fn alg(&self) -> &'static str {
61 Self::jwt_alg_name()
62 }
63
64 fn sign(&self, message: &str) -> Result<Vec<u8>, GeneratorError> {
65 let digest = Self::hash(message.as_bytes());
66 let mut rng = rand::thread_rng();
67 self.key_pair()
68 .as_ref()
69 .sign_blinded(&mut rng, self.padding_scheme(), &digest)
70 .map_err(|e| GeneratorError::SigningError(e.into()))
71 }
72 }
73 };
74}
75
76jwt_rsa!(RS256KeyPair);
77jwt_rsa!(RS384KeyPair);
78jwt_rsa!(RS512KeyPair);
79
80macro_rules! jwt_hmac {
81 ($type_name:ty) => {
82 impl JwtAlgorithm for $type_name {
83 fn alg(&self) -> &'static str {
84 Self::jwt_alg_name()
85 }
86
87 fn sign(&self, message: &str) -> Result<Vec<u8>, GeneratorError> {
88 Ok(self.authentication_tag(message))
89 }
90 }
91 };
92}
93
94jwt_hmac!(HS256Key);
95jwt_hmac!(HS384Key);
96jwt_hmac!(HS512Key);
97
98impl JwtAlgorithm for ES256KeyPair {
99 fn alg(&self) -> &'static str {
100 Self::jwt_alg_name()
101 }
102
103 fn sign(&self, message: &str) -> Result<Vec<u8>, GeneratorError> {
104 let mut digest = hmac_sha256::Hash::new();
105 digest.update(message.as_bytes());
106 let mut rng = rand::thread_rng();
107 let signature: p256::ecdsa::Signature = self
108 .key_pair()
109 .as_ref()
110 .sign_digest_with_rng(&mut rng, digest);
111
112 Ok(signature.to_vec())
113 }
114}
115
116impl JwtAlgorithm for ES384KeyPair {
117 fn alg(&self) -> &'static str {
118 Self::jwt_alg_name()
119 }
120
121 fn sign(&self, message: &str) -> Result<Vec<u8>, GeneratorError> {
122 let mut digest = hmac_sha512::sha384::Hash::new();
123 digest.update(message.as_bytes());
124 let mut rng = rand::thread_rng();
125 let signature: p384::ecdsa::Signature = self
126 .key_pair()
127 .as_ref()
128 .sign_digest_with_rng(&mut rng, digest);
129
130 Ok(signature.to_vec())
131 }
132}
133
134macro_rules! from_pem {
135 ($type_name:ty, $key:expr) => {{
136 Box::new(<$type_name>::from_pem($key).map_err(|e| GeneratorError::KeyParsing(e))?)
137 }};
138}
139
140macro_rules! from_bytes {
141 ($type_name:ty, $key:expr) => {{
142 Box::new(<$type_name>::from_bytes($key.as_bytes()))
143 }};
144}
145
146pub struct JwtGenerator {
148 alg: Box<dyn JwtAlgorithm>,
149}
150
151impl JwtGenerator {
152 pub fn new(
154 algorithm: SigningAlgorithm,
155 length: SigningKeyLength,
156 key: &str,
157 ) -> Result<Self, GeneratorError> {
158 let alg: Box<dyn JwtAlgorithm> = match (&algorithm, &length) {
159 (SigningAlgorithm::Hmac, SigningKeyLength::Len256) => {
160 from_bytes!(HS256Key, key)
161 }
162 (SigningAlgorithm::Hmac, SigningKeyLength::Len384) => {
163 from_bytes!(HS384Key, key)
164 }
165 (SigningAlgorithm::Hmac, SigningKeyLength::Len512) => {
166 from_bytes!(HS512Key, key)
167 }
168 (SigningAlgorithm::Rsa, SigningKeyLength::Len256) => {
169 from_pem!(RS256KeyPair, key)
170 }
171 (SigningAlgorithm::Rsa, SigningKeyLength::Len384) => {
172 from_pem!(RS384KeyPair, key)
173 }
174 (SigningAlgorithm::Rsa, SigningKeyLength::Len512) => {
175 from_pem!(RS512KeyPair, key)
176 }
177 (SigningAlgorithm::Es, SigningKeyLength::Len256) => {
178 from_pem!(ES256KeyPair, key)
179 }
180 (SigningAlgorithm::Es, SigningKeyLength::Len384) => {
181 from_pem!(ES384KeyPair, key)
182 }
183 (SigningAlgorithm::Es, SigningKeyLength::Len512) => {
184 return Err(GeneratorError::InvalidAlgorithm("ES512".to_string()));
185 }
186 };
187
188 Ok(Self { alg })
189 }
190
191 pub fn jwt(&self, claims: JWTClaims) -> Result<String, GeneratorError> {
193 self.alg.jwt(claims)
194 }
195}
196
197#[cfg(test)]
198mod test {
199 type DynamicSimpleClaims = jwt_simple::claims::JWTClaims<HashMap<String, Value>>;
200 use crate::api::model::{JWTClaims, SigningAlgorithm, SigningKeyLength};
201 use crate::generator::{GeneratorError, JwtGenerator};
202 use chrono::{TimeZone, Utc};
203 use jwt_simple::algorithms::{
204 ECDSAP256PublicKeyLike, ECDSAP384PublicKeyLike, ES256PublicKey, ES384PublicKey, HS256Key,
205 HS384Key, HS512Key, MACLike, RS256PublicKey, RS384PublicKey, RS512PublicKey,
206 RSAPublicKeyLike,
207 };
208 use serde_json::Value;
209 use std::collections::HashMap;
210
211 const TEST_EC_PRIVATE_KEY: &str = "-----BEGIN PRIVATE KEY-----
215MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyzC5ONgTRTCKUko8
216elZbv5YjMntLt/exJgdjmm1l7IWhRANCAARLDDmGlhxW5yzgu7SrO86MtQcKtm1j
2172ydR/7bsAOVDGeQB6kVBqvOGZXKmVaT8X2mBc/VZrZkYh5PVapnMngmC
218-----END PRIVATE KEY-----";
219
220 const TEST_EC_PUBLIC_KEY: &str = "-----BEGIN PUBLIC KEY-----
223MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESww5hpYcVucs4Lu0qzvOjLUHCrZt
224Y9snUf+27ADlQxnkAepFQarzhmVyplWk/F9pgXP1Wa2ZGIeT1WqZzJ4Jgg==
225-----END PUBLIC KEY-----";
226
227 const TEST_EC_PRIVATE_KEY_384: &str = "-----BEGIN PRIVATE KEY-----
231MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDA8W5KSitwokEoKlCP7
232h6DdD7fYD567VjEEEl0L9LcpCfrUWp6CMhTfLoyyj7CoW8qhZANiAARTfi70JZsD
233Vf0iS0Gw3+8ylH/7IQwRA3iZpHC5KQDEOrgXZmcEocgxkZD/Ud0X/tZVwJNAqVt9
234XhvK7gvogAUePeAklVfRJTuZuJhb7x3NbAczz43nHvLtgSHIWH1nyrk=
235-----END PRIVATE KEY-----";
236
237 const TEST_EC_PUBLIC_KEY_384: &str = "-----BEGIN PUBLIC KEY-----
240MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEU34u9CWbA1X9IktBsN/vMpR/+yEMEQN4
241maRwuSkAxDq4F2ZnBKHIMZGQ/1HdF/7WVcCTQKlbfV4byu4L6IAFHj3gJJVX0SU7
242mbiYW+8dzWwHM8+N5x7y7YEhyFh9Z8q5
243-----END PUBLIC KEY-----";
244
245 const TEST_RSA_PRIVATE_KEY: &str = "-----BEGIN PRIVATE KEY-----
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
296AhW8CZzWMXVPOgExNZJBW65D7p/V
297-----END PRIVATE KEY-----";
298
299 const TEST_RSA_PUBLIC_KEY: &str = "-----BEGIN PUBLIC KEY-----
301MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvzqxRxjDW7KrjnopVCN/
302SlIQpJ7gZcX/t5lzg6w6fIj5vf7UPxNUtiWraeYqfXBhb/xQO53SJoFDCB2Z0VZD
303WgpOmJf/kgPtAtSCHAb0eGe666Elx+L0LQQU5z1csRAzma7qafzeQGrYbaoKgpXR
304EYj7usvxkopdFITv5xa5Tme+DQPQXgLUIUZRDZEzC/Tm2sTvw7+Y8yeCJCGSfFyn
3056K3l6twmQRJtoNRGRFNlg9rw2cb+1nT9c/08evjy25ywU8uRO2VDsfWx6GjPqFzw
306s6wNnuXPcYWOjNST/HHJfaqDlIVVATIlyEUkdDnmrAM/3RAvqpcfGE/BaSQkDGnU
307ejbqIAFl5Nki9X8bZnNMymFlyY+w4ord6QZlLF7JjsUBhlfbinlibs+Gld23NLjB
308klnARqFVjlULcPHSzRVlHWWL69OoQEXEiwkYS2z+AgkAYF3uTKilw8WuF8GMpoRX
309Mb2v+F6Xp6xHcUHrk2nA8z6CQJyKrBDhwJezznFsyWx15tD1p0OBlWPuFEU4nXvm
3101uWH4QL/xaIwDhvPpzOPZWlWbrkOD5Cg+bc6CzFYeZiGlL3oiRv/3BV7zBrRgC4F
311Dc5XKLWxvBmF09lNRC+c58ADq8R8VqxIwSK09dwfjsJmidtX6XHfCiM5WrPYOEsw
312DGMTi24MRdH9qfphXIXOrW8CAwEAAQ==
313-----END PUBLIC KEY-----";
314
315 fn base64decode<D: AsRef<[u8]>>(data: D) -> Vec<u8> {
316 base64::decode_config(data, base64::URL_SAFE_NO_PAD).unwrap()
317 }
318
319 type Claims = HashMap<String, Value>;
320
321 fn number(map: &Claims, key: &str) -> u64 {
322 map.get(key).unwrap().as_u64().unwrap()
323 }
324
325 fn get_str<'a>(map: &'a Claims, key: &str) -> &'a str {
326 map.get(key).unwrap().as_str().unwrap()
327 }
328
329 fn decode_jwt(jwt: &str) -> (Claims, Claims) {
330 let header: Claims =
331 serde_json::from_slice(base64decode(jwt.split('.').next().unwrap()).as_slice())
332 .unwrap();
333 let claims: Claims =
334 serde_json::from_slice(base64decode(jwt.split('.').nth(1).unwrap()).as_slice())
335 .unwrap();
336 (header, claims)
337 }
338
339 pub fn smoke(alg: SigningAlgorithm, length: SigningKeyLength, key: &str) -> String {
340 let generator = JwtGenerator::new(alg, length, key).unwrap();
341
342 let mut custom_headers = HashMap::new();
343 custom_headers.insert("custom_header".to_string(), Value::from("custom_header"));
344
345 let mut custom_claims = HashMap::new();
346 custom_claims.insert("custom_claim".to_string(), Value::from("custom_claim"));
347
348 let claims = JWTClaims::new(
349 Some(Utc.timestamp_opt(i32::MAX as i64, 0).single().unwrap()),
350 None,
351 None,
352 custom_claims,
353 custom_headers,
354 )
355 .unwrap();
356
357 let jwt = generator.jwt(claims).unwrap();
358
359 println!("{jwt}");
360
361 jwt
362 }
363
364 fn validate(jwt: String, alg: &str) {
365 let (header, claims) = decode_jwt(&jwt);
366
367 assert_eq!(header.len(), 3);
368 assert_eq!(get_str(&header, "alg"), alg);
369 assert_eq!(get_str(&header, "typ"), "JWT");
370 assert_eq!(get_str(&header, "custom_header"), "custom_header");
371
372 assert_eq!(claims.len(), 2);
373 assert_eq!(number(&claims, "exp"), i32::MAX as u64 * 1000 * 1000 * 1000);
374 assert_eq!(get_str(&claims, "custom_claim"), "custom_claim");
375 }
376
377 #[test]
378 pub fn hmac256() {
379 let key = "some";
380 let jwt = smoke(SigningAlgorithm::Hmac, SigningKeyLength::Len256, key);
381 let _: DynamicSimpleClaims = HS256Key::from_bytes(key.as_bytes())
382 .verify_token(jwt.as_str(), None)
383 .unwrap();
384
385 validate(jwt, "HS256");
386 }
387
388 #[test]
389 pub fn hmac384() {
390 let key = "some";
391 let jwt = smoke(SigningAlgorithm::Hmac, SigningKeyLength::Len384, key);
392 let _: DynamicSimpleClaims = HS384Key::from_bytes(key.as_bytes())
393 .verify_token(jwt.as_str(), None)
394 .unwrap();
395
396 validate(jwt, "HS384");
397 }
398
399 #[test]
400 pub fn hmac512() {
401 let key = "some";
402 let jwt = smoke(SigningAlgorithm::Hmac, SigningKeyLength::Len512, key);
403 let _: DynamicSimpleClaims = HS512Key::from_bytes(key.as_bytes())
404 .verify_token(jwt.as_str(), None)
405 .unwrap();
406
407 validate(jwt, "HS512");
408 }
409
410 #[test]
411 pub fn rsa256() {
412 let jwt = smoke(
413 SigningAlgorithm::Rsa,
414 SigningKeyLength::Len256,
415 TEST_RSA_PRIVATE_KEY,
416 );
417
418 let _: DynamicSimpleClaims = RS256PublicKey::from_pem(TEST_RSA_PUBLIC_KEY)
419 .unwrap()
420 .verify_token(jwt.as_str(), None)
421 .unwrap();
422
423 validate(jwt, "RS256");
424 }
425
426 #[test]
427 pub fn rsa384() {
428 let jwt = smoke(
429 SigningAlgorithm::Rsa,
430 SigningKeyLength::Len384,
431 TEST_RSA_PRIVATE_KEY,
432 );
433
434 let _: DynamicSimpleClaims = RS384PublicKey::from_pem(TEST_RSA_PUBLIC_KEY)
435 .unwrap()
436 .verify_token(jwt.as_str(), None)
437 .unwrap();
438
439 validate(jwt, "RS384");
440 }
441
442 #[test]
443 pub fn rsa512() {
444 let jwt = smoke(
445 SigningAlgorithm::Rsa,
446 SigningKeyLength::Len512,
447 TEST_RSA_PRIVATE_KEY,
448 );
449
450 let _: DynamicSimpleClaims = RS512PublicKey::from_pem(TEST_RSA_PUBLIC_KEY)
451 .unwrap()
452 .verify_token(jwt.as_str(), None)
453 .unwrap();
454
455 validate(jwt, "RS512");
456 }
457
458 #[test]
459 pub fn es256() {
460 let jwt = smoke(
461 SigningAlgorithm::Es,
462 SigningKeyLength::Len256,
463 TEST_EC_PRIVATE_KEY,
464 );
465
466 let _: DynamicSimpleClaims = ES256PublicKey::from_pem(TEST_EC_PUBLIC_KEY)
467 .unwrap()
468 .verify_token(jwt.as_str(), None)
469 .unwrap();
470
471 validate(jwt, "ES256");
472 }
473
474 #[test]
475 pub fn es384() {
476 let jwt = smoke(
477 SigningAlgorithm::Es,
478 SigningKeyLength::Len384,
479 TEST_EC_PRIVATE_KEY_384,
480 );
481
482 let _: DynamicSimpleClaims = ES384PublicKey::from_pem(TEST_EC_PUBLIC_KEY_384)
483 .unwrap()
484 .verify_token(jwt.as_str(), None)
485 .unwrap();
486
487 validate(jwt, "ES384");
488 }
489
490 #[test]
491 pub fn es512() {
492 let result = JwtGenerator::new(
493 SigningAlgorithm::Es,
494 SigningKeyLength::Len512,
495 TEST_EC_PRIVATE_KEY_384,
496 );
497
498 let Err(GeneratorError::InvalidAlgorithm(_)) = result else {
499 panic!("should not create a validator")
500 };
501 }
502
503 #[test]
504 pub fn invalid_key() {
505 let result = JwtGenerator::new(
506 SigningAlgorithm::Es,
507 SigningKeyLength::Len256,
508 TEST_EC_PRIVATE_KEY_384,
509 );
510
511 let Err(GeneratorError::KeyParsing(_)) = result else {
512 panic!("should not create a validator")
513 };
514 }
515}