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