Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
use origin_trial_token::{RawToken, Token, TokenValidationError, Usage};
use std::ffi::c_void;
#[repr(u8)]
pub enum OriginTrial {
// NOTE(emilio): 0 is reserved for WebIDL usage.
TestTrial = 1,
CoepCredentialless = 2,
PrivateAttributionV2 = 3,
MAX,
}
impl OriginTrial {
fn from_str(s: &str) -> Option<Self> {
Some(match s {
"TestTrial" => Self::TestTrial,
"CoepCredentialless" => Self::CoepCredentialless,
"PrivateAttributionV2" => Self::PrivateAttributionV2,
_ => return None,
})
}
}
#[repr(u8)]
pub enum OriginTrialResult {
Ok { trial: OriginTrial },
BufferTooSmall,
MismatchedPayloadSize { expected: usize, actual: usize },
InvalidSignature,
UnknownVersion,
UnsupportedThirdPartyToken,
UnexpectedUsageInNonThirdPartyToken,
MalformedPayload,
ExpiredToken,
UnknownTrial,
OriginMismatch,
}
impl OriginTrialResult {
fn from_error(e: TokenValidationError) -> Self {
match e {
TokenValidationError::BufferTooSmall => OriginTrialResult::BufferTooSmall,
TokenValidationError::MismatchedPayloadSize { expected, actual } => {
OriginTrialResult::MismatchedPayloadSize { expected, actual }
}
TokenValidationError::InvalidSignature => OriginTrialResult::InvalidSignature,
TokenValidationError::UnknownVersion => OriginTrialResult::UnknownVersion,
TokenValidationError::UnsupportedThirdPartyToken => {
OriginTrialResult::UnsupportedThirdPartyToken
}
TokenValidationError::UnexpectedUsageInNonThirdPartyToken => {
OriginTrialResult::UnexpectedUsageInNonThirdPartyToken
}
TokenValidationError::MalformedPayload(..) => OriginTrialResult::MalformedPayload,
}
}
}
/// A struct that allows you to configure how validation on works, and pass
/// state to the signature verification.
#[repr(C)]
pub struct OriginTrialValidationParams {
/// Verify a given signature against the signed data.
pub verify_signature: extern "C" fn(
signature: *const u8,
signature_len: usize,
data: *const u8,
data_len: usize,
user_data: *mut c_void,
) -> bool,
/// Returns whether a given origin, which is passed as the first two
/// arguments, and guaranteed to be valid UTF-8, passes the validation for a
/// given invocation.
pub matches_origin: extern "C" fn(
origin: *const u8,
len: usize,
is_subdomain: bool,
is_third_party: bool,
is_usage_subset: bool,
user_data: *mut c_void,
) -> bool,
/// A pointer with user-supplied data that will be passed down to the
/// other functions in this method.
pub user_data: *mut c_void,
}
#[no_mangle]
pub unsafe extern "C" fn origin_trials_parse_and_validate_token(
bytes: *const u8,
len: usize,
params: &OriginTrialValidationParams,
) -> OriginTrialResult {
let slice = std::slice::from_raw_parts(bytes, len);
let raw_token = match RawToken::from_buffer(slice) {
Ok(token) => token,
Err(e) => return OriginTrialResult::from_error(e),
};
// Verifying the token is usually more expensive than the early-outs here.
let token = match Token::from_raw_token_unverified(raw_token) {
Ok(token) => token,
Err(e) => return OriginTrialResult::from_error(e),
};
if token.is_expired() {
return OriginTrialResult::ExpiredToken;
}
let trial = match OriginTrial::from_str(token.feature()) {
Some(t) => t,
None => return OriginTrialResult::UnknownTrial,
};
let is_usage_subset = match token.usage {
Usage::None => false,
Usage::Subset => true,
};
if !(params.matches_origin)(
token.origin.as_ptr(),
token.origin.len(),
token.is_subdomain,
token.is_third_party,
is_usage_subset,
params.user_data,
) {
return OriginTrialResult::OriginMismatch;
}
let valid_signature = raw_token.verify(|signature, data| {
(params.verify_signature)(
signature.as_ptr(),
signature.len(),
data.as_ptr(),
data.len(),
params.user_data,
)
});
if !valid_signature {
return OriginTrialResult::InvalidSignature;
}
OriginTrialResult::Ok { trial }
}