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