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 <ckm-logic.h>
30 #include <certificate-config.h>
31 #include <certificate-store.h>
33 #include <sw-backend/crypto-service.h>
36 const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs";
38 bool isLabelValid(const CKM::Label &label) {
39 // TODO: copy code from libprivilege control (for check smack label)
40 if (label.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Label::npos)
45 bool isNameValid(const CKM::Name &name) {
46 if (name.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Name::npos)
51 } // anonymous namespace
57 CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
59 m_accessControl.updateCCMode();
62 CKMLogic::~CKMLogic(){}
64 void CKMLogic::loadDKEKFile(uid_t user, const Password &password) {
65 auto &handle = m_userDataMap[user];
69 auto wrappedDKEK = fs.getDKEK();
71 if (wrappedDKEK.empty()) {
72 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
73 fs.saveDKEK(wrappedDKEK);
76 handle.keyProvider = KeyProvider(wrappedDKEK, password);
79 void CKMLogic::saveDKEKFile(uid_t user, const Password &password) {
80 auto &handle = m_userDataMap[user];
83 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
86 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) {
87 int retCode = CKM_API_SUCCESS;
90 if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) {
91 auto &handle = m_userDataMap[user];
94 loadDKEKFile(user, password);
96 auto wrappedDatabaseDEK = fs.getDBDEK();
98 if (wrappedDatabaseDEK.empty()) {
99 wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
100 fs.saveDBDEK(wrappedDatabaseDEK);
103 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
104 handle.database = DB::Crypto(fs.getDBPath(), key);
105 handle.crypto = CryptoLogic();
107 // remove data of removed apps during locked state
108 AppLabelVector removedApps = fs.clearRemovedsApps();
109 for(auto& appSmackLabel : removedApps) {
110 handle.database.deleteKey(appSmackLabel);
113 } catch (const KeyProvider::Exception::PassWordError &e) {
114 LogError("Incorrect Password " << e.GetMessage());
115 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
116 } catch (const KeyProvider::Exception::Base &e) {
117 LogError("Error in KeyProvider " << e.GetMessage());
118 retCode = CKM_API_ERROR_SERVER_ERROR;
119 } catch (const CryptoLogic::Exception::Base &e) {
120 LogError("CryptoLogic error: " << e.GetMessage());
121 retCode = CKM_API_ERROR_SERVER_ERROR;
122 } catch (const FileSystem::Exception::Base &e) {
123 LogError("FileSystem error: " << e.GetMessage());
124 retCode = CKM_API_ERROR_FILE_SYSTEM;
125 } catch (const CKM::Exception &e) {
126 LogError("CKM::Exception: " << e.GetMessage());
127 retCode = CKM_API_ERROR_SERVER_ERROR;
130 if(retCode != CKM_API_SUCCESS) {
131 // When not successful, UserData in m_userDataMap should be erased.
132 // Because other operations make decision based on the existence of UserData in m_userDataMap.
133 m_userDataMap.erase(user);
136 return MessageBuffer::Serialize(retCode).Pop();
139 RawBuffer CKMLogic::updateCCMode() {
140 m_accessControl.updateCCMode();
141 return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
144 RawBuffer CKMLogic::lockUserKey(uid_t user) {
145 int retCode = CKM_API_SUCCESS;
146 // TODO try catch for all errors that should be supported by error code
147 m_userDataMap.erase(user);
149 return MessageBuffer::Serialize(retCode).Pop();
153 RawBuffer CKMLogic::removeUserData(uid_t user) {
154 int retCode = CKM_API_SUCCESS;
155 // TODO try catch for all errors that should be supported by error code
156 m_userDataMap.erase(user);
161 return MessageBuffer::Serialize(retCode).Pop();
164 RawBuffer CKMLogic::changeUserPassword(
166 const Password &oldPassword,
167 const Password &newPassword)
169 int retCode = CKM_API_SUCCESS;
171 loadDKEKFile(user, oldPassword);
172 saveDKEKFile(user, newPassword);
173 } catch (const KeyProvider::Exception::PassWordError &e) {
174 LogError("Incorrect Password " << e.GetMessage());
175 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
176 } catch (const KeyProvider::Exception::Base &e) {
177 LogError("Error in KeyProvider " << e.GetMessage());
178 retCode = CKM_API_ERROR_SERVER_ERROR;
179 } catch (const FileSystem::Exception::Base &e) {
180 LogError("Error in FileSystem " << e.GetMessage());
181 retCode = CKM_API_ERROR_FILE_SYSTEM;
182 } catch (const CKM::Exception &e) {
183 LogError("CKM::Exception: " << e.GetMessage());
184 retCode = CKM_API_ERROR_SERVER_ERROR;
187 return MessageBuffer::Serialize(retCode).Pop();
190 RawBuffer CKMLogic::resetUserPassword(
192 const Password &newPassword)
194 int retCode = CKM_API_SUCCESS;
197 if (0 == m_userDataMap.count(user)) {
198 // Check if key exists. If exists we must return error
200 auto wrappedDKEKMain = fs.getDKEK();
201 if (!wrappedDKEKMain.empty())
202 retCode = CKM_API_ERROR_BAD_REQUEST;
204 saveDKEKFile(user, newPassword);
206 } catch (const FileSystem::Exception::Base &e) {
207 LogError("Error in FileSystem " << e.GetMessage());
208 retCode = CKM_API_ERROR_FILE_SYSTEM;
209 } catch (const CKM::Exception &e) {
210 LogError("CKM::Exception: " << e.GetMessage());
211 retCode = CKM_API_ERROR_SERVER_ERROR;
214 return MessageBuffer::Serialize(retCode).Pop();
217 RawBuffer CKMLogic::removeApplicationData(const Label &smackLabel) {
218 int retCode = CKM_API_SUCCESS;
222 if (smackLabel.empty()) {
223 retCode = CKM_API_ERROR_INPUT_PARAM;
225 UidVector uids = FileSystem::getUIDsFromDBFile();
226 for (auto userId : uids) {
227 if (0 == m_userDataMap.count(userId)) {
228 FileSystem fs(userId);
229 fs.addRemovedApp(smackLabel);
231 auto &handle = m_userDataMap[userId];
232 handle.database.deleteKey(smackLabel);
237 } catch (const DB::Crypto::Exception::InternalError &e) {
238 LogError("DB::Crypto couldn't remove data: " << e.GetMessage());
239 retCode = CKM_API_ERROR_DB_ERROR;
240 } catch (const DB::Crypto::Exception::TransactionError &e) {
241 LogError("DB::Crypto transaction failed with message " << e.GetMessage());
242 retCode = CKM_API_ERROR_DB_ERROR;
243 } catch (const FileSystem::Exception::Base &e) {
244 LogError("Error in FileSystem " << e.GetMessage());
245 retCode = CKM_API_ERROR_FILE_SYSTEM;
246 } catch (const CKM::Exception &e) {
247 LogError("CKM::Exception: " << e.GetMessage());
248 retCode = CKM_API_ERROR_SERVER_ERROR;
251 return MessageBuffer::Serialize(retCode).Pop();
254 int CKMLogic::checkSaveConditions(
255 const Credentials &cred,
258 const Label &ownerLabel)
260 // verify name and label are correct
261 if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
262 LogWarning("Invalid parameter passed to key-manager");
263 return CKM_API_ERROR_INPUT_PARAM;
266 // check if allowed to save using ownerLabel
267 int access_ec = m_accessControl.canSave(ownerLabel, cred.smackLabel);
268 if(access_ec != CKM_API_SUCCESS)
270 LogWarning("label " << cred.smackLabel << " can not save rows using label " << ownerLabel);
274 // check if not a duplicate
275 if( handler.database.isNameLabelPresent(name, cred.smackLabel) )
276 return CKM_API_ERROR_DB_ALIAS_EXISTS;
278 // encryption section
279 if (!handler.crypto.haveKey(cred.smackLabel)) {
281 auto key_optional = handler.database.getKey(cred.smackLabel);
283 LogDebug("No Key in database found. Generating new one for label: "
285 got_key = handler.keyProvider.generateDEK(cred.smackLabel);
286 handler.database.saveKey(cred.smackLabel, got_key);
288 LogDebug("Key from DB");
289 got_key = *key_optional;
292 got_key = handler.keyProvider.getPureDEK(got_key);
293 handler.crypto.pushKey(cred.smackLabel, got_key);
296 return CKM_API_SUCCESS;
299 DB::Row CKMLogic::createEncryptedRow(
304 const RawBuffer &data,
305 const Policy &policy) const
307 DB::Row row = { name, label, policy.extractable, dataType, DBCMAlgType::NONE,
308 0, RawBuffer(), static_cast<int>(data.size()), data, RawBuffer() };
310 // do not encrypt data with password during cc_mode on
311 if(m_accessControl.isCCMode()) {
312 crypto.encryptRow("", row);
314 crypto.encryptRow(policy.password, row);
319 int CKMLogic::verifyBinaryData(DataType dataType, const RawBuffer &input_data) const
321 // verify the data integrity
322 if (dataType.isKey())
324 KeyShPtr output_key = CKM::Key::create(input_data);
325 if(output_key.get() == NULL)
327 LogError("provided binary data is not valid key data");
328 return CKM_API_ERROR_INPUT_PARAM;
331 else if (dataType.isCertificate() || dataType.isChainCert())
333 CertificateShPtr cert = CKM::Certificate::create(input_data, DataFormat::FORM_DER);
334 if(cert.get() == NULL)
336 LogError("provided binary data is not valid certificate data");
337 return CKM_API_ERROR_INPUT_PARAM;
340 // TODO: add here BINARY_DATA verification, i.e: max size etc.
341 return CKM_API_SUCCESS;
344 RawBuffer CKMLogic::saveData(
345 const Credentials &cred,
349 const RawBuffer &data,
351 const PolicySerializable &policy)
354 if (0 == m_userDataMap.count(cred.uid))
355 retCode = CKM_API_ERROR_DB_LOCKED;
359 // check if data is correct
360 retCode = verifyBinaryData(dataType, data);
361 if(retCode == CKM_API_SUCCESS)
363 retCode = saveDataHelper(cred, name, label, dataType, data, policy);
365 } catch (const KeyProvider::Exception::Base &e) {
366 LogError("KeyProvider failed with message: " << e.GetMessage());
367 retCode = CKM_API_ERROR_SERVER_ERROR;
368 } catch (const CryptoLogic::Exception::Base &e) {
369 LogError("CryptoLogic failed with message: " << e.GetMessage());
370 retCode = CKM_API_ERROR_SERVER_ERROR;
371 } catch (const DB::Crypto::Exception::InternalError &e) {
372 LogError("DB::Crypto failed with message: " << e.GetMessage());
373 retCode = CKM_API_ERROR_DB_ERROR;
374 } catch (const DB::Crypto::Exception::TransactionError &e) {
375 LogError("DB::Crypto transaction failed with message " << e.GetMessage());
376 retCode = CKM_API_ERROR_DB_ERROR;
377 } catch (const FileSystem::Exception::Base &e) {
378 LogError("Error in FileSystem " << e.GetMessage());
379 retCode = CKM_API_ERROR_FILE_SYSTEM;
380 } catch (const CKM::Exception &e) {
381 LogError("CKM::Exception: " << e.GetMessage());
382 retCode = CKM_API_ERROR_SERVER_ERROR;
386 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
389 static_cast<int>(dataType));
390 return response.Pop();
393 int CKMLogic::extractPKCS12Data(
396 const Label &ownerLabel,
397 const PKCS12Serializable &pkcs,
398 const PolicySerializable &keyPolicy,
399 const PolicySerializable &certPolicy,
400 DB::RowVector &output) const
402 // private key is mandatory
404 return CKM_API_ERROR_INVALID_FORMAT;
405 Key* keyPtr = pkcs.getKey().get();
406 DataType keyType = DataType(keyPtr->getType());
407 RawBuffer keyData = keyPtr->getDER();
408 int retCode = verifyBinaryData(keyType, keyData);
409 if(retCode != CKM_API_SUCCESS)
411 output.push_back(createEncryptedRow(crypto, name, ownerLabel, keyType, keyData, keyPolicy));
413 // certificate is mandatory
414 if( !pkcs.getCertificate() )
415 return CKM_API_ERROR_INVALID_FORMAT;
416 RawBuffer certData = pkcs.getCertificate().get()->getDER();
417 retCode = verifyBinaryData(DataType::CERTIFICATE, certData);
418 if(retCode != CKM_API_SUCCESS)
420 output.push_back(createEncryptedRow(crypto, name, ownerLabel, DataType::CERTIFICATE, certData, certPolicy));
423 unsigned int cert_index = 0;
424 for(const auto & ca : pkcs.getCaCertificateShPtrVector())
426 DataType chainDataType = DataType::getChainDatatype(cert_index ++);
427 RawBuffer caCertData = ca->getDER();
428 int retCode = verifyBinaryData(chainDataType, caCertData);
429 if(retCode != CKM_API_SUCCESS)
432 output.push_back(createEncryptedRow(crypto, name, ownerLabel, chainDataType, caCertData, certPolicy));
435 return CKM_API_SUCCESS;
438 RawBuffer CKMLogic::savePKCS12(
439 const Credentials &cred,
443 const PKCS12Serializable &pkcs,
444 const PolicySerializable &keyPolicy,
445 const PolicySerializable &certPolicy)
448 if (0 == m_userDataMap.count(cred.uid))
449 retCode = CKM_API_ERROR_DB_LOCKED;
453 retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy);
454 } catch (const KeyProvider::Exception::Base &e) {
455 LogError("KeyProvider failed with message: " << e.GetMessage());
456 retCode = CKM_API_ERROR_SERVER_ERROR;
457 } catch (const CryptoLogic::Exception::Base &e) {
458 LogError("CryptoLogic failed with message: " << e.GetMessage());
459 retCode = CKM_API_ERROR_SERVER_ERROR;
460 } catch (const DB::Crypto::Exception::InternalError &e) {
461 LogError("DB::Crypto failed with message: " << e.GetMessage());
462 retCode = CKM_API_ERROR_DB_ERROR;
463 } catch (const DB::Crypto::Exception::TransactionError &e) {
464 LogError("DB::Crypto transaction failed with message " << e.GetMessage());
465 retCode = CKM_API_ERROR_DB_ERROR;
466 } catch (const CKM::Exception &e) {
467 LogError("CKM::Exception: " << e.GetMessage());
468 retCode = CKM_API_ERROR_SERVER_ERROR;
472 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE_PKCS12),
475 return response.Pop();
479 int CKMLogic::removeDataHelper(
480 const Credentials &cred,
482 const Label &ownerLabel)
484 if (0 == m_userDataMap.count(cred.uid))
485 return CKM_API_ERROR_DB_LOCKED;
487 if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
488 LogError("Invalid label or name format");
489 return CKM_API_ERROR_INPUT_PARAM;
492 auto &database = m_userDataMap[cred.uid].database;
493 DB::Crypto::Transaction transaction(&database);
495 // read and check permissions
496 PermissionMaskOptional permissionRowOpt =
497 database.getPermissionRow(name, ownerLabel, cred.smackLabel);
498 int access_ec = m_accessControl.canDelete(PermissionForLabel(cred.smackLabel, permissionRowOpt));
499 if(access_ec != CKM_API_SUCCESS)
501 LogWarning("access control check result: " << access_ec);
505 auto erased = database.deleteRow(name, ownerLabel);
506 // check if the data existed or not
508 transaction.commit();
510 LogError("No row for given name and label");
511 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
514 return CKM_API_SUCCESS;
517 RawBuffer CKMLogic::removeData(
518 const Credentials &cred,
525 // use client label if not explicitly provided
526 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
528 retCode = removeDataHelper(cred, name, ownerLabel);
529 } Catch (CKM::Exception) {
530 LogError("Error in deleting row!");
531 retCode = CKM_API_ERROR_DB_ERROR;
534 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
537 return response.Pop();
540 int CKMLogic::readSingleRow(const Name &name,
541 const Label &ownerLabel,
543 DB::Crypto & database,
546 DB::Crypto::RowOptional row_optional;
547 if (dataType.isKey())
549 // read all key types
550 row_optional = database.getRow(name,
552 DataType::DB_KEY_FIRST,
553 DataType::DB_KEY_LAST);
555 // read anything else
556 row_optional = database.getRow(name,
562 LogError("No row for given name, label and type");
563 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
568 return CKM_API_SUCCESS;
572 int CKMLogic::readMultiRow(const Name &name,
573 const Label &ownerLabel,
575 DB::Crypto & database,
576 DB::RowVector &output)
578 if (dataType.isKey())
580 // read all key types
581 database.getRows(name,
583 DataType::DB_KEY_FIRST,
584 DataType::DB_KEY_LAST,
587 else if (dataType.isChainCert())
589 // read all key types
590 database.getRows(name,
592 DataType::DB_CHAIN_FIRST,
593 DataType::DB_CHAIN_LAST,
598 // read anything else
599 database.getRows(name,
606 LogError("No row for given name, label and type");
607 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
610 return CKM_API_SUCCESS;
613 int CKMLogic::checkDataPermissionsHelper(const Name &name,
614 const Label &ownerLabel,
615 const Label &accessorLabel,
618 DB::Crypto & database)
620 PermissionMaskOptional permissionRowOpt =
621 database.getPermissionRow(name, ownerLabel, accessorLabel);
624 return m_accessControl.canExport(row, PermissionForLabel(accessorLabel, permissionRowOpt));
625 return m_accessControl.canRead(PermissionForLabel(accessorLabel, permissionRowOpt));
628 int CKMLogic::readDataHelper(
630 const Credentials &cred,
634 const Password &password,
637 if (0 == m_userDataMap.count(cred.uid))
638 return CKM_API_ERROR_DB_LOCKED;
640 // use client label if not explicitly provided
641 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
643 if (!isNameValid(name) || !isLabelValid(ownerLabel))
644 return CKM_API_ERROR_INPUT_PARAM;
646 auto &handler = m_userDataMap[cred.uid];
649 DB::Crypto::Transaction transaction(&handler.database);
650 int ec = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
651 if(CKM_API_SUCCESS != ec)
654 // all read rows belong to the same owner
655 DB::Row & firstRow = rows.at(0);
657 // check access rights
658 ec = checkDataPermissionsHelper(name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database);
659 if(CKM_API_SUCCESS != ec)
663 if (!handler.crypto.haveKey(firstRow.ownerLabel)) {
665 auto key_optional = handler.database.getKey(firstRow.ownerLabel);
667 LogError("No key for given label in database");
668 return CKM_API_ERROR_DB_ERROR;
671 key = handler.keyProvider.getPureDEK(key);
672 handler.crypto.pushKey(firstRow.ownerLabel, key);
674 for(auto &row : rows)
675 handler.crypto.decryptRow(password, row);
677 return CKM_API_SUCCESS;
680 int CKMLogic::readDataHelper(
682 const Credentials &cred,
686 const Password &password,
689 if (0 == m_userDataMap.count(cred.uid))
690 return CKM_API_ERROR_DB_LOCKED;
692 // use client label if not explicitly provided
693 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
695 if (!isNameValid(name) || !isLabelValid(ownerLabel))
696 return CKM_API_ERROR_INPUT_PARAM;
698 auto &handler = m_userDataMap[cred.uid];
701 DB::Crypto::Transaction transaction(&handler.database);
702 int ec = readSingleRow(name, ownerLabel, dataType, handler.database, row);
703 if(CKM_API_SUCCESS != ec)
707 // check access rights
708 ec = checkDataPermissionsHelper(name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
709 if(CKM_API_SUCCESS != ec)
713 if (!handler.crypto.haveKey(row.ownerLabel)) {
715 auto key_optional = handler.database.getKey(row.ownerLabel);
717 LogError("No key for given label in database");
718 return CKM_API_ERROR_DB_ERROR;
721 key = handler.keyProvider.getPureDEK(key);
722 handler.crypto.pushKey(row.ownerLabel, key);
724 handler.crypto.decryptRow(password, row);
726 return CKM_API_SUCCESS;
729 RawBuffer CKMLogic::getData(
730 const Credentials &cred,
735 const Password &password)
737 int retCode = CKM_API_SUCCESS;
741 retCode = readDataHelper(true, cred, dataType, name, label, password, row);
742 } catch (const KeyProvider::Exception::Base &e) {
743 LogError("KeyProvider failed with error: " << e.GetMessage());
744 retCode = CKM_API_ERROR_SERVER_ERROR;
745 } catch (const CryptoLogic::Exception::DecryptDBRowError &e) {
746 LogError("CryptoLogic failed with message: " << e.GetMessage());
747 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
748 } catch (const CryptoLogic::Exception::Base &e) {
749 LogError("CryptoLogic failed with message: " << e.GetMessage());
750 retCode = CKM_API_ERROR_SERVER_ERROR;
751 } catch (const DB::Crypto::Exception::Base &e) {
752 LogError("DB::Crypto failed with message: " << e.GetMessage());
753 retCode = CKM_API_ERROR_DB_ERROR;
754 } catch (const CKM::Exception &e) {
755 LogError("CKM::Exception: " << e.GetMessage());
756 retCode = CKM_API_ERROR_SERVER_ERROR;
759 if (CKM_API_SUCCESS != retCode) {
761 row.dataType = dataType;
764 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
767 static_cast<int>(row.dataType),
769 return response.Pop();
772 int CKMLogic::getPKCS12Helper(
773 const Credentials &cred,
776 const Password &keyPassword,
777 const Password &certPassword,
779 CertificateShPtr & cert,
780 CertificateShPtrVector & caChain)
784 // read private key (mandatory)
786 retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, label, keyPassword, privKeyRow);
787 if(retCode != CKM_API_SUCCESS)
789 privKey = CKM::Key::create(privKeyRow.data);
791 // read certificate (mandatory)
793 retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label, certPassword, certRow);
794 if(retCode != CKM_API_SUCCESS)
796 cert = CKM::Certificate::create(certRow.data, DataFormat::FORM_DER);
798 // read CA cert chain (optional)
799 DB::RowVector rawCaChain;
800 retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label, certPassword, rawCaChain);
801 if(retCode != CKM_API_SUCCESS &&
802 retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
804 for(auto &rawCaCert : rawCaChain)
805 caChain.push_back(CKM::Certificate::create(rawCaCert.data, DataFormat::FORM_DER));
807 // if anything found, return it
808 if(privKey || cert || caChain.size()>0)
809 retCode = CKM_API_SUCCESS;
814 RawBuffer CKMLogic::getPKCS12(
815 const Credentials &cred,
819 const Password &keyPassword,
820 const Password &certPassword)
823 PKCS12Serializable output;
827 CertificateShPtr cert;
828 CertificateShPtrVector caChain;
829 retCode = getPKCS12Helper(cred, name, label, keyPassword, certPassword, privKey, cert, caChain);
832 if(retCode == CKM_API_SUCCESS)
833 output = PKCS12Serializable(privKey, cert, caChain);
835 } catch (const KeyProvider::Exception::Base &e) {
836 LogError("KeyProvider failed with error: " << e.GetMessage());
837 retCode = CKM_API_ERROR_SERVER_ERROR;
838 } catch (const CryptoLogic::Exception::DecryptDBRowError &e) {
839 LogError("CryptoLogic failed with message: " << e.GetMessage());
840 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
841 } catch (const CryptoLogic::Exception::Base &e) {
842 LogError("CryptoLogic failed with message: " << e.GetMessage());
843 retCode = CKM_API_ERROR_SERVER_ERROR;
844 } catch (const DB::Crypto::Exception::Base &e) {
845 LogError("DB::Crypto failed with message: " << e.GetMessage());
846 retCode = CKM_API_ERROR_DB_ERROR;
847 } catch (const CKM::Exception &e) {
848 LogError("CKM::Exception: " << e.GetMessage());
849 retCode = CKM_API_ERROR_SERVER_ERROR;
852 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_PKCS12),
856 return response.Pop();
859 RawBuffer CKMLogic::getDataList(
860 const Credentials &cred,
864 int retCode = CKM_API_SUCCESS;
865 LabelNameVector labelNameVector;
867 if (0 < m_userDataMap.count(cred.uid)) {
868 auto &database = m_userDataMap[cred.uid].database;
871 if (dataType.isKey()) {
872 // list all key types
873 database.listNames(cred.smackLabel,
875 DataType::DB_KEY_FIRST,
876 DataType::DB_KEY_LAST);
878 // list anything else
879 database.listNames(cred.smackLabel,
884 Catch (CKM::Exception) {
885 LogError("Failed to get names");
886 retCode = CKM_API_ERROR_DB_ERROR;
889 retCode = CKM_API_ERROR_DB_LOCKED;
892 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_LIST),
895 static_cast<int>(dataType),
897 return response.Pop();
900 int CKMLogic::saveDataHelper(
901 const Credentials &cred,
905 const RawBuffer &data,
906 const PolicySerializable &policy)
908 auto &handler = m_userDataMap[cred.uid];
910 // use client label if not explicitly provided
911 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
913 // check if save is possible
914 DB::Crypto::Transaction transaction(&handler.database);
915 int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
916 if(retCode != CKM_API_SUCCESS)
920 DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, ownerLabel, dataType, data, policy);
921 handler.database.saveRow(encryptedRow);
923 transaction.commit();
924 return CKM_API_SUCCESS;
927 int CKMLogic::saveDataHelper(
928 const Credentials &cred,
931 const PKCS12Serializable &pkcs,
932 const PolicySerializable &keyPolicy,
933 const PolicySerializable &certPolicy)
935 auto &handler = m_userDataMap[cred.uid];
937 // use client label if not explicitly provided
938 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
940 // check if save is possible
941 DB::Crypto::Transaction transaction(&handler.database);
942 int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
943 if(retCode != CKM_API_SUCCESS)
946 // extract and encrypt the data
947 DB::RowVector encryptedRows;
948 retCode = extractPKCS12Data(handler.crypto, name, ownerLabel, pkcs, keyPolicy, certPolicy, encryptedRows);
949 if(retCode != CKM_API_SUCCESS)
953 handler.database.saveRows(name, ownerLabel, encryptedRows);
954 transaction.commit();
956 return CKM_API_SUCCESS;
960 int CKMLogic::createKeyPairHelper(
961 const Credentials &cred,
962 const KeyType key_type,
963 const int additional_param,
964 const Name &namePrivate,
965 const Label &labelPrivate,
966 const Name &namePublic,
967 const Label &labelPublic,
968 const PolicySerializable &policyPrivate,
969 const PolicySerializable &policyPublic)
971 if (0 == m_userDataMap.count(cred.uid))
972 return CKM_API_ERROR_DB_LOCKED;
978 case KeyType::KEY_RSA_PUBLIC:
979 case KeyType::KEY_RSA_PRIVATE:
980 retCode = Crypto::SW::CryptoService::createKeyPairRSA(additional_param, prv, pub);
983 case KeyType::KEY_DSA_PUBLIC:
984 case KeyType::KEY_DSA_PRIVATE:
985 retCode = Crypto::SW::CryptoService::createKeyPairDSA(additional_param, prv, pub);
988 case KeyType::KEY_ECDSA_PUBLIC:
989 case KeyType::KEY_ECDSA_PRIVATE:
990 retCode = Crypto::SW::CryptoService::createKeyPairECDSA(static_cast<ElipticCurve>(additional_param), prv, pub);
994 return CKM_API_ERROR_INPUT_PARAM;
997 if (CKM_CRYPTO_CREATEKEY_SUCCESS != retCode)
999 LogDebug("CryptoService error with code: " << retCode);
1000 return CKM_API_ERROR_SERVER_ERROR; // TODO error code
1003 auto &database = m_userDataMap[cred.uid].database;
1004 DB::Crypto::Transaction transaction(&database);
1006 retCode = saveDataHelper(cred,
1009 DataType(prv.getType()),
1012 if (CKM_API_SUCCESS != retCode)
1015 retCode = saveDataHelper(cred,
1018 DataType(pub.getType()),
1021 if (CKM_API_SUCCESS != retCode)
1024 transaction.commit();
1029 RawBuffer CKMLogic::createKeyPair(
1030 const Credentials &cred,
1031 LogicCommand protocol_cmd,
1033 const int additional_param,
1034 const Name &namePrivate,
1035 const Label &labelPrivate,
1036 const Name &namePublic,
1037 const Label &labelPublic,
1038 const PolicySerializable &policyPrivate,
1039 const PolicySerializable &policyPublic)
1041 int retCode = CKM_API_SUCCESS;
1043 KeyType key_type = KeyType::KEY_NONE;
1044 switch(protocol_cmd)
1046 case LogicCommand::CREATE_KEY_PAIR_RSA:
1047 key_type = KeyType::KEY_RSA_PUBLIC;
1049 case LogicCommand::CREATE_KEY_PAIR_DSA:
1050 key_type = KeyType::KEY_DSA_PUBLIC;
1052 case LogicCommand::CREATE_KEY_PAIR_ECDSA:
1053 key_type = KeyType::KEY_ECDSA_PUBLIC;
1060 retCode = createKeyPairHelper(
1070 } catch (DB::Crypto::Exception::TransactionError &e) {
1071 LogDebug("DB::Crypto error: transaction error: " << e.GetMessage());
1072 retCode = CKM_API_ERROR_DB_ERROR;
1073 } catch (CKM::CryptoLogic::Exception::Base &e) {
1074 LogDebug("CryptoLogic error: " << e.GetMessage());
1075 retCode = CKM_API_ERROR_SERVER_ERROR;
1076 } catch (DB::Crypto::Exception::InternalError &e) {
1077 LogDebug("DB::Crypto internal error: " << e.GetMessage());
1078 retCode = CKM_API_ERROR_DB_ERROR;
1079 } catch (const CKM::Exception &e) {
1080 LogError("CKM::Exception: " << e.GetMessage());
1081 retCode = CKM_API_ERROR_SERVER_ERROR;
1084 return MessageBuffer::Serialize(static_cast<int>(protocol_cmd), commandId, retCode).Pop();
1087 int CKMLogic::readCertificateHelper(
1088 const Credentials &cred,
1089 const LabelNameVector &labelNameVector,
1090 CertificateImplVector &certVector)
1093 for (auto &i: labelNameVector) {
1094 int ec = readDataHelper(false, cred, DataType::CERTIFICATE, i.second, i.first, Password(), row);
1095 if (ec != CKM_API_SUCCESS)
1097 certVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER));
1099 // try to read chain certificates (if present)
1100 DB::RowVector rawCaChain;
1101 ec = readDataHelper(false, cred, DataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), rawCaChain);
1102 if(ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1104 for(auto &rawCaCert : rawCaChain)
1105 certVector.push_back(CertificateImpl(rawCaCert.data, DataFormat::FORM_DER));
1107 return CKM_API_SUCCESS;
1110 int CKMLogic::getCertificateChainHelper(
1111 const CertificateImpl &cert,
1112 const RawBufferVector &untrustedCertificates,
1113 const RawBufferVector &trustedCertificates,
1114 bool useTrustedSystemCertificates,
1115 RawBufferVector &chainRawVector)
1117 CertificateImplVector untrustedCertVector;
1118 CertificateImplVector trustedCertVector;
1119 CertificateImplVector chainVector;
1122 return CKM_API_ERROR_INPUT_PARAM;
1124 for (auto &e: untrustedCertificates)
1125 untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1126 for (auto &e: trustedCertificates)
1127 trustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1129 CertificateStore store;
1130 int retCode = store.verifyCertificate(cert,
1131 untrustedCertVector,
1133 useTrustedSystemCertificates,
1134 m_accessControl.isCCMode(),
1136 if (retCode != CKM_API_SUCCESS)
1139 for (auto &e : chainVector)
1140 chainRawVector.push_back(e.getDER());
1141 return CKM_API_SUCCESS;
1144 int CKMLogic::getCertificateChainHelper(
1145 const Credentials &cred,
1146 const CertificateImpl &cert,
1147 const LabelNameVector &untrusted,
1148 const LabelNameVector &trusted,
1149 bool useTrustedSystemCertificates,
1150 RawBufferVector &chainRawVector)
1152 CertificateImplVector untrustedCertVector;
1153 CertificateImplVector trustedCertVector;
1154 CertificateImplVector chainVector;
1158 return CKM_API_ERROR_INPUT_PARAM;
1160 int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1161 if (retCode != CKM_API_SUCCESS)
1163 retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1164 if (retCode != CKM_API_SUCCESS)
1167 CertificateStore store;
1168 retCode = store.verifyCertificate(cert,
1169 untrustedCertVector,
1171 useTrustedSystemCertificates,
1172 m_accessControl.isCCMode(),
1174 if (retCode != CKM_API_SUCCESS)
1177 for (auto &i: chainVector)
1178 chainRawVector.push_back(i.getDER());
1180 return CKM_API_SUCCESS;
1183 RawBuffer CKMLogic::getCertificateChain(
1184 const Credentials & /*cred*/,
1186 const RawBuffer &certificate,
1187 const RawBufferVector &untrustedCertificates,
1188 const RawBufferVector &trustedCertificates,
1189 bool useTrustedSystemCertificates)
1191 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1192 RawBufferVector chainRawVector;
1193 int retCode = CKM_API_ERROR_UNKNOWN;
1195 retCode = getCertificateChainHelper(cert,
1196 untrustedCertificates,
1197 trustedCertificates,
1198 useTrustedSystemCertificates,
1200 } catch (const CryptoLogic::Exception::Base &e) {
1201 LogError("CryptoLogic failed with message: " << e.GetMessage());
1202 retCode = CKM_API_ERROR_SERVER_ERROR;
1203 } catch (const DB::Crypto::Exception::Base &e) {
1204 LogError("DB::Crypto failed with message: " << e.GetMessage());
1205 retCode = CKM_API_ERROR_DB_ERROR;
1206 } catch (const std::exception& e) {
1207 LogError("STD exception " << e.what());
1208 retCode = CKM_API_ERROR_SERVER_ERROR;
1210 LogError("Unknown error.");
1213 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_CERT),
1217 return response.Pop();
1220 RawBuffer CKMLogic::getCertificateChain(
1221 const Credentials &cred,
1223 const RawBuffer &certificate,
1224 const LabelNameVector &untrustedCertificates,
1225 const LabelNameVector &trustedCertificates,
1226 bool useTrustedSystemCertificates)
1228 int retCode = CKM_API_ERROR_UNKNOWN;
1229 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1230 RawBufferVector chainRawVector;
1232 retCode = getCertificateChainHelper(cred,
1234 untrustedCertificates,
1235 trustedCertificates,
1236 useTrustedSystemCertificates,
1238 } catch (const CryptoLogic::Exception::DecryptDBRowError &e) {
1239 LogError("CryptoLogic failed with message: " << e.GetMessage());
1240 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
1241 } catch (const CryptoLogic::Exception::Base &e) {
1242 LogError("CryptoLogic failed with message: " << e.GetMessage());
1243 retCode = CKM_API_ERROR_SERVER_ERROR;
1244 } catch (const DB::Crypto::Exception::Base &e) {
1245 LogError("DB::Crypto failed with message: " << e.GetMessage());
1246 retCode = CKM_API_ERROR_DB_ERROR;
1247 } catch (const std::exception& e) {
1248 LogError("STD exception " << e.what());
1249 retCode = CKM_API_ERROR_SERVER_ERROR;
1251 LogError("Unknown error.");
1254 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_ALIAS),
1258 return response.Pop();
1261 RawBuffer CKMLogic::createSignature(
1262 const Credentials &cred,
1264 const Name &privateKeyName,
1265 const Label & ownerLabel,
1266 const Password &password, // password for private_key
1267 const RawBuffer &message,
1268 const HashAlgorithm hash,
1269 const RSAPaddingAlgorithm padding)
1272 Crypto::SW::CryptoService cs;
1273 RawBuffer signature;
1275 int retCode = CKM_API_SUCCESS;
1278 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, row);
1279 if(retCode == CKM_API_SUCCESS)
1281 KeyImpl keyParsed(row.data, Password());
1282 if (keyParsed.empty())
1283 retCode = CKM_API_ERROR_SERVER_ERROR;
1285 retCode = cs.createSignature(keyParsed, message, hash, padding, signature);
1287 } catch (const KeyProvider::Exception::Base &e) {
1288 LogError("KeyProvider failed with message: " << e.GetMessage());
1289 retCode = CKM_API_ERROR_SERVER_ERROR;
1290 } catch (const CryptoLogic::Exception::DecryptDBRowError &e) {
1291 LogError("CryptoLogic failed with message: " << e.GetMessage());
1292 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
1293 } catch (const CryptoLogic::Exception::Base &e) {
1294 LogError("CryptoLogic failed with message: " << e.GetMessage());
1295 retCode = CKM_API_ERROR_SERVER_ERROR;
1296 } catch (const DB::Crypto::Exception::Base &e) {
1297 LogError("DB::Crypto failed with message: " << e.GetMessage());
1298 retCode = CKM_API_ERROR_DB_ERROR;
1299 } catch (const CKM::Exception &e) {
1300 LogError("Unknown CKM::Exception: " << e.GetMessage());
1301 retCode = CKM_API_ERROR_SERVER_ERROR;
1304 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_SIGNATURE),
1308 return response.Pop();
1311 RawBuffer CKMLogic::verifySignature(
1312 const Credentials &cred,
1314 const Name &publicKeyOrCertName,
1315 const Label & ownerLabel,
1316 const Password &password, // password for public_key (optional)
1317 const RawBuffer &message,
1318 const RawBuffer &signature,
1319 const HashAlgorithm hash,
1320 const RSAPaddingAlgorithm padding)
1322 int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
1326 Crypto::SW::CryptoService cs;
1330 // try certificate first - looking for a public key.
1331 // in case of PKCS, pub key from certificate will be found first
1332 // rather than private key from the same PKCS.
1333 retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, row);
1334 if (retCode == CKM_API_SUCCESS) {
1335 CertificateImpl cert(row.data, DataFormat::FORM_DER);
1336 key = cert.getKeyImpl();
1337 } else if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
1338 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, row);
1339 if (retCode != CKM_API_SUCCESS)
1341 key = KeyImpl(row.data);
1347 retCode = CKM_API_ERROR_SERVER_ERROR;
1351 retCode = cs.verifySignature(key, message, signature, hash, padding);
1353 } catch (const Crypto::SW::CryptoService::Exception::Crypto_internal &e) {
1354 LogError("KeyProvider failed with message: " << e.GetMessage());
1355 retCode = CKM_API_ERROR_SERVER_ERROR;
1356 } catch (const Crypto::SW::CryptoService::Exception::opensslError &e) {
1357 LogError("KeyProvider failed with message: " << e.GetMessage());
1358 retCode = CKM_API_ERROR_SERVER_ERROR;
1359 } catch (const KeyProvider::Exception::Base &e) {
1360 LogError("KeyProvider failed with error: " << e.GetMessage());
1361 retCode = CKM_API_ERROR_SERVER_ERROR;
1362 } catch (const CryptoLogic::Exception::DecryptDBRowError &e) {
1363 LogError("CryptoLogic failed with message: " << e.GetMessage());
1364 retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
1365 } catch (const CryptoLogic::Exception::Base &e) {
1366 LogError("CryptoLogic failed with message: " << e.GetMessage());
1367 retCode = CKM_API_ERROR_SERVER_ERROR;
1368 } catch (const DB::Crypto::Exception::Base &e) {
1369 LogError("DB::Crypto failed with message: " << e.GetMessage());
1370 retCode = CKM_API_ERROR_DB_ERROR;
1371 } catch (const CKM::Exception &e) {
1372 LogError("Unknown CKM::Exception: " << e.GetMessage());
1373 retCode = CKM_API_ERROR_SERVER_ERROR;
1376 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::VERIFY_SIGNATURE),
1379 return response.Pop();
1382 int CKMLogic::setPermissionHelper(
1383 const Credentials &cred, // who's the client
1385 const Label &label, // who's the owner
1386 const Label &accessorLabel, // who will get the access
1387 const PermissionMask permissionMask)
1389 // we don't know the client
1390 if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel))
1391 return CKM_API_ERROR_INPUT_PARAM;
1393 // use client label if not explicitly provided
1394 const Label& ownerLabel = label.empty() ? cred.smackLabel : label;
1396 // verify name and label are correct
1397 if (!isNameValid(name) || !isLabelValid(ownerLabel) || !isLabelValid(accessorLabel))
1398 return CKM_API_ERROR_INPUT_PARAM;
1400 // currently we don't support modification of owner's permissions to his own rows
1401 if (ownerLabel==accessorLabel)
1402 return CKM_API_ERROR_INPUT_PARAM;
1404 // can the client modify permissions to owner's row?
1405 int access_ec = m_accessControl.canModify(ownerLabel, cred.smackLabel);
1406 if(access_ec != CKM_API_SUCCESS)
1409 if (0 == m_userDataMap.count(cred.uid))
1410 return CKM_API_ERROR_DB_LOCKED;
1412 auto &database = m_userDataMap[cred.uid].database;
1413 DB::Crypto::Transaction transaction(&database);
1415 if( !database.isNameLabelPresent(name, ownerLabel) )
1416 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1418 // removing non-existing permissions: fail
1419 if(permissionMask == Permission::NONE)
1421 if(!database.getPermissionRow(name, ownerLabel, accessorLabel))
1422 return CKM_API_ERROR_INPUT_PARAM;
1425 // set permissions to the row owned by ownerLabel for accessorLabel
1426 database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
1427 transaction.commit();
1429 return CKM_API_SUCCESS;
1432 RawBuffer CKMLogic::setPermission(
1433 const Credentials &cred,
1438 const Label &accessorLabel,
1439 const PermissionMask permissionMask)
1443 retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
1444 } Catch (CKM::Exception) {
1445 LogError("Error in set row!");
1446 retCode = CKM_API_ERROR_DB_ERROR;
1449 return MessageBuffer::Serialize(command, msgID, retCode).Pop();