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(*resource_manager.Esys(), parent_key, ESYS_TR_PASSWORD,
142 ESYS_TR_NONE, ESYS_TR_NONE, key_private, key_public,
143 &raw_handle);
144 if (rc != TSS2_RC_SUCCESS) {
145 LOG(ERROR) << "Esys_Load failed with return code " << rc
146 << " (" << Tss2_RC_Decode(rc) << ")";
147 return {};
148 }
149 key_slot->set(raw_handle);
150 return key_slot;
151 }
152
153 static constexpr uint32_t BLOCK_SIZE = 16;
154
RoundUpToBlockSize(uint32_t num)155 static uint32_t RoundUpToBlockSize(uint32_t num) {
156 return num % BLOCK_SIZE == 0 ? num : num + (BLOCK_SIZE - (num % BLOCK_SIZE));
157 }
158
SerializedSize() const159 size_t EncryptedSerializable::SerializedSize() const {
160 TPM2B_PUBLIC key_public;
161 TPM2B_PRIVATE key_private;
162 auto parent = parent_key_fn_(resource_manager_);
163 if (!CreateKey(
164 resource_manager_, parent->get(), &key_public, &key_private, nullptr)) {
165 LOG(ERROR) << "Unable to create key";
166 return 0;
167 }
168 // Assumes all created keys will have the same size.
169 SerializeTpmKeyPublic serialize_public(&key_public);
170 SerializeTpmKeyPrivate serialize_private(&key_private);
171 auto encrypted_size = RoundUpToBlockSize(wrapped_.SerializedSize());
172 size_t size = serialize_public.SerializedSize(); // tpm key public part
173 size += serialize_private.SerializedSize(); // tpm key private part
174 size += sizeof(uint32_t); // block size
175 size += sizeof(uint32_t); // initialization vector length
176 size += sizeof(((TPM2B_IV*)nullptr)->buffer); // initialization vector
177 size += sizeof(uint32_t); // wrapped size
178 size += encrypted_size; // encrypted data
179 return 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 TPM2B_IV iv;
199 iv.size = sizeof(iv.buffer);
200 auto rc = TpmRandomSource(resource_manager_)
201 .GenerateRandom(iv.buffer, sizeof(iv.buffer));
202 if (rc != KM_ERROR_OK) {
203 LOG(ERROR) << "Failed to get random data";
204 return buf;
205 }
206
207 auto wrapped_size = wrapped_.SerializedSize();
208 auto encrypted_size = RoundUpToBlockSize(wrapped_size);
209 std::vector<uint8_t> unencrypted(encrypted_size + 1, 0);
210 auto unencrypted_buf = unencrypted.data();
211 auto unencrypted_buf_end = unencrypted_buf + unencrypted.size();
212 auto next_buf = wrapped_.Serialize(unencrypted_buf, unencrypted_buf_end);
213 if (next_buf - unencrypted_buf != wrapped_size) {
214 LOG(ERROR) << "Size mismatch on wrapped data";
215 return buf;
216 }
217 std::vector<uint8_t> encrypted(encrypted_size, 0);
218 if (!TpmEncrypt( //
219 *resource_manager_.Esys(), key_slot->get(), TpmAuth(ESYS_TR_PASSWORD),
220 iv, unencrypted.data(), encrypted.data(), encrypted_size)) {
221 LOG(ERROR) << "Encryption failed";
222 return buf;
223 }
224 SerializeTpmKeyPublic serialize_public(&key_public);
225 SerializeTpmKeyPrivate serialize_private(&key_private);
226
227 buf = serialize_public.Serialize(buf, end);
228 buf = serialize_private.Serialize(buf, end);
229 buf = keymaster::append_uint32_to_buf(buf, end, BLOCK_SIZE);
230 buf = keymaster::append_uint32_to_buf(buf, end, iv.size);
231 buf = keymaster::append_to_buf(buf, end, iv.buffer, iv.size);
232 buf = keymaster::append_uint32_to_buf(buf, end, wrapped_size);
233 buf = keymaster::append_to_buf(buf, end, encrypted.data(), encrypted_size);
234 return buf;
235 }
236
Deserialize(const uint8_t ** buf_ptr,const uint8_t * end)237 bool EncryptedSerializable::Deserialize(
238 const uint8_t** buf_ptr, const uint8_t* end) {
239 auto parent_key = parent_key_fn_(resource_manager_);
240 if (!parent_key) {
241 LOG(ERROR) << "Unable to load encryption parent key";
242 return false;
243 }
244 TPM2B_PUBLIC key_public;
245 SerializeTpmKeyPublic serialize_public(&key_public);
246 if (!serialize_public.Deserialize(buf_ptr, end)) {
247 LOG(ERROR) << "Unable to deserialize key public part";
248 return false;
249 }
250 TPM2B_PRIVATE key_private;
251 SerializeTpmKeyPrivate serialize_private(&key_private);
252 if (!serialize_private.Deserialize(buf_ptr, end)) {
253 LOG(ERROR) << "Unable to deserialize key private part";
254 return false;
255 }
256 auto key_slot =
257 LoadKey(resource_manager_, parent_key->get(), &key_public, &key_private);
258 if (!key_slot) {
259 LOG(ERROR) << "Failed to load key into TPM";
260 return false;
261 }
262 uint32_t block_size = 0;
263 if (!keymaster::copy_uint32_from_buf(buf_ptr, end, &block_size)) {
264 LOG(ERROR) << "Failed to read block size";
265 return false;
266 }
267 if (block_size != BLOCK_SIZE) {
268 LOG(ERROR) << "Unexpected block size: was " << block_size
269 << ", expected " << BLOCK_SIZE;
270 return false;
271 }
272 uint32_t iv_size = 0;
273 if (!keymaster::copy_uint32_from_buf(buf_ptr, end, &iv_size)) {
274 LOG(ERROR) << "Failed to read iv size";
275 return false;
276 }
277 TPM2B_IV iv;
278 if (iv_size != sizeof(iv.buffer)) {
279 LOG(ERROR) << "iv size mismatch: received " << iv_size << ", expected "
280 << sizeof(iv.buffer);
281 return false;
282 }
283 iv.size = sizeof(iv.buffer);
284 if (!keymaster::copy_from_buf(buf_ptr, end, iv.buffer, sizeof(iv.buffer))) {
285 LOG(ERROR) << "Failed to read wrapped size";
286 return false;
287 }
288 uint32_t wrapped_size = 0;
289 if (!keymaster::copy_uint32_from_buf(buf_ptr, end, &wrapped_size)) {
290 LOG(ERROR) << "Failed to read wrapped size";
291 return false;
292 }
293 uint32_t encrypted_size = RoundUpToBlockSize(wrapped_size);
294 std::vector<uint8_t> encrypted_data(encrypted_size, 0);
295 if (!keymaster::copy_from_buf(
296 buf_ptr, end, encrypted_data.data(), encrypted_size)) {
297 LOG(ERROR) << "Failed to read encrypted data";
298 return false;
299 }
300 std::vector<uint8_t> decrypted_data(encrypted_size, 0);
301 if (!TpmDecrypt( //
302 *resource_manager_.Esys(), key_slot->get(), TpmAuth(ESYS_TR_PASSWORD),
303 iv, encrypted_data.data(), decrypted_data.data(), encrypted_size)) {
304 LOG(ERROR) << "Failed to decrypt encrypted data";
305 return false;
306 }
307 auto decrypted_buf = decrypted_data.data();
308 auto decrypted_buf_end = decrypted_data.data() + wrapped_size;
309 if (!wrapped_.Deserialize(
310 const_cast<const uint8_t **>(&decrypted_buf), decrypted_buf_end)) {
311 LOG(ERROR) << "Failed to deserialize wrapped type";
312 return false;
313 }
314 if (decrypted_buf != decrypted_buf_end) {
315 LOG(ERROR) << "Inner type did not use all data";
316 return false;
317 }
318 return true;
319 }
320
321 } // namespace cuttlefish
322