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