• 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 "host/commands/secure_env/tpm_keymaster_enforcement.h"
17 
18 #include <android-base/endian.h>
19 #include <android-base/logging.h>
20 
21 #include "host/commands/secure_env/primary_key_builder.h"
22 #include "host/commands/secure_env/tpm_hmac.h"
23 #include "host/commands/secure_env/tpm_key_blob_maker.h"
24 #include "host/commands/secure_env/tpm_random_source.h"
25 
26 namespace cuttlefish {
27 
28 using keymaster::HmacSharingParameters;
29 using keymaster::HmacSharingParametersArray;
30 using keymaster::KeymasterBlob;
31 using keymaster::KeymasterEnforcement;
32 using keymaster::km_id_t;
33 using keymaster::VerifyAuthorizationRequest;
34 using keymaster::VerifyAuthorizationResponse;
35 namespace {
operator ==(const keymaster_blob_t & a,const keymaster_blob_t & b)36 inline bool operator==(const keymaster_blob_t& a, const keymaster_blob_t& b) {
37   if (!a.data_length && !b.data_length) return true;
38   if (!(a.data && b.data)) return a.data == b.data;
39   return (a.data_length == b.data_length &&
40           !memcmp(a.data, b.data, a.data_length));
41 }
42 
operator ==(const HmacSharingParameters & a,const HmacSharingParameters & b)43 bool operator==(const HmacSharingParameters& a,
44                 const HmacSharingParameters& b) {
45   return a.seed == b.seed && !memcmp(a.nonce, b.nonce, sizeof(a.nonce));
46 }
47 }  // namespace
48 class CompareHmacSharingParams {
49  public:
operator ()(const HmacSharingParameters & a,const HmacSharingParameters & b) const50   bool operator()(const HmacSharingParameters& a,
51                   const HmacSharingParameters& b) const {
52     if (a.seed.data_length != b.seed.data_length) {
53       return a.seed.data_length < b.seed.data_length;
54     }
55     auto res = memcmp(a.seed.data, b.seed.data, a.seed.data_length);
56     if (res != 0) {
57       return res < 0;
58     }
59     static_assert(sizeof(a.nonce) == sizeof(b.nonce));
60     return memcmp(a.nonce, b.nonce, sizeof(a.nonce)) < 0;
61   }
62 };
63 
64 namespace {
65 
timespec_to_ms(const struct timespec & tp)66 uint64_t timespec_to_ms(const struct timespec& tp) {
67   if (tp.tv_sec < 0) {
68     return 0;
69   }
70   return static_cast<uint64_t>(tp.tv_sec) * 1000 +
71          static_cast<uint64_t>(tp.tv_nsec) / 1000000;
72 }
73 
get_wall_clock_time_ms()74 uint64_t get_wall_clock_time_ms() {
75   struct timespec tp;
76   int err = clock_gettime(CLOCK_REALTIME, &tp);
77   if (err) {
78     return 0;
79   }
80   return timespec_to_ms(tp);
81 }
82 
83 }  // namespace
84 
TpmKeymasterEnforcement(TpmResourceManager & resource_manager,TpmGatekeeper & gatekeeper)85 TpmKeymasterEnforcement::TpmKeymasterEnforcement(
86     TpmResourceManager& resource_manager, TpmGatekeeper& gatekeeper)
87     : KeymasterEnforcement(64, 64),
88       resource_manager_(resource_manager),
89       gatekeeper_(gatekeeper) {}
90 
~TpmKeymasterEnforcement()91 TpmKeymasterEnforcement::~TpmKeymasterEnforcement() {}
92 
activation_date_valid(uint64_t activation_date) const93 bool TpmKeymasterEnforcement::activation_date_valid(
94     uint64_t activation_date) const {
95   return activation_date < get_wall_clock_time_ms();
96 }
97 
expiration_date_passed(uint64_t expiration_date) const98 bool TpmKeymasterEnforcement::expiration_date_passed(
99     uint64_t expiration_date) const {
100   return expiration_date < get_wall_clock_time_ms();
101 }
102 
auth_token_timed_out(const hw_auth_token_t & token,uint32_t timeout) const103 bool TpmKeymasterEnforcement::auth_token_timed_out(const hw_auth_token_t& token,
104                                                    uint32_t timeout) const {
105   // timeout comes in seconds, token.timestamp comes in milliseconds
106   uint64_t timeout_ms = 1000 * (uint64_t)timeout;
107   return (be64toh(token.timestamp) + timeout_ms) < get_current_time_ms();
108 }
109 
get_current_time_ms() const110 uint64_t TpmKeymasterEnforcement::get_current_time_ms() const {
111   struct timespec tp;
112   int err = clock_gettime(CLOCK_BOOTTIME, &tp);
113   if (err) {
114     return 0;
115   }
116   return timespec_to_ms(tp);
117 }
118 
SecurityLevel() const119 keymaster_security_level_t TpmKeymasterEnforcement::SecurityLevel() const {
120   return KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
121 }
122 
ValidateTokenSignature(const hw_auth_token_t & token) const123 bool TpmKeymasterEnforcement::ValidateTokenSignature(
124     const hw_auth_token_t& token) const {
125   hw_auth_token_t comparison_token = token;
126   memset(comparison_token.hmac, 0, sizeof(comparison_token.hmac));
127 
128   /*
129    * Should match implementation in system/gatekeeper/gatekeeper.cpp
130    * GateKeeper::MintAuthToken
131    */
132 
133   const uint8_t* auth_token_key = nullptr;
134   uint32_t auth_token_key_len = 0;
135   if (!gatekeeper_.GetAuthTokenKey(&auth_token_key, &auth_token_key_len)) {
136     LOG(WARNING) << "Unable to get gatekeeper auth token";
137     return false;
138   }
139 
140   constexpr uint32_t hashable_length =
141       sizeof(token.version) + sizeof(token.challenge) + sizeof(token.user_id) +
142       sizeof(token.authenticator_id) + sizeof(token.authenticator_type) +
143       sizeof(token.timestamp);
144 
145   static_assert(offsetof(hw_auth_token_t, hmac) == hashable_length,
146                 "hw_auth_token_t does not appear to be packed");
147 
148   gatekeeper_.ComputeSignature(
149       comparison_token.hmac, sizeof(comparison_token.hmac), auth_token_key,
150       auth_token_key_len, reinterpret_cast<uint8_t*>(&comparison_token),
151       hashable_length);
152 
153   static_assert(sizeof(token.hmac) == sizeof(comparison_token.hmac));
154 
155   return memcmp(token.hmac, comparison_token.hmac, sizeof(token.hmac)) == 0;
156 }
157 
GetHmacSharingParameters(HmacSharingParameters * params)158 keymaster_error_t TpmKeymasterEnforcement::GetHmacSharingParameters(
159     HmacSharingParameters* params) {
160   if (!have_saved_params_) {
161     saved_params_.seed = {};
162     TpmRandomSource random_source{resource_manager_.Esys()};
163     auto rc = random_source.GenerateRandom(saved_params_.nonce,
164                                            sizeof(saved_params_.nonce));
165     if (rc != KM_ERROR_OK) {
166       LOG(ERROR) << "Failed to generate HmacSharingParameters nonce";
167       return rc;
168     }
169     have_saved_params_ = true;
170   }
171   params->seed = saved_params_.seed;
172   memcpy(params->nonce, saved_params_.nonce, sizeof(params->nonce));
173   return KM_ERROR_OK;
174 }
175 
ComputeSharedHmac(const HmacSharingParametersArray & hmac_array,KeymasterBlob * sharingCheck)176 keymaster_error_t TpmKeymasterEnforcement::ComputeSharedHmac(
177     const HmacSharingParametersArray& hmac_array, KeymasterBlob* sharingCheck) {
178   std::set<HmacSharingParameters, CompareHmacSharingParams> sorted_hmac_inputs;
179   bool found_mine = false;
180   for (int i = 0; i < hmac_array.num_params; i++) {
181     HmacSharingParameters sharing_params;
182     sharing_params.seed =
183         keymaster::KeymasterBlob(hmac_array.params_array[i].seed);
184     memcpy(sharing_params.nonce, hmac_array.params_array[i].nonce,
185            sizeof(sharing_params.nonce));
186     found_mine = found_mine || (sharing_params == saved_params_);
187     sorted_hmac_inputs.emplace(std::move(sharing_params));
188   }
189 
190   if (!found_mine) return KM_ERROR_INVALID_ARGUMENT;
191 
192   // unique data has a low maximum size, so combine the hmac parameters
193   char unique_data[] = "\0\0\0\0\0\0\0\0\0\0";
194   int unique_index = 0;
195   for (const auto& hmac_sharing : sorted_hmac_inputs) {
196     for (size_t j = 0; j < hmac_sharing.seed.data_length; j++) {
197       unique_data[unique_index % sizeof(unique_data)] ^=
198           hmac_sharing.seed.data[j];
199       unique_index++;
200     }
201     for (auto nonce_byte : hmac_sharing.nonce) {
202       unique_data[unique_index % sizeof(unique_data)] ^= nonce_byte;
203       unique_index++;
204     }
205   }
206 
207   auto signing_key_builder = PrimaryKeyBuilder();
208   signing_key_builder.SigningKey();
209   signing_key_builder.UniqueData(std::string(unique_data, sizeof(unique_data)));
210   auto signing_key = signing_key_builder.CreateKey(resource_manager_);
211   if (!signing_key) {
212     LOG(ERROR) << "Could not make signing key for key id";
213     return KM_ERROR_UNKNOWN_ERROR;
214   }
215 
216   static const uint8_t signing_input[] = "Keymaster HMAC Verification";
217 
218   auto hmac =
219       TpmHmac(resource_manager_, signing_key->get(), TpmAuth(ESYS_TR_PASSWORD),
220               signing_input, sizeof(signing_input));
221 
222   if (!hmac) {
223     LOG(ERROR) << "Unable to complete signing check";
224     return KM_ERROR_UNKNOWN_ERROR;
225   }
226 
227   *sharingCheck = KeymasterBlob(hmac->buffer, hmac->size);
228 
229   return KM_ERROR_OK;
230 }
231 
VerifyAuthorization(const VerifyAuthorizationRequest & request)232 VerifyAuthorizationResponse TpmKeymasterEnforcement::VerifyAuthorization(
233     const VerifyAuthorizationRequest& request) {
234   struct VerificationData {
235     uint64_t challenge;
236     uint64_t timestamp;
237     keymaster_security_level_t security_level;
238   };
239   VerifyAuthorizationResponse response(keymaster::kDefaultMessageVersion);
240   response.error = KM_ERROR_UNKNOWN_ERROR;
241   response.token.challenge = request.challenge;
242   response.token.timestamp = get_current_time_ms();
243   response.token.security_level = SecurityLevel();
244 
245   VerificationData verify_data{
246       .challenge = response.token.challenge,
247       .timestamp = response.token.timestamp,
248       .security_level = response.token.security_level,
249   };
250 
251   auto signing_key_builder = PrimaryKeyBuilder();
252   signing_key_builder.SigningKey();
253   signing_key_builder.UniqueData("verify_authorization");
254   auto signing_key = signing_key_builder.CreateKey(resource_manager_);
255   if (!signing_key) {
256     LOG(ERROR) << "Could not make signing key for verifying authorization";
257     return response;
258   }
259   auto hmac =
260       TpmHmac(resource_manager_, signing_key->get(), TpmAuth(ESYS_TR_PASSWORD),
261               reinterpret_cast<uint8_t*>(&verify_data), sizeof(verify_data));
262 
263   if (!hmac) {
264     LOG(ERROR) << "Could not calculate verification hmac";
265     return response;
266   } else if (hmac->size == 0) {
267     LOG(ERROR) << "hmac was too short";
268     return response;
269   }
270   response.token.mac = KeymasterBlob(hmac->buffer, hmac->size);
271   response.error = KM_ERROR_OK;
272 
273   return response;
274 }
275 
GenerateTimestampToken(keymaster::TimestampToken * token)276 keymaster_error_t TpmKeymasterEnforcement::GenerateTimestampToken(
277     keymaster::TimestampToken* token) {
278   token->timestamp = get_current_time_ms();
279   token->security_level = SecurityLevel();
280   token->mac = KeymasterBlob();
281 
282   auto signing_key_builder = PrimaryKeyBuilder();
283   signing_key_builder.SigningKey();
284   signing_key_builder.UniqueData("timestamp_token");
285   auto signing_key = signing_key_builder.CreateKey(resource_manager_);
286   if (!signing_key) {
287     LOG(ERROR) << "Could not make signing key for verifying authorization";
288     return KM_ERROR_UNKNOWN_ERROR;
289   }
290   std::vector<uint8_t> token_buf_to_sign(token->SerializedSize(), 0);
291   auto hmac =
292       TpmHmac(resource_manager_, signing_key->get(), TpmAuth(ESYS_TR_PASSWORD),
293               token_buf_to_sign.data(), token_buf_to_sign.size());
294   if (!hmac) {
295     LOG(ERROR) << "Could not calculate timestamp token hmac";
296     return KM_ERROR_UNKNOWN_ERROR;
297   } else if (hmac->size == 0) {
298     LOG(ERROR) << "hmac was too short";
299     return KM_ERROR_UNKNOWN_ERROR;
300   }
301   token->mac = KeymasterBlob(hmac->buffer, hmac->size);
302 
303   return KM_ERROR_OK;
304 }
305 
306 keymaster::KmErrorOr<std::array<uint8_t, 32>>
ComputeHmac(const std::vector<uint8_t> & data_to_mac) const307 TpmKeymasterEnforcement::ComputeHmac(
308     const std::vector<uint8_t>& data_to_mac) const {
309   std::array<uint8_t, 32> result;
310 
311   const uint8_t* auth_token_key = nullptr;
312   uint32_t auth_token_key_len = 0;
313   if (!gatekeeper_.GetAuthTokenKey(&auth_token_key, &auth_token_key_len)) {
314     LOG(WARNING) << "Unable to get gatekeeper auth token";
315     return KM_ERROR_UNKNOWN_ERROR;
316   }
317 
318   gatekeeper_.ComputeSignature(result.data(), result.size(), auth_token_key,
319                                auth_token_key_len, data_to_mac.data(),
320                                data_to_mac.size());
321   return result;
322 }
323 
CreateKeyId(const keymaster_key_blob_t & key_blob,km_id_t * keyid) const324 bool TpmKeymasterEnforcement::CreateKeyId(const keymaster_key_blob_t& key_blob,
325                                           km_id_t* keyid) const {
326   auto signing_key_builder = PrimaryKeyBuilder();
327   signing_key_builder.SigningKey();
328   signing_key_builder.UniqueData("key_id");
329   auto signing_key = signing_key_builder.CreateKey(resource_manager_);
330   if (!signing_key) {
331     LOG(ERROR) << "Could not make signing key for key id";
332     return false;
333   }
334   auto hmac =
335       TpmHmac(resource_manager_, signing_key->get(), TpmAuth(ESYS_TR_PASSWORD),
336               key_blob.key_material, key_blob.key_material_size);
337   if (!hmac) {
338     LOG(ERROR) << "Failed to make a signature for a key id";
339     return false;
340   }
341   if (hmac->size < sizeof(km_id_t)) {
342     LOG(ERROR) << "hmac return size was less than " << sizeof(km_id_t)
343                << ", got " << hmac->size;
344     return false;
345   }
346   memcpy(keyid, hmac->buffer, sizeof(km_id_t));
347   return true;
348 }
349 
350 }  // namespace cuttlefish
351