• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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