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 "encrypted_serializable.h"
17 
18 #include <vector>
19 
20 #include <android-base/logging.h>
21 
22 #include "host/commands/secure_env/tpm_auth.h"
23 #include "host/commands/secure_env/tpm_encrypt_decrypt.h"
24 #include "host/commands/secure_env/tpm_serialize.h"
25 
EncryptedSerializable(TpmResourceManager * resource_manager,std::function<TpmObjectSlot (TpmResourceManager *)> parent_key_fn,Serializable * wrapped)26 EncryptedSerializable::EncryptedSerializable(
27     TpmResourceManager* resource_manager,
28     std::function<TpmObjectSlot(TpmResourceManager*)> parent_key_fn,
29     Serializable* wrapped) :
30     resource_manager_(resource_manager),
31     parent_key_fn_(parent_key_fn),
32     wrapped_(wrapped) {
33 }
34 
CreateKey(TpmResourceManager * resource_manager,ESYS_TR parent_key,TPM2B_PUBLIC * key_public_out,TPM2B_PRIVATE * key_private_out,TpmObjectSlot * key_slot_out)35 static bool CreateKey(
36     TpmResourceManager* resource_manager, // in
37     ESYS_TR parent_key, // in
38     TPM2B_PUBLIC* key_public_out, // out
39     TPM2B_PRIVATE* key_private_out, // out
40     TpmObjectSlot* key_slot_out) { // out
41   TPM2B_AUTH authValue = {};
42   auto rc = Esys_TR_SetAuth(resource_manager->Esys(), parent_key, &authValue);
43   if (rc != TSS2_RC_SUCCESS) {
44     LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
45                << " (" << Tss2_RC_Decode(rc) << ")";
46     return false;
47   }
48 
49   TPMT_PUBLIC public_area = {
50     .type = TPM2_ALG_SYMCIPHER,
51     .nameAlg = TPM2_ALG_SHA256,
52     .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
53                          TPMA_OBJECT_DECRYPT |
54                          TPMA_OBJECT_SIGN_ENCRYPT |
55                          TPMA_OBJECT_FIXEDTPM |
56                          TPMA_OBJECT_FIXEDPARENT |
57                          TPMA_OBJECT_SENSITIVEDATAORIGIN),
58     .authPolicy.size = 0,
59     .parameters.symDetail.sym = {
60       .algorithm = TPM2_ALG_AES,
61       .keyBits.aes = 128, // The default maximum AES key size in the simulator.
62       .mode.aes = TPM2_ALG_CFB,
63     },
64   };
65 
66   TPM2B_TEMPLATE public_template = {};
67   size_t offset = 0;
68   rc = Tss2_MU_TPMT_PUBLIC_Marshal(&public_area, &public_template.buffer[0],
69                                    sizeof(public_template.buffer), &offset);
70   if (rc != TSS2_RC_SUCCESS) {
71     LOG(ERROR) << "Tss2_MU_TPMT_PUBLIC_Marshal failed with return code " << rc
72                << " (" << Tss2_RC_Decode(rc) << ")";
73     return false;
74   }
75   public_template.size = offset;
76 
77   TPM2B_SENSITIVE_CREATE in_sensitive = {};
78 
79   auto key_slot = resource_manager->ReserveSlot();
80   if (!key_slot) {
81     LOG(ERROR) << "No slots available";
82     return false;
83   }
84   ESYS_TR raw_handle;
85   // TODO(b/154956668): Define better ACLs on these keys.
86   TPM2B_PUBLIC* key_public = nullptr;
87   TPM2B_PRIVATE* key_private = nullptr;
88   // TODO(schuffelen): Use Esys_Create when key_slot is NULL
89   rc = Esys_CreateLoaded(
90     /* esysContext */ resource_manager->Esys(),
91     /* primaryHandle */ parent_key,
92     /* shandle1 */ ESYS_TR_PASSWORD,
93     /* shandle2 */ ESYS_TR_NONE,
94     /* shandle3 */ ESYS_TR_NONE,
95     /* inSensitive */ &in_sensitive,
96     /* inPublic */ &public_template,
97     /* objectHandle */ &raw_handle,
98     /* outPrivate */ &key_private,
99     /* outPublic */ &key_public);
100   if (rc != TSS2_RC_SUCCESS) {
101     LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
102                << " (" << Tss2_RC_Decode(rc) << ")";
103     return false;
104   }
105   CHECK(key_public != nullptr) << "key_public was not assigned.";
106   CHECK(key_private != nullptr) << "key_private was not assigned.";
107   *key_public_out = *key_public;
108   *key_private_out = *key_private;
109   key_slot->set(raw_handle);
110   Esys_Free(key_public);
111   Esys_Free(key_private);
112   if (key_slot_out) {
113     rc = Esys_TR_SetAuth(resource_manager->Esys(), raw_handle, &authValue);
114     if (rc != TSS2_RC_SUCCESS) {
115       LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
116                 << " (" << Tss2_RC_Decode(rc) << ")";
117       return false;
118     }
119   }
120   if (key_slot_out) {
121     *key_slot_out = key_slot;
122   }
123   return true;
124 }
125 
LoadKey(TpmResourceManager * resource_manager,ESYS_TR parent_key,const TPM2B_PUBLIC * key_public,const TPM2B_PRIVATE * key_private)126 static TpmObjectSlot LoadKey(
127     TpmResourceManager* resource_manager,
128     ESYS_TR parent_key,
129     const TPM2B_PUBLIC* key_public,
130     const TPM2B_PRIVATE* key_private) {
131   // TODO
132   ESYS_TR raw_handle;
133   auto key_slot = resource_manager->ReserveSlot();
134   if (!key_slot) {
135     LOG(ERROR) << "No slots available";
136     return {};
137   }
138   auto rc = Esys_Load(
139       resource_manager->Esys(),
140       parent_key,
141       ESYS_TR_PASSWORD,
142       ESYS_TR_NONE,
143       ESYS_TR_NONE,
144       key_private,
145       key_public,
146       &raw_handle);
147   if (rc != TSS2_RC_SUCCESS) {
148     LOG(ERROR) << "Esys_Load failed with return code " << rc
149                << " (" << Tss2_RC_Decode(rc) << ")";
150     return {};
151   }
152   key_slot->set(raw_handle);
153   return key_slot;
154 }
155 
156 static constexpr uint32_t BLOCK_SIZE = 16;
157 
RoundUpToBlockSize(uint32_t num)158 static uint32_t RoundUpToBlockSize(uint32_t num) {
159   return num % BLOCK_SIZE == 0 ? num : num + (BLOCK_SIZE - (num % BLOCK_SIZE));
160 }
161 
SerializedSize() const162 size_t EncryptedSerializable::SerializedSize() const {
163   TPM2B_PUBLIC key_public;
164   TPM2B_PRIVATE key_private;
165   auto parent = parent_key_fn_(resource_manager_);
166   if (!CreateKey(
167       resource_manager_, parent->get(), &key_public, &key_private, nullptr)) {
168     LOG(ERROR) << "Unable to create key";
169     return 0;
170   }
171   // Assumes all created keys will have the same size.
172   SerializeTpmKeyPublic serialize_public(&key_public);
173   SerializeTpmKeyPrivate serialize_private(&key_private);
174   auto encrypted_size = RoundUpToBlockSize(wrapped_->SerializedSize());
175   return serialize_public.SerializedSize()
176     + serialize_private.SerializedSize()
177     + sizeof(uint32_t)
178     + sizeof(uint32_t)
179     + encrypted_size;
180 }
181 
Serialize(uint8_t * buf,const uint8_t * end) const182 uint8_t* EncryptedSerializable::Serialize(
183     uint8_t* buf, const uint8_t* end) const {
184   TPM2B_PUBLIC key_public;
185   TPM2B_PRIVATE key_private;
186   auto parent = parent_key_fn_(resource_manager_);
187   if (!parent) {
188     LOG(ERROR) << "Unable to load encryption parent key";
189     return buf;
190   }
191   TpmObjectSlot key_slot;
192   if (!CreateKey(
193       resource_manager_, parent->get(), &key_public, &key_private, &key_slot)) {
194     LOG(ERROR) << "Unable to create key";
195     return buf;
196   }
197 
198   auto wrapped_size = wrapped_->SerializedSize();
199   auto encrypted_size = RoundUpToBlockSize(wrapped_size);
200   std::vector<uint8_t> unencrypted(encrypted_size + 1, 0);
201   auto unencrypted_buf = unencrypted.data();
202   auto unencrypted_buf_end = unencrypted_buf + unencrypted.size();
203   auto next_buf = wrapped_->Serialize(unencrypted_buf, unencrypted_buf_end);
204   if (next_buf - unencrypted_buf != wrapped_size) {
205     LOG(ERROR) << "Size mismatch on wrapped data";
206     return buf;
207   }
208   std::vector<uint8_t> encrypted(encrypted_size, 0);
209   if (!TpmEncrypt(
210       resource_manager_->Esys(),
211       key_slot->get(),
212       TpmAuth(ESYS_TR_PASSWORD),
213       unencrypted.data(),
214       encrypted.data(),
215       encrypted_size)) {
216     LOG(ERROR) << "Encryption failed";
217     return buf;
218   }
219   SerializeTpmKeyPublic serialize_public(&key_public);
220   SerializeTpmKeyPrivate serialize_private(&key_private);
221 
222   buf = serialize_public.Serialize(buf, end);
223   buf = serialize_private.Serialize(buf, end);
224   buf = keymaster::append_uint32_to_buf(buf, end, BLOCK_SIZE);
225   buf = keymaster::append_uint32_to_buf(buf, end, wrapped_size);
226   buf = keymaster::append_to_buf(buf, end, encrypted.data(), encrypted_size);
227   return buf;
228 }
229 
Deserialize(const uint8_t ** buf_ptr,const uint8_t * end)230 bool EncryptedSerializable::Deserialize(
231     const uint8_t** buf_ptr, const uint8_t* end) {
232   auto parent_key = parent_key_fn_(resource_manager_);
233   if (!parent_key) {
234     LOG(ERROR) << "Unable to load encryption parent key";
235     return false;
236   }
237   TPM2B_PUBLIC key_public;
238   SerializeTpmKeyPublic serialize_public(&key_public);
239   if (!serialize_public.Deserialize(buf_ptr, end)) {
240     LOG(ERROR) << "Unable to deserialize key public part";
241     return false;
242   }
243   TPM2B_PRIVATE key_private;
244   SerializeTpmKeyPrivate serialize_private(&key_private);
245   if (!serialize_private.Deserialize(buf_ptr, end)) {
246     LOG(ERROR) << "Unable to deserialize key private part";
247     return false;
248   }
249   auto key_slot =
250       LoadKey(resource_manager_, parent_key->get(), &key_public, &key_private);
251   if (!key_slot) {
252     LOG(ERROR) << "Failed to load key into TPM";
253     return false;
254   }
255   uint32_t block_size = 0;
256   if (!keymaster::copy_uint32_from_buf(buf_ptr, end, &block_size)) {
257     LOG(ERROR) << "Failed to read block size";
258     return false;
259   }
260   if (block_size != BLOCK_SIZE) {
261     LOG(ERROR) << "Unexpected block size: was " << block_size
262                << ", expected " << BLOCK_SIZE;
263     return false;
264   }
265   uint32_t wrapped_size = 0;
266   if (!keymaster::copy_uint32_from_buf(buf_ptr, end, &wrapped_size)) {
267     LOG(ERROR) << "Failed to read wrapped size";
268     return false;
269   }
270   uint32_t encrypted_size = RoundUpToBlockSize(wrapped_size);
271   std::vector<uint8_t> encrypted_data(encrypted_size, 0);
272   if (!keymaster::copy_from_buf(
273       buf_ptr, end, encrypted_data.data(), encrypted_size)) {
274     LOG(ERROR) << "Failed to read encrypted data";
275     return false;
276   }
277   std::vector<uint8_t> decrypted_data(encrypted_size, 0);
278   if (!TpmDecrypt(
279       resource_manager_->Esys(),
280       key_slot->get(),
281       TpmAuth(ESYS_TR_PASSWORD),
282       encrypted_data.data(),
283       decrypted_data.data(),
284       encrypted_size)) {
285     LOG(ERROR) << "Failed to decrypt encrypted data";
286     return false;
287   }
288   auto decrypted_buf = decrypted_data.data();
289   auto decrypted_buf_end = decrypted_data.data() + wrapped_size;
290   if (!wrapped_->Deserialize(
291       const_cast<const uint8_t **>(&decrypted_buf), decrypted_buf_end)) {
292     LOG(ERROR) << "Failed to deserialize wrapped type";
293     return false;
294   }
295   if (decrypted_buf != decrypted_buf_end) {
296     LOG(ERROR) << "Inner type did not use all data";
297     return false;
298   }
299   return true;
300 }
301