d931083d99b94d5c4d89c22bde139b5665c3011c
[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 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 retCode = readDataHelper(true, cred, dataType, name, owner,
827                                                                          password, obj, objDataType);
828
829                 if (retCode == CKM_API_SUCCESS)
830                         rowData = obj->getBinary();
831
832                 return retCode;
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 retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, owner,
883                                                                          keyPassword, keyObj);
884
885                 if (retCode != CKM_API_SUCCESS) {
886                         if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
887                                 return retCode;
888                 } else {
889                         privKey = CKM::Key::create(keyObj->getBinary());
890                 }
891
892                 // read certificate (mandatory)
893                 Crypto::GObjUPtr certObj;
894                 retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, owner,
895                                                                  certPassword, certObj);
896
897                 if (retCode != CKM_API_SUCCESS) {
898                         if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
899                                 return retCode;
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                 retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, owner,
907                                                                  certPassword, caChainObjs);
908
909                 if (retCode != CKM_API_SUCCESS && retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
910                         if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
911                                 return retCode;
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                         retCode = CKM_API_SUCCESS;
921
922                 // prepare response
923                 if (retCode != CKM_API_SUCCESS)
924                         return retCode;
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::getDataListHelper(const Credentials &cred,
934                                                                 const DataType dataType,
935                                                                 OwnerNameVector &ownerNameVector)
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                         OwnerNameVector tmpVector;
944
945                         if (dataType.isKey()) {
946                                 // list all key types
947                                 database.listNames(cred.client,
948                                                                    tmpVector,
949                                                                    DataType::DB_KEY_FIRST,
950                                                                    DataType::DB_KEY_LAST);
951                         } else {
952                                 // list anything else
953                                 database.listNames(cred.client,
954                                                                    tmpVector,
955                                                                    dataType);
956                         }
957
958                         ownerNameVector.insert(ownerNameVector.end(), tmpVector.begin(),
959                                                                    tmpVector.end());
960                         return CKM_API_SUCCESS;
961                 });
962         }
963
964         return retCode;
965 }
966
967 RawBuffer CKMLogic::getDataList(
968         const Credentials &cred,
969         int msgId,
970         DataType dataType)
971 {
972         OwnerNameVector systemVector;
973         OwnerNameVector userVector;
974         OwnerNameVector ownerNameVector;
975
976         int retCode = unlockSystemDB();
977
978         if (CKM_API_SUCCESS == retCode) {
979                 // system database
980                 if (m_accessControl.isSystemService(cred)) {
981                         // lookup system DB
982                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
983                                                                                 dataType,
984                                                                                 systemVector);
985                 } else {
986                         // user - lookup system, then client DB
987                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, cred.client),
988                                                                                 dataType,
989                                                                                 systemVector);
990
991                         // private database
992                         if (retCode == CKM_API_SUCCESS) {
993                                 retCode = getDataListHelper(cred,
994                                                                                         dataType,
995                                                                                         userVector);
996                         }
997                 }
998         }
999
1000         if (retCode == CKM_API_SUCCESS) {
1001                 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
1002                                                            systemVector.end());
1003                 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
1004                                                            userVector.end());
1005         }
1006
1007         return SerializeMessage(msgId, retCode, dataType, ownerNameVector);
1008 }
1009
1010 int CKMLogic::importInitialData(
1011         const Name &name,
1012         const Crypto::Data &data,
1013         const Crypto::EncryptionParams &encParams,
1014         const Policy &policy)
1015 {
1016         try {
1017                 return tryRet([&] {
1018                         if (encParams.iv.empty() != encParams.tag.empty()) {
1019                                 LogError("Both iv and tag must be empty or set");
1020                                 return CKM_API_ERROR_INPUT_PARAM;
1021                         }
1022
1023                         // Inital values are always imported with root credentials. Client id is not important.
1024                         Credentials rootCred(0, "whatever");
1025                         ClientId owner(CLIENT_ID_SYSTEM);
1026
1027                         auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
1028                         if (retCode != CKM_API_SUCCESS)
1029                                 return retCode;
1030
1031                         Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
1032
1033                         Token token;
1034                         if (encParams.iv.empty()) {
1035                                 // Data are not encrypted, let's try to verify them
1036                                 Crypto::Data binaryData;
1037
1038                                 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
1039                                         return retCode;
1040
1041                                 token = store.import(binaryData,
1042                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1043                                                                          encParams, digest);
1044                         } else {
1045                                 token = store.import(data,
1046                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1047                                                                          encParams, digest);
1048                         }
1049
1050                         dbOp.finalize(std::move(token), policy);
1051
1052                         return CKM_API_SUCCESS;
1053                 });
1054         } catch (const std::exception &e) {
1055                 LogError("Std::exception: " << e.what());
1056                 return CKM_API_ERROR_SERVER_ERROR;
1057         }
1058 }
1059
1060 int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
1061 {
1062         if (!m_handler.crypto.haveKey(m_owner)) {
1063                 RawBuffer wrappedDEK;
1064                 auto wrappedDEKOptional = m_handler.database.getKey(m_owner);
1065
1066                 if (!wrappedDEKOptional) {
1067                         if (keyRequired) {
1068                                 LogError("No key for given owner in database");
1069                                 return CKM_API_ERROR_DB_ERROR;
1070                         }
1071                         LogDebug("No Key in database found. Generating new one for client: " << m_owner);
1072                         wrappedDEK = m_handler.keyProvider.generateDEK(m_owner);
1073                         m_handler.database.saveKey(m_owner, wrappedDEK);
1074                 } else {
1075                         wrappedDEK = *wrappedDEKOptional;
1076                 }
1077
1078                 m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
1079         }
1080
1081         return CKM_API_SUCCESS;
1082 }
1083
1084 std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
1085         const Credentials &cred,
1086         const Name &name,
1087         const ClientId &owner)
1088 {
1089         auto &handler = selectDatabase(cred, owner);
1090         DBOperation op(handler, name, owner);
1091
1092         if (cred.client.empty() || !isClientValid(cred.client) ||
1093                 !isNameValid(name) || !isClientValid(owner))
1094                 return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
1095
1096         return std::make_tuple(std::move(op), CKM_API_SUCCESS);
1097 }
1098
1099 std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
1100         const Credentials &cred,
1101         const Name &name,
1102         const ClientId &owner)
1103 {
1104         PermissionMask permission;
1105         auto [dbOp, retCode] = begin(cred, name, owner);
1106         if (retCode == CKM_API_SUCCESS)
1107                 permission = toPermissionMask(dbOp.database().getPermissionRow(name, owner, cred.client));
1108
1109         return std::make_tuple(std::move(dbOp), permission, retCode);
1110 }
1111
1112 std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
1113         const Credentials &cred,
1114         const Name &name,
1115         const ClientId &owner)
1116 {
1117         auto [dbOp, retCode] = begin(cred, name, owner);
1118         if (retCode != CKM_API_SUCCESS)
1119                 return std::make_tuple(std::move(dbOp), retCode);
1120
1121         retCode = dbOp.loadAppKey(false);
1122         if (retCode != CKM_API_SUCCESS)
1123                 return std::make_tuple(std::move(dbOp), retCode);
1124
1125         // check if accessor is allowed to save owner's items
1126         retCode = m_accessControl.canSave(cred, owner);
1127         if (retCode != CKM_API_SUCCESS) {
1128                 LogDebug("accessor " << cred.client << " can not save rows owned by " << owner);
1129                 return std::make_tuple(std::move(dbOp), retCode);
1130         }
1131
1132         if (dbOp.database().isNameOwnerPresent(name, owner))
1133                 retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
1134
1135         return std::make_tuple(std::move(dbOp), retCode);
1136 }
1137
1138 std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
1139         const Credentials &cred,
1140         const Name &name,
1141         const ClientId &owner)
1142 {
1143         RawBuffer digest;
1144         auto [dbOp, retCode] = beginSave(cred, name, owner);
1145         if (retCode == CKM_API_SUCCESS) {
1146                 digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1147                 if (digest.empty())
1148                         retCode = CKM_API_ERROR_HASH_ERROR;
1149         }
1150
1151         return std::make_tuple(std::move(dbOp), std::move(digest), retCode);
1152 }
1153
1154 RawBuffer CKMLogic::createKeyPair(
1155         const Credentials &cred,
1156         int msgId,
1157         const CryptoAlgorithmSerializable &keyGenParams,
1158         const Name &namePrv,
1159         const ClientId &ownerPrv,
1160         const Name &namePub,
1161         const ClientId &ownerPub,
1162         const PolicySerializable &policyPrv,
1163         const PolicySerializable &policyPub)
1164 {
1165         return SerializeMessage(msgId, tryRet([&] {
1166                 auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
1167                 if (retCodePrv != CKM_API_SUCCESS)
1168                         return retCodePrv;
1169
1170                 auto [dbOpPub, digestPub, retCodePub] = beginSaveAndGetHash(cred, namePub, ownerPub);
1171                 if (retCodePub != CKM_API_SUCCESS)
1172                         return retCodePub;
1173
1174                 if (policyPrv.backend != policyPub.backend)
1175                         ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1176
1177                 bool exportable = policyPrv.extractable || policyPub.extractable;
1178                 Policy lessRestricted(Password(), exportable, policyPrv.backend);
1179
1180                 TokenPair keys = m_decider.getStore(policyPrv).generateAKey(
1181                         keyGenParams,
1182                         policyPrv.password,
1183                         policyPub.password,
1184                         digestPrv, digestPub);
1185
1186                 dbOpPrv.finalize(std::move(keys.first), policyPrv);
1187                 dbOpPub.finalize(std::move(keys.second), policyPub);
1188
1189                 return CKM_API_SUCCESS;
1190         }));
1191 }
1192
1193 RawBuffer CKMLogic::createKeyAES(
1194         const Credentials &cred,
1195         int msgId,
1196         const int size,
1197         const Name &name,
1198         const ClientId &owner,
1199         const PolicySerializable &policy)
1200 {
1201         int retCode = CKM_API_SUCCESS;
1202
1203         try {
1204                 retCode = tryRet([&] {
1205                         auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, name, owner);
1206                         if (retCode != CKM_API_SUCCESS)
1207                                 return retCode;
1208
1209                         // create key in store
1210                         CryptoAlgorithm keyGenAlgorithm;
1211                         keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1212                         keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1213                         Token key = m_decider.getStore(DataType::KEY_AES, policy).generateSKey(keyGenAlgorithm,
1214                                                                                                                                                                    policy.password,
1215                                                                                                                                                                    digest);
1216
1217                         dbOp.finalize(std::move(key), policy);
1218                         return CKM_API_SUCCESS;
1219                 });
1220         } catch (std::invalid_argument &e) {
1221                 LogDebug("invalid argument error: " << e.what());
1222                 retCode = CKM_API_ERROR_INPUT_PARAM;
1223         }
1224
1225         return SerializeMessage(msgId, retCode);
1226 }
1227
1228 int CKMLogic::readCertificateHelper(
1229         const Credentials &cred,
1230         const OwnerNameVector &ownerNameVector,
1231         CertificateImplVector &certVector)
1232 {
1233         for (auto &i : ownerNameVector) {
1234                 // certificates can't be protected with custom user password
1235                 Crypto::GObjUPtr obj;
1236                 int ec;
1237                 ec = readDataHelper(true,
1238                                                         cred,
1239                                                         DataType::CERTIFICATE,
1240                                                         i.second,
1241                                                         cred.effectiveOwner(i.first),
1242                                                         Password(),
1243                                                         obj);
1244
1245                 if (ec != CKM_API_SUCCESS)
1246                         return ec;
1247
1248                 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1249
1250                 // try to read chain certificates (if present)
1251                 Crypto::GObjUPtrVector caChainObjs;
1252                 ec = readDataHelper(true,
1253                                                         cred,
1254                                                         DataType::DB_CHAIN_FIRST,
1255                                                         i.second,
1256                                                         cred.effectiveOwner(i.first),
1257                                                         CKM::Password(),
1258                                                         caChainObjs);
1259
1260                 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1261                         return ec;
1262
1263                 for (auto &caCertObj : caChainObjs)
1264                         certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1265         }
1266
1267         return CKM_API_SUCCESS;
1268 }
1269
1270 int CKMLogic::getCertificateChainHelper(
1271         const CertificateImpl &cert,
1272         const RawBufferVector &untrustedCertificates,
1273         const RawBufferVector &trustedCertificates,
1274         bool useTrustedSystemCertificates,
1275         RawBufferVector &chainRawVector)
1276 {
1277         CertificateImplVector untrustedCertVector;
1278         CertificateImplVector trustedCertVector;
1279         CertificateImplVector chainVector;
1280
1281         if (cert.empty())
1282                 return CKM_API_ERROR_INPUT_PARAM;
1283
1284         for (auto &e : untrustedCertificates) {
1285                 CertificateImpl c(e, DataFormat::FORM_DER);
1286
1287                 if (c.empty())
1288                         return CKM_API_ERROR_INPUT_PARAM;
1289
1290                 untrustedCertVector.push_back(std::move(c));
1291         }
1292
1293         for (auto &e : trustedCertificates) {
1294                 CertificateImpl c(e, DataFormat::FORM_DER);
1295
1296                 if (c.empty())
1297                         return CKM_API_ERROR_INPUT_PARAM;
1298
1299                 trustedCertVector.push_back(std::move(c));
1300         }
1301
1302         CertificateStore store;
1303         int retCode = store.verifyCertificate(cert,
1304                                                                                   untrustedCertVector,
1305                                                                                   trustedCertVector,
1306                                                                                   useTrustedSystemCertificates,
1307                                                                                   m_accessControl.isCCMode(),
1308                                                                                   chainVector);
1309
1310         if (retCode != CKM_API_SUCCESS)
1311                 return retCode;
1312
1313         for (auto &e : chainVector)
1314                 chainRawVector.push_back(e.getDER());
1315
1316         return CKM_API_SUCCESS;
1317 }
1318
1319 int CKMLogic::getCertificateChainHelper(
1320         const Credentials &cred,
1321         const CertificateImpl &cert,
1322         const OwnerNameVector &untrusted,
1323         const OwnerNameVector &trusted,
1324         bool useTrustedSystemCertificates,
1325         RawBufferVector &chainRawVector)
1326 {
1327         CertificateImplVector untrustedCertVector;
1328         CertificateImplVector trustedCertVector;
1329         CertificateImplVector chainVector;
1330
1331         if (cert.empty())
1332                 return CKM_API_ERROR_INPUT_PARAM;
1333
1334         int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1335
1336         if (retCode != CKM_API_SUCCESS)
1337                 return retCode;
1338
1339         retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1340
1341         if (retCode != CKM_API_SUCCESS)
1342                 return retCode;
1343
1344         CertificateStore store;
1345         retCode = store.verifyCertificate(cert,
1346                                                                           untrustedCertVector,
1347                                                                           trustedCertVector,
1348                                                                           useTrustedSystemCertificates,
1349                                                                           m_accessControl.isCCMode(),
1350                                                                           chainVector);
1351
1352         if (retCode != CKM_API_SUCCESS)
1353                 return retCode;
1354
1355         for (auto &i : chainVector)
1356                 chainRawVector.push_back(i.getDER());
1357
1358         return CKM_API_SUCCESS;
1359 }
1360
1361 RawBuffer CKMLogic::getCertificateChain(
1362         const Credentials & /*cred*/,
1363         int msgId,
1364         const RawBuffer &certificate,
1365         const RawBufferVector &untrustedCertificates,
1366         const RawBufferVector &trustedCertificates,
1367         bool useTrustedSystemCertificates)
1368 {
1369         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1370         RawBufferVector chainRawVector;
1371         int retCode = CKM_API_ERROR_UNKNOWN;
1372
1373         try {
1374                 retCode = getCertificateChainHelper(cert,
1375                                                                                         untrustedCertificates,
1376                                                                                         trustedCertificates,
1377                                                                                         useTrustedSystemCertificates,
1378                                                                                         chainRawVector);
1379         } catch (const Exc::Exception &e) {
1380                 retCode = e.error();
1381         } catch (const std::exception &e) {
1382                 LogError("STD exception " << e.what());
1383                 retCode = CKM_API_ERROR_SERVER_ERROR;
1384         } catch (...) {
1385                 LogError("Unknown error.");
1386         }
1387
1388         return SerializeMessage(msgId, retCode, chainRawVector);
1389 }
1390
1391 RawBuffer CKMLogic::getCertificateChain(
1392         const Credentials &cred,
1393         int msgId,
1394         const RawBuffer &certificate,
1395         const OwnerNameVector &untrustedCertificates,
1396         const OwnerNameVector &trustedCertificates,
1397         bool useTrustedSystemCertificates)
1398 {
1399         int retCode = CKM_API_ERROR_UNKNOWN;
1400         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1401         RawBufferVector chainRawVector;
1402
1403         try {
1404                 retCode = getCertificateChainHelper(cred,
1405                                                                                         cert,
1406                                                                                         untrustedCertificates,
1407                                                                                         trustedCertificates,
1408                                                                                         useTrustedSystemCertificates,
1409                                                                                         chainRawVector);
1410         } catch (const Exc::Exception &e) {
1411                 retCode = e.error();
1412         } catch (const std::exception &e) {
1413                 LogError("STD exception " << e.what());
1414                 retCode = CKM_API_ERROR_SERVER_ERROR;
1415         } catch (...) {
1416                 LogError("Unknown error.");
1417         }
1418
1419         return SerializeMessage(msgId, retCode, chainRawVector);
1420 }
1421
1422 RawBuffer CKMLogic::createSignature(
1423         const Credentials &cred,
1424         int msgId,
1425         const Name &privateKeyName,
1426         const ClientId &owner,
1427         const Password &password,           // password for private_key
1428         const RawBuffer &message,
1429         const CryptoAlgorithm &cryptoAlg)
1430 {
1431         RawBuffer signature;
1432
1433         int retCode = CKM_API_SUCCESS;
1434
1435         try {
1436                 retCode = tryRet([&] {
1437                         Crypto::GObjUPtr obj;
1438                         int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1439                                                                                  owner, password, obj);
1440
1441                         if (retCode == CKM_API_SUCCESS)
1442                                 signature = obj->sign(cryptoAlg, message);
1443
1444                         return retCode;
1445                 });
1446         } catch (const std::exception &e) {
1447                 LogError("STD exception " << e.what());
1448                 retCode = CKM_API_ERROR_SERVER_ERROR;
1449         }
1450
1451         return SerializeMessage(msgId, retCode, signature);
1452 }
1453
1454 RawBuffer CKMLogic::verifySignature(
1455         const Credentials &cred,
1456         int msgId,
1457         const Name &publicKeyOrCertName,
1458         const ClientId &owner,
1459         const Password &password,           // password for public_key (optional)
1460         const RawBuffer &message,
1461         const RawBuffer &signature,
1462         const CryptoAlgorithm &params)
1463 {
1464         return SerializeMessage(msgId, tryRet([&] {
1465                 // try certificate first - looking for a public key.
1466                 // in case of PKCS, pub key from certificate will be found first
1467                 // rather than private key from the same PKCS.
1468                 Crypto::GObjUPtr obj;
1469                 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1470                                                                          publicKeyOrCertName, owner, password, obj);
1471
1472                 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1473                         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1474                                                                          publicKeyOrCertName, owner, password, obj);
1475
1476                 if (retCode == CKM_API_SUCCESS)
1477                         retCode = obj->verify(params, message, signature);
1478
1479                 return retCode;
1480         }));
1481 }
1482
1483 int CKMLogic::setPermissionHelper(
1484         const Credentials &cred,                // who's the client
1485         const Name &name,
1486         const ClientId &owner,                     // who's the owner
1487         const ClientId &accessor,             // who will get the access
1488         const PermissionMask permissionMask)
1489 {
1490         auto [dbOp, retCode] = beginSave(cred, name, owner);
1491         // Normally, saving requires alias to be unoccupied. When changing permissions it's the opposite
1492         if (retCode != CKM_API_ERROR_DB_ALIAS_EXISTS) {
1493                 if (retCode == CKM_API_SUCCESS)
1494                         retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1495                 return retCode;
1496         }
1497
1498         // currently we don't support modification of owner's permissions to his own rows
1499         if (owner == accessor)
1500                 return CKM_API_ERROR_INPUT_PARAM;
1501
1502         // system database does not support write/remove permissions
1503         if ((0 == owner.compare(CLIENT_ID_SYSTEM)) && (permissionMask & Permission::REMOVE))
1504                 return CKM_API_ERROR_INPUT_PARAM;
1505
1506         // set permissions to the row owned by owner for accessor
1507         dbOp.database().setPermission(name, owner, accessor, permissionMask);
1508         dbOp.transaction().commit();
1509
1510         return CKM_API_SUCCESS;
1511 }
1512
1513 RawBuffer CKMLogic::setPermission(
1514         const Credentials &cred,
1515         const int msgID,
1516         const Name &name,
1517         const ClientId &owner,
1518         const ClientId &accessor,
1519         const PermissionMask permissionMask)
1520 {
1521         return SerializeMessage(msgID, tryRet([&] {
1522                 return setPermissionHelper(cred, name, owner, accessor, permissionMask);
1523         }));
1524 }
1525
1526 RawBuffer CKMLogic::deriveKey(
1527         const Credentials &cred,
1528         const int msgID,
1529         const CryptoAlgorithm &params,
1530         const Name &secretName,
1531         const ClientId &secretOwner,
1532         const Password &secretPassword,
1533         const Name &newKeyName,
1534         const ClientId &newKeyOwner,
1535         const Policy &newKeyPolicy)
1536 {
1537         return SerializeMessage(msgID, tryRet([&] {
1538                 // Get key/secret for internal service use. It won't be exported to the client
1539                 Crypto::GObjUPtr obj;
1540                 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1541                                                                          secretName, secretOwner, secretPassword, obj);
1542                 if (retCode != CKM_API_SUCCESS) {
1543                         if (retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1544                                 return retCode;
1545
1546                         retCode = readDataHelper(false, cred, DataType::BINARY_DATA,
1547                                                                          secretName, secretOwner, secretPassword, obj);
1548                         if (retCode != CKM_API_SUCCESS)
1549                                 return retCode;
1550                 }
1551
1552                 auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, newKeyName, newKeyOwner);
1553                 if (ret != CKM_API_SUCCESS)
1554                         return ret;
1555
1556                 // derive
1557                 Token derived = obj->derive(params, newKeyPolicy.password, digest);
1558
1559                 dbOp.finalize(std::move(derived), newKeyPolicy);
1560
1561                 return CKM_API_SUCCESS;
1562         }));
1563 }
1564
1565 RawBuffer CKMLogic::importWrappedKey(
1566         const Credentials &cred,
1567         const int msgId,
1568         const CryptoAlgorithm &params,
1569         const Name &wrappingKeyName,
1570         const ClientId &wrappingKeyOwner,
1571         const Password &wrappingKeyPassword,
1572         const Name &encryptedKeyName,
1573         const ClientId &encryptedKeyOwner,
1574         const RawBuffer &encryptedKey,
1575         const CKM::DataType encryptedKeyType,
1576         const PolicySerializable &encryptedKeyPolicy)
1577 {
1578         return SerializeMessage(msgId, tryRet([&] {
1579                 Crypto::GObjUPtr wrappingKey;
1580
1581                 auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, encryptedKeyName, encryptedKeyOwner);
1582                 if (retCode != CKM_API_SUCCESS)
1583                         return retCode;
1584
1585                 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
1586                                                                 wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
1587                 if (retCode != CKM_API_SUCCESS)
1588                         return retCode;
1589
1590                 Token token = wrappingKey->unwrap(params,
1591                                                                                   Crypto::Data(encryptedKeyType, std::move(encryptedKey)),
1592                                                                                   encryptedKeyPolicy.password,
1593                                                                                   digest);
1594
1595                 dbOp.finalize(std::move(token), encryptedKeyPolicy);
1596
1597                 return retCode;
1598         }));
1599 }
1600
1601 RawBuffer CKMLogic::exportWrappedKey(
1602         const Credentials &cred,
1603         const int msgID,
1604         const CryptoAlgorithm &params,
1605         const Name &wrappingKeyName,
1606         const ClientId &wrappingKeyOwner,
1607         const Password &wrappingKeyPassword,
1608         const Name &wrappedKeyName,
1609         const ClientId &wrappedKeyOwner,
1610         const Password &wrappedKeyPassword)
1611 {
1612         Crypto::GObjUPtr wrappingKey;
1613         DB::Row wrappedKeyRow;
1614         DataType wrappedKeyType;
1615         RawBuffer wrappedKey;
1616
1617         auto retCode = tryRet([&] {
1618                 auto retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, wrappingKeyName,
1619                                                                           wrappingKeyOwner, wrappingKeyPassword, wrappingKey);
1620                 if (retCode != CKM_API_SUCCESS)
1621                         return retCode;
1622
1623                 retCode = readRowHelper(false, cred, DataType::DB_KEY_FIRST, wrappedKeyName,
1624                                                                 wrappedKeyOwner, wrappedKeyPassword, wrappedKeyRow, wrappedKeyType);
1625                 if (retCode != CKM_API_SUCCESS)
1626                         return retCode;
1627
1628                 wrappedKey = wrappingKey->wrap(params, wrappedKeyRow, wrappedKeyPassword);
1629
1630                 return retCode;
1631         });
1632
1633         return SerializeMessage(msgID, retCode, wrappedKeyType, wrappedKey);
1634 }
1635
1636 } // namespace CKM