From 4a0dc292d4cc243a615699b3104f2d7749c043c7 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 5 Oct 2022 15:51:33 +0200 Subject: [PATCH] Refactor KeyProvider Apply modifications while keeping key file format and encryption scheme unchanged: * Remove unused code * Deduplicate code * Unify key naming * Simplify structures keeping various forms of keys and their metadata * Update tests Change-Id: I38caceb6c38bfecbdbbb290df39042ba7b17b394 --- misc/encryption_scheme/test_encryption-scheme.cpp | 20 - src/manager/main/key-manager-main.cpp | 6 - src/manager/service/ckm-logic.cpp | 2 +- src/manager/service/key-provider.cpp | 465 ++++++---------------- src/manager/service/key-provider.h | 184 +++------ unit-tests/test_key-provider.cpp | 107 ++--- 6 files changed, 224 insertions(+), 560 deletions(-) diff --git a/misc/encryption_scheme/test_encryption-scheme.cpp b/misc/encryption_scheme/test_encryption-scheme.cpp index 53c5683..d129169 100644 --- a/misc/encryption_scheme/test_encryption-scheme.cpp +++ b/misc/encryption_scheme/test_encryption-scheme.cpp @@ -82,25 +82,6 @@ struct TestConfig { } }; -struct KeyProviderLib { - KeyProviderLib() - { - try { - KeyProvider::initializeLibrary(); - } catch (const Exc::Exception &) { - std::cout << "Library initialization failed!" << std::endl; - } - } - ~KeyProviderLib() - { - try { - KeyProvider::closeLibrary(); - } catch (const Exc::Exception &) { - std::cout << "Library deinitialization failed!" << std::endl; - } - } -}; - struct LogSetup { LogSetup() { @@ -112,7 +93,6 @@ struct LogSetup { } // namespace anonymous -BOOST_GLOBAL_FIXTURE(KeyProviderLib); BOOST_GLOBAL_FIXTURE(TestConfig); BOOST_GLOBAL_FIXTURE(LogSetup); BOOST_FIXTURE_TEST_SUITE(ENCRYPTION_SCHEME_TEST, OnlycapFixture) diff --git a/src/manager/main/key-manager-main.cpp b/src/manager/main/key-manager-main.cpp index bb867b7..d1840c5 100644 --- a/src/manager/main/key-manager-main.cpp +++ b/src/manager/main/key-manager-main.cpp @@ -122,8 +122,6 @@ int main(void) initializeEntropy(); - CKM::KeyProvider::initializeLibrary(); - { LogInfo("Start!"); CKM::SocketManager manager; @@ -135,10 +133,6 @@ int main(void) manager.MainLoop(); } - - // Manager has been destroyed and we may close external libraries. - LogInfo("Deinit SKMM and openssl"); - CKM::KeyProvider::closeLibrary(); } catch (const std::runtime_error &e) { LogError(e.what()); } diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index a81c05f..311884f 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -240,7 +240,7 @@ void CKMLogic::loadDKEKFile(uid_t user, const Password &password) handle.keyProvider = KeyProvider(wrappedDKEK, password); if (!handle.keyProvider.isInitialized()) { - handle.keyProvider.migrateDKEK(wrappedDKEK, password); + handle.keyProvider.migrateDomainKEK(wrappedDKEK, password); fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password)); LogInfo("DKEK migrated"); } diff --git a/src/manager/service/key-provider.cpp b/src/manager/service/key-provider.cpp index ce908c7..24c48aa 100644 --- a/src/manager/service/key-provider.cpp +++ b/src/manager/service/key-provider.cpp @@ -14,14 +14,18 @@ * limitations under the License */ -#include +#include + +#include +#include +#include +#include + #include -#include #include #include #include -#include #include #ifdef SE_BACKEND_ENABLED #include @@ -30,6 +34,10 @@ using namespace CKM; namespace { +constexpr int PBKDF2_ITERATIONS = 4096; +constexpr uint32_t KEYCOMPONENT_VERSION = 2; +constexpr int OPENSSL_ENGINE_ERROR = -4; + template RawBuffer toRawBuffer(const T &data) { @@ -127,100 +135,94 @@ int decryptAes256Gcm(const unsigned char *ciphertext, } typedef std::array KeyData; + +KeyData PBKDF(const std::string& pass, const unsigned char *salt, int saltlen) +{ + KeyData key; + if (!PKCS5_PBKDF2_HMAC_SHA1(pass.c_str(), + pass.size(), + salt, + saltlen, + PBKDF2_ITERATIONS, + key.size(), + key.data())) { + ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); + } + return key; +} + // derives a key used for DomainKEK encryption (aka PKEK1) from random salt & user password -KeyData makePKEK1(const KeyComponentsInfoDKEK& keyInfo, const Password &password) +KeyData makePKEK1(const DomainKEKInfo& domainKEKInfo, const Password &password) { std::string concatPasswordClient(password.c_str()); - concatPasswordClient += std::string(keyInfo.client); - KeyData key; - if (keyInfo.version != KEYCOMPONENT_VERSION) + concatPasswordClient += std::string(domainKEKInfo.client); + + if (domainKEKInfo.version != KEYCOMPONENT_VERSION) ThrowErr(Exc::InternalError, "It's not expected version"); -#if SE_BACKEND_ENABLED RawBuffer salt; - if (keyInfo.backend == (int)CryptoBackend::SecureElement) { - 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); - } + if (domainKEKInfo.backend == (int)CryptoBackend::SecureElement) { +#if SE_BACKEND_ENABLED + salt = Crypto::SE::Internals::encryptWithDbpKey((unsigned char*)domainKEKInfo.salt, + MAX_SALT_SIZE, + (unsigned char*)domainKEKInfo.iv, + MAX_IV_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(), - salt.data(), - salt.size(), - PBKDF2_ITERATIONS, - key.size(), - key.data())) { - ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); + } else if (domainKEKInfo.backend == (int)CryptoBackend::OpenSSL) { + salt = RawBuffer(domainKEKInfo.salt, domainKEKInfo.salt + MAX_SALT_SIZE); + } else { + ThrowErr(Exc::InternalError, "It's not expected backend"); } - return key; + + return PBKDF(concatPasswordClient, salt.data(), salt.size()); } // derives a key (PKEK2) from DomainKEK and custom client string (may be a client id or uid) KeyData makePKEK2(const uint8_t *domainKEK, const std::string &client) { - KeyData key; - if (!PKCS5_PBKDF2_HMAC_SHA1(client.c_str(), - client.size(), - domainKEK, - MAX_SALT_SIZE, - PBKDF2_ITERATIONS, - key.size(), - key.data())) { - ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); - } - return key; + return PBKDF(client, domainKEK, MAX_SALT_SIZE); } void unwrapDomainKEK(const RawBuffer &wrappedDomainKEKbuffer, const Password &password, - KeyAndInfoContainer &domainKEK) + DomainKEKAndInfo &domainKEK) { - WrappedKeyAndInfoContainer wrappedDomainKEK; - wrappedDomainKEK.setWrappedDKEKAndInfo(wrappedDomainKEKbuffer.data()); - KeyData PKEK1 = makePKEK1(wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo, password); + DomainKEKAndInfo wrappedDomainKEK(wrappedDomainKEKbuffer); + KeyData PKEK1 = makePKEK1(wrappedDomainKEK.info, password); int keyLength; - if (0 > (keyLength = decryptAes256Gcm(wrappedDomainKEK.getWrappedDKEKAndInfo().wrappedKey, - wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.keyLength, - wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.tag, + if (0 > (keyLength = decryptAes256Gcm(wrappedDomainKEK.key, + wrappedDomainKEK.info.keyLength, + wrappedDomainKEK.info.tag, PKEK1.data(), - wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.iv, - domainKEK.getDKEKAndInfo().key))) + wrappedDomainKEK.info.iv, + domainKEK.key))) ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed"); - domainKEK.setKeyInfo(&(wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo)); - domainKEK.setDKEKInfo(wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.version, - wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.backend); - domainKEK.setKeyInfoKeyLength(static_cast(keyLength)); + domainKEK.setKeyInfo(wrappedDomainKEK.info); + domainKEK.info.keyLength = static_cast(keyLength); } -RawBuffer wrapDomainKEK(KeyAndInfoContainer &domainKEK, const Password &password) +RawBuffer wrapDomainKEK(DomainKEKAndInfo &domainKEK, const Password &password) { - KeyData PKEK1 = makePKEK1(domainKEK.getDKEKAndInfo().keyInfo, password); + KeyData PKEK1 = makePKEK1(domainKEK.info, password); - WrappedKeyAndInfoContainer wrappedDomainKEK = WrappedKeyAndInfoContainer(); - wrappedDomainKEK.setKeyInfo(&(domainKEK.getDKEKAndInfo().keyInfo)); - wrappedDomainKEK.setDKEKInfo(domainKEK.getDKEKAndInfo().keyInfo.version, - domainKEK.getDKEKAndInfo().keyInfo.backend); + DomainKEKAndInfo wrappedDomainKEK; + wrappedDomainKEK.setKeyInfo(domainKEK.info); int wrappedLength; - if (0 > (wrappedLength = encryptAes256Gcm(domainKEK.getDKEKAndInfo().key, - domainKEK.getDKEKAndInfo().keyInfo.keyLength, + if (0 > (wrappedLength = encryptAes256Gcm(domainKEK.key, + domainKEK.info.keyLength, PKEK1.data(), - domainKEK.getDKEKAndInfo().keyInfo.iv, - wrappedDomainKEK.getWrappedDKEKAndInfo().wrappedKey, - wrappedDomainKEK.getWrappedDKEKAndInfo().keyInfo.tag))) + domainKEK.info.iv, + wrappedDomainKEK.key, + wrappedDomainKEK.info.tag))) ThrowErr(Exc::InternalError, "DomainKEK encryption failed"); - wrappedDomainKEK.setKeyInfoKeyLength(static_cast(wrappedLength)); - return toRawBuffer(wrappedDomainKEK.getWrappedDKEKAndInfo()); + wrappedDomainKEK.info.keyLength = static_cast(wrappedLength); + return toRawBuffer(wrappedDomainKEK); } template @@ -231,148 +233,6 @@ bool randomize(uint8_t (&array)[N]) } // anonymous namespace -WrappedKeyAndInfoContainer::WrappedKeyAndInfoContainer() -{ - memset(&wrappedKeyAndInfo, 0, sizeof(WrappedKeyAndInfo)); - memset(&wrappedDKEKAndInfo, 0, sizeof(WrappedKeyAndInfoDKEK)); -} - -WrappedKeyAndInfo &WrappedKeyAndInfoContainer::getWrappedKeyAndInfo() -{ - return wrappedKeyAndInfo; -} - -WrappedKeyAndInfoDKEK &WrappedKeyAndInfoContainer::getWrappedDKEKAndInfo() -{ - return wrappedDKEKAndInfo; -} - -void WrappedKeyAndInfoContainer::setWrappedKeyAndInfo( - const unsigned char *data) -{ - memcpy(&wrappedKeyAndInfo, data, sizeof(WrappedKeyAndInfo)); - - if (wrappedKeyAndInfo.keyInfo.keyLength > sizeof(wrappedKeyAndInfo.wrappedKey)) { - ThrowErr(Exc::InternalError, - "Wrapped key info is corrupted. Key length exceeds the size of the key buffer."); - } - - size_t maxlen = sizeof(wrappedKeyAndInfo.keyInfo.client); - if (strnlen(wrappedKeyAndInfo.keyInfo.client, maxlen) == maxlen) { - ThrowErr(Exc::InternalError, - "Wrapped key info is corrupted. Client id is not NULL terminated."); - } -} - -void WrappedKeyAndInfoContainer::setWrappedDKEKAndInfo( - const unsigned char *data) -{ - 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 uint32_t length) -{ - wrappedKeyAndInfo.keyInfo.keyLength = length; - wrappedDKEKAndInfo.keyInfo.keyLength = length; -} - -void WrappedKeyAndInfoContainer::setKeyInfoClient(const std::string resized_client) -{ - if (resized_client.size() >= sizeof(wrappedKeyAndInfo.keyInfo.client)) { - ThrowErr(Exc::InternalError, "Client name too long"); - } - - 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 - *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() -{ -} - -KeyAndInfoContainer::KeyAndInfoContainer() -{ - memset(&keyAndInfo, 0, sizeof(KeyAndInfo)); - memset(&DKEKAndInfo, 0, sizeof(KeyAndInfoDKEK)); -} - -KeyAndInfo &KeyAndInfoContainer::getKeyAndInfo() -{ - return keyAndInfo; -} - -KeyAndInfoDKEK &KeyAndInfoContainer::getDKEKAndInfo() -{ - return DKEKAndInfo; -} - -void KeyAndInfoContainer::setKeyAndInfo(const unsigned char *data) -{ - memcpy(&keyAndInfo, data, sizeof(KeyAndInfo)); -} - -void KeyAndInfoContainer::setDKEKAndInfo(const unsigned char *data) -{ - memcpy(&DKEKAndInfo, data, sizeof(KeyAndInfoDKEK)); -} - -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() : m_domainKEK(NULL), m_isInitialized(false) @@ -383,13 +243,14 @@ KeyProvider::KeyProvider() : KeyProvider::KeyProvider( const RawBuffer &domainKEKInWrapForm, const Password &password) : - m_domainKEK(new KeyAndInfoContainer()), + m_domainKEK(new DomainKEKAndInfo()), m_isInitialized(true) { - 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"); + if (domainKEKInWrapForm.size() != sizeof(DomainKEKAndInfo)) { + LogWarning("Input size:" << domainKEKInWrapForm.size() + << " Expected: " << sizeof(DomainKEKAndInfo)); + LogWarning("Buffer doesn't have proper size to store DomainKEKAndInfo in KeyProvider" + "Constructor"); m_isInitialized = false; return; } @@ -431,9 +292,7 @@ RawBuffer KeyProvider::getPureDomainKEK() ThrowErr(Exc::InternalError, "Object not initialized!"); // TODO secure - return RawBuffer(m_domainKEK->getDKEKAndInfo().key, - (m_domainKEK->getDKEKAndInfo().key) + - m_domainKEK->getDKEKAndInfo().keyInfo.keyLength); + return RawBuffer(m_domainKEK->key, m_domainKEK->key + m_domainKEK->info.keyLength); } RawBuffer KeyProvider::getWrappedDomainKEK(const Password &password) @@ -444,45 +303,36 @@ RawBuffer KeyProvider::getWrappedDomainKEK(const Password &password) return wrapDomainKEK(*m_domainKEK, password); } - -RawBuffer KeyProvider::getPureDEK(const RawBuffer &DEKInWrapForm) +RawBuffer KeyProvider::getPureDEK(const RawBuffer &wrappedDEKbuffer) { if (!m_isInitialized) ThrowErr(Exc::InternalError, "Object not initialized!"); - if (DEKInWrapForm.size() != sizeof(WrappedKeyAndInfo)) { - LogError("input size:" << DEKInWrapForm.size() - << " Expected: " << sizeof(WrappedKeyAndInfo)); + if (wrappedDEKbuffer.size() != sizeof(DEKAndInfo)) { + LogError("input size:" << wrappedDEKbuffer.size() << " Expected: " << sizeof(DEKAndInfo)); ThrowErr(Exc::InternalError, - "buffer doesn't have proper size to store " - "WrappedKeyAndInfo in KeyProvider::getPureDEK"); + "buffer doesn't have proper size to store KeyAndInfo in KeyProvider::getPureDEK"); } - KeyAndInfoContainer kmcDEK = KeyAndInfoContainer(); - WrappedKeyAndInfoContainer wkmcDEK = WrappedKeyAndInfoContainer(); - wkmcDEK.setWrappedKeyAndInfo(DEKInWrapForm.data()); + DEKAndInfo DEK; + DEKAndInfo wrappedDEK(wrappedDEKbuffer); - KeyData PKEK2 = makePKEK2(m_domainKEK->getDKEKAndInfo().key, - wkmcDEK.getWrappedKeyAndInfo().keyInfo.client); + KeyData PKEK2 = makePKEK2(m_domainKEK->key, wrappedDEK.info.client); int keyLength; - if (0 > (keyLength = decryptAes256Gcm( - wkmcDEK.getWrappedKeyAndInfo().wrappedKey, - wkmcDEK.getWrappedKeyAndInfo().keyInfo.keyLength, - wkmcDEK.getWrappedKeyAndInfo().keyInfo.tag, - PKEK2.data(), - wkmcDEK.getWrappedKeyAndInfo().keyInfo.iv, - kmcDEK.getKeyAndInfo().key))) - ThrowErr(Exc::InternalError, - "UnwrapDEK Failed in KeyProvider::getPureDEK"); + if (0 > (keyLength = decryptAes256Gcm(wrappedDEK.key, + wrappedDEK.info.keyLength, + wrappedDEK.info.tag, + PKEK2.data(), + wrappedDEK.info.iv, + DEK.key))) + ThrowErr(Exc::InternalError, "UnwrapDEK Failed in KeyProvider::getPureDEK"); - kmcDEK.setKeyInfoKeyLength((unsigned int)keyLength); + DEK.info.keyLength = static_cast(keyLength); LogDebug("getPureDEK SUCCESS"); - return RawBuffer( - kmcDEK.getKeyAndInfo().key, - (kmcDEK.getKeyAndInfo().key) + kmcDEK.getKeyAndInfo().keyInfo.keyLength); + return RawBuffer(DEK.key, DEK.key + DEK.info.keyLength); } RawBuffer KeyProvider::generateDEK(const std::string &client) @@ -490,7 +340,7 @@ RawBuffer KeyProvider::generateDEK(const std::string &client) if (!m_isInitialized) ThrowErr(Exc::InternalError, "Object not initialized!"); - WrappedKeyAndInfoContainer wkmcDEK = WrappedKeyAndInfoContainer(); + DEKAndInfo wrappedDEK; std::string resized_client; if (client.length() < MAX_CLIENT_ID_SIZE) @@ -498,137 +348,78 @@ RawBuffer KeyProvider::generateDEK(const std::string &client) else resized_client = client.substr(0, MAX_CLIENT_ID_SIZE - 1); - uint8_t key[MAX_KEY_SIZE]; + uint8_t DEK[MAX_KEY_SIZE]; - if (!randomize(key) || !randomize(wkmcDEK.getWrappedKeyAndInfo().keyInfo.iv)) + if (!randomize(DEK) || !randomize(wrappedDEK.info.iv)) ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); - KeyData PKEK2 = makePKEK2(m_domainKEK->getDKEKAndInfo().key, resized_client); + KeyData PKEK2 = makePKEK2(m_domainKEK->key, resized_client); int wrappedKeyLength; - if (0 > (wrappedKeyLength = encryptAes256Gcm(key, - m_domainKEK->getDKEKAndInfo().keyInfo.keyLength, + if (0 > (wrappedKeyLength = encryptAes256Gcm(DEK, + sizeof(DEK), PKEK2.data(), - wkmcDEK.getWrappedKeyAndInfo().keyInfo.iv, - wkmcDEK.getWrappedKeyAndInfo().wrappedKey, - wkmcDEK.getWrappedKeyAndInfo().keyInfo.tag))) + wrappedDEK.info.iv, + wrappedDEK.key, + wrappedDEK.info.tag))) ThrowErr(Exc::InternalError, "GenerateDEK Failed in KeyProvider::generateDEK"); - wkmcDEK.setKeyInfoKeyLength((unsigned int)wrappedKeyLength); - wkmcDEK.setKeyInfoClient(resized_client); + wrappedDEK.info.keyLength = static_cast(wrappedKeyLength); + wrappedDEK.setKeyInfoClient(resized_client); LogDebug("GenerateDEK Success"); - return toRawBuffer(wkmcDEK.getWrappedKeyAndInfo()); + return toRawBuffer(wrappedDEK); } -void KeyProvider::migrateDKEK(const RawBuffer &wrappedDomainKEKbuffer, - const Password &password) +void KeyProvider::migrateDomainKEK(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."); - } + DEKAndInfo wrappedOldDomainKEK(wrappedDomainKEKbuffer); - KeyComponentsInfo keyInfo = wrappedInfo.keyInfo; std::string concatPasswordClient(password.c_str()); - concatPasswordClient += std::string(keyInfo.client); + concatPasswordClient += std::string(wrappedOldDomainKEK.info.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"); - } + KeyData PKEK1 = PBKDF(concatPasswordClient, wrappedOldDomainKEK.info.salt, MAX_SALT_SIZE); int keyLength; - if (0 > (keyLength = decryptAes256Gcm(wrappedInfo.wrappedKey, - keyInfo.keyLength, - keyInfo.tag, + if (0 > (keyLength = decryptAes256Gcm(wrappedOldDomainKEK.key, + wrappedOldDomainKEK.info.keyLength, + wrappedOldDomainKEK.info.tag, PKEK1.data(), - keyInfo.iv, - m_domainKEK->getDKEKAndInfo().key))) + wrappedOldDomainKEK.info.iv, + m_domainKEK->key))) ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed"); - m_domainKEK->getDKEKAndInfo().keyInfo.set(keyInfo); - m_domainKEK->setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::OpenSSL); + DomainKEKInfo info(wrappedOldDomainKEK.info); + info.version = KEYCOMPONENT_VERSION; + info.backend = static_cast(CryptoBackend::OpenSSL); #ifdef SE_BACKEND_ENABLED - m_domainKEK->setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::SecureElement); + info.backend = static_cast(CryptoBackend::SecureElement); #endif - m_domainKEK->setKeyInfoKeyLength(static_cast(keyLength)); - m_isInitialized = true; - LogDebug("Migrate DKEK Success"); -} + m_domainKEK->setKeyInfo(info); -RawBuffer KeyProvider::reencrypt( - const RawBuffer &domainKEKInWrapForm, - const Password &oldPass, - const Password &newPass) -{ - 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::reencrypt"); - } - - KeyAndInfoContainer domainKEK; - unwrapDomainKEK(domainKEKInWrapForm, oldPass, domainKEK); - return wrapDomainKEK(domainKEK, newPass); + m_domainKEK->info.keyLength = static_cast(keyLength); + m_isInitialized = true; + LogDebug("Migrate DomainKEK Success"); } -RawBuffer KeyProvider::generateDomainKEK( - const std::string &user, - const Password &userPassword) +RawBuffer KeyProvider::generateDomainKEK(const std::string &user, const Password &userPassword) { - KeyAndInfoContainer domainKEK; + DomainKEKAndInfo domainKEK; - if (!randomize(domainKEK.getDKEKAndInfo().keyInfo.salt) || - !randomize(domainKEK.getDKEKAndInfo().key) || - !randomize(domainKEK.getDKEKAndInfo().keyInfo.iv)) { + if (!randomize(domainKEK.info.salt) || + !randomize(domainKEK.key) || + !randomize(domainKEK.info.iv)) { ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR"); } - domainKEK.setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::OpenSSL); + domainKEK.info.version = KEYCOMPONENT_VERSION; + domainKEK.info.backend = static_cast(CryptoBackend::OpenSSL); #ifdef SE_BACKEND_ENABLED - domainKEK.setDKEKInfo(KEYCOMPONENT_VERSION, (uint32_t)CryptoBackend::SecureElement); + domainKEK.info.backend = static_cast(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.getDKEKAndInfo().keyInfo.client, user.c_str(), user.size()); + domainKEK.info.keyLength = sizeof(domainKEK.key); + domainKEK.setKeyInfoClient(user); return wrapDomainKEK(domainKEK, userPassword); } - -int KeyProvider::initializeLibrary() -{ - LogDebug("initializeLibrary Success"); - return SUCCESS; -} - -int KeyProvider::closeLibrary() -{ - LogDebug("closeLibrary Success"); - return SUCCESS; -} - -KeyProvider::~KeyProvider() -{ - LogDebug("KeyProvider Destructor"); -} diff --git a/src/manager/service/key-provider.h b/src/manager/service/key-provider.h index dcc695e..5acfef5 100644 --- a/src/manager/service/key-provider.h +++ b/src/manager/service/key-provider.h @@ -16,142 +16,93 @@ #pragma once -#include #include -#include -#include -#include -#include -#include +#include -#include +#include -#ifndef SUCCESS -#define SUCCESS 0 -#endif -#ifndef ERROR -#define ERROR -1 -#endif -#ifndef INVALID_ARGUMENTS -#define INVALID_ARGUMENTS -2 -#endif -#ifndef VERIFY_DATA_ERROR -#define VERIFY_DATA_ERROR -3 -#endif -#ifndef OPENSSL_ENGINE_ERROR -#define OPENSSL_ENGINE_ERROR -4 -#endif -#ifndef UNKNOWN_ERROR -#define UNKNOWN_ERROR -5 -#endif - -#define AES256_KEY_LEN_BITS 256 -#define AES256_KEY_LEN_BYTSE (AES256_KEY_LEN_BITS / 8) -// Unused -//#define AES_GCM_TAG_SIZE 32 - -#define PBKDF2_SALT_LEN 16 -#define PBKDF2_ITERATIONS 4096 +#include +#include +#include #define MAX_IV_SIZE 16 #define MAX_SALT_SIZE 16 #define MAX_KEY_SIZE 32 -#define MAX_WRAPPED_KEY_SIZE 32 #define MAX_CLIENT_ID_SIZE 32 -#define DOMAIN_NAME_SIZE 32 namespace CKM { -const uint32_t KEYCOMPONENT_VERSION = 2; - -typedef struct KeyComponentsInfo_ { +struct KeyInfo { uint32_t keyLength; char client[MAX_CLIENT_ID_SIZE]; uint8_t salt[MAX_SALT_SIZE]; uint8_t iv[MAX_IV_SIZE]; uint8_t tag[MAX_IV_SIZE]; -} KeyComponentsInfo; - -typedef struct KeyAndInfo_ { - KeyComponentsInfo keyInfo; - uint8_t key[MAX_KEY_SIZE]; -} KeyAndInfo; - -typedef struct WrappedKeyAndInfo_ { - KeyComponentsInfo keyInfo; - uint8_t wrappedKey[MAX_WRAPPED_KEY_SIZE]; -} WrappedKeyAndInfo; +}; -typedef struct KeyComponentsInfoDKEK_ : KeyComponentsInfo{ +struct DomainKEKInfo : KeyInfo { + DomainKEKInfo() = default; + DomainKEKInfo(const KeyInfo& info) : KeyInfo(info) {} 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); +}; + +template +struct KeyAndInfo final { + KeyAndInfo() { + memset(this, 0, sizeof(*this)); } -} KeyComponentsInfoDKEK; -typedef struct KeyAndInfoDKEK_ { - KeyComponentsInfoDKEK keyInfo; - uint8_t key[MAX_KEY_SIZE]; -} KeyAndInfoDKEK; + explicit KeyAndInfo(const RawBuffer& data) { + if (data.size() != sizeof(*this)) { + LogError("Data size: " << data.size() << " Expected: " << sizeof(*this)); + ThrowErr(Exc::InternalError, "buffer doesn't have proper size to store "); + } -typedef struct WrappedKeyAndInfoDKEK_ { - KeyComponentsInfoDKEK keyInfo; - uint8_t wrappedKey[MAX_WRAPPED_KEY_SIZE]; -} WrappedKeyAndInfoDKEK; + memcpy(this, data.data(), sizeof(*this)); -class WrappedKeyAndInfoContainer { -public: - WrappedKeyAndInfoContainer(); - WrappedKeyAndInfo &getWrappedKeyAndInfo(); - 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(); + if (info.keyLength > sizeof(key)) { + ThrowErr(Exc::InternalError, + "Key info is corrupted. Key length exceeds the size of the key buffer."); + } -private: - WrappedKeyAndInfo wrappedKeyAndInfo; - WrappedKeyAndInfoDKEK wrappedDKEKAndInfo; -}; + size_t maxlen = sizeof(info.client); + if (strnlen(info.client, maxlen) == maxlen) { + ThrowErr(Exc::InternalError, + "Key info is corrupted. Client id is not NULL terminated."); + } + } -class KeyAndInfoContainer { -public: - KeyAndInfoContainer(); - KeyAndInfo &getKeyAndInfo(); - 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(); + void setKeyInfo(const T& info_) { + memcpy(&(info), &info_, sizeof(info)); + } -private: - KeyAndInfo keyAndInfo; - KeyAndInfoDKEK DKEKAndInfo; + void setKeyInfoClient(const std::string& resized_client) { + if (resized_client.size() >= sizeof(info.client)) { + ThrowErr(Exc::InternalError, "Client name too long"); + } + + strncpy(info.client, resized_client.c_str(), resized_client.size()); + } + + ~KeyAndInfo() { + // overwrite key + ZeroMemory(key, sizeof(key)); + } + + T info; + uint8_t key[MAX_KEY_SIZE]; }; +typedef KeyAndInfo DomainKEKAndInfo; +typedef KeyAndInfo DEKAndInfo; // it's also old DomainKEK form + // This is internal api so all functions should throw exception on errors. class KeyProvider { public: - // To store in std containers KeyProvider(); - // In constructor you must check if SKMM is initialized. On error -> exception - // keyInWrapForm should be used like this: - // if (keyInWrapForm.size() != sizeof(WrappedKeyAndInfo)) - // throw exception; // buffer does not have proper size to store WrappedKeyAndInfo - // WrappedKeyAndInfo *wkm = static_cast(keyInWrapForm.data()); - KeyProvider(const RawBuffer &domainKEKInWrapForm, const Password &password); + KeyProvider(const RawBuffer &wrappedDomainKEKbuffer, const Password &password); KeyProvider(KeyProvider &&); KeyProvider(const KeyProvider &) = delete; @@ -164,13 +115,11 @@ public: RawBuffer getPureDomainKEK(); // Returns Key in form used to store key in file - // Requied by Control::resetPassword(const RawBuffer &newPassword); - // This api should be used only on Tizen 2.2.1 RawBuffer getWrappedDomainKEK(const Password &password); // Unwraps (decrypts) a DEK using a key derived from DomainKEK and data stored in wrapped key // info. It returns the DEK in unencrypted form. - RawBuffer getPureDEK(const RawBuffer &DEKInWrapForm); + RawBuffer getPureDEK(const RawBuffer &wrappedDEKbuffer); // Generates a random DEK and encrypts it using a key derived from DomainKEK and custom client // string (not to be confused with ClientId). The function returns the DEK in wrapped @@ -178,31 +127,14 @@ public: // application keys. RawBuffer generateDEK(const std::string &client); - // used by change user password. On error -> exception - static RawBuffer reencrypt( - const RawBuffer &domainKEKInWrapForm, - const Password &oldPass, - const Password &newPass); - // First run of application for some user. DomainKEK was not created yet. We must create one. // This key will be used to encrypt user database. - 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 - static int closeLibrary(); + static RawBuffer generateDomainKEK(const std::string &user, const Password &userPassword); - virtual ~KeyProvider(); + void migrateDomainKEK(const RawBuffer &wrappedDomainKEKbuffer, const Password &password); private: - // KeyAndInfoContainer class - std::shared_ptr m_domainKEK; + std::shared_ptr m_domainKEK; bool m_isInitialized; }; diff --git a/unit-tests/test_key-provider.cpp b/unit-tests/test_key-provider.cpp index 7d9793f..2d6530b 100644 --- a/unit-tests/test_key-provider.cpp +++ b/unit-tests/test_key-provider.cpp @@ -62,19 +62,22 @@ BOOST_AUTO_TEST_SUITE(KEY_PROVIDER_TEST) NEGATIVE_TEST_CASE(KeyProvider_wrong_size) { RawBuffer wdkek = makeDefaultWrappedDomainKEK(); + KeyProvider kp; wdkek.push_back(0); - BOOST_REQUIRE_THROW(KeyProvider(wdkek, PASSWORD), Exc::InternalError); + BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek, PASSWORD)); + BOOST_REQUIRE(!kp.isInitialized()); wdkek.pop_back(); wdkek.pop_back(); - BOOST_REQUIRE_THROW(KeyProvider(wdkek, PASSWORD), Exc::InternalError); + BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek, PASSWORD)); + BOOST_REQUIRE(!kp.isInitialized()); } NEGATIVE_TEST_CASE(KeyProvider_garbage) { - BOOST_REQUIRE_THROW(KeyProvider(RawBuffer(sizeof(WrappedKeyAndInfo)), PASSWORD), - Exc::AuthenticationFailed); + BOOST_REQUIRE_THROW(KeyProvider(RawBuffer(sizeof(DomainKEKAndInfo)), PASSWORD), + Exc::InternalError); } NEGATIVE_TEST_CASE(KeyDomainKek_invalid_password) @@ -148,7 +151,7 @@ POSITIVE_TEST_CASE(KeyGetPureDEK) NEGATIVE_TEST_CASE(KeyGetPureDEK_uninitialized) { KeyProvider kp; - RawBuffer wdek(sizeof(WrappedKeyAndInfo)); + RawBuffer wdek(sizeof(DEKAndInfo)); BOOST_REQUIRE_THROW(kp.getPureDEK(wdek), Exc::InternalError); } @@ -171,7 +174,7 @@ NEGATIVE_TEST_CASE(KeyGetPureDEK_wrong_size) NEGATIVE_TEST_CASE(KeyGetPureDEK_garbage) { KeyProvider kp = makeDefaultKeyProvider(); - RawBuffer wdek(sizeof(WrappedKeyAndInfo)); + RawBuffer wdek(sizeof(DEKAndInfo)); BOOST_REQUIRE_THROW(kp.getPureDEK(wdek), Exc::InternalError); } @@ -180,37 +183,21 @@ POSITIVE_TEST_CASE(KeyReencrypt) { RawBuffer wdkek = makeDefaultWrappedDomainKEK(); RawBuffer wdkek2; + KeyProvider keyProvider; - BOOST_REQUIRE_NO_THROW(wdkek2 = KeyProvider::reencrypt(wdkek, PASSWORD, NEW_PASSWORD)); + BOOST_REQUIRE_NO_THROW(keyProvider = KeyProvider(wdkek, PASSWORD)); + BOOST_REQUIRE_NO_THROW(wdkek2 = keyProvider.getWrappedDomainKEK(NEW_PASSWORD)); BOOST_REQUIRE(!wdkek2.empty()); } -NEGATIVE_TEST_CASE(KeyReencrypt_incorrect_password) -{ - RawBuffer wdkek = makeDefaultWrappedDomainKEK(); - BOOST_REQUIRE_THROW(KeyProvider::reencrypt(wdkek, INCORRECT_PASSWORD, NEW_PASSWORD), - Exc::AuthenticationFailed); -} - -NEGATIVE_TEST_CASE(KeyReencrypt_wrong_size) -{ - RawBuffer wdkek = makeDefaultWrappedDomainKEK(); - - wdkek.push_back(0); - BOOST_REQUIRE_THROW(KeyProvider::reencrypt(wdkek, PASSWORD, NEW_PASSWORD), Exc::InternalError); - - wdkek.pop_back(); - wdkek.pop_back(); - BOOST_REQUIRE_THROW(KeyProvider::reencrypt(wdkek, PASSWORD, NEW_PASSWORD), Exc::InternalError); -} - POSITIVE_TEST_CASE(KeyGetPureDEK_after_reencrypt) { KeyProvider kp; RawBuffer wdek, dek, wdkek2; RawBuffer wdkek = makeDefaultWrappedDomainKEK(); - BOOST_REQUIRE_NO_THROW(wdkek2 = KeyProvider::reencrypt(wdkek, PASSWORD, NEW_PASSWORD)); + BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek, PASSWORD)); + BOOST_REQUIRE_NO_THROW(wdkek2 = kp.getWrappedDomainKEK(NEW_PASSWORD)); BOOST_REQUIRE(!wdkek2.empty()); BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek2, NEW_PASSWORD)); @@ -222,59 +209,39 @@ POSITIVE_TEST_CASE(KeyGetPureDEK_after_reencrypt) BOOST_REQUIRE(dek.size() <= MAX_KEY_SIZE); } -POSITIVE_TEST_CASE(wrapped_container) +POSITIVE_TEST_CASE(dek_and_info) { - WrappedKeyAndInfoContainer wkic; + DEKAndInfo dai; auto salt = createRandom(20); - BOOST_REQUIRE_NO_THROW(wkic.setKeyInfoSalt(salt.data(), salt.size())); - BOOST_REQUIRE_NO_THROW(wkic.setKeyInfoClient("key_info_client")); - - WrappedKeyAndInfoContainer wkic2; - BOOST_REQUIRE_NO_THROW(wkic2.setKeyInfo(&wkic.getWrappedKeyAndInfo().keyInfo)); - - BOOST_REQUIRE(wkic.getWrappedKeyAndInfo().keyInfo.keyLength == - wkic2.getWrappedKeyAndInfo().keyInfo.keyLength); - BOOST_REQUIRE(memcmp(wkic.getWrappedKeyAndInfo().keyInfo.salt, - wkic2.getWrappedKeyAndInfo().keyInfo.salt, - sizeof(wkic.getWrappedKeyAndInfo().keyInfo.salt)) == 0); - BOOST_REQUIRE(memcmp(wkic.getWrappedKeyAndInfo().keyInfo.client, - wkic2.getWrappedKeyAndInfo().keyInfo.client, - sizeof(wkic.getWrappedKeyAndInfo().keyInfo.client)) == 0); - - WrappedKeyAndInfo wki; - wki.keyInfo.keyLength = MAX_WRAPPED_KEY_SIZE; - BOOST_REQUIRE_NO_THROW(wkic.setWrappedKeyAndInfo(reinterpret_cast(&wki))); -} + memcpy(dai.info.salt, salt.data(), sizeof(dai.info.salt)); + BOOST_REQUIRE_NO_THROW(dai.setKeyInfoClient("key_info_client")); + dai.info.keyLength = 10; -NEGATIVE_TEST_CASE(wrapped_container) -{ - WrappedKeyAndInfoContainer wkic; + DEKAndInfo dai2; + BOOST_REQUIRE_NO_THROW(dai2.setKeyInfo(dai.info)); - BOOST_REQUIRE_THROW(wkic.setKeyInfoClient("key_info_client_waaaaay_too_long"), - Exc::InternalError); - - WrappedKeyAndInfo wki; - wki.keyInfo.keyLength = MAX_WRAPPED_KEY_SIZE + 1; - 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(wkic.setWrappedKeyAndInfo(reinterpret_cast(&wki2)), - Exc::InternalError); + BOOST_REQUIRE(dai.info.keyLength == dai2.info.keyLength); + BOOST_REQUIRE(memcmp(dai.info.salt, dai2.info.salt, sizeof(dai.info.salt)) == 0); + BOOST_REQUIRE(memcmp(dai.info.client, dai2.info.client, sizeof(dai.info.client)) == 0); } -POSITIVE_TEST_CASE(container) +NEGATIVE_TEST_CASE(dek_and_info) { - KeyAndInfoContainer kic; - BOOST_REQUIRE_NO_THROW(kic.setKeyInfoKeyLength(10)); + DEKAndInfo dai; + BOOST_REQUIRE_THROW(dai.setKeyInfoClient("key_info_client_waaaaay_too_long"), + Exc::InternalError); + + DEKAndInfo dai2; + dai2.info.keyLength = MAX_KEY_SIZE + 1; - KeyAndInfoContainer kic2; - BOOST_REQUIRE_NO_THROW(kic2.setKeyInfo(&kic.getKeyAndInfo().keyInfo)); + const unsigned char *ptr = reinterpret_cast(&dai2); + RawBuffer buffer(ptr, ptr + sizeof(dai2)); + BOOST_REQUIRE_THROW(new DEKAndInfo((buffer)), Exc::InternalError); - BOOST_REQUIRE(kic.getKeyAndInfo().keyInfo.keyLength == kic2.getKeyAndInfo().keyInfo.keyLength); + // missing NULL termination in dai3.info.client + RawBuffer garbage(0x01, sizeof(DEKAndInfo)); + BOOST_REQUIRE_THROW(new DEKAndInfo((garbage)), Exc::InternalError); } POSITIVE_TEST_CASE(moves) -- 2.7.4