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