Enable -Wshadow and fix warnings
[platform/core/security/key-manager.git] / src / manager / service / ckm-logic.cpp
index aa76b3b..f57f920 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2014-2021 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.
  */
 #include <dpl/serialization.h>
 #include <dpl/log/log.h>
-#include <ckm/key-manager.h>
 #include <ckm/ckm-error.h>
 #include <ckm/ckm-type.h>
 #include <key-provider.h>
 #include <file-system.h>
-#include <CryptoService.h>
 #include <ckm-logic.h>
-#include <generic-key.h>
+#include <key-impl.h>
+#include <key-aes-impl.h>
+#include <certificate-config.h>
+#include <certificate-store.h>
+#include <algorithm>
+#include <sw-backend/store.h>
+#include <generic-backend/exception.h>
+#include <ss-migrate.h>
 
 namespace {
-const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs";
+const char *const CERT_SYSTEM_DIR          = CA_CERTS_DIR;
+const char *const DEFAULT_UNLOCK_STRING    = "cAtRugU7";
+
+bool isClientValid(const CKM::ClientId &client)
+{
+       if (client.find(CKM::ALIAS_SEPARATOR) != CKM::ClientId::npos)
+               return false;
+
+       return true;
+}
+
+bool isNameValid(const CKM::Name &name)
+{
+       if (name.find(CKM::ALIAS_SEPARATOR) != CKM::Name::npos)
+               return false;
+
+       return true;
+}
+
 } // anonymous namespace
 
 namespace CKM {
 
+namespace {
+
+template <int ERROR_ON_CKM_EXCEPTION = CKM_API_ERROR_SERVER_ERROR, class F>
+int tryRet(F &&f)
+{
+       try {
+               static_assert(std::is_same_v<decltype(std::forward<F>(f)()), int>);
+               return std::forward<F>(f)();
+       } catch (const Exc::Exception &e) {
+               return e.error();
+       } catch (const CKM::Exception &e) {
+               LogError("CKM::Exception: " << e.GetMessage());
+               return ERROR_ON_CKM_EXCEPTION;
+       }
+}
+
+int toBinaryData(const Crypto::Data &input, Crypto::Data &output)
+{
+       // verify the data integrity
+       if (input.type.isKey()) {
+               KeyShPtr output_key;
+
+               if (input.type.isSymmetricKey())
+                       output_key = CKM::Key::createAES(input.data);
+               else
+                       output_key = CKM::Key::create(input.data);
+
+               if (output_key.get() == NULL) {
+                       LogDebug("provided binary data is not valid key data");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               output = Crypto::Data(input.type, output_key->getDER());
+       } else if (input.type.isCertificate() || input.type.isChainCert()) {
+               CertificateShPtr cert = CKM::Certificate::create(input.data, DataFormat::FORM_DER);
+
+               if (cert.get() == NULL) {
+                       LogDebug("provided binary data is not valid certificate data");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               output = Crypto::Data(input.type, cert->getDER());
+       } else {
+               output = input;
+       }
+
+       // TODO: add here BINARY_DATA verification, i.e: max size etc.
+       return CKM_API_SUCCESS;
+}
+
+int verifyBinaryData(const Crypto::Data &input)
+{
+       Crypto::Data dummy;
+       return toBinaryData(input, dummy);
+}
+
+int readSingleRow(const Name &name,
+               const ClientId &owner,
+               DataType dataType,
+               DB::Crypto &database,
+               DB::Row &row)
+{
+       DB::Crypto::RowOptional row_optional;
+
+       if (dataType.isKey()) {
+               // read all key types
+               row_optional = database.getRow(name,
+                                                                          owner,
+                                                                          DataType::DB_KEY_FIRST,
+                                                                          DataType::DB_KEY_LAST);
+       } else {
+               // read anything else
+               row_optional = database.getRow(name,
+                                                                          owner,
+                                                                          dataType);
+       }
+
+       if (!row_optional) {
+               LogDebug("No row for given name, owner and type");
+               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+       } else {
+               row = *row_optional;
+       }
+
+       return CKM_API_SUCCESS;
+}
+
+int readMultiRow(const Name &name,
+               const ClientId &owner,
+               DataType dataType,
+               DB::Crypto &database,
+               DB::RowVector &output)
+{
+       if (dataType.isKey())
+               // read all key types
+               database.getRows(name,
+                                                owner,
+                                                DataType::DB_KEY_FIRST,
+                                                DataType::DB_KEY_LAST,
+                                                output);
+       else if (dataType.isChainCert())
+               // read all key types
+               database.getRows(name,
+                                                owner,
+                                                DataType::DB_CHAIN_FIRST,
+                                                DataType::DB_CHAIN_LAST,
+                                                output);
+       else
+               // read anything else
+               database.getRows(name,
+                                                owner,
+                                                dataType,
+                                                output);
+
+       if (!output.size()) {
+               LogDebug("No row for given name, owner and type");
+               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+       }
+
+       return CKM_API_SUCCESS;
+}
+
+} // namespace
+
+const uid_t CKMLogic::SYSTEM_DB_UID = 0;
+const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
+
 CKMLogic::CKMLogic()
 {
-    int retCode = FileSystem::init();
-    // TODO what can I do when init went wrong? exit(-1) ??
-    if (retCode) {
-        LogError("Fatal error in FileSystem::init()");
-    }
+       CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
+
+       m_accessControl.updateCCMode();
+}
+
+CKMLogic::~CKMLogic() {}
+
+void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
+{
+       auto &handle = m_userDataMap[user];
+
+       FileSystem fs(user);
+
+       auto wrappedDKEK = fs.getDKEK();
+
+       if (wrappedDKEK.empty()) {
+               wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
+               fs.saveDKEK(wrappedDKEK);
+       }
+
+       handle.keyProvider = KeyProvider(wrappedDKEK, password);
+       if (!handle.keyProvider.isInitialized()) {
+               handle.keyProvider.migrateDomainKEK(wrappedDKEK, password);
+               fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
+               LogInfo("DKEK migrated");
+       }
+}
+
+void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
+{
+       auto &handle = m_userDataMap[user];
 
-    if (CKM_API_SUCCESS != m_certStore.setSystemCertificateDir(CERT_SYSTEM_DIR)) {
-        LogError("Fatal error in CertificateStore::setSystemCertificateDir. Chain creation will not work");
-    }
+       FileSystem fs(user);
+       fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
 }
 
-CKMLogic::~CKMLogic(){}
+void CKMLogic::migrateSecureStorageData(bool isAdminUser)
+{
+       SsMigration::migrate(isAdminUser, [this](const std::string &name,
+                                                                                        const Crypto::Data &data,
+                                                                                        bool adminUserFlag) {
+               LogInfo("Migrate data called with  name: " << name);
+               auto ownerId = adminUserFlag ? CLIENT_ID_ADMIN_USER : CLIENT_ID_SYSTEM;
+               auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
+
+               int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
+                                                                                 PolicySerializable());
+
+               if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
+                       LogWarning("Alias already exist for migrated name: " << name);
+               else if (ret != CKM_API_SUCCESS)
+                       LogError("Failed to migrate secure-storage data. name: " << name <<
+                                        " ret: " << ret);
+       });
+}
+
+int CKMLogic::unlockDatabase(uid_t user, const Password &password)
+{
+       if (0 < m_userDataMap.count(user) &&
+                       m_userDataMap[user].keyProvider.isInitialized())
+               return CKM_API_SUCCESS;
+
+       int retCode = tryRet([&] {
+               auto &handle = m_userDataMap[user];
+
+               FileSystem fs(user);
+               loadDKEKFile(user, password);
+
+               auto wrappedDatabaseDEK = fs.getDBDEK();
+
+               if (wrappedDatabaseDEK.empty()) {
+                       wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
+                       fs.saveDBDEK(wrappedDatabaseDEK);
+               }
 
-RawBuffer CKMLogic::unlockUserKey(uid_t user, const std::string &password) {
-    // TODO try catch for all errors that should be supported by error code
-    int retCode = CKM_API_SUCCESS;
+               RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
 
-    try {
-        if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) {
-            auto &handle = m_userDataMap[user];
-            FileSystem fs(user);
-            auto wrappedDomainKEK = fs.getDomainKEK();
+               handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
+               handle.crypto = CryptoLogic();
 
-            if (wrappedDomainKEK.empty()) {
-                wrappedDomainKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
-                fs.saveDomainKEK(wrappedDomainKEK);
-            }
+               if (!m_accessControl.isSystemService(user)) {
+                       // remove data of removed apps during locked state
+                       ClientIdVector removedApps = fs.clearRemovedsApps();
 
-            handle.keyProvider = KeyProvider(wrappedDomainKEK, password);
+                       for (auto &app : removedApps) {
+                               handle.crypto.removeKey(app);
+                               handle.database.deleteKey(app);
+                       }
+               }
 
-            RawBuffer key = handle.keyProvider.getPureDomainKEK();
-            handle.database = DBCrypto(fs.getDBPath(), key);
-            handle.crypto = DBCryptoModule(key);
-            // TODO wipe key
-        }
-    } catch (const KeyProvider::Exception::Base &e) {
-        LogError("Error in KeyProvider " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
+               if (user == SYSTEM_DB_UID && SsMigration::hasData())
+                       migrateSecureStorageData(false);
+               else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
+                       migrateSecureStorageData(true);
 
-    MessageBuffer response;
-    Serialization::Serialize(response, retCode);
-    return response.Pop();
+               return CKM_API_SUCCESS;
+       });
+
+       if (CKM_API_SUCCESS != retCode)
+               m_userDataMap.erase(user);
+
+       return retCode;
+}
+
+int CKMLogic::unlockSystemDB()
+{
+       return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
+}
+
+UserData &CKMLogic::selectDatabase(const Credentials &cred,
+                                                                  const ClientId &owner)
+{
+       // if user trying to access system service - check:
+       //    * if user database is unlocked [mandatory]
+       //    * if not - proceed with regular user database
+       //    * if explicit system database owner given -> switch to system DB
+       if (!m_accessControl.isSystemService(cred)) {
+               if (0 == m_userDataMap.count(cred.clientUid))
+                       ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
+
+               if (0 != owner.compare(CLIENT_ID_SYSTEM))
+                       return m_userDataMap[cred.clientUid];
+       }
+
+       // system database selected, modify the owner id
+       if (CKM_API_SUCCESS != unlockSystemDB())
+               ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
+
+       return m_userDataMap[SYSTEM_DB_UID];
 }
 
-RawBuffer CKMLogic::lockUserKey(uid_t user) {
-    int retCode = CKM_API_SUCCESS;
-    // TODO try catch for all errors that should be supported by error code
-    m_userDataMap.erase(user);
+RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
+{
+       int retCode = CKM_API_SUCCESS;
+
+       if (!m_accessControl.isSystemService(user))
+               retCode = unlockDatabase(user, password);
+       else // do not allow lock/unlock operations for system users
+               retCode = CKM_API_ERROR_INPUT_PARAM;
+
+       return SerializeMessage(retCode);
+}
 
-    MessageBuffer response;
-    Serialization::Serialize(response, retCode);
-    return response.Pop();
+RawBuffer CKMLogic::updateCCMode()
+{
+       m_accessControl.updateCCMode();
+       return SerializeMessage(CKM_API_SUCCESS);
 }
 
-RawBuffer CKMLogic::removeUserData(uid_t user) {
-    int retCode = CKM_API_SUCCESS;
-    // TODO try catch for all errors that should be supported by error code
-    m_userDataMap.erase(user);
+RawBuffer CKMLogic::lockUserKey(uid_t user)
+{
+       int retCode = CKM_API_SUCCESS;
 
-    FileSystem fs(user);
-    fs.removeUserData();
+       if (!m_accessControl.isSystemService(user))
+               m_userDataMap.erase(user);
+       else // do not allow lock/unlock operations for system users
+               retCode = CKM_API_ERROR_INPUT_PARAM;
 
-    MessageBuffer response;
-    Serialization::Serialize(response, retCode);
-    return response.Pop();
+       return SerializeMessage(retCode);
+}
+
+RawBuffer CKMLogic::removeUserData(uid_t user)
+{
+       if (m_accessControl.isSystemService(user))
+               user = SYSTEM_DB_UID;
+
+       m_userDataMap.erase(user);
+
+       const int retCode = FileSystem(user).removeUserData()
+               ? CKM_API_ERROR_FILE_SYSTEM
+               : CKM_API_SUCCESS;
+
+       return SerializeMessage(retCode);
 }
 
 RawBuffer CKMLogic::changeUserPassword(
-    uid_t user,
-    const std::string &oldPassword,
-    const std::string &newPassword)
-{
-    int retCode = CKM_API_SUCCESS;
-    // TODO try-catch
-    FileSystem fs(user);
-    auto wrappedDomainKEK = fs.getDomainKEK();
-    if (wrappedDomainKEK.empty()) {
-        retCode = CKM_API_ERROR_BAD_REQUEST;
-    } else {
-        wrappedDomainKEK = KeyProvider::reencrypt(wrappedDomainKEK, oldPassword, newPassword);
-        fs.saveDomainKEK(wrappedDomainKEK);
-    }
-    MessageBuffer response;
-    Serialization::Serialize(response, retCode);
-    return response.Pop();
+       uid_t user,
+       const Password &oldPassword,
+       const Password &newPassword)
+{
+       return SerializeMessage(tryRet([&] {
+               // do not allow to change system database password
+               if (m_accessControl.isSystemService(user))
+                       return CKM_API_ERROR_INPUT_PARAM;
+
+               loadDKEKFile(user, oldPassword);
+               saveDKEKFile(user, newPassword);
+
+               return CKM_API_SUCCESS;
+       }));
 }
 
 RawBuffer CKMLogic::resetUserPassword(
-    uid_t user,
-    const std::string &newPassword)
-{
-    int retCode = CKM_API_SUCCESS;
-    // TODO try-catch
-    if (0 == m_userDataMap.count(user)) {
-        retCode = CKM_API_ERROR_BAD_REQUEST;
-    } else {
-        auto &handler = m_userDataMap[user];
-        FileSystem fs(user);
-        fs.saveDomainKEK(handler.keyProvider.getWrappedDomainKEK(newPassword));
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, retCode);
-    return response.Pop();
-}
-
-int CKMLogic::saveDataHelper(
-    Credentials &cred,
-    DBDataType dataType,
-    const Alias &alias,
-    const RawBuffer &key,
-    const PolicySerializable &policy)
-{
-    if (0 == m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
-
-    DBRow row = { alias, cred.smackLabel, policy.restricted,
-         policy.extractable, dataType, DBCMAlgType::NONE,
-         0, RawBuffer(10, 'c'), key.size(), key };
-
-    auto &handler = m_userDataMap[cred.uid];
-    DBCrypto::Transaction transaction(&handler.database);
-    if (!handler.crypto.haveKey(cred.smackLabel)) {
-        RawBuffer key;
-        auto key_optional = handler.database.getKey(cred.smackLabel);
-        if(!key_optional) {
-            LogDebug("No Key in database found. Generating new one for label: "
-                    << cred.smackLabel);
-            key = handler.keyProvider.generateDEK(cred.smackLabel);
-        } else {
-            key = *key_optional;
-        }
-
-        key = handler.keyProvider.getPureDEK(key);
-        handler.crypto.pushKey(cred.smackLabel, key);
-        handler.database.saveKey(cred.smackLabel, key);
-    }
-    handler.crypto.encryptRow(policy.password, row);
-    handler.database.saveDBRow(row);
-    transaction.commit();
-    return CKM_API_SUCCESS;
+       uid_t user,
+       const Password &newPassword)
+{
+       return SerializeMessage(tryRet([&] {
+               // do not allow to reset system database password
+               if (m_accessControl.isSystemService(user))
+                       return CKM_API_ERROR_INPUT_PARAM;
+
+               int retCode = CKM_API_SUCCESS;
+
+               if (0 == m_userDataMap.count(user)) {
+                       // Check if key exists. If exists we must return error
+                       FileSystem fs(user);
+                       auto wrappedDKEKMain = fs.getDKEK();
+
+                       if (!wrappedDKEKMain.empty())
+                               retCode = CKM_API_ERROR_BAD_REQUEST;
+               } else {
+                       saveDKEKFile(user, newPassword);
+               }
+
+               return retCode;
+       }));
+}
+
+RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
+{
+       return SerializeMessage(tryRet([&] {
+               if (owner.empty())
+                       return CKM_API_ERROR_INPUT_PARAM;
+
+               UidVector uids = FileSystem::getUIDsFromDBFile();
+
+               for (auto userId : uids) {
+                       if (0 == m_userDataMap.count(userId)) {
+                               FileSystem fs(userId);
+                               fs.addRemovedApp(owner);
+                       } else {
+                               auto &handle = m_userDataMap[userId];
+                               handle.crypto.removeKey(owner);
+                               handle.database.deleteKey(owner);
+                       }
+               }
+
+               return CKM_API_SUCCESS;
+       }));
+}
+
+int CKMLogic::verifyAndSaveDataHelper(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner,
+       const Crypto::Data &data,
+       const PolicySerializable &policy)
+{
+       return tryRet([&] {
+               // check if data is correct
+               Crypto::Data binaryData;
+               int retCode = toBinaryData(data, binaryData);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, name, owner);
+               if (ret != CKM_API_SUCCESS)
+                       return ret;
+
+               Crypto::GStore &store = m_decider.getStore(binaryData.type, policy);
+
+               // do not encrypt data with password during cc_mode on
+               Token token = store.import(binaryData,
+                                                                  m_accessControl.isCCMode() ? "" : policy.password,
+                                                                  Crypto::EncryptionParams(), digest);
+               dbOp.finalize(std::move(token), policy);
+               return CKM_API_SUCCESS;
+       });
+}
+
+int CKMLogic::getKeyForService(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner,
+       const Password &pass,
+       Crypto::GObjShPtr &key)
+{
+       return tryRet([&] {
+               // Key is for internal service use. It won't be exported to the client
+               Crypto::GObjUPtr obj;
+               int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, owner, pass, obj);
+               if (retCode == CKM_API_SUCCESS)
+                       key = std::move(obj);
+
+               return retCode;
+       });
 }
 
 RawBuffer CKMLogic::saveData(
-    Credentials &cred,
-    int commandId,
-    DBDataType dataType,
-    const Alias &alias,
-    const RawBuffer &key,
-    const PolicySerializable &policy)
-{
-    int retCode = CKM_API_SUCCESS;
-    try {
-        retCode = saveDataHelper(cred, dataType, alias, key, policy);
-        LogDebug("SaveDataHelper returned: " << retCode);
-    } catch (const KeyProvider::Exception::Base &e) {
-        LogError("KeyProvider failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCryptoModule::Exception::Base &e) {
-        LogError("DBCryptoModule failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCrypto::Exception::InternalError &e) {
-        LogError("DBCrypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const DBCrypto::Exception::AliasExists &e) {
-        LogError("DBCrypto couldn't save duplicate alias");
-        retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
-    } catch (const DBCrypto::Exception::TransactionError &e) {
-        LogError("DBCrypto transaction failed with message " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::SAVE));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-    Serialization::Serialize(response, static_cast<int>(dataType));
-
-    return response.Pop();
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner,
+       const Crypto::Data &data,
+       const PolicySerializable &policy)
+{
+       int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
+       return SerializeMessage(msgId, retCode, data.type);
+}
+
+RawBuffer CKMLogic::savePKCS12(
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner,
+       const PKCS12Serializable &pkcs,
+       const PolicySerializable &keyPolicy,
+       const PolicySerializable &certPolicy)
+{
+       return SerializeMessage(msgId, tryRet([&] {
+               auto [dbOp, retCode] = beginSave(cred, name, owner);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               // extract and encrypt the data
+               DB::RowVector encryptedRows;
+
+               auto import = [&](const Crypto::Data &data, const Policy& policy){
+                       retCode = verifyBinaryData(data);
+                       if (retCode != CKM_API_SUCCESS)
+                               return retCode;
+
+                       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid, data.type);
+                       if (digest.empty())
+                               return CKM_API_ERROR_HASH_ERROR;
+
+                       Crypto::GStore &store = m_decider.getStore(data.type, policy);
+
+                       // do not encrypt data with password during cc_mode on
+                       Token token = store.import(data,
+                                                                          m_accessControl.isCCMode() ? "" : policy.password,
+                                                                          Crypto::EncryptionParams(), digest);
+
+                       encryptedRows.push_back(dbOp.encryptOne(std::move(token), policy));
+                       return CKM_API_SUCCESS;
+               };
+
+               // private key is mandatory
+               auto key = pkcs.getKey();
+               if (!key) {
+                       LogError("Failed to get private key from pkcs");
+                       return CKM_API_ERROR_INVALID_FORMAT;
+               }
+
+               Crypto::Data keyData(DataType(key->getType()), key->getDER());
+               retCode = import(keyData, keyPolicy);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               // certificate is mandatory
+               auto cert = pkcs.getCertificate();
+               if (!cert) {
+                       LogError("Failed to get certificate from pkcs");
+                       return CKM_API_ERROR_INVALID_FORMAT;
+               }
+
+               Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
+               retCode = import(certData, certPolicy);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               // CA cert chain
+               unsigned int cert_index = 0;
+               for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
+                       Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++), ca->getDER());
+                       retCode = import(caCertData, certPolicy);
+                       if (retCode != CKM_API_SUCCESS)
+                               return retCode;
+               }
+
+               // save the data
+               dbOp.database().saveRows(name, owner, encryptedRows);
+               dbOp.transaction().commit();
+
+               return CKM_API_SUCCESS;
+       }));
 }
 
 RawBuffer CKMLogic::removeData(
-    Credentials &cred,
-    int commandId,
-    DBDataType dataType,
-    const Alias &alias)
-{
-    int retCode = CKM_API_SUCCESS;
-
-    if (0 < m_userDataMap.count(cred.uid)) {
-        Try {
-            m_userDataMap[cred.uid].database.deleteDBRow(alias, cred.smackLabel);
-        } Catch (CKM::Exception) {
-            LogError("Error in deleting row!");
-            retCode = CKM_API_ERROR_DB_ERROR;
-        }
-    } else {
-        retCode = CKM_API_ERROR_DB_LOCKED;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::REMOVE));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-    Serialization::Serialize(response, static_cast<int>(dataType));
-
-    return response.Pop();
-}
-
-int CKMLogic::getDataHelper(
-    Credentials &cred,
-    DBDataType dataType,
-    const Alias &alias,
-    const std::string &password,
-    DBRow &row)
-{
-
-    if (0 == m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
-
-    auto &handler = m_userDataMap[cred.uid];
-
-    DBCrypto::DBRowOptional row_optional;
-    if (dataType == DBDataType::CERTIFICATE || dataType == DBDataType::BINARY_DATA) {
-        row_optional = handler.database.getDBRow(alias, cred.smackLabel, dataType);
-    } else if ((static_cast<int>(dataType) >= static_cast<int>(DBDataType::DB_KEY_FIRST))
-            && (static_cast<int>(dataType) <= static_cast<int>(DBDataType::DB_KEY_LAST)))
-    {
-        row_optional = handler.database.getKeyDBRow(alias, cred.smackLabel);
-    } else {
-        LogError("Unknown type of requested data" << (int)dataType);
-        return CKM_API_ERROR_BAD_REQUEST;
-    }
-    if(!row_optional) {
-        LogError("No row for given alias, label and type");
-        return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
-    } else {
-        row = *row_optional;
-    }
-
-    if (!handler.crypto.haveKey(row.smackLabel)) {
-        RawBuffer key;
-        auto key_optional = handler.database.getKey(row.smackLabel);
-        if(!key_optional) {
-            LogError("No key for given label in database");
-            return CKM_API_ERROR_DB_ERROR;
-        }
-        key = *key_optional;
-        key = handler.keyProvider.getPureDEK(key);
-        handler.crypto.pushKey(cred.smackLabel, key);
-    }
-    handler.crypto.decryptRow(password, row);
-
-    return CKM_API_SUCCESS;
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner)
+{
+       return SerializeMessage(msgId, tryRet([&] {
+               auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               retCode = m_accessControl.canDelete(cred, permission);
+               if (retCode != CKM_API_SUCCESS) {
+                       LogWarning("access control check result: " << retCode);
+                       return retCode;
+               }
+
+               // get all matching rows
+               DB::RowVector rows;
+               dbOp.database().getRows(name, owner, DataType::DB_FIRST, DataType::DB_LAST, rows);
+               if (rows.empty()) {
+                       LogDebug("No row for given name and owner");
+                       return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+               }
+
+               retCode = dbOp.loadAppKey();
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               // destroy it in store
+               for (auto &r : rows) {
+                       try {
+                               dbOp.handler().crypto.decryptRow(Password(), r);
+                               m_decider.getStore(r).destroy(r);
+                       } catch (const Exc::AuthenticationFailed &) {
+                               LogDebug("Authentication failed when removing data. Ignored.");
+                       }
+               }
+
+               // delete row in db
+               dbOp.database().deleteRow(name, owner);
+               dbOp.transaction().commit();
+
+               return CKM_API_SUCCESS;
+       }));
+}
+
+
+int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
+               const DB::Row &row,
+               bool exportFlag,
+               const PermissionMask& permission)
+{
+       if (exportFlag)
+               return m_accessControl.canExport(accessorCred, row, permission);
+
+       return m_accessControl.canRead(accessorCred, permission);
+}
+
+void CKMLogic::decryptRow(
+       UserData &handler,
+       DB::Row &row,
+       const Password &password,
+       const RawBuffer &hash)
+{
+       if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
+                       CryptoLogic::ENCRYPTION_V2) {
+               handler.crypto.decryptRow(Password(), row);
+       } else {
+               Crypto::GStore &store = m_decider.getStore(row);
+
+               Password pass = m_accessControl.isCCMode() ? "" : password;
+
+               // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
+               handler.crypto.decryptRow(pass, row);
+               // destroy it in store
+               store.destroy(row);
+
+               // import it to store with new scheme: data -> pass(data)
+               Token token = store.import(Crypto::Data(row.dataType, row.data),
+                                                                  pass,
+                                                                  Crypto::EncryptionParams(),
+                                                                  hash);
+
+               // update row with new token
+               *static_cast<Token *>(&row) = std::move(token);
+
+               // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
+               auto encryptedRow = handler.crypto.encryptRow(row);
+
+               // update it in db
+               handler.database.updateRow(encryptedRow);
+       }
+}
+
+Crypto::GObjUPtr CKMLogic::rowToObject(
+       UserData &handler,
+       DB::Row row,
+       const Password &password,
+       const RawBuffer &hash)
+{
+       decryptRow(handler, row, password, hash);
+
+       return decryptedRowToObj(row, password);
+}
+
+int CKMLogic::readDataHelper(
+       bool exportFlag,
+       const Credentials &cred,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password,
+       Crypto::GObjUPtrVector &objs)
+{
+       auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       // read rows
+       DB::RowVector rows;
+       retCode = readMultiRow(name, owner, dataType, dbOp.database(), rows);
+       if (CKM_API_SUCCESS != retCode)
+               return retCode;
+
+       // all read rows belong to the same owner
+       DB::Row &firstRow = rows.at(0);
+
+       // check access rights
+       retCode = checkDataPermissionsHelper(cred, firstRow, exportFlag, permission);
+       if (CKM_API_SUCCESS != retCode)
+               return retCode;
+
+       // for multiple objects add type as hash input (see pkcs12)
+       bool multiple = rows.size() > 1;
+
+       RawBuffer digest;
+
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       // decrypt row
+       for (auto &row : rows) {
+               if (multiple)
+                       digest = CryptoLogic::makeHash(name, owner, cred.clientUid, row.dataType);
+               else
+                       digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
+
+               if (digest.empty())
+                       return CKM_API_ERROR_HASH_ERROR;
+
+               objs.push_back(rowToObject(dbOp.handler(), std::move(row), password, digest));
+       }
+
+       // rowToObject may modify db
+       dbOp.transaction().commit();
+
+       return CKM_API_SUCCESS;
+}
+
+int CKMLogic::readDataHelper(
+       bool exportFlag,
+       const Credentials &cred,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password,
+       Crypto::GObjUPtr &obj)
+{
+       DataType objDataType;
+       return readDataHelper(exportFlag, cred, dataType, name, owner,
+                                                 password, obj, objDataType);
+}
+
+int CKMLogic::readRowHelper(
+       bool exportFlag,
+       const Credentials &cred,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password,
+       DB::Row &row,
+       DataType &objDataType)
+{
+       auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       retCode = readSingleRow(name, owner, dataType, dbOp.database(), row);
+       if (CKM_API_SUCCESS != retCode)
+               return retCode;
+
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       objDataType = row.dataType;
+
+       // check access rights
+       retCode = checkDataPermissionsHelper(cred, row, exportFlag, permission);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
+       if (digest.empty())
+               return CKM_API_ERROR_HASH_ERROR;
+
+       decryptRow(dbOp.handler(), row, password, digest);
+
+       // decryptRow may modify db
+       dbOp.transaction().commit();
+
+       return CKM_API_SUCCESS;
+}
+
+Crypto::GObjUPtr CKMLogic::decryptedRowToObj(const DB::Row& row, const Password &password)
+{
+       Crypto::GStore &store = m_decider.getStore(row);
+
+       Password pass = m_accessControl.isCCMode() ? "" : password;
+       return store.getObject(row, pass);
+}
+
+int CKMLogic::readDataHelper(
+       bool exportFlag,
+       const Credentials &cred,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password,
+       Crypto::GObjUPtr &obj,
+       DataType &objDataType)
+{
+       DB::Row row;
+       int retCode = readRowHelper(exportFlag, cred, dataType, name, owner, password, row, objDataType);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       obj = decryptedRowToObj(row, password);
+
+       return CKM_API_SUCCESS;
 }
 
 RawBuffer CKMLogic::getData(
-    Credentials &cred,
-    int commandId,
-    DBDataType dataType,
-    const Alias &alias,
-    const std::string &password)
-{
-    int retCode = CKM_API_SUCCESS;
-    DBRow row;
-
-    try {
-        retCode = getDataHelper(cred, dataType, alias, password, row);
-    } catch (const KeyProvider::Exception::Base &e) {
-        LogError("KeyProvider failed with error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCryptoModule::Exception::Base &e) {
-        LogError("DBCryptoModule failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCrypto::Exception::Base &e) {
-        LogError("DBCrypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    if (CKM_API_SUCCESS != retCode) {
-        row.data.clear();
-        row.dataType = dataType;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::GET));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-    Serialization::Serialize(response, static_cast<int>(row.dataType));
-    Serialization::Serialize(response, row.data);
-    return response.Pop();
+       const Credentials &cred,
+       int msgId,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password)
+{
+       RawBuffer rowData;
+       DataType objDataType;
+
+       int retCode = tryRet([&] {
+               Crypto::GObjUPtr obj;
+               int retCode2 = readDataHelper(true, cred, dataType, name, owner,
+                                                                         password, obj, objDataType);
+
+               if (retCode2 == CKM_API_SUCCESS)
+                       rowData = obj->getBinary();
+
+               return retCode2;
+       });
+
+       if (CKM_API_SUCCESS != retCode)
+               rowData.clear();
+
+       return SerializeMessage(msgId, retCode, objDataType, rowData);
+}
+
+RawBuffer CKMLogic::getDataProtectionStatus(
+               const Credentials &cred,
+               int msgId,
+               DataType dataType,
+               const Name &name,
+               const ClientId &owner)
+{
+       bool status = false;
+       DataType objDataType;
+       Password password;
+
+       int retCode = tryRet([&] {
+               Crypto::GObjUPtr obj;
+               return readDataHelper(false, cred, dataType, name, owner, password, obj, objDataType);
+       });
+
+       if (retCode == CKM_API_ERROR_AUTHENTICATION_FAILED) {
+               status = true;
+               retCode = CKM_API_SUCCESS;
+       }
+
+       return SerializeMessage(msgId, retCode, objDataType, status);
+}
+
+RawBuffer CKMLogic::getPKCS12(
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner,
+       const Password &keyPassword,
+       const Password &certPassword)
+{
+       PKCS12Serializable output;
+
+       int retCode = tryRet([&] {
+               KeyShPtr privKey;
+               CertificateShPtr cert;
+               CertificateShPtrVector caChain;
+
+               // read private key (mandatory)
+               Crypto::GObjUPtr keyObj;
+               int retCode2 = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, owner,
+                                                                         keyPassword, keyObj);
+
+               if (retCode2 != CKM_API_SUCCESS) {
+                       if (retCode2 != CKM_API_ERROR_NOT_EXPORTABLE)
+                               return retCode2;
+               } else {
+                       privKey = CKM::Key::create(keyObj->getBinary());
+               }
+
+               // read certificate (mandatory)
+               Crypto::GObjUPtr certObj;
+               retCode2 = readDataHelper(true, cred, DataType::CERTIFICATE, name, owner,
+                                                                 certPassword, certObj);
+
+               if (retCode2 != CKM_API_SUCCESS) {
+                       if (retCode2 != CKM_API_ERROR_NOT_EXPORTABLE)
+                               return retCode2;
+               } else {
+                       cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
+               }
+
+               // read CA cert chain (optional)
+               Crypto::GObjUPtrVector caChainObjs;
+               retCode2 = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, owner,
+                                                                 certPassword, caChainObjs);
+
+               if (retCode2 != CKM_API_SUCCESS && retCode2 != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
+                       if (retCode2 != CKM_API_ERROR_NOT_EXPORTABLE)
+                               return retCode2;
+               } else {
+                       for (auto &caCertObj : caChainObjs)
+                               caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
+                                                                                                                  DataFormat::FORM_DER));
+               }
+
+               // if anything found, return it
+               if (privKey || cert || caChain.size() > 0)
+                       retCode2 = CKM_API_SUCCESS;
+
+               // prepare response
+               if (retCode2 != CKM_API_SUCCESS)
+                       return retCode2;
+
+               output = PKCS12Serializable(std::move(privKey), std::move(cert), std::move(caChain));
+               return CKM_API_SUCCESS;
+       });
+
+       return SerializeMessage(msgId, retCode, output);
+}
+
+int CKMLogic::getAliasInfoListHelper(const Credentials &cred,
+                                                                        const DataType dataType,
+                                                                        AliasInfoVector &aliasInfoVector)
+{
+       int retCode = CKM_API_ERROR_DB_LOCKED;
+
+       if (0 < m_userDataMap.count(cred.clientUid)) {
+               auto &database = m_userDataMap[cred.clientUid].database;
+
+               retCode = tryRet<CKM_API_ERROR_DB_ERROR>([&] {
+                       AliasInfoVector tmpVector;
+
+                       if (dataType.isKey()) {
+                               // list all key types
+                               database.listInfos(cred.client,
+                                                                  tmpVector,
+                                                                  DataType::DB_KEY_FIRST,
+                                                                  DataType::DB_KEY_LAST);
+                       } else {
+                               // list anything else
+                               database.listInfos(cred.client, tmpVector, dataType);
+                       }
+
+                       aliasInfoVector.insert(aliasInfoVector.end(), tmpVector.begin(), tmpVector.end());
+                       return CKM_API_SUCCESS;
+               });
+       }
+
+       return retCode;
 }
 
 RawBuffer CKMLogic::getDataList(
-    Credentials &cred,
-    int commandId,
-    DBDataType dataType)
-{
-    int retCode = CKM_API_SUCCESS;
-    AliasVector aliasVector;
-
-    if (0 < m_userDataMap.count(cred.uid)) {
-        auto &handler = m_userDataMap[cred.uid];
-        Try {
-            if (dataType == DBDataType::CERTIFICATE || dataType == DBDataType::BINARY_DATA) {
-                handler.database.getAliases(dataType, cred.smackLabel, aliasVector);
-            } else {
-                handler.database.getKeyAliases(cred.smackLabel, aliasVector);
-            }
-        } Catch (CKM::Exception) {
-            LogError("Failed to get aliases");
-            retCode = CKM_API_ERROR_DB_ERROR;
-        }
-    } else {
-        retCode = CKM_API_ERROR_DB_LOCKED;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::GET_LIST));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-    Serialization::Serialize(response, static_cast<int>(dataType));
-    Serialization::Serialize(response, aliasVector);
-    return response.Pop();
-}
-
-int CKMLogic::createKeyPairRSAHelper(
-    Credentials &cred,
-    int size,
-    const Alias &aliasPrivate,
-    const Alias &aliasPublic,
-    const PolicySerializable &policyPrivate,
-    const PolicySerializable &policyPublic)
-{
-    if (0 >= m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
-
-    auto &handler = m_userDataMap[cred.uid];
-    GenericKey prv, pub;
-    int retCode;
-
-    if (CKM_CRYPTO_CREATEKEY_SUCCESS !=
-        (retCode = CryptoService::createKeyPairRSA(size, prv, pub)))
-    {
-        LogDebug("CryptoService error with code: " << retCode);
-        return CKM_API_ERROR_SERVER_ERROR; // TODO error code
-    }
-
-    DBCrypto::Transaction transaction(&handler.database);
-    retCode = saveDataHelper(cred,
-                            toDBDataType(prv.getType()),
-                            aliasPrivate,
-                            prv.getDER(),
-                            policyPrivate);
-
-    if (CKM_API_SUCCESS != retCode)
-        return retCode;
-
-    retCode = saveDataHelper(cred,
-                            toDBDataType(pub.getType()),
-                            aliasPublic,
-                            pub.getDER(),
-                            policyPublic);
-
-    if (CKM_API_SUCCESS != retCode)
-        return retCode;
-
-    transaction.commit();
-
-    return retCode;
-}
-
-RawBuffer CKMLogic::createKeyPairRSA(
-    Credentials &cred,
-    int commandId,
-    int size,
-    const Alias &aliasPrivate,
-    const Alias &aliasPublic,
-    const PolicySerializable &policyPrivate,
-    const PolicySerializable &policyPublic)
-{
-    int retCode = CKM_API_SUCCESS;
-
-    try {
-        retCode = createKeyPairRSAHelper(
-                        cred,
-                        size,
-                        aliasPrivate,
-                        aliasPublic,
-                        policyPrivate,
-                        policyPublic);
-
-    } catch (DBCrypto::Exception::AliasExists &e) {
-        LogDebug("DBCrypto error: alias exists: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
-    } catch (DBCrypto::Exception::TransactionError &e) {
-        LogDebug("DBCrypto error: transaction error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (DBCrypto::Exception::InternalError &e) {
-        LogDebug("DBCrypto internal error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::CREATE_KEY_PAIR_RSA));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-
-    return response.Pop();
-}
-
-int CKMLogic::createKeyPairECDSAHelper(
-    Credentials &cred,
-    int type,
-    const Alias &aliasPrivate,
-    const Alias &aliasPublic,
-    const PolicySerializable &policyPrivate,
-    const PolicySerializable &policyPublic)
-{
-    if (0 >= m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
-
-    auto &handler = m_userDataMap[cred.uid];
-    GenericKey prv, pub;
-    int retCode;
-
-    if (CKM_CRYPTO_CREATEKEY_SUCCESS !=
-        (retCode = CryptoService::createKeyPairECDSA(static_cast<ElipticCurve>(type), prv, pub)))
-    {
-        LogError("CryptoService failed with code: " << retCode);
-        return CKM_API_ERROR_SERVER_ERROR; // TODO error code
-    }
-
-    DBCrypto::Transaction transaction(&handler.database);
-
-    retCode = saveDataHelper(cred,
-                            toDBDataType(prv.getType()),
-                            aliasPrivate,
-                            prv.getDER(),
-                            policyPrivate);
-
-    if (CKM_API_SUCCESS != retCode)
-        return retCode;
-
-    retCode = saveDataHelper(cred,
-                            toDBDataType(pub.getType()),
-                            aliasPublic,
-                            pub.getDER(),
-                            policyPublic);
-
-    if (CKM_API_SUCCESS != retCode)
-        return retCode;
-
-    transaction.commit();
-
-    return retCode;
-}
-
-RawBuffer CKMLogic::createKeyPairECDSA(
-    Credentials &cred,
-    int commandId,
-    int type,
-    const Alias &aliasPrivate,
-    const Alias &aliasPublic,
-    const PolicySerializable &policyPrivate,
-    const PolicySerializable &policyPublic)
-{
-    int retCode = CKM_API_SUCCESS;
-
-    try {
-        retCode = createKeyPairECDSAHelper(
-                        cred,
-                        type,
-                        aliasPrivate,
-                        aliasPublic,
-                        policyPrivate,
-                        policyPublic);
-    } catch (const DBCrypto::Exception::AliasExists &e) {
-        LogDebug("DBCrypto error: alias exists: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
-    } catch (const DBCrypto::Exception::TransactionError &e) {
-        LogDebug("DBCrypto error: transaction error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const DBCrypto::Exception::InternalError &e) {
-        LogDebug("DBCrypto internal error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::CREATE_KEY_PAIR_RSA));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-
-    return response.Pop();
+       const Credentials &cred,
+       int msgId,
+       DataType dataType)
+{
+       AliasInfoVector systemVector;
+       AliasInfoVector userVector;
+       AliasInfoVector aliasInfoVector;
+
+       int retCode = unlockSystemDB();
+
+       if (CKM_API_SUCCESS == retCode) {
+               // system database
+               if (m_accessControl.isSystemService(cred)) {
+                       // lookup system DB
+                       retCode = getAliasInfoListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
+                                                                                        dataType,
+                                                                                        systemVector);
+               } else {
+                       // user - lookup system, then client DB
+                       retCode = getAliasInfoListHelper(Credentials(SYSTEM_DB_UID, cred.client),
+                                                                                        dataType,
+                                                                                        systemVector);
+
+                       // private database
+                       if (retCode == CKM_API_SUCCESS) {
+                               retCode = getAliasInfoListHelper(cred,
+                                                                                                dataType,
+                                                                                                userVector);
+                       }
+               }
+       }
+
+       if (retCode == CKM_API_SUCCESS) {
+               aliasInfoVector.insert(aliasInfoVector.end(), systemVector.begin(),
+                                                          systemVector.end());
+               aliasInfoVector.insert(aliasInfoVector.end(), userVector.begin(),
+                                                          userVector.end());
+       }
+
+       return SerializeMessage(msgId, retCode, dataType, AliasInfoSerializableVector(aliasInfoVector));
 }
 
-RawBuffer CKMLogic::getCertificateChain(
-    Credentials &cred,
-    int commandId,
-    const RawBuffer &certificate,
-    const RawBufferVector &untrustedRawCertVector)
+int CKMLogic::importInitialData(
+       const Name &name,
+       const Crypto::Data &data,
+       const Crypto::EncryptionParams &encParams,
+       const Policy &policy)
+{
+       try {
+               return tryRet([&] {
+                       if (encParams.iv.empty() != encParams.tag.empty()) {
+                               LogError("Both iv and tag must be empty or set");
+                               return CKM_API_ERROR_INPUT_PARAM;
+                       }
+
+                       // Inital values are always imported with root credentials. Client id is not important.
+                       Credentials rootCred(0, "whatever");
+                       ClientId owner(CLIENT_ID_SYSTEM);
+
+                       auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
+                       if (retCode != CKM_API_SUCCESS)
+                               return retCode;
+
+                       Crypto::GStore &store = m_decider.getStore(data.type, policy, true, !encParams.iv.empty());
+
+                       Token token;
+                       if (encParams.iv.empty()) {
+                               // Data are not encrypted, let's try to verify them
+                               Crypto::Data binaryData;
+
+                               if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
+                                       return retCode;
+
+                               token = store.import(binaryData,
+                                                                        m_accessControl.isCCMode() ? "" : policy.password,
+                                                                        encParams, digest);
+                       } else {
+                               token = store.import(data,
+                                                                        m_accessControl.isCCMode() ? "" : policy.password,
+                                                                        encParams, digest);
+                       }
+
+                       dbOp.finalize(std::move(token), policy);
+
+                       return CKM_API_SUCCESS;
+               });
+       } catch (const std::exception &e) {
+               LogError("Std::exception: " << e.what());
+               return CKM_API_ERROR_SERVER_ERROR;
+       }
+}
+
+int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
+{
+       if (!m_handler.crypto.haveKey(m_owner)) {
+               RawBuffer wrappedDEK;
+               auto wrappedDEKOptional = m_handler.database.getKey(m_owner);
+
+               if (!wrappedDEKOptional) {
+                       if (keyRequired) {
+                               LogError("No key for given owner in database");
+                               return CKM_API_ERROR_DB_ERROR;
+                       }
+                       LogDebug("No Key in database found. Generating new one for client: " << m_owner);
+                       wrappedDEK = m_handler.keyProvider.generateDEK(m_owner);
+                       m_handler.database.saveKey(m_owner, wrappedDEK);
+               } else {
+                       wrappedDEK = *wrappedDEKOptional;
+               }
+
+               m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
+       }
+
+       return CKM_API_SUCCESS;
+}
+
+std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       auto &handler = selectDatabase(cred, owner);
+       DBOperation op(handler, name, owner);
+
+       if (cred.client.empty() || !isClientValid(cred.client) ||
+               !isNameValid(name) || !isClientValid(owner))
+               return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
+
+       return std::make_tuple(std::move(op), CKM_API_SUCCESS);
+}
+
+std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       PermissionMask permission = Permission::NONE;
+       auto [dbOp, retCode] = begin(cred, name, owner);
+       if (retCode == CKM_API_SUCCESS)
+               permission = toPermissionMask(dbOp.database().getPermissionRow(name, owner, cred.client));
+
+       return std::make_tuple(std::move(dbOp), permission, retCode);
+}
+
+std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       auto [dbOp, retCode] = begin(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return std::make_tuple(std::move(dbOp), retCode);
+
+       retCode = dbOp.loadAppKey(false);
+       if (retCode != CKM_API_SUCCESS)
+               return std::make_tuple(std::move(dbOp), retCode);
+
+       // check if accessor is allowed to save owner's items
+       retCode = m_accessControl.canSave(cred, owner);
+       if (retCode != CKM_API_SUCCESS) {
+               LogDebug("accessor " << cred.client << " can not save rows owned by " << owner);
+               return std::make_tuple(std::move(dbOp), retCode);
+       }
+
+       if (dbOp.database().isNameOwnerPresent(name, owner))
+               retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
+
+       return std::make_tuple(std::move(dbOp), retCode);
+}
+
+std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       RawBuffer digest;
+       auto [dbOp, retCode] = beginSave(cred, name, owner);
+       if (retCode == CKM_API_SUCCESS) {
+               digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
+               if (digest.empty())
+                       retCode = CKM_API_ERROR_HASH_ERROR;
+       }
+
+       return std::make_tuple(std::move(dbOp), std::move(digest), retCode);
+}
+
+RawBuffer CKMLogic::createKeyPair(
+       const Credentials &cred,
+       int msgId,
+       const CryptoAlgorithmSerializable &keyGenParams,
+       const Name &namePrv,
+       const ClientId &ownerPrv,
+       const Name &namePub,
+       const ClientId &ownerPub,
+       const PolicySerializable &policyPrv,
+       const PolicySerializable &policyPub)
+{
+       return SerializeMessage(msgId, tryRet([&] {
+               auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
+               if (retCodePrv != CKM_API_SUCCESS)
+                       return retCodePrv;
+
+               auto [dbOpPub, digestPub, retCodePub] = beginSaveAndGetHash(cred, namePub, ownerPub);
+               if (retCodePub != CKM_API_SUCCESS)
+                       return retCodePub;
+
+               if (policyPrv.backend != policyPub.backend)
+                       ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
+
+               bool exportable = policyPrv.extractable || policyPub.extractable;
+               Policy lessRestricted(Password(), exportable, policyPrv.backend);
+
+               // For now any asymmetric key will do. If necessary we can extract it from keyGenParams.
+               TokenPair keys = m_decider.getStore(DataType::DB_KEY_FIRST, policyPrv, false).generateAKey(
+                       keyGenParams,
+                       policyPrv.password,
+                       policyPub.password,
+                       digestPrv, digestPub);
+
+               dbOpPrv.finalize(std::move(keys.first), policyPrv);
+               dbOpPub.finalize(std::move(keys.second), policyPub);
+
+               return CKM_API_SUCCESS;
+       }));
+}
+
+RawBuffer CKMLogic::createKeyAES(
+       const Credentials &cred,
+       int msgId,
+       const int size,
+       const Name &name,
+       const ClientId &owner,
+       const PolicySerializable &policy)
+{
+       int retCode = CKM_API_SUCCESS;
+
+       try {
+               retCode = tryRet([&] {
+                       auto [dbOp, digest, retCode2] = beginSaveAndGetHash(cred, name, owner);
+                       if (retCode2 != CKM_API_SUCCESS)
+                               return retCode2;
+
+                       // create key in store
+                       CryptoAlgorithm keyGenAlgorithm;
+                       keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
+                       keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
+
+                       auto& store = m_decider.getStore(DataType::KEY_AES, policy, false);
+                       Token key = store.generateSKey(keyGenAlgorithm, policy.password, digest);
+
+                       dbOp.finalize(std::move(key), policy);
+                       return CKM_API_SUCCESS;
+               });
+       } catch (std::invalid_argument &e) {
+               LogDebug("invalid argument error: " << e.what());
+               retCode = CKM_API_ERROR_INPUT_PARAM;
+       }
+
+       return SerializeMessage(msgId, retCode);
+}
+
+int CKMLogic::readCertificateHelper(
+       const Credentials &cred,
+       const OwnerNameVector &ownerNameVector,
+       CertificateImplVector &certVector)
+{
+       for (auto &i : ownerNameVector) {
+               // certificates can't be protected with custom user password
+               Crypto::GObjUPtr obj;
+               int ec;
+               ec = readDataHelper(true,
+                                                       cred,
+                                                       DataType::CERTIFICATE,
+                                                       i.second,
+                                                       cred.effectiveOwner(i.first),
+                                                       Password(),
+                                                       obj);
+
+               if (ec != CKM_API_SUCCESS)
+                       return ec;
+
+               certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
+
+               // try to read chain certificates (if present)
+               Crypto::GObjUPtrVector caChainObjs;
+               ec = readDataHelper(true,
+                                                       cred,
+                                                       DataType::DB_CHAIN_FIRST,
+                                                       i.second,
+                                                       cred.effectiveOwner(i.first),
+                                                       CKM::Password(),
+                                                       caChainObjs);
+
+               if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
+                       return ec;
+
+               for (auto &caCertObj : caChainObjs)
+                       certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
+       }
+
+       return CKM_API_SUCCESS;
+}
+
+int CKMLogic::getCertificateChainHelper(
+       const CertificateImpl &cert,
+       const RawBufferVector &untrustedCertificates,
+       const RawBufferVector &trustedCertificates,
+       bool useTrustedSystemCertificates,
+       RawBufferVector &chainRawVector)
+{
+       CertificateImplVector untrustedCertVector;
+       CertificateImplVector trustedCertVector;
+       CertificateImplVector chainVector;
+
+       if (cert.empty())
+               return CKM_API_ERROR_INPUT_PARAM;
+
+       for (auto &e : untrustedCertificates) {
+               CertificateImpl c(e, DataFormat::FORM_DER);
+
+               if (c.empty())
+                       return CKM_API_ERROR_INPUT_PARAM;
+
+               untrustedCertVector.push_back(std::move(c));
+       }
+
+       for (auto &e : trustedCertificates) {
+               CertificateImpl c(e, DataFormat::FORM_DER);
+
+               if (c.empty())
+                       return CKM_API_ERROR_INPUT_PARAM;
+
+               trustedCertVector.push_back(std::move(c));
+       }
+
+       CertificateStore store;
+       int retCode = store.verifyCertificate(cert,
+                                                                                 untrustedCertVector,
+                                                                                 trustedCertVector,
+                                                                                 useTrustedSystemCertificates,
+                                                                                 m_accessControl.isCCMode(),
+                                                                                 chainVector);
+
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       for (auto &e : chainVector)
+               chainRawVector.push_back(e.getDER());
+
+       return CKM_API_SUCCESS;
+}
+
+int CKMLogic::getCertificateChainHelper(
+       const Credentials &cred,
+       const CertificateImpl &cert,
+       const OwnerNameVector &untrusted,
+       const OwnerNameVector &trusted,
+       bool useTrustedSystemCertificates,
+       RawBufferVector &chainRawVector)
 {
-    (void)cred;
+       CertificateImplVector untrustedCertVector;
+       CertificateImplVector trustedCertVector;
+       CertificateImplVector chainVector;
+
+       if (cert.empty())
+               return CKM_API_ERROR_INPUT_PARAM;
 
-    CertificateImpl cert(certificate, DataFormat::FORM_DER);
-    CertificateImplVector untrustedCertVector;
-    CertificateImplVector chainVector;
-    RawBufferVector chainRawVector;
+       int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
 
-    for (auto &e: untrustedRawCertVector)
-        untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-    LogDebug("Cert is empty: " << cert.empty());
+       retCode = readCertificateHelper(cred, trusted, trustedCertVector);
 
-    int retCode = m_certStore.verifyCertificate(cert, untrustedCertVector, chainVector);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-    if (retCode == CKM_API_SUCCESS) {
-        for (auto &e : chainVector)
-            chainRawVector.push_back(e.getDER());
-    }
+       CertificateStore store;
+       retCode = store.verifyCertificate(cert,
+                                                                         untrustedCertVector,
+                                                                         trustedCertVector,
+                                                                         useTrustedSystemCertificates,
+                                                                         m_accessControl.isCCMode(),
+                                                                         chainVector);
 
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::GET_CHAIN_CERT));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-    Serialization::Serialize(response, chainRawVector);
-    return response.Pop();
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       for (auto &i : chainVector)
+               chainRawVector.push_back(i.getDER());
+
+       return CKM_API_SUCCESS;
 }
 
 RawBuffer CKMLogic::getCertificateChain(
-    Credentials &cred,
-    int commandId,
-    const RawBuffer &certificate,
-    const AliasVector &aliasVector)
+       const Credentials & /*cred*/,
+       int msgId,
+       const RawBuffer &certificate,
+       const RawBufferVector &untrustedCertificates,
+       const RawBufferVector &trustedCertificates,
+       bool useTrustedSystemCertificates)
 {
-    (void) cred;
-    (void) commandId;
-    (void) certificate;
-    (void) aliasVector;
+       CertificateImpl cert(certificate, DataFormat::FORM_DER);
+       RawBufferVector chainRawVector;
+       int retCode = CKM_API_ERROR_UNKNOWN;
+
+       try {
+               retCode = getCertificateChainHelper(cert,
+                                                                                       untrustedCertificates,
+                                                                                       trustedCertificates,
+                                                                                       useTrustedSystemCertificates,
+                                                                                       chainRawVector);
+       } catch (const Exc::Exception &e) {
+               retCode = e.error();
+       } catch (const std::exception &e) {
+               LogError("STD exception " << e.what());
+               retCode = CKM_API_ERROR_SERVER_ERROR;
+       } catch (...) {
+               LogError("Unknown error.");
+       }
+
+       return SerializeMessage(msgId, retCode, chainRawVector);
+}
 
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::GET_CHAIN_ALIAS));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, static_cast<int>(CKM_API_SUCCESS));
-    Serialization::Serialize(response, RawBufferVector());
-    return response.Pop();
+RawBuffer CKMLogic::getCertificateChain(
+       const Credentials &cred,
+       int msgId,
+       const RawBuffer &certificate,
+       const OwnerNameVector &untrustedCertificates,
+       const OwnerNameVector &trustedCertificates,
+       bool useTrustedSystemCertificates)
+{
+       int retCode = CKM_API_ERROR_UNKNOWN;
+       CertificateImpl cert(certificate, DataFormat::FORM_DER);
+       RawBufferVector chainRawVector;
+
+       try {
+               retCode = getCertificateChainHelper(cred,
+                                                                                       cert,
+                                                                                       untrustedCertificates,
+                                                                                       trustedCertificates,
+                                                                                       useTrustedSystemCertificates,
+                                                                                       chainRawVector);
+       } catch (const Exc::Exception &e) {
+               retCode = e.error();
+       } catch (const std::exception &e) {
+               LogError("STD exception " << e.what());
+               retCode = CKM_API_ERROR_SERVER_ERROR;
+       } catch (...) {
+               LogError("Unknown error.");
+       }
+
+       return SerializeMessage(msgId, retCode, chainRawVector);
 }
 
 RawBuffer CKMLogic::createSignature(
-        Credentials &cred,
-        int commandId,
-        const Alias &privateKeyAlias,
-        const std::string &password,           // password for private_key
-        const RawBuffer &message,
-        const HashAlgorithm hash,
-        const RSAPaddingAlgorithm padding)
-{
-
-    DBRow row;
-    CryptoService cs;
-    RawBuffer signature;
-
-    int retCode = CKM_API_SUCCESS;
-
-    try {
-        do {
-            retCode = getDataHelper(cred, DBDataType::KEY_RSA_PUBLIC, privateKeyAlias, password, row);
-            if (CKM_API_SUCCESS != retCode) {
-                LogError("getDataHelper return error:");
-                break;
-            }
-
-            GenericKey keyParsed(row.data, std::string());
-            if (keyParsed.empty())
-                retCode = CKM_API_ERROR_SERVER_ERROR;
-            else
-                cs.createSignature(keyParsed, message, hash, padding, signature);
-        } while(0);
-    } catch (const KeyProvider::Exception::Base &e) {
-        LogError("KeyProvider failed with error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCryptoModule::Exception::Base &e) {
-        LogError("DBCryptoModule failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCrypto::Exception::Base &e) {
-        LogError("DBCrypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::CREATE_SIGNATURE));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-    Serialization::Serialize(response, signature);
-    return response.Pop();
+       const Credentials &cred,
+       int msgId,
+       const Name &privateKeyName,
+       const ClientId &owner,
+       const Password &password,           // password for private_key
+       const RawBuffer &message,
+       const CryptoAlgorithm &cryptoAlg)
+{
+       RawBuffer signature;
+
+       int retCode = CKM_API_SUCCESS;
+
+       try {
+               retCode = tryRet([&] {
+                       Crypto::GObjUPtr obj;
+                       int retCode2 = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
+                                                                                 owner, password, obj);
+
+                       if (retCode2 == CKM_API_SUCCESS)
+                               signature = obj->sign(cryptoAlg, message);
+
+                       return retCode2;
+               });
+       } catch (const std::exception &e) {
+               LogError("STD exception " << e.what());
+               retCode = CKM_API_ERROR_SERVER_ERROR;
+       }
+
+       return SerializeMessage(msgId, retCode, signature);
 }
 
 RawBuffer CKMLogic::verifySignature(
-        Credentials &cred,
-        int commandId,
-        const Alias &publicKeyOrCertAlias,
-        const std::string &password,           // password for public_key (optional)
-        const RawBuffer &message,
-        const RawBuffer &signature,
-        const HashAlgorithm hash,
-        const RSAPaddingAlgorithm padding)
-{
-
-    DBRow row;
-    CryptoService cs;
-
-    int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
-    try {
-        do {
-            retCode = getDataHelper(cred, DBDataType::KEY_RSA_PUBLIC, publicKeyOrCertAlias, password, row);
-
-            if (retCode != CKM_API_SUCCESS) {
-                break;
-            }
-
-            GenericKey keyParsed(row.data, std::string());
-            if (keyParsed.empty()) {
-                retCode = CKM_API_ERROR_SERVER_ERROR;
-                break;
-            }
-
-            retCode = cs.verifySignature(keyParsed, message, signature, hash, padding);
-        } while(0);
-    } catch (const CryptoService::Exception::Crypto_internal &e) {
-        LogError("KeyProvider failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const CryptoService::Exception::opensslError &e) {
-        LogError("KeyProvider failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const KeyProvider::Exception::Base &e) {
-        LogError("KeyProvider failed with error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCryptoModule::Exception::Base &e) {
-        LogError("DBCryptoModule failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (const DBCrypto::Exception::Base &e) {
-        LogError("DBCrypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    MessageBuffer response;
-    Serialization::Serialize(response, static_cast<int>(LogicCommand::VERIFY_SIGNATURE));
-    Serialization::Serialize(response, commandId);
-    Serialization::Serialize(response, retCode);
-
-    return response.Pop();
+       const Credentials &cred,
+       int msgId,
+       const Name &publicKeyOrCertName,
+       const ClientId &owner,
+       const Password &password,           // password for public_key (optional)
+       const RawBuffer &message,
+       const RawBuffer &signature,
+       const CryptoAlgorithm &params)
+{
+       return SerializeMessage(msgId, tryRet([&] {
+               // try certificate first - looking for a public key.
+               // in case of PKCS, pub key from certificate will be found first
+               // rather than private key from the same PKCS.
+               Crypto::GObjUPtr obj;
+               int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
+                                                                        publicKeyOrCertName, owner, password, obj);
+
+               if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
+                       retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
+                                                                        publicKeyOrCertName, owner, password, obj);
+
+               if (retCode == CKM_API_SUCCESS)
+                       retCode = obj->verify(params, message, signature);
+
+               return retCode;
+       }));
 }
-} // namespace CKM
 
+int CKMLogic::setPermissionHelper(
+       const Credentials &cred,                // who's the client
+       const Name &name,
+       const ClientId &owner,                     // who's the owner
+       const ClientId &accessor,             // who will get the access
+       const PermissionMask permissionMask)
+{
+       auto [dbOp, retCode] = beginSave(cred, name, owner);
+       // Normally, saving requires alias to be unoccupied. When changing permissions it's the opposite
+       if (retCode != CKM_API_ERROR_DB_ALIAS_EXISTS) {
+               if (retCode == CKM_API_SUCCESS)
+                       retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+               return retCode;
+       }
+
+       // currently we don't support modification of owner's permissions to his own rows
+       if (owner == accessor)
+               return CKM_API_ERROR_INPUT_PARAM;
+
+       // system database does not support write/remove permissions
+       if ((0 == owner.compare(CLIENT_ID_SYSTEM)) && (permissionMask & Permission::REMOVE))
+               return CKM_API_ERROR_INPUT_PARAM;
+
+       // set permissions to the row owned by owner for accessor
+       dbOp.database().setPermission(name, owner, accessor, permissionMask);
+       dbOp.transaction().commit();
+
+       return CKM_API_SUCCESS;
+}
+
+RawBuffer CKMLogic::setPermission(
+       const Credentials &cred,
+       const int msgID,
+       const Name &name,
+       const ClientId &owner,
+       const ClientId &accessor,
+       const PermissionMask permissionMask)
+{
+       return SerializeMessage(msgID, tryRet([&] {
+               return setPermissionHelper(cred, name, owner, accessor, permissionMask);
+       }));
+}
+
+RawBuffer CKMLogic::deriveKey(
+       const Credentials &cred,
+       const int msgID,
+       const CryptoAlgorithm &params,
+       const Name &secretName,
+       const ClientId &secretOwner,
+       const Password &secretPassword,
+       const Name &newKeyName,
+       const ClientId &newKeyOwner,
+       const Policy &newKeyPolicy)
+{
+       return SerializeMessage(msgID, tryRet([&] {
+               // Get key/secret for internal service use. It won't be exported to the client
+               Crypto::GObjUPtr obj;
+               DataType objType;
+               int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
+                                                                        secretName, secretOwner, secretPassword, obj, objType);
+               if (retCode != CKM_API_SUCCESS) {
+                       if (retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
+                               return retCode;
+
+                       retCode = readDataHelper(false, cred, DataType::BINARY_DATA,
+                                                                        secretName, secretOwner, secretPassword, obj, objType);
+                       if (retCode != CKM_API_SUCCESS)
+                               return retCode;
+               }
+
+               auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, newKeyName, newKeyOwner);
+               if (ret != CKM_API_SUCCESS)
+                       return ret;
+
+               // ECDH (private key) -> binary secret, KBKDF -> symmetric key
+               DataType newKeyType = objType.isKeyPrivate() ? DataType::BINARY_DATA : DataType::KEY_AES;
+               if (!m_decider.checkStore(obj->backendId(), newKeyType, newKeyPolicy, false)) {
+                       LogDebug("Can't import the derived key to backend " <<
+                                static_cast<int>(obj->backendId()) << " with given policy");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               // derive
+               Token derived = obj->derive(params, newKeyPolicy.password, digest);
+
+               dbOp.finalize(std::move(derived), newKeyPolicy);
+
+               return CKM_API_SUCCESS;
+       }));
+}
+
+RawBuffer CKMLogic::importWrappedKey(
+       const Credentials &cred,
+       const int msgId,
+       const CryptoAlgorithm &params,
+       const Name &wrappingKeyName,
+       const ClientId &wrappingKeyOwner,
+       const Password &wrappingKeyPassword,
+       const Name &keyName,
+       const ClientId &keyOwner,
+       const RawBuffer &wrappedKey,
+       const CKM::DataType keyType,
+       const PolicySerializable &policy)
+{
+       return SerializeMessage(msgId, tryRet([&] {
+               Crypto::GObjUPtr wrappingKey;
+
+               auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, keyName, keyOwner);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
+                                                               wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               if (!m_decider.checkStore(wrappingKey->backendId(), keyType, policy, true)) {
+                       LogDebug("Can't import the wrapped key to backend " <<
+                                static_cast<int>(wrappingKey->backendId()) << " with given policy");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               Token token = wrappingKey->unwrap(params,
+                                                                                 Crypto::Data(keyType, std::move(wrappedKey)),
+                                                                                 policy.password,
+                                                                                 digest);
+
+               dbOp.finalize(std::move(token), policy);
+
+               return retCode;
+       }));
+}
+
+RawBuffer CKMLogic::exportWrappedKey(
+       const Credentials &cred,
+       const int msgID,
+       const CryptoAlgorithm &params,
+       const Name &wrappingKeyName,
+       const ClientId &wrappingKeyOwner,
+       const Password &wrappingKeyPassword,
+       const Name &keyName,
+       const ClientId &keyOwner,
+       const Password &keyPassword)
+{
+       Crypto::GObjUPtr wrappingKey;
+       DB::Row wrappedKeyRow;
+       DataType wrappedKeyType;
+       RawBuffer wrappedKey;
+
+       auto retCode = tryRet([&] {
+               auto retCode2 = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
+                                                                          wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
+               if (retCode2 != CKM_API_SUCCESS)
+                       return retCode2;
+
+               retCode2 = readRowHelper(false, cred, DataType::DB_KEY_FIRST, keyName,
+                                                                keyOwner, keyPassword, wrappedKeyRow, wrappedKeyType);
+               if (retCode2 != CKM_API_SUCCESS)
+                       return retCode2;
+
+               wrappedKey = wrappingKey->wrap(params, wrappedKeyRow, keyPassword);
+
+               return retCode2;
+       });
+
+       return SerializeMessage(msgID, retCode, wrappedKeyType, wrappedKey);
+}
+
+RawBuffer CKMLogic::getBackendInfo(const int msgID, BackendId backend)
+{
+       BackendInfo info;
+       auto retCode = tryRet([&] {
+               CryptoBackend cryptoBackend;
+               if (backend == BackendId::SW)
+                       cryptoBackend = CryptoBackend::OpenSSL;
+               else if (backend == BackendId::TZ)
+                       cryptoBackend = CryptoBackend::TrustZone;
+               else
+                       return CKM_API_ERROR_INPUT_PARAM;
+
+               auto store = m_decider.getStore(cryptoBackend);
+               if (store == nullptr) {
+                       LogError("Required backend is unavailable");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               info.maxChunkSize = store->maxChunkSize();
+               return CKM_API_SUCCESS;
+       });
+
+       return SerializeMessage(msgID, retCode, BackendInfoSerializable(info));
+}
+
+} // namespace CKM