/*
- * Copyright (c) 2014 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2020 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.
* limitations under the License
*/
-#include <exception.h>
+#include <array>
+
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
#include <key-provider.h>
-#include <dpl/log/log.h>
#include <ckm/ckm-zero-memory.h>
+#include <utils.h>
#include <string.h>
-#include <array>
-#include <memory>
-
+#include <crypto-backend.h>
+#ifdef SE_BACKEND_ENABLED
+#include <se-backend/internals.h>
+#endif
using namespace CKM;
namespace {
+constexpr int PBKDF2_ITERATIONS = 4096;
+constexpr uint32_t KEYCOMPONENT_VERSION = 2;
+constexpr int OPENSSL_ENGINE_ERROR = -4;
+
template<typename T>
RawBuffer toRawBuffer(const T &data)
{
return RawBuffer();
}
-typedef std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)> CipherCtxPtr;
-
int encryptAes256Gcm(const unsigned char *plaintext,
int plaintext_len, const unsigned char *key, const unsigned char *iv,
unsigned char *ciphertext, unsigned char *tag)
int len;
int ciphertext_len = 0;
- CipherCtxPtr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+ auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
if (!ctx)
return OPENSSL_ENGINE_ERROR;
int plaintext_len;
int ret;
- CipherCtxPtr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+ auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
if (!ctx)
return OPENSSL_ENGINE_ERROR;
typedef std::array<uint8_t, MAX_KEY_SIZE> KeyData;
-// derives a key used for DomainKEK encryption (aka PKEK1) from random salt & user password
-KeyData makePKEK1(const KeyComponentsInfo& keyInfo, const Password &password)
+KeyData PBKDF(const std::string& pass, const unsigned char *salt, int saltlen)
{
- std::string concatPasswordClient(password.c_str());
- concatPasswordClient += std::string(keyInfo.client);
-
KeyData key;
- if (!PKCS5_PBKDF2_HMAC_SHA1(concatPasswordClient.c_str(),
- concatPasswordClient.size(),
- keyInfo.salt,
- MAX_SALT_SIZE,
+ if (!PKCS5_PBKDF2_HMAC_SHA1(pass.c_str(),
+ pass.size(),
+ salt,
+ saltlen,
PBKDF2_ITERATIONS,
key.size(),
key.data())) {
return key;
}
+// derives a key used for DomainKEK encryption (aka PKEK1) from random salt & user password
+KeyData makePKEK1(const DomainKEKInfo& domainKEKInfo, const Password &password)
+{
+ std::string concatPasswordClient(password.c_str());
+ concatPasswordClient += std::string(domainKEKInfo.client);
+
+ if (domainKEKInfo.version != KEYCOMPONENT_VERSION)
+ ThrowErr(Exc::InternalError, "It's not expected version");
+
+ RawBuffer salt;
+ 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
+ ThrowErr(Exc::InternalError, "It's not expected backend");
+#endif
+ } 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 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(wrappedDomainKEKbuffer.data());
-
- KeyData PKEK1 = makePKEK1(wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo, password);
+ DomainKEKAndInfo wrappedDomainKEK(wrappedDomainKEKbuffer);
+ KeyData PKEK1 = makePKEK1(wrappedDomainKEK.info, password);
int keyLength;
- if (0 > (keyLength = decryptAes256Gcm(wrappedDomainKEK.getWrappedKeyAndInfo().wrappedKey,
- wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.keyLength,
- wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.tag,
+ if (0 > (keyLength = decryptAes256Gcm(wrappedDomainKEK.key,
+ wrappedDomainKEK.info.keyLength,
+ wrappedDomainKEK.info.tag,
PKEK1.data(),
- wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.iv,
- domainKEK.getKeyAndInfo().key)))
+ wrappedDomainKEK.info.iv,
+ domainKEK.key)))
ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed");
- domainKEK.setKeyInfo(&(wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo));
- domainKEK.setKeyInfoKeyLength(static_cast<unsigned int>(keyLength));
+ domainKEK.setKeyInfo(wrappedDomainKEK.info);
+ domainKEK.info.keyLength = static_cast<uint32_t>(keyLength);
}
-RawBuffer wrapDomainKEK(KeyAndInfoContainer &domainKEK, const Password &password)
+RawBuffer wrapDomainKEK(DomainKEKAndInfo &domainKEK, const Password &password)
{
- KeyData PKEK1 = makePKEK1(domainKEK.getKeyAndInfo().keyInfo, password);
+ KeyData PKEK1 = makePKEK1(domainKEK.info, password);
- WrappedKeyAndInfoContainer wrappedDomainKEK = WrappedKeyAndInfoContainer();
- wrappedDomainKEK.setKeyInfo(&(domainKEK.getKeyAndInfo().keyInfo));
+ DomainKEKAndInfo wrappedDomainKEK;
+ wrappedDomainKEK.setKeyInfo(domainKEK.info);
int wrappedLength;
- if (0 > (wrappedLength = encryptAes256Gcm(domainKEK.getKeyAndInfo().key,
- domainKEK.getKeyAndInfo().keyInfo.keyLength,
+ if (0 > (wrappedLength = encryptAes256Gcm(domainKEK.key,
+ domainKEK.info.keyLength,
PKEK1.data(),
- domainKEK.getKeyAndInfo().keyInfo.iv,
- wrappedDomainKEK.getWrappedKeyAndInfo().wrappedKey,
- wrappedDomainKEK.getWrappedKeyAndInfo().keyInfo.tag)))
+ domainKEK.info.iv,
+ wrappedDomainKEK.key,
+ wrappedDomainKEK.info.tag)))
ThrowErr(Exc::InternalError, "DomainKEK encryption failed");
- wrappedDomainKEK.setKeyInfoKeyLength(static_cast<unsigned int>(wrappedLength));
- return toRawBuffer(wrappedDomainKEK.getWrappedKeyAndInfo());
+ wrappedDomainKEK.info.keyLength = static_cast<uint32_t>(wrappedLength);
+ return toRawBuffer(wrappedDomainKEK);
}
template <size_t N>
} // anonymous namespace
-WrappedKeyAndInfoContainer::WrappedKeyAndInfoContainer()
-{
- memset(&wrappedKeyAndInfo, 0, sizeof(WrappedKeyAndInfo));
-}
-
-WrappedKeyAndInfoContainer::WrappedKeyAndInfoContainer(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.");
- }
-}
-
-WrappedKeyAndInfo &WrappedKeyAndInfoContainer::getWrappedKeyAndInfo()
-{
- return wrappedKeyAndInfo;
-}
-
-void WrappedKeyAndInfoContainer::setKeyInfoKeyLength(const unsigned int length)
-{
- wrappedKeyAndInfo.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");
- }
-
- strcpy(wrappedKeyAndInfo.keyInfo.client, resized_client.c_str());
-}
-
-void WrappedKeyAndInfoContainer::setKeyInfoSalt(const unsigned char *salt,
- const int size)
-{
- memcpy(wrappedKeyAndInfo.keyInfo.salt, salt, size);
-}
-
-void WrappedKeyAndInfoContainer::setKeyInfo(const KeyComponentsInfo
- *keyComponentsInfo)
-{
- memcpy(&(wrappedKeyAndInfo.keyInfo), keyComponentsInfo,
- sizeof(KeyComponentsInfo));
-}
-
-WrappedKeyAndInfoContainer::~WrappedKeyAndInfoContainer()
-{
-}
-
-KeyAndInfoContainer::KeyAndInfoContainer()
-{
- memset(&keyAndInfo, 0, sizeof(KeyAndInfo));
-}
-
-KeyAndInfoContainer::KeyAndInfoContainer(const unsigned char *data)
-{
- memcpy(&keyAndInfo, data, sizeof(KeyAndInfo));
-}
-
-KeyAndInfo &KeyAndInfoContainer::getKeyAndInfo()
-{
- return keyAndInfo;
-}
-
-void KeyAndInfoContainer::setKeyInfoKeyLength(unsigned int length)
-{
- keyAndInfo.keyInfo.keyLength = length;
-}
-
-void KeyAndInfoContainer::setKeyInfo(const KeyComponentsInfo *keyComponentsInfo)
-{
- memcpy(&(keyAndInfo.keyInfo), keyComponentsInfo, sizeof(KeyComponentsInfo));
-}
-
-KeyAndInfoContainer::~KeyAndInfoContainer()
-{
- // overwrite key
- ZeroMemory(reinterpret_cast<unsigned char*>(&keyAndInfo), sizeof(KeyAndInfo));
-}
-
KeyProvider::KeyProvider() :
m_domainKEK(NULL),
m_isInitialized(false)
KeyProvider::KeyProvider(
const RawBuffer &domainKEKInWrapForm,
const Password &password) :
- m_domainKEK(new KeyAndInfoContainer()),
+ m_domainKEK(new DomainKEKAndInfo()),
m_isInitialized(true)
{
- 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(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;
}
unwrapDomainKEK(domainKEKInWrapForm, password, *m_domainKEK);
second.m_domainKEK = NULL;
}
-bool KeyProvider::isInitialized()
+bool KeyProvider::isInitialized() const
{
return m_isInitialized;
}
-RawBuffer KeyProvider::getPureDomainKEK()
+RawBuffer KeyProvider::getPureDomainKEK() const
{
if (!m_isInitialized)
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->key, m_domainKEK->key + m_domainKEK->info.keyLength);
}
-RawBuffer KeyProvider::getWrappedDomainKEK(const Password &password)
+RawBuffer KeyProvider::getWrappedDomainKEK(const Password &password) const
{
if (!m_isInitialized)
ThrowErr(Exc::InternalError, "Object not initialized!");
return wrapDomainKEK(*m_domainKEK, password);
}
-
-RawBuffer KeyProvider::getPureDEK(const RawBuffer &DEKInWrapForm)
+RawBuffer KeyProvider::getPureDEK(const RawBuffer &wrappedDEKbuffer) const
{
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(
- DEKInWrapForm.data());
+ DEKAndInfo DEK;
+ DEKAndInfo wrappedDEK(wrappedDEKbuffer);
- KeyData PKEK2 = makePKEK2(m_domainKEK->getKeyAndInfo().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<uint32_t>(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)
+RawBuffer KeyProvider::generateDEK(const std::string &client) const
{
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)
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->getKeyAndInfo().key, resized_client);
+ KeyData PKEK2 = makePKEK2(m_domainKEK->key, resized_client);
int wrappedKeyLength;
- if (0 > (wrappedKeyLength = encryptAes256Gcm(key,
- m_domainKEK->getKeyAndInfo().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<uint32_t>(wrappedKeyLength);
+ wrappedDEK.setKeyInfoClient(resized_client);
LogDebug("GenerateDEK Success");
- return toRawBuffer(wkmcDEK.getWrappedKeyAndInfo());
+ return toRawBuffer(wrappedDEK);
}
-RawBuffer KeyProvider::reencrypt(
- const RawBuffer &domainKEKInWrapForm,
- const Password &oldPass,
- const Password &newPass)
+void KeyProvider::migrateDomainKEK(const RawBuffer &wrappedDomainKEKbuffer,
+ const Password &password)
{
- 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");
- }
+ DEKAndInfo wrappedOldDomainKEK(wrappedDomainKEKbuffer);
- KeyAndInfoContainer domainKEK;
- unwrapDomainKEK(domainKEKInWrapForm, oldPass, domainKEK);
- return wrapDomainKEK(domainKEK, newPass);
-}
-
-RawBuffer KeyProvider::generateDomainKEK(
- const std::string &user,
- const Password &userPassword)
-{
- WrappedKeyAndInfoContainer wkmcDKEK = WrappedKeyAndInfoContainer();
-
- KeyAndInfoContainer domainKEK;
+ std::string concatPasswordClient(password.c_str());
+ concatPasswordClient += std::string(wrappedOldDomainKEK.info.client);
- if (!randomize(domainKEK.getKeyAndInfo().keyInfo.salt) ||
- !randomize(domainKEK.getKeyAndInfo().key) ||
- !randomize(domainKEK.getKeyAndInfo().keyInfo.iv)) {
- ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR");
- }
+ KeyData PKEK1 = PBKDF(concatPasswordClient, wrappedOldDomainKEK.info.salt, MAX_SALT_SIZE);
- domainKEK.setKeyInfoKeyLength(sizeof(domainKEK.getKeyAndInfo().key));
+ int keyLength;
+ if (0 > (keyLength = decryptAes256Gcm(wrappedOldDomainKEK.key,
+ wrappedOldDomainKEK.info.keyLength,
+ wrappedOldDomainKEK.info.tag,
+ PKEK1.data(),
+ wrappedOldDomainKEK.info.iv,
+ m_domainKEK->key)))
+ ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed");
- if (user.size() >= sizeof(domainKEK.getKeyAndInfo().keyInfo.client)) {
- ThrowErr(Exc::InternalError, "Client name too long");
- }
- strcpy(domainKEK.getKeyAndInfo().keyInfo.client, user.c_str());
+ DomainKEKInfo info(wrappedOldDomainKEK.info);
+ info.version = KEYCOMPONENT_VERSION;
+ info.backend = static_cast<uint32_t>(CryptoBackend::OpenSSL);
+#ifdef SE_BACKEND_ENABLED
+ info.backend = static_cast<uint32_t>(CryptoBackend::SecureElement);
+#endif
+ m_domainKEK->setKeyInfo(info);
- return wrapDomainKEK(domainKEK, userPassword);
+ m_domainKEK->info.keyLength = static_cast<uint32_t>(keyLength);
+ m_isInitialized = true;
+ LogDebug("Migrate DomainKEK Success");
}
-int KeyProvider::initializeLibrary()
+RawBuffer KeyProvider::generateDomainKEK(const std::string &user, const Password &userPassword)
{
- LogDebug("initializeLibrary Success");
- return SUCCESS;
-}
+ DomainKEKAndInfo domainKEK;
-int KeyProvider::closeLibrary()
-{
- LogDebug("closeLibrary Success");
- return SUCCESS;
-}
+ if (!randomize(domainKEK.info.salt) ||
+ !randomize(domainKEK.key) ||
+ !randomize(domainKEK.info.iv)) {
+ ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR");
+ }
-KeyProvider::~KeyProvider()
-{
- LogDebug("KeyProvider Destructor");
+ domainKEK.info.version = KEYCOMPONENT_VERSION;
+ domainKEK.info.backend = static_cast<uint32_t>(CryptoBackend::OpenSSL);
+#ifdef SE_BACKEND_ENABLED
+ domainKEK.info.backend = static_cast<uint32_t>(CryptoBackend::SecureElement);
+#endif
+ domainKEK.info.keyLength = sizeof(domainKEK.key);
+ domainKEK.setKeyInfoClient(user);
+
+ return wrapDomainKEK(domainKEK, userPassword);
}