diff options
Diffstat (limited to 'dom/origin-trials/ffi/lib.rs')
-rw-r--r-- | dom/origin-trials/ffi/lib.rs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/dom/origin-trials/ffi/lib.rs b/dom/origin-trials/ffi/lib.rs new file mode 100644 index 0000000000..1745c9e790 --- /dev/null +++ b/dom/origin-trials/ffi/lib.rs @@ -0,0 +1,150 @@ +/* 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 + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +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, + + MAX, +} + +impl OriginTrial { + fn from_str(s: &str) -> Option<Self> { + Some(match s { + "TestTrial" => Self::TestTrial, + "CoepCredentialless" => Self::CoepCredentialless, + _ => 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 } +} |