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