From 7db059012a3f4c253c6b4b03bb0fa2056c6c5454 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 | 4 + packaging/key-manager.spec | 9 ++ src/CMakeLists.txt | 8 + 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/crypto-backend.h | 3 +- src/manager/service/file-system.cpp | 14 +- src/manager/service/key-provider.cpp | 238 +++++++++++++++++++++------- src/manager/service/key-provider.h | 44 ++++- tests/CMakeLists.txt | 16 ++ tests/test_key-provider.cpp | 9 +- tools/ckm_db_tool/CMakeLists.txt | 8 + 13 files changed, 581 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 20309dd..dd54573 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,10 @@ IF (TZ_BACKEND_ENABLED) ADD_DEFINITIONS("-DTZ_BACKEND_ENABLED") ENDIF() +IF (SE_BACKEND_ENABLED) + ADD_DEFINITIONS("-DSE_BACKEND_ENABLED") +ENDIF() + IF (DEFINED WATCHDOG_ENABLED) MESSAGE("WATCHDOG ENABELD!") ADD_DEFINITIONS("-DWATCHDOG_ENABLED") diff --git a/packaging/key-manager.spec b/packaging/key-manager.spec index 4040365..6272fa0 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} Name: key-manager Summary: Central Key Manager and utilities @@ -42,6 +43,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} %{?systemd_requires} @@ -182,6 +186,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 -DTEST_DIR=%{test_dir} \ -DDUMP_LEGACY_DB_LIBNAME=%{dump_legacy_db_libname} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7369a67..e66bb78 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,6 +96,14 @@ SET(KEY_MANAGER_SOURCES ) ENDIF() +IF(SE_BACKEND_ENABLED) +SET(KEY_MANAGER_SOURCES + ${KEY_MANAGER_SOURCES} + ${KEY_MANAGER_PATH}/crypto/se-backend/internals.cpp + ) +SET(KM_LINK_EXTRA_DEPS ${KM_LINK_EXTRA_DEPS} key-manager-se-backend) +ENDIF() + SET_SOURCE_FILES_PROPERTIES( ${KEY_MANAGER_SOURCES} PROPERTIES diff --git a/src/manager/crypto/se-backend/internals.cpp b/src/manager/crypto/se-backend/internals.cpp new file mode 100644 index 0000000..4dae68c --- /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..b90bfba --- /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 c26dc6a..ae5b316 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -95,6 +95,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/crypto-backend.h b/src/manager/service/crypto-backend.h index 2e1455e..5a5e28f 100644 --- a/src/manager/service/crypto-backend.h +++ b/src/manager/service/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/service/file-system.cpp b/src/manager/service/file-system.cpp index e1ef844..4b18e10 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 6049acb..c35b775 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 { @@ -126,18 +129,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())) { @@ -166,41 +184,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 @@ -214,10 +236,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)); @@ -233,14 +266,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) @@ -250,12 +296,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 @@ -263,6 +311,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() @@ -272,32 +327,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() : @@ -316,11 +391,12 @@ KeyProvider::KeyProvider( if (!m_isInitialized) ThrowErr(Exc::InternalError, "Object not initialized!. Should not happened"); - 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); @@ -360,9 +436,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) @@ -382,16 +458,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; @@ -431,11 +508,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, @@ -449,6 +526,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, @@ -471,22 +600,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/tests/CMakeLists.txt b/tests/CMakeLists.txt index 27078e4..0ce18e6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,6 +57,14 @@ SET(GENERATOR_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/encryption-scheme/generate-db.cpp ) +IF(SE_BACKEND_ENABLED) +SET(ENCRYPTION_SCHEME_SOURCES + ${ENCRYPTION_SCHEME_SOURCES} + ${KEY_MANAGER_PATH}/crypto/se-backend/internals.cpp + ) +SET(ENCRYPTION_SCHEME_DEP_LIBRARIES ${TEST_LINK_EXTRA_DEPS} key-manager-se-backend) +ENDIF() + ADD_EXECUTABLE(${TARGET_CKM_GENERATOR} ${GENERATOR_SOURCES} ${ENCRYPTION_SCHEME_SOURCES}) SET(SCHEME_TEST_LIBRARIES @@ -163,6 +171,14 @@ SET(TEST_MERGED_SOURCES ) ENDIF() +IF(SE_BACKEND_ENABLED) +SET(TEST_MERGED_SOURCES + ${TEST_MERGED_SOURCES} + ${KEY_MANAGER_PATH}/crypto/se-backend/internals.cpp + ) +SET(TEST_LINK_EXTRA_DEPS ${TEST_LINK_EXTRA_DEPS} key-manager-se-backend) +ENDIF() + LINK_DIRECTORIES(${KEY_MANAGER_DEP_LIBRARY_DIRS}) ADD_EXECUTABLE(${TARGET_TEST_MERGED} ${TEST_MERGED_SOURCES} ${ENCRYPTION_SCHEME_SOURCES}) diff --git a/tests/test_key-provider.cpp b/tests/test_key-provider.cpp index ea369d1..b26e82c 100644 --- a/tests/test_key-provider.cpp +++ b/tests/test_key-provider.cpp @@ -189,7 +189,8 @@ POSITIVE_TEST_CASE(wrapped_container) CKM::WrappedKeyAndInfo wrapped3; wrapped3.keyInfo.keyLength = MAX_WRAPPED_KEY_SIZE; - BOOST_REQUIRE_NO_THROW(CKM::WrappedKeyAndInfoContainer wrappedContainer3( + CKM::WrappedKeyAndInfoContainer wrappedContainer3; + BOOST_REQUIRE_NO_THROW(wrappedContainer3.setWrappedKeyAndInfo( reinterpret_cast(&wrapped3))); } @@ -203,14 +204,16 @@ NEGATIVE_TEST_CASE(wrapped_container) CKM::WrappedKeyAndInfo wrapped3; wrapped3.keyInfo.keyLength = MAX_WRAPPED_KEY_SIZE + 1; - BOOST_REQUIRE_THROW(CKM::WrappedKeyAndInfoContainer wrappedContainer3( + CKM::WrappedKeyAndInfoContainer wrappedContainer3; + BOOST_REQUIRE_THROW(wrappedContainer3.setWrappedKeyAndInfo( reinterpret_cast(&wrapped3)), CKM::Exc::InternalError); // missing NULL termination in wrapped4.keyInfo.client CKM::WrappedKeyAndInfo wrapped4; memset(&wrapped4, 0x01, sizeof(CKM::WrappedKeyAndInfo)); - BOOST_REQUIRE_THROW(CKM::WrappedKeyAndInfoContainer wrappedContainer3( + CKM::WrappedKeyAndInfoContainer wrappedContainer4; + BOOST_REQUIRE_THROW(wrappedContainer4.setWrappedKeyAndInfo( reinterpret_cast(&wrapped4)), CKM::Exc::InternalError); } diff --git a/tools/ckm_db_tool/CMakeLists.txt b/tools/ckm_db_tool/CMakeLists.txt index e282e79..1b20ec4 100644 --- a/tools/ckm_db_tool/CMakeLists.txt +++ b/tools/ckm_db_tool/CMakeLists.txt @@ -91,6 +91,14 @@ SET(CKM_DB_TOOLS_SOURCES ) ENDIF() +IF(SE_BACKEND_ENABLED) +SET(CKM_DB_TOOLS_SOURCES + ${CKM_DB_TOOLS_SOURCES} + ${KEY_MANAGER_PATH}/crypto/se-backend/internals.cpp + ) +SET(CKM_DB_TOOL_LINK_EXTRA_DEPS ${CKM_DB_TOOL_LINK_EXTRA_DEPS} key-manager-se-backend) +ENDIF() + LINK_DIRECTORIES(${CKM_DB_TOOL_DEP_LIBRARY_DIRS}) ADD_EXECUTABLE(${CKM_DB_TOOL} ${CKM_DB_TOOLS_SOURCES} ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm_db_tool.cpp) -- 2.7.4