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