jwt_compact/
alg.rs

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