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