Unify CKMLogic methods and fix PKCS12 support
[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 int CKMLogic::changeUserPasswordHelper(uid_t user,
377                                                                            const Password &oldPassword,
378                                                                            const Password &newPassword)
379 {
380         // do not allow to change system database password
381         if (m_accessControl.isSystemService(user))
382                 return CKM_API_ERROR_INPUT_PARAM;
383
384         loadDKEKFile(user, oldPassword);
385         saveDKEKFile(user, newPassword);
386
387         return CKM_API_SUCCESS;
388 }
389
390 RawBuffer CKMLogic::changeUserPassword(
391         uid_t user,
392         const Password &oldPassword,
393         const Password &newPassword)
394 {
395         return SerializeMessage(tryRet([&] {
396                 return changeUserPasswordHelper(user, oldPassword, newPassword);
397         }));
398 }
399
400 int CKMLogic::resetUserPasswordHelper(
401         uid_t user,
402         const Password &newPassword)
403 {
404         // do not allow to reset system database password
405         if (m_accessControl.isSystemService(user))
406                 return CKM_API_ERROR_INPUT_PARAM;
407
408         int retCode = CKM_API_SUCCESS;
409
410         if (0 == m_userDataMap.count(user)) {
411                 // Check if key exists. If exists we must return error
412                 FileSystem fs(user);
413                 auto wrappedDKEKMain = fs.getDKEK();
414
415                 if (!wrappedDKEKMain.empty())
416                         retCode = CKM_API_ERROR_BAD_REQUEST;
417         } else {
418                 saveDKEKFile(user, newPassword);
419         }
420
421         return retCode;
422 }
423
424 RawBuffer CKMLogic::resetUserPassword(
425         uid_t user,
426         const Password &newPassword)
427 {
428         return SerializeMessage(tryRet([&] {
429                 return resetUserPasswordHelper(user, newPassword);
430         }));
431 }
432
433 RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
434 {
435         return SerializeMessage(tryRet([&] {
436                 if (owner.empty())
437                         return CKM_API_ERROR_INPUT_PARAM;
438
439                 UidVector uids = FileSystem::getUIDsFromDBFile();
440
441                 for (auto userId : uids) {
442                         if (0 == m_userDataMap.count(userId)) {
443                                 FileSystem fs(userId);
444                                 fs.addRemovedApp(owner);
445                         } else {
446                                 auto &handle = m_userDataMap[userId];
447                                 handle.crypto.removeKey(owner);
448                                 handle.database.deleteKey(owner);
449                         }
450                 }
451
452                 return CKM_API_SUCCESS;
453         }));
454 }
455
456 int CKMLogic::verifyAndSaveDataHelper(
457         const Credentials &cred,
458         const Name &name,
459         const ClientId &owner,
460         const Crypto::Data &data,
461         const PolicySerializable &policy)
462 {
463         return tryRet([&] {
464                 // check if data is correct
465                 Crypto::Data binaryData;
466                 int retCode = toBinaryData(data, binaryData);
467
468                 return retCode != CKM_API_SUCCESS
469                         ? retCode
470                         : saveDataHelper(cred, name, owner, binaryData, policy);
471         });
472 }
473
474 int CKMLogic::getKeyForService(
475         const Credentials &cred,
476         const Name &name,
477         const ClientId &owner,
478         const Password &pass,
479         Crypto::GObjShPtr &key)
480 {
481         return tryRet([&] {
482                 // Key is for internal service use. It won't be exported to the client
483                 Crypto::GObjUPtr obj;
484                 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, owner, pass, obj);
485                 if (retCode == CKM_API_SUCCESS)
486                         key = std::move(obj);
487
488                 return retCode;
489         });
490 }
491
492 RawBuffer CKMLogic::saveData(
493         const Credentials &cred,
494         int msgId,
495         const Name &name,
496         const ClientId &owner,
497         const Crypto::Data &data,
498         const PolicySerializable &policy)
499 {
500         int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
501         return SerializeMessage(msgId, retCode, data.type);
502 }
503
504 RawBuffer CKMLogic::savePKCS12(
505         const Credentials &cred,
506         int msgId,
507         const Name &name,
508         const ClientId &owner,
509         const PKCS12Serializable &pkcs,
510         const PolicySerializable &keyPolicy,
511         const PolicySerializable &certPolicy)
512 {
513         return SerializeMessage(msgId, tryRet([&] {
514                 return saveDataHelper(cred, name, owner, pkcs, keyPolicy, certPolicy);
515         }));
516 }
517
518 int CKMLogic::removeDataHelper(
519         const Credentials &cred,
520         const Name &name,
521         const ClientId &owner)
522 {
523         auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
524         if (retCode != CKM_API_SUCCESS)
525                 return retCode;
526
527         retCode = m_accessControl.canDelete(cred, permission);
528         if (retCode != CKM_API_SUCCESS) {
529                 LogWarning("access control check result: " << retCode);
530                 return retCode;
531         }
532
533         // get all matching rows
534         DB::RowVector rows;
535         dbOp.database().getRows(name, owner, DataType::DB_FIRST, DataType::DB_LAST, rows);
536         if (rows.empty()) {
537                 LogDebug("No row for given name and owner");
538                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
539         }
540
541         retCode = dbOp.loadAppKey();
542         if (retCode != CKM_API_SUCCESS)
543                 return retCode;
544
545         // destroy it in store
546         for (auto &r : rows) {
547                 try {
548                         dbOp.handler().crypto.decryptRow(Password(), r);
549                         m_decider.getStore(r).destroy(r);
550                 } catch (const Exc::AuthenticationFailed &) {
551                         LogDebug("Authentication failed when removing data. Ignored.");
552                 }
553         }
554
555         // delete row in db
556         dbOp.database().deleteRow(name, owner);
557         dbOp.transaction().commit();
558
559         return CKM_API_SUCCESS;
560 }
561
562 RawBuffer CKMLogic::removeData(
563         const Credentials &cred,
564         int msgId,
565         const Name &name,
566         const ClientId &owner)
567 {
568         return SerializeMessage(msgId, tryRet([&] {
569                 return removeDataHelper(cred, name, owner);
570         }));
571 }
572
573
574 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
575                 const DB::Row &row,
576                 bool exportFlag,
577                 const PermissionMask& permission)
578 {
579         if (exportFlag)
580                 return m_accessControl.canExport(accessorCred, row, permission);
581
582         return m_accessControl.canRead(accessorCred, permission);
583 }
584
585 Crypto::GObjUPtr CKMLogic::rowToObject(
586         UserData &handler,
587         DB::Row row,
588         const Password &password,
589         const RawBuffer &hash)
590 {
591         Crypto::GStore &store = m_decider.getStore(row);
592
593         Password pass = m_accessControl.isCCMode() ? "" : password;
594
595         // decrypt row
596         Crypto::GObjUPtr obj;
597
598         if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
599                         CryptoLogic::ENCRYPTION_V2) {
600                 handler.crypto.decryptRow(Password(), row);
601
602                 obj = store.getObject(row, pass);
603         } else {
604                 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
605                 handler.crypto.decryptRow(pass, row);
606                 // destroy it in store
607                 store.destroy(row);
608
609                 // import it to store with new scheme: data -> pass(data)
610                 Token token = store.import(Crypto::Data(row.dataType, row.data),
611                                                                    pass,
612                                                                    Crypto::EncryptionParams(),
613                                                                    hash);
614
615                 // get it from the store (it can be different than the data we imported into store)
616                 obj = store.getObject(token, pass);
617
618                 // update row with new token
619                 *static_cast<Token *>(&row) = std::move(token);
620
621                 // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
622                 handler.crypto.encryptRow(row);
623
624                 // update it in db
625                 handler.database.updateRow(row);
626         }
627
628         return obj;
629 }
630
631 int CKMLogic::readDataHelper(
632         bool exportFlag,
633         const Credentials &cred,
634         DataType dataType,
635         const Name &name,
636         const ClientId &owner,
637         const Password &password,
638         Crypto::GObjUPtrVector &objs)
639 {
640         auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
641         if (retCode != CKM_API_SUCCESS)
642                 return retCode;
643
644         // read rows
645         DB::RowVector rows;
646         retCode = readMultiRow(name, owner, dataType, dbOp.database(), rows);
647         if (CKM_API_SUCCESS != retCode)
648                 return retCode;
649
650         // all read rows belong to the same owner
651         DB::Row &firstRow = rows.at(0);
652
653         // check access rights
654         retCode = checkDataPermissionsHelper(cred, firstRow, exportFlag, permission);
655         if (CKM_API_SUCCESS != retCode)
656                 return retCode;
657
658         // for multiple objects add type as hash input (see pkcs12)
659         bool multiple = rows.size() > 1;
660
661         RawBuffer digest;
662
663         retCode = dbOp.loadAppKey();
664         if (retCode != CKM_API_SUCCESS)
665                 return retCode;
666
667         // decrypt row
668         for (auto &row : rows) {
669                 if (multiple)
670                         digest = CryptoLogic::makeHash(name, owner, cred.clientUid, row.dataType);
671                 else
672                         digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
673
674                 if (digest.empty())
675                         return CKM_API_ERROR_HASH_ERROR;
676
677                 objs.push_back(rowToObject(dbOp.handler(), std::move(row), password, digest));
678         }
679
680         // rowToObject may modify db
681         dbOp.transaction().commit();
682
683         return CKM_API_SUCCESS;
684 }
685
686 int CKMLogic::readDataHelper(
687         bool exportFlag,
688         const Credentials &cred,
689         DataType dataType,
690         const Name &name,
691         const ClientId &owner,
692         const Password &password,
693         Crypto::GObjUPtr &obj)
694 {
695         DataType objDataType;
696         return readDataHelper(exportFlag, cred, dataType, name, owner,
697                                                   password, obj, objDataType);
698 }
699
700 int CKMLogic::readDataHelper(
701         bool exportFlag,
702         const Credentials &cred,
703         DataType dataType,
704         const Name &name,
705         const ClientId &owner,
706         const Password &password,
707         Crypto::GObjUPtr &obj,
708         DataType &objDataType)
709 {
710         auto [dbOp, permission, retCode] = beginAndGetPerm(cred, name, owner);
711         if (retCode != CKM_API_SUCCESS)
712                 return retCode;
713
714         DB::Row row;
715         retCode = readSingleRow(name, owner, dataType, dbOp.database(), row);
716         if (CKM_API_SUCCESS != retCode)
717                 return retCode;
718
719         retCode = dbOp.loadAppKey();
720         if (retCode != CKM_API_SUCCESS)
721                 return retCode;
722
723         objDataType = row.dataType;
724
725         // check access rights
726         retCode = checkDataPermissionsHelper(cred, row, exportFlag, permission);
727         if (CKM_API_SUCCESS != retCode)
728                 return retCode;
729
730         auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
731         if (digest.empty())
732                 return CKM_API_ERROR_HASH_ERROR;
733
734         obj = rowToObject(dbOp.handler(), std::move(row), password, digest);
735         // rowToObject may modify db
736         dbOp.transaction().commit();
737
738         return CKM_API_SUCCESS;
739 }
740
741 RawBuffer CKMLogic::getData(
742         const Credentials &cred,
743         int msgId,
744         DataType dataType,
745         const Name &name,
746         const ClientId &owner,
747         const Password &password)
748 {
749         RawBuffer rowData;
750         DataType objDataType;
751
752         int retCode = tryRet([&] {
753                 Crypto::GObjUPtr obj;
754                 int retCode = readDataHelper(true, cred, dataType, name, owner,
755                                                                          password, obj, objDataType);
756
757                 if (retCode == CKM_API_SUCCESS)
758                         rowData = obj->getBinary();
759
760                 return retCode;
761         });
762
763         if (CKM_API_SUCCESS != retCode)
764                 rowData.clear();
765
766         return SerializeMessage(msgId, retCode, objDataType, rowData);
767 }
768
769 RawBuffer CKMLogic::getDataProtectionStatus(
770                 const Credentials &cred,
771                 int msgId,
772                 DataType dataType,
773                 const Name &name,
774                 const ClientId &owner)
775 {
776         bool status = false;
777         DataType objDataType;
778         Password password;
779
780         int retCode = tryRet([&] {
781                 Crypto::GObjUPtr obj;
782                 return readDataHelper(false, cred, dataType, name, owner, password, obj, objDataType);
783         });
784
785         if (retCode == CKM_API_ERROR_AUTHENTICATION_FAILED) {
786                 status = true;
787                 retCode = CKM_API_SUCCESS;
788         }
789
790         return SerializeMessage(msgId, retCode, objDataType, status);
791 }
792
793 int CKMLogic::getPKCS12Helper(
794         const Credentials &cred,
795         const Name &name,
796         const ClientId &owner,
797         const Password &keyPassword,
798         const Password &certPassword,
799         KeyShPtr &privKey,
800         CertificateShPtr &cert,
801         CertificateShPtrVector &caChain)
802 {
803         int retCode;
804
805         // read private key (mandatory)
806         Crypto::GObjUPtr keyObj;
807         retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, owner,
808                                                          keyPassword, keyObj);
809
810         if (retCode != CKM_API_SUCCESS) {
811                 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
812                         return retCode;
813         } else {
814                 privKey = CKM::Key::create(keyObj->getBinary());
815         }
816
817         // read certificate (mandatory)
818         Crypto::GObjUPtr certObj;
819         retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, owner,
820                                                          certPassword, certObj);
821
822         if (retCode != CKM_API_SUCCESS) {
823                 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
824                         return retCode;
825         } else {
826                 cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
827         }
828
829         // read CA cert chain (optional)
830         Crypto::GObjUPtrVector caChainObjs;
831         retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, owner,
832                                                          certPassword, caChainObjs);
833
834         if (retCode != CKM_API_SUCCESS && retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
835                 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
836                         return retCode;
837         } else {
838                 for (auto &caCertObj : caChainObjs)
839                         caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
840                                                                                                            DataFormat::FORM_DER));
841         }
842
843         // if anything found, return it
844         if (privKey || cert || caChain.size() > 0)
845                 retCode = CKM_API_SUCCESS;
846
847         return retCode;
848 }
849
850 RawBuffer CKMLogic::getPKCS12(
851         const Credentials &cred,
852         int msgId,
853         const Name &name,
854         const ClientId &owner,
855         const Password &keyPassword,
856         const Password &certPassword)
857 {
858         PKCS12Serializable output;
859
860         int retCode = tryRet([&] {
861                 KeyShPtr privKey;
862                 CertificateShPtr cert;
863                 CertificateShPtrVector caChain;
864                 int retCode = getPKCS12Helper(cred, name, owner, keyPassword,
865                                                                   certPassword, privKey, cert, caChain);
866
867                 // prepare response
868                 if (retCode == CKM_API_SUCCESS)
869                         output = PKCS12Serializable(std::move(privKey), std::move(cert), std::move(caChain));
870
871                 return retCode;
872         });
873
874         return SerializeMessage(msgId, retCode, output);
875 }
876
877 int CKMLogic::getDataListHelper(const Credentials &cred,
878                                                                 const DataType dataType,
879                                                                 OwnerNameVector &ownerNameVector)
880 {
881         int retCode = CKM_API_ERROR_DB_LOCKED;
882
883         if (0 < m_userDataMap.count(cred.clientUid)) {
884                 auto &database = m_userDataMap[cred.clientUid].database;
885
886                 retCode = tryRet<CKM_API_ERROR_DB_ERROR>([&] {
887                         OwnerNameVector tmpVector;
888
889                         if (dataType.isKey()) {
890                                 // list all key types
891                                 database.listNames(cred.client,
892                                                                    tmpVector,
893                                                                    DataType::DB_KEY_FIRST,
894                                                                    DataType::DB_KEY_LAST);
895                         } else {
896                                 // list anything else
897                                 database.listNames(cred.client,
898                                                                    tmpVector,
899                                                                    dataType);
900                         }
901
902                         ownerNameVector.insert(ownerNameVector.end(), tmpVector.begin(),
903                                                                    tmpVector.end());
904                         return CKM_API_SUCCESS;
905                 });
906         }
907
908         return retCode;
909 }
910
911 RawBuffer CKMLogic::getDataList(
912         const Credentials &cred,
913         int msgId,
914         DataType dataType)
915 {
916         OwnerNameVector systemVector;
917         OwnerNameVector userVector;
918         OwnerNameVector ownerNameVector;
919
920         int retCode = unlockSystemDB();
921
922         if (CKM_API_SUCCESS == retCode) {
923                 // system database
924                 if (m_accessControl.isSystemService(cred)) {
925                         // lookup system DB
926                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, CLIENT_ID_SYSTEM),
927                                                                                 dataType,
928                                                                                 systemVector);
929                 } else {
930                         // user - lookup system, then client DB
931                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, cred.client),
932                                                                                 dataType,
933                                                                                 systemVector);
934
935                         // private database
936                         if (retCode == CKM_API_SUCCESS) {
937                                 retCode = getDataListHelper(cred,
938                                                                                         dataType,
939                                                                                         userVector);
940                         }
941                 }
942         }
943
944         if (retCode == CKM_API_SUCCESS) {
945                 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
946                                                            systemVector.end());
947                 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
948                                                            userVector.end());
949         }
950
951         return SerializeMessage(msgId, retCode, dataType, ownerNameVector);
952 }
953
954 int CKMLogic::importInitialData(
955         const Name &name,
956         const Crypto::Data &data,
957         const Crypto::EncryptionParams &encParams,
958         const Policy &policy)
959 {
960         try {
961                 return tryRet([&] {
962                         if (encParams.iv.empty() != encParams.tag.empty()) {
963                                 LogError("Both iv and tag must be empty or set");
964                                 return CKM_API_ERROR_INPUT_PARAM;
965                         }
966
967                         // Inital values are always imported with root credentials. Client id is not important.
968                         Credentials rootCred(0, "whatever");
969                         ClientId owner(CLIENT_ID_SYSTEM);
970
971                         auto [dbOp, digest, retCode] = beginSaveAndGetHash(rootCred, name, owner);
972                         if (retCode != CKM_API_SUCCESS)
973                                 return retCode;
974
975                         Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
976
977                         Token token;
978                         if (encParams.iv.empty()) {
979                                 // Data are not encrypted, let's try to verify them
980                                 Crypto::Data binaryData;
981
982                                 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
983                                         return retCode;
984
985                                 token = store.import(binaryData,
986                                                                          m_accessControl.isCCMode() ? "" : policy.password,
987                                                                          encParams, digest);
988                         } else {
989                                 token = store.import(data,
990                                                                          m_accessControl.isCCMode() ? "" : policy.password,
991                                                                          encParams, digest);
992                         }
993
994                         dbOp.finalize(std::move(token), policy);
995
996                         return CKM_API_SUCCESS;
997                 });
998         } catch (const std::exception &e) {
999                 LogError("Std::exception: " << e.what());
1000                 return CKM_API_ERROR_SERVER_ERROR;
1001         }
1002 }
1003
1004 int CKMLogic::saveDataHelper(
1005         const Credentials &cred,
1006         const Name &name,
1007         const ClientId &owner,
1008         const Crypto::Data &data,
1009         const PolicySerializable &policy)
1010 {
1011         auto [dbOp, digest, ret] = beginSaveAndGetHash(cred, name, owner);
1012         if (ret != CKM_API_SUCCESS)
1013                 return ret;
1014
1015         Crypto::GStore &store = m_decider.getStore(data.type, policy);
1016
1017         // do not encrypt data with password during cc_mode on
1018         Token token = store.import(data,
1019                                                            m_accessControl.isCCMode() ? "" : policy.password,
1020                                                            Crypto::EncryptionParams(), digest);
1021         dbOp.finalize(std::move(token), policy);
1022         return CKM_API_SUCCESS;
1023 }
1024
1025 int CKMLogic::saveDataHelper(
1026         const Credentials &cred,
1027         const Name &name,
1028         const ClientId &owner,
1029         const PKCS12Serializable &pkcs,
1030         const PolicySerializable &keyPolicy,
1031         const PolicySerializable &certPolicy)
1032 {
1033         auto [dbOp, retCode] = beginSave(cred, name, owner);
1034         if (retCode != CKM_API_SUCCESS)
1035                 return retCode;
1036
1037         // extract and encrypt the data
1038         DB::RowVector encryptedRows;
1039
1040         auto import = [&](const Crypto::Data &data, const Policy& policy){
1041                 retCode = verifyBinaryData(data);
1042                 if (retCode != CKM_API_SUCCESS)
1043                         return retCode;
1044
1045                 auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid, data.type);
1046                 if (digest.empty())
1047                         return CKM_API_ERROR_HASH_ERROR;
1048
1049                 Crypto::GStore &store = m_decider.getStore(data.type, policy);
1050
1051                 // do not encrypt data with password during cc_mode on
1052                 Token token = store.import(data,
1053                                                                    m_accessControl.isCCMode() ? "" : policy.password,
1054                                                                    Crypto::EncryptionParams(), digest);
1055
1056                 encryptedRows.push_back(dbOp.encryptOne(std::move(token), policy));
1057                 return CKM_API_SUCCESS;
1058         };
1059
1060         // private key is mandatory
1061         auto key = pkcs.getKey();
1062         if (!key) {
1063                 LogError("Failed to get private key from pkcs");
1064                 return CKM_API_ERROR_INVALID_FORMAT;
1065         }
1066
1067         Crypto::Data keyData(DataType(key->getType()), key->getDER());
1068         retCode = import(keyData, keyPolicy);
1069         if (retCode != CKM_API_SUCCESS)
1070                 return retCode;
1071
1072         // certificate is mandatory
1073         auto cert = pkcs.getCertificate();
1074         if (!cert) {
1075                 LogError("Failed to get certificate from pkcs");
1076                 return CKM_API_ERROR_INVALID_FORMAT;
1077         }
1078
1079         Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
1080         retCode = import(certData, certPolicy);
1081         if (retCode != CKM_API_SUCCESS)
1082                 return retCode;
1083
1084         // CA cert chain
1085         unsigned int cert_index = 0;
1086         for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
1087                 Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++), ca->getDER());
1088                 retCode = import(caCertData, certPolicy);
1089                 if (retCode != CKM_API_SUCCESS)
1090                         return retCode;
1091         }
1092
1093         // save the data
1094         dbOp.database().saveRows(name, owner, encryptedRows);
1095         dbOp.transaction().commit();
1096
1097         return CKM_API_SUCCESS;
1098 }
1099
1100 int CKMLogic::DBOperation::loadAppKey(bool keyRequired)
1101 {
1102         if (!m_handler.crypto.haveKey(m_owner)) {
1103                 RawBuffer wrappedDEK;
1104                 auto wrappedDEKOptional = m_handler.database.getKey(m_owner);
1105
1106                 if (!wrappedDEKOptional) {
1107                         if (keyRequired) {
1108                                 LogError("No key for given owner in database");
1109                                 return CKM_API_ERROR_DB_ERROR;
1110                         }
1111                         LogDebug("No Key in database found. Generating new one for client: " << m_owner);
1112                         wrappedDEK = m_handler.keyProvider.generateDEK(m_owner);
1113                         m_handler.database.saveKey(m_owner, wrappedDEK);
1114                 } else {
1115                         wrappedDEK = *wrappedDEKOptional;
1116                 }
1117
1118                 m_handler.crypto.pushKey(m_owner, m_handler.keyProvider.getPureDEK(wrappedDEK));
1119         }
1120
1121         return CKM_API_SUCCESS;
1122 }
1123
1124 std::tuple<CKMLogic::DBOperation, int> CKMLogic::begin(
1125         const Credentials &cred,
1126         const Name &name,
1127         const ClientId &owner)
1128 {
1129         auto &handler = selectDatabase(cred, owner);
1130         DBOperation op(handler, name, owner);
1131
1132         if (cred.client.empty() || !isClientValid(cred.client) ||
1133                 !isNameValid(name) || !isClientValid(owner))
1134                 return std::make_tuple(std::move(op), CKM_API_ERROR_INPUT_PARAM);
1135
1136         return std::make_tuple(std::move(op), CKM_API_SUCCESS);
1137 }
1138
1139 std::tuple<CKMLogic::DBOperation, PermissionMask, int> CKMLogic::beginAndGetPerm(
1140         const Credentials &cred,
1141         const Name &name,
1142         const ClientId &owner)
1143 {
1144         PermissionMask permission;
1145         auto [dbOp, retCode] = begin(cred, name, owner);
1146         if (retCode == CKM_API_SUCCESS)
1147                 permission = toPermissionMask(dbOp.database().getPermissionRow(name, owner, cred.client));
1148
1149         return std::make_tuple(std::move(dbOp), permission, retCode);
1150 }
1151
1152 std::tuple<CKMLogic::DBOperation, int> CKMLogic::beginSave(
1153         const Credentials &cred,
1154         const Name &name,
1155         const ClientId &owner)
1156 {
1157         auto [dbOp, retCode] = begin(cred, name, owner);
1158         if (retCode != CKM_API_SUCCESS)
1159                 return std::make_tuple(std::move(dbOp), retCode);
1160
1161         retCode = dbOp.loadAppKey(false);
1162         if (retCode != CKM_API_SUCCESS)
1163                 return std::make_tuple(std::move(dbOp), retCode);
1164
1165         // check if accessor is allowed to save owner's items
1166         retCode = m_accessControl.canSave(cred, owner);
1167         if (retCode != CKM_API_SUCCESS) {
1168                 LogDebug("accessor " << cred.client << " can not save rows owned by " << owner);
1169                 return std::make_tuple(std::move(dbOp), retCode);
1170         }
1171
1172         if (dbOp.database().isNameOwnerPresent(name, owner))
1173                 retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
1174
1175         return std::make_tuple(std::move(dbOp), retCode);
1176 }
1177
1178 std::tuple<CKMLogic::DBOperation, RawBuffer, int> CKMLogic::beginSaveAndGetHash(
1179         const Credentials &cred,
1180         const Name &name,
1181         const ClientId &owner)
1182 {
1183         RawBuffer digest;
1184         auto [dbOp, retCode] = beginSave(cred, name, owner);
1185         if (retCode == CKM_API_SUCCESS) {
1186                 digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1187                 if (digest.empty())
1188                         retCode = CKM_API_ERROR_HASH_ERROR;
1189         }
1190
1191         return std::make_tuple(std::move(dbOp), std::move(digest), retCode);
1192 }
1193
1194 RawBuffer CKMLogic::createKeyPair(
1195         const Credentials &cred,
1196         int msgId,
1197         const CryptoAlgorithmSerializable &keyGenParams,
1198         const Name &namePrv,
1199         const ClientId &ownerPrv,
1200         const Name &namePub,
1201         const ClientId &ownerPub,
1202         const PolicySerializable &policyPrv,
1203         const PolicySerializable &policyPub)
1204 {
1205         return SerializeMessage(msgId, tryRet([&] {
1206                 auto [dbOpPrv, digestPrv, retCodePrv] = beginSaveAndGetHash(cred, namePrv, ownerPrv);
1207                 if (retCodePrv != CKM_API_SUCCESS)
1208                         return retCodePrv;
1209
1210                 auto [dbOpPub, digestPub, retCodePub] = beginSaveAndGetHash(cred, namePub, ownerPub);
1211                 if (retCodePub != CKM_API_SUCCESS)
1212                         return retCodePub;
1213
1214                 AlgoType keyType = AlgoType::RSA_GEN;
1215
1216                 if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1217                         ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1218
1219                 const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType);
1220                 if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end())
1221                         ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1222                 const DataTypePair& dt = dtIt->second;
1223
1224                 if (policyPrv.backend != policyPub.backend)
1225                         ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1226
1227                 bool exportable = policyPrv.extractable || policyPub.extractable;
1228                 Policy lessRestricted(Password(), exportable, policyPrv.backend);
1229
1230                 TokenPair keys = m_decider.getStore(policyPrv, dt.first, dt.second).generateAKey(
1231                         keyGenParams,
1232                         policyPrv.password,
1233                         policyPub.password,
1234                         digestPrv, digestPub);
1235
1236                 dbOpPrv.finalize(std::move(keys.first), policyPrv);
1237                 dbOpPub.finalize(std::move(keys.second), policyPub);
1238
1239                 return CKM_API_SUCCESS;
1240         }));
1241 }
1242
1243 RawBuffer CKMLogic::createKeyAES(
1244         const Credentials &cred,
1245         int msgId,
1246         const int size,
1247         const Name &name,
1248         const ClientId &owner,
1249         const PolicySerializable &policy)
1250 {
1251         int retCode = CKM_API_SUCCESS;
1252
1253         try {
1254                 retCode = tryRet([&] {
1255                         auto [dbOp, digest, retCode] = beginSaveAndGetHash(cred, name, owner);
1256                         if (retCode != CKM_API_SUCCESS)
1257                                 return retCode;
1258
1259                         // create key in store
1260                         CryptoAlgorithm keyGenAlgorithm;
1261                         keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1262                         keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1263                         Token key = m_decider.getStore(DataType::KEY_AES, policy).generateSKey(keyGenAlgorithm,
1264                                                                                                                                                                    policy.password,
1265                                                                                                                                                                    digest);
1266
1267                         dbOp.finalize(std::move(key), policy);
1268                         return CKM_API_SUCCESS;
1269                 });
1270         } catch (std::invalid_argument &e) {
1271                 LogDebug("invalid argument error: " << e.what());
1272                 retCode = CKM_API_ERROR_INPUT_PARAM;
1273         }
1274
1275         return SerializeMessage(msgId, retCode);
1276 }
1277
1278 int CKMLogic::readCertificateHelper(
1279         const Credentials &cred,
1280         const OwnerNameVector &ownerNameVector,
1281         CertificateImplVector &certVector)
1282 {
1283         for (auto &i : ownerNameVector) {
1284                 // certificates can't be protected with custom user password
1285                 Crypto::GObjUPtr obj;
1286                 int ec;
1287                 ec = readDataHelper(true,
1288                                                         cred,
1289                                                         DataType::CERTIFICATE,
1290                                                         i.second,
1291                                                         cred.effectiveOwner(i.first),
1292                                                         Password(),
1293                                                         obj);
1294
1295                 if (ec != CKM_API_SUCCESS)
1296                         return ec;
1297
1298                 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1299
1300                 // try to read chain certificates (if present)
1301                 Crypto::GObjUPtrVector caChainObjs;
1302                 ec = readDataHelper(true,
1303                                                         cred,
1304                                                         DataType::DB_CHAIN_FIRST,
1305                                                         i.second,
1306                                                         cred.effectiveOwner(i.first),
1307                                                         CKM::Password(),
1308                                                         caChainObjs);
1309
1310                 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1311                         return ec;
1312
1313                 for (auto &caCertObj : caChainObjs)
1314                         certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1315         }
1316
1317         return CKM_API_SUCCESS;
1318 }
1319
1320 int CKMLogic::getCertificateChainHelper(
1321         const CertificateImpl &cert,
1322         const RawBufferVector &untrustedCertificates,
1323         const RawBufferVector &trustedCertificates,
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         for (auto &e : untrustedCertificates) {
1335                 CertificateImpl c(e, DataFormat::FORM_DER);
1336
1337                 if (c.empty())
1338                         return CKM_API_ERROR_INPUT_PARAM;
1339
1340                 untrustedCertVector.push_back(std::move(c));
1341         }
1342
1343         for (auto &e : trustedCertificates) {
1344                 CertificateImpl c(e, DataFormat::FORM_DER);
1345
1346                 if (c.empty())
1347                         return CKM_API_ERROR_INPUT_PARAM;
1348
1349                 trustedCertVector.push_back(std::move(c));
1350         }
1351
1352         CertificateStore store;
1353         int retCode = store.verifyCertificate(cert,
1354                                                                                   untrustedCertVector,
1355                                                                                   trustedCertVector,
1356                                                                                   useTrustedSystemCertificates,
1357                                                                                   m_accessControl.isCCMode(),
1358                                                                                   chainVector);
1359
1360         if (retCode != CKM_API_SUCCESS)
1361                 return retCode;
1362
1363         for (auto &e : chainVector)
1364                 chainRawVector.push_back(e.getDER());
1365
1366         return CKM_API_SUCCESS;
1367 }
1368
1369 int CKMLogic::getCertificateChainHelper(
1370         const Credentials &cred,
1371         const CertificateImpl &cert,
1372         const OwnerNameVector &untrusted,
1373         const OwnerNameVector &trusted,
1374         bool useTrustedSystemCertificates,
1375         RawBufferVector &chainRawVector)
1376 {
1377         CertificateImplVector untrustedCertVector;
1378         CertificateImplVector trustedCertVector;
1379         CertificateImplVector chainVector;
1380
1381         if (cert.empty())
1382                 return CKM_API_ERROR_INPUT_PARAM;
1383
1384         int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1385
1386         if (retCode != CKM_API_SUCCESS)
1387                 return retCode;
1388
1389         retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1390
1391         if (retCode != CKM_API_SUCCESS)
1392                 return retCode;
1393
1394         CertificateStore store;
1395         retCode = store.verifyCertificate(cert,
1396                                                                           untrustedCertVector,
1397                                                                           trustedCertVector,
1398                                                                           useTrustedSystemCertificates,
1399                                                                           m_accessControl.isCCMode(),
1400                                                                           chainVector);
1401
1402         if (retCode != CKM_API_SUCCESS)
1403                 return retCode;
1404
1405         for (auto &i : chainVector)
1406                 chainRawVector.push_back(i.getDER());
1407
1408         return CKM_API_SUCCESS;
1409 }
1410
1411 RawBuffer CKMLogic::getCertificateChain(
1412         const Credentials & /*cred*/,
1413         int msgId,
1414         const RawBuffer &certificate,
1415         const RawBufferVector &untrustedCertificates,
1416         const RawBufferVector &trustedCertificates,
1417         bool useTrustedSystemCertificates)
1418 {
1419         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1420         RawBufferVector chainRawVector;
1421         int retCode = CKM_API_ERROR_UNKNOWN;
1422
1423         try {
1424                 retCode = getCertificateChainHelper(cert,
1425                                                                                         untrustedCertificates,
1426                                                                                         trustedCertificates,
1427                                                                                         useTrustedSystemCertificates,
1428                                                                                         chainRawVector);
1429         } catch (const Exc::Exception &e) {
1430                 retCode = e.error();
1431         } catch (const std::exception &e) {
1432                 LogError("STD exception " << e.what());
1433                 retCode = CKM_API_ERROR_SERVER_ERROR;
1434         } catch (...) {
1435                 LogError("Unknown error.");
1436         }
1437
1438         return SerializeMessage(msgId, retCode, chainRawVector);
1439 }
1440
1441 RawBuffer CKMLogic::getCertificateChain(
1442         const Credentials &cred,
1443         int msgId,
1444         const RawBuffer &certificate,
1445         const OwnerNameVector &untrustedCertificates,
1446         const OwnerNameVector &trustedCertificates,
1447         bool useTrustedSystemCertificates)
1448 {
1449         int retCode = CKM_API_ERROR_UNKNOWN;
1450         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1451         RawBufferVector chainRawVector;
1452
1453         try {
1454                 retCode = getCertificateChainHelper(cred,
1455                                                                                         cert,
1456                                                                                         untrustedCertificates,
1457                                                                                         trustedCertificates,
1458                                                                                         useTrustedSystemCertificates,
1459                                                                                         chainRawVector);
1460         } catch (const Exc::Exception &e) {
1461                 retCode = e.error();
1462         } catch (const std::exception &e) {
1463                 LogError("STD exception " << e.what());
1464                 retCode = CKM_API_ERROR_SERVER_ERROR;
1465         } catch (...) {
1466                 LogError("Unknown error.");
1467         }
1468
1469         return SerializeMessage(msgId, retCode, chainRawVector);
1470 }
1471
1472 RawBuffer CKMLogic::createSignature(
1473         const Credentials &cred,
1474         int msgId,
1475         const Name &privateKeyName,
1476         const ClientId &owner,
1477         const Password &password,           // password for private_key
1478         const RawBuffer &message,
1479         const CryptoAlgorithm &cryptoAlg)
1480 {
1481         RawBuffer signature;
1482
1483         int retCode = CKM_API_SUCCESS;
1484
1485         try {
1486                 retCode = tryRet([&] {
1487                         Crypto::GObjUPtr obj;
1488                         int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1489                                                                                  owner, password, obj);
1490
1491                         if (retCode == CKM_API_SUCCESS)
1492                                 signature = obj->sign(cryptoAlg, message);
1493
1494                         return retCode;
1495                 });
1496         } catch (const std::exception &e) {
1497                 LogError("STD exception " << e.what());
1498                 retCode = CKM_API_ERROR_SERVER_ERROR;
1499         }
1500
1501         return SerializeMessage(msgId, retCode, signature);
1502 }
1503
1504 RawBuffer CKMLogic::verifySignature(
1505         const Credentials &cred,
1506         int msgId,
1507         const Name &publicKeyOrCertName,
1508         const ClientId &owner,
1509         const Password &password,           // password for public_key (optional)
1510         const RawBuffer &message,
1511         const RawBuffer &signature,
1512         const CryptoAlgorithm &params)
1513 {
1514         return SerializeMessage(msgId, tryRet([&] {
1515                 // try certificate first - looking for a public key.
1516                 // in case of PKCS, pub key from certificate will be found first
1517                 // rather than private key from the same PKCS.
1518                 Crypto::GObjUPtr obj;
1519                 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1520                                                                          publicKeyOrCertName, owner, password, obj);
1521
1522                 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1523                         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1524                                                                          publicKeyOrCertName, owner, password, obj);
1525
1526                 if (retCode == CKM_API_SUCCESS)
1527                         retCode = obj->verify(params, message, signature);
1528
1529                 return retCode;
1530         }));
1531 }
1532
1533 int CKMLogic::setPermissionHelper(
1534         const Credentials &cred,                // who's the client
1535         const Name &name,
1536         const ClientId &owner,                     // who's the owner
1537         const ClientId &accessor,             // who will get the access
1538         const PermissionMask permissionMask)
1539 {
1540         auto [dbOp, retCode] = beginSave(cred, name, owner);
1541         // Normally, saving requires alias to be unoccupied. When changing permissions it's the opposite
1542         if (retCode != CKM_API_ERROR_DB_ALIAS_EXISTS) {
1543                 if (retCode == CKM_API_SUCCESS)
1544                         retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1545                 return retCode;
1546         }
1547
1548         // currently we don't support modification of owner's permissions to his own rows
1549         if (owner == accessor)
1550                 return CKM_API_ERROR_INPUT_PARAM;
1551
1552         // system database does not support write/remove permissions
1553         if ((0 == owner.compare(CLIENT_ID_SYSTEM)) && (permissionMask & Permission::REMOVE))
1554                 return CKM_API_ERROR_INPUT_PARAM;
1555
1556         // set permissions to the row owned by owner for accessor
1557         dbOp.database().setPermission(name, owner, accessor, permissionMask);
1558         dbOp.transaction().commit();
1559
1560         return CKM_API_SUCCESS;
1561 }
1562
1563 RawBuffer CKMLogic::setPermission(
1564         const Credentials &cred,
1565         const int msgID,
1566         const Name &name,
1567         const ClientId &owner,
1568         const ClientId &accessor,
1569         const PermissionMask permissionMask)
1570 {
1571         return SerializeMessage(msgID, tryRet([&] {
1572                 return setPermissionHelper(cred, name, owner, accessor, permissionMask);
1573         }));
1574 }
1575
1576 } // namespace CKM
1577