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