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