1use ct_codecs::{Base64UrlSafeNoPadding, Encoder};
2use hmac_sha512::sha384 as hmac_sha384;
3use rand::RngCore;
4use serde::{de::DeserializeOwned, Serialize};
5use zeroize::Zeroize;
6
7use crate::claims::*;
8use crate::common::*;
9#[cfg(feature = "cwt")]
10use crate::cwt_token::*;
11use crate::error::*;
12use crate::jwt_header::*;
13use crate::token::*;
14
15#[doc(hidden)]
16#[derive(Debug, Clone)]
17pub struct HMACKey {
18 raw_key: Vec<u8>,
19 metadata: Option<KeyMetadata>,
20}
21
22impl Drop for HMACKey {
23 fn drop(&mut self) {
24 self.raw_key.zeroize();
25 }
26}
27
28impl HMACKey {
29 pub fn from_bytes(raw_key: &[u8]) -> Self {
31 HMACKey {
32 raw_key: raw_key.to_vec(),
33 metadata: None,
34 }
35 }
36
37 pub fn to_bytes(&self) -> Vec<u8> {
39 self.raw_key.clone()
40 }
41
42 pub fn salt(&self) -> Option<Salt> {
44 self.metadata.as_ref().map(|metadata| metadata.salt.clone())
45 }
46
47 pub fn with_salt(mut self, salt: Salt) -> Self {
49 if let Some(metadata) = self.metadata.as_mut() {
50 metadata.salt = salt;
51 } else {
52 self.metadata = Some(KeyMetadata {
53 salt,
54 ..Default::default()
55 });
56 }
57 self
58 }
59
60 pub fn generate() -> Self {
62 let mut raw_key = vec![0u8; 32];
63 rand::thread_rng().fill_bytes(&mut raw_key);
64 HMACKey {
65 raw_key,
66 metadata: None,
67 }
68 }
69
70 pub fn generate_with_salt() -> Self {
72 HMACKey::generate().with_salt(Salt::generate())
73 }
74}
75
76impl AsRef<[u8]> for HMACKey {
77 fn as_ref(&self) -> &[u8] {
79 &self.raw_key
80 }
81}
82
83pub trait MACLike {
84 fn jwt_alg_name() -> &'static str;
85 fn key(&self) -> &HMACKey;
86 fn key_id(&self) -> &Option<String>;
87 fn set_key_id(&mut self, key_id: String);
88 fn metadata(&self) -> &Option<KeyMetadata>;
89 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error>;
90 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8>;
91
92 fn salt(&self) -> Salt {
94 self.metadata()
95 .as_ref()
96 .map(|metadata| metadata.salt.clone())
97 .unwrap_or(Salt::None)
98 }
99
100 fn verifier_salt(&self) -> Result<Salt, Error> {
102 match self.metadata().as_ref().map(|metadata| &metadata.salt) {
103 None => bail!(JWTError::MissingSalt),
104 Some(Salt::Signer(salt)) => {
105 let authenticated_salt = self.authentication_tag(salt);
106 Ok(Salt::Verifier(authenticated_salt))
107 }
108 Some(x @ Salt::Verifier(_)) => Ok(x.clone()),
109 Some(Salt::None) => bail!(JWTError::MissingSalt),
110 }
111 }
112
113 fn attach_salt(&mut self, salt: Salt) -> Result<(), Error> {
115 let metadata = KeyMetadata {
116 salt,
117 ..Default::default()
118 };
119 self.attach_metadata(metadata)?;
120 Ok(())
121 }
122
123 fn authenticate<CustomClaims: Serialize + DeserializeOwned>(
125 &self,
126 claims: JWTClaims<CustomClaims>,
127 ) -> Result<String, Error> {
128 self.authenticate_with_options(claims, &Default::default())
129 }
130
131 fn authenticate_with_options<CustomClaims: Serialize + DeserializeOwned>(
132 &self,
133 claims: JWTClaims<CustomClaims>,
134 options: &HeaderOptions,
135 ) -> Result<String, Error> {
136 let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
137 .with_key_metadata(self.metadata())
138 .with_options(options);
139 Token::build(&jwt_header, claims, |authenticated| {
140 Ok(self.authentication_tag(authenticated.as_bytes()))
141 })
142 }
143
144 fn verify_token<CustomClaims: Serialize + DeserializeOwned>(
146 &self,
147 token: &str,
148 options: Option<VerificationOptions>,
149 ) -> Result<JWTClaims<CustomClaims>, Error> {
150 Token::verify(
151 Self::jwt_alg_name(),
152 token,
153 options,
154 |authenticated, authentication_tag| {
155 ensure!(
156 timingsafe_eq(
157 &self.authentication_tag(authenticated.as_bytes()),
158 authentication_tag
159 ),
160 JWTError::InvalidAuthenticationTag
161 );
162 Ok(())
163 },
164 |salt: Option<&[u8]>| {
165 if let Some(Salt::Verifier(authenticated_salt)) =
166 self.metadata().as_ref().map(|metadata| &metadata.salt)
167 {
168 match salt {
169 None => bail!(JWTError::MissingSalt),
170 Some(salt) => {
171 let expected_authenticated_tag = self.authentication_tag(salt);
172 ensure!(
173 timingsafe_eq(authenticated_salt, &expected_authenticated_tag),
174 JWTError::InvalidAuthenticationTag
175 );
176 }
177 }
178 } else {
179 ensure!(salt.is_none(), JWTError::MissingSalt);
180 }
181 Ok(())
182 },
183 )
184 }
185
186 #[cfg(feature = "cwt")]
187 fn verify_cwt_token(
188 &self,
189 token: impl AsRef<[u8]>,
190 options: Option<VerificationOptions>,
191 ) -> Result<JWTClaims<NoCustomClaims>, Error> {
192 CWTToken::verify(
193 Self::jwt_alg_name(),
194 token,
195 options,
196 |authenticated, authentication_tag| {
197 ensure!(
198 timingsafe_eq(
199 &self.authentication_tag(authenticated.as_bytes()),
200 authentication_tag
201 ),
202 JWTError::InvalidAuthenticationTag
203 );
204 Ok(())
205 },
206 )
207 }
208
209 #[cfg(feature = "cwt")]
257 fn verify_cwt_token_with_custom_claims<CustomClaims>(
258 &self,
259 token: impl AsRef<[u8]>,
260 options: Option<VerificationOptions>,
261 ) -> Result<JWTClaims<CustomClaims>, Error>
262 where
263 CustomClaims: DeserializeOwned + Default + 'static,
264 {
265 CWTToken::verify(
266 Self::jwt_alg_name(),
267 token,
268 options,
269 |authenticated, authentication_tag| {
270 ensure!(
271 timingsafe_eq(
272 &self.authentication_tag(authenticated.as_bytes()),
273 authentication_tag
274 ),
275 JWTError::InvalidAuthenticationTag
276 );
277 Ok(())
278 },
279 )
280 }
281
282 #[cfg(feature = "cwt")]
284 fn decode_cwt_metadata(&self, token: impl AsRef<[u8]>) -> Result<TokenMetadata, Error> {
285 CWTToken::decode_metadata(token)
286 }
287
288 fn create_key_id(&mut self) -> &str {
289 self.set_key_id(
290 Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
291 &self.key().to_bytes(),
292 ))
293 .unwrap(),
294 );
295 self.key_id().as_ref().map(|x| x.as_str()).unwrap()
296 }
297}
298
299#[derive(Debug, Clone)]
300pub struct HS256Key {
301 key: HMACKey,
302 key_id: Option<String>,
303}
304
305impl MACLike for HS256Key {
306 fn jwt_alg_name() -> &'static str {
307 "HS256"
308 }
309
310 fn key(&self) -> &HMACKey {
311 &self.key
312 }
313
314 fn key_id(&self) -> &Option<String> {
315 &self.key_id
316 }
317
318 fn set_key_id(&mut self, key_id: String) {
319 self.key_id = Some(key_id);
320 }
321
322 fn metadata(&self) -> &Option<KeyMetadata> {
323 &self.key.metadata
324 }
325
326 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
327 self.key.metadata = Some(metadata);
328 Ok(())
329 }
330
331 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
332 hmac_sha256::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
333 }
334}
335
336impl HS256Key {
337 pub fn from_bytes(raw_key: &[u8]) -> Self {
338 HS256Key {
339 key: HMACKey::from_bytes(raw_key),
340 key_id: None,
341 }
342 }
343
344 pub fn to_bytes(&self) -> Vec<u8> {
345 self.key.to_bytes()
346 }
347
348 pub fn generate() -> Self {
349 HS256Key {
350 key: HMACKey::generate(),
351 key_id: None,
352 }
353 }
354
355 pub fn generate_with_salt() -> Self {
356 HS256Key {
357 key: HMACKey::generate_with_salt(),
358 key_id: None,
359 }
360 }
361
362 pub fn with_key_id(mut self, key_id: &str) -> Self {
363 self.key_id = Some(key_id.to_string());
364 self
365 }
366
367 #[cfg(feature = "cwt")]
415 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
416 &self,
417 token: impl AsRef<[u8]>,
418 options: Option<VerificationOptions>,
419 ) -> Result<JWTClaims<CustomClaims>, Error>
420 where
421 CustomClaims: DeserializeOwned + Default + 'static,
422 {
423 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
424 }
425}
426
427#[derive(Debug, Clone)]
428pub struct HS512Key {
429 key: HMACKey,
430 key_id: Option<String>,
431}
432
433impl MACLike for HS512Key {
434 fn jwt_alg_name() -> &'static str {
435 "HS512"
436 }
437
438 fn key(&self) -> &HMACKey {
439 &self.key
440 }
441
442 fn key_id(&self) -> &Option<String> {
443 &self.key_id
444 }
445
446 fn set_key_id(&mut self, key_id: String) {
447 self.key_id = Some(key_id);
448 }
449
450 fn metadata(&self) -> &Option<KeyMetadata> {
451 &self.key.metadata
452 }
453
454 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
455 self.key.metadata = Some(metadata);
456 Ok(())
457 }
458
459 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
460 hmac_sha512::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
461 }
462}
463
464impl HS512Key {
465 pub fn from_bytes(raw_key: &[u8]) -> Self {
466 HS512Key {
467 key: HMACKey::from_bytes(raw_key),
468 key_id: None,
469 }
470 }
471
472 pub fn to_bytes(&self) -> Vec<u8> {
473 self.key.to_bytes()
474 }
475
476 pub fn generate() -> Self {
477 HS512Key {
478 key: HMACKey::generate(),
479 key_id: None,
480 }
481 }
482
483 pub fn generate_with_salt() -> Self {
484 HS512Key {
485 key: HMACKey::generate_with_salt(),
486 key_id: None,
487 }
488 }
489
490 pub fn with_key_id(mut self, key_id: &str) -> Self {
491 self.key_id = Some(key_id.to_string());
492 self
493 }
494
495 #[cfg(feature = "cwt")]
514 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
515 &self,
516 token: impl AsRef<[u8]>,
517 options: Option<VerificationOptions>,
518 ) -> Result<JWTClaims<CustomClaims>, Error>
519 where
520 CustomClaims: DeserializeOwned + Default + 'static,
521 {
522 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
523 }
524}
525
526#[derive(Debug, Clone)]
527pub struct HS384Key {
528 key: HMACKey,
529 key_id: Option<String>,
530}
531
532impl MACLike for HS384Key {
533 fn jwt_alg_name() -> &'static str {
534 "HS384"
535 }
536
537 fn key(&self) -> &HMACKey {
538 &self.key
539 }
540
541 fn key_id(&self) -> &Option<String> {
542 &self.key_id
543 }
544
545 fn set_key_id(&mut self, key_id: String) {
546 self.key_id = Some(key_id);
547 }
548
549 fn metadata(&self) -> &Option<KeyMetadata> {
550 &self.key.metadata
551 }
552
553 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
554 self.key.metadata = Some(metadata);
555 Ok(())
556 }
557
558 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
559 hmac_sha384::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
560 }
561}
562
563impl HS384Key {
564 pub fn from_bytes(raw_key: &[u8]) -> Self {
565 HS384Key {
566 key: HMACKey::from_bytes(raw_key),
567 key_id: None,
568 }
569 }
570
571 pub fn to_bytes(&self) -> Vec<u8> {
572 self.key.to_bytes()
573 }
574
575 pub fn generate() -> Self {
576 HS384Key {
577 key: HMACKey::generate(),
578 key_id: None,
579 }
580 }
581
582 pub fn generate_with_salt() -> Self {
583 HS384Key {
584 key: HMACKey::generate_with_salt(),
585 key_id: None,
586 }
587 }
588
589 pub fn with_key_id(mut self, key_id: &str) -> Self {
590 self.key_id = Some(key_id.to_string());
591 self
592 }
593
594 #[cfg(feature = "cwt")]
613 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
614 &self,
615 token: impl AsRef<[u8]>,
616 options: Option<VerificationOptions>,
617 ) -> Result<JWTClaims<CustomClaims>, Error>
618 where
619 CustomClaims: DeserializeOwned + Default + 'static,
620 {
621 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
622 }
623}
624
625#[derive(Debug, Clone)]
628pub struct Blake2bKey {
629 key: HMACKey,
630 key_id: Option<String>,
631}
632
633impl MACLike for Blake2bKey {
634 fn jwt_alg_name() -> &'static str {
635 "BLAKE2B"
636 }
637
638 fn key(&self) -> &HMACKey {
639 &self.key
640 }
641
642 fn key_id(&self) -> &Option<String> {
643 &self.key_id
644 }
645
646 fn set_key_id(&mut self, key_id: String) {
647 self.key_id = Some(key_id);
648 }
649
650 fn metadata(&self) -> &Option<KeyMetadata> {
651 &self.key.metadata
652 }
653
654 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
655 self.key.metadata = Some(metadata);
656 Ok(())
657 }
658
659 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
660 blake2b_simd::Params::new()
661 .hash_length(32)
662 .key(self.key().as_ref())
663 .to_state()
664 .update(authenticated)
665 .finalize()
666 .as_bytes()
667 .to_vec()
668 }
669}
670
671impl Blake2bKey {
672 pub fn from_bytes(raw_key: &[u8]) -> Self {
673 Blake2bKey {
674 key: HMACKey::from_bytes(raw_key),
675 key_id: None,
676 }
677 }
678
679 pub fn to_bytes(&self) -> Vec<u8> {
680 self.key.to_bytes()
681 }
682
683 pub fn generate() -> Self {
684 Blake2bKey {
685 key: HMACKey::generate(),
686 key_id: None,
687 }
688 }
689
690 #[cfg(feature = "cwt")]
709 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
710 &self,
711 token: impl AsRef<[u8]>,
712 options: Option<VerificationOptions>,
713 ) -> Result<JWTClaims<CustomClaims>, Error>
714 where
715 CustomClaims: DeserializeOwned + Default + 'static,
716 {
717 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
718 }
719
720 pub fn generate_with_salt() -> Self {
721 Blake2bKey {
722 key: HMACKey::generate_with_salt(),
723 key_id: None,
724 }
725 }
726
727 pub fn with_key_id(mut self, key_id: &str) -> Self {
728 self.key_id = Some(key_id.to_string());
729 self
730 }
731}