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_public_key: Option<String>,
33
34 pub required_nonce: Option<String>,
36
37 pub allowed_issuers: Option<HashSet<String>>,
39
40 pub allowed_audiences: Option<HashSet<String>>,
42
43 pub time_tolerance: Option<Duration>,
46
47 pub max_validity: Option<Duration>,
49
50 pub max_token_length: Option<usize>,
52
53 pub max_header_length: Option<usize>,
55
56 pub artificial_time: Option<UnixTimeStamp>,
58}
59
60impl Default for VerificationOptions {
61 fn default() -> Self {
62 Self {
63 reject_before: None,
64 accept_future: false,
65 required_subject: None,
66 required_key_id: None,
67 required_public_key: None,
68 required_nonce: None,
69 allowed_issuers: None,
70 allowed_audiences: None,
71 time_tolerance: Some(Duration::from_secs(DEFAULT_TIME_TOLERANCE_SECS)),
72 max_validity: None,
73 max_token_length: Some(DEFAULT_MAX_TOKEN_LENGTH),
74 max_header_length: None,
75 artificial_time: None,
76 }
77 }
78}
79
80#[derive(Debug, Clone, Default)]
81pub enum Salt {
82 #[default]
84 None,
85 Signer(Vec<u8>),
87 Verifier(Vec<u8>),
89}
90
91impl Salt {
92 pub fn len(&self) -> usize {
94 match self {
95 Salt::None => 0,
96 Salt::Signer(s) => s.len(),
97 Salt::Verifier(s) => s.len(),
98 }
99 }
100
101 pub fn generate() -> Self {
103 let mut salt = vec![0u8; 32];
104 rand::thread_rng().fill_bytes(&mut salt);
105 Salt::Signer(salt)
106 }
107}
108
109impl AsRef<[u8]> for Salt {
110 fn as_ref(&self) -> &[u8] {
112 match self {
113 Salt::None => &[],
114 Salt::Signer(s) => s,
115 Salt::Verifier(s) => s,
116 }
117 }
118}
119
120#[derive(Debug, Clone, Default)]
124pub struct KeyMetadata {
125 pub(crate) key_set_url: Option<String>,
126 pub(crate) public_key: Option<String>,
127 pub(crate) certificate_url: Option<String>,
128 pub(crate) certificate_sha1_thumbprint: Option<String>,
129 pub(crate) certificate_sha256_thumbprint: Option<String>,
130 pub(crate) salt: Salt,
131}
132
133impl KeyMetadata {
134 pub fn with_salt(mut self, salt: Salt) -> Self {
136 self.salt = salt;
137 self
138 }
139
140 pub fn with_key_set_url(mut self, key_set_url: impl ToString) -> Self {
142 self.key_set_url = Some(key_set_url.to_string());
143 self
144 }
145
146 pub fn with_public_key(mut self, public_key: impl ToString) -> Self {
148 self.public_key = Some(public_key.to_string());
149 self
150 }
151
152 pub fn with_certificate_url(mut self, certificate_url: impl ToString) -> Self {
154 self.certificate_url = Some(certificate_url.to_string());
155 self
156 }
157
158 pub fn with_certificate_sha1_thumbprint(
160 mut self,
161 certificate_sha1_thumbprint: impl ToString,
162 ) -> Result<Self, Error> {
163 let thumbprint = certificate_sha1_thumbprint.to_string();
164 let mut bin = [0u8; 20];
165 if thumbprint.len() == 40 {
166 ensure!(
167 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
168 JWTError::InvalidCertThumprint
169 );
170 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
171 self.certificate_sha1_thumbprint = Some(thumbprint);
172 return Ok(self);
173 }
174 ensure!(
175 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
176 JWTError::InvalidCertThumprint
177 );
178 self.certificate_sha1_thumbprint = Some(thumbprint);
179 Ok(self)
180 }
181
182 pub fn with_certificate_sha256_thumbprint(
184 mut self,
185 certificate_sha256_thumbprint: impl ToString,
186 ) -> Result<Self, Error> {
187 let thumbprint = certificate_sha256_thumbprint.to_string();
188 let mut bin = [0u8; 32];
189 if thumbprint.len() == 64 {
190 ensure!(
191 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
192 JWTError::InvalidCertThumprint
193 );
194 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
195 self.certificate_sha256_thumbprint = Some(thumbprint);
196 return Ok(self);
197 }
198 ensure!(
199 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
200 JWTError::InvalidCertThumprint
201 );
202 self.certificate_sha256_thumbprint = Some(thumbprint);
203 Ok(self)
204 }
205}
206
207#[inline(never)]
208pub(crate) fn timingsafe_eq(a: &[u8], b: &[u8]) -> bool {
209 if a.len() != b.len() {
210 return false;
211 }
212 a.iter().zip(b.iter()).fold(0, |c, (x, y)| c | (x ^ y)) == 0
213}