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