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