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