use std::collections::HashSet;
use coarsetime::{Duration, UnixTimeStamp};
use ct_codecs::{Base64UrlSafeNoPadding, Decoder, Encoder, Hex};
use crate::{claims::DEFAULT_TIME_TOLERANCE_SECS, error::*};
pub const DEFAULT_MAX_TOKEN_LENGTH: usize = 1_000_000;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VerificationOptions {
pub reject_before: Option<UnixTimeStamp>,
pub accept_future: bool,
pub required_subject: Option<String>,
pub required_key_id: Option<String>,
pub required_public_key: Option<String>,
pub required_nonce: Option<String>,
pub allowed_issuers: Option<HashSet<String>>,
pub allowed_audiences: Option<HashSet<String>>,
pub time_tolerance: Option<Duration>,
pub max_validity: Option<Duration>,
pub max_token_length: Option<usize>,
pub max_header_length: Option<usize>,
pub artificial_time: Option<UnixTimeStamp>,
}
impl Default for VerificationOptions {
fn default() -> Self {
Self {
reject_before: None,
accept_future: false,
required_subject: None,
required_key_id: None,
required_public_key: None,
required_nonce: None,
allowed_issuers: None,
allowed_audiences: None,
time_tolerance: Some(Duration::from_secs(DEFAULT_TIME_TOLERANCE_SECS)),
max_validity: None,
max_token_length: Some(DEFAULT_MAX_TOKEN_LENGTH),
max_header_length: None,
artificial_time: None,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct KeyMetadata {
pub(crate) key_set_url: Option<String>,
pub(crate) public_key: Option<String>,
pub(crate) certificate_url: Option<String>,
pub(crate) certificate_sha1_thumbprint: Option<String>,
pub(crate) certificate_sha256_thumbprint: Option<String>,
}
impl KeyMetadata {
pub fn with_key_set_url(mut self, key_set_url: impl ToString) -> Self {
self.key_set_url = Some(key_set_url.to_string());
self
}
pub fn with_public_key(mut self, public_key: impl ToString) -> Self {
self.public_key = Some(public_key.to_string());
self
}
pub fn with_certificate_url(mut self, certificate_url: impl ToString) -> Self {
self.certificate_url = Some(certificate_url.to_string());
self
}
pub fn with_certificate_sha1_thumbprint(
mut self,
certificate_sha1_thumbprint: impl ToString,
) -> Result<Self, Error> {
let thumbprint = certificate_sha1_thumbprint.to_string();
let mut bin = [0u8; 20];
if thumbprint.len() == 40 {
ensure!(
Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
JWTError::InvalidCertThumprint
);
let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
self.certificate_sha1_thumbprint = Some(thumbprint);
return Ok(self);
}
ensure!(
Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
JWTError::InvalidCertThumprint
);
self.certificate_sha1_thumbprint = Some(thumbprint);
Ok(self)
}
pub fn with_certificate_sha256_thumbprint(
mut self,
certificate_sha256_thumbprint: impl ToString,
) -> Result<Self, Error> {
let thumbprint = certificate_sha256_thumbprint.to_string();
let mut bin = [0u8; 32];
if thumbprint.len() == 64 {
ensure!(
Hex::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
JWTError::InvalidCertThumprint
);
let thumbprint = Base64UrlSafeNoPadding::encode_to_string(bin)?;
self.certificate_sha256_thumbprint = Some(thumbprint);
return Ok(self);
}
ensure!(
Base64UrlSafeNoPadding::decode(&mut bin, &thumbprint, None)?.len() == bin.len(),
JWTError::InvalidCertThumprint
);
self.certificate_sha256_thumbprint = Some(thumbprint);
Ok(self)
}
}
#[inline(never)]
pub(crate) fn timingsafe_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
a.iter().zip(b.iter()).fold(0, |c, (x, y)| c | (x ^ y)) == 0
}