1 //
2 // Copyright (C) 2020 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
16 #include "tpm_gatekeeper.h"
17
18 #include <algorithm>
19 #include <optional>
20 #include <vector>
21
22 #include <android-base/logging.h>
23 #include <tss2/tss2_esys.h>
24 #include <tss2/tss2_mu.h>
25 #include <tss2/tss2_rc.h>
26
27 #ifdef _WIN32
28 #include <sysinfoapi.h>
29 #endif
30
31 #include "host/commands/secure_env/primary_key_builder.h"
32 #include "host/commands/secure_env/tpm_auth.h"
33 #include "host/commands/secure_env/tpm_hmac.h"
34 #include "host/commands/secure_env/tpm_random_source.h"
35
36 namespace cuttlefish {
37
TpmGatekeeper(TpmResourceManager & resource_manager,GatekeeperStorage & secure_storage,GatekeeperStorage & insecure_storage)38 TpmGatekeeper::TpmGatekeeper(
39 TpmResourceManager& resource_manager,
40 GatekeeperStorage& secure_storage,
41 GatekeeperStorage& insecure_storage)
42 : resource_manager_(resource_manager)
43 , secure_storage_(secure_storage)
44 , insecure_storage_(insecure_storage) {
45 }
46
47 /*
48 * The reinterpret_cast and kPasswordUnique data is combined together with TPM
49 * internal state to create the actual key used for Gatekeeper operations.
50 */
51
GetAuthTokenKey(const uint8_t ** auth_token_key,uint32_t * length) const52 bool TpmGatekeeper::GetAuthTokenKey(
53 const uint8_t** auth_token_key, uint32_t* length) const {
54 static constexpr char kAuthTokenUnique[] = "TpmGatekeeper auth token key";
55 *auth_token_key = reinterpret_cast<const uint8_t*>(kAuthTokenUnique);
56 *length = sizeof(kAuthTokenUnique);
57 return true;
58 }
59
GetPasswordKey(const uint8_t ** password_key,uint32_t * length)60 void TpmGatekeeper::GetPasswordKey(
61 const uint8_t** password_key, uint32_t* length) {
62 static constexpr char kPasswordUnique[] = "TpmGatekeeper password key";
63 *password_key = reinterpret_cast<const uint8_t*>(kPasswordUnique);
64 *length = sizeof(kPasswordUnique);
65 }
66
ComputePasswordSignature(uint8_t * signature,uint32_t signature_length,const uint8_t * key,uint32_t key_length,const uint8_t * password,uint32_t password_length,gatekeeper::salt_t salt) const67 void TpmGatekeeper::ComputePasswordSignature(
68 uint8_t* signature,
69 uint32_t signature_length,
70 const uint8_t* key,
71 uint32_t key_length,
72 const uint8_t* password,
73 uint32_t password_length,
74 gatekeeper::salt_t salt) const {
75 std::vector<uint8_t> message(password_length + sizeof(salt));
76 memcpy(message.data(), password, password_length);
77 memcpy(message.data() + password_length, &salt, sizeof(salt));
78 return ComputeSignature(
79 signature,
80 signature_length,
81 key,
82 key_length,
83 message.data(),
84 message.size());
85 }
86
GetRandom(void * random,uint32_t requested_size) const87 void TpmGatekeeper::GetRandom(void* random, uint32_t requested_size) const {
88 auto random_uint8 = reinterpret_cast<uint8_t*>(random);
89 TpmRandomSource(resource_manager_.Esys())
90 .GenerateRandom(random_uint8, requested_size);
91 }
92
ComputeSignature(uint8_t * signature,uint32_t signature_length,const uint8_t * key,uint32_t key_length,const uint8_t * message,uint32_t length) const93 void TpmGatekeeper::ComputeSignature(
94 uint8_t* signature,
95 uint32_t signature_length,
96 const uint8_t* key,
97 uint32_t key_length,
98 const uint8_t* message,
99 uint32_t length) const {
100 memset(signature, 0, signature_length);
101 std::string key_unique(reinterpret_cast<const char*>(key), key_length);
102
103 auto calculated_signature =
104 TpmHmacWithContext(resource_manager_, key_unique, message, length);
105 if (!calculated_signature) {
106 LOG(ERROR) << "Failure in calculating signature";
107 return;
108 }
109 memcpy(
110 signature,
111 calculated_signature->buffer,
112 std::min((int) calculated_signature->size, (int) signature_length));
113 }
114
GetMillisecondsSinceBoot() const115 uint64_t TpmGatekeeper::GetMillisecondsSinceBoot() const {
116 #ifdef _WIN32
117 return GetTickCount64();
118 #else
119 struct timespec time;
120 int res = clock_gettime(CLOCK_BOOTTIME, &time);
121 if (res < 0) return 0;
122 return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
123 #endif
124 }
125
DefaultRecord(gatekeeper::secure_id_t secure_user_id)126 gatekeeper::failure_record_t DefaultRecord(
127 gatekeeper::secure_id_t secure_user_id) {
128 return (gatekeeper::failure_record_t) {
129 .secure_user_id = secure_user_id,
130 .last_checked_timestamp = 0,
131 .failure_counter = 0,
132 };
133 }
134
RecordToNvBuffer(const gatekeeper::failure_record_t & record)135 static std::unique_ptr<TPM2B_MAX_NV_BUFFER> RecordToNvBuffer(
136 const gatekeeper::failure_record_t& record) {
137 auto ret = std::make_unique<TPM2B_MAX_NV_BUFFER>();
138 static_assert(sizeof(ret->buffer) >= sizeof(record));
139 ret->size = sizeof(record);
140 std::memcpy(ret->buffer, &record, sizeof(record));
141 return ret;
142 }
143
NvBufferToRecord(const TPM2B_MAX_NV_BUFFER & buffer)144 static std::optional<gatekeeper::failure_record_t> NvBufferToRecord(
145 const TPM2B_MAX_NV_BUFFER& buffer) {
146 gatekeeper::failure_record_t ret;
147 if (buffer.size != sizeof(ret)) {
148 LOG(ERROR) << "NV Buffer had an incorrect size.";
149 return {};
150 }
151 memcpy(&ret, buffer.buffer, sizeof(ret));
152 return ret;
153 }
154
GetFailureRecordImpl(GatekeeperStorage & storage,uint32_t uid,gatekeeper::secure_id_t secure_user_id,gatekeeper::failure_record_t * record)155 static bool GetFailureRecordImpl(
156 GatekeeperStorage& storage,
157 uint32_t uid,
158 gatekeeper::secure_id_t secure_user_id,
159 gatekeeper::failure_record_t *record) {
160 Json::Value key{std::to_string(uid)}; // jsoncpp integer comparisons are janky
161 if (!storage.HasKey(key)) {
162 if (!storage.Allocate(key, sizeof(gatekeeper::failure_record_t))) {
163 LOG(ERROR) << "Allocation failed for user " << uid;
164 return false;
165 }
166 auto buf = RecordToNvBuffer(DefaultRecord(secure_user_id));
167 if (!storage.Write(key, *buf)) {
168 LOG(ERROR) << "Failed to write record for " << uid;
169 return false;
170 }
171 }
172 auto record_read = storage.Read(key);
173 if (!record_read) {
174 LOG(ERROR) << "Failed to read record for " << uid;
175 return false;
176 }
177 auto record_decoded = NvBufferToRecord(*record_read);
178 if (!record_decoded) {
179 LOG(ERROR) << "Failed to deserialize record for " << uid;
180 return false;
181 }
182 if (record_decoded->secure_user_id == secure_user_id) {
183 *record = *record_decoded;
184 return true;
185 }
186 LOG(DEBUG) << "User id mismatch for " << uid;
187 auto buf = RecordToNvBuffer(DefaultRecord(secure_user_id));
188 if (!storage.Write(key, *buf)) {
189 LOG(ERROR) << "Failed to write record for " << uid;
190 return false;
191 }
192 *record = DefaultRecord(secure_user_id);
193 return true;
194 }
195
GetFailureRecord(uint32_t uid,gatekeeper::secure_id_t secure_user_id,gatekeeper::failure_record_t * record,bool secure)196 bool TpmGatekeeper::GetFailureRecord(
197 uint32_t uid,
198 gatekeeper::secure_id_t secure_user_id,
199 gatekeeper::failure_record_t *record,
200 bool secure) {
201 GatekeeperStorage& storage = secure ? secure_storage_ : insecure_storage_;
202 return GetFailureRecordImpl(storage, uid, secure_user_id, record);
203 }
204
WriteFailureRecordImpl(GatekeeperStorage & storage,uint32_t uid,gatekeeper::failure_record_t * record)205 static bool WriteFailureRecordImpl(
206 GatekeeperStorage& storage,
207 uint32_t uid,
208 gatekeeper::failure_record_t* record) {
209 Json::Value key{std::to_string(uid)}; // jsoncpp integer comparisons are janky
210 if (!storage.HasKey(key)) {
211 if (!storage.Allocate(key, sizeof(gatekeeper::failure_record_t))) {
212 LOG(ERROR) << "Allocation failed for user " << uid;
213 return false;
214 }
215 }
216 auto buf = RecordToNvBuffer(*record);
217 if (!storage.Write(key, *buf)) {
218 LOG(ERROR) << "Failed to write record for " << uid;
219 return false;
220 }
221 return true;
222 }
223
ClearFailureRecord(uint32_t uid,gatekeeper::secure_id_t secure_user_id,bool secure)224 bool TpmGatekeeper::ClearFailureRecord(
225 uint32_t uid, gatekeeper::secure_id_t secure_user_id, bool secure) {
226 GatekeeperStorage& storage = secure ? secure_storage_ : insecure_storage_;
227 gatekeeper::failure_record_t record = DefaultRecord(secure_user_id);
228 return WriteFailureRecordImpl(storage, uid, &record);
229 }
230
WriteFailureRecord(uint32_t uid,gatekeeper::failure_record_t * record,bool secure)231 bool TpmGatekeeper::WriteFailureRecord(
232 uint32_t uid, gatekeeper::failure_record_t *record, bool secure) {
233 GatekeeperStorage& storage = secure ? secure_storage_ : insecure_storage_;
234 return WriteFailureRecordImpl(storage, uid, record);
235 }
236
IsHardwareBacked() const237 bool TpmGatekeeper::IsHardwareBacked() const {
238 return true;
239 }
240
241 } // namespace cuttlefish
242