blob: 5b3ca5d616f50d07f53300e8d04057b9af846842 [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 <UniquePtr.h>
Andres Moralesac808182015-02-26 14:11:04 -080017
Andres Morales7d0f0402015-03-19 18:02:55 -070018#include <gatekeeper/gatekeeper.h>
Andres Moralesac808182015-02-26 14:11:04 -080019
Andres Morales7d0f0402015-03-19 18:02:55 -070020namespace gatekeeper {
Andres Moralesac808182015-02-26 14:11:04 -080021
Andres Moralesedd3e3d2015-03-12 13:30:15 -070022/**
23 * Internal only structure for easy serialization
24 * and deserialization of password handles.
25 */
26static const uint8_t HANDLE_VERSION = 0;
27struct __attribute__ ((__packed__)) password_handle_t {
28 // fields included in signature
29 uint8_t version = HANDLE_VERSION;
30 secure_id_t user_id;
31 secure_id_t authenticator_id;
32
33 // fields not included in signature
34 salt_t salt;
35 uint8_t signature[32];
36};
Andres Moralesac808182015-02-26 14:11:04 -080037
Andres Morales7d0f0402015-03-19 18:02:55 -070038void GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) {
Andres Moralesac808182015-02-26 14:11:04 -080039 if (response == NULL) return;
40
Andres Moralesb2abaa82015-03-03 09:09:18 -080041 if (!request.provided_password.buffer.get()) {
Andres Morales7d0f0402015-03-19 18:02:55 -070042 response->error = ERROR_INVALID;
Andres Moralesac808182015-02-26 14:11:04 -080043 return;
44 }
Andres Moralesb2abaa82015-03-03 09:09:18 -080045
Andres Moralesedd3e3d2015-03-12 13:30:15 -070046 secure_id_t user_id = 0;
47 uint8_t *current_password = NULL;
48 size_t current_password_size = 0;
Andres Moralesb2abaa82015-03-03 09:09:18 -080049
Andres Moralesedd3e3d2015-03-12 13:30:15 -070050 if (request.password_handle.buffer.get() == NULL) {
51 // Password handle does not match what is stored, generate new SecureID
52 GetRandom(&user_id, sizeof(secure_id_t));
53 } else {
54 if (!ValidatePasswordFile(request.user_id, request.password_handle)) {
Andres Morales7d0f0402015-03-19 18:02:55 -070055 response->error = ERROR_INVALID;
Andres Moralesedd3e3d2015-03-12 13:30:15 -070056 return;
57 } else {
58 // Password handle matches password file
59 password_handle_t *pw_handle =
60 reinterpret_cast<password_handle_t *>(request.password_handle.buffer.get());
61 if (!DoVerify(pw_handle, request.enrolled_password)) {
62 // incorrect old password
Andres Morales7d0f0402015-03-19 18:02:55 -070063 response->error = ERROR_INVALID;
Andres Moralesedd3e3d2015-03-12 13:30:15 -070064 return;
65 }
Andres Moralesb2abaa82015-03-03 09:09:18 -080066
Andres Moralesedd3e3d2015-03-12 13:30:15 -070067 user_id = pw_handle->user_id;
68 }
69 }
70
71 salt_t salt;
72 GetRandom(&salt, sizeof(salt));
73
74 secure_id_t authenticator_id;
75 GetRandom(&authenticator_id, sizeof(authenticator_id));
76
77
78 SizedBuffer password_handle;
79 if(!CreatePasswordHandle(&password_handle,
80 salt, user_id, authenticator_id, request.provided_password.buffer.get(),
81 request.provided_password.length)) {
Andres Morales7d0f0402015-03-19 18:02:55 -070082 response->error = ERROR_INVALID;
Andres Moralesedd3e3d2015-03-12 13:30:15 -070083 return;
84 }
85
86
87 WritePasswordFile(request.user_id, password_handle);
88
89 response->SetEnrolledPasswordHandle(&password_handle);
Andres Moralesac808182015-02-26 14:11:04 -080090}
91
Andres Morales7d0f0402015-03-19 18:02:55 -070092void GateKeeper::Verify(const VerifyRequest &request, VerifyResponse *response) {
Andres Moralesac808182015-02-26 14:11:04 -080093 if (response == NULL) return;
94
Andres Moralesb2abaa82015-03-03 09:09:18 -080095 if (!request.provided_password.buffer.get() || !request.password_handle.buffer.get()) {
Andres Morales7d0f0402015-03-19 18:02:55 -070096 response->error = ERROR_INVALID;
Andres Moralesac808182015-02-26 14:11:04 -080097 return;
98 }
99
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700100 secure_id_t user_id, authenticator_id;
101 password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
102 request.password_handle.buffer.get());
Andres Moralesb2abaa82015-03-03 09:09:18 -0800103
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700104 // Sanity check
105 if (password_handle->version != HANDLE_VERSION) {
Andres Morales7d0f0402015-03-19 18:02:55 -0700106 response->error = ERROR_INVALID;
Andres Moralesb2abaa82015-03-03 09:09:18 -0800107 return;
108 }
109
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700110 if (!ValidatePasswordFile(request.user_id, request.password_handle)) {
111 // we don't allow access to keys if we can't validate the file.
112 // we must allow this case to support authentication before we decrypt
113 // /data, however.
114 user_id = 0;
115 authenticator_id = 0;
116 } else {
117 user_id = password_handle->user_id;
118 authenticator_id = password_handle->authenticator_id;
119 }
Andres Moralesb2abaa82015-03-03 09:09:18 -0800120
Andres Morales11c2a512015-03-23 10:10:44 -0700121 uint64_t timestamp = GetNanosecondsSinceBoot();
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700122
123 if (DoVerify(password_handle, request.provided_password)) {
Andres Moralesac808182015-02-26 14:11:04 -0800124 // Signature matches
125 SizedBuffer auth_token;
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700126 MintAuthToken(&auth_token.buffer, &auth_token.length, timestamp,
127 user_id, authenticator_id);
Andres Moralesac808182015-02-26 14:11:04 -0800128 response->SetVerificationToken(&auth_token);
129 } else {
Andres Morales7d0f0402015-03-19 18:02:55 -0700130 response->error = ERROR_INVALID;
Andres Moralesac808182015-02-26 14:11:04 -0800131 }
132}
133
Andres Morales7d0f0402015-03-19 18:02:55 -0700134bool GateKeeper::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt,
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700135 secure_id_t user_id, secure_id_t authenticator_id, const uint8_t *password,
136 size_t password_length) {
137 password_handle_buffer->buffer.reset(new uint8_t[sizeof(password_handle_t)]);
138 password_handle_buffer->length = sizeof(password_handle_t);
139
140 password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
141 password_handle_buffer->buffer.get());
142 password_handle->version = HANDLE_VERSION;
143 password_handle->salt = salt;
144 password_handle->user_id = user_id;
145 password_handle->authenticator_id = authenticator_id;
146
147 size_t metadata_length = sizeof(user_id) /* user id */
148 + sizeof(authenticator_id) /* auth id */ + sizeof(uint8_t) /* version */;
149 uint8_t to_sign[password_length + metadata_length];
150 memcpy(to_sign, &password_handle->version, metadata_length);
151 memcpy(to_sign + metadata_length, password, password_length);
152
153 UniquePtr<uint8_t> password_key;
154 size_t password_key_length = 0;
155 GetPasswordKey(&password_key, &password_key_length);
156
157 if (!password_key.get() || password_key_length == 0) {
158 return false;
159 }
160
161 ComputePasswordSignature(password_handle->signature, sizeof(password_handle->signature),
162 password_key.get(), password_key_length, to_sign, sizeof(to_sign), salt);
163 return true;
164}
165
Andres Morales7d0f0402015-03-19 18:02:55 -0700166bool GateKeeper::DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700167 if (!password.buffer.get()) return false;
168
169 SizedBuffer provided_handle;
170 if (!CreatePasswordHandle(&provided_handle, expected_handle->salt, expected_handle->user_id,
171 expected_handle->authenticator_id, password.buffer.get(), password.length)) {
172 return false;
173 }
174
175 return memcmp_s(provided_handle.buffer.get(), expected_handle, sizeof(*expected_handle)) == 0;
176}
177
Andres Morales7d0f0402015-03-19 18:02:55 -0700178bool GateKeeper::ValidatePasswordFile(uint32_t uid, const SizedBuffer &provided_handle) {
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700179 SizedBuffer stored_handle;
180 ReadPasswordFile(uid, &stored_handle);
181
182 if (!stored_handle.buffer.get() || stored_handle.length == 0) return false;
183
184 // do we also verify the signature here?
185 return stored_handle.length == provided_handle.length &&
186 memcmp_s(stored_handle.buffer.get(), provided_handle.buffer.get(), stored_handle.length)
187 == 0;
188}
189
Andres Morales7d0f0402015-03-19 18:02:55 -0700190void GateKeeper::MintAuthToken(UniquePtr<uint8_t> *auth_token, size_t *length,
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700191 uint32_t timestamp, secure_id_t user_id, secure_id_t authenticator_id) {
Andres Moralesb2abaa82015-03-03 09:09:18 -0800192 if (auth_token == NULL) return;
193
194 AuthToken *token = new AuthToken;
Andres Moralesac808182015-02-26 14:11:04 -0800195 SizedBuffer serialized_auth_token;
196
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700197 token->root_secure_user_id = user_id;
198 token->auxiliary_secure_user_id = authenticator_id;
199 token->timestamp = timestamp;
Andres Moralesac808182015-02-26 14:11:04 -0800200
Andres Moralesb2abaa82015-03-03 09:09:18 -0800201 UniquePtr<uint8_t> auth_token_key;
202 size_t key_len;
203 GetAuthTokenKey(&auth_token_key, &key_len);
204
Andres Moralesedd3e3d2015-03-12 13:30:15 -0700205 size_t hash_len = (size_t)((uint8_t *)&token->hmac - (uint8_t *)token);
206 ComputeSignature(token->hmac, sizeof(token->hmac), auth_token_key.get(), key_len,
207 reinterpret_cast<uint8_t *>(token), hash_len);
Andres Moralesac808182015-02-26 14:11:04 -0800208
Andres Moralesac808182015-02-26 14:11:04 -0800209 if (length != NULL) *length = sizeof(AuthToken);
Andres Moralesb2abaa82015-03-03 09:09:18 -0800210 auth_token->reset(reinterpret_cast<uint8_t *>(token));
Andres Moralesac808182015-02-26 14:11:04 -0800211}
Andres Moralesb2abaa82015-03-03 09:09:18 -0800212
Andres Moralesac808182015-02-26 14:11:04 -0800213}