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