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}