1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Implementations of JWT signing / verification algorithms. Also contains generic traits
//! for signing and verifying keys.

use core::fmt;

#[cfg(feature = "ed25519-compact")]
pub use self::eddsa_compact::*;
#[cfg(feature = "ed25519-dalek")]
pub use self::eddsa_dalek::Ed25519;
#[cfg(feature = "exonum-crypto")]
pub use self::eddsa_sodium::Ed25519;
#[cfg(feature = "es256k")]
pub use self::es256k::Es256k;
#[cfg(feature = "k256")]
pub use self::k256::Es256k;
#[cfg(feature = "p256")]
pub use self::p256::Es256;
#[cfg(feature = "rsa")]
#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
pub use self::rsa::{
    ModulusBits, ModulusBitsError, Rsa, RsaError, RsaParseError, RsaPrivateKey, RsaPublicKey,
    RsaSignature,
};
pub use self::{
    generic::{SecretBytes, SigningKey, VerifyingKey},
    hmacs::*,
};
use crate::{alloc::Cow, Algorithm};

mod generic;
mod hmacs;
// Alternative ES256K implementations.
#[cfg(feature = "secp256k1")]
mod es256k;
#[cfg(feature = "k256")]
mod k256;
// Alternative EdDSA implementations.
#[cfg(feature = "ed25519-compact")]
mod eddsa_compact;
#[cfg(feature = "ed25519-dalek")]
mod eddsa_dalek;
#[cfg(feature = "exonum-crypto")]
mod eddsa_sodium;
// ES256 implemenation.
#[cfg(feature = "p256")]
mod p256;
// RSA implementation.
#[cfg(feature = "rsa")]
mod rsa;

/// Wrapper around keys allowing to enforce key strength requirements.
///
/// The wrapper signifies that the key has supported strength as per the corresponding
/// algorithm spec. For example, RSA keys must have length at least 2,048 bits per [RFC 7518].
/// Likewise, `HS*` keys must have at least the length of the hash output
/// (e.g., 32 bytes for `HS256`). Since these requirements sometimes clash with backward
/// compatibility (and sometimes a lesser level of security is enough),
/// notion of key strength is implemented in such an opt-in, composable way.
///
/// It's easy to convert a `StrongKey<T>` to `T` via [`into_inner()`](Self::into_inner()) or to
/// access `&T` via `AsRef` impl. In contrast, the reverse transformation is fallible, and
/// is defined with the help of [`TryFrom`]. The error type for `TryFrom` is [`WeakKeyError`],
/// a simple wrapper around a weak key.
///
/// # Examples
///
/// See [`StrongAlg`] docs for an example of usage.
///
/// [RFC 7518]: https://www.rfc-editor.org/rfc/rfc7518.html
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StrongKey<T>(T);

impl<T> StrongKey<T> {
    /// Returns the wrapped value.
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> AsRef<T> for StrongKey<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}

/// Error type used for fallible conversion into a [`StrongKey`].
///
/// The error wraps around a weak key, which can be extracted for further use.
#[derive(Debug)]
pub struct WeakKeyError<T>(pub T);

impl<T> fmt::Display for WeakKeyError<T> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("Weak cryptographic key")
    }
}

#[cfg(feature = "std")]
impl<T: fmt::Debug + 'static> std::error::Error for WeakKeyError<T> {}

/// Wrapper around a JWT algorithm signalling that it supports only [`StrongKey`]s.
///
/// The wrapper will implement `Algorithm` if the wrapped value is an `Algorithm` with both
/// signing and verifying keys convertible to `StrongKey`s.
///
/// # Examples
///
/// ```
/// # use rand::thread_rng;
/// # use jwt_compact::{prelude::*, alg::{Hs256, Hs256Key, StrongAlg, StrongKey}};
/// # fn main() -> anyhow::Result<()> {
/// let weak_key = Hs256Key::new(b"too short!");
/// assert!(StrongKey::try_from(weak_key).is_err());
/// // There is no way to create a `StrongKey` from `weak_key`!
///
/// let strong_key: StrongKey<_> = Hs256Key::generate(&mut thread_rng());
/// let claims = // ...
/// #   Claims::empty();
/// let token = StrongAlg(Hs256)
///     .token(&Header::empty(), &claims, &strong_key)?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone, Copy, Default)]
pub struct StrongAlg<T>(pub T);

#[allow(clippy::trait_duplication_in_bounds)] // false positive
impl<T: Algorithm> Algorithm for StrongAlg<T>
where
    StrongKey<T::SigningKey>: TryFrom<T::SigningKey>,
    StrongKey<T::VerifyingKey>: TryFrom<T::VerifyingKey>,
{
    type SigningKey = StrongKey<T::SigningKey>;
    type VerifyingKey = StrongKey<T::VerifyingKey>;
    type Signature = T::Signature;

    fn name(&self) -> Cow<'static, str> {
        self.0.name()
    }

    fn sign(&self, signing_key: &Self::SigningKey, message: &[u8]) -> Self::Signature {
        self.0.sign(&signing_key.0, message)
    }

    fn verify_signature(
        &self,
        signature: &Self::Signature,
        verifying_key: &Self::VerifyingKey,
        message: &[u8],
    ) -> bool {
        self.0
            .verify_signature(signature, &verifying_key.0, message)
    }
}