Fixed the build error using gcc 13
[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.isSymmetricKey())
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 void CKMLogic::decryptRow(
629         UserData &handler,
630         DB::Row &row,
631         const Password &password,
632         const RawBuffer &hash)
633 {
634         if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
635                         CryptoLogic::ENCRYPTION_V2) {
636                 handler.crypto.decryptRow(Password(), row);
637         } else {
638                 Crypto::GStore &store = m_decider.getStore(row);
639
640                 Password pass = m_accessControl.isCCMode() ? "" : password;
641
642                 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
643                 handler.crypto.decryptRow(pass, row);
644                 // destroy it in store
645                 store.destroy(row);
646
647                 // import it to store with new scheme: data -> pass(data)
648                 Token token = store.import(Crypto::Data(row.dataType, row.data),
649                                                                    pass,
650                                                                    Crypto::EncryptionParams(),
651                                                                    hash);
652
653                 // update row with new token
654                 *static_cast<Token *>(&row) = std::move(token);
655
656                 // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
657                 auto encryptedRow = handler.crypto.encryptRow(row);
658
659                 // update it in db
660                 handler.database.updateRow(encryptedRow);
661         }
662 }
663
664 Crypto::GObjUPtr CKMLogic::rowToObject(
665         UserData &handler,
666         DB::Row row,
667         const Password &password,
668         const RawBuffer &hash)
669 {
670         decryptRow(handler, row, password, hash);
671
672         return decryptedRowToObj(row, password);
673 }
674
675 int CKMLogic::readDataHelper(
676         bool exportFlag,
677         const Credentials &cred,
678         DataType dataType,
679         const Name &name,
680         const ClientId &owner,
681         const Password &password,
682         Crypto::GObjUPtrVector &objs)
683 {
684         auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
685         if (retCode != CKM_API_SUCCESS)
686                 return retCode;
687
688         // read rows
689         DB::RowVector rows;
690         retCode = readMultiRow(name, owner, dataType, dbOp.database(), rows);
691         if (CKM_API_SUCCESS != retCode)
692                 return retCode;
693
694         // all read rows belong to the same owner
695         DB::Row &firstRow = rows.at(0);
696
697         // check access rights
698         retCode = checkDataPermissionsHelper(cred, firstRow, exportFlag, permission);
699         if (CKM_API_SUCCESS != retCode)
700                 return retCode;
701
702         // for multiple objects add type as hash input (see pkcs12)
703         bool multiple = rows.size() > 1;
704
705         RawBuffer digest;
706
707         retCode = dbOp.loadAppKey();
708         if (retCode != CKM_API_SUCCESS)
709                 return retCode;
710
711         // decrypt row
712         for (auto &row : rows) {
713                 if (multiple)
714                         digest = CryptoLogic::makeHash(name, owner, cred.clientUid, row.dataType);
715                 else
716                         digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
717
718                 if (digest.empty())
719                         return CKM_API_ERROR_HASH_ERROR;
720
721                 objs.push_back(rowToObject(dbOp.handler(), std::move(row), password, digest));
722         }
723
724         // rowToObject may modify db
725         dbOp.transaction().commit();
726
727         return CKM_API_SUCCESS;
728 }
729
730 int CKMLogic::readDataHelper(
731         bool exportFlag,
732         const Credentials &cred,
733         DataType dataType,
734         const Name &name,
735         const ClientId &owner,
736         const Password &password,
737         Crypto::GObjUPtr &obj)
738 {
739         DataType objDataType;
740         return readDataHelper(exportFlag, cred, dataType, name, owner,
741                                                   password, obj, objDataType);
742 }
743
744 int CKMLogic::readRowHelper(
745         bool exportFlag,
746         const Credentials &cred,
747         DataType dataType,
748         const Name &name,
749         const ClientId &owner,
750         const Password &password,
751         DB::Row &row,
752         DataType &objDataType)
753 {
754         auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
755         if (retCode != CKM_API_SUCCESS)
756                 return retCode;
757
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 (retCode != CKM_API_SUCCESS)
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         decryptRow(dbOp.handler(), row, password, digest);
778
779         // decryptRow may modify db
780         dbOp.transaction().commit();
781
782         return CKM_API_SUCCESS;
783 }
784
785 Crypto::GObjUPtr CKMLogic::decryptedRowToObj(const DB::Row& row, const Password &password)
786 {
787         Crypto::GStore &store = m_decider.getStore(row);
788
789         Password pass = m_accessControl.isCCMode() ? "" : password;
790         return store.getObject(row, pass);
791 }
792
793 int CKMLogic::readDataHelper(
794         bool exportFlag,
795         const Credentials &cred,
796         DataType dataType,
797         const Name &name,
798         const ClientId &owner,
799         const Password &password,
800         Crypto::GObjUPtr &obj,
801         DataType &objDataType)
802 {
803         DB::Row row;
804         int retCode = readRowHelper(exportFlag, cred, dataType, name, owner, password, row, objDataType);
805         if (retCode != CKM_API_SUCCESS)
806                 return retCode;
807
808         obj = decryptedRowToObj(row, password);
809
810         return CKM_API_SUCCESS;
811 }
812
813 RawBuffer CKMLogic::getData(
814         const Credentials &cred,
815         int msgId,
816         DataType dataType,
817         const Name &name,
818         const ClientId &owner,
819         const Password &password)
820 {
821         RawBuffer rowData;
822         DataType objDataType;
823
824         int retCode = tryRet([&] {
825                 Crypto::GObjUPtr obj;
826                 int retCode2 = readDataHelper(true, cred, dataType, name, owner,
827                                                                           password, obj, objDataType);
828
829                 if (retCode2 == CKM_API_SUCCESS)
830                         rowData = obj->getBinary();
831
832                 return retCode2;
833         });
834
835         if (CKM_API_SUCCESS != retCode)
836                 rowData.clear();
837
838         return SerializeMessage(msgId, retCode, objDataType, rowData);
839 }
840
841 RawBuffer CKMLogic::getDataProtectionStatus(
842                 const Credentials &cred,
843                 int msgId,
844                 DataType dataType,
845                 const Name &name,
846                 const ClientId &owner)
847 {
848         bool status = false;
849         DataType objDataType;
850         Password password;
851
852         int retCode = tryRet([&] {
853                 Crypto::GObjUPtr obj;
854                 return readDataHelper(false, cred, dataType, name, owner, password, obj, objDataType);
855         });
856
857         if (retCode == CKM_API_ERROR_AUTHENTICATION_FAILED) {
858                 status = true;
859                 retCode = CKM_API_SUCCESS;
860         }
861
862         return SerializeMessage(msgId, retCode, objDataType, status);
863 }
864
865 RawBuffer CKMLogic::getPKCS12(
866         const Credentials &cred,
867         int msgId,
868         const Name &name,
869         const ClientId &owner,
870         const Password &keyPassword,
871         const Password &certPassword)
872 {
873         PKCS12Serializable output;
874
875         int retCode = tryRet([&] {
876                 KeyShPtr privKey;
877                 CertificateShPtr cert;
878                 CertificateShPtrVector caChain;
879
880                 // read private key (mandatory)
881                 Crypto::GObjUPtr keyObj;
882                 int retCode2 = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, owner,
883                                                                           keyPassword, keyObj);
884
885                 if (retCode2 != CKM_API_SUCCESS) {
886                         if (retCode2 != CKM_API_ERROR_NOT_EXPORTABLE)
887                                 return retCode2;
888                 } else {
889                         privKey = CKM::Key::create(keyObj->getBinary());
890                 }
891
892                 // read certificate (mandatory)
893                 Crypto::GObjUPtr certObj;
894                 retCode2 = readDataHelper(true, cred, DataType::CERTIFICATE, name, owner,
895                                                                   certPassword, certObj);
896
897                 if (retCode2 != CKM_API_SUCCESS) {
898                         if (retCode2 != CKM_API_ERROR_NOT_EXPORTABLE)
899                                 return retCode2;
900                 } else {
901                         cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
902                 }
903
904                 // read CA cert chain (optional)
905                 Crypto::GObjUPtrVector caChainObjs;
906                 retCode2 = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, owner,
907                                                                   certPassword, caChainObjs);
908
909                 if (retCode2 != CKM_API_SUCCESS && retCode2 != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
910                         if (retCode2 != CKM_API_ERROR_NOT_EXPORTABLE)
911                                 return retCode2;
912                 } else {
913                         for (auto &caCertObj : caChainObjs)
914                                 caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
915                                                                                                                    DataFormat::FORM_DER));
916                 }
917
918                 // if anything found, return it
919                 if (privKey || cert || caChain.size() > 0)
920                         retCode2 = CKM_API_SUCCESS;
921
922                 // prepare response
923                 if (retCode2 != CKM_API_SUCCESS)
924                         return retCode2;
925
926                 output = PKCS12Serializable(std::move(privKey), std::move(cert), std::move(caChain));
927                 return CKM_API_SUCCESS;
928         });
929
930         return SerializeMessage(msgId, retCode, output);
931 }
932
933 int CKMLogic::getAliasInfoListHelper(const Credentials &cred,
934                                                                          const DataType dataType,
935                                                                          AliasInfoVector &aliasInfoVector)
936 {
937         int retCode = CKM_API_ERROR_DB_LOCKED;
938
939         if (0 < m_userDataMap.count(cred.clientUid)) {
940                 auto &database = m_userDataMap[cred.clientUid].database;
941
942                 retCode = tryRet<CKM_API_ERROR_DB_ERROR>([&] {
943                         AliasInfoVector tmpVector;
944
945                         if (dataType.isKey()) {
946                                 // list all key types
947                                 database.listInfos(cred.client,
948                                                                    tmpVector,
949                                                                    DataType::DB_KEY_FIRST,
950                                                                    DataType::DB_KEY_LAST);
951                         } else {
952                                 // list anything else
953                                 database.listInfos(cred.client, tmpVector, dataType);
954                         }
955
956                         aliasInfoVector.insert(aliasInfoVector.end(), tmpVector.begin(), tmpVector.end());
957                         return CKM_API_SUCCESS;
958                 });
959         }
960
961         return retCode;
962 }
963
964 RawBuffer CKMLogic::getDataList(
965         const Credentials &cred,
966         int msgId,
967         DataType dataType)
968 {
969         AliasInfoVector systemVector;
970         AliasInfoVector userVector;
971         AliasInfoVector aliasInfoVector;
972
973         int retCode = unlockSystemDB();
974
975         if (CKM_API_SUCCESS == retCode) {
976                 // system database
977                 if (m_accessControl.isSystemService(cred)) {
978                         // lookup system DB
979                         retCode = getAliasInfoListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
980                                                                                          dataType,
981                                                                                          systemVector);
982                 } else {
983                         // user - lookup system, then client DB
984                         retCode = getAliasInfoListHelper(Credentials(SYSTEM_DB_UID, cred.client),
985                                                                                          dataType,
986                                                                                          systemVector);
987
988                         // private database
989                         if (retCode == CKM_API_SUCCESS) {
990                                 retCode = getAliasInfoListHelper(cred,
991                                                                                                  dataType,
992                                                                                                  userVector);
993                         }
994                 }
995         }
996
997         if (retCode == CKM_API_SUCCESS) {
998                 aliasInfoVector.insert(aliasInfoVector.end(), systemVector.begin(),
999                                                            systemVector.end());
1000                 aliasInfoVector.insert(aliasInfoVector.end(), userVector.begin(),
1001                                                            userVector.end());
1002         }
1003
1004         return SerializeMessage(msgId, retCode, dataType, AliasInfoSerializableVector(aliasInfoVector));
1005 }
1006
1007 int CKMLogic::importInitialData(
1008         const Name &name,
1009         const Crypto::Data &data,
1010         const Crypto::EncryptionParams &encParams,
1011         const Policy &policy)
1012 {
1013         try {
1014                 return tryRet([&] {
1015                         if (encParams.iv.empty() != encParams.tag.empty()) {
1016                                 LogError("Both iv and tag must be empty or set");
1017                                 return CKM_API_ERROR_INPUT_PARAM;
1018                         }
1019
1020                         // Inital values are always imported with root credentials. Client id is not important.
1021                         Credentials rootCred(0, "whatever");
1022                         ClientId owner(CLIENT_ID_SYSTEM);
1023
1024                         auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
1025                         if (retCode != CKM_API_SUCCESS)
1026                                 return retCode;
1027
1028                         Crypto::GStore &store = m_decider.getStore(data.type, policy, true, !encParams.iv.empty());
1029
1030                         Token token;
1031                         if (encParams.iv.empty()) {
1032                                 // Data are not encrypted, let's try to verify them
1033                                 Crypto::Data binaryData;
1034
1035                                 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
1036                                         return retCode;
1037
1038                                 token = store.import(binaryData,
1039                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1040                                                                          encParams, digest);
1041                         } else {
1042                                 token = store.import(data,
1043                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1044                                                                          encParams, digest);
1045                         }
1046
1047                         dbOp.finalize(std::move(token), policy);
1048
1049                         return CKM_API_SUCCESS;
1050                 });
1051         } catch (const std::exception &e) {
1052                 LogError("Std::exception: " << e.what());
1053                 return CKM_API_ERROR_SERVER_ERROR;
1054         }
1055 }
1056
1057 int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
1058 {
1059         if (!m_handler.crypto.haveKey(m_owner)) {
1060                 RawBuffer wrappedDEK;
1061                 auto wrappedDEKOptional = m_handler.database.getKey(m_owner);
1062
1063                 if (!wrappedDEKOptional) {
1064                         if (keyRequired) {
1065                                 LogError("No key for given owner in database");
1066                                 return CKM_API_ERROR_DB_ERROR;
1067                         }
1068                         LogDebug("No Key in database found. Generating new one for client: " << m_owner);
1069                         wrappedDEK = m_handler.keyProvider.generateDEK(m_owner);
1070                         m_handler.database.saveKey(m_owner, wrappedDEK);
1071                 } else {
1072                         wrappedDEK = *wrappedDEKOptional;
1073                 }
1074
1075                 m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
1076         }
1077
1078         return CKM_API_SUCCESS;
1079 }
1080
1081 std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
1082         const Credentials &cred,
1083         const Name &name,
1084         const ClientId &owner)
1085 {
1086         auto &handler = selectDatabase(cred, owner);
1087         DBOperation op(handler, name, owner);
1088
1089         if (cred.client.empty() || !isClientValid(cred.client) ||
1090                 !isNameValid(name) || !isClientValid(owner))
1091                 return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
1092
1093         return std::make_tuple(std::move(op), CKM_API_SUCCESS);
1094 }
1095
1096 std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
1097         const Credentials &cred,
1098         const Name &name,
1099         const ClientId &owner)
1100 {
1101         PermissionMask permission = Permission::NONE;
1102         auto [dbOp, retCode] = begin(cred, name, owner);
1103         if (retCode == CKM_API_SUCCESS)
1104                 permission = toPermissionMask(dbOp.database().getPermissionRow(name, owner, cred.client));
1105
1106         return std::make_tuple(std::move(dbOp), permission, retCode);
1107 }
1108
1109 std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
1110         const Credentials &cred,
1111         const Name &name,
1112         const ClientId &owner)
1113 {
1114         auto [dbOp, retCode] = begin(cred, name, owner);
1115         if (retCode != CKM_API_SUCCESS)
1116                 return std::make_tuple(std::move(dbOp), retCode);
1117
1118         retCode = dbOp.loadAppKey(false);
1119         if (retCode != CKM_API_SUCCESS)
1120                 return std::make_tuple(std::move(dbOp), retCode);
1121
1122         // check if accessor is allowed to save owner's items
1123         retCode = m_accessControl.canSave(cred, owner);
1124         if (retCode != CKM_API_SUCCESS) {
1125                 LogDebug("accessor " << cred.client << " can not save rows owned by " << owner);
1126                 return std::make_tuple(std::move(dbOp), retCode);
1127         }
1128
1129         if (dbOp.database().isNameOwnerPresent(name, owner))
1130                 retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
1131
1132         return std::make_tuple(std::move(dbOp), retCode);
1133 }
1134
1135 std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
1136         const Credentials &cred,
1137         const Name &name,
1138         const ClientId &owner)
1139 {
1140         RawBuffer digest;
1141         auto [dbOp, retCode] = beginSave(cred, name, owner);
1142         if (retCode == CKM_API_SUCCESS) {
1143                 digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1144                 if (digest.empty())
1145                         retCode = CKM_API_ERROR_HASH_ERROR;
1146         }
1147
1148         return std::make_tuple(std::move(dbOp), std::move(digest), retCode);
1149 }
1150
1151 RawBuffer CKMLogic::createKeyPair(
1152         const Credentials &cred,
1153         int msgId,
1154         const CryptoAlgorithmSerializable &keyGenParams,
1155         const Name &namePrv,
1156         const ClientId &ownerPrv,
1157         const Name &namePub,
1158         const ClientId &ownerPub,
1159         const PolicySerializable &policyPrv,
1160         const PolicySerializable &policyPub)
1161 {
1162         return SerializeMessage(msgId, tryRet([&] {
1163                 auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
1164                 if (retCodePrv != CKM_API_SUCCESS)
1165                         return retCodePrv;
1166
1167                 auto [dbOpPub, digestPub, retCodePub] = beginSaveAndGetHash(cred, namePub, ownerPub);
1168                 if (retCodePub != CKM_API_SUCCESS)
1169                         return retCodePub;
1170
1171                 if (policyPrv.backend != policyPub.backend)
1172                         ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1173
1174                 bool exportable = policyPrv.extractable || policyPub.extractable;
1175                 Policy lessRestricted(Password(), exportable, policyPrv.backend);
1176
1177                 // For now any asymmetric key will do. If necessary we can extract it from keyGenParams.
1178                 TokenPair keys = m_decider.getStore(DataType::DB_KEY_FIRST, policyPrv, false).generateAKey(
1179                         keyGenParams,
1180                         policyPrv.password,
1181                         policyPub.password,
1182                         digestPrv, digestPub);
1183
1184                 dbOpPrv.finalize(std::move(keys.first), policyPrv);
1185                 dbOpPub.finalize(std::move(keys.second), policyPub);
1186
1187                 return CKM_API_SUCCESS;
1188         }));
1189 }
1190
1191 RawBuffer CKMLogic::createKeyAES(
1192         const Credentials &cred,
1193         int msgId,
1194         const int size,
1195         const Name &name,
1196         const ClientId &owner,
1197         const PolicySerializable &policy)
1198 {
1199         int retCode = CKM_API_SUCCESS;
1200
1201         try {
1202                 retCode = tryRet([&] {
1203                         auto [dbOp, digest, retCode2] = beginSaveAndGetHash(cred, name, owner);
1204                         if (retCode2 != CKM_API_SUCCESS)
1205                                 return retCode2;
1206
1207                         // create key in store
1208                         CryptoAlgorithm keyGenAlgorithm;
1209                         keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1210                         keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1211
1212                         auto& store = m_decider.getStore(DataType::KEY_AES, policy, false);
1213                         Token key = store.generateSKey(keyGenAlgorithm, policy.password, digest);
1214
1215                         dbOp.finalize(std::move(key), policy);
1216                         return CKM_API_SUCCESS;
1217                 });
1218         } catch (std::invalid_argument &e) {
1219                 LogDebug("invalid argument error: " << e.what());
1220                 retCode = CKM_API_ERROR_INPUT_PARAM;
1221         }
1222
1223         return SerializeMessage(msgId, retCode);
1224 }
1225
1226 int CKMLogic::readCertificateHelper(
1227         const Credentials &cred,
1228         const OwnerNameVector &ownerNameVector,
1229         CertificateImplVector &certVector)
1230 {
1231         for (auto &i : ownerNameVector) {
1232                 // certificates can't be protected with custom user password
1233                 Crypto::GObjUPtr obj;
1234                 int ec;
1235                 ec = readDataHelper(true,
1236                                                         cred,
1237                                                         DataType::CERTIFICATE,
1238                                                         i.second,
1239                                                         cred.effectiveOwner(i.first),
1240                                                         Password(),
1241                                                         obj);
1242
1243                 if (ec != CKM_API_SUCCESS)
1244                         return ec;
1245
1246                 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1247
1248                 // try to read chain certificates (if present)
1249                 Crypto::GObjUPtrVector caChainObjs;
1250                 ec = readDataHelper(true,
1251                                                         cred,
1252                                                         DataType::DB_CHAIN_FIRST,
1253                                                         i.second,
1254                                                         cred.effectiveOwner(i.first),
1255                                                         CKM::Password(),
1256                                                         caChainObjs);
1257
1258                 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1259                         return ec;
1260
1261                 for (auto &caCertObj : caChainObjs)
1262                         certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1263         }
1264
1265         return CKM_API_SUCCESS;
1266 }
1267
1268 int CKMLogic::getCertificateChainHelper(
1269         const CertificateImpl &cert,
1270         const RawBufferVector &untrustedCertificates,
1271         const RawBufferVector &trustedCertificates,
1272         bool useTrustedSystemCertificates,
1273         RawBufferVector &chainRawVector)
1274 {
1275         CertificateImplVector untrustedCertVector;
1276         CertificateImplVector trustedCertVector;
1277         CertificateImplVector chainVector;
1278
1279         if (cert.empty())
1280                 return CKM_API_ERROR_INPUT_PARAM;
1281
1282         for (auto &e : untrustedCertificates) {
1283                 CertificateImpl c(e, DataFormat::FORM_DER);
1284
1285                 if (c.empty())
1286                         return CKM_API_ERROR_INPUT_PARAM;
1287
1288                 untrustedCertVector.push_back(std::move(c));
1289         }
1290
1291         for (auto &e : trustedCertificates) {
1292                 CertificateImpl c(e, DataFormat::FORM_DER);
1293
1294                 if (c.empty())
1295                         return CKM_API_ERROR_INPUT_PARAM;
1296
1297                 trustedCertVector.push_back(std::move(c));
1298         }
1299
1300         CertificateStore store;
1301         int retCode = store.verifyCertificate(cert,
1302                                                                                   untrustedCertVector,
1303                                                                                   trustedCertVector,
1304                                                                                   useTrustedSystemCertificates,
1305                                                                                   m_accessControl.isCCMode(),
1306                                                                                   chainVector);
1307
1308         if (retCode != CKM_API_SUCCESS)
1309                 return retCode;
1310
1311         for (auto &e : chainVector)
1312                 chainRawVector.push_back(e.getDER());
1313
1314         return CKM_API_SUCCESS;
1315 }
1316
1317 int CKMLogic::getCertificateChainHelper(
1318         const Credentials &cred,
1319         const CertificateImpl &cert,
1320         const OwnerNameVector &untrusted,
1321         const OwnerNameVector &trusted,
1322         bool useTrustedSystemCertificates,
1323         RawBufferVector &chainRawVector)
1324 {
1325         CertificateImplVector untrustedCertVector;
1326         CertificateImplVector trustedCertVector;
1327         CertificateImplVector chainVector;
1328
1329         if (cert.empty())
1330                 return CKM_API_ERROR_INPUT_PARAM;
1331
1332         int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1333
1334         if (retCode != CKM_API_SUCCESS)
1335                 return retCode;
1336
1337         retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1338
1339         if (retCode != CKM_API_SUCCESS)
1340                 return retCode;
1341
1342         CertificateStore store;
1343         retCode = store.verifyCertificate(cert,
1344                                                                           untrustedCertVector,
1345                                                                           trustedCertVector,
1346                                                                           useTrustedSystemCertificates,
1347                                                                           m_accessControl.isCCMode(),
1348                                                                           chainVector);
1349
1350         if (retCode != CKM_API_SUCCESS)
1351                 return retCode;
1352
1353         for (auto &i : chainVector)
1354                 chainRawVector.push_back(i.getDER());
1355
1356         return CKM_API_SUCCESS;
1357 }
1358
1359 RawBuffer CKMLogic::getCertificateChain(
1360         const Credentials & /*cred*/,
1361         int msgId,
1362         const RawBuffer &certificate,
1363         const RawBufferVector &untrustedCertificates,
1364         const RawBufferVector &trustedCertificates,
1365         bool useTrustedSystemCertificates)
1366 {
1367         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1368         RawBufferVector chainRawVector;
1369         int retCode = CKM_API_ERROR_UNKNOWN;
1370
1371         try {
1372                 retCode = getCertificateChainHelper(cert,
1373                                                                                         untrustedCertificates,
1374                                                                                         trustedCertificates,
1375                                                                                         useTrustedSystemCertificates,
1376                                                                                         chainRawVector);
1377         } catch (const Exc::Exception &e) {
1378                 retCode = e.error();
1379         } catch (const std::exception &e) {
1380                 LogError("STD exception " << e.what());
1381                 retCode = CKM_API_ERROR_SERVER_ERROR;
1382         } catch (...) {
1383                 LogError("Unknown error.");
1384         }
1385
1386         return SerializeMessage(msgId, retCode, chainRawVector);
1387 }
1388
1389 RawBuffer CKMLogic::getCertificateChain(
1390         const Credentials &cred,
1391         int msgId,
1392         const RawBuffer &certificate,
1393         const OwnerNameVector &untrustedCertificates,
1394         const OwnerNameVector &trustedCertificates,
1395         bool useTrustedSystemCertificates)
1396 {
1397         int retCode = CKM_API_ERROR_UNKNOWN;
1398         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1399         RawBufferVector chainRawVector;
1400
1401         try {
1402                 retCode = getCertificateChainHelper(cred,
1403                                                                                         cert,
1404                                                                                         untrustedCertificates,
1405                                                                                         trustedCertificates,
1406                                                                                         useTrustedSystemCertificates,
1407                                                                                         chainRawVector);
1408         } catch (const Exc::Exception &e) {
1409                 retCode = e.error();
1410         } catch (const std::exception &e) {
1411                 LogError("STD exception " << e.what());
1412                 retCode = CKM_API_ERROR_SERVER_ERROR;
1413         } catch (...) {
1414                 LogError("Unknown error.");
1415         }
1416
1417         return SerializeMessage(msgId, retCode, chainRawVector);
1418 }
1419
1420 RawBuffer CKMLogic::createSignature(
1421         const Credentials &cred,
1422         int msgId,
1423         const Name &privateKeyName,
1424         const ClientId &owner,
1425         const Password &password,           // password for private_key
1426         const RawBuffer &message,
1427         const CryptoAlgorithm &cryptoAlg)
1428 {
1429         RawBuffer signature;
1430
1431         int retCode = CKM_API_SUCCESS;
1432
1433         try {
1434                 retCode = tryRet([&] {
1435                         Crypto::GObjUPtr obj;
1436                         int retCode2 = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1437                                                                                   owner, password, obj);
1438
1439                         if (retCode2 == CKM_API_SUCCESS)
1440                                 signature = obj->sign(cryptoAlg, message);
1441
1442                         return retCode2;
1443                 });
1444         } catch (const std::exception &e) {
1445                 LogError("STD exception " << e.what());
1446                 retCode = CKM_API_ERROR_SERVER_ERROR;
1447         }
1448
1449         return SerializeMessage(msgId, retCode, signature);
1450 }
1451
1452 RawBuffer CKMLogic::verifySignature(
1453         const Credentials &cred,
1454         int msgId,
1455         const Name &publicKeyOrCertName,
1456         const ClientId &owner,
1457         const Password &password,           // password for public_key (optional)
1458         const RawBuffer &message,
1459         const RawBuffer &signature,
1460         const CryptoAlgorithm &params)
1461 {
1462         return SerializeMessage(msgId, tryRet([&] {
1463                 // try certificate first - looking for a public key.
1464                 // in case of PKCS, pub key from certificate will be found first
1465                 // rather than private key from the same PKCS.
1466                 Crypto::GObjUPtr obj;
1467                 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1468                                                                          publicKeyOrCertName, owner, password, obj);
1469
1470                 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1471                         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1472                                                                          publicKeyOrCertName, owner, password, obj);
1473
1474                 if (retCode == CKM_API_SUCCESS)
1475                         retCode = obj->verify(params, message, signature);
1476
1477                 return retCode;
1478         }));
1479 }
1480
1481 int CKMLogic::setPermissionHelper(
1482         const Credentials &cred,                // who's the client
1483         const Name &name,
1484         const ClientId &owner,                     // who's the owner
1485         const ClientId &accessor,             // who will get the access
1486         const PermissionMask permissionMask)
1487 {
1488         auto [dbOp, retCode] = beginSave(cred, name, owner);
1489         // Normally, saving requires alias to be unoccupied. When changing permissions it's the opposite
1490         if (retCode != CKM_API_ERROR_DB_ALIAS_EXISTS) {
1491                 if (retCode == CKM_API_SUCCESS)
1492                         retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1493                 return retCode;
1494         }
1495
1496         // currently we don't support modification of owner's permissions to his own rows
1497         if (owner == accessor)
1498                 return CKM_API_ERROR_INPUT_PARAM;
1499
1500         // system database does not support write/remove permissions
1501         if ((0 == owner.compare(CLIENT_ID_SYSTEM)) && (permissionMask & Permission::REMOVE))
1502                 return CKM_API_ERROR_INPUT_PARAM;
1503
1504         // set permissions to the row owned by owner for accessor
1505         dbOp.database().setPermission(name, owner, accessor, permissionMask);
1506         dbOp.transaction().commit();
1507
1508         return CKM_API_SUCCESS;
1509 }
1510
1511 RawBuffer CKMLogic::setPermission(
1512         const Credentials &cred,
1513         const int msgID,
1514         const Name &name,
1515         const ClientId &owner,
1516         const ClientId &accessor,
1517         const PermissionMask permissionMask)
1518 {
1519         return SerializeMessage(msgID, tryRet([&] {
1520                 return setPermissionHelper(cred, name, owner, accessor, permissionMask);
1521         }));
1522 }
1523
1524 RawBuffer CKMLogic::deriveKey(
1525         const Credentials &cred,
1526         const int msgID,
1527         const CryptoAlgorithm &params,
1528         const Name &secretName,
1529         const ClientId &secretOwner,
1530         const Password &secretPassword,
1531         const Name &newKeyName,
1532         const ClientId &newKeyOwner,
1533         const Policy &newKeyPolicy)
1534 {
1535         return SerializeMessage(msgID, tryRet([&] {
1536                 // Get key/secret for internal service use. It won't be exported to the client
1537                 Crypto::GObjUPtr obj;
1538                 DataType objType;
1539                 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1540                                                                          secretName, secretOwner, secretPassword, obj, objType);
1541                 if (retCode != CKM_API_SUCCESS) {
1542                         if (retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1543                                 return retCode;
1544
1545                         retCode = readDataHelper(false, cred, DataType::BINARY_DATA,
1546                                                                          secretName, secretOwner, secretPassword, obj, objType);
1547                         if (retCode != CKM_API_SUCCESS)
1548                                 return retCode;
1549                 }
1550
1551                 auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, newKeyName, newKeyOwner);
1552                 if (ret != CKM_API_SUCCESS)
1553                         return ret;
1554
1555                 // ECDH (private key) -> binary secret, KBKDF -> symmetric key
1556                 DataType newKeyType = objType.isKeyPrivate() ? DataType::BINARY_DATA : DataType::KEY_AES;
1557                 if (!m_decider.checkStore(obj->backendId(), newKeyType, newKeyPolicy, false)) {
1558                         LogDebug("Can't import the derived key to backend " <<
1559                                  static_cast<int>(obj->backendId()) << " with given policy");
1560                         return CKM_API_ERROR_INPUT_PARAM;
1561                 }
1562
1563                 // derive
1564                 Token derived = obj->derive(params, newKeyPolicy.password, digest);
1565
1566                 dbOp.finalize(std::move(derived), newKeyPolicy);
1567
1568                 return CKM_API_SUCCESS;
1569         }));
1570 }
1571
1572 RawBuffer CKMLogic::importWrappedKey(
1573         const Credentials &cred,
1574         const int msgId,
1575         const CryptoAlgorithm &params,
1576         const Name &wrappingKeyName,
1577         const ClientId &wrappingKeyOwner,
1578         const Password &wrappingKeyPassword,
1579         const Name &keyName,
1580         const ClientId &keyOwner,
1581         const RawBuffer &wrappedKey,
1582         const CKM::DataType keyType,
1583         const PolicySerializable &policy)
1584 {
1585         return SerializeMessage(msgId, tryRet([&] {
1586                 Crypto::GObjUPtr wrappingKey;
1587
1588                 auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, keyName, keyOwner);
1589                 if (retCode != CKM_API_SUCCESS)
1590                         return retCode;
1591
1592                 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
1593                                                                 wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
1594                 if (retCode != CKM_API_SUCCESS)
1595                         return retCode;
1596
1597                 if (!m_decider.checkStore(wrappingKey->backendId(), keyType, policy, true)) {
1598                         LogDebug("Can't import the wrapped key to backend " <<
1599                                  static_cast<int>(wrappingKey->backendId()) << " with given policy");
1600                         return CKM_API_ERROR_INPUT_PARAM;
1601                 }
1602
1603                 Token token = wrappingKey->unwrap(params,
1604                                                                                   Crypto::Data(keyType, wrappedKey),
1605                                                                                   policy.password,
1606                                                                                   digest);
1607
1608                 dbOp.finalize(std::move(token), policy);
1609
1610                 return retCode;
1611         }));
1612 }
1613
1614 RawBuffer CKMLogic::exportWrappedKey(
1615         const Credentials &cred,
1616         const int msgID,
1617         const CryptoAlgorithm &params,
1618         const Name &wrappingKeyName,
1619         const ClientId &wrappingKeyOwner,
1620         const Password &wrappingKeyPassword,
1621         const Name &keyName,
1622         const ClientId &keyOwner,
1623         const Password &keyPassword)
1624 {
1625         Crypto::GObjUPtr wrappingKey;
1626         DB::Row wrappedKeyRow;
1627         DataType wrappedKeyType;
1628         RawBuffer wrappedKey;
1629
1630         auto retCode = tryRet([&] {
1631                 auto retCode2 = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
1632                                                                            wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
1633                 if (retCode2 != CKM_API_SUCCESS)
1634                         return retCode2;
1635
1636                 retCode2 = readRowHelper(false, cred, DataType::DB_KEY_FIRST, keyName,
1637                                                                  keyOwner, keyPassword, wrappedKeyRow, wrappedKeyType);
1638                 if (retCode2 != CKM_API_SUCCESS)
1639                         return retCode2;
1640
1641                 wrappedKey = wrappingKey->wrap(params, wrappedKeyRow, keyPassword);
1642
1643                 return retCode2;
1644         });
1645
1646         return SerializeMessage(msgID, retCode, wrappedKeyType, wrappedKey);
1647 }
1648
1649 RawBuffer CKMLogic::getBackendInfo(const int msgID, BackendId backend)
1650 {
1651         BackendInfo info;
1652         auto retCode = tryRet([&] {
1653                 CryptoBackend cryptoBackend;
1654                 if (backend == BackendId::SW)
1655                         cryptoBackend = CryptoBackend::OpenSSL;
1656                 else if (backend == BackendId::TZ)
1657                         cryptoBackend = CryptoBackend::TrustZone;
1658                 else
1659                         return CKM_API_ERROR_INPUT_PARAM;
1660
1661                 auto store = m_decider.getStore(cryptoBackend);
1662                 if (store == nullptr) {
1663                         LogError("Required backend is unavailable");
1664                         return CKM_API_ERROR_INPUT_PARAM;
1665                 }
1666
1667                 info.maxChunkSize = store->maxChunkSize();
1668                 return CKM_API_SUCCESS;
1669         });
1670
1671         return SerializeMessage(msgID, retCode, BackendInfoSerializable(info));
1672 }
1673
1674 } // namespace CKM