1use std::collections::HashSet;
2
3use coarsetime::{Duration, UnixTimeStamp};
4use ct_codecs::{Base64UrlSafeNoPadding, Decoder, Encoder, Hex};
5
6use crate::{claims::DEFAULT_TIME_TOLERANCE_SECS, error::*};
7
8pub const DEFAULT_MAX_TOKEN_LENGTH: usize = 1_000_000;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct VerificationOptions {
14 pub reject_before: Option<UnixTimeStamp>,
20
21 pub accept_future: bool,
23
24 pub required_subject: Option<String>,
26
27 pub required_key_id: Option<String>,
29
30 pub required_public_key: Option<String>,
32
33 pub required_nonce: Option<String>,
35
36 pub allowed_issuers: Option<HashSet<String>>,
38
39 pub allowed_audiences: Option<HashSet<String>>,
41
42 pub time_tolerance: Option<Duration>,
44
45 pub max_validity: Option<Duration>,
47
48 pub max_token_length: Option<usize>,
50
51 pub max_header_length: Option<usize>,
53
54 pub artificial_time: Option<UnixTimeStamp>,
56}
57
58impl Default for VerificationOptions {
59 fn default() -> Self {
60 Self {
61 reject_before: None,
62 accept_future: false,
63 required_subject: None,
64 required_key_id: None,
65 required_public_key: None,
66 required_nonce: None,
67 allowed_issuers: None,
68 allowed_audiences: None,
69 time_tolerance: Some(Duration::from_secs(DEFAULT_TIME_TOLERANCE_SECS)),
70 max_validity: None,
71 max_token_length: Some(DEFAULT_MAX_TOKEN_LENGTH),
72 max_header_length: None,
73 artificial_time: None,
74 }
75 }
76}
77
78#[derive(Debug, Clone, Default)]
82pub struct KeyMetadata {
83 pub(crate) key_set_url: Option<String>,
84 pub(crate) public_key: Option<String>,
85 pub(crate) certificate_url: Option<String>,
86 pub(crate) certificate_sha1_thumbprint: Option<String>,
87 pub(crate) certificate_sha256_thumbprint: Option<String>,
88}
89
90impl KeyMetadata {
91 pub fn with_key_set_url(mut self, key_set_url: impl ToString) -> Self {
93 self.key_set_url = Some(key_set_url.to_string());
94 self
95 }
96
97 pub fn with_public_key(mut self, public_key: impl ToString) -> Self {
99 self.public_key = Some(public_key.to_string());
100 self
101 }
102
103 pub fn with_certificate_url(mut self, certificate_url: impl ToString) -> Self {
105 self.certificate_url = Some(certificate_url.to_string());
106 self
107 }
108
109 pub fn with_certificate_sha1_thumbprint(
111 mut self,
112 certificate_sha1_thumbprint: impl ToString,
113 ) -> Result<Self, Error> {
114 let thumbprint = certificate_sha1_thumbprint.to_string();
115 let mut bin = [0u8; 20];
116 if thumbprint.len() == 40 {
117 ensure!(
118 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
119 JWTError::InvalidCertThumprint
120 );
121 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
122 self.certificate_sha1_thumbprint = Some(thumbprint);
123 return Ok(self);
124 }
125 ensure!(
126 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
127 JWTError::InvalidCertThumprint
128 );
129 self.certificate_sha1_thumbprint = Some(thumbprint);
130 Ok(self)
131 }
132
133 pub fn with_certificate_sha256_thumbprint(
135 mut self,
136 certificate_sha256_thumbprint: impl ToString,
137 ) -> Result<Self, Error> {
138 let thumbprint = certificate_sha256_thumbprint.to_string();
139 let mut bin = [0u8; 32];
140 if thumbprint.len() == 64 {
141 ensure!(
142 Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
143 JWTError::InvalidCertThumprint
144 );
145 let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
146 self.certificate_sha256_thumbprint = Some(thumbprint);
147 return Ok(self);
148 }
149 ensure!(
150 Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
151 JWTError::InvalidCertThumprint
152 );
153 self.certificate_sha256_thumbprint = Some(thumbprint);
154 Ok(self)
155 }
156}
157
158#[inline(never)]
159pub(crate) fn timingsafe_eq(a: &[u8], b: &[u8]) -> bool {
160 if a.len() != b.len() {
161 return false;
162 }
163 a.iter().zip(b.iter()).fold(0, |c, (x, y)| c | (x ^ y)) == 0
164}