Merge branch e2ee into tizen
[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 uint32_t TrustZoneContext::initGcmCipher(uint32_t encrypt,
480                                                                                  const RawBuffer &keyId,
481                                                                                  const Pwd &pwd,
482                                                                                  const RawBuffer &iv,
483                                                                                  int tagSizeBits,
484                                                                                  const RawBuffer &aad)
485 {
486         // command ID = CMD_CIPHER_INIT (from km_ta_defines.h)
487         if (keyId.size() != KM_KEY_ID_SIZE) {
488                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
489         }
490
491         auto sIn = makeSerializer(pwd, iv, keyId, aad, tagSizeBits);
492         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
493         sIn.Serialize(inMemory);
494
495         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
496         op.params[0].value.a = ALGO_AES_GCM;
497         op.params[0].value.b = encrypt;
498
499         Execute(CMD_CIPHER_INIT, &op);
500
501         return op.params[0].value.b;
502 }
503
504 void TrustZoneContext::addGcmAAD(uint32_t opId,
505                                                                  const RawBuffer &aad)
506 {
507         // command ID = CMD_CIPHER_INIT_AAD (from km_ta_defines.h)
508         auto sIn = makeSerializer(aad);
509         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
510         sIn.Serialize(inMemory);
511
512         TEEC_Operation op = makeOp(TEEC_VALUE_INPUT, inMemory);
513         op.params[0].value.a = opId;
514
515         Execute(CMD_CIPHER_INIT_AAD, &op);
516 }
517
518 RawBuffer TrustZoneContext::updateGcmCipher(uint32_t opId,
519                                                                                         const RawBuffer &data)
520 {
521         auto sIn = makeSerializer(data);
522         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
523         sIn.Serialize(inMemory);
524
525         TZSerializer sOut;
526         sOut.Push(new TZSerializableBinary(data.size()));
527         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
528
529         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
530         op.params[0].value.a = opId;
531
532         Execute(CMD_CIPHER_UPDATE, &op);
533
534         sOut.Deserialize(outMemory);
535
536         RawBuffer out;
537         sOut.Pull(out);
538         return out;
539 }
540
541 RawBuffer TrustZoneContext::finalizeGcmCipher(uint32_t opId,
542                                                                                           const RawBuffer &data)
543 {
544         auto sIn = makeSerializer(data);
545         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
546         sIn.Serialize(inMemory);
547
548         TZSerializer sOut;
549         sOut.Push(new TZSerializableBinary(data.size()));
550         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
551
552         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
553         op.params[0].value.a = opId;
554
555         Execute(CMD_CIPHER_FINALIZE, &op);
556
557         sOut.Deserialize(outMemory);
558
559         RawBuffer out;
560         sOut.Pull(out);
561         return out;
562 }
563
564 void TrustZoneContext::executeSign(tz_algo_type algo,
565                                                                 tz_hash_type hash,
566                                                                 const RawBuffer &keyId,
567                                                                 const Pwd &pwd,
568                                                                 const RawBuffer &message,
569                                                                 RawBuffer &signature)
570 {
571         // command ID = CMD_SIGN (from km_ta_defines.h)
572         if (keyId.size() != KM_KEY_ID_SIZE) {
573                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
574                         + std::to_string(keyId.size()) + ")");
575         }
576
577         auto sIn = makeSerializer(message, pwd, keyId);
578         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
579         sIn.Serialize(inMemory);
580
581         TZSerializer sOut;
582         sOut.Push(new TZSerializableBinary(MAX_KEY_SIZE.at(algo), false));
583         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
584
585         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
586         op.params[0].value.a = algo;
587         op.params[0].value.b = hash;
588
589         Execute(CMD_SIGN, &op);
590
591         sOut.Deserialize(outMemory);
592         sOut.Pull(signature);
593 }
594
595 int TrustZoneContext::executeVerify(tz_algo_type algo,
596                                                                         tz_hash_type hash,
597                                                                         const RawBuffer &keyId,
598                                                                         const Pwd &pwd,
599                                                                         const RawBuffer &message,
600                                                                         const RawBuffer &signature)
601 {
602         // command ID = CMD_VERIFY (from km_ta_defines.h)
603         if (keyId.size() != KM_KEY_ID_SIZE) {
604                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
605                         + std::to_string(keyId.size()) + ")");
606         }
607
608         auto sIn = makeSerializer(message, signature, pwd, keyId);
609         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
610         sIn.Serialize(inMemory);
611
612         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
613         op.params[0].value.a = algo;
614         op.params[0].value.b = hash;
615
616         Execute(CMD_VERIFY, &op);
617
618         int opRet = op.params[0].value.a;
619         switch (opRet) {
620         case KM_TA_SUCCESS:
621                 return CKM_API_SUCCESS;
622         case KM_TA_ERROR_SIGNATURE:
623                 LogWarning("Signature verification failed");
624                 return CKM_API_ERROR_VERIFICATION_FAILED;
625         default:
626                 assert(false); // This condition should be checked inside Execute() function
627                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet);
628         }
629 }
630
631 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
632 {
633         // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
634         if (keyId.size() != KM_KEY_ID_SIZE) {
635                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
636         }
637
638         auto sIn = makeSerializer(keyId);
639         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
640         sIn.Serialize(inMemory);
641
642         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
643
644         Execute(CMD_DESTROY_KEY, &op);
645 }
646
647 void TrustZoneContext::importData(
648                                 const uint32_t dataType,
649                                 const RawBuffer &data,
650                                 const Crypto::EncryptionParams &encData,
651                                 const RawBuffer &pwd,
652                                 const RawBuffer &iv,
653                                 const uint32_t keySizeBits,
654                                 RawBuffer &pwdTag,
655                                 const RawBuffer &hash)
656 {
657         // command ID = CMD_IMPORT_DATA
658         LogDebug("TrustZoneContext::importData data size = [" << data.size() << "]");
659
660         auto sIn = makeSerializer(
661                 dataType, data, keySizeBits, encData.iv, encData.tag, EncPwd{pwd, iv}, hash);
662
663         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
664         sIn.Serialize(inMemory);
665
666         TZSerializer sOut;
667         if (!pwd.empty()) {
668                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
669         }
670
671         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
672
673         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
674         if (!pwd.empty())
675                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
676
677         Execute(CMD_IMPORT_DATA, &op);
678
679         if (!pwd.empty()) {
680                 sOut.Deserialize(outMemory);
681                 sOut.Pull(pwdTag);
682         }
683
684         LogDebug("Imported object ID is (hex): " << rawToHexString(hash));
685 }
686
687 void TrustZoneContext::importWrappedKey(const RawBuffer &wrappingKey,
688                                                                                 const Pwd &wrappingKeyPwd,
689                                                                                 tz_algo_type algo,
690                                                                                 const RawBuffer &iv,
691                                                                                 const uint32_t ctrLenOrTagSizeBits,
692                                                                                 const RawBuffer &aad,
693                                                                                 const tz_data_type encryptedKeyType,
694                                                                                 const RawBuffer &encryptedKey,
695                                                                                 const RawBuffer &encryptedKeyPwdBuf,
696                                                                                 const RawBuffer &encryptedKeyIV,
697                                                                                 RawBuffer &encryptedKeyTag,
698                                                                                 const RawBuffer &encryptedKeyId)
699 {
700         // command ID = CMD_IMPORT_WRAPPED_KEY
701         LogDebug("TrustZoneContext::importWrappedKey encryptedKey size = [" << encryptedKey.size() << "]");
702
703         auto sIn = makeSerializer(wrappingKey,
704                                                           wrappingKeyPwd,
705                                                           algo,
706                                                           iv,
707                                                           ctrLenOrTagSizeBits,
708                                                           aad,
709                                                           encryptedKeyType,
710                                                           encryptedKey,
711                                                           EncPwd{encryptedKeyPwdBuf, encryptedKeyIV},
712                                                           encryptedKeyId);
713
714         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
715         sIn.Serialize(inMemory);
716
717         TZSerializer sOut;
718         if (!encryptedKeyPwdBuf.empty()) {
719                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
720         }
721
722         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
723
724         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
725         if (!encryptedKeyPwdBuf.empty())
726                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
727
728         Execute(CMD_IMPORT_WRAPPED_KEY, &op);
729
730         if (!encryptedKeyPwdBuf.empty()) {
731                 sOut.Deserialize(outMemory);
732                 sOut.Pull(encryptedKeyTag);
733         }
734
735         LogDebug("Imported object ID is (hex): " << rawToHexString(encryptedKeyId));
736 }
737
738 RawBuffer TrustZoneContext::exportWrappedKey(const RawBuffer &wrappingKey,
739                                                                                          const Pwd &wrappingKeyPwd,
740                                                                                          tz_algo_type algo,
741                                                                                          const RawBuffer &iv,
742                                                                                          const uint32_t ctrLenOrTagSizeBits,
743                                                                                          const RawBuffer &aad,
744                                                                                          const RawBuffer &keyToWrapId,
745                                                                                          const Pwd &keyToWrapPwd)
746 {
747         // command ID = CMD_EXPORT_WRAPPED_KEY
748         LogDebug("TrustZoneContext::exportWrappedKey");
749
750         auto sIn = makeSerializer(wrappingKey,
751                                                           wrappingKeyPwd,
752                                                           algo,
753                                                           iv,
754                                                           ctrLenOrTagSizeBits,
755                                                           aad,
756                                                           keyToWrapId,
757                                                           keyToWrapPwd);
758
759         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
760         sIn.Serialize(inMemory);
761
762         uint32_t data_size = 0;
763         GetDataSize(keyToWrapId, data_size);
764
765         LogDebug("GetData data_size = [" << data_size << "]");
766
767         // encrypted data may be longer
768         TZSerializer sOut;
769         sOut.Push(new TZSerializableBinary(data_size + KM_ENCRYPTION_OVERHEAD));
770         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
771         sOut.Serialize(outMemory);
772
773         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
774
775         Execute(CMD_EXPORT_WRAPPED_KEY, &op);
776
777         sOut.Deserialize(outMemory);
778
779         RawBuffer wrappedKey;
780         sOut.Pull(wrappedKey);
781
782         return wrappedKey;
783 }
784
785 void TrustZoneContext::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize)
786 {
787         // command ID = CMD_GET_DATA_SIZE
788         LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
789
790         auto sIn = makeSerializer(dataId);
791         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
792         sIn.Serialize(inMemory);
793
794         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
795
796         Execute(CMD_GET_DATA_SIZE, &op);
797         dataSize = op.params[0].value.b;
798 }
799
800 void TrustZoneContext::getData(const RawBuffer &dataId,
801                          const Pwd &pwd,
802                          RawBuffer &data)
803 {
804         // command ID = CMD_GET_DATA
805         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
806
807         auto sIn = makeSerializer(dataId, pwd);
808         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
809         sIn.Serialize(inMemory);
810
811         uint32_t data_size = 0;
812         GetDataSize(dataId, data_size);
813
814         LogDebug("GetData data_size = [" << data_size << "]");
815
816         TZSerializer sOut;
817         sOut.Push(new TZSerializableBinary(data_size));
818         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
819         sOut.Serialize(outMemory);
820
821         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
822
823         Execute(CMD_GET_DATA, &op);
824
825         sOut.Deserialize(outMemory);
826         sOut.Pull(data);
827 }
828
829
830 void TrustZoneContext::destroyData(const RawBuffer &dataId)
831 {
832         //      command ID = CMD_DESTROY_DATA
833         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
834         auto sIn = makeSerializer(dataId);
835         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
836         sIn.Serialize(inMemory);
837
838         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
839
840         Execute(CMD_DESTROY_DATA, &op);
841 }
842
843 TZSerializablePwdData* makeSerializablePwd(const Pwd &pwd)
844 {
845         auto &tag = pwd.getTag();
846         return new TZSerializablePwdData(pwd.getPassword(), pwd.getIV(), tag.size() * 8, tag);
847 }
848
849 void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId,
850                                                                    const Pwd &prvKeyPwd,
851                                                                    const RawBuffer &pubX,
852                                                                    const RawBuffer &pubY,
853                                                                    const RawBuffer &secretPwdBuf,
854                                                                    const RawBuffer &secretPwdIV,
855                                                                    RawBuffer &secretTag,
856                                                                    const RawBuffer &secretHash)
857 {
858         // command ID = CMD_DERIVE
859         LogDebug("TrustZoneContext::executeEcdh");
860
861         auto sIn = makeSerializer(
862                 prvKeyId, prvKeyPwd, pubX, pubY, EncPwd{secretPwdBuf, secretPwdIV}, secretHash);
863         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
864         sIn.Serialize(inMemory);
865
866         TZSerializer sOut;
867         if (!secretPwdBuf.empty()) {
868                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
869         }
870
871         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
872
873         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
874         if (!secretPwdBuf.empty())
875                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
876         op.params[0].value.a = ALGO_ECDH_DRV;
877
878         Execute(CMD_DERIVE, &op);
879
880         if (!secretPwdBuf.empty()) {
881                 sOut.Deserialize(outMemory);
882                 sOut.Pull(secretTag);
883         }
884
885         LogDebug("Derived object ID is (hex): " << rawToHexString(secretHash));
886 }
887
888 void TrustZoneContext::executeKbkdf(const RawBuffer& secret,
889                                                                         const RawBuffer& label,
890                                                                         const RawBuffer& context,
891                                                                         const RawBuffer& fixed,
892                                                                         tz_prf prf,
893                                                                         tz_kbkdf_mode mode,
894                                                                         tz_kbkdf_ctr_loc location,
895                                                                         size_t rlen,
896                                                                         size_t llen,
897                                                                         bool noSeparator,
898                                                                         const RawBuffer &keyPwdBuf,
899                                                                         const RawBuffer &keyPwdIV,
900                                                                         RawBuffer &keyTag,
901                                                                         const RawBuffer &keyHash)
902 {
903         // command ID = CMD_DERIVE
904         LogDebug("TrustZoneContext::executeKbkdf");
905
906         auto sIn = makeSerializer(secret,
907                                                           label,
908                                                           context,
909                                                           fixed,
910                                                           prf,
911                                                           mode,
912                                                           location,
913                                                           rlen,
914                                                           llen,
915                                                           noSeparator,
916                                                           EncPwd{keyPwdBuf, keyPwdIV}, keyHash);
917
918         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
919         sIn.Serialize(inMemory);
920
921         TZSerializer sOut;
922         if (!keyPwdBuf.empty()) {
923                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
924         }
925
926         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
927
928         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
929         if (!keyPwdBuf.empty())
930                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
931         op.params[0].value.a = ALGO_KBKDF_DRV;
932
933         Execute(CMD_DERIVE, &op);
934
935         if (!keyPwdBuf.empty()) {
936                 sOut.Deserialize(outMemory);
937                 sOut.Pull(keyTag);
938         }
939
940         LogDebug("Derived object ID is (hex): " << rawToHexString(keyHash));
941 }
942
943 void TrustZoneContext::Initialize()
944 {
945         TEEC_Operation op;
946         TEEC_Result result;
947         uint32_t retOrigin;
948
949         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
950
951         result = TEEC_InitializeContext(nullptr, &m_Context);
952         if (result != TEEC_SUCCESS) {
953                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
954         }
955         m_ContextInitialized = true;
956
957         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
958         if (result != TEEC_SUCCESS) {
959                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
960         }
961         m_SessionInitialized = true;
962 }
963
964 void TrustZoneContext::Destroy()
965 {
966         if (m_SessionInitialized) {
967                 TEEC_CloseSession(&m_Session);
968                 m_SessionInitialized = false;
969         }
970
971         if (m_ContextInitialized) {
972                 TEEC_FinalizeContext(&m_Context);
973                 m_ContextInitialized = false;
974         }
975 }
976
977 void TrustZoneContext::Reload()
978 {
979         Destroy();
980         Initialize();
981 }
982
983 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
984 {
985         uint32_t retOrigin = 0;
986         LogDebug("Executing TZ operation " << commandID);
987
988         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
989         if (result != TEEC_SUCCESS) {
990                 switch (result) {
991                 case TEEC_ERROR_TARGET_DEAD:
992                         Reload();
993                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
994                                         static_cast<unsigned int>(commandID));
995                 case TEEC_ERROR_BAD_PARAMETERS:
996                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
997                 default:
998                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
999                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
1000                                         static_cast<unsigned int>(result), " with origin: ", std::hex,
1001                                         retOrigin);
1002                 }
1003         }
1004
1005         int ta_ret = op->params[0].value.a;
1006         switch (ta_ret) {
1007         case KM_TA_SUCCESS:
1008         case KM_TA_ERROR_SIGNATURE:
1009                 break;
1010         case KM_TA_ERROR_AUTH_FAILED:
1011                 // Authentication cipher failed - notify with proper exception
1012                 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
1013         default:
1014                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
1015         }
1016 }
1017
1018 } // namespace Internals
1019 } // namespace TZ
1020 } // namespace Crypto
1021 } // namespace CKM