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(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;
194 int loadAppKey(UserData &handler, const ClientId &owner, bool keyRequired = true)
196 if (!handler.crypto.haveKey(owner)) {
197 RawBuffer wrappedDEK;
198 auto wrappedDEKOptional = handler.database.getKey(owner);
200 if (!wrappedDEKOptional) {
202 LogError("No key for given owner in database");
203 return CKM_API_ERROR_DB_ERROR;
205 LogDebug("No Key in database found. Generating new one for client: " << owner);
206 wrappedDEK = handler.keyProvider.generateDEK(owner);
207 handler.database.saveKey(owner, wrappedDEK);
209 wrappedDEK = *wrappedDEKOptional;
212 handler.crypto.pushKey(owner, handler.keyProvider.getPureDEK(wrappedDEK));
215 return CKM_API_SUCCESS;
220 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
221 const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
225 CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
227 m_accessControl.updateCCMode();
230 CKMLogic::~CKMLogic() {}
232 void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
234 auto &handle = m_userDataMap[user];
238 auto wrappedDKEK = fs.getDKEK();
240 if (wrappedDKEK.empty()) {
241 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
242 fs.saveDKEK(wrappedDKEK);
245 handle.keyProvider = KeyProvider(wrappedDKEK, password);
246 if (!handle.keyProvider.isInitialized()) {
247 handle.keyProvider.migrateDomainKEK(wrappedDKEK, password);
248 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
249 LogInfo("DKEK migrated");
253 void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
255 auto &handle = m_userDataMap[user];
258 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
261 void CKMLogic::migrateSecureStorageData(bool isAdminUser)
263 SsMigration::migrate(isAdminUser, [this](const std::string &name,
264 const Crypto::Data &data,
265 bool adminUserFlag) {
266 LogInfo("Migrate data called with name: " << name);
267 auto ownerId = adminUserFlag ? CLIENT_ID_ADMIN_USER : CLIENT_ID_SYSTEM;
268 auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
270 int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
271 PolicySerializable());
273 if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
274 LogWarning("Alias already exist for migrated name: " << name);
275 else if (ret != CKM_API_SUCCESS)
276 LogError("Failed to migrate secure-storage data. name: " << name <<
281 int CKMLogic::unlockDatabase(uid_t user, const Password &password)
283 if (0 < m_userDataMap.count(user) &&
284 m_userDataMap[user].keyProvider.isInitialized())
285 return CKM_API_SUCCESS;
287 int retCode = tryRet([&] {
288 auto &handle = m_userDataMap[user];
291 loadDKEKFile(user, password);
293 auto wrappedDatabaseDEK = fs.getDBDEK();
295 if (wrappedDatabaseDEK.empty()) {
296 wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
297 fs.saveDBDEK(wrappedDatabaseDEK);
300 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
302 handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
303 handle.crypto = CryptoLogic();
305 if (!m_accessControl.isSystemService(user)) {
306 // remove data of removed apps during locked state
307 ClientIdVector removedApps = fs.clearRemovedsApps();
309 for (auto &app : removedApps) {
310 handle.crypto.removeKey(app);
311 handle.database.deleteKey(app);
315 if (user == SYSTEM_DB_UID && SsMigration::hasData())
316 migrateSecureStorageData(false);
317 else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
318 migrateSecureStorageData(true);
320 return CKM_API_SUCCESS;
323 if (CKM_API_SUCCESS != retCode)
324 m_userDataMap.erase(user);
329 int CKMLogic::unlockSystemDB()
331 return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
334 UserData &CKMLogic::selectDatabase(const Credentials &cred,
335 const ClientId &owner)
337 // if user trying to access system service - check:
338 // * if user database is unlocked [mandatory]
339 // * if not - proceed with regular user database
340 // * if explicit system database owner given -> switch to system DB
341 if (!m_accessControl.isSystemService(cred)) {
342 if (0 == m_userDataMap.count(cred.clientUid))
343 ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
345 if (0 != owner.compare(CLIENT_ID_SYSTEM))
346 return m_userDataMap[cred.clientUid];
349 // system database selected, modify the owner id
350 if (CKM_API_SUCCESS != unlockSystemDB())
351 ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
353 return m_userDataMap[SYSTEM_DB_UID];
356 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
358 int retCode = CKM_API_SUCCESS;
360 if (!m_accessControl.isSystemService(user))
361 retCode = unlockDatabase(user, password);
362 else // do not allow lock/unlock operations for system users
363 retCode = CKM_API_ERROR_INPUT_PARAM;
365 return SerializeMessage(retCode);
368 RawBuffer CKMLogic::updateCCMode()
370 m_accessControl.updateCCMode();
371 return SerializeMessage(CKM_API_SUCCESS);
374 RawBuffer CKMLogic::lockUserKey(uid_t user)
376 int retCode = CKM_API_SUCCESS;
378 if (!m_accessControl.isSystemService(user))
379 m_userDataMap.erase(user);
380 else // do not allow lock/unlock operations for system users
381 retCode = CKM_API_ERROR_INPUT_PARAM;
383 return SerializeMessage(retCode);
386 RawBuffer CKMLogic::removeUserData(uid_t user)
388 if (m_accessControl.isSystemService(user))
389 user = SYSTEM_DB_UID;
391 m_userDataMap.erase(user);
393 const int retCode = FileSystem(user).removeUserData()
394 ? CKM_API_ERROR_FILE_SYSTEM
397 return SerializeMessage(retCode);
400 int CKMLogic::changeUserPasswordHelper(uid_t user,
401 const Password &oldPassword,
402 const Password &newPassword)
404 // do not allow to change system database password
405 if (m_accessControl.isSystemService(user))
406 return CKM_API_ERROR_INPUT_PARAM;
408 loadDKEKFile(user, oldPassword);
409 saveDKEKFile(user, newPassword);
411 return CKM_API_SUCCESS;
414 RawBuffer CKMLogic::changeUserPassword(
416 const Password &oldPassword,
417 const Password &newPassword)
419 return SerializeMessage(tryRet([&] {
420 return changeUserPasswordHelper(user, oldPassword, newPassword);
424 int CKMLogic::resetUserPasswordHelper(
426 const Password &newPassword)
428 // do not allow to reset system database password
429 if (m_accessControl.isSystemService(user))
430 return CKM_API_ERROR_INPUT_PARAM;
432 int retCode = CKM_API_SUCCESS;
434 if (0 == m_userDataMap.count(user)) {
435 // Check if key exists. If exists we must return error
437 auto wrappedDKEKMain = fs.getDKEK();
439 if (!wrappedDKEKMain.empty())
440 retCode = CKM_API_ERROR_BAD_REQUEST;
442 saveDKEKFile(user, newPassword);
448 RawBuffer CKMLogic::resetUserPassword(
450 const Password &newPassword)
452 return SerializeMessage(tryRet([&] {
453 return resetUserPasswordHelper(user, newPassword);
457 RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
459 return SerializeMessage(tryRet([&] {
461 return CKM_API_ERROR_INPUT_PARAM;
463 UidVector uids = FileSystem::getUIDsFromDBFile();
465 for (auto userId : uids) {
466 if (0 == m_userDataMap.count(userId)) {
467 FileSystem fs(userId);
468 fs.addRemovedApp(owner);
470 auto &handle = m_userDataMap[userId];
471 handle.crypto.removeKey(owner);
472 handle.database.deleteKey(owner);
476 return CKM_API_SUCCESS;
480 int CKMLogic::checkSaveConditions(
481 const Credentials &accessorCred,
484 const ClientId &owner)
486 // verify name and client are correct
487 if (!isNameValid(name) || !isClientValid(owner)) {
488 LogDebug("Invalid parameter passed to key-manager");
489 return CKM_API_ERROR_INPUT_PARAM;
492 // check if accessor is allowed to save owner's items
493 int access_ec = m_accessControl.canSave(accessorCred, owner);
495 if (access_ec != CKM_API_SUCCESS) {
496 LogDebug("accessor " << accessorCred.client << " can not save rows owned by " <<
501 // check if not a duplicate
502 if (handler.database.isNameOwnerPresent(name, owner))
503 return CKM_API_ERROR_DB_ALIAS_EXISTS;
505 // generate (if needed) and load the app key
506 loadAppKey(handler, owner, false);
508 return CKM_API_SUCCESS;
511 DB::Row CKMLogic::createEncryptedRow(
514 const ClientId &owner,
515 const Crypto::Data &data,
516 const Policy &policy,
517 const RawBuffer &hash)
519 Crypto::GStore &store = m_decider.getStore(data.type, policy);
521 // do not encrypt data with password during cc_mode on
522 Token token = store.import(data,
523 m_accessControl.isCCMode() ? "" : policy.password,
524 Crypto::EncryptionParams(), hash);
525 DB::Row row(std::move(token), name, owner,
526 static_cast<int>(policy.extractable));
527 crypto.encryptRow(row);
531 int CKMLogic::verifyAndSaveDataHelper(
532 const Credentials &cred,
534 const ClientId &owner,
535 const Crypto::Data &data,
536 const PolicySerializable &policy)
539 // check if data is correct
540 Crypto::Data binaryData;
541 int retCode = toBinaryData(data, binaryData);
543 return retCode != CKM_API_SUCCESS
545 : saveDataHelper(cred, name, owner, binaryData, policy);
549 int CKMLogic::getKeyForService(
550 const Credentials &cred,
552 const ClientId &owner,
553 const Password &pass,
554 Crypto::GObjShPtr &key)
557 // Key is for internal service use. It won't be exported to the client
558 Crypto::GObjUPtr obj;
559 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, owner, pass, obj);
560 if (retCode == CKM_API_SUCCESS)
561 key = std::move(obj);
567 RawBuffer CKMLogic::saveData(
568 const Credentials &cred,
571 const ClientId &owner,
572 const Crypto::Data &data,
573 const PolicySerializable &policy)
575 int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
576 return SerializeMessage(msgId, retCode, data.type);
579 int CKMLogic::extractPKCS12Data(
582 const ClientId &owner,
583 const PKCS12Serializable &pkcs,
584 const PolicySerializable &keyPolicy,
585 const PolicySerializable &certPolicy,
586 DB::RowVector &output,
587 const Credentials &cred)
589 // private key is mandatory
590 auto key = pkcs.getKey();
593 LogError("Failed to get private key from pkcs");
594 return CKM_API_ERROR_INVALID_FORMAT;
597 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
599 return CKM_API_ERROR_HASH_ERROR;
601 Crypto::Data keyData(DataType(key->getType()), key->getDER());
602 int retCode = verifyBinaryData(keyData);
604 if (retCode != CKM_API_SUCCESS)
607 output.push_back(createEncryptedRow(crypto, name, owner, keyData,
610 // certificate is mandatory
611 auto cert = pkcs.getCertificate();
614 LogError("Failed to get certificate from pkcs");
615 return CKM_API_ERROR_INVALID_FORMAT;
618 Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
619 retCode = verifyBinaryData(certData);
621 if (retCode != CKM_API_SUCCESS)
624 output.push_back(createEncryptedRow(crypto, name, owner, certData,
625 certPolicy, digest));
628 unsigned int cert_index = 0;
630 for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
631 Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++),
633 int retCode = verifyBinaryData(caCertData);
635 if (retCode != CKM_API_SUCCESS)
638 output.push_back(createEncryptedRow(crypto, name, owner, caCertData,
639 certPolicy, digest));
642 return CKM_API_SUCCESS;
645 RawBuffer CKMLogic::savePKCS12(
646 const Credentials &cred,
649 const ClientId &owner,
650 const PKCS12Serializable &pkcs,
651 const PolicySerializable &keyPolicy,
652 const PolicySerializable &certPolicy)
654 return SerializeMessage(msgId, tryRet([&] {
655 return saveDataHelper(cred, name, owner, pkcs, keyPolicy, certPolicy);
660 int CKMLogic::removeDataHelper(
661 const Credentials &cred,
663 const ClientId &owner)
665 auto &handler = selectDatabase(cred, owner);
667 if (!isNameValid(name) || !isClientValid(owner)) {
668 LogDebug("Invalid owner or name format");
669 return CKM_API_ERROR_INPUT_PARAM;
672 DB::Crypto::Transaction transaction(&handler.database);
674 // read and check permissions
675 PermissionMaskOptional permissionRowOpt =
676 handler.database.getPermissionRow(name, owner, cred.client);
677 int retCode = m_accessControl.canDelete(cred,
678 toPermissionMask(permissionRowOpt));
680 if (retCode != CKM_API_SUCCESS) {
681 LogWarning("access control check result: " << retCode);
685 // get all matching rows
687 handler.database.getRows(name, owner, DataType::DB_FIRST,
688 DataType::DB_LAST, rows);
691 LogDebug("No row for given name and owner");
692 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
695 // load app key if needed
696 retCode = loadAppKey(handler, rows.front().owner);
698 if (CKM_API_SUCCESS != retCode)
701 // destroy it in store
702 for (auto &r : rows) {
704 handler.crypto.decryptRow(Password(), r);
705 m_decider.getStore(r).destroy(r);
706 } catch (const Exc::AuthenticationFailed &) {
707 LogDebug("Authentication failed when removing data. Ignored.");
712 handler.database.deleteRow(name, owner);
713 transaction.commit();
715 return CKM_API_SUCCESS;
718 RawBuffer CKMLogic::removeData(
719 const Credentials &cred,
722 const ClientId &owner)
724 return SerializeMessage(msgId, tryRet([&] {
725 return removeDataHelper(cred, name, owner);
730 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
732 const ClientId &owner,
735 DB::Crypto &database)
737 PermissionMaskOptional permissionRowOpt =
738 database.getPermissionRow(name, owner, accessorCred.client);
741 return m_accessControl.canExport(accessorCred,
743 toPermissionMask(permissionRowOpt));
745 return m_accessControl.canRead(accessorCred,
746 toPermissionMask(permissionRowOpt));
749 Crypto::GObjUPtr CKMLogic::rowToObject(
752 const Password &password,
753 const RawBuffer &hash)
755 Crypto::GStore &store = m_decider.getStore(row);
757 Password pass = m_accessControl.isCCMode() ? "" : password;
760 Crypto::GObjUPtr obj;
762 if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
763 CryptoLogic::ENCRYPTION_V2) {
764 handler.crypto.decryptRow(Password(), row);
766 obj = store.getObject(row, pass);
768 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
769 handler.crypto.decryptRow(pass, row);
770 // destroy it in store
773 // import it to store with new scheme: data -> pass(data)
774 Token token = store.import(Crypto::Data(row.dataType, row.data),
776 Crypto::EncryptionParams(),
779 // get it from the store (it can be different than the data we imported into store)
780 obj = store.getObject(token, pass);
782 // update row with new token
783 *static_cast<Token *>(&row) = std::move(token);
785 // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
786 handler.crypto.encryptRow(row);
789 handler.database.updateRow(row);
795 int CKMLogic::readDataHelper(
797 const Credentials &cred,
800 const ClientId &owner,
801 const Password &password,
802 Crypto::GObjUPtrVector &objs)
804 auto &handler = selectDatabase(cred, owner);
806 if (!isNameValid(name) || !isClientValid(owner))
807 return CKM_API_ERROR_INPUT_PARAM;
810 DB::Crypto::Transaction transaction(&handler.database);
812 int retCode = readMultiRow(name, owner, dataType, handler.database, rows);
814 if (CKM_API_SUCCESS != retCode)
817 // all read rows belong to the same owner
818 DB::Row &firstRow = rows.at(0);
820 // check access rights
821 retCode = checkDataPermissionsHelper(cred, name, owner, firstRow,
822 exportFlag, handler.database);
824 if (CKM_API_SUCCESS != retCode)
827 // load app key if needed
828 retCode = loadAppKey(handler, firstRow.owner);
830 if (CKM_API_SUCCESS != retCode)
833 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
835 return CKM_API_ERROR_HASH_ERROR;
838 for (auto &row : rows)
839 objs.push_back(rowToObject(handler, std::move(row), password, digest));
841 // rowToObject may modify db
842 transaction.commit();
844 return CKM_API_SUCCESS;
847 int CKMLogic::readDataHelper(
849 const Credentials &cred,
852 const ClientId &owner,
853 const Password &password,
854 Crypto::GObjUPtr &obj)
856 DataType objDataType;
857 return readDataHelper(exportFlag, cred, dataType, name, owner,
858 password, obj, objDataType);
861 int CKMLogic::readDataHelper(
863 const Credentials &cred,
866 const ClientId &owner,
867 const Password &password,
868 Crypto::GObjUPtr &obj,
869 DataType &objDataType)
871 auto &handler = selectDatabase(cred, owner);
873 if (!isNameValid(name) || !isClientValid(owner))
874 return CKM_API_ERROR_INPUT_PARAM;
877 DB::Crypto::Transaction transaction(&handler.database);
879 int retCode = readSingleRow(name, owner, dataType, handler.database, row);
881 if (CKM_API_SUCCESS != retCode)
884 objDataType = row.dataType;
886 // check access rights
887 retCode = checkDataPermissionsHelper(cred, name, owner, row, exportFlag,
890 if (CKM_API_SUCCESS != retCode)
893 // load app key if needed
894 retCode = loadAppKey(handler, row.owner);
896 if (CKM_API_SUCCESS != retCode)
899 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
901 return CKM_API_ERROR_HASH_ERROR;
903 obj = rowToObject(handler, std::move(row), password, digest);
904 // rowToObject may modify db
905 transaction.commit();
907 return CKM_API_SUCCESS;
910 RawBuffer CKMLogic::getData(
911 const Credentials &cred,
915 const ClientId &owner,
916 const Password &password)
919 DataType objDataType;
921 int retCode = tryRet([&] {
922 Crypto::GObjUPtr obj;
923 int retCode = readDataHelper(true, cred, dataType, name, owner,
924 password, obj, objDataType);
926 if (retCode == CKM_API_SUCCESS)
927 rowData = obj->getBinary();
932 if (CKM_API_SUCCESS != retCode)
935 return SerializeMessage(msgId, retCode, objDataType, rowData);
938 RawBuffer CKMLogic::getDataProtectionStatus(
939 const Credentials &cred,
943 const ClientId &owner)
946 DataType objDataType;
949 int retCode = tryRet([&] {
950 Crypto::GObjUPtr obj;
951 return readDataHelper(false, cred, dataType, name, owner, password, obj, objDataType);
954 if (retCode == CKM_API_ERROR_AUTHENTICATION_FAILED) {
956 retCode = CKM_API_SUCCESS;
959 return SerializeMessage(msgId, retCode, objDataType, status);
962 int CKMLogic::getPKCS12Helper(
963 const Credentials &cred,
965 const ClientId &owner,
966 const Password &keyPassword,
967 const Password &certPassword,
969 CertificateShPtr &cert,
970 CertificateShPtrVector &caChain)
974 // read private key (mandatory)
975 Crypto::GObjUPtr keyObj;
976 retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, owner,
977 keyPassword, keyObj);
979 if (retCode != CKM_API_SUCCESS) {
980 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
983 privKey = CKM::Key::create(keyObj->getBinary());
986 // read certificate (mandatory)
987 Crypto::GObjUPtr certObj;
988 retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, owner,
989 certPassword, certObj);
991 if (retCode != CKM_API_SUCCESS) {
992 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
995 cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
998 // read CA cert chain (optional)
999 Crypto::GObjUPtrVector caChainObjs;
1000 retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, owner,
1001 certPassword, caChainObjs);
1003 if (retCode != CKM_API_SUCCESS && retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
1004 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
1007 for (auto &caCertObj : caChainObjs)
1008 caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
1009 DataFormat::FORM_DER));
1012 // if anything found, return it
1013 if (privKey || cert || caChain.size() > 0)
1014 retCode = CKM_API_SUCCESS;
1019 RawBuffer CKMLogic::getPKCS12(
1020 const Credentials &cred,
1023 const ClientId &owner,
1024 const Password &keyPassword,
1025 const Password &certPassword)
1027 PKCS12Serializable output;
1029 int retCode = tryRet([&] {
1031 CertificateShPtr cert;
1032 CertificateShPtrVector caChain;
1033 int retCode = getPKCS12Helper(cred, name, owner, keyPassword,
1034 certPassword, privKey, cert, caChain);
1037 if (retCode == CKM_API_SUCCESS)
1038 output = PKCS12Serializable(std::move(privKey), std::move(cert), std::move(caChain));
1043 return SerializeMessage(msgId, retCode, output);
1046 int CKMLogic::getDataListHelper(const Credentials &cred,
1047 const DataType dataType,
1048 OwnerNameVector &ownerNameVector)
1050 int retCode = CKM_API_ERROR_DB_LOCKED;
1052 if (0 < m_userDataMap.count(cred.clientUid)) {
1053 auto &database = m_userDataMap[cred.clientUid].database;
1055 retCode = tryRet<CKM_API_ERROR_DB_ERROR>([&] {
1056 OwnerNameVector tmpVector;
1058 if (dataType.isKey()) {
1059 // list all key types
1060 database.listNames(cred.client,
1062 DataType::DB_KEY_FIRST,
1063 DataType::DB_KEY_LAST);
1065 // list anything else
1066 database.listNames(cred.client,
1071 ownerNameVector.insert(ownerNameVector.end(), tmpVector.begin(),
1073 return CKM_API_SUCCESS;
1080 RawBuffer CKMLogic::getDataList(
1081 const Credentials &cred,
1085 OwnerNameVector systemVector;
1086 OwnerNameVector userVector;
1087 OwnerNameVector ownerNameVector;
1089 int retCode = unlockSystemDB();
1091 if (CKM_API_SUCCESS == retCode) {
1093 if (m_accessControl.isSystemService(cred)) {
1095 retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
1099 // user - lookup system, then client DB
1100 retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, cred.client),
1105 if (retCode == CKM_API_SUCCESS) {
1106 retCode = getDataListHelper(cred,
1113 if (retCode == CKM_API_SUCCESS) {
1114 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
1115 systemVector.end());
1116 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
1120 return SerializeMessage(msgId, retCode, dataType, ownerNameVector);
1123 int CKMLogic::importInitialData(
1125 const Crypto::Data &data,
1126 const Crypto::EncryptionParams &encParams,
1127 const Policy &policy)
1131 if (encParams.iv.empty() != encParams.tag.empty()) {
1132 LogError("Both iv and tag must be empty or set");
1133 return CKM_API_ERROR_INPUT_PARAM;
1136 // Inital values are always imported with root credentials. Client id is not important.
1137 Credentials rootCred(0, "");
1138 ClientId owner(CLIENT_ID_SYSTEM);
1139 auto &handler = selectDatabase(rootCred, CLIENT_ID_SYSTEM);
1141 // check if save is possible
1142 DB::Crypto::Transaction transaction(&handler.database);
1143 int retCode = checkSaveConditions(rootCred, handler, name, CLIENT_ID_SYSTEM);
1144 if (retCode != CKM_API_SUCCESS)
1147 Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
1151 auto digest = CryptoLogic::makeHash(name, owner, rootCred.clientUid);
1153 return CKM_API_ERROR_HASH_ERROR;
1155 if (encParams.iv.empty()) {
1156 // Data are not encrypted, let's try to verify them
1157 Crypto::Data binaryData;
1159 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
1162 token = store.import(binaryData,
1163 m_accessControl.isCCMode() ? "" : policy.password,
1166 token = store.import(data,
1167 m_accessControl.isCCMode() ? "" : policy.password,
1171 DB::Row row(std::move(token), name, CLIENT_ID_SYSTEM,
1172 static_cast<int>(policy.extractable));
1173 handler.crypto.encryptRow(row);
1175 handler.database.saveRow(row);
1176 transaction.commit();
1178 return CKM_API_SUCCESS;
1180 } catch (const std::exception &e) {
1181 LogError("Std::exception: " << e.what());
1182 return CKM_API_ERROR_SERVER_ERROR;
1186 int CKMLogic::saveDataHelper(
1187 const Credentials &cred,
1189 const ClientId &owner,
1190 const Crypto::Data &data,
1191 const PolicySerializable &policy)
1193 auto &handler = selectDatabase(cred, owner);
1195 // check if save is possible
1196 DB::Crypto::Transaction transaction(&handler.database);
1197 int retCode = checkSaveConditions(cred, handler, name, owner);
1198 if (retCode != CKM_API_SUCCESS)
1201 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1203 return CKM_API_ERROR_HASH_ERROR;
1206 DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, owner,
1207 data, policy, digest);
1208 handler.database.saveRow(encryptedRow);
1210 transaction.commit();
1211 return CKM_API_SUCCESS;
1214 int CKMLogic::saveDataHelper(
1215 const Credentials &cred,
1217 const ClientId &owner,
1218 const PKCS12Serializable &pkcs,
1219 const PolicySerializable &keyPolicy,
1220 const PolicySerializable &certPolicy)
1222 auto &handler = selectDatabase(cred, owner);
1224 // check if save is possible
1225 DB::Crypto::Transaction transaction(&handler.database);
1226 int retCode = checkSaveConditions(cred, handler, name, owner);
1227 if (retCode != CKM_API_SUCCESS)
1230 // extract and encrypt the data
1231 DB::RowVector encryptedRows;
1232 retCode = extractPKCS12Data(handler.crypto, name, owner, pkcs, keyPolicy,
1233 certPolicy, encryptedRows, cred);
1235 if (retCode != CKM_API_SUCCESS)
1239 handler.database.saveRows(name, owner, encryptedRows);
1240 transaction.commit();
1242 return CKM_API_SUCCESS;
1246 int CKMLogic::createKeyAESHelper(
1247 const Credentials &cred,
1250 const ClientId &owner,
1251 const PolicySerializable &policy)
1253 auto &handler = selectDatabase(cred, owner);
1255 // check if save is possible
1256 DB::Crypto::Transaction transaction(&handler.database);
1257 int retCode = checkSaveConditions(cred, handler, name, owner);
1258 if (retCode != CKM_API_SUCCESS)
1261 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1263 return CKM_API_ERROR_HASH_ERROR;
1265 // create key in store
1266 CryptoAlgorithm keyGenAlgorithm;
1267 keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1268 keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1269 Token key = m_decider.getStore(DataType::KEY_AES,
1270 policy).generateSKey(keyGenAlgorithm, policy.password, digest);
1273 DB::Row row(std::move(key), name, owner,
1274 static_cast<int>(policy.extractable));
1275 handler.crypto.encryptRow(row);
1277 handler.database.saveRow(row);
1279 transaction.commit();
1280 return CKM_API_SUCCESS;
1283 int CKMLogic::createKeyPairHelper(
1284 const Credentials &cred,
1285 const CryptoAlgorithmSerializable &keyGenParams,
1286 const Name &namePrivate,
1287 const ClientId &ownerPrivate,
1288 const Name &namePublic,
1289 const ClientId &ownerPublic,
1290 const PolicySerializable &policyPrivate,
1291 const PolicySerializable &policyPublic)
1293 auto &handlerPriv = selectDatabase(cred, ownerPrivate);
1294 auto &handlerPub = selectDatabase(cred, ownerPublic);
1296 AlgoType keyType = AlgoType::RSA_GEN;
1298 if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1299 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1301 const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType);
1302 if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end())
1303 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1304 const DataTypePair& dt = dtIt->second;
1306 if (policyPrivate.backend != policyPublic.backend)
1307 ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1309 bool exportable = policyPrivate.extractable || policyPublic.extractable;
1310 Policy lessRestricted(Password(), exportable, policyPrivate.backend);
1312 auto digestPriv = CryptoLogic::makeHash(namePrivate, ownerPrivate, cred.clientUid);
1313 if (digestPriv.empty())
1314 return CKM_API_ERROR_HASH_ERROR;
1316 auto digestPub = CryptoLogic::makeHash(namePublic, ownerPublic, cred.clientUid);
1317 if (digestPub.empty())
1318 return CKM_API_ERROR_HASH_ERROR;
1320 TokenPair keys = m_decider.getStore(policyPrivate, dt.first, dt.second).generateAKey(keyGenParams,
1321 policyPrivate.password,
1322 policyPublic.password,
1323 digestPriv, digestPub);
1325 DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
1326 // in case the same database is used for private and public - the second
1327 // transaction will not be executed
1328 DB::Crypto::Transaction transactionPub(&handlerPub.database);
1331 retCode = checkSaveConditions(cred, handlerPriv, namePrivate, ownerPrivate);
1332 if (CKM_API_SUCCESS != retCode)
1335 retCode = checkSaveConditions(cred, handlerPub, namePublic, ownerPublic);
1336 if (CKM_API_SUCCESS != retCode)
1340 DB::Row rowPrv(std::move(keys.first), namePrivate, ownerPrivate,
1341 static_cast<int>(policyPrivate.extractable));
1342 handlerPriv.crypto.encryptRow(rowPrv);
1343 handlerPriv.database.saveRow(rowPrv);
1345 DB::Row rowPub(std::move(keys.second), namePublic, ownerPublic,
1346 static_cast<int>(policyPublic.extractable));
1347 handlerPub.crypto.encryptRow(rowPub);
1348 handlerPub.database.saveRow(rowPub);
1350 transactionPub.commit();
1351 transactionPriv.commit();
1352 return CKM_API_SUCCESS;
1355 RawBuffer CKMLogic::createKeyPair(
1356 const Credentials &cred,
1358 const CryptoAlgorithmSerializable &keyGenParams,
1359 const Name &namePrivate,
1360 const ClientId &ownerPrivate,
1361 const Name &namePublic,
1362 const ClientId &ownerPublic,
1363 const PolicySerializable &policyPrivate,
1364 const PolicySerializable &policyPublic)
1366 return SerializeMessage(msgId, tryRet([&] {
1367 return createKeyPairHelper(cred, keyGenParams, namePrivate, ownerPrivate,
1368 namePublic, ownerPublic, policyPrivate, policyPublic);
1372 RawBuffer CKMLogic::createKeyAES(
1373 const Credentials &cred,
1377 const ClientId &owner,
1378 const PolicySerializable &policy)
1380 int retCode = CKM_API_SUCCESS;
1383 retCode = tryRet([&] {
1384 return createKeyAESHelper(cred, size, name, owner, policy);
1386 } catch (std::invalid_argument &e) {
1387 LogDebug("invalid argument error: " << e.what());
1388 retCode = CKM_API_ERROR_INPUT_PARAM;
1391 return SerializeMessage(msgId, retCode);
1394 int CKMLogic::readCertificateHelper(
1395 const Credentials &cred,
1396 const OwnerNameVector &ownerNameVector,
1397 CertificateImplVector &certVector)
1399 for (auto &i : ownerNameVector) {
1400 // certificates can't be protected with custom user password
1401 Crypto::GObjUPtr obj;
1403 ec = readDataHelper(true,
1405 DataType::CERTIFICATE,
1407 cred.effectiveOwner(i.first),
1411 if (ec != CKM_API_SUCCESS)
1414 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1416 // try to read chain certificates (if present)
1417 Crypto::GObjUPtrVector caChainObjs;
1418 ec = readDataHelper(true,
1420 DataType::DB_CHAIN_FIRST,
1422 cred.effectiveOwner(i.first),
1426 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1429 for (auto &caCertObj : caChainObjs)
1430 certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1433 return CKM_API_SUCCESS;
1436 int CKMLogic::getCertificateChainHelper(
1437 const CertificateImpl &cert,
1438 const RawBufferVector &untrustedCertificates,
1439 const RawBufferVector &trustedCertificates,
1440 bool useTrustedSystemCertificates,
1441 RawBufferVector &chainRawVector)
1443 CertificateImplVector untrustedCertVector;
1444 CertificateImplVector trustedCertVector;
1445 CertificateImplVector chainVector;
1448 return CKM_API_ERROR_INPUT_PARAM;
1450 for (auto &e : untrustedCertificates) {
1451 CertificateImpl c(e, DataFormat::FORM_DER);
1454 return CKM_API_ERROR_INPUT_PARAM;
1456 untrustedCertVector.push_back(std::move(c));
1459 for (auto &e : trustedCertificates) {
1460 CertificateImpl c(e, DataFormat::FORM_DER);
1463 return CKM_API_ERROR_INPUT_PARAM;
1465 trustedCertVector.push_back(std::move(c));
1468 CertificateStore store;
1469 int retCode = store.verifyCertificate(cert,
1470 untrustedCertVector,
1472 useTrustedSystemCertificates,
1473 m_accessControl.isCCMode(),
1476 if (retCode != CKM_API_SUCCESS)
1479 for (auto &e : chainVector)
1480 chainRawVector.push_back(e.getDER());
1482 return CKM_API_SUCCESS;
1485 int CKMLogic::getCertificateChainHelper(
1486 const Credentials &cred,
1487 const CertificateImpl &cert,
1488 const OwnerNameVector &untrusted,
1489 const OwnerNameVector &trusted,
1490 bool useTrustedSystemCertificates,
1491 RawBufferVector &chainRawVector)
1493 CertificateImplVector untrustedCertVector;
1494 CertificateImplVector trustedCertVector;
1495 CertificateImplVector chainVector;
1498 return CKM_API_ERROR_INPUT_PARAM;
1500 int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1502 if (retCode != CKM_API_SUCCESS)
1505 retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1507 if (retCode != CKM_API_SUCCESS)
1510 CertificateStore store;
1511 retCode = store.verifyCertificate(cert,
1512 untrustedCertVector,
1514 useTrustedSystemCertificates,
1515 m_accessControl.isCCMode(),
1518 if (retCode != CKM_API_SUCCESS)
1521 for (auto &i : chainVector)
1522 chainRawVector.push_back(i.getDER());
1524 return CKM_API_SUCCESS;
1527 RawBuffer CKMLogic::getCertificateChain(
1528 const Credentials & /*cred*/,
1530 const RawBuffer &certificate,
1531 const RawBufferVector &untrustedCertificates,
1532 const RawBufferVector &trustedCertificates,
1533 bool useTrustedSystemCertificates)
1535 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1536 RawBufferVector chainRawVector;
1537 int retCode = CKM_API_ERROR_UNKNOWN;
1540 retCode = getCertificateChainHelper(cert,
1541 untrustedCertificates,
1542 trustedCertificates,
1543 useTrustedSystemCertificates,
1545 } catch (const Exc::Exception &e) {
1546 retCode = e.error();
1547 } catch (const std::exception &e) {
1548 LogError("STD exception " << e.what());
1549 retCode = CKM_API_ERROR_SERVER_ERROR;
1551 LogError("Unknown error.");
1554 return SerializeMessage(msgId, retCode, chainRawVector);
1557 RawBuffer CKMLogic::getCertificateChain(
1558 const Credentials &cred,
1560 const RawBuffer &certificate,
1561 const OwnerNameVector &untrustedCertificates,
1562 const OwnerNameVector &trustedCertificates,
1563 bool useTrustedSystemCertificates)
1565 int retCode = CKM_API_ERROR_UNKNOWN;
1566 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1567 RawBufferVector chainRawVector;
1570 retCode = getCertificateChainHelper(cred,
1572 untrustedCertificates,
1573 trustedCertificates,
1574 useTrustedSystemCertificates,
1576 } catch (const Exc::Exception &e) {
1577 retCode = e.error();
1578 } catch (const std::exception &e) {
1579 LogError("STD exception " << e.what());
1580 retCode = CKM_API_ERROR_SERVER_ERROR;
1582 LogError("Unknown error.");
1585 return SerializeMessage(msgId, retCode, chainRawVector);
1588 RawBuffer CKMLogic::createSignature(
1589 const Credentials &cred,
1591 const Name &privateKeyName,
1592 const ClientId &owner,
1593 const Password &password, // password for private_key
1594 const RawBuffer &message,
1595 const CryptoAlgorithm &cryptoAlg)
1597 RawBuffer signature;
1599 int retCode = CKM_API_SUCCESS;
1602 retCode = tryRet([&] {
1603 Crypto::GObjUPtr obj;
1604 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1605 owner, password, obj);
1607 if (retCode == CKM_API_SUCCESS)
1608 signature = obj->sign(cryptoAlg, message);
1612 } catch (const std::exception &e) {
1613 LogError("STD exception " << e.what());
1614 retCode = CKM_API_ERROR_SERVER_ERROR;
1617 return SerializeMessage(msgId, retCode, signature);
1620 RawBuffer CKMLogic::verifySignature(
1621 const Credentials &cred,
1623 const Name &publicKeyOrCertName,
1624 const ClientId &owner,
1625 const Password &password, // password for public_key (optional)
1626 const RawBuffer &message,
1627 const RawBuffer &signature,
1628 const CryptoAlgorithm ¶ms)
1630 return SerializeMessage(msgId, tryRet([&] {
1631 // try certificate first - looking for a public key.
1632 // in case of PKCS, pub key from certificate will be found first
1633 // rather than private key from the same PKCS.
1634 Crypto::GObjUPtr obj;
1635 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1636 publicKeyOrCertName, owner, password, obj);
1638 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1639 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1640 publicKeyOrCertName, owner, password, obj);
1642 if (retCode == CKM_API_SUCCESS)
1643 retCode = obj->verify(params, message, signature);
1649 int CKMLogic::setPermissionHelper(
1650 const Credentials &cred, // who's the client
1652 const ClientId &owner, // who's the owner
1653 const ClientId &accessor, // who will get the access
1654 const PermissionMask permissionMask)
1656 auto &handler = selectDatabase(cred, owner);
1658 // we don't know the client
1659 if (cred.client.empty() || !isClientValid(cred.client))
1660 return CKM_API_ERROR_INPUT_PARAM;
1662 // verify name and owner are correct
1663 if (!isNameValid(name) || !isClientValid(owner) ||
1664 !isClientValid(accessor))
1665 return CKM_API_ERROR_INPUT_PARAM;
1667 // currently we don't support modification of owner's permissions to his own rows
1668 if (owner == accessor)
1669 return CKM_API_ERROR_INPUT_PARAM;
1671 // system database does not support write/remove permissions
1672 if ((0 == owner.compare(CLIENT_ID_SYSTEM)) &&
1673 (permissionMask & Permission::REMOVE))
1674 return CKM_API_ERROR_INPUT_PARAM;
1676 // can the client modify permissions to owner's row?
1677 int retCode = m_accessControl.canModify(cred, owner);
1679 if (retCode != CKM_API_SUCCESS)
1682 DB::Crypto::Transaction transaction(&handler.database);
1684 if (!handler.database.isNameOwnerPresent(name, owner))
1685 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1687 // set permissions to the row owned by owner for accessor
1688 handler.database.setPermission(name, owner, accessor, permissionMask);
1689 transaction.commit();
1691 return CKM_API_SUCCESS;
1694 RawBuffer CKMLogic::setPermission(
1695 const Credentials &cred,
1698 const ClientId &owner,
1699 const ClientId &accessor,
1700 const PermissionMask permissionMask)
1702 return SerializeMessage(msgID, tryRet([&] {
1703 return setPermissionHelper(cred, name, owner, accessor, permissionMask);