use std::collections::HashSet;
use coarsetime::{Duration, UnixTimeStamp};
use ct_codecs::{Base64UrlSafeNoPadding, Decoder, Encoder, Hex};
use rand::RngCore;
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_signature_type: Option<String>,
pub required_content_type: 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_signature_type: None,
required_content_type: 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 HeaderOptions {
pub content_type: Option<String>,
pub signature_type: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub enum Salt {
#[default]
None,
Signer(Vec<u8>),
Verifier(Vec<u8>),
}
impl Salt {
pub fn len(&self) -> usize {
match self {
Salt::None => 0,
Salt::Signer(s) => s.len(),
Salt::Verifier(s) => s.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn generate() -> Self {
let mut salt = vec![0u8; 32];
rand::thread_rng().fill_bytes(&mut salt);
Salt::Signer(salt)
}
}
impl AsRef<[u8]> for Salt {
fn as_ref(&self) -> &[u8] {
match self {
Salt::None => &[],
Salt::Signer(s) => s,
Salt::Verifier(s) => s,
}
}
}
#[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>,
pub(crate) salt: Salt,
}
impl KeyMetadata {
pub fn with_salt(mut self, salt: Salt) -> Self {
self.salt = salt;
self
}
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)
}
}