35e96135954f93a9d614a0f5b37565b55ee3cc69
[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         LogWarning("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         LogWarning("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     DB::Row row(name, label, static_cast<int>(policy.extractable), dataType, data, static_cast<int>(data.size()));
421     row.backendId = m_decider.chooseCryptoBackend(dataType, policy.extractable);
422
423     // do not encrypt data with password during cc_mode on
424     if(m_accessControl.isCCMode()) {
425         crypto.encryptRow("", row);
426     } else {
427         crypto.encryptRow(policy.password, row);
428     }
429     return row;
430 }
431
432 int CKMLogic::verifyBinaryData(DataType dataType, RawBuffer &input_data) const
433 {
434     RawBuffer dummy;
435     return toBinaryData(dataType, input_data, dummy);
436 }
437
438 int CKMLogic::toBinaryData(DataType dataType,
439                            const RawBuffer &input_data,
440                            RawBuffer &output_data) const
441 {
442     // verify the data integrity
443     if (dataType.isKey())
444     {
445         KeyShPtr output_key;
446         if(dataType.isSKey())
447             output_key = CKM::Key::createAES(input_data);
448         else
449             output_key = CKM::Key::create(input_data);
450         if(output_key.get() == NULL)
451         {
452             LogError("provided binary data is not valid key data");
453             return CKM_API_ERROR_INPUT_PARAM;
454         }
455         output_data = output_key->getDER();
456     }
457     else if (dataType.isCertificate() || dataType.isChainCert())
458     {
459         CertificateShPtr cert = CKM::Certificate::create(input_data, DataFormat::FORM_DER);
460         if(cert.get() == NULL)
461         {
462             LogError("provided binary data is not valid certificate data");
463             return CKM_API_ERROR_INPUT_PARAM;
464         }
465         output_data = cert->getDER();
466     }
467     else
468         output_data = input_data;
469     // TODO: add here BINARY_DATA verification, i.e: max size etc.
470     return CKM_API_SUCCESS;
471 }
472
473 int CKMLogic::verifyAndSaveDataHelper(
474     const Credentials &cred,
475     const Name &name,
476     const Label &label,
477     const RawBuffer &data,
478     DataType dataType,
479     const PolicySerializable &policy)
480 {
481     int retCode = CKM_API_ERROR_UNKNOWN;
482
483     try {
484         // check if data is correct
485         RawBuffer binaryData;
486         retCode = toBinaryData(dataType, data, binaryData);
487         if(retCode == CKM_API_SUCCESS)
488         {
489             retCode = saveDataHelper(cred, name, label, dataType, binaryData, policy);
490         }
491     } catch (const DB::Crypto::Exception::InternalError &e) {
492         LogError("DB::Crypto failed with message: " << e.GetMessage());
493         retCode = CKM_API_ERROR_DB_ERROR;
494     } catch (const DB::Crypto::Exception::TransactionError &e) {
495         LogError("DB::Crypto transaction failed with message " << e.GetMessage());
496         retCode = CKM_API_ERROR_DB_ERROR;
497     } catch (const Exc::Exception &e) {
498         retCode = e.error();
499     } catch (const CKM::Exception &e) {
500         LogError("CKM::Exception: " << e.GetMessage());
501         retCode = CKM_API_ERROR_SERVER_ERROR;
502     }
503     return retCode;
504 }
505
506 int CKMLogic::getKeyForService(
507         const Credentials &cred,
508         const Name &name,
509         const Label &label,
510         const Password &pass,
511         Crypto::GKeyShPtr &key)
512 {
513     DB::Row row;
514     try {
515         // Key is for internal service use. It won't be exported to the client
516         int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, label, pass, row);
517         if (retCode == CKM_API_SUCCESS)
518             key = m_decider.getStore(row).getKey(row);
519         return retCode;
520     } catch (const KeyProvider::Exception::Base &e) {
521         LogError("KeyProvider failed with error: " << e.GetMessage());
522         return CKM_API_ERROR_SERVER_ERROR;
523     } catch (const DB::Crypto::Exception::Base &e) {
524         LogError("DB::Crypto failed with message: " << e.GetMessage());
525         return CKM_API_ERROR_DB_ERROR;
526     } catch (const Exc::Exception &e) {
527         return e.error();
528     } catch (const CKM::Exception &e) {
529         LogError("CKM::Exception: " << e.GetMessage());
530         return CKM_API_ERROR_SERVER_ERROR;
531     }
532 }
533
534 RawBuffer CKMLogic::saveData(
535     const Credentials &cred,
536     int commandId,
537     const Name &name,
538     const Label &label,
539     const RawBuffer &data,
540     DataType dataType,
541     const PolicySerializable &policy)
542 {
543     int retCode = verifyAndSaveDataHelper(cred, name, label, data, dataType, policy);
544     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
545                                              commandId,
546                                              retCode,
547                                              static_cast<int>(dataType));
548     return response.Pop();
549 }
550
551 int CKMLogic::extractPKCS12Data(
552     CryptoLogic &crypto,
553     const Name &name,
554     const Label &ownerLabel,
555     const PKCS12Serializable &pkcs,
556     const PolicySerializable &keyPolicy,
557     const PolicySerializable &certPolicy,
558     DB::RowVector &output) const
559 {
560     // private key is mandatory
561     if( !pkcs.getKey() )
562         return CKM_API_ERROR_INVALID_FORMAT;
563     Key* keyPtr = pkcs.getKey().get();
564     DataType keyType = DataType(keyPtr->getType());
565     RawBuffer keyData = keyPtr->getDER();
566     int retCode = verifyBinaryData(keyType, keyData);
567     if(retCode != CKM_API_SUCCESS)
568         return retCode;
569     output.push_back(createEncryptedRow(crypto, name, ownerLabel, keyType, keyData, keyPolicy));
570
571     // certificate is mandatory
572     if( !pkcs.getCertificate() )
573         return CKM_API_ERROR_INVALID_FORMAT;
574     RawBuffer certData = pkcs.getCertificate().get()->getDER();
575     retCode = verifyBinaryData(DataType::CERTIFICATE, certData);
576     if(retCode != CKM_API_SUCCESS)
577         return retCode;
578     output.push_back(createEncryptedRow(crypto, name, ownerLabel, DataType::CERTIFICATE, certData, certPolicy));
579
580     // CA cert chain
581     unsigned int cert_index = 0;
582     for(const auto & ca : pkcs.getCaCertificateShPtrVector())
583     {
584         DataType chainDataType = DataType::getChainDatatype(cert_index ++);
585         RawBuffer caCertData = ca->getDER();
586         int retCode = verifyBinaryData(chainDataType, caCertData);
587         if(retCode != CKM_API_SUCCESS)
588             return retCode;
589
590         output.push_back(createEncryptedRow(crypto, name, ownerLabel, chainDataType, caCertData, certPolicy));
591     }
592
593     return CKM_API_SUCCESS;
594 }
595
596 RawBuffer CKMLogic::savePKCS12(
597     const Credentials &cred,
598     int commandId,
599     const Name &name,
600     const Label &label,
601     const PKCS12Serializable &pkcs,
602     const PolicySerializable &keyPolicy,
603     const PolicySerializable &certPolicy)
604 {
605     int retCode = CKM_API_ERROR_UNKNOWN;
606     try {
607         retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy);
608     } catch (const Exc::Exception &e) {
609         retCode = e.error();
610     } catch (const DB::Crypto::Exception::InternalError &e) {
611         LogError("DB::Crypto failed with message: " << e.GetMessage());
612         retCode = CKM_API_ERROR_DB_ERROR;
613     } catch (const DB::Crypto::Exception::TransactionError &e) {
614         LogError("DB::Crypto transaction failed with message " << e.GetMessage());
615         retCode = CKM_API_ERROR_DB_ERROR;
616     } catch (const CKM::Exception &e) {
617         LogError("CKM::Exception: " << e.GetMessage());
618         retCode = CKM_API_ERROR_SERVER_ERROR;
619     }
620
621     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE_PKCS12),
622                                              commandId,
623                                              retCode);
624     return response.Pop();
625 }
626
627
628 int CKMLogic::removeDataHelper(
629         const Credentials &cred,
630         const Name &name,
631         const Label &label)
632 {
633     auto &handler = selectDatabase(cred, label);
634
635     // use client label if not explicitly provided
636     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
637     if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
638         LogError("Invalid label or name format");
639         return CKM_API_ERROR_INPUT_PARAM;
640     }
641
642     DB::Crypto::Transaction transaction(&handler.database);
643
644     // read and check permissions
645     PermissionMaskOptional permissionRowOpt =
646             handler.database.getPermissionRow(name, ownerLabel, cred.smackLabel);
647     int retCode = m_accessControl.canDelete(cred,
648                         PermissionForLabel(cred.smackLabel, permissionRowOpt));
649     if(retCode != CKM_API_SUCCESS)
650     {
651         LogWarning("access control check result: " << retCode);
652         return retCode;
653     }
654
655     auto erased = handler.database.deleteRow(name, ownerLabel);
656     // check if the data existed or not
657     if(erased)
658         transaction.commit();
659     else {
660         LogError("No row for given name and label");
661         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
662     }
663
664     return CKM_API_SUCCESS;
665 }
666
667 RawBuffer CKMLogic::removeData(
668     const Credentials &cred,
669     int commandId,
670     const Name &name,
671     const Label &label)
672 {
673     int retCode = CKM_API_ERROR_UNKNOWN;
674
675     try
676     {
677         retCode = removeDataHelper(cred, name, label);
678     }
679     catch (const Exc::Exception &e)
680     {
681         retCode = e.error();
682     }
683     catch (const CKM::Exception &)
684     {
685         LogError("Error in deleting row!");
686         retCode = CKM_API_ERROR_DB_ERROR;
687     }
688
689     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
690                                              commandId,
691                                              retCode);
692     return response.Pop();
693 }
694
695 int CKMLogic::readSingleRow(const Name &name,
696                             const Label &ownerLabel,
697                             DataType dataType,
698                             DB::Crypto & database,
699                             DB::Row &row)
700 {
701     DB::Crypto::RowOptional row_optional;
702     if (dataType.isKey())
703     {
704         // read all key types
705         row_optional = database.getRow(name,
706                                          ownerLabel,
707                                          DataType::DB_KEY_FIRST,
708                                          DataType::DB_KEY_LAST);
709     } else {
710         // read anything else
711         row_optional = database.getRow(name,
712                                          ownerLabel,
713                                          dataType);
714     }
715
716     if(!row_optional) {
717         LogError("No row for given name, label and type");
718         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
719     } else {
720         row = *row_optional;
721     }
722
723     return CKM_API_SUCCESS;
724 }
725
726
727 int CKMLogic::readMultiRow(const Name &name,
728                            const Label &ownerLabel,
729                            DataType dataType,
730                            DB::Crypto & database,
731                            DB::RowVector &output)
732 {
733     if (dataType.isKey())
734     {
735         // read all key types
736         database.getRows(name,
737                           ownerLabel,
738                           DataType::DB_KEY_FIRST,
739                           DataType::DB_KEY_LAST,
740                           output);
741     }
742     else if (dataType.isChainCert())
743     {
744         // read all key types
745         database.getRows(name,
746                          ownerLabel,
747                          DataType::DB_CHAIN_FIRST,
748                          DataType::DB_CHAIN_LAST,
749                          output);
750     }
751     else
752     {
753         // read anything else
754         database.getRows(name,
755                          ownerLabel,
756                          dataType,
757                          output);
758     }
759
760     if(!output.size()) {
761         LogError("No row for given name, label and type");
762         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
763     }
764
765     return CKM_API_SUCCESS;
766 }
767
768 int CKMLogic::checkDataPermissionsHelper(const Credentials &cred,
769                                          const Name &name,
770                                          const Label &ownerLabel,
771                                          const Label &accessorLabel,
772                                          const DB::Row &row,
773                                          bool exportFlag,
774                                          DB::Crypto & database)
775 {
776     PermissionMaskOptional permissionRowOpt =
777             database.getPermissionRow(name, ownerLabel, accessorLabel);
778
779     if(exportFlag)
780         return m_accessControl.canExport(cred, row, PermissionForLabel(accessorLabel, permissionRowOpt));
781     return m_accessControl.canRead(cred, PermissionForLabel(accessorLabel, permissionRowOpt));
782 }
783
784 int CKMLogic::readDataHelper(
785     bool exportFlag,
786     const Credentials &cred,
787     DataType dataType,
788     const Name &name,
789     const Label &label,
790     const Password &password,
791     DB::RowVector &rows)
792 {
793     auto &handler = selectDatabase(cred, label);
794
795     // use client label if not explicitly provided
796     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
797
798     if (!isNameValid(name) || !isLabelValid(ownerLabel))
799         return CKM_API_ERROR_INPUT_PARAM;
800
801     // read rows
802     DB::Crypto::Transaction transaction(&handler.database);
803     int retCode = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
804     if(CKM_API_SUCCESS != retCode)
805         return retCode;
806
807     // all read rows belong to the same owner
808     DB::Row & firstRow = rows.at(0);
809
810     // check access rights
811     retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database);
812     if(CKM_API_SUCCESS != retCode)
813         return retCode;
814
815     // decrypt row
816     if (!handler.crypto.haveKey(firstRow.ownerLabel)) {
817         RawBuffer key;
818         auto key_optional = handler.database.getKey(firstRow.ownerLabel);
819         if(!key_optional) {
820             LogError("No key for given label in database");
821             return CKM_API_ERROR_DB_ERROR;
822         }
823         key = *key_optional;
824         key = handler.keyProvider.getPureDEK(key);
825         handler.crypto.pushKey(firstRow.ownerLabel, key);
826     }
827     for(auto &row : rows)
828         handler.crypto.decryptRow(password, row);
829
830     return CKM_API_SUCCESS;
831 }
832
833 int CKMLogic::readDataHelper(
834     bool exportFlag,
835     const Credentials &cred,
836     DataType dataType,
837     const Name &name,
838     const Label &label,
839     const Password &password,
840     DB::Row &row)
841 {
842     auto &handler = selectDatabase(cred, label);
843
844     // use client label if not explicitly provided
845     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
846
847     if (!isNameValid(name) || !isLabelValid(ownerLabel))
848         return CKM_API_ERROR_INPUT_PARAM;
849
850     // read row
851     DB::Crypto::Transaction transaction(&handler.database);
852     int retCode = readSingleRow(name, ownerLabel, dataType, handler.database, row);
853     if(CKM_API_SUCCESS != retCode)
854         return retCode;
855
856     // check access rights
857     retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
858     if(CKM_API_SUCCESS != retCode)
859         return retCode;
860
861     // decrypt row
862     if (!handler.crypto.haveKey(row.ownerLabel)) {
863         RawBuffer key;
864         auto key_optional = handler.database.getKey(row.ownerLabel);
865         if(!key_optional) {
866             LogError("No key for given label in database");
867             return CKM_API_ERROR_DB_ERROR;
868         }
869         key = *key_optional;
870         key = handler.keyProvider.getPureDEK(key);
871         handler.crypto.pushKey(row.ownerLabel, key);
872     }
873     handler.crypto.decryptRow(password, row);
874
875     return CKM_API_SUCCESS;
876 }
877
878 RawBuffer CKMLogic::getData(
879     const Credentials &cred,
880     int commandId,
881     DataType dataType,
882     const Name &name,
883     const Label &label,
884     const Password &password)
885 {
886     int retCode = CKM_API_SUCCESS;
887     DB::Row row;
888
889     try {
890         retCode = readDataHelper(true, cred, dataType, name, label, password, row);
891     } catch (const DB::Crypto::Exception::Base &e) {
892         LogError("DB::Crypto failed with message: " << e.GetMessage());
893         retCode = CKM_API_ERROR_DB_ERROR;
894     } catch (const Exc::Exception &e) {
895         retCode = e.error();
896     } catch (const CKM::Exception &e) {
897         LogError("CKM::Exception: " << e.GetMessage());
898         retCode = CKM_API_ERROR_SERVER_ERROR;
899     }
900
901     if (CKM_API_SUCCESS != retCode) {
902         row.data.clear();
903         row.dataType = dataType;
904     }
905
906     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
907                                              commandId,
908                                              retCode,
909                                              static_cast<int>(row.dataType),
910                                              row.data);
911     return response.Pop();
912 }
913
914 int CKMLogic::getPKCS12Helper(
915     const Credentials &cred,
916     const Name &name,
917     const Label &label,
918     const Password &keyPassword,
919     const Password &certPassword,
920     KeyShPtr & privKey,
921     CertificateShPtr & cert,
922     CertificateShPtrVector & caChain)
923 {
924     int retCode;
925
926     // read private key (mandatory)
927     DB::Row privKeyRow;
928     retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, label, keyPassword, privKeyRow);
929     if(retCode != CKM_API_SUCCESS)
930         return retCode;
931     privKey = CKM::Key::create(privKeyRow.data);
932
933     // read certificate (mandatory)
934     DB::Row certRow;
935     retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label, certPassword, certRow);
936     if(retCode != CKM_API_SUCCESS)
937         return retCode;
938     cert = CKM::Certificate::create(certRow.data, DataFormat::FORM_DER);
939
940     // read CA cert chain (optional)
941     DB::RowVector rawCaChain;
942     retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label, certPassword, rawCaChain);
943     if(retCode != CKM_API_SUCCESS &&
944        retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
945         return retCode;
946     for(auto &rawCaCert : rawCaChain)
947         caChain.push_back(CKM::Certificate::create(rawCaCert.data, DataFormat::FORM_DER));
948
949     // if anything found, return it
950     if(privKey || cert || caChain.size()>0)
951         retCode = CKM_API_SUCCESS;
952
953     return retCode;
954 }
955
956 RawBuffer CKMLogic::getPKCS12(
957         const Credentials &cred,
958         int commandId,
959         const Name &name,
960         const Label &label,
961         const Password &keyPassword,
962         const Password &certPassword)
963 {
964     int retCode = CKM_API_ERROR_UNKNOWN;
965
966     PKCS12Serializable output;
967     try {
968         KeyShPtr privKey;
969         CertificateShPtr cert;
970         CertificateShPtrVector caChain;
971         retCode = getPKCS12Helper(cred, name, label, keyPassword, certPassword, privKey, cert, caChain);
972
973         // prepare response
974         if(retCode == CKM_API_SUCCESS)
975             output = PKCS12Serializable(privKey, cert, caChain);
976     } catch (const DB::Crypto::Exception::Base &e) {
977         LogError("DB::Crypto failed with message: " << e.GetMessage());
978         retCode = CKM_API_ERROR_DB_ERROR;
979     } catch (const Exc::Exception &e) {
980         retCode = e.error();
981     } catch (const CKM::Exception &e) {
982         LogError("CKM::Exception: " << e.GetMessage());
983         retCode = CKM_API_ERROR_SERVER_ERROR;
984     }
985
986     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_PKCS12),
987                                              commandId,
988                                              retCode,
989                                              output);
990     return response.Pop();
991 }
992
993 int CKMLogic::getDataListHelper(const Credentials &cred,
994                                 const DataType dataType,
995                                 LabelNameVector &labelNameVector)
996 {
997     int retCode = CKM_API_ERROR_DB_LOCKED;
998     if (0 < m_userDataMap.count(cred.clientUid))
999     {
1000         auto &database = m_userDataMap[cred.clientUid].database;
1001
1002         Try {
1003             LabelNameVector tmpVector;
1004             if (dataType.isKey()) {
1005                 // list all key types
1006                 database.listNames(cred.smackLabel,
1007                                    tmpVector,
1008                                    DataType::DB_KEY_FIRST,
1009                                    DataType::DB_KEY_LAST);
1010             } else {
1011                 // list anything else
1012                 database.listNames(cred.smackLabel,
1013                                    tmpVector,
1014                                    dataType);
1015             }
1016             labelNameVector.insert(labelNameVector.end(), tmpVector.begin(), tmpVector.end());
1017             retCode = CKM_API_SUCCESS;
1018         }
1019         Catch (CKM::Exception) {
1020             LogError("Failed to get names");
1021             retCode = CKM_API_ERROR_DB_ERROR;
1022         }
1023     }
1024     return retCode;
1025 }
1026
1027 RawBuffer CKMLogic::getDataList(
1028     const Credentials &cred,
1029     int commandId,
1030     DataType dataType)
1031 {
1032     LabelNameVector systemVector;
1033     LabelNameVector userVector;
1034     LabelNameVector labelNameVector;
1035
1036     int retCode = unlockSystemDB();
1037     if (CKM_API_SUCCESS == retCode)
1038     {
1039         // system database
1040         if (m_accessControl.isSystemService(cred))
1041         {
1042             // lookup system DB
1043             retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
1044                                                     LABEL_SYSTEM_DB),
1045                                         dataType,
1046                                         systemVector);
1047         }
1048         else
1049         {
1050             // user - lookup system, then client DB
1051             retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
1052                                                     cred.smackLabel),
1053                                         dataType,
1054                                         systemVector);
1055
1056             // private database
1057             if(retCode == CKM_API_SUCCESS)
1058             {
1059                 retCode = getDataListHelper(cred,
1060                                             dataType,
1061                                             userVector);
1062             }
1063         }
1064     }
1065
1066     if(retCode == CKM_API_SUCCESS)
1067     {
1068         labelNameVector.insert(labelNameVector.end(), systemVector.begin(), systemVector.end());
1069         labelNameVector.insert(labelNameVector.end(), userVector.begin(), userVector.end());
1070     }
1071     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_LIST),
1072                                              commandId,
1073                                              retCode,
1074                                              static_cast<int>(dataType),
1075                                              labelNameVector);
1076     return response.Pop();
1077 }
1078
1079 int CKMLogic::saveDataHelper(
1080     const Credentials &cred,
1081     const Name &name,
1082     const Label &label,
1083     DataType dataType,
1084     const RawBuffer &data,
1085     const PolicySerializable &policy)
1086 {
1087     auto &handler = selectDatabase(cred, label);
1088
1089     // use client label if not explicitly provided
1090     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
1091     if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0)
1092         return CKM_API_ERROR_INPUT_PARAM;
1093
1094     // check if save is possible
1095     DB::Crypto::Transaction transaction(&handler.database);
1096     int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
1097     if(retCode != CKM_API_SUCCESS)
1098         return retCode;
1099
1100     // save the data
1101     DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, ownerLabel, dataType, data, policy);
1102     handler.database.saveRow(encryptedRow);
1103
1104     transaction.commit();
1105     return CKM_API_SUCCESS;
1106 }
1107
1108 int CKMLogic::saveDataHelper(
1109     const Credentials &cred,
1110     const Name &name,
1111     const Label &label,
1112     const PKCS12Serializable &pkcs,
1113     const PolicySerializable &keyPolicy,
1114     const PolicySerializable &certPolicy)
1115 {
1116     auto &handler = selectDatabase(cred, label);
1117
1118     // use client label if not explicitly provided
1119     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
1120     if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0)
1121         return CKM_API_ERROR_INPUT_PARAM;
1122
1123     // check if save is possible
1124     DB::Crypto::Transaction transaction(&handler.database);
1125     int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
1126     if(retCode != CKM_API_SUCCESS)
1127         return retCode;
1128
1129     // extract and encrypt the data
1130     DB::RowVector encryptedRows;
1131     retCode = extractPKCS12Data(handler.crypto, name, ownerLabel, pkcs, keyPolicy, certPolicy, encryptedRows);
1132     if(retCode != CKM_API_SUCCESS)
1133         return retCode;
1134
1135     // save the data
1136     handler.database.saveRows(name, ownerLabel, encryptedRows);
1137     transaction.commit();
1138
1139     return CKM_API_SUCCESS;
1140 }
1141
1142
1143 int CKMLogic::createKeyAESHelper(
1144     const Credentials &cred,
1145     const int size,
1146     const Name &name,
1147     const Label &label,
1148     const PolicySerializable &policy)
1149 {
1150     CryptoAlgorithm keyGenAlgorithm;
1151     keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1152     Token key = m_decider.getStore(DataType::KEY_AES, policy.extractable).generateSKey(keyGenAlgorithm);
1153
1154     return saveDataHelper(cred,
1155                           name,
1156                           label,
1157                           DataType::KEY_AES,
1158                           key.data,
1159                           policy);
1160 }
1161
1162
1163 int CKMLogic::createKeyPairHelper(
1164     const Credentials &cred,
1165     const CryptoAlgorithmSerializable & keyGenParams,
1166     const Name &namePrivate,
1167     const Label &labelPrivate,
1168     const Name &namePublic,
1169     const Label &labelPublic,
1170     const PolicySerializable &policyPrivate,
1171     const PolicySerializable &policyPublic)
1172 {
1173     auto &handlerPriv = selectDatabase(cred, labelPrivate);
1174     auto &handlerPub = selectDatabase(cred, labelPublic);
1175
1176     AlgoType keyType = AlgoType::RSA_GEN;
1177     if(!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1178         ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1179     DataType dt(keyType);
1180     if(!dt.isKey())
1181         ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1182
1183     bool exportable = policyPrivate.extractable || policyPublic.extractable;
1184     TokenPair keys = m_decider.getStore(dt, exportable).generateAKey(keyGenParams);
1185
1186     DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
1187     // in case the same database is used for private and public - the second
1188     // transaction will not be executed
1189     DB::Crypto::Transaction transactionPub(&handlerPub.database);
1190
1191     int retCode = saveDataHelper(cred,
1192                              namePrivate,
1193                              labelPrivate,
1194                              keys.first.dataType,
1195                              keys.first.data,
1196                              policyPrivate);
1197     if (CKM_API_SUCCESS != retCode)
1198         return retCode;
1199
1200     retCode = saveDataHelper(cred,
1201                              namePublic,
1202                              labelPublic,
1203                              keys.second.dataType,
1204                              keys.second.data,
1205                              policyPublic);
1206     if (CKM_API_SUCCESS != retCode)
1207         return retCode;
1208
1209     transactionPub.commit();
1210     transactionPriv.commit();
1211     return CKM_API_SUCCESS;
1212 }
1213
1214 RawBuffer CKMLogic::createKeyPair(
1215     const Credentials &cred,
1216     int commandId,
1217     const CryptoAlgorithmSerializable & keyGenParams,
1218     const Name &namePrivate,
1219     const Label &labelPrivate,
1220     const Name &namePublic,
1221     const Label &labelPublic,
1222     const PolicySerializable &policyPrivate,
1223     const PolicySerializable &policyPublic)
1224 {
1225     int retCode = CKM_API_SUCCESS;
1226
1227     try {
1228         retCode = createKeyPairHelper(
1229                         cred,
1230                         keyGenParams,
1231                         namePrivate,
1232                         labelPrivate,
1233                         namePublic,
1234                         labelPublic,
1235                         policyPrivate,
1236                         policyPublic);
1237     } catch(const Exc::Exception &e) {
1238         retCode = e.error();
1239     } catch (DB::Crypto::Exception::TransactionError &e) {
1240         LogDebug("DB::Crypto error: transaction error: " << e.GetMessage());
1241         retCode = CKM_API_ERROR_DB_ERROR;
1242     } catch (DB::Crypto::Exception::InternalError &e) {
1243         LogDebug("DB::Crypto internal error: " << e.GetMessage());
1244         retCode = CKM_API_ERROR_DB_ERROR;
1245     } catch (const CKM::Exception &e) {
1246         LogError("CKM::Exception: " << e.GetMessage());
1247         retCode = CKM_API_ERROR_SERVER_ERROR;
1248     }
1249
1250     return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_PAIR),
1251                                     commandId, retCode).Pop();
1252 }
1253
1254 RawBuffer CKMLogic::createKeyAES(
1255     const Credentials &cred,
1256     int commandId,
1257     const int size,
1258     const Name &name,
1259     const Label &label,
1260     const PolicySerializable &policy)
1261 {
1262     int retCode = CKM_API_SUCCESS;
1263
1264     try {
1265         retCode = createKeyAESHelper(cred, size, name, label, policy);
1266     } catch (const Exc::Exception &e) {
1267         retCode = e.error();
1268     } catch (std::invalid_argument &e) {
1269         LogDebug("invalid argument error: " << e.what());
1270         retCode = CKM_API_ERROR_INPUT_PARAM;
1271     } catch (DB::Crypto::Exception::TransactionError &e) {
1272         LogDebug("DB::Crypto error: transaction error: " << e.GetMessage());
1273         retCode = CKM_API_ERROR_DB_ERROR;
1274     } catch (DB::Crypto::Exception::InternalError &e) {
1275         LogDebug("DB::Crypto internal error: " << e.GetMessage());
1276         retCode = CKM_API_ERROR_DB_ERROR;
1277     } catch (const CKM::Exception &e) {
1278         LogError("CKM::Exception: " << e.GetMessage());
1279         retCode = CKM_API_ERROR_SERVER_ERROR;
1280     }
1281
1282     return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_AES),
1283                                     commandId, retCode).Pop();
1284 }
1285
1286 int CKMLogic::readCertificateHelper(
1287         const Credentials &cred,
1288         const LabelNameVector &labelNameVector,
1289         CertificateImplVector &certVector)
1290 {
1291     DB::Row row;
1292     for (auto &i: labelNameVector) {
1293         int ec = readDataHelper(false, cred, DataType::CERTIFICATE, i.second, i.first, Password(), row);
1294         if (ec != CKM_API_SUCCESS)
1295             return ec;
1296         certVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER));
1297
1298         // try to read chain certificates (if present)
1299         DB::RowVector rawCaChain;
1300         ec = readDataHelper(false, cred, DataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), rawCaChain);
1301         if(ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1302             return ec;
1303         for(auto &rawCaCert : rawCaChain)
1304             certVector.push_back(CertificateImpl(rawCaCert.data, DataFormat::FORM_DER));
1305     }
1306     return CKM_API_SUCCESS;
1307 }
1308
1309 int CKMLogic::getCertificateChainHelper(
1310         const CertificateImpl &cert,
1311         const RawBufferVector &untrustedCertificates,
1312         const RawBufferVector &trustedCertificates,
1313         bool useTrustedSystemCertificates,
1314         RawBufferVector &chainRawVector)
1315 {
1316     CertificateImplVector untrustedCertVector;
1317     CertificateImplVector trustedCertVector;
1318     CertificateImplVector chainVector;
1319
1320     if (cert.empty())
1321         return CKM_API_ERROR_INPUT_PARAM;
1322
1323     for (auto &e: untrustedCertificates)
1324         untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1325     for (auto &e: trustedCertificates)
1326         trustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1327
1328     CertificateStore store;
1329     int retCode = store.verifyCertificate(cert,
1330                                           untrustedCertVector,
1331                                           trustedCertVector,
1332                                           useTrustedSystemCertificates,
1333                                           m_accessControl.isCCMode(),
1334                                           chainVector);
1335     if (retCode != CKM_API_SUCCESS)
1336         return retCode;
1337
1338     for (auto &e : chainVector)
1339         chainRawVector.push_back(e.getDER());
1340     return CKM_API_SUCCESS;
1341 }
1342
1343 int CKMLogic::getCertificateChainHelper(
1344         const Credentials &cred,
1345         const CertificateImpl &cert,
1346         const LabelNameVector &untrusted,
1347         const LabelNameVector &trusted,
1348         bool useTrustedSystemCertificates,
1349         RawBufferVector &chainRawVector)
1350 {
1351     CertificateImplVector untrustedCertVector;
1352     CertificateImplVector trustedCertVector;
1353     CertificateImplVector chainVector;
1354     DB::Row row;
1355
1356     if (cert.empty())
1357         return CKM_API_ERROR_INPUT_PARAM;
1358
1359     int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1360     if (retCode != CKM_API_SUCCESS)
1361         return retCode;
1362     retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1363     if (retCode != CKM_API_SUCCESS)
1364         return retCode;
1365
1366     CertificateStore store;
1367     retCode = store.verifyCertificate(cert,
1368                                       untrustedCertVector,
1369                                       trustedCertVector,
1370                                       useTrustedSystemCertificates,
1371                                       m_accessControl.isCCMode(),
1372                                       chainVector);
1373     if (retCode != CKM_API_SUCCESS)
1374         return retCode;
1375
1376     for (auto &i: chainVector)
1377         chainRawVector.push_back(i.getDER());
1378
1379     return CKM_API_SUCCESS;
1380 }
1381
1382 RawBuffer CKMLogic::getCertificateChain(
1383     const Credentials & /*cred*/,
1384     int commandId,
1385     const RawBuffer &certificate,
1386     const RawBufferVector &untrustedCertificates,
1387     const RawBufferVector &trustedCertificates,
1388     bool useTrustedSystemCertificates)
1389 {
1390     CertificateImpl cert(certificate, DataFormat::FORM_DER);
1391     RawBufferVector chainRawVector;
1392     int retCode = CKM_API_ERROR_UNKNOWN;
1393     try {
1394         retCode = getCertificateChainHelper(cert,
1395                                             untrustedCertificates,
1396                                             trustedCertificates,
1397                                             useTrustedSystemCertificates,
1398                                             chainRawVector);
1399     } catch (const Exc::Exception &e) {
1400         retCode = e.error();
1401     } catch (const DB::Crypto::Exception::Base &e) {
1402         LogError("DB::Crypto failed with message: " << e.GetMessage());
1403         retCode = CKM_API_ERROR_DB_ERROR;
1404     } catch (const std::exception& e) {
1405         LogError("STD exception " << e.what());
1406         retCode = CKM_API_ERROR_SERVER_ERROR;
1407     } catch (...) {
1408         LogError("Unknown error.");
1409     }
1410
1411     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_CERT),
1412                                              commandId,
1413                                              retCode,
1414                                              chainRawVector);
1415     return response.Pop();
1416 }
1417
1418 RawBuffer CKMLogic::getCertificateChain(
1419     const Credentials &cred,
1420     int commandId,
1421     const RawBuffer &certificate,
1422     const LabelNameVector &untrustedCertificates,
1423     const LabelNameVector &trustedCertificates,
1424     bool useTrustedSystemCertificates)
1425 {
1426     int retCode = CKM_API_ERROR_UNKNOWN;
1427     CertificateImpl cert(certificate, DataFormat::FORM_DER);
1428     RawBufferVector chainRawVector;
1429     try {
1430         retCode = getCertificateChainHelper(cred,
1431                                             cert,
1432                                             untrustedCertificates,
1433                                             trustedCertificates,
1434                                             useTrustedSystemCertificates,
1435                                             chainRawVector);
1436     } catch (const DB::Crypto::Exception::Base &e) {
1437         LogError("DB::Crypto failed with message: " << e.GetMessage());
1438         retCode = CKM_API_ERROR_DB_ERROR;
1439     } catch (const Exc::Exception &e) {
1440         retCode = e.error();
1441     } catch (const std::exception& e) {
1442         LogError("STD exception " << e.what());
1443         retCode = CKM_API_ERROR_SERVER_ERROR;
1444     } catch (...) {
1445         LogError("Unknown error.");
1446     }
1447
1448     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_ALIAS),
1449                                              commandId,
1450                                              retCode,
1451                                              chainRawVector);
1452     return response.Pop();
1453 }
1454
1455 RawBuffer CKMLogic::createSignature(
1456         const Credentials &cred,
1457         int commandId,
1458         const Name &privateKeyName,
1459         const Label & ownerLabel,
1460         const Password &password,           // password for private_key
1461         const RawBuffer &message,
1462         const HashAlgorithm hash,
1463         const RSAPaddingAlgorithm padding)
1464 {
1465     DB::Row row;
1466     RawBuffer signature;
1467     CryptoAlgorithm cryptoAlg;
1468     cryptoAlg.setParam(ParamName::SV_HASH_ALGO, hash);
1469     cryptoAlg.setParam(ParamName::SV_RSA_PADDING, padding);
1470
1471     int retCode = CKM_API_SUCCESS;
1472
1473     try {
1474         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, row);
1475         if(retCode == CKM_API_SUCCESS) {
1476             signature = m_decider.getStore(row).getKey(row)->sign(cryptoAlg, message);
1477         }
1478     } catch (const DB::Crypto::Exception::Base &e) {
1479         LogError("DB::Crypto failed with message: " << e.GetMessage());
1480         retCode = CKM_API_ERROR_DB_ERROR;
1481     } catch (const Exc::Exception &e) {
1482         retCode = e.error();
1483     } catch (const CKM::Exception &e) {
1484         LogError("Unknown CKM::Exception: " << e.GetMessage());
1485         retCode = CKM_API_ERROR_SERVER_ERROR;
1486     }
1487
1488     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_SIGNATURE),
1489                                              commandId,
1490                                              retCode,
1491                                              signature);
1492     return response.Pop();
1493 }
1494
1495 RawBuffer CKMLogic::verifySignature(
1496         const Credentials &cred,
1497         int commandId,
1498         const Name &publicKeyOrCertName,
1499         const Label & ownerLabel,
1500         const Password &password,           // password for public_key (optional)
1501         const RawBuffer &message,
1502         const RawBuffer &signature,
1503         const HashAlgorithm hash,
1504         const RSAPaddingAlgorithm padding)
1505 {
1506     int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
1507
1508     try {
1509         DB::Row row;
1510
1511         CryptoAlgorithm params;
1512         params.setParam(ParamName::SV_HASH_ALGO, hash);
1513         params.setParam(ParamName::SV_RSA_PADDING, padding);
1514
1515         // try certificate first - looking for a public key.
1516         // in case of PKCS, pub key from certificate will be found first
1517         // rather than private key from the same PKCS.
1518         retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, row);
1519         if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
1520             retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, row);
1521         }
1522
1523         if (retCode == CKM_API_SUCCESS) {
1524             retCode = m_decider.getStore(row).getKey(row)->verify(params, message, signature);
1525         }
1526     } catch (const Exc::Exception &e) {
1527         retCode = e.error();
1528     } catch (const DB::Crypto::Exception::Base &e) {
1529         LogError("DB::Crypto failed with message: " << e.GetMessage());
1530         retCode = CKM_API_ERROR_DB_ERROR;
1531     } catch (const CKM::Exception &e) {
1532         LogError("Unknown CKM::Exception: " << e.GetMessage());
1533         retCode = CKM_API_ERROR_SERVER_ERROR;
1534     }
1535
1536     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::VERIFY_SIGNATURE),
1537                                              commandId,
1538                                              retCode);
1539     return response.Pop();
1540 }
1541
1542 int CKMLogic::setPermissionHelper(
1543         const Credentials &cred,                // who's the client
1544         const Name &name,
1545         const Label &label,                     // who's the owner
1546         const Label &accessorLabel,             // who will get the access
1547         const PermissionMask permissionMask)
1548 {
1549     auto &handler = selectDatabase(cred, label);
1550
1551     // we don't know the client
1552     if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel))
1553         return CKM_API_ERROR_INPUT_PARAM;
1554
1555     // use client label if not explicitly provided
1556     const Label& ownerLabel = label.empty() ? cred.smackLabel : label;
1557
1558     // verify name and label are correct
1559     if (!isNameValid(name) || !isLabelValid(ownerLabel) || !isLabelValid(accessorLabel))
1560         return CKM_API_ERROR_INPUT_PARAM;
1561
1562     // currently we don't support modification of owner's permissions to his own rows
1563     if (ownerLabel==accessorLabel)
1564         return CKM_API_ERROR_INPUT_PARAM;
1565
1566     // system database does not support write/remove permissions
1567     if ((0 == ownerLabel.compare(LABEL_SYSTEM_DB)) &&
1568         (permissionMask & Permission::REMOVE))
1569         return CKM_API_ERROR_INPUT_PARAM;
1570
1571     // can the client modify permissions to owner's row?
1572     int retCode = m_accessControl.canModify(cred, ownerLabel);
1573     if(retCode != CKM_API_SUCCESS)
1574         return retCode;
1575
1576     DB::Crypto::Transaction transaction(&handler.database);
1577
1578     if( !handler.database.isNameLabelPresent(name, ownerLabel) )
1579         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1580
1581     // removing non-existing permissions: fail
1582     if(permissionMask == Permission::NONE)
1583     {
1584         if(!handler.database.getPermissionRow(name, ownerLabel, accessorLabel))
1585             return CKM_API_ERROR_INPUT_PARAM;
1586     }
1587
1588     // set permissions to the row owned by ownerLabel for accessorLabel
1589     handler.database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
1590     transaction.commit();
1591
1592     return CKM_API_SUCCESS;
1593 }
1594
1595 RawBuffer CKMLogic::setPermission(
1596         const Credentials &cred,
1597         const int command,
1598         const int msgID,
1599         const Name &name,
1600         const Label &label,
1601         const Label &accessorLabel,
1602         const PermissionMask permissionMask)
1603 {
1604     int retCode;
1605     Try {
1606         retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
1607     } catch (const Exc::Exception &e) {
1608         retCode = e.error();
1609     } Catch (CKM::Exception) {
1610         LogError("Error in set row!");
1611         retCode = CKM_API_ERROR_DB_ERROR;
1612     }
1613
1614     return MessageBuffer::Serialize(command, msgID, retCode).Pop();
1615 }
1616
1617 } // namespace CKM
1618