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