tz-backend: Implement symmetric encryption through TA
[platform/core/security/key-manager.git] / src / manager / crypto / tz-backend / tz-context.cpp
1 /*
2  *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
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 /*
17  * @file       tz-context.cpp
18  * @author     Lukasz Kostyra (l.kostyra@samsung.com)
19  * @version    1.0
20  */
21
22 #include <tz-backend/tz-context.h>
23 #include <tz-backend/tz-memory.h>
24 #include <generic-backend/exception.h>
25 #include <generic-backend/crypto-params.h>
26 #include <dpl/log/log.h>
27
28 #include <km_serialization.h>
29 #include <km_ta_defines.h>
30
31 #include <cstdint>
32 #include <cstring>
33
34 namespace CKM {
35 namespace Crypto {
36 namespace TZ {
37 namespace Internals {
38
39 namespace {
40
41 // A little bit of extra memory to add to output buffers.
42 //
43 // We need this extra memory to output for padding purposes - after encryption
44 // we can resize the result memory back to its proper size according to
45 // whatever TA will return us.
46 const uint32_t CIPHER_EXTRA_PADDING_SIZE = 16;
47
48 // Identifier of our TA
49 const TEEC_UUID KEY_MANAGER_TA_UUID = KM_TA_UUID;
50
51 } // anonymous namespace
52
53 TrustZoneContext::TrustZoneContext()
54         : m_ContextInitialized(false)
55         , m_SessionInitialized(false)
56 {
57         Initialize();
58 }
59
60 TrustZoneContext::~TrustZoneContext()
61 {
62         Destroy();
63 }
64
65 TrustZoneContext& TrustZoneContext::Instance()
66 {
67         static TrustZoneContext instance;
68         return instance;
69 }
70
71 void TrustZoneContext::generateIV(uint32_t ivSize, RawBuffer& iv)
72 {
73         // command ID = CMD_GENERATE_IV
74         //
75         // TEEC_Operation layout:
76         // params:
77         //   [1].memref.buffer - output
78         //   [1].memref.size - output size
79         // output:
80         //   [0].value.a - return code
81
82         // IV generation is a simple call - no need to serialize data
83         // just provide the output buffer with size equal to iv.
84         TrustZoneMemory ivMemory(m_Context, ivSize, TEEC_MEM_OUTPUT);
85
86         TEEC_Operation op;
87         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
88                                                                         TEEC_NONE, TEEC_NONE);
89         op.params[1].memref.parent = ivMemory.Get();
90         op.params[1].memref.offset = 0;
91         op.params[1].memref.size = ivMemory.Get()->size;
92         Execute(CMD_GENERATE_IV, &op);
93
94         iv.resize(ivSize);
95         memcpy(iv.data(), ivMemory.Get()->buffer, ivMemory.Get()->size);
96 }
97
98 void TrustZoneContext::generateSKey(tz_algo_type algo,
99                                                                         uint32_t keySizeBits,
100                                                                         RawBuffer &keyId)
101 {
102         // command ID = CMD_GENERATE_KEY
103         //
104         // TEEC_Operation layout:
105         // params:
106         //   [0].value.a - key type
107         //   [0].value.b - key bit size
108         // output:
109         //   [0].value.a - return code
110         //   [1].memref - serialized key reference
111
112         KM_BufferSizeDesc bufSize;
113
114         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
115         bufSize.out_size = KM_KEY_ID_SIZE;
116         uint32_t keyMemorySize = KM_CalcBufferSize(bufSize);
117         TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT);
118
119         TEEC_Operation op;
120         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
121                                                                         TEEC_NONE, TEEC_NONE);
122         op.params[0].value.a = algo;
123         op.params[0].value.b = keySizeBits;
124         op.params[1].memref.parent = keyMemory.Get();
125         op.params[1].memref.offset = 0;
126         op.params[1].memref.size = keyMemorySize;
127         Execute(CMD_GENERATE_KEY, &op);
128
129         KM_SymmetricInput* output = nullptr;
130         int ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output);
131         if (ret) {
132                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID");
133         }
134
135         KM_OutData* outData = nullptr;
136         ret = KM_ParamsDeserializeOutData(output, &outData);
137         if (ret) {
138                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID");
139         }
140
141         if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) {
142                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID");
143         }
144
145         keyId.resize(KM_KEY_ID_SIZE);
146         memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE);
147 }
148
149 void TrustZoneContext::generateSKeyPwd(tz_algo_type algo,
150                                                                         const RawBuffer &pwd,
151                                                                         const RawBuffer &iv,
152                                                                         const uint32_t keySizeBits,
153                                                                         const uint32_t pwdTagSizeBits,
154                                                                         RawBuffer &keyId,
155                                                                         RawBuffer &pwdTag)
156 {
157         // command ID = CMD_GENERATE_KEY_PWD
158         //
159         // TEEC_Operation layout:
160         // params:
161         //   [0].value.a - key type
162         //   [0].value.b - key size in bits
163         //   [1].memref  - input (seralized pwd/iv for pbkdf2)
164         // output:
165         //   [0].value.a - return code
166         //   [2].memref - serialized key reference ID
167
168         KM_BufferSizeDesc bufSize;
169
170         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
171         bufSize.with_pwd_data = true;
172         bufSize.pwd_size = static_cast<uint32_t>(pwd.size());
173         bufSize.pwd_iv_size = static_cast<uint32_t>(iv.size());
174         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
175         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
176
177         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
178         bufSize.out_size = KM_KEY_ID_SIZE;
179         bufSize.tag_size = pwdTagSizeBits / 8;
180         uint32_t keyMemorySize = KM_CalcBufferSize(bufSize);
181         TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT);
182
183         KM_SymmetricInput* input = nullptr;
184         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
185         if (ret) {
186                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
187         }
188
189         ret = KM_ParamsSerializePwdData(input, pwd.data(), pwd.size(), iv.data(), iv.size(),
190                                                                         nullptr, 0, Params::DERIVED_KEY_LENGTH_BITS,
191                                                                         Params::DERIVED_KEY_ITERATIONS, pwdTagSizeBits);
192         if (ret) {
193                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
194         }
195
196         TEEC_Operation op;
197         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
198                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
199         op.params[0].value.a = algo;
200         op.params[0].value.b = keySizeBits;
201         op.params[1].memref.parent = inMemory.Get();
202         op.params[1].memref.offset = 0;
203         op.params[1].memref.size = inMemory.Get()->size;
204         op.params[2].memref.parent = keyMemory.Get();
205         op.params[2].memref.offset = 0;
206         op.params[2].memref.size = keyMemory.Get()->size;
207         Execute(CMD_GENERATE_KEY_PWD, &op);
208
209         KM_SymmetricInput* output = nullptr;
210         ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output);
211         if (ret) {
212                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID");
213         }
214
215         KM_OutData* outData = nullptr;
216         ret = KM_ParamsDeserializeOutData(output, &outData);
217         if (ret) {
218                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID");
219         }
220
221         KM_TagData* tagData = nullptr;
222         ret = KM_ParamsDeserializeTagData(output, &tagData);
223         if (ret) {
224                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize key's tag");
225         }
226
227         if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) {
228                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID");
229         }
230
231         if (tagData == nullptr || tagData->data_size != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) {
232                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag");
233         }
234
235         keyId.resize(KM_KEY_ID_SIZE);
236         memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE);
237
238         pwdTag.resize(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES);
239         memcpy(pwdTag.data(), tagData->data, Params::DEFAULT_AES_GCM_TAG_LEN_BYTES);
240 }
241
242
243 void TrustZoneContext::importKey(tz_algo_type algo,
244                                                                 const RawBuffer &key,
245                                                                 const RawBuffer &pwd,
246                                                                 const RawBuffer &iv,
247                                                                 const uint32_t keySizeBits,
248                                                                 const uint32_t pwdTagSizeBits,
249                                                                 RawBuffer &keyId,
250                                                                 RawBuffer &pwdTag)
251 {
252         // command ID = CMD_IMPORT_KEY
253         //
254         // TEEC_Operation layout:
255         // params:
256         //   [0].value.a - key type
257         //   [0].value.b - key size in bits
258         //   [1].memref  - seralized key & password data
259         // output:
260         //   [0].value.a - return code
261         //   [2].memref - serialized key reference ID
262
263         KM_BufferSizeDesc bufSize;
264
265         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
266         bufSize.input_size = static_cast<uint32_t>(key.size());
267         if (!pwd.empty()) {
268                 bufSize.with_pwd_data = true;
269                 bufSize.pwd_size = static_cast<uint32_t>(pwd.size());
270                 bufSize.pwd_iv_size = static_cast<uint32_t>(iv.size());
271         }
272         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
273         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
274
275         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
276         bufSize.out_size = KM_KEY_ID_SIZE;
277         bufSize.tag_size = pwdTagSizeBits / 8;
278         uint32_t keyMemorySize = KM_CalcBufferSize(bufSize);
279         TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT);
280
281         KM_SymmetricInput* input = nullptr;
282         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
283         if (ret) {
284                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for key import: ", ret);
285         }
286
287         ret = KM_ParamsSerializeInputData(input, key.data(), key.size());
288         if (ret) {
289                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key to import: ", ret);
290         }
291
292         if (!pwd.empty()) {
293                 ret = KM_ParamsSerializePwdData(input, pwd.data(), pwd.size(), iv.data(), iv.size(),
294                                                                                 nullptr, 0, Params::DERIVED_KEY_LENGTH_BITS,
295                                                                                 Params::DERIVED_KEY_ITERATIONS, pwdTagSizeBits);
296                 if (ret) {
297                         ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key data for import: ", ret);
298                 }
299         }
300
301         TEEC_Operation op;
302         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
303                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
304         op.params[0].value.a = algo;
305         op.params[0].value.b = keySizeBits;
306         op.params[1].memref.parent = inMemory.Get();
307         op.params[1].memref.offset = 0;
308         op.params[1].memref.size = inMemory.Get()->size;
309         op.params[2].memref.parent = keyMemory.Get();
310         op.params[2].memref.offset = 0;
311         op.params[2].memref.size = keyMemory.Get()->size;
312         Execute(CMD_IMPORT_KEY, &op);
313
314         KM_SymmetricInput* output = nullptr;
315         ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output);
316         if (ret) {
317                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for imported key ID");
318         }
319
320         KM_OutData* outData = nullptr;
321         ret = KM_ParamsDeserializeOutData(output, &outData);
322         if (ret) {
323                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize imported key ID");
324         }
325
326         if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) {
327                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID");
328         }
329
330         keyId.resize(KM_KEY_ID_SIZE);
331         memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE);
332
333         if (!pwd.empty()) {
334                 KM_TagData* tagData = nullptr;
335                 uint32_t pwdTagSizeBytes = pwdTagSizeBits / 8;
336
337                 ret = KM_ParamsDeserializeTagData(output, &tagData);
338                 if (ret) {
339                         ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize imported key's tag");
340                 }
341
342                 if (tagData == nullptr || tagData->data_size != pwdTagSizeBytes) {
343                         ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag");
344                 }
345
346                 pwdTag.resize(pwdTagSizeBytes);
347                 memcpy(pwdTag.data(), tagData->data, pwdTagSizeBytes);
348         }
349 }
350
351 void TrustZoneContext::executeCrypt(tz_command cmd,
352                                                                         tz_algo_type algo,
353                                                                         const RawBuffer &key,
354                                                                         const Pwd &pwd,
355                                                                         const RawBuffer &iv,
356                                                                         const RawBuffer &data,
357                                                                         RawBuffer &out)
358 {
359         // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
360         //
361         // TEEC_Operation layout:
362         // params:
363         //   [0].value.a - keyid
364         //   [0].value.b - algo
365         //   [1].memref - input data (serialized key/input)
366         // returned:
367         //   [0].value.a - return code
368         //   [2].memref - serialized output buffer
369
370         if (key.size() != KM_KEY_ID_SIZE) {
371                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
372                         + std::to_string(key.size()) + ")");
373         }
374
375         KM_BufferSizeDesc bufSize;
376
377         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
378         bufSize.input_size = static_cast<uint32_t>(data.size());
379         bufSize.with_pwd_data = true;
380         bufSize.pwd_size = static_cast<uint32_t>(pwd.getPassword().size());
381         bufSize.pwd_iv_size = static_cast<uint32_t>(pwd.getIV().size());
382         bufSize.pwd_tag_size = static_cast<uint32_t>(pwd.getTag().size());
383         bufSize.iv_size = static_cast<uint32_t>(iv.size());
384         bufSize.key_id_size = static_cast<uint32_t>(key.size());
385         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
386         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
387
388         // decrypt operation does not require padding
389         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
390         bufSize.out_size = static_cast<uint32_t>((cmd == CMD_ENCRYPT) ?
391                                                         data.size() + CIPHER_EXTRA_PADDING_SIZE :
392                                                         data.size());
393         uint32_t outMemorySize = KM_CalcBufferSize(bufSize);
394         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
395
396         KM_SymmetricInput* input = nullptr;
397         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
398         if (ret) {
399                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
400         }
401
402         ret = KM_ParamsSerializeInputData(input, data.data(), data.size());
403         if (ret) {
404                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret);
405         }
406
407         uint32_t pwdTagSizeBits = pwd.getTag().size() * 8;
408         ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(),
409                                                                         pwd.getIV().data(), pwd.getIV().size(),
410                                                                         pwd.getTag().data(), pwd.getTag().size(),
411                                                                         Params::DERIVED_KEY_LENGTH_BITS,
412                                                                         Params::DERIVED_KEY_ITERATIONS,
413                                                                         pwdTagSizeBits);
414         if (ret) {
415                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
416         }
417
418         ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size());
419         if (ret) {
420                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret);
421         }
422
423         ret = KM_ParamsSerializeKeyId(input, key.data(), key.size());
424         if (ret) {
425                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret);
426         }
427
428         TEEC_Operation op;
429         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
430                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
431         op.params[0].value.a = algo;
432         op.params[1].memref.parent = inMemory.Get();
433         op.params[1].memref.offset = 0;
434         op.params[1].memref.size = inMemory.Get()->size;
435         op.params[2].memref.parent = outMemory.Get();
436         op.params[2].memref.offset = 0;
437         op.params[2].memref.size = outMemory.Get()->size;
438         Execute(cmd, &op);
439
440         KM_SymmetricInput* output = nullptr;
441         ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output);
442         if (ret) {
443                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret);
444         }
445
446         KM_OutData* outData = nullptr;
447         ret = KM_ParamsDeserializeOutData(output, &outData);
448         if (ret) {
449                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret);
450         }
451
452         // data_size should contain how much memory we actually took for our cipher operation
453         out.resize(outData->data_size);
454         memcpy(out.data(), outData->data, outData->data_size);
455 }
456
457 void TrustZoneContext::executeEncryptAE(const RawBuffer &key,
458                                                                                 const Pwd &pwd,
459                                                                                 const RawBuffer &iv,
460                                                                                 int tagSizeBits,
461                                                                                 const RawBuffer &aad,
462                                                                                 const RawBuffer &data,
463                                                                                 RawBuffer &out,
464                                                                                 RawBuffer &tag)
465 {
466         // command ID = CMD_ENCRYPT (from km_ta_defines.h)
467         //
468         // TEEC_Operation layout:
469         // params:
470         //   [0].value.a - keyid
471         //   [0].value.b - algo
472         //   [1].memref - input data (serialized key/input/iv/aad)
473         // returned:
474         //   [0].value.a - return code
475         //   [2].memref - output
476
477         if (key.size() != KM_KEY_ID_SIZE) {
478                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
479         }
480
481         uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
482         KM_BufferSizeDesc bufSize;
483
484         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
485         bufSize.input_size = static_cast<uint32_t>(data.size());
486         bufSize.with_pwd_data = true;
487         bufSize.pwd_size = static_cast<uint32_t>(pwd.getPassword().size());
488         bufSize.pwd_iv_size = static_cast<uint32_t>(pwd.getIV().size());
489         bufSize.pwd_tag_size = static_cast<uint32_t>(pwd.getTag().size());
490         bufSize.iv_size = static_cast<uint32_t>(iv.size());
491         bufSize.key_id_size = static_cast<uint32_t>(key.size());
492         bufSize.with_ae_data = true;
493         bufSize.aad_size = static_cast<uint32_t>(aad.size());
494         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
495         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
496
497         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
498         bufSize.out_size = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
499         bufSize.tag_size = static_cast<uint32_t>(tagSizeBytes);
500         uint32_t outMemorySize = KM_CalcBufferSize(bufSize);
501         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
502
503         KM_SymmetricInput* input = nullptr;
504         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
505         if (ret) {
506                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
507         }
508
509         ret = KM_ParamsSerializeInputData(input, data.data(), data.size());
510         if (ret) {
511                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret);
512         }
513
514         uint32_t pwdTagSizeBits = pwd.getTag().size() * 8;
515         ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(),
516                                                                         pwd.getIV().data(), pwd.getIV().size(),
517                                                                         pwd.getTag().data(), pwd.getTag().size(),
518                                                                         Params::DERIVED_KEY_LENGTH_BITS,
519                                                                         Params::DERIVED_KEY_ITERATIONS,
520                                                                         pwdTagSizeBits);
521         if (ret) {
522                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
523         }
524
525         ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size());
526         if (ret) {
527                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret);
528         }
529
530         ret = KM_ParamsSerializeKeyId(input, key.data(), key.size());
531         if (ret) {
532                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret);
533         }
534
535         ret = KM_ParamsSerializeAEData(input, tagSizeBits, 0, aad.data(), aad.size());
536         if (ret) {
537                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize auth data for TZ crypto operation: ", ret);
538         }
539
540         TEEC_Operation op;
541         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
542                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
543         op.params[0].value.a = ALGO_AES_GCM;
544         op.params[1].memref.parent = inMemory.Get();
545         op.params[1].memref.offset = 0;
546         op.params[1].memref.size = inMemory.Get()->size;
547         op.params[2].memref.parent = outMemory.Get();
548         op.params[2].memref.offset = 0;
549         op.params[2].memref.size = outMemory.Get()->size;
550         Execute(CMD_ENCRYPT, &op);
551
552         KM_SymmetricInput* output = nullptr;
553         ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output);
554         if (ret) {
555                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret);
556         }
557
558         KM_OutData* outData = nullptr;
559         ret = KM_ParamsDeserializeOutData(output, &outData);
560         if (ret) {
561                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret);
562         }
563
564         KM_TagData* tagData = nullptr;
565         ret = KM_ParamsDeserializeTagData(output, &tagData);
566         if (ret) {
567                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize tag data: ", ret);
568         }
569
570         out.resize(outData->data_size);
571         memcpy(out.data(), outData->data, outData->data_size);
572
573         if (tagData->data_size) {
574                 tag.resize(tagData->data_size);
575                 memcpy(tag.data(), tagData->data, tagData->data_size);
576         }
577 }
578
579 void TrustZoneContext::executeDecryptAE(const RawBuffer &key,
580                                                                                 const Pwd &pwd,
581                                                                                 const RawBuffer &iv,
582                                                                                 int tagSizeBits,
583                                                                                 const RawBuffer &tag,
584                                                                                 const RawBuffer &aad,
585                                                                                 const RawBuffer &data,
586                                                                                 RawBuffer &out)
587 {
588         // command ID = CMD_DECRYPT (from km_ta_defines.h)
589         //
590         // TEEC_Operation layout:
591         // params:
592         //   [0].value.a - keyid
593         //   [0].value.b - algo
594         //   [1].memref - input data (serialized key/input/iv/tag/aad)
595         // returned:
596         //   [0].value.a - output size
597         //   [2].memref - output (decrypted data)
598
599         if (key.size() != KM_KEY_ID_SIZE) {
600                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
601         }
602
603         KM_BufferSizeDesc bufSize;
604
605         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
606         bufSize.input_size = static_cast<uint32_t>(data.size());
607         bufSize.with_pwd_data = true;
608         bufSize.pwd_size = static_cast<uint32_t>(pwd.getPassword().size());
609         bufSize.pwd_iv_size = static_cast<uint32_t>(pwd.getIV().size());
610         bufSize.pwd_tag_size = static_cast<uint32_t>(pwd.getTag().size());
611         bufSize.iv_size = static_cast<uint32_t>(iv.size());
612         bufSize.key_id_size = static_cast<uint32_t>(key.size());
613         bufSize.with_ae_data = true;
614         bufSize.aad_size = static_cast<uint32_t>(aad.size());
615         bufSize.tag_size = static_cast<uint32_t>(tag.size());
616         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
617         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
618
619         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
620         bufSize.out_size = static_cast<uint32_t>(data.size());
621         uint32_t outMemorySize = KM_CalcBufferSize(bufSize);
622         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
623
624         KM_SymmetricInput* input = nullptr;
625         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
626         if (ret) {
627                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
628         }
629
630         ret = KM_ParamsSerializeInputData(input, data.data(), data.size());
631         if (ret) {
632                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret);
633         }
634
635         uint32_t pwdTagSizeBits = pwd.getTag().size() * 8;
636         ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(),
637                                                                         pwd.getIV().data(), pwd.getIV().size(),
638                                                                         pwd.getTag().data(), pwd.getTag().size(),
639                                                                         Params::DERIVED_KEY_LENGTH_BITS,
640                                                                         Params::DERIVED_KEY_ITERATIONS,
641                                                                         pwdTagSizeBits);
642         if (ret) {
643                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
644         }
645
646         ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size());
647         if (ret) {
648                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret);
649         }
650
651         ret = KM_ParamsSerializeKeyId(input, key.data(), key.size());
652         if (ret) {
653                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret);
654         }
655
656         ret = KM_ParamsSerializeAEData(input, tagSizeBits, 0, aad.data(), aad.size());
657         if (ret) {
658                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize auth data for TZ crypto operation: ", ret);
659         }
660
661         ret = KM_ParamsSerializeTagData(input, tag.data(), tag.size());
662         if (ret) {
663                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize tag data for TZ crypto operation: ", ret);
664         }
665
666         TEEC_Operation op;
667         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
668                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
669         op.params[0].value.a = ALGO_AES_GCM;
670         op.params[1].memref.parent = inMemory.Get();
671         op.params[1].memref.offset = 0;
672         op.params[1].memref.size = inMemory.Get()->size;
673         op.params[2].memref.parent = outMemory.Get();
674         op.params[2].memref.offset = 0;
675         op.params[2].memref.size = outMemory.Get()->size;
676         Execute(CMD_DECRYPT, &op);
677
678         KM_SymmetricInput* output = nullptr;
679         ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output);
680         if (ret) {
681                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret);
682         }
683
684         KM_OutData* outData = nullptr;
685         ret = KM_ParamsDeserializeOutData(output, &outData);
686         if (ret) {
687                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret);
688         }
689
690         out.resize(outData->data_size);
691         memcpy(out.data(), outData->data, outData->data_size);
692 }
693
694 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
695 {
696         // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
697         //
698         // TEEC_Operation layout:
699         // input params:
700         //   [1].memref - input data (serialized key ID)
701         // output params:
702         //   [0].value.a - return code
703
704         if (keyId.size() != KM_KEY_ID_SIZE) {
705                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
706         }
707
708         KM_BufferSizeDesc bufSize;
709
710         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
711         bufSize.key_id_size = static_cast<uint32_t>(keyId.size());
712         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
713         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
714
715         KM_SymmetricInput* input = nullptr;
716         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
717         if (ret) {
718                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization: ", ret);
719         }
720
721         ret = KM_ParamsSerializeInputData(input, keyId.data(), keyId.size());
722         if (ret) {
723                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key ID to destroy: ", ret);
724         }
725
726         TEEC_Operation op;
727         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE,
728                                                                         TEEC_NONE, TEEC_NONE);
729         op.params[1].memref.parent = inMemory.Get();
730         op.params[1].memref.offset = 0;
731         op.params[1].memref.size = inMemory.Get()->size;
732         Execute(CMD_DESTROY_KEY, &op);
733 }
734
735 void TrustZoneContext::Initialize()
736 {
737         TEEC_Operation op;
738         TEEC_Result result;
739         uint32_t retOrigin;
740
741         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
742
743         result = TEEC_InitializeContext(nullptr, &m_Context);
744         if (result != TEEC_SUCCESS) {
745                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
746         }
747         m_ContextInitialized = true;
748
749         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
750         if (result != TEEC_SUCCESS) {
751                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
752         }
753         m_SessionInitialized = true;
754 }
755
756 void TrustZoneContext::Destroy()
757 {
758         if (m_SessionInitialized) {
759                 TEEC_CloseSession(&m_Session);
760                 m_SessionInitialized = false;
761         }
762
763         if (m_ContextInitialized) {
764                 TEEC_FinalizeContext(&m_Context);
765                 m_ContextInitialized = false;
766         }
767 }
768
769 void TrustZoneContext::Reload()
770 {
771         Destroy();
772         Initialize();
773 }
774
775 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
776 {
777         LogDebug("Executing TZ operation " << commandID);
778
779         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, NULL);
780         if (result != TEEC_SUCCESS) {
781                 switch (result) {
782                 case TEEC_ERROR_TARGET_DEAD:
783                         Reload();
784                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
785                                         static_cast<unsigned int>(commandID));
786                 case TEEC_ERROR_BAD_PARAMETERS:
787                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
788                 default:
789                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
790                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
791                                         static_cast<unsigned int>(result));
792                 }
793         }
794
795         int ta_ret = op->params[0].value.a;
796         if (ta_ret != KM_TA_SUCCESS) {
797                 switch (ta_ret) {
798                 case KM_TA_ERROR_AUTH_FAILED:
799                         // Authentication cipher failed - notify with proper exception
800                         ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
801                 default:
802                         ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
803                 }
804         }
805 }
806
807 } // namespace Internals
808 } // namespace TZ
809 } // namespace Crypto
810 } // namespace CKM