1use std::collections::HashSet;
2
3use coarsetime::{Duration, UnixTimeStamp};
4use ct_codecs::{Base64UrlSafeNoPadding, Decoder, Encoder, Hex};
5use rand::Rng;
6
7use crate::{claims::DEFAULT_TIME_TOLERANCE_SECS, error::*};
8
9pub const DEFAULT_MAX_TOKEN_LENGTH: usize = 1_000_000;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
14pub struct VerificationOptions {
15 pub reject_before: Option<UnixTimeStamp>,
26
27 pub accept_future: bool,
29
30 pub required_subject: Option<String>,
32
33 pub required_key_id: Option<String>,
35
36 pub required_signature_type: Option<String>,
38
39 pub required_content_type: Option<String>,
41
42 pub required_nonce: Option<String>,
44
45 pub allowed_issuers: Option<HashSet<String>>,
47
48 pub allowed_audiences: Option<HashSet<String>>,
50
51 pub time_tolerance: Option<Duration>,
54
55 pub max_validity: Option<Duration>,
57
58 pub max_token_length: Option<usize>,
61
62 pub max_header_length: Option<usize>,
64
65 pub artificial_time: Option<UnixTimeStamp>,
67}
68
69impl Default for VerificationOptions {
70 fn default() -> Self {
71 Self {
72 reject_before: None,
73 accept_future: false,
74 required_subject: None,
75 required_key_id: None,
76 required_signature_type: None,
77 required_content_type: None,
78 required_nonce: None,
79 allowed_issuers: None,
80 allowed_audiences: None,
81 time_tolerance: Some(Duration::from_secs(DEFAULT_TIME_TOLERANCE_SECS)),
82 max_validity: None,
83 max_token_length: Some(DEFAULT_MAX_TOKEN_LENGTH),
84 max_header_length: None,
85 artificial_time: None,
86 }
87 }
88}
89
90#[derive(Debug, Clone, Default)]
92pub struct HeaderOptions {
93 pub content_type: Option<String>,
96 pub signature_type: Option<String>,
100}
101
102#[derive(Debug, Clone, Default)]
103pub enum Salt {
104 #[default]
106 None,
107 Signer(Vec<u8>),
109 Verifier(Vec<u8>),
111}
112
113impl Salt {
114 pub fn len(&self) -> usize {
116 match self {
117 Salt::None => 0,
118 Salt::Signer(s) => s.len(),
119 Salt::Verifier(s) => s.len(),
120 }
121 }
122
123 pub fn is_empty(&self) -> bool {
125 self.len() == 0
126 }
127
128 pub fn generate() -> Self {
130 let mut salt = vec![0u8; 32];
131 rand::rng().fill_bytes(&mut salt);
132 Salt::Signer(salt)
133 }
134}
135
136impl AsRef<[u8]> for Salt {
137 fn as_ref(&self) -> &[u8] {
139 match self {
140 Salt::None => &[],
141 Salt::Signer(s) => s,
142 Salt::Verifier(s) => s,
143 }
144 }
145}
146
147#[derive(Debug, Clone, Default)]
151pub struct KeyMetadata {
152 pub(crate) key_set_url: Option<String>,
153 pub(crate) public_key: Option<String>,
154 pub(crate) certificate_url: Option<String>,
155 pub(crate) certificate_sha1_thumbprint: Option<String>,
156 pub(crate) certificate_sha256_thumbprint: Option<String>,
157 pub(crate) salt: Salt,
158}
159
160impl KeyMetadata {
161 pub fn with_salt(mut self, salt: Salt) -> Self {
163 self.salt = salt;
164 self
165 }
166
167 pub fn with_key_set_url(mut self, key_set_url: impl ToString) -> Self {
169 self.key_set_url = Some(key_set_url.to_string());
170 self
171 }
172
173 pub fn with_public_key(mut self, public_key: impl ToString) -> Self {
175 self.public_key = Some(public_key.to_string());
176 self
177 }
178
179 pub fn with_certificate_url(mut self, certificate_url: impl ToString) -> Self {
181 self.certificate_url = Some(certificate_url.to_string());
182 self
183 }
184
185 pub fn with_certificate_sha1_thumbprint(
187 mut self,
188 certificate_sha1_thumbprint: impl ToString,
189 ) -> Result<Self, Error> {
190 let thumbprint = certificate_sha1_thumbprint.to_string();
191 let mut bin = [0u8; 20];
192 if thumbprint.len() == 40 {
193 ensure!(
194 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
195 JWTError::InvalidCertThumprint
196 );
197 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
198 self.certificate_sha1_thumbprint = Some(thumbprint);
199 return Ok(self);
200 }
201 ensure!(
202 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
203 JWTError::InvalidCertThumprint
204 );
205 self.certificate_sha1_thumbprint = Some(thumbprint);
206 Ok(self)
207 }
208
209 pub fn with_certificate_sha256_thumbprint(
211 mut self,
212 certificate_sha256_thumbprint: impl ToString,
213 ) -> Result<Self, Error> {
214 let thumbprint = certificate_sha256_thumbprint.to_string();
215 let mut bin = [0u8; 32];
216 if thumbprint.len() == 64 {
217 ensure!(
218 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
219 JWTError::InvalidCertThumprint
220 );
221 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
222 self.certificate_sha256_thumbprint = Some(thumbprint);
223 return Ok(self);
224 }
225 ensure!(
226 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
227 JWTError::InvalidCertThumprint
228 );
229 self.certificate_sha256_thumbprint = Some(thumbprint);
230 Ok(self)
231 }
232}