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).unwrap();
120 Ok(())
121 }
122
123 fn authenticate<CustomClaims: Serialize + DeserializeOwned>(
125 &self,
126 claims: JWTClaims<CustomClaims>,
127 ) -> Result<String, Error> {
128 let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
129 .with_key_metadata(self.metadata());
130 Token::build(&jwt_header, claims, |authenticated| {
131 Ok(self.authentication_tag(authenticated.as_bytes()))
132 })
133 }
134
135 fn verify_token<CustomClaims: Serialize + DeserializeOwned>(
137 &self,
138 token: &str,
139 options: Option<VerificationOptions>,
140 ) -> Result<JWTClaims<CustomClaims>, Error> {
141 Token::verify(
142 Self::jwt_alg_name(),
143 token,
144 options,
145 |authenticated, authentication_tag| {
146 ensure!(
147 timingsafe_eq(
148 &self.authentication_tag(authenticated.as_bytes()),
149 authentication_tag
150 ),
151 JWTError::InvalidAuthenticationTag
152 );
153 Ok(())
154 },
155 |salt: Option<&[u8]>| {
156 if let Some(Salt::Verifier(authenticated_salt)) =
157 self.metadata().as_ref().map(|metadata| &metadata.salt)
158 {
159 match salt {
160 None => bail!(JWTError::MissingSalt),
161 Some(salt) => {
162 let expected_authenticated_tag = self.authentication_tag(salt);
163 ensure!(
164 timingsafe_eq(authenticated_salt, &expected_authenticated_tag),
165 JWTError::InvalidAuthenticationTag
166 );
167 }
168 }
169 } else {
170 ensure!(salt.is_none(), JWTError::MissingSalt);
171 }
172 Ok(())
173 },
174 )
175 }
176
177 #[cfg(feature = "cwt")]
178 fn verify_cwt_token(
179 &self,
180 token: impl AsRef<[u8]>,
181 options: Option<VerificationOptions>,
182 ) -> Result<JWTClaims<NoCustomClaims>, Error> {
183 CWTToken::verify(
184 Self::jwt_alg_name(),
185 token,
186 options,
187 |authenticated, authentication_tag| {
188 ensure!(
189 timingsafe_eq(
190 &self.authentication_tag(authenticated.as_bytes()),
191 authentication_tag
192 ),
193 JWTError::InvalidAuthenticationTag
194 );
195 Ok(())
196 },
197 )
198 }
199
200 fn create_key_id(&mut self) -> &str {
201 self.set_key_id(
202 Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
203 &self.key().to_bytes(),
204 ))
205 .unwrap(),
206 );
207 self.key_id().as_ref().map(|x| x.as_str()).unwrap()
208 }
209}
210
211#[derive(Debug, Clone)]
212pub struct HS256Key {
213 key: HMACKey,
214 key_id: Option<String>,
215}
216
217impl MACLike for HS256Key {
218 fn jwt_alg_name() -> &'static str {
219 "HS256"
220 }
221
222 fn key(&self) -> &HMACKey {
223 &self.key
224 }
225
226 fn key_id(&self) -> &Option<String> {
227 &self.key_id
228 }
229
230 fn set_key_id(&mut self, key_id: String) {
231 self.key_id = Some(key_id);
232 }
233
234 fn metadata(&self) -> &Option<KeyMetadata> {
235 &self.key.metadata
236 }
237
238 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
239 self.key.metadata = Some(metadata);
240 Ok(())
241 }
242
243 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
244 hmac_sha256::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
245 }
246}
247
248impl HS256Key {
249 pub fn from_bytes(raw_key: &[u8]) -> Self {
250 HS256Key {
251 key: HMACKey::from_bytes(raw_key),
252 key_id: None,
253 }
254 }
255
256 pub fn to_bytes(&self) -> Vec<u8> {
257 self.key.to_bytes()
258 }
259
260 pub fn generate() -> Self {
261 HS256Key {
262 key: HMACKey::generate(),
263 key_id: None,
264 }
265 }
266
267 pub fn generate_with_salt() -> Self {
268 HS256Key {
269 key: HMACKey::generate_with_salt(),
270 key_id: None,
271 }
272 }
273
274 pub fn with_key_id(mut self, key_id: &str) -> Self {
275 self.key_id = Some(key_id.to_string());
276 self
277 }
278}
279
280#[derive(Debug, Clone)]
281pub struct HS512Key {
282 key: HMACKey,
283 key_id: Option<String>,
284}
285
286impl MACLike for HS512Key {
287 fn jwt_alg_name() -> &'static str {
288 "HS512"
289 }
290
291 fn key(&self) -> &HMACKey {
292 &self.key
293 }
294
295 fn key_id(&self) -> &Option<String> {
296 &self.key_id
297 }
298
299 fn set_key_id(&mut self, key_id: String) {
300 self.key_id = Some(key_id);
301 }
302
303 fn metadata(&self) -> &Option<KeyMetadata> {
304 &self.key.metadata
305 }
306
307 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
308 self.key.metadata = Some(metadata);
309 Ok(())
310 }
311
312 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
313 hmac_sha512::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
314 }
315}
316
317impl HS512Key {
318 pub fn from_bytes(raw_key: &[u8]) -> Self {
319 HS512Key {
320 key: HMACKey::from_bytes(raw_key),
321 key_id: None,
322 }
323 }
324
325 pub fn to_bytes(&self) -> Vec<u8> {
326 self.key.to_bytes()
327 }
328
329 pub fn generate() -> Self {
330 HS512Key {
331 key: HMACKey::generate(),
332 key_id: None,
333 }
334 }
335
336 pub fn generate_with_salt() -> Self {
337 HS512Key {
338 key: HMACKey::generate_with_salt(),
339 key_id: None,
340 }
341 }
342
343 pub fn with_key_id(mut self, key_id: &str) -> Self {
344 self.key_id = Some(key_id.to_string());
345 self
346 }
347}
348
349#[derive(Debug, Clone)]
350pub struct HS384Key {
351 key: HMACKey,
352 key_id: Option<String>,
353}
354
355impl MACLike for HS384Key {
356 fn jwt_alg_name() -> &'static str {
357 "HS384"
358 }
359
360 fn key(&self) -> &HMACKey {
361 &self.key
362 }
363
364 fn key_id(&self) -> &Option<String> {
365 &self.key_id
366 }
367
368 fn set_key_id(&mut self, key_id: String) {
369 self.key_id = Some(key_id);
370 }
371
372 fn metadata(&self) -> &Option<KeyMetadata> {
373 &self.key.metadata
374 }
375
376 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
377 self.key.metadata = Some(metadata);
378 Ok(())
379 }
380
381 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
382 hmac_sha384::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
383 }
384}
385
386impl HS384Key {
387 pub fn from_bytes(raw_key: &[u8]) -> Self {
388 HS384Key {
389 key: HMACKey::from_bytes(raw_key),
390 key_id: None,
391 }
392 }
393
394 pub fn to_bytes(&self) -> Vec<u8> {
395 self.key.to_bytes()
396 }
397
398 pub fn generate() -> Self {
399 HS384Key {
400 key: HMACKey::generate(),
401 key_id: None,
402 }
403 }
404
405 pub fn generate_with_salt() -> Self {
406 HS384Key {
407 key: HMACKey::generate_with_salt(),
408 key_id: None,
409 }
410 }
411
412 pub fn with_key_id(mut self, key_id: &str) -> Self {
413 self.key_id = Some(key_id.to_string());
414 self
415 }
416}
417
418#[derive(Debug, Clone)]
421pub struct Blake2bKey {
422 key: HMACKey,
423 key_id: Option<String>,
424}
425
426impl MACLike for Blake2bKey {
427 fn jwt_alg_name() -> &'static str {
428 "BLAKE2B"
429 }
430
431 fn key(&self) -> &HMACKey {
432 &self.key
433 }
434
435 fn key_id(&self) -> &Option<String> {
436 &self.key_id
437 }
438
439 fn set_key_id(&mut self, key_id: String) {
440 self.key_id = Some(key_id);
441 }
442
443 fn metadata(&self) -> &Option<KeyMetadata> {
444 &self.key.metadata
445 }
446
447 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
448 self.key.metadata = Some(metadata);
449 Ok(())
450 }
451
452 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
453 blake2b_simd::Params::new()
454 .hash_length(32)
455 .key(self.key().as_ref())
456 .to_state()
457 .update(authenticated)
458 .finalize()
459 .as_bytes()
460 .to_vec()
461 }
462}
463
464impl Blake2bKey {
465 pub fn from_bytes(raw_key: &[u8]) -> Self {
466 Blake2bKey {
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 Blake2bKey {
478 key: HMACKey::generate(),
479 key_id: None,
480 }
481 }
482
483 pub fn generate_with_salt() -> Self {
484 Blake2bKey {
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}