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