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