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