2 * Copyright (c) 2017-2021 Samsung Electronics Co., Ltd. All rights reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 * @file tz-context.cpp
18 * @author Lukasz Kostyra (l.kostyra@samsung.com)
22 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
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>
31 #include <km_serialization.h>
32 #include <km_ta_defines.h>
37 #include <unordered_map>
46 // A little bit of extra memory to add to output buffers.
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;
53 // Identifier of our TA
54 const TEEC_UUID KEY_MANAGER_TA_UUID = KM_TA_UUID;
56 //raw to hex string conversion to print persistent storage data ID
57 static std::string rawToHexString(const RawBuffer &raw)
59 return hexDump<std::string>(raw);
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.
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 }
73 const RawBuffer &password;
78 void push(TZSerializer& ser, const T& value)
80 ser.Push(new TZSerializableFlag(static_cast<uint32_t>(value)));
84 void push<RawBuffer>(TZSerializer& ser, const RawBuffer& value)
86 ser.Push(new TZSerializableBinary(value));
90 void push<Pwd>(TZSerializer& ser, const Pwd& value)
92 int32_t pwd_flag = value.getPassword().empty() ? 0 : 1;
93 ser.Push(new TZSerializableFlag(pwd_flag));
95 ser.Push(new TZSerializablePwdData(value.getPassword(),
97 value.getTag().size() * 8,
102 void push<EncPwd>(TZSerializer& ser, const EncPwd& value)
104 int32_t pwd_flag = value.password.empty() ? 0 : 1;
105 ser.Push(new TZSerializableFlag(pwd_flag));
107 ser.Push(new TZSerializablePwdData(value.password,
109 Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
112 template <typename T, typename ...Args>
113 void push(TZSerializer& ser, const T& first, const Args&... args)
116 push<Args...>(ser, args...);
119 template <typename ...Args>
120 TZSerializer makeSerializer(const Args&... args)
123 push<Args...>(ser, args...);
127 } // anonymous namespace
129 TrustZoneContext::TrustZoneContext()
130 : m_ContextInitialized(false)
131 , m_SessionInitialized(false)
136 TrustZoneContext::~TrustZoneContext()
141 TrustZoneContext& TrustZoneContext::Instance()
143 static TrustZoneContext instance;
147 TEEC_Operation makeOp(uint32_t value, TrustZoneMemory& mem1)
151 op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_NONE, TEEC_NONE);
153 op.params[1].memref.parent = mem1.Get();
154 op.params[1].memref.offset = 0;
155 op.params[1].memref.size = mem1.Get()->size;
159 TEEC_Operation makeOp(uint32_t value, TrustZoneMemory& mem1, TrustZoneMemory& mem2)
161 TEEC_Operation op = makeOp(value, mem1);
163 op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_MEMREF_WHOLE, TEEC_NONE);
165 op.params[2].memref.parent = mem2.Get();
166 op.params[2].memref.offset = 0;
167 op.params[2].memref.size = mem2.Get()->size;
172 void TrustZoneContext::generateIV(RawBuffer& iv)
174 // command ID = CMD_GENERATE_IV
175 // IV generation is a simple call - no need to serialize data
176 // just provide the output buffer with size equal to iv.
177 uint32_t ivSize = Params::DEFAULT_AES_IV_LEN;
178 TrustZoneMemory ivMemory(m_Context, ivSize, TEEC_MEM_OUTPUT);
180 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, ivMemory);
182 Execute(CMD_GENERATE_IV, &op);
185 memcpy(iv.data(), ivMemory.Get()->buffer, ivMemory.Get()->size);
188 void TrustZoneContext::generateSKey(tz_algo_type algo,
189 uint32_t keySizeBits,
190 const RawBuffer &hash)
192 // command ID = CMD_GENERATE_KEY
193 auto sIn = makeSerializer(hash);
194 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
195 sIn.Serialize(inMemory);
197 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
198 op.params[0].value.a = algo;
199 op.params[0].value.b = keySizeBits;
201 Execute(CMD_GENERATE_KEY, &op);
204 void TrustZoneContext::generateSKeyPwd(tz_algo_type algo,
205 const RawBuffer &pwd,
207 const uint32_t keySizeBits,
209 const RawBuffer &hash)
211 // command ID = CMD_GENERATE_KEY_PWD
213 sIn.Push(new TZSerializablePwdData(pwd, iv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
214 sIn.Push(new TZSerializableBinary(hash));
215 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
216 sIn.Serialize(inMemory);
219 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
220 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
222 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
223 op.params[0].value.a = algo;
224 op.params[0].value.b = keySizeBits;
226 Execute(CMD_GENERATE_KEY_PWD, &op);
228 sOut.Deserialize(outMemory);
231 if (pwdTag.size() != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) {
232 ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag");
236 void TrustZoneContext::GenerateAKey(tz_command commandId,
238 uint32_t keySizeBits,
239 const RawBuffer &pubPwd,
240 const RawBuffer &pubPwdIv,
241 const RawBuffer &privPwd,
242 const RawBuffer &privPwdIv,
243 RawBuffer &pubKeyTag,
244 RawBuffer &privKeyTag,
245 const RawBuffer &hashPriv,
246 const RawBuffer &hashPub)
248 uint32_t pubTagSize = 0;
249 uint32_t privTagSize = 0;
250 uint32_t pubPwdExists = pubPwd.empty() ? 0 : 1;
252 pubTagSize = Params::DEFAULT_AES_GCM_TAG_LEN_BYTES;
254 uint32_t privPwdExists = privPwd.empty() ? 0 : 1;
256 privTagSize = Params::DEFAULT_AES_GCM_TAG_LEN_BYTES;
259 push(sIn, EncPwd{pubPwd, pubPwdIv}, EncPwd{privPwd, privPwdIv}, hashPriv, hashPub);
260 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
261 sIn.Serialize(inMemory);
264 sOut.Push(new TZSerializableBinary(pubTagSize));
265 sOut.Push(new TZSerializableBinary(privTagSize));
267 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
269 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
270 op.params[0].value.b = keySizeBits;
272 Execute(commandId, &op);
274 sOut.Deserialize(outMemory);
276 sOut.Pull(pubKeyTag);
280 sOut.Pull(privKeyTag);
284 void TrustZoneContext::generateRSAKey(uint32_t keySizeBits,
285 const RawBuffer &pubPwd,
286 const RawBuffer &pubPwdIv,
287 const RawBuffer &privPwd,
288 const RawBuffer &privPwdIv,
289 RawBuffer &pubKeyTag,
290 RawBuffer &privKeyTag,
291 const RawBuffer &hashPriv,
292 const RawBuffer &hashPub)
294 // command ID = CMD_GENERATE_RSA_KEYPAIR
297 GenerateAKey(CMD_GENERATE_RSA_KEYPAIR,
310 void TrustZoneContext::generateDSAKey(uint32_t keySizeBits,
311 const RawBuffer &prime,
312 const RawBuffer &subprime,
313 const RawBuffer &base,
314 const RawBuffer &pubPwd,
315 const RawBuffer &pubPwdIv,
316 const RawBuffer &privPwd,
317 const RawBuffer &privPwdIv,
318 RawBuffer &pubKeyTag,
319 RawBuffer &privKeyTag,
320 const RawBuffer &hashPriv,
321 const RawBuffer &hashPub)
323 // command ID = CMD_GENERATE_DSA_KEYPAIR
324 auto sIn = makeSerializer(prime, subprime, base);
326 GenerateAKey(CMD_GENERATE_DSA_KEYPAIR,
339 void TrustZoneContext::executeCrypt(tz_command cmd,
341 const RawBuffer &keyId,
344 const RawBuffer &data,
347 // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
348 if (keyId.size() != KM_KEY_ID_SIZE) {
349 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
350 + std::to_string(keyId.size()) + ")");
354 if (algo == ALGO_RSA)
355 sIn = makeSerializer(data, pwd, keyId);
357 sIn = makeSerializer(data, pwd, iv, keyId);
359 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
360 sIn.Serialize(inMemory);
362 // decrypt operation does not require padding
363 uint32_t outMemorySize = data.size();
364 if (cmd == CMD_ENCRYPT) {
365 if (algo == ALGO_RSA) {
366 // We don't know the key length
367 outMemorySize = MAX_KEY_SIZE.at(ALGO_RSA);
369 outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
374 sOut.Push(new TZSerializableBinary(outMemorySize, false));
375 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
377 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
378 op.params[0].value.a = algo;
382 sOut.Deserialize(outMemory);
386 void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId,
390 const RawBuffer &aad,
391 const RawBuffer &data,
395 // command ID = CMD_ENCRYPT (from km_ta_defines.h)
396 if (keyId.size() != KM_KEY_ID_SIZE) {
397 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
400 auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits);
401 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
402 sIn.Serialize(inMemory);
404 uint32_t outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
405 uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
408 sOut.Push(new TZSerializableBinary(outMemorySize, false));
409 sOut.Push(new TZSerializableBinary(tagSizeBytes));
410 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
412 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
413 op.params[0].value.a = ALGO_AES_GCM;
415 Execute(CMD_ENCRYPT, &op);
417 sOut.Deserialize(outMemory);
422 void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId,
426 const RawBuffer &tag,
427 const RawBuffer &aad,
428 const RawBuffer &data,
431 // command ID = CMD_DECRYPT (from km_ta_defines.h)
432 if (keyId.size() != KM_KEY_ID_SIZE) {
433 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
436 auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits, tag);
437 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
438 sIn.Serialize(inMemory);
441 sOut.Push(new TZSerializableBinary(data.size()));
442 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
444 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
445 op.params[0].value.a = ALGO_AES_GCM;
447 Execute(CMD_DECRYPT, &op);
449 sOut.Deserialize(outMemory);
453 void TrustZoneContext::executeSign(tz_algo_type algo,
455 const RawBuffer &keyId,
457 const RawBuffer &message,
458 RawBuffer &signature)
460 // command ID = CMD_SIGN (from km_ta_defines.h)
461 if (keyId.size() != KM_KEY_ID_SIZE) {
462 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
463 + std::to_string(keyId.size()) + ")");
466 auto sIn = makeSerializer(message, pwd, keyId);
467 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
468 sIn.Serialize(inMemory);
471 sOut.Push(new TZSerializableBinary(MAX_KEY_SIZE.at(algo), false));
472 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
474 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
475 op.params[0].value.a = algo;
476 op.params[0].value.b = hash;
478 Execute(CMD_SIGN, &op);
480 sOut.Deserialize(outMemory);
481 sOut.Pull(signature);
484 int TrustZoneContext::executeVerify(tz_algo_type algo,
486 const RawBuffer &keyId,
488 const RawBuffer &message,
489 const RawBuffer &signature)
491 // command ID = CMD_VERIFY (from km_ta_defines.h)
492 if (keyId.size() != KM_KEY_ID_SIZE) {
493 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
494 + std::to_string(keyId.size()) + ")");
497 auto sIn = makeSerializer(message, signature, pwd, keyId);
498 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
499 sIn.Serialize(inMemory);
501 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
502 op.params[0].value.a = algo;
503 op.params[0].value.b = hash;
505 Execute(CMD_VERIFY, &op);
507 int opRet = op.params[0].value.a;
510 return CKM_API_SUCCESS;
511 case KM_TA_ERROR_SIGNATURE:
512 LogWarning("Signature verification failed");
513 return CKM_API_ERROR_VERIFICATION_FAILED;
515 assert(false); // This condition should be checked inside Execute() function
516 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet);
520 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
522 // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
523 if (keyId.size() != KM_KEY_ID_SIZE) {
524 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
527 auto sIn = makeSerializer(keyId);
528 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
529 sIn.Serialize(inMemory);
531 TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
533 Execute(CMD_DESTROY_KEY, &op);
536 void TrustZoneContext::importData(
537 const uint32_t dataType,
538 const RawBuffer &data,
539 const Crypto::EncryptionParams &encData,
540 const RawBuffer &pwd,
542 const uint32_t keySizeBits,
544 const RawBuffer &hash)
546 // command ID = CMD_IMPORT_DATA
547 LogDebug("TrustZoneContext::importData data size = [" << data.size() << "]");
549 auto sIn = makeSerializer(
550 dataType, data, keySizeBits, encData.iv, encData.tag, EncPwd{pwd, iv}, hash);
552 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
553 sIn.Serialize(inMemory);
557 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
560 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
562 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
564 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
566 Execute(CMD_IMPORT_DATA, &op);
569 sOut.Deserialize(outMemory);
573 LogDebug("Imported object ID is (hex): " << rawToHexString(hash));
576 void TrustZoneContext::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize)
578 // command ID = CMD_GET_DATA_SIZE
579 LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
581 auto sIn = makeSerializer(dataId);
582 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
583 sIn.Serialize(inMemory);
585 TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
587 Execute(CMD_GET_DATA_SIZE, &op);
588 dataSize = op.params[0].value.b;
591 void TrustZoneContext::getData(const RawBuffer &dataId,
595 // command ID = CMD_GET_DATA
596 LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
598 auto sIn = makeSerializer(dataId, pwd);
599 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
600 sIn.Serialize(inMemory);
602 uint32_t data_size = 0;
603 GetDataSize(dataId, data_size);
605 LogDebug("GetData data_size = [" << data_size << "]");
608 sOut.Push(new TZSerializableBinary(data_size));
609 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
610 sOut.Serialize(outMemory);
612 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
614 Execute(CMD_GET_DATA, &op);
616 sOut.Deserialize(outMemory);
621 void TrustZoneContext::destroyData(const RawBuffer &dataId)
623 // command ID = CMD_DESTROY_DATA
624 LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
625 auto sIn = makeSerializer(dataId);
626 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
627 sIn.Serialize(inMemory);
629 TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
631 Execute(CMD_DESTROY_DATA, &op);
634 void TrustZoneContext::Initialize()
640 op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
642 result = TEEC_InitializeContext(nullptr, &m_Context);
643 if (result != TEEC_SUCCESS) {
644 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
646 m_ContextInitialized = true;
648 result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
649 if (result != TEEC_SUCCESS) {
650 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
652 m_SessionInitialized = true;
655 void TrustZoneContext::Destroy()
657 if (m_SessionInitialized) {
658 TEEC_CloseSession(&m_Session);
659 m_SessionInitialized = false;
662 if (m_ContextInitialized) {
663 TEEC_FinalizeContext(&m_Context);
664 m_ContextInitialized = false;
668 void TrustZoneContext::Reload()
674 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
676 uint32_t retOrigin = 0;
677 LogDebug("Executing TZ operation " << commandID);
679 TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
680 if (result != TEEC_SUCCESS) {
682 case TEEC_ERROR_TARGET_DEAD:
684 ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
685 static_cast<unsigned int>(commandID));
686 case TEEC_ERROR_BAD_PARAMETERS:
687 ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
689 ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
690 static_cast<unsigned int>(commandID), " with error: ", std::hex,
691 static_cast<unsigned int>(result), " with origin: ", std::hex,
696 int ta_ret = op->params[0].value.a;
699 case KM_TA_ERROR_SIGNATURE:
701 case KM_TA_ERROR_AUTH_FAILED:
702 // Authentication cipher failed - notify with proper exception
703 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
705 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
709 } // namespace Internals
711 } // namespace Crypto