1use crypto::{
2 curve25519::ed25519,
3 mldsa::{
4 MlDsa44PublicKey, MlDsa44SecretKey, MlDsa65PublicKey, MlDsa65SecretKey, MlDsa87PublicKey, MlDsa87SecretKey,
5 },
6 p256, p384, p521,
7};
8use serde::{Deserialize, Serialize};
9use small_collections::SmallString;
10use smallvec::SmallVec;
11
12use crate::{Algorithm, Error, RsaPublicKey, SecretKey};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct Jwks {
16 pub keys: SmallVec<Jwk, 5>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct Jwk {
26 pub kid: SmallString<36>, pub r#use: KeyUse,
28 #[serde(rename = "alg")]
29 pub algorithm: Algorithm,
30
31 #[serde(flatten)]
32 pub crypto: JwkCrypto,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "UPPERCASE", tag = "kty")]
37pub enum JwkCrypto {
38 Okp {
40 #[serde(rename = "crv")]
41 curve: OkpCurve,
42 #[serde(with = "base64_url_no_padding")]
43 x: SmallVec<u8, 32>,
44 #[serde(with = "base64_url_no_padding::option", skip_serializing_if = "Option::is_none")]
45 d: Option<SmallVec<u8, 32>>,
46 },
47 Ec {
49 #[serde(rename = "crv")]
50 curve: EcCurve,
51 #[serde(with = "base64_url_no_padding")]
52 x: SmallVec<u8, 32>,
53 #[serde(with = "base64_url_no_padding")]
54 y: SmallVec<u8, 32>,
55 #[serde(with = "base64_url_no_padding::option", skip_serializing_if = "Option::is_none")]
56 d: Option<SmallVec<u8, 32>>,
57 },
58 #[serde(rename = "oct")]
60 Oct {
61 #[serde(with = "base64_url_no_padding")]
62 key: SmallVec<u8, 32>,
63 },
64 #[serde(rename = "RSA")]
66 Rsa {
67 #[serde(with = "base64_url_no_padding")]
70 n: SmallVec<u8, 0>,
71 #[serde(with = "base64_url_no_padding")]
72 e: SmallVec<u8, 4>,
73 },
74 #[serde(rename = "AKP")]
79 Akp {
80 #[serde(rename = "pub", with = "base64_url_no_padding")]
81 pub_key: SmallVec<u8, 0>,
82 #[serde(
83 rename = "priv",
84 with = "base64_url_no_padding::option",
85 skip_serializing_if = "Option::is_none"
86 )]
87 private_key: Option<SmallVec<u8, 0>>,
88 },
89}
90
91#[derive(Copy, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
92pub enum KeyUse {
93 #[serde(rename = "sig")]
94 Sign,
95 #[serde(rename = "enc")]
96 Encrypt,
97}
98
99#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
103pub enum OkpCurve {
104 Ed25519,
105}
106
107impl core::str::FromStr for OkpCurve {
108 type Err = Error;
109
110 fn from_str(s: &str) -> Result<Self, Self::Err> {
111 match s {
112 "Ed25519" => Ok(OkpCurve::Ed25519),
113 _ => Err(Error::InvalidCurve),
114 }
115 }
116}
117
118impl core::fmt::Display for OkpCurve {
119 fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
120 write!(f, "{self:?}")
121 }
122}
123
124#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
125pub enum EcCurve {
126 #[serde(rename = "P-256")]
128 P256,
129
130 #[serde(rename = "P-384")]
132 P384,
133
134 #[serde(rename = "P-521")]
136 P521,
137}
138
139impl From<&SecretKey<'_>> for Jwk {
144 #[inline]
145 fn from(key: &SecretKey<'_>) -> Self {
146 return Jwk {
147 kid: SmallString::new(),
148 r#use: KeyUse::Sign,
149 algorithm: key.algorithm,
150 crypto: JwkCrypto::Oct {
151 key: key.key.into(),
152 },
153 };
154 }
155}
156
157impl<'a> TryFrom<&'a Jwk> for SecretKey<'a> {
158 type Error = Error;
159
160 #[inline]
161 fn try_from(jwk: &'a Jwk) -> Result<Self, Self::Error> {
162 if !matches!(
163 jwk.algorithm,
164 Algorithm::BLAKE3 | Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512
165 ) {
166 return Err(Error::InvalidKey);
167 }
168
169 match &jwk.crypto {
170 JwkCrypto::Oct {
171 key,
172 } => Ok(SecretKey::new(jwk.algorithm, key.as_slice())),
173 _ => Err(Error::InvalidKey),
174 }
175 }
176}
177
178impl From<&ed25519::SecretKey> for Jwk {
183 #[inline]
184 fn from(key: &ed25519::SecretKey) -> Self {
185 return Jwk {
186 kid: SmallString::new(),
187 r#use: KeyUse::Sign,
188 algorithm: Algorithm::EdDSA,
189 crypto: JwkCrypto::Okp {
190 curve: OkpCurve::Ed25519,
191 x: key.public_key().to_bytes().into(),
192 d: Some(key.to_bytes().into()),
193 },
194 };
195 }
196}
197
198impl From<&ed25519::PublicKey> for Jwk {
199 #[inline]
200 fn from(key: &ed25519::PublicKey) -> Self {
201 return Jwk {
202 kid: SmallString::new(),
203 r#use: KeyUse::Sign,
204 algorithm: Algorithm::EdDSA,
205 crypto: JwkCrypto::Okp {
206 curve: OkpCurve::Ed25519,
207 x: key.to_bytes().into(),
208 d: None,
209 },
210 };
211 }
212}
213
214impl TryFrom<&Jwk> for ed25519::SecretKey {
215 type Error = Error;
216
217 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
218 match &jwk.crypto {
219 JwkCrypto::Okp {
220 curve: OkpCurve::Ed25519,
221 d: Some(d_bytes),
222 ..
223 } => {
224 let seed: [u8; 32] = d_bytes.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
225 Ok(ed25519::SecretKey::from_bytes(&seed))
226 }
227 _ => Err(Error::InvalidKey),
228 }
229 }
230}
231
232impl TryFrom<&Jwk> for ed25519::PublicKey {
233 type Error = Error;
234
235 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
236 match &jwk.crypto {
237 JwkCrypto::Okp {
238 curve: OkpCurve::Ed25519,
239 x,
240 ..
241 } => {
242 let public_key: [u8; 32] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
243 ed25519::PublicKey::from_bytes(&public_key).map_err(|_| Error::InvalidKey)
244 }
245 _ => Err(Error::InvalidKey),
246 }
247 }
248}
249
250impl From<&p256::SecretKey> for Jwk {
255 #[inline]
256 fn from(key: &p256::SecretKey) -> Self {
257 let (x, y) = key.public_key().x_y();
258 return Jwk {
259 kid: SmallString::new(),
260 r#use: KeyUse::Sign,
261 algorithm: Algorithm::ES256,
262 crypto: JwkCrypto::Ec {
263 curve: EcCurve::P256,
264 x: x.into(),
265 y: y.into(),
266 d: Some(key.to_bytes().into()),
267 },
268 };
269 }
270}
271
272impl From<&p256::PublicKey> for Jwk {
273 #[inline]
274 fn from(key: &p256::PublicKey) -> Self {
275 let (x, y) = key.x_y();
276 return Jwk {
277 kid: SmallString::new(),
278 r#use: KeyUse::Sign,
279 algorithm: Algorithm::ES256,
280 crypto: JwkCrypto::Ec {
281 curve: EcCurve::P256,
282 x: x.into(),
283 y: y.into(),
284 d: None,
285 },
286 };
287 }
288}
289
290impl TryFrom<&Jwk> for p256::SecretKey {
291 type Error = Error;
292
293 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
294 match &jwk.crypto {
295 JwkCrypto::Ec {
296 curve: EcCurve::P256,
297 d: Some(d_bytes),
298 ..
299 } => {
300 let key: [u8; 32] = d_bytes.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
301 p256::SecretKey::from_bytes(&key).map_err(|_| Error::InvalidKey)
302 }
303 _ => Err(Error::InvalidKey),
304 }
305 }
306}
307
308impl TryFrom<&Jwk> for p256::PublicKey {
309 type Error = Error;
310
311 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
312 match &jwk.crypto {
313 JwkCrypto::Ec {
314 curve: EcCurve::P256,
315 x,
316 y,
317 ..
318 } => {
319 let x: [u8; 32] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
320 let y: [u8; 32] = y.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
321 p256::PublicKey::from_x_y(&x, &y).map_err(|_| Error::InvalidKey)
322 }
323 _ => Err(Error::InvalidKey),
324 }
325 }
326}
327
328impl From<&p384::PublicKey> for Jwk {
333 #[inline]
334 fn from(key: &p384::PublicKey) -> Self {
335 let (x, y) = key.x_y();
336 return Jwk {
337 kid: SmallString::new(),
338 r#use: KeyUse::Sign,
339 algorithm: Algorithm::ES384,
340 crypto: JwkCrypto::Ec {
341 curve: EcCurve::P384,
342 x: x.into(),
343 y: y.into(),
344 d: None,
345 },
346 };
347 }
348}
349
350impl TryFrom<&Jwk> for p384::PublicKey {
351 type Error = Error;
352
353 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
354 match &jwk.crypto {
355 JwkCrypto::Ec {
356 curve: EcCurve::P384,
357 x,
358 y,
359 ..
360 } => {
361 let x: [u8; 48] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
362 let y: [u8; 48] = y.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
363 p384::PublicKey::from_x_y(&x, &y).map_err(|_| Error::InvalidKey)
364 }
365 _ => Err(Error::InvalidKey),
366 }
367 }
368}
369
370impl From<&p521::SecretKey> for Jwk {
375 #[inline]
376 fn from(key: &p521::SecretKey) -> Self {
377 let (x, y) = key.public_key().x_y();
378 return Jwk {
379 kid: SmallString::new(),
380 r#use: KeyUse::Sign,
381 algorithm: Algorithm::ES512,
382 crypto: JwkCrypto::Ec {
383 curve: EcCurve::P521,
384 x: x.into(),
385 y: y.into(),
386 d: Some(key.to_bytes().into()),
387 },
388 };
389 }
390}
391
392impl From<&p521::PublicKey> for Jwk {
393 #[inline]
394 fn from(key: &p521::PublicKey) -> Self {
395 let (x, y) = key.x_y();
396 return Jwk {
397 kid: SmallString::new(),
398 r#use: KeyUse::Sign,
399 algorithm: Algorithm::ES512,
400 crypto: JwkCrypto::Ec {
401 curve: EcCurve::P521,
402 x: x.into(),
403 y: y.into(),
404 d: None,
405 },
406 };
407 }
408}
409
410impl TryFrom<&Jwk> for p521::SecretKey {
411 type Error = Error;
412
413 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
414 match &jwk.crypto {
415 JwkCrypto::Ec {
416 curve: EcCurve::P521,
417 d: Some(d_bytes),
418 ..
419 } => {
420 let key: [u8; 66] = d_bytes.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
421 p521::SecretKey::from_bytes(&key).map_err(|_| Error::InvalidKey)
422 }
423 _ => Err(Error::InvalidKey),
424 }
425 }
426}
427
428impl TryFrom<&Jwk> for p521::PublicKey {
429 type Error = Error;
430
431 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
432 match &jwk.crypto {
433 JwkCrypto::Ec {
434 curve: EcCurve::P521,
435 x,
436 y,
437 ..
438 } => {
439 let x: [u8; 66] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
440 let y: [u8; 66] = y.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
441 p521::PublicKey::from_x_y(&x, &y).map_err(|_| Error::InvalidKey)
442 }
443 _ => Err(Error::InvalidKey),
444 }
445 }
446}
447
448impl From<&RsaPublicKey> for Jwk {
453 fn from(key: &RsaPublicKey) -> Self {
454 Jwk {
455 kid: SmallString::new(),
456 r#use: KeyUse::Sign,
457 algorithm: key.alg,
458 crypto: JwkCrypto::Rsa {
459 n: key.key.n_bytes().into(),
460 e: key.key.e_bytes().into(),
461 },
462 }
463 }
464}
465
466impl TryFrom<&Jwk> for RsaPublicKey {
467 type Error = Error;
468
469 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
470 match &jwk.crypto {
471 JwkCrypto::Rsa {
472 n,
473 e,
474 } => RsaPublicKey::from_n_e(jwk.algorithm, n, e),
475 _ => Err(Error::InvalidKey),
476 }
477 }
478}
479
480impl From<&MlDsa44PublicKey> for Jwk {
485 fn from(key: &MlDsa44PublicKey) -> Self {
486 Jwk {
487 kid: SmallString::new(),
488 r#use: KeyUse::Sign,
489 algorithm: Algorithm::MlDsa44,
490 crypto: JwkCrypto::Akp {
491 pub_key: key.to_bytes().into(),
492 private_key: None,
493 },
494 }
495 }
496}
497
498impl From<&MlDsa44SecretKey> for Jwk {
499 fn from(key: &MlDsa44SecretKey) -> Self {
500 Jwk {
501 kid: SmallString::new(),
502 r#use: KeyUse::Sign,
503 algorithm: Algorithm::MlDsa44,
504 crypto: JwkCrypto::Akp {
505 pub_key: key.public_key().to_bytes().into(),
506 private_key: Some(key.seed().as_slice().into()),
507 },
508 }
509 }
510}
511
512impl TryFrom<&Jwk> for MlDsa44PublicKey {
513 type Error = Error;
514
515 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
516 if jwk.algorithm != Algorithm::MlDsa44 {
517 return Err(Error::InvalidKey);
518 }
519
520 match &jwk.crypto {
521 JwkCrypto::Akp {
522 pub_key, ..
523 } => MlDsa44PublicKey::try_from(pub_key.as_slice()).map_err(|_| Error::InvalidKey),
524 _ => Err(Error::InvalidKey),
525 }
526 }
527}
528
529impl TryFrom<&Jwk> for MlDsa44SecretKey {
530 type Error = Error;
531
532 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
533 if jwk.algorithm != Algorithm::MlDsa44 {
534 return Err(Error::InvalidKey);
535 }
536
537 match &jwk.crypto {
538 JwkCrypto::Akp {
539 private_key: Some(seed),
540 ..
541 } => {
542 let seed: [u8; 32] = seed.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
543 Ok(MlDsa44SecretKey::new(&seed))
544 }
545 _ => Err(Error::InvalidKey),
546 }
547 }
548}
549
550impl From<&MlDsa65PublicKey> for Jwk {
555 fn from(key: &MlDsa65PublicKey) -> Self {
556 Jwk {
557 kid: SmallString::new(),
558 r#use: KeyUse::Sign,
559 algorithm: Algorithm::MlDsa65,
560 crypto: JwkCrypto::Akp {
561 pub_key: key.to_bytes().into(),
562 private_key: None,
563 },
564 }
565 }
566}
567
568impl From<&MlDsa65SecretKey> for Jwk {
569 fn from(key: &MlDsa65SecretKey) -> Self {
570 Jwk {
571 kid: SmallString::new(),
572 r#use: KeyUse::Sign,
573 algorithm: Algorithm::MlDsa65,
574 crypto: JwkCrypto::Akp {
575 pub_key: key.public_key().to_bytes().into(),
576 private_key: Some(key.seed().as_slice().into()),
577 },
578 }
579 }
580}
581
582impl TryFrom<&Jwk> for MlDsa65PublicKey {
583 type Error = Error;
584
585 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
586 if jwk.algorithm != Algorithm::MlDsa65 {
587 return Err(Error::InvalidKey);
588 }
589
590 match &jwk.crypto {
591 JwkCrypto::Akp {
592 pub_key, ..
593 } => MlDsa65PublicKey::try_from(pub_key.as_slice()).map_err(|_| Error::InvalidKey),
594 _ => Err(Error::InvalidKey),
595 }
596 }
597}
598
599impl TryFrom<&Jwk> for MlDsa65SecretKey {
600 type Error = Error;
601
602 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
603 if jwk.algorithm != Algorithm::MlDsa65 {
604 return Err(Error::InvalidKey);
605 }
606
607 match &jwk.crypto {
608 JwkCrypto::Akp {
609 private_key: Some(seed),
610 ..
611 } => {
612 let seed: [u8; 32] = seed.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
613 Ok(MlDsa65SecretKey::new(&seed))
614 }
615 _ => Err(Error::InvalidKey),
616 }
617 }
618}
619
620impl From<&MlDsa87PublicKey> for Jwk {
625 fn from(key: &MlDsa87PublicKey) -> Self {
626 Jwk {
627 kid: SmallString::new(),
628 r#use: KeyUse::Sign,
629 algorithm: Algorithm::MlDsa87,
630 crypto: JwkCrypto::Akp {
631 pub_key: key.to_bytes().into(),
632 private_key: None,
633 },
634 }
635 }
636}
637
638impl From<&MlDsa87SecretKey> for Jwk {
639 fn from(key: &MlDsa87SecretKey) -> Self {
640 Jwk {
641 kid: SmallString::new(),
642 r#use: KeyUse::Sign,
643 algorithm: Algorithm::MlDsa87,
644 crypto: JwkCrypto::Akp {
645 pub_key: key.public_key().to_bytes().into(),
646 private_key: Some(key.seed().as_slice().into()),
647 },
648 }
649 }
650}
651
652impl TryFrom<&Jwk> for MlDsa87PublicKey {
653 type Error = Error;
654
655 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
656 if jwk.algorithm != Algorithm::MlDsa87 {
657 return Err(Error::InvalidKey);
658 }
659
660 match &jwk.crypto {
661 JwkCrypto::Akp {
662 pub_key, ..
663 } => MlDsa87PublicKey::try_from(pub_key.as_slice()).map_err(|_| Error::InvalidKey),
664 _ => Err(Error::InvalidKey),
665 }
666 }
667}
668
669impl TryFrom<&Jwk> for MlDsa87SecretKey {
670 type Error = Error;
671
672 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
673 if jwk.algorithm != Algorithm::MlDsa87 {
674 return Err(Error::InvalidKey);
675 }
676
677 match &jwk.crypto {
678 JwkCrypto::Akp {
679 private_key: Some(seed),
680 ..
681 } => {
682 let seed: [u8; 32] = seed.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
683 Ok(MlDsa87SecretKey::new(&seed))
684 }
685 _ => Err(Error::InvalidKey),
686 }
687 }
688}
689
690mod base64_url_no_padding {
691 use base64::{Alphabet, decode, encode};
692 use serde::{Deserializer, Serializer};
693
694 use super::*;
695
696 pub fn serialize<S: Serializer, const N: usize>(data: &SmallVec<u8, N>, serializer: S) -> Result<S::Ok, S::Error> {
697 serializer.serialize_str(&encode(data, Alphabet::UrlNoPadding))
698 }
699
700 pub fn deserialize<'de, D: Deserializer<'de>, const N: usize>(
701 deserializer: D,
702 ) -> Result<SmallVec<u8, N>, D::Error> {
703 let s = <&str>::deserialize(deserializer)?;
704 let bytes = decode(s.as_bytes(), Alphabet::UrlNoPadding).map_err(serde::de::Error::custom)?;
705 Ok(SmallVec::from(bytes))
706 }
707
708 pub(crate) mod option {
709 use alloc::string::String;
710
711 use super::*;
712
713 pub fn serialize<S: Serializer, const N: usize>(
714 data: &Option<SmallVec<u8, N>>,
715 serializer: S,
716 ) -> Result<S::Ok, S::Error> {
717 match data {
718 Some(val) => serializer.serialize_str(&encode(val, Alphabet::UrlNoPadding)),
719 None => serializer.serialize_none(),
720 }
721 }
722
723 pub fn deserialize<'de, D: Deserializer<'de>, const N: usize>(
724 deserializer: D,
725 ) -> Result<Option<SmallVec<u8, N>>, D::Error> {
726 let opt: Option<String> = Option::deserialize(deserializer)?;
727 match opt {
728 Some(s) => {
729 let bytes = decode(s.as_bytes(), Alphabet::UrlNoPadding).map_err(serde::de::Error::custom)?;
730 Ok(Some(SmallVec::from(bytes)))
731 }
732 None => Ok(None),
733 }
734 }
735 }
736}