diff options
Diffstat (limited to 'dom/origin-trials/ffi')
-rw-r--r-- | dom/origin-trials/ffi/.gitignore | 2 | ||||
-rw-r--r-- | dom/origin-trials/ffi/Cargo.toml | 14 | ||||
-rw-r--r-- | dom/origin-trials/ffi/cbindgen.toml | 18 | ||||
-rw-r--r-- | dom/origin-trials/ffi/lib.rs | 150 |
4 files changed, 184 insertions, 0 deletions
diff --git a/dom/origin-trials/ffi/.gitignore b/dom/origin-trials/ffi/.gitignore new file mode 100644 index 0000000000..2c96eb1b65 --- /dev/null +++ b/dom/origin-trials/ffi/.gitignore @@ -0,0 +1,2 @@ +target/ +Cargo.lock diff --git a/dom/origin-trials/ffi/Cargo.toml b/dom/origin-trials/ffi/Cargo.toml new file mode 100644 index 0000000000..710b846176 --- /dev/null +++ b/dom/origin-trials/ffi/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "origin-trials-ffi" +version = "0.1.0" +edition = "2021" +authors = [ + "Emilio Cobos Álvarez <emilio@crisal.io>", +] +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies] +origin-trial-token = "0.1" diff --git a/dom/origin-trials/ffi/cbindgen.toml b/dom/origin-trials/ffi/cbindgen.toml new file mode 100644 index 0000000000..1b95a60280 --- /dev/null +++ b/dom/origin-trials/ffi/cbindgen.toml @@ -0,0 +1,18 @@ +header = """/* 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/. */ + +#ifndef mozilla_OriginTrials_h +#error "Don't include this file directly, include mozilla/OriginTrials.h instead" +#endif +""" +include_guard = "mozilla_OriginTrials_ffi_h" +include_version = true +language = "C++" +namespaces = ["mozilla", "origin_trials_ffi"] +includes = ["mozilla/Assertions.h"] + +[enum] +derive_helper_methods = true +derive_const_casts = true +cast_assert_name = "MOZ_DIAGNOSTIC_ASSERT" 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 } +} |