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