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_key_blob_maker.h"
17
18 #include <vector>
19
20 #include <android-base/logging.h>
21 #include <tss2/tss2_mu.h>
22 #include <tss2/tss2_rc.h>
23
24 #include "host/commands/secure_env/composite_serialization.h"
25 #include "host/commands/secure_env/encrypted_serializable.h"
26 #include "host/commands/secure_env/hmac_serializable.h"
27
28 using keymaster::AuthorizationSet;
29 using keymaster::KeymasterKeyBlob;
30 using keymaster::Serializable;
31
32 /**
33 * Returns a TPM reference to a key used for integrity checking on wrapped keys.
34 */
SigningKey(TpmResourceManager * resource_manager)35 static TpmObjectSlot SigningKey(TpmResourceManager* resource_manager) {
36 TPM2B_AUTH authValue = {};
37 auto rc =
38 Esys_TR_SetAuth(resource_manager->Esys(), ESYS_TR_RH_OWNER, &authValue);
39 if (rc != TSS2_RC_SUCCESS) {
40 LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
41 << " (" << Tss2_RC_Decode(rc) << ")";
42 return {};
43 }
44
45 TPMT_PUBLIC public_area;
46 public_area.nameAlg = TPM2_ALG_SHA1;
47 public_area.type = TPM2_ALG_KEYEDHASH;
48 public_area.objectAttributes |= TPMA_OBJECT_SIGN_ENCRYPT;
49 public_area.objectAttributes |= TPMA_OBJECT_USERWITHAUTH;
50 public_area.objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN;
51 public_area.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_HMAC;
52 public_area.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = TPM2_ALG_SHA1;
53
54 TPM2B_TEMPLATE public_template = {};
55 size_t offset = 0;
56 rc = Tss2_MU_TPMT_PUBLIC_Marshal(&public_area, &public_template.buffer[0],
57 sizeof(public_template.buffer), &offset);
58 if (rc != TSS2_RC_SUCCESS) {
59 LOG(ERROR) << "Tss2_MU_TPMT_PUBLIC_Marshal failed with return code " << rc
60 << " (" << Tss2_RC_Decode(rc) << ")";
61 return {};
62 }
63 public_template.size = offset;
64
65 TPM2B_SENSITIVE_CREATE in_sensitive = {};
66
67 auto key_slot = resource_manager->ReserveSlot();
68 if (!key_slot) {
69 LOG(ERROR) << "No slots available";
70 return {};
71 }
72 ESYS_TR raw_handle;
73 // TODO(b/154956668): Define better ACLs on these keys.
74 // Since this is a primary key, it's generated deterministically. It would
75 // also be possible to generate this once and hold it in storage.
76 rc = Esys_CreateLoaded(
77 /* esysContext */ resource_manager->Esys(),
78 /* primaryHandle */ ESYS_TR_RH_OWNER,
79 /* shandle1 */ ESYS_TR_PASSWORD,
80 /* shandle2 */ ESYS_TR_NONE,
81 /* shandle3 */ ESYS_TR_NONE,
82 /* inSensitive */ &in_sensitive,
83 /* inPublic */ &public_template,
84 /* objectHandle */ &raw_handle,
85 /* outPrivate */ nullptr,
86 /* outPublic */ nullptr);
87 if (rc != TSS2_RC_SUCCESS) {
88 LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
89 << " (" << Tss2_RC_Decode(rc) << ")";
90 return {};
91 }
92 key_slot->set(raw_handle);
93 return key_slot;
94 }
95
ParentKey(TpmResourceManager * resource_manager)96 static TpmObjectSlot ParentKey(TpmResourceManager* resource_manager) {
97 TPM2B_AUTH authValue = {};
98 auto rc =
99 Esys_TR_SetAuth(resource_manager->Esys(), ESYS_TR_RH_PLATFORM, &authValue);
100 if (rc != TSS2_RC_SUCCESS) {
101 LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
102 << " (" << Tss2_RC_Decode(rc) << ")";
103 return {};
104 }
105
106 TPMT_PUBLIC public_area = {
107 .type = TPM2_ALG_SYMCIPHER,
108 .nameAlg = TPM2_ALG_SHA256,
109 .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
110 TPMA_OBJECT_RESTRICTED |
111 TPMA_OBJECT_DECRYPT |
112 TPMA_OBJECT_FIXEDTPM |
113 TPMA_OBJECT_FIXEDPARENT |
114 TPMA_OBJECT_SENSITIVEDATAORIGIN),
115 .authPolicy.size = 0,
116 .parameters.symDetail.sym = {
117 .algorithm = TPM2_ALG_AES,
118 .keyBits.aes = 128, // The default maximum AES key size in the simulator.
119 .mode.aes = TPM2_ALG_CFB,
120 },
121 };
122
123 TPM2B_TEMPLATE public_template = {};
124 size_t offset = 0;
125 rc = Tss2_MU_TPMT_PUBLIC_Marshal(&public_area, &public_template.buffer[0],
126 sizeof(public_template.buffer), &offset);
127 if (rc != TSS2_RC_SUCCESS) {
128 LOG(ERROR) << "Tss2_MU_TPMT_PUBLIC_Marshal failed with return code " << rc
129 << " (" << Tss2_RC_Decode(rc) << ")";
130 return {};
131 }
132 public_template.size = offset;
133
134 TPM2B_SENSITIVE_CREATE in_sensitive = {};
135
136 auto key_slot = resource_manager->ReserveSlot();
137 if (!key_slot) {
138 LOG(ERROR) << "No key slots available";
139 return {};
140 }
141 ESYS_TR raw_handle;
142 // TODO(b/154956668): Define better ACLs on these keys.
143 TPM2B_PUBLIC* key_public = nullptr;
144 TPM2B_PRIVATE* key_private = nullptr;
145 rc = Esys_CreateLoaded(
146 /* esysContext */ resource_manager->Esys(),
147 /* primaryHandle */ ESYS_TR_RH_PLATFORM,
148 /* shandle1 */ ESYS_TR_PASSWORD,
149 /* shandle2 */ ESYS_TR_NONE,
150 /* shandle3 */ ESYS_TR_NONE,
151 /* inSensitive */ &in_sensitive,
152 /* inPublic */ &public_template,
153 /* objectHandle */ &raw_handle,
154 /* outPrivate */ &key_private,
155 /* outPublic */ &key_public);
156 if (rc != TSS2_RC_SUCCESS) {
157 LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
158 << " (" << Tss2_RC_Decode(rc) << ")";
159 return {};
160 }
161 Esys_Free(key_private);
162 Esys_Free(key_public);
163 key_slot->set(raw_handle);
164 return key_slot;
165 }
166
167 /**
168 * Distinguish what properties the secure_env implementation handles. If
169 * secure_env handles it, the property is put in `hw_enforced`. Otherwise, the
170 * property is put in `sw_enforced`, and the Keystore process inside Android
171 * will try to enforce the property.
172 */
SplitEnforcedProperties(const keymaster::AuthorizationSet & key_description,keymaster::AuthorizationSet * hw_enforced,keymaster::AuthorizationSet * sw_enforced)173 static keymaster_error_t SplitEnforcedProperties(
174 const keymaster::AuthorizationSet& key_description,
175 keymaster::AuthorizationSet* hw_enforced,
176 keymaster::AuthorizationSet* sw_enforced) {
177 for (auto& entry : key_description) {
178 switch (entry.tag) {
179 case KM_TAG_PURPOSE:
180 case KM_TAG_ALGORITHM:
181 case KM_TAG_KEY_SIZE:
182 case KM_TAG_RSA_PUBLIC_EXPONENT:
183 case KM_TAG_BLOB_USAGE_REQUIREMENTS:
184 case KM_TAG_DIGEST:
185 case KM_TAG_PADDING:
186 case KM_TAG_BLOCK_MODE:
187 case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
188 case KM_TAG_MAX_USES_PER_BOOT:
189 case KM_TAG_USER_SECURE_ID:
190 case KM_TAG_NO_AUTH_REQUIRED:
191 case KM_TAG_AUTH_TIMEOUT:
192 case KM_TAG_CALLER_NONCE:
193 case KM_TAG_MIN_MAC_LENGTH:
194 case KM_TAG_KDF:
195 case KM_TAG_EC_CURVE:
196 case KM_TAG_ECIES_SINGLE_HASH_MODE:
197 case KM_TAG_USER_AUTH_TYPE:
198 case KM_TAG_ORIGIN:
199 case KM_TAG_OS_VERSION:
200 case KM_TAG_OS_PATCHLEVEL:
201 case KM_TAG_EARLY_BOOT_ONLY:
202 case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
203 hw_enforced->push_back(entry);
204 break;
205 default:
206 sw_enforced->push_back(entry);
207 }
208 }
209 return KM_ERROR_OK;
210 }
211
SerializableToKeyBlob(const Serializable & serializable)212 static KeymasterKeyBlob SerializableToKeyBlob(
213 const Serializable& serializable) {
214 std::vector<uint8_t> data(serializable.SerializedSize() + 1);
215 uint8_t* buf = data.data();
216 uint8_t* buf_end = buf + data.size();
217 buf = serializable.Serialize(buf, buf_end);
218 if (buf != (buf_end - 1)) {
219 LOG(ERROR) << "Serialized size did not match up with actual usage.";
220 return {};
221 }
222 return KeymasterKeyBlob(data.data(), buf - data.data());
223 }
224
225
TpmKeyBlobMaker(TpmResourceManager * resource_manager)226 TpmKeyBlobMaker::TpmKeyBlobMaker(TpmResourceManager* resource_manager)
227 : resource_manager_(resource_manager) {
228 }
229
CreateKeyBlob(const AuthorizationSet & key_description,keymaster_key_origin_t origin,const KeymasterKeyBlob & key_material,KeymasterKeyBlob * blob,AuthorizationSet * hw_enforced,AuthorizationSet * sw_enforced) const230 keymaster_error_t TpmKeyBlobMaker::CreateKeyBlob(
231 const AuthorizationSet& key_description,
232 keymaster_key_origin_t origin,
233 const KeymasterKeyBlob& key_material,
234 KeymasterKeyBlob* blob,
235 AuthorizationSet* hw_enforced,
236 AuthorizationSet* sw_enforced) const {
237 std::set<keymaster_tag_t> protected_tags = {
238 KM_TAG_ROOT_OF_TRUST,
239 KM_TAG_ORIGIN,
240 KM_TAG_OS_VERSION,
241 KM_TAG_OS_PATCHLEVEL,
242 };
243 for (auto tag : protected_tags) {
244 if (key_description.Contains(tag)) {
245 return KM_ERROR_INVALID_TAG;
246 }
247 }
248 auto rc =
249 SplitEnforcedProperties(key_description, hw_enforced, sw_enforced);
250 if (rc != KM_ERROR_OK) {
251 return rc;
252 }
253 hw_enforced->push_back(keymaster::TAG_ORIGIN, origin);
254 // TODO(schuffelen): Set the os level and patch level.
255 keymaster::Buffer key_material_buffer(
256 key_material.key_material, key_material.key_material_size);
257 CompositeSerializable sensitive_material(
258 {&key_material_buffer, hw_enforced, sw_enforced});
259 EncryptedSerializable encryption(
260 resource_manager_, ParentKey, &sensitive_material);
261 HmacSerializable sign_check(
262 resource_manager_, SigningKey, TPM2_SHA1_DIGEST_SIZE, &encryption);
263 auto generated_blob = SerializableToKeyBlob(sign_check);
264 LOG(DEBUG) << "Keymaster key size: " << generated_blob.key_material_size;
265 if (generated_blob.key_material_size != 0) {
266 *blob = generated_blob;
267 return KM_ERROR_OK;
268 }
269 LOG(ERROR) << "Failed to serialize key.";
270 return KM_ERROR_UNKNOWN_ERROR;
271 }
272
UnwrapKeyBlob(const keymaster_key_blob_t & blob,AuthorizationSet * hw_enforced,AuthorizationSet * sw_enforced,KeymasterKeyBlob * key_material) const273 keymaster_error_t TpmKeyBlobMaker::UnwrapKeyBlob(
274 const keymaster_key_blob_t& blob,
275 AuthorizationSet* hw_enforced,
276 AuthorizationSet* sw_enforced,
277 KeymasterKeyBlob* key_material) const {
278 keymaster::Buffer key_material_buffer(blob.key_material_size);
279 CompositeSerializable sensitive_material(
280 {&key_material_buffer, hw_enforced, sw_enforced});
281 EncryptedSerializable encryption(
282 resource_manager_, ParentKey, &sensitive_material);
283 HmacSerializable sign_check(
284 resource_manager_, SigningKey, TPM2_SHA1_DIGEST_SIZE, &encryption);
285 auto buf = blob.key_material;
286 auto buf_end = buf + blob.key_material_size;
287 if (!sign_check.Deserialize(&buf, buf_end)) {
288 LOG(ERROR) << "Failed to deserialize key.";
289 return KM_ERROR_UNKNOWN_ERROR;
290 }
291 if (key_material_buffer.available_read() == 0) {
292 LOG(ERROR) << "Key material was corrupted and the size was too large";
293 return KM_ERROR_UNKNOWN_ERROR;
294 }
295 *key_material = KeymasterKeyBlob(
296 key_material_buffer.peek_read(), key_material_buffer.available_read());
297 return KM_ERROR_OK;
298 }
299