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 }