Skip to main content

jwt/
jwt_crypto.rs

1use alloc::boxed::Box;
2
3use constant_time_eq::constant_time_eq;
4use crypto::{
5    Hash, Hasher,
6    blake3::Blake3,
7    curve25519::ed25519,
8    hmac::Hmac,
9    mldsa::{
10        ML_DSA_44_SIGNATURE_SIZE, ML_DSA_65_SIGNATURE_SIZE, ML_DSA_87_SIGNATURE_SIZE, MlDsa44PublicKey,
11        MlDsa44SecretKey, MlDsa65PublicKey, MlDsa65SecretKey, MlDsa87PublicKey, MlDsa87SecretKey,
12    },
13    p256, p384, p521, rsa,
14    sha2::{Sha256, Sha384, Sha512},
15};
16
17use crate::{Algorithm, EcCurve, Error, Jwk, JwkCrypto, OkpCurve};
18
19pub(crate) const SIGNATURE_MAX_SIZE: usize = 4627; // ML-DSA-87
20
21pub trait Signer {
22    fn sign(&self, message: &[u8]) -> Result<Signature, Error>;
23    fn algorithm(&self) -> Algorithm;
24}
25
26pub trait Verifier {
27    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error>;
28    fn algorithm(&self) -> Algorithm;
29}
30
31////////////////////////////////////////////////////////////////////////////////////////////////////
32// Signature
33////////////////////////////////////////////////////////////////////////////////////////////////////
34
35#[derive(Clone, Copy)]
36pub struct Signature {
37    value: [u8; SIGNATURE_MAX_SIZE],
38    length: usize,
39}
40
41impl core::ops::Deref for Signature {
42    type Target = [u8];
43
44    #[inline]
45    fn deref(&self) -> &[u8] {
46        &self.value[..self.length as usize]
47    }
48}
49
50impl AsRef<[u8]> for Signature {
51    #[inline]
52    fn as_ref(&self) -> &[u8] {
53        &self.value[..self.length]
54    }
55}
56
57impl TryFrom<&[u8]> for Signature {
58    type Error = Error;
59
60    #[inline]
61    fn try_from(signature: &[u8]) -> Result<Self, Self::Error> {
62        let length = signature.len();
63        if length > SIGNATURE_MAX_SIZE {
64            return Err(Error::InvalidSignature);
65        }
66
67        let mut value = [0u8; SIGNATURE_MAX_SIZE];
68        value[..length].copy_from_slice(signature);
69
70        return Ok(Signature {
71            value,
72            length,
73        });
74    }
75}
76
77impl<const N: usize> TryFrom<[u8; N]> for Signature {
78    type Error = Error;
79
80    #[inline]
81    fn try_from(signature: [u8; N]) -> Result<Self, Self::Error> {
82        signature.as_slice().try_into()
83    }
84}
85
86impl<const N: usize> TryFrom<&[u8; N]> for Signature {
87    type Error = Error;
88
89    #[inline]
90    fn try_from(signature: &[u8; N]) -> Result<Self, Self::Error> {
91        signature.as_slice().try_into()
92    }
93}
94
95////////////////////////////////////////////////////////////////////////////////////////////////////
96// key
97////////////////////////////////////////////////////////////////////////////////////////////////////
98
99/// A JWK decoded into a concrete cryptographic key.
100///
101/// This is the entry point when the key type is only known at runtime, for example after fetching
102/// a JWKS document. [`Key::try_from`] inspects the JWK's `kty` (and `crv`) to select the right
103/// variant, so callers do not need to know in advance whether the key is RSA, EC, OKP, ...
104///
105/// When a JWK carries both public and secret material (for example one produced from a secret
106/// key), the secret variant is preferred.
107///
108/// `Key` implements both [`Signer`] and [`Verifier`], so a decoded key can be passed directly to
109/// [`sign`] or [`parse_and_verify`]. Public-only keys return [`Error::InvalidKey`] when signing.
110///
111/// # Errors
112///
113/// [`Key::try_from`] returns [`Error::InvalidKey`] if the JWK's key material is inconsistent with
114/// its declared algorithm, if the curve or algorithm is unsupported, or if the underlying key
115/// bytes are invalid.
116///
117/// [`sign`]: crate::sign
118/// [`parse_and_verify`]: crate::parse_and_verify
119#[allow(clippy::large_enum_variant)] // ML-DSA-44 secret keys are large by nature; 65/87 are boxed to keep `Key` small
120pub enum Key<'a> {
121    /// Symmetric key for the `BLAKE3`, `HS256`, `HS384`, and `HS512` algorithms.
122    Secret(SecretKey<'a>),
123
124    /// Ed25519 public key for `EdDSA`.
125    Ed25519Public(ed25519::PublicKey),
126
127    /// Ed25519 secret key for `EdDSA`.
128    Ed25519Secret(ed25519::SecretKey),
129
130    /// P-256 public key for `ES256`.
131    P256Public(p256::PublicKey),
132
133    /// P-256 secret key for `ES256`.
134    P256Secret(p256::SecretKey),
135
136    /// P-384 public key for `ES384`.
137    P384Public(p384::PublicKey),
138
139    /// P-521 public key for `ES512`.
140    P521Public(p521::PublicKey),
141
142    /// P-521 secret key for `ES512`.
143    P521Secret(p521::SecretKey),
144
145    /// RSA public key for the `RS*` and `PS*` algorithms.
146    Rsa(RsaPublicKey),
147
148    /// ML-DSA-44 public key for `ML-DSA-44`.
149    MlDsa44Public(MlDsa44PublicKey),
150
151    /// ML-DSA-44 secret key for `ML-DSA-44`.
152    MlDsa44Secret(MlDsa44SecretKey),
153
154    /// ML-DSA-65 public key for `ML-DSA-65`.
155    MlDsa65Public(MlDsa65PublicKey),
156
157    /// ML-DSA-65 secret key for `ML-DSA-65`.
158    ///
159    /// Boxed because an expanded ML-DSA-65 secret key is roughly 50 KiB, which would otherwise
160    /// inflate every [`Key`] value and overflow the stack in debug builds.
161    MlDsa65Secret(Box<MlDsa65SecretKey>),
162
163    /// ML-DSA-87 public key for `ML-DSA-87`.
164    MlDsa87Public(MlDsa87PublicKey),
165
166    /// ML-DSA-87 secret key for `ML-DSA-87`.
167    ///
168    /// Boxed because an expanded ML-DSA-87 secret key is roughly 82 KiB, which would otherwise
169    /// inflate every [`Key`] value and overflow the stack in debug builds.
170    MlDsa87Secret(Box<MlDsa87SecretKey>),
171}
172
173impl<'a> TryFrom<&'a Jwk> for Key<'a> {
174    type Error = Error;
175
176    fn try_from(jwk: &'a Jwk) -> Result<Self, Self::Error> {
177        match &jwk.crypto {
178            JwkCrypto::Oct {
179                ..
180            } => Ok(Key::Secret(SecretKey::try_from(jwk)?)),
181            JwkCrypto::Okp {
182                curve: OkpCurve::Ed25519,
183                d: Some(_),
184                ..
185            } => Ok(Key::Ed25519Secret(ed25519::SecretKey::try_from(jwk)?)),
186            JwkCrypto::Okp {
187                curve: OkpCurve::Ed25519,
188                ..
189            } => Ok(Key::Ed25519Public(ed25519::PublicKey::try_from(jwk)?)),
190            JwkCrypto::Ec {
191                curve: EcCurve::P256,
192                d: Some(_),
193                ..
194            } => Ok(Key::P256Secret(p256::SecretKey::try_from(jwk)?)),
195            JwkCrypto::Ec {
196                curve: EcCurve::P256, ..
197            } => Ok(Key::P256Public(p256::PublicKey::try_from(jwk)?)),
198            JwkCrypto::Ec {
199                curve: EcCurve::P384, ..
200            } => Ok(Key::P384Public(p384::PublicKey::try_from(jwk)?)),
201            JwkCrypto::Ec {
202                curve: EcCurve::P521,
203                d: Some(_),
204                ..
205            } => Ok(Key::P521Secret(p521::SecretKey::try_from(jwk)?)),
206            JwkCrypto::Ec {
207                curve: EcCurve::P521, ..
208            } => Ok(Key::P521Public(p521::PublicKey::try_from(jwk)?)),
209            JwkCrypto::Rsa {
210                ..
211            } => Ok(Key::Rsa(RsaPublicKey::try_from(jwk)?)),
212            JwkCrypto::Akp {
213                private_key: Some(_), ..
214            } => match jwk.algorithm {
215                Algorithm::MlDsa44 => Ok(Key::MlDsa44Secret(MlDsa44SecretKey::try_from(jwk)?)),
216                Algorithm::MlDsa65 => Ok(Key::MlDsa65Secret(alloc::boxed::Box::new(MlDsa65SecretKey::try_from(jwk)?))),
217                Algorithm::MlDsa87 => Ok(Key::MlDsa87Secret(alloc::boxed::Box::new(MlDsa87SecretKey::try_from(jwk)?))),
218                _ => Err(Error::InvalidKey),
219            },
220            JwkCrypto::Akp {
221                private_key: None, ..
222            } => match jwk.algorithm {
223                Algorithm::MlDsa44 => Ok(Key::MlDsa44Public(MlDsa44PublicKey::try_from(jwk)?)),
224                Algorithm::MlDsa65 => Ok(Key::MlDsa65Public(MlDsa65PublicKey::try_from(jwk)?)),
225                Algorithm::MlDsa87 => Ok(Key::MlDsa87Public(MlDsa87PublicKey::try_from(jwk)?)),
226                _ => Err(Error::InvalidKey),
227            },
228        }
229    }
230}
231
232impl Key<'_> {
233    /// Returns the JOSE algorithm associated with the key.
234    fn jose_algorithm(&self) -> Algorithm {
235        match self {
236            Key::Secret(key) => Signer::algorithm(key),
237            Key::Ed25519Public(_) | Key::Ed25519Secret(_) => Algorithm::EdDSA,
238            Key::P256Public(_) | Key::P256Secret(_) => Algorithm::ES256,
239            Key::P384Public(_) => Algorithm::ES384,
240            Key::P521Public(_) | Key::P521Secret(_) => Algorithm::ES512,
241            Key::Rsa(key) => Verifier::algorithm(key),
242            Key::MlDsa44Public(_) | Key::MlDsa44Secret(_) => Algorithm::MlDsa44,
243            Key::MlDsa65Public(_) | Key::MlDsa65Secret(_) => Algorithm::MlDsa65,
244            Key::MlDsa87Public(_) | Key::MlDsa87Secret(_) => Algorithm::MlDsa87,
245        }
246    }
247
248    /// Returns true if the Key is a secret key that can be used for signing.
249    pub fn is_secret_key(&self) -> bool {
250        match self {
251            Key::Secret(_)
252            | Key::Ed25519Secret(_)
253            | Key::P256Secret(_)
254            | Key::P521Secret(_)
255            | Key::MlDsa44Secret(_)
256            | Key::MlDsa65Secret(_)
257            | Key::MlDsa87Secret(_) => true,
258            _ => false,
259        }
260    }
261}
262
263impl Signer for Key<'_> {
264    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
265        match self {
266            Key::Secret(key) => Signer::sign(key, message),
267            Key::Ed25519Secret(key) => Signer::sign(key, message),
268            Key::P256Secret(key) => Signer::sign(key, message),
269            Key::P521Secret(key) => Signer::sign(key, message),
270            Key::MlDsa44Secret(key) => Signer::sign(key, message),
271            Key::MlDsa65Secret(key) => Signer::sign(key.as_ref(), message),
272            Key::MlDsa87Secret(key) => Signer::sign(key.as_ref(), message),
273            _ => Err(Error::InvalidKey),
274        }
275    }
276
277    #[inline(always)]
278    fn algorithm(&self) -> Algorithm {
279        self.jose_algorithm()
280    }
281}
282
283impl Verifier for Key<'_> {
284    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
285        match self {
286            Key::Secret(key) => Verifier::verify(key, message, signature),
287            Key::Ed25519Public(key) => Verifier::verify(key, message, signature),
288            Key::Ed25519Secret(key) => Verifier::verify(&key.public_key(), message, signature),
289            Key::P256Public(key) => Verifier::verify(key, message, signature),
290            Key::P256Secret(key) => Verifier::verify(&key.public_key(), message, signature),
291            Key::P384Public(key) => Verifier::verify(key, message, signature),
292            Key::P521Public(key) => Verifier::verify(key, message, signature),
293            Key::P521Secret(key) => Verifier::verify(&key.public_key(), message, signature),
294            Key::Rsa(key) => Verifier::verify(key, message, signature),
295            Key::MlDsa44Public(key) => Verifier::verify(key, message, signature),
296            Key::MlDsa44Secret(key) => Verifier::verify(&key.public_key(), message, signature),
297            Key::MlDsa65Public(key) => Verifier::verify(key, message, signature),
298            Key::MlDsa65Secret(key) => Verifier::verify(&key.public_key(), message, signature),
299            Key::MlDsa87Public(key) => Verifier::verify(key, message, signature),
300            Key::MlDsa87Secret(key) => Verifier::verify(&key.public_key(), message, signature),
301        }
302    }
303
304    #[inline(always)]
305    fn algorithm(&self) -> Algorithm {
306        self.jose_algorithm()
307    }
308}
309
310impl core::fmt::Debug for Key<'_> {
311    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
312        f.write_str(match self {
313            Key::Secret(_) => "Key::Secret",
314            Key::Ed25519Public(_) => "Key::Ed25519Public",
315            Key::Ed25519Secret(_) => "Key::Ed25519Secret",
316            Key::P256Public(_) => "Key::P256Public",
317            Key::P256Secret(_) => "Key::P256Secret",
318            Key::P384Public(_) => "Key::P384Public",
319            Key::P521Public(_) => "Key::P521Public",
320            Key::P521Secret(_) => "Key::P521Secret",
321            Key::Rsa(_) => "Key::Rsa",
322            Key::MlDsa44Public(_) => "Key::MlDsa44Public",
323            Key::MlDsa44Secret(_) => "Key::MlDsa44Secret",
324            Key::MlDsa65Public(_) => "Key::MlDsa65Public",
325            Key::MlDsa65Secret(_) => "Key::MlDsa65Secret",
326            Key::MlDsa87Public(_) => "Key::MlDsa87Public",
327            Key::MlDsa87Secret(_) => "Key::MlDsa87Secret",
328        })
329    }
330}
331
332////////////////////////////////////////////////////////////////////////////////////////////////////
333// Secret key (BLAKE3 / HMAC)
334////////////////////////////////////////////////////////////////////////////////////////////////////
335
336/// A symmetric secret key used with the `BLAKE3`, `HS256`, `HS384`, and `HS512` algorithms.
337///
338/// The key is borrowed, so it must outlive any signing or verification.
339///
340/// Signing and verification fail with [`Error::InvalidKey`] if `algorithm` is not one of the
341/// supported MAC algorithms, if a `BLAKE3` key is not exactly 32 bytes long, or if an HMAC key is
342/// shorter than 16 bytes (128 bits).
343pub struct SecretKey<'a> {
344    pub(crate) key: &'a [u8],
345    pub(crate) algorithm: Algorithm,
346}
347
348impl<'a> SecretKey<'a> {
349    /// Creates a new [`SecretKey`] for `algorithm`.
350    #[inline(always)]
351    pub fn new(algorithm: Algorithm, key: &'a [u8]) -> Self {
352        Self {
353            key,
354            algorithm,
355        }
356    }
357
358    /// Computes the message authentication code of `message`.
359    fn mac(&self, message: &[u8]) -> Result<Hash, Error> {
360        match self.algorithm {
361            Algorithm::BLAKE3 => {
362                let key: &[u8; 32] = self.key.try_into().map_err(|_| Error::InvalidKey)?;
363                Ok(Blake3::keyed_hash(key, message))
364            }
365            Algorithm::HS256 => self.hmac::<Sha256>(message),
366            Algorithm::HS384 => self.hmac::<Sha384>(message),
367            Algorithm::HS512 => self.hmac::<Sha512>(message),
368            _ => Err(Error::InvalidKey),
369        }
370    }
371
372    /// Computes the HMAC of `message` with `H`, requiring at least a 128-bit key.
373    fn hmac<H: Hasher>(&self, message: &[u8]) -> Result<Hash, Error> {
374        if self.key.len() < 16 {
375            return Err(Error::InvalidKey);
376        }
377
378        Ok(Hmac::<H>::mac(self.key, message))
379    }
380}
381
382impl Signer for SecretKey<'_> {
383    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
384        return self.mac(message)?.as_ref().try_into();
385    }
386
387    #[inline(always)]
388    fn algorithm(&self) -> Algorithm {
389        self.algorithm
390    }
391}
392
393impl Verifier for SecretKey<'_> {
394    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
395        let mac = self.mac(message)?;
396        return match constant_time_eq(mac.as_ref(), signature) {
397            true => Ok(()),
398            false => Err(Error::InvalidSignature),
399        };
400    }
401
402    #[inline(always)]
403    fn algorithm(&self) -> Algorithm {
404        self.algorithm
405    }
406}
407
408////////////////////////////////////////////////////////////////////////////////////////////////////
409// Ed25519
410////////////////////////////////////////////////////////////////////////////////////////////////////
411
412impl Signer for ed25519::SecretKey {
413    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
414        return ed25519::SecretKey::sign(self, message).as_ref().try_into();
415    }
416
417    #[inline(always)]
418    fn algorithm(&self) -> Algorithm {
419        Algorithm::EdDSA
420    }
421}
422
423impl Verifier for ed25519::PublicKey {
424    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
425        let signature = signature.try_into().map_err(|_| Error::InvalidSignature)?;
426        return ed25519::PublicKey::verify(self, message, &signature).map_err(|_| Error::InvalidSignature);
427    }
428
429    #[inline(always)]
430    fn algorithm(&self) -> Algorithm {
431        Algorithm::EdDSA
432    }
433}
434
435////////////////////////////////////////////////////////////////////////////////////////////////////
436// P-256
437////////////////////////////////////////////////////////////////////////////////////////////////////
438
439impl Signer for p256::SecretKey {
440    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
441        return p256::SecretKey::sign(self, message)
442            .map_err(|err| Error::Unspecified(alloc::format!("error signing message: {err:?}")))?
443            .as_ref()
444            .try_into();
445    }
446
447    #[inline(always)]
448    fn algorithm(&self) -> Algorithm {
449        Algorithm::ES256
450    }
451}
452
453impl Verifier for p256::PublicKey {
454    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
455        let signature = signature.try_into().map_err(|_| Error::InvalidSignature)?;
456        return p256::PublicKey::verify(self, message, &signature).map_err(|_| Error::InvalidSignature);
457    }
458
459    #[inline(always)]
460    fn algorithm(&self) -> Algorithm {
461        Algorithm::ES256
462    }
463}
464
465////////////////////////////////////////////////////////////////////////////////////////////////////
466// P-384
467////////////////////////////////////////////////////////////////////////////////////////////////////
468
469impl Verifier for p384::PublicKey {
470    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
471        let signature = signature.try_into().map_err(|_| Error::InvalidSignature)?;
472        return p384::PublicKey::verify(self, message, &signature).map_err(|_| Error::InvalidSignature);
473    }
474
475    #[inline(always)]
476    fn algorithm(&self) -> Algorithm {
477        Algorithm::ES384
478    }
479}
480
481////////////////////////////////////////////////////////////////////////////////////////////////////
482// P-521
483////////////////////////////////////////////////////////////////////////////////////////////////////
484
485impl Signer for p521::SecretKey {
486    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
487        return p521::SecretKey::sign(self, message)
488            .map_err(|err| Error::Unspecified(alloc::format!("error signing message: {err:?}")))?
489            .as_ref()
490            .try_into();
491    }
492
493    #[inline(always)]
494    fn algorithm(&self) -> Algorithm {
495        Algorithm::ES512
496    }
497}
498
499impl Verifier for p521::PublicKey {
500    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
501        let signature = signature.try_into().map_err(|_| Error::InvalidSignature)?;
502        return p521::PublicKey::verify(self, message, &signature).map_err(|_| Error::InvalidSignature);
503    }
504
505    #[inline(always)]
506    fn algorithm(&self) -> Algorithm {
507        Algorithm::ES512
508    }
509}
510
511////////////////////////////////////////////////////////////////////////////////////////////////////
512// ML-DSA-44
513////////////////////////////////////////////////////////////////////////////////////////////////////
514
515impl Signer for MlDsa44SecretKey {
516    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
517        return MlDsa44SecretKey::sign(self, message, b"")
518            .map_err(|_| Error::InvalidSignature)?
519            .as_ref()
520            .try_into();
521    }
522
523    #[inline(always)]
524    fn algorithm(&self) -> Algorithm {
525        Algorithm::MlDsa44
526    }
527}
528
529impl Verifier for MlDsa44PublicKey {
530    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
531        let signature: &[u8; ML_DSA_44_SIGNATURE_SIZE] = signature.try_into().map_err(|_| Error::InvalidSignature)?;
532        return MlDsa44PublicKey::verify(self, message, signature, b"").map_err(|_| Error::InvalidSignature);
533    }
534
535    #[inline(always)]
536    fn algorithm(&self) -> Algorithm {
537        Algorithm::MlDsa44
538    }
539}
540
541////////////////////////////////////////////////////////////////////////////////////////////////////
542// ML-DSA-65
543////////////////////////////////////////////////////////////////////////////////////////////////////
544
545impl Signer for MlDsa65SecretKey {
546    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
547        return MlDsa65SecretKey::sign(self, message, b"")
548            .map_err(|_| Error::InvalidSignature)?
549            .as_ref()
550            .try_into();
551    }
552
553    #[inline(always)]
554    fn algorithm(&self) -> Algorithm {
555        Algorithm::MlDsa65
556    }
557}
558
559impl Verifier for MlDsa65PublicKey {
560    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
561        let signature: &[u8; ML_DSA_65_SIGNATURE_SIZE] = signature.try_into().map_err(|_| Error::InvalidSignature)?;
562        return MlDsa65PublicKey::verify(self, message, signature, b"").map_err(|_| Error::InvalidSignature);
563    }
564
565    #[inline(always)]
566    fn algorithm(&self) -> Algorithm {
567        Algorithm::MlDsa65
568    }
569}
570
571////////////////////////////////////////////////////////////////////////////////////////////////////
572// ML-DSA-87
573////////////////////////////////////////////////////////////////////////////////////////////////////
574
575impl Signer for MlDsa87SecretKey {
576    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
577        return MlDsa87SecretKey::sign(self, message, b"")
578            .map_err(|_| Error::InvalidSignature)?
579            .as_ref()
580            .try_into();
581    }
582
583    #[inline(always)]
584    fn algorithm(&self) -> Algorithm {
585        Algorithm::MlDsa87
586    }
587}
588
589impl Verifier for MlDsa87PublicKey {
590    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
591        let signature: &[u8; ML_DSA_87_SIGNATURE_SIZE] = signature.try_into().map_err(|_| Error::InvalidSignature)?;
592        return MlDsa87PublicKey::verify(self, message, signature, b"").map_err(|_| Error::InvalidSignature);
593    }
594
595    #[inline(always)]
596    fn algorithm(&self) -> Algorithm {
597        Algorithm::MlDsa87
598    }
599}
600
601////////////////////////////////////////////////////////////////////////////////////////////////////
602// RSA
603////////////////////////////////////////////////////////////////////////////////////////////////////
604
605/// An RSA public key for JWT verification, supporting both PKCS#1 v1.5 and RSA-PSS signatures.
606///
607/// The algorithm is stored alongside the key because a bare [`rsa::PublicKey`] cannot tell
608/// whether it must verify `RS*` (PKCS#1 v1.5) or `PS*` (RSA-PSS) signatures, nor which hash to use.
609///
610/// # Algorithms
611///
612/// | Variant   | JWT Algorithm | Scheme          | Hash     |
613/// |-----------|---------------|-----------------|----------|
614/// | RS256     | `RS256`       | PKCS#1 v1.5     | SHA-256  |
615/// | RS384     | `RS384`       | PKCS#1 v1.5     | SHA-384  |
616/// | RS512     | `RS512`       | PKCS#1 v1.5     | SHA-512  |
617/// | PS256     | `PS256`       | RSA-PSS         | SHA-256  |
618/// | PS384     | `PS384`       | RSA-PSS         | SHA-384  |
619/// | PS512     | `PS512`       | RSA-PSS         | SHA-512  |
620///
621/// Signing is not supported — this key type is verification-only.
622///
623/// # Constructors
624///
625/// * [`RsaPublicKey::from_n_e`] — build from raw modulus and exponent bytes (useful with JWK)
626/// * [`RsaPublicKey::from_pkcs1_der`] — parse from PKCS#1 DER `SEQUENCE { INTEGER n, INTEGER e }`
627///
628/// # Errors
629///
630/// Returns [`Error::InvalidKey`] if the algorithm is not an RSA variant or
631/// if the underlying RSA key parsing fails. Returns [`Error::InvalidSignature`]
632/// on verification failures.
633pub struct RsaPublicKey {
634    pub(crate) key: rsa::PublicKey,
635    pub(crate) alg: Algorithm,
636}
637
638impl RsaPublicKey {
639    /// Build an RSA public key from raw modulus `n` and public exponent `e`
640    /// (both big-endian byte slices).
641    ///
642    /// This is useful when importing keys from JWK format where `n` and `e`
643    /// are base64url-encoded big-endian byte values.
644    ///
645    /// # Errors
646    ///
647    /// Returns [`Error::InvalidKey`] if `alg` is not an RSA algorithm
648    /// or if the modulus/exponent bytes describe an invalid RSA key.
649    pub(crate) fn from_n_e(alg: Algorithm, n: &[u8], e: &[u8]) -> Result<Self, Error> {
650        if !matches!(
651            alg,
652            Algorithm::RS256
653                | Algorithm::RS384
654                | Algorithm::RS512
655                | Algorithm::PS256
656                | Algorithm::PS384
657                | Algorithm::PS512
658        ) {
659            return Err(Error::InvalidKey);
660        }
661        let key = rsa::PublicKey::from_n_e(n, e).map_err(|_| Error::InvalidKey)?;
662        Ok(RsaPublicKey {
663            key,
664            alg,
665        })
666    }
667
668    /// Parse an RSA public key from PKCS#1 DER bytes.
669    ///
670    /// The input is the raw `SEQUENCE { INTEGER n, INTEGER e }` inside the
671    /// `SubjectPublicKeyInfo` BIT STRING.
672    ///
673    /// # Errors
674    ///
675    /// Returns [`Error::InvalidKey`] if `alg` is not an RSA algorithm
676    /// or if the DER bytes do not encode a valid RSA public key.
677    pub fn from_pkcs1_der(pkcs1_der: &[u8], alg: Algorithm) -> Result<Self, Error> {
678        if !matches!(
679            alg,
680            Algorithm::RS256
681                | Algorithm::RS384
682                | Algorithm::RS512
683                | Algorithm::PS256
684                | Algorithm::PS384
685                | Algorithm::PS512
686        ) {
687            return Err(Error::InvalidKey);
688        }
689        let key = rsa::PublicKey::from_pkcs1_der(pkcs1_der).map_err(|_| Error::InvalidKey)?;
690        Ok(RsaPublicKey {
691            key,
692            alg,
693        })
694    }
695}
696
697impl Verifier for RsaPublicKey {
698    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
699        match self.alg {
700            Algorithm::RS256 => {
701                let digest = Sha256::hash(message);
702                self.key
703                    .verify_pkcs1_v1_5(signature, digest.as_ref(), rsa::DIGEST_INFO_SHA256_PREFIX)
704            }
705            Algorithm::RS384 => {
706                let digest = Sha384::hash(message);
707                self.key
708                    .verify_pkcs1_v1_5(signature, digest.as_ref(), rsa::DIGEST_INFO_SHA384_PREFIX)
709            }
710            Algorithm::RS512 => {
711                let digest = Sha512::hash(message);
712                self.key
713                    .verify_pkcs1_v1_5(signature, digest.as_ref(), rsa::DIGEST_INFO_SHA512_PREFIX)
714            }
715            Algorithm::PS256 => self.key.verify_pss::<Sha256>(signature, message, Sha256::OUTPUT_SIZE),
716            Algorithm::PS384 => self.key.verify_pss::<Sha384>(signature, message, Sha384::OUTPUT_SIZE),
717            Algorithm::PS512 => self.key.verify_pss::<Sha512>(signature, message, Sha512::OUTPUT_SIZE),
718            _ => return Err(Error::InvalidKey),
719        }
720        .map_err(|_| Error::InvalidSignature)
721    }
722
723    #[inline(always)]
724    fn algorithm(&self) -> Algorithm {
725        self.alg
726    }
727}