xref: /aosp_15_r20/system/gatekeeper/gatekeeper.cpp (revision e582193eb076ba33b8e166dadabb22babbe4aebd)
1*e582193eSAndroid Build Coastguard Worker /*
2*e582193eSAndroid Build Coastguard Worker  * Copyright 2015 The Android Open Source Project
3*e582193eSAndroid Build Coastguard Worker  *
4*e582193eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e582193eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e582193eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e582193eSAndroid Build Coastguard Worker  *
8*e582193eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e582193eSAndroid Build Coastguard Worker  *
10*e582193eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e582193eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e582193eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e582193eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e582193eSAndroid Build Coastguard Worker  * limitations under the License.
15*e582193eSAndroid Build Coastguard Worker  */
16*e582193eSAndroid Build Coastguard Worker #include <gatekeeper/UniquePtr.h>
17*e582193eSAndroid Build Coastguard Worker #include <gatekeeper/gatekeeper.h>
18*e582193eSAndroid Build Coastguard Worker 
19*e582193eSAndroid Build Coastguard Worker #ifdef _WIN32
20*e582193eSAndroid Build Coastguard Worker #include <winsock2.h>
21*e582193eSAndroid Build Coastguard Worker #define htobe32 htonl
22*e582193eSAndroid Build Coastguard Worker #define htobe64 htonll_gk
23*e582193eSAndroid Build Coastguard Worker #else
24*e582193eSAndroid Build Coastguard Worker #include <endian.h>
25*e582193eSAndroid Build Coastguard Worker #endif
26*e582193eSAndroid Build Coastguard Worker 
27*e582193eSAndroid Build Coastguard Worker #include <stddef.h>
28*e582193eSAndroid Build Coastguard Worker 
29*e582193eSAndroid Build Coastguard Worker #define DAY_IN_MS (1000 * 60 * 60 * 24)
30*e582193eSAndroid Build Coastguard Worker 
31*e582193eSAndroid Build Coastguard Worker #ifdef _WIN32
htonll_gk(uint64_t value)32*e582193eSAndroid Build Coastguard Worker __forceinline uint64_t htonll_gk(uint64_t value) {
33*e582193eSAndroid Build Coastguard Worker     return (((uint64_t)htonl(value & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)(value >> 32));
34*e582193eSAndroid Build Coastguard Worker }
35*e582193eSAndroid Build Coastguard Worker #endif
36*e582193eSAndroid Build Coastguard Worker 
37*e582193eSAndroid Build Coastguard Worker namespace gatekeeper {
38*e582193eSAndroid Build Coastguard Worker 
Enroll(const EnrollRequest & request,EnrollResponse * response)39*e582193eSAndroid Build Coastguard Worker void GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) {
40*e582193eSAndroid Build Coastguard Worker     if (response == nullptr) return;
41*e582193eSAndroid Build Coastguard Worker 
42*e582193eSAndroid Build Coastguard Worker     if (!request.provided_password) {
43*e582193eSAndroid Build Coastguard Worker         response->error = ERROR_INVALID;
44*e582193eSAndroid Build Coastguard Worker         return;
45*e582193eSAndroid Build Coastguard Worker     }
46*e582193eSAndroid Build Coastguard Worker 
47*e582193eSAndroid Build Coastguard Worker     secure_id_t user_id = 0;// todo: rename to policy
48*e582193eSAndroid Build Coastguard Worker     uint32_t uid = request.user_id;
49*e582193eSAndroid Build Coastguard Worker 
50*e582193eSAndroid Build Coastguard Worker     if (!request.password_handle) {
51*e582193eSAndroid Build Coastguard Worker         // Password handle does not match what is stored, generate new SecureID
52*e582193eSAndroid Build Coastguard Worker         GetRandom(&user_id, sizeof(secure_id_t));
53*e582193eSAndroid Build Coastguard Worker     } else {
54*e582193eSAndroid Build Coastguard Worker         const password_handle_t *pw_handle = request.password_handle.Data<password_handle_t>();
55*e582193eSAndroid Build Coastguard Worker 
56*e582193eSAndroid Build Coastguard Worker         if (!pw_handle || pw_handle->version > HANDLE_VERSION) {
57*e582193eSAndroid Build Coastguard Worker             response->error = ERROR_INVALID;
58*e582193eSAndroid Build Coastguard Worker             return;
59*e582193eSAndroid Build Coastguard Worker         }
60*e582193eSAndroid Build Coastguard Worker 
61*e582193eSAndroid Build Coastguard Worker         user_id = pw_handle->user_id;
62*e582193eSAndroid Build Coastguard Worker 
63*e582193eSAndroid Build Coastguard Worker         uint64_t timestamp = GetMillisecondsSinceBoot();
64*e582193eSAndroid Build Coastguard Worker 
65*e582193eSAndroid Build Coastguard Worker         uint32_t timeout = 0;
66*e582193eSAndroid Build Coastguard Worker         bool throttle = (pw_handle->version >= HANDLE_VERSION_THROTTLE);
67*e582193eSAndroid Build Coastguard Worker         if (throttle) {
68*e582193eSAndroid Build Coastguard Worker             bool throttle_secure = pw_handle->flags & HANDLE_FLAG_THROTTLE_SECURE;
69*e582193eSAndroid Build Coastguard Worker             failure_record_t record;
70*e582193eSAndroid Build Coastguard Worker             if (!GetFailureRecord(uid, user_id, &record, throttle_secure)) {
71*e582193eSAndroid Build Coastguard Worker                 response->error = ERROR_UNKNOWN;
72*e582193eSAndroid Build Coastguard Worker                 return;
73*e582193eSAndroid Build Coastguard Worker             }
74*e582193eSAndroid Build Coastguard Worker 
75*e582193eSAndroid Build Coastguard Worker             if (ThrottleRequest(uid, timestamp, &record, throttle_secure, response)) return;
76*e582193eSAndroid Build Coastguard Worker 
77*e582193eSAndroid Build Coastguard Worker             if (!IncrementFailureRecord(uid, user_id, timestamp, &record, throttle_secure)) {
78*e582193eSAndroid Build Coastguard Worker                 response->error = ERROR_UNKNOWN;
79*e582193eSAndroid Build Coastguard Worker                 return;
80*e582193eSAndroid Build Coastguard Worker             }
81*e582193eSAndroid Build Coastguard Worker 
82*e582193eSAndroid Build Coastguard Worker             timeout = ComputeRetryTimeout(&record);
83*e582193eSAndroid Build Coastguard Worker         }
84*e582193eSAndroid Build Coastguard Worker 
85*e582193eSAndroid Build Coastguard Worker         if (!DoVerify(pw_handle, request.enrolled_password)) {
86*e582193eSAndroid Build Coastguard Worker             // incorrect old password
87*e582193eSAndroid Build Coastguard Worker             if (throttle && timeout > 0) {
88*e582193eSAndroid Build Coastguard Worker                 response->SetRetryTimeout(timeout);
89*e582193eSAndroid Build Coastguard Worker             } else {
90*e582193eSAndroid Build Coastguard Worker                 response->error = ERROR_INVALID;
91*e582193eSAndroid Build Coastguard Worker             }
92*e582193eSAndroid Build Coastguard Worker             return;
93*e582193eSAndroid Build Coastguard Worker         }
94*e582193eSAndroid Build Coastguard Worker     }
95*e582193eSAndroid Build Coastguard Worker 
96*e582193eSAndroid Build Coastguard Worker     uint64_t flags = 0;
97*e582193eSAndroid Build Coastguard Worker     if (ClearFailureRecord(uid, user_id, true)) {
98*e582193eSAndroid Build Coastguard Worker         flags |= HANDLE_FLAG_THROTTLE_SECURE;
99*e582193eSAndroid Build Coastguard Worker     } else {
100*e582193eSAndroid Build Coastguard Worker         ClearFailureRecord(uid, user_id, false);
101*e582193eSAndroid Build Coastguard Worker     }
102*e582193eSAndroid Build Coastguard Worker 
103*e582193eSAndroid Build Coastguard Worker     salt_t salt;
104*e582193eSAndroid Build Coastguard Worker     GetRandom(&salt, sizeof(salt));
105*e582193eSAndroid Build Coastguard Worker 
106*e582193eSAndroid Build Coastguard Worker     SizedBuffer password_handle;
107*e582193eSAndroid Build Coastguard Worker     if (!CreatePasswordHandle(&password_handle,
108*e582193eSAndroid Build Coastguard Worker             salt, user_id, flags, HANDLE_VERSION, request.provided_password)) {
109*e582193eSAndroid Build Coastguard Worker         response->error = ERROR_INVALID;
110*e582193eSAndroid Build Coastguard Worker         return;
111*e582193eSAndroid Build Coastguard Worker     }
112*e582193eSAndroid Build Coastguard Worker 
113*e582193eSAndroid Build Coastguard Worker     response->SetEnrolledPasswordHandle(move(password_handle));
114*e582193eSAndroid Build Coastguard Worker }
115*e582193eSAndroid Build Coastguard Worker 
Verify(const VerifyRequest & request,VerifyResponse * response)116*e582193eSAndroid Build Coastguard Worker void GateKeeper::Verify(const VerifyRequest &request, VerifyResponse *response) {
117*e582193eSAndroid Build Coastguard Worker     if (response == nullptr) return;
118*e582193eSAndroid Build Coastguard Worker 
119*e582193eSAndroid Build Coastguard Worker     if (!request.provided_password || !request.password_handle) {
120*e582193eSAndroid Build Coastguard Worker         response->error = ERROR_INVALID;
121*e582193eSAndroid Build Coastguard Worker         return;
122*e582193eSAndroid Build Coastguard Worker     }
123*e582193eSAndroid Build Coastguard Worker 
124*e582193eSAndroid Build Coastguard Worker     const password_handle_t *password_handle = request.password_handle.Data<password_handle_t>();
125*e582193eSAndroid Build Coastguard Worker 
126*e582193eSAndroid Build Coastguard Worker     if (!password_handle || password_handle->version > HANDLE_VERSION) {
127*e582193eSAndroid Build Coastguard Worker         response->error = ERROR_INVALID;
128*e582193eSAndroid Build Coastguard Worker         return;
129*e582193eSAndroid Build Coastguard Worker     }
130*e582193eSAndroid Build Coastguard Worker 
131*e582193eSAndroid Build Coastguard Worker     secure_id_t user_id = password_handle->user_id;
132*e582193eSAndroid Build Coastguard Worker     secure_id_t authenticator_id = 0;
133*e582193eSAndroid Build Coastguard Worker     uint32_t uid = request.user_id;
134*e582193eSAndroid Build Coastguard Worker 
135*e582193eSAndroid Build Coastguard Worker     uint64_t timestamp = GetMillisecondsSinceBoot();
136*e582193eSAndroid Build Coastguard Worker 
137*e582193eSAndroid Build Coastguard Worker     uint32_t timeout = 0;
138*e582193eSAndroid Build Coastguard Worker     bool throttle = (password_handle->version >= HANDLE_VERSION_THROTTLE);
139*e582193eSAndroid Build Coastguard Worker     bool throttle_secure = password_handle->flags & HANDLE_FLAG_THROTTLE_SECURE;
140*e582193eSAndroid Build Coastguard Worker     if (throttle) {
141*e582193eSAndroid Build Coastguard Worker         failure_record_t record;
142*e582193eSAndroid Build Coastguard Worker         if (!GetFailureRecord(uid, user_id, &record, throttle_secure)) {
143*e582193eSAndroid Build Coastguard Worker             response->error = ERROR_UNKNOWN;
144*e582193eSAndroid Build Coastguard Worker             return;
145*e582193eSAndroid Build Coastguard Worker         }
146*e582193eSAndroid Build Coastguard Worker 
147*e582193eSAndroid Build Coastguard Worker         if (ThrottleRequest(uid, timestamp, &record, throttle_secure, response)) return;
148*e582193eSAndroid Build Coastguard Worker 
149*e582193eSAndroid Build Coastguard Worker         if (!IncrementFailureRecord(uid, user_id, timestamp, &record, throttle_secure)) {
150*e582193eSAndroid Build Coastguard Worker             response->error = ERROR_UNKNOWN;
151*e582193eSAndroid Build Coastguard Worker             return;
152*e582193eSAndroid Build Coastguard Worker         }
153*e582193eSAndroid Build Coastguard Worker 
154*e582193eSAndroid Build Coastguard Worker         timeout = ComputeRetryTimeout(&record);
155*e582193eSAndroid Build Coastguard Worker     } else {
156*e582193eSAndroid Build Coastguard Worker         response->request_reenroll = true;
157*e582193eSAndroid Build Coastguard Worker     }
158*e582193eSAndroid Build Coastguard Worker 
159*e582193eSAndroid Build Coastguard Worker     if (DoVerify(password_handle, request.provided_password)) {
160*e582193eSAndroid Build Coastguard Worker         // Signature matches
161*e582193eSAndroid Build Coastguard Worker         SizedBuffer auth_token;
162*e582193eSAndroid Build Coastguard Worker         response->error = MintAuthToken(&auth_token, timestamp,
163*e582193eSAndroid Build Coastguard Worker                 user_id, authenticator_id, request.challenge);
164*e582193eSAndroid Build Coastguard Worker 
165*e582193eSAndroid Build Coastguard Worker         if (response->error != ERROR_NONE) return;
166*e582193eSAndroid Build Coastguard Worker 
167*e582193eSAndroid Build Coastguard Worker         response->SetVerificationToken(move(auth_token));
168*e582193eSAndroid Build Coastguard Worker         if (throttle) ClearFailureRecord(uid, user_id, throttle_secure);
169*e582193eSAndroid Build Coastguard Worker     } else {
170*e582193eSAndroid Build Coastguard Worker         // compute the new timeout given the incremented record
171*e582193eSAndroid Build Coastguard Worker         if (throttle && timeout > 0) {
172*e582193eSAndroid Build Coastguard Worker             response->SetRetryTimeout(timeout);
173*e582193eSAndroid Build Coastguard Worker         } else {
174*e582193eSAndroid Build Coastguard Worker             response->error = ERROR_INVALID;
175*e582193eSAndroid Build Coastguard Worker         }
176*e582193eSAndroid Build Coastguard Worker     }
177*e582193eSAndroid Build Coastguard Worker }
178*e582193eSAndroid Build Coastguard Worker 
DeleteUser(const DeleteUserRequest & request,DeleteUserResponse * response)179*e582193eSAndroid Build Coastguard Worker void GateKeeper::DeleteUser(const DeleteUserRequest &request, DeleteUserResponse *response) {
180*e582193eSAndroid Build Coastguard Worker     if (response == nullptr) return;
181*e582193eSAndroid Build Coastguard Worker 
182*e582193eSAndroid Build Coastguard Worker     uint32_t uid = request.user_id;
183*e582193eSAndroid Build Coastguard Worker     response->error = RemoveUser(uid);
184*e582193eSAndroid Build Coastguard Worker }
185*e582193eSAndroid Build Coastguard Worker 
DeleteAllUsers(const DeleteAllUsersRequest &,DeleteAllUsersResponse * response)186*e582193eSAndroid Build Coastguard Worker void GateKeeper::DeleteAllUsers(const DeleteAllUsersRequest &/*request*/,
187*e582193eSAndroid Build Coastguard Worker         DeleteAllUsersResponse *response) {
188*e582193eSAndroid Build Coastguard Worker     if (response == nullptr) return;
189*e582193eSAndroid Build Coastguard Worker 
190*e582193eSAndroid Build Coastguard Worker     response->error = RemoveAllUsers();
191*e582193eSAndroid Build Coastguard Worker }
192*e582193eSAndroid Build Coastguard Worker 
CreatePasswordHandle(SizedBuffer * password_handle_buffer,salt_t salt,secure_id_t user_id,uint64_t flags,uint8_t handle_version,const SizedBuffer & password)193*e582193eSAndroid Build Coastguard Worker bool GateKeeper::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt,
194*e582193eSAndroid Build Coastguard Worker         secure_id_t user_id, uint64_t flags, uint8_t handle_version, const SizedBuffer & password) {
195*e582193eSAndroid Build Coastguard Worker     if (password_handle_buffer == nullptr) return false;
196*e582193eSAndroid Build Coastguard Worker 
197*e582193eSAndroid Build Coastguard Worker     password_handle_t password_handle;
198*e582193eSAndroid Build Coastguard Worker 
199*e582193eSAndroid Build Coastguard Worker     password_handle.version = handle_version;
200*e582193eSAndroid Build Coastguard Worker     password_handle.salt = salt;
201*e582193eSAndroid Build Coastguard Worker     password_handle.user_id = user_id;
202*e582193eSAndroid Build Coastguard Worker     password_handle.flags = flags;
203*e582193eSAndroid Build Coastguard Worker     password_handle.hardware_backed = IsHardwareBacked();
204*e582193eSAndroid Build Coastguard Worker 
205*e582193eSAndroid Build Coastguard Worker     constexpr uint32_t metadata_length = sizeof(password_handle.version) +
206*e582193eSAndroid Build Coastguard Worker                                          sizeof(password_handle.user_id) +
207*e582193eSAndroid Build Coastguard Worker                                          sizeof(password_handle.flags);
208*e582193eSAndroid Build Coastguard Worker     static_assert(offsetof(password_handle_t, salt) == metadata_length,
209*e582193eSAndroid Build Coastguard Worker             "password_handle_t does not appear to be packed");
210*e582193eSAndroid Build Coastguard Worker 
211*e582193eSAndroid Build Coastguard Worker     const size_t to_sign_size = password.size() + metadata_length;
212*e582193eSAndroid Build Coastguard Worker 
213*e582193eSAndroid Build Coastguard Worker     UniquePtr<uint8_t[]> to_sign(new(std::nothrow) uint8_t[to_sign_size]);
214*e582193eSAndroid Build Coastguard Worker     if (!to_sign) return false;
215*e582193eSAndroid Build Coastguard Worker 
216*e582193eSAndroid Build Coastguard Worker     memcpy(to_sign.get(), &password_handle, metadata_length);
217*e582193eSAndroid Build Coastguard Worker     memcpy(to_sign.get() + metadata_length, password.Data<uint8_t>(), password.size());
218*e582193eSAndroid Build Coastguard Worker 
219*e582193eSAndroid Build Coastguard Worker     const uint8_t *password_key = nullptr;
220*e582193eSAndroid Build Coastguard Worker     uint32_t password_key_length = 0;
221*e582193eSAndroid Build Coastguard Worker     GetPasswordKey(&password_key, &password_key_length);
222*e582193eSAndroid Build Coastguard Worker 
223*e582193eSAndroid Build Coastguard Worker     if (!password_key || password_key_length == 0) {
224*e582193eSAndroid Build Coastguard Worker         return false;
225*e582193eSAndroid Build Coastguard Worker     }
226*e582193eSAndroid Build Coastguard Worker 
227*e582193eSAndroid Build Coastguard Worker     ComputePasswordSignature(password_handle.signature, sizeof(password_handle.signature),
228*e582193eSAndroid Build Coastguard Worker             password_key, password_key_length, to_sign.get(), to_sign_size, salt);
229*e582193eSAndroid Build Coastguard Worker 
230*e582193eSAndroid Build Coastguard Worker     uint8_t *ph_buffer = new(std::nothrow) uint8_t[sizeof(password_handle_t)];
231*e582193eSAndroid Build Coastguard Worker     if (ph_buffer == nullptr) return false;
232*e582193eSAndroid Build Coastguard Worker 
233*e582193eSAndroid Build Coastguard Worker     *password_handle_buffer = { ph_buffer, sizeof(password_handle_t) };
234*e582193eSAndroid Build Coastguard Worker     memcpy(ph_buffer, &password_handle, sizeof(password_handle_t));
235*e582193eSAndroid Build Coastguard Worker 
236*e582193eSAndroid Build Coastguard Worker     return true;
237*e582193eSAndroid Build Coastguard Worker }
238*e582193eSAndroid Build Coastguard Worker 
DoVerify(const password_handle_t * expected_handle,const SizedBuffer & password)239*e582193eSAndroid Build Coastguard Worker bool GateKeeper::DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
240*e582193eSAndroid Build Coastguard Worker     if (!password) return false;
241*e582193eSAndroid Build Coastguard Worker 
242*e582193eSAndroid Build Coastguard Worker     SizedBuffer provided_handle;
243*e582193eSAndroid Build Coastguard Worker     if (!CreatePasswordHandle(&provided_handle, expected_handle->salt, expected_handle->user_id,
244*e582193eSAndroid Build Coastguard Worker             expected_handle->flags, expected_handle->version, password)) {
245*e582193eSAndroid Build Coastguard Worker         return false;
246*e582193eSAndroid Build Coastguard Worker     }
247*e582193eSAndroid Build Coastguard Worker 
248*e582193eSAndroid Build Coastguard Worker     const password_handle_t *generated_handle = provided_handle.Data<password_handle_t>();
249*e582193eSAndroid Build Coastguard Worker     return memcmp_s(generated_handle->signature, expected_handle->signature,
250*e582193eSAndroid Build Coastguard Worker             sizeof(expected_handle->signature)) == 0;
251*e582193eSAndroid Build Coastguard Worker }
252*e582193eSAndroid Build Coastguard Worker 
MintAuthToken(SizedBuffer * auth_token,uint64_t timestamp,secure_id_t user_id,secure_id_t authenticator_id,uint64_t challenge)253*e582193eSAndroid Build Coastguard Worker gatekeeper_error_t GateKeeper::MintAuthToken(SizedBuffer *auth_token,
254*e582193eSAndroid Build Coastguard Worker         uint64_t timestamp, secure_id_t user_id, secure_id_t authenticator_id,
255*e582193eSAndroid Build Coastguard Worker         uint64_t challenge) {
256*e582193eSAndroid Build Coastguard Worker     if (auth_token == nullptr) return ERROR_INVALID;
257*e582193eSAndroid Build Coastguard Worker 
258*e582193eSAndroid Build Coastguard Worker     hw_auth_token_t token;
259*e582193eSAndroid Build Coastguard Worker 
260*e582193eSAndroid Build Coastguard Worker     token.version = HW_AUTH_TOKEN_VERSION;
261*e582193eSAndroid Build Coastguard Worker     token.challenge = challenge;
262*e582193eSAndroid Build Coastguard Worker     token.user_id = user_id;
263*e582193eSAndroid Build Coastguard Worker     token.authenticator_id = authenticator_id;
264*e582193eSAndroid Build Coastguard Worker     token.authenticator_type = htobe32(HW_AUTH_PASSWORD);
265*e582193eSAndroid Build Coastguard Worker     token.timestamp = htobe64(timestamp);
266*e582193eSAndroid Build Coastguard Worker 
267*e582193eSAndroid Build Coastguard Worker     constexpr uint32_t hashable_length = sizeof(token.version) +
268*e582193eSAndroid Build Coastguard Worker                                          sizeof(token.challenge) +
269*e582193eSAndroid Build Coastguard Worker                                          sizeof(token.user_id) +
270*e582193eSAndroid Build Coastguard Worker                                          sizeof(token.authenticator_id) +
271*e582193eSAndroid Build Coastguard Worker                                          sizeof(token.authenticator_type) +
272*e582193eSAndroid Build Coastguard Worker                                          sizeof(token.timestamp);
273*e582193eSAndroid Build Coastguard Worker 
274*e582193eSAndroid Build Coastguard Worker     static_assert(offsetof(hw_auth_token_t, hmac) == hashable_length,
275*e582193eSAndroid Build Coastguard Worker             "hw_auth_token_t does not appear to be packed");
276*e582193eSAndroid Build Coastguard Worker 
277*e582193eSAndroid Build Coastguard Worker     const uint8_t *auth_token_key = nullptr;
278*e582193eSAndroid Build Coastguard Worker     uint32_t key_len = 0;
279*e582193eSAndroid Build Coastguard Worker     if (GetAuthTokenKey(&auth_token_key, &key_len)) {
280*e582193eSAndroid Build Coastguard Worker         ComputeSignature(token.hmac, sizeof(token.hmac), auth_token_key, key_len,
281*e582193eSAndroid Build Coastguard Worker                 reinterpret_cast<uint8_t *>(&token), hashable_length);
282*e582193eSAndroid Build Coastguard Worker     } else {
283*e582193eSAndroid Build Coastguard Worker         memset(token.hmac, 0, sizeof(token.hmac));
284*e582193eSAndroid Build Coastguard Worker     }
285*e582193eSAndroid Build Coastguard Worker 
286*e582193eSAndroid Build Coastguard Worker     uint8_t *token_buffer = new(std::nothrow) uint8_t[sizeof(hw_auth_token_t)];
287*e582193eSAndroid Build Coastguard Worker     if (token_buffer == nullptr) return ERROR_MEMORY_ALLOCATION_FAILED;
288*e582193eSAndroid Build Coastguard Worker 
289*e582193eSAndroid Build Coastguard Worker     *reinterpret_cast<hw_auth_token_t*>(token_buffer) = token;
290*e582193eSAndroid Build Coastguard Worker 
291*e582193eSAndroid Build Coastguard Worker     *auth_token = { token_buffer, sizeof(hw_auth_token_t) };
292*e582193eSAndroid Build Coastguard Worker     return ERROR_NONE;
293*e582193eSAndroid Build Coastguard Worker }
294*e582193eSAndroid Build Coastguard Worker 
295*e582193eSAndroid Build Coastguard Worker /*
296*e582193eSAndroid Build Coastguard Worker  * Calculates the timeout in milliseconds as a function of the failure
297*e582193eSAndroid Build Coastguard Worker  * counter 'x' as follows:
298*e582193eSAndroid Build Coastguard Worker  *
299*e582193eSAndroid Build Coastguard Worker  * [0, 4] -> 0
300*e582193eSAndroid Build Coastguard Worker  * 5 -> 30
301*e582193eSAndroid Build Coastguard Worker  * [6, 10] -> 0
302*e582193eSAndroid Build Coastguard Worker  * [11, 29] -> 30
303*e582193eSAndroid Build Coastguard Worker  * [30, 139] -> 30 * (2^((x - 30)/10))
304*e582193eSAndroid Build Coastguard Worker  * [140, inf) -> 1 day
305*e582193eSAndroid Build Coastguard Worker  *
306*e582193eSAndroid Build Coastguard Worker  */
ComputeRetryTimeout(const failure_record_t * record)307*e582193eSAndroid Build Coastguard Worker uint32_t GateKeeper::ComputeRetryTimeout(const failure_record_t *record) {
308*e582193eSAndroid Build Coastguard Worker     static const int failure_timeout_ms = 30000;
309*e582193eSAndroid Build Coastguard Worker     if (record->failure_counter == 0) return 0;
310*e582193eSAndroid Build Coastguard Worker 
311*e582193eSAndroid Build Coastguard Worker     if (record->failure_counter > 0 && record->failure_counter <= 10) {
312*e582193eSAndroid Build Coastguard Worker         if (record->failure_counter % 5 == 0) {
313*e582193eSAndroid Build Coastguard Worker             return failure_timeout_ms;
314*e582193eSAndroid Build Coastguard Worker         }  else {
315*e582193eSAndroid Build Coastguard Worker             return 0;
316*e582193eSAndroid Build Coastguard Worker         }
317*e582193eSAndroid Build Coastguard Worker     } else if (record->failure_counter < 30) {
318*e582193eSAndroid Build Coastguard Worker         return failure_timeout_ms;
319*e582193eSAndroid Build Coastguard Worker     } else if (record->failure_counter < 140) {
320*e582193eSAndroid Build Coastguard Worker         return failure_timeout_ms << ((record->failure_counter - 30) / 10);
321*e582193eSAndroid Build Coastguard Worker     }
322*e582193eSAndroid Build Coastguard Worker 
323*e582193eSAndroid Build Coastguard Worker     return DAY_IN_MS;
324*e582193eSAndroid Build Coastguard Worker }
325*e582193eSAndroid Build Coastguard Worker 
ThrottleRequest(uint32_t uid,uint64_t timestamp,failure_record_t * record,bool secure,GateKeeperMessage * response)326*e582193eSAndroid Build Coastguard Worker bool GateKeeper::ThrottleRequest(uint32_t uid, uint64_t timestamp,
327*e582193eSAndroid Build Coastguard Worker         failure_record_t *record, bool secure, GateKeeperMessage *response) {
328*e582193eSAndroid Build Coastguard Worker 
329*e582193eSAndroid Build Coastguard Worker     uint64_t last_checked = record->last_checked_timestamp;
330*e582193eSAndroid Build Coastguard Worker     uint32_t timeout = ComputeRetryTimeout(record);
331*e582193eSAndroid Build Coastguard Worker 
332*e582193eSAndroid Build Coastguard Worker     if (timeout > 0) {
333*e582193eSAndroid Build Coastguard Worker         // we have a pending timeout
334*e582193eSAndroid Build Coastguard Worker         if (timestamp < last_checked + timeout && timestamp > last_checked) {
335*e582193eSAndroid Build Coastguard Worker             // attempt before timeout expired, return remaining time
336*e582193eSAndroid Build Coastguard Worker             response->SetRetryTimeout(timeout - (timestamp - last_checked));
337*e582193eSAndroid Build Coastguard Worker             return true;
338*e582193eSAndroid Build Coastguard Worker         } else if (timestamp <= last_checked) {
339*e582193eSAndroid Build Coastguard Worker             // device was rebooted or timer reset, don't count as new failure but
340*e582193eSAndroid Build Coastguard Worker             // reset timeout
341*e582193eSAndroid Build Coastguard Worker             record->last_checked_timestamp = timestamp;
342*e582193eSAndroid Build Coastguard Worker             if (!WriteFailureRecord(uid, record, secure)) {
343*e582193eSAndroid Build Coastguard Worker                 response->error = ERROR_UNKNOWN;
344*e582193eSAndroid Build Coastguard Worker                 return true;
345*e582193eSAndroid Build Coastguard Worker             }
346*e582193eSAndroid Build Coastguard Worker             response->SetRetryTimeout(timeout);
347*e582193eSAndroid Build Coastguard Worker             return true;
348*e582193eSAndroid Build Coastguard Worker         }
349*e582193eSAndroid Build Coastguard Worker     }
350*e582193eSAndroid Build Coastguard Worker 
351*e582193eSAndroid Build Coastguard Worker     return false;
352*e582193eSAndroid Build Coastguard Worker }
353*e582193eSAndroid Build Coastguard Worker 
IncrementFailureRecord(uint32_t uid,secure_id_t user_id,uint64_t timestamp,failure_record_t * record,bool secure)354*e582193eSAndroid Build Coastguard Worker bool GateKeeper::IncrementFailureRecord(uint32_t uid, secure_id_t user_id, uint64_t timestamp,
355*e582193eSAndroid Build Coastguard Worker             failure_record_t *record, bool secure) {
356*e582193eSAndroid Build Coastguard Worker     record->secure_user_id = user_id;
357*e582193eSAndroid Build Coastguard Worker     record->failure_counter++;
358*e582193eSAndroid Build Coastguard Worker     record->last_checked_timestamp = timestamp;
359*e582193eSAndroid Build Coastguard Worker 
360*e582193eSAndroid Build Coastguard Worker     return WriteFailureRecord(uid, record, secure);
361*e582193eSAndroid Build Coastguard Worker }
362*e582193eSAndroid Build Coastguard Worker } // namespace gatekeeper
363*e582193eSAndroid Build Coastguard Worker 
364