blob: a63b221f3b586f744e621be45ef94d5dd2c419b1 [file] [log] [blame]
Andres Moralesac808182015-02-26 14:11:04 -08001/*
2 * Copyright 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Andres Moralesb2abaa82015-03-03 09:09:18 -080016#include <time.h>
17#include <iostream>
18#include <iomanip>
19#include <UniquePtr.h>
Andres Moralesac808182015-02-26 14:11:04 -080020
Andres Morales7d0f0402015-03-19 18:02:55 -070021#include <gatekeeper/gatekeeper.h>
Andres Moralesac808182015-02-26 14:11:04 -080022
Andres Morales7d0f0402015-03-19 18:02:55 -070023namespace gatekeeper {
Andres Moralesac808182015-02-26 14:11:04 -080024
Andres Moralesedd3e3d2015-03-12 13:30:15 -070025/**
26 * Internal only structure for easy serialization
27 * and deserialization of password handles.
28 */
29static const uint8_t HANDLE_VERSION = 0;
30struct __attribute__ ((__packed__)) password_handle_t {
31 // fields included in signature
32 uint8_t version = HANDLE_VERSION;
33 secure_id_t user_id;
34 secure_id_t authenticator_id;
35
36 // fields not included in signature
37 salt_t salt;
38 uint8_t signature[32];
39};
Andres Moralesac808182015-02-26 14:11:04 -080040
Andres Morales7d0f0402015-03-19 18:02:55 -070041void GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) {
Andres Moralesac808182015-02-26 14:11:04 -080042 if (response == NULL) return;
43
Andres Moralesb2abaa82015-03-03 09:09:18 -080044 if (!request.provided_password.buffer.get()) {
Andres Morales7d0f0402015-03-19 18:02:55 -070045 response->error = ERROR_INVALID;
Andres Moralesac808182015-02-26 14:11:04 -080046 return;
47 }
Andres Moralesb2abaa82015-03-03 09:09:18 -080048
Andres Moralesedd3e3d2015-03-12 13:30:15 -070049 secure_id_t user_id = 0;
50 uint8_t *current_password = NULL;
51 size_t current_password_size = 0;
Andres Moralesb2abaa82015-03-03 09:09:18 -080052
Andres Moralesedd3e3d2015-03-12 13:30:15 -070053 if (request.password_handle.buffer.get() == NULL) {
54 // Password handle does not match what is stored, generate new SecureID
55 GetRandom(&user_id, sizeof(secure_id_t));
56 } else {
57 if (!ValidatePasswordFile(request.user_id, request.password_handle)) {
Andres Morales7d0f0402015-03-19 18:02:55 -070058 response->error = ERROR_INVALID;
Andres Moralesedd3e3d2015-03-12 13:30:15 -070059 return;
60 } else {
61 // Password handle matches password file
62 password_handle_t *pw_handle =
63 reinterpret_cast<password_handle_t *>(request.password_handle.buffer.get());
64 if (!DoVerify(pw_handle, request.enrolled_password)) {
65 // incorrect old password
Andres Morales7d0f0402015-03-19 18:02:55 -070066 response->error = ERROR_INVALID;
Andres Moralesedd3e3d2015-03-12 13:30:15 -070067 return;
68 }
Andres Moralesb2abaa82015-03-03 09:09:18 -080069
Andres Moralesedd3e3d2015-03-12 13:30:15 -070070 user_id = pw_handle->user_id;
71 }
72 }
73
74 salt_t salt;
75 GetRandom(&salt, sizeof(salt));
76
77 secure_id_t authenticator_id;
78 GetRandom(&authenticator_id, sizeof(authenticator_id));
79
80
81 SizedBuffer password_handle;
82 if(!CreatePasswordHandle(&password_handle,
83 salt, user_id, authenticator_id, request.provided_password.buffer.get(),
84 request.provided_password.length)) {
Andres Morales7d0f0402015-03-19 18:02:55 -070085 response->error = ERROR_INVALID;
Andres Moralesedd3e3d2015-03-12 13:30:15 -070086 return;
87 }
88
89
90 WritePasswordFile(request.user_id, password_handle);
91
92 response->SetEnrolledPasswordHandle(&password_handle);
Andres Moralesac808182015-02-26 14:11:04 -080093}
94
Andres Morales7d0f0402015-03-19 18:02:55 -070095void GateKeeper::Verify(const VerifyRequest &request, VerifyResponse *response) {
Andres Moralesac808182015-02-26 14:11:04 -080096 if (response == NULL) return;
97
Andres Moralesb2abaa82015-03-03 09:09:18 -080098 if (!request.provided_password.buffer.get() || !request.password_handle.buffer.get()) {
Andres Morales7d0f0402015-03-19 18:02:55 -070099 response->error = ERROR_INVALID;
Andres Moralesac808182015-02-26 14:11:04 -0800100 return;
101 }
102
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700103 secure_id_t user_id, authenticator_id;
104 password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
105 request.password_handle.buffer.get());
Andres Moralesb2abaa82015-03-03 09:09:18 -0800106
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700107 // Sanity check
108 if (password_handle->version != HANDLE_VERSION) {
Andres Morales7d0f0402015-03-19 18:02:55 -0700109 response->error = ERROR_INVALID;
Andres Moralesb2abaa82015-03-03 09:09:18 -0800110 return;
111 }
112
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700113 if (!ValidatePasswordFile(request.user_id, request.password_handle)) {
114 // we don't allow access to keys if we can't validate the file.
115 // we must allow this case to support authentication before we decrypt
116 // /data, however.
117 user_id = 0;
118 authenticator_id = 0;
119 } else {
120 user_id = password_handle->user_id;
121 authenticator_id = password_handle->authenticator_id;
122 }
Andres Moralesb2abaa82015-03-03 09:09:18 -0800123
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700124 struct timespec time;
125 uint64_t timestamp;
126 clock_gettime(CLOCK_MONOTONIC_RAW, &time);
127 timestamp = static_cast<uint32_t>(time.tv_sec);
128
129 if (DoVerify(password_handle, request.provided_password)) {
Andres Moralesac808182015-02-26 14:11:04 -0800130 // Signature matches
131 SizedBuffer auth_token;
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700132 MintAuthToken(&auth_token.buffer, &auth_token.length, timestamp,
133 user_id, authenticator_id);
Andres Moralesac808182015-02-26 14:11:04 -0800134 response->SetVerificationToken(&auth_token);
135 } else {
Andres Morales7d0f0402015-03-19 18:02:55 -0700136 response->error = ERROR_INVALID;
Andres Moralesac808182015-02-26 14:11:04 -0800137 }
138}
139
Andres Morales7d0f0402015-03-19 18:02:55 -0700140bool GateKeeper::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt,
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700141 secure_id_t user_id, secure_id_t authenticator_id, const uint8_t *password,
142 size_t password_length) {
143 password_handle_buffer->buffer.reset(new uint8_t[sizeof(password_handle_t)]);
144 password_handle_buffer->length = sizeof(password_handle_t);
145
146 password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
147 password_handle_buffer->buffer.get());
148 password_handle->version = HANDLE_VERSION;
149 password_handle->salt = salt;
150 password_handle->user_id = user_id;
151 password_handle->authenticator_id = authenticator_id;
152
153 size_t metadata_length = sizeof(user_id) /* user id */
154 + sizeof(authenticator_id) /* auth id */ + sizeof(uint8_t) /* version */;
155 uint8_t to_sign[password_length + metadata_length];
156 memcpy(to_sign, &password_handle->version, metadata_length);
157 memcpy(to_sign + metadata_length, password, password_length);
158
159 UniquePtr<uint8_t> password_key;
160 size_t password_key_length = 0;
161 GetPasswordKey(&password_key, &password_key_length);
162
163 if (!password_key.get() || password_key_length == 0) {
164 return false;
165 }
166
167 ComputePasswordSignature(password_handle->signature, sizeof(password_handle->signature),
168 password_key.get(), password_key_length, to_sign, sizeof(to_sign), salt);
169 return true;
170}
171
Andres Morales7d0f0402015-03-19 18:02:55 -0700172bool GateKeeper::DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700173 if (!password.buffer.get()) return false;
174
175 SizedBuffer provided_handle;
176 if (!CreatePasswordHandle(&provided_handle, expected_handle->salt, expected_handle->user_id,
177 expected_handle->authenticator_id, password.buffer.get(), password.length)) {
178 return false;
179 }
180
181 return memcmp_s(provided_handle.buffer.get(), expected_handle, sizeof(*expected_handle)) == 0;
182}
183
Andres Morales7d0f0402015-03-19 18:02:55 -0700184bool GateKeeper::ValidatePasswordFile(uint32_t uid, const SizedBuffer &provided_handle) {
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700185 SizedBuffer stored_handle;
186 ReadPasswordFile(uid, &stored_handle);
187
188 if (!stored_handle.buffer.get() || stored_handle.length == 0) return false;
189
190 // do we also verify the signature here?
191 return stored_handle.length == provided_handle.length &&
192 memcmp_s(stored_handle.buffer.get(), provided_handle.buffer.get(), stored_handle.length)
193 == 0;
194}
195
Andres Morales7d0f0402015-03-19 18:02:55 -0700196void GateKeeper::MintAuthToken(UniquePtr<uint8_t> *auth_token, size_t *length,
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700197 uint32_t timestamp, secure_id_t user_id, secure_id_t authenticator_id) {
Andres Moralesb2abaa82015-03-03 09:09:18 -0800198 if (auth_token == NULL) return;
199
200 AuthToken *token = new AuthToken;
Andres Moralesac808182015-02-26 14:11:04 -0800201 SizedBuffer serialized_auth_token;
202
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700203 token->root_secure_user_id = user_id;
204 token->auxiliary_secure_user_id = authenticator_id;
205 token->timestamp = timestamp;
Andres Moralesac808182015-02-26 14:11:04 -0800206
Andres Moralesb2abaa82015-03-03 09:09:18 -0800207 UniquePtr<uint8_t> auth_token_key;
208 size_t key_len;
209 GetAuthTokenKey(&auth_token_key, &key_len);
210
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700211 size_t hash_len = (size_t)((uint8_t *)&token->hmac - (uint8_t *)token);
212 ComputeSignature(token->hmac, sizeof(token->hmac), auth_token_key.get(), key_len,
213 reinterpret_cast<uint8_t *>(token), hash_len);
Andres Moralesac808182015-02-26 14:11:04 -0800214
Andres Moralesac808182015-02-26 14:11:04 -0800215 if (length != NULL) *length = sizeof(AuthToken);
Andres Moralesb2abaa82015-03-03 09:09:18 -0800216 auth_token->reset(reinterpret_cast<uint8_t *>(token));
Andres Moralesac808182015-02-26 14:11:04 -0800217}
Andres Moralesb2abaa82015-03-03 09:09:18 -0800218
Andres Moralesac808182015-02-26 14:11:04 -0800219}