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