2 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
20 * @brief Sample service implementation.
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 <CryptoService.h>
29 #include <ckm-logic.h>
31 #include <certificate-config.h>
32 #include <certificate-store.h>
35 const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs";
37 bool isLabelValid(const CKM::Label &label) {
38 // TODO: copy code from libprivilege control (for check smack label)
39 if (label.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Label::npos)
44 bool isNameValid(const CKM::Name &name) {
45 if (name.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Name::npos)
50 } // anonymous namespace
56 CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
58 m_accessControl.updateCCMode();
61 CKMLogic::~CKMLogic(){}
63 void CKMLogic::loadDKEKFile(uid_t user, const Password &password, bool apiReq) {
64 auto &handle = m_userDataMap[user];
68 auto wrappedDKEKMain = fs.getDKEK();
69 auto wrappedDKEKBackup = fs.getDKEKBackup();
71 if (wrappedDKEKMain.empty()) {
72 wrappedDKEKMain = KeyProvider::generateDomainKEK(std::to_string(user), password);
73 fs.saveDKEK(wrappedDKEKMain);
76 chooseDKEKFile(handle, password, wrappedDKEKMain, wrappedDKEKBackup);
78 if (!password.empty() || apiReq) {
79 handle.isDKEKConfirmed = true;
81 if (true == handle.isMainDKEK)
82 fs.removeDKEKBackup();
88 void CKMLogic::chooseDKEKFile(
90 const Password &password,
91 const RawBuffer &first,
92 const RawBuffer &second)
95 handle.keyProvider = KeyProvider(first, password);
96 handle.isMainDKEK = true;
97 } catch (const KeyProvider::Exception::Base &e) {
98 // Second buffer is empty. Lets rethrow first error
101 handle.keyProvider = KeyProvider(second, password);
102 handle.isMainDKEK = false;
106 void CKMLogic::saveDKEKFile(uid_t user, const Password &password) {
107 auto &handle = m_userDataMap[user];
110 if (handle.isMainDKEK)
111 fs.createDKEKBackup();
113 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
115 handle.isMainDKEK = true;
116 handle.isDKEKConfirmed = false;
119 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password, bool apiRequest) {
120 int retCode = CKM_API_SUCCESS;
123 if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) {
124 auto &handle = m_userDataMap[user];
127 loadDKEKFile(user, password, apiRequest);
129 auto wrappedDatabaseDEK = fs.getDBDEK();
131 if (wrappedDatabaseDEK.empty()) {
132 wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
133 fs.saveDBDEK(wrappedDatabaseDEK);
136 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
137 handle.database = DBCrypto(fs.getDBPath(), key);
138 handle.crypto = CryptoLogic();
140 // remove data of removed apps during locked state
141 AppLabelVector removedApps = fs.clearRemovedsApps();
142 for(auto& appSmackLabel : removedApps) {
143 handle.database.deleteKey(appSmackLabel);
145 } else if (apiRequest == true && m_userDataMap[user].isDKEKConfirmed == false) {
146 // now we will try to choose the DKEK key and remove old one
147 loadDKEKFile(user, password, apiRequest);
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 CryptoLogic::Exception::Base &e) {
156 LogError("CryptoLogic error: " << e.GetMessage());
157 retCode = CKM_API_ERROR_SERVER_ERROR;
158 } catch (const FileSystem::Exception::Base &e) {
159 LogError("FileSystem error: " << e.GetMessage());
160 retCode = CKM_API_ERROR_FILE_SYSTEM;
161 } catch (const CKM::Exception &e) {
162 LogError("CKM::Exception: " << e.GetMessage());
163 retCode = CKM_API_ERROR_SERVER_ERROR;
166 if(retCode != CKM_API_SUCCESS) {
167 // When not successful, UserData in m_userDataMap should be erased.
168 // Because other operations make decision based on the existence of UserData in m_userDataMap.
169 m_userDataMap.erase(user);
172 return MessageBuffer::Serialize(retCode).Pop();
175 RawBuffer CKMLogic::updateCCMode() {
176 m_accessControl.updateCCMode();
177 return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
180 RawBuffer CKMLogic::lockUserKey(uid_t user) {
181 int retCode = CKM_API_SUCCESS;
182 // TODO try catch for all errors that should be supported by error code
183 m_userDataMap.erase(user);
185 return MessageBuffer::Serialize(retCode).Pop();
189 RawBuffer CKMLogic::removeUserData(uid_t user) {
190 int retCode = CKM_API_SUCCESS;
191 // TODO try catch for all errors that should be supported by error code
192 m_userDataMap.erase(user);
197 return MessageBuffer::Serialize(retCode).Pop();
200 RawBuffer CKMLogic::changeUserPassword(
202 const Password &oldPassword,
203 const Password &newPassword)
205 int retCode = CKM_API_SUCCESS;
207 loadDKEKFile(user, oldPassword, true);
208 saveDKEKFile(user, newPassword);
209 } catch (const KeyProvider::Exception::PassWordError &e) {
210 LogError("Incorrect Password " << e.GetMessage());
211 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
212 } catch (const KeyProvider::Exception::Base &e) {
213 LogError("Error in KeyProvider " << e.GetMessage());
214 retCode = CKM_API_ERROR_SERVER_ERROR;
215 } catch (const FileSystem::Exception::Base &e) {
216 LogError("Error in FileSystem " << e.GetMessage());
217 retCode = CKM_API_ERROR_FILE_SYSTEM;
218 } catch (const CKM::Exception &e) {
219 LogError("CKM::Exception: " << e.GetMessage());
220 retCode = CKM_API_ERROR_SERVER_ERROR;
223 return MessageBuffer::Serialize(retCode).Pop();
226 RawBuffer CKMLogic::resetUserPassword(
228 const Password &newPassword)
230 int retCode = CKM_API_SUCCESS;
233 if (0 == m_userDataMap.count(user)) {
234 retCode = CKM_API_ERROR_BAD_REQUEST;
236 saveDKEKFile(user, newPassword);
238 } catch (const FileSystem::Exception::Base &e) {
239 LogError("Error in FileSystem " << e.GetMessage());
240 retCode = CKM_API_ERROR_FILE_SYSTEM;
241 } catch (const CKM::Exception &e) {
242 LogError("CKM::Exception: " << e.GetMessage());
243 retCode = CKM_API_ERROR_SERVER_ERROR;
246 return MessageBuffer::Serialize(retCode).Pop();
249 RawBuffer CKMLogic::removeApplicationData(const Label &smackLabel) {
250 int retCode = CKM_API_SUCCESS;
254 if (smackLabel.empty()) {
255 retCode = CKM_API_ERROR_INPUT_PARAM;
257 UidVector uids = FileSystem::getUIDsFromDBFile();
258 for (auto userId : uids) {
259 if (0 == m_userDataMap.count(userId)) {
260 FileSystem fs(userId);
261 fs.addRemovedApp(smackLabel);
263 auto &handle = m_userDataMap[userId];
264 handle.database.deleteKey(smackLabel);
269 } catch (const DBCrypto::Exception::InternalError &e) {
270 LogError("DBCrypto couldn't remove data: " << e.GetMessage());
271 retCode = CKM_API_ERROR_DB_ERROR;
272 } catch (const DBCrypto::Exception::TransactionError &e) {
273 LogError("DBCrypto transaction failed with message " << e.GetMessage());
274 retCode = CKM_API_ERROR_DB_ERROR;
275 } catch (const FileSystem::Exception::Base &e) {
276 LogError("Error in FileSystem " << e.GetMessage());
277 retCode = CKM_API_ERROR_FILE_SYSTEM;
278 } catch (const CKM::Exception &e) {
279 LogError("CKM::Exception: " << e.GetMessage());
280 retCode = CKM_API_ERROR_SERVER_ERROR;
283 return MessageBuffer::Serialize(retCode).Pop();
286 int CKMLogic::checkSaveConditions(
287 const Credentials &cred,
290 const Label &ownerLabel)
292 // verify name and label are correct
293 if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
294 LogWarning("Invalid parameter passed to key-manager");
295 return CKM_API_ERROR_INPUT_PARAM;
298 // check if allowed to save using ownerLabel
299 int access_ec = m_accessControl.canSave(ownerLabel, cred.smackLabel);
300 if(access_ec != CKM_API_SUCCESS)
302 LogWarning("label " << cred.smackLabel << " can not save rows using label " << ownerLabel);
306 // check if not a duplicate
307 if( handler.database.isNameLabelPresent(name, cred.smackLabel) )
308 return CKM_API_ERROR_DB_ALIAS_EXISTS;
310 // encryption section
311 if (!handler.crypto.haveKey(cred.smackLabel)) {
313 auto key_optional = handler.database.getKey(cred.smackLabel);
315 LogDebug("No Key in database found. Generating new one for label: "
317 got_key = handler.keyProvider.generateDEK(cred.smackLabel);
318 handler.database.saveKey(cred.smackLabel, got_key);
320 LogDebug("Key from DB");
321 got_key = *key_optional;
324 got_key = handler.keyProvider.getPureDEK(got_key);
325 handler.crypto.pushKey(cred.smackLabel, got_key);
328 return CKM_API_SUCCESS;
331 DBRow CKMLogic::createEncryptedDBRow(
336 const RawBuffer &data,
337 const Policy &policy) const
339 DBRow row = { name, label, policy.extractable, dataType, DBCMAlgType::NONE,
340 0, RawBuffer(), static_cast<int>(data.size()), data, RawBuffer() };
342 // do not encrypt data with password during cc_mode on
343 if(m_accessControl.isCCMode()) {
344 crypto.encryptRow("", row);
346 crypto.encryptRow(policy.password, row);
351 int CKMLogic::verifyBinaryData(DBDataType dataType, const RawBuffer &input_data) const
353 // verify the data integrity
354 if (dataType.isKey())
356 KeyShPtr output_key = CKM::Key::create(input_data);
357 if(output_key.get() == NULL)
359 LogError("provided binary data is not valid key data");
360 return CKM_API_ERROR_INPUT_PARAM;
363 else if (dataType.isCertificate() || dataType.isChainCert())
365 CertificateShPtr cert = CKM::Certificate::create(input_data, DataFormat::FORM_DER);
366 if(cert.get() == NULL)
368 LogError("provided binary data is not valid certificate data");
369 return CKM_API_ERROR_INPUT_PARAM;
372 // TODO: add here BINARY_DATA verification, i.e: max size etc.
373 return CKM_API_SUCCESS;
376 RawBuffer CKMLogic::saveData(
377 const Credentials &cred,
381 const RawBuffer &data,
383 const PolicySerializable &policy)
386 if (0 == m_userDataMap.count(cred.uid))
387 retCode = CKM_API_ERROR_DB_LOCKED;
391 // check if data is correct
392 retCode = verifyBinaryData(dataType, data);
393 if(retCode == CKM_API_SUCCESS)
395 retCode = saveDataHelper(cred, name, label, dataType, data, policy);
397 } catch (const KeyProvider::Exception::Base &e) {
398 LogError("KeyProvider failed with message: " << e.GetMessage());
399 retCode = CKM_API_ERROR_SERVER_ERROR;
400 } catch (const CryptoLogic::Exception::Base &e) {
401 LogError("CryptoLogic failed with message: " << e.GetMessage());
402 retCode = CKM_API_ERROR_SERVER_ERROR;
403 } catch (const DBCrypto::Exception::InternalError &e) {
404 LogError("DBCrypto failed with message: " << e.GetMessage());
405 retCode = CKM_API_ERROR_DB_ERROR;
406 } catch (const DBCrypto::Exception::TransactionError &e) {
407 LogError("DBCrypto transaction failed with message " << e.GetMessage());
408 retCode = CKM_API_ERROR_DB_ERROR;
409 } catch (const FileSystem::Exception::Base &e) {
410 LogError("Error in FileSystem " << e.GetMessage());
411 retCode = CKM_API_ERROR_FILE_SYSTEM;
412 } catch (const CKM::Exception &e) {
413 LogError("CKM::Exception: " << e.GetMessage());
414 retCode = CKM_API_ERROR_SERVER_ERROR;
418 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
421 static_cast<int>(dataType));
422 return response.Pop();
425 int CKMLogic::extractPKCS12Data(
428 const Label &ownerLabel,
429 const PKCS12Serializable &pkcs,
430 const PolicySerializable &keyPolicy,
431 const PolicySerializable &certPolicy,
432 DBRowVector &output) const
434 // private key is mandatory
436 return CKM_API_ERROR_INVALID_FORMAT;
437 Key* keyPtr = pkcs.getKey().get();
438 DBDataType keyType = DBDataType(keyPtr->getType());
439 RawBuffer keyData = keyPtr->getDER();
440 int retCode = verifyBinaryData(keyType, keyData);
441 if(retCode != CKM_API_SUCCESS)
443 output.push_back(createEncryptedDBRow(crypto, name, ownerLabel, keyType, keyData, keyPolicy));
445 // certificate is mandatory
446 if( !pkcs.getCertificate() )
447 return CKM_API_ERROR_INVALID_FORMAT;
448 RawBuffer certData = pkcs.getCertificate().get()->getDER();
449 retCode = verifyBinaryData(DBDataType::CERTIFICATE, certData);
450 if(retCode != CKM_API_SUCCESS)
452 output.push_back(createEncryptedDBRow(crypto, name, ownerLabel, DBDataType::CERTIFICATE, certData, certPolicy));
455 unsigned int cert_index = 0;
456 for(const auto & ca : pkcs.getCaCertificateShPtrVector())
458 DBDataType chainDataType = DBDataType::getChainDatatype(cert_index ++);
459 RawBuffer caCertData = ca->getDER();
460 int retCode = verifyBinaryData(chainDataType, caCertData);
461 if(retCode != CKM_API_SUCCESS)
464 output.push_back(createEncryptedDBRow(crypto, name, ownerLabel, chainDataType, caCertData, certPolicy));
467 return CKM_API_SUCCESS;
470 RawBuffer CKMLogic::savePKCS12(
471 const Credentials &cred,
475 const PKCS12Serializable &pkcs,
476 const PolicySerializable &keyPolicy,
477 const PolicySerializable &certPolicy)
480 if (0 == m_userDataMap.count(cred.uid))
481 retCode = CKM_API_ERROR_DB_LOCKED;
485 retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy);
486 } catch (const KeyProvider::Exception::Base &e) {
487 LogError("KeyProvider failed with message: " << e.GetMessage());
488 retCode = CKM_API_ERROR_SERVER_ERROR;
489 } catch (const CryptoLogic::Exception::Base &e) {
490 LogError("CryptoLogic failed with message: " << e.GetMessage());
491 retCode = CKM_API_ERROR_SERVER_ERROR;
492 } catch (const DBCrypto::Exception::InternalError &e) {
493 LogError("DBCrypto failed with message: " << e.GetMessage());
494 retCode = CKM_API_ERROR_DB_ERROR;
495 } catch (const DBCrypto::Exception::TransactionError &e) {
496 LogError("DBCrypto transaction failed with message " << e.GetMessage());
497 retCode = CKM_API_ERROR_DB_ERROR;
498 } catch (const CKM::Exception &e) {
499 LogError("CKM::Exception: " << e.GetMessage());
500 retCode = CKM_API_ERROR_SERVER_ERROR;
504 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE_PKCS12),
507 return response.Pop();
511 int CKMLogic::removeDataHelper(
512 const Credentials &cred,
514 const Label &ownerLabel)
516 if (0 == m_userDataMap.count(cred.uid))
517 return CKM_API_ERROR_DB_LOCKED;
519 if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
520 LogError("Invalid label or name format");
521 return CKM_API_ERROR_INPUT_PARAM;
524 auto &database = m_userDataMap[cred.uid].database;
525 DBCrypto::Transaction transaction(&database);
527 // read and check permissions
528 PermissionMaskOptional permissionRowOpt =
529 database.getPermissionRow(name, ownerLabel, cred.smackLabel);
530 int access_ec = m_accessControl.canDelete(PermissionForLabel(cred.smackLabel, permissionRowOpt));
531 if(access_ec != CKM_API_SUCCESS)
533 LogWarning("access control check result: " << access_ec);
537 auto erased = database.deleteDBRow(name, ownerLabel);
538 // check if the data existed or not
540 transaction.commit();
542 LogError("No row for given name and label");
543 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
546 return CKM_API_SUCCESS;
549 RawBuffer CKMLogic::removeData(
550 const Credentials &cred,
557 // use client label if not explicitly provided
558 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
560 retCode = removeDataHelper(cred, name, ownerLabel);
561 } Catch (CKM::Exception) {
562 LogError("Error in deleting row!");
563 retCode = CKM_API_ERROR_DB_ERROR;
566 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
569 return response.Pop();
572 int CKMLogic::readSingleRow(const Name &name,
573 const Label &ownerLabel,
578 DBCrypto::DBRowOptional row_optional;
579 if (dataType.isKey())
581 // read all key types
582 row_optional = database.getDBRow(name,
584 DBDataType::DB_KEY_FIRST,
585 DBDataType::DB_KEY_LAST);
587 // read anything else
588 row_optional = database.getDBRow(name,
594 LogError("No row for given name, label and type");
595 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
600 return CKM_API_SUCCESS;
604 int CKMLogic::readMultiRow(const Name &name,
605 const Label &ownerLabel,
610 if (dataType.isKey())
612 // read all key types
613 database.getDBRows(name,
615 DBDataType::DB_KEY_FIRST,
616 DBDataType::DB_KEY_LAST,
619 else if (dataType.isChainCert())
621 // read all key types
622 database.getDBRows(name,
624 DBDataType::DB_CHAIN_FIRST,
625 DBDataType::DB_CHAIN_LAST,
630 // read anything else
631 database.getDBRows(name,
638 LogError("No row for given name, label and type");
639 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
642 return CKM_API_SUCCESS;
645 int CKMLogic::checkDataPermissionsHelper(const Name &name,
646 const Label &ownerLabel,
647 const Label &accessorLabel,
652 PermissionMaskOptional permissionRowOpt =
653 database.getPermissionRow(name, ownerLabel, accessorLabel);
656 return m_accessControl.canExport(row, PermissionForLabel(accessorLabel, permissionRowOpt));
657 return m_accessControl.canRead(PermissionForLabel(accessorLabel, permissionRowOpt));
660 int CKMLogic::readDataHelper(
662 const Credentials &cred,
666 const Password &password,
669 if (0 == m_userDataMap.count(cred.uid))
670 return CKM_API_ERROR_DB_LOCKED;
672 // use client label if not explicitly provided
673 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
675 if (!isNameValid(name) || !isLabelValid(ownerLabel))
676 return CKM_API_ERROR_INPUT_PARAM;
678 auto &handler = m_userDataMap[cred.uid];
681 DBCrypto::Transaction transaction(&handler.database);
682 int ec = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
683 if(CKM_API_SUCCESS != ec)
686 // all read rows belong to the same owner
687 DBRow & firstRow = rows.at(0);
689 // check access rights
690 ec = checkDataPermissionsHelper(name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database);
691 if(CKM_API_SUCCESS != ec)
695 if (!handler.crypto.haveKey(firstRow.ownerLabel)) {
697 auto key_optional = handler.database.getKey(firstRow.ownerLabel);
699 LogError("No key for given label in database");
700 return CKM_API_ERROR_DB_ERROR;
703 key = handler.keyProvider.getPureDEK(key);
704 handler.crypto.pushKey(firstRow.ownerLabel, key);
706 for(auto &row : rows)
707 handler.crypto.decryptRow(password, row);
709 return CKM_API_SUCCESS;
712 int CKMLogic::readDataHelper(
714 const Credentials &cred,
718 const Password &password,
721 if (0 == m_userDataMap.count(cred.uid))
722 return CKM_API_ERROR_DB_LOCKED;
724 // use client label if not explicitly provided
725 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
727 if (!isNameValid(name) || !isLabelValid(ownerLabel))
728 return CKM_API_ERROR_INPUT_PARAM;
730 auto &handler = m_userDataMap[cred.uid];
733 DBCrypto::Transaction transaction(&handler.database);
734 int ec = readSingleRow(name, ownerLabel, dataType, handler.database, row);
735 if(CKM_API_SUCCESS != ec)
739 // check access rights
740 ec = checkDataPermissionsHelper(name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
741 if(CKM_API_SUCCESS != ec)
745 if (!handler.crypto.haveKey(row.ownerLabel)) {
747 auto key_optional = handler.database.getKey(row.ownerLabel);
749 LogError("No key for given label in database");
750 return CKM_API_ERROR_DB_ERROR;
753 key = handler.keyProvider.getPureDEK(key);
754 handler.crypto.pushKey(row.ownerLabel, key);
756 handler.crypto.decryptRow(password, row);
758 return CKM_API_SUCCESS;
761 RawBuffer CKMLogic::getData(
762 const Credentials &cred,
767 const Password &password)
769 int retCode = CKM_API_SUCCESS;
773 retCode = readDataHelper(true, cred, dataType, name, label, password, row);
774 } catch (const KeyProvider::Exception::Base &e) {
775 LogError("KeyProvider failed with error: " << e.GetMessage());
776 retCode = CKM_API_ERROR_SERVER_ERROR;
777 } catch (const CryptoLogic::Exception::Base &e) {
778 LogError("CryptoLogic failed with message: " << e.GetMessage());
779 retCode = CKM_API_ERROR_SERVER_ERROR;
780 } catch (const DBCrypto::Exception::Base &e) {
781 LogError("DBCrypto failed with message: " << e.GetMessage());
782 retCode = CKM_API_ERROR_DB_ERROR;
783 } catch (const CKM::Exception &e) {
784 LogError("CKM::Exception: " << e.GetMessage());
785 retCode = CKM_API_ERROR_SERVER_ERROR;
788 if (CKM_API_SUCCESS != retCode) {
790 row.dataType = dataType;
793 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
796 static_cast<int>(row.dataType),
798 return response.Pop();
801 int CKMLogic::getPKCS12Helper(
802 const Credentials &cred,
806 CertificateShPtr & cert,
807 CertificateShPtrVector & caChain)
811 // read private key (mandatory)
813 retCode = readDataHelper(true, cred, DBDataType::DB_KEY_FIRST, name, label, CKM::Password(), privKeyRow);
814 if(retCode != CKM_API_SUCCESS)
816 privKey = CKM::Key::create(privKeyRow.data);
818 // read certificate (mandatory)
820 retCode = readDataHelper(true, cred, DBDataType::CERTIFICATE, name, label, CKM::Password(), certRow);
821 if(retCode != CKM_API_SUCCESS)
823 cert = CKM::Certificate::create(certRow.data, DataFormat::FORM_DER);
825 // read CA cert chain (optional)
826 DBRowVector rawCaChain;
827 retCode = readDataHelper(true, cred, DBDataType::DB_CHAIN_FIRST, name, label, CKM::Password(), rawCaChain);
828 if(retCode != CKM_API_SUCCESS &&
829 retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
831 for(auto &rawCaCert : rawCaChain)
832 caChain.push_back(CKM::Certificate::create(rawCaCert.data, DataFormat::FORM_DER));
834 // if anything found, return it
835 if(privKey || cert || caChain.size()>0)
836 retCode = CKM_API_SUCCESS;
841 RawBuffer CKMLogic::getPKCS12(
842 const Credentials &cred,
848 PKCS12Serializable output;
852 CertificateShPtr cert;
853 CertificateShPtrVector caChain;
854 retCode = getPKCS12Helper(cred, name, label, privKey, cert, caChain);
857 if(retCode == CKM_API_SUCCESS)
858 output = PKCS12Serializable(privKey, cert, caChain);
860 } catch (const KeyProvider::Exception::Base &e) {
861 LogError("KeyProvider failed with error: " << e.GetMessage());
862 retCode = CKM_API_ERROR_SERVER_ERROR;
863 } catch (const CryptoLogic::Exception::Base &e) {
864 LogError("CryptoLogic failed with message: " << e.GetMessage());
865 retCode = CKM_API_ERROR_SERVER_ERROR;
866 } catch (const DBCrypto::Exception::Base &e) {
867 LogError("DBCrypto failed with message: " << e.GetMessage());
868 retCode = CKM_API_ERROR_DB_ERROR;
869 } catch (const CKM::Exception &e) {
870 LogError("CKM::Exception: " << e.GetMessage());
871 retCode = CKM_API_ERROR_SERVER_ERROR;
874 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_PKCS12),
878 return response.Pop();
881 RawBuffer CKMLogic::getDataList(
882 const Credentials &cred,
886 int retCode = CKM_API_SUCCESS;
887 LabelNameVector labelNameVector;
889 if (0 < m_userDataMap.count(cred.uid)) {
890 auto &database = m_userDataMap[cred.uid].database;
893 if (dataType.isKey()) {
894 // list all key types
895 database.listNames(cred.smackLabel,
897 DBDataType::DB_KEY_FIRST,
898 DBDataType::DB_KEY_LAST);
900 // list anything else
901 database.listNames(cred.smackLabel,
906 Catch (CKM::Exception) {
907 LogError("Failed to get names");
908 retCode = CKM_API_ERROR_DB_ERROR;
911 retCode = CKM_API_ERROR_DB_LOCKED;
914 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_LIST),
917 static_cast<int>(dataType),
919 return response.Pop();
922 int CKMLogic::saveDataHelper(
923 const Credentials &cred,
927 const RawBuffer &data,
928 const PolicySerializable &policy)
930 auto &handler = m_userDataMap[cred.uid];
932 // use client label if not explicitly provided
933 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
935 // check if save is possible
936 DBCrypto::Transaction transaction(&handler.database);
937 int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
938 if(retCode != CKM_API_SUCCESS)
942 DBRow encryptedRow = createEncryptedDBRow(handler.crypto, name, ownerLabel, dataType, data, policy);
943 handler.database.saveDBRow(encryptedRow);
945 transaction.commit();
946 return CKM_API_SUCCESS;
949 int CKMLogic::saveDataHelper(
950 const Credentials &cred,
953 const PKCS12Serializable &pkcs,
954 const PolicySerializable &keyPolicy,
955 const PolicySerializable &certPolicy)
957 auto &handler = m_userDataMap[cred.uid];
959 // use client label if not explicitly provided
960 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
962 // check if save is possible
963 DBCrypto::Transaction transaction(&handler.database);
964 int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
965 if(retCode != CKM_API_SUCCESS)
968 // extract and encrypt the data
969 DBRowVector encryptedRows;
970 retCode = extractPKCS12Data(handler.crypto, name, ownerLabel, pkcs, keyPolicy, certPolicy, encryptedRows);
971 if(retCode != CKM_API_SUCCESS)
975 handler.database.saveDBRows(name, ownerLabel, encryptedRows);
976 transaction.commit();
978 return CKM_API_SUCCESS;
982 int CKMLogic::createKeyPairHelper(
983 const Credentials &cred,
984 const KeyType key_type,
985 const int additional_param,
986 const Name &namePrivate,
987 const Label &labelPrivate,
988 const Name &namePublic,
989 const Label &labelPublic,
990 const PolicySerializable &policyPrivate,
991 const PolicySerializable &policyPublic)
993 if (0 == m_userDataMap.count(cred.uid))
994 return CKM_API_ERROR_DB_LOCKED;
1000 case KeyType::KEY_RSA_PUBLIC:
1001 case KeyType::KEY_RSA_PRIVATE:
1002 retCode = CryptoService::createKeyPairRSA(additional_param, prv, pub);
1005 case KeyType::KEY_DSA_PUBLIC:
1006 case KeyType::KEY_DSA_PRIVATE:
1007 retCode = CryptoService::createKeyPairDSA(additional_param, prv, pub);
1010 case KeyType::KEY_ECDSA_PUBLIC:
1011 case KeyType::KEY_ECDSA_PRIVATE:
1012 retCode = CryptoService::createKeyPairECDSA(static_cast<ElipticCurve>(additional_param), prv, pub);
1016 return CKM_API_ERROR_INPUT_PARAM;
1019 if (CKM_CRYPTO_CREATEKEY_SUCCESS != retCode)
1021 LogDebug("CryptoService error with code: " << retCode);
1022 return CKM_API_ERROR_SERVER_ERROR; // TODO error code
1025 auto &database = m_userDataMap[cred.uid].database;
1026 DBCrypto::Transaction transaction(&database);
1028 retCode = saveDataHelper(cred,
1031 DBDataType(prv.getType()),
1034 if (CKM_API_SUCCESS != retCode)
1037 retCode = saveDataHelper(cred,
1040 DBDataType(pub.getType()),
1043 if (CKM_API_SUCCESS != retCode)
1046 transaction.commit();
1051 RawBuffer CKMLogic::createKeyPair(
1052 const Credentials &cred,
1053 LogicCommand protocol_cmd,
1055 const int additional_param,
1056 const Name &namePrivate,
1057 const Label &labelPrivate,
1058 const Name &namePublic,
1059 const Label &labelPublic,
1060 const PolicySerializable &policyPrivate,
1061 const PolicySerializable &policyPublic)
1063 int retCode = CKM_API_SUCCESS;
1065 KeyType key_type = KeyType::KEY_NONE;
1066 switch(protocol_cmd)
1068 case LogicCommand::CREATE_KEY_PAIR_RSA:
1069 key_type = KeyType::KEY_RSA_PUBLIC;
1071 case LogicCommand::CREATE_KEY_PAIR_DSA:
1072 key_type = KeyType::KEY_DSA_PUBLIC;
1074 case LogicCommand::CREATE_KEY_PAIR_ECDSA:
1075 key_type = KeyType::KEY_ECDSA_PUBLIC;
1082 retCode = createKeyPairHelper(
1092 } catch (DBCrypto::Exception::TransactionError &e) {
1093 LogDebug("DBCrypto error: transaction error: " << e.GetMessage());
1094 retCode = CKM_API_ERROR_DB_ERROR;
1095 } catch (CKM::CryptoLogic::Exception::Base &e) {
1096 LogDebug("CryptoLogic error: " << e.GetMessage());
1097 retCode = CKM_API_ERROR_SERVER_ERROR;
1098 } catch (DBCrypto::Exception::InternalError &e) {
1099 LogDebug("DBCrypto internal error: " << e.GetMessage());
1100 retCode = CKM_API_ERROR_DB_ERROR;
1101 } catch (const CKM::Exception &e) {
1102 LogError("CKM::Exception: " << e.GetMessage());
1103 retCode = CKM_API_ERROR_SERVER_ERROR;
1106 return MessageBuffer::Serialize(static_cast<int>(protocol_cmd), commandId, retCode).Pop();
1109 int CKMLogic::readCertificateHelper(
1110 const Credentials &cred,
1111 const LabelNameVector &labelNameVector,
1112 CertificateImplVector &certVector)
1115 for (auto &i: labelNameVector) {
1116 int ec = readDataHelper(false, cred, DBDataType::CERTIFICATE, i.second, i.first, Password(), row);
1117 if (ec != CKM_API_SUCCESS)
1119 certVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER));
1121 // try to read chain certificates (if present)
1122 DBRowVector rawCaChain;
1123 ec = readDataHelper(false, cred, DBDataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), rawCaChain);
1124 if(ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1126 for(auto &rawCaCert : rawCaChain)
1127 certVector.push_back(CertificateImpl(rawCaCert.data, DataFormat::FORM_DER));
1129 return CKM_API_SUCCESS;
1132 int CKMLogic::getCertificateChainHelper(
1133 const CertificateImpl &cert,
1134 const RawBufferVector &untrustedCertificates,
1135 const RawBufferVector &trustedCertificates,
1136 bool useTrustedSystemCertificates,
1137 RawBufferVector &chainRawVector)
1139 CertificateImplVector untrustedCertVector;
1140 CertificateImplVector trustedCertVector;
1141 CertificateImplVector chainVector;
1144 return CKM_API_ERROR_INPUT_PARAM;
1146 for (auto &e: untrustedCertificates)
1147 untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1148 for (auto &e: trustedCertificates)
1149 trustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1151 CertificateStore store;
1152 int retCode = store.verifyCertificate(cert,
1153 untrustedCertVector,
1155 useTrustedSystemCertificates,
1156 m_accessControl.isCCMode(),
1158 if (retCode != CKM_API_SUCCESS)
1161 for (auto &e : chainVector)
1162 chainRawVector.push_back(e.getDER());
1163 return CKM_API_SUCCESS;
1166 int CKMLogic::getCertificateChainHelper(
1167 const Credentials &cred,
1168 const CertificateImpl &cert,
1169 const LabelNameVector &untrusted,
1170 const LabelNameVector &trusted,
1171 bool useTrustedSystemCertificates,
1172 RawBufferVector &chainRawVector)
1174 CertificateImplVector untrustedCertVector;
1175 CertificateImplVector trustedCertVector;
1176 CertificateImplVector chainVector;
1180 return CKM_API_ERROR_INPUT_PARAM;
1182 int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1183 if (retCode != CKM_API_SUCCESS)
1185 retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1186 if (retCode != CKM_API_SUCCESS)
1189 CertificateStore store;
1190 retCode = store.verifyCertificate(cert,
1191 untrustedCertVector,
1193 useTrustedSystemCertificates,
1194 m_accessControl.isCCMode(),
1196 if (retCode != CKM_API_SUCCESS)
1199 for (auto &i: chainVector)
1200 chainRawVector.push_back(i.getDER());
1202 return CKM_API_SUCCESS;
1205 RawBuffer CKMLogic::getCertificateChain(
1206 const Credentials & /*cred*/,
1208 const RawBuffer &certificate,
1209 const RawBufferVector &untrustedCertificates,
1210 const RawBufferVector &trustedCertificates,
1211 bool useTrustedSystemCertificates)
1213 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1214 RawBufferVector chainRawVector;
1215 int retCode = CKM_API_ERROR_UNKNOWN;
1217 retCode = getCertificateChainHelper(cert,
1218 untrustedCertificates,
1219 trustedCertificates,
1220 useTrustedSystemCertificates,
1222 } catch (const CryptoLogic::Exception::Base &e) {
1223 LogError("CryptoLogic failed with message: " << e.GetMessage());
1224 retCode = CKM_API_ERROR_SERVER_ERROR;
1225 } catch (const DBCrypto::Exception::Base &e) {
1226 LogError("DBCrypto failed with message: " << e.GetMessage());
1227 retCode = CKM_API_ERROR_DB_ERROR;
1228 } catch (const std::exception& e) {
1229 LogError("STD exception " << e.what());
1230 retCode = CKM_API_ERROR_SERVER_ERROR;
1232 LogError("Unknown error.");
1235 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_CERT),
1239 return response.Pop();
1242 RawBuffer CKMLogic::getCertificateChain(
1243 const Credentials &cred,
1245 const RawBuffer &certificate,
1246 const LabelNameVector &untrustedCertificates,
1247 const LabelNameVector &trustedCertificates,
1248 bool useTrustedSystemCertificates)
1250 int retCode = CKM_API_ERROR_UNKNOWN;
1251 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1252 RawBufferVector chainRawVector;
1254 retCode = getCertificateChainHelper(cred,
1256 untrustedCertificates,
1257 trustedCertificates,
1258 useTrustedSystemCertificates,
1261 } catch (const CryptoLogic::Exception::Base &e) {
1262 LogError("CryptoLogic failed with message: " << e.GetMessage());
1263 retCode = CKM_API_ERROR_SERVER_ERROR;
1264 } catch (const DBCrypto::Exception::Base &e) {
1265 LogError("DBCrypto failed with message: " << e.GetMessage());
1266 retCode = CKM_API_ERROR_DB_ERROR;
1267 } catch (const std::exception& e) {
1268 LogError("STD exception " << e.what());
1269 retCode = CKM_API_ERROR_SERVER_ERROR;
1271 LogError("Unknown error.");
1274 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_ALIAS),
1278 return response.Pop();
1281 RawBuffer CKMLogic::createSignature(
1282 const Credentials &cred,
1284 const Name &privateKeyName,
1285 const Label & ownerLabel,
1286 const Password &password, // password for private_key
1287 const RawBuffer &message,
1288 const HashAlgorithm hash,
1289 const RSAPaddingAlgorithm padding)
1293 RawBuffer signature;
1295 int retCode = CKM_API_SUCCESS;
1298 retCode = readDataHelper(false, cred, DBDataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, row);
1299 if(retCode == CKM_API_SUCCESS)
1301 KeyImpl keyParsed(row.data, Password());
1302 if (keyParsed.empty())
1303 retCode = CKM_API_ERROR_SERVER_ERROR;
1305 retCode = cs.createSignature(keyParsed, message, hash, padding, signature);
1307 } catch (const KeyProvider::Exception::Base &e) {
1308 LogError("KeyProvider failed with message: " << e.GetMessage());
1309 retCode = CKM_API_ERROR_SERVER_ERROR;
1310 } catch (const CryptoLogic::Exception::Base &e) {
1311 LogError("CryptoLogic failed with message: " << e.GetMessage());
1312 retCode = CKM_API_ERROR_SERVER_ERROR;
1313 } catch (const DBCrypto::Exception::Base &e) {
1314 LogError("DBCrypto failed with message: " << e.GetMessage());
1315 retCode = CKM_API_ERROR_DB_ERROR;
1316 } catch (const CKM::Exception &e) {
1317 LogError("Unknown CKM::Exception: " << e.GetMessage());
1318 retCode = CKM_API_ERROR_SERVER_ERROR;
1321 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_SIGNATURE),
1325 return response.Pop();
1328 RawBuffer CKMLogic::verifySignature(
1329 const Credentials &cred,
1331 const Name &publicKeyOrCertName,
1332 const Label & ownerLabel,
1333 const Password &password, // password for public_key (optional)
1334 const RawBuffer &message,
1335 const RawBuffer &signature,
1336 const HashAlgorithm hash,
1337 const RSAPaddingAlgorithm padding)
1339 int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
1347 // try certificate first - looking for a public key.
1348 // in case of PKCS, pub key from certificate will be found first
1349 // rather than private key from the same PKCS.
1350 retCode = readDataHelper(false, cred, DBDataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, row);
1351 if (retCode == CKM_API_SUCCESS) {
1352 CertificateImpl cert(row.data, DataFormat::FORM_DER);
1353 key = cert.getKeyImpl();
1354 } else if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
1355 retCode = readDataHelper(false, cred, DBDataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, row);
1356 if (retCode != CKM_API_SUCCESS)
1358 key = KeyImpl(row.data);
1364 retCode = CKM_API_ERROR_SERVER_ERROR;
1368 retCode = cs.verifySignature(key, message, signature, hash, padding);
1370 } catch (const CryptoService::Exception::Crypto_internal &e) {
1371 LogError("KeyProvider failed with message: " << e.GetMessage());
1372 retCode = CKM_API_ERROR_SERVER_ERROR;
1373 } catch (const CryptoService::Exception::opensslError &e) {
1374 LogError("KeyProvider failed with message: " << e.GetMessage());
1375 retCode = CKM_API_ERROR_SERVER_ERROR;
1376 } catch (const KeyProvider::Exception::Base &e) {
1377 LogError("KeyProvider failed with error: " << e.GetMessage());
1378 retCode = CKM_API_ERROR_SERVER_ERROR;
1379 } catch (const CryptoLogic::Exception::Base &e) {
1380 LogError("CryptoLogic failed with message: " << e.GetMessage());
1381 retCode = CKM_API_ERROR_SERVER_ERROR;
1382 } catch (const DBCrypto::Exception::Base &e) {
1383 LogError("DBCrypto failed with message: " << e.GetMessage());
1384 retCode = CKM_API_ERROR_DB_ERROR;
1385 } catch (const CKM::Exception &e) {
1386 LogError("Unknown CKM::Exception: " << e.GetMessage());
1387 retCode = CKM_API_ERROR_SERVER_ERROR;
1390 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::VERIFY_SIGNATURE),
1393 return response.Pop();
1396 int CKMLogic::setPermissionHelper(
1397 const Credentials &cred, // who's the client
1399 const Label &label, // who's the owner
1400 const Label &accessorLabel, // who will get the access
1401 const PermissionMask permissionMask)
1403 // we don't know the client
1404 if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel))
1405 return CKM_API_ERROR_INPUT_PARAM;
1407 // use client label if not explicitly provided
1408 const Label& ownerLabel = label.empty() ? cred.smackLabel : label;
1410 // verify name and label are correct
1411 if (!isNameValid(name) || !isLabelValid(ownerLabel) || !isLabelValid(accessorLabel))
1412 return CKM_API_ERROR_INPUT_PARAM;
1414 // currently we don't support modification of owner's permissions to his own rows
1415 if (ownerLabel==accessorLabel)
1416 return CKM_API_ERROR_INPUT_PARAM;
1418 // can the client modify permissions to owner's row?
1419 int access_ec = m_accessControl.canModify(ownerLabel, cred.smackLabel);
1420 if(access_ec != CKM_API_SUCCESS)
1423 if (0 == m_userDataMap.count(cred.uid))
1424 return CKM_API_ERROR_DB_LOCKED;
1426 auto &database = m_userDataMap[cred.uid].database;
1427 DBCrypto::Transaction transaction(&database);
1429 if( !database.isNameLabelPresent(name, ownerLabel) )
1430 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1432 // removing non-existing permissions: fail
1433 if(permissionMask == Permission::NONE)
1435 if(!database.getPermissionRow(name, ownerLabel, accessorLabel))
1436 return CKM_API_ERROR_INPUT_PARAM;
1439 // set permissions to the row owned by ownerLabel for accessorLabel
1440 database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
1441 transaction.commit();
1443 return CKM_API_SUCCESS;
1446 RawBuffer CKMLogic::setPermission(
1447 const Credentials &cred,
1452 const Label &accessorLabel,
1453 const PermissionMask permissionMask)
1457 retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
1458 } Catch (CKM::Exception) {
1459 LogError("Error in set row!");
1460 retCode = CKM_API_ERROR_DB_ERROR;
1463 return MessageBuffer::Serialize(command, msgID, retCode).Pop();