From b69ec951ea341627a7670d202a1873553ca266ec Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 25 Jul 2017 14:59:49 +0200 Subject: [PATCH] tz-backend: Implement symmetric encryption through TA Change-Id: Id1b563f099e1671fb5fbcca9ca08757b34b1dfd8 --- packaging/key-manager.spec | 4 + src/CMakeLists.txt | 5 + .../crypto/generic-backend/algo-validation.h | 2 +- src/manager/crypto/generic-backend/crypto-params.h | 38 + src/manager/crypto/platform/decider.cpp | 65 +- src/manager/crypto/sw-backend/internals.cpp | 10 +- src/manager/crypto/sw-backend/store.cpp | 13 +- src/manager/crypto/tz-backend/internals.cpp | 350 +++++++++ src/manager/crypto/tz-backend/internals.h | 104 +++ src/manager/crypto/tz-backend/obj.cpp | 74 +- src/manager/crypto/tz-backend/obj.h | 87 ++- src/manager/crypto/tz-backend/store.cpp | 133 +++- src/manager/crypto/tz-backend/store.h | 9 +- src/manager/crypto/tz-backend/tz-context.cpp | 810 +++++++++++++++++++++ src/manager/crypto/tz-backend/tz-context.h | 109 +++ src/manager/crypto/tz-backend/tz-memory.cpp | 72 ++ src/manager/crypto/tz-backend/tz-memory.h | 54 ++ tests/CMakeLists.txt | 4 + tools/ckm_db_tool/CMakeLists.txt | 6 + 19 files changed, 1900 insertions(+), 49 deletions(-) create mode 100644 src/manager/crypto/generic-backend/crypto-params.h create mode 100644 src/manager/crypto/tz-backend/internals.cpp create mode 100644 src/manager/crypto/tz-backend/internals.h create mode 100644 src/manager/crypto/tz-backend/tz-context.cpp create mode 100644 src/manager/crypto/tz-backend/tz-context.h create mode 100644 src/manager/crypto/tz-backend/tz-memory.cpp create mode 100644 src/manager/crypto/tz-backend/tz-memory.h diff --git a/packaging/key-manager.spec b/packaging/key-manager.spec index cf9518b..d953b27 100644 --- a/packaging/key-manager.spec +++ b/packaging/key-manager.spec @@ -35,8 +35,12 @@ BuildRequires: pkgconfig(argos_watchdog) %endif BuildRequires: boost-devel BuildRequires: ca-certificates-devel +BuildRequires: key-manager-ta-devel +BuildRequires: key-manager-ta-serialization-devel +BuildRequires: pkgconfig(tef-libteec) #Requires(pre): tizen-platform-config-tools Requires: libkey-manager-common = %{version}-%{release} + %{?systemd_requires} %global user_name key-manager diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9eeaab7..ea04f25 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,6 +20,7 @@ PKG_CHECK_MODULES(KEY_MANAGER_DEP cynara-creds-socket pkgmgr vconf + tef-libteec ${EXTRA_KM_DEPS} ) FIND_PACKAGE(Threads REQUIRED) @@ -77,6 +78,9 @@ SET(KEY_MANAGER_SOURCES ${KEY_MANAGER_PATH}/crypto/platform/decider.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/obj.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/store.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/internals.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-context.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-memory.cpp ${SECURITY_MANAGER_WRAPPER_PATH} ${CYNARA_WRAPPER_PATH} ) @@ -112,6 +116,7 @@ TARGET_LINK_LIBRARIES(${TARGET_KEY_MANAGER} ${KEY_MANAGER_DEP_LIBRARIES} ${TARGET_KEY_MANAGER_COMMON} -ldl + km_serialization ) ################################################################################ diff --git a/src/manager/crypto/generic-backend/algo-validation.h b/src/manager/crypto/generic-backend/algo-validation.h index b4621df..dc14966 100644 --- a/src/manager/crypto/generic-backend/algo-validation.h +++ b/src/manager/crypto/generic-backend/algo-validation.h @@ -131,7 +131,7 @@ struct DefaultGetter { }; template <> -void DefaultGetter::Print(std::ostringstream &os, +inline void DefaultGetter::Print(std::ostringstream &os, const RawBuffer &buffer) { os << "[" << buffer.size() << "B buffer]"; diff --git a/src/manager/crypto/generic-backend/crypto-params.h b/src/manager/crypto/generic-backend/crypto-params.h new file mode 100644 index 0000000..ae23fba --- /dev/null +++ b/src/manager/crypto/generic-backend/crypto-params.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file crypto-params.h + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + */ + #pragma once + +namespace CKM { +namespace Crypto { + +class Params +{ +public: + static const size_t DEFAULT_AES_IV_LEN = 16; // max acceptable size of IV + static const int DEFAULT_AES_GCM_TAG_LEN_BYTES = 16; // length of AES GCM tag + static const int DEFAULT_AES_GCM_TAG_LEN_BITS = DEFAULT_AES_GCM_TAG_LEN_BYTES * 8; + static const int DERIVED_KEY_LENGTH = 16; // length of AES key derived from password in bytes + static const int DERIVED_KEY_LENGTH_BITS = DERIVED_KEY_LENGTH * 8; // as above, in bits + static const int DERIVED_KEY_ITERATIONS = 1024; // iteration count used to derive key +}; + +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/platform/decider.cpp b/src/manager/crypto/platform/decider.cpp index c986f4e..98bd69f 100644 --- a/src/manager/crypto/platform/decider.cpp +++ b/src/manager/crypto/platform/decider.cpp @@ -16,6 +16,7 @@ /* * @file decider.cpp * @author Bartłomiej Grzelewski (b.grzelewski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) * @version 1.0 */ #include @@ -28,36 +29,74 @@ #include #include +#include +#include + +#include +#include +#include + namespace CKM { namespace Crypto { namespace { -CryptoBackend chooseCryptoBackend(DataType dataType, bool exportable, + +const std::string TA_STORE_PATH = "/usr/lib/tastore"; + +template +std::string ValueToString(const T& value) +{ + std::stringstream str; + // we need to re-cast because otherwise stringstream + // will write our value incorrectly + str << std::setfill('0') << std::setw(2 * sizeof(T)) << std::hex + << static_cast(value); + return str.str(); +} + +std::string convertTeecUUIDToString(TEEC_UUID uuid) +{ + std::string uuidStr; + uuidStr += ValueToString(uuid.timeLow); + uuidStr += ValueToString(uuid.timeMid); + uuidStr += ValueToString(uuid.timeHiAndVersion); + for (auto& c: uuid.clockSeqAndNode) + uuidStr += ValueToString(c); + + return uuidStr; +} + +CryptoBackend chooseCryptoBackend(DataType data, bool exportable, bool encrypted) { - // Only software backend supports device encyption key + // For now only software backend supports device encyption key + // TODO tz-backend could support the master key, but it would require + // hardcoding a known key ID and querying TA whether the key is + // reachable if (encrypted) return CryptoBackend::OpenSSL; - // The list of items that MUST be support by OpenSSL - if (dataType.isCertificate()) + // Only software backend allows for key export + if (exportable) return CryptoBackend::OpenSSL; - if (dataType.isBinaryData()) + // Use TrustZone only with symmetric keys until asymmetric + // cryptography is implemented + if (!data.isSKey()) return CryptoBackend::OpenSSL; - if (exportable) - return CryptoBackend::OpenSSL; + // Check if key-manager TA exists + std::string taUUIDStr = convertTeecUUIDToString(KM_TA_UUID); - // This is the place where we can use trust zone backend - // Examples: - // - // if (dataType.isKeyPrivate()) - // return CryptoBackend::TrustZone; + LogDebug("Checking for " << TA_STORE_PATH << "/" << taUUIDStr); + std::ifstream taFile(TA_STORE_PATH + "/" + taUUIDStr); + if (taFile) + return CryptoBackend::TrustZone; - // This item does not met Trust Zone requirements. Let's use software backend + // no TA available - fallback to OpenSSL return CryptoBackend::OpenSSL; } + } // namespace Decider::Decider() diff --git a/src/manager/crypto/sw-backend/internals.cpp b/src/manager/crypto/sw-backend/internals.cpp index f37d2ef..b519e11 100644 --- a/src/manager/crypto/sw-backend/internals.cpp +++ b/src/manager/crypto/sw-backend/internals.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -61,9 +62,6 @@ typedef std::unique_ptr> EvpPkeyUPtr; typedef std::unique_ptr> BioUniquePtr; typedef int(*I2D_CONV)(BIO *, EVP_PKEY *); -const size_t DEFAULT_AES_GCM_TAG_LEN = - 128; // tag length in bits according to W3C Crypto API -const size_t DEFAULT_AES_IV_LEN = 16; // default iv size in bytes for AES RawBuffer i2d(I2D_CONV fun, EVP_PKEY *pkey) { @@ -107,7 +105,7 @@ typedef ParamCheck::Equals, + Type::Equals, BufferSizeGetter> IvSizeCheck; typedef ParamCheck #include +#include #include #include #include @@ -38,10 +39,6 @@ namespace SW { namespace { -const int ITERATIONS = 1024; -const int KEY_LENGTH = 16; // length of AES key derived from password -const int STORE_AES_GCM_TAG_SIZE = 16; // length of AES GCM tag - // internal SW encryption scheme flags enum EncryptionScheme { NONE = 0, @@ -74,7 +71,7 @@ RawBuffer passwordToKey(const Password &password, const RawBuffer &salt, password.size(), salt.data(), salt.size(), - ITERATIONS, + Params::DERIVED_KEY_ITERATIONS, result.size(), result.data())) ThrowErr(Exc::InternalError, "PCKS5_PKKDF2_HMAC_SHA1 failed."); @@ -109,7 +106,7 @@ RawBuffer unpack(const RawBuffer &packed, const Password &pass) * - password is empty when it shouldn't be * - password is not empty when it should be */ - RawBuffer key = passwordToKey(pass, iv, KEY_LENGTH); + RawBuffer key = passwordToKey(pass, iv, Params::DERIVED_KEY_LENGTH); RawBuffer ret; @@ -129,13 +126,13 @@ RawBuffer pack(const RawBuffer &data, const Password &pass) if (!pass.empty()) { RawBuffer iv = generateRandIV(); - RawBuffer key = passwordToKey(pass, iv, KEY_LENGTH); + RawBuffer key = passwordToKey(pass, iv, Params::DERIVED_KEY_LENGTH); std::pair ret; try { ret = Crypto::SW::Internals::encryptDataAesGcm(key, data, iv, - STORE_AES_GCM_TAG_SIZE); + Params::DEFAULT_AES_GCM_TAG_LEN_BYTES); } catch (const Exc::Crypto::InternalError &e) { ThrowErr(Exc::AuthenticationFailed, "Encryption with custom password failed"); } diff --git a/src/manager/crypto/tz-backend/internals.cpp b/src/manager/crypto/tz-backend/internals.cpp new file mode 100644 index 0000000..bfb78d7 --- /dev/null +++ b/src/manager/crypto/tz-backend/internals.cpp @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file internals.h + * @author Krzysztof Dynowski (k.dynowski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + */ + +#include +#include +#include +#include + +#include +#include +#include + + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +tz_algo_type getGenKeyType(AlgoType type) +{ + switch (type) + { + case AlgoType::AES_GEN: return ALGO_AES_GEN; + default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); + } +} + +tz_algo_type getAlgType(AlgoType type) +{ + switch (type) + { + case AlgoType::AES_CBC: return ALGO_AES_CBC; + case AlgoType::AES_CTR: return ALGO_AES_CTR; + case AlgoType::AES_CFB: return ALGO_AES_CFB; + case AlgoType::AES_GCM: return ALGO_AES_GCM; + default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); + }; +} + +tz_algo_type getAlgType(KeyType keyType) +{ + switch (keyType) + { + case KeyType::KEY_AES: + return ALGO_AES_GEN; + case KeyType::KEY_RSA_PUBLIC: + case KeyType::KEY_RSA_PRIVATE: + return ALGO_RSA_GEN; + default: + ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); + }; +} + +RawBuffer generateIV() +{ + RawBuffer result; + TrustZoneContext::Instance().generateIV(Params::DEFAULT_AES_IV_LEN, result); + return result; +} + +Data generateSKey(const CryptoAlgorithm &alg, + const Password &pwd, + const RawBuffer &iv, + RawBuffer &tag) +{ + AlgoType keyType = unpack(alg, ParamName::ALGO_TYPE); + int keyBits = unpack(alg, ParamName::GEN_KEY_LEN); + + Data keyData; + keyData.type = DataType(keyType); + + if (!pwd.empty()) { + if (iv.empty()) { + ThrowErr(Exc::InputParam, "Key generation with password encryption requires an IV"); + } + + RawBuffer pwdBuf(pwd.begin(), pwd.end()); + TrustZoneContext::Instance().generateSKeyPwd(getGenKeyType(keyType), + pwdBuf, iv, keyBits, + Params::DEFAULT_AES_GCM_TAG_LEN_BITS, + keyData.data, tag); + } else { + TrustZoneContext::Instance().generateSKey(getGenKeyType(keyType), keyBits, + keyData.data); + } + + return keyData; +} + +DataPair generateAKey(const CryptoAlgorithm &, + const Password &, + const RawBuffer &) +{ + ThrowErr(Exc::Crypto::OperationNotSupported, + "AKeys are not yet implemented in TrustZone backend"); +} + +void destroyKey(const RawBuffer &key) +{ + TrustZoneContext::Instance().executeDestroy(key); +} + +RawBuffer importKey(const Data &data, + const Password &pwd, + const RawBuffer &iv, + RawBuffer &tag) +{ + tz_algo_type algo = getAlgType(data.type); + RawBuffer result; + + RawBuffer pwdBuf(pwd.begin(), pwd.end()); + uint32_t keySizeBits = data.data.size() * 8; + TrustZoneContext::Instance().importKey(algo, + data.data, + pwdBuf, + iv, + keySizeBits, + Params::DERIVED_KEY_LENGTH_BITS, + result, + tag); + return result; +} + +BufferPair encryptDataAesGcm(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSize, + const RawBuffer &data, + const RawBuffer &aad) +{ + RawBuffer result; + RawBuffer tag; + + TrustZoneContext::Instance().executeEncryptAE(key, pwd, iv, tagSize, + aad, data, result, tag); + + return std::make_pair(result, tag); +} + +RawBuffer encryptDataAesGcmPacked(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSize, + const RawBuffer &data, + const RawBuffer &aad) +{ + auto pair = encryptDataAesGcm(key, pwd, iv, tagSize, data, aad); + std::copy(pair.second.begin(), pair.second.end(), + std::back_inserter(pair.first)); + return pair.first; +} + +RawBuffer decryptDataAesGcm(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSizeBits, + const RawBuffer &tag, + const RawBuffer &data, + const RawBuffer &aad) +{ + RawBuffer result; + + TrustZoneContext::Instance().executeDecryptAE(key, pwd, iv, tagSizeBits, + tag, aad, data, result); + + return result; +} + +RawBuffer decryptDataAesGcmPacked(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSizeBits, + const RawBuffer &data, + const RawBuffer &aad) +{ + int tagSizeBytes = tagSizeBits / 8; + if (tagSizeBytes > static_cast(data.size())) + ThrowErr(Exc::Crypto::InputParam, "Wrong size of tag"); + + auto tagPos = data.data() + data.size() - tagSizeBytes; + return decryptDataAesGcm(key, + pwd, + iv, + tagSizeBits, + RawBuffer(tagPos, data.data() + data.size()), + RawBuffer(data.data(), tagPos), + aad); +} + + +RawBuffer symmetricEncrypt(const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &data) +{ + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + uint64_t ctrLen = 0; + + switch (algo) { + case AlgoType::AES_CTR: { + ctrLen = unpack(alg, ParamName::ED_CTR_LEN); + // counter length is in bits + if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) { + LogError("CTR length invalid: " << std::to_string(ctrLen)); + ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length"); + } + // no break here, we still need to slide down to executeCrypt + } + case AlgoType::AES_CBC: + case AlgoType::AES_CFB: { + RawBuffer result; + TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT, + getAlgType(algo), + key, + pwd, + unpack(alg, ParamName::ED_IV), + data, + result); + return result; + } + case AlgoType::AES_GCM: { + int tagLenBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS; + alg.getParam(ParamName::ED_TAG_LEN, tagLenBits); + RawBuffer aad; + alg.getParam(ParamName::ED_AAD, aad); + return encryptDataAesGcmPacked(key, + pwd, + unpack(alg, ParamName::ED_IV), + tagLenBits, + data, + aad); + } + default: + break; + } + + ThrowErr(Exc::Crypto::OperationNotSupported, + "Incorrect algorithm provided for symmetric crypto operation"); +} + +RawBuffer symmetricDecrypt(const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &data) +{ + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + uint64_t ctrLen = 0; + + switch (algo) { + case AlgoType::AES_CTR: { + ctrLen = unpack(alg, ParamName::ED_CTR_LEN); + // counter length is in bits + if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) { + LogError("CTR length invalid: " << std::to_string(ctrLen)); + ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length"); + } + // no break here, we still need to slide down to executeCrypt + } + case AlgoType::AES_CBC: + case AlgoType::AES_CFB: { + RawBuffer result; + TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT, + getAlgType(algo), + key, + pwd, + unpack(alg, ParamName::ED_IV), + data, + result); + return result; + } + case AlgoType::AES_GCM: { + int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS; + alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits); + RawBuffer aad; + alg.getParam(ParamName::ED_AAD, aad); + return decryptDataAesGcmPacked(key, + pwd, + unpack(alg, ParamName::ED_IV), + tagSizeBits, + data, + aad); + } + default: + break; + } + + ThrowErr(Exc::Crypto::OperationNotSupported, + "Incorrect algorithm provided for symmetric crypto operation"); +} + +RawBuffer asymmetricEncrypt(const RawBuffer &, + const Pwd &, + const CryptoAlgorithm &, + const RawBuffer &) +{ + ThrowErr(Exc::Crypto::OperationNotSupported, + "Asymmetric encryption is not yet supported on TrustZone backend"); +} + +RawBuffer asymmetricDecrypt(const RawBuffer &, + const Pwd &, + const CryptoAlgorithm &, + const RawBuffer &) +{ + ThrowErr(Exc::Crypto::OperationNotSupported, + "Asymmetric encryption is not yet supported on TrustZone backend"); +} + +RawBuffer sign(const RawBuffer &, + const Pwd &, + const CryptoAlgorithm &, + const RawBuffer &) +{ + ThrowErr(Exc::Crypto::OperationNotSupported, + "Certificate signing is not yet supported on TrustZone backend"); +} + +int verify(const RawBuffer &, + const Pwd &, + const CryptoAlgorithm &, + const RawBuffer &, + const RawBuffer &) +{ + ThrowErr(Exc::Crypto::OperationNotSupported, + "Certificate signing is not yet supported on TrustZone backend"); +} + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/tz-backend/internals.h b/src/manager/crypto/tz-backend/internals.h new file mode 100644 index 0000000..c8af8c7 --- /dev/null +++ b/src/manager/crypto/tz-backend/internals.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file internals.h + * @author Krzysztof Dynowski (k.dynowski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + */ +#pragma once + +#include +#include +#include +#include + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +using DataPair = std::pair; +using BufferPair = std::pair; + +// encryption schema + buffer pair +using KeyIdPair = std::pair; + +RawBuffer generateIV(); +DataPair generateAKey(const CryptoAlgorithm &alg, + const Password &pwd, + const RawBuffer &iv); +Data generateSKey(const CryptoAlgorithm &alg, + const Password &pwd, + const RawBuffer &iv, + RawBuffer &tag); +RawBuffer importKey(const Data &key, + const Password &pwd, + const RawBuffer &iv, + RawBuffer &tag); +void destroyKey(const RawBuffer &key); + +RawBuffer symmetricEncrypt( + const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &data); +RawBuffer symmetricDecrypt( + const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &cipher); + +RawBuffer asymmetricEncrypt( + const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &data); +RawBuffer asymmetricDecrypt( + const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &cipher); + +BufferPair encryptDataAesGcm(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSize, + const RawBuffer &data, + const RawBuffer &aad = RawBuffer()); + +RawBuffer decryptDataAesGcm(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + const RawBuffer &tag, + const RawBuffer &data, + const RawBuffer &aad = RawBuffer()); + +RawBuffer sign(const RawBuffer &pkey, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &message); + +int verify(const RawBuffer &pkey, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &message, + const RawBuffer &signature); + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/tz-backend/obj.cpp b/src/manager/crypto/tz-backend/obj.cpp index b1109b7..81aabaa 100644 --- a/src/manager/crypto/tz-backend/obj.cpp +++ b/src/manager/crypto/tz-backend/obj.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +15,83 @@ */ /* * @file obj.cpp - * @author Bartłomiej Grzelewski (b.grzelewski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) * @version 1.0 */ +#include +#include +#include + namespace CKM { namespace Crypto { namespace TZ { +namespace { +AlgoType key2algo(DataType type) +{ + switch (static_cast(type)) { + case DataType::Type::KEY_RSA_PRIVATE: + case DataType::Type::KEY_RSA_PUBLIC: + return AlgoType::RSA_SV; + + case DataType::Type::KEY_DSA_PRIVATE: + case DataType::Type::KEY_DSA_PUBLIC: + return AlgoType::DSA_SV; + + case DataType::Type::KEY_ECDSA_PRIVATE: + case DataType::Type::KEY_ECDSA_PUBLIC: + return AlgoType::ECDSA_SV; + + default: + ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", type); + } +} +} // namespace anonymous + +RawBuffer SKey::encrypt(const CryptoAlgorithm &alg, const RawBuffer &data) +{ + return Internals::symmetricEncrypt(getBinary(), getPassword(), alg, data); +} + +RawBuffer SKey::decrypt(const CryptoAlgorithm &alg, const RawBuffer &cipher) +{ + return Internals::symmetricDecrypt(getBinary(), getPassword(), alg, cipher); +} + +RawBuffer AKey::encrypt(const CryptoAlgorithm &alg, const RawBuffer &data) +{ + return Internals::asymmetricEncrypt(getBinary(), getPassword(), alg, data); +} + +RawBuffer AKey::decrypt(const CryptoAlgorithm &alg, const RawBuffer &cipher) +{ + return Internals::asymmetricDecrypt(getBinary(), getPassword(), alg, cipher); +} + +RawBuffer AKey::sign( + const CryptoAlgorithm &alg, + const RawBuffer &message) +{ + CryptoAlgorithm algWithType(alg); + algWithType.setParam(ParamName::ALGO_TYPE, key2algo(m_type)); + return Internals::sign(getBinary(), getPassword(), algWithType, message); +} + +int AKey::verify(const CryptoAlgorithm &alg, const RawBuffer &message, + const RawBuffer &sign) +{ + CryptoAlgorithm algWithType(alg); + AlgoType type; + + // setup algorithm type basing on key type if it doesn't exist + if (!algWithType.getParam(ParamName::ALGO_TYPE, type)) { + ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", "not given"); + } + + return Internals::verify(getBinary(), getPassword(), algWithType, message, sign); +} + + } // namespace TZ } // namespace Crypto } // namespace CKM diff --git a/src/manager/crypto/tz-backend/obj.h b/src/manager/crypto/tz-backend/obj.h index 424563c..f3459c1 100644 --- a/src/manager/crypto/tz-backend/obj.h +++ b/src/manager/crypto/tz-backend/obj.h @@ -15,31 +15,104 @@ */ /* * @file obj.h - * @author Bartłomiej Grzelewski (b.grzelewski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) * @version 1.0 */ #pragma once #include +#include namespace CKM { namespace Crypto { namespace TZ { -class SKey : public GObj { +class Pwd { public: - SKey() {} - virtual ~SKey() {} + Pwd(Password pwd, RawBuffer iv, RawBuffer tag) + : m_password(pwd.begin(), pwd.end()) + , m_iv(std::move(iv)) + , m_tag(std::move(tag)) + {} + + const RawBuffer& getPassword() const + { + return m_password; + } + + const RawBuffer& getIV() const + { + return m_iv; + } + + const RawBuffer& getTag() const + { + return m_tag; + } + + +private: + RawBuffer m_password; + RawBuffer m_iv; + RawBuffer m_tag; +}; + +class BData : public GObj { +public: + BData(int scheme, RawBuffer buffer, Pwd pwd, DataType keyType): + m_scheme(scheme), m_raw(std::move(buffer)), m_password(std::move(pwd)), + m_type(keyType) {} + + virtual RawBuffer getBinary() const override + { + return m_raw; + } + + virtual int getScheme() const + { + return m_scheme; + } + + virtual Pwd getPassword() const + { + return m_password; + } protected: + int m_scheme; + RawBuffer m_raw; + Pwd m_password; + DataType m_type; +}; + +class SKey : public BData { +public: + SKey(int scheme, RawBuffer buffer, Pwd pwd, DataType keyType) : + BData(scheme, std::move(buffer), std::move(pwd), keyType) {} + + virtual RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &); + virtual RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &); }; -class AKey : public GObj { +class AKey : public BData { public: - AKey() {} + AKey(int scheme, RawBuffer buffer, Pwd pwd, DataType dataType) : + BData(scheme, std::move(buffer), std::move(pwd), dataType) {} + + virtual RawBuffer sign(const CryptoAlgorithm &alg, const RawBuffer &message); + virtual int verify(const CryptoAlgorithm &alg, const RawBuffer &message, + const RawBuffer &sign); + virtual RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &); + virtual RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &); virtual ~AKey() {} +}; -protected: +class Cert : public AKey { +public: + Cert(int scheme, RawBuffer buffer, Pwd pwd, DataType dataType) : + AKey(scheme, std::move(buffer), std::move(pwd), dataType) {} + + virtual ~Cert() {} }; } // namespace TZ diff --git a/src/manager/crypto/tz-backend/store.cpp b/src/manager/crypto/tz-backend/store.cpp index e878b45..76cb253 100644 --- a/src/manager/crypto/tz-backend/store.cpp +++ b/src/manager/crypto/tz-backend/store.cpp @@ -15,46 +15,161 @@ */ /* * @file store.cpp - * @author Bartłomiej Grzelewski (b.grzelewski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) * @version 1.0 */ + #include +#include #include #include +#include + +#include +#include namespace CKM { namespace Crypto { namespace TZ { +namespace { + +template +std::unique_ptr make_unique(Args &&...args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +// internal SW encryption scheme flags +enum EncryptionScheme { + NONE = 0, + PASSWORD = 1 << 0 +}; + +void unpack(const RawBuffer &packed, + int &scheme, + RawBuffer &data, + RawBuffer &iv, + RawBuffer &tag) +{ + MessageBuffer buffer; + buffer.Push(packed); + + buffer.Deserialize(scheme); + + if (scheme == EncryptionScheme::PASSWORD) { + buffer.Deserialize(data, iv, tag); + } else { + buffer.Deserialize(data); + } +} + +RawBuffer unpackData(const RawBuffer &packed) +{ + MessageBuffer buffer; + buffer.Push(packed); + + int scheme; + buffer.Deserialize(scheme); + + RawBuffer data; + buffer.Deserialize(data); + return data; +} + +RawBuffer pack(const RawBuffer &keyId, const Password &pwd, + const RawBuffer &iv, const RawBuffer &tag) +{ + // determine whether the key is password protected and store schema info + // we don't need to additionally encrypt key ID + int scheme = pwd.empty() ? EncryptionScheme::NONE : EncryptionScheme::PASSWORD; + + if (scheme == EncryptionScheme::PASSWORD) { + return MessageBuffer::Serialize(scheme, keyId, iv, tag).Pop(); + } else { + return MessageBuffer::Serialize(scheme, keyId).Pop(); + } +} + +} // namespace + Store::Store(CryptoBackend backendId) : GStore(backendId) { } -GObjUPtr Store::getObject(const Token &, const Password &) +GObjUPtr Store::getObject(const Token &token, const Password &pass) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "Trust zone backend is not implemented!"); + int scheme; + RawBuffer data; + RawBuffer iv; + RawBuffer tag; + unpack(token.data, scheme, data, iv, tag); + + // TODO AKeys + + if (token.dataType == DataType(DataType::KEY_AES)) + return make_unique(scheme, data, Pwd(pass, iv, tag), token.dataType); + + // TODO certificate/chaincert + + if (token.dataType.isBinaryData()) + return make_unique(scheme, data, Pwd(pass, iv, tag), token.dataType); + + ThrowErr(Exc::Crypto::DataTypeNotSupported, + "This type of data is not supported by trustzone backend: ", (int)token.dataType); } TokenPair Store::generateAKey(const CryptoAlgorithm &, const Password &, const Password &) { ThrowErr(Exc::Crypto::OperationNotSupported, - "Trust zone backend is not implemented!"); + "AKey operations are not implemented on TrustZone backend!"); } -Token Store::import(const Data &, const Password &) +Token Store::generateSKey(const CryptoAlgorithm &alg, const Password &pass) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "Trust zone backend is not implemented!"); + RawBuffer iv; + RawBuffer tag; + if (!pass.empty()) { + // IV is needed for key encryption + iv = Internals::generateIV(); + } + + Data ret = Internals::generateSKey(alg, pass, iv, tag); + return Token(m_backendId, ret.type, pack(ret.data, pass, iv, tag)); +} + +Token Store::import(const Data &data, const Password &pass) +{ + if (!data.type.isKey()) + ThrowErr(Exc::Crypto::InputParam, "Invalid data provided for import"); + + if (!data.type.isSKey()) + ThrowErr(Exc::Crypto::DataTypeNotSupported, "Asymmetric keys are not supported"); + + RawBuffer iv; + RawBuffer tag; + if (!pass.empty()) { + // IV is needed for key encryption + iv = Internals::generateIV(); + } + + RawBuffer keyId = Internals::importKey(data, pass, iv, tag); + return Token(m_backendId, data.type, pack(keyId, pass, iv, tag)); } Token Store::importEncrypted(const Data &, const Password &, const DataEncryption &) { ThrowErr(Exc::Crypto::OperationNotSupported, - "Trust zone backend is not implemented!"); + "Encrypted import is not yet supported on TrustZone backend!"); +} + +void Store::destroy(const Token &token) +{ + RawBuffer data = unpackData(token.data); + Internals::destroyKey(data); } } // namespace TZ diff --git a/src/manager/crypto/tz-backend/store.h b/src/manager/crypto/tz-backend/store.h index bb61607..2eddfbe 100644 --- a/src/manager/crypto/tz-backend/store.h +++ b/src/manager/crypto/tz-backend/store.h @@ -15,7 +15,7 @@ */ /* * @file store.h - * @author Bartłomiej Grzelewski (b.grzelewski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) * @version 1.0 */ #pragma once @@ -34,10 +34,13 @@ public: virtual GObjUPtr getObject(const Token &, const Password &); virtual TokenPair generateAKey(const CryptoAlgorithm &, const Password &, const Password &); - virtual Token import(const Data &data, const Password &); + virtual Token generateSKey(const CryptoAlgorithm &, const Password &); + virtual Token import(const Data &, const Password &); virtual Token importEncrypted(const Data &, const Password &, const DataEncryption &); - virtual void destroy(const Token &) {} + virtual void destroy(const Token &); + + // TODO device key ID is needed here to support importEncrypted }; } // namespace TZ diff --git a/src/manager/crypto/tz-backend/tz-context.cpp b/src/manager/crypto/tz-backend/tz-context.cpp new file mode 100644 index 0000000..7a59fbe --- /dev/null +++ b/src/manager/crypto/tz-backend/tz-context.cpp @@ -0,0 +1,810 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file tz-context.cpp + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +namespace { + +// A little bit of extra memory to add to output buffers. +// +// We need this extra memory to output for padding purposes - after encryption +// we can resize the result memory back to its proper size according to +// whatever TA will return us. +const uint32_t CIPHER_EXTRA_PADDING_SIZE = 16; + +// Identifier of our TA +const TEEC_UUID KEY_MANAGER_TA_UUID = KM_TA_UUID; + +} // anonymous namespace + +TrustZoneContext::TrustZoneContext() + : m_ContextInitialized(false) + , m_SessionInitialized(false) +{ + Initialize(); +} + +TrustZoneContext::~TrustZoneContext() +{ + Destroy(); +} + +TrustZoneContext& TrustZoneContext::Instance() +{ + static TrustZoneContext instance; + return instance; +} + +void TrustZoneContext::generateIV(uint32_t ivSize, RawBuffer& iv) +{ + // command ID = CMD_GENERATE_IV + // + // TEEC_Operation layout: + // params: + // [1].memref.buffer - output + // [1].memref.size - output size + // output: + // [0].value.a - return code + + // IV generation is a simple call - no need to serialize data + // just provide the output buffer with size equal to iv. + TrustZoneMemory ivMemory(m_Context, ivSize, TEEC_MEM_OUTPUT); + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_NONE, TEEC_NONE); + op.params[1].memref.parent = ivMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = ivMemory.Get()->size; + Execute(CMD_GENERATE_IV, &op); + + iv.resize(ivSize); + memcpy(iv.data(), ivMemory.Get()->buffer, ivMemory.Get()->size); +} + +void TrustZoneContext::generateSKey(tz_algo_type algo, + uint32_t keySizeBits, + RawBuffer &keyId) +{ + // command ID = CMD_GENERATE_KEY + // + // TEEC_Operation layout: + // params: + // [0].value.a - key type + // [0].value.b - key bit size + // output: + // [0].value.a - return code + // [1].memref - serialized key reference + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = KM_KEY_ID_SIZE; + uint32_t keyMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT); + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_NONE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[0].value.b = keySizeBits; + op.params[1].memref.parent = keyMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = keyMemorySize; + Execute(CMD_GENERATE_KEY, &op); + + KM_SymmetricInput* output = nullptr; + int ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID"); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID"); + } + + if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID"); + } + + keyId.resize(KM_KEY_ID_SIZE); + memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE); +} + +void TrustZoneContext::generateSKeyPwd(tz_algo_type algo, + const RawBuffer &pwd, + const RawBuffer &iv, + const uint32_t keySizeBits, + const uint32_t pwdTagSizeBits, + RawBuffer &keyId, + RawBuffer &pwdTag) +{ + // command ID = CMD_GENERATE_KEY_PWD + // + // TEEC_Operation layout: + // params: + // [0].value.a - key type + // [0].value.b - key size in bits + // [1].memref - input (seralized pwd/iv for pbkdf2) + // output: + // [0].value.a - return code + // [2].memref - serialized key reference ID + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.size()); + bufSize.pwd_iv_size = static_cast(iv.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = KM_KEY_ID_SIZE; + bufSize.tag_size = pwdTagSizeBits / 8; + uint32_t keyMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations"); + } + + ret = KM_ParamsSerializePwdData(input, pwd.data(), pwd.size(), iv.data(), iv.size(), + nullptr, 0, Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[0].value.b = keySizeBits; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = keyMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = keyMemory.Get()->size; + Execute(CMD_GENERATE_KEY_PWD, &op); + + KM_SymmetricInput* output = nullptr; + ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID"); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID"); + } + + KM_TagData* tagData = nullptr; + ret = KM_ParamsDeserializeTagData(output, &tagData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize key's tag"); + } + + if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID"); + } + + if (tagData == nullptr || tagData->data_size != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) { + ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag"); + } + + keyId.resize(KM_KEY_ID_SIZE); + memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE); + + pwdTag.resize(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES); + memcpy(pwdTag.data(), tagData->data, Params::DEFAULT_AES_GCM_TAG_LEN_BYTES); +} + + +void TrustZoneContext::importKey(tz_algo_type algo, + const RawBuffer &key, + const RawBuffer &pwd, + const RawBuffer &iv, + const uint32_t keySizeBits, + const uint32_t pwdTagSizeBits, + RawBuffer &keyId, + RawBuffer &pwdTag) +{ + // command ID = CMD_IMPORT_KEY + // + // TEEC_Operation layout: + // params: + // [0].value.a - key type + // [0].value.b - key size in bits + // [1].memref - seralized key & password data + // output: + // [0].value.a - return code + // [2].memref - serialized key reference ID + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(key.size()); + if (!pwd.empty()) { + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.size()); + bufSize.pwd_iv_size = static_cast(iv.size()); + } + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = KM_KEY_ID_SIZE; + bufSize.tag_size = pwdTagSizeBits / 8; + uint32_t keyMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory keyMemory(m_Context, keyMemorySize, TEEC_MEM_OUTPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for key import: ", ret); + } + + ret = KM_ParamsSerializeInputData(input, key.data(), key.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key to import: ", ret); + } + + if (!pwd.empty()) { + ret = KM_ParamsSerializePwdData(input, pwd.data(), pwd.size(), iv.data(), iv.size(), + nullptr, 0, Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key data for import: ", ret); + } + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[0].value.b = keySizeBits; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = keyMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = keyMemory.Get()->size; + Execute(CMD_IMPORT_KEY, &op); + + KM_SymmetricInput* output = nullptr; + ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for imported key ID"); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize imported key ID"); + } + + if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID"); + } + + keyId.resize(KM_KEY_ID_SIZE); + memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE); + + if (!pwd.empty()) { + KM_TagData* tagData = nullptr; + uint32_t pwdTagSizeBytes = pwdTagSizeBits / 8; + + ret = KM_ParamsDeserializeTagData(output, &tagData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize imported key's tag"); + } + + if (tagData == nullptr || tagData->data_size != pwdTagSizeBytes) { + ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key tag"); + } + + pwdTag.resize(pwdTagSizeBytes); + memcpy(pwdTag.data(), tagData->data, pwdTagSizeBytes); + } +} + +void TrustZoneContext::executeCrypt(tz_command cmd, + tz_algo_type algo, + const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + const RawBuffer &data, + RawBuffer &out) +{ + // command IDs = CMD_ENCRYPT, CMD_DECRYPT (from km_ta_defines.h) + // + // TEEC_Operation layout: + // params: + // [0].value.a - keyid + // [0].value.b - algo + // [1].memref - input data (serialized key/input) + // returned: + // [0].value.a - return code + // [2].memref - serialized output buffer + + if (key.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = " + + std::to_string(key.size()) + ")"); + } + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(data.size()); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.getPassword().size()); + bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); + bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); + bufSize.iv_size = static_cast(iv.size()); + bufSize.key_id_size = static_cast(key.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + // decrypt operation does not require padding + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = static_cast((cmd == CMD_ENCRYPT) ? + data.size() + CIPHER_EXTRA_PADDING_SIZE : + data.size()); + uint32_t outMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations"); + } + + ret = KM_ParamsSerializeInputData(input, data.data(), data.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret); + } + + uint32_t pwdTagSizeBits = pwd.getTag().size() * 8; + ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(), + pwd.getIV().data(), pwd.getIV().size(), + pwd.getTag().data(), pwd.getTag().size(), + Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, + pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = outMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = outMemory.Get()->size; + Execute(cmd, &op); + + KM_SymmetricInput* output = nullptr; + ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret); + } + + // data_size should contain how much memory we actually took for our cipher operation + out.resize(outData->data_size); + memcpy(out.data(), outData->data, outData->data_size); +} + +void TrustZoneContext::executeEncryptAE(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSizeBits, + const RawBuffer &aad, + const RawBuffer &data, + RawBuffer &out, + RawBuffer &tag) +{ + // command ID = CMD_ENCRYPT (from km_ta_defines.h) + // + // TEEC_Operation layout: + // params: + // [0].value.a - keyid + // [0].value.b - algo + // [1].memref - input data (serialized key/input/iv/aad) + // returned: + // [0].value.a - return code + // [2].memref - output + + if (key.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer"); + } + + uint32_t tagSizeBytes = (tagSizeBits + 7) / 8; + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(data.size()); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.getPassword().size()); + bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); + bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); + bufSize.iv_size = static_cast(iv.size()); + bufSize.key_id_size = static_cast(key.size()); + bufSize.with_ae_data = true; + bufSize.aad_size = static_cast(aad.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = static_cast(data.size() + CIPHER_EXTRA_PADDING_SIZE); + bufSize.tag_size = static_cast(tagSizeBytes); + uint32_t outMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations"); + } + + ret = KM_ParamsSerializeInputData(input, data.data(), data.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret); + } + + uint32_t pwdTagSizeBits = pwd.getTag().size() * 8; + ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(), + pwd.getIV().data(), pwd.getIV().size(), + pwd.getTag().data(), pwd.getTag().size(), + Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, + pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeAEData(input, tagSizeBits, 0, aad.data(), aad.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize auth data for TZ crypto operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.a = ALGO_AES_GCM; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = outMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = outMemory.Get()->size; + Execute(CMD_ENCRYPT, &op); + + KM_SymmetricInput* output = nullptr; + ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret); + } + + KM_TagData* tagData = nullptr; + ret = KM_ParamsDeserializeTagData(output, &tagData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize tag data: ", ret); + } + + out.resize(outData->data_size); + memcpy(out.data(), outData->data, outData->data_size); + + if (tagData->data_size) { + tag.resize(tagData->data_size); + memcpy(tag.data(), tagData->data, tagData->data_size); + } +} + +void TrustZoneContext::executeDecryptAE(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSizeBits, + const RawBuffer &tag, + const RawBuffer &aad, + const RawBuffer &data, + RawBuffer &out) +{ + // command ID = CMD_DECRYPT (from km_ta_defines.h) + // + // TEEC_Operation layout: + // params: + // [0].value.a - keyid + // [0].value.b - algo + // [1].memref - input data (serialized key/input/iv/tag/aad) + // returned: + // [0].value.a - output size + // [2].memref - output (decrypted data) + + if (key.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer"); + } + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(data.size()); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.getPassword().size()); + bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); + bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); + bufSize.iv_size = static_cast(iv.size()); + bufSize.key_id_size = static_cast(key.size()); + bufSize.with_ae_data = true; + bufSize.aad_size = static_cast(aad.size()); + bufSize.tag_size = static_cast(tag.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = static_cast(data.size()); + uint32_t outMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ crypto operations"); + } + + ret = KM_ParamsSerializeInputData(input, data.data(), data.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ crypto operation: ", ret); + } + + uint32_t pwdTagSizeBits = pwd.getTag().size() * 8; + ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(), + pwd.getIV().data(), pwd.getIV().size(), + pwd.getTag().data(), pwd.getTag().size(), + Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, + pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeIVData(input, iv.data(), iv.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeAEData(input, tagSizeBits, 0, aad.data(), aad.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize auth data for TZ crypto operation: ", ret); + } + + ret = KM_ParamsSerializeTagData(input, tag.data(), tag.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize tag data for TZ crypto operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.a = ALGO_AES_GCM; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = outMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = outMemory.Get()->size; + Execute(CMD_DECRYPT, &op); + + KM_SymmetricInput* output = nullptr; + ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret); + } + + out.resize(outData->data_size); + memcpy(out.data(), outData->data, outData->data_size); +} + +void TrustZoneContext::executeDestroy(const RawBuffer &keyId) +{ + // command ID = CMD_DESTROY_KEY (from km_ta_defines.h) + // + // TEEC_Operation layout: + // input params: + // [1].memref - input data (serialized key ID) + // output params: + // [0].value.a - return code + + if (keyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer"); + } + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.key_id_size = static_cast(keyId.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization: ", ret); + } + + ret = KM_ParamsSerializeInputData(input, keyId.data(), keyId.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key ID to destroy: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE, + TEEC_NONE, TEEC_NONE); + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + Execute(CMD_DESTROY_KEY, &op); +} + +void TrustZoneContext::Initialize() +{ + TEEC_Operation op; + TEEC_Result result; + uint32_t retOrigin; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE); + + result = TEEC_InitializeContext(nullptr, &m_Context); + if (result != TEEC_SUCCESS) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize TEE context: ", result); + } + m_ContextInitialized = true; + + result = TEEC_OpenSession(&m_Context, &m_Session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &retOrigin); + if (result != TEEC_SUCCESS) { + ThrowErr(Exc::Crypto::InternalError, "Failed to open session to Key Manager TA: ", result); + } + m_SessionInitialized = true; +} + +void TrustZoneContext::Destroy() +{ + if (m_SessionInitialized) { + TEEC_CloseSession(&m_Session); + m_SessionInitialized = false; + } + + if (m_ContextInitialized) { + TEEC_FinalizeContext(&m_Context); + m_ContextInitialized = false; + } +} + +void TrustZoneContext::Reload() +{ + Destroy(); + Initialize(); +} + +void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op) +{ + LogDebug("Executing TZ operation " << commandID); + + TEEC_Result result = TEEC_InvokeCommand(&m_Session, static_cast(commandID), op, NULL); + if (result != TEEC_SUCCESS) { + switch (result) { + case TEEC_ERROR_TARGET_DEAD: + Reload(); + ThrowErr(Exc::Crypto::InternalError, "TA panicked while executing command ", + static_cast(commandID)); + case TEEC_ERROR_BAD_PARAMETERS: + ThrowErr(Exc::Crypto::InputParam, "Incorrect parameters provided to TA"); + default: + ThrowErr(Exc::Crypto::InternalError, "TA failed to invoke command ", + static_cast(commandID), " with error: ", std::hex, + static_cast(result)); + } + } + + int ta_ret = op->params[0].value.a; + if (ta_ret != KM_TA_SUCCESS) { + switch (ta_ret) { + case KM_TA_ERROR_AUTH_FAILED: + // Authentication cipher failed - notify with proper exception + ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed"); + default: + ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret); + } + } +} + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/tz-backend/tz-context.h b/src/manager/crypto/tz-backend/tz-context.h new file mode 100644 index 0000000..44ad38c --- /dev/null +++ b/src/manager/crypto/tz-backend/tz-context.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file tz-context.h + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +class TrustZoneContext final +{ +public: + static TrustZoneContext& Instance(); + + void generateIV(uint32_t ivSize, RawBuffer &iv); + void generateSKey(tz_algo_type algo, + uint32_t keySizeBits, + RawBuffer &keyId); + void generateSKeyPwd(tz_algo_type algo, + const RawBuffer &pwd, + const RawBuffer &iv, + const uint32_t pwdKeySizeBits, + const uint32_t pwdTagSizeBits, + RawBuffer &keyId, + RawBuffer &pwdTag); + void importKey(tz_algo_type algo, + const RawBuffer &key, + const RawBuffer &pwd, + const RawBuffer &iv, + const uint32_t keySizeBits, + const uint32_t pwdTagSizeBits, + RawBuffer &keyId, + RawBuffer &pwdTag); + + void executeCrypt(tz_command cmd, + tz_algo_type algo, + const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + const RawBuffer &data, + RawBuffer &out); + + void executeEncryptAE(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSizeBits, + const RawBuffer &aad, + const RawBuffer &data, + RawBuffer &out, + RawBuffer &tag); + void executeDecryptAE(const RawBuffer &key, + const Pwd &pwd, + const RawBuffer &iv, + int tagSizeBits, + const RawBuffer &tag, + const RawBuffer &aad, + const RawBuffer &data, + RawBuffer &out); + + void executeDestroy(const RawBuffer &keyId); + +private: + TrustZoneContext(); + ~TrustZoneContext(); + TrustZoneContext(const TrustZoneContext &other) = delete; + TrustZoneContext(TrustZoneContext &&other) = delete; + + void Initialize(); + void Destroy(); + void Reload(); + + void Execute(tz_command commandID, TEEC_Operation* op); + + TEEC_Context m_Context; + TEEC_Session m_Session; + + bool m_ContextInitialized; + bool m_SessionInitialized; +}; + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/tz-backend/tz-memory.cpp b/src/manager/crypto/tz-backend/tz-memory.cpp new file mode 100644 index 0000000..1f76e41 --- /dev/null +++ b/src/manager/crypto/tz-backend/tz-memory.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file tz-memory.cpp + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + * @brief TrustZone Shared Memory wrapper definitions + */ + +#include +#include +#include + +#include + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +TrustZoneMemory::TrustZoneMemory(TEEC_Context context, const size_t size, const uint32_t flags) +{ + Allocate(context, size, flags); +} + +TrustZoneMemory::~TrustZoneMemory() +{ + Release(); +} + +void TrustZoneMemory::Allocate(TEEC_Context context, const size_t size, const uint32_t flags) +{ + m_SharedMemory.size = size; + m_SharedMemory.flags = flags; + + LogDebug("Allocating " << size << " bytes of shared TZ memory, flags: " << flags); + TEEC_Result result = TEEC_AllocateSharedMemory(&context, &m_SharedMemory); + if (result != TEEC_SUCCESS) { + ThrowErr(Exc::Crypto::InternalError, "TZ failed to register memory: ", + static_cast(result)); + } + + memset(m_SharedMemory.buffer, 0, m_SharedMemory.size); +} + +TEEC_SharedMemory* TrustZoneMemory::Get() const +{ + return &m_SharedMemory; +} + +void TrustZoneMemory::Release() +{ + TEEC_ReleaseSharedMemory(&m_SharedMemory); +} + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/tz-backend/tz-memory.h b/src/manager/crypto/tz-backend/tz-memory.h new file mode 100644 index 0000000..e4f559c --- /dev/null +++ b/src/manager/crypto/tz-backend/tz-memory.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file tz-memory.h + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + * @brief TrustZone Shared Memory wrapper declaration + */ + +#pragma once + +#include + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +class TrustZoneMemory final +{ +public: + TrustZoneMemory(TEEC_Context context, const size_t size, const uint32_t flags); + TrustZoneMemory(const TrustZoneMemory&) = delete; + TrustZoneMemory(TrustZoneMemory &&) = delete; + TrustZoneMemory& operator=(const TrustZoneMemory&) = delete; + TrustZoneMemory& operator=(TrustZoneMemory &&) = delete; + ~TrustZoneMemory(); + + TEEC_SharedMemory* Get() const; + +private: + void Allocate(TEEC_Context context, const size_t size, const uint32_t flags); + void Release(); + + mutable TEEC_SharedMemory m_SharedMemory; +}; + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5431f8e..e90d8d7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -79,6 +79,9 @@ SET(TEST_MERGED_SOURCES ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/obj.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/store.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/internals.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-context.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-memory.cpp ${KEY_MANAGER_PATH}/dpl/core/src/assert.cpp ${KEY_MANAGER_PATH}/dpl/core/src/colors.cpp ${KEY_MANAGER_PATH}/dpl/core/src/errno_string.cpp @@ -109,6 +112,7 @@ TARGET_LINK_LIBRARIES(${TARGET_TEST_MERGED} ${KEY_MANAGER_DEP_LIBRARIES} ${TARGET_ENCRYPTION_SCHEME_COMMON} boost_unit_test_framework + teec km_serialization -ldl ) diff --git a/tools/ckm_db_tool/CMakeLists.txt b/tools/ckm_db_tool/CMakeLists.txt index cd8d413..40de878 100644 --- a/tools/ckm_db_tool/CMakeLists.txt +++ b/tools/ckm_db_tool/CMakeLists.txt @@ -12,6 +12,7 @@ PKG_CHECK_MODULES(CKM_DB_TOOL_DEP cynara-client-async cynara-creds-socket security-manager + tef-libteec ) FIND_PACKAGE(Threads REQUIRED) @@ -38,7 +39,11 @@ SET(CKM_DB_TOOL_SOURCES ${KEY_MANAGER_PATH}/crypto/sw-backend/internals.cpp ${KEY_MANAGER_PATH}/crypto/sw-backend/obj.cpp ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/internals.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/obj.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/store.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-context.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-memory.cpp ${KEY_MANAGER_PATH}/dpl/core/src/assert.cpp ${KEY_MANAGER_PATH}/dpl/db/src/naive_synchronization_object.cpp ${KEY_MANAGER_PATH}/dpl/db/src/sql_connection.cpp @@ -82,6 +87,7 @@ TARGET_LINK_LIBRARIES(${CKM_DB_TOOL} ${CMAKE_THREAD_LIBS_INIT} ${CKM_DB_TOOL_DEP_LIBRARIES} ${TARGET_KEY_MANAGER_COMMON} + teec km_serialization -ldl ) -- 2.7.4