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