Key unwrapping implementation in TZ backend
[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 genParam, // key size in bits or EC type
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 = genParam;
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::generateECKey(tz_ec ec,
340                                                                          const RawBuffer &pubPwd,
341                                                                          const RawBuffer &pubPwdIv,
342                                                                          const RawBuffer &privPwd,
343                                                                          const RawBuffer &privPwdIv,
344                                                                          RawBuffer &pubKeyTag,
345                                                                          RawBuffer &privKeyTag,
346                                                                          const RawBuffer &hashPriv,
347                                                                          const RawBuffer &hashPub)
348 {
349         // command ID = CMD_GENERATE_EC_KEYPAIR
350         TZSerializer sIn;
351
352         GenerateAKey(CMD_GENERATE_EC_KEYPAIR,
353                      sIn,
354                      static_cast<uint32_t>(ec),
355                      pubPwd,
356                      pubPwdIv,
357                      privPwd,
358                      privPwdIv,
359                      pubKeyTag,
360                      privKeyTag,
361                      hashPriv,
362                      hashPub);
363 }
364
365 void TrustZoneContext::executeCrypt(tz_command cmd,
366                                                                         tz_algo_type algo,
367                                                                         const RawBuffer &keyId,
368                                                                         const Pwd &pwd,
369                                                                         const RawBuffer &iv,
370                                                                         const RawBuffer &data,
371                                                                         RawBuffer &out)
372 {
373         // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
374         if (keyId.size() != KM_KEY_ID_SIZE) {
375                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
376                         + std::to_string(keyId.size()) + ")");
377         }
378
379         TZSerializer sIn;
380         if (algo == ALGO_RSA)
381                 sIn = makeSerializer(data, pwd, keyId);
382         else
383                 sIn = makeSerializer(data, pwd, iv, keyId);
384
385         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
386         sIn.Serialize(inMemory);
387
388         // decrypt operation does not require padding
389         uint32_t outMemorySize = data.size();
390         if (cmd == CMD_ENCRYPT) {
391                 if (algo == ALGO_RSA) {
392                         // We don't know the key length
393                         outMemorySize = MAX_KEY_SIZE.at(ALGO_RSA);
394                 } else {
395                         outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
396                 }
397         }
398
399         TZSerializer sOut;
400         sOut.Push(new TZSerializableBinary(outMemorySize, false));
401         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
402
403         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
404         op.params[0].value.a = algo;
405
406         Execute(cmd, &op);
407
408         sOut.Deserialize(outMemory);
409         sOut.Pull(out);
410 }
411
412 void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId,
413                                                                                 const Pwd &pwd,
414                                                                                 const RawBuffer &iv,
415                                                                                 int tagSizeBits,
416                                                                                 const RawBuffer &aad,
417                                                                                 const RawBuffer &data,
418                                                                                 RawBuffer &out,
419                                                                                 RawBuffer &tag)
420 {
421         // command ID = CMD_ENCRYPT (from km_ta_defines.h)
422         if (keyId.size() != KM_KEY_ID_SIZE) {
423                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
424         }
425
426         auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits);
427         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
428         sIn.Serialize(inMemory);
429
430         uint32_t outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
431         uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
432
433         TZSerializer sOut;
434         sOut.Push(new TZSerializableBinary(outMemorySize, false));
435         sOut.Push(new TZSerializableBinary(tagSizeBytes));
436         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
437
438         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
439         op.params[0].value.a = ALGO_AES_GCM;
440
441         Execute(CMD_ENCRYPT, &op);
442
443         sOut.Deserialize(outMemory);
444         sOut.Pull(out);
445         sOut.Pull(tag);
446 }
447
448 void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId,
449                                                                                 const Pwd &pwd,
450                                                                                 const RawBuffer &iv,
451                                                                                 int  tagSizeBits,
452                                                                                 const RawBuffer &tag,
453                                                                                 const RawBuffer &aad,
454                                                                                 const RawBuffer &data,
455                                                                                 RawBuffer &out)
456 {
457         // command ID = CMD_DECRYPT (from km_ta_defines.h)
458         if (keyId.size() != KM_KEY_ID_SIZE) {
459                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
460         }
461
462         auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits, tag);
463         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
464         sIn.Serialize(inMemory);
465
466         TZSerializer sOut;
467         sOut.Push(new TZSerializableBinary(data.size()));
468         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
469
470         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
471         op.params[0].value.a = ALGO_AES_GCM;
472
473         Execute(CMD_DECRYPT, &op);
474
475         sOut.Deserialize(outMemory);
476         sOut.Pull(out);
477 }
478
479 void TrustZoneContext::executeSign(tz_algo_type algo,
480                                                                 tz_hash_type hash,
481                                                                 const RawBuffer &keyId,
482                                                                 const Pwd &pwd,
483                                                                 const RawBuffer &message,
484                                                                 RawBuffer &signature)
485 {
486         // command ID = CMD_SIGN (from km_ta_defines.h)
487         if (keyId.size() != KM_KEY_ID_SIZE) {
488                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
489                         + std::to_string(keyId.size()) + ")");
490         }
491
492         auto sIn = makeSerializer(message, pwd, keyId);
493         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
494         sIn.Serialize(inMemory);
495
496         TZSerializer sOut;
497         sOut.Push(new TZSerializableBinary(MAX_KEY_SIZE.at(algo), false));
498         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
499
500         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
501         op.params[0].value.a = algo;
502         op.params[0].value.b = hash;
503
504         Execute(CMD_SIGN, &op);
505
506         sOut.Deserialize(outMemory);
507         sOut.Pull(signature);
508 }
509
510 int TrustZoneContext::executeVerify(tz_algo_type algo,
511                                                                         tz_hash_type hash,
512                                                                         const RawBuffer &keyId,
513                                                                         const Pwd &pwd,
514                                                                         const RawBuffer &message,
515                                                                         const RawBuffer &signature)
516 {
517         // command ID = CMD_VERIFY (from km_ta_defines.h)
518         if (keyId.size() != KM_KEY_ID_SIZE) {
519                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
520                         + std::to_string(keyId.size()) + ")");
521         }
522
523         auto sIn = makeSerializer(message, signature, pwd, keyId);
524         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
525         sIn.Serialize(inMemory);
526
527         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
528         op.params[0].value.a = algo;
529         op.params[0].value.b = hash;
530
531         Execute(CMD_VERIFY, &op);
532
533         int opRet = op.params[0].value.a;
534         switch (opRet) {
535         case KM_TA_SUCCESS:
536                 return CKM_API_SUCCESS;
537         case KM_TA_ERROR_SIGNATURE:
538                 LogWarning("Signature verification failed");
539                 return CKM_API_ERROR_VERIFICATION_FAILED;
540         default:
541                 assert(false); // This condition should be checked inside Execute() function
542                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet);
543         }
544 }
545
546 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
547 {
548         // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
549         if (keyId.size() != KM_KEY_ID_SIZE) {
550                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
551         }
552
553         auto sIn = makeSerializer(keyId);
554         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
555         sIn.Serialize(inMemory);
556
557         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
558
559         Execute(CMD_DESTROY_KEY, &op);
560 }
561
562 void TrustZoneContext::importData(
563                                 const uint32_t dataType,
564                                 const RawBuffer &data,
565                                 const Crypto::EncryptionParams &encData,
566                                 const RawBuffer &pwd,
567                                 const RawBuffer &iv,
568                                 const uint32_t keySizeBits,
569                                 RawBuffer &pwdTag,
570                                 const RawBuffer &hash)
571 {
572         // command ID = CMD_IMPORT_DATA
573         LogDebug("TrustZoneContext::importData data size = [" << data.size() << "]");
574
575         auto sIn = makeSerializer(
576                 dataType, data, keySizeBits, encData.iv, encData.tag, EncPwd{pwd, iv}, hash);
577
578         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
579         sIn.Serialize(inMemory);
580
581         TZSerializer sOut;
582         if (!pwd.empty()) {
583                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
584         }
585
586         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
587
588         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
589         if (!pwd.empty())
590                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
591
592         Execute(CMD_IMPORT_DATA, &op);
593
594         if (!pwd.empty()) {
595                 sOut.Deserialize(outMemory);
596                 sOut.Pull(pwdTag);
597         }
598
599         LogDebug("Imported object ID is (hex): " << rawToHexString(hash));
600 }
601
602 void TrustZoneContext::importWrappedKey(const RawBuffer &wrappingKey,
603                                                                                 const Pwd &wrappingKeyPwd,
604                                                                                 tz_algo_type algo,
605                                                                                 const RawBuffer &iv,
606                                                                                 const uint32_t ctrLenOrTagSizeBits,
607                                                                                 const RawBuffer &aad,
608                                                                                 const tz_data_type encryptedKeyType,
609                                                                                 const RawBuffer &encryptedKey,
610                                                                                 const RawBuffer &encryptedKeyPwdBuf,
611                                                                                 const RawBuffer &encryptedKeyIV,
612                                                                                 RawBuffer &encryptedKeyTag,
613                                                                                 const RawBuffer &encryptedKeyId)
614 {
615         // command ID = CMD_IMPORT_WRAPPED_KEY
616         LogDebug("TrustZoneContext::importWrappedKey encryptedKey size = [" << encryptedKey.size() << "]");
617
618         auto sIn = makeSerializer(wrappingKey,
619                                                           wrappingKeyPwd,
620                                                           algo,
621                                                           iv,
622                                                           ctrLenOrTagSizeBits,
623                                                           aad,
624                                                           encryptedKeyType,
625                                                           encryptedKey,
626                                                           EncPwd{encryptedKeyPwdBuf, encryptedKeyIV},
627                                                           encryptedKeyId);
628
629         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
630         sIn.Serialize(inMemory);
631
632         TZSerializer sOut;
633         if (!encryptedKeyPwdBuf.empty()) {
634                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
635         }
636
637         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
638
639         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
640         if (!encryptedKeyPwdBuf.empty())
641                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
642
643         Execute(CMD_IMPORT_WRAPPED_KEY, &op);
644
645         if (!encryptedKeyPwdBuf.empty()) {
646                 sOut.Deserialize(outMemory);
647                 sOut.Pull(encryptedKeyTag);
648         }
649
650         LogDebug("Imported object ID is (hex): " << rawToHexString(encryptedKeyId));
651 }
652
653 void TrustZoneContext::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize)
654 {
655         // command ID = CMD_GET_DATA_SIZE
656         LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
657
658         auto sIn = makeSerializer(dataId);
659         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
660         sIn.Serialize(inMemory);
661
662         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
663
664         Execute(CMD_GET_DATA_SIZE, &op);
665         dataSize = op.params[0].value.b;
666 }
667
668 void TrustZoneContext::getData(const RawBuffer &dataId,
669                          const Pwd &pwd,
670                          RawBuffer &data)
671 {
672         // command ID = CMD_GET_DATA
673         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
674
675         auto sIn = makeSerializer(dataId, pwd);
676         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
677         sIn.Serialize(inMemory);
678
679         uint32_t data_size = 0;
680         GetDataSize(dataId, data_size);
681
682         LogDebug("GetData data_size = [" << data_size << "]");
683
684         TZSerializer sOut;
685         sOut.Push(new TZSerializableBinary(data_size));
686         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
687         sOut.Serialize(outMemory);
688
689         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
690
691         Execute(CMD_GET_DATA, &op);
692
693         sOut.Deserialize(outMemory);
694         sOut.Pull(data);
695 }
696
697
698 void TrustZoneContext::destroyData(const RawBuffer &dataId)
699 {
700         //      command ID = CMD_DESTROY_DATA
701         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
702         auto sIn = makeSerializer(dataId);
703         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
704         sIn.Serialize(inMemory);
705
706         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
707
708         Execute(CMD_DESTROY_DATA, &op);
709 }
710
711 TZSerializablePwdData* makeSerializablePwd(const Pwd &pwd)
712 {
713         auto &tag = pwd.getTag();
714         return new TZSerializablePwdData(pwd.getPassword(), pwd.getIV(), tag.size() * 8, tag);
715 }
716
717 void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId,
718                                                                    const Pwd &prvKeyPwd,
719                                                                    const RawBuffer &pubX,
720                                                                    const RawBuffer &pubY,
721                                                                    const RawBuffer &secretPwdBuf,
722                                                                    const RawBuffer &secretPwdIV,
723                                                                    RawBuffer &secretTag,
724                                                                    const RawBuffer &secretHash)
725 {
726         // command ID = CMD_DERIVE
727         LogDebug("TrustZoneContext::executeEcdh");
728
729         auto sIn = makeSerializer(
730                 prvKeyId, prvKeyPwd, pubX, pubY, EncPwd{secretPwdBuf, secretPwdIV}, secretHash);
731         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
732         sIn.Serialize(inMemory);
733
734         TZSerializer sOut;
735         if (!secretPwdBuf.empty()) {
736                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
737         }
738
739         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
740
741         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
742         if (!secretPwdBuf.empty())
743                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
744         op.params[0].value.a = ALGO_ECDH_DRV;
745
746         Execute(CMD_DERIVE, &op);
747
748         if (!secretPwdBuf.empty()) {
749                 sOut.Deserialize(outMemory);
750                 sOut.Pull(secretTag);
751         }
752
753         LogDebug("Derived object ID is (hex): " << rawToHexString(secretHash));
754 }
755
756 void TrustZoneContext::executeKbkdf(const RawBuffer& secret,
757                                                                         tz_prf prf,
758                                                                         tz_kbkdf_mode mode,
759                                                                         tz_kbkdf_ctr_loc location,
760                                                                         size_t rlen,
761                                                                         size_t llen,
762                                                                         bool noSeparator,
763                                                                         const RawBuffer &keyPwdBuf,
764                                                                         const RawBuffer &keyPwdIV,
765                                                                         RawBuffer &keyTag,
766                                                                         const RawBuffer &keyHash)
767 {
768         // command ID = CMD_DERIVE
769         LogDebug("TrustZoneContext::executeKbkdf");
770
771         auto sIn = makeSerializer(
772                 secret, prf, mode, location, rlen, llen, noSeparator, EncPwd{keyPwdBuf, keyPwdIV}, keyHash);
773         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
774         sIn.Serialize(inMemory);
775
776         TZSerializer sOut;
777         if (!keyPwdBuf.empty()) {
778                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
779         }
780
781         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
782
783         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
784         if (!keyPwdBuf.empty())
785                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
786         op.params[0].value.a = ALGO_KBKDF_DRV;
787
788         Execute(CMD_DERIVE, &op);
789
790         if (!keyPwdBuf.empty()) {
791                 sOut.Deserialize(outMemory);
792                 sOut.Pull(keyTag);
793         }
794
795         LogDebug("Derived object ID is (hex): " << rawToHexString(keyHash));
796 }
797
798 void TrustZoneContext::Initialize()
799 {
800         TEEC_Operation op;
801         TEEC_Result result;
802         uint32_t retOrigin;
803
804         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
805
806         result = TEEC_InitializeContext(nullptr, &m_Context);
807         if (result != TEEC_SUCCESS) {
808                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
809         }
810         m_ContextInitialized = true;
811
812         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
813         if (result != TEEC_SUCCESS) {
814                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
815         }
816         m_SessionInitialized = true;
817 }
818
819 void TrustZoneContext::Destroy()
820 {
821         if (m_SessionInitialized) {
822                 TEEC_CloseSession(&m_Session);
823                 m_SessionInitialized = false;
824         }
825
826         if (m_ContextInitialized) {
827                 TEEC_FinalizeContext(&m_Context);
828                 m_ContextInitialized = false;
829         }
830 }
831
832 void TrustZoneContext::Reload()
833 {
834         Destroy();
835         Initialize();
836 }
837
838 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
839 {
840         uint32_t retOrigin = 0;
841         LogDebug("Executing TZ operation " << commandID);
842
843         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
844         if (result != TEEC_SUCCESS) {
845                 switch (result) {
846                 case TEEC_ERROR_TARGET_DEAD:
847                         Reload();
848                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
849                                         static_cast<unsigned int>(commandID));
850                 case TEEC_ERROR_BAD_PARAMETERS:
851                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
852                 default:
853                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
854                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
855                                         static_cast<unsigned int>(result), " with origin: ", std::hex,
856                                         retOrigin);
857                 }
858         }
859
860         int ta_ret = op->params[0].value.a;
861         switch (ta_ret) {
862         case KM_TA_SUCCESS:
863         case KM_TA_ERROR_SIGNATURE:
864                 break;
865         case KM_TA_ERROR_AUTH_FAILED:
866                 // Authentication cipher failed - notify with proper exception
867                 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
868         default:
869                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
870         }
871 }
872
873 } // namespace Internals
874 } // namespace TZ
875 } // namespace Crypto
876 } // namespace CKM