attenuable_jwt/
protocol.rs

1//! This module provides types and traits library users need for signing and verifying attenuable JWTs.
2
3use erased_serde::Serialize as ErasedSerialize;
4use serde::{de::DeserializeOwned, Deserialize, Serialize};
5
6/// Newtype struct for a string representing a signed JWT.
7#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(transparent)]
9pub struct SignedJWT(pub String);
10
11impl AsRef<str> for SignedJWT {
12    fn as_ref(&self) -> &str {
13        &self.0
14    }
15}
16
17/// Claims for a sealed attenuated JWT.
18/// These are the claims of the JWT produced by [crate::sign::AttenuableJWT::seal].
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
20pub(crate) struct SealedClaims {
21    /// Expiration.
22    pub exp: Option<SecondsSinceEpoch>,
23    /// Not before.
24    pub nbf: Option<SecondsSinceEpoch>,
25    /// Issuer.
26    pub iss: Option<Issuer>,
27    /// Audience.
28    pub aud: Option<Audience>,
29    /// Inner JWTs, starting with the root JWT and ending with the most-attenuated JWT.
30    pub jwts: Vec<SignedJWT>,
31}
32
33/// Newtype wrapper for the number of seconds elapsed since the unix epoch.
34/// Used in the `exp` and `nbf` claims of JWTs.
35#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
36#[serde(transparent)]
37pub struct SecondsSinceEpoch(pub u64);
38
39/// Newtype wrapper for issuer identifiers.
40/// Used in the `iss` claim of JWTs.
41#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
42#[serde(transparent)]
43pub struct Issuer(pub String);
44
45impl AsRef<str> for Issuer {
46    fn as_ref(&self) -> &str {
47        &self.0
48    }
49}
50
51/// Newtype wrapper for audience identifiers.
52/// Used in the `aud` claim of JWTs.
53#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
54#[serde(transparent)]
55pub struct Audience(pub String);
56
57impl AsRef<str> for Audience {
58    fn as_ref(&self) -> &str {
59        &self.0
60    }
61}
62
63/// A private key. The [ErasedSerialize] implementation must serialize to a JWK.
64pub trait PrivateKey: ErasedSerialize {
65    /// Key ID.
66    fn key_id(&self) -> &str;
67    /// Algorithm.
68    fn algorithm(&self) -> &str;
69    /// Sign the message.
70    fn sign(&self, message: &[u8]) -> crate::sign::Result<Vec<u8>>;
71}
72
73/// A public key. The [ErasedSerialize] implementation must serialize to a JWK.
74pub trait PublicKey: ErasedSerialize {
75    /// Key ID.
76    fn key_id(&self) -> &str;
77    /// Algorithm.
78    fn algorithm(&self) -> &str;
79    /// Intended use for the key.
80    fn key_use(&self) -> KeyUse;
81    /// Verify the signature of the message.
82    fn verify(&self, message: &[u8], signature: &[u8]) -> bool;
83}
84
85erased_serde::serialize_trait_object!(PublicKey);
86
87/// Key use identifiers.
88/// Used in the `use` claim of a JWK.
89#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
90pub enum KeyUse {
91    /// Encryption.
92    #[serde(rename = "enc")]
93    Encryption,
94    /// Signing.
95    #[serde(rename = "sig")]
96    Signing,
97}
98
99/// Trait containing all client-supplied information needed for verify a sealed [crate::sign::AttenuableJWT].
100pub trait VerificationKeyManager: Clone {
101    /// Type of the public key for the root JWT.
102    /// The root JWT may be signed by a different algorithm with a different type of key than the attenuated JWTs added to it.
103    /// For example, the root JWT may be signed with a secret key, whereas only asymmetric keys are suitable for attenuated JWTs.
104    type PublicRootKey: PublicKey;
105    /// Type of the public key for attenuated JWTs.
106    /// IMPORTANT: THIS MUST BE AN ASYMMETRIC KEY.
107    /// This is the public key counterpart to the [Self::PrivateAttenuationKey].
108    type PublicAttenuationKey: PublicKey;
109    /// Type of the private key for attenuated JWTs.
110    /// IMPORTANT: THIS MUST BE AN ASYMMETRIC KEY.
111    /// This is the private key counterpart to the [Self::PublicAttenuationKey].
112    type PrivateAttenuationKey: PrivateKey;
113    /// Type of the client-supplied attenuated claims.
114    /// Any type that is serializable to/from a JSON object is suitable.
115    type Claims: Serialize + DeserializeOwned;
116    /// Type of the JWK that represents a [Self::PublicAttenuationKey].
117    type JWK: Serialize + DeserializeOwned;
118
119    /// Given a `key_id` if it is present in the JWT header, return the corresponding [Self::PublicRootKey].
120    fn get_root_key(&self, key_id: &Option<String>) -> Option<Self::PublicRootKey>;
121    /// The [VerificationRequirements] to use for verifying the sealed JWT envelope.
122    fn get_envelope_verification_requirements(&self) -> VerificationRequirements;
123    /// [crate::verify::verify] performs a fold over existing and new claims for each JWT in the chain, invoking the client-provided `resolve_claims` function with the existing and new claims.
124    /// The `default_claims` are used as the initial value in that fold.
125    fn default_claims(&self) -> Self::Claims;
126    /// Given a [Self::JWK], return a [Self::PublicAttenuationKey].
127
128    // Convert a [Self::JWK] into a [Self::PublicAttenuationKey].
129    fn jwk_to_public_attenuation_key(&self, jwk: &Self::JWK) -> Option<Self::PublicAttenuationKey>;
130}
131
132/// JWT header.
133#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
134pub(crate) struct JWTHeader {
135    /// Key ID for the key used to sign this JWT.
136    #[serde(rename = "kid")]
137    pub key_id: Option<String>,
138    /// Algorithm used to sign this JWT.
139    #[serde(rename = "alg")]
140    pub algorithm: String,
141}
142
143/// Verification requirements to use when verifying a signed JWT.
144#[derive(Clone, Debug, PartialEq, Eq)]
145pub enum VerificationRequirements {
146    /// Verify the signature and provided claims for the JWT.
147    VerifyClaims {
148        /// Acceptable signing algorithms.
149        acceptable_algorithms: Vec<String>,
150        /// Acceptable issuers. None indicates any issuer is acceptable.
151        acceptable_issuers: Option<Vec<Issuer>>,
152        /// Acceptable audiences. None indicates any audience is acceptable.
153        acceptable_audiences: Option<Vec<Audience>>,
154        /// Acceptable subject. None indicates any subject is acceptable.
155        acceptable_subject: Option<String>,
156    },
157    /// Only verify the signature of the JWT but do not verify any claims.
158    VerifySignatureOnly {
159        /// Acceptable signing algorithms.
160        acceptable_algorithms: Vec<String>,
161    },
162}
163
164impl VerificationRequirements {
165    /// Acceptable signing algorithms.
166    pub fn acceptable_algorithms(&self) -> &[String] {
167        match self {
168            VerificationRequirements::VerifyClaims {
169                acceptable_algorithms,
170                ..
171            } => acceptable_algorithms,
172            VerificationRequirements::VerifySignatureOnly {
173                acceptable_algorithms,
174            } => acceptable_algorithms,
175        }
176    }
177}
178
179/// Trait handling signing and key generation for [crate::sign::AttenuableJWT].
180pub trait SigningKeyManager:
181    AttenuationKeyGenerator<Self::PublicAttenuationKey, Self::PrivateAttenuationKey> + Clone
182{
183    /// Type of the JWK for the [Self::PublicAttenuationKey].
184    type JWK: Serialize;
185    /// Type of the public key for the attenuation keys.
186    type PublicAttenuationKey: PublicKey;
187    /// Type of the private key for the attenuation keys.
188    type PrivateAttenuationKey: PrivateKey;
189    /// Type of the private key for the root JWT.
190    type PrivateRootKey: PrivateKey;
191    /// Type to represent the claims of the JWT. Any type that serializes to a map is suitable.
192    type Claims: Serialize;
193
194    /// Return a JWK representing the provided public attenuation key.
195    fn jwk_for_public_attenuation_key(
196        public_attenuation_key: &Self::PublicAttenuationKey,
197    ) -> Self::JWK;
198}
199
200/// Trait for generating new attenuation keys.
201pub trait AttenuationKeyGenerator<
202    PublicAttenuationKey: PublicKey,
203    PrivateAttenuationKey: PrivateKey,
204>
205{
206    /// Generate a new, random attenuation key.
207    fn generate_attenuation_key(
208        &self,
209    ) -> Result<(PublicAttenuationKey, PrivateAttenuationKey), crate::sign::Error>;
210}
211
212/// The full set of claims for an attenuated JWT, combining user-provided claims with the attenuation key claim.
213#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
214pub(crate) struct FullClaims<JWK, Claims> {
215    /// User-provided claims.
216    #[serde(flatten)]
217    pub user_provided_claims: Claims,
218    /// Attenuation key claim containing a JWK representing the public key of the next attenuation key.
219    pub aky: JWK,
220}
221
222impl<JWK: Serialize, Claims: Serialize> FullClaims<JWK, Claims> {
223    /// Create a FullClaims.
224    pub fn new(user_provided_claims: Claims, aky: JWK) -> Self {
225        Self {
226            user_provided_claims,
227            aky,
228        }
229    }
230}