X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fmanager%2Fservice%2Fckm-logic.cpp;h=0154933060a4bc014ac6dd2479ab3f05829925e2;hb=05f39b404b29c1471c8f7d3477548c86699f3456;hp=1e9c14c633c1de4eaeb2b46be88636e0bd175dcc;hpb=70cc3da3f521e834a2a8cb3e61fa716d9446b9b9;p=platform%2Fcore%2Fsecurity%2Fkey-manager.git diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index 1e9c14c..0154933 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -21,276 +21,860 @@ */ #include #include -#include -#include #include #include #include #include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace { -const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs"; +const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs"; +const char * const INIT_VALUES_DIR = "/opt/data/ckm/initial_values/"; +const char * const INIT_VALUES_XSD = "/usr/share/ckm/initial_values.xsd"; +const char * const INIT_VALUES_FILE_SUFFIX = ".xml"; +const char * const SYSTEM_DB_PASSWD = "cAtRugU7"; + +bool isLabelValid(const CKM::Label &label) { + // TODO: copy code from libprivilege control (for check smack label) + if (label.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Label::npos) + return false; + return true; +} + +bool isNameValid(const CKM::Name &name) { + if (name.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Name::npos) + return false; + return true; +} } // anonymous namespace namespace CKM { +const uid_t CKMLogic::SYSTEM_DB_UID = 0; + CKMLogic::CKMLogic() { - int retCode = FileSystem::init(); - // TODO what can I do when init went wrong? exit(-1) ?? - if (retCode) { - LogError("Fatal error in FileSystem::init()"); + CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR); + + m_accessControl.updateCCMode(); + + // make initial file list + std::vector filesToParse; + DIR *dp = opendir(INIT_VALUES_DIR); + if(dp) + { + struct dirent *entry; + while ((entry = readdir(dp))) + { + std::string filename = std::string(entry->d_name); + + // check if XML file + std::string lowercaseFilename = filename; + std::transform(lowercaseFilename.begin(), lowercaseFilename.end(), lowercaseFilename.begin(), ::tolower); + if(lowercaseFilename.find(INIT_VALUES_FILE_SUFFIX) == std::string::npos) + continue; + + filesToParse.push_back(std::string(INIT_VALUES_DIR) + filename); + } + closedir(dp); } - if (CKM_API_SUCCESS != m_certStore.setSystemCertificateDir(CERT_SYSTEM_DIR)) { - LogError("Fatal error in CertificateStore::setSystemCertificateDir. Chain creation will not work"); + // parse + for(const auto & file : filesToParse) + { + InitialValues::InitialValuesFile xmlFile(file.c_str(), *this); + int rc = xmlFile.Validate(INIT_VALUES_XSD); + if(rc == XML::Parser::PARSE_SUCCESS) + { + rc = xmlFile.Parse(); + if(rc != XML::Parser::PARSE_SUCCESS) + LogError("invalid initial values file: " << file << ", parsing code: " << rc); + } + else + LogError("invalid initial values file: " << file << ", validation code: " << rc); + unlink(file.c_str()); } } CKMLogic::~CKMLogic(){} -RawBuffer CKMLogic::unlockUserKey(uid_t user, const std::string &password) { - // TODO try catch for all errors that should be supported by error code +void CKMLogic::loadDKEKFile(uid_t user, const Password &password) { + auto &handle = m_userDataMap[user]; + + FileSystem fs(user); + + auto wrappedDKEK = fs.getDKEK(); + + if (wrappedDKEK.empty()) { + wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password); + fs.saveDKEK(wrappedDKEK); + } + + handle.keyProvider = KeyProvider(wrappedDKEK, password); +} + +void CKMLogic::saveDKEKFile(uid_t user, const Password &password) { + auto &handle = m_userDataMap[user]; + + FileSystem fs(user); + fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password)); +} + +int CKMLogic::unlockDatabase(uid_t user, const Password & password) +{ + if (0 switch to system DB + if ( !m_accessControl.isSystemService(cred) ) + { + if (0 == m_userDataMap.count(cred.clientUid)) + ThrowMsg(Exception::DatabaseLocked, "database with UID: " << cred.clientUid << " locked"); + + if (0 != incoming_label.compare(LABEL_SYSTEM_DB)) + return m_userDataMap[cred.clientUid]; + } + + // system database selected, modify the label + if (CKM_API_SUCCESS != unlockSystemDB() ) + ThrowMsg(Exception::DatabaseLocked, "can not unlock system database"); + return m_userDataMap[SYSTEM_DB_UID]; +} + +RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) +{ int retCode = CKM_API_SUCCESS; - // TODO try catch for all errors that should be supported by error code - m_userDataMap.erase(user); - MessageBuffer response; - Serialization::Serialize(response, retCode); - return response.Pop(); + if( !m_accessControl.isSystemService(user) ) + { + retCode = unlockDatabase(user, password); + } + else + { + // do not allow lock/unlock operations for system users + retCode = CKM_API_ERROR_INPUT_PARAM; + } + + return MessageBuffer::Serialize(retCode).Pop(); +} + +RawBuffer CKMLogic::updateCCMode() { + m_accessControl.updateCCMode(); + return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop(); +} + +RawBuffer CKMLogic::lockUserKey(uid_t user) +{ + int retCode = CKM_API_SUCCESS; + if( !m_accessControl.isSystemService(user) ) + { + m_userDataMap.erase(user); + } + else + { + // do not allow lock/unlock operations for system users + retCode = CKM_API_ERROR_INPUT_PARAM; + } + + return MessageBuffer::Serialize(retCode).Pop(); + } RawBuffer CKMLogic::removeUserData(uid_t user) { int retCode = CKM_API_SUCCESS; - // TODO try catch for all errors that should be supported by error code + + if (m_accessControl.isSystemService(user)) + user = SYSTEM_DB_UID; + m_userDataMap.erase(user); FileSystem fs(user); fs.removeUserData(); - MessageBuffer response; - Serialization::Serialize(response, retCode); - return response.Pop(); + return MessageBuffer::Serialize(retCode).Pop(); +} + +int CKMLogic::changeUserPasswordHelper(uid_t user, + const Password &oldPassword, + const Password &newPassword) +{ + // do not allow to change system database password + if( m_accessControl.isSystemService(user) ) + return CKM_API_ERROR_INPUT_PARAM; + + loadDKEKFile(user, oldPassword); + saveDKEKFile(user, newPassword); + + return CKM_API_SUCCESS; } RawBuffer CKMLogic::changeUserPassword( uid_t user, - const std::string &oldPassword, - const std::string &newPassword) + const Password &oldPassword, + const Password &newPassword) { int retCode = CKM_API_SUCCESS; - // TODO try-catch - FileSystem fs(user); - auto wrappedDomainKEK = fs.getDomainKEK(); - if (wrappedDomainKEK.empty()) { - retCode = CKM_API_ERROR_BAD_REQUEST; + try + { + retCode = changeUserPasswordHelper(user, oldPassword, newPassword); + } catch (const KeyProvider::Exception::PassWordError &e) { + LogError("Incorrect Password " << e.GetMessage()); + retCode = CKM_API_ERROR_AUTHENTICATION_FAILED; + } catch (const KeyProvider::Exception::Base &e) { + LogError("Error in KeyProvider " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const FileSystem::Exception::Base &e) { + LogError("Error in FileSystem " << e.GetMessage()); + retCode = CKM_API_ERROR_FILE_SYSTEM; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + + return MessageBuffer::Serialize(retCode).Pop(); +} + +int CKMLogic::resetUserPasswordHelper( + uid_t user, + const Password &newPassword) +{ + // do not allow to reset system database password + if( m_accessControl.isSystemService(user) ) + return CKM_API_ERROR_INPUT_PARAM; + + int retCode = CKM_API_SUCCESS; + if (0 == m_userDataMap.count(user)) + { + // Check if key exists. If exists we must return error + FileSystem fs(user); + auto wrappedDKEKMain = fs.getDKEK(); + if (!wrappedDKEKMain.empty()) + retCode = CKM_API_ERROR_BAD_REQUEST; } else { - wrappedDomainKEK = KeyProvider::reencrypt(wrappedDomainKEK, oldPassword, newPassword); - fs.saveDomainKEK(wrappedDomainKEK); + saveDKEKFile(user, newPassword); } - MessageBuffer response; - Serialization::Serialize(response, retCode); - return response.Pop(); + + return retCode; } RawBuffer CKMLogic::resetUserPassword( uid_t user, - const std::string &newPassword) + const Password &newPassword) { int retCode = CKM_API_SUCCESS; - // TODO try-catch - if (0 == m_userDataMap.count(user)) { - retCode = CKM_API_ERROR_BAD_REQUEST; - } else { - auto &handler = m_userDataMap[user]; - FileSystem fs(user); - fs.saveDomainKEK(handler.keyProvider.getWrappedDomainKEK(newPassword)); + try { + retCode = resetUserPasswordHelper(user, newPassword); + } catch (const FileSystem::Exception::Base &e) { + LogError("Error in FileSystem " << e.GetMessage()); + retCode = CKM_API_ERROR_FILE_SYSTEM; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } - MessageBuffer response; - Serialization::Serialize(response, retCode); - return response.Pop(); + return MessageBuffer::Serialize(retCode).Pop(); } -int CKMLogic::saveDataHelper( - Credentials &cred, - DBDataType dataType, - const Alias &alias, - const RawBuffer &key, - const PolicySerializable &policy) +RawBuffer CKMLogic::removeApplicationData(const Label &smackLabel) { + int retCode = CKM_API_SUCCESS; + + try { + + if (smackLabel.empty()) { + retCode = CKM_API_ERROR_INPUT_PARAM; + } else { + UidVector uids = FileSystem::getUIDsFromDBFile(); + for (auto userId : uids) { + if (0 == m_userDataMap.count(userId)) { + FileSystem fs(userId); + fs.addRemovedApp(smackLabel); + } else { + auto &handle = m_userDataMap[userId]; + handle.crypto.removeKey(smackLabel); + handle.database.deleteKey(smackLabel); + } + } + } + + } catch (const DB::Crypto::Exception::InternalError &e) { + LogError("DB::Crypto couldn't remove data: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const DB::Crypto::Exception::TransactionError &e) { + LogError("DB::Crypto transaction failed with message " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const FileSystem::Exception::Base &e) { + LogError("Error in FileSystem " << e.GetMessage()); + retCode = CKM_API_ERROR_FILE_SYSTEM; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + + return MessageBuffer::Serialize(retCode).Pop(); +} + +int CKMLogic::checkSaveConditions( + const Credentials &cred, + UserData &handler, + const Name &name, + const Label &ownerLabel) { - if (0 == m_userDataMap.count(cred.uid)) - return CKM_API_ERROR_DB_LOCKED; + // verify name and label are correct + if (!isNameValid(name) || !isLabelValid(ownerLabel)) { + LogWarning("Invalid parameter passed to key-manager"); + return CKM_API_ERROR_INPUT_PARAM; + } - DBRow row = { alias, cred.smackLabel, policy.restricted, - policy.extractable, dataType, DBCMAlgType::NONE, - 0, RawBuffer(10, 'c'), static_cast(key.size()), key }; + // check if allowed to save using ownerLabel + int access_ec = m_accessControl.canSave(cred, ownerLabel); + if( access_ec != CKM_API_SUCCESS) + { + LogWarning("label " << cred.smackLabel << " can not save rows using label " << ownerLabel); + return access_ec; + } - auto &handler = m_userDataMap[cred.uid]; - DBCrypto::Transaction transaction(&handler.database); - if (!handler.crypto.haveKey(cred.smackLabel)) { - RawBuffer key; - auto key_optional = handler.database.getKey(cred.smackLabel); + // check if not a duplicate + if( handler.database.isNameLabelPresent(name, ownerLabel)) + return CKM_API_ERROR_DB_ALIAS_EXISTS; + + // encryption section + if (!handler.crypto.haveKey(ownerLabel)) + { + RawBuffer got_key; + auto key_optional = handler.database.getKey(ownerLabel); if(!key_optional) { - LogDebug("No Key in database found. Generating new one for label: " - << cred.smackLabel); - key = handler.keyProvider.generateDEK(cred.smackLabel); - handler.database.saveKey(cred.smackLabel, key); + LogDebug("No Key in database found. Generating new one for label: " << ownerLabel); + got_key = handler.keyProvider.generateDEK(ownerLabel); + handler.database.saveKey(ownerLabel, got_key); } else { LogDebug("Key from DB"); - key = *key_optional; + got_key = *key_optional; } - key = handler.keyProvider.getPureDEK(key); - handler.crypto.pushKey(cred.smackLabel, key); + got_key = handler.keyProvider.getPureDEK(got_key); + handler.crypto.pushKey(ownerLabel, got_key); } - handler.crypto.encryptRow(policy.password, row); - handler.database.saveDBRow(row); - transaction.commit(); + return CKM_API_SUCCESS; } +DB::Row CKMLogic::createEncryptedRow( + CryptoLogic &crypto, + const Name &name, + const Label &label, + DataType dataType, + const RawBuffer &data, + const Policy &policy) const +{ + DB::Row row(name, label, static_cast(policy.extractable), dataType, data, static_cast(data.size())); + row.backendId = m_decider.chooseCryptoBackend(dataType, policy.extractable); + + // do not encrypt data with password during cc_mode on + if(m_accessControl.isCCMode()) { + crypto.encryptRow("", row); + } else { + crypto.encryptRow(policy.password, row); + } + return row; +} + +int CKMLogic::verifyBinaryData(DataType dataType, RawBuffer &input_data) const +{ + RawBuffer dummy; + return toBinaryData(dataType, input_data, dummy); +} + +int CKMLogic::toBinaryData(DataType dataType, + const RawBuffer &input_data, + RawBuffer &output_data) const +{ + // verify the data integrity + if (dataType.isKey()) + { + KeyShPtr output_key; + if(dataType.isSKey()) + output_key = CKM::Key::createAES(input_data); + else + output_key = CKM::Key::create(input_data); + if(output_key.get() == NULL) + { + LogError("provided binary data is not valid key data"); + return CKM_API_ERROR_INPUT_PARAM; + } + output_data = output_key->getDER(); + } + else if (dataType.isCertificate() || dataType.isChainCert()) + { + CertificateShPtr cert = CKM::Certificate::create(input_data, DataFormat::FORM_DER); + if(cert.get() == NULL) + { + LogError("provided binary data is not valid certificate data"); + return CKM_API_ERROR_INPUT_PARAM; + } + output_data = cert->getDER(); + } + else + output_data = input_data; + // TODO: add here BINARY_DATA verification, i.e: max size etc. + return CKM_API_SUCCESS; +} + +int CKMLogic::verifyAndSaveDataHelper( + const Credentials &cred, + const Name &name, + const Label &label, + const RawBuffer &data, + DataType dataType, + const PolicySerializable &policy) +{ + int retCode = CKM_API_ERROR_UNKNOWN; + + try { + // check if data is correct + RawBuffer binaryData; + retCode = toBinaryData(dataType, data, binaryData); + if(retCode == CKM_API_SUCCESS) + { + retCode = saveDataHelper(cred, name, label, dataType, binaryData, policy); + } + } catch (const KeyProvider::Exception::Base &e) { + LogError("KeyProvider failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const DB::Crypto::Exception::InternalError &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const DB::Crypto::Exception::TransactionError &e) { + LogError("DB::Crypto transaction failed with message " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const FileSystem::Exception::Base &e) { + LogError("Error in FileSystem " << e.GetMessage()); + retCode = CKM_API_ERROR_FILE_SYSTEM; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + return retCode; +} + RawBuffer CKMLogic::saveData( - Credentials &cred, + const Credentials &cred, int commandId, - DBDataType dataType, - const Alias &alias, - const RawBuffer &key, + const Name &name, + const Label &label, + const RawBuffer &data, + DataType dataType, const PolicySerializable &policy) { - int retCode = CKM_API_SUCCESS; + int retCode = verifyAndSaveDataHelper(cred, name, label, data, dataType, policy); + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::SAVE), + commandId, + retCode, + static_cast(dataType)); + return response.Pop(); +} + +int CKMLogic::extractPKCS12Data( + CryptoLogic &crypto, + const Name &name, + const Label &ownerLabel, + const PKCS12Serializable &pkcs, + const PolicySerializable &keyPolicy, + const PolicySerializable &certPolicy, + DB::RowVector &output) const +{ + // private key is mandatory + if( !pkcs.getKey() ) + return CKM_API_ERROR_INVALID_FORMAT; + Key* keyPtr = pkcs.getKey().get(); + DataType keyType = DataType(keyPtr->getType()); + RawBuffer keyData = keyPtr->getDER(); + int retCode = verifyBinaryData(keyType, keyData); + if(retCode != CKM_API_SUCCESS) + return retCode; + output.push_back(createEncryptedRow(crypto, name, ownerLabel, keyType, keyData, keyPolicy)); + + // certificate is mandatory + if( !pkcs.getCertificate() ) + return CKM_API_ERROR_INVALID_FORMAT; + RawBuffer certData = pkcs.getCertificate().get()->getDER(); + retCode = verifyBinaryData(DataType::CERTIFICATE, certData); + if(retCode != CKM_API_SUCCESS) + return retCode; + output.push_back(createEncryptedRow(crypto, name, ownerLabel, DataType::CERTIFICATE, certData, certPolicy)); + + // CA cert chain + unsigned int cert_index = 0; + for(const auto & ca : pkcs.getCaCertificateShPtrVector()) + { + DataType chainDataType = DataType::getChainDatatype(cert_index ++); + RawBuffer caCertData = ca->getDER(); + int retCode = verifyBinaryData(chainDataType, caCertData); + if(retCode != CKM_API_SUCCESS) + return retCode; + + output.push_back(createEncryptedRow(crypto, name, ownerLabel, chainDataType, caCertData, certPolicy)); + } + + return CKM_API_SUCCESS; +} + +RawBuffer CKMLogic::savePKCS12( + const Credentials &cred, + int commandId, + const Name &name, + const Label &label, + const PKCS12Serializable &pkcs, + const PolicySerializable &keyPolicy, + const PolicySerializable &certPolicy) +{ + int retCode = CKM_API_ERROR_UNKNOWN; try { - retCode = saveDataHelper(cred, dataType, alias, key, policy); - LogDebug("SaveDataHelper returned: " << retCode); + retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy); } catch (const KeyProvider::Exception::Base &e) { LogError("KeyProvider failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCryptoModule::Exception::Base &e) { - LogError("DBCryptoModule failed with message: " << e.GetMessage()); + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCrypto::Exception::InternalError &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + } catch (const DB::Crypto::Exception::InternalError &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; - } catch (const DBCrypto::Exception::AliasExists &e) { - LogError("DBCrypto couldn't save duplicate alias"); - retCode = CKM_API_ERROR_DB_ALIAS_EXISTS; - } catch (const DBCrypto::Exception::TransactionError &e) { - LogError("DBCrypto transaction failed with message " << e.GetMessage()); + } catch (const DB::Crypto::Exception::TransactionError &e) { + LogError("DB::Crypto transaction failed with message " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::SAVE)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - Serialization::Serialize(response, static_cast(dataType)); - + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::SAVE_PKCS12), + commandId, + retCode); return response.Pop(); } -RawBuffer CKMLogic::removeData( - Credentials &cred, - int commandId, - DBDataType dataType, - const Alias &alias) + +int CKMLogic::removeDataHelper( + const Credentials &cred, + const Name &name, + const Label &label) { - int retCode = CKM_API_SUCCESS; + auto &handler = selectDatabase(cred, label); - if (0 < m_userDataMap.count(cred.uid)) { - Try { - m_userDataMap[cred.uid].database.deleteDBRow(alias, cred.smackLabel); - } Catch (CKM::Exception) { - LogError("Error in deleting row!"); - retCode = CKM_API_ERROR_DB_ERROR; - } - } else { - retCode = CKM_API_ERROR_DB_LOCKED; + // use client label if not explicitly provided + const Label &ownerLabel = label.empty() ? cred.smackLabel : label; + if (!isNameValid(name) || !isLabelValid(ownerLabel)) { + LogError("Invalid label or name format"); + return CKM_API_ERROR_INPUT_PARAM; } - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::REMOVE)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - Serialization::Serialize(response, static_cast(dataType)); + DB::Crypto::Transaction transaction(&handler.database); - return response.Pop(); + // read and check permissions + PermissionMaskOptional permissionRowOpt = + handler.database.getPermissionRow(name, ownerLabel, cred.smackLabel); + int retCode = m_accessControl.canDelete(cred, + PermissionForLabel(cred.smackLabel, permissionRowOpt)); + if(retCode != CKM_API_SUCCESS) + { + LogWarning("access control check result: " << retCode); + return retCode; + } + + auto erased = handler.database.deleteRow(name, ownerLabel); + // check if the data existed or not + if(erased) + transaction.commit(); + else { + LogError("No row for given name and label"); + return CKM_API_ERROR_DB_ALIAS_UNKNOWN; + } + + return CKM_API_SUCCESS; } -int CKMLogic::getDataHelper( - Credentials &cred, - DBDataType dataType, - const Alias &alias, - const std::string &password, - DBRow &row) +RawBuffer CKMLogic::removeData( + const Credentials &cred, + int commandId, + const Name &name, + const Label &label) { + int retCode = CKM_API_ERROR_UNKNOWN; - if (0 == m_userDataMap.count(cred.uid)) - return CKM_API_ERROR_DB_LOCKED; + try + { + retCode = removeDataHelper(cred, name, label); + } + catch (const CKMLogic::Exception::DatabaseLocked &e) + { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } + catch (const CKM::Exception &) + { + LogError("Error in deleting row!"); + retCode = CKM_API_ERROR_DB_ERROR; + } - auto &handler = m_userDataMap[cred.uid]; + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::REMOVE), + commandId, + retCode); + return response.Pop(); +} - DBCrypto::DBRowOptional row_optional; - if (dataType == DBDataType::CERTIFICATE || dataType == DBDataType::BINARY_DATA) { - row_optional = handler.database.getDBRow(alias, cred.smackLabel, dataType); - } else if ((static_cast(dataType) >= static_cast(DBDataType::DB_KEY_FIRST)) - && (static_cast(dataType) <= static_cast(DBDataType::DB_KEY_LAST))) +int CKMLogic::readSingleRow(const Name &name, + const Label &ownerLabel, + DataType dataType, + DB::Crypto & database, + DB::Row &row) +{ + DB::Crypto::RowOptional row_optional; + if (dataType.isKey()) { - row_optional = handler.database.getKeyDBRow(alias, cred.smackLabel); + // read all key types + row_optional = database.getRow(name, + ownerLabel, + DataType::DB_KEY_FIRST, + DataType::DB_KEY_LAST); } else { - LogError("Unknown type of requested data" << (int)dataType); - return CKM_API_ERROR_BAD_REQUEST; + // read anything else + row_optional = database.getRow(name, + ownerLabel, + dataType); } + if(!row_optional) { - LogError("No row for given alias, label and type"); + LogError("No row for given name, label and type"); return CKM_API_ERROR_DB_ALIAS_UNKNOWN; } else { row = *row_optional; } - if (!handler.crypto.haveKey(row.smackLabel)) { + return CKM_API_SUCCESS; +} + + +int CKMLogic::readMultiRow(const Name &name, + const Label &ownerLabel, + DataType dataType, + DB::Crypto & database, + DB::RowVector &output) +{ + if (dataType.isKey()) + { + // read all key types + database.getRows(name, + ownerLabel, + DataType::DB_KEY_FIRST, + DataType::DB_KEY_LAST, + output); + } + else if (dataType.isChainCert()) + { + // read all key types + database.getRows(name, + ownerLabel, + DataType::DB_CHAIN_FIRST, + DataType::DB_CHAIN_LAST, + output); + } + else + { + // read anything else + database.getRows(name, + ownerLabel, + dataType, + output); + } + + if(!output.size()) { + LogError("No row for given name, label and type"); + return CKM_API_ERROR_DB_ALIAS_UNKNOWN; + } + + return CKM_API_SUCCESS; +} + +int CKMLogic::checkDataPermissionsHelper(const Credentials &cred, + const Name &name, + const Label &ownerLabel, + const Label &accessorLabel, + const DB::Row &row, + bool exportFlag, + DB::Crypto & database) +{ + PermissionMaskOptional permissionRowOpt = + database.getPermissionRow(name, ownerLabel, accessorLabel); + + if(exportFlag) + return m_accessControl.canExport(cred, row, PermissionForLabel(accessorLabel, permissionRowOpt)); + return m_accessControl.canRead(cred, PermissionForLabel(accessorLabel, permissionRowOpt)); +} + +int CKMLogic::readDataHelper( + bool exportFlag, + const Credentials &cred, + DataType dataType, + const Name &name, + const Label &label, + const Password &password, + DB::RowVector &rows) +{ + auto &handler = selectDatabase(cred, label); + + // use client label if not explicitly provided + const Label &ownerLabel = label.empty() ? cred.smackLabel : label; + + if (!isNameValid(name) || !isLabelValid(ownerLabel)) + return CKM_API_ERROR_INPUT_PARAM; + + // read rows + DB::Crypto::Transaction transaction(&handler.database); + int retCode = readMultiRow(name, ownerLabel, dataType, handler.database, rows); + if(CKM_API_SUCCESS != retCode) + return retCode; + + // all read rows belong to the same owner + DB::Row & firstRow = rows.at(0); + + // check access rights + retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database); + if(CKM_API_SUCCESS != retCode) + return retCode; + + // decrypt row + if (!handler.crypto.haveKey(firstRow.ownerLabel)) { RawBuffer key; - auto key_optional = handler.database.getKey(row.smackLabel); + auto key_optional = handler.database.getKey(firstRow.ownerLabel); if(!key_optional) { LogError("No key for given label in database"); return CKM_API_ERROR_DB_ERROR; } key = *key_optional; key = handler.keyProvider.getPureDEK(key); - handler.crypto.pushKey(cred.smackLabel, key); + handler.crypto.pushKey(firstRow.ownerLabel, key); + } + for(auto &row : rows) + handler.crypto.decryptRow(password, row); + + return CKM_API_SUCCESS; +} + +int CKMLogic::readDataHelper( + bool exportFlag, + const Credentials &cred, + DataType dataType, + const Name &name, + const Label &label, + const Password &password, + DB::Row &row) +{ + auto &handler = selectDatabase(cred, label); + + // use client label if not explicitly provided + const Label &ownerLabel = label.empty() ? cred.smackLabel : label; + + if (!isNameValid(name) || !isLabelValid(ownerLabel)) + return CKM_API_ERROR_INPUT_PARAM; + + // read row + DB::Crypto::Transaction transaction(&handler.database); + int retCode = readSingleRow(name, ownerLabel, dataType, handler.database, row); + if(CKM_API_SUCCESS != retCode) + return retCode; + + // check access rights + retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database); + if(CKM_API_SUCCESS != retCode) + return retCode; + + // decrypt row + if (!handler.crypto.haveKey(row.ownerLabel)) { + RawBuffer key; + auto key_optional = handler.database.getKey(row.ownerLabel); + if(!key_optional) { + LogError("No key for given label in database"); + return CKM_API_ERROR_DB_ERROR; + } + key = *key_optional; + key = handler.keyProvider.getPureDEK(key); + handler.crypto.pushKey(row.ownerLabel, key); } handler.crypto.decryptRow(password, row); @@ -298,26 +882,36 @@ int CKMLogic::getDataHelper( } RawBuffer CKMLogic::getData( - Credentials &cred, + const Credentials &cred, int commandId, - DBDataType dataType, - const Alias &alias, - const std::string &password) + DataType dataType, + const Name &name, + const Label &label, + const Password &password) { int retCode = CKM_API_SUCCESS; - DBRow row; + DB::Row row; try { - retCode = getDataHelper(cred, dataType, alias, password, row); + retCode = readDataHelper(true, cred, dataType, name, label, password, row); } catch (const KeyProvider::Exception::Base &e) { LogError("KeyProvider failed with error: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCryptoModule::Exception::Base &e) { - LogError("DBCryptoModule failed with message: " << e.GetMessage()); + } catch (const CryptoLogic::Exception::DecryptDBRowError &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_AUTHENTICATION_FAILED; + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } if (CKM_API_SUCCESS != retCode) { @@ -325,359 +919,662 @@ RawBuffer CKMLogic::getData( row.dataType = dataType; } - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::GET)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - Serialization::Serialize(response, static_cast(row.dataType)); - Serialization::Serialize(response, row.data); + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET), + commandId, + retCode, + static_cast(row.dataType), + row.data); return response.Pop(); } -RawBuffer CKMLogic::getDataList( - Credentials &cred, - int commandId, - DBDataType dataType) +int CKMLogic::getPKCS12Helper( + const Credentials &cred, + const Name &name, + const Label &label, + const Password &keyPassword, + const Password &certPassword, + KeyShPtr & privKey, + CertificateShPtr & cert, + CertificateShPtrVector & caChain) { - int retCode = CKM_API_SUCCESS; - AliasVector aliasVector; + int retCode; + + // read private key (mandatory) + DB::Row privKeyRow; + retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, label, keyPassword, privKeyRow); + if(retCode != CKM_API_SUCCESS) + return retCode; + privKey = CKM::Key::create(privKeyRow.data); + + // read certificate (mandatory) + DB::Row certRow; + retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label, certPassword, certRow); + if(retCode != CKM_API_SUCCESS) + return retCode; + cert = CKM::Certificate::create(certRow.data, DataFormat::FORM_DER); + + // read CA cert chain (optional) + DB::RowVector rawCaChain; + retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label, certPassword, rawCaChain); + if(retCode != CKM_API_SUCCESS && + retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) + return retCode; + for(auto &rawCaCert : rawCaChain) + caChain.push_back(CKM::Certificate::create(rawCaCert.data, DataFormat::FORM_DER)); + + // if anything found, return it + if(privKey || cert || caChain.size()>0) + retCode = CKM_API_SUCCESS; + + return retCode; +} + +RawBuffer CKMLogic::getPKCS12( + const Credentials &cred, + int commandId, + const Name &name, + const Label &label, + const Password &keyPassword, + const Password &certPassword) +{ + int retCode = CKM_API_ERROR_UNKNOWN; + + PKCS12Serializable output; + try { + KeyShPtr privKey; + CertificateShPtr cert; + CertificateShPtrVector caChain; + retCode = getPKCS12Helper(cred, name, label, keyPassword, certPassword, privKey, cert, caChain); + + // prepare response + if(retCode == CKM_API_SUCCESS) + output = PKCS12Serializable(privKey, cert, caChain); + + } catch (const KeyProvider::Exception::Base &e) { + LogError("KeyProvider failed with error: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const CryptoLogic::Exception::DecryptDBRowError &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_AUTHENTICATION_FAILED; + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET_PKCS12), + commandId, + retCode, + output); + return response.Pop(); +} + +int CKMLogic::getDataListHelper(const Credentials &cred, + const DataType dataType, + LabelNameVector &labelNameVector) +{ + int retCode = CKM_API_ERROR_DB_LOCKED; + if (0 < m_userDataMap.count(cred.clientUid)) + { + auto &database = m_userDataMap[cred.clientUid].database; - if (0 < m_userDataMap.count(cred.uid)) { - auto &handler = m_userDataMap[cred.uid]; Try { - if (dataType == DBDataType::CERTIFICATE || dataType == DBDataType::BINARY_DATA) { - handler.database.getAliases(dataType, cred.smackLabel, aliasVector); + LabelNameVector tmpVector; + if (dataType.isKey()) { + // list all key types + database.listNames(cred.smackLabel, + tmpVector, + DataType::DB_KEY_FIRST, + DataType::DB_KEY_LAST); } else { - handler.database.getKeyAliases(cred.smackLabel, aliasVector); + // list anything else + database.listNames(cred.smackLabel, + tmpVector, + dataType); } - } Catch (CKM::Exception) { - LogError("Failed to get aliases"); + labelNameVector.insert(labelNameVector.end(), tmpVector.begin(), tmpVector.end()); + retCode = CKM_API_SUCCESS; + } + Catch (CKM::Exception) { + LogError("Failed to get names"); retCode = CKM_API_ERROR_DB_ERROR; } - } else { - retCode = CKM_API_ERROR_DB_LOCKED; } - - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::GET_LIST)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - Serialization::Serialize(response, static_cast(dataType)); - Serialization::Serialize(response, aliasVector); - return response.Pop(); + return retCode; } -int CKMLogic::createKeyPairRSAHelper( - Credentials &cred, - int size, - const Alias &aliasPrivate, - const Alias &aliasPublic, - const PolicySerializable &policyPrivate, - const PolicySerializable &policyPublic) +RawBuffer CKMLogic::getDataList( + const Credentials &cred, + int commandId, + DataType dataType) { - if (0 >= m_userDataMap.count(cred.uid)) - return CKM_API_ERROR_DB_LOCKED; + LabelNameVector systemVector; + LabelNameVector userVector; + LabelNameVector labelNameVector; - auto &handler = m_userDataMap[cred.uid]; - GenericKey prv, pub; - int retCode; - - if (CKM_CRYPTO_CREATEKEY_SUCCESS != - (retCode = CryptoService::createKeyPairRSA(size, prv, pub))) + int retCode = unlockSystemDB(); + if (CKM_API_SUCCESS == retCode) { - LogDebug("CryptoService error with code: " << retCode); - return CKM_API_ERROR_SERVER_ERROR; // TODO error code + // system database + if (m_accessControl.isSystemService(cred)) + { + // lookup system DB + retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, + LABEL_SYSTEM_DB), + dataType, + systemVector); + } + else + { + // user - lookup system, then client DB + retCode = getDataListHelper(Credentials(SYSTEM_DB_UID, + cred.smackLabel), + dataType, + systemVector); + + // private database + if(retCode == CKM_API_SUCCESS) + { + retCode = getDataListHelper(cred, + dataType, + userVector); + } + } } - DBCrypto::Transaction transaction(&handler.database); - retCode = saveDataHelper(cred, - toDBDataType(prv.getType()), - aliasPrivate, - prv.getDER(), - policyPrivate); + if(retCode == CKM_API_SUCCESS) + { + labelNameVector.insert(labelNameVector.end(), systemVector.begin(), systemVector.end()); + labelNameVector.insert(labelNameVector.end(), userVector.begin(), userVector.end()); + } + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET_LIST), + commandId, + retCode, + static_cast(dataType), + labelNameVector); + return response.Pop(); +} - if (CKM_API_SUCCESS != retCode) - return retCode; +int CKMLogic::saveDataHelper( + const Credentials &cred, + const Name &name, + const Label &label, + DataType dataType, + const RawBuffer &data, + const PolicySerializable &policy) +{ + auto &handler = selectDatabase(cred, label); - retCode = saveDataHelper(cred, - toDBDataType(pub.getType()), - aliasPublic, - pub.getDER(), - policyPublic); + // use client label if not explicitly provided + const Label &ownerLabel = label.empty() ? cred.smackLabel : label; + if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0) + return CKM_API_ERROR_INPUT_PARAM; - if (CKM_API_SUCCESS != retCode) + // check if save is possible + DB::Crypto::Transaction transaction(&handler.database); + int retCode = checkSaveConditions(cred, handler, name, ownerLabel); + if(retCode != CKM_API_SUCCESS) return retCode; - transaction.commit(); + // save the data + DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, ownerLabel, dataType, data, policy); + handler.database.saveRow(encryptedRow); - return retCode; + transaction.commit(); + return CKM_API_SUCCESS; } -RawBuffer CKMLogic::createKeyPairRSA( - Credentials &cred, - int commandId, - int size, - const Alias &aliasPrivate, - const Alias &aliasPublic, - const PolicySerializable &policyPrivate, - const PolicySerializable &policyPublic) +int CKMLogic::saveDataHelper( + const Credentials &cred, + const Name &name, + const Label &label, + const PKCS12Serializable &pkcs, + const PolicySerializable &keyPolicy, + const PolicySerializable &certPolicy) { - int retCode = CKM_API_SUCCESS; + auto &handler = selectDatabase(cred, label); - try { - retCode = createKeyPairRSAHelper( - cred, - size, - aliasPrivate, - aliasPublic, - policyPrivate, - policyPublic); - - } catch (DBCrypto::Exception::AliasExists &e) { - LogDebug("DBCrypto error: alias exists: " << e.GetMessage()); - retCode = CKM_API_ERROR_DB_ALIAS_EXISTS; - } catch (DBCrypto::Exception::TransactionError &e) { - LogDebug("DBCrypto error: transaction error: " << e.GetMessage()); - retCode = CKM_API_ERROR_DB_ERROR; - } catch (DBCrypto::Exception::InternalError &e) { - LogDebug("DBCrypto internal error: " << e.GetMessage()); - retCode = CKM_API_ERROR_DB_ERROR; - } + // use client label if not explicitly provided + const Label &ownerLabel = label.empty() ? cred.smackLabel : label; + if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0) + return CKM_API_ERROR_INPUT_PARAM; - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::CREATE_KEY_PAIR_RSA)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); + // check if save is possible + DB::Crypto::Transaction transaction(&handler.database); + int retCode = checkSaveConditions(cred, handler, name, ownerLabel); + if(retCode != CKM_API_SUCCESS) + return retCode; - return response.Pop(); -} + // extract and encrypt the data + DB::RowVector encryptedRows; + retCode = extractPKCS12Data(handler.crypto, name, ownerLabel, pkcs, keyPolicy, certPolicy, encryptedRows); + if(retCode != CKM_API_SUCCESS) + return retCode; -int CKMLogic::createKeyPairECDSAHelper( - Credentials &cred, - int type, - const Alias &aliasPrivate, - const Alias &aliasPublic, - const PolicySerializable &policyPrivate, - const PolicySerializable &policyPublic) -{ - if (0 >= m_userDataMap.count(cred.uid)) - return CKM_API_ERROR_DB_LOCKED; + // save the data + handler.database.saveRows(name, ownerLabel, encryptedRows); + transaction.commit(); - auto &handler = m_userDataMap[cred.uid]; - GenericKey prv, pub; - int retCode; + return CKM_API_SUCCESS; +} - if (CKM_CRYPTO_CREATEKEY_SUCCESS != - (retCode = CryptoService::createKeyPairECDSA(static_cast(type), prv, pub))) - { - LogError("CryptoService failed with code: " << retCode); - return CKM_API_ERROR_SERVER_ERROR; // TODO error code - } - DBCrypto::Transaction transaction(&handler.database); +int CKMLogic::createKeyAESHelper( + const Credentials &cred, + const int size, + const Name &name, + const Label &label, + const PolicySerializable &policy) +{ + CryptoAlgorithm keyGenAlgorithm; + keyGenAlgorithm.addParam(ParamName::GEN_KEY_LEN, size); + Token key = m_decider.getStore(DataType::KEY_AES, policy.extractable).generateSKey(keyGenAlgorithm); + + return saveDataHelper(cred, + name, + label, + DataType::KEY_AES, + key.data, + policy); +} - retCode = saveDataHelper(cred, - toDBDataType(prv.getType()), - aliasPrivate, - prv.getDER(), - policyPrivate); +int CKMLogic::createKeyPairHelper( + const Credentials &cred, + const CryptoAlgorithmSerializable & keyGenParams, + const Name &namePrivate, + const Label &labelPrivate, + const Name &namePublic, + const Label &labelPublic, + const PolicySerializable &policyPrivate, + const PolicySerializable &policyPublic) +{ + auto &handlerPriv = selectDatabase(cred, labelPrivate); + auto &handlerPub = selectDatabase(cred, labelPublic); + + AlgoType keyType = AlgoType::RSA_GEN; + if(!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType)) + ThrowMsg(Crypto::Exception::InputParam, "Error, parameter ALGO_TYPE not found."); + DataType dt(keyType); + if(!dt.isKey()) + ThrowMsg(Crypto::Exception::InputParam, "Error, parameter ALGO_TYPE with wrong value."); + + bool exportable = policyPrivate.extractable || policyPublic.extractable; + TokenPair keys = m_decider.getStore(dt, exportable).generateAKey(keyGenParams); + + DB::Crypto::Transaction transactionPriv(&handlerPriv.database); + // in case the same database is used for private and public - the second + // transaction will not be executed + DB::Crypto::Transaction transactionPub(&handlerPub.database); + + int retCode = saveDataHelper(cred, + namePrivate, + labelPrivate, + keys.first.dataType, + keys.first.data, + policyPrivate); if (CKM_API_SUCCESS != retCode) return retCode; retCode = saveDataHelper(cred, - toDBDataType(pub.getType()), - aliasPublic, - pub.getDER(), - policyPublic); - + namePublic, + labelPublic, + keys.second.dataType, + keys.second.data, + policyPublic); if (CKM_API_SUCCESS != retCode) return retCode; - transaction.commit(); - - return retCode; + transactionPub.commit(); + transactionPriv.commit(); + return CKM_API_SUCCESS; } -RawBuffer CKMLogic::createKeyPairECDSA( - Credentials &cred, +RawBuffer CKMLogic::createKeyPair( + const Credentials &cred, int commandId, - int type, - const Alias &aliasPrivate, - const Alias &aliasPublic, + const CryptoAlgorithmSerializable & keyGenParams, + const Name &namePrivate, + const Label &labelPrivate, + const Name &namePublic, + const Label &labelPublic, const PolicySerializable &policyPrivate, const PolicySerializable &policyPublic) { int retCode = CKM_API_SUCCESS; try { - retCode = createKeyPairECDSAHelper( + retCode = createKeyPairHelper( cred, - type, - aliasPrivate, - aliasPublic, + keyGenParams, + namePrivate, + labelPrivate, + namePublic, + labelPublic, policyPrivate, policyPublic); - } catch (const DBCrypto::Exception::AliasExists &e) { - LogDebug("DBCrypto error: alias exists: " << e.GetMessage()); - retCode = CKM_API_ERROR_DB_ALIAS_EXISTS; - } catch (const DBCrypto::Exception::TransactionError &e) { - LogDebug("DBCrypto error: transaction error: " << e.GetMessage()); + } catch (const Crypto::Exception::OperationNotSupported &e) { + LogDebug("GStore error: operation not supported: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const Crypto::Exception::InternalError & e) { + LogDebug("GStore key generation failed: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch( const Crypto::Exception::InputParam & e) { + LogDebug("Missing or wrong input parameters: " << e.GetMessage()); + retCode = CKM_API_ERROR_INPUT_PARAM; + } catch (DB::Crypto::Exception::TransactionError &e) { + LogDebug("DB::Crypto error: transaction error: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; - } catch (const DBCrypto::Exception::InternalError &e) { - LogDebug("DBCrypto internal error: " << e.GetMessage()); + } catch (CKM::CryptoLogic::Exception::Base &e) { + LogDebug("CryptoLogic error: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (DB::Crypto::Exception::InternalError &e) { + LogDebug("DB::Crypto internal error: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::CREATE_KEY_PAIR_RSA)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - - return response.Pop(); + return MessageBuffer::Serialize(static_cast(LogicCommand::CREATE_KEY_PAIR), + commandId, retCode).Pop(); } -RawBuffer CKMLogic::getCertificateChain( - Credentials &cred, +RawBuffer CKMLogic::createKeyAES( + const Credentials &cred, int commandId, - const RawBuffer &certificate, - const RawBufferVector &untrustedRawCertVector) + const int size, + const Name &name, + const Label &label, + const PolicySerializable &policy) { - (void)cred; + int retCode = CKM_API_SUCCESS; - CertificateImpl cert(certificate, DataFormat::FORM_DER); + try { + retCode = createKeyAESHelper(cred, size, name, label, policy); + } catch (const Crypto::Exception::OperationNotSupported &e) { + LogDebug("GStore error: operation not supported: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const Crypto::Exception::InternalError & e) { + LogDebug("GStore key generation failed: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch( const Crypto::Exception::InputParam & e) { + LogDebug("Missing or wrong input parameters: " << e.GetMessage()); + retCode = CKM_API_ERROR_INPUT_PARAM; + } catch (std::invalid_argument &e) { + LogDebug("invalid argument error: " << e.what()); + retCode = CKM_API_ERROR_INPUT_PARAM; + } catch (DB::Crypto::Exception::TransactionError &e) { + LogDebug("DB::Crypto error: transaction error: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (CKM::CryptoLogic::Exception::Base &e) { + LogDebug("CryptoLogic error: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (DB::Crypto::Exception::InternalError &e) { + LogDebug("DB::Crypto internal error: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + + return MessageBuffer::Serialize(static_cast(LogicCommand::CREATE_KEY_AES), + commandId, retCode).Pop(); +} + +int CKMLogic::readCertificateHelper( + const Credentials &cred, + const LabelNameVector &labelNameVector, + CertificateImplVector &certVector) +{ + DB::Row row; + for (auto &i: labelNameVector) { + int ec = readDataHelper(false, cred, DataType::CERTIFICATE, i.second, i.first, Password(), row); + if (ec != CKM_API_SUCCESS) + return ec; + certVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER)); + + // try to read chain certificates (if present) + DB::RowVector rawCaChain; + ec = readDataHelper(false, cred, DataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), rawCaChain); + if(ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN) + return ec; + for(auto &rawCaCert : rawCaChain) + certVector.push_back(CertificateImpl(rawCaCert.data, DataFormat::FORM_DER)); + } + return CKM_API_SUCCESS; +} + +int CKMLogic::getCertificateChainHelper( + const CertificateImpl &cert, + const RawBufferVector &untrustedCertificates, + const RawBufferVector &trustedCertificates, + bool useTrustedSystemCertificates, + RawBufferVector &chainRawVector) +{ CertificateImplVector untrustedCertVector; + CertificateImplVector trustedCertVector; CertificateImplVector chainVector; - RawBufferVector chainRawVector; - for (auto &e: untrustedRawCertVector) + if (cert.empty()) + return CKM_API_ERROR_INPUT_PARAM; + + for (auto &e: untrustedCertificates) untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER)); + for (auto &e: trustedCertificates) + trustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER)); + + CertificateStore store; + int retCode = store.verifyCertificate(cert, + untrustedCertVector, + trustedCertVector, + useTrustedSystemCertificates, + m_accessControl.isCCMode(), + chainVector); + if (retCode != CKM_API_SUCCESS) + return retCode; - LogDebug("Cert is empty: " << cert.empty()); + for (auto &e : chainVector) + chainRawVector.push_back(e.getDER()); + return CKM_API_SUCCESS; +} - int retCode = m_certStore.verifyCertificate(cert, untrustedCertVector, chainVector); +int CKMLogic::getCertificateChainHelper( + const Credentials &cred, + const CertificateImpl &cert, + const LabelNameVector &untrusted, + const LabelNameVector &trusted, + bool useTrustedSystemCertificates, + RawBufferVector &chainRawVector) +{ + CertificateImplVector untrustedCertVector; + CertificateImplVector trustedCertVector; + CertificateImplVector chainVector; + DB::Row row; - if (retCode == CKM_API_SUCCESS) { - for (auto &e : chainVector) - chainRawVector.push_back(e.getDER()); - } + if (cert.empty()) + return CKM_API_ERROR_INPUT_PARAM; - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::GET_CHAIN_CERT)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - Serialization::Serialize(response, chainRawVector); - return response.Pop(); + int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector); + if (retCode != CKM_API_SUCCESS) + return retCode; + retCode = readCertificateHelper(cred, trusted, trustedCertVector); + if (retCode != CKM_API_SUCCESS) + return retCode; + + CertificateStore store; + retCode = store.verifyCertificate(cert, + untrustedCertVector, + trustedCertVector, + useTrustedSystemCertificates, + m_accessControl.isCCMode(), + chainVector); + if (retCode != CKM_API_SUCCESS) + return retCode; + + for (auto &i: chainVector) + chainRawVector.push_back(i.getDER()); + + return CKM_API_SUCCESS; } RawBuffer CKMLogic::getCertificateChain( - Credentials &cred, + const Credentials & /*cred*/, int commandId, const RawBuffer &certificate, - const AliasVector &aliasVector) + const RawBufferVector &untrustedCertificates, + const RawBufferVector &trustedCertificates, + bool useTrustedSystemCertificates) { - int retCode = CKM_API_SUCCESS; + CertificateImpl cert(certificate, DataFormat::FORM_DER); RawBufferVector chainRawVector; + int retCode = CKM_API_ERROR_UNKNOWN; try { - CertificateImpl cert(certificate, DataFormat::FORM_DER); - CertificateImplVector untrustedCertVector; - CertificateImplVector chainVector; - DBRow row; - - if (cert.empty()) { - retCode = CKM_API_ERROR_SERVER_ERROR; - goto senderror; - } - - for (auto &i: aliasVector) { - retCode = getDataHelper(cred, DBDataType::CERTIFICATE, i, std::string(), row); - - if (retCode != CKM_API_SUCCESS) - goto senderror; - - untrustedCertVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER)); - } - - retCode = m_certStore.verifyCertificate(cert, untrustedCertVector, chainVector); - - if (retCode != CKM_API_SUCCESS) - goto senderror; + retCode = getCertificateChainHelper(cert, + untrustedCertificates, + trustedCertificates, + useTrustedSystemCertificates, + chainRawVector); + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const std::exception& e) { + LogError("STD exception " << e.what()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (...) { + LogError("Unknown error."); + } - for (auto &i: chainVector) - chainRawVector.push_back(i.getDER()); + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET_CHAIN_CERT), + commandId, + retCode, + chainRawVector); + return response.Pop(); +} - } catch (const DBCryptoModule::Exception::Base &e) { - LogError("DBCyptorModule failed with message: " << e.GetMessage()); +RawBuffer CKMLogic::getCertificateChain( + const Credentials &cred, + int commandId, + const RawBuffer &certificate, + const LabelNameVector &untrustedCertificates, + const LabelNameVector &trustedCertificates, + bool useTrustedSystemCertificates) +{ + int retCode = CKM_API_ERROR_UNKNOWN; + CertificateImpl cert(certificate, DataFormat::FORM_DER); + RawBufferVector chainRawVector; + try { + retCode = getCertificateChainHelper(cred, + cert, + untrustedCertificates, + trustedCertificates, + useTrustedSystemCertificates, + chainRawVector); + } catch (const CryptoLogic::Exception::DecryptDBRowError &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_AUTHENTICATION_FAILED; + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const std::exception& e) { + LogError("STD exception " << e.what()); + retCode = CKM_API_ERROR_SERVER_ERROR; } catch (...) { LogError("Unknown error."); } -senderror: - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::GET_CHAIN_ALIAS)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - Serialization::Serialize(response, chainRawVector); + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET_CHAIN_ALIAS), + commandId, + retCode, + chainRawVector); return response.Pop(); } RawBuffer CKMLogic::createSignature( - Credentials &cred, + const Credentials &cred, int commandId, - const Alias &privateKeyAlias, - const std::string &password, // password for private_key + const Name &privateKeyName, + const Label & ownerLabel, + const Password &password, // password for private_key const RawBuffer &message, const HashAlgorithm hash, const RSAPaddingAlgorithm padding) { - DBRow row; - CryptoService cs; + DB::Row row; RawBuffer signature; + CryptoAlgorithm cryptoAlg; + cryptoAlg.addParam(ParamName::SV_HASH_ALGO, hash); + cryptoAlg.addParam(ParamName::SV_RSA_PADDING, padding); int retCode = CKM_API_SUCCESS; try { - do { - retCode = getDataHelper(cred, DBDataType::KEY_RSA_PUBLIC, privateKeyAlias, password, row); - if (CKM_API_SUCCESS != retCode) { - LogError("getDataHelper return error"); - break; - } - - GenericKey keyParsed(row.data, std::string()); - if (keyParsed.empty()) - retCode = CKM_API_ERROR_SERVER_ERROR; - else - cs.createSignature(keyParsed, message, hash, padding, signature); - } while(0); + retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, row); + if(retCode == CKM_API_SUCCESS) { + signature = m_decider.getStore(row).getKey(row)->sign(cryptoAlg, message); + } } catch (const KeyProvider::Exception::Base &e) { LogError("KeyProvider failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCryptoModule::Exception::Base &e) { - LogError("DBCryptoModule failed with message: " << e.GetMessage()); + } catch (const CryptoLogic::Exception::DecryptDBRowError &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_AUTHENTICATION_FAILED; + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const CKM::Crypto::Exception::InputParam &e) { + LogError("CKM::Crypto failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_INPUT_PARAM; + } catch (const CKM::Crypto::Exception::Base &e) { + LogError("CKM::Crypto failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } catch (const CKM::Exception &e) { + LogError("Unknown CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::CREATE_SIGNATURE)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - Serialization::Serialize(response, signature); + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::CREATE_SIGNATURE), + commandId, + retCode, + signature); return response.Pop(); } RawBuffer CKMLogic::verifySignature( - Credentials &cred, + const Credentials &cred, int commandId, - const Alias &publicKeyOrCertAlias, - const std::string &password, // password for public_key (optional) + const Name &publicKeyOrCertName, + const Label & ownerLabel, + const Password &password, // password for public_key (optional) const RawBuffer &message, const RawBuffer &signature, const HashAlgorithm hash, @@ -686,55 +1583,127 @@ RawBuffer CKMLogic::verifySignature( int retCode = CKM_API_ERROR_VERIFICATION_FAILED; try { - do { - CryptoService cs; - DBRow row; - GenericKey key; - - retCode = getDataHelper(cred, DBDataType::DB_KEY_FIRST, publicKeyOrCertAlias, password, row); - - if (retCode == CKM_API_SUCCESS) { - key = GenericKey(row.data); - } else if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) { - retCode = getDataHelper(cred, DBDataType::CERTIFICATE, publicKeyOrCertAlias, password, row); - if (retCode != CKM_API_SUCCESS) - break; - CertificateImpl cert(row.data, DataFormat::FORM_DER); - key = cert.getGenericKey(); - } else { - break; - } - - if (key.empty()) { - retCode = CKM_API_ERROR_SERVER_ERROR; - break; - } + DB::Row row; + + CryptoAlgorithm params; + params.addParam(ParamName::SV_HASH_ALGO, hash); + params.addParam(ParamName::SV_RSA_PADDING, padding); + + // try certificate first - looking for a public key. + // in case of PKCS, pub key from certificate will be found first + // rather than private key from the same PKCS. + retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, row); + if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) { + retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, row); + } - retCode = cs.verifySignature(key, message, signature, hash, padding); - } while(0); - } catch (const CryptoService::Exception::Crypto_internal &e) { - LogError("KeyProvider failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const CryptoService::Exception::opensslError &e) { - LogError("KeyProvider failed with message: " << e.GetMessage()); + if (retCode == CKM_API_SUCCESS) { + retCode = m_decider.getStore(row).getKey(row)->verify(params, message, signature); + } + } catch (const Crypto::Exception::Base &e) { + LogError("GStore failed with error: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; } catch (const KeyProvider::Exception::Base &e) { LogError("KeyProvider failed with error: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCryptoModule::Exception::Base &e) { - LogError("DBCryptoModule failed with message: " << e.GetMessage()); + } catch (const CryptoLogic::Exception::DecryptDBRowError &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_AUTHENTICATION_FAILED; + } catch (const CryptoLogic::Exception::Base &e) { + LogError("CryptoLogic failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } catch (const CKM::Exception &e) { + LogError("Unknown CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } - MessageBuffer response; - Serialization::Serialize(response, static_cast(LogicCommand::VERIFY_SIGNATURE)); - Serialization::Serialize(response, commandId); - Serialization::Serialize(response, retCode); - + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::VERIFY_SIGNATURE), + commandId, + retCode); return response.Pop(); } + +int CKMLogic::setPermissionHelper( + const Credentials &cred, // who's the client + const Name &name, + const Label &label, // who's the owner + const Label &accessorLabel, // who will get the access + const PermissionMask permissionMask) +{ + auto &handler = selectDatabase(cred, label); + + // we don't know the client + if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel)) + return CKM_API_ERROR_INPUT_PARAM; + + // use client label if not explicitly provided + const Label& ownerLabel = label.empty() ? cred.smackLabel : label; + + // verify name and label are correct + if (!isNameValid(name) || !isLabelValid(ownerLabel) || !isLabelValid(accessorLabel)) + return CKM_API_ERROR_INPUT_PARAM; + + // currently we don't support modification of owner's permissions to his own rows + if (ownerLabel==accessorLabel) + return CKM_API_ERROR_INPUT_PARAM; + + // system database does not support write/remove permissions + if ((0 == ownerLabel.compare(LABEL_SYSTEM_DB)) && + (permissionMask & Permission::REMOVE)) + return CKM_API_ERROR_INPUT_PARAM; + + // can the client modify permissions to owner's row? + int retCode = m_accessControl.canModify(cred, ownerLabel); + if(retCode != CKM_API_SUCCESS) + return retCode; + + DB::Crypto::Transaction transaction(&handler.database); + + if( !handler.database.isNameLabelPresent(name, ownerLabel) ) + return CKM_API_ERROR_DB_ALIAS_UNKNOWN; + + // removing non-existing permissions: fail + if(permissionMask == Permission::NONE) + { + if(!handler.database.getPermissionRow(name, ownerLabel, accessorLabel)) + return CKM_API_ERROR_INPUT_PARAM; + } + + // set permissions to the row owned by ownerLabel for accessorLabel + handler.database.setPermission(name, ownerLabel, accessorLabel, permissionMask); + transaction.commit(); + + return CKM_API_SUCCESS; +} + +RawBuffer CKMLogic::setPermission( + const Credentials &cred, + const int command, + const int msgID, + const Name &name, + const Label &label, + const Label &accessorLabel, + const PermissionMask permissionMask) +{ + int retCode; + Try { + retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask); + } catch (const CKMLogic::Exception::DatabaseLocked &e) { + LogError("Error " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_LOCKED; + } Catch (CKM::Exception) { + LogError("Error in set row!"); + retCode = CKM_API_ERROR_DB_ERROR; + } + + return MessageBuffer::Serialize(command, msgID, retCode).Pop(); +} + } // namespace CKM