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,
107 DataFormat::FORM_DER);
109 if (cert.get() == NULL) {
110 LogDebug("provided binary data is not valid certificate data");
111 return CKM_API_ERROR_INPUT_PARAM;
114 output = Crypto::Data(input.type, cert->getDER());
119 // TODO: add here BINARY_DATA verification, i.e: max size etc.
120 return CKM_API_SUCCESS;
123 int verifyBinaryData(Crypto::Data &input)
126 return toBinaryData(input, dummy);
129 int readSingleRow(const Name &name,
130 const ClientId &owner,
132 DB::Crypto &database,
135 DB::Crypto::RowOptional row_optional;
137 if (dataType.isKey()) {
138 // read all key types
139 row_optional = database.getRow(name,
141 DataType::DB_KEY_FIRST,
142 DataType::DB_KEY_LAST);
144 // read anything else
145 row_optional = database.getRow(name,
151 LogDebug("No row for given name, owner and type");
152 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
157 return CKM_API_SUCCESS;
160 int readMultiRow(const Name &name,
161 const ClientId &owner,
163 DB::Crypto &database,
164 DB::RowVector &output)
166 if (dataType.isKey())
167 // read all key types
168 database.getRows(name,
170 DataType::DB_KEY_FIRST,
171 DataType::DB_KEY_LAST,
173 else if (dataType.isChainCert())
174 // read all key types
175 database.getRows(name,
177 DataType::DB_CHAIN_FIRST,
178 DataType::DB_CHAIN_LAST,
181 // read anything else
182 database.getRows(name,
187 if (!output.size()) {
188 LogDebug("No row for given name, owner and type");
189 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
192 return CKM_API_SUCCESS;
195 int loadAppKey(UserData &handler, const ClientId &owner, bool keyRequired = true)
197 if (!handler.crypto.haveKey(owner)) {
198 RawBuffer wrappedDEK;
199 auto wrappedDEKOptional = handler.database.getKey(owner);
201 if (!wrappedDEKOptional) {
203 LogError("No key for given owner in database");
204 return CKM_API_ERROR_DB_ERROR;
206 LogDebug("No Key in database found. Generating new one for client: " << owner);
207 wrappedDEK = handler.keyProvider.generateDEK(owner);
208 handler.database.saveKey(owner, wrappedDEK);
210 wrappedDEK = *wrappedDEKOptional;
213 handler.crypto.pushKey(owner, handler.keyProvider.getPureDEK(wrappedDEK));
216 return CKM_API_SUCCESS;
221 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
222 const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
226 CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
228 m_accessControl.updateCCMode();
231 CKMLogic::~CKMLogic() {}
233 void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
235 auto &handle = m_userDataMap[user];
239 auto wrappedDKEK = fs.getDKEK();
241 if (wrappedDKEK.empty()) {
242 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
243 fs.saveDKEK(wrappedDKEK);
246 handle.keyProvider = KeyProvider(wrappedDKEK, password);
247 if (!handle.keyProvider.isInitialized()) {
248 handle.keyProvider.migrateDomainKEK(wrappedDKEK, password);
249 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
250 LogInfo("DKEK migrated");
254 void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
256 auto &handle = m_userDataMap[user];
259 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
262 void CKMLogic::migrateSecureStorageData(bool isAdminUser)
264 SsMigration::migrate(isAdminUser, [this](const std::string &name,
265 const Crypto::Data &data,
266 bool adminUserFlag) {
267 LogInfo("Migrate data called with name: " << name);
268 auto ownerId = adminUserFlag ? CLIENT_ID_ADMIN_USER : CLIENT_ID_SYSTEM;
269 auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
271 int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
272 PolicySerializable());
274 if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
275 LogWarning("Alias already exist for migrated name: " << name);
276 else if (ret != CKM_API_SUCCESS)
277 LogError("Failed to migrate secure-storage data. name: " << name <<
282 int CKMLogic::unlockDatabase(uid_t user, const Password &password)
284 if (0 < m_userDataMap.count(user) &&
285 m_userDataMap[user].keyProvider.isInitialized())
286 return CKM_API_SUCCESS;
288 int retCode = tryRet([&] {
289 auto &handle = m_userDataMap[user];
292 loadDKEKFile(user, password);
294 auto wrappedDatabaseDEK = fs.getDBDEK();
296 if (wrappedDatabaseDEK.empty()) {
297 wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
298 fs.saveDBDEK(wrappedDatabaseDEK);
301 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
303 handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
304 handle.crypto = CryptoLogic();
306 if (!m_accessControl.isSystemService(user)) {
307 // remove data of removed apps during locked state
308 ClientIdVector removedApps = fs.clearRemovedsApps();
310 for (auto &app : removedApps) {
311 handle.crypto.removeKey(app);
312 handle.database.deleteKey(app);
316 if (user == SYSTEM_DB_UID && SsMigration::hasData())
317 migrateSecureStorageData(false);
318 else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
319 migrateSecureStorageData(true);
321 return CKM_API_SUCCESS;
324 if (CKM_API_SUCCESS != retCode)
325 m_userDataMap.erase(user);
330 int CKMLogic::unlockSystemDB()
332 return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
335 UserData &CKMLogic::selectDatabase(const Credentials &cred,
336 const ClientId &owner)
338 // if user trying to access system service - check:
339 // * if user database is unlocked [mandatory]
340 // * if not - proceed with regular user database
341 // * if explicit system database owner given -> switch to system DB
342 if (!m_accessControl.isSystemService(cred)) {
343 if (0 == m_userDataMap.count(cred.clientUid))
344 ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
346 if (0 != owner.compare(CLIENT_ID_SYSTEM))
347 return m_userDataMap[cred.clientUid];
350 // system database selected, modify the owner id
351 if (CKM_API_SUCCESS != unlockSystemDB())
352 ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
354 return m_userDataMap[SYSTEM_DB_UID];
357 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
359 int retCode = CKM_API_SUCCESS;
361 if (!m_accessControl.isSystemService(user))
362 retCode = unlockDatabase(user, password);
363 else // do not allow lock/unlock operations for system users
364 retCode = CKM_API_ERROR_INPUT_PARAM;
366 return SerializeMessage(retCode);
369 RawBuffer CKMLogic::updateCCMode()
371 m_accessControl.updateCCMode();
372 return SerializeMessage(CKM_API_SUCCESS);
375 RawBuffer CKMLogic::lockUserKey(uid_t user)
377 int retCode = CKM_API_SUCCESS;
379 if (!m_accessControl.isSystemService(user))
380 m_userDataMap.erase(user);
381 else // do not allow lock/unlock operations for system users
382 retCode = CKM_API_ERROR_INPUT_PARAM;
384 return SerializeMessage(retCode);
387 RawBuffer CKMLogic::removeUserData(uid_t user)
389 if (m_accessControl.isSystemService(user))
390 user = SYSTEM_DB_UID;
392 m_userDataMap.erase(user);
394 const int retCode = FileSystem(user).removeUserData()
395 ? CKM_API_ERROR_FILE_SYSTEM
398 return SerializeMessage(retCode);
401 int CKMLogic::changeUserPasswordHelper(uid_t user,
402 const Password &oldPassword,
403 const Password &newPassword)
405 // do not allow to change system database password
406 if (m_accessControl.isSystemService(user))
407 return CKM_API_ERROR_INPUT_PARAM;
409 loadDKEKFile(user, oldPassword);
410 saveDKEKFile(user, newPassword);
412 return CKM_API_SUCCESS;
415 RawBuffer CKMLogic::changeUserPassword(
417 const Password &oldPassword,
418 const Password &newPassword)
420 return SerializeMessage(tryRet([&] {
421 return changeUserPasswordHelper(user, oldPassword, newPassword);
425 int CKMLogic::resetUserPasswordHelper(
427 const Password &newPassword)
429 // do not allow to reset system database password
430 if (m_accessControl.isSystemService(user))
431 return CKM_API_ERROR_INPUT_PARAM;
433 int retCode = CKM_API_SUCCESS;
435 if (0 == m_userDataMap.count(user)) {
436 // Check if key exists. If exists we must return error
438 auto wrappedDKEKMain = fs.getDKEK();
440 if (!wrappedDKEKMain.empty())
441 retCode = CKM_API_ERROR_BAD_REQUEST;
443 saveDKEKFile(user, newPassword);
449 RawBuffer CKMLogic::resetUserPassword(
451 const Password &newPassword)
453 return SerializeMessage(tryRet([&] {
454 return resetUserPasswordHelper(user, newPassword);
458 RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
460 return SerializeMessage(tryRet([&] {
462 return CKM_API_ERROR_INPUT_PARAM;
464 UidVector uids = FileSystem::getUIDsFromDBFile();
466 for (auto userId : uids) {
467 if (0 == m_userDataMap.count(userId)) {
468 FileSystem fs(userId);
469 fs.addRemovedApp(owner);
471 auto &handle = m_userDataMap[userId];
472 handle.crypto.removeKey(owner);
473 handle.database.deleteKey(owner);
477 return CKM_API_SUCCESS;
481 int CKMLogic::checkSaveConditions(
482 const Credentials &accessorCred,
485 const ClientId &owner)
487 // verify name and client are correct
488 if (!isNameValid(name) || !isClientValid(owner)) {
489 LogDebug("Invalid parameter passed to key-manager");
490 return CKM_API_ERROR_INPUT_PARAM;
493 // check if accessor is allowed to save owner's items
494 int access_ec = m_accessControl.canSave(accessorCred, owner);
496 if (access_ec != CKM_API_SUCCESS) {
497 LogDebug("accessor " << accessorCred.client << " can not save rows owned by " <<
502 // check if not a duplicate
503 if (handler.database.isNameOwnerPresent(name, owner))
504 return CKM_API_ERROR_DB_ALIAS_EXISTS;
506 // generate (if needed) and load the app key
507 loadAppKey(handler, owner, false);
509 return CKM_API_SUCCESS;
512 DB::Row CKMLogic::createEncryptedRow(
515 const ClientId &owner,
516 const Crypto::Data &data,
517 const Policy &policy,
518 const RawBuffer &hash)
520 Crypto::GStore &store = m_decider.getStore(data.type, policy);
522 // do not encrypt data with password during cc_mode on
523 Token token = store.import(data,
524 m_accessControl.isCCMode() ? "" : policy.password,
525 Crypto::EncryptionParams(), hash);
526 DB::Row row(std::move(token), name, owner,
527 static_cast<int>(policy.extractable));
528 crypto.encryptRow(row);
532 int CKMLogic::verifyAndSaveDataHelper(
533 const Credentials &cred,
535 const ClientId &owner,
536 const Crypto::Data &data,
537 const PolicySerializable &policy)
540 // check if data is correct
541 Crypto::Data binaryData;
542 int retCode = toBinaryData(data, binaryData);
544 return retCode != CKM_API_SUCCESS
546 : saveDataHelper(cred, name, owner, binaryData, policy);
550 int CKMLogic::getKeyForService(
551 const Credentials &cred,
553 const ClientId &owner,
554 const Password &pass,
555 Crypto::GObjShPtr &key)
558 // Key is for internal service use. It won't be exported to the client
559 Crypto::GObjUPtr obj;
560 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, owner,
563 if (retCode == CKM_API_SUCCESS)
564 key = std::move(obj);
570 RawBuffer CKMLogic::saveData(
571 const Credentials &cred,
574 const ClientId &owner,
575 const Crypto::Data &data,
576 const PolicySerializable &policy)
578 int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
579 return SerializeMessage(msgId, retCode, data.type);
582 int CKMLogic::extractPKCS12Data(
585 const ClientId &owner,
586 const PKCS12Serializable &pkcs,
587 const PolicySerializable &keyPolicy,
588 const PolicySerializable &certPolicy,
589 DB::RowVector &output,
590 const Credentials &cred)
592 // private key is mandatory
593 auto key = pkcs.getKey();
596 LogError("Failed to get private key from pkcs");
597 return CKM_API_ERROR_INVALID_FORMAT;
600 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
602 return CKM_API_ERROR_HASH_ERROR;
604 Crypto::Data keyData(DataType(key->getType()), key->getDER());
605 int retCode = verifyBinaryData(keyData);
607 if (retCode != CKM_API_SUCCESS)
610 output.push_back(createEncryptedRow(crypto, name, owner, keyData,
613 // certificate is mandatory
614 auto cert = pkcs.getCertificate();
617 LogError("Failed to get certificate from pkcs");
618 return CKM_API_ERROR_INVALID_FORMAT;
621 Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
622 retCode = verifyBinaryData(certData);
624 if (retCode != CKM_API_SUCCESS)
627 output.push_back(createEncryptedRow(crypto, name, owner, certData,
628 certPolicy, digest));
631 unsigned int cert_index = 0;
633 for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
634 Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++),
636 int retCode = verifyBinaryData(caCertData);
638 if (retCode != CKM_API_SUCCESS)
641 output.push_back(createEncryptedRow(crypto, name, owner, caCertData,
642 certPolicy, digest));
645 return CKM_API_SUCCESS;
648 RawBuffer CKMLogic::savePKCS12(
649 const Credentials &cred,
652 const ClientId &owner,
653 const PKCS12Serializable &pkcs,
654 const PolicySerializable &keyPolicy,
655 const PolicySerializable &certPolicy)
657 return SerializeMessage(msgId, tryRet([&] {
658 return saveDataHelper(cred, name, owner, pkcs, keyPolicy, certPolicy);
663 int CKMLogic::removeDataHelper(
664 const Credentials &cred,
666 const ClientId &owner)
668 auto &handler = selectDatabase(cred, owner);
670 if (!isNameValid(name) || !isClientValid(owner)) {
671 LogDebug("Invalid owner or name format");
672 return CKM_API_ERROR_INPUT_PARAM;
675 DB::Crypto::Transaction transaction(&handler.database);
677 // read and check permissions
678 PermissionMaskOptional permissionRowOpt =
679 handler.database.getPermissionRow(name, owner, cred.client);
680 int retCode = m_accessControl.canDelete(cred,
681 toPermissionMask(permissionRowOpt));
683 if (retCode != CKM_API_SUCCESS) {
684 LogWarning("access control check result: " << retCode);
688 // get all matching rows
690 handler.database.getRows(name, owner, DataType::DB_FIRST,
691 DataType::DB_LAST, rows);
694 LogDebug("No row for given name and owner");
695 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
698 // load app key if needed
699 retCode = loadAppKey(handler, rows.front().owner);
701 if (CKM_API_SUCCESS != retCode)
704 // destroy it in store
705 for (auto &r : rows) {
707 handler.crypto.decryptRow(Password(), r);
708 m_decider.getStore(r).destroy(r);
709 } catch (const Exc::AuthenticationFailed &) {
710 LogDebug("Authentication failed when removing data. Ignored.");
715 handler.database.deleteRow(name, owner);
716 transaction.commit();
718 return CKM_API_SUCCESS;
721 RawBuffer CKMLogic::removeData(
722 const Credentials &cred,
725 const ClientId &owner)
727 return SerializeMessage(msgId, tryRet([&] {
728 return removeDataHelper(cred, name, owner);
733 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
735 const ClientId &owner,
738 DB::Crypto &database)
740 PermissionMaskOptional permissionRowOpt =
741 database.getPermissionRow(name, owner, accessorCred.client);
744 return m_accessControl.canExport(accessorCred,
746 toPermissionMask(permissionRowOpt));
748 return m_accessControl.canRead(accessorCred,
749 toPermissionMask(permissionRowOpt));
752 Crypto::GObjUPtr CKMLogic::rowToObject(
755 const Password &password,
756 const RawBuffer &hash)
758 Crypto::GStore &store = m_decider.getStore(row);
760 Password pass = m_accessControl.isCCMode() ? "" : password;
763 Crypto::GObjUPtr obj;
765 if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
766 CryptoLogic::ENCRYPTION_V2) {
767 handler.crypto.decryptRow(Password(), row);
769 obj = store.getObject(row, pass);
771 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
772 handler.crypto.decryptRow(pass, row);
773 // destroy it in store
776 // import it to store with new scheme: data -> pass(data)
777 Token token = store.import(Crypto::Data(row.dataType, row.data), pass, Crypto::EncryptionParams(), hash);
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,
1100 // user - lookup system, then client DB
1101 retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
1107 if (retCode == CKM_API_SUCCESS) {
1108 retCode = getDataListHelper(cred,
1115 if (retCode == CKM_API_SUCCESS) {
1116 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
1117 systemVector.end());
1118 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
1122 return SerializeMessage(msgId, retCode, dataType, ownerNameVector);
1125 int CKMLogic::importInitialData(
1127 const Crypto::Data &data,
1128 const Crypto::EncryptionParams &encParams,
1129 const Policy &policy)
1133 if (encParams.iv.empty() != encParams.tag.empty()) {
1134 LogError("Both iv and tag must be empty or set");
1135 return CKM_API_ERROR_INPUT_PARAM;
1138 // Inital values are always imported with root credentials. Client id is not important.
1139 Credentials rootCred(0, "");
1140 ClientId owner(CLIENT_ID_SYSTEM);
1141 auto &handler = selectDatabase(rootCred, CLIENT_ID_SYSTEM);
1143 // check if save is possible
1144 DB::Crypto::Transaction transaction(&handler.database);
1145 int retCode = checkSaveConditions(rootCred, handler, name, CLIENT_ID_SYSTEM);
1146 if (retCode != CKM_API_SUCCESS)
1149 Crypto::GStore &store = m_decider.getStore(data.type,
1151 !encParams.iv.empty());
1155 auto digest = CryptoLogic::makeHash(name, owner, rootCred.clientUid);
1157 return CKM_API_ERROR_HASH_ERROR;
1159 if (encParams.iv.empty()) {
1160 // Data are not encrypted, let's try to verify them
1161 Crypto::Data binaryData;
1163 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
1166 token = store.import(binaryData,
1167 m_accessControl.isCCMode() ? "" : policy.password,
1170 token = store.import(data,
1171 m_accessControl.isCCMode() ? "" : policy.password,
1175 DB::Row row(std::move(token), name, CLIENT_ID_SYSTEM,
1176 static_cast<int>(policy.extractable));
1177 handler.crypto.encryptRow(row);
1179 handler.database.saveRow(row);
1180 transaction.commit();
1182 return CKM_API_SUCCESS;
1184 } catch (const std::exception &e) {
1185 LogError("Std::exception: " << e.what());
1186 return CKM_API_ERROR_SERVER_ERROR;
1190 int CKMLogic::saveDataHelper(
1191 const Credentials &cred,
1193 const ClientId &owner,
1194 const Crypto::Data &data,
1195 const PolicySerializable &policy)
1197 auto &handler = selectDatabase(cred, owner);
1199 // check if save is possible
1200 DB::Crypto::Transaction transaction(&handler.database);
1201 int retCode = checkSaveConditions(cred, handler, name, owner);
1202 if (retCode != CKM_API_SUCCESS)
1205 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1207 return CKM_API_ERROR_HASH_ERROR;
1210 DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, owner,
1211 data, policy, digest);
1212 handler.database.saveRow(encryptedRow);
1214 transaction.commit();
1215 return CKM_API_SUCCESS;
1218 int CKMLogic::saveDataHelper(
1219 const Credentials &cred,
1221 const ClientId &owner,
1222 const PKCS12Serializable &pkcs,
1223 const PolicySerializable &keyPolicy,
1224 const PolicySerializable &certPolicy)
1226 auto &handler = selectDatabase(cred, owner);
1228 // check if save is possible
1229 DB::Crypto::Transaction transaction(&handler.database);
1230 int retCode = checkSaveConditions(cred, handler, name, owner);
1231 if (retCode != CKM_API_SUCCESS)
1234 // extract and encrypt the data
1235 DB::RowVector encryptedRows;
1236 retCode = extractPKCS12Data(handler.crypto, name, owner, pkcs, keyPolicy,
1237 certPolicy, encryptedRows, cred);
1239 if (retCode != CKM_API_SUCCESS)
1243 handler.database.saveRows(name, owner, encryptedRows);
1244 transaction.commit();
1246 return CKM_API_SUCCESS;
1250 int CKMLogic::createKeyAESHelper(
1251 const Credentials &cred,
1254 const ClientId &owner,
1255 const PolicySerializable &policy)
1257 auto &handler = selectDatabase(cred, owner);
1259 // check if save is possible
1260 DB::Crypto::Transaction transaction(&handler.database);
1261 int retCode = checkSaveConditions(cred, handler, name, owner);
1262 if (retCode != CKM_API_SUCCESS)
1265 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1267 return CKM_API_ERROR_HASH_ERROR;
1269 // create key in store
1270 CryptoAlgorithm keyGenAlgorithm;
1271 keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1272 keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1273 Token key = m_decider.getStore(DataType::KEY_AES,
1274 policy).generateSKey(keyGenAlgorithm, policy.password, digest);
1277 DB::Row row(std::move(key), name, owner,
1278 static_cast<int>(policy.extractable));
1279 handler.crypto.encryptRow(row);
1281 handler.database.saveRow(row);
1283 transaction.commit();
1284 return CKM_API_SUCCESS;
1287 int CKMLogic::createKeyPairHelper(
1288 const Credentials &cred,
1289 const CryptoAlgorithmSerializable &keyGenParams,
1290 const Name &namePrivate,
1291 const ClientId &ownerPrivate,
1292 const Name &namePublic,
1293 const ClientId &ownerPublic,
1294 const PolicySerializable &policyPrivate,
1295 const PolicySerializable &policyPublic)
1297 auto &handlerPriv = selectDatabase(cred, ownerPrivate);
1298 auto &handlerPub = selectDatabase(cred, ownerPublic);
1300 AlgoType keyType = AlgoType::RSA_GEN;
1302 if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1303 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1305 const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType);
1306 if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end())
1307 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1308 const DataTypePair& dt = dtIt->second;
1310 if (policyPrivate.backend != policyPublic.backend)
1311 ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1313 bool exportable = policyPrivate.extractable || policyPublic.extractable;
1314 Policy lessRestricted(Password(), exportable, policyPrivate.backend);
1316 auto digestPriv = CryptoLogic::makeHash(namePrivate, ownerPrivate, cred.clientUid);
1317 if (digestPriv.empty())
1318 return CKM_API_ERROR_HASH_ERROR;
1320 auto digestPub = CryptoLogic::makeHash(namePublic, ownerPublic, cred.clientUid);
1321 if (digestPub.empty())
1322 return CKM_API_ERROR_HASH_ERROR;
1324 TokenPair keys = m_decider.getStore(policyPrivate, dt.first, dt.second).generateAKey(keyGenParams,
1325 policyPrivate.password,
1326 policyPublic.password,
1327 digestPriv, digestPub);
1329 DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
1330 // in case the same database is used for private and public - the second
1331 // transaction will not be executed
1332 DB::Crypto::Transaction transactionPub(&handlerPub.database);
1335 retCode = checkSaveConditions(cred, handlerPriv, namePrivate, ownerPrivate);
1336 if (CKM_API_SUCCESS != retCode)
1339 retCode = checkSaveConditions(cred, handlerPub, namePublic, ownerPublic);
1340 if (CKM_API_SUCCESS != retCode)
1344 DB::Row rowPrv(std::move(keys.first), namePrivate, ownerPrivate,
1345 static_cast<int>(policyPrivate.extractable));
1346 handlerPriv.crypto.encryptRow(rowPrv);
1347 handlerPriv.database.saveRow(rowPrv);
1349 DB::Row rowPub(std::move(keys.second), namePublic, ownerPublic,
1350 static_cast<int>(policyPublic.extractable));
1351 handlerPub.crypto.encryptRow(rowPub);
1352 handlerPub.database.saveRow(rowPub);
1354 transactionPub.commit();
1355 transactionPriv.commit();
1356 return CKM_API_SUCCESS;
1359 RawBuffer CKMLogic::createKeyPair(
1360 const Credentials &cred,
1362 const CryptoAlgorithmSerializable &keyGenParams,
1363 const Name &namePrivate,
1364 const ClientId &ownerPrivate,
1365 const Name &namePublic,
1366 const ClientId &ownerPublic,
1367 const PolicySerializable &policyPrivate,
1368 const PolicySerializable &policyPublic)
1370 return SerializeMessage(msgId, tryRet([&] {
1371 return createKeyPairHelper(cred, keyGenParams, namePrivate, ownerPrivate,
1372 namePublic, ownerPublic, policyPrivate, policyPublic);
1376 RawBuffer CKMLogic::createKeyAES(
1377 const Credentials &cred,
1381 const ClientId &owner,
1382 const PolicySerializable &policy)
1384 int retCode = CKM_API_SUCCESS;
1387 retCode = tryRet([&] {
1388 return createKeyAESHelper(cred, size, name, owner, policy);
1390 } catch (std::invalid_argument &e) {
1391 LogDebug("invalid argument error: " << e.what());
1392 retCode = CKM_API_ERROR_INPUT_PARAM;
1395 return SerializeMessage(msgId, retCode);
1398 int CKMLogic::readCertificateHelper(
1399 const Credentials &cred,
1400 const OwnerNameVector &ownerNameVector,
1401 CertificateImplVector &certVector)
1403 for (auto &i : ownerNameVector) {
1404 // certificates can't be protected with custom user password
1405 Crypto::GObjUPtr obj;
1407 ec = readDataHelper(true,
1409 DataType::CERTIFICATE,
1411 cred.effectiveOwner(i.first),
1415 if (ec != CKM_API_SUCCESS)
1418 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1420 // try to read chain certificates (if present)
1421 Crypto::GObjUPtrVector caChainObjs;
1422 ec = readDataHelper(true,
1424 DataType::DB_CHAIN_FIRST,
1426 cred.effectiveOwner(i.first),
1430 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1433 for (auto &caCertObj : caChainObjs)
1434 certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1437 return CKM_API_SUCCESS;
1440 int CKMLogic::getCertificateChainHelper(
1441 const CertificateImpl &cert,
1442 const RawBufferVector &untrustedCertificates,
1443 const RawBufferVector &trustedCertificates,
1444 bool useTrustedSystemCertificates,
1445 RawBufferVector &chainRawVector)
1447 CertificateImplVector untrustedCertVector;
1448 CertificateImplVector trustedCertVector;
1449 CertificateImplVector chainVector;
1452 return CKM_API_ERROR_INPUT_PARAM;
1454 for (auto &e : untrustedCertificates) {
1455 CertificateImpl c(e, DataFormat::FORM_DER);
1458 return CKM_API_ERROR_INPUT_PARAM;
1460 untrustedCertVector.push_back(std::move(c));
1463 for (auto &e : trustedCertificates) {
1464 CertificateImpl c(e, DataFormat::FORM_DER);
1467 return CKM_API_ERROR_INPUT_PARAM;
1469 trustedCertVector.push_back(std::move(c));
1472 CertificateStore store;
1473 int retCode = store.verifyCertificate(cert,
1474 untrustedCertVector,
1476 useTrustedSystemCertificates,
1477 m_accessControl.isCCMode(),
1480 if (retCode != CKM_API_SUCCESS)
1483 for (auto &e : chainVector)
1484 chainRawVector.push_back(e.getDER());
1486 return CKM_API_SUCCESS;
1489 int CKMLogic::getCertificateChainHelper(
1490 const Credentials &cred,
1491 const CertificateImpl &cert,
1492 const OwnerNameVector &untrusted,
1493 const OwnerNameVector &trusted,
1494 bool useTrustedSystemCertificates,
1495 RawBufferVector &chainRawVector)
1497 CertificateImplVector untrustedCertVector;
1498 CertificateImplVector trustedCertVector;
1499 CertificateImplVector chainVector;
1502 return CKM_API_ERROR_INPUT_PARAM;
1504 int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1506 if (retCode != CKM_API_SUCCESS)
1509 retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1511 if (retCode != CKM_API_SUCCESS)
1514 CertificateStore store;
1515 retCode = store.verifyCertificate(cert,
1516 untrustedCertVector,
1518 useTrustedSystemCertificates,
1519 m_accessControl.isCCMode(),
1522 if (retCode != CKM_API_SUCCESS)
1525 for (auto &i : chainVector)
1526 chainRawVector.push_back(i.getDER());
1528 return CKM_API_SUCCESS;
1531 RawBuffer CKMLogic::getCertificateChain(
1532 const Credentials & /*cred*/,
1534 const RawBuffer &certificate,
1535 const RawBufferVector &untrustedCertificates,
1536 const RawBufferVector &trustedCertificates,
1537 bool useTrustedSystemCertificates)
1539 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1540 RawBufferVector chainRawVector;
1541 int retCode = CKM_API_ERROR_UNKNOWN;
1544 retCode = getCertificateChainHelper(cert,
1545 untrustedCertificates,
1546 trustedCertificates,
1547 useTrustedSystemCertificates,
1549 } catch (const Exc::Exception &e) {
1550 retCode = e.error();
1551 } catch (const std::exception &e) {
1552 LogError("STD exception " << e.what());
1553 retCode = CKM_API_ERROR_SERVER_ERROR;
1555 LogError("Unknown error.");
1558 return SerializeMessage(msgId, retCode, chainRawVector);
1561 RawBuffer CKMLogic::getCertificateChain(
1562 const Credentials &cred,
1564 const RawBuffer &certificate,
1565 const OwnerNameVector &untrustedCertificates,
1566 const OwnerNameVector &trustedCertificates,
1567 bool useTrustedSystemCertificates)
1569 int retCode = CKM_API_ERROR_UNKNOWN;
1570 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1571 RawBufferVector chainRawVector;
1574 retCode = getCertificateChainHelper(cred,
1576 untrustedCertificates,
1577 trustedCertificates,
1578 useTrustedSystemCertificates,
1580 } catch (const Exc::Exception &e) {
1581 retCode = e.error();
1582 } catch (const std::exception &e) {
1583 LogError("STD exception " << e.what());
1584 retCode = CKM_API_ERROR_SERVER_ERROR;
1586 LogError("Unknown error.");
1589 return SerializeMessage(msgId, retCode, chainRawVector);
1592 RawBuffer CKMLogic::createSignature(
1593 const Credentials &cred,
1595 const Name &privateKeyName,
1596 const ClientId &owner,
1597 const Password &password, // password for private_key
1598 const RawBuffer &message,
1599 const CryptoAlgorithm &cryptoAlg)
1601 RawBuffer signature;
1603 int retCode = CKM_API_SUCCESS;
1606 retCode = tryRet([&] {
1607 Crypto::GObjUPtr obj;
1608 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1609 owner, password, obj);
1611 if (retCode == CKM_API_SUCCESS)
1612 signature = obj->sign(cryptoAlg, message);
1616 } catch (const std::exception &e) {
1617 LogError("STD exception " << e.what());
1618 retCode = CKM_API_ERROR_SERVER_ERROR;
1621 return SerializeMessage(msgId, retCode, signature);
1624 RawBuffer CKMLogic::verifySignature(
1625 const Credentials &cred,
1627 const Name &publicKeyOrCertName,
1628 const ClientId &owner,
1629 const Password &password, // password for public_key (optional)
1630 const RawBuffer &message,
1631 const RawBuffer &signature,
1632 const CryptoAlgorithm ¶ms)
1634 return SerializeMessage(msgId, tryRet([&] {
1635 // try certificate first - looking for a public key.
1636 // in case of PKCS, pub key from certificate will be found first
1637 // rather than private key from the same PKCS.
1638 Crypto::GObjUPtr obj;
1639 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1640 publicKeyOrCertName, owner, password, obj);
1642 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1643 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1644 publicKeyOrCertName, owner, password, obj);
1646 if (retCode == CKM_API_SUCCESS)
1647 retCode = obj->verify(params, message, signature);
1653 int CKMLogic::setPermissionHelper(
1654 const Credentials &cred, // who's the client
1656 const ClientId &owner, // who's the owner
1657 const ClientId &accessor, // who will get the access
1658 const PermissionMask permissionMask)
1660 auto &handler = selectDatabase(cred, owner);
1662 // we don't know the client
1663 if (cred.client.empty() || !isClientValid(cred.client))
1664 return CKM_API_ERROR_INPUT_PARAM;
1666 // verify name and owner are correct
1667 if (!isNameValid(name) || !isClientValid(owner) ||
1668 !isClientValid(accessor))
1669 return CKM_API_ERROR_INPUT_PARAM;
1671 // currently we don't support modification of owner's permissions to his own rows
1672 if (owner == accessor)
1673 return CKM_API_ERROR_INPUT_PARAM;
1675 // system database does not support write/remove permissions
1676 if ((0 == owner.compare(CLIENT_ID_SYSTEM)) &&
1677 (permissionMask & Permission::REMOVE))
1678 return CKM_API_ERROR_INPUT_PARAM;
1680 // can the client modify permissions to owner's row?
1681 int retCode = m_accessControl.canModify(cred, owner);
1683 if (retCode != CKM_API_SUCCESS)
1686 DB::Crypto::Transaction transaction(&handler.database);
1688 if (!handler.database.isNameOwnerPresent(name, owner))
1689 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1691 // set permissions to the row owned by owner for accessor
1692 handler.database.setPermission(name, owner, accessor, permissionMask);
1693 transaction.commit();
1695 return CKM_API_SUCCESS;
1698 RawBuffer CKMLogic::setPermission(
1699 const Credentials &cred,
1702 const ClientId &owner,
1703 const ClientId &accessor,
1704 const PermissionMask permissionMask)
1706 return SerializeMessage(msgID, tryRet([&] {
1707 return setPermissionHelper(cred, name, owner, accessor, permissionMask);