1ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales/*
2ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * Copyright 2015 The Android Open Source Project
3ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales *
4ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * Licensed under the Apache License, Version 2.0 (the "License");
5ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * you may not use this file except in compliance with the License.
6ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * You may obtain a copy of the License at
7ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales *
8ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales *      http://www.apache.org/licenses/LICENSE-2.0
9ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales *
10ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * Unless required by applicable law or agreed to in writing, software
11ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * distributed under the License is distributed on an "AS IS" BASIS,
12ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * See the License for the specific language governing permissions and
14ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales * limitations under the License.
15ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales */
16002c8667ef19be4b80ef7079a3a5cfb4ca85038cJiyong Park#include <gatekeeper/UniquePtr.h>
177d0f0406314df47b7502c3cd72dcefb83ead7132Andres Morales#include <gatekeeper/gatekeeper.h>
18ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
19ec9fd1d44227dc0e8538153214eae9e7cedb66abAndres Morales#include <endian.h>
20ec9fd1d44227dc0e8538153214eae9e7cedb66abAndres Morales
21f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales#define DAY_IN_MS (1000 * 60 * 60 * 24)
22f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales
237d0f0406314df47b7502c3cd72dcefb83ead7132Andres Moralesnamespace gatekeeper {
24ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
257d0f0406314df47b7502c3cd72dcefb83ead7132Andres Moralesvoid GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) {
26ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales    if (response == NULL) return;
27ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
28b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales    if (!request.provided_password.buffer.get()) {
297d0f0406314df47b7502c3cd72dcefb83ead7132Andres Morales        response->error = ERROR_INVALID;
30ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales        return;
31ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales    }
32b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales
33aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    secure_id_t user_id = 0;// todo: rename to policy
34aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    uint32_t uid = request.user_id;
35b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales
36edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    if (request.password_handle.buffer.get() == NULL) {
37edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales        // Password handle does not match what is stored, generate new SecureID
38edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales        GetRandom(&user_id, sizeof(secure_id_t));
39edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    } else {
40426fcfb152001e3ae8b43333444e013ee7e48b42Andres Morales        password_handle_t *pw_handle =
41426fcfb152001e3ae8b43333444e013ee7e48b42Andres Morales            reinterpret_cast<password_handle_t *>(request.password_handle.buffer.get());
42aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
4348a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        if (pw_handle->version > HANDLE_VERSION) {
44426fcfb152001e3ae8b43333444e013ee7e48b42Andres Morales            response->error = ERROR_INVALID;
45426fcfb152001e3ae8b43333444e013ee7e48b42Andres Morales            return;
46edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales        }
47426fcfb152001e3ae8b43333444e013ee7e48b42Andres Morales
4848a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        user_id = pw_handle->user_id;
4948a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales
5048a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        uint64_t timestamp = GetMillisecondsSinceBoot();
5148a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales
52aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        uint32_t timeout = 0;
5348a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        bool throttle = (pw_handle->version >= HANDLE_VERSION_THROTTLE);
54aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        if (throttle) {
5548a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            bool throttle_secure = pw_handle->flags & HANDLE_FLAG_THROTTLE_SECURE;
56aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            failure_record_t record;
5748a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            if (!GetFailureRecord(uid, user_id, &record, throttle_secure)) {
58aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                response->error = ERROR_UNKNOWN;
59aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                return;
60aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            }
61aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
6248a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            if (ThrottleRequest(uid, timestamp, &record, throttle_secure, response)) return;
63aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
6448a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            if (!IncrementFailureRecord(uid, user_id, timestamp, &record, throttle_secure)) {
65aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                response->error = ERROR_UNKNOWN;
66aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                return;
67aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            }
68aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
69aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            timeout = ComputeRetryTimeout(&record);
70aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        }
71aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
72aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        if (!DoVerify(pw_handle, request.enrolled_password)) {
73aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            // incorrect old password
74aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            if (throttle && timeout > 0) {
75aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                response->SetRetryTimeout(timeout);
76aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            } else {
77aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                response->error = ERROR_INVALID;
78aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            }
79aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            return;
80aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        }
81edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    }
82edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
8348a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    uint64_t flags = 0;
8448a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    if (ClearFailureRecord(uid, user_id, true)) {
8548a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        flags |= HANDLE_FLAG_THROTTLE_SECURE;
8648a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    } else {
8748a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        ClearFailureRecord(uid, user_id, false);
8848a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    }
89aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
90edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    salt_t salt;
91edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    GetRandom(&salt, sizeof(salt));
92edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
93edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    SizedBuffer password_handle;
94aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    if (!CreatePasswordHandle(&password_handle,
9548a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            salt, user_id, flags, HANDLE_VERSION, request.provided_password.buffer.get(),
96edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales            request.provided_password.length)) {
977d0f0406314df47b7502c3cd72dcefb83ead7132Andres Morales        response->error = ERROR_INVALID;
98edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales        return;
99edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    }
100edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
101edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    response->SetEnrolledPasswordHandle(&password_handle);
102ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales}
103ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
1047d0f0406314df47b7502c3cd72dcefb83ead7132Andres Moralesvoid GateKeeper::Verify(const VerifyRequest &request, VerifyResponse *response) {
105ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales    if (response == NULL) return;
106ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
107b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales    if (!request.provided_password.buffer.get() || !request.password_handle.buffer.get()) {
1087d0f0406314df47b7502c3cd72dcefb83ead7132Andres Morales        response->error = ERROR_INVALID;
109b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales        return;
110b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales    }
111ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
112edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
113edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales            request.password_handle.buffer.get());
114ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
11548a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    if (password_handle->version > HANDLE_VERSION) {
1167d0f0406314df47b7502c3cd72dcefb83ead7132Andres Morales        response->error = ERROR_INVALID;
117ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales        return;
118ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales    }
119ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
120426fcfb152001e3ae8b43333444e013ee7e48b42Andres Morales    secure_id_t user_id = password_handle->user_id;
12148a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    secure_id_t authenticator_id = 0;
122aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    uint32_t uid = request.user_id;
123edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
124ec9fd1d44227dc0e8538153214eae9e7cedb66abAndres Morales    uint64_t timestamp = GetMillisecondsSinceBoot();
125b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales
126aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    uint32_t timeout = 0;
12748a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    bool throttle = (password_handle->version >= HANDLE_VERSION_THROTTLE);
12848a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    bool throttle_secure = password_handle->flags & HANDLE_FLAG_THROTTLE_SECURE;
129aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    if (throttle) {
130aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        failure_record_t record;
13148a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        if (!GetFailureRecord(uid, user_id, &record, throttle_secure)) {
132aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            response->error = ERROR_UNKNOWN;
133aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            return;
134aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        }
135aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
13648a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        if (ThrottleRequest(uid, timestamp, &record, throttle_secure, response)) return;
137aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
13848a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        if (!IncrementFailureRecord(uid, user_id, timestamp, &record, throttle_secure)) {
139aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            response->error = ERROR_UNKNOWN;
140aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            return;
141aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        }
142aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
143aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        timeout = ComputeRetryTimeout(&record);
144893fa7f7cc668ebe67c85851f49c1504d07b1f95Andres Morales    } else {
145893fa7f7cc668ebe67c85851f49c1504d07b1f95Andres Morales        response->request_reenroll = true;
146aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    }
147aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
148edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    if (DoVerify(password_handle, request.provided_password)) {
149ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales        // Signature matches
150f73a010f4f2c6f2b7888e0f6501d2a5044154337Shawn Willden        UniquePtr<uint8_t> auth_token_buffer;
15148a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        uint32_t auth_token_len;
15248a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        MintAuthToken(&auth_token_buffer, &auth_token_len, timestamp,
1536034309d9caa185c406def66bd4a7b71ea4b6409Andres Morales                user_id, authenticator_id, request.challenge);
15448a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales
15548a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        SizedBuffer auth_token(auth_token_len);
15648a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        memcpy(auth_token.buffer.get(), auth_token_buffer.get(), auth_token_len);
157ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales        response->SetVerificationToken(&auth_token);
15848a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        if (throttle) ClearFailureRecord(uid, user_id, throttle_secure);
159ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales    } else {
160aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        // compute the new timeout given the incremented record
161aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        if (throttle && timeout > 0) {
162aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            response->SetRetryTimeout(timeout);
163aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        } else {
164aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            response->error = ERROR_INVALID;
165aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        }
166ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales    }
167ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales}
168ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
1697d0f0406314df47b7502c3cd72dcefb83ead7132Andres Moralesbool GateKeeper::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt,
17048a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        secure_id_t user_id, uint64_t flags, uint8_t handle_version, const uint8_t *password,
17111ed52a7139a6c867850113aa19293c05581fcfcAndres Morales        uint32_t password_length) {
172edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    password_handle_buffer->buffer.reset(new uint8_t[sizeof(password_handle_t)]);
173edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    password_handle_buffer->length = sizeof(password_handle_t);
174edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
175edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
176edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales            password_handle_buffer->buffer.get());
177aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    password_handle->version = handle_version;
178edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    password_handle->salt = salt;
179edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    password_handle->user_id = user_id;
18048a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    password_handle->flags = flags;
181aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    password_handle->hardware_backed = IsHardwareBacked();
182edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
18348a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    uint32_t metadata_length = sizeof(user_id) + sizeof(flags) + sizeof(HANDLE_VERSION);
18484f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov    const size_t to_sign_size = password_length + metadata_length;
185f73a010f4f2c6f2b7888e0f6501d2a5044154337Shawn Willden    UniquePtr<uint8_t> to_sign(new uint8_t[to_sign_size]);
18684f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov
18784f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov    if (to_sign.get() == nullptr) {
18884f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov        return false;
18984f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov    }
19084f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov
19184f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov    memcpy(to_sign.get(), password_handle, metadata_length);
19284f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov    memcpy(to_sign.get() + metadata_length, password, password_length);
193edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
194f10e2890fd223d37c024ec2d1b3b89aec8d72d76Andres Morales    const uint8_t *password_key = NULL;
19511ed52a7139a6c867850113aa19293c05581fcfcAndres Morales    uint32_t password_key_length = 0;
196edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    GetPasswordKey(&password_key, &password_key_length);
197edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
198f10e2890fd223d37c024ec2d1b3b89aec8d72d76Andres Morales    if (!password_key || password_key_length == 0) {
199edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales        return false;
200edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    }
201edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
202edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    ComputePasswordSignature(password_handle->signature, sizeof(password_handle->signature),
20384f8f9fdc2c779ffd938e730d7e950c3958d799eAlexey Polyudov            password_key, password_key_length, to_sign.get(), to_sign_size, salt);
204edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    return true;
205edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales}
206edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
2077d0f0406314df47b7502c3cd72dcefb83ead7132Andres Moralesbool GateKeeper::DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
208edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    if (!password.buffer.get()) return false;
209edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
210edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    SizedBuffer provided_handle;
211edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    if (!CreatePasswordHandle(&provided_handle, expected_handle->salt, expected_handle->user_id,
21248a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            expected_handle->flags, expected_handle->version,
213aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            password.buffer.get(), password.length)) {
214edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales        return false;
215edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales    }
216edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
217aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    password_handle_t *generated_handle =
218aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            reinterpret_cast<password_handle_t *>(provided_handle.buffer.get());
219aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    return memcmp_s(generated_handle->signature, expected_handle->signature,
220aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            sizeof(expected_handle->signature)) == 0;
221edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales}
222edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3Andres Morales
223f73a010f4f2c6f2b7888e0f6501d2a5044154337Shawn Willdenvoid GateKeeper::MintAuthToken(UniquePtr<uint8_t> *auth_token, uint32_t *length,
224652f076f7fab74dc3159e3f9122ff17eb689dbc2Andres Morales        uint64_t timestamp, secure_id_t user_id, secure_id_t authenticator_id,
2256034309d9caa185c406def66bd4a7b71ea4b6409Andres Morales        uint64_t challenge) {
226b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales    if (auth_token == NULL) return;
227b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales
228fa104e1a3bb5e8fed1235b16e64aa88049ecb18aAndres Morales    hw_auth_token_t *token = new hw_auth_token_t;
229ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales    SizedBuffer serialized_auth_token;
230ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
231fa104e1a3bb5e8fed1235b16e64aa88049ecb18aAndres Morales    token->version = HW_AUTH_TOKEN_VERSION;
2326034309d9caa185c406def66bd4a7b71ea4b6409Andres Morales    token->challenge = challenge;
233fa104e1a3bb5e8fed1235b16e64aa88049ecb18aAndres Morales    token->user_id = user_id;
234fa104e1a3bb5e8fed1235b16e64aa88049ecb18aAndres Morales    token->authenticator_id = authenticator_id;
235fa104e1a3bb5e8fed1235b16e64aa88049ecb18aAndres Morales    token->authenticator_type = htonl(HW_AUTH_PASSWORD);
236ec9fd1d44227dc0e8538153214eae9e7cedb66abAndres Morales    token->timestamp = htobe64(timestamp);
237ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales
238f10e2890fd223d37c024ec2d1b3b89aec8d72d76Andres Morales    const uint8_t *auth_token_key = NULL;
23911ed52a7139a6c867850113aa19293c05581fcfcAndres Morales    uint32_t key_len = 0;
24058bb246744cf767c3d4aeb65a4fae1207fc4e86bAndres Morales    if (GetAuthTokenKey(&auth_token_key, &key_len)) {
24158bb246744cf767c3d4aeb65a4fae1207fc4e86bAndres Morales        uint32_t hash_len = (uint32_t)((uint8_t *)&token->hmac - (uint8_t *)token);
24258bb246744cf767c3d4aeb65a4fae1207fc4e86bAndres Morales        ComputeSignature(token->hmac, sizeof(token->hmac), auth_token_key, key_len,
24358bb246744cf767c3d4aeb65a4fae1207fc4e86bAndres Morales                reinterpret_cast<uint8_t *>(token), hash_len);
24448a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        delete[] auth_token_key;
24558bb246744cf767c3d4aeb65a4fae1207fc4e86bAndres Morales    } else {
24658bb246744cf767c3d4aeb65a4fae1207fc4e86bAndres Morales        memset(token->hmac, 0, sizeof(token->hmac));
24758bb246744cf767c3d4aeb65a4fae1207fc4e86bAndres Morales    }
248b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales
249fa104e1a3bb5e8fed1235b16e64aa88049ecb18aAndres Morales    if (length != NULL) *length = sizeof(*token);
250b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales    auth_token->reset(reinterpret_cast<uint8_t *>(token));
251b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales}
252b2abaa89b8090c7f14048d4404a3eb146f709a6aAndres Morales
253f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales/*
254f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * Calculates the timeout in milliseconds as a function of the failure
255f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * counter 'x' as follows:
256f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales *
257f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * [0. 5) -> 0
258f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * 5 -> 30
259f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * [6, 10) -> 0
260f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * [11, 30) -> 30
261f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * [30, 140) -> 30 * (2^((x - 30)/10))
262f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales * [140, inf) -> 1 day
263f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales *
264f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales */
265aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Moralesuint32_t GateKeeper::ComputeRetryTimeout(const failure_record_t *record) {
266b6a5cd7ccf0d4c9215ee1f235679d9218d24506bAndres Morales    static const int failure_timeout_ms = 30000;
267b6a5cd7ccf0d4c9215ee1f235679d9218d24506bAndres Morales    if (record->failure_counter == 0) return 0;
268b6a5cd7ccf0d4c9215ee1f235679d9218d24506bAndres Morales
269aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    if (record->failure_counter > 0 && record->failure_counter <= 10) {
270aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        if (record->failure_counter % 5 == 0) {
271b6a5cd7ccf0d4c9215ee1f235679d9218d24506bAndres Morales            return failure_timeout_ms;
272d14f472dcc6742481f687cb16f5a3115026e1c74Andres Morales        }  else {
273d14f472dcc6742481f687cb16f5a3115026e1c74Andres Morales            return 0;
274aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        }
275f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales    } else if (record->failure_counter < 30) {
276b6a5cd7ccf0d4c9215ee1f235679d9218d24506bAndres Morales        return failure_timeout_ms;
277f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales    } else if (record->failure_counter < 140) {
278f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales        return failure_timeout_ms << ((record->failure_counter - 30) / 10);
279aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    }
280f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales
281f436c80fdf98c62a81b97b940719e1224fc5f4f5Andres Morales    return DAY_IN_MS;
282aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales}
283aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
284a623e45c36f36f855c985f22db78077f828ce389Andres Moralesbool GateKeeper::ThrottleRequest(uint32_t uid, uint64_t timestamp,
28548a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales        failure_record_t *record, bool secure, GateKeeperMessage *response) {
286aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
287aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    uint64_t last_checked = record->last_checked_timestamp;
288aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    uint32_t timeout = ComputeRetryTimeout(record);
289aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
290aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    if (timeout > 0) {
291aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        // we have a pending timeout
292aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        if (timestamp < last_checked + timeout && timestamp > last_checked) {
293aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            // attempt before timeout expired, return remaining time
294aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            response->SetRetryTimeout(timeout - (timestamp - last_checked));
295aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            return true;
296aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        } else if (timestamp <= last_checked) {
297aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            // device was rebooted or timer reset, don't count as new failure but
298aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            // reset timeout
299aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            record->last_checked_timestamp = timestamp;
30048a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            if (!WriteFailureRecord(uid, record, secure)) {
301aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                response->error = ERROR_UNKNOWN;
302aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales                return true;
303aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            }
304aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            response->SetRetryTimeout(timeout);
305aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales            return true;
306aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales        }
307aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    }
308aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
309aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    return false;
310aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales}
311aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
312aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Moralesbool GateKeeper::IncrementFailureRecord(uint32_t uid, secure_id_t user_id, uint64_t timestamp,
31348a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales            failure_record_t *record, bool secure) {
314aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    record->secure_user_id = user_id;
315aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    record->failure_counter++;
316aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales    record->last_checked_timestamp = timestamp;
317aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
31848a4f837d1a696f6edfd48270047b36a3d21086bAndres Morales    return WriteFailureRecord(uid, record, secure);
319ac80818fd9e477d142dd8ed2f3902ba3757855c9Andres Morales}
320aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales} // namespace gatekeeper
321aedf605d883b4ebade9c810eb39cbf5125a58c7dAndres Morales
322