Skip to main content

jwt/
jwt_crypto.rs

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