Backed out changeset 1d9301697aa0 (bug 1887752) for causing failures on browser_all_f...
[gecko.git] / dom / origin-trials / ffi / lib.rs
blob1745c9e790a60dd98d3b76aee4bd001acc7d5273
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/. */
5 use origin_trial_token::{RawToken, Token, TokenValidationError, Usage};
6 use std::ffi::c_void;
8 #[repr(u8)]
9 pub enum OriginTrial {
10     // NOTE(emilio): 0 is reserved for WebIDL usage.
11     TestTrial = 1,
12     CoepCredentialless = 2,
14     MAX,
17 impl OriginTrial {
18     fn from_str(s: &str) -> Option<Self> {
19         Some(match s {
20             "TestTrial" => Self::TestTrial,
21             "CoepCredentialless" => Self::CoepCredentialless,
22             _ => return None,
23         })
24     }
27 #[repr(u8)]
28 pub enum OriginTrialResult {
29     Ok { trial: OriginTrial },
30     BufferTooSmall,
31     MismatchedPayloadSize { expected: usize, actual: usize },
32     InvalidSignature,
33     UnknownVersion,
34     UnsupportedThirdPartyToken,
35     UnexpectedUsageInNonThirdPartyToken,
36     MalformedPayload,
37     ExpiredToken,
38     UnknownTrial,
39     OriginMismatch,
42 impl OriginTrialResult {
43     fn from_error(e: TokenValidationError) -> Self {
44         match e {
45             TokenValidationError::BufferTooSmall => OriginTrialResult::BufferTooSmall,
46             TokenValidationError::MismatchedPayloadSize { expected, actual } => {
47                 OriginTrialResult::MismatchedPayloadSize { expected, actual }
48             }
49             TokenValidationError::InvalidSignature => OriginTrialResult::InvalidSignature,
50             TokenValidationError::UnknownVersion => OriginTrialResult::UnknownVersion,
51             TokenValidationError::UnsupportedThirdPartyToken => {
52                 OriginTrialResult::UnsupportedThirdPartyToken
53             }
54             TokenValidationError::UnexpectedUsageInNonThirdPartyToken => {
55                 OriginTrialResult::UnexpectedUsageInNonThirdPartyToken
56             }
57             TokenValidationError::MalformedPayload(..) => OriginTrialResult::MalformedPayload,
58         }
59     }
62 /// A struct that allows you to configure how validation on works, and pass
63 /// state to the signature verification.
64 #[repr(C)]
65 pub struct OriginTrialValidationParams {
66     /// Verify a given signature against the signed data.
67     pub verify_signature: extern "C" fn(
68         signature: *const u8,
69         signature_len: usize,
70         data: *const u8,
71         data_len: usize,
72         user_data: *mut c_void,
73     ) -> bool,
75     /// Returns whether a given origin, which is passed as the first two
76     /// arguments, and guaranteed to be valid UTF-8, passes the validation for a
77     /// given invocation.
78     pub matches_origin: extern "C" fn(
79         origin: *const u8,
80         len: usize,
81         is_subdomain: bool,
82         is_third_party: bool,
83         is_usage_subset: bool,
84         user_data: *mut c_void,
85     ) -> bool,
87     /// A pointer with user-supplied data that will be passed down to the
88     /// other functions in this method.
89     pub user_data: *mut c_void,
92 #[no_mangle]
93 pub unsafe extern "C" fn origin_trials_parse_and_validate_token(
94     bytes: *const u8,
95     len: usize,
96     params: &OriginTrialValidationParams,
97 ) -> OriginTrialResult {
98     let slice = std::slice::from_raw_parts(bytes, len);
99     let raw_token = match RawToken::from_buffer(slice) {
100         Ok(token) => token,
101         Err(e) => return OriginTrialResult::from_error(e),
102     };
104     // Verifying the token is usually more expensive than the early-outs here.
105     let token = match Token::from_raw_token_unverified(raw_token) {
106         Ok(token) => token,
107         Err(e) => return OriginTrialResult::from_error(e),
108     };
110     if token.is_expired() {
111         return OriginTrialResult::ExpiredToken;
112     }
114     let trial = match OriginTrial::from_str(token.feature()) {
115         Some(t) => t,
116         None => return OriginTrialResult::UnknownTrial,
117     };
119     let is_usage_subset = match token.usage {
120         Usage::None => false,
121         Usage::Subset => true,
122     };
124     if !(params.matches_origin)(
125         token.origin.as_ptr(),
126         token.origin.len(),
127         token.is_subdomain,
128         token.is_third_party,
129         is_usage_subset,
130         params.user_data,
131     ) {
132         return OriginTrialResult::OriginMismatch;
133     }
135     let valid_signature = raw_token.verify(|signature, data| {
136         (params.verify_signature)(
137             signature.as_ptr(),
138             signature.len(),
139             data.as_ptr(),
140             data.len(),
141             params.user_data,
142         )
143     });
145     if !valid_signature {
146         return OriginTrialResult::InvalidSignature;
147     }
149     OriginTrialResult::Ok { trial }