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