From 7e82d914fda678621a36478c07444ef0b539aaec Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9D=B4=EC=9D=B4=EC=82=AD/System=20Security=20Lab=28SR=29?= =?utf8?q?/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 5 Oct 2022 16:10:38 +0900 Subject: [PATCH] add the se-backend for db encryption * add the se-backend for db encryption * change se-backend include dependancy and remove the unavailable codes * remove migration DBDEK and rearrange KeyProvider structures Change-Id: I52e07ac5af7b41d0f79b7fee818221f25b1d60cd --- CMakeLists.txt | 8 + misc/ckm_db_tool/CMakeLists.txt | 1 + misc/db_perf/CMakeLists.txt | 3 + misc/encryption_scheme/CMakeLists.txt | 3 + packaging/key-manager.spec | 9 ++ src/CMakeLists.txt | 1 + src/manager/common/crypto-backend.h | 3 +- src/manager/crypto/se-backend/internals.cpp | 225 ++++++++++++++++++++++++++ src/manager/crypto/se-backend/internals.h | 64 ++++++++ src/manager/service/ckm-logic.cpp | 5 + src/manager/service/file-system.cpp | 14 +- src/manager/service/key-provider.cpp | 238 +++++++++++++++++++++------- src/manager/service/key-provider.h | 44 ++++- unit-tests/CMakeLists.txt | 1 + unit-tests/test_key-provider.cpp | 6 +- 15 files changed, 559 insertions(+), 66 deletions(-) create mode 100644 src/manager/crypto/se-backend/internals.cpp create mode 100644 src/manager/crypto/se-backend/internals.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 19ff954..1113a56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,14 @@ IF (TZ_BACKEND_ENABLED) ) ENDIF() +IF (SE_BACKEND_ENABLED) + ADD_DEFINITIONS("-DSE_BACKEND_ENABLED") + SET(SE_BACKEND_SOURCES + ${KEY_MANAGER_PATH}/crypto/se-backend/internals.cpp + ) + SET(EXTRA_KM_DEPS ${EXTRA_KM_DEPS} key-manager-se-backend) +ENDIF() + IF (DEFINED WATCHDOG_ENABLED) MESSAGE("WATCHDOG ENABLED!") ADD_DEFINITIONS("-DWATCHDOG_ENABLED") diff --git a/misc/ckm_db_tool/CMakeLists.txt b/misc/ckm_db_tool/CMakeLists.txt index a8ccca7..4547c85 100644 --- a/misc/ckm_db_tool/CMakeLists.txt +++ b/misc/ckm_db_tool/CMakeLists.txt @@ -61,6 +61,7 @@ SET(CKM_DB_TOOLS_SOURCES ${KEY_MANAGER_PATH}/service/ss-crypto.cpp ${KEY_MANAGER_PATH}/service/permission.cpp ${TZ_BACKEND_SOURCES} + ${SE_BACKEND_SOURCES} ) LINK_DIRECTORIES(${CKM_DB_TOOL_DEP_LIBRARY_DIRS}) diff --git a/misc/db_perf/CMakeLists.txt b/misc/db_perf/CMakeLists.txt index 672a079..ca9608b 100644 --- a/misc/db_perf/CMakeLists.txt +++ b/misc/db_perf/CMakeLists.txt @@ -11,6 +11,8 @@ INCLUDE_DIRECTORIES( ${MANAGER_PATH}/dpl/db/include ${MANAGER_PATH}/dpl/core/include ${MANAGER_PATH}/dpl/log/include + ${MANAGER_PATH}/crypto + ${MANAGER_PATH}/main ${MANAGER_PATH}/service ${MANAGER_PATH}/common ${PROJECT_SOURCE_DIR}/src/include @@ -33,6 +35,7 @@ SET(DB_PERF_SOURCES ${MANAGER_PATH}/service/file-system.cpp ${MANAGER_PATH}/service/for-each-file.cpp ${MANAGER_PATH}/service/key-provider.cpp + ${SE_BACKEND_SOURCES} ) SET(TARGET_CKM_DB_PERF "ckm_db_perf") diff --git a/misc/encryption_scheme/CMakeLists.txt b/misc/encryption_scheme/CMakeLists.txt index 2a1bd82..25d101c 100644 --- a/misc/encryption_scheme/CMakeLists.txt +++ b/misc/encryption_scheme/CMakeLists.txt @@ -11,6 +11,8 @@ INCLUDE_DIRECTORIES( ${MANAGER_PATH}/dpl/db/include ${MANAGER_PATH}/dpl/core/include ${MANAGER_PATH}/dpl/log/include + ${MANAGER_PATH}/crypto + ${MANAGER_PATH}/main ${MANAGER_PATH}/service ${MANAGER_PATH}/common ${PROJECT_SOURCE_DIR}/src/include @@ -44,6 +46,7 @@ SET(ENCRYPTION_SCHEME_COMMON_SOURCES ${MANAGER_PATH}/service/file-system.cpp ${MANAGER_PATH}/service/for-each-file.cpp ${MANAGER_PATH}/service/key-provider.cpp + ${SE_BACKEND_SOURCES} ) # binary for filling db for scheme migration testing diff --git a/packaging/key-manager.spec b/packaging/key-manager.spec index 68a8609..db4714d 100644 --- a/packaging/key-manager.spec +++ b/packaging/key-manager.spec @@ -2,6 +2,7 @@ %global watchdog_timeout_sec 60 %global watchdog_notify_sec 20 %global tz_backend_enabled %{?tz_backend:%tz_backend}%{!?tz_backend:OFF} +%global se_backend_enabled %{?se_backend:%se_backend}%{!?se_backend:OFF} %{!?build_type:%global build_type RELEASE} %global coverage_only 0 %if %{build_type} == COVERAGE_ONLY @@ -47,6 +48,9 @@ BuildRequires: key-manager-ta-devel BuildRequires: key-manager-ta-serialization-devel BuildRequires: pkgconfig(tef-libteec) %endif +%if %{se_backend_enabled} == ON +BuildRequires: pkgconfig(key-manager-se-backend) +%endif Requires: libkey-manager-common = %{version}-%{release} %if "%{build_type}" == "COVERAGE" BuildRequires: lcov @@ -209,6 +213,11 @@ export LDFLAGS+="-Wl,--rpath=%{_libdir},-Bsymbolic-functions" %else -DTZ_BACKEND_ENABLED=OFF \ %endif +%if %{se_backend_enabled} == ON + -DSE_BACKEND_ENABLED=ON \ +%else + -DSE_BACKEND_ENABLED=OFF \ +%endif -DUNIT_TESTS_DIR=%{unit_tests_dir} \ -DMISC_DIR=%{misc_dir} \ -DCOVERAGE_DIR=%{coverage_dir} \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2c06a86..c492eeb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,7 @@ SET(KEY_MANAGER_SOURCES ${SECURITY_MANAGER_WRAPPER_PATH} ${CYNARA_WRAPPER_PATH} ${TZ_BACKEND_SOURCES} + ${SE_BACKEND_SOURCES} ) SET_SOURCE_FILES_PROPERTIES( diff --git a/src/manager/common/crypto-backend.h b/src/manager/common/crypto-backend.h index 2e1455e..5a5e28f 100644 --- a/src/manager/common/crypto-backend.h +++ b/src/manager/common/crypto-backend.h @@ -25,7 +25,8 @@ namespace CKM { enum class CryptoBackend { None = 0, OpenSSL = 1, - TrustZone = 2 + TrustZone = 2, + SecureElement = 3 }; } // namespace CKM diff --git a/src/manager/crypto/se-backend/internals.cpp b/src/manager/crypto/se-backend/internals.cpp new file mode 100644 index 0000000..65260ed --- /dev/null +++ b/src/manager/crypto/se-backend/internals.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2017-2022 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.cpp + * @author isaac2.lee (isaac2.lee@samsung.com) + * @version 1.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef UNUSED_PARAMETER +#define UNUSED_PARAMETER(x) (void)(x) +#endif + +namespace CKM { +namespace Crypto { +namespace SE { +namespace Internals { + +RawBuffer toRawBuffer(unsigned char* buf, uint32_t buf_len) +{ + RawBuffer output; + output.assign(buf, buf + buf_len); + return output; +} + +kmsb_hash_algo_e getHashType(const CryptoAlgorithm &alg) +{ + HashAlgorithm hash = unpack(alg, ParamName::SV_HASH_ALGO); + switch (hash) + { + case HashAlgorithm::SHA1: + return KMSB_HASH_SHA1; + case HashAlgorithm::SHA256: + return KMSB_HASH_SHA256; + case HashAlgorithm::SHA384: + return KMSB_HASH_SHA384; + case HashAlgorithm::SHA512: + return KMSB_HASH_SHA512; + default: + break; + } + return KMSB_HASH_SHA256; +} + +kmsb_ec_type_e getEcType(const ElipticCurve ecType) +{ + if (ecType == ElipticCurve::prime192v1) + return KMSB_EC_PRIME192V1; + else if (ecType == ElipticCurve::prime256v1) + return KMSB_EC_PRIME256V1; + else if (ecType == ElipticCurve::secp384r1) + return KMSB_EC_SECP384R1; + return KMSB_EC_PRIME256V1; +} + +int kmsb_failure_retry(std::function func) +{ + int result = KMSB_ERROR_NONE; + for (size_t attempt = 0; attempt < 3; ++attempt) { + result = func(); + if (result == KMSB_ERROR_NONE || result == KMSB_ERROR_NO_KEY) + break; + LogError("occured err inside SE(errcode:" << result << ")"); + usleep(100000); + } + return result; +} + +void generateSKey(const CryptoAlgorithm &alg, + const uint32_t key_idx) +{ + UNUSED_PARAMETER(alg); + UNUSED_PARAMETER(key_idx); + + ThrowErr(Exc::Crypto::OperationNotSupported, "SE Backend not supported"); +} + +void generateAKey(const CryptoAlgorithm &alg, + const uint32_t key_idx) +{ + UNUSED_PARAMETER(alg); + UNUSED_PARAMETER(key_idx); + + ThrowErr(Exc::Crypto::OperationNotSupported, "SE Backend not supported"); +} + +/// @brief encrypt key data using SE api for DB metadata +/// @param key: target data for encryption +/// @param key_len: target data length +/// @param iv: iv data +/// @param iv_len: iv data length +/// @return Rawbuffer encrypted output +RawBuffer encryptWithDbpKey(const unsigned char* key, const uint32_t key_len, + const unsigned char* iv, const uint32_t iv_len) +{ + + unsigned char* output_data; + uint32_t output_len; + + int ret = kmsb_failure_retry(std::bind(kmsb_encrypt_with_dbp_key, + SE_BACKEND_DBP_SCHEME_VERSION, + key, key_len, + iv, iv_len, + &output_data, &output_len)); + if (ret == KMSB_ERROR_NO_KEY) { + ret = kmsb_failure_retry(std::bind(kmsb_generate_dbp_key, + false)); + if (ret != KMSB_ERROR_NONE) { + LogError("Generate Key: SE Internal error: " << ret); + ThrowErr(Exc::Crypto::InternalError, "Generate Key: SE Internal error"); + } + ret = kmsb_failure_retry(std::bind(kmsb_encrypt_with_dbp_key, + SE_BACKEND_DBP_SCHEME_VERSION, + key, key_len, + iv, iv_len, + &output_data, &output_len)); + } + if (ret != KMSB_ERROR_NONE) { + LogError("Encrypt Key: SE Internal error: " << ret); + ThrowErr(Exc::Crypto::InternalError, "Encrypt key: SE Internal error"); + } + return toRawBuffer(output_data, output_len); +} + +RawBuffer halAES(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data, + const bool isEncrypt) +{ + UNUSED_PARAMETER(key_idx); + UNUSED_PARAMETER(alg); + UNUSED_PARAMETER(data); + UNUSED_PARAMETER(isEncrypt); + + ThrowErr(Exc::Crypto::OperationNotSupported, "SE Backend not supported AES yet"); +} + +RawBuffer symmetricEncrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data) +{ + return halAES(key_idx, alg, data, true); +} + +RawBuffer symmetricDecrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data) +{ + return halAES(key_idx, alg, data, false); +} + +RawBuffer asymmetricEncrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data) +{ + UNUSED_PARAMETER(key_idx); + UNUSED_PARAMETER(alg); + UNUSED_PARAMETER(data); + + ThrowErr(Exc::Crypto::OperationNotSupported, "SE Backend not supported RSA"); +} + +RawBuffer asymmetricDecrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data) +{ + UNUSED_PARAMETER(key_idx); + UNUSED_PARAMETER(alg); + UNUSED_PARAMETER(data); + + ThrowErr(Exc::Crypto::OperationNotSupported, "SE Backend not supported RSA"); +} + +RawBuffer sign(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &message) +{ + UNUSED_PARAMETER(key_idx); + UNUSED_PARAMETER(alg); + UNUSED_PARAMETER(message); + + ThrowErr(Exc::Crypto::OperationNotSupported, "SE Backend not supported signing yet"); +} + +int verify(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &hash, + RawBuffer &signature) +{ + UNUSED_PARAMETER(key_idx); + UNUSED_PARAMETER(alg); + UNUSED_PARAMETER(hash); + UNUSED_PARAMETER(signature); + + ThrowErr(Exc::Crypto::OperationNotSupported, "SE Backend not supported verifying yet"); +} + +} // namespace Internals +} // namespace SE +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/se-backend/internals.h b/src/manager/crypto/se-backend/internals.h new file mode 100644 index 0000000..e5a5c7a --- /dev/null +++ b/src/manager/crypto/se-backend/internals.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017-2022 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 isaac2.lee (isaac2.lee@samsung.com) + * @version 1.0 + */ +#pragma once + +#include +#include +#include + +namespace CKM { +namespace Crypto { +namespace SE { +namespace Internals { + +void generateSKey(const CryptoAlgorithm &alg, const uint32_t key_idx); + +void generateAKey(const CryptoAlgorithm &alg, const uint32_t key_idx); + +// encrypt key data using SE api +RawBuffer encryptWithDbpKey(const unsigned char* key, const uint32_t key_len, + const unsigned char* iv, const uint32_t iv_len); + +RawBuffer symmetricEncrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data); +RawBuffer symmetricDecrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data); + +RawBuffer asymmetricEncrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data); + +RawBuffer asymmetricDecrypt(const uint32_t key_idx, + const CryptoAlgorithm &alg, + RawBuffer &data); + +RawBuffer sign(const uint32_t key_idx, const CryptoAlgorithm &alg, + RawBuffer &message); + +int verify(const uint32_t key_idx, const CryptoAlgorithm &alg, + RawBuffer &hash, RawBuffer &signature); + +} // namespace Internals +} // namespace SE +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index 393386d..a81c05f 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -239,6 +239,11 @@ void CKMLogic::loadDKEKFile(uid_t user, const Password &password) } handle.keyProvider = KeyProvider(wrappedDKEK, password); + if (!handle.keyProvider.isInitialized()) { + handle.keyProvider.migrateDKEK(wrappedDKEK, password); + fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password)); + LogInfo("DKEK migrated"); + } } void CKMLogic::saveDKEKFile(uid_t user, const Password &password) diff --git a/src/manager/service/file-system.cpp b/src/manager/service/file-system.cpp index e1ef844..29cdaa0 100644 --- a/src/manager/service/file-system.cpp +++ b/src/manager/service/file-system.cpp @@ -50,6 +50,7 @@ const std::string CKM_LEGACY_DB_PREFIX = "db-"; const std::string CKM_DB_PREFIX = "db0-"; const std::string CKM_REMOVED_APP_PREFIX = "removed-app-"; const std::string CKM_LOCK_FILE = RUN_DIR "/" SERVICE_NAME "/key-manager.pid"; +const std::string CKM_TEMP_POSTFIX = ".tmp"; wur std::string getPath(const std::string &prefix, uid_t uid) { @@ -125,8 +126,8 @@ RawBuffer FileSystem::getDBDEK() const void FileSystem::saveFile(const std::string &path, const RawBuffer &buffer) const { - std::ofstream os(path, std::ios::out | std::ofstream::binary | - std::ofstream::trunc); + std::ofstream os(path + CKM_TEMP_POSTFIX, std::ios::out | + std::ofstream::binary | std::ofstream::trunc); if (os.fail()) ThrowErr(Exc::FileSystemFailed, "Can't open file for writing: ", path); @@ -143,16 +144,21 @@ void FileSystem::saveFile(const std::string &path, if (os.fail()) ThrowErr(Exc::FileSystemFailed, "Failed to save file: ", path); + + if (std::rename((path + CKM_TEMP_POSTFIX).c_str(), path.c_str())) + ThrowErr(Exc::FileSystemFailed, "Can't rename file: ", path); } void FileSystem::saveDKEK(const RawBuffer &buffer) const { - saveFile(getDKEKPath(), buffer); + std::string path(getDKEKPath()); + saveFile(path, buffer); } void FileSystem::saveDBDEK(const RawBuffer &buffer) const { - saveFile(getDBDEKPath(), buffer); + std::string path(getDBDEKPath()); + saveFile(path, buffer); } void FileSystem::addRemovedApp(const ClientId &app) const diff --git a/src/manager/service/key-provider.cpp b/src/manager/service/key-provider.cpp index ddf9adf..b860c49 100644 --- a/src/manager/service/key-provider.cpp +++ b/src/manager/service/key-provider.cpp @@ -22,7 +22,10 @@ #include #include - +#include +#ifdef SE_BACKEND_ENABLED +#include +#endif using namespace CKM; namespace { @@ -124,18 +127,33 @@ int decryptAes256Gcm(const unsigned char *ciphertext, } typedef std::array KeyData; - // derives a key used for DomainKEK encryption (aka PKEK1) from random salt & user password -KeyData makePKEK1(const KeyComponentsInfo& keyInfo, const Password &password) +KeyData makePKEK1(const KeyComponentsInfoDKEK& keyInfo, const Password &password) { std::string concatPasswordClient(password.c_str()); concatPasswordClient += std::string(keyInfo.client); - KeyData key; + if (keyInfo.version != KEYCOMPONENT_VERSION) + ThrowErr(Exc::InternalError, "It's not expected version"); + +#if SE_BACKEND_ENABLED + RawBuffer salt; + if (keyInfo.backend == (int)CryptoBackend::SecureElement) { + RawBuffer salt = Crypto::SE::Internals::encryptWithDbpKey((unsigned char*)keyInfo.salt, MAX_SALT_SIZE, + (unsigned char*)keyInfo.iv, MAX_IV_SIZE); + } else { + salt = RawBuffer(keyInfo.salt, keyInfo.salt + MAX_SALT_SIZE); + } +#else + if (keyInfo.backend != (int)CryptoBackend::OpenSSL) + ThrowErr(Exc::InternalError, "It's not expected backend"); + + RawBuffer salt(keyInfo.salt, keyInfo.salt + MAX_SALT_SIZE); +#endif if (!PKCS5_PBKDF2_HMAC_SHA1(concatPasswordClient.c_str(), concatPasswordClient.size(), - keyInfo.salt, - MAX_SALT_SIZE, + salt.data(), + salt.size(), PBKDF2_ITERATIONS, key.size(), key.data())) { @@ -164,41 +182,45 @@ void unwrapDomainKEK(const RawBuffer &wrappedDomainKEKbuffer, const Password &password, KeyAndInfoContainer &domainKEK) { - WrappedKeyAndInfoContainer wrappedDomainKEK(wrappedDomainKEKbuffer.data()); - - KeyData PKEK1 = makePKEK1(wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo, password); + WrappedKeyAndInfoContainer wrappedDomainKEK; + wrappedDomainKEK.setWrappedDKEKAndInfo(wrappedDomainKEKbuffer.data()); + KeyData PKEK1 = makePKEK1(wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo, password); int keyLength; - if (0 > (keyLength = decryptAes256Gcm(wrappedDomainKEK.getWrappedKeyAndInfo().wrappedKey, - wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.keyLength, - wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.tag, + if (0 > (keyLength = decryptAes256Gcm(wrappedDomainKEK.getWrappedDKEKAndInfo().wrappedKey, + wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.keyLength, + wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.tag, PKEK1.data(), - wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.iv, - domainKEK.getKeyAndInfo().key))) + wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.iv, + domainKEK.getDKEKAndInfo().key))) ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed"); - domainKEK.setKeyInfo(&(wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo)); + domainKEK.setKeyInfo(&(wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo)); + domainKEK.setDKEKInfo(wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.version, + wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.backend); domainKEK.setKeyInfoKeyLength(static_cast(keyLength)); } RawBuffer wrapDomainKEK(KeyAndInfoContainer &domainKEK, const Password &password) { - KeyData PKEK1 = makePKEK1(domainKEK.getKeyAndInfo().keyInfo, password); + KeyData PKEK1 = makePKEK1(domainKEK.getDKEKAndInfo().keyInfo, password); WrappedKeyAndInfoContainer wrappedDomainKEK = WrappedKeyAndInfoContainer(); - wrappedDomainKEK.setKeyInfo(&(domainKEK.getKeyAndInfo().keyInfo)); + wrappedDomainKEK.setKeyInfo(&(domainKEK.getDKEKAndInfo().keyInfo)); + wrappedDomainKEK.setDKEKInfo(domainKEK.getDKEKAndInfo().keyInfo.version, + domainKEK.getDKEKAndInfo().keyInfo.backend); int wrappedLength; - if (0 > (wrappedLength = encryptAes256Gcm(domainKEK.getKeyAndInfo().key, - domainKEK.getKeyAndInfo().keyInfo.keyLength, + if (0 > (wrappedLength = encryptAes256Gcm(domainKEK.getDKEKAndInfo().key, + domainKEK.getDKEKAndInfo().keyInfo.keyLength, PKEK1.data(), - domainKEK.getKeyAndInfo().keyInfo.iv, - wrappedDomainKEK.getWrappedKeyAndInfo().wrappedKey, - wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.tag))) + domainKEK.getDKEKAndInfo().keyInfo.iv, + wrappedDomainKEK.getWrappedDKEKAndInfo().wrappedKey, + wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.tag))) ThrowErr(Exc::InternalError, "DomainKEK encryption failed"); wrappedDomainKEK.setKeyInfoKeyLength(static_cast(wrappedLength)); - return toRawBuffer(wrappedDomainKEK.getWrappedKeyAndInfo()); + return toRawBuffer(wrappedDomainKEK.getWrappedDKEKAndInfo()); } template @@ -212,10 +234,21 @@ bool randomize(uint8_t (&array)[N]) WrappedKeyAndInfoContainer::WrappedKeyAndInfoContainer() { memset(&wrappedKeyAndInfo, 0, sizeof(WrappedKeyAndInfo)); + memset(&wrappedDKEKAndInfo, 0, sizeof(WrappedKeyAndInfoDKEK)); } -WrappedKeyAndInfoContainer::WrappedKeyAndInfoContainer(const unsigned char - *data) +WrappedKeyAndInfo &WrappedKeyAndInfoContainer::getWrappedKeyAndInfo() +{ + return wrappedKeyAndInfo; +} + +WrappedKeyAndInfoDKEK &WrappedKeyAndInfoContainer::getWrappedDKEKAndInfo() +{ + return wrappedDKEKAndInfo; +} + +void WrappedKeyAndInfoContainer::setWrappedKeyAndInfo( + const unsigned char *data) { memcpy(&wrappedKeyAndInfo, data, sizeof(WrappedKeyAndInfo)); @@ -231,14 +264,27 @@ WrappedKeyAndInfoContainer::WrappedKeyAndInfoContainer(const unsigned char } } -WrappedKeyAndInfo &WrappedKeyAndInfoContainer::getWrappedKeyAndInfo() +void WrappedKeyAndInfoContainer::setWrappedDKEKAndInfo( + const unsigned char *data) { - return wrappedKeyAndInfo; + memcpy(&wrappedDKEKAndInfo, data, sizeof(WrappedKeyAndInfoDKEK)); + + if (wrappedDKEKAndInfo.keyInfo.keyLength > sizeof(wrappedDKEKAndInfo.wrappedKey)) { + ThrowErr(Exc::InternalError, + "Wrapped key info is corrupted. Key length exceeds the size of the key buffer."); + } + + size_t maxlen = sizeof(wrappedDKEKAndInfo.keyInfo.client); + if (strnlen(wrappedDKEKAndInfo.keyInfo.client, maxlen) == maxlen) { + ThrowErr(Exc::InternalError, + "Wrapped key info is corrupted. Client id is not NULL terminated."); + } } -void WrappedKeyAndInfoContainer::setKeyInfoKeyLength(const unsigned int length) +void WrappedKeyAndInfoContainer::setKeyInfoKeyLength(const uint32_t length) { wrappedKeyAndInfo.keyInfo.keyLength = length; + wrappedDKEKAndInfo.keyInfo.keyLength = length; } void WrappedKeyAndInfoContainer::setKeyInfoClient(const std::string resized_client) @@ -248,12 +294,14 @@ void WrappedKeyAndInfoContainer::setKeyInfoClient(const std::string resized_clie } strncpy(wrappedKeyAndInfo.keyInfo.client, resized_client.c_str(), resized_client.size()); + strncpy(wrappedDKEKAndInfo.keyInfo.client, resized_client.c_str(), resized_client.size()); } void WrappedKeyAndInfoContainer::setKeyInfoSalt(const unsigned char *salt, const int size) { memcpy(wrappedKeyAndInfo.keyInfo.salt, salt, size); + memcpy(wrappedDKEKAndInfo.keyInfo.salt, salt, size); } void WrappedKeyAndInfoContainer::setKeyInfo(const KeyComponentsInfo @@ -261,6 +309,13 @@ void WrappedKeyAndInfoContainer::setKeyInfo(const KeyComponentsInfo { memcpy(&(wrappedKeyAndInfo.keyInfo), keyComponentsInfo, sizeof(KeyComponentsInfo)); + wrappedDKEKAndInfo.keyInfo.set(wrappedKeyAndInfo.keyInfo); +} + +void WrappedKeyAndInfoContainer::setDKEKInfo(const uint32_t version, const uint32_t backend) +{ + wrappedDKEKAndInfo.keyInfo.version = version; + wrappedDKEKAndInfo.keyInfo.backend = backend; } WrappedKeyAndInfoContainer::~WrappedKeyAndInfoContainer() @@ -270,32 +325,52 @@ WrappedKeyAndInfoContainer::~WrappedKeyAndInfoContainer() KeyAndInfoContainer::KeyAndInfoContainer() { memset(&keyAndInfo, 0, sizeof(KeyAndInfo)); + memset(&DKEKAndInfo, 0, sizeof(KeyAndInfoDKEK)); +} + +KeyAndInfo &KeyAndInfoContainer::getKeyAndInfo() +{ + return keyAndInfo; +} + +KeyAndInfoDKEK &KeyAndInfoContainer::getDKEKAndInfo() +{ + return DKEKAndInfo; } -KeyAndInfoContainer::KeyAndInfoContainer(const unsigned char *data) +void KeyAndInfoContainer::setKeyAndInfo(const unsigned char *data) { memcpy(&keyAndInfo, data, sizeof(KeyAndInfo)); } -KeyAndInfo &KeyAndInfoContainer::getKeyAndInfo() +void KeyAndInfoContainer::setDKEKAndInfo(const unsigned char *data) { - return keyAndInfo; + memcpy(&DKEKAndInfo, data, sizeof(KeyAndInfoDKEK)); } -void KeyAndInfoContainer::setKeyInfoKeyLength(unsigned int length) +void KeyAndInfoContainer::setKeyInfoKeyLength(const uint32_t length) { keyAndInfo.keyInfo.keyLength = length; + DKEKAndInfo.keyInfo.keyLength = length; } void KeyAndInfoContainer::setKeyInfo(const KeyComponentsInfo *keyComponentsInfo) { memcpy(&(keyAndInfo.keyInfo), keyComponentsInfo, sizeof(KeyComponentsInfo)); + DKEKAndInfo.keyInfo.set(keyAndInfo.keyInfo); +} + +void KeyAndInfoContainer::setDKEKInfo(const uint32_t version, const uint32_t backend) +{ + DKEKAndInfo.keyInfo.version = version; + DKEKAndInfo.keyInfo.backend = backend; } KeyAndInfoContainer::~KeyAndInfoContainer() { // overwrite key ZeroMemory(reinterpret_cast(&keyAndInfo), sizeof(KeyAndInfo)); + ZeroMemory(reinterpret_cast(&DKEKAndInfo), sizeof(KeyAndInfoDKEK)); } KeyProvider::KeyProvider() : @@ -311,11 +386,12 @@ KeyProvider::KeyProvider( m_domainKEK(new KeyAndInfoContainer()), m_isInitialized(true) { - if (domainKEKInWrapForm.size() != sizeof(WrappedKeyAndInfo)) { - LogError("input size:" << domainKEKInWrapForm.size() - << " Expected: " << sizeof(WrappedKeyAndInfo)); - ThrowErr(Exc::InternalError, - "buffer doesn't have proper size to store WrappedKeyAndInfo in KeyProvider Constructor"); + if (domainKEKInWrapForm.size() != sizeof(WrappedKeyAndInfoDKEK)) { + LogWarning("input size:" << domainKEKInWrapForm.size() + << " Expected: " << sizeof(WrappedKeyAndInfoDKEK)); + LogWarning("buffer doesn't have proper size to store WrappedKeyAndInfoDKEK in KeyProvider Constructor"); + m_isInitialized = false; + return; } unwrapDomainKEK(domainKEKInWrapForm, password, *m_domainKEK); @@ -355,9 +431,9 @@ RawBuffer KeyProvider::getPureDomainKEK() ThrowErr(Exc::InternalError, "Object not initialized!"); // TODO secure - return RawBuffer(m_domainKEK->getKeyAndInfo().key, - (m_domainKEK->getKeyAndInfo().key) + - m_domainKEK->getKeyAndInfo().keyInfo.keyLength); + return RawBuffer(m_domainKEK->getDKEKAndInfo().key, + (m_domainKEK->getDKEKAndInfo().key) + + m_domainKEK->getDKEKAndInfo().keyInfo.keyLength); } RawBuffer KeyProvider::getWrappedDomainKEK(const Password &password) @@ -377,16 +453,17 @@ RawBuffer KeyProvider::getPureDEK(const RawBuffer &DEKInWrapForm) if (DEKInWrapForm.size() != sizeof(WrappedKeyAndInfo)) { LogError("input size:" << DEKInWrapForm.size() << " Expected: " << sizeof(WrappedKeyAndInfo)); + ThrowErr(Exc::InternalError, "buffer doesn't have proper size to store " "WrappedKeyAndInfo in KeyProvider::getPureDEK"); } KeyAndInfoContainer kmcDEK = KeyAndInfoContainer(); - WrappedKeyAndInfoContainer wkmcDEK = WrappedKeyAndInfoContainer( - DEKInWrapForm.data()); + WrappedKeyAndInfoContainer wkmcDEK = WrappedKeyAndInfoContainer(); + wkmcDEK.setWrappedKeyAndInfo(DEKInWrapForm.data()); - KeyData PKEK2 = makePKEK2(m_domainKEK->getKeyAndInfo().key, + KeyData PKEK2 = makePKEK2(m_domainKEK->getDKEKAndInfo().key, wkmcDEK.getWrappedKeyAndInfo().keyInfo.client); int keyLength; @@ -426,11 +503,11 @@ RawBuffer KeyProvider::generateDEK(const std::string &client) if (!randomize(key) || !randomize(wkmcDEK.getWrappedKeyAndInfo().keyInfo.iv)) ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); - KeyData PKEK2 = makePKEK2(m_domainKEK->getKeyAndInfo().key, resized_client); + KeyData PKEK2 = makePKEK2(m_domainKEK->getDKEKAndInfo().key, resized_client); int wrappedKeyLength; if (0 > (wrappedKeyLength = encryptAes256Gcm(key, - m_domainKEK->getKeyAndInfo().keyInfo.keyLength, + m_domainKEK->getDKEKAndInfo().keyInfo.keyLength, PKEK2.data(), wkmcDEK.getWrappedKeyAndInfo().keyInfo.iv, wkmcDEK.getWrappedKeyAndInfo().wrappedKey, @@ -444,6 +521,58 @@ RawBuffer KeyProvider::generateDEK(const std::string &client) return toRawBuffer(wkmcDEK.getWrappedKeyAndInfo()); } +void KeyProvider::migrateDKEK(const RawBuffer &wrappedDomainKEKbuffer, + const Password &password) +{ + WrappedKeyAndInfo wrappedInfo; + if (wrappedDomainKEKbuffer.size() != sizeof(WrappedKeyAndInfo)) { + LogError("[migrateDKEK] Input size:" << wrappedDomainKEKbuffer.size() << + " Expected: " << sizeof(WrappedKeyAndInfo)); + ThrowErr(Exc::InternalError, + "buffer doesn't have proper size to store "); + } + memcpy(&wrappedInfo, wrappedDomainKEKbuffer.data(), sizeof(WrappedKeyAndInfo)); + + size_t maxlen = sizeof(wrappedInfo.keyInfo.client); + if (strnlen(wrappedInfo.keyInfo.client, maxlen) == maxlen) { + ThrowErr(Exc::InternalError, + "Wrapped key info is corrupted. Client id is not NULL terminated."); + } + + KeyComponentsInfo keyInfo = wrappedInfo.keyInfo; + std::string concatPasswordClient(password.c_str()); + concatPasswordClient += std::string(keyInfo.client); + + KeyData PKEK1; + if (!PKCS5_PBKDF2_HMAC_SHA1(concatPasswordClient.c_str(), + concatPasswordClient.size(), + keyInfo.salt, + MAX_SALT_SIZE, + PBKDF2_ITERATIONS, + PKEK1.size(), + PKEK1.data())) { + ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); + } + + int keyLength; + if (0 > (keyLength = decryptAes256Gcm(wrappedInfo.wrappedKey, + keyInfo.keyLength, + keyInfo.tag, + PKEK1.data(), + keyInfo.iv, + m_domainKEK->getDKEKAndInfo().key))) + ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed"); + + m_domainKEK->getDKEKAndInfo().keyInfo.set(keyInfo); + m_domainKEK->setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::OpenSSL); +#ifdef SE_BACKEND_ENABLED + m_domainKEK->setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::SecureElement); +#endif + m_domainKEK->setKeyInfoKeyLength(static_cast(keyLength)); + m_isInitialized = true; + LogDebug("Migrate DKEK Success"); +} + RawBuffer KeyProvider::reencrypt( const RawBuffer &domainKEKInWrapForm, const Password &oldPass, @@ -466,22 +595,23 @@ RawBuffer KeyProvider::generateDomainKEK( const std::string &user, const Password &userPassword) { - WrappedKeyAndInfoContainer wkmcDKEK = WrappedKeyAndInfoContainer(); - KeyAndInfoContainer domainKEK; - if (!randomize(domainKEK.getKeyAndInfo().keyInfo.salt) || - !randomize(domainKEK.getKeyAndInfo().key) || - !randomize(domainKEK.getKeyAndInfo().keyInfo.iv)) { + if (!randomize(domainKEK.getDKEKAndInfo().keyInfo.salt) || + !randomize(domainKEK.getDKEKAndInfo().key) || + !randomize(domainKEK.getDKEKAndInfo().keyInfo.iv)) { ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); } - domainKEK.setKeyInfoKeyLength(sizeof(domainKEK.getKeyAndInfo().key)); - - if (user.size() >= sizeof(domainKEK.getKeyAndInfo().keyInfo.client)) { + domainKEK.setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::OpenSSL); +#ifdef SE_BACKEND_ENABLED + domainKEK.setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::SecureElement); +#endif + domainKEK.setKeyInfoKeyLength(sizeof(domainKEK.getDKEKAndInfo().key)); + if (user.size() >= sizeof(domainKEK.getDKEKAndInfo().keyInfo.client)) { ThrowErr(Exc::InternalError, "Client name too long"); } - strncpy(domainKEK.getKeyAndInfo().keyInfo.client, user.c_str(), user.size()); + strncpy(domainKEK.getDKEKAndInfo().keyInfo.client, user.c_str(), user.size()); return wrapDomainKEK(domainKEK, userPassword); } diff --git a/src/manager/service/key-provider.h b/src/manager/service/key-provider.h index 713e952..dcc695e 100644 --- a/src/manager/service/key-provider.h +++ b/src/manager/service/key-provider.h @@ -62,6 +62,8 @@ namespace CKM { +const uint32_t KEYCOMPONENT_VERSION = 2; + typedef struct KeyComponentsInfo_ { uint32_t keyLength; char client[MAX_CLIENT_ID_SIZE]; @@ -80,32 +82,62 @@ typedef struct WrappedKeyAndInfo_ { uint8_t wrappedKey[MAX_WRAPPED_KEY_SIZE]; } WrappedKeyAndInfo; +typedef struct KeyComponentsInfoDKEK_ : KeyComponentsInfo{ + uint32_t version; + uint32_t backend; + void set(const KeyComponentsInfo &src) { + keyLength = src.keyLength; + memcpy(&client, &src.client, MAX_CLIENT_ID_SIZE); + memcpy(&salt, &src.salt, MAX_SALT_SIZE); + memcpy(&iv, &src.iv, MAX_IV_SIZE); + memcpy(&tag, &src.tag, MAX_IV_SIZE); + } +} KeyComponentsInfoDKEK; + +typedef struct KeyAndInfoDKEK_ { + KeyComponentsInfoDKEK keyInfo; + uint8_t key[MAX_KEY_SIZE]; +} KeyAndInfoDKEK; + +typedef struct WrappedKeyAndInfoDKEK_ { + KeyComponentsInfoDKEK keyInfo; + uint8_t wrappedKey[MAX_WRAPPED_KEY_SIZE]; +} WrappedKeyAndInfoDKEK; + class WrappedKeyAndInfoContainer { public: WrappedKeyAndInfoContainer(); - WrappedKeyAndInfoContainer(const unsigned char *); WrappedKeyAndInfo &getWrappedKeyAndInfo(); - void setKeyInfoKeyLength(const unsigned int); + WrappedKeyAndInfoDKEK &getWrappedDKEKAndInfo(); + void setWrappedKeyAndInfo(const unsigned char *); + void setWrappedDKEKAndInfo(const unsigned char *); + void setKeyInfoKeyLength(const uint32_t); void setKeyInfoClient(const std::string); void setKeyInfoSalt(const unsigned char *, const int); void setKeyInfo(const KeyComponentsInfo *); + void setDKEKInfo(const uint32_t, const uint32_t); ~WrappedKeyAndInfoContainer(); private: WrappedKeyAndInfo wrappedKeyAndInfo; + WrappedKeyAndInfoDKEK wrappedDKEKAndInfo; }; class KeyAndInfoContainer { public: KeyAndInfoContainer(); - explicit KeyAndInfoContainer(const unsigned char *); KeyAndInfo &getKeyAndInfo(); - void setKeyInfoKeyLength(const unsigned int); + KeyAndInfoDKEK &getDKEKAndInfo(); + void setKeyAndInfo(const unsigned char *); + void setDKEKAndInfo(const unsigned char *); + void setKeyInfoKeyLength(const uint32_t); void setKeyInfo(const KeyComponentsInfo *); + void setDKEKInfo(const uint32_t, const uint32_t); ~KeyAndInfoContainer(); private: KeyAndInfo keyAndInfo; + KeyAndInfoDKEK DKEKAndInfo; }; @@ -157,6 +189,10 @@ public: static RawBuffer generateDomainKEK(const std::string &user, const Password &userPassword); + void migrateDKEK(const RawBuffer &wrappedDomainKEKbuffer, + const Password &password); + RawBuffer migrateDBDEK(const RawBuffer &DEKInWrapForm); + // This will be called by framework at the begin of the program static int initializeLibrary(); // This will be called by framework at the end of the program diff --git a/unit-tests/CMakeLists.txt b/unit-tests/CMakeLists.txt index 6f8636f..c104e5e 100644 --- a/unit-tests/CMakeLists.txt +++ b/unit-tests/CMakeLists.txt @@ -135,6 +135,7 @@ SET(UNIT_TESTS_SOURCES ${MANAGER_PATH}/service/for-each-file.cpp ${MANAGER_PATH}/service/key-provider.cpp ${MANAGER_PATH}/service/ss-crypto.cpp + ${SE_BACKEND_SOURCES} ) ADD_EXECUTABLE( diff --git a/unit-tests/test_key-provider.cpp b/unit-tests/test_key-provider.cpp index c5eb60d..7d9793f 100644 --- a/unit-tests/test_key-provider.cpp +++ b/unit-tests/test_key-provider.cpp @@ -244,7 +244,7 @@ POSITIVE_TEST_CASE(wrapped_container) WrappedKeyAndInfo wki; wki.keyInfo.keyLength = MAX_WRAPPED_KEY_SIZE; - BOOST_REQUIRE_NO_THROW(WrappedKeyAndInfoContainer(reinterpret_cast(&wki))); + BOOST_REQUIRE_NO_THROW(wkic.setWrappedKeyAndInfo(reinterpret_cast(&wki))); } NEGATIVE_TEST_CASE(wrapped_container) @@ -256,13 +256,13 @@ NEGATIVE_TEST_CASE(wrapped_container) WrappedKeyAndInfo wki; wki.keyInfo.keyLength = MAX_WRAPPED_KEY_SIZE + 1; - BOOST_REQUIRE_THROW(WrappedKeyAndInfoContainer(reinterpret_cast(&wki)), + BOOST_REQUIRE_THROW(wkic.setWrappedKeyAndInfo(reinterpret_cast(&wki)), Exc::InternalError); // missing NULL termination in wki2.keyInfo.client WrappedKeyAndInfo wki2; memset(&wki2, 0x01, sizeof(WrappedKeyAndInfo)); - BOOST_REQUIRE_THROW(WrappedKeyAndInfoContainer(reinterpret_cast(&wki2)), + BOOST_REQUIRE_THROW(wkic.setWrappedKeyAndInfo(reinterpret_cast(&wki2)), Exc::InternalError); } -- 2.7.4