Remove deprecated comments and logs.
[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 <vconf/vconf.h>
23 #include <dpl/serialization.h>
24 #include <dpl/log/log.h>
25 #include <ckm/ckm-error.h>
26 #include <ckm/ckm-type.h>
27 #include <key-provider.h>
28 #include <file-system.h>
29 #include <CryptoService.h>
30 #include <ckm-logic.h>
31 #include <key-impl.h>
32
33 namespace {
34 const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs";
35 } // anonymous namespace
36
37 namespace CKM {
38
39 CKMLogic::CKMLogic()
40 {
41     if (CKM_API_SUCCESS != m_certStore.setSystemCertificateDir(CERT_SYSTEM_DIR)) {
42         LogError("Fatal error in CertificateStore::setSystemCertificateDir. Chain creation will not work");
43     }
44
45     m_accessControl.updateCCMode();
46 }
47
48 CKMLogic::~CKMLogic(){}
49
50 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) {
51     // TODO try catch for all errors that should be supported by error code
52     int retCode = CKM_API_SUCCESS;
53
54     try {
55         if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) {
56             auto &handle = m_userDataMap[user];
57             FileSystem fs(user);
58             auto wrappedDomainKEK = fs.getDKEK();
59
60             if (wrappedDomainKEK.empty()) {
61                 wrappedDomainKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
62                 fs.saveDKEK(wrappedDomainKEK);
63             }
64
65             handle.keyProvider = KeyProvider(wrappedDomainKEK, password);
66
67             auto wrappedDatabaseDEK = fs.getDBDEK();
68
69             if (wrappedDatabaseDEK.empty()) {
70                 wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
71                 fs.saveDBDEK(wrappedDatabaseDEK);
72             }
73
74             RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
75             handle.database = DBCrypto(fs.getDBPath(), key);
76             handle.crypto = CryptoLogic();
77
78             // remove data of removed apps during locked state
79             AppLabelVector removedApps = fs.clearRemovedsApps();
80             for(auto& appSmackLabel : removedApps) {
81                 handle.database.deleteKey(appSmackLabel);
82             }
83         }
84     } catch (const KeyProvider::Exception::PassWordError &e) {
85         LogError("Incorrect Password " << e.GetMessage());
86         retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
87     } catch (const KeyProvider::Exception::Base &e) {
88         LogError("Error in KeyProvider " << e.GetMessage());
89         retCode = CKM_API_ERROR_SERVER_ERROR;
90     } catch (const CryptoLogic::Exception::Base &e) {
91         LogError("CryptoLogic error: " << e.GetMessage());
92         retCode = CKM_API_ERROR_SERVER_ERROR;
93     } catch (const CKM::Exception &e) {
94         LogError("CKM::Exception: " << e.GetMessage());
95         retCode = CKM_API_ERROR_SERVER_ERROR;
96     }
97
98     if(retCode != CKM_API_SUCCESS) {
99         // When not successful, UserData in m_userDataMap should be erased.
100         // Because other operations make decision based on the existence of UserData in m_userDataMap.
101         m_userDataMap.erase(user);
102     }
103
104     return MessageBuffer::Serialize(retCode).Pop();
105 }
106
107 RawBuffer CKMLogic::updateCCMode() {
108     m_accessControl.updateCCMode();
109     return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
110 }
111
112 RawBuffer CKMLogic::lockUserKey(uid_t user) {
113     int retCode = CKM_API_SUCCESS;
114     // TODO try catch for all errors that should be supported by error code
115     m_userDataMap.erase(user);
116
117     return MessageBuffer::Serialize(retCode).Pop();
118
119 }
120
121 RawBuffer CKMLogic::removeUserData(uid_t user) {
122     int retCode = CKM_API_SUCCESS;
123     // TODO try catch for all errors that should be supported by error code
124     m_userDataMap.erase(user);
125
126     FileSystem fs(user);
127     fs.removeUserData();
128
129     return MessageBuffer::Serialize(retCode).Pop();
130 }
131
132 RawBuffer CKMLogic::changeUserPassword(
133     uid_t user,
134     const Password &oldPassword,
135     const Password &newPassword)
136 {
137     int retCode = CKM_API_SUCCESS;
138     try {
139         FileSystem fs(user);
140         auto wrappedDomainKEK = fs.getDKEK();
141         if (wrappedDomainKEK.empty()) {
142             retCode = CKM_API_ERROR_BAD_REQUEST;
143         } else {
144             wrappedDomainKEK = KeyProvider::reencrypt(wrappedDomainKEK, oldPassword, newPassword);
145             fs.saveDKEK(wrappedDomainKEK);
146         }
147     } catch (const KeyProvider::Exception::PassWordError &e) {
148         LogError("Incorrect Password " << e.GetMessage());
149         retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
150     } catch (const KeyProvider::Exception::Base &e) {
151         LogError("Error in KeyProvider " << e.GetMessage());
152         retCode = CKM_API_ERROR_SERVER_ERROR;
153     } catch (const CKM::Exception &e) {
154         LogError("CKM::Exception: " << e.GetMessage());
155         retCode = CKM_API_ERROR_SERVER_ERROR;
156     }
157
158     return MessageBuffer::Serialize(retCode).Pop();
159 }
160
161 RawBuffer CKMLogic::resetUserPassword(
162     uid_t user,
163     const Password &newPassword)
164 {
165     int retCode = CKM_API_SUCCESS;
166     // TODO try-catch
167     if (0 == m_userDataMap.count(user)) {
168         retCode = CKM_API_ERROR_BAD_REQUEST;
169     } else {
170         auto &handler = m_userDataMap[user];
171         FileSystem fs(user);
172         fs.saveDKEK(handler.keyProvider.getWrappedDomainKEK(newPassword));
173     }
174
175     return MessageBuffer::Serialize(retCode).Pop();
176 }
177
178 RawBuffer CKMLogic::removeApplicationData(const Label &smackLabel) {
179     int retCode = CKM_API_SUCCESS;
180
181     try {
182
183         if (smackLabel.empty()) {
184             retCode = CKM_API_ERROR_INPUT_PARAM;
185         } else {
186             UidVector uids = FileSystem::getUIDsFromDBFile();
187             for (auto userId : uids) {
188                 if (0 == m_userDataMap.count(userId)) {
189                     FileSystem fs(userId);
190                     fs.addRemovedApp(smackLabel);
191                 } else {
192                     auto &handle = m_userDataMap[userId];
193                     handle.database.deleteKey(smackLabel);
194                 }
195             }
196         }
197
198     } catch (const DBCrypto::Exception::InternalError &e) {
199         LogError("DBCrypto couldn't remove data: " << e.GetMessage());
200         retCode = CKM_API_ERROR_DB_ERROR;
201     } catch (const DBCrypto::Exception::TransactionError &e) {
202         LogError("DBCrypto transaction failed with message " << e.GetMessage());
203         retCode = CKM_API_ERROR_DB_ERROR;
204     }
205
206     return MessageBuffer::Serialize(retCode).Pop();
207 }
208
209 int CKMLogic::saveDataHelper(
210     const Credentials &cred,
211     DBDataType dataType,
212     const Name &name,
213     const RawBuffer &key,
214     const PolicySerializable &policy)
215 {
216     if (0 == m_userDataMap.count(cred.uid))
217         return CKM_API_ERROR_DB_LOCKED;
218
219     // proceed to data save
220     DBRow row = { name, cred.smackLabel,
221          policy.extractable, dataType, DBCMAlgType::NONE,
222          0, RawBuffer(), static_cast<int>(key.size()), key, RawBuffer() };
223
224     auto &handler = m_userDataMap[cred.uid];
225     DBCrypto::Transaction transaction(&handler.database);
226
227     // check if not a duplicate
228     if( handler.database.isNameLabelPresent(name, cred.smackLabel) )
229         return CKM_API_ERROR_DB_ALIAS_EXISTS;
230
231     // encryption section
232     if (!handler.crypto.haveKey(cred.smackLabel)) {
233         RawBuffer got_key;
234         auto key_optional = handler.database.getKey(cred.smackLabel);
235         if(!key_optional) {
236             LogDebug("No Key in database found. Generating new one for label: "
237                     << cred.smackLabel);
238             got_key = handler.keyProvider.generateDEK(cred.smackLabel);
239             handler.database.saveKey(cred.smackLabel, got_key);
240         } else {
241             LogDebug("Key from DB");
242             got_key = *key_optional;
243         }
244
245         got_key = handler.keyProvider.getPureDEK(got_key);
246         handler.crypto.pushKey(cred.smackLabel, got_key);
247     }
248
249     // do not encrypt data with password during cc_mode on
250     if(m_accessControl.isCCMode()) {
251         handler.crypto.encryptRow("", row);
252     } else {
253         handler.crypto.encryptRow(policy.password, row);
254     }
255
256     handler.database.saveDBRow(row);
257     transaction.commit();
258     return CKM_API_SUCCESS;
259 }
260
261 void CKMLogic::verifyBinaryData(DBDataType dataType, const RawBuffer &input_data) const
262 {
263     // verify the data integrity
264     switch(dataType)
265     {
266         case DBDataType::KEY_RSA_PUBLIC:
267         case DBDataType::KEY_RSA_PRIVATE:
268         case DBDataType::KEY_ECDSA_PUBLIC:
269         case DBDataType::KEY_ECDSA_PRIVATE:
270         case DBDataType::KEY_DSA_PUBLIC:
271         case DBDataType::KEY_DSA_PRIVATE:
272         case DBDataType::KEY_AES:
273         {
274             KeyShPtr output_key = CKM::Key::create(input_data);
275             if(output_key.get() == NULL)
276                 ThrowMsg(CKMLogic::Exception::InputDataInvalid, "provided binary data is not valid key data");
277             break;
278         }
279
280         case DBDataType::CERTIFICATE:
281         {
282             CertificateShPtr cert = CKM::Certificate::create(input_data, DataFormat::FORM_DER);
283             if(cert.get() == NULL)
284                 ThrowMsg(CKMLogic::Exception::InputDataInvalid, "provided binary data is not valid certificate data");
285             break;
286         }
287
288         // TODO: add here BINARY_DATA verification, i.e: max size etc.
289
290         default: break;
291     }
292 }
293
294 RawBuffer CKMLogic::saveData(
295     const Credentials &cred,
296     int commandId,
297     DBDataType dataType,
298     const Name &name,
299     const Label &label,
300     const RawBuffer &key,
301     const PolicySerializable &policy)
302 {
303     int retCode = CKM_API_SUCCESS;
304     try {
305         if (!label.empty() && label.compare(cred.smackLabel))
306             ThrowMsg(CKMLogic::Exception::InputDataInvalid, "smack label in param is not your label");
307
308         verifyBinaryData(dataType, key);
309
310         retCode = saveDataHelper(cred, dataType, name, key, policy);
311         LogDebug("SaveDataHelper returned: " << retCode);
312     } catch (const CKMLogic::Exception::InputDataInvalid &e) {
313         LogError("Provided data invalid: " << e.GetMessage());
314         retCode = CKM_API_ERROR_INPUT_PARAM;
315     } catch (const KeyProvider::Exception::Base &e) {
316         LogError("KeyProvider failed with message: " << e.GetMessage());
317         retCode = CKM_API_ERROR_SERVER_ERROR;
318     } catch (const CryptoLogic::Exception::Base &e) {
319         LogError("CryptoLogic failed with message: " << e.GetMessage());
320         retCode = CKM_API_ERROR_SERVER_ERROR;
321     } catch (const DBCrypto::Exception::InternalError &e) {
322         LogError("DBCrypto failed with message: " << e.GetMessage());
323         retCode = CKM_API_ERROR_DB_ERROR;
324     } catch (const DBCrypto::Exception::TransactionError &e) {
325         LogError("DBCrypto transaction failed with message " << e.GetMessage());
326         retCode = CKM_API_ERROR_DB_ERROR;
327     }
328
329     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
330                                              commandId,
331                                              retCode,
332                                              static_cast<int>(dataType));
333     return response.Pop();
334 }
335
336 int CKMLogic::removeDataHelper(
337         const Credentials &cred,
338         const Name &name,
339         const Label &ownerLabel)
340 {
341     if (0 == m_userDataMap.count(cred.uid))
342         return CKM_API_ERROR_DB_LOCKED;
343
344     // verify name and label are correct
345     if( !checkNameAndLabelValid(name, ownerLabel) )
346     {
347         LogError("Invalid label or name format");
348         return CKM_API_ERROR_INPUT_PARAM;
349     }
350
351     auto &database = m_userDataMap[cred.uid].database;
352     DBCrypto::Transaction transaction(&database);
353
354     // read and check permissions
355     PermissionOptional permissionRowOpt =
356             database.getPermissionRow(name, ownerLabel, cred.smackLabel);
357     int access_ec = m_accessControl.canDelete(ownerLabel, PermissionForLabel(cred.smackLabel, permissionRowOpt));
358     if(access_ec != CKM_API_SUCCESS)
359     {
360         LogWarning("access control check result: " << access_ec);
361         return access_ec;
362     }
363
364     auto erased = database.deleteDBRow(name, ownerLabel);
365     // check if the data existed or not
366     if(erased)
367         transaction.commit();
368     else {
369         LogError("No row for given name and label");
370         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
371     }
372
373     return CKM_API_SUCCESS;
374 }
375
376 RawBuffer CKMLogic::removeData(
377     const Credentials &cred,
378     int commandId,
379     DBDataType dataType,
380     const Name &name,
381     const Label &label)
382 {
383     int retCode;
384     Try {
385         // use client label if not explicitly provided
386         const Label & ownerLabel = label.empty() ? cred.smackLabel : label;
387
388         retCode = removeDataHelper(cred, name, ownerLabel);
389     } Catch (CKM::Exception) {
390         LogError("Error in deleting row!");
391         retCode = CKM_API_ERROR_DB_ERROR;
392     }
393
394     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
395                                              commandId,
396                                              retCode,
397                                              static_cast<int>(dataType));
398     return response.Pop();
399 }
400
401 bool CKMLogic::checkNameAndLabelValid(const Name &name, const Label &label)
402 {
403     // verify the name is valid
404     if(name.find(':') != Label::npos)
405         return false;
406
407     // verify the label is valid
408     if(label.find(LABEL_NAME_SEPARATOR) != Label::npos)
409         return false;
410
411     return true;
412 }
413
414 int CKMLogic::readDataRowHelper(const Name &name,
415                                 const Label &ownerLabel,
416                                 DBDataType dataType,
417                                 DBCrypto & database,
418                                 DBRow &row)
419 {
420     // read row
421     DBCrypto::DBRowOptional row_optional;
422     // TODO: move this check into request deserialization
423     if((static_cast<int>(dataType)<static_cast<int>(DBDataType::DB_DATA_TYPE_FIRST)) ||
424        (static_cast<int>(dataType)>static_cast<int>(DBDataType::DB_DATA_TYPE_LAST)))
425     {
426         LogError("Unknown type of requested data: " << (int)dataType);
427         return CKM_API_ERROR_BAD_REQUEST;
428     }
429     // TODO: provide internal type rather than using DB types in socket comms
430     else if ((dataType >= DBDataType::DB_KEY_FIRST) &&
431              (dataType <= DBDataType::DB_KEY_LAST))
432     {
433         // read all key types
434         row_optional = database.getDBRow(name,
435                                          ownerLabel,
436                                          DBDataType::DB_KEY_FIRST,
437                                          DBDataType::DB_KEY_LAST);
438     }
439     else {
440         // read anything else
441         row_optional = database.getDBRow(name,
442                                          ownerLabel,
443                                          dataType);
444     }
445
446     if(!row_optional) {
447         LogError("No row for given name, label and type");
448         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
449     } else {
450         row = *row_optional;
451     }
452
453     return CKM_API_SUCCESS;
454 }
455
456 int CKMLogic::checkDataPermissionsHelper(const Name &name,
457                                          const Label &ownerLabel,
458                                          const Label &accessorLabel,
459                                          const DBRow &row,
460                                          bool exportFlag,
461                                          DBCrypto & database)
462 {
463     PermissionOptional permissionRowOpt =
464             database.getPermissionRow(name, ownerLabel, accessorLabel);
465
466     if(exportFlag)
467         return m_accessControl.canExport(row, PermissionForLabel(accessorLabel, permissionRowOpt));
468     return m_accessControl.canRead(row, PermissionForLabel(accessorLabel, permissionRowOpt));
469 }
470
471 int CKMLogic::readDataHelper(
472     bool exportFlag,
473     const Credentials &cred,
474     DBDataType dataType,
475     const Name &name,
476     const Label &label,
477     const Password &password,
478     DBRow &row)
479 {
480     if (0 == m_userDataMap.count(cred.uid))
481         return CKM_API_ERROR_DB_LOCKED;
482
483     // use client label if not explicitly provided
484     const Label ownerLabel = label.empty() ? cred.smackLabel : label;
485
486     // verify name and label are correct
487     if (true != checkNameAndLabelValid(name, ownerLabel))
488         return CKM_API_ERROR_INPUT_PARAM;
489
490     auto &handler = m_userDataMap[cred.uid];
491
492     // read row
493     DBCrypto::Transaction transaction(&handler.database);
494     int ec = readDataRowHelper(name, ownerLabel, dataType, handler.database, row);
495     if(CKM_API_SUCCESS != ec)
496         return ec;
497
498
499     // check access rights
500     ec = checkDataPermissionsHelper(name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
501     if(CKM_API_SUCCESS != ec)
502         return ec;
503
504     // decrypt row
505     if (!handler.crypto.haveKey(row.ownerLabel)) {
506         RawBuffer key;
507         auto key_optional = handler.database.getKey(row.ownerLabel);
508         if(!key_optional) {
509             LogError("No key for given label in database");
510             return CKM_API_ERROR_DB_ERROR;
511         }
512         key = *key_optional;
513         key = handler.keyProvider.getPureDEK(key);
514         handler.crypto.pushKey(row.ownerLabel, key);
515     }
516     handler.crypto.decryptRow(password, row);
517
518     return CKM_API_SUCCESS;
519 }
520
521 RawBuffer CKMLogic::getData(
522     const Credentials &cred,
523     int commandId,
524     DBDataType dataType,
525     const Name &name,
526     const Label &label,
527     const Password &password)
528 {
529     int retCode = CKM_API_SUCCESS;
530     DBRow row;
531
532     try {
533         retCode = readDataHelper(true, cred, dataType, name, label, password, row);
534     } catch (const KeyProvider::Exception::Base &e) {
535         LogError("KeyProvider failed with error: " << e.GetMessage());
536         retCode = CKM_API_ERROR_SERVER_ERROR;
537     } catch (const CryptoLogic::Exception::Base &e) {
538         LogError("CryptoLogic failed with message: " << e.GetMessage());
539         retCode = CKM_API_ERROR_SERVER_ERROR;
540     } catch (const DBCrypto::Exception::Base &e) {
541         LogError("DBCrypto failed with message: " << e.GetMessage());
542         retCode = CKM_API_ERROR_DB_ERROR;
543     }
544
545     if (CKM_API_SUCCESS != retCode) {
546         row.data.clear();
547         row.dataType = dataType;
548     }
549
550     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
551                                              commandId,
552                                              retCode,
553                                              static_cast<int>(row.dataType),
554                                              row.data);
555     return response.Pop();
556 }
557
558 RawBuffer CKMLogic::getDataList(
559     const Credentials &cred,
560     int commandId,
561     DBDataType dataType)
562 {
563     int retCode = CKM_API_SUCCESS;
564     LabelNameVector labelNameVector;
565
566     if (0 < m_userDataMap.count(cred.uid)) {
567         auto &database = m_userDataMap[cred.uid].database;
568
569         Try {
570             // list names
571             // TODO: move this check into request deserialization
572             if((static_cast<int>(dataType)<static_cast<int>(DBDataType::DB_DATA_TYPE_FIRST)) ||
573                (static_cast<int>(dataType)>static_cast<int>(DBDataType::DB_DATA_TYPE_LAST)))
574             {
575                 LogError("Unknown type of requested data: " << (int)dataType);
576                 retCode = CKM_API_ERROR_BAD_REQUEST;
577             }
578             // TODO: provide internal type rather than using DB types in socket comms
579             else if ((dataType >= DBDataType::DB_KEY_FIRST) && (dataType <= DBDataType::DB_KEY_LAST))
580             {
581                 // list all key types
582                 database.listNames(cred.smackLabel,
583                                    labelNameVector,
584                                    DBDataType::DB_KEY_FIRST,
585                                    DBDataType::DB_KEY_LAST);
586             }
587             else {
588                 // list anything else
589                 database.listNames(cred.smackLabel,
590                                    labelNameVector,
591                                    dataType);
592             }
593         }
594         Catch (CKM::Exception) {
595             LogError("Failed to get names");
596             retCode = CKM_API_ERROR_DB_ERROR;
597         }
598     } else {
599         retCode = CKM_API_ERROR_DB_LOCKED;
600     }
601
602     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_LIST),
603                                              commandId,
604                                              retCode,
605                                              static_cast<int>(dataType),
606                                              labelNameVector);
607     return response.Pop();
608 }
609
610
611 int CKMLogic::createKeyPairHelper(
612     const Credentials &cred,
613     const KeyType key_type,
614     const int additional_param,
615     const Name &namePrivate,
616     const Name &namePublic,
617     const PolicySerializable &policyPrivate,
618     const PolicySerializable &policyPublic)
619 {
620     if (0 == m_userDataMap.count(cred.uid))
621         return CKM_API_ERROR_DB_LOCKED;
622
623     KeyImpl prv, pub;
624     int retCode;
625     switch(key_type)
626     {
627         case KeyType::KEY_RSA_PUBLIC:
628         case KeyType::KEY_RSA_PRIVATE:
629             retCode = CryptoService::createKeyPairRSA(additional_param, prv, pub);
630             break;
631
632         case KeyType::KEY_DSA_PUBLIC:
633         case KeyType::KEY_DSA_PRIVATE:
634             retCode = CryptoService::createKeyPairDSA(additional_param, prv, pub);
635             break;
636
637         case KeyType::KEY_ECDSA_PUBLIC:
638         case KeyType::KEY_ECDSA_PRIVATE:
639             retCode = CryptoService::createKeyPairECDSA(static_cast<ElipticCurve>(additional_param), prv, pub);
640             break;
641
642         default:
643             return CKM_API_ERROR_INPUT_PARAM;
644     }
645
646     if (CKM_CRYPTO_CREATEKEY_SUCCESS != retCode)
647     {
648         LogDebug("CryptoService error with code: " << retCode);
649         return CKM_API_ERROR_SERVER_ERROR; // TODO error code
650     }
651
652     auto &database = m_userDataMap[cred.uid].database;
653     DBCrypto::Transaction transaction(&database);
654     retCode = saveDataHelper(cred,
655                             toDBDataType(prv.getType()),
656                             namePrivate,
657                             prv.getDER(),
658                             policyPrivate);
659
660     if (CKM_API_SUCCESS != retCode)
661         return retCode;
662
663     retCode = saveDataHelper(cred,
664                             toDBDataType(pub.getType()),
665                             namePublic,
666                             pub.getDER(),
667                             policyPublic);
668
669     if (CKM_API_SUCCESS != retCode)
670         return retCode;
671
672     transaction.commit();
673
674     return retCode;
675 }
676
677 RawBuffer CKMLogic::createKeyPair(
678     const Credentials &cred,
679     LogicCommand protocol_cmd,
680     int commandId,
681     const int additional_param,
682     const Name &namePrivate,
683     const Name &namePublic,
684     const PolicySerializable &policyPrivate,
685     const PolicySerializable &policyPublic)
686 {
687     int retCode = CKM_API_SUCCESS;
688
689     KeyType key_type = KeyType::KEY_NONE;
690     switch(protocol_cmd)
691     {
692         case LogicCommand::CREATE_KEY_PAIR_RSA:
693             key_type = KeyType::KEY_RSA_PUBLIC;
694             break;
695         case LogicCommand::CREATE_KEY_PAIR_DSA:
696             key_type = KeyType::KEY_DSA_PUBLIC;
697             break;
698         case LogicCommand::CREATE_KEY_PAIR_ECDSA:
699             key_type = KeyType::KEY_ECDSA_PUBLIC;
700             break;
701         default:
702             break;
703     }
704
705     try {
706         retCode = createKeyPairHelper(
707                         cred,
708                         key_type,
709                         additional_param,
710                         namePrivate,
711                         namePublic,
712                         policyPrivate,
713                         policyPublic);
714     } catch (DBCrypto::Exception::TransactionError &e) {
715         LogDebug("DBCrypto error: transaction error: " << e.GetMessage());
716         retCode = CKM_API_ERROR_DB_ERROR;
717     } catch (CKM::CryptoLogic::Exception::Base &e) {
718         LogDebug("CryptoLogic error: " << e.GetMessage());
719         retCode = CKM_API_ERROR_SERVER_ERROR;
720     } catch (DBCrypto::Exception::InternalError &e) {
721         LogDebug("DBCrypto internal error: " << e.GetMessage());
722         retCode = CKM_API_ERROR_DB_ERROR;
723     }
724
725     return MessageBuffer::Serialize(static_cast<int>(protocol_cmd), commandId, retCode).Pop();
726 }
727
728 RawBuffer CKMLogic::getCertificateChain(
729     const Credentials &cred,
730     int commandId,
731     const RawBuffer &certificate,
732     const RawBufferVector &untrustedRawCertVector)
733 {
734     (void)cred;
735
736     CertificateImpl cert(certificate, DataFormat::FORM_DER);
737     CertificateImplVector untrustedCertVector;
738     CertificateImplVector chainVector;
739     RawBufferVector chainRawVector;
740
741     for (auto &e: untrustedRawCertVector)
742         untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
743
744     LogDebug("Cert is empty: " << cert.empty());
745
746     int retCode = m_certStore.verifyCertificate(cert, untrustedCertVector, chainVector);
747
748     if (retCode == CKM_API_SUCCESS) {
749         for (auto &e : chainVector)
750             chainRawVector.push_back(e.getDER());
751     }
752
753     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_CERT),
754                                              commandId,
755                                              retCode,
756                                              chainRawVector);
757     return response.Pop();
758 }
759
760 int CKMLogic::getCertificateChainHelper(
761         const Credentials &cred,
762         const RawBuffer &certificate,
763         const LabelNameVector &labelNameVector,
764         RawBufferVector & chainRawVector)
765 {
766     CertificateImpl cert(certificate, DataFormat::FORM_DER);
767     CertificateImplVector untrustedCertVector;
768     CertificateImplVector chainVector;
769     DBRow row;
770
771     if (cert.empty())
772         return CKM_API_ERROR_SERVER_ERROR;
773
774     for (auto &i: labelNameVector) {
775         int ec = readDataHelper(false, cred, DBDataType::CERTIFICATE, i.second, i.first, Password(), row);
776         if (ec != CKM_API_SUCCESS)
777             return ec;
778
779         untrustedCertVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER));
780     }
781
782     int ec = m_certStore.verifyCertificate(cert, untrustedCertVector, chainVector);
783     if (ec != CKM_API_SUCCESS)
784         return ec;
785
786     for (auto &i: chainVector)
787         chainRawVector.push_back(i.getDER());
788
789     return CKM_API_SUCCESS;
790 }
791
792 RawBuffer CKMLogic::getCertificateChain(
793     const Credentials &cred,
794     int commandId,
795     const RawBuffer &certificate,
796     const LabelNameVector &labelNameVector)
797 {
798     int retCode = CKM_API_SUCCESS;
799     RawBufferVector chainRawVector;
800     try {
801
802         retCode = getCertificateChainHelper(cred, certificate, labelNameVector, chainRawVector);
803     } catch (const CryptoLogic::Exception::Base &e) {
804         LogError("DBCyptorModule failed with message: " << e.GetMessage());
805         retCode = CKM_API_ERROR_SERVER_ERROR;
806     } catch (const DBCrypto::Exception::Base &e) {
807         LogError("DBCrypto failed with message: " << e.GetMessage());
808         retCode = CKM_API_ERROR_DB_ERROR;
809     } catch (...) {
810         LogError("Unknown error.");
811     }
812
813     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_ALIAS),
814                                              commandId,
815                                              retCode,
816                                              chainRawVector);
817     return response.Pop();
818 }
819
820 RawBuffer CKMLogic::createSignature(
821         const Credentials &cred,
822         int commandId,
823         const Name &privateKeyName,
824         const Label & ownerLabel,
825         const Password &password,           // password for private_key
826         const RawBuffer &message,
827         const HashAlgorithm hash,
828         const RSAPaddingAlgorithm padding)
829 {
830     DBRow row;
831     CryptoService cs;
832     RawBuffer signature;
833
834     int retCode = CKM_API_SUCCESS;
835
836     try {
837         retCode = readDataHelper(false, cred, DBDataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, row);
838         if(retCode == CKM_API_SUCCESS)
839         {
840             KeyImpl keyParsed(row.data, Password());
841             if (keyParsed.empty())
842                 retCode = CKM_API_ERROR_SERVER_ERROR;
843             else
844                 retCode = cs.createSignature(keyParsed, message, hash, padding, signature);
845         }
846     } catch (const KeyProvider::Exception::Base &e) {
847         LogError("KeyProvider failed with message: " << e.GetMessage());
848         retCode = CKM_API_ERROR_SERVER_ERROR;
849     } catch (const CryptoLogic::Exception::Base &e) {
850         LogError("CryptoLogic failed with message: " << e.GetMessage());
851         retCode = CKM_API_ERROR_SERVER_ERROR;
852     } catch (const DBCrypto::Exception::Base &e) {
853         LogError("DBCrypto failed with message: " << e.GetMessage());
854         retCode = CKM_API_ERROR_DB_ERROR;
855     } catch (const CKM::Exception &e) {
856         LogError("Unknown CKM::Exception: " << e.GetMessage());
857         retCode = CKM_API_ERROR_SERVER_ERROR;
858     }
859
860     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_SIGNATURE),
861                                              commandId,
862                                              retCode,
863                                              signature);
864     return response.Pop();
865 }
866
867 RawBuffer CKMLogic::verifySignature(
868         const Credentials &cred,
869         int commandId,
870         const Name &publicKeyOrCertName,
871         const Label & ownerLabel,
872         const Password &password,           // password for public_key (optional)
873         const RawBuffer &message,
874         const RawBuffer &signature,
875         const HashAlgorithm hash,
876         const RSAPaddingAlgorithm padding)
877 {
878     int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
879
880     try {
881         do {
882             CryptoService cs;
883             DBRow row;
884             KeyImpl key;
885
886             retCode = readDataHelper(false, cred, DBDataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, row);
887
888             if (retCode == CKM_API_SUCCESS) {
889                 key = KeyImpl(row.data);
890             } else if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
891                 retCode = readDataHelper(false, cred, DBDataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, row);
892                 if (retCode != CKM_API_SUCCESS)
893                     break;
894                 CertificateImpl cert(row.data, DataFormat::FORM_DER);
895                 key = cert.getKeyImpl();
896             } else {
897                 break;
898             }
899
900             if (key.empty()) {
901                 retCode = CKM_API_ERROR_SERVER_ERROR;
902                 break;
903             }
904
905             retCode = cs.verifySignature(key, message, signature, hash, padding);
906         } while(0);
907     } catch (const CryptoService::Exception::Crypto_internal &e) {
908         LogError("KeyProvider failed with message: " << e.GetMessage());
909         retCode = CKM_API_ERROR_SERVER_ERROR;
910     } catch (const CryptoService::Exception::opensslError &e) {
911         LogError("KeyProvider failed with message: " << e.GetMessage());
912         retCode = CKM_API_ERROR_SERVER_ERROR;
913     } catch (const KeyProvider::Exception::Base &e) {
914         LogError("KeyProvider failed with error: " << e.GetMessage());
915         retCode = CKM_API_ERROR_SERVER_ERROR;
916     } catch (const CryptoLogic::Exception::Base &e) {
917         LogError("CryptoLogic failed with message: " << e.GetMessage());
918         retCode = CKM_API_ERROR_SERVER_ERROR;
919     } catch (const DBCrypto::Exception::Base &e) {
920         LogError("DBCrypto failed with message: " << e.GetMessage());
921         retCode = CKM_API_ERROR_DB_ERROR;
922     } catch (const CKM::Exception &e) {
923         LogError("Unknown CKM::Exception: " << e.GetMessage());
924         retCode = CKM_API_ERROR_SERVER_ERROR;
925     }
926
927     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::VERIFY_SIGNATURE),
928                                              commandId,
929                                              retCode);
930     return response.Pop();
931 }
932
933 int CKMLogic::setPermissionHelper(
934         const Credentials &cred,
935         const Name &name,
936         const Label &accessorLabel,
937         const Permission reqRights)
938 {
939     int retCode;
940     if(cred.smackLabel.empty() || cred.smackLabel==accessorLabel)
941         return CKM_API_ERROR_INPUT_PARAM;
942
943     if (0 == m_userDataMap.count(cred.uid))
944         return CKM_API_ERROR_DB_LOCKED;
945     auto &database = m_userDataMap[cred.uid].database;
946     DBCrypto::Transaction transaction(&database);
947
948     if( ! database.isNameLabelPresent(name, cred.smackLabel) )
949         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
950
951     // removing non-existing permissions: fail
952     if(reqRights == Permission::NONE)
953     {
954         if( !database.getPermissionRow(name, cred.smackLabel, accessorLabel) )
955             return CKM_API_ERROR_INPUT_PARAM;
956     }
957
958     retCode = database.setPermission(name,
959                                        cred.smackLabel,
960                                        accessorLabel,
961                                        reqRights);
962
963     transaction.commit();
964
965     return retCode;
966 }
967
968 RawBuffer CKMLogic::setPermission(
969         const Credentials &cred,
970         int command,
971         int msgID,
972         const Name &name,
973         const Label &accessorLabel,
974         const Permission reqRights)
975 {
976     int retCode;
977     Try {
978         retCode = setPermissionHelper(cred, name, accessorLabel, reqRights);
979     } Catch (CKM::Exception) {
980         LogError("Error in set row!");
981         retCode = CKM_API_ERROR_DB_ERROR;
982     }
983
984     return MessageBuffer::Serialize(command, msgID, retCode).Pop();
985 }
986
987 } // namespace CKM
988