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 genParam, // key size in bits or EC type
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 = genParam;
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::generateECKey(tz_ec ec,
340 const RawBuffer &pubPwd,
341 const RawBuffer &pubPwdIv,
342 const RawBuffer &privPwd,
343 const RawBuffer &privPwdIv,
344 RawBuffer &pubKeyTag,
345 RawBuffer &privKeyTag,
346 const RawBuffer &hashPriv,
347 const RawBuffer &hashPub)
349 // command ID = CMD_GENERATE_EC_KEYPAIR
352 GenerateAKey(CMD_GENERATE_EC_KEYPAIR,
354 static_cast<uint32_t>(ec),
365 void TrustZoneContext::executeCrypt(tz_command cmd,
367 const RawBuffer &keyId,
370 const RawBuffer &data,
373 // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h)
374 if (keyId.size() != KM_KEY_ID_SIZE) {
375 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
376 + std::to_string(keyId.size()) + ")");
380 if (algo == ALGO_RSA)
381 sIn = makeSerializer(data, pwd, keyId);
383 sIn = makeSerializer(data, pwd, iv, keyId);
385 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
386 sIn.Serialize(inMemory);
388 // decrypt operation does not require padding
389 uint32_t outMemorySize = data.size();
390 if (cmd == CMD_ENCRYPT) {
391 if (algo == ALGO_RSA) {
392 // We don't know the key length
393 outMemorySize = MAX_KEY_SIZE.at(ALGO_RSA);
395 outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
400 sOut.Push(new TZSerializableBinary(outMemorySize, false));
401 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
403 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
404 op.params[0].value.a = algo;
408 sOut.Deserialize(outMemory);
412 void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId,
416 const RawBuffer &aad,
417 const RawBuffer &data,
421 // command ID = CMD_ENCRYPT (from km_ta_defines.h)
422 if (keyId.size() != KM_KEY_ID_SIZE) {
423 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
426 auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits);
427 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
428 sIn.Serialize(inMemory);
430 uint32_t outMemorySize = static_cast<uint32_t>(data.size() + CIPHER_EXTRA_PADDING_SIZE);
431 uint32_t tagSizeBytes = (tagSizeBits + 7) / 8;
434 sOut.Push(new TZSerializableBinary(outMemorySize, false));
435 sOut.Push(new TZSerializableBinary(tagSizeBytes));
436 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
438 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
439 op.params[0].value.a = ALGO_AES_GCM;
441 Execute(CMD_ENCRYPT, &op);
443 sOut.Deserialize(outMemory);
448 void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId,
452 const RawBuffer &tag,
453 const RawBuffer &aad,
454 const RawBuffer &data,
457 // command ID = CMD_DECRYPT (from km_ta_defines.h)
458 if (keyId.size() != KM_KEY_ID_SIZE) {
459 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
462 auto sIn = makeSerializer(data, pwd, iv, keyId, aad, tagSizeBits, tag);
463 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
464 sIn.Serialize(inMemory);
467 sOut.Push(new TZSerializableBinary(data.size()));
468 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
470 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
471 op.params[0].value.a = ALGO_AES_GCM;
473 Execute(CMD_DECRYPT, &op);
475 sOut.Deserialize(outMemory);
479 void TrustZoneContext::executeSign(tz_algo_type algo,
481 const RawBuffer &keyId,
483 const RawBuffer &message,
484 RawBuffer &signature)
486 // command ID = CMD_SIGN (from km_ta_defines.h)
487 if (keyId.size() != KM_KEY_ID_SIZE) {
488 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
489 + std::to_string(keyId.size()) + ")");
492 auto sIn = makeSerializer(message, pwd, keyId);
493 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
494 sIn.Serialize(inMemory);
497 sOut.Push(new TZSerializableBinary(MAX_KEY_SIZE.at(algo), false));
498 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
500 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
501 op.params[0].value.a = algo;
502 op.params[0].value.b = hash;
504 Execute(CMD_SIGN, &op);
506 sOut.Deserialize(outMemory);
507 sOut.Pull(signature);
510 int TrustZoneContext::executeVerify(tz_algo_type algo,
512 const RawBuffer &keyId,
514 const RawBuffer &message,
515 const RawBuffer &signature)
517 // command ID = CMD_VERIFY (from km_ta_defines.h)
518 if (keyId.size() != KM_KEY_ID_SIZE) {
519 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = "
520 + std::to_string(keyId.size()) + ")");
523 auto sIn = makeSerializer(message, signature, pwd, keyId);
524 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
525 sIn.Serialize(inMemory);
527 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
528 op.params[0].value.a = algo;
529 op.params[0].value.b = hash;
531 Execute(CMD_VERIFY, &op);
533 int opRet = op.params[0].value.a;
536 return CKM_API_SUCCESS;
537 case KM_TA_ERROR_SIGNATURE:
538 LogWarning("Signature verification failed");
539 return CKM_API_ERROR_VERIFICATION_FAILED;
541 assert(false); // This condition should be checked inside Execute() function
542 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet);
546 void TrustZoneContext::executeDestroy(const RawBuffer &keyId)
548 // command ID = CMD_DESTROY_KEY (from km_ta_defines.h)
549 if (keyId.size() != KM_KEY_ID_SIZE) {
550 ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer");
553 auto sIn = makeSerializer(keyId);
554 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
555 sIn.Serialize(inMemory);
557 TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
559 Execute(CMD_DESTROY_KEY, &op);
562 void TrustZoneContext::importData(
563 const uint32_t dataType,
564 const RawBuffer &data,
565 const Crypto::EncryptionParams &encData,
566 const RawBuffer &pwd,
568 const uint32_t keySizeBits,
570 const RawBuffer &hash)
572 // command ID = CMD_IMPORT_DATA
573 LogDebug("TrustZoneContext::importData data size = [" << data.size() << "]");
575 auto sIn = makeSerializer(
576 dataType, data, keySizeBits, encData.iv, encData.tag, EncPwd{pwd, iv}, hash);
578 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
579 sIn.Serialize(inMemory);
583 sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
586 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
588 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
590 op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
592 Execute(CMD_IMPORT_DATA, &op);
595 sOut.Deserialize(outMemory);
599 LogDebug("Imported object ID is (hex): " << rawToHexString(hash));
602 void TrustZoneContext::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize)
604 // command ID = CMD_GET_DATA_SIZE
605 LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId));
607 auto sIn = makeSerializer(dataId);
608 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
609 sIn.Serialize(inMemory);
611 TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
613 Execute(CMD_GET_DATA_SIZE, &op);
614 dataSize = op.params[0].value.b;
617 void TrustZoneContext::getData(const RawBuffer &dataId,
621 // command ID = CMD_GET_DATA
622 LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
624 auto sIn = makeSerializer(dataId, pwd);
625 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
626 sIn.Serialize(inMemory);
628 uint32_t data_size = 0;
629 GetDataSize(dataId, data_size);
631 LogDebug("GetData data_size = [" << data_size << "]");
634 sOut.Push(new TZSerializableBinary(data_size));
635 TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
636 sOut.Serialize(outMemory);
638 TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
640 Execute(CMD_GET_DATA, &op);
642 sOut.Deserialize(outMemory);
647 void TrustZoneContext::destroyData(const RawBuffer &dataId)
649 // command ID = CMD_DESTROY_DATA
650 LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId));
651 auto sIn = makeSerializer(dataId);
652 TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
653 sIn.Serialize(inMemory);
655 TEEC_Operation op = makeOp(TEEC_VALUE_OUTPUT, inMemory);
657 Execute(CMD_DESTROY_DATA, &op);
660 void TrustZoneContext::Initialize()
666 op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
668 result = TEEC_InitializeContext(nullptr, &m_Context);
669 if (result != TEEC_SUCCESS) {
670 ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result);
672 m_ContextInitialized = true;
674 result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin);
675 if (result != TEEC_SUCCESS) {
676 ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result);
678 m_SessionInitialized = true;
681 void TrustZoneContext::Destroy()
683 if (m_SessionInitialized) {
684 TEEC_CloseSession(&m_Session);
685 m_SessionInitialized = false;
688 if (m_ContextInitialized) {
689 TEEC_FinalizeContext(&m_Context);
690 m_ContextInitialized = false;
694 void TrustZoneContext::Reload()
700 void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op)
702 uint32_t retOrigin = 0;
703 LogDebug("Executing TZ operation " << commandID);
705 TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast<unsigned int>(commandID), op, &retOrigin);
706 if (result != TEEC_SUCCESS) {
708 case TEEC_ERROR_TARGET_DEAD:
710 ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ",
711 static_cast<unsigned int>(commandID));
712 case TEEC_ERROR_BAD_PARAMETERS:
713 ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA");
715 ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ",
716 static_cast<unsigned int>(commandID), " with error: ", std::hex,
717 static_cast<unsigned int>(result), " with origin: ", std::hex,
722 int ta_ret = op->params[0].value.a;
725 case KM_TA_ERROR_SIGNATURE:
727 case KM_TA_ERROR_AUTH_FAILED:
728 // Authentication cipher failed - notify with proper exception
729 ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed");
731 ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret);
735 } // namespace Internals
737 } // namespace Crypto