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