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