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