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