Fix indentation
[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(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 int loadAppKey(UserData &handler, const ClientId &owner, bool keyRequired = true)
195 {
196         if (!handler.crypto.haveKey(owner)) {
197                 RawBuffer wrappedDEK;
198                 auto wrappedDEKOptional = handler.database.getKey(owner);
199
200                 if (!wrappedDEKOptional) {
201                         if (keyRequired) {
202                                 LogError("No key for given owner in database");
203                                 return CKM_API_ERROR_DB_ERROR;
204                         }
205                         LogDebug("No Key in database found. Generating new one for client: " << owner);
206                         wrappedDEK = handler.keyProvider.generateDEK(owner);
207                         handler.database.saveKey(owner, wrappedDEK);
208                 } else {
209                         wrappedDEK = *wrappedDEKOptional;
210                 }
211
212                 handler.crypto.pushKey(owner, handler.keyProvider.getPureDEK(wrappedDEK));
213         }
214
215         return CKM_API_SUCCESS;
216 }
217
218 } // namespace
219
220 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
221 const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
222
223 CKMLogic::CKMLogic()
224 {
225         CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
226
227         m_accessControl.updateCCMode();
228 }
229
230 CKMLogic::~CKMLogic() {}
231
232 void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
233 {
234         auto &handle = m_userDataMap[user];
235
236         FileSystem fs(user);
237
238         auto wrappedDKEK = fs.getDKEK();
239
240         if (wrappedDKEK.empty()) {
241                 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
242                 fs.saveDKEK(wrappedDKEK);
243         }
244
245         handle.keyProvider = KeyProvider(wrappedDKEK, password);
246         if (!handle.keyProvider.isInitialized()) {
247                 handle.keyProvider.migrateDomainKEK(wrappedDKEK, password);
248                 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
249                 LogInfo("DKEK migrated");
250         }
251 }
252
253 void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
254 {
255         auto &handle = m_userDataMap[user];
256
257         FileSystem fs(user);
258         fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
259 }
260
261 void CKMLogic::migrateSecureStorageData(bool isAdminUser)
262 {
263         SsMigration::migrate(isAdminUser, [this](const std::string &name,
264                                                                                          const Crypto::Data &data,
265                                                                                          bool adminUserFlag) {
266                 LogInfo("Migrate data called with  name: " << name);
267                 auto ownerId = adminUserFlag ? CLIENT_ID_ADMIN_USER : CLIENT_ID_SYSTEM;
268                 auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
269
270                 int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
271                                                                                   PolicySerializable());
272
273                 if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
274                         LogWarning("Alias already exist for migrated name: " << name);
275                 else if (ret != CKM_API_SUCCESS)
276                         LogError("Failed to migrate secure-storage data. name: " << name <<
277                                          " ret: " << ret);
278         });
279 }
280
281 int CKMLogic::unlockDatabase(uid_t user, const Password &password)
282 {
283         if (0 < m_userDataMap.count(user) &&
284                         m_userDataMap[user].keyProvider.isInitialized())
285                 return CKM_API_SUCCESS;
286
287         int retCode = tryRet([&] {
288                 auto &handle = m_userDataMap[user];
289
290                 FileSystem fs(user);
291                 loadDKEKFile(user, password);
292
293                 auto wrappedDatabaseDEK = fs.getDBDEK();
294
295                 if (wrappedDatabaseDEK.empty()) {
296                         wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
297                         fs.saveDBDEK(wrappedDatabaseDEK);
298                 }
299
300                 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
301
302                 handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
303                 handle.crypto = CryptoLogic();
304
305                 if (!m_accessControl.isSystemService(user)) {
306                         // remove data of removed apps during locked state
307                         ClientIdVector removedApps = fs.clearRemovedsApps();
308
309                         for (auto &app : removedApps) {
310                                 handle.crypto.removeKey(app);
311                                 handle.database.deleteKey(app);
312                         }
313                 }
314
315                 if (user == SYSTEM_DB_UID && SsMigration::hasData())
316                         migrateSecureStorageData(false);
317                 else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
318                         migrateSecureStorageData(true);
319
320                 return CKM_API_SUCCESS;
321         });
322
323         if (CKM_API_SUCCESS != retCode)
324                 m_userDataMap.erase(user);
325
326         return retCode;
327 }
328
329 int CKMLogic::unlockSystemDB()
330 {
331         return unlockDatabase(SYSTEM_DB_UID, DEFAULT_UNLOCK_STRING);
332 }
333
334 UserData &CKMLogic::selectDatabase(const Credentials &cred,
335                                                                    const ClientId &owner)
336 {
337         // if user trying to access system service - check:
338         //    * if user database is unlocked [mandatory]
339         //    * if not - proceed with regular user database
340         //    * if explicit system database owner given -> switch to system DB
341         if (!m_accessControl.isSystemService(cred)) {
342                 if (0 == m_userDataMap.count(cred.clientUid))
343                         ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
344
345                 if (0 != owner.compare(CLIENT_ID_SYSTEM))
346                         return m_userDataMap[cred.clientUid];
347         }
348
349         // system database selected, modify the owner id
350         if (CKM_API_SUCCESS != unlockSystemDB())
351                 ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
352
353         return m_userDataMap[SYSTEM_DB_UID];
354 }
355
356 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
357 {
358         int retCode = CKM_API_SUCCESS;
359
360         if (!m_accessControl.isSystemService(user))
361                 retCode = unlockDatabase(user, password);
362         else // do not allow lock/unlock operations for system users
363                 retCode = CKM_API_ERROR_INPUT_PARAM;
364
365         return SerializeMessage(retCode);
366 }
367
368 RawBuffer CKMLogic::updateCCMode()
369 {
370         m_accessControl.updateCCMode();
371         return SerializeMessage(CKM_API_SUCCESS);
372 }
373
374 RawBuffer CKMLogic::lockUserKey(uid_t user)
375 {
376         int retCode = CKM_API_SUCCESS;
377
378         if (!m_accessControl.isSystemService(user))
379                 m_userDataMap.erase(user);
380         else // do not allow lock/unlock operations for system users
381                 retCode = CKM_API_ERROR_INPUT_PARAM;
382
383         return SerializeMessage(retCode);
384 }
385
386 RawBuffer CKMLogic::removeUserData(uid_t user)
387 {
388         if (m_accessControl.isSystemService(user))
389                 user = SYSTEM_DB_UID;
390
391         m_userDataMap.erase(user);
392
393         const int retCode = FileSystem(user).removeUserData()
394                 ? CKM_API_ERROR_FILE_SYSTEM
395                 : CKM_API_SUCCESS;
396
397         return SerializeMessage(retCode);
398 }
399
400 int CKMLogic::changeUserPasswordHelper(uid_t user,
401                                                                            const Password &oldPassword,
402                                                                            const Password &newPassword)
403 {
404         // do not allow to change system database password
405         if (m_accessControl.isSystemService(user))
406                 return CKM_API_ERROR_INPUT_PARAM;
407
408         loadDKEKFile(user, oldPassword);
409         saveDKEKFile(user, newPassword);
410
411         return CKM_API_SUCCESS;
412 }
413
414 RawBuffer CKMLogic::changeUserPassword(
415         uid_t user,
416         const Password &oldPassword,
417         const Password &newPassword)
418 {
419         return SerializeMessage(tryRet([&] {
420                 return changeUserPasswordHelper(user, oldPassword, newPassword);
421         }));
422 }
423
424 int CKMLogic::resetUserPasswordHelper(
425         uid_t user,
426         const Password &newPassword)
427 {
428         // do not allow to reset system database password
429         if (m_accessControl.isSystemService(user))
430                 return CKM_API_ERROR_INPUT_PARAM;
431
432         int retCode = CKM_API_SUCCESS;
433
434         if (0 == m_userDataMap.count(user)) {
435                 // Check if key exists. If exists we must return error
436                 FileSystem fs(user);
437                 auto wrappedDKEKMain = fs.getDKEK();
438
439                 if (!wrappedDKEKMain.empty())
440                         retCode = CKM_API_ERROR_BAD_REQUEST;
441         } else {
442                 saveDKEKFile(user, newPassword);
443         }
444
445         return retCode;
446 }
447
448 RawBuffer CKMLogic::resetUserPassword(
449         uid_t user,
450         const Password &newPassword)
451 {
452         return SerializeMessage(tryRet([&] {
453                 return resetUserPasswordHelper(user, newPassword);
454         }));
455 }
456
457 RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
458 {
459         return SerializeMessage(tryRet([&] {
460                 if (owner.empty())
461                         return CKM_API_ERROR_INPUT_PARAM;
462
463                 UidVector uids = FileSystem::getUIDsFromDBFile();
464
465                 for (auto userId : uids) {
466                         if (0 == m_userDataMap.count(userId)) {
467                                 FileSystem fs(userId);
468                                 fs.addRemovedApp(owner);
469                         } else {
470                                 auto &handle = m_userDataMap[userId];
471                                 handle.crypto.removeKey(owner);
472                                 handle.database.deleteKey(owner);
473                         }
474                 }
475
476                 return CKM_API_SUCCESS;
477         }));
478 }
479
480 int CKMLogic::checkSaveConditions(
481         const Credentials &accessorCred,
482         UserData &handler,
483         const Name &name,
484         const ClientId &owner)
485 {
486         // verify name and client are correct
487         if (!isNameValid(name) || !isClientValid(owner)) {
488                 LogDebug("Invalid parameter passed to key-manager");
489                 return CKM_API_ERROR_INPUT_PARAM;
490         }
491
492         // check if accessor is allowed to save owner's items
493         int access_ec = m_accessControl.canSave(accessorCred, owner);
494
495         if (access_ec != CKM_API_SUCCESS) {
496                 LogDebug("accessor " << accessorCred.client << " can not save rows owned by " <<
497                                  owner);
498                 return access_ec;
499         }
500
501         // check if not a duplicate
502         if (handler.database.isNameOwnerPresent(name, owner))
503                 return CKM_API_ERROR_DB_ALIAS_EXISTS;
504
505         // generate (if needed) and load the app key
506         loadAppKey(handler, owner, false);
507
508         return CKM_API_SUCCESS;
509 }
510
511 DB::Row CKMLogic::createEncryptedRow(
512         CryptoLogic &crypto,
513         const Name &name,
514         const ClientId &owner,
515         const Crypto::Data &data,
516         const Policy &policy,
517         const RawBuffer &hash)
518 {
519         Crypto::GStore &store = m_decider.getStore(data.type, policy);
520
521         // do not encrypt data with password during cc_mode on
522         Token token = store.import(data,
523                                                            m_accessControl.isCCMode() ? "" : policy.password,
524                                                            Crypto::EncryptionParams(), hash);
525         DB::Row row(std::move(token), name, owner,
526                                 static_cast<int>(policy.extractable));
527         crypto.encryptRow(row);
528         return row;
529 }
530
531 int CKMLogic::verifyAndSaveDataHelper(
532         const Credentials &cred,
533         const Name &name,
534         const ClientId &owner,
535         const Crypto::Data &data,
536         const PolicySerializable &policy)
537 {
538         return tryRet([&] {
539                 // check if data is correct
540                 Crypto::Data binaryData;
541                 int retCode = toBinaryData(data, binaryData);
542
543                 return retCode != CKM_API_SUCCESS
544                         ? retCode
545                         : saveDataHelper(cred, name, owner, binaryData, policy);
546         });
547 }
548
549 int CKMLogic::getKeyForService(
550         const Credentials &cred,
551         const Name &name,
552         const ClientId &owner,
553         const Password &pass,
554         Crypto::GObjShPtr &key)
555 {
556         return tryRet([&] {
557                 // Key is for internal service use. It won't be exported to the client
558                 Crypto::GObjUPtr obj;
559                 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, owner, pass, obj);
560                 if (retCode == CKM_API_SUCCESS)
561                         key = std::move(obj);
562
563                 return retCode;
564         });
565 }
566
567 RawBuffer CKMLogic::saveData(
568         const Credentials &cred,
569         int msgId,
570         const Name &name,
571         const ClientId &owner,
572         const Crypto::Data &data,
573         const PolicySerializable &policy)
574 {
575         int retCode = verifyAndSaveDataHelper(cred, name, owner, data, policy);
576         return SerializeMessage(msgId, retCode, data.type);
577 }
578
579 int CKMLogic::extractPKCS12Data(
580         CryptoLogic &crypto,
581         const Name &name,
582         const ClientId &owner,
583         const PKCS12Serializable &pkcs,
584         const PolicySerializable &keyPolicy,
585         const PolicySerializable &certPolicy,
586         DB::RowVector &output,
587         const Credentials &cred)
588 {
589         // private key is mandatory
590         auto key = pkcs.getKey();
591
592         if (!key) {
593                 LogError("Failed to get private key from pkcs");
594                 return CKM_API_ERROR_INVALID_FORMAT;
595         }
596
597         auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
598         if (digest.empty())
599                 return CKM_API_ERROR_HASH_ERROR;
600
601         Crypto::Data keyData(DataType(key->getType()), key->getDER());
602         int retCode = verifyBinaryData(keyData);
603
604         if (retCode != CKM_API_SUCCESS)
605                 return retCode;
606
607         output.push_back(createEncryptedRow(crypto, name, owner, keyData,
608                                                                                 keyPolicy, digest));
609
610         // certificate is mandatory
611         auto cert = pkcs.getCertificate();
612
613         if (!cert) {
614                 LogError("Failed to get certificate from pkcs");
615                 return CKM_API_ERROR_INVALID_FORMAT;
616         }
617
618         Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
619         retCode = verifyBinaryData(certData);
620
621         if (retCode != CKM_API_SUCCESS)
622                 return retCode;
623
624         output.push_back(createEncryptedRow(crypto, name, owner, certData,
625                                                                                 certPolicy, digest));
626
627         // CA cert chain
628         unsigned int cert_index = 0;
629
630         for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
631                 Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++),
632                                                                 ca->getDER());
633                 int retCode = verifyBinaryData(caCertData);
634
635                 if (retCode != CKM_API_SUCCESS)
636                         return retCode;
637
638                 output.push_back(createEncryptedRow(crypto, name, owner, caCertData,
639                                                                                         certPolicy, digest));
640         }
641
642         return CKM_API_SUCCESS;
643 }
644
645 RawBuffer CKMLogic::savePKCS12(
646         const Credentials &cred,
647         int msgId,
648         const Name &name,
649         const ClientId &owner,
650         const PKCS12Serializable &pkcs,
651         const PolicySerializable &keyPolicy,
652         const PolicySerializable &certPolicy)
653 {
654         return SerializeMessage(msgId, tryRet([&] {
655                 return saveDataHelper(cred, name, owner, pkcs, keyPolicy, certPolicy);
656         }));
657 }
658
659
660 int CKMLogic::removeDataHelper(
661         const Credentials &cred,
662         const Name &name,
663         const ClientId &owner)
664 {
665         auto &handler = selectDatabase(cred, owner);
666
667         if (!isNameValid(name) || !isClientValid(owner)) {
668                 LogDebug("Invalid owner or name format");
669                 return CKM_API_ERROR_INPUT_PARAM;
670         }
671
672         DB::Crypto::Transaction transaction(&handler.database);
673
674         // read and check permissions
675         PermissionMaskOptional permissionRowOpt =
676                 handler.database.getPermissionRow(name, owner, cred.client);
677         int retCode = m_accessControl.canDelete(cred,
678                                                                                         toPermissionMask(permissionRowOpt));
679
680         if (retCode != CKM_API_SUCCESS) {
681                 LogWarning("access control check result: " << retCode);
682                 return retCode;
683         }
684
685         // get all matching rows
686         DB::RowVector rows;
687         handler.database.getRows(name, owner, DataType::DB_FIRST,
688                                                          DataType::DB_LAST, rows);
689
690         if (rows.empty()) {
691                 LogDebug("No row for given name and owner");
692                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
693         }
694
695         // load app key if needed
696         retCode = loadAppKey(handler, rows.front().owner);
697
698         if (CKM_API_SUCCESS != retCode)
699                 return retCode;
700
701         // destroy it in store
702         for (auto &r : rows) {
703                 try {
704                         handler.crypto.decryptRow(Password(), r);
705                         m_decider.getStore(r).destroy(r);
706                 } catch (const Exc::AuthenticationFailed &) {
707                         LogDebug("Authentication failed when removing data. Ignored.");
708                 }
709         }
710
711         // delete row in db
712         handler.database.deleteRow(name, owner);
713         transaction.commit();
714
715         return CKM_API_SUCCESS;
716 }
717
718 RawBuffer CKMLogic::removeData(
719         const Credentials &cred,
720         int msgId,
721         const Name &name,
722         const ClientId &owner)
723 {
724         return SerializeMessage(msgId, tryRet([&] {
725                 return removeDataHelper(cred, name, owner);
726         }));
727 }
728
729
730 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
731                 const Name &name,
732                 const ClientId &owner,
733                 const DB::Row &row,
734                 bool exportFlag,
735                 DB::Crypto &database)
736 {
737         PermissionMaskOptional permissionRowOpt =
738                 database.getPermissionRow(name, owner, accessorCred.client);
739
740         if (exportFlag)
741                 return m_accessControl.canExport(accessorCred,
742                                                                                  row,
743                                                                                  toPermissionMask(permissionRowOpt));
744
745         return m_accessControl.canRead(accessorCred,
746                                                                    toPermissionMask(permissionRowOpt));
747 }
748
749 Crypto::GObjUPtr CKMLogic::rowToObject(
750         UserData &handler,
751         DB::Row row,
752         const Password &password,
753         const RawBuffer &hash)
754 {
755         Crypto::GStore &store = m_decider.getStore(row);
756
757         Password pass = m_accessControl.isCCMode() ? "" : password;
758
759         // decrypt row
760         Crypto::GObjUPtr obj;
761
762         if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
763                         CryptoLogic::ENCRYPTION_V2) {
764                 handler.crypto.decryptRow(Password(), row);
765
766                 obj = store.getObject(row, pass);
767         } else {
768                 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
769                 handler.crypto.decryptRow(pass, row);
770                 // destroy it in store
771                 store.destroy(row);
772
773                 // import it to store with new scheme: data -> pass(data)
774                 Token token = store.import(Crypto::Data(row.dataType, row.data),
775                                                                    pass,
776                                                                    Crypto::EncryptionParams(),
777                                                                    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, CLIENT_ID_SYSTEM),
1096                                                                                 dataType,
1097                                                                                 systemVector);
1098                 } else {
1099                         // user - lookup system, then client DB
1100                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, cred.client),
1101                                                                                 dataType,
1102                                                                                 systemVector);
1103
1104                         // private database
1105                         if (retCode == CKM_API_SUCCESS) {
1106                                 retCode = getDataListHelper(cred,
1107                                                                                         dataType,
1108                                                                                         userVector);
1109                         }
1110                 }
1111         }
1112
1113         if (retCode == CKM_API_SUCCESS) {
1114                 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
1115                                                            systemVector.end());
1116                 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
1117                                                            userVector.end());
1118         }
1119
1120         return SerializeMessage(msgId, retCode, dataType, ownerNameVector);
1121 }
1122
1123 int CKMLogic::importInitialData(
1124         const Name &name,
1125         const Crypto::Data &data,
1126         const Crypto::EncryptionParams &encParams,
1127         const Policy &policy)
1128 {
1129         try {
1130                 return tryRet([&] {
1131                         if (encParams.iv.empty() != encParams.tag.empty()) {
1132                                 LogError("Both iv and tag must be empty or set");
1133                                 return CKM_API_ERROR_INPUT_PARAM;
1134                         }
1135
1136                         // Inital values are always imported with root credentials. Client id is not important.
1137                         Credentials rootCred(0, "");
1138                         ClientId owner(CLIENT_ID_SYSTEM);
1139                         auto &handler = selectDatabase(rootCred, CLIENT_ID_SYSTEM);
1140
1141                         // check if save is possible
1142                         DB::Crypto::Transaction transaction(&handler.database);
1143                         int retCode = checkSaveConditions(rootCred, handler, name, CLIENT_ID_SYSTEM);
1144                         if (retCode != CKM_API_SUCCESS)
1145                                 return retCode;
1146
1147                         Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
1148
1149                         Token token;
1150
1151                         auto digest = CryptoLogic::makeHash(name, owner, rootCred.clientUid);
1152                         if (digest.empty())
1153                                 return CKM_API_ERROR_HASH_ERROR;
1154
1155                         if (encParams.iv.empty()) {
1156                                 // Data are not encrypted, let's try to verify them
1157                                 Crypto::Data binaryData;
1158
1159                                 if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
1160                                         return retCode;
1161
1162                                 token = store.import(binaryData,
1163                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1164                                                                          encParams, digest);
1165                         } else {
1166                                 token = store.import(data,
1167                                                                          m_accessControl.isCCMode() ? "" : policy.password,
1168                                                                          encParams, digest);
1169                         }
1170
1171                         DB::Row row(std::move(token), name, CLIENT_ID_SYSTEM,
1172                                                 static_cast<int>(policy.extractable));
1173                         handler.crypto.encryptRow(row);
1174
1175                         handler.database.saveRow(row);
1176                         transaction.commit();
1177
1178                         return CKM_API_SUCCESS;
1179                 });
1180         } catch (const std::exception &e) {
1181                 LogError("Std::exception: " << e.what());
1182                 return CKM_API_ERROR_SERVER_ERROR;
1183         }
1184 }
1185
1186 int CKMLogic::saveDataHelper(
1187         const Credentials &cred,
1188         const Name &name,
1189         const ClientId &owner,
1190         const Crypto::Data &data,
1191         const PolicySerializable &policy)
1192 {
1193         auto &handler = selectDatabase(cred, owner);
1194
1195         // check if save is possible
1196         DB::Crypto::Transaction transaction(&handler.database);
1197         int retCode = checkSaveConditions(cred, handler, name, owner);
1198         if (retCode != CKM_API_SUCCESS)
1199                 return retCode;
1200
1201         auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1202         if (digest.empty())
1203                 return CKM_API_ERROR_HASH_ERROR;
1204
1205         // save the data
1206         DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, owner,
1207                                                    data, policy, digest);
1208         handler.database.saveRow(encryptedRow);
1209
1210         transaction.commit();
1211         return CKM_API_SUCCESS;
1212 }
1213
1214 int CKMLogic::saveDataHelper(
1215         const Credentials &cred,
1216         const Name &name,
1217         const ClientId &owner,
1218         const PKCS12Serializable &pkcs,
1219         const PolicySerializable &keyPolicy,
1220         const PolicySerializable &certPolicy)
1221 {
1222         auto &handler = selectDatabase(cred, owner);
1223
1224         // check if save is possible
1225         DB::Crypto::Transaction transaction(&handler.database);
1226         int retCode = checkSaveConditions(cred, handler, name, owner);
1227         if (retCode != CKM_API_SUCCESS)
1228                 return retCode;
1229
1230         // extract and encrypt the data
1231         DB::RowVector encryptedRows;
1232         retCode = extractPKCS12Data(handler.crypto, name, owner, pkcs, keyPolicy,
1233                                                                 certPolicy, encryptedRows, cred);
1234
1235         if (retCode != CKM_API_SUCCESS)
1236                 return retCode;
1237
1238         // save the data
1239         handler.database.saveRows(name, owner, encryptedRows);
1240         transaction.commit();
1241
1242         return CKM_API_SUCCESS;
1243 }
1244
1245
1246 int CKMLogic::createKeyAESHelper(
1247         const Credentials &cred,
1248         const int size,
1249         const Name &name,
1250         const ClientId &owner,
1251         const PolicySerializable &policy)
1252 {
1253         auto &handler = selectDatabase(cred, owner);
1254
1255         // check if save is possible
1256         DB::Crypto::Transaction transaction(&handler.database);
1257         int retCode = checkSaveConditions(cred, handler, name, owner);
1258         if (retCode != CKM_API_SUCCESS)
1259                 return retCode;
1260
1261         auto digest = CryptoLogic::makeHash(name, owner, cred.clientUid);
1262         if (digest.empty())
1263                 return CKM_API_ERROR_HASH_ERROR;
1264
1265         // create key in store
1266         CryptoAlgorithm keyGenAlgorithm;
1267         keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1268         keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1269         Token key = m_decider.getStore(DataType::KEY_AES,
1270                                        policy).generateSKey(keyGenAlgorithm, policy.password, digest);
1271
1272         // save the data
1273         DB::Row row(std::move(key), name, owner,
1274                                 static_cast<int>(policy.extractable));
1275         handler.crypto.encryptRow(row);
1276
1277         handler.database.saveRow(row);
1278
1279         transaction.commit();
1280         return CKM_API_SUCCESS;
1281 }
1282
1283 int CKMLogic::createKeyPairHelper(
1284         const Credentials &cred,
1285         const CryptoAlgorithmSerializable &keyGenParams,
1286         const Name &namePrivate,
1287         const ClientId &ownerPrivate,
1288         const Name &namePublic,
1289         const ClientId &ownerPublic,
1290         const PolicySerializable &policyPrivate,
1291         const PolicySerializable &policyPublic)
1292 {
1293         auto &handlerPriv = selectDatabase(cred, ownerPrivate);
1294         auto &handlerPub = selectDatabase(cred, ownerPublic);
1295
1296         AlgoType keyType = AlgoType::RSA_GEN;
1297
1298         if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1299                 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1300
1301         const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType);
1302         if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end())
1303                 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1304         const DataTypePair& dt = dtIt->second;
1305
1306         if (policyPrivate.backend != policyPublic.backend)
1307                 ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1308
1309         bool exportable = policyPrivate.extractable || policyPublic.extractable;
1310         Policy lessRestricted(Password(), exportable, policyPrivate.backend);
1311
1312         auto digestPriv = CryptoLogic::makeHash(namePrivate, ownerPrivate, cred.clientUid);
1313         if (digestPriv.empty())
1314                 return CKM_API_ERROR_HASH_ERROR;
1315
1316         auto digestPub = CryptoLogic::makeHash(namePublic, ownerPublic, cred.clientUid);
1317         if (digestPub.empty())
1318                 return CKM_API_ERROR_HASH_ERROR;
1319
1320         TokenPair keys = m_decider.getStore(policyPrivate, dt.first, dt.second).generateAKey(keyGenParams,
1321                                          policyPrivate.password,
1322                                          policyPublic.password,
1323                                          digestPriv, digestPub);
1324
1325         DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
1326         // in case the same database is used for private and public - the second
1327         // transaction will not be executed
1328         DB::Crypto::Transaction transactionPub(&handlerPub.database);
1329
1330         int retCode;
1331         retCode = checkSaveConditions(cred, handlerPriv, namePrivate, ownerPrivate);
1332         if (CKM_API_SUCCESS != retCode)
1333                 return retCode;
1334
1335         retCode = checkSaveConditions(cred, handlerPub, namePublic, ownerPublic);
1336         if (CKM_API_SUCCESS != retCode)
1337                 return retCode;
1338
1339         // save the data
1340         DB::Row rowPrv(std::move(keys.first), namePrivate, ownerPrivate,
1341                                    static_cast<int>(policyPrivate.extractable));
1342         handlerPriv.crypto.encryptRow(rowPrv);
1343         handlerPriv.database.saveRow(rowPrv);
1344
1345         DB::Row rowPub(std::move(keys.second), namePublic, ownerPublic,
1346                                    static_cast<int>(policyPublic.extractable));
1347         handlerPub.crypto.encryptRow(rowPub);
1348         handlerPub.database.saveRow(rowPub);
1349
1350         transactionPub.commit();
1351         transactionPriv.commit();
1352         return CKM_API_SUCCESS;
1353 }
1354
1355 RawBuffer CKMLogic::createKeyPair(
1356         const Credentials &cred,
1357         int msgId,
1358         const CryptoAlgorithmSerializable &keyGenParams,
1359         const Name &namePrivate,
1360         const ClientId &ownerPrivate,
1361         const Name &namePublic,
1362         const ClientId &ownerPublic,
1363         const PolicySerializable &policyPrivate,
1364         const PolicySerializable &policyPublic)
1365 {
1366         return SerializeMessage(msgId, tryRet([&] {
1367                 return createKeyPairHelper(cred, keyGenParams, namePrivate, ownerPrivate,
1368                                            namePublic, ownerPublic, policyPrivate, policyPublic);
1369         }));
1370 }
1371
1372 RawBuffer CKMLogic::createKeyAES(
1373         const Credentials &cred,
1374         int msgId,
1375         const int size,
1376         const Name &name,
1377         const ClientId &owner,
1378         const PolicySerializable &policy)
1379 {
1380         int retCode = CKM_API_SUCCESS;
1381
1382         try {
1383                 retCode = tryRet([&] {
1384                         return createKeyAESHelper(cred, size, name, owner, policy);
1385                 });
1386         } catch (std::invalid_argument &e) {
1387                 LogDebug("invalid argument error: " << e.what());
1388                 retCode = CKM_API_ERROR_INPUT_PARAM;
1389         }
1390
1391         return SerializeMessage(msgId, retCode);
1392 }
1393
1394 int CKMLogic::readCertificateHelper(
1395         const Credentials &cred,
1396         const OwnerNameVector &ownerNameVector,
1397         CertificateImplVector &certVector)
1398 {
1399         for (auto &i : ownerNameVector) {
1400                 // certificates can't be protected with custom user password
1401                 Crypto::GObjUPtr obj;
1402                 int ec;
1403                 ec = readDataHelper(true,
1404                                                         cred,
1405                                                         DataType::CERTIFICATE,
1406                                                         i.second,
1407                                                         cred.effectiveOwner(i.first),
1408                                                         Password(),
1409                                                         obj);
1410
1411                 if (ec != CKM_API_SUCCESS)
1412                         return ec;
1413
1414                 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1415
1416                 // try to read chain certificates (if present)
1417                 Crypto::GObjUPtrVector caChainObjs;
1418                 ec = readDataHelper(true,
1419                                                         cred,
1420                                                         DataType::DB_CHAIN_FIRST,
1421                                                         i.second,
1422                                                         cred.effectiveOwner(i.first),
1423                                                         CKM::Password(),
1424                                                         caChainObjs);
1425
1426                 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1427                         return ec;
1428
1429                 for (auto &caCertObj : caChainObjs)
1430                         certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1431         }
1432
1433         return CKM_API_SUCCESS;
1434 }
1435
1436 int CKMLogic::getCertificateChainHelper(
1437         const CertificateImpl &cert,
1438         const RawBufferVector &untrustedCertificates,
1439         const RawBufferVector &trustedCertificates,
1440         bool useTrustedSystemCertificates,
1441         RawBufferVector &chainRawVector)
1442 {
1443         CertificateImplVector untrustedCertVector;
1444         CertificateImplVector trustedCertVector;
1445         CertificateImplVector chainVector;
1446
1447         if (cert.empty())
1448                 return CKM_API_ERROR_INPUT_PARAM;
1449
1450         for (auto &e : untrustedCertificates) {
1451                 CertificateImpl c(e, DataFormat::FORM_DER);
1452
1453                 if (c.empty())
1454                         return CKM_API_ERROR_INPUT_PARAM;
1455
1456                 untrustedCertVector.push_back(std::move(c));
1457         }
1458
1459         for (auto &e : trustedCertificates) {
1460                 CertificateImpl c(e, DataFormat::FORM_DER);
1461
1462                 if (c.empty())
1463                         return CKM_API_ERROR_INPUT_PARAM;
1464
1465                 trustedCertVector.push_back(std::move(c));
1466         }
1467
1468         CertificateStore store;
1469         int retCode = store.verifyCertificate(cert,
1470                                                                                   untrustedCertVector,
1471                                                                                   trustedCertVector,
1472                                                                                   useTrustedSystemCertificates,
1473                                                                                   m_accessControl.isCCMode(),
1474                                                                                   chainVector);
1475
1476         if (retCode != CKM_API_SUCCESS)
1477                 return retCode;
1478
1479         for (auto &e : chainVector)
1480                 chainRawVector.push_back(e.getDER());
1481
1482         return CKM_API_SUCCESS;
1483 }
1484
1485 int CKMLogic::getCertificateChainHelper(
1486         const Credentials &cred,
1487         const CertificateImpl &cert,
1488         const OwnerNameVector &untrusted,
1489         const OwnerNameVector &trusted,
1490         bool useTrustedSystemCertificates,
1491         RawBufferVector &chainRawVector)
1492 {
1493         CertificateImplVector untrustedCertVector;
1494         CertificateImplVector trustedCertVector;
1495         CertificateImplVector chainVector;
1496
1497         if (cert.empty())
1498                 return CKM_API_ERROR_INPUT_PARAM;
1499
1500         int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1501
1502         if (retCode != CKM_API_SUCCESS)
1503                 return retCode;
1504
1505         retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1506
1507         if (retCode != CKM_API_SUCCESS)
1508                 return retCode;
1509
1510         CertificateStore store;
1511         retCode = store.verifyCertificate(cert,
1512                                                                           untrustedCertVector,
1513                                                                           trustedCertVector,
1514                                                                           useTrustedSystemCertificates,
1515                                                                           m_accessControl.isCCMode(),
1516                                                                           chainVector);
1517
1518         if (retCode != CKM_API_SUCCESS)
1519                 return retCode;
1520
1521         for (auto &i : chainVector)
1522                 chainRawVector.push_back(i.getDER());
1523
1524         return CKM_API_SUCCESS;
1525 }
1526
1527 RawBuffer CKMLogic::getCertificateChain(
1528         const Credentials & /*cred*/,
1529         int msgId,
1530         const RawBuffer &certificate,
1531         const RawBufferVector &untrustedCertificates,
1532         const RawBufferVector &trustedCertificates,
1533         bool useTrustedSystemCertificates)
1534 {
1535         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1536         RawBufferVector chainRawVector;
1537         int retCode = CKM_API_ERROR_UNKNOWN;
1538
1539         try {
1540                 retCode = getCertificateChainHelper(cert,
1541                                                                                         untrustedCertificates,
1542                                                                                         trustedCertificates,
1543                                                                                         useTrustedSystemCertificates,
1544                                                                                         chainRawVector);
1545         } catch (const Exc::Exception &e) {
1546                 retCode = e.error();
1547         } catch (const std::exception &e) {
1548                 LogError("STD exception " << e.what());
1549                 retCode = CKM_API_ERROR_SERVER_ERROR;
1550         } catch (...) {
1551                 LogError("Unknown error.");
1552         }
1553
1554         return SerializeMessage(msgId, retCode, chainRawVector);
1555 }
1556
1557 RawBuffer CKMLogic::getCertificateChain(
1558         const Credentials &cred,
1559         int msgId,
1560         const RawBuffer &certificate,
1561         const OwnerNameVector &untrustedCertificates,
1562         const OwnerNameVector &trustedCertificates,
1563         bool useTrustedSystemCertificates)
1564 {
1565         int retCode = CKM_API_ERROR_UNKNOWN;
1566         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1567         RawBufferVector chainRawVector;
1568
1569         try {
1570                 retCode = getCertificateChainHelper(cred,
1571                                                                                         cert,
1572                                                                                         untrustedCertificates,
1573                                                                                         trustedCertificates,
1574                                                                                         useTrustedSystemCertificates,
1575                                                                                         chainRawVector);
1576         } catch (const Exc::Exception &e) {
1577                 retCode = e.error();
1578         } catch (const std::exception &e) {
1579                 LogError("STD exception " << e.what());
1580                 retCode = CKM_API_ERROR_SERVER_ERROR;
1581         } catch (...) {
1582                 LogError("Unknown error.");
1583         }
1584
1585         return SerializeMessage(msgId, retCode, chainRawVector);
1586 }
1587
1588 RawBuffer CKMLogic::createSignature(
1589         const Credentials &cred,
1590         int msgId,
1591         const Name &privateKeyName,
1592         const ClientId &owner,
1593         const Password &password,           // password for private_key
1594         const RawBuffer &message,
1595         const CryptoAlgorithm &cryptoAlg)
1596 {
1597         RawBuffer signature;
1598
1599         int retCode = CKM_API_SUCCESS;
1600
1601         try {
1602                 retCode = tryRet([&] {
1603                         Crypto::GObjUPtr obj;
1604                         int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1605                                                                                  owner, password, obj);
1606
1607                         if (retCode == CKM_API_SUCCESS)
1608                                 signature = obj->sign(cryptoAlg, message);
1609
1610                         return retCode;
1611                 });
1612         } catch (const std::exception &e) {
1613                 LogError("STD exception " << e.what());
1614                 retCode = CKM_API_ERROR_SERVER_ERROR;
1615         }
1616
1617         return SerializeMessage(msgId, retCode, signature);
1618 }
1619
1620 RawBuffer CKMLogic::verifySignature(
1621         const Credentials &cred,
1622         int msgId,
1623         const Name &publicKeyOrCertName,
1624         const ClientId &owner,
1625         const Password &password,           // password for public_key (optional)
1626         const RawBuffer &message,
1627         const RawBuffer &signature,
1628         const CryptoAlgorithm &params)
1629 {
1630         return SerializeMessage(msgId, tryRet([&] {
1631                 // try certificate first - looking for a public key.
1632                 // in case of PKCS, pub key from certificate will be found first
1633                 // rather than private key from the same PKCS.
1634                 Crypto::GObjUPtr obj;
1635                 int retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1636                                                                          publicKeyOrCertName, owner, password, obj);
1637
1638                 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1639                         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1640                                                                          publicKeyOrCertName, owner, password, obj);
1641
1642                 if (retCode == CKM_API_SUCCESS)
1643                         retCode = obj->verify(params, message, signature);
1644
1645                 return retCode;
1646         }));
1647 }
1648
1649 int CKMLogic::setPermissionHelper(
1650         const Credentials &cred,                // who's the client
1651         const Name &name,
1652         const ClientId &owner,                     // who's the owner
1653         const ClientId &accessor,             // who will get the access
1654         const PermissionMask permissionMask)
1655 {
1656         auto &handler = selectDatabase(cred, owner);
1657
1658         // we don't know the client
1659         if (cred.client.empty() || !isClientValid(cred.client))
1660                 return CKM_API_ERROR_INPUT_PARAM;
1661
1662         // verify name and owner are correct
1663         if (!isNameValid(name) || !isClientValid(owner) ||
1664                         !isClientValid(accessor))
1665                 return CKM_API_ERROR_INPUT_PARAM;
1666
1667         // currently we don't support modification of owner's permissions to his own rows
1668         if (owner == accessor)
1669                 return CKM_API_ERROR_INPUT_PARAM;
1670
1671         // system database does not support write/remove permissions
1672         if ((0 == owner.compare(CLIENT_ID_SYSTEM)) &&
1673                         (permissionMask & Permission::REMOVE))
1674                 return CKM_API_ERROR_INPUT_PARAM;
1675
1676         // can the client modify permissions to owner's row?
1677         int retCode = m_accessControl.canModify(cred, owner);
1678
1679         if (retCode != CKM_API_SUCCESS)
1680                 return retCode;
1681
1682         DB::Crypto::Transaction transaction(&handler.database);
1683
1684         if (!handler.database.isNameOwnerPresent(name, owner))
1685                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1686
1687         // set permissions to the row owned by owner for accessor
1688         handler.database.setPermission(name, owner, accessor, permissionMask);
1689         transaction.commit();
1690
1691         return CKM_API_SUCCESS;
1692 }
1693
1694 RawBuffer CKMLogic::setPermission(
1695         const Credentials &cred,
1696         const int msgID,
1697         const Name &name,
1698         const ClientId &owner,
1699         const ClientId &accessor,
1700         const PermissionMask permissionMask)
1701 {
1702         return SerializeMessage(msgID, tryRet([&] {
1703                 return setPermissionHelper(cred, name, owner, accessor, permissionMask);
1704         }));
1705 }
1706
1707 } // namespace CKM
1708