efeb4a9150241b31b3495da9e8446be2d0a0fe2b
[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::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize)
603 {
604         // command ID = CMD_GET_DATA_SIZE
605         LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
606
607         auto sIn = makeSerializer(dataId);
608         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
609         sIn.Serialize(inMemory);
610
611         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
612
613         Execute(CMD_GET_DATA_SIZE, &op);
614         dataSize = op.params[0].value.b;
615 }
616
617 void TrustZoneContext::getData(const RawBuffer &dataId,
618                          const Pwd &pwd,
619                          RawBuffer &data)
620 {
621         // command ID = CMD_GET_DATA
622         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
623
624         auto sIn = makeSerializer(dataId, pwd);
625         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
626         sIn.Serialize(inMemory);
627
628         uint32_t data_size = 0;
629         GetDataSize(dataId, data_size);
630
631         LogDebug("GetData data_size = [" << data_size << "]");
632
633         TZSerializer sOut;
634         sOut.Push(new TZSerializableBinary(data_size));
635         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
636         sOut.Serialize(outMemory);
637
638         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
639
640         Execute(CMD_GET_DATA, &op);
641
642         sOut.Deserialize(outMemory);
643         sOut.Pull(data);
644 }
645
646
647 void TrustZoneContext::destroyData(const RawBuffer &dataId)
648 {
649         //      command ID = CMD_DESTROY_DATA
650         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
651         auto sIn = makeSerializer(dataId);
652         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
653         sIn.Serialize(inMemory);
654
655         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
656
657         Execute(CMD_DESTROY_DATA, &op);
658 }
659
660 TZSerializablePwdData* makeSerializablePwd(const Pwd &pwd)
661 {
662         auto &tag = pwd.getTag();
663         return new TZSerializablePwdData(pwd.getPassword(), pwd.getIV(), tag.size() * 8, tag);
664 }
665
666 void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId,
667                                                                    const Pwd &prvKeyPwd,
668                                                                    const RawBuffer &pubX,
669                                                                    const RawBuffer &pubY,
670                                                                    const RawBuffer &secretPwdBuf,
671                                                                    const RawBuffer &secretPwdIV,
672                                                                    RawBuffer &secretTag,
673                                                                    const RawBuffer &secretHash)
674 {
675         // command ID = CMD_DERIVE
676         LogDebug("TrustZoneContext::executeEcdh");
677
678         auto sIn = makeSerializer(
679                 prvKeyId, prvKeyPwd, pubX, pubY, EncPwd{secretPwdBuf, secretPwdIV}, secretHash);
680         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
681         sIn.Serialize(inMemory);
682
683         TZSerializer sOut;
684         if (!secretPwdBuf.empty()) {
685                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
686         }
687
688         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
689
690         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
691         if (!secretPwdBuf.empty())
692                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
693         op.params[0].value.a = ALGO_ECDH_DRV;
694
695         Execute(CMD_DERIVE, &op);
696
697         if (!secretPwdBuf.empty()) {
698                 sOut.Deserialize(outMemory);
699                 sOut.Pull(secretTag);
700         }
701
702         LogDebug("Derived object ID is (hex): " << rawToHexString(secretHash));
703 }
704
705 void TrustZoneContext::executeKbkdf(const RawBuffer& secret,
706                                                                         KdfPrf prf,
707                                                                         KbkdfMode mode,
708                                                                         KbkdfCounterLocation location,
709                                                                         size_t rlen,
710                                                                         size_t llen,
711                                                                         bool noSeparator,
712                                                                         const RawBuffer &keyPwdBuf,
713                                                                         const RawBuffer &keyPwdIV,
714                                                                         RawBuffer &keyTag,
715                                                                         const RawBuffer &keyHash)
716 {
717         // command ID = CMD_DERIVE
718         LogDebug("TrustZoneContext::executeKbkdf");
719
720         auto sIn = makeSerializer(
721                 secret, prf, mode, location, rlen, llen, noSeparator, EncPwd{keyPwdBuf, keyPwdIV}, keyHash);
722         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
723         sIn.Serialize(inMemory);
724
725         TZSerializer sOut;
726         if (!keyPwdBuf.empty()) {
727                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
728         }
729
730         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
731
732         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
733         if (!keyPwdBuf.empty())
734                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
735         op.params[0].value.a = ALGO_KBKDF_DRV;
736
737         Execute(CMD_DERIVE, &op);
738
739         if (!keyPwdBuf.empty()) {
740                 sOut.Deserialize(outMemory);
741                 sOut.Pull(keyTag);
742         }
743
744         LogDebug("Derived object ID is (hex): " << rawToHexString(keyHash));
745 }
746
747 void TrustZoneContext::Initialize()
748 {
749         TEEC_Operation op;
750         TEEC_Result result;
751         uint32_t retOrigin;
752
753         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
754
755         result = TEEC_InitializeContext(nullptr, &m_Context);
756         if (result != TEEC_SUCCESS) {
757                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
758         }
759         m_ContextInitialized = true;
760
761         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
762         if (result != TEEC_SUCCESS) {
763                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
764         }
765         m_SessionInitialized = true;
766 }
767
768 void TrustZoneContext::Destroy()
769 {
770         if (m_SessionInitialized) {
771                 TEEC_CloseSession(&m_Session);
772                 m_SessionInitialized = false;
773         }
774
775         if (m_ContextInitialized) {
776                 TEEC_FinalizeContext(&m_Context);
777                 m_ContextInitialized = false;
778         }
779 }
780
781 void TrustZoneContext::Reload()
782 {
783         Destroy();
784         Initialize();
785 }
786
787 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
788 {
789         uint32_t retOrigin = 0;
790         LogDebug("Executing TZ operation " << commandID);
791
792         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
793         if (result != TEEC_SUCCESS) {
794                 switch (result) {
795                 case TEEC_ERROR_TARGET_DEAD:
796                         Reload();
797                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
798                                         static_cast<unsigned int>(commandID));
799                 case TEEC_ERROR_BAD_PARAMETERS:
800                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
801                 default:
802                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
803                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
804                                         static_cast<unsigned int>(result), " with origin: ", std::hex,
805                                         retOrigin);
806                 }
807         }
808
809         int ta_ret = op->params[0].value.a;
810         switch (ta_ret) {
811         case KM_TA_SUCCESS:
812         case KM_TA_ERROR_SIGNATURE:
813                 break;
814         case KM_TA_ERROR_AUTH_FAILED:
815                 // Authentication cipher failed - notify with proper exception
816                 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
817         default:
818                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
819         }
820 }
821
822 } // namespace Internals
823 } // namespace TZ
824 } // namespace Crypto
825 } // namespace CKM