Enable EC key pair generation in TZ backend
[platform/core/security/key-manager.git] / src / manager / service / ckm-logic.cpp
1 /*
2  *  Copyright (c) 2014-2021 Samsung Electronics Co., Ltd. All rights reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
15  *
16  *
17  * @file        ckm-logic.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     1.0
20  * @brief       Sample service implementation.
21  */
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>
29 #include <key-impl.h>
30 #include <key-aes-impl.h>
31 #include <certificate-config.h>
32 #include <certificate-store.h>
33 #include <algorithm>
34 #include <sw-backend/store.h>
35 #include <generic-backend/exception.h>
36 #include <ss-migrate.h>
37
38 namespace {
39 const char *const CERT_SYSTEM_DIR          = CA_CERTS_DIR;
40 const char *const DEFAULT_UNLOCK_STRING    = "cAtRugU7";
41
42 bool isClientValid(const CKM::ClientId &client)
43 {
44         if (client.find(CKM::ALIAS_SEPARATOR) != CKM::ClientId::npos)
45                 return false;
46
47         return true;
48 }
49
50 bool isNameValid(const CKM::Name &name)
51 {
52         if (name.find(CKM::ALIAS_SEPARATOR) != CKM::Name::npos)
53                 return false;
54
55         return true;
56 }
57
58 } // anonymous namespace
59
60 namespace CKM {
61
62 namespace {
63
64 template <int ERROR_ON_CKM_EXCEPTION = CKM_API_ERROR_SERVER_ERROR, class F>
65 int tryRet(F &&f)
66 {
67         try {
68                 static_assert(std::is_same_v<decltype(std::forward<F>(f)()), int>);
69                 return std::forward<F>(f)();
70         } catch (const Exc::Exception &e) {
71                 return e.error();
72         } catch (const CKM::Exception &e) {
73                 LogError("CKM::Exception: " << e.GetMessage());
74                 return ERROR_ON_CKM_EXCEPTION;
75         }
76 }
77
78 int toBinaryData(const Crypto::Data &input, Crypto::Data &output)
79 {
80         // verify the data integrity
81         if (input.type.isKey()) {
82                 KeyShPtr output_key;
83
84                 if (input.type.isSKey())
85                         output_key = CKM::Key::createAES(input.data);
86                 else
87                         output_key = CKM::Key::create(input.data);
88
89                 if (output_key.get() == NULL) {
90                         LogDebug("provided binary data is not valid key data");
91                         return CKM_API_ERROR_INPUT_PARAM;
92                 }
93
94                 output = Crypto::Data(input.type, output_key->getDER());
95         } else if (input.type.isCertificate() || input.type.isChainCert()) {
96                 CertificateShPtr cert = CKM::Certificate::create(input.data, DataFormat::FORM_DER);
97
98                 if (cert.get() == NULL) {
99                         LogDebug("provided binary data is not valid certificate data");
100                         return CKM_API_ERROR_INPUT_PARAM;
101                 }
102
103                 output = Crypto::Data(input.type, cert->getDER());
104         } else {
105                 output = input;
106         }
107
108         // TODO: add here BINARY_DATA verification, i.e: max size etc.
109         return CKM_API_SUCCESS;
110 }
111
112 int verifyBinaryData(const Crypto::Data &input)
113 {
114         Crypto::Data dummy;
115         return toBinaryData(input, dummy);
116 }
117
118 int readSingleRow(const Name &name,
119                 const ClientId &owner,
120                 DataType dataType,
121                 DB::Crypto &database,
122                 DB::Row &row)
123 {
124         DB::Crypto::RowOptional row_optional;
125
126         if (dataType.isKey()) {
127                 // read all key types
128                 row_optional = database.getRow(name,
129                                                                            owner,
130                                                                            DataType::DB_KEY_FIRST,
131                                                                            DataType::DB_KEY_LAST);
132         } else {
133                 // read anything else
134                 row_optional = database.getRow(name,
135                                                                            owner,
136                                                                            dataType);
137         }
138
139         if (!row_optional) {
140                 LogDebug("No row for given name, owner and type");
141                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
142         } else {
143                 row = *row_optional;
144         }
145
146         return CKM_API_SUCCESS;
147 }
148
149 int readMultiRow(const Name &name,
150                 const ClientId &owner,
151                 DataType dataType,
152                 DB::Crypto &database,
153                 DB::RowVector &output)
154 {
155         if (dataType.isKey())
156                 // read all key types
157                 database.getRows(name,
158                                                  owner,
159                                                  DataType::DB_KEY_FIRST,
160                                                  DataType::DB_KEY_LAST,
161                                                  output);
162         else if (dataType.isChainCert())
163                 // read all key types
164                 database.getRows(name,
165                                                  owner,
166                                                  DataType::DB_CHAIN_FIRST,
167                                                  DataType::DB_CHAIN_LAST,
168                                                  output);
169         else
170                 // read anything else
171                 database.getRows(name,
172                                                  owner,
173                                                  dataType,
174                                                  output);
175
176         if (!output.size()) {
177                 LogDebug("No row for given name, owner and type");
178                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
179         }
180
181         return CKM_API_SUCCESS;
182 }
183
184 } // namespace
185
186 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
187 const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
188
189 CKMLogic::CKMLogic()
190 {
191         CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
192
193         m_accessControl.updateCCMode();
194 }
195
196 CKMLogic::~CKMLogic() {}
197
198 void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
199 {
200         auto &handle = m_userDataMap[user];
201
202         FileSystem fs(user);
203
204         auto wrappedDKEK = fs.getDKEK();
205
206         if (wrappedDKEK.empty()) {
207                 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
208                 fs.saveDKEK(wrappedDKEK);
209         }
210
211         handle.keyProvider = KeyProvider(wrappedDKEK, password);
212         if (!handle.keyProvider.isInitialized()) {
213                 handle.keyProvider.migrateDomainKEK(wrappedDKEK, password);
214                 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
215                 LogInfo("DKEK migrated");
216         }
217 }
218
219 void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
220 {
221         auto &handle = m_userDataMap[user];
222
223         FileSystem fs(user);
224         fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
225 }
226
227 void CKMLogic::migrateSecureStorageData(bool isAdminUser)
228 {
229         SsMigration::migrate(isAdminUser, [this](const std::string &name,
230                                                                                          const Crypto::Data &data,
231                                                                                          bool adminUserFlag) {
232                 LogInfo("Migrate data called with  name: " << name);
233                 auto ownerId = adminUserFlag ? CLIENT_ID_ADMIN_USER : CLIENT_ID_SYSTEM;
234                 auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
235
236                 int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
237                                                                                   PolicySerializable());
238
239                 if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
240                         LogWarning("Alias already exist for migrated name: " << name);
241                 else if (ret != CKM_API_SUCCESS)
242                         LogError("Failed to migrate secure-storage data. name: " << name <<
243                                          " ret: " << ret);
244         });
245 }
246
247 int CKMLogic::unlockDatabase(uid_t user, const Password &password)
248 {
249         if (0 < m_userDataMap.count(user) &&
250                         m_userDataMap[user].keyProvider.isInitialized())
251                 return CKM_API_SUCCESS;
252
253         int retCode = tryRet([&] {
254                 auto &handle = m_userDataMap[user];
255
256                 FileSystem fs(user);
257                 loadDKEKFile(user, password);
258
259                 auto wrappedDatabaseDEK = fs.getDBDEK();
260
261                 if (wrappedDatabaseDEK.empty()) {
262                         wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
263                         fs.saveDBDEK(wrappedDatabaseDEK);
264                 }
265
266                 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
267
268                 handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
269                 handle.crypto = CryptoLogic();
270
271                 if (!m_accessControl.isSystemService(user)) {
272                         // remove data of removed apps during locked state
273                         ClientIdVector removedApps = fs.clearRemovedsApps();
274
275                         for (auto &app : removedApps) {
276                                 handle.crypto.removeKey(app);
277                                 handle.database.deleteKey(app);
278                         }
279                 }
280
281                 if (user == SYSTEM_DB_UID && SsMigration::hasData())
282                         migrateSecureStorageData(false);
283                 else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
284                         migrateSecureStorageData(true);
285
286                 return CKM_API_SUCCESS;
287         });
288
289         if (CKM_API_SUCCESS != retCode)
290                 m_userDataMap.erase(user);
291
292         return retCode;
293 }
294
295 int CKMLogic::unlockSystemDB()
296 {
297         return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
298 }
299
300 UserData &CKMLogic::selectDatabase(const Credentials &cred,
301                                                                    const ClientId &owner)
302 {
303         // if user trying to access system service - check:
304         //    * if user database is unlocked [mandatory]
305         //    * if not - proceed with regular user database
306         //    * if explicit system database owner given -> switch to system DB
307         if (!m_accessControl.isSystemService(cred)) {
308                 if (0 == m_userDataMap.count(cred.clientUid))
309                         ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
310
311                 if (0 != owner.compare(CLIENT_ID_SYSTEM))
312                         return m_userDataMap[cred.clientUid];
313         }
314
315         // system database selected, modify the owner id
316         if (CKM_API_SUCCESS != unlockSystemDB())
317                 ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
318
319         return m_userDataMap[SYSTEM_DB_UID];
320 }
321
322 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
323 {
324         int retCode = CKM_API_SUCCESS;
325
326         if (!m_accessControl.isSystemService(user))
327                 retCode = unlockDatabase(user, password);
328         else // do not allow lock/unlock operations for system users
329                 retCode = CKM_API_ERROR_INPUT_PARAM;
330
331         return SerializeMessage(retCode);
332 }
333
334 RawBuffer CKMLogic::updateCCMode()
335 {
336         m_accessControl.updateCCMode();
337         return SerializeMessage(CKM_API_SUCCESS);
338 }
339
340 RawBuffer CKMLogic::lockUserKey(uid_t user)
341 {
342         int retCode = CKM_API_SUCCESS;
343
344         if (!m_accessControl.isSystemService(user))
345                 m_userDataMap.erase(user);
346         else // do not allow lock/unlock operations for system users
347                 retCode = CKM_API_ERROR_INPUT_PARAM;
348
349         return SerializeMessage(retCode);
350 }
351
352 RawBuffer CKMLogic::removeUserData(uid_t user)
353 {
354         if (m_accessControl.isSystemService(user))
355                 user = SYSTEM_DB_UID;
356
357         m_userDataMap.erase(user);
358
359         const int retCode = FileSystem(user).removeUserData()
360                 ? CKM_API_ERROR_FILE_SYSTEM
361                 : CKM_API_SUCCESS;
362
363         return SerializeMessage(retCode);
364 }
365
366 RawBuffer CKMLogic::changeUserPassword(
367         uid_t user,
368         const Password &oldPassword,
369         const Password &newPassword)
370 {
371         return SerializeMessage(tryRet([&] {
372                 // do not allow to change system database password
373                 if (m_accessControl.isSystemService(user))
374                         return CKM_API_ERROR_INPUT_PARAM;
375
376                 loadDKEKFile(user, oldPassword);
377                 saveDKEKFile(user, newPassword);
378
379                 return CKM_API_SUCCESS;
380         }));
381 }
382
383 RawBuffer CKMLogic::resetUserPassword(
384         uid_t user,
385         const Password &newPassword)
386 {
387         return SerializeMessage(tryRet([&] {
388                 // do not allow to reset system database password
389                 if (m_accessControl.isSystemService(user))
390                         return CKM_API_ERROR_INPUT_PARAM;
391
392                 int retCode = CKM_API_SUCCESS;
393
394                 if (0 == m_userDataMap.count(user)) {
395                         // Check if key exists. If exists we must return error
396                         FileSystem fs(user);
397                         auto wrappedDKEKMain = fs.getDKEK();
398
399                         if (!wrappedDKEKMain.empty())
400                                 retCode = CKM_API_ERROR_BAD_REQUEST;
401                 } else {
402                         saveDKEKFile(user, newPassword);
403                 }
404
405                 return retCode;
406         }));
407 }
408
409 RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
410 {
411         return SerializeMessage(tryRet([&] {
412                 if (owner.empty())
413                         return CKM_API_ERROR_INPUT_PARAM;
414
415                 UidVector uids = FileSystem::getUIDsFromDBFile();
416
417                 for (auto userId : uids) {
418                         if (0 == m_userDataMap.count(userId)) {
419                                 FileSystem fs(userId);
420                                 fs.addRemovedApp(owner);
421                         } else {
422                                 auto &handle = m_userDataMap[userId];
423                                 handle.crypto.removeKey(owner);
424                                 handle.database.deleteKey(owner);
425                         }
426                 }
427
428                 return CKM_API_SUCCESS;
429         }));
430 }
431
432 int CKMLogic::verifyAndSaveDataHelper(
433         const Credentials &cred,
434         const Name &name,
435         const ClientId &owner,
436         const Crypto::Data &data,
437         const PolicySerializable &policy)
438 {
439         return tryRet([&] {
440                 // check if data is correct
441                 Crypto::Data binaryData;
442                 int retCode = toBinaryData(data, binaryData);
443                 if (retCode != CKM_API_SUCCESS)
444                         return retCode;
445
446                 auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, name, owner);
447                 if (ret != CKM_API_SUCCESS)
448                         return ret;
449
450                 Crypto::GStore &store = m_decider.getStore(binaryData.type, policy);
451
452                 // do not encrypt data with password during cc_mode on
453                 Token token = store.import(binaryData,
454                                                                    m_accessControl.isCCMode() ? "" : policy.password,
455                                                                    Crypto::EncryptionParams(), digest);
456                 dbOp.finalize(std::move(token), policy);
457                 return CKM_API_SUCCESS;
458         });
459 }
460
461 int CKMLogic::getKeyForService(
462         const Credentials &cred,
463         const Name &name,
464         const ClientId &owner,
465         const Password &pass,
466         Crypto::GObjShPtr &key)
467 {
468         return tryRet([&] {
469                 // Key is for internal service use. It won't be exported to the client
470                 Crypto::GObjUPtr obj;
471                 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, owner, pass, obj);
472                 if (retCode == CKM_API_SUCCESS)
473                         key = std::move(obj);
474
475                 return retCode;
476         });
477 }
478
479 RawBuffer CKMLogic::saveData(
480         const Credentials &cred,
481         int msgId,
482         const Name &name,
483         const ClientId &owner,
484         const Crypto::Data &data,
485         const PolicySerializable &policy)
486 {
487         int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
488         return SerializeMessage(msgId, retCode, data.type);
489 }
490
491 RawBuffer CKMLogic::savePKCS12(
492         const Credentials &cred,
493         int msgId,
494         const Name &name,
495         const ClientId &owner,
496         const PKCS12Serializable &pkcs,
497         const PolicySerializable &keyPolicy,
498         const PolicySerializable &certPolicy)
499 {
500         return SerializeMessage(msgId, tryRet([&] {
501                 auto [dbOp, retCode] = beginSave(cred, name, owner);
502                 if (retCode != CKM_API_SUCCESS)
503                         return retCode;
504
505                 // extract and encrypt the data
506                 DB::RowVector encryptedRows;
507
508                 auto import = [&](const Crypto::Data &data, const Policy& policy){
509                         retCode = verifyBinaryData(data);
510                         if (retCode != CKM_API_SUCCESS)
511                                 return retCode;
512
513                         auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid, data.type);
514                         if (digest.empty())
515                                 return CKM_API_ERROR_HASH_ERROR;
516
517                         Crypto::GStore &store = m_decider.getStore(data.type, policy);
518
519                         // do not encrypt data with password during cc_mode on
520                         Token token = store.import(data,
521                                                                            m_accessControl.isCCMode() ? "" : policy.password,
522                                                                            Crypto::EncryptionParams(), digest);
523
524                         encryptedRows.push_back(dbOp.encryptOne(std::move(token), policy));
525                         return CKM_API_SUCCESS;
526                 };
527
528                 // private key is mandatory
529                 auto key = pkcs.getKey();
530                 if (!key) {
531                         LogError("Failed to get private key from pkcs");
532                         return CKM_API_ERROR_INVALID_FORMAT;
533                 }
534
535                 Crypto::Data keyData(DataType(key->getType()), key->getDER());
536                 retCode = import(keyData, keyPolicy);
537                 if (retCode != CKM_API_SUCCESS)
538                         return retCode;
539
540                 // certificate is mandatory
541                 auto cert = pkcs.getCertificate();
542                 if (!cert) {
543                         LogError("Failed to get certificate from pkcs");
544                         return CKM_API_ERROR_INVALID_FORMAT;
545                 }
546
547                 Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
548                 retCode = import(certData, certPolicy);
549                 if (retCode != CKM_API_SUCCESS)
550                         return retCode;
551
552                 // CA cert chain
553                 unsigned int cert_index = 0;
554                 for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
555                         Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++), ca->getDER());
556                         retCode = import(caCertData, certPolicy);
557                         if (retCode != CKM_API_SUCCESS)
558                                 return retCode;
559                 }
560
561                 // save the data
562                 dbOp.database().saveRows(name, owner, encryptedRows);
563                 dbOp.transaction().commit();
564
565                 return CKM_API_SUCCESS;
566         }));
567 }
568
569 RawBuffer CKMLogic::removeData(
570         const Credentials &cred,
571         int msgId,
572         const Name &name,
573         const ClientId &owner)
574 {
575         return SerializeMessage(msgId, tryRet([&] {
576                 auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
577                 if (retCode != CKM_API_SUCCESS)
578                         return retCode;
579
580                 retCode = m_accessControl.canDelete(cred, permission);
581                 if (retCode != CKM_API_SUCCESS) {
582                         LogWarning("access control check result: " << retCode);
583                         return retCode;
584                 }
585
586                 // get all matching rows
587                 DB::RowVector rows;
588                 dbOp.database().getRows(name, owner, DataType::DB_FIRST, DataType::DB_LAST, rows);
589                 if (rows.empty()) {
590                         LogDebug("No row for given name and owner");
591                         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
592                 }
593
594                 retCode = dbOp.loadAppKey();
595                 if (retCode != CKM_API_SUCCESS)
596                         return retCode;
597
598                 // destroy it in store
599                 for (auto &r : rows) {
600                         try {
601                                 dbOp.handler().crypto.decryptRow(Password(), r);
602                                 m_decider.getStore(r).destroy(r);
603                         } catch (const Exc::AuthenticationFailed &) {
604                                 LogDebug("Authentication failed when removing data. Ignored.");
605                         }
606                 }
607
608                 // delete row in db
609                 dbOp.database().deleteRow(name, owner);
610                 dbOp.transaction().commit();
611
612                 return CKM_API_SUCCESS;
613         }));
614 }
615
616
617 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
618                 const DB::Row &row,
619                 bool exportFlag,
620                 const PermissionMask& permission)
621 {
622         if (exportFlag)
623                 return m_accessControl.canExport(accessorCred, row, permission);
624
625         return m_accessControl.canRead(accessorCred, permission);
626 }
627
628 Crypto::GObjUPtr CKMLogic::rowToObject(
629         UserData &handler,
630         DB::Row row,
631         const Password &password,
632         const RawBuffer &hash)
633 {
634         Crypto::GStore &store = m_decider.getStore(row);
635
636         Password pass = m_accessControl.isCCMode() ? "" : password;
637
638         // decrypt row
639         Crypto::GObjUPtr obj;
640
641         if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
642                         CryptoLogic::ENCRYPTION_V2) {
643                 handler.crypto.decryptRow(Password(), row);
644
645                 obj = store.getObject(row, pass);
646         } else {
647                 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
648                 handler.crypto.decryptRow(pass, row);
649                 // destroy it in store
650                 store.destroy(row);
651
652                 // import it to store with new scheme: data -> pass(data)
653                 Token token = store.import(Crypto::Data(row.dataType, row.data),
654                                                                    pass,
655                                                                    Crypto::EncryptionParams(),
656                                                                    hash);
657
658                 // get it from the store (it can be different than the data we imported into store)
659                 obj = store.getObject(token, pass);
660
661                 // update row with new token
662                 *static_cast<Token *>(&row) = std::move(token);
663
664                 // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
665                 handler.crypto.encryptRow(row);
666
667                 // update it in db
668                 handler.database.updateRow(row);
669         }
670
671         return obj;
672 }
673
674 int CKMLogic::readDataHelper(
675         bool exportFlag,
676         const Credentials &cred,
677         DataType dataType,
678         const Name &name,
679         const ClientId &owner,
680         const Password &password,
681         Crypto::GObjUPtrVector &objs)
682 {
683         auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
684         if (retCode != CKM_API_SUCCESS)
685                 return retCode;
686
687         // read rows
688         DB::RowVector rows;
689         retCode = readMultiRow(name, owner, dataType, dbOp.database(), rows);
690         if (CKM_API_SUCCESS != retCode)
691                 return retCode;
692
693         // all read rows belong to the same owner
694         DB::Row &firstRow = rows.at(0);
695
696         // check access rights
697         retCode = checkDataPermissionsHelper(cred, firstRow, exportFlag, permission);
698         if (CKM_API_SUCCESS != retCode)
699                 return retCode;
700
701         // for multiple objects add type as hash input (see pkcs12)
702         bool multiple = rows.size() > 1;
703
704         RawBuffer digest;
705
706         retCode = dbOp.loadAppKey();
707         if (retCode != CKM_API_SUCCESS)
708                 return retCode;
709
710         // decrypt row
711         for (auto &row : rows) {
712                 if (multiple)
713                         digest = CryptoLogic::makeHash(name, owner, cred.clientUid, row.dataType);
714                 else
715                         digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
716
717                 if (digest.empty())
718                         return CKM_API_ERROR_HASH_ERROR;
719
720                 objs.push_back(rowToObject(dbOp.handler(), std::move(row), password, digest));
721         }
722
723         // rowToObject may modify db
724         dbOp.transaction().commit();
725
726         return CKM_API_SUCCESS;
727 }
728
729 int CKMLogic::readDataHelper(
730         bool exportFlag,
731         const Credentials &cred,
732         DataType dataType,
733         const Name &name,
734         const ClientId &owner,
735         const Password &password,
736         Crypto::GObjUPtr &obj)
737 {
738         DataType objDataType;
739         return readDataHelper(exportFlag, cred, dataType, name, owner,
740                                                   password, obj, objDataType);
741 }
742
743 int CKMLogic::readDataHelper(
744         bool exportFlag,
745         const Credentials &cred,
746         DataType dataType,
747         const Name &name,
748         const ClientId &owner,
749         const Password &password,
750         Crypto::GObjUPtr &obj,
751         DataType &objDataType)
752 {
753         auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
754         if (retCode != CKM_API_SUCCESS)
755                 return retCode;
756
757         DB::Row row;
758         retCode = readSingleRow(name, owner, dataType, dbOp.database(), row);
759         if (CKM_API_SUCCESS != retCode)
760                 return retCode;
761
762         retCode = dbOp.loadAppKey();
763         if (retCode != CKM_API_SUCCESS)
764                 return retCode;
765
766         objDataType = row.dataType;
767
768         // check access rights
769         retCode = checkDataPermissionsHelper(cred, row, exportFlag, permission);
770         if (CKM_API_SUCCESS != retCode)
771                 return retCode;
772
773         auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
774         if (digest.empty())
775                 return CKM_API_ERROR_HASH_ERROR;
776
777         obj = rowToObject(dbOp.handler(), std::move(row), password, digest);
778         // rowToObject may modify db
779         dbOp.transaction().commit();
780
781         return CKM_API_SUCCESS;
782 }
783
784 RawBuffer CKMLogic::getData(
785         const Credentials &cred,
786         int msgId,
787         DataType dataType,
788         const Name &name,
789         const ClientId &owner,
790         const Password &password)
791 {
792         RawBuffer rowData;
793         DataType objDataType;
794
795         int retCode = tryRet([&] {
796                 Crypto::GObjUPtr obj;
797                 int retCode = readDataHelper(true, cred, dataType, name, owner,
798                                                                          password, obj, objDataType);
799
800                 if (retCode == CKM_API_SUCCESS)
801                         rowData = obj->getBinary();
802
803                 return retCode;
804         });
805
806         if (CKM_API_SUCCESS != retCode)
807                 rowData.clear();
808
809         return SerializeMessage(msgId, retCode, objDataType, rowData);
810 }
811
812 RawBuffer CKMLogic::getDataProtectionStatus(
813                 const Credentials &cred,
814                 int msgId,
815                 DataType dataType,
816                 const Name &name,
817                 const ClientId &owner)
818 {
819         bool status = false;
820         DataType objDataType;
821         Password password;
822
823         int retCode = tryRet([&] {
824                 Crypto::GObjUPtr obj;
825                 return readDataHelper(false, cred, dataType, name, owner, password, obj, objDataType);
826         });
827
828         if (retCode == CKM_API_ERROR_AUTHENTICATION_FAILED) {
829                 status = true;
830                 retCode = CKM_API_SUCCESS;
831         }
832
833         return SerializeMessage(msgId, retCode, objDataType, status);
834 }
835
836 RawBuffer CKMLogic::getPKCS12(
837         const Credentials &cred,
838         int msgId,
839         const Name &name,
840         const ClientId &owner,
841         const Password &keyPassword,
842         const Password &certPassword)
843 {
844         PKCS12Serializable output;
845
846         int retCode = tryRet([&] {
847                 KeyShPtr privKey;
848                 CertificateShPtr cert;
849                 CertificateShPtrVector caChain;
850
851                 // read private key (mandatory)
852                 Crypto::GObjUPtr keyObj;
853                 int retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, owner,
854                                                                          keyPassword, keyObj);
855
856                 if (retCode != CKM_API_SUCCESS) {
857                         if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
858                                 return retCode;
859                 } else {
860                         privKey = CKM::Key::create(keyObj->getBinary());
861                 }
862
863                 // read certificate (mandatory)
864                 Crypto::GObjUPtr certObj;
865                 retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, owner,
866                                                                  certPassword, certObj);
867
868                 if (retCode != CKM_API_SUCCESS) {
869                         if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
870                                 return retCode;
871                 } else {
872                         cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
873                 }
874
875                 // read CA cert chain (optional)
876                 Crypto::GObjUPtrVector caChainObjs;
877                 retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, owner,
878                                                                  certPassword, caChainObjs);
879
880                 if (retCode != CKM_API_SUCCESS && retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
881                         if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
882                                 return retCode;
883                 } else {
884                         for (auto &caCertObj : caChainObjs)
885                                 caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
886                                                                                                                    DataFormat::FORM_DER));
887                 }
888
889                 // if anything found, return it
890                 if (privKey || cert || caChain.size() > 0)
891                         retCode = CKM_API_SUCCESS;
892
893                 // prepare response
894                 if (retCode != CKM_API_SUCCESS)
895                         return retCode;
896
897                 output = PKCS12Serializable(std::move(privKey), std::move(cert), std::move(caChain));
898                 return CKM_API_SUCCESS;
899         });
900
901         return SerializeMessage(msgId, retCode, output);
902 }
903
904 int CKMLogic::getDataListHelper(const Credentials &cred,
905                                                                 const DataType dataType,
906                                                                 OwnerNameVector &ownerNameVector)
907 {
908         int retCode = CKM_API_ERROR_DB_LOCKED;
909
910         if (0 < m_userDataMap.count(cred.clientUid)) {
911                 auto &database = m_userDataMap[cred.clientUid].database;
912
913                 retCode = tryRet<CKM_API_ERROR_DB_ERROR>([&] {
914                         OwnerNameVector tmpVector;
915
916                         if (dataType.isKey()) {
917                                 // list all key types
918                                 database.listNames(cred.client,
919                                                                    tmpVector,
920                                                                    DataType::DB_KEY_FIRST,
921                                                                    DataType::DB_KEY_LAST);
922                         } else {
923                                 // list anything else
924                                 database.listNames(cred.client,
925                                                                    tmpVector,
926                                                                    dataType);
927                         }
928
929                         ownerNameVector.insert(ownerNameVector.end(), tmpVector.begin(),
930                                                                    tmpVector.end());
931                         return CKM_API_SUCCESS;
932                 });
933         }
934
935         return retCode;
936 }
937
938 RawBuffer CKMLogic::getDataList(
939         const Credentials &cred,
940         int msgId,
941         DataType dataType)
942 {
943         OwnerNameVector systemVector;
944         OwnerNameVector userVector;
945         OwnerNameVector ownerNameVector;
946
947         int retCode = unlockSystemDB();
948
949         if (CKM_API_SUCCESS == retCode) {
950                 // system database
951                 if (m_accessControl.isSystemService(cred)) {
952                         // lookup system DB
953                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
954                                                                                 dataType,
955                                                                                 systemVector);
956                 } else {
957                         // user - lookup system, then client DB
958                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, cred.client),
959                                                                                 dataType,
960                                                                                 systemVector);
961
962                         // private database
963                         if (retCode == CKM_API_SUCCESS) {
964                                 retCode = getDataListHelper(cred,
965                                                                                         dataType,
966                                                                                         userVector);
967                         }
968                 }
969         }
970
971         if (retCode == CKM_API_SUCCESS) {
972                 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
973                                                            systemVector.end());
974                 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
975                                                            userVector.end());
976         }
977
978         return SerializeMessage(msgId, retCode, dataType, ownerNameVector);
979 }
980
981 int CKMLogic::importInitialData(
982         const Name &name,
983         const Crypto::Data &data,
984         const Crypto::EncryptionParams &encParams,
985         const Policy &policy)
986 {
987         try {
988                 return tryRet([&] {
989                         if (encParams.iv.empty() != encParams.tag.empty()) {
990                                 LogError("Both iv and tag must be empty or set");
991                                 return CKM_API_ERROR_INPUT_PARAM;
992                         }
993
994                         // Inital values are always imported with root credentials. Client id is not important.
995                         Credentials rootCred(0, "whatever");
996                         ClientId owner(CLIENT_ID_SYSTEM);
997
998                         auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
999                         if (retCode != CKM_API_SUCCESS)
1000                                 return retCode;
1001
1002                         Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
1003
1004                         Token token;
1005                         if (encParams.iv.empty()) {
1006                                 // Data are not encrypted, let's try to verify them
1007                                 Crypto::Data binaryData;
1008
1009                                 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
1010                                         return retCode;
1011
1012                                 token = store.import(binaryData,
1013                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1014                                                                          encParams, digest);
1015                         } else {
1016                                 token = store.import(data,
1017                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1018                                                                          encParams, digest);
1019                         }
1020
1021                         dbOp.finalize(std::move(token), policy);
1022
1023                         return CKM_API_SUCCESS;
1024                 });
1025         } catch (const std::exception &e) {
1026                 LogError("Std::exception: " << e.what());
1027                 return CKM_API_ERROR_SERVER_ERROR;
1028         }
1029 }
1030
1031 int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
1032 {
1033         if (!m_handler.crypto.haveKey(m_owner)) {
1034                 RawBuffer wrappedDEK;
1035                 auto wrappedDEKOptional = m_handler.database.getKey(m_owner);
1036
1037                 if (!wrappedDEKOptional) {
1038                         if (keyRequired) {
1039                                 LogError("No key for given owner in database");
1040                                 return CKM_API_ERROR_DB_ERROR;
1041                         }
1042                         LogDebug("No Key in database found. Generating new one for client: " << m_owner);
1043                         wrappedDEK = m_handler.keyProvider.generateDEK(m_owner);
1044                         m_handler.database.saveKey(m_owner, wrappedDEK);
1045                 } else {
1046                         wrappedDEK = *wrappedDEKOptional;
1047                 }
1048
1049                 m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
1050         }
1051
1052         return CKM_API_SUCCESS;
1053 }
1054
1055 std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
1056         const Credentials &cred,
1057         const Name &name,
1058         const ClientId &owner)
1059 {
1060         auto &handler = selectDatabase(cred, owner);
1061         DBOperation op(handler, name, owner);
1062
1063         if (cred.client.empty() || !isClientValid(cred.client) ||
1064                 !isNameValid(name) || !isClientValid(owner))
1065                 return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
1066
1067         return std::make_tuple(std::move(op), CKM_API_SUCCESS);
1068 }
1069
1070 std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
1071         const Credentials &cred,
1072         const Name &name,
1073         const ClientId &owner)
1074 {
1075         PermissionMask permission;
1076         auto [dbOp, retCode] = begin(cred, name, owner);
1077         if (retCode == CKM_API_SUCCESS)
1078                 permission = toPermissionMask(dbOp.database().getPermissionRow(name, owner, cred.client));
1079
1080         return std::make_tuple(std::move(dbOp), permission, retCode);
1081 }
1082
1083 std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
1084         const Credentials &cred,
1085         const Name &name,
1086         const ClientId &owner)
1087 {
1088         auto [dbOp, retCode] = begin(cred, name, owner);
1089         if (retCode != CKM_API_SUCCESS)
1090                 return std::make_tuple(std::move(dbOp), retCode);
1091
1092         retCode = dbOp.loadAppKey(false);
1093         if (retCode != CKM_API_SUCCESS)
1094                 return std::make_tuple(std::move(dbOp), retCode);
1095
1096         // check if accessor is allowed to save owner's items
1097         retCode = m_accessControl.canSave(cred, owner);
1098         if (retCode != CKM_API_SUCCESS) {
1099                 LogDebug("accessor " << cred.client << " can not save rows owned by " << owner);
1100                 return std::make_tuple(std::move(dbOp), retCode);
1101         }
1102
1103         if (dbOp.database().isNameOwnerPresent(name, owner))
1104                 retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
1105
1106         return std::make_tuple(std::move(dbOp), retCode);
1107 }
1108
1109 std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
1110         const Credentials &cred,
1111         const Name &name,
1112         const ClientId &owner)
1113 {
1114         RawBuffer digest;
1115         auto [dbOp, retCode] = beginSave(cred, name, owner);
1116         if (retCode == CKM_API_SUCCESS) {
1117                 digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1118                 if (digest.empty())
1119                         retCode = CKM_API_ERROR_HASH_ERROR;
1120         }
1121
1122         return std::make_tuple(std::move(dbOp), std::move(digest), retCode);
1123 }
1124
1125 RawBuffer CKMLogic::createKeyPair(
1126         const Credentials &cred,
1127         int msgId,
1128         const CryptoAlgorithmSerializable &keyGenParams,
1129         const Name &namePrv,
1130         const ClientId &ownerPrv,
1131         const Name &namePub,
1132         const ClientId &ownerPub,
1133         const PolicySerializable &policyPrv,
1134         const PolicySerializable &policyPub)
1135 {
1136         return SerializeMessage(msgId, tryRet([&] {
1137                 auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
1138                 if (retCodePrv != CKM_API_SUCCESS)
1139                         return retCodePrv;
1140
1141                 auto [dbOpPub, digestPub, retCodePub] = beginSaveAndGetHash(cred, namePub, ownerPub);
1142                 if (retCodePub != CKM_API_SUCCESS)
1143                         return retCodePub;
1144
1145                 if (policyPrv.backend != policyPub.backend)
1146                         ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1147
1148                 bool exportable = policyPrv.extractable || policyPub.extractable;
1149                 Policy lessRestricted(Password(), exportable, policyPrv.backend);
1150
1151                 TokenPair keys = m_decider.getStore(policyPrv).generateAKey(
1152                         keyGenParams,
1153                         policyPrv.password,
1154                         policyPub.password,
1155                         digestPrv, digestPub);
1156
1157                 dbOpPrv.finalize(std::move(keys.first), policyPrv);
1158                 dbOpPub.finalize(std::move(keys.second), policyPub);
1159
1160                 return CKM_API_SUCCESS;
1161         }));
1162 }
1163
1164 RawBuffer CKMLogic::createKeyAES(
1165         const Credentials &cred,
1166         int msgId,
1167         const int size,
1168         const Name &name,
1169         const ClientId &owner,
1170         const PolicySerializable &policy)
1171 {
1172         int retCode = CKM_API_SUCCESS;
1173
1174         try {
1175                 retCode = tryRet([&] {
1176                         auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, name, owner);
1177                         if (retCode != CKM_API_SUCCESS)
1178                                 return retCode;
1179
1180                         // create key in store
1181                         CryptoAlgorithm keyGenAlgorithm;
1182                         keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1183                         keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1184                         Token key = m_decider.getStore(DataType::KEY_AES, policy).generateSKey(keyGenAlgorithm,
1185                                                                                                                                                                    policy.password,
1186                                                                                                                                                                    digest);
1187
1188                         dbOp.finalize(std::move(key), policy);
1189                         return CKM_API_SUCCESS;
1190                 });
1191         } catch (std::invalid_argument &e) {
1192                 LogDebug("invalid argument error: " << e.what());
1193                 retCode = CKM_API_ERROR_INPUT_PARAM;
1194         }
1195
1196         return SerializeMessage(msgId, retCode);
1197 }
1198
1199 int CKMLogic::readCertificateHelper(
1200         const Credentials &cred,
1201         const OwnerNameVector &ownerNameVector,
1202         CertificateImplVector &certVector)
1203 {
1204         for (auto &i : ownerNameVector) {
1205                 // certificates can't be protected with custom user password
1206                 Crypto::GObjUPtr obj;
1207                 int ec;
1208                 ec = readDataHelper(true,
1209                                                         cred,
1210                                                         DataType::CERTIFICATE,
1211                                                         i.second,
1212                                                         cred.effectiveOwner(i.first),
1213                                                         Password(),
1214                                                         obj);
1215
1216                 if (ec != CKM_API_SUCCESS)
1217                         return ec;
1218
1219                 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1220
1221                 // try to read chain certificates (if present)
1222                 Crypto::GObjUPtrVector caChainObjs;
1223                 ec = readDataHelper(true,
1224                                                         cred,
1225                                                         DataType::DB_CHAIN_FIRST,
1226                                                         i.second,
1227                                                         cred.effectiveOwner(i.first),
1228                                                         CKM::Password(),
1229                                                         caChainObjs);
1230
1231                 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1232                         return ec;
1233
1234                 for (auto &caCertObj : caChainObjs)
1235                         certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1236         }
1237
1238         return CKM_API_SUCCESS;
1239 }
1240
1241 int CKMLogic::getCertificateChainHelper(
1242         const CertificateImpl &cert,
1243         const RawBufferVector &untrustedCertificates,
1244         const RawBufferVector &trustedCertificates,
1245         bool useTrustedSystemCertificates,
1246         RawBufferVector &chainRawVector)
1247 {
1248         CertificateImplVector untrustedCertVector;
1249         CertificateImplVector trustedCertVector;
1250         CertificateImplVector chainVector;
1251
1252         if (cert.empty())
1253                 return CKM_API_ERROR_INPUT_PARAM;
1254
1255         for (auto &e : untrustedCertificates) {
1256                 CertificateImpl c(e, DataFormat::FORM_DER);
1257
1258                 if (c.empty())
1259                         return CKM_API_ERROR_INPUT_PARAM;
1260
1261                 untrustedCertVector.push_back(std::move(c));
1262         }
1263
1264         for (auto &e : trustedCertificates) {
1265                 CertificateImpl c(e, DataFormat::FORM_DER);
1266
1267                 if (c.empty())
1268                         return CKM_API_ERROR_INPUT_PARAM;
1269
1270                 trustedCertVector.push_back(std::move(c));
1271         }
1272
1273         CertificateStore store;
1274         int retCode = store.verifyCertificate(cert,
1275                                                                                   untrustedCertVector,
1276                                                                                   trustedCertVector,
1277                                                                                   useTrustedSystemCertificates,
1278                                                                                   m_accessControl.isCCMode(),
1279                                                                                   chainVector);
1280
1281         if (retCode != CKM_API_SUCCESS)
1282                 return retCode;
1283
1284         for (auto &e : chainVector)
1285                 chainRawVector.push_back(e.getDER());
1286
1287         return CKM_API_SUCCESS;
1288 }
1289
1290 int CKMLogic::getCertificateChainHelper(
1291         const Credentials &cred,
1292         const CertificateImpl &cert,
1293         const OwnerNameVector &untrusted,
1294         const OwnerNameVector &trusted,
1295         bool useTrustedSystemCertificates,
1296         RawBufferVector &chainRawVector)
1297 {
1298         CertificateImplVector untrustedCertVector;
1299         CertificateImplVector trustedCertVector;
1300         CertificateImplVector chainVector;
1301
1302         if (cert.empty())
1303                 return CKM_API_ERROR_INPUT_PARAM;
1304
1305         int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1306
1307         if (retCode != CKM_API_SUCCESS)
1308                 return retCode;
1309
1310         retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1311
1312         if (retCode != CKM_API_SUCCESS)
1313                 return retCode;
1314
1315         CertificateStore store;
1316         retCode = store.verifyCertificate(cert,
1317                                                                           untrustedCertVector,
1318                                                                           trustedCertVector,
1319                                                                           useTrustedSystemCertificates,
1320                                                                           m_accessControl.isCCMode(),
1321                                                                           chainVector);
1322
1323         if (retCode != CKM_API_SUCCESS)
1324                 return retCode;
1325
1326         for (auto &i : chainVector)
1327                 chainRawVector.push_back(i.getDER());
1328
1329         return CKM_API_SUCCESS;
1330 }
1331
1332 RawBuffer CKMLogic::getCertificateChain(
1333         const Credentials & /*cred*/,
1334         int msgId,
1335         const RawBuffer &certificate,
1336         const RawBufferVector &untrustedCertificates,
1337         const RawBufferVector &trustedCertificates,
1338         bool useTrustedSystemCertificates)
1339 {
1340         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1341         RawBufferVector chainRawVector;
1342         int retCode = CKM_API_ERROR_UNKNOWN;
1343
1344         try {
1345                 retCode = getCertificateChainHelper(cert,
1346                                                                                         untrustedCertificates,
1347                                                                                         trustedCertificates,
1348                                                                                         useTrustedSystemCertificates,
1349                                                                                         chainRawVector);
1350         } catch (const Exc::Exception &e) {
1351                 retCode = e.error();
1352         } catch (const std::exception &e) {
1353                 LogError("STD exception " << e.what());
1354                 retCode = CKM_API_ERROR_SERVER_ERROR;
1355         } catch (...) {
1356                 LogError("Unknown error.");
1357         }
1358
1359         return SerializeMessage(msgId, retCode, chainRawVector);
1360 }
1361
1362 RawBuffer CKMLogic::getCertificateChain(
1363         const Credentials &cred,
1364         int msgId,
1365         const RawBuffer &certificate,
1366         const OwnerNameVector &untrustedCertificates,
1367         const OwnerNameVector &trustedCertificates,
1368         bool useTrustedSystemCertificates)
1369 {
1370         int retCode = CKM_API_ERROR_UNKNOWN;
1371         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1372         RawBufferVector chainRawVector;
1373
1374         try {
1375                 retCode = getCertificateChainHelper(cred,
1376                                                                                         cert,
1377                                                                                         untrustedCertificates,
1378                                                                                         trustedCertificates,
1379                                                                                         useTrustedSystemCertificates,
1380                                                                                         chainRawVector);
1381         } catch (const Exc::Exception &e) {
1382                 retCode = e.error();
1383         } catch (const std::exception &e) {
1384                 LogError("STD exception " << e.what());
1385                 retCode = CKM_API_ERROR_SERVER_ERROR;
1386         } catch (...) {
1387                 LogError("Unknown error.");
1388         }
1389
1390         return SerializeMessage(msgId, retCode, chainRawVector);
1391 }
1392
1393 RawBuffer CKMLogic::createSignature(
1394         const Credentials &cred,
1395         int msgId,
1396         const Name &privateKeyName,
1397         const ClientId &owner,
1398         const Password &password,           // password for private_key
1399         const RawBuffer &message,
1400         const CryptoAlgorithm &cryptoAlg)
1401 {
1402         RawBuffer signature;
1403
1404         int retCode = CKM_API_SUCCESS;
1405
1406         try {
1407                 retCode = tryRet([&] {
1408                         Crypto::GObjUPtr obj;
1409                         int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1410                                                                                  owner, password, obj);
1411
1412                         if (retCode == CKM_API_SUCCESS)
1413                                 signature = obj->sign(cryptoAlg, message);
1414
1415                         return retCode;
1416                 });
1417         } catch (const std::exception &e) {
1418                 LogError("STD exception " << e.what());
1419                 retCode = CKM_API_ERROR_SERVER_ERROR;
1420         }
1421
1422         return SerializeMessage(msgId, retCode, signature);
1423 }
1424
1425 RawBuffer CKMLogic::verifySignature(
1426         const Credentials &cred,
1427         int msgId,
1428         const Name &publicKeyOrCertName,
1429         const ClientId &owner,
1430         const Password &password,           // password for public_key (optional)
1431         const RawBuffer &message,
1432         const RawBuffer &signature,
1433         const CryptoAlgorithm &params)
1434 {
1435         return SerializeMessage(msgId, tryRet([&] {
1436                 // try certificate first - looking for a public key.
1437                 // in case of PKCS, pub key from certificate will be found first
1438                 // rather than private key from the same PKCS.
1439                 Crypto::GObjUPtr obj;
1440                 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1441                                                                          publicKeyOrCertName, owner, password, obj);
1442
1443                 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1444                         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1445                                                                          publicKeyOrCertName, owner, password, obj);
1446
1447                 if (retCode == CKM_API_SUCCESS)
1448                         retCode = obj->verify(params, message, signature);
1449
1450                 return retCode;
1451         }));
1452 }
1453
1454 int CKMLogic::setPermissionHelper(
1455         const Credentials &cred,                // who's the client
1456         const Name &name,
1457         const ClientId &owner,                     // who's the owner
1458         const ClientId &accessor,             // who will get the access
1459         const PermissionMask permissionMask)
1460 {
1461         auto [dbOp, retCode] = beginSave(cred, name, owner);
1462         // Normally, saving requires alias to be unoccupied. When changing permissions it's the opposite
1463         if (retCode != CKM_API_ERROR_DB_ALIAS_EXISTS) {
1464                 if (retCode == CKM_API_SUCCESS)
1465                         retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1466                 return retCode;
1467         }
1468
1469         // currently we don't support modification of owner's permissions to his own rows
1470         if (owner == accessor)
1471                 return CKM_API_ERROR_INPUT_PARAM;
1472
1473         // system database does not support write/remove permissions
1474         if ((0 == owner.compare(CLIENT_ID_SYSTEM)) && (permissionMask & Permission::REMOVE))
1475                 return CKM_API_ERROR_INPUT_PARAM;
1476
1477         // set permissions to the row owned by owner for accessor
1478         dbOp.database().setPermission(name, owner, accessor, permissionMask);
1479         dbOp.transaction().commit();
1480
1481         return CKM_API_SUCCESS;
1482 }
1483
1484 RawBuffer CKMLogic::setPermission(
1485         const Credentials &cred,
1486         const int msgID,
1487         const Name &name,
1488         const ClientId &owner,
1489         const ClientId &accessor,
1490         const PermissionMask permissionMask)
1491 {
1492         return SerializeMessage(msgID, tryRet([&] {
1493                 return setPermissionHelper(cred, name, owner, accessor, permissionMask);
1494         }));
1495 }
1496
1497 RawBuffer CKMLogic::deriveKey(
1498         const Credentials &cred,
1499         const int msgID,
1500         const CryptoAlgorithm &params,
1501         const Name &secretName,
1502         const ClientId &secretOwner,
1503         const Password &secretPassword,
1504         const Name &newKeyName,
1505         const ClientId &newKeyOwner,
1506         const Policy &newKeyPolicy)
1507 {
1508         return SerializeMessage(msgID, tryRet([&] {
1509                 // Get key/secret for internal service use. It won't be exported to the client
1510                 Crypto::GObjUPtr obj;
1511                 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1512                                                                          secretName, secretOwner, secretPassword, obj);
1513                 if (retCode != CKM_API_SUCCESS) {
1514                         if (retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1515                                 return retCode;
1516
1517                         retCode = readDataHelper(false, cred, DataType::BINARY_DATA,
1518                                                                          secretName, secretOwner, secretPassword, obj);
1519                         if (retCode != CKM_API_SUCCESS)
1520                                 return retCode;
1521                 }
1522
1523                 auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, newKeyName, newKeyOwner);
1524                 if (ret != CKM_API_SUCCESS)
1525                         return ret;
1526
1527                 // derive
1528                 Token derived = obj->derive(params, newKeyPolicy.password, digest);
1529
1530                 dbOp.finalize(std::move(derived), newKeyPolicy);
1531
1532                 return CKM_API_SUCCESS;
1533         }));
1534 }
1535
1536 } // namespace CKM
1537