1use core::fmt;
4
5use indexmap::IndexMap;
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use sha2::{Digest as _, Sha256};
9use zeroize::{Zeroize, ZeroizeOnDrop};
10
11use super::JwkError;
12use super::base64url;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[non_exhaustive]
20pub enum KeyType {
21 Ed25519,
23 P256,
25 Secp256k1,
27 Rsa2048,
30 Rsa4096,
33}
34
35#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
67pub struct Jwk {
68 kty: String,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 crv: Option<String>,
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 x: Option<String>,
73 #[serde(default, skip_serializing_if = "Option::is_none")]
74 y: Option<String>,
75 #[serde(default, skip_serializing_if = "Option::is_none")]
76 n: Option<String>,
77 #[serde(default, skip_serializing_if = "Option::is_none")]
78 e: Option<String>,
79 #[serde(flatten)]
81 pub(crate) private: PrivateParams,
82 #[serde(rename = "use", default, skip_serializing_if = "Option::is_none")]
83 key_use: Option<String>,
84 #[serde(default, skip_serializing_if = "Option::is_none")]
85 key_ops: Option<Vec<String>>,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 alg: Option<String>,
88 #[serde(default, skip_serializing_if = "Option::is_none")]
89 kid: Option<String>,
90 #[serde(flatten)]
91 additional: IndexMap<String, Value>,
92}
93
94#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
96pub(crate) struct PrivateParams {
97 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub(crate) d: Option<String>,
100 #[serde(default, skip_serializing_if = "Option::is_none")]
101 pub(crate) p: Option<String>,
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub(crate) q: Option<String>,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub(crate) dp: Option<String>,
106 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub(crate) dq: Option<String>,
108 #[serde(default, skip_serializing_if = "Option::is_none")]
109 pub(crate) qi: Option<String>,
110 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub(crate) oth: Option<Vec<OtherPrime>>,
112 #[serde(default, skip_serializing_if = "Option::is_none")]
114 pub(crate) k: Option<String>,
115}
116
117impl PrivateParams {
118 fn is_empty(&self) -> bool {
119 *self == Self::default()
120 }
121}
122
123#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
125pub(crate) struct OtherPrime {
126 pub(crate) r: String,
127 pub(crate) d: String,
128 pub(crate) t: String,
129}
130
131fn decode_member(name: &'static str, value: Option<&str>) -> Result<Vec<u8>, JwkError> {
133 let value = value.ok_or(JwkError::MissingMember(name))?;
134 base64url::decode(value).map_err(|_| JwkError::InvalidBase64Url(name))
135}
136
137impl Jwk {
138 fn with_kty(kty: &str) -> Self {
140 Self {
141 kty: kty.to_owned(),
142 crv: None,
143 x: None,
144 y: None,
145 n: None,
146 e: None,
147 key_use: None,
148 key_ops: None,
149 alg: None,
150 kid: None,
151 private: PrivateParams::default(),
152 additional: IndexMap::new(),
153 }
154 }
155
156 pub fn from_ed25519_public(public: &[u8]) -> Result<Self, JwkError> {
162 let bytes: &[u8; 32] = public.try_into().map_err(|_| JwkError::InvalidKey {
163 key: "Ed25519",
164 reason: format!("expected 32 bytes, found {}", public.len()),
165 })?;
166 ed25519_dalek::VerifyingKey::from_bytes(bytes).map_err(|e| JwkError::InvalidKey {
167 key: "Ed25519",
168 reason: e.to_string(),
169 })?;
170 let mut jwk = Self::with_kty("OKP");
171 jwk.crv = Some("Ed25519".to_owned());
172 jwk.x = Some(base64url::encode(bytes));
173 Ok(jwk)
174 }
175
176 pub fn from_x25519_public(public: &[u8]) -> Result<Self, JwkError> {
183 if public.len() != 32 {
184 return Err(JwkError::InvalidKeyLength {
185 key: "X25519",
186 expected: 32,
187 actual: public.len(),
188 });
189 }
190 let mut jwk = Self::with_kty("OKP");
191 jwk.crv = Some("X25519".to_owned());
192 jwk.x = Some(base64url::encode(public));
193 Ok(jwk)
194 }
195
196 pub fn from_p256_public(sec1: &[u8]) -> Result<Self, JwkError> {
202 let key = p256::PublicKey::from_sec1_bytes(sec1).map_err(|e| JwkError::InvalidKey {
203 key: "P-256",
204 reason: e.to_string(),
205 })?;
206 Ok(Self::from_p256_key(&key))
207 }
208
209 fn from_p256_key(key: &p256::PublicKey) -> Self {
210 use p256::elliptic_curve::sec1::ToSec1Point as _;
211 let point = key.to_sec1_point(false);
212 let mut jwk = Self::with_kty("EC");
213 jwk.crv = Some("P-256".to_owned());
214 jwk.x = point.x().map(|x| base64url::encode(x));
215 jwk.y = point.y().map(|y| base64url::encode(y));
216 jwk
217 }
218
219 #[cfg(feature = "secp256k1")]
225 #[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))]
226 pub fn from_secp256k1_public(sec1: &[u8]) -> Result<Self, JwkError> {
227 let key = k256::PublicKey::from_sec1_bytes(sec1).map_err(|e| JwkError::InvalidKey {
228 key: "secp256k1",
229 reason: e.to_string(),
230 })?;
231 Ok(Self::from_secp256k1_key(&key))
232 }
233
234 #[cfg(feature = "secp256k1")]
235 fn from_secp256k1_key(key: &k256::PublicKey) -> Self {
236 use k256::elliptic_curve::sec1::ToSec1Point as _;
237 let point = key.to_sec1_point(false);
238 let mut jwk = Self::with_kty("EC");
239 jwk.crv = Some("secp256k1".to_owned());
240 jwk.x = point.x().map(|x| base64url::encode(x));
241 jwk.y = point.y().map(|y| base64url::encode(y));
242 jwk
243 }
244
245 pub fn from_rsa_public(n: &[u8], e: &[u8]) -> Result<Self, JwkError> {
255 if n.is_empty() || e.is_empty() {
256 return Err(JwkError::InvalidKey {
257 key: "RSA",
258 reason: "modulus and exponent must not be empty".to_owned(),
259 });
260 }
261 let mut jwk = Self::with_kty("RSA");
262 jwk.n = Some(base64url::encode_uint(n));
263 jwk.e = Some(base64url::encode_uint(e));
264 Ok(jwk)
265 }
266
267 pub fn from_spki_der(hint: KeyType, der: &[u8]) -> Result<Self, JwkError> {
279 match hint {
280 KeyType::Ed25519 => {
281 use ed25519_dalek::pkcs8::DecodePublicKey as _;
282 let key = ed25519_dalek::VerifyingKey::from_public_key_der(der).map_err(|e| {
283 JwkError::InvalidKey {
284 key: "Ed25519",
285 reason: e.to_string(),
286 }
287 })?;
288 Self::from_ed25519_public(&key.to_bytes())
289 }
290 KeyType::P256 => {
291 use p256::pkcs8::DecodePublicKey as _;
292 let key = p256::PublicKey::from_public_key_der(der).map_err(|e| {
293 JwkError::InvalidKey {
294 key: "P-256",
295 reason: e.to_string(),
296 }
297 })?;
298 Ok(Self::from_p256_key(&key))
299 }
300 #[cfg(feature = "secp256k1")]
301 KeyType::Secp256k1 => {
302 use k256::pkcs8::DecodePublicKey as _;
303 let key = k256::PublicKey::from_public_key_der(der).map_err(|e| {
304 JwkError::InvalidKey {
305 key: "secp256k1",
306 reason: e.to_string(),
307 }
308 })?;
309 Ok(Self::from_secp256k1_key(&key))
310 }
311 #[cfg(not(feature = "secp256k1"))]
312 KeyType::Secp256k1 => Err(JwkError::FeatureDisabled {
313 key: "secp256k1",
314 feature: "secp256k1",
315 }),
316 #[cfg(feature = "rsa")]
317 KeyType::Rsa2048 | KeyType::Rsa4096 => {
318 use rsa::pkcs8::DecodePublicKey as _;
319 use rsa::traits::PublicKeyParts as _;
320 let key = rsa::RsaPublicKey::from_public_key_der(der).map_err(|e| {
321 JwkError::InvalidKey {
322 key: "RSA",
323 reason: e.to_string(),
324 }
325 })?;
326 let expected_bits = match hint {
327 KeyType::Rsa4096 => 4096,
328 _ => 2048,
329 };
330 if key.n().bits_vartime() != expected_bits {
331 return Err(JwkError::KeyMismatch { expected: hint });
332 }
333 Self::from_rsa_public(
334 &key.n().to_be_bytes_trimmed_vartime(),
335 &key.e().to_be_bytes_trimmed_vartime(),
336 )
337 }
338 #[cfg(not(feature = "rsa"))]
339 KeyType::Rsa2048 | KeyType::Rsa4096 => Err(JwkError::FeatureDisabled {
340 key: "RSA",
341 feature: "rsa",
342 }),
343 }
344 }
345
346 pub fn kty(&self) -> &str {
348 &self.kty
349 }
350
351 pub fn crv(&self) -> Option<&str> {
353 self.crv.as_deref()
354 }
355
356 pub fn x(&self) -> Option<&str> {
358 self.x.as_deref()
359 }
360
361 pub fn y(&self) -> Option<&str> {
363 self.y.as_deref()
364 }
365
366 pub fn n(&self) -> Option<&str> {
368 self.n.as_deref()
369 }
370
371 pub fn e(&self) -> Option<&str> {
373 self.e.as_deref()
374 }
375
376 pub fn key_use(&self) -> Option<&str> {
378 self.key_use.as_deref()
379 }
380
381 pub fn key_ops(&self) -> Option<&[String]> {
383 self.key_ops.as_deref()
384 }
385
386 pub fn alg(&self) -> Option<&str> {
388 self.alg.as_deref()
389 }
390
391 pub fn kid(&self) -> Option<&str> {
393 self.kid.as_deref()
394 }
395
396 pub fn additional(&self) -> &IndexMap<String, Value> {
398 &self.additional
399 }
400
401 pub fn additional_mut(&mut self) -> &mut IndexMap<String, Value> {
403 &mut self.additional
404 }
405
406 pub fn is_private(&self) -> bool {
409 !self.private.is_empty()
410 }
411
412 #[must_use]
414 pub fn with_kid(mut self, kid: impl Into<String>) -> Self {
415 self.kid = Some(kid.into());
416 self
417 }
418
419 #[must_use]
421 pub fn with_alg(mut self, alg: impl Into<String>) -> Self {
422 self.alg = Some(alg.into());
423 self
424 }
425
426 #[must_use]
428 pub fn with_key_use(mut self, key_use: impl Into<String>) -> Self {
429 self.key_use = Some(key_use.into());
430 self
431 }
432
433 #[must_use]
435 pub fn with_key_ops<I, S>(mut self, key_ops: I) -> Self
436 where
437 I: IntoIterator<Item = S>,
438 S: Into<String>,
439 {
440 self.key_ops = Some(key_ops.into_iter().map(Into::into).collect());
441 self
442 }
443
444 #[must_use]
446 pub fn public(&self) -> Self {
447 let mut public = self.clone();
448 public.private = PrivateParams::default();
449 public
450 }
451
452 pub fn thumbprint_sha256(&self) -> Result<String, JwkError> {
480 let canonical = self.thumbprint_input()?;
481 Ok(base64url::encode(&Sha256::digest(canonical.as_bytes())))
482 }
483
484 pub(crate) fn thumbprint_input(&self) -> Result<String, JwkError> {
486 fn member(name: &'static str, value: Option<&str>) -> Result<String, JwkError> {
487 let value = value.ok_or(JwkError::MissingMember(name))?;
488 Ok(serde_json::to_string(value).unwrap_or_default())
490 }
491 let kty = serde_json::to_string(&self.kty).unwrap_or_default();
492 Ok(match self.kty.as_str() {
493 "EC" => format!(
494 r#"{{"crv":{},"kty":{kty},"x":{},"y":{}}}"#,
495 member("crv", self.crv())?,
496 member("x", self.x())?,
497 member("y", self.y())?
498 ),
499 "OKP" => format!(
500 r#"{{"crv":{},"kty":{kty},"x":{}}}"#,
501 member("crv", self.crv())?,
502 member("x", self.x())?
503 ),
504 "RSA" => format!(
505 r#"{{"e":{},"kty":{kty},"n":{}}}"#,
506 member("e", self.e())?,
507 member("n", self.n())?
508 ),
509 "oct" => format!(
510 r#"{{"k":{},"kty":{kty}}}"#,
511 member("k", self.private.k.as_deref())?
512 ),
513 _ => return Err(self.unsupported()),
514 })
515 }
516
517 pub fn ed25519_public_bytes(&self) -> Result<[u8; 32], JwkError> {
525 Ok(self.ed25519_verifying_key()?.to_bytes())
526 }
527
528 pub(crate) fn ed25519_verifying_key(&self) -> Result<ed25519_dalek::VerifyingKey, JwkError> {
529 self.expect("Ed25519", "OKP", Some("Ed25519"))?;
530 let x = decode_member("x", self.x())?;
531 let bytes: &[u8; 32] = x.as_slice().try_into().map_err(|_| JwkError::InvalidKey {
532 key: "Ed25519",
533 reason: format!("expected 32 bytes, found {}", x.len()),
534 })?;
535 ed25519_dalek::VerifyingKey::from_bytes(bytes).map_err(|e| JwkError::InvalidKey {
536 key: "Ed25519",
537 reason: e.to_string(),
538 })
539 }
540
541 pub fn x25519_public_bytes(&self) -> Result<[u8; 32], JwkError> {
549 self.expect("X25519", "OKP", Some("X25519"))?;
550 let x = decode_member("x", self.x())?;
551 x.as_slice()
552 .try_into()
553 .map_err(|_| JwkError::InvalidKeyLength {
554 key: "X25519",
555 expected: 32,
556 actual: x.len(),
557 })
558 }
559
560 pub fn p256_public_bytes(&self) -> Result<[u8; 65], JwkError> {
569 use p256::elliptic_curve::sec1::ToSec1Point as _;
570 let point = self.p256_public_key()?.to_sec1_point(false);
571 point
572 .as_bytes()
573 .try_into()
574 .map_err(|_| JwkError::InvalidKey {
575 key: "P-256",
576 reason: "point is not 65 bytes".to_owned(),
577 })
578 }
579
580 pub(crate) fn p256_public_key(&self) -> Result<p256::PublicKey, JwkError> {
581 self.expect("P-256", "EC", Some("P-256"))?;
582 let sec1 = self.ec_uncompressed_point(32, "P-256")?;
583 p256::PublicKey::from_sec1_bytes(&sec1).map_err(|e| JwkError::InvalidKey {
584 key: "P-256",
585 reason: e.to_string(),
586 })
587 }
588
589 #[cfg(feature = "secp256k1")]
598 #[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))]
599 pub fn secp256k1_public_bytes(&self) -> Result<[u8; 65], JwkError> {
600 use k256::elliptic_curve::sec1::ToSec1Point as _;
601 let point = self.secp256k1_public_key()?.to_sec1_point(false);
602 point
603 .as_bytes()
604 .try_into()
605 .map_err(|_| JwkError::InvalidKey {
606 key: "secp256k1",
607 reason: "point is not 65 bytes".to_owned(),
608 })
609 }
610
611 #[cfg(feature = "secp256k1")]
612 pub(crate) fn secp256k1_public_key(&self) -> Result<k256::PublicKey, JwkError> {
613 self.expect("secp256k1", "EC", Some("secp256k1"))?;
614 let sec1 = self.ec_uncompressed_point(32, "secp256k1")?;
615 k256::PublicKey::from_sec1_bytes(&sec1).map_err(|e| JwkError::InvalidKey {
616 key: "secp256k1",
617 reason: e.to_string(),
618 })
619 }
620
621 fn ec_uncompressed_point(&self, len: usize, key: &'static str) -> Result<Vec<u8>, JwkError> {
623 let x = decode_member("x", self.x())?;
624 let y = decode_member("y", self.y())?;
625 if x.len() != len || y.len() != len {
626 return Err(JwkError::InvalidKey {
627 key,
628 reason: format!(
629 "expected {len}-byte coordinates, found {} and {}",
630 x.len(),
631 y.len()
632 ),
633 });
634 }
635 let mut sec1 = Vec::with_capacity(1 + 2 * len);
636 sec1.push(0x04);
637 sec1.extend_from_slice(&x);
638 sec1.extend_from_slice(&y);
639 Ok(sec1)
640 }
641
642 pub fn rsa_public_components(&self) -> Result<(Vec<u8>, Vec<u8>), JwkError> {
649 self.expect("RSA", "RSA", None)?;
650 Ok((decode_member("n", self.n())?, decode_member("e", self.e())?))
651 }
652
653 #[cfg(feature = "rsa")]
654 pub(crate) fn rsa_public_key(&self) -> Result<rsa::RsaPublicKey, JwkError> {
655 let (n, e) = self.rsa_public_components()?;
656 if n.is_empty() || e.is_empty() {
657 return Err(JwkError::InvalidKey {
658 key: "RSA",
659 reason: "modulus and exponent must not be empty".to_owned(),
660 });
661 }
662 rsa::RsaPublicKey::new(
663 rsa::BoxedUint::from_be_slice_vartime(&n),
664 rsa::BoxedUint::from_be_slice_vartime(&e),
665 )
666 .map_err(|e| JwkError::InvalidKey {
667 key: "RSA",
668 reason: e.to_string(),
669 })
670 }
671
672 pub fn to_decoding_key(&self) -> Result<jsonwebtoken::DecodingKey, JwkError> {
683 use jsonwebtoken::DecodingKey;
684 let result = match (self.kty.as_str(), self.crv()) {
685 ("OKP", Some("Ed25519")) => {
686 DecodingKey::from_ed_components(self.x().ok_or(JwkError::MissingMember("x"))?)
687 }
688 ("EC", Some("P-256" | "P-384")) => DecodingKey::from_ec_components(
689 self.x().ok_or(JwkError::MissingMember("x"))?,
690 self.y().ok_or(JwkError::MissingMember("y"))?,
691 ),
692 ("RSA", _) => DecodingKey::from_rsa_components(
693 self.n().ok_or(JwkError::MissingMember("n"))?,
694 self.e().ok_or(JwkError::MissingMember("e"))?,
695 ),
696 _ => return Err(self.unsupported()),
697 };
698 result.map_err(|e| JwkError::DecodingKey(e.to_string()))
699 }
700
701 pub(super) fn expect(
703 &self,
704 expected: &'static str,
705 kty: &str,
706 crv: Option<&str>,
707 ) -> Result<(), JwkError> {
708 if self.kty == kty && (crv.is_none() || self.crv() == crv) {
709 Ok(())
710 } else {
711 Err(JwkError::UnexpectedKeyType {
712 expected,
713 kty: self.kty.clone(),
714 crv: self.crv.clone(),
715 })
716 }
717 }
718
719 pub(super) fn unsupported(&self) -> JwkError {
720 JwkError::UnsupportedKeyType {
721 kty: self.kty.clone(),
722 crv: self.crv.clone(),
723 }
724 }
725}
726
727impl fmt::Debug for Jwk {
728 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
730 let mut s = f.debug_struct("Jwk");
731 s.field("kty", &self.kty);
732 for (name, value) in [
733 ("crv", &self.crv),
734 ("x", &self.x),
735 ("y", &self.y),
736 ("n", &self.n),
737 ("e", &self.e),
738 ("use", &self.key_use),
739 ("alg", &self.alg),
740 ("kid", &self.kid),
741 ] {
742 if let Some(value) = value {
743 s.field(name, value);
744 }
745 }
746 if let Some(key_ops) = &self.key_ops {
747 s.field("key_ops", key_ops);
748 }
749 if !self.additional.is_empty() {
750 s.field("additional", &self.additional);
751 }
752 s.field("private", &self.is_private());
753 s.finish()
754 }
755}
756
757impl fmt::Display for Jwk {
758 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
760 let json = serde_json::to_string(&self.public()).map_err(|_| fmt::Error)?;
761 f.write_str(&json)
762 }
763}