1use std::collections::HashSet;
2
3use coarsetime::{Duration, UnixTimeStamp};
4use ct_codecs::{Base64UrlSafeNoPadding, Decoder, Encoder, Hex};
5use rand::RngCore;
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>,
21
22 pub accept_future: bool,
24
25 pub required_subject: Option<String>,
27
28 pub required_key_id: Option<String>,
30
31 pub required_signature_type: Option<String>,
33
34 pub required_content_type: Option<String>,
36
37 pub required_nonce: Option<String>,
39
40 pub allowed_issuers: Option<HashSet<String>>,
42
43 pub allowed_audiences: Option<HashSet<String>>,
45
46 pub time_tolerance: Option<Duration>,
49
50 pub max_validity: Option<Duration>,
52
53 pub max_token_length: Option<usize>,
55
56 pub max_header_length: Option<usize>,
58
59 pub artificial_time: Option<UnixTimeStamp>,
61}
62
63impl Default for VerificationOptions {
64 fn default() -> Self {
65 Self {
66 reject_before: None,
67 accept_future: false,
68 required_subject: None,
69 required_key_id: None,
70 required_signature_type: None,
71 required_content_type: None,
72 required_nonce: None,
73 allowed_issuers: None,
74 allowed_audiences: None,
75 time_tolerance: Some(Duration::from_secs(DEFAULT_TIME_TOLERANCE_SECS)),
76 max_validity: None,
77 max_token_length: Some(DEFAULT_MAX_TOKEN_LENGTH),
78 max_header_length: None,
79 artificial_time: None,
80 }
81 }
82}
83
84#[derive(Debug, Clone, Default)]
86pub struct HeaderOptions {
87 pub content_type: Option<String>,
90 pub signature_type: Option<String>,
94}
95
96#[derive(Debug, Clone, Default)]
97pub enum Salt {
98 #[default]
100 None,
101 Signer(Vec<u8>),
103 Verifier(Vec<u8>),
105}
106
107impl Salt {
108 pub fn len(&self) -> usize {
110 match self {
111 Salt::None => 0,
112 Salt::Signer(s) => s.len(),
113 Salt::Verifier(s) => s.len(),
114 }
115 }
116
117 pub fn is_empty(&self) -> bool {
119 self.len() == 0
120 }
121
122 pub fn generate() -> Self {
124 let mut salt = vec![0u8; 32];
125 rand::thread_rng().fill_bytes(&mut salt);
126 Salt::Signer(salt)
127 }
128}
129
130impl AsRef<[u8]> for Salt {
131 fn as_ref(&self) -> &[u8] {
133 match self {
134 Salt::None => &[],
135 Salt::Signer(s) => s,
136 Salt::Verifier(s) => s,
137 }
138 }
139}
140
141#[derive(Debug, Clone, Default)]
145pub struct KeyMetadata {
146 pub(crate) key_set_url: Option<String>,
147 pub(crate) public_key: Option<String>,
148 pub(crate) certificate_url: Option<String>,
149 pub(crate) certificate_sha1_thumbprint: Option<String>,
150 pub(crate) certificate_sha256_thumbprint: Option<String>,
151 pub(crate) salt: Salt,
152}
153
154impl KeyMetadata {
155 pub fn with_salt(mut self, salt: Salt) -> Self {
157 self.salt = salt;
158 self
159 }
160
161 pub fn with_key_set_url(mut self, key_set_url: impl ToString) -> Self {
163 self.key_set_url = Some(key_set_url.to_string());
164 self
165 }
166
167 pub fn with_public_key(mut self, public_key: impl ToString) -> Self {
169 self.public_key = Some(public_key.to_string());
170 self
171 }
172
173 pub fn with_certificate_url(mut self, certificate_url: impl ToString) -> Self {
175 self.certificate_url = Some(certificate_url.to_string());
176 self
177 }
178
179 pub fn with_certificate_sha1_thumbprint(
181 mut self,
182 certificate_sha1_thumbprint: impl ToString,
183 ) -> Result<Self, Error> {
184 let thumbprint = certificate_sha1_thumbprint.to_string();
185 let mut bin = [0u8; 20];
186 if thumbprint.len() == 40 {
187 ensure!(
188 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
189 JWTError::InvalidCertThumprint
190 );
191 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
192 self.certificate_sha1_thumbprint = Some(thumbprint);
193 return Ok(self);
194 }
195 ensure!(
196 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
197 JWTError::InvalidCertThumprint
198 );
199 self.certificate_sha1_thumbprint = Some(thumbprint);
200 Ok(self)
201 }
202
203 pub fn with_certificate_sha256_thumbprint(
205 mut self,
206 certificate_sha256_thumbprint: impl ToString,
207 ) -> Result<Self, Error> {
208 let thumbprint = certificate_sha256_thumbprint.to_string();
209 let mut bin = [0u8; 32];
210 if thumbprint.len() == 64 {
211 ensure!(
212 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
213 JWTError::InvalidCertThumprint
214 );
215 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
216 self.certificate_sha256_thumbprint = Some(thumbprint);
217 return Ok(self);
218 }
219 ensure!(
220 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
221 JWTError::InvalidCertThumprint
222 );
223 self.certificate_sha256_thumbprint = Some(thumbprint);
224 Ok(self)
225 }
226}
227
228#[inline(never)]
229pub(crate) fn timingsafe_eq(a: &[u8], b: &[u8]) -> bool {
230 if a.len() != b.len() {
231 return false;
232 }
233 a.iter().zip(b.iter()).fold(0, |c, (x, y)| c | (x ^ y)) == 0
234}