Unify CKMLogic methods and fix PKCS12 support 73/287973/3
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 6 Feb 2023 08:50:25 +0000 (09:50 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 9 Feb 2023 14:49:09 +0000 (15:49 +0100)
Add helper functions for frequently repeated code (input parameter
checks, database selection, permission checks, hash calculation,
transaction start)

Fixed object Id is calculated from uid, pkg_id & alias. PKCS12
components are stored under common alias differing only by type. As a
result, all PKCS12 components are saved with identical object id which
may lead to conflicts.

For PKCS12 add type information as hash function input.

Change-Id: Id54c5eb4e0ad5b3521f2661df64619316cf4a9ea

src/manager/service/access-control.cpp
src/manager/service/access-control.h
src/manager/service/ckm-logic.cpp
src/manager/service/ckm-logic.h
src/manager/service/crypto-logic.cpp
src/manager/service/crypto-logic.h
src/manager/service/db-crypto.h

index 7c08c03..39abb72 100644 (file)
@@ -66,7 +66,6 @@ bool AccessControl::isSystemService(const CKM::Credentials &cred) const
        return isSystemService(cred.clientUid);
 }
 
-
 int AccessControl::canSave(
        const CKM::Credentials &accessorCred,
        const ClientId &owner) const
@@ -85,13 +84,6 @@ int AccessControl::canSave(
        return CKM_API_SUCCESS;
 }
 
-int AccessControl::canModify(
-       const CKM::Credentials &accessorCred,
-       const ClientId &owner) const
-{
-       return canSave(accessorCred, owner);
-}
-
 int AccessControl::canRead(
        const CKM::Credentials &accessorCred,
        const PermissionMask &existingPermission) const
index 3e50ce3..91d71f5 100644 (file)
@@ -47,13 +47,6 @@ public:
                                const ClientId &owner) const;
 
        /**
-        * check if given data can be modified by accessor
-        * @return CKM_API_SUCCESS if access is allowed, otherwise negative error code
-        */
-       int canModify(const CKM::Credentials &accessorCred,
-                                 const ClientId &owner) const;
-
-       /**
         * check if given row can be read (for internal use)
         * @return CKM_API_SUCCESS if access is allowed, otherwise negative error code
         */
index 330423a..d39ca76 100644 (file)
@@ -119,7 +119,7 @@ int toBinaryData(const Crypto::Data &input, Crypto::Data &output)
        return CKM_API_SUCCESS;
 }
 
-int verifyBinaryData(Crypto::Data &input)
+int verifyBinaryData(const Crypto::Data &input)
 {
        Crypto::Data dummy;
        return toBinaryData(input, dummy);
@@ -191,30 +191,6 @@ int readMultiRow(const Name &name,
        return CKM_API_SUCCESS;
 }
 
-int loadAppKey(UserData &handler, const ClientId &owner, bool keyRequired = true)
-{
-       if (!handler.crypto.haveKey(owner)) {
-               RawBuffer wrappedDEK;
-               auto wrappedDEKOptional = handler.database.getKey(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: " << owner);
-                       wrappedDEK = handler.keyProvider.generateDEK(owner);
-                       handler.database.saveKey(owner, wrappedDEK);
-               } else {
-                       wrappedDEK = *wrappedDEKOptional;
-               }
-
-               handler.crypto.pushKey(owner, handler.keyProvider.getPureDEK(wrappedDEK));
-       }
-
-       return CKM_API_SUCCESS;
-}
-
 } // namespace
 
 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
@@ -477,57 +453,6 @@ RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
        }));
 }
 
-int CKMLogic::checkSaveConditions(
-       const Credentials &accessorCred,
-       UserData &handler,
-       const Name &name,
-       const ClientId &owner)
-{
-       // verify name and client are correct
-       if (!isNameValid(name) || !isClientValid(owner)) {
-               LogDebug("Invalid parameter passed to key-manager");
-               return CKM_API_ERROR_INPUT_PARAM;
-       }
-
-       // check if accessor is allowed to save owner's items
-       int access_ec = m_accessControl.canSave(accessorCred, owner);
-
-       if (access_ec != CKM_API_SUCCESS) {
-               LogDebug("accessor " << accessorCred.client << " can not save rows owned by " <<
-                                owner);
-               return access_ec;
-       }
-
-       // check if not a duplicate
-       if (handler.database.isNameOwnerPresent(name, owner))
-               return CKM_API_ERROR_DB_ALIAS_EXISTS;
-
-       // generate (if needed) and load the app key
-       loadAppKey(handler, owner, false);
-
-       return CKM_API_SUCCESS;
-}
-
-DB::Row CKMLogic::createEncryptedRow(
-       CryptoLogic &crypto,
-       const Name &name,
-       const ClientId &owner,
-       const Crypto::Data &data,
-       const Policy &policy,
-       const RawBuffer &hash)
-{
-       Crypto::GStore &store = m_decider.getStore(data.type, policy);
-
-       // do not encrypt data with password during cc_mode on
-       Token token = store.import(data,
-                                                          m_accessControl.isCCMode() ? "" : policy.password,
-                                                          Crypto::EncryptionParams(), hash);
-       DB::Row row(std::move(token), name, owner,
-                               static_cast<int>(policy.extractable));
-       crypto.encryptRow(row);
-       return row;
-}
-
 int CKMLogic::verifyAndSaveDataHelper(
        const Credentials &cred,
        const Name &name,
@@ -576,72 +501,6 @@ RawBuffer CKMLogic::saveData(
        return SerializeMessage(msgId, retCode, data.type);
 }
 
-int CKMLogic::extractPKCS12Data(
-       CryptoLogic &crypto,
-       const Name &name,
-       const ClientId &owner,
-       const PKCS12Serializable &pkcs,
-       const PolicySerializable &keyPolicy,
-       const PolicySerializable &certPolicy,
-       DB::RowVector &output,
-       const Credentials &cred)
-{
-       // private key is mandatory
-       auto key = pkcs.getKey();
-
-       if (!key) {
-               LogError("Failed to get private key from pkcs");
-               return CKM_API_ERROR_INVALID_FORMAT;
-       }
-
-       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
-       if (digest.empty())
-               return CKM_API_ERROR_HASH_ERROR;
-
-       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, owner, keyData,
-                                                                               keyPolicy, digest));
-
-       // 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, owner, certData,
-                                                                               certPolicy, digest));
-
-       // 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, owner, caCertData,
-                                                                                       certPolicy, digest));
-       }
-
-       return CKM_API_SUCCESS;
-}
-
 RawBuffer CKMLogic::savePKCS12(
        const Credentials &cred,
        int msgId,
@@ -656,27 +515,16 @@ RawBuffer CKMLogic::savePKCS12(
        }));
 }
 
-
 int CKMLogic::removeDataHelper(
        const Credentials &cred,
        const Name &name,
        const ClientId &owner)
 {
-       auto &handler = selectDatabase(cred, owner);
-
-       if (!isNameValid(name) || !isClientValid(owner)) {
-               LogDebug("Invalid owner or name format");
-               return CKM_API_ERROR_INPUT_PARAM;
-       }
-
-       DB::Crypto::Transaction transaction(&handler.database);
-
-       // read and check permissions
-       PermissionMaskOptional permissionRowOpt =
-               handler.database.getPermissionRow(name, owner, cred.client);
-       int retCode = m_accessControl.canDelete(cred,
-                                                                                       toPermissionMask(permissionRowOpt));
+       auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
+       retCode = m_accessControl.canDelete(cred, permission);
        if (retCode != CKM_API_SUCCESS) {
                LogWarning("access control check result: " << retCode);
                return retCode;
@@ -684,24 +532,20 @@ int CKMLogic::removeDataHelper(
 
        // get all matching rows
        DB::RowVector rows;
-       handler.database.getRows(name, owner, DataType::DB_FIRST,
-                                                        DataType::DB_LAST, 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;
        }
 
-       // load app key if needed
-       retCode = loadAppKey(handler, rows.front().owner);
-
-       if (CKM_API_SUCCESS != retCode)
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
                return retCode;
 
        // destroy it in store
        for (auto &r : rows) {
                try {
-                       handler.crypto.decryptRow(Password(), r);
+                       dbOp.handler().crypto.decryptRow(Password(), r);
                        m_decider.getStore(r).destroy(r);
                } catch (const Exc::AuthenticationFailed &) {
                        LogDebug("Authentication failed when removing data. Ignored.");
@@ -709,8 +553,8 @@ int CKMLogic::removeDataHelper(
        }
 
        // delete row in db
-       handler.database.deleteRow(name, owner);
-       transaction.commit();
+       dbOp.database().deleteRow(name, owner);
+       dbOp.transaction().commit();
 
        return CKM_API_SUCCESS;
 }
@@ -728,22 +572,14 @@ RawBuffer CKMLogic::removeData(
 
 
 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
-               const Name &name,
-               const ClientId &owner,
                const DB::Row &row,
                bool exportFlag,
-               DB::Crypto &database)
+               const PermissionMask& permission)
 {
-       PermissionMaskOptional permissionRowOpt =
-               database.getPermissionRow(name, owner, accessorCred.client);
-
        if (exportFlag)
-               return m_accessControl.canExport(accessorCred,
-                                                                                row,
-                                                                                toPermissionMask(permissionRowOpt));
+               return m_accessControl.canExport(accessorCred, row, permission);
 
-       return m_accessControl.canRead(accessorCred,
-                                                                  toPermissionMask(permissionRowOpt));
+       return m_accessControl.canRead(accessorCred, permission);
 }
 
 Crypto::GObjUPtr CKMLogic::rowToObject(
@@ -801,16 +637,13 @@ int CKMLogic::readDataHelper(
        const Password &password,
        Crypto::GObjUPtrVector &objs)
 {
-       auto &handler = selectDatabase(cred, owner);
-
-       if (!isNameValid(name) || !isClientValid(owner))
-               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, owner, dataType, handler.database, rows);
-
+       retCode = readMultiRow(name, owner, dataType, dbOp.database(), rows);
        if (CKM_API_SUCCESS != retCode)
                return retCode;
 
@@ -818,28 +651,34 @@ int CKMLogic::readDataHelper(
        DB::Row &firstRow = rows.at(0);
 
        // check access rights
-       retCode = checkDataPermissionsHelper(cred, name, owner, 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.owner);
+       // for multiple objects add type as hash input (see pkcs12)
+       bool multiple = rows.size() > 1;
 
-       if (CKM_API_SUCCESS != retCode)
-               return retCode;
+       RawBuffer digest;
 
-       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
-       if (digest.empty())
-               return CKM_API_ERROR_HASH_ERROR;
+       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, digest));
+       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;
 }
@@ -868,31 +707,23 @@ int CKMLogic::readDataHelper(
        Crypto::GObjUPtr &obj,
        DataType &objDataType)
 {
-       auto &handler = selectDatabase(cred, owner);
-
-       if (!isNameValid(name) || !isClientValid(owner))
-               return CKM_API_ERROR_INPUT_PARAM;
+       auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
 
-       // read row
-       DB::Crypto::Transaction transaction(&handler.database);
        DB::Row row;
-       int retCode = readSingleRow(name, owner, dataType, handler.database, row);
-
+       retCode = readSingleRow(name, owner, dataType, dbOp.database(), row);
        if (CKM_API_SUCCESS != retCode)
                return retCode;
 
-       objDataType = row.dataType;
-
-       // check access rights
-       retCode = checkDataPermissionsHelper(cred, name, owner, row, exportFlag,
-                                                                                handler.database);
-
-       if (CKM_API_SUCCESS != retCode)
+       retCode = dbOp.loadAppKey();
+       if (retCode != CKM_API_SUCCESS)
                return retCode;
 
-       // load app key if needed
-       retCode = loadAppKey(handler, row.owner);
+       objDataType = row.dataType;
 
+       // check access rights
+       retCode = checkDataPermissionsHelper(cred, row, exportFlag, permission);
        if (CKM_API_SUCCESS != retCode)
                return retCode;
 
@@ -900,9 +731,9 @@ int CKMLogic::readDataHelper(
        if (digest.empty())
                return CKM_API_ERROR_HASH_ERROR;
 
-       obj = rowToObject(handler, std::move(row), password, digest);
+       obj = rowToObject(dbOp.handler(), std::move(row), password, digest);
        // rowToObject may modify db
-       transaction.commit();
+       dbOp.transaction().commit();
 
        return CKM_API_SUCCESS;
 }
@@ -1134,24 +965,16 @@ int CKMLogic::importInitialData(
                        }
 
                        // Inital values are always imported with root credentials. Client id is not important.
-                       Credentials rootCred(0, "");
-                       ClientId owner(CLIENT_ID_SYSTEM);
-                       auto &handler = selectDatabase(rootCred, CLIENT_ID_SYSTEM);
+                       Credentials rootCred(0, "whatever");
+                       ClientId owner(CLIENT_ID_SYSTEM);
 
-                       // check if save is possible
-                       DB::Crypto::Transaction transaction(&handler.database);
-                       int retCode = checkSaveConditions(rootCred, handler, name, CLIENT_ID_SYSTEM);
+                       auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
                        if (retCode != CKM_API_SUCCESS)
                                return retCode;
 
                        Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
 
                        Token token;
-
-                       auto digest = CryptoLogic::makeHash(name, owner, rootCred.clientUid);
-                       if (digest.empty())
-                               return CKM_API_ERROR_HASH_ERROR;
-
                        if (encParams.iv.empty()) {
                                // Data are not encrypted, let's try to verify them
                                Crypto::Data binaryData;
@@ -1168,12 +991,7 @@ int CKMLogic::importInitialData(
                                                                         encParams, digest);
                        }
 
-                       DB::Row row(std::move(token), name, CLIENT_ID_SYSTEM,
-                                               static_cast<int>(policy.extractable));
-                       handler.crypto.encryptRow(row);
-
-                       handler.database.saveRow(row);
-                       transaction.commit();
+                       dbOp.finalize(std::move(token), policy);
 
                        return CKM_API_SUCCESS;
                });
@@ -1190,24 +1008,17 @@ int CKMLogic::saveDataHelper(
        const Crypto::Data &data,
        const PolicySerializable &policy)
 {
-       auto &handler = selectDatabase(cred, owner);
-
-       // check if save is possible
-       DB::Crypto::Transaction transaction(&handler.database);
-       int retCode = checkSaveConditions(cred, handler, name, owner);
-       if (retCode != CKM_API_SUCCESS)
-               return retCode;
-
-       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
-       if (digest.empty())
-               return CKM_API_ERROR_HASH_ERROR;
+       auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, name, owner);
+       if (ret != CKM_API_SUCCESS)
+               return ret;
 
-       // save the data
-       DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, owner,
-                                                  data, policy, digest);
-       handler.database.saveRow(encryptedRow);
+       Crypto::GStore &store = m_decider.getStore(data.type, policy);
 
-       transaction.commit();
+       // do not encrypt data with password during cc_mode on
+       Token token = store.import(data,
+                                                          m_accessControl.isCCMode() ? "" : policy.password,
+                                                          Crypto::EncryptionParams(), digest);
+       dbOp.finalize(std::move(token), policy);
        return CKM_API_SUCCESS;
 }
 
@@ -1219,153 +1030,213 @@ int CKMLogic::saveDataHelper(
        const PolicySerializable &keyPolicy,
        const PolicySerializable &certPolicy)
 {
-       auto &handler = selectDatabase(cred, owner);
-
-       // check if save is possible
-       DB::Crypto::Transaction transaction(&handler.database);
-       int retCode = checkSaveConditions(cred, handler, name, owner);
+       auto [dbOp, retCode] = beginSave(cred, name, owner);
        if (retCode != CKM_API_SUCCESS)
                return retCode;
 
        // extract and encrypt the data
        DB::RowVector encryptedRows;
-       retCode = extractPKCS12Data(handler.crypto, name, owner, pkcs, keyPolicy,
-                                                               certPolicy, encryptedRows, cred);
 
-       if (retCode != CKM_API_SUCCESS)
-               return retCode;
+       auto import = [&](const Crypto::Data &data, const Policy& policy){
+               retCode = verifyBinaryData(data);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
 
-       // save the data
-       handler.database.saveRows(name, owner, encryptedRows);
-       transaction.commit();
+               auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid, data.type);
+               if (digest.empty())
+                       return CKM_API_ERROR_HASH_ERROR;
 
-       return CKM_API_SUCCESS;
-}
+               Crypto::GStore &store = m_decider.getStore(data.type, policy);
 
+               // do not encrypt data with password during cc_mode on
+               Token token = store.import(data,
+                                                                  m_accessControl.isCCMode() ? "" : policy.password,
+                                                                  Crypto::EncryptionParams(), digest);
 
-int CKMLogic::createKeyAESHelper(
-       const Credentials &cred,
-       const int size,
-       const Name &name,
-       const ClientId &owner,
-       const PolicySerializable &policy)
-{
-       auto &handler = selectDatabase(cred, owner);
+               encryptedRows.push_back(dbOp.encryptOne(std::move(token), policy));
+               return CKM_API_SUCCESS;
+       };
 
-       // check if save is possible
-       DB::Crypto::Transaction transaction(&handler.database);
-       int retCode = checkSaveConditions(cred, handler, name, owner);
+       // private key is mandatory
+       auto key = pkcs.getKey();
+       if (!key) {
+               LogError("Failed to get private key from pkcs");
+               return CKM_API_ERROR_INVALID_FORMAT;
+       }
+
+       Crypto::Data keyData(DataType(key->getType()), key->getDER());
+       retCode = import(keyData, keyPolicy);
        if (retCode != CKM_API_SUCCESS)
                return retCode;
 
-       auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
-       if (digest.empty())
-               return CKM_API_ERROR_HASH_ERROR;
+       // certificate is mandatory
+       auto cert = pkcs.getCertificate();
+       if (!cert) {
+               LogError("Failed to get certificate from pkcs");
+               return CKM_API_ERROR_INVALID_FORMAT;
+       }
 
-       // 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).generateSKey(keyGenAlgorithm, policy.password, digest);
+       Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
+       retCode = import(certData, certPolicy);
+       if (retCode != CKM_API_SUCCESS)
+               return retCode;
+
+       // CA cert chain
+       unsigned int cert_index = 0;
+       for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
+               Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++), ca->getDER());
+               retCode = import(caCertData, certPolicy);
+               if (retCode != CKM_API_SUCCESS)
+                       return retCode;
+       }
 
        // save the data
-       DB::Row row(std::move(key), name, owner,
-                               static_cast<int>(policy.extractable));
-       handler.crypto.encryptRow(row);
+       dbOp.database().saveRows(name, owner, encryptedRows);
+       dbOp.transaction().commit();
+
+       return CKM_API_SUCCESS;
+}
+
+int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
+{
+       if (!m_handler.crypto.haveKey(m_owner)) {
+               RawBuffer wrappedDEK;
+               auto wrappedDEKOptional = m_handler.database.getKey(m_owner);
+
+               if (!wrappedDEKOptional) {
+                       if (keyRequired) {
+                               LogError("No key for given owner in database");
+                               return CKM_API_ERROR_DB_ERROR;
+                       }
+                       LogDebug("No Key in database found. Generating new one for client: " << m_owner);
+                       wrappedDEK = m_handler.keyProvider.generateDEK(m_owner);
+                       m_handler.database.saveKey(m_owner, wrappedDEK);
+               } else {
+                       wrappedDEK = *wrappedDEKOptional;
+               }
 
-       handler.database.saveRow(row);
+               m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
+       }
 
-       transaction.commit();
        return CKM_API_SUCCESS;
 }
 
-int CKMLogic::createKeyPairHelper(
+std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
        const Credentials &cred,
-       const CryptoAlgorithmSerializable &keyGenParams,
-       const Name &namePrivate,
-       const ClientId &ownerPrivate,
-       const Name &namePublic,
-       const ClientId &ownerPublic,
-       const PolicySerializable &policyPrivate,
-       const PolicySerializable &policyPublic)
+       const Name &name,
+       const ClientId &owner)
 {
-       auto &handlerPriv = selectDatabase(cred, ownerPrivate);
-       auto &handlerPub = selectDatabase(cred, ownerPublic);
-
-       AlgoType keyType = AlgoType::RSA_GEN;
+       auto &handler = selectDatabase(cred, owner);
+       DBOperation op(handler, name, owner);
 
-       if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
-               ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
+       if (cred.client.empty() || !isClientValid(cred.client) ||
+               !isNameValid(name) || !isClientValid(owner))
+               return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
 
-       const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType);
-       if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end())
-               ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
-       const DataTypePair& dt = dtIt->second;
+       return std::make_tuple(std::move(op), CKM_API_SUCCESS);
+}
 
-       if (policyPrivate.backend != policyPublic.backend)
-               ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
+std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       PermissionMask permission;
+       auto [dbOp, retCode] = begin(cred, name, owner);
+       if (retCode == CKM_API_SUCCESS)
+               permission = toPermissionMask(dbOp.database().getPermissionRow(name, owner, cred.client));
 
-       bool exportable = policyPrivate.extractable || policyPublic.extractable;
-       Policy lessRestricted(Password(), exportable, policyPrivate.backend);
+       return std::make_tuple(std::move(dbOp), permission, retCode);
+}
 
-       auto digestPriv = CryptoLogic::makeHash(namePrivate, ownerPrivate, cred.clientUid);
-       if (digestPriv.empty())
-               return CKM_API_ERROR_HASH_ERROR;
+std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       auto [dbOp, retCode] = begin(cred, name, owner);
+       if (retCode != CKM_API_SUCCESS)
+               return std::make_tuple(std::move(dbOp), retCode);
 
-       auto digestPub = CryptoLogic::makeHash(namePublic, ownerPublic, cred.clientUid);
-       if (digestPub.empty())
-               return CKM_API_ERROR_HASH_ERROR;
+       retCode = dbOp.loadAppKey(false);
+       if (retCode != CKM_API_SUCCESS)
+               return std::make_tuple(std::move(dbOp), retCode);
 
-       TokenPair keys = m_decider.getStore(policyPrivate, dt.first, dt.second).generateAKey(keyGenParams,
-                                        policyPrivate.password,
-                                        policyPublic.password,
-                                        digestPriv, digestPub);
+       // 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);
+       }
 
-       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);
+       if (dbOp.database().isNameOwnerPresent(name, owner))
+               retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
 
-       int retCode;
-       retCode = checkSaveConditions(cred, handlerPriv, namePrivate, ownerPrivate);
-       if (CKM_API_SUCCESS != retCode)
-               return retCode;
+       return std::make_tuple(std::move(dbOp), retCode);
+}
 
-       retCode = checkSaveConditions(cred, handlerPub, namePublic, ownerPublic);
-       if (CKM_API_SUCCESS != retCode)
-               return retCode;
+std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
+       const Credentials &cred,
+       const Name &name,
+       const ClientId &owner)
+{
+       RawBuffer digest;
+       auto [dbOp, retCode] = beginSave(cred, name, owner);
+       if (retCode == CKM_API_SUCCESS) {
+               digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
+               if (digest.empty())
+                       retCode = CKM_API_ERROR_HASH_ERROR;
+       }
 
-       // save the data
-       DB::Row rowPrv(std::move(keys.first), namePrivate, ownerPrivate,
-                                  static_cast<int>(policyPrivate.extractable));
-       handlerPriv.crypto.encryptRow(rowPrv);
-       handlerPriv.database.saveRow(rowPrv);
-
-       DB::Row rowPub(std::move(keys.second), namePublic, ownerPublic,
-                                  static_cast<int>(policyPublic.extractable));
-       handlerPub.crypto.encryptRow(rowPub);
-       handlerPub.database.saveRow(rowPub);
-
-       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 msgId,
        const CryptoAlgorithmSerializable &keyGenParams,
-       const Name &namePrivate,
-       const ClientId &ownerPrivate,
-       const Name &namePublic,
-       const ClientId &ownerPublic,
-       const PolicySerializable &policyPrivate,
-       const PolicySerializable &policyPublic)
+       const Name &namePrv,
+       const ClientId &ownerPrv,
+       const Name &namePub,
+       const ClientId &ownerPub,
+       const PolicySerializable &policyPrv,
+       const PolicySerializable &policyPub)
 {
        return SerializeMessage(msgId, tryRet([&] {
-               return createKeyPairHelper(cred, keyGenParams, namePrivate, ownerPrivate,
-                                          namePublic, ownerPublic, policyPrivate, policyPublic);
+               auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
+               if (retCodePrv != CKM_API_SUCCESS)
+                       return retCodePrv;
+
+               auto [dbOpPub, digestPub, retCodePub] = beginSaveAndGetHash(cred, namePub, ownerPub);
+               if (retCodePub != CKM_API_SUCCESS)
+                       return retCodePub;
+
+               AlgoType keyType = AlgoType::RSA_GEN;
+
+               if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
+                       ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
+
+               const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType);
+               if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end())
+                       ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
+               const DataTypePair& dt = dtIt->second;
+
+               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);
+
+               TokenPair keys = m_decider.getStore(policyPrv, dt.first, dt.second).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;
        }));
 }
 
@@ -1381,7 +1252,20 @@ RawBuffer CKMLogic::createKeyAES(
 
        try {
                retCode = tryRet([&] {
-                       return createKeyAESHelper(cred, size, name, owner, policy);
+                       auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, name, owner);
+                       if (retCode != CKM_API_SUCCESS)
+                               return 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).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());
@@ -1653,40 +1537,25 @@ int CKMLogic::setPermissionHelper(
        const ClientId &accessor,             // who will get the access
        const PermissionMask permissionMask)
 {
-       auto &handler = selectDatabase(cred, owner);
-
-       // we don't know the client
-       if (cred.client.empty() || !isClientValid(cred.client))
-               return CKM_API_ERROR_INPUT_PARAM;
-
-       // verify name and owner are correct
-       if (!isNameValid(name) || !isClientValid(owner) ||
-                       !isClientValid(accessor))
-               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 (owner == accessor)
                return CKM_API_ERROR_INPUT_PARAM;
 
        // system database does not support write/remove permissions
-       if ((0 == owner.compare(CLIENT_ID_SYSTEM)) &&
-                       (permissionMask & Permission::REMOVE))
+       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, owner);
-
-       if (retCode != CKM_API_SUCCESS)
-               return retCode;
-
-       DB::Crypto::Transaction transaction(&handler.database);
-
-       if (!handler.database.isNameOwnerPresent(name, owner))
-               return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
-
        // set permissions to the row owned by owner for accessor
-       handler.database.setPermission(name, owner, accessor, permissionMask);
-       transaction.commit();
+       dbOp.database().setPermission(name, owner, accessor, permissionMask);
+       dbOp.transaction().commit();
 
        return CKM_API_SUCCESS;
 }
index c64a493..b4cc491 100644 (file)
@@ -236,12 +236,6 @@ private:
                uid_t user,
                const Password &password);
 
-       int checkSaveConditions(
-               const Credentials &cred,
-               UserData &handler,
-               const Name &name,
-               const ClientId &owner);
-
        int saveDataHelper(
                const Credentials &cred,
                const Name &name,
@@ -257,14 +251,6 @@ private:
                const PolicySerializable &keyPolicy,
                const PolicySerializable &certPolicy);
 
-       DB::Row createEncryptedRow(
-               CryptoLogic &crypto,
-               const Name &name,
-               const ClientId &owner,
-               const Crypto::Data &data,
-               const Policy &policy,
-               const RawBuffer &hash);
-
        int getPKCS12Helper(
                const Credentials &cred,
                const Name &name,
@@ -275,16 +261,6 @@ private:
                CertificateShPtr &cert,
                CertificateShPtrVector &caChain);
 
-       int extractPKCS12Data(
-               CryptoLogic &crypto,
-               const Name &name,
-               const ClientId &owner,
-               const PKCS12Serializable &pkcs,
-               const PolicySerializable &keyPolicy,
-               const PolicySerializable &certPolicy,
-               DB::RowVector &output,
-               const Credentials &cred);
-
        int removeDataHelper(
                const Credentials &cred,
                const Name &name,
@@ -292,11 +268,9 @@ private:
 
        int checkDataPermissionsHelper(
                const Credentials &accessorCred,
-               const Name &name,
-               const ClientId &owner,
                const DB::Row &row,
                bool exportFlag,
-               DB::Crypto &database);
+               const PermissionMask& permission);
 
        Crypto::GObjUPtr rowToObject(
                UserData &handler,
@@ -333,23 +307,6 @@ private:
                const Password &password,
                Crypto::GObjUPtrVector &objs);
 
-       int createKeyAESHelper(
-               const Credentials &cred,
-               const int size,
-               const Name &name,
-               const ClientId &owner,
-               const PolicySerializable &policy);
-
-       int createKeyPairHelper(
-               const Credentials &cred,
-               const CryptoAlgorithmSerializable &keyGenParams,
-               const Name &namePrivate,
-               const ClientId &ownerPrivate,
-               const Name &namePublic,
-               const ClientId &ownerPublic,
-               const PolicySerializable &policyPrivate,
-               const PolicySerializable &policyPublic);
-
        int readCertificateHelper(
                const Credentials &cred,
                const OwnerNameVector &ownerNameVector,
@@ -383,6 +340,60 @@ private:
 
        void migrateSecureStorageData(bool isAdminUser);
 
+       class DBOperation {
+       public:
+               DBOperation(UserData& handler, const Name &name, const ClientId &owner) :
+                       m_handler(handler),
+                       m_transaction(&handler.database),
+                       m_name(name),
+                       m_owner(owner) {
+               }
+
+               DB::Row encryptOne(Token&& token, const Policy& policy) {
+                       DB::Row row(std::move(token), m_name, m_owner, static_cast<int>(policy.extractable));
+                       m_handler.crypto.encryptRow(row);
+                       return row;
+               }
+
+               void finalize(Token&& token, const Policy& policy) {
+                       auto row = encryptOne(std::move(token), policy);
+                       m_handler.database.saveRow(row);
+                       m_transaction.commit();
+               }
+
+               DB::Crypto& database() { return m_handler.database; }
+               DB::Crypto::Transaction& transaction() { return m_transaction; }
+               UserData& handler() { return m_handler; }
+               PermissionMask permission(const Credentials &cred) {
+                       return toPermissionMask(
+                               m_handler.database.getPermissionRow(m_name, m_owner, cred.client));
+               }
+               int loadAppKey(bool keyRequired = true);
+
+       private:
+               UserData& m_handler;
+               DB::Crypto::Transaction m_transaction;
+               const Name& m_name;
+               const ClientId& m_owner;
+       };
+
+       std::tuple<DBOperation, int> begin(
+               const Credentials &cred,
+               const Name &name,
+               const ClientId &owner);
+       std::tuple<DBOperation, PermissionMask, int> beginAndGetPerm(
+               const Credentials &cred,
+               const Name &name,
+               const ClientId &owner);
+       std::tuple<CKMLogic::DBOperation, int> beginSave(
+               const Credentials &cred,
+               const Name &name,
+               const ClientId &owner);
+       std::tuple<CKMLogic::DBOperation, RawBuffer, int> beginSaveAndGetHash(
+               const Credentials &cred,
+               const Name &name,
+               const ClientId &owner);
+
        AccessControl m_accessControl;
        Crypto::Decider m_decider;
 
index 810200c..bebdb7a 100644 (file)
@@ -50,6 +50,17 @@ namespace {
 const static int AES_CBC_KEY_SIZE = 32;
 const static int AES_GCM_TAG_SIZE = 16;
 
+RawBuffer makeHashInternal(const std::string& message)
+{
+       RawBuffer digest(SHA512_DIGEST_LENGTH);
+       auto msg_ptr = reinterpret_cast<const unsigned char*>(message.data());
+
+       if (!SHA512(msg_ptr, message.length(), digest.data()))
+               return RawBuffer();
+
+       return digest;
+}
+
 } // anonymous namespace
 
 CryptoLogic::CryptoLogic() {}
@@ -245,13 +256,19 @@ RawBuffer CryptoLogic::makeHash(
        uid_t uid)
 {
        const std::string msg = name + owner + std::to_string(uid);
-       RawBuffer digest(SHA512_DIGEST_LENGTH);
-       auto msg_ptr = reinterpret_cast<const unsigned char*>(msg.data());
 
-       if (!SHA512(msg_ptr, msg.length(), digest.data()))
-           return RawBuffer();
+       return makeHashInternal(msg);
+}
 
-       return digest;
+RawBuffer CryptoLogic::makeHash(
+       const std::string& name,
+       const std::string& owner,
+       uid_t uid,
+       DataType type)
+{
+       const std::string msg = name + owner + std::to_string(uid) + std::to_string(type);
+
+       return makeHashInternal(msg);
 }
 
 } // namespace CKM
index df6131c..6054384 100644 (file)
@@ -53,6 +53,12 @@ public:
                const std::string& owner,
                uid_t uid);
 
+       static RawBuffer makeHash(
+               const std::string& name,
+               const std::string& owner,
+               uid_t uid,
+               DataType type);
+
        /*
         * v1 encryption.
         *    Token returned from store is encrypted with app key and
index 6fd3a39..1b4ec71 100644 (file)
@@ -147,6 +147,25 @@ public:
                        }
                }
 
+               Transaction(Transaction&& other)
+               {
+                       m_db = other.m_db;
+                       m_inTransaction = other.m_inTransaction;
+                       other.m_inTransaction = false;
+               }
+
+               Transaction& operator=(Transaction&& other)
+               {
+                       if (this == &other)
+                               return *this;
+
+                       m_db = other.m_db;
+                       m_inTransaction = other.m_inTransaction;
+                       other.m_inTransaction = false;
+
+                       return *this;
+               }
+
                void commit()
                {
                        if (m_inTransaction) {