Change serialization in TZ backend to match km-ta changes
[platform/core/security/key-manager.git] / src / manager / crypto / tz-backend / tz-context.cpp
1 /*
2  *  Copyright (c) 2017-2019 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 #include <tz-backend/tz-context.h>
23 #include <tz-backend/tz-memory.h>
24 #include <generic-backend/exception.h>
25 #include <generic-backend/crypto-params.h>
26 #include <generic-backend/encryption-params.h>
27 #include <dpl/log/log.h>
28
29 #include <km_serialization.h>
30 #include <km_ta_defines.h>
31
32 #include <cstdint>
33 #include <cstring>
34 #include <cassert>
35 #include <iomanip>
36 #include <sstream>
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         std::string dump;
60
61         for (auto &e : raw) {
62                 char buf[3];
63                 snprintf(buf, sizeof(buf), "%02x", (e & 0xff));
64                 dump.push_back(buf[0]);
65                 dump.push_back(buf[1]);
66         }
67
68         return dump;
69 }
70
71 /*
72  * Maximum size for given key type in bytes according to key-manager-ta implementation.
73  * Note that they are greater than TEE Internal Core API v1.1.2.50 (Table 5-9) values.
74  */
75 const std::unordered_map<tz_algo_type, size_t> MAX_KEY_SIZE = {
76         { ALGO_RSA, 4096 / 8 },
77         { ALGO_RSA_SV, 4096 / 8 },
78         { ALGO_DSA_SV, 4096 / 8 }
79 };
80
81 } // anonymous namespace
82
83 TrustZoneContext::TrustZoneContext()
84         : m_ContextInitialized(false)
85         , m_SessionInitialized(false)
86 {
87         Initialize();
88 }
89
90 TrustZoneContext::~TrustZoneContext()
91 {
92         Destroy();
93 }
94
95 TrustZoneContext& TrustZoneContext::Instance()
96 {
97         static TrustZoneContext instance;
98         return instance;
99 }
100
101 void TrustZoneContext::generateIV(RawBuffer& iv)
102 {
103         // command ID = CMD_GENERATE_IV
104         // IV generation is a simple call - no need to serialize data
105         // just provide the output buffer with size equal to iv.
106         uint32_t ivSize = Params::DEFAULT_AES_IV_LEN;
107         TrustZoneMemory ivMemory(m_Context, ivSize, TEEC_MEM_OUTPUT);
108
109         TEEC_Operation op;
110         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
111                                                                         TEEC_NONE, TEEC_NONE);
112         op.params[1].memref.parent = ivMemory.Get();
113         op.params[1].memref.offset = 0;
114         op.params[1].memref.size = ivMemory.Get()->size;
115         Execute(CMD_GENERATE_IV, &op);
116
117         iv.resize(ivSize);
118         memcpy(iv.data(), ivMemory.Get()->buffer, ivMemory.Get()->size);
119 }
120
121 void TrustZoneContext::generateSKey(tz_algo_type algo,
122                                                                         uint32_t keySizeBits,
123                                                                         RawBuffer &keyId)
124 {
125         // command ID = CMD_GENERATE_KEY
126         TZSerializer sOut;
127         sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE));
128
129         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
130
131         TEEC_Operation op;
132         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
133                                                                         TEEC_NONE, TEEC_NONE);
134         op.params[0].value.a = algo;
135         op.params[0].value.b = keySizeBits;
136         op.params[1].memref.parent = outMemory.Get();
137         op.params[1].memref.offset = 0;
138         op.params[1].memref.size = outMemory.Get()->size;
139         Execute(CMD_GENERATE_KEY, &op);
140
141         sOut.Deserialize(outMemory);
142         sOut.Pull(keyId);
143 }
144
145 void TrustZoneContext::generateSKeyPwd(tz_algo_type algo,
146                                                                         const RawBuffer &pwd,
147                                                                         const RawBuffer &iv,
148                                                                         const uint32_t keySizeBits,
149                                                                         RawBuffer &keyId,
150                                                                         RawBuffer &pwdTag)
151 {
152         // command ID = CMD_GENERATE_KEY_PWD
153         TZSerializer sIn;
154         sIn.Push(new TZSerializablePwdData(pwd, iv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
155         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
156         sIn.Serialize(inMemory);
157
158         TZSerializer sOut;
159         sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE));
160         sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
161         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
162
163         TEEC_Operation op;
164         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
165                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
166         op.params[0].value.a = algo;
167         op.params[0].value.b = keySizeBits;
168         op.params[1].memref.parent = inMemory.Get();
169         op.params[1].memref.offset = 0;
170         op.params[1].memref.size = inMemory.Get()->size;
171         op.params[2].memref.parent = outMemory.Get();
172         op.params[2].memref.offset = 0;
173         op.params[2].memref.size = outMemory.Get()->size;
174         Execute(CMD_GENERATE_KEY_PWD, &op);
175
176         sOut.Deserialize(outMemory);
177         sOut.Pull(keyId);
178         sOut.Pull(pwdTag);
179
180         if (keyId.size() != KM_KEY_ID_SIZE) {
181                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID");
182         }
183
184         if (pwdTag.size() != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) {
185                 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag");
186         }
187 }
188
189 void TrustZoneContext::GenerateAKey(tz_command commandId,
190                                     TZSerializer &sIn,
191                                     uint32_t keySizeBits,
192                                     const RawBuffer &pubPwd,
193                                     const RawBuffer &pubPwdIv,
194                                     const RawBuffer &privPwd,
195                                     const RawBuffer &privPwdIv,
196                                     RawBuffer &pubKeyId,
197                                     RawBuffer &pubKeyTag,
198                                     RawBuffer &privKeyId,
199                                     RawBuffer &privKeyTag)
200 {
201         uint32_t pubTagSize = 0;
202         uint32_t privTagSize = 0;
203
204         uint32_t pubPwdExists = pubPwd.empty() ? 0 : 1;
205         sIn.Push(new TZSerializableFlag(pubPwdExists));
206         if (pubPwdExists) {
207                 sIn.Push(new TZSerializablePwdData(pubPwd, pubPwdIv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
208                 pubTagSize = (Params::DEFAULT_AES_GCM_TAG_LEN_BITS + 7) >> 3;
209         }
210         uint32_t privPwdExists = privPwd.empty() ? 0 : 1;
211         sIn.Push(new TZSerializableFlag(privPwdExists));
212         if (privPwdExists) {
213                 sIn.Push(new TZSerializablePwdData(privPwd, privPwdIv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
214                 privTagSize = (Params::DEFAULT_AES_GCM_TAG_LEN_BITS + 7) >> 3;
215         }
216
217         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
218         sIn.Serialize(inMemory);
219
220         TZSerializer sOut;
221         sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE));
222         sOut.Push(new TZSerializableBinary(pubTagSize));
223         sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE));
224         sOut.Push(new TZSerializableBinary(privTagSize));
225
226         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
227
228         TEEC_Operation op;
229         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
230                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
231         op.params[0].value.b = keySizeBits;
232         op.params[1].memref.parent = inMemory.Get();
233         op.params[1].memref.offset = 0;
234         op.params[1].memref.size = inMemory.Get()->size;
235         op.params[2].memref.parent = outMemory.Get();
236         op.params[2].memref.offset = 0;
237         op.params[2].memref.size = outMemory.Get()->size;
238         Execute(commandId, &op);
239
240         sOut.Deserialize(outMemory);
241
242         sOut.Pull(pubKeyId);
243         if (pubKeyId.size() != KM_KEY_ID_SIZE) {
244                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize public key ID");
245         }
246
247         if (pubPwdExists) {
248                 sOut.Pull(pubKeyTag);
249         }
250
251         sOut.Pull(privKeyId);
252         if (privKeyId.size() != KM_KEY_ID_SIZE) {
253                 ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize private key ID");
254         }
255
256         if (privPwdExists) {
257                 sOut.Pull(privKeyTag);
258         }
259 }
260
261 void TrustZoneContext::generateRSAKey(uint32_t keySizeBits,
262                                                                         const RawBuffer &pubPwd,
263                                                                         const RawBuffer &pubPwdIv,
264                                                                         const RawBuffer &privPwd,
265                                                                         const RawBuffer &privPwdIv,
266                                                                         RawBuffer &pubKeyId,
267                                                                         RawBuffer &pubKeyTag,
268                                                                         RawBuffer &privKeyId,
269                                                                         RawBuffer &privKeyTag)
270 {
271         // command ID = CMD_GENERATE_RSA_KEYPAIR
272         TZSerializer sIn;
273
274         GenerateAKey(CMD_GENERATE_RSA_KEYPAIR,
275                      sIn,
276                      keySizeBits,
277                      pubPwd,
278                      pubPwdIv,
279                      privPwd,
280                      privPwdIv,
281                      pubKeyId,
282                      pubKeyTag,
283                      privKeyId,
284                      privKeyTag);
285 }
286
287 void TrustZoneContext::generateDSAKey(uint32_t keySizeBits,
288                                                                         const RawBuffer &prime,
289                                                                         const RawBuffer &subprime,
290                                                                         const RawBuffer &base,
291                                                                         const RawBuffer &pubPwd,
292                                                                         const RawBuffer &pubPwdIv,
293                                                                         const RawBuffer &privPwd,
294                                                                         const RawBuffer &privPwdIv,
295                                                                         RawBuffer &pubKeyId,
296                                                                         RawBuffer &pubKeyTag,
297                                                                         RawBuffer &privKeyId,
298                                                                         RawBuffer &privKeyTag)
299 {
300         // command ID = CMD_GENERATE_DSA_KEYPAIR
301         TZSerializer sIn;
302         sIn.Push(new TZSerializableBinary(prime));
303         sIn.Push(new TZSerializableBinary(subprime));
304         sIn.Push(new TZSerializableBinary(base));
305
306         GenerateAKey(CMD_GENERATE_DSA_KEYPAIR,
307                      sIn,
308                      keySizeBits,
309                      pubPwd,
310                      pubPwdIv,
311                      privPwd,
312                      privPwdIv,
313                      pubKeyId,
314                      pubKeyTag,
315                      privKeyId,
316                      privKeyTag);
317 }
318
319 void TrustZoneContext::executeCrypt(tz_command cmd,
320                                                                         tz_algo_type algo,
321                                                                         const RawBuffer &keyId,
322                                                                         const Pwd &pwd,
323                                                                         const RawBuffer &iv,
324                                                                         const RawBuffer &data,
325                                                                         RawBuffer &out)
326 {
327         // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
328         if (keyId.size() != KM_KEY_ID_SIZE) {
329                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
330                         + std::to_string(keyId.size()) + ")");
331         }
332
333         TZSerializer sIn;
334         sIn.Push(new TZSerializableBinary(data));
335         int32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1;
336         sIn.Push(new TZSerializableFlag(pwd_flag));
337         if (pwd_flag)
338                 sIn.Push(new TZSerializablePwdData(pwd.getPassword(),
339                                                                            pwd.getIV(),
340                                                                            pwd.getTag().size() * 8,
341                                                                            pwd.getTag()));
342         if (algo != ALGO_RSA)
343                 sIn.Push(new TZSerializableBinary(iv));
344         sIn.Push(new TZSerializableBinary(keyId));
345
346         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
347         sIn.Serialize(inMemory);
348
349         // decrypt operation does not require padding
350         uint32_t outMemorySize = data.size();
351         if (cmd == CMD_ENCRYPT) {
352                 if (algo == ALGO_RSA) {
353                         // We don't know the key length
354                         outMemorySize = MAX_KEY_SIZE.at(ALGO_RSA);
355                 } else {
356                         outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
357                 }
358         }
359
360         TZSerializer sOut;
361         sOut.Push(new TZSerializableBinary(outMemorySize));
362         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
363
364         TEEC_Operation op;
365         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
366                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
367         op.params[0].value.a = algo;
368         op.params[1].memref.parent = inMemory.Get();
369         op.params[1].memref.offset = 0;
370         op.params[1].memref.size = inMemory.Get()->size;
371         op.params[2].memref.parent = outMemory.Get();
372         op.params[2].memref.offset = 0;
373         op.params[2].memref.size = outMemory.Get()->size;
374
375         Execute(cmd, &op);
376
377         sOut.Deserialize(outMemory);
378         sOut.Pull(out);
379 }
380
381 void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId,
382                                                                                 const Pwd &pwd,
383                                                                                 const RawBuffer &iv,
384                                                                                 int tagSizeBits,
385                                                                                 const RawBuffer &aad,
386                                                                                 const RawBuffer &data,
387                                                                                 RawBuffer &out,
388                                                                                 RawBuffer &tag)
389 {
390         // command ID = CMD_ENCRYPT (from km_ta_defines.h)
391         if (keyId.size() != KM_KEY_ID_SIZE) {
392                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
393         }
394
395         TZSerializer sIn;
396         sIn.Push(new TZSerializableBinary(data));
397         int32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1;
398         sIn.Push(new TZSerializableFlag(pwd_flag));
399         if (pwd_flag)
400                 sIn.Push(new TZSerializablePwdData(pwd.getPassword(),
401                                                                            pwd.getIV(),
402                                                                            pwd.getTag().size() * 8,
403                                                                            pwd.getTag()));
404         sIn.Push(new TZSerializableBinary(iv));
405         sIn.Push(new TZSerializableBinary(keyId));
406         sIn.Push(new TZSerializableBinary(aad));
407         sIn.Push(new TZSerializableFlag(tagSizeBits));
408
409         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
410         sIn.Serialize(inMemory);
411
412         uint32_t outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
413         uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
414
415         TZSerializer sOut;
416         sOut.Push(new TZSerializableBinary(outMemorySize));
417         sOut.Push(new TZSerializableBinary(tagSizeBytes));
418         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
419
420         TEEC_Operation op;
421         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
422                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
423         op.params[0].value.a = ALGO_AES_GCM;
424         op.params[1].memref.parent = inMemory.Get();
425         op.params[1].memref.offset = 0;
426         op.params[1].memref.size = inMemory.Get()->size;
427         op.params[2].memref.parent = outMemory.Get();
428         op.params[2].memref.offset = 0;
429         op.params[2].memref.size = outMemory.Get()->size;
430
431         Execute(CMD_ENCRYPT, &op);
432
433         sOut.Deserialize(outMemory);
434         sOut.Pull(out);
435         sOut.Pull(tag);
436 }
437
438 void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId,
439                                                                                 const Pwd &pwd,
440                                                                                 const RawBuffer &iv,
441                                                                                 int  tagSizeBits,
442                                                                                 const RawBuffer &tag,
443                                                                                 const RawBuffer &aad,
444                                                                                 const RawBuffer &data,
445                                                                                 RawBuffer &out)
446 {
447         // command ID = CMD_DECRYPT (from km_ta_defines.h)
448         if (keyId.size() != KM_KEY_ID_SIZE) {
449                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
450         }
451
452         TZSerializer sIn;
453         sIn.Push(new TZSerializableBinary(data));
454         int32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1;
455         sIn.Push(new TZSerializableFlag(pwd_flag));
456         if (pwd_flag)
457                 sIn.Push(new TZSerializablePwdData(pwd.getPassword(),
458                                                                            pwd.getIV(),
459                                                                            pwd.getTag().size() * 8,
460                                                                            pwd.getTag()));
461         sIn.Push(new TZSerializableBinary(iv));
462         sIn.Push(new TZSerializableBinary(keyId));
463         sIn.Push(new TZSerializableBinary(aad));
464         sIn.Push(new TZSerializableFlag(tagSizeBits));
465         sIn.Push(new TZSerializableBinary(tag));
466
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;
475         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
476                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
477         op.params[0].value.a = ALGO_AES_GCM;
478         op.params[1].memref.parent = inMemory.Get();
479         op.params[1].memref.offset = 0;
480         op.params[1].memref.size = inMemory.Get()->size;
481         op.params[2].memref.parent = outMemory.Get();
482         op.params[2].memref.offset = 0;
483         op.params[2].memref.size = outMemory.Get()->size;
484
485         Execute(CMD_DECRYPT, &op);
486
487         sOut.Deserialize(outMemory);
488         sOut.Pull(out);
489 }
490
491 void TrustZoneContext::executeSign(tz_algo_type algo,
492                                                                 tz_hash_type hash,
493                                                                 const RawBuffer &keyId,
494                                                                 const Pwd &pwd,
495                                                                 const RawBuffer &message,
496                                                                 RawBuffer &signature)
497 {
498         // command ID = CMD_SIGN (from km_ta_defines.h)
499         if (keyId.size() != KM_KEY_ID_SIZE) {
500                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
501                         + std::to_string(keyId.size()) + ")");
502         }
503
504         TZSerializer sIn;
505         sIn.Push(new TZSerializableBinary(message));
506         int32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1;
507         sIn.Push(new TZSerializableFlag(pwd_flag));
508         if (pwd_flag)
509                 sIn.Push(new TZSerializablePwdData(pwd.getPassword(),
510                                                                            pwd.getIV(),
511                                                                            pwd.getTag().size() * 8,
512                                                                            pwd.getTag()));
513         sIn.Push(new TZSerializableBinary(keyId));
514         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
515         sIn.Serialize(inMemory);
516
517         TZSerializer sOut;
518         sOut.Push(new TZSerializableBinary(MAX_KEY_SIZE.at(algo)));
519         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
520
521         TEEC_Operation op;
522         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
523                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
524         op.params[0].value.a = algo;
525         op.params[0].value.b = hash;
526         op.params[1].memref.parent = inMemory.Get();
527         op.params[1].memref.offset = 0;
528         op.params[1].memref.size = inMemory.Get()->size;
529         op.params[2].memref.parent = outMemory.Get();
530         op.params[2].memref.offset = 0;
531         op.params[2].memref.size = outMemory.Get()->size;
532         Execute(CMD_SIGN, &op);
533
534         sOut.Deserialize(outMemory);
535         sOut.Pull(signature);
536 }
537
538 int TrustZoneContext::executeVerify(tz_algo_type algo,
539                                                                         tz_hash_type hash,
540                                                                         const RawBuffer &keyId,
541                                                                         const Pwd &pwd,
542                                                                         const RawBuffer &message,
543                                                                         const RawBuffer &signature)
544 {
545         // command ID = CMD_VERIFY (from km_ta_defines.h)
546         if (keyId.size() != KM_KEY_ID_SIZE) {
547                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
548                         + std::to_string(keyId.size()) + ")");
549         }
550
551         TZSerializer sIn;
552         sIn.Push(new TZSerializableBinary(message));
553         sIn.Push(new TZSerializableBinary(signature));
554         int32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1;
555         sIn.Push(new TZSerializableFlag(pwd_flag));
556         if (pwd_flag)
557                 sIn.Push(new TZSerializablePwdData(pwd.getPassword(),
558                                                                            pwd.getIV(),
559                                                                            pwd.getTag().size() * 8,
560                                                                            pwd.getTag()));
561         sIn.Push(new TZSerializableBinary(keyId));
562         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
563         sIn.Serialize(inMemory);
564
565         TEEC_Operation op;
566         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
567                                                                         TEEC_NONE, TEEC_NONE);
568         op.params[0].value.a = algo;
569         op.params[0].value.b = hash;
570         op.params[1].memref.parent = inMemory.Get();
571         op.params[1].memref.offset = 0;
572         op.params[1].memref.size = inMemory.Get()->size;
573         Execute(CMD_VERIFY, &op);
574
575         int opRet = op.params[0].value.a;
576         switch (opRet) {
577         case KM_TA_SUCCESS:
578                 return CKM_API_SUCCESS;
579         case KM_TA_ERROR_SIGNATURE:
580                 LogWarning("Signature verification failed");
581                 return CKM_API_ERROR_VERIFICATION_FAILED;
582         default:
583                 assert(false); // This condition should be checked inside Execute() function
584                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet);
585         }
586 }
587
588 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
589 {
590         // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
591         if (keyId.size() != KM_KEY_ID_SIZE) {
592                 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
593         }
594
595         TZSerializer sIn;
596         sIn.Push(new TZSerializableBinary(keyId));
597         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
598         sIn.Serialize(inMemory);
599
600         TEEC_Operation op;
601         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE,
602                                                                         TEEC_NONE, TEEC_NONE);
603         op.params[1].memref.parent = inMemory.Get();
604         op.params[1].memref.offset = 0;
605         op.params[1].memref.size = inMemory.Get()->size;
606         Execute(CMD_DESTROY_KEY, &op);
607 }
608
609 void TrustZoneContext::importData(
610                                 const uint32_t dataType,
611                                 const RawBuffer &data,
612                                 const Crypto::EncryptionParams &encData,
613                                 const RawBuffer &pwd,
614                                 const RawBuffer &iv,
615                                 const uint32_t keySizeBits,
616                                 const uint32_t pwdTagSizeBits,
617                                 RawBuffer &dataId,
618                                 RawBuffer &pwdTag)
619 {
620         // command ID = CMD_IMPORT_DATA
621         TZSerializer sIn;
622         sIn.Push(new TZSerializableFlag(dataType));
623         sIn.Push(new TZSerializableBinary(data));
624         sIn.Push(new TZSerializableFlag(keySizeBits));
625         sIn.Push(new TZSerializableBinary(encData.iv));
626         sIn.Push(new TZSerializableBinary(encData.tag));
627
628         uint32_t pwd_flag = pwd.empty() ? 0 : 1;
629         sIn.Push(new TZSerializableFlag(pwd_flag));
630         if (pwd_flag)
631                 sIn.Push(new TZSerializablePwdData(pwd, iv, pwdTagSizeBits));
632
633         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
634         sIn.Serialize(inMemory);
635
636
637         TZSerializer sOut;
638         sOut.Push(new TZSerializableBinary(KM_DATA_ID_SIZE));
639         if (pwd_flag) {
640                 sOut.Push(new TZSerializableBinary(pwdTagSizeBits / 8));
641         }
642
643         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
644
645         TEEC_Operation op;
646         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
647                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
648         op.params[1].memref.parent = inMemory.Get();
649         op.params[1].memref.offset = 0;
650         op.params[1].memref.size = inMemory.Get()->size;
651         op.params[2].memref.parent = outMemory.Get();
652         op.params[2].memref.offset = 0;
653         op.params[2].memref.size = outMemory.Get()->size;
654
655         Execute(CMD_IMPORT_DATA, &op);
656
657         sOut.Deserialize(outMemory);
658         sOut.Pull(dataId);
659         if (pwd_flag) {
660                 sOut.Pull(pwdTag);
661         }
662
663         LogDebug("Imported object ID is (hex): " << rawToHexString(dataId));
664 }
665
666 void TrustZoneContext::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize)
667 {
668         // command ID = CMD_GET_DATA_SIZE
669         LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
670
671         TZSerializer sIn;
672         sIn.Push(new TZSerializableBinary(dataId));
673
674         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
675         sIn.Serialize(inMemory);
676
677         TEEC_Operation op;
678         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE,
679                                                                         TEEC_NONE, TEEC_NONE);
680
681         op.params[1].memref.parent = inMemory.Get();
682         op.params[1].memref.offset = 0;
683         op.params[1].memref.size = inMemory.Get()->size;
684         Execute(CMD_GET_DATA_SIZE, &op);
685         dataSize = op.params[0].value.b;
686 }
687
688 void TrustZoneContext::getData(const RawBuffer &dataId,
689                          const Pwd &pwd,
690                          RawBuffer &data)
691 {
692         // command ID = CMD_GET_DATA
693         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
694
695         TZSerializer sIn;
696         sIn.Push(new TZSerializableBinary(dataId));
697
698         uint32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1;
699         sIn.Push(new TZSerializableFlag(pwd_flag));
700
701         if (pwd_flag) {
702                 sIn.Push(new TZSerializablePwdData(pwd.getPassword(),
703                                                   pwd.getIV(),
704                                                   Params::DEFAULT_AES_GCM_TAG_LEN_BITS,
705                                                   pwd.getTag()));
706         }
707
708         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
709         sIn.Serialize(inMemory);
710
711         uint32_t data_size = 0;
712         GetDataSize(dataId, data_size);
713
714         TZSerializer sOut;
715         sOut.Push(new TZSerializableBinary(data_size));
716         TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
717         sOut.Serialize(outMemory);
718
719         TEEC_Operation op;
720         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE,
721                                                                         TEEC_MEMREF_WHOLE, TEEC_NONE);
722         op.params[1].memref.parent = inMemory.Get();
723         op.params[1].memref.offset = 0;
724         op.params[1].memref.size = inMemory.Get()->size;
725         op.params[2].memref.parent = outMemory.Get();
726         op.params[2].memref.offset = 0;
727         op.params[2].memref.size = outMemory.Get()->size;
728
729         Execute(CMD_GET_DATA, &op);
730
731         sOut.Deserialize(outMemory);
732         sOut.Pull(data);
733 }
734
735
736 void TrustZoneContext::destroyData(const RawBuffer &dataId)
737 {
738         //      command ID = CMD_DESTROY_DATA
739         LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
740         TZSerializer sIn;
741         sIn.Push(new TZSerializableBinary(dataId));
742
743         TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
744         sIn.Serialize(inMemory);
745
746         TEEC_Operation op;
747         op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE,
748                                                                         TEEC_NONE, TEEC_NONE);
749
750         op.params[1].memref.parent = inMemory.Get();
751         op.params[1].memref.offset = 0;
752         op.params[1].memref.size = inMemory.Get()->size;
753         Execute(CMD_DESTROY_DATA, &op);
754 }
755
756 void TrustZoneContext::Initialize()
757 {
758         TEEC_Operation op;
759         TEEC_Result result;
760         uint32_t retOrigin;
761
762         op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
763
764         result = TEEC_InitializeContext(nullptr, &m_Context);
765         if (result != TEEC_SUCCESS) {
766                 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
767         }
768         m_ContextInitialized = true;
769
770         result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
771         if (result != TEEC_SUCCESS) {
772                 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
773         }
774         m_SessionInitialized = true;
775 }
776
777 void TrustZoneContext::Destroy()
778 {
779         if (m_SessionInitialized) {
780                 TEEC_CloseSession(&m_Session);
781                 m_SessionInitialized = false;
782         }
783
784         if (m_ContextInitialized) {
785                 TEEC_FinalizeContext(&m_Context);
786                 m_ContextInitialized = false;
787         }
788 }
789
790 void TrustZoneContext::Reload()
791 {
792         Destroy();
793         Initialize();
794 }
795
796 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
797 {
798         uint32_t retOrigin = 0;
799         LogDebug("Executing TZ operation " << commandID);
800
801         TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
802         if (result != TEEC_SUCCESS) {
803                 switch (result) {
804                 case TEEC_ERROR_TARGET_DEAD:
805                         Reload();
806                         ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
807                                         static_cast<unsigned int>(commandID));
808                 case TEEC_ERROR_BAD_PARAMETERS:
809                         ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
810                 default:
811                         ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
812                                         static_cast<unsigned int>(commandID), " with error: ", std::hex,
813                                         static_cast<unsigned int>(result), " with origin: ", std::hex,
814                                         retOrigin);
815                 }
816         }
817
818         int ta_ret = op->params[0].value.a;
819         switch (ta_ret) {
820         case KM_TA_SUCCESS:
821         case KM_TA_ERROR_SIGNATURE:
822                 break;
823         case KM_TA_ERROR_AUTH_FAILED:
824                 // Authentication cipher failed - notify with proper exception
825                 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
826         default:
827                 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
828         }
829 }
830
831 } // namespace Internals
832 } // namespace TZ
833 } // namespace Crypto
834 } // namespace CKM