Reduce number of import methods in tz-backend
[platform/core/security/key-manager.git] / src / manager / crypto / tz-backend / tz-context.cpp
1 /*
2  *  Copyright (c) 2017 - 2018 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 //raw to hex string conversion to print persistent storage data ID
52 static std::string rawToHexString(const RawBuffer &raw)
53 {
54         std::string dump;
55
56         for (auto &e : raw) {
57                 char buf[3];
58                 snprintf(buf, sizeof(buf), "%02x", (e & 0xff));
59                 dump.push_back(buf[0]);
60                 dump.push_back(buf[1]);
61         }
62
63         return dump;
64 }
65
66 } // anonymous namespace
67
68 TrustZoneContext::TrustZoneContext()
69         : m_ContextInitialized(false)
70         , m_SessionInitialized(false)
71 {
72         Initialize();
73 }
74
75 TrustZoneContext::~TrustZoneContext()
76 {
77         Destroy();
78 }
79
80 TrustZoneContext& TrustZoneContext::Instance()
81 {
82         static TrustZoneContext instance;
83         return instance;
84 }
85
86 void TrustZoneContext::generateIV(RawBuffer& iv)
87 {
88         // command ID = CMD_GENERATE_IV
89         //
90         // TEEC_Operation layout:
91         // params:
92         //   [1].memref.buffer - output
93         //   [1].memref.size - output size
94         // output:
95         //   [0].value.a - return code
96
97         // IV generation is a simple call - no need to serialize data
98         // just provide the output buffer with size equal to iv.
99         uint32_t ivSize = Params::DEFAULT_AES_IV_LEN;
100         TrustZoneMemory ivMemory(m_Context, ivSize, TEEC_MEM_OUTPUT);
101
102         TEEC_Operation op;
103         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
104                                                                         TEEC_NONE, TEEC_NONE);
105         op.params[1].memref.parent = ivMemory.Get();
106         op.params[1].memref.offset = 0;
107         op.params[1].memref.size = ivMemory.Get()->size;
108         Execute(CMD_GENERATE_IV, &op);
109
110         iv.resize(ivSize);
111         memcpy(iv.data(), ivMemory.Get()->buffer, ivMemory.Get()->size);
112 }
113
114 void TrustZoneContext::generateSKey(tz_algo_type algo,
115                                                                         uint32_t keySizeBits,
116                                                                         RawBuffer &keyId)
117 {
118         // command ID = CMD_GENERATE_KEY
119         //
120         // TEEC_Operation layout:
121         // params:
122         //   [0].value.a - key type
123         //   [0].value.b - key bit size
124         // output:
125         //   [0].value.a - return code
126         //   [1].memref - serialized key reference
127
128         KM_BufferSizeDesc bufSize;
129
130         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
131         bufSize.out_size = KM_KEY_ID_SIZE;
132         uint32_t keyMemorySize = KM_CalcBufferSize(bufSize);
133         TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT);
134
135         TEEC_Operation op;
136         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
137                                                                         TEEC_NONE, TEEC_NONE);
138         op.params[0].value.a = algo;
139         op.params[0].value.b = keySizeBits;
140         op.params[1].memref.parent = keyMemory.Get();
141         op.params[1].memref.offset = 0;
142         op.params[1].memref.size = keyMemorySize;
143         Execute(CMD_GENERATE_KEY, &op);
144
145         KM_SymmetricInput* output = nullptr;
146         int ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output);
147         if (ret) {
148                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID");
149         }
150
151         KM_OutData* outData = nullptr;
152         ret = KM_ParamsDeserializeOutData(output, &outData);
153         if (ret) {
154                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID");
155         }
156
157         if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) {
158                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID");
159         }
160
161         keyId.resize(KM_KEY_ID_SIZE);
162         memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE);
163 }
164
165 void TrustZoneContext::generateSKeyPwd(tz_algo_type algo,
166                                                                         const RawBuffer &pwd,
167                                                                         const RawBuffer &iv,
168                                                                         const uint32_t keySizeBits,
169                                                                         RawBuffer &keyId,
170                                                                         RawBuffer &pwdTag)
171 {
172         // command ID = CMD_GENERATE_KEY_PWD
173         //
174         // TEEC_Operation layout:
175         // params:
176         //   [0].value.a - key type
177         //   [0].value.b - key size in bits
178         //   [1].memref  - input (seralized pwd/iv for pbkdf2)
179         // output:
180         //   [0].value.a - return code
181         //   [2].memref - serialized key reference ID
182
183         KM_BufferSizeDesc bufSize;
184
185         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
186         bufSize.with_pwd_data = true;
187         bufSize.pwd_size = static_cast<uint32_t>(pwd.size());
188         bufSize.pwd_iv_size = static_cast<uint32_t>(iv.size());
189         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
190         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
191
192         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
193         bufSize.out_size = KM_KEY_ID_SIZE;
194         bufSize.tag_size = Params::DEFAULT_AES_GCM_TAG_LEN_BYTES;
195         uint32_t keyMemorySize = KM_CalcBufferSize(bufSize);
196         TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT);
197
198         KM_SymmetricInput* input = nullptr;
199         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
200         if (ret) {
201                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
202         }
203
204         ret = KM_ParamsSerializePwdData(input, pwd.data(), pwd.size(), iv.data(), iv.size(),
205                                                                         nullptr, 0, Params::DERIVED_KEY_LENGTH_BITS,
206                                                                         Params::DERIVED_KEY_ITERATIONS, bufSize.tag_size * 8);
207         if (ret) {
208                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
209         }
210
211         TEEC_Operation op;
212         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
213                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
214         op.params[0].value.a = algo;
215         op.params[0].value.b = keySizeBits;
216         op.params[1].memref.parent = inMemory.Get();
217         op.params[1].memref.offset = 0;
218         op.params[1].memref.size = inMemory.Get()->size;
219         op.params[2].memref.parent = keyMemory.Get();
220         op.params[2].memref.offset = 0;
221         op.params[2].memref.size = keyMemory.Get()->size;
222         Execute(CMD_GENERATE_KEY_PWD, &op);
223
224         KM_SymmetricInput* output = nullptr;
225         ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output);
226         if (ret) {
227                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID");
228         }
229
230         KM_OutData* outData = nullptr;
231         ret = KM_ParamsDeserializeOutData(output, &outData);
232         if (ret) {
233                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID");
234         }
235
236         KM_TagData* tagData = nullptr;
237         ret = KM_ParamsDeserializeTagData(output, &tagData);
238         if (ret) {
239                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize key's tag");
240         }
241
242         if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) {
243                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID");
244         }
245
246         if (tagData == nullptr || tagData->data_size != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) {
247                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag");
248         }
249
250         keyId.resize(KM_KEY_ID_SIZE);
251         memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE);
252
253         pwdTag.resize(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES);
254         memcpy(pwdTag.data(), tagData->data, Params::DEFAULT_AES_GCM_TAG_LEN_BYTES);
255 }
256
257 void TrustZoneContext::executeCrypt(tz_command cmd,
258                                                                         tz_algo_type algo,
259                                                                         const RawBuffer &key,
260                                                                         const Pwd &pwd,
261                                                                         const RawBuffer &iv,
262                                                                         const RawBuffer &data,
263                                                                         RawBuffer &out)
264 {
265         // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
266         //
267         // TEEC_Operation layout:
268         // params:
269         //   [0].value.a - keyid
270         //   [0].value.b - algo
271         //   [1].memref - input data (serialized key/input)
272         // returned:
273         //   [0].value.a - return code
274         //   [2].memref - serialized output buffer
275
276         if (key.size() != KM_KEY_ID_SIZE) {
277                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
278                         + std::to_string(key.size()) + ")");
279         }
280
281         KM_BufferSizeDesc bufSize;
282
283         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
284         bufSize.input_size = static_cast<uint32_t>(data.size());
285         bufSize.with_pwd_data = true;
286         bufSize.pwd_size = static_cast<uint32_t>(pwd.getPassword().size());
287         bufSize.pwd_iv_size = static_cast<uint32_t>(pwd.getIV().size());
288         bufSize.pwd_tag_size = static_cast<uint32_t>(pwd.getTag().size());
289         bufSize.iv_size = static_cast<uint32_t>(iv.size());
290         bufSize.key_id_size = static_cast<uint32_t>(key.size());
291         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
292         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
293
294         // decrypt operation does not require padding
295         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
296         bufSize.out_size = static_cast<uint32_t>((cmd == CMD_ENCRYPT) ?
297                                                         data.size() + CIPHER_EXTRA_PADDING_SIZE :
298                                                         data.size());
299         uint32_t outMemorySize = KM_CalcBufferSize(bufSize);
300         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
301
302         KM_SymmetricInput* input = nullptr;
303         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
304         if (ret) {
305                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
306         }
307
308         ret = KM_ParamsSerializeInputData(input, data.data(), data.size());
309         if (ret) {
310                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret);
311         }
312
313         uint32_t pwdTagSizeBits = pwd.getTag().size() * 8;
314         ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(),
315                                                                         pwd.getIV().data(), pwd.getIV().size(),
316                                                                         pwd.getTag().data(), pwd.getTag().size(),
317                                                                         Params::DERIVED_KEY_LENGTH_BITS,
318                                                                         Params::DERIVED_KEY_ITERATIONS,
319                                                                         pwdTagSizeBits);
320         if (ret) {
321                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
322         }
323
324         ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size());
325         if (ret) {
326                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret);
327         }
328
329         ret = KM_ParamsSerializeKeyId(input, key.data(), key.size());
330         if (ret) {
331                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret);
332         }
333
334         TEEC_Operation op;
335         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
336                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
337         op.params[0].value.a = algo;
338         op.params[1].memref.parent = inMemory.Get();
339         op.params[1].memref.offset = 0;
340         op.params[1].memref.size = inMemory.Get()->size;
341         op.params[2].memref.parent = outMemory.Get();
342         op.params[2].memref.offset = 0;
343         op.params[2].memref.size = outMemory.Get()->size;
344         Execute(cmd, &op);
345
346         KM_SymmetricInput* output = nullptr;
347         ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output);
348         if (ret) {
349                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret);
350         }
351
352         KM_OutData* outData = nullptr;
353         ret = KM_ParamsDeserializeOutData(output, &outData);
354         if (ret) {
355                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret);
356         }
357
358         // data_size should contain how much memory we actually took for our cipher operation
359         out.resize(outData->data_size);
360         memcpy(out.data(), outData->data, outData->data_size);
361 }
362
363 void TrustZoneContext::executeEncryptAE(const RawBuffer &key,
364                                                                                 const Pwd &pwd,
365                                                                                 const RawBuffer &iv,
366                                                                                 int tagSizeBits,
367                                                                                 const RawBuffer &aad,
368                                                                                 const RawBuffer &data,
369                                                                                 RawBuffer &out,
370                                                                                 RawBuffer &tag)
371 {
372         // command ID = CMD_ENCRYPT (from km_ta_defines.h)
373         //
374         // TEEC_Operation layout:
375         // params:
376         //   [0].value.a - keyid
377         //   [0].value.b - algo
378         //   [1].memref - input data (serialized key/input/iv/aad)
379         // returned:
380         //   [0].value.a - return code
381         //   [2].memref - output
382
383         if (key.size() != KM_KEY_ID_SIZE) {
384                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
385         }
386
387         uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
388         KM_BufferSizeDesc bufSize;
389
390         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
391         bufSize.input_size = static_cast<uint32_t>(data.size());
392         bufSize.with_pwd_data = true;
393         bufSize.pwd_size = static_cast<uint32_t>(pwd.getPassword().size());
394         bufSize.pwd_iv_size = static_cast<uint32_t>(pwd.getIV().size());
395         bufSize.pwd_tag_size = static_cast<uint32_t>(pwd.getTag().size());
396         bufSize.iv_size = static_cast<uint32_t>(iv.size());
397         bufSize.key_id_size = static_cast<uint32_t>(key.size());
398         bufSize.with_ae_data = true;
399         bufSize.aad_size = static_cast<uint32_t>(aad.size());
400         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
401         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
402
403         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
404         bufSize.out_size = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
405         bufSize.tag_size = static_cast<uint32_t>(tagSizeBytes);
406         uint32_t outMemorySize = KM_CalcBufferSize(bufSize);
407         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
408
409         KM_SymmetricInput* input = nullptr;
410         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
411         if (ret) {
412                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
413         }
414
415         ret = KM_ParamsSerializeInputData(input, data.data(), data.size());
416         if (ret) {
417                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret);
418         }
419
420         uint32_t pwdTagSizeBits = pwd.getTag().size() * 8;
421         ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(),
422                                                                         pwd.getIV().data(), pwd.getIV().size(),
423                                                                         pwd.getTag().data(), pwd.getTag().size(),
424                                                                         Params::DERIVED_KEY_LENGTH_BITS,
425                                                                         Params::DERIVED_KEY_ITERATIONS,
426                                                                         pwdTagSizeBits);
427         if (ret) {
428                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
429         }
430
431         ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size());
432         if (ret) {
433                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret);
434         }
435
436         ret = KM_ParamsSerializeKeyId(input, key.data(), key.size());
437         if (ret) {
438                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret);
439         }
440
441         ret = KM_ParamsSerializeAEData(input, tagSizeBits, 0, aad.data(), aad.size());
442         if (ret) {
443                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize auth data for TZ crypto operation: ", ret);
444         }
445
446         TEEC_Operation op;
447         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
448                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
449         op.params[0].value.a = ALGO_AES_GCM;
450         op.params[1].memref.parent = inMemory.Get();
451         op.params[1].memref.offset = 0;
452         op.params[1].memref.size = inMemory.Get()->size;
453         op.params[2].memref.parent = outMemory.Get();
454         op.params[2].memref.offset = 0;
455         op.params[2].memref.size = outMemory.Get()->size;
456         Execute(CMD_ENCRYPT, &op);
457
458         KM_SymmetricInput* output = nullptr;
459         ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output);
460         if (ret) {
461                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret);
462         }
463
464         KM_OutData* outData = nullptr;
465         ret = KM_ParamsDeserializeOutData(output, &outData);
466         if (ret) {
467                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret);
468         }
469
470         KM_TagData* tagData = nullptr;
471         ret = KM_ParamsDeserializeTagData(output, &tagData);
472         if (ret) {
473                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize tag data: ", ret);
474         }
475
476         out.resize(outData->data_size);
477         memcpy(out.data(), outData->data, outData->data_size);
478
479         if (tagData->data_size) {
480                 tag.resize(tagData->data_size);
481                 memcpy(tag.data(), tagData->data, tagData->data_size);
482         }
483 }
484
485 void TrustZoneContext::executeDecryptAE(const RawBuffer &key,
486                                                                                 const Pwd &pwd,
487                                                                                 const RawBuffer &iv,
488                                                                                 int tagSizeBits,
489                                                                                 const RawBuffer &tag,
490                                                                                 const RawBuffer &aad,
491                                                                                 const RawBuffer &data,
492                                                                                 RawBuffer &out)
493 {
494         // command ID = CMD_DECRYPT (from km_ta_defines.h)
495         //
496         // TEEC_Operation layout:
497         // params:
498         //   [0].value.a - keyid
499         //   [0].value.b - algo
500         //   [1].memref - input data (serialized key/input/iv/tag/aad)
501         // returned:
502         //   [0].value.a - output size
503         //   [2].memref - output (decrypted data)
504
505         if (key.size() != KM_KEY_ID_SIZE) {
506                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
507         }
508
509         KM_BufferSizeDesc bufSize;
510
511         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
512         bufSize.input_size = static_cast<uint32_t>(data.size());
513         bufSize.with_pwd_data = true;
514         bufSize.pwd_size = static_cast<uint32_t>(pwd.getPassword().size());
515         bufSize.pwd_iv_size = static_cast<uint32_t>(pwd.getIV().size());
516         bufSize.pwd_tag_size = static_cast<uint32_t>(pwd.getTag().size());
517         bufSize.iv_size = static_cast<uint32_t>(iv.size());
518         bufSize.key_id_size = static_cast<uint32_t>(key.size());
519         bufSize.with_ae_data = true;
520         bufSize.aad_size = static_cast<uint32_t>(aad.size());
521         bufSize.tag_size = static_cast<uint32_t>(tag.size());
522         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
523         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
524
525         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
526         bufSize.out_size = static_cast<uint32_t>(data.size());
527         uint32_t outMemorySize = KM_CalcBufferSize(bufSize);
528         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
529
530         KM_SymmetricInput* input = nullptr;
531         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
532         if (ret) {
533                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations");
534         }
535
536         ret = KM_ParamsSerializeInputData(input, data.data(), data.size());
537         if (ret) {
538                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret);
539         }
540
541         uint32_t pwdTagSizeBits = pwd.getTag().size() * 8;
542         ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(),
543                                                                         pwd.getIV().data(), pwd.getIV().size(),
544                                                                         pwd.getTag().data(), pwd.getTag().size(),
545                                                                         Params::DERIVED_KEY_LENGTH_BITS,
546                                                                         Params::DERIVED_KEY_ITERATIONS,
547                                                                         pwdTagSizeBits);
548         if (ret) {
549                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret);
550         }
551
552         ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size());
553         if (ret) {
554                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret);
555         }
556
557         ret = KM_ParamsSerializeKeyId(input, key.data(), key.size());
558         if (ret) {
559                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret);
560         }
561
562         ret = KM_ParamsSerializeAEData(input, tagSizeBits, 0, aad.data(), aad.size());
563         if (ret) {
564                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize auth data for TZ crypto operation: ", ret);
565         }
566
567         ret = KM_ParamsSerializeTagData(input, tag.data(), tag.size());
568         if (ret) {
569                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize tag data for TZ crypto operation: ", ret);
570         }
571
572         TEEC_Operation op;
573         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
574                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
575         op.params[0].value.a = ALGO_AES_GCM;
576         op.params[1].memref.parent = inMemory.Get();
577         op.params[1].memref.offset = 0;
578         op.params[1].memref.size = inMemory.Get()->size;
579         op.params[2].memref.parent = outMemory.Get();
580         op.params[2].memref.offset = 0;
581         op.params[2].memref.size = outMemory.Get()->size;
582         Execute(CMD_DECRYPT, &op);
583
584         KM_SymmetricInput* output = nullptr;
585         ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output);
586         if (ret) {
587                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret);
588         }
589
590         KM_OutData* outData = nullptr;
591         ret = KM_ParamsDeserializeOutData(output, &outData);
592         if (ret) {
593                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret);
594         }
595
596         out.resize(outData->data_size);
597         memcpy(out.data(), outData->data, outData->data_size);
598 }
599
600 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
601 {
602         // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
603         //
604         // TEEC_Operation layout:
605         // input params:
606         //   [1].memref - input data (serialized key ID)
607         // output params:
608         //   [0].value.a - return code
609
610         if (keyId.size() != KM_KEY_ID_SIZE) {
611                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
612         }
613
614         KM_BufferSizeDesc bufSize;
615
616         memset(&bufSize, 0, sizeof(KM_BufferSizeDesc));
617         bufSize.key_id_size = static_cast<uint32_t>(keyId.size());
618         uint32_t inMemorySize = KM_CalcBufferSize(bufSize);
619         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
620
621         KM_SymmetricInput* input = nullptr;
622         int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input);
623         if (ret) {
624                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization: ", ret);
625         }
626
627         ret = KM_ParamsSerializeInputData(input, keyId.data(), keyId.size());
628         if (ret) {
629                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key ID to destroy: ", ret);
630         }
631
632         TEEC_Operation op;
633         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE,
634                                                                         TEEC_NONE, TEEC_NONE);
635         op.params[1].memref.parent = inMemory.Get();
636         op.params[1].memref.offset = 0;
637         op.params[1].memref.size = inMemory.Get()->size;
638         Execute(CMD_DESTROY_KEY, &op);
639 }
640
641 void TrustZoneContext::importData(
642                                 const uint32_t dataType,
643                                 const RawBuffer &data,
644                                 const RawBuffer &encIV,
645                                 const RawBuffer &pwd,
646                                 const RawBuffer &iv,
647                                 const uint32_t keySizeBits,
648                                 const uint32_t pwdTagSizeBits,
649                                 RawBuffer &dataId,
650                                 RawBuffer &pwdTag)
651 {
652         // command ID = CMD_IMPORT_DATA
653         // input:
654         //    [1].memref  - reference to serialized buffer:
655         //        uint32_t dataType contains information about type stored as binary data
656         //        KM_BinaryData with binary data
657         //        uint32_t binary/key size in bits
658         //        KM_BinaryData IV for data decryption with build in key
659         //        uint32_t boolean value - true if password is provided
660         //        KM_PwdData with password (optional)
661         // Output:
662         //    [0].value.a - return code
663         //    [2].memref  - reference to serialized buffer:
664         //        KM_BinaryData with data id
665         //        KM_BinaryData with tag id (optional, if password was provided)
666         uint32_t inMemorySize = 0;
667
668         // place for dataType
669         inMemorySize += KM_SizeOfFlag();
670
671         KM_BinaryData ta_data;
672         ta_data.data_size = static_cast<uint32_t>(data.size());
673         ta_data.data = const_cast<unsigned char *>(data.data());
674         inMemorySize += KM_SizeOfBinaryData(&ta_data);
675
676         uint32_t keySizeBits_flags = static_cast<uint32_t>(keySizeBits);
677         inMemorySize += KM_SizeOfFlag();
678
679         KM_BinaryData ta_data_enc_iv;
680         ta_data_enc_iv.data_size = static_cast<uint32_t>(encIV.size());
681         ta_data_enc_iv.data = const_cast<unsigned char *>(encIV.data());
682         inMemorySize += KM_SizeOfBinaryData(&ta_data_enc_iv);
683
684         uint32_t pwd_flag = pwd.empty() ? 0 : 1;
685         inMemorySize += KM_SizeOfFlag();
686
687         KM_PwdData kmPwdData;
688         if (pwd_flag) {
689                 memset(&kmPwdData, 0, sizeof(KM_PwdData));
690                 kmPwdData.pwd = const_cast<unsigned char *>(pwd.data());
691                 kmPwdData.pwd_size = pwd.size();
692                 kmPwdData.iv = const_cast<unsigned char *>(iv.data());
693                 kmPwdData.iv_size = iv.size();
694                 kmPwdData.tag = NULL;
695                 kmPwdData.tag_size = 0;
696                 kmPwdData.derive_len_bits = Params::DERIVED_KEY_LENGTH_BITS;
697                 kmPwdData.it_count = Params::DERIVED_KEY_ITERATIONS;
698                 kmPwdData.tag_len_bits = pwdTagSizeBits;
699
700                 inMemorySize += KM_SizeOfPwdData(&kmPwdData);
701         }
702
703         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
704         void *inMemoryPtr = inMemory.Get()->buffer;
705
706         int ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, dataType);
707         if (ret){
708                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
709         }
710
711         ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &ta_data);
712         if (ret) {
713                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
714         }
715
716         ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, keySizeBits_flags);
717         if (ret) {
718                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
719         }
720
721         ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &ta_data_enc_iv);
722         if (ret) {
723                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
724         }
725
726         ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, pwd_flag);
727         if (ret) {
728                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
729         }
730
731         if (pwd_flag) {
732                 ret = KM_SerializePwdData(&inMemoryPtr, &inMemorySize, &kmPwdData);
733                 if (ret) {
734                         ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
735                 }
736         }
737
738         KM_BinaryData kmDataId;
739         KM_BinaryData kmTag;
740         memset(&kmDataId, 0, sizeof(KM_BinaryData));
741         memset(&kmTag, 0, sizeof(KM_BinaryData));
742         kmDataId.data_size = KM_DATA_ID_SIZE;
743         uint32_t outMemorySize = KM_SizeOfBinaryData(&kmDataId);
744         if (pwd_flag) {
745                 kmTag.data_size = pwdTagSizeBits / 8;
746                 outMemorySize += KM_SizeOfBinaryData(&kmTag);
747         }
748
749         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
750         void *outMemoryPtr = outMemory.Get()->buffer;
751
752         TEEC_Operation op;
753         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
754                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
755         op.params[1].memref.parent = inMemory.Get();
756         op.params[1].memref.offset = 0;
757         op.params[1].memref.size = inMemory.Get()->size;
758         op.params[2].memref.parent = outMemory.Get();
759         op.params[2].memref.offset = 0;
760         op.params[2].memref.size = outMemory.Get()->size;
761
762         Execute(CMD_IMPORT_DATA, &op);
763
764         ret = KM_DeserializeBinaryData(&outMemoryPtr, &outMemorySize, &kmDataId);
765         if (ret) {
766                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize data, ret: ", ret);
767         }
768         dataId.resize(kmDataId.data_size);
769         memcpy(dataId.data(), kmDataId.data, kmDataId.data_size);
770         if (pwd_flag) {
771                 ret = KM_DeserializeBinaryData(&outMemoryPtr, &outMemorySize, &kmTag);
772                 if (ret) {
773                         ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize data, ret: ", ret);
774                 }
775                 pwdTag.resize(kmTag.data_size);
776                 memcpy(pwdTag.data(), kmTag.data, kmTag.data_size);
777         }
778
779         LogDebug("Imported object ID is (hex): " << rawToHexString(dataId));
780 }
781
782 void TrustZoneContext::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize)
783 {
784         // command ID = CMD_GET_DATA_SIZE
785         // TA will decrypt data with password if provided
786         // Parameters:
787         //    [1].memref  - reference to serialized buffer:
788         //        KM_BinaryData with object ID
789         // Output:
790         //    [0].value.a - return code
791         //    [0].value.b - size of buffer to be passed from CA
792         LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
793         KM_BinaryData kmDataId;
794         kmDataId.data_size = static_cast<uint32_t>(dataId.size());
795         kmDataId.data = const_cast<unsigned char *>(dataId.data());
796         uint32_t inMemorySize = KM_SizeOfBinaryData(&kmDataId);
797         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
798         void *inMemoryPtr = inMemory.Get()->buffer;
799         int ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &kmDataId);
800         if (ret) {
801                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize data, ret: ", ret);
802         }
803         TEEC_Operation op;
804         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE,
805                                                                         TEEC_NONE, TEEC_NONE);
806
807         op.params[1].memref.parent = inMemory.Get();
808         op.params[1].memref.offset = 0;
809         op.params[1].memref.size = inMemory.Get()->size;
810         Execute(CMD_GET_DATA_SIZE, &op);
811         dataSize = op.params[0].value.b;
812 }
813
814 void TrustZoneContext::getData(const RawBuffer &dataId,
815                          const Pwd &pwd,
816                          RawBuffer &data)
817 {
818         // command ID = CMD_GET_DATA
819         // TA will decrypt data with password if provided
820         // Parameters:
821         //    [1].memref  - reference to serialized buffer:
822         //        KM_BinaryData with object ID
823         //        uint32_t boolean value - true if password is provided
824         //        KM_PwdData with password (optional)
825         // Output:
826         //    [0].value.a - return code
827         //    [2].memref  - reference to serialized buffer:
828         //        KM_BinaryData with binary data
829         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
830         uint32_t data_size = 0;
831         GetDataSize(dataId, data_size);
832
833         KM_BinaryData kmDataId;
834         kmDataId.data_size = static_cast<uint32_t>(dataId.size());
835         kmDataId.data = const_cast<unsigned char *>(dataId.data());
836         uint32_t inMemorySize = KM_SizeOfBinaryData(&kmDataId) + KM_SizeOfFlag();
837         uint32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1;
838         uint32_t pwdTagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
839
840         KM_PwdData kmPwdData;
841         if (pwd_flag) {
842                 memset(&kmPwdData, 0, sizeof(KM_PwdData));
843                 kmPwdData.pwd = const_cast<unsigned char *>(pwd.getPassword().data());
844                 kmPwdData.pwd_size = pwd.getPassword().size();
845                 kmPwdData.iv = const_cast<unsigned char *>(pwd.getIV().data());
846                 kmPwdData.iv_size = pwd.getIV().size();
847                 kmPwdData.tag = const_cast<unsigned char *>(pwd.getTag().data());
848                 kmPwdData.tag_size = pwd.getTag().size();
849                 kmPwdData.derive_len_bits = Params::DERIVED_KEY_LENGTH_BITS;
850                 kmPwdData.it_count = Params::DERIVED_KEY_ITERATIONS;
851                 kmPwdData.tag_len_bits = pwdTagSizeBits;
852
853                 inMemorySize += KM_SizeOfPwdData(&kmPwdData);
854         }
855
856         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
857         void *inMemoryPtr = inMemory.Get()->buffer;
858
859         int ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &kmDataId);
860         if (ret) {
861                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
862         }
863         ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, pwd_flag);
864         if (ret) {
865                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
866         }
867         if (pwd_flag) {
868                 ret = KM_SerializePwdData(&inMemoryPtr, &inMemorySize, &kmPwdData);
869                 if (ret) {
870                         ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
871                 }
872         }
873
874         KM_BinaryData kmExtractedData;
875         memset(&kmExtractedData, 0, sizeof(KM_BinaryData));
876         kmExtractedData.data_size = data_size;
877
878         uint32_t outMemorySize = KM_SizeOfBinaryData(&kmExtractedData);
879         uint32_t outMemorySize2 = outMemorySize;
880
881         TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT);
882         void *outMemoryPtr = outMemory.Get()->buffer;
883         void *outMemoryPtr2 = outMemory.Get()->buffer;
884
885         // requesting size is saved in this buffer
886         ret = KM_SerializeBinaryData(&outMemoryPtr2, &outMemorySize2, &kmExtractedData);
887         if (ret) {
888                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
889         }
890
891         TEEC_Operation op;
892         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
893                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
894         op.params[1].memref.parent = inMemory.Get();
895         op.params[1].memref.offset = 0;
896         op.params[1].memref.size = inMemory.Get()->size;
897         op.params[2].memref.parent = outMemory.Get();
898         op.params[2].memref.offset = 0;
899         op.params[2].memref.size = outMemory.Get()->size;
900
901         Execute(CMD_GET_DATA, &op);
902
903         ret = KM_DeserializeBinaryData(&outMemoryPtr, &outMemorySize, &kmExtractedData);
904         if (ret) {
905                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
906         }
907
908         data.resize(kmExtractedData.data_size);
909         memcpy(data.data(), kmExtractedData.data, kmExtractedData.data_size);
910 }
911
912
913 void TrustZoneContext::destroyData(const RawBuffer &dataId)
914 {
915         //      command ID = CMD_DESTROY_DATA
916         //  TEEC_Operation parameters layout:
917         //      input:
918         //     [1].memref  - reference to serialized buffer:
919         //         KM_BinaryData with object ID
920         //  output:
921         //     [0].value.a - return code
922         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
923         KM_BinaryData kmDataId;
924         kmDataId.data_size = static_cast<uint32_t>(dataId.size());
925         kmDataId.data = const_cast<unsigned char *>(dataId.data());
926         uint32_t inMemorySize = KM_SizeOfBinaryData(&kmDataId);
927         TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT);
928         void *inMemoryPtr = inMemory.Get()->buffer;
929
930         int ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &kmDataId);
931
932         if (ret) {
933                 ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret);
934         }
935
936         TEEC_Operation op;
937         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE,
938                                                                         TEEC_NONE, TEEC_NONE);
939
940         op.params[1].memref.parent = inMemory.Get();
941         op.params[1].memref.offset = 0;
942         op.params[1].memref.size = inMemory.Get()->size;
943         Execute(CMD_DESTROY_DATA, &op);
944 }
945
946 void TrustZoneContext::Initialize()
947 {
948         TEEC_Operation op;
949         TEEC_Result result;
950         uint32_t retOrigin;
951
952         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
953
954         result = TEEC_InitializeContext(nullptr, &m_Context);
955         if (result != TEEC_SUCCESS) {
956                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
957         }
958         m_ContextInitialized = true;
959
960         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
961         if (result != TEEC_SUCCESS) {
962                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
963         }
964         m_SessionInitialized = true;
965 }
966
967 void TrustZoneContext::Destroy()
968 {
969         if (m_SessionInitialized) {
970                 TEEC_CloseSession(&m_Session);
971                 m_SessionInitialized = false;
972         }
973
974         if (m_ContextInitialized) {
975                 TEEC_FinalizeContext(&m_Context);
976                 m_ContextInitialized = false;
977         }
978 }
979
980 void TrustZoneContext::Reload()
981 {
982         Destroy();
983         Initialize();
984 }
985
986 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
987 {
988         LogDebug("Executing TZ operation " << commandID);
989
990         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, NULL);
991         if (result != TEEC_SUCCESS) {
992                 switch (result) {
993                 case TEEC_ERROR_TARGET_DEAD:
994                         Reload();
995                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
996                                         static_cast<unsigned int>(commandID));
997                 case TEEC_ERROR_BAD_PARAMETERS:
998                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
999                 default:
1000                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
1001                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
1002                                         static_cast<unsigned int>(result));
1003                 }
1004         }
1005
1006         int ta_ret = op->params[0].value.a;
1007         if (ta_ret != KM_TA_SUCCESS) {
1008                 switch (ta_ret) {
1009                 case KM_TA_ERROR_AUTH_FAILED:
1010                         // Authentication cipher failed - notify with proper exception
1011                         ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
1012                 default:
1013                         ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
1014                 }
1015         }
1016 }
1017
1018 } // namespace Internals
1019 } // namespace TZ
1020 } // namespace Crypto
1021 } // namespace CKM