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::{Token, TokenValidationError, Usage};
6 use std::ffi::c_void;
7
8 #[repr(u8)]
9 pub enum OriginTrial {
10 TestTrial,
11 }
12
13 impl OriginTrial {
from_str(s: &str) -> Option<Self>14 fn from_str(s: &str) -> Option<Self> {
15 return Some(match s {
16 "TestTrial" => Self::TestTrial,
17 _ => return None,
18 });
19 }
20 }
21
22 #[repr(u8)]
23 pub enum OriginTrialResult {
24 Ok { trial: OriginTrial },
25 BufferTooSmall,
26 MismatchedPayloadSize { expected: usize, actual: usize },
27 InvalidSignature,
28 UnknownVersion,
29 UnsupportedThirdPartyToken,
30 UnexpectedUsageInNonThirdPartyToken,
31 MalformedPayload,
32 ExpiredToken,
33 UnknownTrial,
34 OriginMismatch,
35 }
36
37 /// A struct that allows you to configure how validation on works, and pass
38 /// state to the signature verification.
39 #[repr(C)]
40 pub struct OriginTrialValidationParams {
41 /// Verify a given signature against the signed data.
42 pub verify_signature: extern "C" fn(
43 signature: *const u8,
44 signature_len: usize,
45 data: *const u8,
46 data_len: usize,
47 user_data: *mut c_void,
48 ) -> bool,
49
50 /// Returns whether a given origin, which is passed as the first two
51 /// arguments, and guaranteed to be valid UTF-8, passes the validation for a
52 /// given invocation.
53 pub matches_origin: extern "C" fn(
54 origin: *const u8,
55 len: usize,
56 is_subdomain: bool,
57 is_third_party: bool,
58 is_usage_subset: bool,
59 user_data: *mut c_void,
60 ) -> bool,
61
62 /// A pointer with user-supplied data that will be passed down to the
63 /// other functions in this method.
64 pub user_data: *mut c_void,
65 }
66
67 #[no_mangle]
origin_trials_parse_and_validate_token( bytes: *const u8, len: usize, params: &OriginTrialValidationParams, ) -> OriginTrialResult68 pub unsafe extern "C" fn origin_trials_parse_and_validate_token(
69 bytes: *const u8,
70 len: usize,
71 params: &OriginTrialValidationParams,
72 ) -> OriginTrialResult {
73 let slice = std::slice::from_raw_parts(bytes, len);
74 let token = Token::from_buffer(slice, |signature, data| {
75 (params.verify_signature)(
76 signature.as_ptr(),
77 signature.len(),
78 data.as_ptr(),
79 data.len(),
80 params.user_data,
81 )
82 });
83
84 let token = match token {
85 Ok(token) => token,
86 Err(e) => {
87 return match e {
88 TokenValidationError::BufferTooSmall => OriginTrialResult::BufferTooSmall,
89 TokenValidationError::MismatchedPayloadSize { expected, actual } => {
90 OriginTrialResult::MismatchedPayloadSize { expected, actual }
91 }
92 TokenValidationError::InvalidSignature => OriginTrialResult::InvalidSignature,
93 TokenValidationError::UnknownVersion => OriginTrialResult::UnknownVersion,
94 TokenValidationError::UnsupportedThirdPartyToken => {
95 OriginTrialResult::UnsupportedThirdPartyToken
96 }
97 TokenValidationError::UnexpectedUsageInNonThirdPartyToken => {
98 OriginTrialResult::UnexpectedUsageInNonThirdPartyToken
99 }
100 TokenValidationError::MalformedPayload(..) => OriginTrialResult::MalformedPayload,
101 }
102 }
103 };
104
105 if token.is_expired() {
106 return OriginTrialResult::ExpiredToken;
107 }
108
109 let trial = match OriginTrial::from_str(token.feature()) {
110 Some(t) => t,
111 None => return OriginTrialResult::UnknownTrial,
112 };
113
114 let is_usage_subset = match token.usage {
115 Usage::None => false,
116 Usage::Subset => true,
117 };
118
119 if !(params.matches_origin)(
120 token.origin.as_ptr(),
121 token.origin.len(),
122 token.is_subdomain,
123 token.is_third_party,
124 is_usage_subset,
125 params.user_data,
126 ) {
127 return OriginTrialResult::OriginMismatch;
128 }
129
130 OriginTrialResult::Ok { trial }
131 }
132