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