Enable -Wshadow and fix warnings
[platform/core/security/key-manager.git] / src / manager / service / ckm-logic.cpp
index 7d32228..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.
 
 namespace {
 const char *const CERT_SYSTEM_DIR          = CA_CERTS_DIR;
-const char *const SYSTEM_DB_PASSWD         = "cAtRugU7";
+const char *const DEFAULT_UNLOCK_STRING    = "cAtRugU7";
 
-bool isLabelValid(const CKM::Label &label)
+bool isClientValid(const CKM::ClientId &client)
 {
-       // TODO: copy code from libprivilege control (for check smack label)
-       if (label.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Label::npos)
+       if (client.find(CKM::ALIAS_SEPARATOR) != CKM::ClientId::npos)
                return false;
 
        return true;
@@ -50,7 +49,7 @@ bool isLabelValid(const CKM::Label &label)
 
 bool isNameValid(const CKM::Name &name)
 {
-       if (name.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Name::npos)
+       if (name.find(CKM::ALIAS_SEPARATOR) != CKM::Name::npos)
                return false;
 
        return true;
@@ -60,6 +59,130 @@ bool isNameValid(const CKM::Name &name)
 
 namespace CKM {
 
+namespace {
+
+template <int ERROR_ON_CKM_EXCEPTION = CKM_API_ERROR_SERVER_ERROR, class F>
+int tryRet(F &&f)
+{
+       try {
+               static_assert(std::is_same_v<decltype(std::forward<F>(f)()), int>);
+               return std::forward<F>(f)();
+       } catch (const Exc::Exception &e) {
+               return e.error();
+       } catch (const CKM::Exception &e) {
+               LogError("CKM::Exception: " << e.GetMessage());
+               return ERROR_ON_CKM_EXCEPTION;
+       }
+}
+
+int toBinaryData(const Crypto::Data &input, Crypto::Data &output)
+{
+       // verify the data integrity
+       if (input.type.isKey()) {
+               KeyShPtr output_key;
+
+               if (input.type.isSymmetricKey())
+                       output_key = CKM::Key::createAES(input.data);
+               else
+                       output_key = CKM::Key::create(input.data);
+
+               if (output_key.get() == NULL) {
+                       LogDebug("provided binary data is not valid key data");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               output = Crypto::Data(input.type, output_key->getDER());
+       } else if (input.type.isCertificate() || input.type.isChainCert()) {
+               CertificateShPtr cert = CKM::Certificate::create(input.data, DataFormat::FORM_DER);
+
+               if (cert.get() == NULL) {
+                       LogDebug("provided binary data is not valid certificate data");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               output = Crypto::Data(input.type, cert->getDER());
+       } else {
+               output = input;
+       }
+
+       // TODO: add here BINARY_DATA verification, i.e: max size etc.
+       return CKM_API_SUCCESS;
+}
+
+int verifyBinaryData(const Crypto::Data &input)
+{
+       Crypto::Data dummy;
+       return toBinaryData(input, dummy);
+}
+
+int readSingleRow(const Name &name,
+               const ClientId &owner,
+               DataType dataType,
+               DB::Crypto &database,
+               DB::Row &row)
+{
+       DB::Crypto::RowOptional row_optional;
+
+       if (dataType.isKey()) {
+               // read all key types
+               row_optional = database.getRow(name,
+                                                                          owner,
+                                                                          DataType::DB_KEY_FIRST,
+                                                                          DataType::DB_KEY_LAST);
+       } else {
+               // read anything else
+               row_optional = database.getRow(name,
+                                                                          owner,
+                                                                          dataType);
+       }
+
+       if (!row_optional) {
+               LogDebug("No row for given name, owner and type");
+               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+       } else {
+               row = *row_optional;
+       }
+
+       return CKM_API_SUCCESS;
+}
+
+int readMultiRow(const Name &name,
+               const ClientId &owner,
+               DataType dataType,
+               DB::Crypto &database,
+               DB::RowVector &output)
+{
+       if (dataType.isKey())
+               // read all key types
+               database.getRows(name,
+                                                owner,
+                                                DataType::DB_KEY_FIRST,
+                                                DataType::DB_KEY_LAST,
+                                                output);
+       else if (dataType.isChainCert())
+               // read all key types
+               database.getRows(name,
+                                                owner,
+                                                DataType::DB_CHAIN_FIRST,
+                                                DataType::DB_CHAIN_LAST,
+                                                output);
+       else
+               // read anything else
+               database.getRows(name,
+                                                owner,
+                                                dataType,
+                                                output);
+
+       if (!output.size()) {
+               LogDebug("No row for given name, owner and type");
+               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+       }
+
+       return CKM_API_SUCCESS;
+}
+
+} // namespace
+
 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
 const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
 
@@ -86,6 +209,11 @@ void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
        }
 
        handle.keyProvider = KeyProvider(wrappedDKEK, password);
+       if (!handle.keyProvider.isInitialized()) {
+               handle.keyProvider.migrateDomainKEK(wrappedDKEK, password);
+               fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
+               LogInfo("DKEK migrated");
+       }
 }
 
 void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
@@ -102,7 +230,7 @@ void CKMLogic::migrateSecureStorageData(bool isAdminUser)
                                                                                         const Crypto::Data &data,
                                                                                         bool adminUserFlag) {
                LogInfo("Migrate data called with  name: " << name);
-               auto ownerId = adminUserFlag ? OWNER_ID_ADMIN_USER : OWNER_ID_SYSTEM;
+               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,
@@ -122,9 +250,7 @@ int CKMLogic::unlockDatabase(uid_t user, const Password &password)
                        m_userDataMap[user].keyProvider.isInitialized())
                return CKM_API_SUCCESS;
 
-       int retCode = CKM_API_SUCCESS;
-
-       try {
+       int retCode = tryRet([&] {
                auto &handle = m_userDataMap[user];
 
                FileSystem fs(user);
@@ -139,16 +265,16 @@ int CKMLogic::unlockDatabase(uid_t user, const Password &password)
 
                RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
 
-               handle.database = DB::Crypto(fs.getDBPath(), key);
+               handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
                handle.crypto = CryptoLogic();
 
                if (!m_accessControl.isSystemService(user)) {
                        // remove data of removed apps during locked state
-                       AppLabelVector removedApps = fs.clearRemovedsApps();
+                       ClientIdVector removedApps = fs.clearRemovedsApps();
 
-                       for (auto &appSmackLabel : removedApps) {
-                               handle.crypto.removeKey(appSmackLabel);
-                               handle.database.deleteKey(appSmackLabel);
+                       for (auto &app : removedApps) {
+                               handle.crypto.removeKey(app);
+                               handle.database.deleteKey(app);
                        }
                }
 
@@ -156,12 +282,9 @@ int CKMLogic::unlockDatabase(uid_t user, const Password &password)
                        migrateSecureStorageData(false);
                else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
                        migrateSecureStorageData(true);
-       } 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 CKM_API_SUCCESS;
+       });
 
        if (CKM_API_SUCCESS != retCode)
                m_userDataMap.erase(user);
@@ -171,25 +294,25 @@ int CKMLogic::unlockDatabase(uid_t user, const Password &password)
 
 int CKMLogic::unlockSystemDB()
 {
-       return unlockDatabase(SYSTEM_DB_UID, SYSTEM_DB_PASSWD);
+       return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
 }
 
 UserData &CKMLogic::selectDatabase(const Credentials &cred,
-                                                                  const Label &incoming_label)
+                                                                  const ClientId &owner)
 {
        // if user trying to access system service - check:
        //    * if user database is unlocked [mandatory]
        //    * if not - proceed with regular user database
-       //    * if explicit system database label given -> switch to system DB
+       //    * 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 != incoming_label.compare(OWNER_ID_SYSTEM))
+               if (0 != owner.compare(CLIENT_ID_SYSTEM))
                        return m_userDataMap[cred.clientUid];
        }
 
-       // system database selected, modify the label
+       // system database selected, modify the owner id
        if (CKM_API_SUCCESS != unlockSystemDB())
                ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
 
@@ -205,13 +328,13 @@ RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
        else // do not allow lock/unlock operations for system users
                retCode = CKM_API_ERROR_INPUT_PARAM;
 
-       return MessageBuffer::Serialize(retCode).Pop();
+       return SerializeMessage(retCode);
 }
 
 RawBuffer CKMLogic::updateCCMode()
 {
        m_accessControl.updateCCMode();
-       return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
+       return SerializeMessage(CKM_API_SUCCESS);
 }
 
 RawBuffer CKMLogic::lockUserKey(uid_t user)
@@ -223,36 +346,21 @@ RawBuffer CKMLogic::lockUserKey(uid_t user)
        else // do not allow lock/unlock operations for system users
                retCode = CKM_API_ERROR_INPUT_PARAM;
 
-       return MessageBuffer::Serialize(retCode).Pop();
+       return SerializeMessage(retCode);
 }
 
 RawBuffer CKMLogic::removeUserData(uid_t user)
 {
-       int retCode = CKM_API_SUCCESS;
-
        if (m_accessControl.isSystemService(user))
                user = SYSTEM_DB_UID;
 
        m_userDataMap.erase(user);
 
-       FileSystem fs(user);
-       fs.removeUserData();
-
-       return MessageBuffer::Serialize(retCode).Pop();
-}
-
-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;
-
-       loadDKEKFile(user, oldPassword);
-       saveDKEKFile(user, newPassword);
+       const int retCode = FileSystem(user).removeUserData()
+               ? CKM_API_ERROR_FILE_SYSTEM
+               : CKM_API_SUCCESS;
 
-       return CKM_API_SUCCESS;
+       return SerializeMessage(retCode);
 }
 
 RawBuffer CKMLogic::changeUserPassword(
@@ -260,568 +368,308 @@ RawBuffer CKMLogic::changeUserPassword(
        const Password &oldPassword,
        const Password &newPassword)
 {
-       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();
-}
-
-int CKMLogic::resetUserPasswordHelper(
-       uid_t user,
-       const Password &newPassword)
-{
-       // 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();
+       return SerializeMessage(tryRet([&] {
+               // do not allow to change system database password
+               if (m_accessControl.isSystemService(user))
+                       return CKM_API_ERROR_INPUT_PARAM;
 
-               if (!wrappedDKEKMain.empty())
-                       retCode = CKM_API_ERROR_BAD_REQUEST;
-       } else {
+               loadDKEKFile(user, oldPassword);
                saveDKEKFile(user, newPassword);
-       }
 
-       return retCode;
+               return CKM_API_SUCCESS;
+       }));
 }
 
 RawBuffer CKMLogic::resetUserPassword(
        uid_t user,
        const Password &newPassword)
 {
-       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();
-}
-
-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 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 CKMLogic::checkSaveConditions(
-       const Credentials &cred,
-       UserData &handler,
-       const Name &name,
-       const Label &ownerLabel)
-{
-       // 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;
-       }
+       return SerializeMessage(tryRet([&] {
+               // do not allow to reset system database password
+               if (m_accessControl.isSystemService(user))
+                       return CKM_API_ERROR_INPUT_PARAM;
 
-       // check if not a duplicate
-       if (handler.database.isNameLabelPresent(name, ownerLabel))
-               return CKM_API_ERROR_DB_ALIAS_EXISTS;
+               int retCode = CKM_API_SUCCESS;
 
-       // encryption section
-       if (!handler.crypto.haveKey(ownerLabel)) {
-               RawBuffer got_key;
-               auto key_optional = handler.database.getKey(ownerLabel);
+               if (0 == m_userDataMap.count(user)) {
+                       // Check if key exists. If exists we must return error
+                       FileSystem fs(user);
+                       auto wrappedDKEKMain = fs.getDKEK();
 
-               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);
+                       if (!wrappedDKEKMain.empty())
+                               retCode = CKM_API_ERROR_BAD_REQUEST;
                } else {
-                       LogDebug("Key from DB");
-                       got_key = *key_optional;
+                       saveDKEKFile(user, newPassword);
                }
 
-               got_key = handler.keyProvider.getPureDEK(got_key);
-               handler.crypto.pushKey(ownerLabel, got_key);
-       }
-
-       return CKM_API_SUCCESS;
-}
-
-DB::Row CKMLogic::createEncryptedRow(
-       CryptoLogic &crypto,
-       const Name &name,
-       const Label &label,
-       const Crypto::Data &data,
-       const Policy &policy) const
-{
-       Crypto::GStore &store = m_decider.getStore(data.type, policy.extractable);
-
-       // 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;
-}
-
-int CKMLogic::verifyBinaryData(Crypto::Data &input) const
-{
-       Crypto::Data dummy;
-       return toBinaryData(input, dummy);
+               return retCode;
+       }));
 }
 
-int CKMLogic::toBinaryData(const Crypto::Data &input,
-                                                  Crypto::Data &output) const
+RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
 {
-       // 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 SerializeMessage(tryRet([&] {
+               if (owner.empty())
                        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);
+               UidVector uids = FileSystem::getUIDsFromDBFile();
 
-               if (cert.get() == NULL) {
-                       LogDebug("provided binary data is not valid certificate data");
-                       return CKM_API_ERROR_INPUT_PARAM;
+               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);
+                       }
                }
 
-               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 CKM_API_SUCCESS;
+       }));
 }
 
 int CKMLogic::verifyAndSaveDataHelper(
        const Credentials &cred,
        const Name &name,
-       const Label &label,
+       const ClientId &owner,
        const Crypto::Data &data,
        const PolicySerializable &policy)
 {
-       int retCode = CKM_API_ERROR_UNKNOWN;
-
-       try {
+       return tryRet([&] {
                // check if data is correct
                Crypto::Data binaryData;
-               retCode = toBinaryData(data, binaryData);
-
+               int retCode = toBinaryData(data, binaryData);
                if (retCode != CKM_API_SUCCESS)
                        return retCode;
-               else
-                       return saveDataHelper(cred, name, label, binaryData, policy);
-       } catch (const Exc::Exception &e) {
-               return e.error();
-       } catch (const CKM::Exception &e) {
-               LogError("CKM::Exception: " << e.GetMessage());
-               return CKM_API_ERROR_SERVER_ERROR;
-       }
+
+               auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, name, owner);
+               if (ret != CKM_API_SUCCESS)
+                       return ret;
+
+               Crypto::GStore &store = m_decider.getStore(binaryData.type, policy);
+
+               // do not encrypt data with password during cc_mode on
+               Token token = store.import(binaryData,
+                                                                  m_accessControl.isCCMode() ? "" : policy.password,
+                                                                  Crypto::EncryptionParams(), digest);
+               dbOp.finalize(std::move(token), policy);
+               return CKM_API_SUCCESS;
+       });
 }
 
 int CKMLogic::getKeyForService(
        const Credentials &cred,
        const Name &name,
-       const Label &label,
+       const ClientId &owner,
        const Password &pass,
        Crypto::GObjShPtr &key)
 {
-       DB::Row row;
-
-       try {
+       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, label,
-                                                                        pass, 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;
-       } catch (const Exc::Exception &e) {
-               return e.error();
-       } catch (const CKM::Exception &e) {
-               LogError("CKM::Exception: " << e.GetMessage());
-               return CKM_API_ERROR_SERVER_ERROR;
-       }
+       });
 }
 
 RawBuffer CKMLogic::saveData(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const Name &name,
-       const Label &label,
+       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();
-}
-
-int CKMLogic::extractPKCS12Data(
-       CryptoLogic &crypto,
-       const Name &name,
-       const Label &ownerLabel,
-       const PKCS12Serializable &pkcs,
-       const PolicySerializable &keyPolicy,
-       const PolicySerializable &certPolicy,
-       DB::RowVector &output) const
-{
-       // 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());
-       int retCode = verifyBinaryData(keyData);
-
-       if (retCode != CKM_API_SUCCESS)
-               return retCode;
-
-       output.push_back(createEncryptedRow(crypto, name, ownerLabel, keyData,
-                                                                               keyPolicy));
-
-       // 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 = 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;
+       int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
+       return SerializeMessage(msgId, retCode, data.type);
 }
 
 RawBuffer CKMLogic::savePKCS12(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const Name &name,
-       const Label &label,
+       const ClientId &owner,
        const PKCS12Serializable &pkcs,
        const PolicySerializable &keyPolicy,
        const PolicySerializable &certPolicy)
 {
-       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 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();
-}
+       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;
 
-int CKMLogic::removeDataHelper(
-       const Credentials &cred,
-       const Name &name,
-       const Label &label)
-{
-       auto &handler = selectDatabase(cred, label);
+               auto import = [&](const Crypto::Data &data, const Policy& policy){
+                       retCode = verifyBinaryData(data);
+                       if (retCode != CKM_API_SUCCESS)
+                               return retCode;
 
-       // use client label if not explicitly provided
-       const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+                       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid, data.type);
+                       if (digest.empty())
+                               return CKM_API_ERROR_HASH_ERROR;
 
-       if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
-               LogDebug("Invalid label or name format");
-               return CKM_API_ERROR_INPUT_PARAM;
-       }
+                       Crypto::GStore &store = m_decider.getStore(data.type, policy);
 
-       DB::Crypto::Transaction transaction(&handler.database);
+                       // do not encrypt data with password during cc_mode on
+                       Token token = store.import(data,
+                                                                          m_accessControl.isCCMode() ? "" : policy.password,
+                                                                          Crypto::EncryptionParams(), digest);
 
-       // read and check permissions
-       PermissionMaskOptional permissionRowOpt =
-               handler.database.getPermissionRow(name, ownerLabel, cred.smackLabel);
-       int retCode = m_accessControl.canDelete(cred,
-                                                                                       PermissionForLabel(cred.smackLabel, permissionRowOpt));
+                       encryptedRows.push_back(dbOp.encryptOne(std::move(token), policy));
+                       return CKM_API_SUCCESS;
+               };
 
-       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);
+               // private key is mandatory
+               auto key = pkcs.getKey();
+               if (!key) {
+                       LogError("Failed to get private key from pkcs");
+                       return CKM_API_ERROR_INVALID_FORMAT;
+               }
 
-       if (rows.empty()) {
-               LogDebug("No row for given name and label");
-               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
-       }
+               Crypto::Data keyData(DataType(key->getType()), key->getDER());
+               retCode = import(keyData, keyPolicy);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
 
-       // load app key if needed
-       retCode = loadAppKey(handler, rows.front().ownerLabel);
+               // certificate is mandatory
+               auto cert = pkcs.getCertificate();
+               if (!cert) {
+                       LogError("Failed to get certificate from pkcs");
+                       return CKM_API_ERROR_INVALID_FORMAT;
+               }
 
-       if (CKM_API_SUCCESS != retCode)
-               return retCode;
+               Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
+               retCode = import(certData, certPolicy);
+               if (retCode != CKM_API_SUCCESS)
+                       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.");
+               // 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;
                }
-       }
 
-       // delete row in db
-       handler.database.deleteRow(name, ownerLabel);
-       transaction.commit();
+               // save the data
+               dbOp.database().saveRows(name, owner, encryptedRows);
+               dbOp.transaction().commit();
 
-       return CKM_API_SUCCESS;
+               return CKM_API_SUCCESS;
+       }));
 }
 
 RawBuffer CKMLogic::removeData(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const Name &name,
-       const Label &label)
+       const ClientId &owner)
 {
-       int retCode = CKM_API_ERROR_UNKNOWN;
+       return SerializeMessage(msgId, tryRet([&] {
+               auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
 
-       try {
-               retCode = removeDataHelper(cred, name, label);
-       } catch (const Exc::Exception &e) {
-               retCode = e.error();
-       } catch (const CKM::Exception &e) {
-               LogError("Error: " << e.GetMessage());
-               retCode = CKM_API_ERROR_DB_ERROR;
-       }
+               retCode = m_accessControl.canDelete(cred, permission);
+               if (retCode != CKM_API_SUCCESS) {
+                       LogWarning("access control check result: " << retCode);
+                       return retCode;
+               }
 
-       auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
-                                       commandId,
-                                       retCode);
-       return response.Pop();
-}
+               // 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;
+               }
 
-int CKMLogic::readSingleRow(const Name &name,
-                                                       const Label &ownerLabel,
-                                                       DataType dataType,
-                                                       DB::Crypto &database,
-                                                       DB::Row &row)
-{
-       DB::Crypto::RowOptional row_optional;
+               retCode = dbOp.loadAppKey();
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
 
-       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);
-       }
+               // 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.");
+                       }
+               }
 
-       if (!row_optional) {
-               LogDebug("No row for given name, label and type");
-               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
-       } else {
-               row = *row_optional;
-       }
+               // delete row in db
+               dbOp.database().deleteRow(name, owner);
+               dbOp.transaction().commit();
 
-       return CKM_API_SUCCESS;
+               return CKM_API_SUCCESS;
+       }));
 }
 
 
-int CKMLogic::readMultiRow(const Name &name,
-                                                  const Label &ownerLabel,
-                                                  DataType dataType,
-                                                  DB::Crypto &database,
-                                                  DB::RowVector &output)
-{
-       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;
-}
-
-int CKMLogic::checkDataPermissionsHelper(const Credentials &cred,
-               const Name &name,
-               const Label &ownerLabel,
-               const Label &accessorLabel,
+int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
                const DB::Row &row,
                bool exportFlag,
-               DB::Crypto &database)
+               const PermissionMask& permission)
 {
-       PermissionMaskOptional permissionRowOpt =
-               database.getPermissionRow(name, ownerLabel, accessorLabel);
-
        if (exportFlag)
-               return m_accessControl.canExport(cred, row, PermissionForLabel(accessorLabel,
-                                                                                permissionRowOpt));
+               return m_accessControl.canExport(accessorCred, row, permission);
 
-       return m_accessControl.canRead(cred, PermissionForLabel(accessorLabel,
-                                                                  permissionRowOpt));
+       return m_accessControl.canRead(accessorCred, permission);
 }
 
-Crypto::GObjUPtr CKMLogic::rowToObject(
+void CKMLogic::decryptRow(
        UserData &handler,
-       DB::Row row,
-       const Password &password)
+       DB::Row &row,
+       const Password &password,
+       const RawBuffer &hash)
 {
-       Crypto::GStore &store = m_decider.getStore(row);
-
-       Password pass = m_accessControl.isCCMode() ? "" : password;
-
-       // decrypt row
-       Crypto::GObjUPtr obj;
-
        if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
                        CryptoLogic::ENCRYPTION_V2) {
                handler.crypto.decryptRow(Password(), row);
-
-               obj = store.getObject(row, pass);
        } 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);
-
-               // get it from the store (it can be different than the data we imported into store)
-               obj = store.getObject(token, pass);
+               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))
-               handler.crypto.encryptRow(row);
+               auto encryptedRow = handler.crypto.encryptRow(row);
 
                // update it in db
-               handler.database.updateRow(row);
+               handler.database.updateRow(encryptedRow);
        }
+}
 
-       return obj;
+Crypto::GObjUPtr CKMLogic::rowToObject(
+       UserData &handler,
+       DB::Row row,
+       const Password &password,
+       const RawBuffer &hash)
+{
+       decryptRow(handler, row, password, hash);
+
+       return decryptedRowToObj(row, password);
 }
 
 int CKMLogic::readDataHelper(
@@ -829,23 +677,17 @@ int CKMLogic::readDataHelper(
        const Credentials &cred,
        DataType dataType,
        const Name &name,
-       const Label &label,
+       const ClientId &owner,
        const Password &password,
        Crypto::GObjUPtrVector &objs)
 {
-       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))
-               return CKM_API_ERROR_INPUT_PARAM;
+       auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
        // read rows
-       DB::Crypto::Transaction transaction(&handler.database);
        DB::RowVector rows;
-       int retCode = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
-
+       retCode = readMultiRow(name, owner, dataType, dbOp.database(), rows);
        if (CKM_API_SUCCESS != retCode)
                return retCode;
 
@@ -853,24 +695,34 @@ int CKMLogic::readDataHelper(
        DB::Row &firstRow = rows.at(0);
 
        // check access rights
-       retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel,
-                                                                                firstRow, exportFlag, handler.database);
-
+       retCode = checkDataPermissionsHelper(cred, firstRow, exportFlag, permission);
        if (CKM_API_SUCCESS != retCode)
                return retCode;
 
-       // load app key if needed
-       retCode = loadAppKey(handler, firstRow.ownerLabel);
+       // for multiple objects add type as hash input (see pkcs12)
+       bool multiple = rows.size() > 1;
 
-       if (CKM_API_SUCCESS != retCode)
+       RawBuffer digest;
+
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
                return retCode;
 
        // decrypt row
-       for (auto &row : rows)
-               objs.push_back(rowToObject(handler, std::move(row), password));
+       for (auto &row : rows) {
+               if (multiple)
+                       digest = CryptoLogic::makeHash(name, owner, cred.clientUid, row.dataType);
+               else
+                       digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
+
+               if (digest.empty())
+                       return CKM_API_ERROR_HASH_ERROR;
+
+               objs.push_back(rowToObject(dbOp.handler(), std::move(row), password, digest));
+       }
 
        // rowToObject may modify db
-       transaction.commit();
+       dbOp.transaction().commit();
 
        return CKM_API_SUCCESS;
 }
@@ -880,226 +732,230 @@ int CKMLogic::readDataHelper(
        const Credentials &cred,
        DataType dataType,
        const Name &name,
-       const Label &label,
+       const ClientId &owner,
        const Password &password,
        Crypto::GObjUPtr &obj)
 {
        DataType objDataType;
-       return readDataHelper(exportFlag, cred, dataType, name, label, password, obj,
-                                                 objDataType);
+       return readDataHelper(exportFlag, cred, dataType, name, owner,
+                                                 password, obj, objDataType);
 }
 
-int CKMLogic::readDataHelper(
+int CKMLogic::readRowHelper(
        bool exportFlag,
        const Credentials &cred,
        DataType dataType,
        const Name &name,
-       const Label &label,
+       const ClientId &owner,
        const Password &password,
-       Crypto::GObjUPtr &obj,
+       DB::Row &row,
        DataType &objDataType)
 {
-       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))
-               return CKM_API_ERROR_INPUT_PARAM;
-
-       // read row
-       DB::Crypto::Transaction transaction(&handler.database);
-       DB::Row row;
-       int retCode = readSingleRow(name, ownerLabel, dataType, handler.database, row);
+       auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
+       retCode = readSingleRow(name, owner, dataType, dbOp.database(), row);
        if (CKM_API_SUCCESS != retCode)
                return retCode;
 
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
        objDataType = row.dataType;
 
        // check access rights
-       retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel,
-                                                                                row, exportFlag, handler.database);
-
-       if (CKM_API_SUCCESS != retCode)
+       retCode = checkDataPermissionsHelper(cred, row, exportFlag, permission);
+       if (retCode != CKM_API_SUCCESS)
                return retCode;
 
-       // load app key if needed
-       retCode = loadAppKey(handler, row.ownerLabel);
+       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
+       if (digest.empty())
+               return CKM_API_ERROR_HASH_ERROR;
 
-       if (CKM_API_SUCCESS != retCode)
-               return retCode;
+       decryptRow(dbOp.handler(), row, password, digest);
 
-       obj = rowToObject(handler, std::move(row), password);
-       // rowToObject may modify db
-       transaction.commit();
+       // decryptRow may modify db
+       dbOp.transaction().commit();
 
        return CKM_API_SUCCESS;
 }
 
-RawBuffer CKMLogic::getData(
+Crypto::GObjUPtr CKMLogic::decryptedRowToObj(const DB::Row& row, const Password &password)
+{
+       Crypto::GStore &store = m_decider.getStore(row);
+
+       Password pass = m_accessControl.isCCMode() ? "" : password;
+       return store.getObject(row, pass);
+}
+
+int CKMLogic::readDataHelper(
+       bool exportFlag,
        const Credentials &cred,
-       int commandId,
        DataType dataType,
        const Name &name,
-       const Label &label,
-       const Password &password)
+       const ClientId &owner,
+       const Password &password,
+       Crypto::GObjUPtr &obj,
+       DataType &objDataType)
 {
-       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 Exc::Exception &e) {
-               retCode = e.error();
-       } catch (const CKM::Exception &e) {
-               LogError("CKM::Exception: " << e.GetMessage());
-               retCode = CKM_API_ERROR_SERVER_ERROR;
-       }
+       int retCode = readRowHelper(exportFlag, cred, dataType, name, owner, password, row, objDataType);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-       if (CKM_API_SUCCESS != retCode) {
-               row.data.clear();
-               row.dataType = dataType;
-       }
+       obj = decryptedRowToObj(row, password);
 
-       auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
-                                       commandId,
-                                       retCode,
-                                       static_cast<int>(objDataType),
-                                       row.data);
-       return response.Pop();
+       return CKM_API_SUCCESS;
 }
 
-int CKMLogic::getPKCS12Helper(
+RawBuffer CKMLogic::getData(
        const Credentials &cred,
+       int msgId,
+       DataType dataType,
        const Name &name,
-       const Label &label,
-       const Password &keyPassword,
-       const Password &certPassword,
-       KeyShPtr &privKey,
-       CertificateShPtr &cert,
-       CertificateShPtrVector &caChain)
+       const ClientId &owner,
+       const Password &password)
 {
-       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;
+       RawBuffer rowData;
+       DataType objDataType;
 
-       privKey = CKM::Key::create(keyObj->getBinary());
+       int retCode = tryRet([&] {
+               Crypto::GObjUPtr obj;
+               int retCode2 = readDataHelper(true, cred, dataType, name, owner,
+                                                                         password, obj, objDataType);
 
-       // read certificate (mandatory)
-       Crypto::GObjUPtr certObj;
-       retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label,
-                                                        certPassword, certObj);
+               if (retCode2 == CKM_API_SUCCESS)
+                       rowData = obj->getBinary();
 
-       if (retCode != CKM_API_SUCCESS)
-               return retCode;
+               return retCode2;
+       });
 
-       cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
+       if (CKM_API_SUCCESS != retCode)
+               rowData.clear();
 
-       // read CA cert chain (optional)
-       Crypto::GObjUPtrVector caChainObjs;
-       retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label,
-                                                        certPassword, caChainObjs);
+       return SerializeMessage(msgId, retCode, objDataType, rowData);
+}
 
-       if (retCode != CKM_API_SUCCESS &&
-                       retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
-               return retCode;
+RawBuffer CKMLogic::getDataProtectionStatus(
+               const Credentials &cred,
+               int msgId,
+               DataType dataType,
+               const Name &name,
+               const ClientId &owner)
+{
+       bool status = false;
+       DataType objDataType;
+       Password password;
 
-       for (auto &caCertObj : caChainObjs)
-               caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
-                                                 DataFormat::FORM_DER));
+       int retCode = tryRet([&] {
+               Crypto::GObjUPtr obj;
+               return readDataHelper(false, cred, dataType, name, owner, password, obj, objDataType);
+       });
 
-       // if anything found, return it
-       if (privKey || cert || caChain.size() > 0)
+       if (retCode == CKM_API_ERROR_AUTHENTICATION_FAILED) {
+               status = true;
                retCode = CKM_API_SUCCESS;
+       }
 
-       return retCode;
+       return SerializeMessage(msgId, retCode, objDataType, status);
 }
 
 RawBuffer CKMLogic::getPKCS12(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const Name &name,
-       const Label &label,
+       const ClientId &owner,
        const Password &keyPassword,
        const Password &certPassword)
 {
-       int retCode = CKM_API_ERROR_UNKNOWN;
-
        PKCS12Serializable output;
 
-       try {
+       int retCode = tryRet([&] {
                KeyShPtr privKey;
                CertificateShPtr cert;
                CertificateShPtrVector caChain;
-               retCode = getPKCS12Helper(cred, name, label, keyPassword, certPassword, privKey,
-                                                                 cert, 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 (retCode == CKM_API_SUCCESS)
-                       output = PKCS12Serializable(std::move(privKey), std::move(cert),
-                                                                               std::move(caChain));
-       } 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 (retCode2 != CKM_API_SUCCESS)
+                       return retCode2;
+
+               output = PKCS12Serializable(std::move(privKey), std::move(cert), std::move(caChain));
+               return CKM_API_SUCCESS;
+       });
 
-       auto response = MessageBuffer::Serialize(static_cast<int>
-                                       (LogicCommand::GET_PKCS12),
-                                       commandId,
-                                       retCode,
-                                       output);
-       return response.Pop();
+       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;
+               retCode = tryRet<CKM_API_ERROR_DB_ERROR>([&] {
+                       AliasInfoVector tmpVector;
 
                        if (dataType.isKey()) {
                                // list all key types
-                               database.listNames(cred.smackLabel,
+                               database.listInfos(cred.client,
                                                                   tmpVector,
                                                                   DataType::DB_KEY_FIRST,
                                                                   DataType::DB_KEY_LAST);
                        } else {
                                // list anything else
-                               database.listNames(cred.smackLabel,
-                                                                  tmpVector,
-                                                                  dataType);
+                               database.listInfos(cred.client, tmpVector, dataType);
                        }
 
-                       labelNameVector.insert(labelNameVector.end(), tmpVector.begin(),
-                                                                  tmpVector.end());
-                       retCode = CKM_API_SUCCESS;
-               } catch (const CKM::Exception &e) {
-                       LogError("Error: " << e.GetMessage());
-                       retCode = CKM_API_ERROR_DB_ERROR;
-               } catch (const Exc::Exception &e) {
-                       retCode = e.error();
-               }
+                       aliasInfoVector.insert(aliasInfoVector.end(), tmpVector.begin(), tmpVector.end());
+                       return CKM_API_SUCCESS;
+               });
        }
 
        return retCode;
@@ -1107,12 +963,12 @@ int CKMLogic::getDataListHelper(const Credentials &cred,
 
 RawBuffer CKMLogic::getDataList(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        DataType dataType)
 {
-       LabelNameVector systemVector;
-       LabelNameVector userVector;
-       LabelNameVector labelNameVector;
+       AliasInfoVector systemVector;
+       AliasInfoVector userVector;
+       AliasInfoVector aliasInfoVector;
 
        int retCode = unlockSystemDB();
 
@@ -1120,354 +976,259 @@ RawBuffer CKMLogic::getDataList(
                // system database
                if (m_accessControl.isSystemService(cred)) {
                        // lookup system DB
-                       retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
-                                                                                                       OWNER_ID_SYSTEM),
-                                                                               dataType,
-                                                                               systemVector);
+                       retCode = getAliasInfoListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
+                                                                                        dataType,
+                                                                                        systemVector);
                } else {
                        // user - lookup system, then client DB
-                       retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
-                                                                                                       cred.smackLabel),
-                                                                               dataType,
-                                                                               systemVector);
+                       retCode = getAliasInfoListHelper(Credentials(SYSTEM_DB_UID, cred.client),
+                                                                                        dataType,
+                                                                                        systemVector);
 
                        // private database
                        if (retCode == CKM_API_SUCCESS) {
-                               retCode = getDataListHelper(cred,
-                                                                                       dataType,
-                                                                                       userVector);
+                               retCode = getAliasInfoListHelper(cred,
+                                                                                                dataType,
+                                                                                                userVector);
                        }
                }
        }
 
        if (retCode == CKM_API_SUCCESS) {
-               labelNameVector.insert(labelNameVector.end(), systemVector.begin(),
+               aliasInfoVector.insert(aliasInfoVector.end(), systemVector.begin(),
                                                           systemVector.end());
-               labelNameVector.insert(labelNameVector.end(), userVector.begin(),
+               aliasInfoVector.insert(aliasInfoVector.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();
+       return SerializeMessage(msgId, retCode, dataType, AliasInfoSerializableVector(aliasInfoVector));
 }
 
 int CKMLogic::importInitialData(
        const Name &name,
        const Crypto::Data &data,
-       const Crypto::DataEncryption &enc,
+       const Crypto::EncryptionParams &encParams,
        const Policy &policy)
 {
        try {
-               // Inital values are always imported with root credentials. Label is not important.
-               Credentials rootCred(0, "");
-
-               auto &handler = selectDatabase(rootCred, OWNER_ID_SYSTEM);
-
-               // check if save is possible
-               DB::Crypto::Transaction transaction(&handler.database);
-               int retCode = checkSaveConditions(rootCred, handler, name, OWNER_ID_SYSTEM);
+               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;
+                       }
 
-               if (retCode != CKM_API_SUCCESS)
-                       return retCode;
+                       // Inital values are always imported with root credentials. Client id is not important.
+                       Credentials rootCred(0, "whatever");
+                       ClientId owner(CLIENT_ID_SYSTEM);
 
-               Crypto::GStore &store =
-                       m_decider.getStore(data.type, policy.extractable, !enc.encryptedKey.empty());
+                       auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
+                       if (retCode != CKM_API_SUCCESS)
+                               return retCode;
 
-               Token token;
+                       Crypto::GStore &store = m_decider.getStore(data.type, policy, true, !encParams.iv.empty());
 
-               if (enc.encryptedKey.empty()) {
-                       Crypto::Data binaryData;
+                       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;
+                               if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
+                                       return retCode;
 
-                       token = store.import(binaryData,
-                                                                m_accessControl.isCCMode() ? "" : policy.password);
-               } else {
-                       token = store.importEncrypted(data,
-                                                                                 m_accessControl.isCCMode() ? "" : policy.password, enc);
-               }
+                               token = store.import(binaryData,
+                                                                        m_accessControl.isCCMode() ? "" : policy.password,
+                                                                        encParams, digest);
+                       } else {
+                               token = store.import(data,
+                                                                        m_accessControl.isCCMode() ? "" : policy.password,
+                                                                        encParams, digest);
+                       }
 
-               DB::Row row(std::move(token), name, OWNER_ID_SYSTEM,
-                                       static_cast<int>(policy.extractable));
-               handler.crypto.encryptRow(row);
+                       dbOp.finalize(std::move(token), policy);
 
-               handler.database.saveRow(row);
-               transaction.commit();
-       } 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 CKM_API_SUCCESS;
+               });
        } catch (const std::exception &e) {
                LogError("Std::exception: " << e.what());
                return CKM_API_ERROR_SERVER_ERROR;
        }
-
-       return CKM_API_SUCCESS;
 }
 
-int CKMLogic::saveDataHelper(
-       const Credentials &cred,
-       const Name &name,
-       const Label &label,
-       const Crypto::Data &data,
-       const PolicySerializable &policy)
+int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
 {
-       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;
+       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;
+               }
 
-       // save the data
-       DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, ownerLabel,
-                                                  data, policy);
-       handler.database.saveRow(encryptedRow);
+               m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
+       }
 
-       transaction.commit();
        return CKM_API_SUCCESS;
 }
 
-int CKMLogic::saveDataHelper(
+std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
        const Credentials &cred,
        const Name &name,
-       const Label &label,
-       const PKCS12Serializable &pkcs,
-       const PolicySerializable &keyPolicy,
-       const PolicySerializable &certPolicy)
+       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);
+       auto &handler = selectDatabase(cred, owner);
+       DBOperation op(handler, name, owner);
 
-       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;
+       if (cred.client.empty() || !isClientValid(cred.client) ||
+               !isNameValid(name) || !isClientValid(owner))
+               return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
 
-       // save the data
-       handler.database.saveRows(name, ownerLabel, encryptedRows);
-       transaction.commit();
-
-       return CKM_API_SUCCESS;
+       return std::make_tuple(std::move(op), CKM_API_SUCCESS);
 }
 
-
-int CKMLogic::createKeyAESHelper(
+std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
        const Credentials &cred,
-       const int size,
        const Name &name,
-       const Label &label,
-       const PolicySerializable &policy)
+       const ClientId &owner)
 {
-       auto &handler = selectDatabase(cred, label);
-
-       // use client label if not explicitly provided
-       const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+       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));
 
-       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);
+       return std::make_tuple(std::move(dbOp), permission, retCode);
+}
 
+std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       auto [dbOp, retCode] = begin(cred, name, owner);
        if (retCode != CKM_API_SUCCESS)
-               return retCode;
+               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);
+       retCode = dbOp.loadAppKey(false);
+       if (retCode != CKM_API_SUCCESS)
+               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);
+       // 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);
+       }
 
-       handler.database.saveRow(row);
+       if (dbOp.database().isNameOwnerPresent(name, owner))
+               retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
 
-       transaction.commit();
-       return CKM_API_SUCCESS;
+       return std::make_tuple(std::move(dbOp), retCode);
 }
 
-int CKMLogic::createKeyPairHelper(
+std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
        const Credentials &cred,
-       const CryptoAlgorithmSerializable &keyGenParams,
-       const Name &namePrivate,
-       const Label &labelPrivate,
-       const Name &namePublic,
-       const Label &labelPublic,
-       const PolicySerializable &policyPrivate,
-       const PolicySerializable &policyPublic)
+       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);
+       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;
+       }
 
-       transactionPub.commit();
-       transactionPriv.commit();
-       return CKM_API_SUCCESS;
+       return std::make_tuple(std::move(dbOp), std::move(digest), retCode);
 }
 
 RawBuffer CKMLogic::createKeyPair(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const CryptoAlgorithmSerializable &keyGenParams,
-       const Name &namePrivate,
-       const Label &labelPrivate,
-       const Name &namePublic,
-       const Label &labelPublic,
-       const PolicySerializable &policyPrivate,
-       const PolicySerializable &policyPublic)
+       const Name &namePrv,
+       const ClientId &ownerPrv,
+       const Name &namePub,
+       const ClientId &ownerPub,
+       const PolicySerializable &policyPrv,
+       const PolicySerializable &policyPub)
 {
-       int retCode = CKM_API_SUCCESS;
+       return SerializeMessage(msgId, tryRet([&] {
+               auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
+               if (retCodePrv != CKM_API_SUCCESS)
+                       return retCodePrv;
 
-       try {
-               retCode = createKeyPairHelper(
-                                         cred,
-                                         keyGenParams,
-                                         namePrivate,
-                                         labelPrivate,
-                                         namePublic,
-                                         labelPublic,
-                                         policyPrivate,
-                                         policyPublic);
-       } 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 [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);
 
-       return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_PAIR),
-                                                                       commandId, retCode).Pop();
+               // 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,
+       int msgId,
        const int size,
        const Name &name,
-       const Label &label,
+       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();
+               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;
-       } 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();
+       return SerializeMessage(msgId, retCode);
 }
 
 int CKMLogic::readCertificateHelper(
        const Credentials &cred,
-       const LabelNameVector &labelNameVector,
+       const OwnerNameVector &ownerNameVector,
        CertificateImplVector &certVector)
 {
-       DB::Row row;
-
-       for (auto &i : labelNameVector) {
+       for (auto &i : ownerNameVector) {
                // certificates can't be protected with custom user password
                Crypto::GObjUPtr obj;
                int ec;
@@ -1475,7 +1236,7 @@ int CKMLogic::readCertificateHelper(
                                                        cred,
                                                        DataType::CERTIFICATE,
                                                        i.second,
-                                                       i.first,
+                                                       cred.effectiveOwner(i.first),
                                                        Password(),
                                                        obj);
 
@@ -1490,7 +1251,7 @@ int CKMLogic::readCertificateHelper(
                                                        cred,
                                                        DataType::DB_CHAIN_FIRST,
                                                        i.second,
-                                                       i.first,
+                                                       cred.effectiveOwner(i.first),
                                                        CKM::Password(),
                                                        caChainObjs);
 
@@ -1556,15 +1317,14 @@ int CKMLogic::getCertificateChainHelper(
 int CKMLogic::getCertificateChainHelper(
        const Credentials &cred,
        const CertificateImpl &cert,
-       const LabelNameVector &untrusted,
-       const LabelNameVector &trusted,
+       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;
@@ -1598,7 +1358,7 @@ int CKMLogic::getCertificateChainHelper(
 
 RawBuffer CKMLogic::getCertificateChain(
        const Credentials & /*cred*/,
-       int commandId,
+       int msgId,
        const RawBuffer &certificate,
        const RawBufferVector &untrustedCertificates,
        const RawBufferVector &trustedCertificates,
@@ -1623,20 +1383,15 @@ RawBuffer CKMLogic::getCertificateChain(
                LogError("Unknown error.");
        }
 
-       auto response = MessageBuffer::Serialize(static_cast<int>
-                                       (LogicCommand::GET_CHAIN_CERT),
-                                       commandId,
-                                       retCode,
-                                       chainRawVector);
-       return response.Pop();
+       return SerializeMessage(msgId, retCode, chainRawVector);
 }
 
 RawBuffer CKMLogic::getCertificateChain(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const RawBuffer &certificate,
-       const LabelNameVector &untrustedCertificates,
-       const LabelNameVector &trustedCertificates,
+       const OwnerNameVector &untrustedCertificates,
+       const OwnerNameVector &trustedCertificates,
        bool useTrustedSystemCertificates)
 {
        int retCode = CKM_API_ERROR_UNKNOWN;
@@ -1659,190 +1414,261 @@ RawBuffer CKMLogic::getCertificateChain(
                LogError("Unknown error.");
        }
 
-       auto response = MessageBuffer::Serialize(static_cast<int>
-                                       (LogicCommand::GET_CHAIN_ALIAS),
-                                       commandId,
-                                       retCode,
-                                       chainRawVector);
-       return response.Pop();
+       return SerializeMessage(msgId, retCode, chainRawVector);
 }
 
 RawBuffer CKMLogic::createSignature(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const Name &privateKeyName,
-       const Label &ownerLabel,
+       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);
+               retCode = tryRet([&] {
+                       Crypto::GObjUPtr obj;
+                       int retCode2 = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
+                                                                                 owner, password, obj);
 
-               if (retCode == CKM_API_SUCCESS)
-                       signature = obj->sign(cryptoAlg, message);
-       } 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;
+                       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;
        }
 
-       auto response = MessageBuffer::Serialize(static_cast<int>
-                                       (LogicCommand::CREATE_SIGNATURE),
-                                       commandId,
-                                       retCode,
-                                       signature);
-       return response.Pop();
+       return SerializeMessage(msgId, retCode, signature);
 }
 
 RawBuffer CKMLogic::verifySignature(
        const Credentials &cred,
-       int commandId,
+       int msgId,
        const Name &publicKeyOrCertName,
-       const Label &ownerLabel,
+       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;
-
+       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;
-               retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
-                                                                publicKeyOrCertName, ownerLabel, password, 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, ownerLabel, password, obj);
+                                                                        publicKeyOrCertName, owner, password, obj);
 
                if (retCode == CKM_API_SUCCESS)
                        retCode = obj->verify(params, message, signature);
-       } 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::VERIFY_SIGNATURE),
-                                       commandId,
-                                       retCode);
-       return response.Pop();
+               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 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;
-
-       // verify name and label are correct
-       if (!isNameValid(name) || !isLabelValid(ownerLabel) ||
-                       !isLabelValid(accessorLabel))
-               return CKM_API_ERROR_INPUT_PARAM;
+       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 (ownerLabel == accessorLabel)
+       if (owner == accessor)
                return CKM_API_ERROR_INPUT_PARAM;
 
        // system database does not support write/remove permissions
-       if ((0 == ownerLabel.compare(OWNER_ID_SYSTEM)) &&
-                       (permissionMask & Permission::REMOVE))
+       if ((0 == owner.compare(CLIENT_ID_SYSTEM)) && (permissionMask & Permission::REMOVE))
                return CKM_API_ERROR_INPUT_PARAM;
 
-       // can the client modify permissions to owner's row?
-       int retCode = m_accessControl.canModify(cred, ownerLabel);
+       // set permissions to the row owned by owner for accessor
+       dbOp.database().setPermission(name, owner, accessor, permissionMask);
+       dbOp.transaction().commit();
 
-       if (retCode != CKM_API_SUCCESS)
-               return retCode;
+       return CKM_API_SUCCESS;
+}
 
-       DB::Crypto::Transaction transaction(&handler.database);
+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);
+       }));
+}
 
-       if (!handler.database.isNameLabelPresent(name, ownerLabel))
-               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
+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;
+               }
 
-       // removing non-existing permissions: fail
-       if (permissionMask == Permission::NONE) {
-               if (!handler.database.getPermissionRow(name, ownerLabel, accessorLabel))
+               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;
-       }
+               }
 
-       // set permissions to the row owned by ownerLabel for accessorLabel
-       handler.database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
-       transaction.commit();
+               // derive
+               Token derived = obj->derive(params, newKeyPolicy.password, digest);
 
-       return CKM_API_SUCCESS;
+               dbOp.finalize(std::move(derived), newKeyPolicy);
+
+               return CKM_API_SUCCESS;
+       }));
 }
 
-RawBuffer CKMLogic::setPermission(
+RawBuffer CKMLogic::importWrappedKey(
+       const Credentials &cred,
+       const int msgId,
+       const CryptoAlgorithm &params,
+       const Name &wrappingKeyName,
+       const ClientId &wrappingKeyOwner,
+       const Password &wrappingKeyPassword,
+       const Name &keyName,
+       const ClientId &keyOwner,
+       const RawBuffer &wrappedKey,
+       const CKM::DataType keyType,
+       const PolicySerializable &policy)
+{
+       return SerializeMessage(msgId, tryRet([&] {
+               Crypto::GObjUPtr wrappingKey;
+
+               auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, keyName, keyOwner);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
+                                                               wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+
+               if (!m_decider.checkStore(wrappingKey->backendId(), keyType, policy, true)) {
+                       LogDebug("Can't import the wrapped key to backend " <<
+                                static_cast<int>(wrappingKey->backendId()) << " with given policy");
+                       return CKM_API_ERROR_INPUT_PARAM;
+               }
+
+               Token token = wrappingKey->unwrap(params,
+                                                                                 Crypto::Data(keyType, std::move(wrappedKey)),
+                                                                                 policy.password,
+                                                                                 digest);
+
+               dbOp.finalize(std::move(token), policy);
+
+               return retCode;
+       }));
+}
+
+RawBuffer CKMLogic::exportWrappedKey(
        const Credentials &cred,
-       const int command,
        const int msgID,
-       const Name &name,
-       const Label &label,
-       const Label &accessorLabel,
-       const PermissionMask permissionMask)
+       const CryptoAlgorithm &params,
+       const Name &wrappingKeyName,
+       const ClientId &wrappingKeyOwner,
+       const Password &wrappingKeyPassword,
+       const Name &keyName,
+       const ClientId &keyOwner,
+       const Password &keyPassword)
 {
-       int retCode;
+       Crypto::GObjUPtr wrappingKey;
+       DB::Row wrappedKeyRow;
+       DataType wrappedKeyType;
+       RawBuffer wrappedKey;
 
-       try {
-               retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
-       } catch (const Exc::Exception &e) {
-               retCode = e.error();
-       } catch (const CKM::Exception &e) {
-               LogError("Error: " << e.GetMessage());
-               retCode = CKM_API_ERROR_DB_ERROR;
-       }
+       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 MessageBuffer::Serialize(command, msgID, retCode).Pop();
+       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);
+       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;
 
-               if (!key_optional) {
-                       LogError("No key for given label in database");
-                       return CKM_API_ERROR_DB_ERROR;
+               auto store = m_decider.getStore(cryptoBackend);
+               if (store == nullptr) {
+                       LogError("Required backend is unavailable");
+                       return CKM_API_ERROR_INPUT_PARAM;
                }
 
-               key = *key_optional;
-               key = handle.keyProvider.getPureDEK(key);
-               handle.crypto.pushKey(appLabel, key);
-       }
+               info.maxChunkSize = store->maxChunkSize();
+               return CKM_API_SUCCESS;
+       });
 
-       return CKM_API_SUCCESS;
+       return SerializeMessage(msgID, retCode, BackendInfoSerializable(info));
 }
 
 } // namespace CKM
-