Skip to main content

identity_kit/jose/
jwk.rs

1//! `Jwk`: a JSON Web Key (RFC 7517) with the parameters of RFC 7518 and RFC 8037.
2
3use 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/// The kind of key behind a [`Jwk`], as a key store or HSM names it.
15///
16/// Used as the hint for [`Jwk::from_spki_der`], where it selects the parser and is checked against
17/// the encoded key.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[non_exhaustive]
20pub enum KeyType {
21    /// Ed25519, used with [`EdDSA`](super::JwsAlgorithm::EdDSA).
22    Ed25519,
23    /// NIST P-256 (secp256r1), used with [`ES256`](super::JwsAlgorithm::ES256).
24    P256,
25    /// secp256k1, used with [`ES256K`](super::JwsAlgorithm::ES256K).
26    Secp256k1,
27    /// RSA with a 2048-bit modulus, used with [`RS256`](super::JwsAlgorithm::RS256) and
28    /// [`PS256`](super::JwsAlgorithm::PS256).
29    Rsa2048,
30    /// RSA with a 4096-bit modulus, used with [`RS256`](super::JwsAlgorithm::RS256) and
31    /// [`PS256`](super::JwsAlgorithm::PS256).
32    Rsa4096,
33}
34
35/// A JSON Web Key (RFC 7517).
36///
37/// A `Jwk` carries the common members (`kty`, `use`, `key_ops`, `alg`, `kid`), the public
38/// parameters of RFC 7518 and RFC 8037 (`crv`, `x`, `y`, `n`, `e`), the private parameters (`d`,
39/// `p`, `q`, `dp`, `dq`, `qi`, `oth`, `k`) and any other member in an insertion-ordered map, so a
40/// key round-trips through JSON with its extension members intact.
41///
42/// Private parameters never appear in `Debug` or `Display` output and are zeroized when the key
43/// is dropped. [`Jwk::public`] strips them; serde serialization keeps them, because a key store
44/// that persists private JWKs needs it to.
45///
46/// Members are kept as the base64url strings they arrive as. Nothing is validated when a key is
47/// parsed; the accessors that decode the material ([`Jwk::ed25519_public_bytes`],
48/// [`Jwk::p256_public_bytes`], …) and the operations that need it ([`Jwk::thumbprint_sha256`],
49/// [`Jwk::to_decoding_key`], the verifiers) report what is wrong.
50///
51/// # Examples
52///
53/// ```
54/// use identity_kit::jose::Jwk;
55///
56/// // The Ed25519 key of RFC 8037 Appendix A.2.
57/// let jwk: Jwk = serde_json::from_str(
58///     r#"{"kty":"OKP","crv":"Ed25519","x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"}"#,
59/// )?;
60/// assert_eq!(jwk.kty(), "OKP");
61/// assert_eq!(jwk.crv(), Some("Ed25519"));
62/// assert_eq!(jwk.ed25519_public_bytes()?.len(), 32);
63/// assert_eq!(jwk.thumbprint_sha256()?, "kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k");
64/// # Ok::<(), Box<dyn std::error::Error>>(())
65/// ```
66#[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    // Private parameters follow the public ones, as in the examples of RFC 7517 Appendix A.2.
80    #[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/// The private parameters of RFC 7518 §6.2.2, §6.3.2 and §6.4 and RFC 8037 §2.
95#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
96pub(crate) struct PrivateParams {
97    /// EC and OKP private key, RSA private exponent.
98    #[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    /// Symmetric key value.
113    #[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/// One entry of the RSA `oth` member (RFC 7518 §6.3.2.7).
124#[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
131/// Decodes the base64url member `name` of `value`.
132fn 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    /// A key with only `kty` set, the starting point of the `from_*` constructors.
139    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    /// An `OKP` key with `crv` `Ed25519` from the 32-byte public key of RFC 8032.
157    ///
158    /// # Errors
159    ///
160    /// [`JwkError::InvalidKey`] when `public` is not 32 bytes or not a valid point.
161    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    /// An `OKP` key with `crv` `X25519` from the 32-byte public key of RFC 7748, for key
177    /// agreement (RFC 8037 §3).
178    ///
179    /// # Errors
180    ///
181    /// [`JwkError::InvalidKeyLength`] when `public` is not 32 bytes.
182    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    /// An `EC` key with `crv` `P-256` from a SEC1-encoded point, compressed or uncompressed.
197    ///
198    /// # Errors
199    ///
200    /// [`JwkError::InvalidKey`] when `sec1` is not a valid P-256 point.
201    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    /// An `EC` key with `crv` `secp256k1` from a SEC1-encoded point, compressed or uncompressed.
220    ///
221    /// # Errors
222    ///
223    /// [`JwkError::InvalidKey`] when `sec1` is not a valid secp256k1 point.
224    #[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    /// An `RSA` key from the big-endian modulus `n` and public exponent `e`.
246    ///
247    /// Leading zero octets are dropped, as RFC 7518 §6.3.1 requires. The values are not checked
248    /// beyond being non-empty; [`DefaultVerifier`](super::DefaultVerifier) rejects an unusable
249    /// modulus or exponent when the key is used.
250    ///
251    /// # Errors
252    ///
253    /// [`JwkError::InvalidKey`] when `n` or `e` is empty.
254    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    /// A key from a DER-encoded X.509 `SubjectPublicKeyInfo` (RFC 5280 §4.1.2.7), the form in
268    /// which KMS and HSM backends return public keys.
269    ///
270    /// `hint` is what the caller expects and selects the parser; a key of another type is an
271    /// error, as is an RSA modulus of another size than the hint names.
272    ///
273    /// # Errors
274    ///
275    /// - [`JwkError::InvalidKey`] when `der` does not decode as a key of the hinted type.
276    /// - [`JwkError::KeyMismatch`] when it decodes but has another size than hinted.
277    /// - [`JwkError::FeatureDisabled`] when the hinted type is compiled out.
278    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    /// The key type (`kty`): `OKP`, `EC`, `RSA` or `oct`.
347    pub fn kty(&self) -> &str {
348        &self.kty
349    }
350
351    /// The curve (`crv`) of an `EC` or `OKP` key.
352    pub fn crv(&self) -> Option<&str> {
353        self.crv.as_deref()
354    }
355
356    /// The base64url `x` coordinate (`EC`) or public key (`OKP`).
357    pub fn x(&self) -> Option<&str> {
358        self.x.as_deref()
359    }
360
361    /// The base64url `y` coordinate of an `EC` key.
362    pub fn y(&self) -> Option<&str> {
363        self.y.as_deref()
364    }
365
366    /// The base64url RSA modulus `n`.
367    pub fn n(&self) -> Option<&str> {
368        self.n.as_deref()
369    }
370
371    /// The base64url RSA public exponent `e`.
372    pub fn e(&self) -> Option<&str> {
373        self.e.as_deref()
374    }
375
376    /// The public key use (`use`): `sig` or `enc`.
377    pub fn key_use(&self) -> Option<&str> {
378        self.key_use.as_deref()
379    }
380
381    /// The key operations (`key_ops`), such as `sign` and `verify`.
382    pub fn key_ops(&self) -> Option<&[String]> {
383        self.key_ops.as_deref()
384    }
385
386    /// The algorithm (`alg`) the key is intended for.
387    pub fn alg(&self) -> Option<&str> {
388        self.alg.as_deref()
389    }
390
391    /// The key id (`kid`).
392    pub fn kid(&self) -> Option<&str> {
393        self.kid.as_deref()
394    }
395
396    /// Members other than the ones this type models, in the order they were inserted.
397    pub fn additional(&self) -> &IndexMap<String, Value> {
398        &self.additional
399    }
400
401    /// Mutable access to the members other than the ones this type models.
402    pub fn additional_mut(&mut self) -> &mut IndexMap<String, Value> {
403        &mut self.additional
404    }
405
406    /// Whether the key carries private parameters (`d`, `p`, `q`, `dp`, `dq`, `qi`, `oth` or
407    /// `k`).
408    pub fn is_private(&self) -> bool {
409        !self.private.is_empty()
410    }
411
412    /// This key with its `kid` set.
413    #[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    /// This key with its `alg` set.
420    #[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    /// This key with its `use` set.
427    #[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    /// This key with its `key_ops` set.
434    #[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    /// A copy of this key without private parameters.
445    #[must_use]
446    pub fn public(&self) -> Self {
447        let mut public = self.clone();
448        public.private = PrivateParams::default();
449        public
450    }
451
452    /// The RFC 7638 JWK thumbprint with SHA-256, as base64url.
453    ///
454    /// The thumbprint hashes the required members of the key type (`crv`, `kty`, `x`, `y` for
455    /// `EC`; `crv`, `kty`, `x` for `OKP`; `e`, `kty`, `n` for `RSA`; `k`, `kty` for `oct`) in
456    /// lexicographic order with no whitespace, exactly as they appear in the key.
457    ///
458    /// # Errors
459    ///
460    /// [`JwkError::MissingMember`] when a required member is absent and
461    /// [`JwkError::UnsupportedKeyType`] for any other `kty`.
462    ///
463    /// # Examples
464    ///
465    /// ```
466    /// use identity_kit::jose::Jwk;
467    ///
468    /// // RFC 7638 §3.1.
469    /// let jwk: Jwk = serde_json::from_str(r#"{
470    ///   "kty": "RSA",
471    ///   "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
472    ///   "e": "AQAB",
473    ///   "alg": "RS256",
474    ///   "kid": "2011-04-29"
475    /// }"#)?;
476    /// assert_eq!(jwk.thumbprint_sha256()?, "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs");
477    /// # Ok::<(), Box<dyn std::error::Error>>(())
478    /// ```
479    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    /// The canonical JSON that [`Jwk::thumbprint_sha256`] hashes.
485    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            // Serializing a `str` cannot fail.
489            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    /// The 32-byte Ed25519 public key of an `OKP` key with `crv` `Ed25519`.
518    ///
519    /// # Errors
520    ///
521    /// [`JwkError::UnexpectedKeyType`] for any other key, [`JwkError::MissingMember`] or
522    /// [`JwkError::InvalidBase64Url`] for a broken `x`, and [`JwkError::InvalidKey`] when `x` is
523    /// not a valid point.
524    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    /// The 32-byte X25519 public key of an `OKP` key with `crv` `X25519`.
542    ///
543    /// # Errors
544    ///
545    /// [`JwkError::UnexpectedKeyType`] for any other key, [`JwkError::MissingMember`] or
546    /// [`JwkError::InvalidBase64Url`] for a broken `x`, and [`JwkError::InvalidKeyLength`] when
547    /// `x` is not 32 bytes.
548    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    /// The uncompressed SEC1 point (`0x04 || x || y`, 65 bytes) of an `EC` key with `crv`
561    /// `P-256`.
562    ///
563    /// # Errors
564    ///
565    /// [`JwkError::UnexpectedKeyType`] for any other key, [`JwkError::MissingMember`] or
566    /// [`JwkError::InvalidBase64Url`] for a broken `x` or `y`, and [`JwkError::InvalidKey`] when
567    /// the coordinates are not a point on the curve.
568    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    /// The uncompressed SEC1 point (`0x04 || x || y`, 65 bytes) of an `EC` key with `crv`
590    /// `secp256k1`.
591    ///
592    /// # Errors
593    ///
594    /// [`JwkError::UnexpectedKeyType`] for any other key, [`JwkError::MissingMember`] or
595    /// [`JwkError::InvalidBase64Url`] for a broken `x` or `y`, and [`JwkError::InvalidKey`] when
596    /// the coordinates are not a point on the curve.
597    #[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    /// `0x04 || x || y` from the `x` and `y` members, each of which must be `len` bytes.
622    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    /// The big-endian modulus `n` and public exponent `e` of an `RSA` key.
643    ///
644    /// # Errors
645    ///
646    /// [`JwkError::UnexpectedKeyType`] for any other key, [`JwkError::MissingMember`] or
647    /// [`JwkError::InvalidBase64Url`] for a broken `n` or `e`.
648    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    /// A [`jsonwebtoken::DecodingKey`] for this key, so a JWT can be verified with `jsonwebtoken`.
673    ///
674    /// Supports `OKP`/`Ed25519`, `EC`/`P-256`, `EC`/`P-384` and `RSA` keys, the types
675    /// `jsonwebtoken` can verify with. Private parameters are not needed and not used.
676    ///
677    /// # Errors
678    ///
679    /// [`JwkError::UnsupportedKeyType`] for any other key, [`JwkError::MissingMember`] when a
680    /// required member is absent and [`JwkError::DecodingKey`] when `jsonwebtoken` rejects the
681    /// material.
682    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    /// Checks that this is a `kty` key on curve `crv`.
702    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    /// Public members only; private parameters are shown as `private: true`.
729    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    /// The public key as compact JSON, as [`Jwk::public`] serializes.
759    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}