jwt_compact/alg.rs
1//! Implementations of JWT signing / verification algorithms. Also contains generic traits
2//! for signing and verifying keys.
3
4use alloc::borrow::Cow;
5use core::fmt;
6
7#[cfg(feature = "ed25519-compact")]
8pub use self::eddsa_compact::*;
9#[cfg(feature = "ed25519-dalek")]
10pub use self::eddsa_dalek::Ed25519;
11#[cfg(feature = "exonum-crypto")]
12pub use self::eddsa_sodium::Ed25519;
13#[cfg(feature = "es256k")]
14pub use self::es256k::Es256k;
15#[cfg(feature = "k256")]
16pub use self::k256::Es256k;
17#[cfg(feature = "p256")]
18pub use self::p256::Es256;
19#[cfg(feature = "rsa")]
20#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
21pub use self::rsa::{
22 ModulusBits, ModulusBitsError, Rsa, RsaError, RsaParseError, RsaPrivateKey, RsaPublicKey,
23 RsaSignature,
24};
25pub use self::{
26 generic::{SecretBytes, SigningKey, VerifyingKey},
27 hmacs::*,
28};
29use crate::Algorithm;
30
31mod generic;
32mod hmacs;
33// Alternative ES256K implementations.
34#[cfg(feature = "secp256k1")]
35mod es256k;
36#[cfg(feature = "k256")]
37mod k256;
38// Alternative EdDSA implementations.
39#[cfg(feature = "ed25519-compact")]
40mod eddsa_compact;
41#[cfg(feature = "ed25519-dalek")]
42mod eddsa_dalek;
43#[cfg(feature = "exonum-crypto")]
44mod eddsa_sodium;
45// ES256 implemenation.
46#[cfg(feature = "p256")]
47mod p256;
48// RSA implementation.
49#[cfg(feature = "rsa")]
50mod rsa;
51
52/// Wrapper around keys allowing to enforce key strength requirements.
53///
54/// The wrapper signifies that the key has supported strength as per the corresponding
55/// algorithm spec. For example, RSA keys must have length at least 2,048 bits per [RFC 7518].
56/// Likewise, `HS*` keys must have at least the length of the hash output
57/// (e.g., 32 bytes for `HS256`). Since these requirements sometimes clash with backward
58/// compatibility (and sometimes a lesser level of security is enough),
59/// notion of key strength is implemented in such an opt-in, composable way.
60///
61/// It's easy to convert a `StrongKey<T>` to `T` via [`into_inner()`](Self::into_inner()) or to
62/// access `&T` via `AsRef` impl. In contrast, the reverse transformation is fallible, and
63/// is defined with the help of [`TryFrom`]. The error type for `TryFrom` is [`WeakKeyError`],
64/// a simple wrapper around a weak key.
65///
66/// # Examples
67///
68/// See [`StrongAlg`] docs for an example of usage.
69///
70/// [RFC 7518]: https://www.rfc-editor.org/rfc/rfc7518.html
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub struct StrongKey<T>(T);
73
74impl<T> StrongKey<T> {
75 /// Returns the wrapped value.
76 pub fn into_inner(self) -> T {
77 self.0
78 }
79}
80
81impl<T> AsRef<T> for StrongKey<T> {
82 fn as_ref(&self) -> &T {
83 &self.0
84 }
85}
86
87/// Error type used for fallible conversion into a [`StrongKey`].
88///
89/// The error wraps around a weak key, which can be extracted for further use.
90#[derive(Debug)]
91pub struct WeakKeyError<T>(pub T);
92
93impl<T> fmt::Display for WeakKeyError<T> {
94 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
95 formatter.write_str("Weak cryptographic key")
96 }
97}
98
99impl<T: fmt::Debug + 'static> core::error::Error for WeakKeyError<T> {}
100
101/// Wrapper around a JWT algorithm signalling that it supports only [`StrongKey`]s.
102///
103/// The wrapper will implement `Algorithm` if the wrapped value is an `Algorithm` with both
104/// signing and verifying keys convertible to `StrongKey`s.
105///
106/// # Examples
107///
108/// ```
109/// # use jwt_compact::{prelude::*, alg::{Hs256, Hs256Key, StrongAlg, StrongKey}};
110/// # fn main() -> anyhow::Result<()> {
111/// let weak_key = Hs256Key::new(b"too short!");
112/// assert!(StrongKey::try_from(weak_key).is_err());
113/// // There is no way to create a `StrongKey` from `weak_key`!
114///
115/// let strong_key: StrongKey<_> = Hs256Key::generate(&mut rand::rng());
116/// let claims = // ...
117/// # Claims::empty();
118/// let token = StrongAlg(Hs256)
119/// .token(&Header::empty(), &claims, &strong_key)?;
120/// # Ok(())
121/// # }
122/// ```
123#[derive(Debug, Clone, Copy, Default)]
124pub struct StrongAlg<T>(pub T);
125
126#[allow(clippy::trait_duplication_in_bounds)] // false positive
127impl<T: Algorithm> Algorithm for StrongAlg<T>
128where
129 StrongKey<T::SigningKey>: TryFrom<T::SigningKey>,
130 StrongKey<T::VerifyingKey>: TryFrom<T::VerifyingKey>,
131{
132 type SigningKey = StrongKey<T::SigningKey>;
133 type VerifyingKey = StrongKey<T::VerifyingKey>;
134 type Signature = T::Signature;
135
136 fn name(&self) -> Cow<'static, str> {
137 self.0.name()
138 }
139
140 fn sign(&self, signing_key: &Self::SigningKey, message: &[u8]) -> Self::Signature {
141 self.0.sign(&signing_key.0, message)
142 }
143
144 fn verify_signature(
145 &self,
146 signature: &Self::Signature,
147 verifying_key: &Self::VerifyingKey,
148 message: &[u8],
149 ) -> bool {
150 self.0
151 .verify_signature(signature, &verifying_key.0, message)
152 }
153}