2 * Copyright (c) 2014-2021 Samsung Electronics Co., Ltd. All rights reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
20 * @brief Sample service implementation.
22 #include <dpl/serialization.h>
23 #include <dpl/log/log.h>
24 #include <ckm/ckm-error.h>
25 #include <ckm/ckm-type.h>
26 #include <key-provider.h>
27 #include <file-system.h>
28 #include <ckm-logic.h>
30 #include <key-aes-impl.h>
31 #include <certificate-config.h>
32 #include <certificate-store.h>
34 #include <sw-backend/store.h>
35 #include <generic-backend/exception.h>
36 #include <ss-migrate.h>
39 const char *const CERT_SYSTEM_DIR = CA_CERTS_DIR;
40 const char *const DEFAULT_UNLOCK_STRING = "cAtRugU7";
42 bool isClientValid(const CKM::ClientId &client)
44 if (client.find(CKM::ALIAS_SEPARATOR) != CKM::ClientId::npos)
50 bool isNameValid(const CKM::Name &name)
52 if (name.find(CKM::ALIAS_SEPARATOR) != CKM::Name::npos)
58 // keypair data type, having private key data type and public key data type
59 // private is assumed to be .first, public .second
60 using DataTypePair = std::pair<CKM::DataType, CKM::DataType>;
62 const std::map<CKM::AlgoType, DataTypePair> ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP = {
63 { CKM::AlgoType::RSA_GEN, { CKM::DataType(CKM::KeyType::KEY_RSA_PRIVATE), CKM::DataType(CKM::KeyType::KEY_RSA_PUBLIC) } },
64 { CKM::AlgoType::DSA_GEN, { CKM::DataType(CKM::KeyType::KEY_DSA_PRIVATE), CKM::DataType(CKM::KeyType::KEY_DSA_PUBLIC) } },
65 { CKM::AlgoType::ECDSA_GEN, { CKM::DataType(CKM::KeyType::KEY_ECDSA_PRIVATE), CKM::DataType(CKM::KeyType::KEY_ECDSA_PUBLIC) } },
68 } // anonymous namespace
74 template <int ERROR_ON_CKM_EXCEPTION = CKM_API_ERROR_SERVER_ERROR, class F>
78 static_assert(std::is_same_v<decltype(std::forward<F>(f)()), int>);
79 return std::forward<F>(f)();
80 } catch (const Exc::Exception &e) {
82 } catch (const CKM::Exception &e) {
83 LogError("CKM::Exception: " << e.GetMessage());
84 return ERROR_ON_CKM_EXCEPTION;
88 int toBinaryData(const Crypto::Data &input, Crypto::Data &output)
90 // verify the data integrity
91 if (input.type.isKey()) {
94 if (input.type.isSKey())
95 output_key = CKM::Key::createAES(input.data);
97 output_key = CKM::Key::create(input.data);
99 if (output_key.get() == NULL) {
100 LogDebug("provided binary data is not valid key data");
101 return CKM_API_ERROR_INPUT_PARAM;
104 output = Crypto::Data(input.type, output_key->getDER());
105 } else if (input.type.isCertificate() || input.type.isChainCert()) {
106 CertificateShPtr cert = CKM::Certificate::create(input.data, DataFormat::FORM_DER);
108 if (cert.get() == NULL) {
109 LogDebug("provided binary data is not valid certificate data");
110 return CKM_API_ERROR_INPUT_PARAM;
113 output = Crypto::Data(input.type, cert->getDER());
118 // TODO: add here BINARY_DATA verification, i.e: max size etc.
119 return CKM_API_SUCCESS;
122 int verifyBinaryData(const Crypto::Data &input)
125 return toBinaryData(input, dummy);
128 int readSingleRow(const Name &name,
129 const ClientId &owner,
131 DB::Crypto &database,
134 DB::Crypto::RowOptional row_optional;
136 if (dataType.isKey()) {
137 // read all key types
138 row_optional = database.getRow(name,
140 DataType::DB_KEY_FIRST,
141 DataType::DB_KEY_LAST);
143 // read anything else
144 row_optional = database.getRow(name,
150 LogDebug("No row for given name, owner and type");
151 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
156 return CKM_API_SUCCESS;
159 int readMultiRow(const Name &name,
160 const ClientId &owner,
162 DB::Crypto &database,
163 DB::RowVector &output)
165 if (dataType.isKey())
166 // read all key types
167 database.getRows(name,
169 DataType::DB_KEY_FIRST,
170 DataType::DB_KEY_LAST,
172 else if (dataType.isChainCert())
173 // read all key types
174 database.getRows(name,
176 DataType::DB_CHAIN_FIRST,
177 DataType::DB_CHAIN_LAST,
180 // read anything else
181 database.getRows(name,
186 if (!output.size()) {
187 LogDebug("No row for given name, owner and type");
188 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
191 return CKM_API_SUCCESS;
196 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
197 const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
201 CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
203 m_accessControl.updateCCMode();
206 CKMLogic::~CKMLogic() {}
208 void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
210 auto &handle = m_userDataMap[user];
214 auto wrappedDKEK = fs.getDKEK();
216 if (wrappedDKEK.empty()) {
217 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
218 fs.saveDKEK(wrappedDKEK);
221 handle.keyProvider = KeyProvider(wrappedDKEK, password);
222 if (!handle.keyProvider.isInitialized()) {
223 handle.keyProvider.migrateDomainKEK(wrappedDKEK, password);
224 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
225 LogInfo("DKEK migrated");
229 void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
231 auto &handle = m_userDataMap[user];
234 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
237 void CKMLogic::migrateSecureStorageData(bool isAdminUser)
239 SsMigration::migrate(isAdminUser, [this](const std::string &name,
240 const Crypto::Data &data,
241 bool adminUserFlag) {
242 LogInfo("Migrate data called with name: " << name);
243 auto ownerId = adminUserFlag ? CLIENT_ID_ADMIN_USER : CLIENT_ID_SYSTEM;
244 auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
246 int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
247 PolicySerializable());
249 if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
250 LogWarning("Alias already exist for migrated name: " << name);
251 else if (ret != CKM_API_SUCCESS)
252 LogError("Failed to migrate secure-storage data. name: " << name <<
257 int CKMLogic::unlockDatabase(uid_t user, const Password &password)
259 if (0 < m_userDataMap.count(user) &&
260 m_userDataMap[user].keyProvider.isInitialized())
261 return CKM_API_SUCCESS;
263 int retCode = tryRet([&] {
264 auto &handle = m_userDataMap[user];
267 loadDKEKFile(user, password);
269 auto wrappedDatabaseDEK = fs.getDBDEK();
271 if (wrappedDatabaseDEK.empty()) {
272 wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
273 fs.saveDBDEK(wrappedDatabaseDEK);
276 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
278 handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
279 handle.crypto = CryptoLogic();
281 if (!m_accessControl.isSystemService(user)) {
282 // remove data of removed apps during locked state
283 ClientIdVector removedApps = fs.clearRemovedsApps();
285 for (auto &app : removedApps) {
286 handle.crypto.removeKey(app);
287 handle.database.deleteKey(app);
291 if (user == SYSTEM_DB_UID && SsMigration::hasData())
292 migrateSecureStorageData(false);
293 else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
294 migrateSecureStorageData(true);
296 return CKM_API_SUCCESS;
299 if (CKM_API_SUCCESS != retCode)
300 m_userDataMap.erase(user);
305 int CKMLogic::unlockSystemDB()
307 return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
310 UserData &CKMLogic::selectDatabase(const Credentials &cred,
311 const ClientId &owner)
313 // if user trying to access system service - check:
314 // * if user database is unlocked [mandatory]
315 // * if not - proceed with regular user database
316 // * if explicit system database owner given -> switch to system DB
317 if (!m_accessControl.isSystemService(cred)) {
318 if (0 == m_userDataMap.count(cred.clientUid))
319 ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
321 if (0 != owner.compare(CLIENT_ID_SYSTEM))
322 return m_userDataMap[cred.clientUid];
325 // system database selected, modify the owner id
326 if (CKM_API_SUCCESS != unlockSystemDB())
327 ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
329 return m_userDataMap[SYSTEM_DB_UID];
332 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
334 int retCode = CKM_API_SUCCESS;
336 if (!m_accessControl.isSystemService(user))
337 retCode = unlockDatabase(user, password);
338 else // do not allow lock/unlock operations for system users
339 retCode = CKM_API_ERROR_INPUT_PARAM;
341 return SerializeMessage(retCode);
344 RawBuffer CKMLogic::updateCCMode()
346 m_accessControl.updateCCMode();
347 return SerializeMessage(CKM_API_SUCCESS);
350 RawBuffer CKMLogic::lockUserKey(uid_t user)
352 int retCode = CKM_API_SUCCESS;
354 if (!m_accessControl.isSystemService(user))
355 m_userDataMap.erase(user);
356 else // do not allow lock/unlock operations for system users
357 retCode = CKM_API_ERROR_INPUT_PARAM;
359 return SerializeMessage(retCode);
362 RawBuffer CKMLogic::removeUserData(uid_t user)
364 if (m_accessControl.isSystemService(user))
365 user = SYSTEM_DB_UID;
367 m_userDataMap.erase(user);
369 const int retCode = FileSystem(user).removeUserData()
370 ? CKM_API_ERROR_FILE_SYSTEM
373 return SerializeMessage(retCode);
376 int CKMLogic::changeUserPasswordHelper(uid_t user,
377 const Password &oldPassword,
378 const Password &newPassword)
380 // do not allow to change system database password
381 if (m_accessControl.isSystemService(user))
382 return CKM_API_ERROR_INPUT_PARAM;
384 loadDKEKFile(user, oldPassword);
385 saveDKEKFile(user, newPassword);
387 return CKM_API_SUCCESS;
390 RawBuffer CKMLogic::changeUserPassword(
392 const Password &oldPassword,
393 const Password &newPassword)
395 return SerializeMessage(tryRet([&] {
396 return changeUserPasswordHelper(user, oldPassword, newPassword);
400 int CKMLogic::resetUserPasswordHelper(
402 const Password &newPassword)
404 // do not allow to reset system database password
405 if (m_accessControl.isSystemService(user))
406 return CKM_API_ERROR_INPUT_PARAM;
408 int retCode = CKM_API_SUCCESS;
410 if (0 == m_userDataMap.count(user)) {
411 // Check if key exists. If exists we must return error
413 auto wrappedDKEKMain = fs.getDKEK();
415 if (!wrappedDKEKMain.empty())
416 retCode = CKM_API_ERROR_BAD_REQUEST;
418 saveDKEKFile(user, newPassword);
424 RawBuffer CKMLogic::resetUserPassword(
426 const Password &newPassword)
428 return SerializeMessage(tryRet([&] {
429 return resetUserPasswordHelper(user, newPassword);
433 RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
435 return SerializeMessage(tryRet([&] {
437 return CKM_API_ERROR_INPUT_PARAM;
439 UidVector uids = FileSystem::getUIDsFromDBFile();
441 for (auto userId : uids) {
442 if (0 == m_userDataMap.count(userId)) {
443 FileSystem fs(userId);
444 fs.addRemovedApp(owner);
446 auto &handle = m_userDataMap[userId];
447 handle.crypto.removeKey(owner);
448 handle.database.deleteKey(owner);
452 return CKM_API_SUCCESS;
456 int CKMLogic::verifyAndSaveDataHelper(
457 const Credentials &cred,
459 const ClientId &owner,
460 const Crypto::Data &data,
461 const PolicySerializable &policy)
464 // check if data is correct
465 Crypto::Data binaryData;
466 int retCode = toBinaryData(data, binaryData);
468 return retCode != CKM_API_SUCCESS
470 : saveDataHelper(cred, name, owner, binaryData, policy);
474 int CKMLogic::getKeyForService(
475 const Credentials &cred,
477 const ClientId &owner,
478 const Password &pass,
479 Crypto::GObjShPtr &key)
482 // Key is for internal service use. It won't be exported to the client
483 Crypto::GObjUPtr obj;
484 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, owner, pass, obj);
485 if (retCode == CKM_API_SUCCESS)
486 key = std::move(obj);
492 RawBuffer CKMLogic::saveData(
493 const Credentials &cred,
496 const ClientId &owner,
497 const Crypto::Data &data,
498 const PolicySerializable &policy)
500 int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
501 return SerializeMessage(msgId, retCode, data.type);
504 RawBuffer CKMLogic::savePKCS12(
505 const Credentials &cred,
508 const ClientId &owner,
509 const PKCS12Serializable &pkcs,
510 const PolicySerializable &keyPolicy,
511 const PolicySerializable &certPolicy)
513 return SerializeMessage(msgId, tryRet([&] {
514 return saveDataHelper(cred, name, owner, pkcs, keyPolicy, certPolicy);
518 int CKMLogic::removeDataHelper(
519 const Credentials &cred,
521 const ClientId &owner)
523 auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
524 if (retCode != CKM_API_SUCCESS)
527 retCode = m_accessControl.canDelete(cred, permission);
528 if (retCode != CKM_API_SUCCESS) {
529 LogWarning("access control check result: " << retCode);
533 // get all matching rows
535 dbOp.database().getRows(name, owner, DataType::DB_FIRST, DataType::DB_LAST, rows);
537 LogDebug("No row for given name and owner");
538 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
541 retCode = dbOp.loadAppKey();
542 if (retCode != CKM_API_SUCCESS)
545 // destroy it in store
546 for (auto &r : rows) {
548 dbOp.handler().crypto.decryptRow(Password(), r);
549 m_decider.getStore(r).destroy(r);
550 } catch (const Exc::AuthenticationFailed &) {
551 LogDebug("Authentication failed when removing data. Ignored.");
556 dbOp.database().deleteRow(name, owner);
557 dbOp.transaction().commit();
559 return CKM_API_SUCCESS;
562 RawBuffer CKMLogic::removeData(
563 const Credentials &cred,
566 const ClientId &owner)
568 return SerializeMessage(msgId, tryRet([&] {
569 return removeDataHelper(cred, name, owner);
574 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
577 const PermissionMask& permission)
580 return m_accessControl.canExport(accessorCred, row, permission);
582 return m_accessControl.canRead(accessorCred, permission);
585 Crypto::GObjUPtr CKMLogic::rowToObject(
588 const Password &password,
589 const RawBuffer &hash)
591 Crypto::GStore &store = m_decider.getStore(row);
593 Password pass = m_accessControl.isCCMode() ? "" : password;
596 Crypto::GObjUPtr obj;
598 if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
599 CryptoLogic::ENCRYPTION_V2) {
600 handler.crypto.decryptRow(Password(), row);
602 obj = store.getObject(row, pass);
604 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
605 handler.crypto.decryptRow(pass, row);
606 // destroy it in store
609 // import it to store with new scheme: data -> pass(data)
610 Token token = store.import(Crypto::Data(row.dataType, row.data),
612 Crypto::EncryptionParams(),
615 // get it from the store (it can be different than the data we imported into store)
616 obj = store.getObject(token, pass);
618 // update row with new token
619 *static_cast<Token *>(&row) = std::move(token);
621 // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
622 handler.crypto.encryptRow(row);
625 handler.database.updateRow(row);
631 int CKMLogic::readDataHelper(
633 const Credentials &cred,
636 const ClientId &owner,
637 const Password &password,
638 Crypto::GObjUPtrVector &objs)
640 auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
641 if (retCode != CKM_API_SUCCESS)
646 retCode = readMultiRow(name, owner, dataType, dbOp.database(), rows);
647 if (CKM_API_SUCCESS != retCode)
650 // all read rows belong to the same owner
651 DB::Row &firstRow = rows.at(0);
653 // check access rights
654 retCode = checkDataPermissionsHelper(cred, firstRow, exportFlag, permission);
655 if (CKM_API_SUCCESS != retCode)
658 // for multiple objects add type as hash input (see pkcs12)
659 bool multiple = rows.size() > 1;
663 retCode = dbOp.loadAppKey();
664 if (retCode != CKM_API_SUCCESS)
668 for (auto &row : rows) {
670 digest = CryptoLogic::makeHash(name, owner, cred.clientUid, row.dataType);
672 digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
675 return CKM_API_ERROR_HASH_ERROR;
677 objs.push_back(rowToObject(dbOp.handler(), std::move(row), password, digest));
680 // rowToObject may modify db
681 dbOp.transaction().commit();
683 return CKM_API_SUCCESS;
686 int CKMLogic::readDataHelper(
688 const Credentials &cred,
691 const ClientId &owner,
692 const Password &password,
693 Crypto::GObjUPtr &obj)
695 DataType objDataType;
696 return readDataHelper(exportFlag, cred, dataType, name, owner,
697 password, obj, objDataType);
700 int CKMLogic::readDataHelper(
702 const Credentials &cred,
705 const ClientId &owner,
706 const Password &password,
707 Crypto::GObjUPtr &obj,
708 DataType &objDataType)
710 auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
711 if (retCode != CKM_API_SUCCESS)
715 retCode = readSingleRow(name, owner, dataType, dbOp.database(), row);
716 if (CKM_API_SUCCESS != retCode)
719 retCode = dbOp.loadAppKey();
720 if (retCode != CKM_API_SUCCESS)
723 objDataType = row.dataType;
725 // check access rights
726 retCode = checkDataPermissionsHelper(cred, row, exportFlag, permission);
727 if (CKM_API_SUCCESS != retCode)
730 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
732 return CKM_API_ERROR_HASH_ERROR;
734 obj = rowToObject(dbOp.handler(), std::move(row), password, digest);
735 // rowToObject may modify db
736 dbOp.transaction().commit();
738 return CKM_API_SUCCESS;
741 RawBuffer CKMLogic::getData(
742 const Credentials &cred,
746 const ClientId &owner,
747 const Password &password)
750 DataType objDataType;
752 int retCode = tryRet([&] {
753 Crypto::GObjUPtr obj;
754 int retCode = readDataHelper(true, cred, dataType, name, owner,
755 password, obj, objDataType);
757 if (retCode == CKM_API_SUCCESS)
758 rowData = obj->getBinary();
763 if (CKM_API_SUCCESS != retCode)
766 return SerializeMessage(msgId, retCode, objDataType, rowData);
769 RawBuffer CKMLogic::getDataProtectionStatus(
770 const Credentials &cred,
774 const ClientId &owner)
777 DataType objDataType;
780 int retCode = tryRet([&] {
781 Crypto::GObjUPtr obj;
782 return readDataHelper(false, cred, dataType, name, owner, password, obj, objDataType);
785 if (retCode == CKM_API_ERROR_AUTHENTICATION_FAILED) {
787 retCode = CKM_API_SUCCESS;
790 return SerializeMessage(msgId, retCode, objDataType, status);
793 int CKMLogic::getPKCS12Helper(
794 const Credentials &cred,
796 const ClientId &owner,
797 const Password &keyPassword,
798 const Password &certPassword,
800 CertificateShPtr &cert,
801 CertificateShPtrVector &caChain)
805 // read private key (mandatory)
806 Crypto::GObjUPtr keyObj;
807 retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, owner,
808 keyPassword, keyObj);
810 if (retCode != CKM_API_SUCCESS) {
811 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
814 privKey = CKM::Key::create(keyObj->getBinary());
817 // read certificate (mandatory)
818 Crypto::GObjUPtr certObj;
819 retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, owner,
820 certPassword, certObj);
822 if (retCode != CKM_API_SUCCESS) {
823 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
826 cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
829 // read CA cert chain (optional)
830 Crypto::GObjUPtrVector caChainObjs;
831 retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, owner,
832 certPassword, caChainObjs);
834 if (retCode != CKM_API_SUCCESS && retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
835 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
838 for (auto &caCertObj : caChainObjs)
839 caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
840 DataFormat::FORM_DER));
843 // if anything found, return it
844 if (privKey || cert || caChain.size() > 0)
845 retCode = CKM_API_SUCCESS;
850 RawBuffer CKMLogic::getPKCS12(
851 const Credentials &cred,
854 const ClientId &owner,
855 const Password &keyPassword,
856 const Password &certPassword)
858 PKCS12Serializable output;
860 int retCode = tryRet([&] {
862 CertificateShPtr cert;
863 CertificateShPtrVector caChain;
864 int retCode = getPKCS12Helper(cred, name, owner, keyPassword,
865 certPassword, privKey, cert, caChain);
868 if (retCode == CKM_API_SUCCESS)
869 output = PKCS12Serializable(std::move(privKey), std::move(cert), std::move(caChain));
874 return SerializeMessage(msgId, retCode, output);
877 int CKMLogic::getDataListHelper(const Credentials &cred,
878 const DataType dataType,
879 OwnerNameVector &ownerNameVector)
881 int retCode = CKM_API_ERROR_DB_LOCKED;
883 if (0 < m_userDataMap.count(cred.clientUid)) {
884 auto &database = m_userDataMap[cred.clientUid].database;
886 retCode = tryRet<CKM_API_ERROR_DB_ERROR>([&] {
887 OwnerNameVector tmpVector;
889 if (dataType.isKey()) {
890 // list all key types
891 database.listNames(cred.client,
893 DataType::DB_KEY_FIRST,
894 DataType::DB_KEY_LAST);
896 // list anything else
897 database.listNames(cred.client,
902 ownerNameVector.insert(ownerNameVector.end(), tmpVector.begin(),
904 return CKM_API_SUCCESS;
911 RawBuffer CKMLogic::getDataList(
912 const Credentials &cred,
916 OwnerNameVector systemVector;
917 OwnerNameVector userVector;
918 OwnerNameVector ownerNameVector;
920 int retCode = unlockSystemDB();
922 if (CKM_API_SUCCESS == retCode) {
924 if (m_accessControl.isSystemService(cred)) {
926 retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
930 // user - lookup system, then client DB
931 retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, cred.client),
936 if (retCode == CKM_API_SUCCESS) {
937 retCode = getDataListHelper(cred,
944 if (retCode == CKM_API_SUCCESS) {
945 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
947 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
951 return SerializeMessage(msgId, retCode, dataType, ownerNameVector);
954 int CKMLogic::importInitialData(
956 const Crypto::Data &data,
957 const Crypto::EncryptionParams &encParams,
958 const Policy &policy)
962 if (encParams.iv.empty() != encParams.tag.empty()) {
963 LogError("Both iv and tag must be empty or set");
964 return CKM_API_ERROR_INPUT_PARAM;
967 // Inital values are always imported with root credentials. Client id is not important.
968 Credentials rootCred(0, "whatever");
969 ClientId owner(CLIENT_ID_SYSTEM);
971 auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
972 if (retCode != CKM_API_SUCCESS)
975 Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
978 if (encParams.iv.empty()) {
979 // Data are not encrypted, let's try to verify them
980 Crypto::Data binaryData;
982 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
985 token = store.import(binaryData,
986 m_accessControl.isCCMode() ? "" : policy.password,
989 token = store.import(data,
990 m_accessControl.isCCMode() ? "" : policy.password,
994 dbOp.finalize(std::move(token), policy);
996 return CKM_API_SUCCESS;
998 } catch (const std::exception &e) {
999 LogError("Std::exception: " << e.what());
1000 return CKM_API_ERROR_SERVER_ERROR;
1004 int CKMLogic::saveDataHelper(
1005 const Credentials &cred,
1007 const ClientId &owner,
1008 const Crypto::Data &data,
1009 const PolicySerializable &policy)
1011 auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, name, owner);
1012 if (ret != CKM_API_SUCCESS)
1015 Crypto::GStore &store = m_decider.getStore(data.type, policy);
1017 // do not encrypt data with password during cc_mode on
1018 Token token = store.import(data,
1019 m_accessControl.isCCMode() ? "" : policy.password,
1020 Crypto::EncryptionParams(), digest);
1021 dbOp.finalize(std::move(token), policy);
1022 return CKM_API_SUCCESS;
1025 int CKMLogic::saveDataHelper(
1026 const Credentials &cred,
1028 const ClientId &owner,
1029 const PKCS12Serializable &pkcs,
1030 const PolicySerializable &keyPolicy,
1031 const PolicySerializable &certPolicy)
1033 auto [dbOp, retCode] = beginSave(cred, name, owner);
1034 if (retCode != CKM_API_SUCCESS)
1037 // extract and encrypt the data
1038 DB::RowVector encryptedRows;
1040 auto import = [&](const Crypto::Data &data, const Policy& policy){
1041 retCode = verifyBinaryData(data);
1042 if (retCode != CKM_API_SUCCESS)
1045 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid, data.type);
1047 return CKM_API_ERROR_HASH_ERROR;
1049 Crypto::GStore &store = m_decider.getStore(data.type, policy);
1051 // do not encrypt data with password during cc_mode on
1052 Token token = store.import(data,
1053 m_accessControl.isCCMode() ? "" : policy.password,
1054 Crypto::EncryptionParams(), digest);
1056 encryptedRows.push_back(dbOp.encryptOne(std::move(token), policy));
1057 return CKM_API_SUCCESS;
1060 // private key is mandatory
1061 auto key = pkcs.getKey();
1063 LogError("Failed to get private key from pkcs");
1064 return CKM_API_ERROR_INVALID_FORMAT;
1067 Crypto::Data keyData(DataType(key->getType()), key->getDER());
1068 retCode = import(keyData, keyPolicy);
1069 if (retCode != CKM_API_SUCCESS)
1072 // certificate is mandatory
1073 auto cert = pkcs.getCertificate();
1075 LogError("Failed to get certificate from pkcs");
1076 return CKM_API_ERROR_INVALID_FORMAT;
1079 Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
1080 retCode = import(certData, certPolicy);
1081 if (retCode != CKM_API_SUCCESS)
1085 unsigned int cert_index = 0;
1086 for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
1087 Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++), ca->getDER());
1088 retCode = import(caCertData, certPolicy);
1089 if (retCode != CKM_API_SUCCESS)
1094 dbOp.database().saveRows(name, owner, encryptedRows);
1095 dbOp.transaction().commit();
1097 return CKM_API_SUCCESS;
1100 int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
1102 if (!m_handler.crypto.haveKey(m_owner)) {
1103 RawBuffer wrappedDEK;
1104 auto wrappedDEKOptional = m_handler.database.getKey(m_owner);
1106 if (!wrappedDEKOptional) {
1108 LogError("No key for given owner in database");
1109 return CKM_API_ERROR_DB_ERROR;
1111 LogDebug("No Key in database found. Generating new one for client: " << m_owner);
1112 wrappedDEK = m_handler.keyProvider.generateDEK(m_owner);
1113 m_handler.database.saveKey(m_owner, wrappedDEK);
1115 wrappedDEK = *wrappedDEKOptional;
1118 m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
1121 return CKM_API_SUCCESS;
1124 std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
1125 const Credentials &cred,
1127 const ClientId &owner)
1129 auto &handler = selectDatabase(cred, owner);
1130 DBOperation op(handler, name, owner);
1132 if (cred.client.empty() || !isClientValid(cred.client) ||
1133 !isNameValid(name) || !isClientValid(owner))
1134 return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
1136 return std::make_tuple(std::move(op), CKM_API_SUCCESS);
1139 std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
1140 const Credentials &cred,
1142 const ClientId &owner)
1144 PermissionMask permission;
1145 auto [dbOp, retCode] = begin(cred, name, owner);
1146 if (retCode == CKM_API_SUCCESS)
1147 permission = toPermissionMask(dbOp.database().getPermissionRow(name, owner, cred.client));
1149 return std::make_tuple(std::move(dbOp), permission, retCode);
1152 std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
1153 const Credentials &cred,
1155 const ClientId &owner)
1157 auto [dbOp, retCode] = begin(cred, name, owner);
1158 if (retCode != CKM_API_SUCCESS)
1159 return std::make_tuple(std::move(dbOp), retCode);
1161 retCode = dbOp.loadAppKey(false);
1162 if (retCode != CKM_API_SUCCESS)
1163 return std::make_tuple(std::move(dbOp), retCode);
1165 // check if accessor is allowed to save owner's items
1166 retCode = m_accessControl.canSave(cred, owner);
1167 if (retCode != CKM_API_SUCCESS) {
1168 LogDebug("accessor " << cred.client << " can not save rows owned by " << owner);
1169 return std::make_tuple(std::move(dbOp), retCode);
1172 if (dbOp.database().isNameOwnerPresent(name, owner))
1173 retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
1175 return std::make_tuple(std::move(dbOp), retCode);
1178 std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
1179 const Credentials &cred,
1181 const ClientId &owner)
1184 auto [dbOp, retCode] = beginSave(cred, name, owner);
1185 if (retCode == CKM_API_SUCCESS) {
1186 digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1188 retCode = CKM_API_ERROR_HASH_ERROR;
1191 return std::make_tuple(std::move(dbOp), std::move(digest), retCode);
1194 RawBuffer CKMLogic::createKeyPair(
1195 const Credentials &cred,
1197 const CryptoAlgorithmSerializable &keyGenParams,
1198 const Name &namePrv,
1199 const ClientId &ownerPrv,
1200 const Name &namePub,
1201 const ClientId &ownerPub,
1202 const PolicySerializable &policyPrv,
1203 const PolicySerializable &policyPub)
1205 return SerializeMessage(msgId, tryRet([&] {
1206 auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
1207 if (retCodePrv != CKM_API_SUCCESS)
1210 auto [dbOpPub, digestPub, retCodePub] = beginSaveAndGetHash(cred, namePub, ownerPub);
1211 if (retCodePub != CKM_API_SUCCESS)
1214 AlgoType keyType = AlgoType::RSA_GEN;
1216 if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1217 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1219 const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType);
1220 if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end())
1221 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1222 const DataTypePair& dt = dtIt->second;
1224 if (policyPrv.backend != policyPub.backend)
1225 ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1227 bool exportable = policyPrv.extractable || policyPub.extractable;
1228 Policy lessRestricted(Password(), exportable, policyPrv.backend);
1230 TokenPair keys = m_decider.getStore(policyPrv, dt.first, dt.second).generateAKey(
1234 digestPrv, digestPub);
1236 dbOpPrv.finalize(std::move(keys.first), policyPrv);
1237 dbOpPub.finalize(std::move(keys.second), policyPub);
1239 return CKM_API_SUCCESS;
1243 RawBuffer CKMLogic::createKeyAES(
1244 const Credentials &cred,
1248 const ClientId &owner,
1249 const PolicySerializable &policy)
1251 int retCode = CKM_API_SUCCESS;
1254 retCode = tryRet([&] {
1255 auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, name, owner);
1256 if (retCode != CKM_API_SUCCESS)
1259 // create key in store
1260 CryptoAlgorithm keyGenAlgorithm;
1261 keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1262 keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1263 Token key = m_decider.getStore(DataType::KEY_AES, policy).generateSKey(keyGenAlgorithm,
1267 dbOp.finalize(std::move(key), policy);
1268 return CKM_API_SUCCESS;
1270 } catch (std::invalid_argument &e) {
1271 LogDebug("invalid argument error: " << e.what());
1272 retCode = CKM_API_ERROR_INPUT_PARAM;
1275 return SerializeMessage(msgId, retCode);
1278 int CKMLogic::readCertificateHelper(
1279 const Credentials &cred,
1280 const OwnerNameVector &ownerNameVector,
1281 CertificateImplVector &certVector)
1283 for (auto &i : ownerNameVector) {
1284 // certificates can't be protected with custom user password
1285 Crypto::GObjUPtr obj;
1287 ec = readDataHelper(true,
1289 DataType::CERTIFICATE,
1291 cred.effectiveOwner(i.first),
1295 if (ec != CKM_API_SUCCESS)
1298 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1300 // try to read chain certificates (if present)
1301 Crypto::GObjUPtrVector caChainObjs;
1302 ec = readDataHelper(true,
1304 DataType::DB_CHAIN_FIRST,
1306 cred.effectiveOwner(i.first),
1310 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1313 for (auto &caCertObj : caChainObjs)
1314 certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1317 return CKM_API_SUCCESS;
1320 int CKMLogic::getCertificateChainHelper(
1321 const CertificateImpl &cert,
1322 const RawBufferVector &untrustedCertificates,
1323 const RawBufferVector &trustedCertificates,
1324 bool useTrustedSystemCertificates,
1325 RawBufferVector &chainRawVector)
1327 CertificateImplVector untrustedCertVector;
1328 CertificateImplVector trustedCertVector;
1329 CertificateImplVector chainVector;
1332 return CKM_API_ERROR_INPUT_PARAM;
1334 for (auto &e : untrustedCertificates) {
1335 CertificateImpl c(e, DataFormat::FORM_DER);
1338 return CKM_API_ERROR_INPUT_PARAM;
1340 untrustedCertVector.push_back(std::move(c));
1343 for (auto &e : trustedCertificates) {
1344 CertificateImpl c(e, DataFormat::FORM_DER);
1347 return CKM_API_ERROR_INPUT_PARAM;
1349 trustedCertVector.push_back(std::move(c));
1352 CertificateStore store;
1353 int retCode = store.verifyCertificate(cert,
1354 untrustedCertVector,
1356 useTrustedSystemCertificates,
1357 m_accessControl.isCCMode(),
1360 if (retCode != CKM_API_SUCCESS)
1363 for (auto &e : chainVector)
1364 chainRawVector.push_back(e.getDER());
1366 return CKM_API_SUCCESS;
1369 int CKMLogic::getCertificateChainHelper(
1370 const Credentials &cred,
1371 const CertificateImpl &cert,
1372 const OwnerNameVector &untrusted,
1373 const OwnerNameVector &trusted,
1374 bool useTrustedSystemCertificates,
1375 RawBufferVector &chainRawVector)
1377 CertificateImplVector untrustedCertVector;
1378 CertificateImplVector trustedCertVector;
1379 CertificateImplVector chainVector;
1382 return CKM_API_ERROR_INPUT_PARAM;
1384 int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1386 if (retCode != CKM_API_SUCCESS)
1389 retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1391 if (retCode != CKM_API_SUCCESS)
1394 CertificateStore store;
1395 retCode = store.verifyCertificate(cert,
1396 untrustedCertVector,
1398 useTrustedSystemCertificates,
1399 m_accessControl.isCCMode(),
1402 if (retCode != CKM_API_SUCCESS)
1405 for (auto &i : chainVector)
1406 chainRawVector.push_back(i.getDER());
1408 return CKM_API_SUCCESS;
1411 RawBuffer CKMLogic::getCertificateChain(
1412 const Credentials & /*cred*/,
1414 const RawBuffer &certificate,
1415 const RawBufferVector &untrustedCertificates,
1416 const RawBufferVector &trustedCertificates,
1417 bool useTrustedSystemCertificates)
1419 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1420 RawBufferVector chainRawVector;
1421 int retCode = CKM_API_ERROR_UNKNOWN;
1424 retCode = getCertificateChainHelper(cert,
1425 untrustedCertificates,
1426 trustedCertificates,
1427 useTrustedSystemCertificates,
1429 } catch (const Exc::Exception &e) {
1430 retCode = e.error();
1431 } catch (const std::exception &e) {
1432 LogError("STD exception " << e.what());
1433 retCode = CKM_API_ERROR_SERVER_ERROR;
1435 LogError("Unknown error.");
1438 return SerializeMessage(msgId, retCode, chainRawVector);
1441 RawBuffer CKMLogic::getCertificateChain(
1442 const Credentials &cred,
1444 const RawBuffer &certificate,
1445 const OwnerNameVector &untrustedCertificates,
1446 const OwnerNameVector &trustedCertificates,
1447 bool useTrustedSystemCertificates)
1449 int retCode = CKM_API_ERROR_UNKNOWN;
1450 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1451 RawBufferVector chainRawVector;
1454 retCode = getCertificateChainHelper(cred,
1456 untrustedCertificates,
1457 trustedCertificates,
1458 useTrustedSystemCertificates,
1460 } catch (const Exc::Exception &e) {
1461 retCode = e.error();
1462 } catch (const std::exception &e) {
1463 LogError("STD exception " << e.what());
1464 retCode = CKM_API_ERROR_SERVER_ERROR;
1466 LogError("Unknown error.");
1469 return SerializeMessage(msgId, retCode, chainRawVector);
1472 RawBuffer CKMLogic::createSignature(
1473 const Credentials &cred,
1475 const Name &privateKeyName,
1476 const ClientId &owner,
1477 const Password &password, // password for private_key
1478 const RawBuffer &message,
1479 const CryptoAlgorithm &cryptoAlg)
1481 RawBuffer signature;
1483 int retCode = CKM_API_SUCCESS;
1486 retCode = tryRet([&] {
1487 Crypto::GObjUPtr obj;
1488 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1489 owner, password, obj);
1491 if (retCode == CKM_API_SUCCESS)
1492 signature = obj->sign(cryptoAlg, message);
1496 } catch (const std::exception &e) {
1497 LogError("STD exception " << e.what());
1498 retCode = CKM_API_ERROR_SERVER_ERROR;
1501 return SerializeMessage(msgId, retCode, signature);
1504 RawBuffer CKMLogic::verifySignature(
1505 const Credentials &cred,
1507 const Name &publicKeyOrCertName,
1508 const ClientId &owner,
1509 const Password &password, // password for public_key (optional)
1510 const RawBuffer &message,
1511 const RawBuffer &signature,
1512 const CryptoAlgorithm ¶ms)
1514 return SerializeMessage(msgId, tryRet([&] {
1515 // try certificate first - looking for a public key.
1516 // in case of PKCS, pub key from certificate will be found first
1517 // rather than private key from the same PKCS.
1518 Crypto::GObjUPtr obj;
1519 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1520 publicKeyOrCertName, owner, password, obj);
1522 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1523 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1524 publicKeyOrCertName, owner, password, obj);
1526 if (retCode == CKM_API_SUCCESS)
1527 retCode = obj->verify(params, message, signature);
1533 int CKMLogic::setPermissionHelper(
1534 const Credentials &cred, // who's the client
1536 const ClientId &owner, // who's the owner
1537 const ClientId &accessor, // who will get the access
1538 const PermissionMask permissionMask)
1540 auto [dbOp, retCode] = beginSave(cred, name, owner);
1541 // Normally, saving requires alias to be unoccupied. When changing permissions it's the opposite
1542 if (retCode != CKM_API_ERROR_DB_ALIAS_EXISTS) {
1543 if (retCode == CKM_API_SUCCESS)
1544 retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1548 // currently we don't support modification of owner's permissions to his own rows
1549 if (owner == accessor)
1550 return CKM_API_ERROR_INPUT_PARAM;
1552 // system database does not support write/remove permissions
1553 if ((0 == owner.compare(CLIENT_ID_SYSTEM)) && (permissionMask & Permission::REMOVE))
1554 return CKM_API_ERROR_INPUT_PARAM;
1556 // set permissions to the row owned by owner for accessor
1557 dbOp.database().setPermission(name, owner, accessor, permissionMask);
1558 dbOp.transaction().commit();
1560 return CKM_API_SUCCESS;
1563 RawBuffer CKMLogic::setPermission(
1564 const Credentials &cred,
1567 const ClientId &owner,
1568 const ClientId &accessor,
1569 const PermissionMask permissionMask)
1571 return SerializeMessage(msgID, tryRet([&] {
1572 return setPermissionHelper(cred, name, owner, accessor, permissionMask);