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