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