Enable -Wshadow and fix warnings
[platform/core/security/key-manager.git] / src / manager / service / ckm-logic.cpp
index 5b8f1a3..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 <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 SYSTEM_DB_PASSWD         = "cAtRugU7";
-
-bool isLabelValid(const CKM::Label &label) {
-    // TODO: copy code from libprivilege control (for check smack label)
-    if (label.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Label::npos)
-        return false;
-    return true;
+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::LABEL_NAME_SEPARATOR) != CKM::Name::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 {
 
-const uid_t CKMLogic::SYSTEM_DB_UID = 0;
+namespace {
 
-CKMLogic::CKMLogic()
+template <int ERROR_ON_CKM_EXCEPTION = CKM_API_ERROR_SERVER_ERROR, class F>
+int tryRet(F &&f)
 {
-    CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
-
-    m_accessControl.updateCCMode();
+       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;
+       }
 }
 
-CKMLogic::~CKMLogic(){}
+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;
+}
 
-void CKMLogic::loadDKEKFile(uid_t user, const Password &password) {
-    auto &handle = m_userDataMap[user];
+int verifyBinaryData(const Crypto::Data &input)
+{
+       Crypto::Data dummy;
+       return toBinaryData(input, dummy);
+}
 
-    FileSystem fs(user);
+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;
+}
 
-    auto wrappedDKEK = fs.getDKEK();
+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;
+}
 
-    if (wrappedDKEK.empty()) {
-        wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
-        fs.saveDKEK(wrappedDKEK);
-    }
+} // namespace
 
-    handle.keyProvider = KeyProvider(wrappedDKEK, password);
-}
+const uid_t CKMLogic::SYSTEM_DB_UID = 0;
+const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
 
-void CKMLogic::saveDKEKFile(uid_t user, const Password &password) {
-    auto &handle = m_userDataMap[user];
+CKMLogic::CKMLogic()
+{
+       CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
 
-    FileSystem fs(user);
-    fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
+       m_accessControl.updateCCMode();
 }
 
-int CKMLogic::unlockDatabase(uid_t user, const Password & password)
+CKMLogic::~CKMLogic() {}
+
+void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
 {
-    if (0<m_userDataMap.count(user) && m_userDataMap[user].keyProvider.isInitialized())
-        return CKM_API_SUCCESS;
-
-    int retCode = CKM_API_SUCCESS;
-    try
-    {
-        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 key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
-
-        handle.database = DB::Crypto(fs.getDBPath(), key);
-        handle.crypto = CryptoLogic();
-
-        if ( !m_accessControl.isSystemService(user) )
-        {
-            // remove data of removed apps during locked state
-            AppLabelVector removedApps = fs.clearRemovedsApps();
-            for(auto& appSmackLabel : removedApps) {
-                handle.crypto.removeKey(appSmackLabel);
-                handle.database.deleteKey(appSmackLabel);
-            }
-        }
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    if (CKM_API_SUCCESS != retCode)
-        m_userDataMap.erase(user);
-
-    return retCode;
+       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");
+       }
 }
 
-int CKMLogic::unlockSystemDB()
+void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
 {
-    return unlockDatabase(SYSTEM_DB_UID, SYSTEM_DB_PASSWD);
+       auto &handle = m_userDataMap[user];
+
+       FileSystem fs(user);
+       fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
 }
 
-UserData & CKMLogic::selectDatabase(const Credentials &cred, const Label &incoming_label)
+void CKMLogic::migrateSecureStorageData(bool isAdminUser)
 {
-    // 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 label 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 != incoming_label.compare(OWNER_ID_SYSTEM))
-            return m_userDataMap[cred.clientUid];
-    }
-
-    // system database selected, modify the label
-    if (CKM_API_SUCCESS != unlockSystemDB() )
-        ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
-    return m_userDataMap[SYSTEM_DB_UID];
+       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);
+       });
 }
 
-RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
+int CKMLogic::unlockDatabase(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 MessageBuffer::Serialize(retCode).Pop();
-}
+       if (0 < m_userDataMap.count(user) &&
+                       m_userDataMap[user].keyProvider.isInitialized())
+               return CKM_API_SUCCESS;
 
-RawBuffer CKMLogic::updateCCMode() {
-    m_accessControl.updateCCMode();
-    return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
-}
+       int retCode = tryRet([&] {
+               auto &handle = m_userDataMap[user];
 
-RawBuffer CKMLogic::lockUserKey(uid_t user)
-{
-    int retCode = CKM_API_SUCCESS;
-    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;
-    }
-
-    return MessageBuffer::Serialize(retCode).Pop();
+               FileSystem fs(user);
+               loadDKEKFile(user, password);
 
-}
+               auto wrappedDatabaseDEK = fs.getDBDEK();
 
-RawBuffer CKMLogic::removeUserData(uid_t user) {
-    int retCode = CKM_API_SUCCESS;
+               if (wrappedDatabaseDEK.empty()) {
+                       wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
+                       fs.saveDBDEK(wrappedDatabaseDEK);
+               }
 
-    if (m_accessControl.isSystemService(user))
-        user = SYSTEM_DB_UID;
+               RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
 
-    m_userDataMap.erase(user);
+               handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
+               handle.crypto = CryptoLogic();
 
-    FileSystem fs(user);
-    fs.removeUserData();
+               if (!m_accessControl.isSystemService(user)) {
+                       // remove data of removed apps during locked state
+                       ClientIdVector removedApps = fs.clearRemovedsApps();
 
-    return MessageBuffer::Serialize(retCode).Pop();
-}
+                       for (auto &app : removedApps) {
+                               handle.crypto.removeKey(app);
+                               handle.database.deleteKey(app);
+                       }
+               }
 
-int CKMLogic::changeUserPasswordHelper(uid_t user,
-                                       const Password &oldPassword,
-                                       const Password &newPassword)
-{
-    // do not allow to change system database password
-    if( m_accessControl.isSystemService(user) )
-        return CKM_API_ERROR_INPUT_PARAM;
+               if (user == SYSTEM_DB_UID && SsMigration::hasData())
+                       migrateSecureStorageData(false);
+               else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
+                       migrateSecureStorageData(true);
+
+               return CKM_API_SUCCESS;
+       });
 
-    loadDKEKFile(user, oldPassword);
-    saveDKEKFile(user, newPassword);
+       if (CKM_API_SUCCESS != retCode)
+               m_userDataMap.erase(user);
 
-    return CKM_API_SUCCESS;
+       return retCode;
 }
 
-RawBuffer CKMLogic::changeUserPassword(
-    uid_t user,
-    const Password &oldPassword,
-    const Password &newPassword)
+int CKMLogic::unlockSystemDB()
 {
-    int retCode = CKM_API_SUCCESS;
-    try
-    {
-        retCode = changeUserPasswordHelper(user, oldPassword, newPassword);
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    return MessageBuffer::Serialize(retCode).Pop();
+       return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
 }
 
-int CKMLogic::resetUserPasswordHelper(
-    uid_t user,
-    const Password &newPassword)
+UserData &CKMLogic::selectDatabase(const Credentials &cred,
+                                                                  const ClientId &owner)
 {
-    // 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;
+       // 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::resetUserPassword(
-    uid_t user,
-    const Password &newPassword)
+RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
 {
-    int retCode = CKM_API_SUCCESS;
-    try {
-        retCode = resetUserPasswordHelper(user, newPassword);
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    return MessageBuffer::Serialize(retCode).Pop();
-}
+       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;
 
-RawBuffer CKMLogic::removeApplicationData(const Label &smackLabel) {
-    int retCode = CKM_API_SUCCESS;
-
-    try {
-
-        if (smackLabel.empty()) {
-            retCode = CKM_API_ERROR_INPUT_PARAM;
-        } else {
-            UidVector uids = FileSystem::getUIDsFromDBFile();
-            for (auto userId : uids) {
-                if (0 == m_userDataMap.count(userId)) {
-                    FileSystem fs(userId);
-                    fs.addRemovedApp(smackLabel);
-                } else {
-                    auto &handle = m_userDataMap[userId];
-                    handle.crypto.removeKey(smackLabel);
-                    handle.database.deleteKey(smackLabel);
-                }
-            }
-        }
-
-    } catch (const DB::Crypto::Exception::InternalError &e) {
-        LogError("DB::Crypto couldn't remove data: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const DB::Crypto::Exception::TransactionError &e) {
-        LogError("DB::Crypto transaction failed with message " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    return MessageBuffer::Serialize(retCode).Pop();
+       return SerializeMessage(retCode);
 }
 
-int CKMLogic::checkSaveConditions(
-    const Credentials &cred,
-    UserData &handler,
-    const Name &name,
-    const Label &ownerLabel)
+RawBuffer CKMLogic::updateCCMode()
 {
-    // verify name and label are correct
-    if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
-        LogDebug("Invalid parameter passed to key-manager");
-        return CKM_API_ERROR_INPUT_PARAM;
-    }
-
-    // check if allowed to save using ownerLabel
-    int access_ec = m_accessControl.canSave(cred, ownerLabel);
-    if( access_ec != CKM_API_SUCCESS)
-    {
-        LogDebug("label " << cred.smackLabel << " can not save rows using label " << ownerLabel);
-        return access_ec;
-    }
-
-    // check if not a duplicate
-    if( handler.database.isNameLabelPresent(name, ownerLabel))
-        return CKM_API_ERROR_DB_ALIAS_EXISTS;
-
-    // encryption section
-    if (!handler.crypto.haveKey(ownerLabel))
-    {
-        RawBuffer got_key;
-        auto key_optional = handler.database.getKey(ownerLabel);
-        if(!key_optional) {
-            LogDebug("No Key in database found. Generating new one for label: " << ownerLabel);
-            got_key = handler.keyProvider.generateDEK(ownerLabel);
-            handler.database.saveKey(ownerLabel, got_key);
-        } else {
-            LogDebug("Key from DB");
-            got_key = *key_optional;
-        }
-
-        got_key = handler.keyProvider.getPureDEK(got_key);
-        handler.crypto.pushKey(ownerLabel, got_key);
-    }
-
-    return CKM_API_SUCCESS;
+       m_accessControl.updateCCMode();
+       return SerializeMessage(CKM_API_SUCCESS);
 }
 
-DB::Row CKMLogic::createEncryptedRow(
-    CryptoLogic &crypto,
-    const Name &name,
-    const Label &label,
-    const Crypto::Data &data,
-    const Policy &policy) const
+RawBuffer CKMLogic::lockUserKey(uid_t user)
 {
-    Crypto::GStore& store = m_decider.getStore(data.type, policy.extractable);
+       int retCode = CKM_API_SUCCESS;
+
+       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;
 
-    // do not encrypt data with password during cc_mode on
-    Token token = store.import(data, m_accessControl.isCCMode() ? "" : policy.password);
-    DB::Row row(std::move(token), name, label, static_cast<int>(policy.extractable));
-    crypto.encryptRow(row);
-    return row;
+       return SerializeMessage(retCode);
 }
 
-int CKMLogic::verifyBinaryData(Crypto::Data &input) const
+RawBuffer CKMLogic::removeUserData(uid_t user)
 {
-    Crypto::Data dummy;
-    return toBinaryData(input, dummy);
+       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);
 }
 
-int CKMLogic::toBinaryData(const Crypto::Data &input, Crypto::Data &output) const
+RawBuffer CKMLogic::changeUserPassword(
+       uid_t user,
+       const Password &oldPassword,
+       const Password &newPassword)
 {
-    // verify the data integrity
-    if (input.type.isKey())
-    {
-        KeyShPtr output_key;
-        if(input.type.isSKey())
-            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 = std::move(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 = std::move(Crypto::Data(input.type, cert->getDER()));
-    }
-    else
-        output = input;
-    // TODO: add here BINARY_DATA verification, i.e: max size etc.
-    return CKM_API_SUCCESS;
+       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;
+       }));
 }
 
-int CKMLogic::verifyAndSaveDataHelper(
-    const Credentials &cred,
-    const Name &name,
-    const Label &label,
-    const Crypto::Data &data,
-    const PolicySerializable &policy)
+RawBuffer CKMLogic::resetUserPassword(
+       uid_t user,
+       const Password &newPassword)
 {
-    int retCode = CKM_API_ERROR_UNKNOWN;
-
-    try {
-        // check if data is correct
-        Crypto::Data binaryData;
-        retCode = toBinaryData(data, binaryData);
-        if(retCode == CKM_API_SUCCESS)
-        {
-            retCode = saveDataHelper(cred, name, label, binaryData, policy);
-        }
-    } catch (const DB::Crypto::Exception::InternalError &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const DB::Crypto::Exception::TransactionError &e) {
-        LogError("DB::Crypto transaction failed with message " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-    return retCode;
+       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;
+       }));
 }
 
-int CKMLogic::getKeyForService(
-        const Credentials &cred,
-        const Name &name,
-        const Label &label,
-        const Password &pass,
-        Crypto::GObjShPtr &key)
+RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
 {
-    DB::Row row;
-    try {
-        // 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, label, pass, obj);
-        if (retCode == CKM_API_SUCCESS)
-            key = std::move(obj);
-        return retCode;
-    } catch (const DB::Crypto::Exception::Base &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        return CKM_API_ERROR_DB_ERROR;
-    } catch (const Exc::Exception &e) {
-        return e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        return CKM_API_ERROR_SERVER_ERROR;
-    }
+       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;
+       }));
 }
 
-RawBuffer CKMLogic::saveData(
-    const Credentials &cred,
-    int commandId,
-    const Name &name,
-    const Label &label,
-    const Crypto::Data &data,
-    const PolicySerializable &policy)
+int CKMLogic::verifyAndSaveDataHelper(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner,
+       const Crypto::Data &data,
+       const PolicySerializable &policy)
 {
-    int retCode = verifyAndSaveDataHelper(cred, name, label, data, policy);
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
-                                             commandId,
-                                             retCode,
-                                             static_cast<int>(data.type));
-    return response.Pop();
+       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::extractPKCS12Data(
-    CryptoLogic &crypto,
-    const Name &name,
-    const Label &ownerLabel,
-    const PKCS12Serializable &pkcs,
-    const PolicySerializable &keyPolicy,
-    const PolicySerializable &certPolicy,
-    DB::RowVector &output) const
+int CKMLogic::getKeyForService(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner,
+       const Password &pass,
+       Crypto::GObjShPtr &key)
 {
-    // private key is mandatory
-    if( !pkcs.getKey() )
-        return CKM_API_ERROR_INVALID_FORMAT;
-    Key* keyPtr = pkcs.getKey().get();
-    Crypto::Data keyData(DataType(keyPtr->getType()), keyPtr->getDER());
-    int retCode = verifyBinaryData(keyData);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
-    output.push_back(createEncryptedRow(crypto, name, ownerLabel, keyData, keyPolicy));
-
-    // certificate is mandatory
-    if( !pkcs.getCertificate() )
-        return CKM_API_ERROR_INVALID_FORMAT;
-    Crypto::Data certData(DataType::CERTIFICATE, pkcs.getCertificate().get()->getDER());
-    retCode = verifyBinaryData(certData);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
-    output.push_back(createEncryptedRow(crypto, name, ownerLabel, certData, certPolicy));
-
-    // CA cert chain
-    unsigned int cert_index = 0;
-    for(const auto & ca : pkcs.getCaCertificateShPtrVector())
-    {
-        Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++), ca->getDER());
-        int retCode = verifyBinaryData(caCertData);
-        if(retCode != CKM_API_SUCCESS)
-            return retCode;
-
-        output.push_back(createEncryptedRow(crypto, name, ownerLabel, caCertData, certPolicy));
-    }
-
-    return CKM_API_SUCCESS;
+       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::savePKCS12(
-    const Credentials &cred,
-    int commandId,
-    const Name &name,
-    const Label &label,
-    const PKCS12Serializable &pkcs,
-    const PolicySerializable &keyPolicy,
-    const PolicySerializable &certPolicy)
+RawBuffer CKMLogic::saveData(
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner,
+       const Crypto::Data &data,
+       const PolicySerializable &policy)
 {
-    int retCode = CKM_API_ERROR_UNKNOWN;
-    try {
-        retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy);
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const DB::Crypto::Exception::InternalError &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const DB::Crypto::Exception::TransactionError &e) {
-        LogError("DB::Crypto transaction failed with message " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE_PKCS12),
-                                             commandId,
-                                             retCode);
-    return response.Pop();
+       int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
+       return SerializeMessage(msgId, retCode, data.type);
 }
 
-
-int CKMLogic::removeDataHelper(
-        const Credentials &cred,
-        const Name &name,
-        const Label &label)
+RawBuffer CKMLogic::savePKCS12(
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner,
+       const PKCS12Serializable &pkcs,
+       const PolicySerializable &keyPolicy,
+       const PolicySerializable &certPolicy)
 {
-    auto &handler = selectDatabase(cred, label);
-
-    // use client label if not explicitly provided
-    const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
-    if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
-        LogDebug("Invalid label or name format");
-        return CKM_API_ERROR_INPUT_PARAM;
-    }
-
-    DB::Crypto::Transaction transaction(&handler.database);
-
-    // read and check permissions
-    PermissionMaskOptional permissionRowOpt =
-            handler.database.getPermissionRow(name, ownerLabel, cred.smackLabel);
-    int retCode = m_accessControl.canDelete(cred,
-                        PermissionForLabel(cred.smackLabel, permissionRowOpt));
-    if(retCode != CKM_API_SUCCESS)
-    {
-        LogWarning("access control check result: " << retCode);
-        return retCode;
-    }
-
-    // get all matching rows
-    DB::RowVector rows;
-    handler.database.getRows(name, ownerLabel, DataType::DB_FIRST, DataType::DB_LAST, rows);
-    if (rows.empty()) {
-        LogDebug("No row for given name and label");
-        return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
-    }
-
-    // load app key if needed
-    retCode = loadAppKey(handler, rows.front().ownerLabel);
-    if(CKM_API_SUCCESS != retCode)
-        return retCode;
-
-    // destroy it in store
-    for(auto& r : rows) {
-        try {
-            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
-    handler.database.deleteRow(name, ownerLabel);
-    transaction.commit();
-
-    return CKM_API_SUCCESS;
+       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(
-    const Credentials &cred,
-    int commandId,
-    const Name &name,
-    const Label &label)
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner)
 {
-    int retCode = CKM_API_ERROR_UNKNOWN;
-
-    try
-    {
-        retCode = removeDataHelper(cred, name, label);
-    }
-    catch (const Exc::Exception &e)
-    {
-        retCode = e.error();
-    }
-    catch (const CKM::Exception &)
-    {
-        LogError("Error in deleting row!");
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
-                                             commandId,
-                                             retCode);
-    return response.Pop();
+       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::readSingleRow(const Name &name,
-                            const Label &ownerLabel,
-                            DataType dataType,
-                            DB::Crypto & database,
-                            DB::Row &row)
+
+int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
+               const DB::Row &row,
+               bool exportFlag,
+               const PermissionMask& permission)
 {
-    DB::Crypto::RowOptional row_optional;
-    if (dataType.isKey())
-    {
-        // read all key types
-        row_optional = database.getRow(name,
-                                         ownerLabel,
-                                         DataType::DB_KEY_FIRST,
-                                         DataType::DB_KEY_LAST);
-    } else {
-        // read anything else
-        row_optional = database.getRow(name,
-                                         ownerLabel,
-                                         dataType);
-    }
-
-    if(!row_optional) {
-        LogDebug("No row for given name, label and type");
-        return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
-    } else {
-        row = *row_optional;
-    }
-
-    return CKM_API_SUCCESS;
-}
+       if (exportFlag)
+               return m_accessControl.canExport(accessorCred, row, permission);
 
+       return m_accessControl.canRead(accessorCred, permission);
+}
 
-int CKMLogic::readMultiRow(const Name &name,
-                           const Label &ownerLabel,
-                           DataType dataType,
-                           DB::Crypto & database,
-                           DB::RowVector &output)
+void CKMLogic::decryptRow(
+       UserData &handler,
+       DB::Row &row,
+       const Password &password,
+       const RawBuffer &hash)
 {
-    if (dataType.isKey())
-    {
-        // read all key types
-        database.getRows(name,
-                          ownerLabel,
-                          DataType::DB_KEY_FIRST,
-                          DataType::DB_KEY_LAST,
-                          output);
-    }
-    else if (dataType.isChainCert())
-    {
-        // read all key types
-        database.getRows(name,
-                         ownerLabel,
-                         DataType::DB_CHAIN_FIRST,
-                         DataType::DB_CHAIN_LAST,
-                         output);
-    }
-    else
-    {
-        // read anything else
-        database.getRows(name,
-                         ownerLabel,
-                         dataType,
-                         output);
-    }
-
-    if(!output.size()) {
-        LogDebug("No row for given name, label and type");
-        return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
-    }
-
-    return CKM_API_SUCCESS;
+       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);
+       }
 }
 
-int CKMLogic::checkDataPermissionsHelper(const Credentials &cred,
-                                         const Name &name,
-                                         const Label &ownerLabel,
-                                         const Label &accessorLabel,
-                                         const DB::Row &row,
-                                         bool exportFlag,
-                                         DB::Crypto & database)
+Crypto::GObjUPtr CKMLogic::rowToObject(
+       UserData &handler,
+       DB::Row row,
+       const Password &password,
+       const RawBuffer &hash)
 {
-    PermissionMaskOptional permissionRowOpt =
-            database.getPermissionRow(name, ownerLabel, accessorLabel);
+       decryptRow(handler, row, password, hash);
 
-    if(exportFlag)
-        return m_accessControl.canExport(cred, row, PermissionForLabel(accessorLabel, permissionRowOpt));
-    return m_accessControl.canRead(cred, PermissionForLabel(accessorLabel, permissionRowOpt));
+       return decryptedRowToObj(row, password);
 }
 
-Crypto::GObjUPtr CKMLogic::rowToObject(
-    UserData& handler,
-    DB::Row row,
-    const Password& password)
+int CKMLogic::readDataHelper(
+       bool exportFlag,
+       const Credentials &cred,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password,
+       Crypto::GObjUPtrVector &objs)
 {
-    Crypto::GStore& store = m_decider.getStore(row);
+       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);
 
-    Password pass = m_accessControl.isCCMode() ? "" : password;
+       // check access rights
+       retCode = checkDataPermissionsHelper(cred, firstRow, exportFlag, permission);
+       if (CKM_API_SUCCESS != retCode)
+               return retCode;
 
-    // decrypt row
-    Crypto::GObjUPtr obj;
-    if(CryptoLogic::getSchemeVersion(row.encryptionScheme) == CryptoLogic::ENCRYPTION_V2) {
-        handler.crypto.decryptRow(Password(), row);
+       // for multiple objects add type as hash input (see pkcs12)
+       bool multiple = rows.size() > 1;
 
-        obj = store.getObject(row, pass);
-    } else {
-        // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
-        handler.crypto.decryptRow(pass, row);
-        // destroy it in store
-        store.destroy(row);
+       RawBuffer digest;
 
-        // import it to store with new scheme: data -> pass(data)
-        Token token = store.import(Crypto::Data(row.dataType, row.data), pass);
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-        // get it from the store (it can be different than the data we imported into store)
-        obj = store.getObject(token, pass);
+       // 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);
 
-        // update row with new token
-        *static_cast<Token*>(&row) = std::move(token);
+               if (digest.empty())
+                       return CKM_API_ERROR_HASH_ERROR;
 
-        // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
-        handler.crypto.encryptRow(row);
+               objs.push_back(rowToObject(dbOp.handler(), std::move(row), password, digest));
+       }
 
-        // update it in db
-        handler.database.updateRow(row);
-    }
-    return obj;
+       // 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 Label &label,
-    const Password &password,
-    Crypto::GObjUPtrVector &objs)
+       bool exportFlag,
+       const Credentials &cred,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password,
+       Crypto::GObjUPtr &obj)
 {
-    auto &handler = selectDatabase(cred, label);
+       DataType objDataType;
+       return readDataHelper(exportFlag, cred, dataType, name, owner,
+                                                 password, obj, objDataType);
+}
 
-    // use client label if not explicitly provided
-    const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+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;
 
-    if (!isNameValid(name) || !isLabelValid(ownerLabel))
-        return CKM_API_ERROR_INPUT_PARAM;
+       retCode = readSingleRow(name, owner, dataType, dbOp.database(), row);
+       if (CKM_API_SUCCESS != retCode)
+               return retCode;
 
-    // read rows
-    DB::Crypto::Transaction transaction(&handler.database);
-    DB::RowVector rows;
-    int retCode = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
-    if(CKM_API_SUCCESS != retCode)
-        return retCode;
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-    // all read rows belong to the same owner
-    DB::Row & firstRow = rows.at(0);
+       objDataType = row.dataType;
 
-    // check access rights
-    retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database);
-    if(CKM_API_SUCCESS != retCode)
-        return retCode;
+       // check access rights
+       retCode = checkDataPermissionsHelper(cred, row, exportFlag, permission);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-    // load app key if needed
-    retCode = loadAppKey(handler, firstRow.ownerLabel);
-    if(CKM_API_SUCCESS != retCode)
-        return retCode;
+       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
+       if (digest.empty())
+               return CKM_API_ERROR_HASH_ERROR;
 
-    // decrypt row
-    for(auto &row : rows)
-        objs.push_back(rowToObject(handler, std::move(row), password));
-    // rowToObject may modify db
-    transaction.commit();
+       decryptRow(dbOp.handler(), row, password, digest);
 
-    return CKM_API_SUCCESS;
+       // decryptRow may modify db
+       dbOp.transaction().commit();
+
+       return CKM_API_SUCCESS;
 }
 
-int CKMLogic::readDataHelper(
-    bool exportFlag,
-    const Credentials &cred,
-    DataType dataType,
-    const Name &name,
-    const Label &label,
-    const Password &password,
-    Crypto::GObjUPtr &obj)
+Crypto::GObjUPtr CKMLogic::decryptedRowToObj(const DB::Row& row, const Password &password)
 {
-    DataType objDataType;
-    return readDataHelper(exportFlag, cred, dataType, name, label, password, obj, objDataType);
+       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 Label &label,
-    const Password &password,
-    Crypto::GObjUPtr &obj,
-    DataType& objDataType)
+       bool exportFlag,
+       const Credentials &cred,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password,
+       Crypto::GObjUPtr &obj,
+       DataType &objDataType)
 {
-    auto &handler = selectDatabase(cred, label);
+       DB::Row row;
+       int retCode = readRowHelper(exportFlag, cred, dataType, name, owner, password, row, objDataType);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-    // use client label if not explicitly provided
-    const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+       obj = decryptedRowToObj(row, password);
 
-    if (!isNameValid(name) || !isLabelValid(ownerLabel))
-        return CKM_API_ERROR_INPUT_PARAM;
+       return CKM_API_SUCCESS;
+}
 
-    // read row
-    DB::Crypto::Transaction transaction(&handler.database);
-    DB::Row row;
-    int retCode = readSingleRow(name, ownerLabel, dataType, handler.database, row);
-    if(CKM_API_SUCCESS != retCode)
-        return retCode;
+RawBuffer CKMLogic::getData(
+       const Credentials &cred,
+       int msgId,
+       DataType dataType,
+       const Name &name,
+       const ClientId &owner,
+       const Password &password)
+{
+       RawBuffer rowData;
+       DataType objDataType;
 
-    objDataType = row.dataType;
+       int retCode = tryRet([&] {
+               Crypto::GObjUPtr obj;
+               int retCode2 = readDataHelper(true, cred, dataType, name, owner,
+                                                                         password, obj, objDataType);
 
-    // check access rights
-    retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
-    if(CKM_API_SUCCESS != retCode)
-        return retCode;
+               if (retCode2 == CKM_API_SUCCESS)
+                       rowData = obj->getBinary();
 
-    // load app key if needed
-    retCode = loadAppKey(handler, row.ownerLabel);
-    if(CKM_API_SUCCESS != retCode)
-        return retCode;
+               return retCode2;
+       });
 
-    obj = rowToObject(handler, std::move(row), password);
-    // rowToObject may modify db
-    transaction.commit();
+       if (CKM_API_SUCCESS != retCode)
+               rowData.clear();
 
-    return CKM_API_SUCCESS;
+       return SerializeMessage(msgId, retCode, objDataType, rowData);
 }
 
-RawBuffer CKMLogic::getData(
-    const Credentials &cred,
-    int commandId,
-    DataType dataType,
-    const Name &name,
-    const Label &label,
-    const Password &password)
+RawBuffer CKMLogic::getDataProtectionStatus(
+               const Credentials &cred,
+               int msgId,
+               DataType dataType,
+               const Name &name,
+               const ClientId &owner)
 {
-    int retCode = CKM_API_SUCCESS;
-    DB::Row row;
-    DataType objDataType;
-
-    try {
-        Crypto::GObjUPtr obj;
-        retCode = readDataHelper(true, cred, dataType, name, label, password, obj, objDataType);
-        if(retCode == CKM_API_SUCCESS)
-            row.data = std::move(obj->getBinary());
-    } catch (const DB::Crypto::Exception::Base &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    if (CKM_API_SUCCESS != retCode) {
-        row.data.clear();
-        row.dataType = dataType;
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
-                                             commandId,
-                                             retCode,
-                                             static_cast<int>(objDataType),
-                                             row.data);
-    return response.Pop();
-}
+       bool status = false;
+       DataType objDataType;
+       Password password;
 
-int CKMLogic::getPKCS12Helper(
-    const Credentials &cred,
-    const Name &name,
-    const Label &label,
-    const Password &keyPassword,
-    const Password &certPassword,
-    KeyShPtr & privKey,
-    CertificateShPtr & cert,
-    CertificateShPtrVector & caChain)
-{
-    int retCode;
-
-    // read private key (mandatory)
-    Crypto::GObjUPtr keyObj;
-    retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, label, keyPassword, keyObj);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
-    privKey = CKM::Key::create(keyObj->getBinary());
-
-    // read certificate (mandatory)
-    Crypto::GObjUPtr certObj;
-    retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label, certPassword, certObj);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
-    cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
-
-    // read CA cert chain (optional)
-    Crypto::GObjUPtrVector caChainObjs;
-    retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label, certPassword, caChainObjs);
-    if(retCode != CKM_API_SUCCESS &&
-       retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
-        return retCode;
-    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)
-        retCode = CKM_API_SUCCESS;
-
-    return retCode;
+       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 commandId,
-        const Name &name,
-        const Label &label,
-        const Password &keyPassword,
-        const Password &certPassword)
+       const Credentials &cred,
+       int msgId,
+       const Name &name,
+       const ClientId &owner,
+       const Password &keyPassword,
+       const Password &certPassword)
 {
-    int retCode = CKM_API_ERROR_UNKNOWN;
-
-    PKCS12Serializable output;
-    try {
-        KeyShPtr privKey;
-        CertificateShPtr cert;
-        CertificateShPtrVector caChain;
-        retCode = getPKCS12Helper(cred, name, label, keyPassword, certPassword, privKey, cert, caChain);
-
-        // prepare response
-        if(retCode == CKM_API_SUCCESS)
-            output = PKCS12Serializable(privKey, cert, caChain);
-    } catch (const DB::Crypto::Exception::Base &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_PKCS12),
-                                             commandId,
-                                             retCode,
-                                             output);
-    return response.Pop();
+       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::getDataListHelper(const Credentials &cred,
-                                const DataType dataType,
-                                LabelNameVector &labelNameVector)
+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;
-
-        Try {
-            LabelNameVector tmpVector;
-            if (dataType.isKey()) {
-                // list all key types
-                database.listNames(cred.smackLabel,
-                                   tmpVector,
-                                   DataType::DB_KEY_FIRST,
-                                   DataType::DB_KEY_LAST);
-            } else {
-                // list anything else
-                database.listNames(cred.smackLabel,
-                                   tmpVector,
-                                   dataType);
-            }
-            labelNameVector.insert(labelNameVector.end(), tmpVector.begin(), tmpVector.end());
-            retCode = CKM_API_SUCCESS;
-        }
-        Catch (CKM::Exception) {
-            LogError("Failed to get names");
-            retCode = CKM_API_ERROR_DB_ERROR;
-        }
-    }
-    return retCode;
+       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(
-    const Credentials &cred,
-    int commandId,
-    DataType dataType)
+       const Credentials &cred,
+       int msgId,
+       DataType dataType)
 {
-    LabelNameVector systemVector;
-    LabelNameVector userVector;
-    LabelNameVector labelNameVector;
-
-    int retCode = unlockSystemDB();
-    if (CKM_API_SUCCESS == retCode)
-    {
-        // system database
-        if (m_accessControl.isSystemService(cred))
-        {
-            // lookup system DB
-            retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
-                                                    OWNER_ID_SYSTEM),
-                                        dataType,
-                                        systemVector);
-        }
-        else
-        {
-            // user - lookup system, then client DB
-            retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
-                                                    cred.smackLabel),
-                                        dataType,
-                                        systemVector);
-
-            // private database
-            if(retCode == CKM_API_SUCCESS)
-            {
-                retCode = getDataListHelper(cred,
-                                            dataType,
-                                            userVector);
-            }
-        }
-    }
-
-    if(retCode == CKM_API_SUCCESS)
-    {
-        labelNameVector.insert(labelNameVector.end(), systemVector.begin(), systemVector.end());
-        labelNameVector.insert(labelNameVector.end(), userVector.begin(), userVector.end());
-    }
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_LIST),
-                                             commandId,
-                                             retCode,
-                                             static_cast<int>(dataType),
-                                             labelNameVector);
-    return response.Pop();
+       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));
 }
 
-int CKMLogic::saveDataHelper(
-    const Credentials &cred,
-    const Name &name,
-    const Label &label,
-    const Crypto::Data &data,
-    const PolicySerializable &policy)
+int CKMLogic::importInitialData(
+       const Name &name,
+       const Crypto::Data &data,
+       const Crypto::EncryptionParams &encParams,
+       const Policy &policy)
 {
-    auto &handler = selectDatabase(cred, label);
+       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;
+       }
+}
 
-    // use client label if not explicitly provided
-    const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
-    if( m_accessControl.isSystemService(cred) && ownerLabel.compare(OWNER_ID_SYSTEM)!=0)
-        return CKM_API_ERROR_INPUT_PARAM;
+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;
+}
 
-    // check if save is possible
-    DB::Crypto::Transaction transaction(&handler.database);
-    int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
+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);
 
-    // save the data
-    DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, ownerLabel, data, policy);
-    handler.database.saveRow(encryptedRow);
+       if (cred.client.empty() || !isClientValid(cred.client) ||
+               !isNameValid(name) || !isClientValid(owner))
+               return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
 
-    transaction.commit();
-    return CKM_API_SUCCESS;
+       return std::make_tuple(std::move(op), CKM_API_SUCCESS);
 }
 
-int CKMLogic::saveDataHelper(
-    const Credentials &cred,
-    const Name &name,
-    const Label &label,
-    const PKCS12Serializable &pkcs,
-    const PolicySerializable &keyPolicy,
-    const PolicySerializable &certPolicy)
+std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
 {
-    auto &handler = selectDatabase(cred, label);
-
-    // use client label if not explicitly provided
-    const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
-    if( m_accessControl.isSystemService(cred) && ownerLabel.compare(OWNER_ID_SYSTEM)!=0)
-        return CKM_API_ERROR_INPUT_PARAM;
-
-    // check if save is possible
-    DB::Crypto::Transaction transaction(&handler.database);
-    int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
-
-    // extract and encrypt the data
-    DB::RowVector encryptedRows;
-    retCode = extractPKCS12Data(handler.crypto, name, ownerLabel, pkcs, keyPolicy, certPolicy, encryptedRows);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
-
-    // save the data
-    handler.database.saveRows(name, ownerLabel, encryptedRows);
-    transaction.commit();
-
-    return CKM_API_SUCCESS;
-}
+       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);
+}
 
-int CKMLogic::createKeyAESHelper(
-    const Credentials &cred,
-    const int size,
-    const Name &name,
-    const Label &label,
-    const PolicySerializable &policy)
+std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
 {
-    auto &handler = selectDatabase(cred, label);
-
-    // use client label if not explicitly provided
-    const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
-    if( m_accessControl.isSystemService(cred) && ownerLabel.compare(OWNER_ID_SYSTEM)!=0)
-        return CKM_API_ERROR_INPUT_PARAM;
+       auto [dbOp, retCode] = begin(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return std::make_tuple(std::move(dbOp), retCode);
 
-    // check if save is possible
-    DB::Crypto::Transaction transaction(&handler.database);
-    int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
+       retCode = dbOp.loadAppKey(false);
+       if (retCode != CKM_API_SUCCESS)
+               return std::make_tuple(std::move(dbOp), retCode);
 
-    // create key in store
-    CryptoAlgorithm keyGenAlgorithm;
-    keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
-    keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
-    Token key = m_decider.getStore(DataType::KEY_AES, policy.extractable).generateSKey(keyGenAlgorithm, policy.password);
+       // 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);
+       }
 
-    // save the data
-    DB::Row row(std::move(key), name, ownerLabel, static_cast<int>(policy.extractable));
-    handler.crypto.encryptRow(row);
+       if (dbOp.database().isNameOwnerPresent(name, owner))
+               retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
 
-    handler.database.saveRow(row);
-
-    transaction.commit();
-    return CKM_API_SUCCESS;
+       return std::make_tuple(std::move(dbOp), retCode);
 }
 
-int CKMLogic::createKeyPairHelper(
-    const Credentials &cred,
-    const CryptoAlgorithmSerializable & keyGenParams,
-    const Name &namePrivate,
-    const Label &labelPrivate,
-    const Name &namePublic,
-    const Label &labelPublic,
-    const PolicySerializable &policyPrivate,
-    const PolicySerializable &policyPublic)
+std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
 {
-    auto &handlerPriv = selectDatabase(cred, labelPrivate);
-    auto &handlerPub = selectDatabase(cred, labelPublic);
-
-    AlgoType keyType = AlgoType::RSA_GEN;
-    if(!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
-        ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
-    DataType dt(keyType);
-    if(!dt.isKey())
-        ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
-
-    // use client label if not explicitly provided
-    const Label &ownerLabelPrv = labelPrivate.empty() ? cred.smackLabel : labelPrivate;
-    if( m_accessControl.isSystemService(cred) && ownerLabelPrv.compare(OWNER_ID_SYSTEM)!=0)
-        return CKM_API_ERROR_INPUT_PARAM;
-    const Label &ownerLabelPub = labelPublic.empty() ? cred.smackLabel : labelPublic;
-    if( m_accessControl.isSystemService(cred) && ownerLabelPub.compare(OWNER_ID_SYSTEM)!=0)
-        return CKM_API_ERROR_INPUT_PARAM;
-
-    bool exportable = policyPrivate.extractable || policyPublic.extractable;
-    TokenPair keys = m_decider.getStore(dt, exportable).generateAKey(keyGenParams,
-                                                                     policyPrivate.password,
-                                                                     policyPublic.password);
-
-    DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
-    // in case the same database is used for private and public - the second
-    // transaction will not be executed
-    DB::Crypto::Transaction transactionPub(&handlerPub.database);
-
-    int retCode;
-    retCode = checkSaveConditions(cred, handlerPriv, namePrivate, ownerLabelPrv);
-    if (CKM_API_SUCCESS != retCode)
-        return retCode;
-
-    retCode = checkSaveConditions(cred, handlerPub, namePublic, ownerLabelPub);
-    if (CKM_API_SUCCESS != retCode)
-        return retCode;
-
-    // save the data
-    DB::Row rowPrv(std::move(keys.first), namePrivate, ownerLabelPrv, static_cast<int>(policyPrivate.extractable));
-    handlerPriv.crypto.encryptRow(rowPrv);
-    handlerPriv.database.saveRow(rowPrv);
-
-    DB::Row rowPub(std::move(keys.second), namePublic, ownerLabelPub, static_cast<int>(policyPublic.extractable));
-    handlerPub.crypto.encryptRow(rowPub);
-    handlerPub.database.saveRow(rowPub);
-
-    transactionPub.commit();
-    transactionPriv.commit();
-    return CKM_API_SUCCESS;
+       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 commandId,
-    const CryptoAlgorithmSerializable & keyGenParams,
-    const Name &namePrivate,
-    const Label &labelPrivate,
-    const Name &namePublic,
-    const Label &labelPublic,
-    const PolicySerializable &policyPrivate,
-    const PolicySerializable &policyPublic)
+       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)
 {
-    int retCode = CKM_API_SUCCESS;
-
-    try {
-        retCode = createKeyPairHelper(
-                        cred,
-                        keyGenParams,
-                        namePrivate,
-                        labelPrivate,
-                        namePublic,
-                        labelPublic,
-                        policyPrivate,
-                        policyPublic);
-    } catch(const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (DB::Crypto::Exception::TransactionError &e) {
-        LogDebug("DB::Crypto error: transaction error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (DB::Crypto::Exception::InternalError &e) {
-        LogDebug("DB::Crypto internal error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_PAIR),
-                                    commandId, retCode).Pop();
+       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 commandId,
-    const int size,
-    const Name &name,
-    const Label &label,
-    const PolicySerializable &policy)
+       const Credentials &cred,
+       int msgId,
+       const int size,
+       const Name &name,
+       const ClientId &owner,
+       const PolicySerializable &policy)
 {
-    int retCode = CKM_API_SUCCESS;
-
-    try {
-        retCode = createKeyAESHelper(cred, size, name, label, policy);
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (std::invalid_argument &e) {
-        LogDebug("invalid argument error: " << e.what());
-        retCode = CKM_API_ERROR_INPUT_PARAM;
-    } catch (DB::Crypto::Exception::TransactionError &e) {
-        LogDebug("DB::Crypto error: transaction error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (DB::Crypto::Exception::InternalError &e) {
-        LogDebug("DB::Crypto internal error: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const CKM::Exception &e) {
-        LogError("CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_AES),
-                                    commandId, retCode).Pop();
+       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 LabelNameVector &labelNameVector,
-        CertificateImplVector &certVector)
+       const Credentials &cred,
+       const OwnerNameVector &ownerNameVector,
+       CertificateImplVector &certVector)
 {
-    DB::Row row;
-    for (auto &i: labelNameVector) {
-        // certificates can't be protected with custom user password
-        Crypto::GObjUPtr obj;
-        int ec;
-        ec = readDataHelper(true,
-                            cred,
-                            DataType::CERTIFICATE,
-                            i.second,
-                            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,
-                            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;
+       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)
+       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;
+       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 LabelNameVector &untrusted,
-        const LabelNameVector &trusted,
-        bool useTrustedSystemCertificates,
-        RawBufferVector &chainRawVector)
+       const Credentials &cred,
+       const CertificateImpl &cert,
+       const OwnerNameVector &untrusted,
+       const OwnerNameVector &trusted,
+       bool useTrustedSystemCertificates,
+       RawBufferVector &chainRawVector)
 {
-    CertificateImplVector untrustedCertVector;
-    CertificateImplVector trustedCertVector;
-    CertificateImplVector chainVector;
-    DB::Row row;
-
-    if (cert.empty())
-        return CKM_API_ERROR_INPUT_PARAM;
-
-    int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
-    if (retCode != CKM_API_SUCCESS)
-        return retCode;
-    retCode = readCertificateHelper(cred, trusted, trustedCertVector);
-    if (retCode != CKM_API_SUCCESS)
-        return retCode;
-
-    CertificateStore store;
-    retCode = store.verifyCertificate(cert,
-                                      untrustedCertVector,
-                                      trustedCertVector,
-                                      useTrustedSystemCertificates,
-                                      m_accessControl.isCCMode(),
-                                      chainVector);
-    if (retCode != CKM_API_SUCCESS)
-        return retCode;
-
-    for (auto &i: chainVector)
-        chainRawVector.push_back(i.getDER());
-
-    return CKM_API_SUCCESS;
+       CertificateImplVector untrustedCertVector;
+       CertificateImplVector trustedCertVector;
+       CertificateImplVector chainVector;
+
+       if (cert.empty())
+               return CKM_API_ERROR_INPUT_PARAM;
+
+       int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
+
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       retCode = readCertificateHelper(cred, trusted, trustedCertVector);
+
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       CertificateStore store;
+       retCode = store.verifyCertificate(cert,
+                                                                         untrustedCertVector,
+                                                                         trustedCertVector,
+                                                                         useTrustedSystemCertificates,
+                                                                         m_accessControl.isCCMode(),
+                                                                         chainVector);
+
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       for (auto &i : chainVector)
+               chainRawVector.push_back(i.getDER());
+
+       return CKM_API_SUCCESS;
 }
 
 RawBuffer CKMLogic::getCertificateChain(
-    const Credentials & /*cred*/,
-    int commandId,
-    const RawBuffer &certificate,
-    const RawBufferVector &untrustedCertificates,
-    const RawBufferVector &trustedCertificates,
-    bool useTrustedSystemCertificates)
+       const Credentials & /*cred*/,
+       int msgId,
+       const RawBuffer &certificate,
+       const RawBufferVector &untrustedCertificates,
+       const RawBufferVector &trustedCertificates,
+       bool useTrustedSystemCertificates)
 {
-    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 DB::Crypto::Exception::Base &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const std::exception& e) {
-        LogError("STD exception " << e.what());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    } catch (...) {
-        LogError("Unknown error.");
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_CERT),
-                                             commandId,
-                                             retCode,
-                                             chainRawVector);
-    return response.Pop();
+       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);
 }
 
 RawBuffer CKMLogic::getCertificateChain(
-    const Credentials &cred,
-    int commandId,
-    const RawBuffer &certificate,
-    const LabelNameVector &untrustedCertificates,
-    const LabelNameVector &trustedCertificates,
-    bool useTrustedSystemCertificates)
+       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 DB::Crypto::Exception::Base &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } 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.");
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_ALIAS),
-                                             commandId,
-                                             retCode,
-                                             chainRawVector);
-    return response.Pop();
+       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(
-        const Credentials &cred,
-        int commandId,
-        const Name &privateKeyName,
-        const Label & ownerLabel,
-        const Password &password,           // password for private_key
-        const RawBuffer &message,
-        const CryptoAlgorithm &cryptoAlg)
+       const Credentials &cred,
+       int msgId,
+       const Name &privateKeyName,
+       const ClientId &owner,
+       const Password &password,           // password for private_key
+       const RawBuffer &message,
+       const CryptoAlgorithm &cryptoAlg)
 {
-    DB::Row row;
-    RawBuffer signature;
-
-    int retCode = CKM_API_SUCCESS;
-
-    try {
-        Crypto::GObjUPtr obj;
-        retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, obj);
-        if(retCode == CKM_API_SUCCESS) {
-            signature = obj->sign(cryptoAlg, message);
-        }
-    } catch (const DB::Crypto::Exception::Base &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const CKM::Exception &e) {
-        LogError("Unknown CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_SIGNATURE),
-                                             commandId,
-                                             retCode,
-                                             signature);
-    return response.Pop();
+       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(
-        const Credentials &cred,
-        int commandId,
-        const Name &publicKeyOrCertName,
-        const Label & ownerLabel,
-        const Password &password,           // password for public_key (optional)
-        const RawBuffer &message,
-        const RawBuffer &signature,
-        const CryptoAlgorithm &params)
+       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)
 {
-    int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
-
-    try {
-        DB::Row row;
-
-        // 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;
-        retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, obj);
-        if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
-            retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, obj);
-        }
-
-        if (retCode == CKM_API_SUCCESS) {
-            retCode = obj->verify(params, message, signature);
-        }
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } catch (const DB::Crypto::Exception::Base &e) {
-        LogError("DB::Crypto failed with message: " << e.GetMessage());
-        retCode = CKM_API_ERROR_DB_ERROR;
-    } catch (const CKM::Exception &e) {
-        LogError("Unknown CKM::Exception: " << e.GetMessage());
-        retCode = CKM_API_ERROR_SERVER_ERROR;
-    }
-
-    auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::VERIFY_SIGNATURE),
-                                             commandId,
-                                             retCode);
-    return response.Pop();
+       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;
+       }));
 }
 
 int CKMLogic::setPermissionHelper(
-        const Credentials &cred,                // who's the client
-        const Name &name,
-        const Label &label,                     // who's the owner
-        const Label &accessorLabel,             // who will get the access
-        const PermissionMask permissionMask)
+       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 &handler = selectDatabase(cred, label);
-
-    // we don't know the client
-    if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel))
-        return CKM_API_ERROR_INPUT_PARAM;
-
-    // use client label if not explicitly provided
-    const Label& ownerLabel = label.empty() ? cred.smackLabel : label;
+       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;
+}
 
-    // verify name and label are correct
-    if (!isNameValid(name) || !isLabelValid(ownerLabel) || !isLabelValid(accessorLabel))
-        return CKM_API_ERROR_INPUT_PARAM;
+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);
+       }));
+}
 
-    // currently we don't support modification of owner's permissions to his own rows
-    if (ownerLabel==accessorLabel)
-        return CKM_API_ERROR_INPUT_PARAM;
+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;
+       }));
+}
 
-    // system database does not support write/remove permissions
-    if ((0 == ownerLabel.compare(OWNER_ID_SYSTEM)) &&
-        (permissionMask & Permission::REMOVE))
-        return CKM_API_ERROR_INPUT_PARAM;
+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;
 
-    // can the client modify permissions to owner's row?
-    int retCode = m_accessControl.canModify(cred, ownerLabel);
-    if(retCode != CKM_API_SUCCESS)
-        return retCode;
+               auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, keyName, keyOwner);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
 
-    DB::Crypto::Transaction transaction(&handler.database);
+               retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
+                                                               wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
 
-    if( !handler.database.isNameLabelPresent(name, ownerLabel) )
-        return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+               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;
+               }
 
-    // removing non-existing permissions: fail
-    if(permissionMask == Permission::NONE)
-    {
-        if(!handler.database.getPermissionRow(name, ownerLabel, accessorLabel))
-            return CKM_API_ERROR_INPUT_PARAM;
-    }
+               Token token = wrappingKey->unwrap(params,
+                                                                                 Crypto::Data(keyType, std::move(wrappedKey)),
+                                                                                 policy.password,
+                                                                                 digest);
 
-    // set permissions to the row owned by ownerLabel for accessorLabel
-    handler.database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
-    transaction.commit();
+               dbOp.finalize(std::move(token), policy);
 
-    return CKM_API_SUCCESS;
+               return retCode;
+       }));
 }
 
-RawBuffer CKMLogic::setPermission(
-        const Credentials &cred,
-        const int command,
-        const int msgID,
-        const Name &name,
-        const Label &label,
-        const Label &accessorLabel,
-        const PermissionMask permissionMask)
+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)
 {
-    int retCode;
-    Try {
-        retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
-    } catch (const Exc::Exception &e) {
-        retCode = e.error();
-    } Catch (CKM::Exception) {
-        LogError("Error in set row!");
-        retCode = CKM_API_ERROR_DB_ERROR;
-    }
-
-    return MessageBuffer::Serialize(command, msgID, retCode).Pop();
+       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);
 }
 
-int CKMLogic::loadAppKey(UserData& handle, const Label& appLabel)
+RawBuffer CKMLogic::getBackendInfo(const int msgID, BackendId backend)
 {
-    if (!handle.crypto.haveKey(appLabel)) {
-        RawBuffer key;
-        auto key_optional = handle.database.getKey(appLabel);
-        if(!key_optional) {
-            LogError("No key for given label in database");
-            return CKM_API_ERROR_DB_ERROR;
-        }
-        key = *key_optional;
-        key = handle.keyProvider.getPureDEK(key);
-        handle.crypto.pushKey(appLabel, key);
-    }
-    return CKM_API_SUCCESS;
+       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
-