tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lib.rs (4739B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 use origin_trial_token::{RawToken, Token, TokenValidationError, Usage};
      6 use std::ffi::c_void;
      7 
      8 #[repr(u8)]
      9 pub enum OriginTrial {
     10    // NOTE(emilio): 0 is reserved for WebIDL usage.
     11    TestTrial = 1,
     12    CoepCredentialless = 2,
     13    PrivateAttributionV2 = 3,
     14    MLS = 4,
     15 
     16    MAX,
     17 }
     18 
     19 impl OriginTrial {
     20    fn from_str(s: &str) -> Option<Self> {
     21        Some(match s {
     22            "TestTrial" => Self::TestTrial,
     23            "CoepCredentialless" => Self::CoepCredentialless,
     24            "PrivateAttributionV2" => Self::PrivateAttributionV2,
     25            "MLS" => Self::MLS,
     26            _ => return None,
     27        })
     28    }
     29 }
     30 
     31 #[repr(u8)]
     32 pub enum OriginTrialResult {
     33    Ok { trial: OriginTrial },
     34    BufferTooSmall,
     35    MismatchedPayloadSize { expected: usize, actual: usize },
     36    InvalidSignature,
     37    UnknownVersion,
     38    UnsupportedThirdPartyToken,
     39    UnexpectedUsageInNonThirdPartyToken,
     40    MalformedPayload,
     41    ExpiredToken,
     42    UnknownTrial,
     43    OriginMismatch,
     44 }
     45 
     46 impl OriginTrialResult {
     47    fn from_error(e: TokenValidationError) -> Self {
     48        match e {
     49            TokenValidationError::BufferTooSmall => OriginTrialResult::BufferTooSmall,
     50            TokenValidationError::MismatchedPayloadSize { expected, actual } => {
     51                OriginTrialResult::MismatchedPayloadSize { expected, actual }
     52            }
     53            TokenValidationError::InvalidSignature => OriginTrialResult::InvalidSignature,
     54            TokenValidationError::UnknownVersion => OriginTrialResult::UnknownVersion,
     55            TokenValidationError::UnsupportedThirdPartyToken => {
     56                OriginTrialResult::UnsupportedThirdPartyToken
     57            }
     58            TokenValidationError::UnexpectedUsageInNonThirdPartyToken => {
     59                OriginTrialResult::UnexpectedUsageInNonThirdPartyToken
     60            }
     61            TokenValidationError::MalformedPayload(..) => OriginTrialResult::MalformedPayload,
     62        }
     63    }
     64 }
     65 
     66 /// A struct that allows you to configure how validation on works, and pass
     67 /// state to the signature verification.
     68 #[repr(C)]
     69 pub struct OriginTrialValidationParams {
     70    /// Verify a given signature against the signed data.
     71    pub verify_signature: extern "C" fn(
     72        signature: *const u8,
     73        signature_len: usize,
     74        data: *const u8,
     75        data_len: usize,
     76        user_data: *mut c_void,
     77    ) -> bool,
     78 
     79    /// Returns whether a given origin, which is passed as the first two
     80    /// arguments, and guaranteed to be valid UTF-8, passes the validation for a
     81    /// given invocation.
     82    pub matches_origin: extern "C" fn(
     83        origin: *const u8,
     84        len: usize,
     85        is_subdomain: bool,
     86        is_third_party: bool,
     87        is_usage_subset: bool,
     88        user_data: *mut c_void,
     89    ) -> bool,
     90 
     91    /// A pointer with user-supplied data that will be passed down to the
     92    /// other functions in this method.
     93    pub user_data: *mut c_void,
     94 }
     95 
     96 #[no_mangle]
     97 pub unsafe extern "C" fn origin_trials_parse_and_validate_token(
     98    bytes: *const u8,
     99    len: usize,
    100    params: &OriginTrialValidationParams,
    101 ) -> OriginTrialResult {
    102    let slice = std::slice::from_raw_parts(bytes, len);
    103    let raw_token = match RawToken::from_buffer(slice) {
    104        Ok(token) => token,
    105        Err(e) => return OriginTrialResult::from_error(e),
    106    };
    107 
    108    // Verifying the token is usually more expensive than the early-outs here.
    109    let token = match Token::from_raw_token_unverified(raw_token) {
    110        Ok(token) => token,
    111        Err(e) => return OriginTrialResult::from_error(e),
    112    };
    113 
    114    if token.is_expired() {
    115        return OriginTrialResult::ExpiredToken;
    116    }
    117 
    118    let trial = match OriginTrial::from_str(token.feature()) {
    119        Some(t) => t,
    120        None => return OriginTrialResult::UnknownTrial,
    121    };
    122 
    123    let is_usage_subset = match token.usage {
    124        Usage::None => false,
    125        Usage::Subset => true,
    126    };
    127 
    128    if !(params.matches_origin)(
    129        token.origin.as_ptr(),
    130        token.origin.len(),
    131        token.is_subdomain,
    132        token.is_third_party,
    133        is_usage_subset,
    134        params.user_data,
    135    ) {
    136        return OriginTrialResult::OriginMismatch;
    137    }
    138 
    139    let valid_signature = raw_token.verify(|signature, data| {
    140        (params.verify_signature)(
    141            signature.as_ptr(),
    142            signature.len(),
    143            data.as_ptr(),
    144            data.len(),
    145            params.user_data,
    146        )
    147    });
    148 
    149    if !valid_signature {
    150        return OriginTrialResult::InvalidSignature;
    151    }
    152 
    153    OriginTrialResult::Ok { trial }
    154 }