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