9bfc390062f02edd595002227702911e744d30de
[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 // Maximum size of GCM tag in bytes.
54 const size_t MAX_GCM_TAG_SIZE = 16;
55
56 // Identifier of our TA
57 const TEEC_UUID KEY_MANAGER_TA_UUID = KM_TA_UUID;
58
59 //raw to hex string conversion to print persistent storage data ID
60 static std::string rawToHexString(const RawBuffer &raw)
61 {
62         return hexDump<std::string>(raw);
63 }
64
65 /*
66  * Maximum size for given key type in bytes according to key-manager-ta implementation.
67  * Note that they are greater than TEE Internal Core API v1.1.2.50 (Table 5-9) values.
68  */
69 const std::unordered_map<tz_algo_type, size_t> MAX_KEY_SIZE = {
70         { ALGO_RSA, 4096 / 8 },
71         { ALGO_RSA_SV, 4096 / 8 },
72         { ALGO_DSA_SV, 4096 / 8 },
73         { ALGO_ECDSA_SV, 1024 / 8 } // 384*2 + additional space for DERR encoding
74 };
75
76 struct EncPwd {
77         const RawBuffer &password;
78         const RawBuffer &iv;
79 };
80
81 template <typename T>
82 void push(TZSerializer& ser, const T& value)
83 {
84         ser.Push(new TZSerializableFlag(static_cast<uint32_t>(value)));
85 }
86
87 template<>
88 void push<RawBuffer>(TZSerializer& ser, const RawBuffer& value)
89 {
90         ser.Push(new TZSerializableBinary(value));
91 }
92
93 template<>
94 void push<Pwd>(TZSerializer& ser, const Pwd& value)
95 {
96         int32_t pwd_flag = value.getPassword().empty() ? 0 : 1;
97         ser.Push(new TZSerializableFlag(pwd_flag));
98         if (pwd_flag)
99                 ser.Push(new TZSerializablePwdData(value.getPassword(),
100                                                                                    value.getIV(),
101                                                                                    value.getTag().size() * 8,
102                                                                                    value.getTag()));
103 }
104
105 template<>
106 void push<EncPwd>(TZSerializer& ser, const EncPwd& value)
107 {
108         int32_t pwd_flag = value.password.empty() ? 0 : 1;
109         ser.Push(new TZSerializableFlag(pwd_flag));
110         if (pwd_flag)
111                 ser.Push(new TZSerializablePwdData(value.password,
112                                                                                    value.iv,
113                                                                                    Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
114 }
115
116 template <typename T, typename ...Args>
117 void push(TZSerializer& ser, const T& first, const Args&... args)
118 {
119         push<T>(ser, first);
120         push<Args...>(ser, args...);
121 }
122
123 template <typename ...Args>
124 TZSerializer makeSerializer(const Args&... args)
125 {
126         TZSerializer ser;
127         push<Args...>(ser, args...);
128         return ser;
129 }
130
131 } // anonymous namespace
132
133 TrustZoneContext::TrustZoneContext()
134         : m_ContextInitialized(false)
135         , m_SessionInitialized(false)
136 {
137         Initialize();
138 }
139
140 TrustZoneContext::~TrustZoneContext()
141 {
142         Destroy();
143 }
144
145 TrustZoneContext& TrustZoneContext::Instance()
146 {
147         static TrustZoneContext instance;
148         return instance;
149 }
150
151 TEEC_Operation makeOp(uint32_t value, TrustZoneMemory& mem1)
152 {
153         TEEC_Operation op;
154
155         op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_NONE, TEEC_NONE);
156
157         op.params[1].memref.parent = mem1.Get();
158         op.params[1].memref.offset = 0;
159         op.params[1].memref.size = mem1.Get()->size;
160         return op;
161 }
162
163 TEEC_Operation makeOp(uint32_t value, TrustZoneMemory& mem1, TrustZoneMemory& mem2)
164 {
165         TEEC_Operation op = makeOp(value, mem1);
166
167         op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_MEMREF_WHOLE, TEEC_NONE);
168
169         op.params[2].memref.parent = mem2.Get();
170         op.params[2].memref.offset = 0;
171         op.params[2].memref.size = mem2.Get()->size;
172
173         return op;
174 }
175
176 void TrustZoneContext::generateIV(RawBuffer& iv)
177 {
178         // command ID = CMD_GENERATE_IV
179         // IV generation is a simple call - no need to serialize data
180         // just provide the output buffer with size equal to iv.
181         uint32_t ivSize = Params::DEFAULT_AES_IV_LEN;
182         TrustZoneMemory ivMemory(m_Context, ivSize, TEEC_MEM_OUTPUT);
183
184         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, ivMemory);
185
186         Execute(CMD_GENERATE_IV, &op);
187
188         iv.resize(ivSize);
189         memcpy(iv.data(), ivMemory.Get()->buffer, ivMemory.Get()->size);
190 }
191
192 void TrustZoneContext::generateSKey(tz_algo_type algo,
193                                                                         uint32_t keySizeBits,
194                                                                         const RawBuffer &hash)
195 {
196         // command ID = CMD_GENERATE_KEY
197         auto sIn = makeSerializer(hash);
198         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
199         sIn.Serialize(inMemory);
200
201         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
202         op.params[0].value.a = algo;
203         op.params[0].value.b = keySizeBits;
204
205         Execute(CMD_GENERATE_KEY, &op);
206 }
207
208 void TrustZoneContext::generateSKeyPwd(tz_algo_type algo,
209                                                                         const RawBuffer &pwd,
210                                                                         const RawBuffer &iv,
211                                                                         const uint32_t keySizeBits,
212                                                                         RawBuffer &pwdTag,
213                                                                         const RawBuffer &hash)
214 {
215         // command ID = CMD_GENERATE_KEY_PWD
216         TZSerializer sIn;
217         sIn.Push(new TZSerializablePwdData(pwd, iv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
218         sIn.Push(new TZSerializableBinary(hash));
219         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
220         sIn.Serialize(inMemory);
221
222         TZSerializer sOut;
223         sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
224         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
225
226         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
227         op.params[0].value.a = algo;
228         op.params[0].value.b = keySizeBits;
229
230         Execute(CMD_GENERATE_KEY_PWD, &op);
231
232         sOut.Deserialize(outMemory);
233         sOut.Pull(pwdTag);
234
235         if (pwdTag.size() != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) {
236                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag");
237         }
238 }
239
240 void TrustZoneContext::GenerateAKey(tz_command commandId,
241                                     TZSerializer &sIn,
242                                     uint32_t genParam, // key size in bits or EC type
243                                     const RawBuffer &pubPwd,
244                                     const RawBuffer &pubPwdIv,
245                                     const RawBuffer &privPwd,
246                                     const RawBuffer &privPwdIv,
247                                     RawBuffer &pubKeyTag,
248                                     RawBuffer &privKeyTag,
249                                     const RawBuffer &hashPriv,
250                                                                         const RawBuffer &hashPub)
251 {
252         uint32_t pubPwdExists = pubPwd.empty() ? 0 : 1;
253         TZSerializer sOut;
254         if (pubPwdExists)
255                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
256
257         uint32_t privPwdExists = privPwd.empty() ? 0 : 1;
258         if (privPwdExists)
259                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
260
261         push(sIn, EncPwd{pubPwd, pubPwdIv}, EncPwd{privPwd, privPwdIv}, hashPriv, hashPub);
262         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
263         sIn.Serialize(inMemory);
264
265         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
266
267         TEEC_Operation op;
268         if (sOut.GetSize() == 0) {
269                 op = makeOp(TEEC_VALUE_INOUT, inMemory);
270         } else {
271                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
272         }
273         op.params[0].value.b = genParam;
274
275         Execute(commandId, &op);
276
277         sOut.Deserialize(outMemory);
278         if (pubPwdExists) {
279                 sOut.Pull(pubKeyTag);
280         }
281
282         if (privPwdExists) {
283                 sOut.Pull(privKeyTag);
284         }
285 }
286
287 void TrustZoneContext::generateRSAKey(uint32_t keySizeBits,
288                                                                         const RawBuffer &pubPwd,
289                                                                         const RawBuffer &pubPwdIv,
290                                                                         const RawBuffer &privPwd,
291                                                                         const RawBuffer &privPwdIv,
292                                                                         RawBuffer &pubKeyTag,
293                                                                         RawBuffer &privKeyTag,
294                                                                         const RawBuffer &hashPriv,
295                                                                         const RawBuffer &hashPub)
296 {
297         // command ID = CMD_GENERATE_RSA_KEYPAIR
298         TZSerializer sIn;
299
300         GenerateAKey(CMD_GENERATE_RSA_KEYPAIR,
301                      sIn,
302                      keySizeBits,
303                      pubPwd,
304                      pubPwdIv,
305                      privPwd,
306                      privPwdIv,
307                      pubKeyTag,
308                      privKeyTag,
309                      hashPriv,
310                      hashPub);
311 }
312
313 void TrustZoneContext::generateDSAKey(uint32_t keySizeBits,
314                                                                         const RawBuffer &prime,
315                                                                         const RawBuffer &subprime,
316                                                                         const RawBuffer &base,
317                                                                         const RawBuffer &pubPwd,
318                                                                         const RawBuffer &pubPwdIv,
319                                                                         const RawBuffer &privPwd,
320                                                                         const RawBuffer &privPwdIv,
321                                                                         RawBuffer &pubKeyTag,
322                                                                         RawBuffer &privKeyTag,
323                                                                         const RawBuffer &hashPriv,
324                                                                         const RawBuffer &hashPub)
325 {
326         // command ID = CMD_GENERATE_DSA_KEYPAIR
327         auto sIn = makeSerializer(prime, subprime, base);
328
329         GenerateAKey(CMD_GENERATE_DSA_KEYPAIR,
330                      sIn,
331                      keySizeBits,
332                      pubPwd,
333                      pubPwdIv,
334                      privPwd,
335                      privPwdIv,
336                      pubKeyTag,
337                      privKeyTag,
338                      hashPriv,
339                      hashPub);
340 }
341
342 void TrustZoneContext::generateECKey(tz_ec ec,
343                                                                          const RawBuffer &pubPwd,
344                                                                          const RawBuffer &pubPwdIv,
345                                                                          const RawBuffer &privPwd,
346                                                                          const RawBuffer &privPwdIv,
347                                                                          RawBuffer &pubKeyTag,
348                                                                          RawBuffer &privKeyTag,
349                                                                          const RawBuffer &hashPriv,
350                                                                          const RawBuffer &hashPub)
351 {
352         // command ID = CMD_GENERATE_EC_KEYPAIR
353         TZSerializer sIn;
354
355         GenerateAKey(CMD_GENERATE_EC_KEYPAIR,
356                      sIn,
357                      static_cast<uint32_t>(ec),
358                      pubPwd,
359                      pubPwdIv,
360                      privPwd,
361                      privPwdIv,
362                      pubKeyTag,
363                      privKeyTag,
364                      hashPriv,
365                      hashPub);
366 }
367
368 void TrustZoneContext::executeCrypt(tz_command cmd,
369                                                                         tz_algo_type algo,
370                                                                         const RawBuffer &keyId,
371                                                                         const Pwd &pwd,
372                                                                         const RawBuffer &iv,
373                                                                         const RawBuffer &data,
374                                                                         RawBuffer &out)
375 {
376         // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
377         if (keyId.size() != KM_KEY_ID_SIZE) {
378                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
379                         + std::to_string(keyId.size()) + ")");
380         }
381
382         TZSerializer sIn;
383         if (algo == ALGO_RSA)
384                 sIn = makeSerializer(data, pwd, keyId);
385         else
386                 sIn = makeSerializer(data, pwd, iv, keyId);
387
388         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
389         sIn.Serialize(inMemory);
390
391         // decrypt operation does not require padding
392         uint32_t outMemorySize = data.size();
393         if (cmd == CMD_ENCRYPT) {
394                 if (algo == ALGO_RSA) {
395                         // We don't know the key length
396                         outMemorySize = MAX_KEY_SIZE.at(ALGO_RSA);
397                 } else {
398                         outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
399                 }
400         }
401
402         TZSerializer sOut;
403         sOut.Push(new TZSerializableBinary(outMemorySize, false));
404         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
405
406         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
407         op.params[0].value.a = algo;
408
409         Execute(cmd, &op);
410
411         sOut.Deserialize(outMemory);
412         sOut.Pull(out);
413 }
414
415 void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId,
416                                                                                 const Pwd &pwd,
417                                                                                 const RawBuffer &iv,
418                                                                                 int tagSizeBits,
419                                                                                 const RawBuffer &aad,
420                                                                                 const RawBuffer &data,
421                                                                                 RawBuffer &out,
422                                                                                 RawBuffer &tag)
423 {
424         // command ID = CMD_ENCRYPT (from km_ta_defines.h)
425         if (keyId.size() != KM_KEY_ID_SIZE) {
426                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
427         }
428
429         auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits);
430         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
431         sIn.Serialize(inMemory);
432
433         uint32_t outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
434         uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
435
436         TZSerializer sOut;
437         sOut.Push(new TZSerializableBinary(outMemorySize, false));
438         sOut.Push(new TZSerializableBinary(tagSizeBytes));
439         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
440
441         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
442         op.params[0].value.a = ALGO_AES_GCM;
443
444         Execute(CMD_ENCRYPT, &op);
445
446         sOut.Deserialize(outMemory);
447         sOut.Pull(out);
448         sOut.Pull(tag);
449 }
450
451 void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId,
452                                                                                 const Pwd &pwd,
453                                                                                 const RawBuffer &iv,
454                                                                                 int  tagSizeBits,
455                                                                                 const RawBuffer &tag,
456                                                                                 const RawBuffer &aad,
457                                                                                 const RawBuffer &data,
458                                                                                 RawBuffer &out)
459 {
460         // command ID = CMD_DECRYPT (from km_ta_defines.h)
461         if (keyId.size() != KM_KEY_ID_SIZE) {
462                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
463         }
464
465         auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits, tag);
466         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
467         sIn.Serialize(inMemory);
468
469         TZSerializer sOut;
470         sOut.Push(new TZSerializableBinary(data.size()));
471         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
472
473         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
474         op.params[0].value.a = ALGO_AES_GCM;
475
476         Execute(CMD_DECRYPT, &op);
477
478         sOut.Deserialize(outMemory);
479         sOut.Pull(out);
480 }
481
482 uint32_t TrustZoneContext::initGcmCipher(uint32_t encrypt,
483                                                                                  const RawBuffer &keyId,
484                                                                                  const Pwd &pwd,
485                                                                                  const RawBuffer &iv,
486                                                                                  int tagSizeBits,
487                                                                                  const RawBuffer &aad)
488 {
489         // command ID = CMD_CIPHER_INIT (from km_ta_defines.h)
490         if (keyId.size() != KM_KEY_ID_SIZE) {
491                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
492         }
493
494         auto sIn = makeSerializer(pwd, iv, keyId, aad, tagSizeBits);
495         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
496         sIn.Serialize(inMemory);
497
498         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
499         op.params[0].value.a = ALGO_AES_GCM;
500         op.params[0].value.b = encrypt;
501
502         Execute(CMD_CIPHER_INIT, &op);
503
504         return op.params[0].value.b;
505 }
506
507 void TrustZoneContext::addGcmAAD(uint32_t opId,
508                                                                  const RawBuffer &aad)
509 {
510         // command ID = CMD_CIPHER_INIT_AAD (from km_ta_defines.h)
511         auto sIn = makeSerializer(aad);
512         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
513         sIn.Serialize(inMemory);
514
515         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
516         op.params[0].value.a = opId;
517
518         Execute(CMD_CIPHER_INIT_AAD, &op);
519 }
520
521 RawBuffer TrustZoneContext::updateGcmCipher(uint32_t opId,
522                                                                                         const RawBuffer &data)
523 {
524         auto sIn = makeSerializer(data);
525         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
526         sIn.Serialize(inMemory);
527
528         TZSerializer sOut;
529         sOut.Push(new TZSerializableBinary(data.size()));
530         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
531
532         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
533         op.params[0].value.a = opId;
534
535         Execute(CMD_CIPHER_UPDATE, &op);
536
537         sOut.Deserialize(outMemory);
538
539         RawBuffer out;
540         sOut.Pull(out);
541         return out;
542 }
543
544 RawBuffer TrustZoneContext::finalizeGcmCipher(uint32_t opId,
545                                                                                           const RawBuffer &data)
546 {
547         auto sIn = makeSerializer(data);
548         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
549         sIn.Serialize(inMemory);
550
551         TZSerializer sOut;
552         sOut.Push(new TZSerializableBinary(MAX_GCM_TAG_SIZE, false));
553         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
554
555         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
556         op.params[0].value.a = opId;
557
558         Execute(CMD_CIPHER_FINALIZE, &op);
559
560         sOut.Deserialize(outMemory);
561
562         RawBuffer out;
563         sOut.Pull(out);
564         return out;
565 }
566
567 void TrustZoneContext::cleanupCipher(uint32_t opId)
568 {
569         TEEC_Operation op;
570         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
571         op.params[0].value.a = opId;
572
573         Execute(CMD_CIPHER_CLEANUP, &op);
574 }
575
576 void TrustZoneContext::executeSign(tz_algo_type algo,
577                                                                 tz_hash_type hash,
578                                                                 const RawBuffer &keyId,
579                                                                 const Pwd &pwd,
580                                                                 const RawBuffer &message,
581                                                                 RawBuffer &signature)
582 {
583         // command ID = CMD_SIGN (from km_ta_defines.h)
584         if (keyId.size() != KM_KEY_ID_SIZE) {
585                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
586                         + std::to_string(keyId.size()) + ")");
587         }
588
589         auto sIn = makeSerializer(message, pwd, keyId);
590         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
591         sIn.Serialize(inMemory);
592
593         TZSerializer sOut;
594         sOut.Push(new TZSerializableBinary(MAX_KEY_SIZE.at(algo), false));
595         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
596
597         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
598         op.params[0].value.a = algo;
599         op.params[0].value.b = hash;
600
601         Execute(CMD_SIGN, &op);
602
603         sOut.Deserialize(outMemory);
604         sOut.Pull(signature);
605 }
606
607 int TrustZoneContext::executeVerify(tz_algo_type algo,
608                                                                         tz_hash_type hash,
609                                                                         const RawBuffer &keyId,
610                                                                         const Pwd &pwd,
611                                                                         const RawBuffer &message,
612                                                                         const RawBuffer &signature)
613 {
614         // command ID = CMD_VERIFY (from km_ta_defines.h)
615         if (keyId.size() != KM_KEY_ID_SIZE) {
616                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
617                         + std::to_string(keyId.size()) + ")");
618         }
619
620         auto sIn = makeSerializer(message, signature, pwd, keyId);
621         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
622         sIn.Serialize(inMemory);
623
624         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
625         op.params[0].value.a = algo;
626         op.params[0].value.b = hash;
627
628         Execute(CMD_VERIFY, &op);
629
630         int opRet = op.params[0].value.a;
631         switch (opRet) {
632         case KM_TA_SUCCESS:
633                 return CKM_API_SUCCESS;
634         case KM_TA_ERROR_SIGNATURE:
635                 LogWarning("Signature verification failed");
636                 return CKM_API_ERROR_VERIFICATION_FAILED;
637         default:
638                 assert(false); // This condition should be checked inside Execute() function
639                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet);
640         }
641 }
642
643 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
644 {
645         // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
646         if (keyId.size() != KM_KEY_ID_SIZE) {
647                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
648         }
649
650         auto sIn = makeSerializer(keyId);
651         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
652         sIn.Serialize(inMemory);
653
654         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
655
656         Execute(CMD_DESTROY_KEY, &op);
657 }
658
659 void TrustZoneContext::importData(
660                                 const uint32_t dataType,
661                                 const RawBuffer &data,
662                                 const Crypto::EncryptionParams &encData,
663                                 const RawBuffer &pwd,
664                                 const RawBuffer &iv,
665                                 const uint32_t keySizeBits,
666                                 RawBuffer &pwdTag,
667                                 const RawBuffer &hash)
668 {
669         // command ID = CMD_IMPORT_DATA
670         LogDebug("TrustZoneContext::importData data size = [" << data.size() << "]");
671
672         auto sIn = makeSerializer(
673                 dataType, data, keySizeBits, encData.iv, encData.tag, EncPwd{pwd, iv}, hash);
674
675         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
676         sIn.Serialize(inMemory);
677
678         TZSerializer sOut;
679         if (!pwd.empty()) {
680                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
681         }
682
683         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
684
685         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
686         if (!pwd.empty())
687                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
688
689         Execute(CMD_IMPORT_DATA, &op);
690
691         if (!pwd.empty()) {
692                 sOut.Deserialize(outMemory);
693                 sOut.Pull(pwdTag);
694         }
695
696         LogDebug("Imported object ID is (hex): " << rawToHexString(hash));
697 }
698
699 void TrustZoneContext::importWrappedKey(const RawBuffer &wrappingKeyId,
700                                                                                 const Pwd &wrappingKeyPwd,
701                                                                                 tz_algo_type algo,
702                                                                                 const RawBuffer &iv,
703                                                                                 const uint32_t ctrLenOrTagSizeBits,
704                                                                                 const RawBuffer &aad,
705                                                                                 const tz_data_type encryptedKeyType,
706                                                                                 const RawBuffer &encryptedKey,
707                                                                                 const RawBuffer &encryptedKeyPwdBuf,
708                                                                                 const RawBuffer &encryptedKeyIV,
709                                                                                 RawBuffer &encryptedKeyTag,
710                                                                                 const RawBuffer &encryptedKeyId)
711 {
712         // command ID = CMD_IMPORT_WRAPPED_KEY
713         LogDebug("TrustZoneContext::importWrappedKey encryptedKey size = [" << encryptedKey.size() << "]");
714
715         auto sIn = makeSerializer(wrappingKeyId,
716                                                           wrappingKeyPwd,
717                                                           algo,
718                                                           iv,
719                                                           ctrLenOrTagSizeBits,
720                                                           aad,
721                                                           encryptedKeyType,
722                                                           encryptedKey,
723                                                           EncPwd{encryptedKeyPwdBuf, encryptedKeyIV},
724                                                           encryptedKeyId);
725
726         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
727         sIn.Serialize(inMemory);
728
729         TZSerializer sOut;
730         if (!encryptedKeyPwdBuf.empty()) {
731                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
732         }
733
734         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
735
736         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
737         if (!encryptedKeyPwdBuf.empty())
738                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
739
740         Execute(CMD_IMPORT_WRAPPED_KEY, &op);
741
742         if (!encryptedKeyPwdBuf.empty()) {
743                 sOut.Deserialize(outMemory);
744                 sOut.Pull(encryptedKeyTag);
745         }
746
747         LogDebug("Imported object ID is (hex): " << rawToHexString(encryptedKeyId));
748 }
749
750 RawBuffer TrustZoneContext::exportWrappedKey(const RawBuffer &wrappingKeyId,
751                                                                                          const Pwd &wrappingKeyPwd,
752                                                                                          tz_algo_type algo,
753                                                                                          const RawBuffer &iv,
754                                                                                          const uint32_t ctrLenOrTagSizeBits,
755                                                                                          const RawBuffer &aad,
756                                                                                          const RawBuffer &keyToWrapId,
757                                                                                          const Pwd &keyToWrapPwd,
758                                                                                          tz_data_type keyToWrapType)
759 {
760         // command ID = CMD_EXPORT_WRAPPED_KEY
761         LogDebug("TrustZoneContext::exportWrappedKey");
762
763         auto sIn = makeSerializer(wrappingKeyId,
764                                                           wrappingKeyPwd,
765                                                           algo,
766                                                           iv,
767                                                           ctrLenOrTagSizeBits,
768                                                           aad,
769                                                           keyToWrapId,
770                                                           keyToWrapPwd,
771                                                           keyToWrapType);
772
773         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
774         sIn.Serialize(inMemory);
775
776         uint32_t dataSize = 0;
777         GetDataSize(keyToWrapId, keyToWrapPwd, keyToWrapType, dataSize);
778
779         LogDebug("GetData data_size = [" << dataSize << "]");
780
781         uint32_t enc_overhead = KM_ENCRYPTION_OVERHEAD;
782         if (algo == ALGO_RSA)
783                 enc_overhead = KM_RSA_BLOCK_SIZE;
784
785         // encrypted data may be longer
786         TZSerializer sOut;
787         sOut.Push(new TZSerializableBinary(dataSize + enc_overhead, false));
788         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
789         sOut.Serialize(outMemory);
790
791         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
792
793         Execute(CMD_EXPORT_WRAPPED_KEY, &op);
794
795         sOut.Deserialize(outMemory);
796
797         RawBuffer wrappedKey;
798         sOut.Pull(wrappedKey);
799
800         return wrappedKey;
801 }
802
803 void TrustZoneContext::GetDataSize(const RawBuffer &dataId,
804                                                                    const Pwd &pwd,
805                                                                    const tz_data_type type,
806                                                                    uint32_t &dataSize)
807 {
808         // command ID = CMD_GET_DATA_SIZE
809         LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
810
811         auto sIn = makeSerializer(dataId, pwd, type);
812         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
813         sIn.Serialize(inMemory);
814
815         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
816
817         Execute(CMD_GET_DATA_SIZE, &op);
818         dataSize = op.params[0].value.b;
819 }
820
821 void TrustZoneContext::getData(const RawBuffer &dataId,
822                          const Pwd &pwd,
823                          const tz_data_type type,
824                          RawBuffer &data)
825 {
826         // command ID = CMD_GET_DATA
827         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
828
829         auto sIn = makeSerializer(dataId, pwd, type);
830         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
831         sIn.Serialize(inMemory);
832
833         uint32_t data_size = 0;
834         GetDataSize(dataId, pwd, type, data_size);
835
836         LogDebug("GetData data_size = [" << data_size << "]");
837
838         TZSerializer sOut;
839         sOut.Push(new TZSerializableBinary(data_size));
840         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
841         sOut.Serialize(outMemory);
842
843         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
844
845         Execute(CMD_GET_DATA, &op);
846
847         sOut.Deserialize(outMemory);
848         sOut.Pull(data);
849 }
850
851
852 void TrustZoneContext::destroyData(const RawBuffer &dataId)
853 {
854         //      command ID = CMD_DESTROY_DATA
855         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
856         auto sIn = makeSerializer(dataId);
857         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
858         sIn.Serialize(inMemory);
859
860         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
861
862         Execute(CMD_DESTROY_DATA, &op);
863 }
864
865 TZSerializablePwdData* makeSerializablePwd(const Pwd &pwd)
866 {
867         auto &tag = pwd.getTag();
868         return new TZSerializablePwdData(pwd.getPassword(), pwd.getIV(), tag.size() * 8, tag);
869 }
870
871 void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId,
872                                                                    const Pwd &prvKeyPwd,
873                                                                    const tz_ec curve,
874                                                                    const RawBuffer &pubX,
875                                                                    const RawBuffer &pubY,
876                                                                    const RawBuffer &secretPwdBuf,
877                                                                    const RawBuffer &secretPwdIV,
878                                                                    RawBuffer &secretTag,
879                                                                    const RawBuffer &secretHash)
880 {
881         // command ID = CMD_DERIVE
882         LogDebug("TrustZoneContext::executeEcdh");
883
884         auto sIn = makeSerializer(
885                 prvKeyId, prvKeyPwd, curve, pubX, pubY, EncPwd{secretPwdBuf, secretPwdIV}, secretHash);
886         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
887         sIn.Serialize(inMemory);
888
889         TZSerializer sOut;
890         if (!secretPwdBuf.empty()) {
891                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
892         }
893
894         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
895
896         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
897         if (!secretPwdBuf.empty())
898                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
899         op.params[0].value.a = ALGO_ECDH_DRV;
900
901         Execute(CMD_DERIVE, &op);
902
903         if (!secretPwdBuf.empty()) {
904                 sOut.Deserialize(outMemory);
905                 sOut.Pull(secretTag);
906         }
907
908         LogDebug("Derived object ID is (hex): " << rawToHexString(secretHash));
909 }
910
911 void TrustZoneContext::executeKbkdf(const RawBuffer& secretId,
912                                                                         const Pwd& secretPwd,
913                                                                         size_t length,
914                                                                         const RawBuffer& label,
915                                                                         const RawBuffer& context,
916                                                                         const RawBuffer& fixed,
917                                                                         tz_prf prf,
918                                                                         tz_kbkdf_mode mode,
919                                                                         tz_kbkdf_ctr_loc location,
920                                                                         size_t rlen,
921                                                                         size_t llen,
922                                                                         bool noSeparator,
923                                                                         const RawBuffer &keyPwdBuf,
924                                                                         const RawBuffer &keyPwdIV,
925                                                                         RawBuffer &keyTag,
926                                                                         const RawBuffer &keyHash)
927 {
928         // command ID = CMD_DERIVE
929         LogDebug("TrustZoneContext::executeKbkdf");
930
931         auto sIn = makeSerializer(secretId,
932                                                           secretPwd,
933                                                           length,
934                                                           label,
935                                                           context,
936                                                           fixed,
937                                                           prf,
938                                                           mode,
939                                                           location,
940                                                           rlen,
941                                                           llen,
942                                                           noSeparator,
943                                                           EncPwd{keyPwdBuf, keyPwdIV}, keyHash);
944
945         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
946         sIn.Serialize(inMemory);
947
948         TZSerializer sOut;
949         if (!keyPwdBuf.empty()) {
950                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
951         }
952
953         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
954
955         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
956         if (!keyPwdBuf.empty())
957                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
958         op.params[0].value.a = ALGO_KBKDF_DRV;
959
960         Execute(CMD_DERIVE, &op);
961
962         if (!keyPwdBuf.empty()) {
963                 sOut.Deserialize(outMemory);
964                 sOut.Pull(keyTag);
965         }
966
967         LogDebug("Derived object ID is (hex): " << rawToHexString(keyHash));
968 }
969
970 uint32_t TrustZoneContext::getMaxChunkSize()
971 {
972         // command ID = CMD_GET_MAX_CHUNK_SIZE
973         LogDebug("TrustZoneContext::getMaxChunkSize");
974
975         TEEC_Operation op;
976         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
977
978         Execute(CMD_GET_MAX_CHUNK_SIZE, &op);
979
980         return op.params[0].value.b;
981 }
982
983 void TrustZoneContext::Initialize()
984 {
985         TEEC_Operation op;
986         TEEC_Result result;
987         uint32_t retOrigin;
988
989         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
990
991         result = TEEC_InitializeContext(nullptr, &m_Context);
992         if (result != TEEC_SUCCESS) {
993                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
994         }
995         m_ContextInitialized = true;
996
997         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
998         if (result != TEEC_SUCCESS) {
999                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
1000         }
1001         m_SessionInitialized = true;
1002 }
1003
1004 void TrustZoneContext::Destroy()
1005 {
1006         if (m_SessionInitialized) {
1007                 TEEC_CloseSession(&m_Session);
1008                 m_SessionInitialized = false;
1009         }
1010
1011         if (m_ContextInitialized) {
1012                 TEEC_FinalizeContext(&m_Context);
1013                 m_ContextInitialized = false;
1014         }
1015 }
1016
1017 void TrustZoneContext::Reload()
1018 {
1019         Destroy();
1020         Initialize();
1021 }
1022
1023 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
1024 {
1025         uint32_t retOrigin = 0;
1026         LogDebug("Executing TZ operation " << commandID);
1027
1028         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
1029         if (result != TEEC_SUCCESS) {
1030                 switch (result) {
1031                 case TEEC_ERROR_TARGET_DEAD:
1032                         Reload();
1033                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
1034                                         static_cast<unsigned int>(commandID));
1035                 case TEEC_ERROR_BAD_PARAMETERS:
1036                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
1037                 default:
1038                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
1039                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
1040                                         static_cast<unsigned int>(result), " with origin: ", std::hex,
1041                                         retOrigin);
1042                 }
1043         }
1044
1045         int ta_ret = op->params[0].value.a;
1046         switch (ta_ret) {
1047         case KM_TA_SUCCESS:
1048         case KM_TA_ERROR_SIGNATURE:
1049                 break;
1050         case KM_TA_ERROR_AUTH_FAILED:
1051                 // Authentication cipher failed - notify with proper exception
1052                 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
1053         default:
1054                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
1055         }
1056 }
1057
1058 } // namespace Internals
1059 } // namespace TZ
1060 } // namespace Crypto
1061 } // namespace CKM