Modify encryption scheme
[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 = readDataHelper(false, cred, DataType::CERTIFICATE, i.second, i.first, Password(), obj);
1387         if (ec != CKM_API_SUCCESS)
1388             return ec;
1389
1390         certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1391
1392         // try to read chain certificates (if present)
1393         Crypto::GObjUPtrVector caChainObjs;
1394         ec = readDataHelper(false, cred, DataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), caChainObjs);
1395         if(ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1396             return ec;
1397         for(auto &caCertObj : caChainObjs)
1398             certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1399     }
1400     return CKM_API_SUCCESS;
1401 }
1402
1403 int CKMLogic::getCertificateChainHelper(
1404         const CertificateImpl &cert,
1405         const RawBufferVector &untrustedCertificates,
1406         const RawBufferVector &trustedCertificates,
1407         bool useTrustedSystemCertificates,
1408         RawBufferVector &chainRawVector)
1409 {
1410     CertificateImplVector untrustedCertVector;
1411     CertificateImplVector trustedCertVector;
1412     CertificateImplVector chainVector;
1413
1414     if (cert.empty())
1415         return CKM_API_ERROR_INPUT_PARAM;
1416
1417     for (auto &e: untrustedCertificates) {
1418         CertificateImpl c(e, DataFormat::FORM_DER);
1419         if(c.empty())
1420             return CKM_API_ERROR_INPUT_PARAM;
1421         untrustedCertVector.push_back(std::move(c));
1422     }
1423     for (auto &e: trustedCertificates) {
1424         CertificateImpl c(e, DataFormat::FORM_DER);
1425         if(c.empty())
1426             return CKM_API_ERROR_INPUT_PARAM;
1427         trustedCertVector.push_back(std::move(c));
1428     }
1429
1430     CertificateStore store;
1431     int retCode = store.verifyCertificate(cert,
1432                                           untrustedCertVector,
1433                                           trustedCertVector,
1434                                           useTrustedSystemCertificates,
1435                                           m_accessControl.isCCMode(),
1436                                           chainVector);
1437     if (retCode != CKM_API_SUCCESS)
1438         return retCode;
1439
1440     for (auto &e : chainVector)
1441         chainRawVector.push_back(e.getDER());
1442     return CKM_API_SUCCESS;
1443 }
1444
1445 int CKMLogic::getCertificateChainHelper(
1446         const Credentials &cred,
1447         const CertificateImpl &cert,
1448         const LabelNameVector &untrusted,
1449         const LabelNameVector &trusted,
1450         bool useTrustedSystemCertificates,
1451         RawBufferVector &chainRawVector)
1452 {
1453     CertificateImplVector untrustedCertVector;
1454     CertificateImplVector trustedCertVector;
1455     CertificateImplVector chainVector;
1456     DB::Row row;
1457
1458     if (cert.empty())
1459         return CKM_API_ERROR_INPUT_PARAM;
1460
1461     int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1462     if (retCode != CKM_API_SUCCESS)
1463         return retCode;
1464     retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1465     if (retCode != CKM_API_SUCCESS)
1466         return retCode;
1467
1468     CertificateStore store;
1469     retCode = store.verifyCertificate(cert,
1470                                       untrustedCertVector,
1471                                       trustedCertVector,
1472                                       useTrustedSystemCertificates,
1473                                       m_accessControl.isCCMode(),
1474                                       chainVector);
1475     if (retCode != CKM_API_SUCCESS)
1476         return retCode;
1477
1478     for (auto &i: chainVector)
1479         chainRawVector.push_back(i.getDER());
1480
1481     return CKM_API_SUCCESS;
1482 }
1483
1484 RawBuffer CKMLogic::getCertificateChain(
1485     const Credentials & /*cred*/,
1486     int commandId,
1487     const RawBuffer &certificate,
1488     const RawBufferVector &untrustedCertificates,
1489     const RawBufferVector &trustedCertificates,
1490     bool useTrustedSystemCertificates)
1491 {
1492     CertificateImpl cert(certificate, DataFormat::FORM_DER);
1493     RawBufferVector chainRawVector;
1494     int retCode = CKM_API_ERROR_UNKNOWN;
1495     try {
1496         retCode = getCertificateChainHelper(cert,
1497                                             untrustedCertificates,
1498                                             trustedCertificates,
1499                                             useTrustedSystemCertificates,
1500                                             chainRawVector);
1501     } catch (const Exc::Exception &e) {
1502         retCode = e.error();
1503     } catch (const DB::Crypto::Exception::Base &e) {
1504         LogError("DB::Crypto failed with message: " << e.GetMessage());
1505         retCode = CKM_API_ERROR_DB_ERROR;
1506     } catch (const std::exception& e) {
1507         LogError("STD exception " << e.what());
1508         retCode = CKM_API_ERROR_SERVER_ERROR;
1509     } catch (...) {
1510         LogError("Unknown error.");
1511     }
1512
1513     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_CERT),
1514                                              commandId,
1515                                              retCode,
1516                                              chainRawVector);
1517     return response.Pop();
1518 }
1519
1520 RawBuffer CKMLogic::getCertificateChain(
1521     const Credentials &cred,
1522     int commandId,
1523     const RawBuffer &certificate,
1524     const LabelNameVector &untrustedCertificates,
1525     const LabelNameVector &trustedCertificates,
1526     bool useTrustedSystemCertificates)
1527 {
1528     int retCode = CKM_API_ERROR_UNKNOWN;
1529     CertificateImpl cert(certificate, DataFormat::FORM_DER);
1530     RawBufferVector chainRawVector;
1531     try {
1532         retCode = getCertificateChainHelper(cred,
1533                                             cert,
1534                                             untrustedCertificates,
1535                                             trustedCertificates,
1536                                             useTrustedSystemCertificates,
1537                                             chainRawVector);
1538     } catch (const DB::Crypto::Exception::Base &e) {
1539         LogError("DB::Crypto failed with message: " << e.GetMessage());
1540         retCode = CKM_API_ERROR_DB_ERROR;
1541     } catch (const Exc::Exception &e) {
1542         retCode = e.error();
1543     } catch (const std::exception& e) {
1544         LogError("STD exception " << e.what());
1545         retCode = CKM_API_ERROR_SERVER_ERROR;
1546     } catch (...) {
1547         LogError("Unknown error.");
1548     }
1549
1550     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_ALIAS),
1551                                              commandId,
1552                                              retCode,
1553                                              chainRawVector);
1554     return response.Pop();
1555 }
1556
1557 RawBuffer CKMLogic::createSignature(
1558         const Credentials &cred,
1559         int commandId,
1560         const Name &privateKeyName,
1561         const Label & ownerLabel,
1562         const Password &password,           // password for private_key
1563         const RawBuffer &message,
1564         const HashAlgorithm hash,
1565         const RSAPaddingAlgorithm padding)
1566 {
1567     DB::Row row;
1568     RawBuffer signature;
1569     CryptoAlgorithm cryptoAlg;
1570     cryptoAlg.setParam(ParamName::SV_HASH_ALGO, hash);
1571     cryptoAlg.setParam(ParamName::SV_RSA_PADDING, padding);
1572
1573     int retCode = CKM_API_SUCCESS;
1574
1575     try {
1576         Crypto::GObjUPtr obj;
1577         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, obj);
1578         if(retCode == CKM_API_SUCCESS) {
1579             signature = obj->sign(cryptoAlg, message);
1580         }
1581     } catch (const DB::Crypto::Exception::Base &e) {
1582         LogError("DB::Crypto failed with message: " << e.GetMessage());
1583         retCode = CKM_API_ERROR_DB_ERROR;
1584     } catch (const Exc::Exception &e) {
1585         retCode = e.error();
1586     } catch (const CKM::Exception &e) {
1587         LogError("Unknown CKM::Exception: " << e.GetMessage());
1588         retCode = CKM_API_ERROR_SERVER_ERROR;
1589     }
1590
1591     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_SIGNATURE),
1592                                              commandId,
1593                                              retCode,
1594                                              signature);
1595     return response.Pop();
1596 }
1597
1598 RawBuffer CKMLogic::verifySignature(
1599         const Credentials &cred,
1600         int commandId,
1601         const Name &publicKeyOrCertName,
1602         const Label & ownerLabel,
1603         const Password &password,           // password for public_key (optional)
1604         const RawBuffer &message,
1605         const RawBuffer &signature,
1606         const HashAlgorithm hash,
1607         const RSAPaddingAlgorithm padding)
1608 {
1609     int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
1610
1611     try {
1612         DB::Row row;
1613
1614         CryptoAlgorithm params;
1615         params.setParam(ParamName::SV_HASH_ALGO, hash);
1616         params.setParam(ParamName::SV_RSA_PADDING, padding);
1617
1618         // try certificate first - looking for a public key.
1619         // in case of PKCS, pub key from certificate will be found first
1620         // rather than private key from the same PKCS.
1621         Crypto::GObjUPtr obj;
1622         retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, obj);
1623         if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
1624             retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, obj);
1625         }
1626
1627         if (retCode == CKM_API_SUCCESS) {
1628             retCode = obj->verify(params, message, signature);
1629         }
1630     } catch (const Exc::Exception &e) {
1631         retCode = e.error();
1632     } catch (const DB::Crypto::Exception::Base &e) {
1633         LogError("DB::Crypto failed with message: " << e.GetMessage());
1634         retCode = CKM_API_ERROR_DB_ERROR;
1635     } catch (const CKM::Exception &e) {
1636         LogError("Unknown CKM::Exception: " << e.GetMessage());
1637         retCode = CKM_API_ERROR_SERVER_ERROR;
1638     }
1639
1640     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::VERIFY_SIGNATURE),
1641                                              commandId,
1642                                              retCode);
1643     return response.Pop();
1644 }
1645
1646 int CKMLogic::setPermissionHelper(
1647         const Credentials &cred,                // who's the client
1648         const Name &name,
1649         const Label &label,                     // who's the owner
1650         const Label &accessorLabel,             // who will get the access
1651         const PermissionMask permissionMask)
1652 {
1653     auto &handler = selectDatabase(cred, label);
1654
1655     // we don't know the client
1656     if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel))
1657         return CKM_API_ERROR_INPUT_PARAM;
1658
1659     // use client label if not explicitly provided
1660     const Label& ownerLabel = label.empty() ? cred.smackLabel : label;
1661
1662     // verify name and label are correct
1663     if (!isNameValid(name) || !isLabelValid(ownerLabel) || !isLabelValid(accessorLabel))
1664         return CKM_API_ERROR_INPUT_PARAM;
1665
1666     // currently we don't support modification of owner's permissions to his own rows
1667     if (ownerLabel==accessorLabel)
1668         return CKM_API_ERROR_INPUT_PARAM;
1669
1670     // system database does not support write/remove permissions
1671     if ((0 == ownerLabel.compare(OWNER_ID_SYSTEM)) &&
1672         (permissionMask & Permission::REMOVE))
1673         return CKM_API_ERROR_INPUT_PARAM;
1674
1675     // can the client modify permissions to owner's row?
1676     int retCode = m_accessControl.canModify(cred, ownerLabel);
1677     if(retCode != CKM_API_SUCCESS)
1678         return retCode;
1679
1680     DB::Crypto::Transaction transaction(&handler.database);
1681
1682     if( !handler.database.isNameLabelPresent(name, ownerLabel) )
1683         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1684
1685     // removing non-existing permissions: fail
1686     if(permissionMask == Permission::NONE)
1687     {
1688         if(!handler.database.getPermissionRow(name, ownerLabel, accessorLabel))
1689             return CKM_API_ERROR_INPUT_PARAM;
1690     }
1691
1692     // set permissions to the row owned by ownerLabel for accessorLabel
1693     handler.database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
1694     transaction.commit();
1695
1696     return CKM_API_SUCCESS;
1697 }
1698
1699 RawBuffer CKMLogic::setPermission(
1700         const Credentials &cred,
1701         const int command,
1702         const int msgID,
1703         const Name &name,
1704         const Label &label,
1705         const Label &accessorLabel,
1706         const PermissionMask permissionMask)
1707 {
1708     int retCode;
1709     Try {
1710         retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
1711     } catch (const Exc::Exception &e) {
1712         retCode = e.error();
1713     } Catch (CKM::Exception) {
1714         LogError("Error in set row!");
1715         retCode = CKM_API_ERROR_DB_ERROR;
1716     }
1717
1718     return MessageBuffer::Serialize(command, msgID, retCode).Pop();
1719 }
1720
1721 int CKMLogic::loadAppKey(UserData& handle, const Label& appLabel)
1722 {
1723     if (!handle.crypto.haveKey(appLabel)) {
1724         RawBuffer key;
1725         auto key_optional = handle.database.getKey(appLabel);
1726         if(!key_optional) {
1727             LogError("No key for given label in database");
1728             return CKM_API_ERROR_DB_ERROR;
1729         }
1730         key = *key_optional;
1731         key = handle.keyProvider.getPureDEK(key);
1732         handle.crypto.pushKey(appLabel, key);
1733     }
1734     return CKM_API_SUCCESS;
1735 }
1736
1737 } // namespace CKM
1738