Fix bugs during exporting a wrapped key
[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 pubTagSize = 0;
253         uint32_t privTagSize = 0;
254         uint32_t pubPwdExists = pubPwd.empty() ? 0 : 1;
255         if (pubPwdExists) {
256                 pubTagSize = Params::DEFAULT_AES_GCM_TAG_LEN_BYTES;
257         }
258         uint32_t privPwdExists = privPwd.empty() ? 0 : 1;
259         if (privPwdExists) {
260                 privTagSize = Params::DEFAULT_AES_GCM_TAG_LEN_BYTES;
261         }
262
263         push(sIn, EncPwd{pubPwd, pubPwdIv}, EncPwd{privPwd, privPwdIv}, hashPriv, hashPub);
264         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
265         sIn.Serialize(inMemory);
266
267         TZSerializer sOut;
268         sOut.Push(new TZSerializableBinary(pubTagSize));
269         sOut.Push(new TZSerializableBinary(privTagSize));
270
271         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
272
273         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
274         op.params[0].value.b = genParam;
275
276         Execute(commandId, &op);
277
278         sOut.Deserialize(outMemory);
279         if (pubPwdExists) {
280                 sOut.Pull(pubKeyTag);
281         }
282
283         if (privPwdExists) {
284                 sOut.Pull(privKeyTag);
285         }
286 }
287
288 void TrustZoneContext::generateRSAKey(uint32_t keySizeBits,
289                                                                         const RawBuffer &pubPwd,
290                                                                         const RawBuffer &pubPwdIv,
291                                                                         const RawBuffer &privPwd,
292                                                                         const RawBuffer &privPwdIv,
293                                                                         RawBuffer &pubKeyTag,
294                                                                         RawBuffer &privKeyTag,
295                                                                         const RawBuffer &hashPriv,
296                                                                         const RawBuffer &hashPub)
297 {
298         // command ID = CMD_GENERATE_RSA_KEYPAIR
299         TZSerializer sIn;
300
301         GenerateAKey(CMD_GENERATE_RSA_KEYPAIR,
302                      sIn,
303                      keySizeBits,
304                      pubPwd,
305                      pubPwdIv,
306                      privPwd,
307                      privPwdIv,
308                      pubKeyTag,
309                      privKeyTag,
310                      hashPriv,
311                      hashPub);
312 }
313
314 void TrustZoneContext::generateDSAKey(uint32_t keySizeBits,
315                                                                         const RawBuffer &prime,
316                                                                         const RawBuffer &subprime,
317                                                                         const RawBuffer &base,
318                                                                         const RawBuffer &pubPwd,
319                                                                         const RawBuffer &pubPwdIv,
320                                                                         const RawBuffer &privPwd,
321                                                                         const RawBuffer &privPwdIv,
322                                                                         RawBuffer &pubKeyTag,
323                                                                         RawBuffer &privKeyTag,
324                                                                         const RawBuffer &hashPriv,
325                                                                         const RawBuffer &hashPub)
326 {
327         // command ID = CMD_GENERATE_DSA_KEYPAIR
328         auto sIn = makeSerializer(prime, subprime, base);
329
330         GenerateAKey(CMD_GENERATE_DSA_KEYPAIR,
331                      sIn,
332                      keySizeBits,
333                      pubPwd,
334                      pubPwdIv,
335                      privPwd,
336                      privPwdIv,
337                      pubKeyTag,
338                      privKeyTag,
339                      hashPriv,
340                      hashPub);
341 }
342
343 void TrustZoneContext::generateECKey(tz_ec ec,
344                                                                          const RawBuffer &pubPwd,
345                                                                          const RawBuffer &pubPwdIv,
346                                                                          const RawBuffer &privPwd,
347                                                                          const RawBuffer &privPwdIv,
348                                                                          RawBuffer &pubKeyTag,
349                                                                          RawBuffer &privKeyTag,
350                                                                          const RawBuffer &hashPriv,
351                                                                          const RawBuffer &hashPub)
352 {
353         // command ID = CMD_GENERATE_EC_KEYPAIR
354         TZSerializer sIn;
355
356         GenerateAKey(CMD_GENERATE_EC_KEYPAIR,
357                      sIn,
358                      static_cast<uint32_t>(ec),
359                      pubPwd,
360                      pubPwdIv,
361                      privPwd,
362                      privPwdIv,
363                      pubKeyTag,
364                      privKeyTag,
365                      hashPriv,
366                      hashPub);
367 }
368
369 void TrustZoneContext::executeCrypt(tz_command cmd,
370                                                                         tz_algo_type algo,
371                                                                         const RawBuffer &keyId,
372                                                                         const Pwd &pwd,
373                                                                         const RawBuffer &iv,
374                                                                         const RawBuffer &data,
375                                                                         RawBuffer &out)
376 {
377         // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
378         if (keyId.size() != KM_KEY_ID_SIZE) {
379                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
380                         + std::to_string(keyId.size()) + ")");
381         }
382
383         TZSerializer sIn;
384         if (algo == ALGO_RSA)
385                 sIn = makeSerializer(data, pwd, keyId);
386         else
387                 sIn = makeSerializer(data, pwd, iv, keyId);
388
389         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
390         sIn.Serialize(inMemory);
391
392         // decrypt operation does not require padding
393         uint32_t outMemorySize = data.size();
394         if (cmd == CMD_ENCRYPT) {
395                 if (algo == ALGO_RSA) {
396                         // We don't know the key length
397                         outMemorySize = MAX_KEY_SIZE.at(ALGO_RSA);
398                 } else {
399                         outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
400                 }
401         }
402
403         TZSerializer sOut;
404         sOut.Push(new TZSerializableBinary(outMemorySize, false));
405         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
406
407         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
408         op.params[0].value.a = algo;
409
410         Execute(cmd, &op);
411
412         sOut.Deserialize(outMemory);
413         sOut.Pull(out);
414 }
415
416 void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId,
417                                                                                 const Pwd &pwd,
418                                                                                 const RawBuffer &iv,
419                                                                                 int tagSizeBits,
420                                                                                 const RawBuffer &aad,
421                                                                                 const RawBuffer &data,
422                                                                                 RawBuffer &out,
423                                                                                 RawBuffer &tag)
424 {
425         // command ID = CMD_ENCRYPT (from km_ta_defines.h)
426         if (keyId.size() != KM_KEY_ID_SIZE) {
427                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
428         }
429
430         auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits);
431         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
432         sIn.Serialize(inMemory);
433
434         uint32_t outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
435         uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
436
437         TZSerializer sOut;
438         sOut.Push(new TZSerializableBinary(outMemorySize, false));
439         sOut.Push(new TZSerializableBinary(tagSizeBytes));
440         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
441
442         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
443         op.params[0].value.a = ALGO_AES_GCM;
444
445         Execute(CMD_ENCRYPT, &op);
446
447         sOut.Deserialize(outMemory);
448         sOut.Pull(out);
449         sOut.Pull(tag);
450 }
451
452 void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId,
453                                                                                 const Pwd &pwd,
454                                                                                 const RawBuffer &iv,
455                                                                                 int  tagSizeBits,
456                                                                                 const RawBuffer &tag,
457                                                                                 const RawBuffer &aad,
458                                                                                 const RawBuffer &data,
459                                                                                 RawBuffer &out)
460 {
461         // command ID = CMD_DECRYPT (from km_ta_defines.h)
462         if (keyId.size() != KM_KEY_ID_SIZE) {
463                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
464         }
465
466         auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits, tag);
467         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
468         sIn.Serialize(inMemory);
469
470         TZSerializer sOut;
471         sOut.Push(new TZSerializableBinary(data.size()));
472         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
473
474         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
475         op.params[0].value.a = ALGO_AES_GCM;
476
477         Execute(CMD_DECRYPT, &op);
478
479         sOut.Deserialize(outMemory);
480         sOut.Pull(out);
481 }
482
483 uint32_t TrustZoneContext::initGcmCipher(uint32_t encrypt,
484                                                                                  const RawBuffer &keyId,
485                                                                                  const Pwd &pwd,
486                                                                                  const RawBuffer &iv,
487                                                                                  int tagSizeBits,
488                                                                                  const RawBuffer &aad)
489 {
490         // command ID = CMD_CIPHER_INIT (from km_ta_defines.h)
491         if (keyId.size() != KM_KEY_ID_SIZE) {
492                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
493         }
494
495         auto sIn = makeSerializer(pwd, iv, keyId, aad, tagSizeBits);
496         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
497         sIn.Serialize(inMemory);
498
499         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
500         op.params[0].value.a = ALGO_AES_GCM;
501         op.params[0].value.b = encrypt;
502
503         Execute(CMD_CIPHER_INIT, &op);
504
505         return op.params[0].value.b;
506 }
507
508 void TrustZoneContext::addGcmAAD(uint32_t opId,
509                                                                  const RawBuffer &aad)
510 {
511         // command ID = CMD_CIPHER_INIT_AAD (from km_ta_defines.h)
512         auto sIn = makeSerializer(aad);
513         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
514         sIn.Serialize(inMemory);
515
516         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
517         op.params[0].value.a = opId;
518
519         Execute(CMD_CIPHER_INIT_AAD, &op);
520 }
521
522 RawBuffer TrustZoneContext::updateGcmCipher(uint32_t opId,
523                                                                                         const RawBuffer &data)
524 {
525         auto sIn = makeSerializer(data);
526         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
527         sIn.Serialize(inMemory);
528
529         TZSerializer sOut;
530         sOut.Push(new TZSerializableBinary(data.size()));
531         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
532
533         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
534         op.params[0].value.a = opId;
535
536         Execute(CMD_CIPHER_UPDATE, &op);
537
538         sOut.Deserialize(outMemory);
539
540         RawBuffer out;
541         sOut.Pull(out);
542         return out;
543 }
544
545 RawBuffer TrustZoneContext::finalizeGcmCipher(uint32_t opId,
546                                                                                           const RawBuffer &data)
547 {
548         auto sIn = makeSerializer(data);
549         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
550         sIn.Serialize(inMemory);
551
552         TZSerializer sOut;
553         sOut.Push(new TZSerializableBinary(MAX_GCM_TAG_SIZE, false));
554         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
555
556         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
557         op.params[0].value.a = opId;
558
559         Execute(CMD_CIPHER_FINALIZE, &op);
560
561         sOut.Deserialize(outMemory);
562
563         RawBuffer out;
564         sOut.Pull(out);
565         return out;
566 }
567
568 void TrustZoneContext::executeSign(tz_algo_type algo,
569                                                                 tz_hash_type hash,
570                                                                 const RawBuffer &keyId,
571                                                                 const Pwd &pwd,
572                                                                 const RawBuffer &message,
573                                                                 RawBuffer &signature)
574 {
575         // command ID = CMD_SIGN (from km_ta_defines.h)
576         if (keyId.size() != KM_KEY_ID_SIZE) {
577                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
578                         + std::to_string(keyId.size()) + ")");
579         }
580
581         auto sIn = makeSerializer(message, pwd, keyId);
582         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
583         sIn.Serialize(inMemory);
584
585         TZSerializer sOut;
586         sOut.Push(new TZSerializableBinary(MAX_KEY_SIZE.at(algo), false));
587         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
588
589         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
590         op.params[0].value.a = algo;
591         op.params[0].value.b = hash;
592
593         Execute(CMD_SIGN, &op);
594
595         sOut.Deserialize(outMemory);
596         sOut.Pull(signature);
597 }
598
599 int TrustZoneContext::executeVerify(tz_algo_type algo,
600                                                                         tz_hash_type hash,
601                                                                         const RawBuffer &keyId,
602                                                                         const Pwd &pwd,
603                                                                         const RawBuffer &message,
604                                                                         const RawBuffer &signature)
605 {
606         // command ID = CMD_VERIFY (from km_ta_defines.h)
607         if (keyId.size() != KM_KEY_ID_SIZE) {
608                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
609                         + std::to_string(keyId.size()) + ")");
610         }
611
612         auto sIn = makeSerializer(message, signature, pwd, keyId);
613         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
614         sIn.Serialize(inMemory);
615
616         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
617         op.params[0].value.a = algo;
618         op.params[0].value.b = hash;
619
620         Execute(CMD_VERIFY, &op);
621
622         int opRet = op.params[0].value.a;
623         switch (opRet) {
624         case KM_TA_SUCCESS:
625                 return CKM_API_SUCCESS;
626         case KM_TA_ERROR_SIGNATURE:
627                 LogWarning("Signature verification failed");
628                 return CKM_API_ERROR_VERIFICATION_FAILED;
629         default:
630                 assert(false); // This condition should be checked inside Execute() function
631                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet);
632         }
633 }
634
635 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
636 {
637         // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
638         if (keyId.size() != KM_KEY_ID_SIZE) {
639                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
640         }
641
642         auto sIn = makeSerializer(keyId);
643         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
644         sIn.Serialize(inMemory);
645
646         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
647
648         Execute(CMD_DESTROY_KEY, &op);
649 }
650
651 void TrustZoneContext::importData(
652                                 const uint32_t dataType,
653                                 const RawBuffer &data,
654                                 const Crypto::EncryptionParams &encData,
655                                 const RawBuffer &pwd,
656                                 const RawBuffer &iv,
657                                 const uint32_t keySizeBits,
658                                 RawBuffer &pwdTag,
659                                 const RawBuffer &hash)
660 {
661         // command ID = CMD_IMPORT_DATA
662         LogDebug("TrustZoneContext::importData data size = [" << data.size() << "]");
663
664         auto sIn = makeSerializer(
665                 dataType, data, keySizeBits, encData.iv, encData.tag, EncPwd{pwd, iv}, hash);
666
667         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
668         sIn.Serialize(inMemory);
669
670         TZSerializer sOut;
671         if (!pwd.empty()) {
672                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
673         }
674
675         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
676
677         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
678         if (!pwd.empty())
679                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
680
681         Execute(CMD_IMPORT_DATA, &op);
682
683         if (!pwd.empty()) {
684                 sOut.Deserialize(outMemory);
685                 sOut.Pull(pwdTag);
686         }
687
688         LogDebug("Imported object ID is (hex): " << rawToHexString(hash));
689 }
690
691 void TrustZoneContext::importWrappedKey(const RawBuffer &wrappingKeyId,
692                                                                                 const Pwd &wrappingKeyPwd,
693                                                                                 tz_algo_type algo,
694                                                                                 const RawBuffer &iv,
695                                                                                 const uint32_t ctrLenOrTagSizeBits,
696                                                                                 const RawBuffer &aad,
697                                                                                 const tz_data_type encryptedKeyType,
698                                                                                 const RawBuffer &encryptedKey,
699                                                                                 const RawBuffer &encryptedKeyPwdBuf,
700                                                                                 const RawBuffer &encryptedKeyIV,
701                                                                                 RawBuffer &encryptedKeyTag,
702                                                                                 const RawBuffer &encryptedKeyId)
703 {
704         // command ID = CMD_IMPORT_WRAPPED_KEY
705         LogDebug("TrustZoneContext::importWrappedKey encryptedKey size = [" << encryptedKey.size() << "]");
706
707         auto sIn = makeSerializer(wrappingKeyId,
708                                                           wrappingKeyPwd,
709                                                           algo,
710                                                           iv,
711                                                           ctrLenOrTagSizeBits,
712                                                           aad,
713                                                           encryptedKeyType,
714                                                           encryptedKey,
715                                                           EncPwd{encryptedKeyPwdBuf, encryptedKeyIV},
716                                                           encryptedKeyId);
717
718         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
719         sIn.Serialize(inMemory);
720
721         TZSerializer sOut;
722         if (!encryptedKeyPwdBuf.empty()) {
723                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
724         }
725
726         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
727
728         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
729         if (!encryptedKeyPwdBuf.empty())
730                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
731
732         Execute(CMD_IMPORT_WRAPPED_KEY, &op);
733
734         if (!encryptedKeyPwdBuf.empty()) {
735                 sOut.Deserialize(outMemory);
736                 sOut.Pull(encryptedKeyTag);
737         }
738
739         LogDebug("Imported object ID is (hex): " << rawToHexString(encryptedKeyId));
740 }
741
742 RawBuffer TrustZoneContext::exportWrappedKey(const RawBuffer &wrappingKeyId,
743                                                                                          const Pwd &wrappingKeyPwd,
744                                                                                          tz_algo_type algo,
745                                                                                          const RawBuffer &iv,
746                                                                                          const uint32_t ctrLenOrTagSizeBits,
747                                                                                          const RawBuffer &aad,
748                                                                                          const RawBuffer &keyToWrapId,
749                                                                                          const Pwd &keyToWrapPwd,
750                                                                                          tz_data_type keyToWrapType)
751 {
752         // command ID = CMD_EXPORT_WRAPPED_KEY
753         LogDebug("TrustZoneContext::exportWrappedKey");
754
755         auto sIn = makeSerializer(wrappingKeyId,
756                                                           wrappingKeyPwd,
757                                                           algo,
758                                                           iv,
759                                                           ctrLenOrTagSizeBits,
760                                                           aad,
761                                                           keyToWrapId,
762                                                           keyToWrapPwd,
763                                                           keyToWrapType);
764
765         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
766         sIn.Serialize(inMemory);
767
768         uint32_t dataSize = 0;
769         GetDataSize(keyToWrapId, keyToWrapType, dataSize);
770
771         LogDebug("GetData data_size = [" << dataSize << "]");
772
773         uint32_t enc_overhead = KM_ENCRYPTION_OVERHEAD;
774         if (algo == ALGO_RSA)
775                 enc_overhead = KM_RSA_BLOCK_SIZE;
776
777         // encrypted data may be longer
778         TZSerializer sOut;
779         sOut.Push(new TZSerializableBinary(dataSize + enc_overhead, false));
780         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
781         sOut.Serialize(outMemory);
782
783         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
784
785         Execute(CMD_EXPORT_WRAPPED_KEY, &op);
786
787         sOut.Deserialize(outMemory);
788
789         RawBuffer wrappedKey;
790         sOut.Pull(wrappedKey);
791
792         return wrappedKey;
793 }
794
795 void TrustZoneContext::GetDataSize(const RawBuffer &dataId,
796                                                                    const tz_data_type type,
797                                                                    uint32_t &dataSize)
798 {
799         // command ID = CMD_GET_DATA_SIZE
800         LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
801
802         auto sIn = makeSerializer(dataId, type);
803         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
804         sIn.Serialize(inMemory);
805
806         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
807
808         Execute(CMD_GET_DATA_SIZE, &op);
809         dataSize = op.params[0].value.b;
810 }
811
812 void TrustZoneContext::getData(const RawBuffer &dataId,
813                          const Pwd &pwd,
814                          const tz_data_type type,
815                          RawBuffer &data)
816 {
817         // command ID = CMD_GET_DATA
818         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
819
820         auto sIn = makeSerializer(dataId, pwd, type);
821         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
822         sIn.Serialize(inMemory);
823
824         uint32_t data_size = 0;
825         GetDataSize(dataId, type, data_size);
826
827         LogDebug("GetData data_size = [" << data_size << "]");
828
829         TZSerializer sOut;
830         sOut.Push(new TZSerializableBinary(data_size));
831         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
832         sOut.Serialize(outMemory);
833
834         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
835
836         Execute(CMD_GET_DATA, &op);
837
838         sOut.Deserialize(outMemory);
839         sOut.Pull(data);
840 }
841
842
843 void TrustZoneContext::destroyData(const RawBuffer &dataId)
844 {
845         //      command ID = CMD_DESTROY_DATA
846         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
847         auto sIn = makeSerializer(dataId);
848         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
849         sIn.Serialize(inMemory);
850
851         TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
852
853         Execute(CMD_DESTROY_DATA, &op);
854 }
855
856 TZSerializablePwdData* makeSerializablePwd(const Pwd &pwd)
857 {
858         auto &tag = pwd.getTag();
859         return new TZSerializablePwdData(pwd.getPassword(), pwd.getIV(), tag.size() * 8, tag);
860 }
861
862 void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId,
863                                                                    const Pwd &prvKeyPwd,
864                                                                    const RawBuffer &pubX,
865                                                                    const RawBuffer &pubY,
866                                                                    const RawBuffer &secretPwdBuf,
867                                                                    const RawBuffer &secretPwdIV,
868                                                                    RawBuffer &secretTag,
869                                                                    const RawBuffer &secretHash)
870 {
871         // command ID = CMD_DERIVE
872         LogDebug("TrustZoneContext::executeEcdh");
873
874         auto sIn = makeSerializer(
875                 prvKeyId, prvKeyPwd, pubX, pubY, EncPwd{secretPwdBuf, secretPwdIV}, secretHash);
876         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
877         sIn.Serialize(inMemory);
878
879         TZSerializer sOut;
880         if (!secretPwdBuf.empty()) {
881                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
882         }
883
884         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
885
886         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
887         if (!secretPwdBuf.empty())
888                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
889         op.params[0].value.a = ALGO_ECDH_DRV;
890
891         Execute(CMD_DERIVE, &op);
892
893         if (!secretPwdBuf.empty()) {
894                 sOut.Deserialize(outMemory);
895                 sOut.Pull(secretTag);
896         }
897
898         LogDebug("Derived object ID is (hex): " << rawToHexString(secretHash));
899 }
900
901 void TrustZoneContext::executeKbkdf(const RawBuffer& secretId,
902                                                                         const Pwd& secretPwd,
903                                                                         size_t length,
904                                                                         const RawBuffer& label,
905                                                                         const RawBuffer& context,
906                                                                         const RawBuffer& fixed,
907                                                                         tz_prf prf,
908                                                                         tz_kbkdf_mode mode,
909                                                                         tz_kbkdf_ctr_loc location,
910                                                                         size_t rlen,
911                                                                         size_t llen,
912                                                                         bool noSeparator,
913                                                                         const RawBuffer &keyPwdBuf,
914                                                                         const RawBuffer &keyPwdIV,
915                                                                         RawBuffer &keyTag,
916                                                                         const RawBuffer &keyHash)
917 {
918         // command ID = CMD_DERIVE
919         LogDebug("TrustZoneContext::executeKbkdf");
920
921         auto sIn = makeSerializer(secretId,
922                                                           secretPwd,
923                                                           length,
924                                                           label,
925                                                           context,
926                                                           fixed,
927                                                           prf,
928                                                           mode,
929                                                           location,
930                                                           rlen,
931                                                           llen,
932                                                           noSeparator,
933                                                           EncPwd{keyPwdBuf, keyPwdIV}, keyHash);
934
935         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
936         sIn.Serialize(inMemory);
937
938         TZSerializer sOut;
939         if (!keyPwdBuf.empty()) {
940                 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
941         }
942
943         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
944
945         TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
946         if (!keyPwdBuf.empty())
947                 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
948         op.params[0].value.a = ALGO_KBKDF_DRV;
949
950         Execute(CMD_DERIVE, &op);
951
952         if (!keyPwdBuf.empty()) {
953                 sOut.Deserialize(outMemory);
954                 sOut.Pull(keyTag);
955         }
956
957         LogDebug("Derived object ID is (hex): " << rawToHexString(keyHash));
958 }
959
960 uint32_t TrustZoneContext::getMaxChunkSize()
961 {
962         // command ID = CMD_GET_MAX_CHUNK_SIZE
963         LogDebug("TrustZoneContext::getMaxChunkSize");
964
965         TEEC_Operation op;
966         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
967
968         Execute(CMD_GET_MAX_CHUNK_SIZE, &op);
969
970         return op.params[0].value.b;
971 }
972
973 void TrustZoneContext::Initialize()
974 {
975         TEEC_Operation op;
976         TEEC_Result result;
977         uint32_t retOrigin;
978
979         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
980
981         result = TEEC_InitializeContext(nullptr, &m_Context);
982         if (result != TEEC_SUCCESS) {
983                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
984         }
985         m_ContextInitialized = true;
986
987         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
988         if (result != TEEC_SUCCESS) {
989                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
990         }
991         m_SessionInitialized = true;
992 }
993
994 void TrustZoneContext::Destroy()
995 {
996         if (m_SessionInitialized) {
997                 TEEC_CloseSession(&m_Session);
998                 m_SessionInitialized = false;
999         }
1000
1001         if (m_ContextInitialized) {
1002                 TEEC_FinalizeContext(&m_Context);
1003                 m_ContextInitialized = false;
1004         }
1005 }
1006
1007 void TrustZoneContext::Reload()
1008 {
1009         Destroy();
1010         Initialize();
1011 }
1012
1013 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
1014 {
1015         uint32_t retOrigin = 0;
1016         LogDebug("Executing TZ operation " << commandID);
1017
1018         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
1019         if (result != TEEC_SUCCESS) {
1020                 switch (result) {
1021                 case TEEC_ERROR_TARGET_DEAD:
1022                         Reload();
1023                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
1024                                         static_cast<unsigned int>(commandID));
1025                 case TEEC_ERROR_BAD_PARAMETERS:
1026                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
1027                 default:
1028                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
1029                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
1030                                         static_cast<unsigned int>(result), " with origin: ", std::hex,
1031                                         retOrigin);
1032                 }
1033         }
1034
1035         int ta_ret = op->params[0].value.a;
1036         switch (ta_ret) {
1037         case KM_TA_SUCCESS:
1038         case KM_TA_ERROR_SIGNATURE:
1039                 break;
1040         case KM_TA_ERROR_AUTH_FAILED:
1041                 // Authentication cipher failed - notify with proper exception
1042                 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
1043         default:
1044                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
1045         }
1046 }
1047
1048 } // namespace Internals
1049 } // namespace TZ
1050 } // namespace Crypto
1051 } // namespace CKM