1use crate::error::KeyError;
2use crate::generate::generate;
3use crate::{Algorithm, Claims};
4use base64::Engine;
5use elliptic_curve::SecretKey;
6use elliptic_curve::pkcs8::EncodePrivateKey;
7use jsonwebtoken::{DecodingKey, EncodingKey, Header};
8use rsa::BigUint;
9use rsa::pkcs1::EncodeRsaPrivateKey;
10use serde::{Deserialize, Deserializer, Serialize, Serializer};
11use std::sync::OnceLock;
12use std::{collections::HashSet, fmt, path::Path as StdPath};
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)]
16#[serde(rename_all = "camelCase")]
17pub enum KeyOperation {
18 Sign,
19 Verify,
20 Decrypt,
21 Encrypt,
22}
23
24#[derive(Clone, Serialize, Deserialize)]
26#[serde(tag = "kty")]
27pub enum KeyType {
28 EC {
30 #[serde(rename = "crv")]
31 curve: EllipticCurve,
32 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
34 x: Vec<u8>,
35 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
37 y: Vec<u8>,
38 #[serde(
40 default,
41 skip_serializing_if = "Option::is_none",
42 serialize_with = "serialize_base64url_optional",
43 deserialize_with = "deserialize_base64url_optional"
44 )]
45 d: Option<Vec<u8>>,
46 },
47 RSA {
49 #[serde(flatten)]
50 public: RsaPublicKey,
51 #[serde(flatten, skip_serializing_if = "Option::is_none")]
52 private: Option<RsaPrivateKey>,
53 },
54 #[serde(rename = "oct")]
56 OCT {
57 #[serde(
59 rename = "k",
60 default,
61 serialize_with = "serialize_base64url",
62 deserialize_with = "deserialize_base64url"
63 )]
64 secret: Vec<u8>,
65 },
66 OKP {
68 #[serde(rename = "crv")]
69 curve: EllipticCurve,
70 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
71 x: Vec<u8>,
72 #[serde(
73 rename = "d",
74 default,
75 skip_serializing_if = "Option::is_none",
76 serialize_with = "serialize_base64url_optional",
77 deserialize_with = "deserialize_base64url_optional"
78 )]
79 d: Option<Vec<u8>>,
80 },
81}
82
83#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)]
87pub enum EllipticCurve {
88 #[serde(rename = "P-256")]
89 P256,
90 #[serde(rename = "P-384")]
91 P384,
92 #[serde(rename = "Ed25519")]
96 Ed25519,
97}
98
99#[derive(Clone, Serialize, Deserialize)]
103pub struct RsaPublicKey {
104 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
105 pub n: Vec<u8>,
106 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
107 pub e: Vec<u8>,
108}
109
110#[derive(Clone, Serialize, Deserialize)]
114pub struct RsaPrivateKey {
115 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
116 pub d: Vec<u8>,
117 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
118 pub p: Vec<u8>,
119 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
120 pub q: Vec<u8>,
121 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
122 pub dp: Vec<u8>,
123 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
124 pub dq: Vec<u8>,
125 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
126 pub qi: Vec<u8>,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub oth: Option<Vec<RsaAdditionalPrime>>,
129}
130
131#[derive(Clone, Serialize, Deserialize)]
133pub struct RsaAdditionalPrime {
134 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
135 pub r: Vec<u8>,
136 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
137 pub d: Vec<u8>,
138 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
139 pub t: Vec<u8>,
140}
141
142#[derive(Clone, Serialize, Deserialize)]
145#[serde(remote = "Self")]
146pub struct Key {
147 #[serde(rename = "alg")]
149 pub algorithm: Algorithm,
150
151 #[serde(rename = "key_ops")]
153 pub operations: HashSet<KeyOperation>,
154
155 #[serde(flatten)]
157 pub key: KeyType,
158
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub kid: Option<crate::KeyId>,
162
163 #[serde(skip)]
165 pub(crate) decode: OnceLock<DecodingKey>,
166
167 #[serde(skip)]
168 pub(crate) encode: OnceLock<EncodingKey>,
169}
170
171impl<'de> Deserialize<'de> for Key {
172 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
173 where
174 D: Deserializer<'de>,
175 {
176 let mut value = serde_json::Value::deserialize(deserializer)?;
177
178 if let Some(obj) = value.as_object_mut()
182 && !obj.contains_key("kty")
183 {
184 obj.insert("kty".to_string(), serde_json::Value::String("oct".to_string()));
185 }
186
187 Self::deserialize(value).map_err(serde::de::Error::custom)
188 }
189}
190
191impl Serialize for Key {
192 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193 where
194 S: Serializer,
195 {
196 Self::serialize(self, serializer)
197 }
198}
199
200impl fmt::Debug for Key {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 f.debug_struct("Key")
203 .field("algorithm", &self.algorithm)
204 .field("operations", &self.operations)
205 .field("kid", &self.kid)
206 .finish()
207 }
208}
209
210impl Key {
211 #[allow(clippy::should_implement_trait)]
213 pub fn from_str(s: &str) -> crate::Result<Self> {
214 let s = s.trim();
215 if s.starts_with('{') {
216 Ok(serde_json::from_str(s)?)
217 } else {
218 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(s)?;
219 let json = String::from_utf8(decoded)?;
220 Ok(serde_json::from_str(&json)?)
221 }
222 }
223
224 pub fn from_file<P: AsRef<StdPath>>(path: P) -> crate::Result<Self> {
226 let contents = std::fs::read_to_string(&path)?;
227 Self::from_str(&contents)
228 }
229
230 #[cfg(feature = "tokio")]
232 pub async fn from_file_async<P: AsRef<StdPath>>(path: P) -> crate::Result<Self> {
233 let contents = tokio::fs::read_to_string(path).await?;
234 Self::from_str(&contents)
235 }
236
237 pub fn to_str(&self) -> crate::Result<String> {
239 let json = serde_json::to_string(self)?;
240 Ok(base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(json.as_bytes()))
241 }
242
243 pub fn to_file<P: AsRef<StdPath>>(&self, path: P) -> crate::Result<()> {
245 let encoded = self.to_str()?;
246 std::fs::write(path, encoded)?;
247 Ok(())
248 }
249
250 pub fn to_public(&self) -> crate::Result<Self> {
251 if !self.operations.contains(&KeyOperation::Verify) {
252 return Err(KeyError::VerifyUnsupported.into());
253 }
254
255 let key = match self.key {
256 KeyType::RSA { ref public, .. } => KeyType::RSA {
257 public: public.clone(),
258 private: None,
259 },
260 KeyType::EC {
261 ref x,
262 ref y,
263 ref curve,
264 ..
265 } => KeyType::EC {
266 x: x.clone(),
267 y: y.clone(),
268 curve: curve.clone(),
269 d: None,
270 },
271 KeyType::OCT { .. } => return Err(KeyError::NoPublicKey.into()),
272 KeyType::OKP { ref x, ref curve, .. } => KeyType::OKP {
273 x: x.clone(),
274 curve: curve.clone(),
275 d: None,
276 },
277 };
278
279 Ok(Self {
280 algorithm: self.algorithm,
281 operations: [KeyOperation::Verify].into(),
282 key,
283 kid: self.kid.clone(),
284 decode: Default::default(),
285 encode: Default::default(),
286 })
287 }
288
289 fn to_decoding_key(&self) -> crate::Result<&DecodingKey> {
290 if let Some(key) = self.decode.get() {
291 return Ok(key);
292 }
293
294 let decoding_key = match self.key {
295 KeyType::OCT { ref secret } => match self.algorithm {
296 Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => DecodingKey::from_secret(secret),
297 _ => return Err(KeyError::InvalidAlgorithm.into()),
298 },
299 KeyType::EC {
300 ref curve,
301 ref x,
302 ref y,
303 ..
304 } => match curve {
305 EllipticCurve::P256 => {
306 if self.algorithm != Algorithm::ES256 {
307 return Err(KeyError::InvalidAlgorithmForCurve("P-256").into());
308 }
309 if x.len() != 32 || y.len() != 32 {
310 return Err(KeyError::InvalidCoordinateLength("P-256").into());
311 }
312
313 DecodingKey::from_ec_components(
314 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(x).as_ref(),
315 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(y).as_ref(),
316 )?
317 }
318 EllipticCurve::P384 => {
319 if self.algorithm != Algorithm::ES384 {
320 return Err(KeyError::InvalidAlgorithmForCurve("P-384").into());
321 }
322 if x.len() != 48 || y.len() != 48 {
323 return Err(KeyError::InvalidCoordinateLength("P-384").into());
324 }
325
326 DecodingKey::from_ec_components(
327 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(x).as_ref(),
328 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(y).as_ref(),
329 )?
330 }
331 _ => return Err(KeyError::InvalidCurve("EC").into()),
332 },
333 KeyType::OKP { ref curve, ref x, .. } => match curve {
334 EllipticCurve::Ed25519 => {
335 if self.algorithm != Algorithm::EdDSA {
336 return Err(KeyError::InvalidAlgorithmForCurve("Ed25519").into());
337 }
338
339 DecodingKey::from_ed_components(
340 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(x).as_ref(),
341 )?
342 }
343 _ => return Err(KeyError::InvalidCurve("OKP").into()),
344 },
345 KeyType::RSA { ref public, .. } => {
346 DecodingKey::from_rsa_raw_components(public.n.as_ref(), public.e.as_ref())
347 }
348 };
349
350 Ok(self.decode.get_or_init(|| decoding_key))
351 }
352
353 fn to_encoding_key(&self) -> crate::Result<&EncodingKey> {
354 if let Some(key) = self.encode.get() {
355 return Ok(key);
356 }
357
358 let encoding_key = match self.key {
359 KeyType::OCT { ref secret } => match self.algorithm {
360 Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => EncodingKey::from_secret(secret),
361 _ => return Err(KeyError::InvalidAlgorithm.into()),
362 },
363 KeyType::EC { ref curve, ref d, .. } => {
364 let d = d.as_ref().ok_or(KeyError::MissingPrivateKey)?;
365
366 match curve {
367 EllipticCurve::P256 => {
368 let secret_key = SecretKey::<p256::NistP256>::from_slice(d)?;
369 let doc = secret_key.to_pkcs8_der()?;
370 EncodingKey::from_ec_der(doc.as_bytes())
371 }
372 EllipticCurve::P384 => {
373 let secret_key = SecretKey::<p384::NistP384>::from_slice(d)?;
374 let doc = secret_key.to_pkcs8_der()?;
375 EncodingKey::from_ec_der(doc.as_bytes())
376 }
377 _ => return Err(KeyError::InvalidCurve("EC").into()),
378 }
379 }
380 KeyType::OKP {
381 ref curve,
382 ref d,
383 ref x,
384 } => {
385 let d = d.as_ref().ok_or(KeyError::MissingPrivateKey)?;
386
387 let key_pair =
388 aws_lc_rs::signature::Ed25519KeyPair::from_seed_and_public_key(d.as_slice(), x.as_slice())?;
389
390 match curve {
391 EllipticCurve::Ed25519 => EncodingKey::from_ed_der(key_pair.to_pkcs8()?.as_ref()),
392 _ => return Err(KeyError::InvalidCurve("OKP").into()),
393 }
394 }
395 KeyType::RSA {
396 ref public,
397 ref private,
398 } => {
399 let n = BigUint::from_bytes_be(&public.n);
400 let e = BigUint::from_bytes_be(&public.e);
401 let private = private.as_ref().ok_or(KeyError::MissingPrivateKey)?;
402 let d = BigUint::from_bytes_be(&private.d);
403 let p = BigUint::from_bytes_be(&private.p);
404 let q = BigUint::from_bytes_be(&private.q);
405
406 let rsa = rsa::RsaPrivateKey::from_components(n, e, d, vec![p, q]);
407 let pem = rsa?.to_pkcs1_pem(rsa::pkcs1::LineEnding::LF);
408
409 EncodingKey::from_rsa_pem(pem?.as_bytes())?
410 }
411 };
412
413 Ok(self.encode.get_or_init(|| encoding_key))
414 }
415
416 pub fn decode(&self, token: &str) -> crate::Result<Claims> {
417 if !self.operations.contains(&KeyOperation::Verify) {
418 return Err(KeyError::VerifyUnsupported.into());
419 }
420
421 let decode = self.to_decoding_key()?;
422
423 let mut validation = jsonwebtoken::Validation::new(self.algorithm.into());
424 validation.required_spec_claims = Default::default(); validation.validate_exp = false; let token = jsonwebtoken::decode::<Claims>(token, decode, &validation)?;
428
429 if let Some(exp) = token.claims.expires
430 && exp < std::time::SystemTime::now()
431 {
432 return Err(crate::Error::TokenExpired);
433 }
434
435 token.claims.validate()?;
436
437 Ok(token.claims)
438 }
439
440 pub fn encode(&self, payload: &Claims) -> crate::Result<String> {
441 if !self.operations.contains(&KeyOperation::Sign) {
442 return Err(KeyError::SignUnsupported.into());
443 }
444
445 payload.validate()?;
446
447 let encode = self.to_encoding_key()?;
448
449 let mut header = Header::new(self.algorithm.into());
450 header.kid = self.kid.as_ref().map(|k| k.to_string());
451 let token = jsonwebtoken::encode(&header, &payload, encode)?;
452 Ok(token)
453 }
454
455 pub fn generate(algorithm: Algorithm, id: Option<crate::KeyId>) -> crate::Result<Self> {
457 generate(algorithm, id)
458 }
459}
460
461fn serialize_base64url<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
463where
464 S: Serializer,
465{
466 let encoded = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes);
467 serializer.serialize_str(&encoded)
468}
469
470fn serialize_base64url_optional<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
471where
472 S: Serializer,
473{
474 match bytes {
475 Some(b) => serialize_base64url(b, serializer),
476 None => serializer.serialize_none(),
477 }
478}
479
480fn deserialize_base64url<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
482where
483 D: Deserializer<'de>,
484{
485 let s = String::deserialize(deserializer)?;
486
487 base64::engine::general_purpose::URL_SAFE_NO_PAD
489 .decode(&s)
490 .or_else(|_| {
491 base64::engine::general_purpose::URL_SAFE.decode(&s)
493 })
494 .map_err(serde::de::Error::custom)
495}
496
497fn deserialize_base64url_optional<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
498where
499 D: Deserializer<'de>,
500{
501 let s: Option<String> = Option::deserialize(deserializer)?;
502 match s {
503 Some(s) => {
504 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD
505 .decode(&s)
506 .or_else(|_| base64::engine::general_purpose::URL_SAFE.decode(&s))
507 .map_err(serde::de::Error::custom)?;
508 Ok(Some(decoded))
509 }
510 None => Ok(None),
511 }
512}
513
514#[cfg(test)]
515mod tests {
516 use super::*;
517 use std::time::{Duration, SystemTime};
518
519 fn create_test_key() -> Key {
520 Key {
521 algorithm: Algorithm::HS256,
522 operations: [KeyOperation::Sign, KeyOperation::Verify].into(),
523 key: KeyType::OCT {
524 secret: b"test-secret-that-is-long-enough-for-hmac-sha256".to_vec(),
525 },
526 kid: Some(crate::KeyId::decode("test-key-1").unwrap()),
527 decode: Default::default(),
528 encode: Default::default(),
529 }
530 }
531
532 fn create_test_claims() -> Claims {
533 Claims {
534 root: "test-path".to_string(),
535 publish: vec!["test-pub".into()],
536 subscribe: vec!["test-sub".into()],
537 expires: Some(SystemTime::now() + Duration::from_secs(3600)),
538 issued: Some(SystemTime::now()),
539 }
540 }
541
542 #[test]
543 fn test_key_from_str_valid() {
544 let key = create_test_key();
545 let json = key.to_str().unwrap();
546 let loaded_key = Key::from_str(&json).unwrap();
547
548 assert_eq!(loaded_key.algorithm, key.algorithm);
549 assert_eq!(loaded_key.operations, key.operations);
550 match (loaded_key.key, key.key) {
551 (KeyType::OCT { secret: loaded_secret }, KeyType::OCT { secret }) => {
552 assert_eq!(loaded_secret, secret);
553 }
554 _ => panic!("Expected OCT key"),
555 }
556 assert_eq!(loaded_key.kid, key.kid);
557 }
558
559 #[test]
561 fn test_key_oct_backwards_compatibility() {
562 let json = r#"{"alg":"HS256","key_ops":["sign","verify"],"k":"Fp8kipWUJeUFqeSqWym_tRC_tyI8z-QpqopIGrbrD68"}"#;
563 let key = Key::from_str(json);
564
565 assert!(key.is_ok());
566 let key = key.unwrap();
567
568 if let KeyType::OCT { ref secret, .. } = key.key {
569 let base64_key = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(secret);
570 assert_eq!(base64_key, "Fp8kipWUJeUFqeSqWym_tRC_tyI8z-QpqopIGrbrD68");
571 } else {
572 panic!("Expected OCT key");
573 }
574
575 let key_str = key.to_str().unwrap();
576
577 let loaded = Key::from_str(&key_str).unwrap();
579 assert_eq!(loaded.algorithm, Algorithm::HS256);
580 assert!(loaded.operations.contains(&KeyOperation::Sign));
581 assert!(loaded.operations.contains(&KeyOperation::Verify));
582 assert!(matches!(loaded.key, KeyType::OCT { .. }));
583 }
584
585 #[test]
586 fn test_key_from_str_invalid_json() {
587 let result = Key::from_str("invalid json");
588 assert!(result.is_err());
589 }
590
591 #[test]
592 fn test_key_to_str() {
593 let key = create_test_key();
594 let encoded = key.to_str().unwrap();
595
596 assert!(!encoded.contains('{'));
598
599 let loaded = Key::from_str(&encoded).unwrap();
601 assert_eq!(loaded.algorithm, Algorithm::HS256);
602 assert_eq!(loaded.kid, key.kid);
603 assert!(loaded.operations.contains(&KeyOperation::Sign));
604 assert!(loaded.operations.contains(&KeyOperation::Verify));
605 }
606
607 #[test]
608 fn test_key_sign_success() {
609 let key = create_test_key();
610 let claims = create_test_claims();
611 let token = key.encode(&claims).unwrap();
612
613 assert!(!token.is_empty());
614 assert_eq!(token.matches('.').count(), 2); }
616
617 #[test]
618 fn test_key_sign_no_permission() {
619 let mut key = create_test_key();
620 key.operations = [KeyOperation::Verify].into();
621 let claims = create_test_claims();
622
623 let result = key.encode(&claims);
624 assert!(result.is_err());
625 assert!(result.unwrap_err().to_string().contains("key does not support signing"));
626 }
627
628 #[test]
629 fn test_key_sign_invalid_claims() {
630 let key = create_test_key();
631 let invalid_claims = Claims {
632 root: "test-path".to_string(),
633 publish: vec![],
634 subscribe: vec![],
635 expires: None,
636 issued: None,
637 };
638
639 let result = key.encode(&invalid_claims);
640 assert!(result.is_err());
641 assert!(
642 result
643 .unwrap_err()
644 .to_string()
645 .contains("no publish or subscribe allowed; token is useless")
646 );
647 }
648
649 #[test]
650 fn test_key_verify_success() {
651 let key = create_test_key();
652 let claims = create_test_claims();
653 let token = key.encode(&claims).unwrap();
654
655 let verified_claims = key.decode(&token).unwrap();
656 assert_eq!(verified_claims.root, claims.root);
657 assert_eq!(verified_claims.publish, claims.publish);
658 assert_eq!(verified_claims.subscribe, claims.subscribe);
659 }
660
661 #[test]
662 fn test_key_verify_no_permission() {
663 let mut key = create_test_key();
664 key.operations = [KeyOperation::Sign].into();
665
666 let result = key.decode("some.jwt.token");
667 assert!(result.is_err());
668 assert!(
669 result
670 .unwrap_err()
671 .to_string()
672 .contains("key does not support verification")
673 );
674 }
675
676 #[test]
677 fn test_key_verify_invalid_token() {
678 let key = create_test_key();
679 let result = key.decode("invalid-token");
680 assert!(result.is_err());
681 }
682
683 #[test]
684 fn test_key_verify_path_mismatch() {
685 let key = create_test_key();
686 let claims = create_test_claims();
687 let token = key.encode(&claims).unwrap();
688
689 let result = key.decode(&token);
691 assert!(result.is_ok());
692 }
693
694 #[test]
695 fn test_key_verify_expired_token() {
696 let key = create_test_key();
697 let mut claims = create_test_claims();
698 claims.expires = Some(SystemTime::now() - Duration::from_secs(3600)); let token = key.encode(&claims).unwrap();
700
701 let result = key.decode(&token);
702 assert!(result.is_err());
703 }
704
705 #[test]
706 fn test_key_verify_token_without_exp() {
707 let key = create_test_key();
708 let claims = Claims {
709 root: "test-path".to_string(),
710 publish: vec!["".to_string()],
711 subscribe: vec!["".to_string()],
712 expires: None,
713 issued: None,
714 };
715 let token = key.encode(&claims).unwrap();
716
717 let verified_claims = key.decode(&token).unwrap();
718 assert_eq!(verified_claims.root, claims.root);
719 assert_eq!(verified_claims.publish, claims.publish);
720 assert_eq!(verified_claims.subscribe, claims.subscribe);
721 assert_eq!(verified_claims.expires, None);
722 }
723
724 #[test]
725 fn test_key_round_trip() {
726 let key = create_test_key();
727 let original_claims = Claims {
728 root: "test-path".to_string(),
729 publish: vec!["test-pub".into()],
730 subscribe: vec!["test-sub".into()],
731 expires: Some(SystemTime::now() + Duration::from_secs(3600)),
732 issued: Some(SystemTime::now()),
733 };
734
735 let token = key.encode(&original_claims).unwrap();
736 let verified_claims = key.decode(&token).unwrap();
737
738 assert_eq!(verified_claims.root, original_claims.root);
739 assert_eq!(verified_claims.publish, original_claims.publish);
740 assert_eq!(verified_claims.subscribe, original_claims.subscribe);
741 }
742
743 #[test]
744 fn test_key_generate_hs256() {
745 let key = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
746 assert!(key.is_ok());
747 let key = key.unwrap();
748
749 assert_eq!(key.algorithm, Algorithm::HS256);
750 assert_eq!(key.kid, Some(crate::KeyId::decode("test-id").unwrap()));
751 assert_eq!(key.operations, [KeyOperation::Sign, KeyOperation::Verify].into());
752
753 match key.key {
754 KeyType::OCT { ref secret } => assert_eq!(secret.len(), 32),
755 _ => panic!("Expected OCT key"),
756 }
757 }
758
759 #[test]
760 fn test_key_generate_hs384() {
761 let key = Key::generate(Algorithm::HS384, Some(crate::KeyId::decode("test-id").unwrap()));
762 assert!(key.is_ok());
763 let key = key.unwrap();
764
765 assert_eq!(key.algorithm, Algorithm::HS384);
766
767 match key.key {
768 KeyType::OCT { ref secret } => assert_eq!(secret.len(), 48),
769 _ => panic!("Expected OCT key"),
770 }
771 }
772
773 #[test]
774 fn test_key_generate_hs512() {
775 let key = Key::generate(Algorithm::HS512, Some(crate::KeyId::decode("test-id").unwrap()));
776 assert!(key.is_ok());
777 let key = key.unwrap();
778
779 assert_eq!(key.algorithm, Algorithm::HS512);
780
781 match key.key {
782 KeyType::OCT { ref secret } => assert_eq!(secret.len(), 64),
783 _ => panic!("Expected OCT key"),
784 }
785 }
786
787 #[test]
788 fn test_key_generate_rs512() {
789 let key = Key::generate(Algorithm::RS512, Some(crate::KeyId::decode("test-id").unwrap()));
790 assert!(key.is_ok());
791 let key = key.unwrap();
792
793 assert_eq!(key.algorithm, Algorithm::RS512);
794 assert!(matches!(key.key, KeyType::RSA { .. }));
795 match key.key {
796 KeyType::RSA {
797 ref public,
798 ref private,
799 } => {
800 assert!(private.is_some());
801 assert_eq!(public.n.len(), 256);
802 assert_eq!(public.e.len(), 3);
803 }
804 _ => panic!("Expected RSA key"),
805 }
806 }
807
808 #[test]
809 fn test_key_generate_es256() {
810 let key = Key::generate(Algorithm::ES256, Some(crate::KeyId::decode("test-id").unwrap()));
811 assert!(key.is_ok());
812 let key = key.unwrap();
813
814 assert_eq!(key.algorithm, Algorithm::ES256);
815 assert!(matches!(key.key, KeyType::EC { .. }))
816 }
817
818 #[test]
819 fn test_key_generate_ps512() {
820 let key = Key::generate(Algorithm::PS512, Some(crate::KeyId::decode("test-id").unwrap()));
821 assert!(key.is_ok());
822 let key = key.unwrap();
823
824 assert_eq!(key.algorithm, Algorithm::PS512);
825 assert!(matches!(key.key, KeyType::RSA { .. }));
826 }
827
828 #[test]
829 fn test_key_generate_eddsa() {
830 let key = Key::generate(Algorithm::EdDSA, Some(crate::KeyId::decode("test-id").unwrap()));
831 assert!(key.is_ok());
832 let key = key.unwrap();
833
834 assert_eq!(key.algorithm, Algorithm::EdDSA);
835 assert!(matches!(key.key, KeyType::OKP { .. }));
836 }
837
838 #[test]
839 fn test_key_generate_without_id() {
840 let key = Key::generate(Algorithm::HS256, None);
841 assert!(key.is_ok());
842 let key = key.unwrap();
843
844 assert_eq!(key.algorithm, Algorithm::HS256);
845 assert_eq!(key.kid, None);
846 assert_eq!(key.operations, [KeyOperation::Sign, KeyOperation::Verify].into());
847 }
848
849 #[test]
850 fn test_public_key_conversion_hmac() {
851 let key = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()))
852 .expect("HMAC key generation failed");
853
854 assert!(key.to_public().is_err());
855 }
856
857 #[test]
858 fn test_public_key_conversion_rsa() {
859 let key = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
860 assert!(key.is_ok());
861 let key = key.unwrap();
862
863 let public_key = key.to_public().unwrap();
864 assert_eq!(key.kid, public_key.kid);
865 assert_eq!(public_key.operations, [KeyOperation::Verify].into());
866 assert!(public_key.encode.get().is_none());
867 assert!(public_key.decode.get().is_none());
868 assert!(matches!(public_key.key, KeyType::RSA { .. }));
869
870 if let KeyType::RSA { public, private } = &public_key.key {
871 assert!(private.is_none());
872
873 if let KeyType::RSA { public: src_public, .. } = &key.key {
874 assert_eq!(public.e, src_public.e);
875 assert_eq!(public.n, src_public.n);
876 } else {
877 unreachable!("Expected RSA key")
878 }
879 } else {
880 unreachable!("Expected RSA key");
881 }
882 }
883
884 #[test]
885 fn test_public_key_conversion_es() {
886 let key = Key::generate(Algorithm::ES256, Some(crate::KeyId::decode("test-id").unwrap()));
887 assert!(key.is_ok());
888 let key = key.unwrap();
889
890 let public_key = key.to_public().unwrap();
891 assert_eq!(key.kid, public_key.kid);
892 assert_eq!(public_key.operations, [KeyOperation::Verify].into());
893 assert!(public_key.encode.get().is_none());
894 assert!(public_key.decode.get().is_none());
895 assert!(matches!(public_key.key, KeyType::EC { .. }));
896
897 if let KeyType::EC { x, y, d, curve } = &public_key.key {
898 assert!(d.is_none());
899
900 if let KeyType::EC {
901 x: src_x,
902 y: src_y,
903 curve: src_curve,
904 ..
905 } = &key.key
906 {
907 assert_eq!(x, src_x);
908 assert_eq!(y, src_y);
909 assert_eq!(curve, src_curve);
910 } else {
911 unreachable!("Expected EC key")
912 }
913 } else {
914 unreachable!("Expected EC key");
915 }
916 }
917
918 #[test]
919 fn test_public_key_conversion_ed() {
920 let key = Key::generate(Algorithm::EdDSA, Some(crate::KeyId::decode("test-id").unwrap()));
921 assert!(key.is_ok());
922 let key = key.unwrap();
923
924 let public_key = key.to_public().unwrap();
925 assert_eq!(key.kid, public_key.kid);
926 assert_eq!(public_key.operations, [KeyOperation::Verify].into());
927 assert!(public_key.encode.get().is_none());
928 assert!(public_key.decode.get().is_none());
929 assert!(matches!(public_key.key, KeyType::OKP { .. }));
930
931 if let KeyType::OKP { x, d, curve } = &public_key.key {
932 assert!(d.is_none());
933
934 if let KeyType::OKP {
935 x: src_x,
936 curve: src_curve,
937 ..
938 } = &key.key
939 {
940 assert_eq!(x, src_x);
941 assert_eq!(curve, src_curve);
942 } else {
943 unreachable!("Expected OKP key")
944 }
945 } else {
946 unreachable!("Expected OKP key");
947 }
948 }
949
950 #[test]
951 fn test_key_generate_sign_verify_cycle() {
952 let key = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
953 assert!(key.is_ok());
954 let key = key.unwrap();
955
956 let claims = create_test_claims();
957
958 let token = key.encode(&claims).unwrap();
959 let verified_claims = key.decode(&token).unwrap();
960
961 assert_eq!(verified_claims.root, claims.root);
962 assert_eq!(verified_claims.publish, claims.publish);
963 assert_eq!(verified_claims.subscribe, claims.subscribe);
964 }
965
966 #[test]
967 fn test_key_debug_no_secret() {
968 let key = create_test_key();
969 let debug_str = format!("{key:?}");
970
971 assert!(debug_str.contains("algorithm: HS256"));
972 assert!(debug_str.contains("operations"));
973 assert!(debug_str.contains("kid: Some(KeyId(\"test-key-1\"))"));
974 assert!(!debug_str.contains("secret")); }
976
977 #[test]
978 fn test_key_operations_enum() {
979 let sign_op = KeyOperation::Sign;
980 let verify_op = KeyOperation::Verify;
981 let decrypt_op = KeyOperation::Decrypt;
982 let encrypt_op = KeyOperation::Encrypt;
983
984 assert_eq!(sign_op, KeyOperation::Sign);
985 assert_eq!(verify_op, KeyOperation::Verify);
986 assert_eq!(decrypt_op, KeyOperation::Decrypt);
987 assert_eq!(encrypt_op, KeyOperation::Encrypt);
988
989 assert_ne!(sign_op, verify_op);
990 assert_ne!(decrypt_op, encrypt_op);
991 }
992
993 #[test]
994 fn test_key_operations_serde() {
995 let operations = [KeyOperation::Sign, KeyOperation::Verify];
996 let json = serde_json::to_string(&operations).unwrap();
997 assert!(json.contains("\"sign\""));
998 assert!(json.contains("\"verify\""));
999
1000 let deserialized: Vec<KeyOperation> = serde_json::from_str(&json).unwrap();
1001 assert_eq!(deserialized, operations);
1002 }
1003
1004 #[test]
1005 fn test_key_serde() {
1006 let key = create_test_key();
1007 let json = serde_json::to_string(&key).unwrap();
1008 let deserialized: Key = serde_json::from_str(&json).unwrap();
1009
1010 assert_eq!(deserialized.algorithm, key.algorithm);
1011 assert_eq!(deserialized.operations, key.operations);
1012 assert_eq!(deserialized.kid, key.kid);
1013
1014 if let (
1015 KeyType::OCT {
1016 secret: original_secret,
1017 },
1018 KeyType::OCT {
1019 secret: deserialized_secret,
1020 },
1021 ) = (&key.key, &deserialized.key)
1022 {
1023 assert_eq!(deserialized_secret, original_secret);
1024 } else {
1025 panic!("Expected both keys to be OCT variant");
1026 }
1027 }
1028
1029 #[test]
1030 fn test_key_clone() {
1031 let key = create_test_key();
1032 let cloned = key.clone();
1033
1034 assert_eq!(cloned.algorithm, key.algorithm);
1035 assert_eq!(cloned.operations, key.operations);
1036 assert_eq!(cloned.kid, key.kid);
1037
1038 if let (
1039 KeyType::OCT {
1040 secret: original_secret,
1041 },
1042 KeyType::OCT { secret: cloned_secret },
1043 ) = (&key.key, &cloned.key)
1044 {
1045 assert_eq!(cloned_secret, original_secret);
1046 } else {
1047 panic!("Expected both keys to be OCT variant");
1048 }
1049 }
1050
1051 #[test]
1052 fn test_hmac_algorithms() {
1053 let key_256 = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
1054 let key_384 = Key::generate(Algorithm::HS384, Some(crate::KeyId::decode("test-id").unwrap()));
1055 let key_512 = Key::generate(Algorithm::HS512, Some(crate::KeyId::decode("test-id").unwrap()));
1056
1057 let claims = create_test_claims();
1058
1059 for key in [key_256, key_384, key_512] {
1061 assert!(key.is_ok());
1062 let key = key.unwrap();
1063
1064 let token = key.encode(&claims).unwrap();
1065 let verified_claims = key.decode(&token).unwrap();
1066 assert_eq!(verified_claims.root, claims.root);
1067 }
1068 }
1069
1070 #[test]
1071 fn test_rsa_pkcs1_asymmetric_algorithms() {
1072 let key_rs256 = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
1073 let key_rs384 = Key::generate(Algorithm::RS384, Some(crate::KeyId::decode("test-id").unwrap()));
1074 let key_rs512 = Key::generate(Algorithm::RS512, Some(crate::KeyId::decode("test-id").unwrap()));
1075
1076 for key in [key_rs256, key_rs384, key_rs512] {
1077 test_asymmetric_key(key);
1078 }
1079 }
1080
1081 #[test]
1082 fn test_rsa_pss_asymmetric_algorithms() {
1083 let key_ps256 = Key::generate(Algorithm::PS256, Some(crate::KeyId::decode("test-id").unwrap()));
1084 let key_ps384 = Key::generate(Algorithm::PS384, Some(crate::KeyId::decode("test-id").unwrap()));
1085 let key_ps512 = Key::generate(Algorithm::PS512, Some(crate::KeyId::decode("test-id").unwrap()));
1086
1087 for key in [key_ps256, key_ps384, key_ps512] {
1088 test_asymmetric_key(key);
1089 }
1090 }
1091
1092 #[test]
1093 fn test_ec_asymmetric_algorithms() {
1094 let key_es256 = Key::generate(Algorithm::ES256, Some(crate::KeyId::decode("test-id").unwrap()));
1095 let key_es384 = Key::generate(Algorithm::ES384, Some(crate::KeyId::decode("test-id").unwrap()));
1096
1097 for key in [key_es256, key_es384] {
1098 test_asymmetric_key(key);
1099 }
1100 }
1101
1102 #[test]
1103 fn test_ed_asymmetric_algorithms() {
1104 let key_eddsa = Key::generate(Algorithm::EdDSA, Some(crate::KeyId::decode("test-id").unwrap()));
1105
1106 test_asymmetric_key(key_eddsa);
1107 }
1108
1109 fn test_asymmetric_key(key: crate::Result<Key>) {
1110 assert!(key.is_ok());
1111 let key = key.unwrap();
1112
1113 let claims = create_test_claims();
1114 let token = key.encode(&claims).unwrap();
1115
1116 let private_verified_claims = key.decode(&token).unwrap();
1117 assert_eq!(
1118 private_verified_claims.root, claims.root,
1119 "validation using private key"
1120 );
1121
1122 let public_verified_claims = key.to_public().unwrap().decode(&token).unwrap();
1123 assert_eq!(public_verified_claims.root, claims.root, "validation using public key");
1124 }
1125
1126 #[test]
1127 fn test_cross_algorithm_verification_fails() {
1128 let key_256 = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
1129 assert!(key_256.is_ok());
1130 let key_256 = key_256.unwrap();
1131
1132 let key_384 = Key::generate(Algorithm::HS384, Some(crate::KeyId::decode("test-id").unwrap()));
1133 assert!(key_384.is_ok());
1134 let key_384 = key_384.unwrap();
1135
1136 let claims = create_test_claims();
1137 let token = key_256.encode(&claims).unwrap();
1138
1139 let result = key_384.decode(&token);
1141 assert!(result.is_err());
1142 }
1143
1144 #[test]
1145 fn test_asymmetric_cross_algorithm_verification_fails() {
1146 let key_rs256 = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
1147 assert!(key_rs256.is_ok());
1148 let key_rs256 = key_rs256.unwrap();
1149
1150 let key_ps256 = Key::generate(Algorithm::PS256, Some(crate::KeyId::decode("test-id").unwrap()));
1151 assert!(key_ps256.is_ok());
1152 let key_ps256 = key_ps256.unwrap();
1153
1154 let claims = create_test_claims();
1155 let token = key_rs256.encode(&claims).unwrap();
1156
1157 let private_result = key_ps256.decode(&token);
1159 let public_result = key_ps256.to_public().unwrap().decode(&token);
1160 assert!(private_result.is_err());
1161 assert!(public_result.is_err());
1162 }
1163
1164 #[test]
1165 fn test_rsa_pkcs1_public_key_conversion() {
1166 let key = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
1167 assert!(key.is_ok());
1168 let key = key.unwrap();
1169
1170 assert!(key.operations.contains(&KeyOperation::Sign));
1171 assert!(key.operations.contains(&KeyOperation::Verify));
1172
1173 let public_key = key.to_public().unwrap();
1174 assert!(!public_key.operations.contains(&KeyOperation::Sign));
1175 assert!(public_key.operations.contains(&KeyOperation::Verify));
1176
1177 match key.key {
1178 KeyType::RSA {
1179 ref public,
1180 ref private,
1181 } => {
1182 assert!(private.is_some());
1183 assert_eq!(public.n.len(), 256);
1184 assert_eq!(public.e.len(), 3);
1185
1186 match public_key.key {
1187 KeyType::RSA {
1188 public: ref guest_public,
1189 private: ref public_private,
1190 } => {
1191 assert!(public_private.is_none());
1192 assert_eq!(public.n, guest_public.n);
1193 assert_eq!(public.e, guest_public.e);
1194 }
1195 _ => panic!("Expected public key to be an RSA key"),
1196 }
1197 }
1198 _ => panic!("Expected private key to be an RSA key"),
1199 }
1200 }
1201
1202 #[test]
1203 fn test_rsa_pss_public_key_conversion() {
1204 let key = Key::generate(Algorithm::PS384, Some(crate::KeyId::decode("test-id").unwrap()));
1205 assert!(key.is_ok());
1206 let key = key.unwrap();
1207
1208 assert!(key.operations.contains(&KeyOperation::Sign));
1209 assert!(key.operations.contains(&KeyOperation::Verify));
1210
1211 let public_key = key.to_public().unwrap();
1212 assert!(!public_key.operations.contains(&KeyOperation::Sign));
1213 assert!(public_key.operations.contains(&KeyOperation::Verify));
1214
1215 match key.key {
1216 KeyType::RSA {
1217 ref public,
1218 ref private,
1219 } => {
1220 assert!(private.is_some());
1221 assert_eq!(public.n.len(), 256);
1222 assert_eq!(public.e.len(), 3);
1223
1224 match public_key.key {
1225 KeyType::RSA {
1226 public: ref guest_public,
1227 private: ref public_private,
1228 } => {
1229 assert!(public_private.is_none());
1230 assert_eq!(public.n, guest_public.n);
1231 assert_eq!(public.e, guest_public.e);
1232 }
1233 _ => panic!("Expected public key to be an RSA key"),
1234 }
1235 }
1236 _ => panic!("Expected private key to be an RSA key"),
1237 }
1238 }
1239
1240 #[test]
1241 fn test_base64url_serialization() {
1242 let key = create_test_key();
1243 let json = serde_json::to_string(&key).unwrap();
1244
1245 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
1247 let k_value = parsed["k"].as_str().unwrap();
1248
1249 assert!(!k_value.contains('='));
1251 assert!(!k_value.contains('+'));
1252 assert!(!k_value.contains('/'));
1253
1254 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD
1256 .decode(k_value)
1257 .unwrap();
1258
1259 if let KeyType::OCT {
1260 secret: original_secret,
1261 } = &key.key
1262 {
1263 assert_eq!(decoded, *original_secret);
1264 } else {
1265 panic!("Expected both keys to be OCT variant");
1266 }
1267 }
1268
1269 #[test]
1270 fn test_backwards_compatibility_unpadded_base64url() {
1271 let unpadded_json = r#"{"kty":"oct","alg":"HS256","key_ops":["sign","verify"],"k":"dGVzdC1zZWNyZXQtdGhhdC1pcy1sb25nLWVub3VnaC1mb3ItaG1hYy1zaGEyNTY","kid":"test-key-1"}"#;
1273
1274 let key: Key = serde_json::from_str(unpadded_json).unwrap();
1276 assert_eq!(key.algorithm, Algorithm::HS256);
1277 assert_eq!(key.kid, Some(crate::KeyId::decode("test-key-1").unwrap()));
1278
1279 if let KeyType::OCT { secret } = &key.key {
1280 assert_eq!(secret, b"test-secret-that-is-long-enough-for-hmac-sha256");
1281 } else {
1282 panic!("Expected key to be OCT variant");
1283 }
1284 }
1285
1286 #[test]
1287 fn test_backwards_compatibility_padded_base64url() {
1288 let padded_json = r#"{"kty":"oct","alg":"HS256","key_ops":["sign","verify"],"k":"dGVzdC1zZWNyZXQtdGhhdC1pcy1sb25nLWVub3VnaC1mb3ItaG1hYy1zaGEyNTY=","kid":"test-key-1"}"#;
1290
1291 let key: Key = serde_json::from_str(padded_json).unwrap();
1293 assert_eq!(key.algorithm, Algorithm::HS256);
1294 assert_eq!(key.kid, Some(crate::KeyId::decode("test-key-1").unwrap()));
1295
1296 if let KeyType::OCT { secret } = &key.key {
1297 assert_eq!(secret, b"test-secret-that-is-long-enough-for-hmac-sha256");
1298 } else {
1299 panic!("Expected key to be OCT variant");
1300 }
1301 }
1302
1303 const JS_HS256_KEY: &str = r#"{"kty":"oct","alg":"HS256","k":"xm6xsSkfFqzPU3KfcbAcF2_h0OkStxQ_nNqVPYl0ync","kid":"js-test-key","key_ops":["sign","verify"],"guest":[],"guest_sub":[],"guest_pub":[]}"#;
1311
1312 const JS_HS256_TOKEN: &str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImpzLXRlc3Qta2V5In0.eyJyb290IjoibGl2ZSIsInB1dCI6WyJjYW1lcmExIl0sImdldCI6WyJjYW1lcmExIiwiY2FtZXJhMiJdLCJpYXQiOjE3NzUxNzY3NTR9.tHNQtHh_HCIKxXOexDCM7AkjqWzbULLZzjEckfOGRfY";
1314
1315 const JS_EDDSA_PRIVATE_KEY: &str = r#"{"kty":"OKP","alg":"EdDSA","crv":"Ed25519","x":"UiU9fT_SdBBpkFtJPRCY0gX1jK_Dr9syYLFuEz4QUM4","d":"lm-L_PV3ksuQ-KrFBgFMDJqAZC3_Z6Z5UC4ZQY5OoDQ","kid":"js-eddsa-key","key_ops":["sign","verify"],"guest":[],"guest_sub":[],"guest_pub":[]}"#;
1317
1318 const JS_EDDSA_PUBLIC_KEY: &str = r#"{"kty":"OKP","alg":"EdDSA","crv":"Ed25519","x":"UiU9fT_SdBBpkFtJPRCY0gX1jK_Dr9syYLFuEz4QUM4","kid":"js-eddsa-key","guest":[],"guest_sub":[],"guest_pub":[],"key_ops":["verify"]}"#;
1320
1321 const JS_EDDSA_TOKEN: &str = "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImpzLWVkZHNhLWtleSJ9.eyJyb290Ijoic3RyZWFtIiwicHV0IjpbInZpZGVvIl0sImlhdCI6MTc3NTE3Njc1Nn0.l9rUMHjPSXWKSXRP3mmeMgTAywtqpdqQehhViWaPrKxax1Y2D9KRIYTixYz-b6PI-AoHQYusHWeeLu_HRw2cAg";
1323
1324 #[test]
1325 fn test_js_hs256_key_load() {
1326 let key = Key::from_str(JS_HS256_KEY).unwrap();
1327 assert_eq!(key.algorithm, Algorithm::HS256);
1328 assert_eq!(key.kid, Some(crate::KeyId::decode("js-test-key").unwrap()));
1329 }
1330
1331 #[test]
1332 fn test_js_hs256_token_verify() {
1333 let key = Key::from_str(JS_HS256_KEY).unwrap();
1334 let claims = key.decode(JS_HS256_TOKEN).unwrap();
1335 assert_eq!(claims.root, "live");
1336 assert_eq!(claims.publish, vec!["camera1"]);
1337 assert_eq!(claims.subscribe, vec!["camera1", "camera2"]);
1338 }
1339
1340 #[test]
1341 fn test_js_hs256_sign_and_roundtrip() {
1342 let key = Key::from_str(JS_HS256_KEY).unwrap();
1343 let claims = Claims {
1344 root: "rust-test".to_string(),
1345 publish: vec!["pub1".into()],
1346 subscribe: vec!["sub1".into()],
1347 ..Default::default()
1348 };
1349 let token = key.encode(&claims).unwrap();
1350 let verified = key.decode(&token).unwrap();
1351 assert_eq!(verified.root, "rust-test");
1352 assert_eq!(verified.publish, vec!["pub1"]);
1353 }
1354
1355 #[test]
1356 fn test_js_eddsa_key_load() {
1357 let private_key = Key::from_str(JS_EDDSA_PRIVATE_KEY).unwrap();
1358 assert_eq!(private_key.algorithm, Algorithm::EdDSA);
1359 assert!(matches!(private_key.key, KeyType::OKP { .. }));
1360
1361 let public_key = Key::from_str(JS_EDDSA_PUBLIC_KEY).unwrap();
1362 assert_eq!(public_key.algorithm, Algorithm::EdDSA);
1363 }
1364
1365 #[test]
1366 fn test_js_eddsa_token_verify_with_private_key() {
1367 let key = Key::from_str(JS_EDDSA_PRIVATE_KEY).unwrap();
1368 let claims = key.decode(JS_EDDSA_TOKEN).unwrap();
1369 assert_eq!(claims.root, "stream");
1370 assert_eq!(claims.publish, vec!["video"]);
1371 }
1372
1373 #[test]
1374 fn test_js_eddsa_token_verify_with_public_key() {
1375 let key = Key::from_str(JS_EDDSA_PUBLIC_KEY).unwrap();
1376 let claims = key.decode(JS_EDDSA_TOKEN).unwrap();
1377 assert_eq!(claims.root, "stream");
1378 assert_eq!(claims.publish, vec!["video"]);
1379 }
1380
1381 #[test]
1382 fn test_js_token_wrong_key_fails() {
1383 let wrong_key = Key::generate(Algorithm::HS256, None).unwrap();
1385 let result = wrong_key.decode(JS_HS256_TOKEN);
1386 assert!(result.is_err());
1387 }
1388
1389 #[test]
1390 fn test_js_eddsa_token_wrong_key_fails() {
1391 let wrong_key = Key::from_str(JS_HS256_KEY).unwrap();
1393 let result = wrong_key.decode(JS_EDDSA_TOKEN);
1394 assert!(result.is_err());
1395 }
1396
1397 #[test]
1398 fn test_file_io_base64url() {
1399 let key = create_test_key();
1400 let temp_dir = std::env::temp_dir();
1401 let temp_path = temp_dir.join("test_jwk.key");
1402
1403 key.to_file(&temp_path).unwrap();
1405
1406 let contents = std::fs::read_to_string(&temp_path).unwrap();
1408
1409 assert!(!contents.contains('{'));
1411 assert!(!contents.contains('}'));
1412 assert!(!contents.contains('"'));
1413
1414 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD
1416 .decode(&contents)
1417 .unwrap();
1418 let json_str = String::from_utf8(decoded).unwrap();
1419 let _: serde_json::Value = serde_json::from_str(&json_str).unwrap();
1420
1421 let loaded_key = Key::from_file(&temp_path).unwrap();
1423 assert_eq!(loaded_key.algorithm, key.algorithm);
1424 assert_eq!(loaded_key.operations, key.operations);
1425 assert_eq!(loaded_key.kid, key.kid);
1426
1427 if let (
1428 KeyType::OCT {
1429 secret: original_secret,
1430 },
1431 KeyType::OCT { secret: loaded_secret },
1432 ) = (&key.key, &loaded_key.key)
1433 {
1434 assert_eq!(loaded_secret, original_secret);
1435 } else {
1436 panic!("Expected both keys to be OCT variant");
1437 }
1438
1439 std::fs::remove_file(temp_path).ok();
1441 }
1442
1443 #[test]
1444 fn test_file_io_raw_json() {
1445 let key = create_test_key();
1446 let temp_dir = std::env::temp_dir();
1447 let temp_path = temp_dir.join("test_jwk_raw_json.key");
1448
1449 let json = serde_json::to_string(&key).unwrap();
1451 std::fs::write(&temp_path, &json).unwrap();
1452
1453 assert!(json.starts_with('{'));
1455
1456 let loaded_key = Key::from_file(&temp_path).unwrap();
1458 assert_eq!(loaded_key.algorithm, key.algorithm);
1459 assert_eq!(loaded_key.operations, key.operations);
1460 assert_eq!(loaded_key.kid, key.kid);
1461
1462 if let (
1463 KeyType::OCT {
1464 secret: original_secret,
1465 },
1466 KeyType::OCT { secret: loaded_secret },
1467 ) = (&key.key, &loaded_key.key)
1468 {
1469 assert_eq!(loaded_secret, original_secret);
1470 } else {
1471 panic!("Expected both keys to be OCT variant");
1472 }
1473
1474 std::fs::remove_file(temp_path).ok();
1476 }
1477}