X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fmanager%2Fservice%2Fckm-logic.cpp;h=217d0cde524edb11cb7e22494e9dc47b8984038e;hb=720242043b3488a5abf805424847e5cd087bd90b;hp=7744066abc48fbc8e0d3a6929e113510151ad9ac;hpb=11a0d3c4490474e1fff622098a2fe3153af97271;p=platform%2Fcore%2Fsecurity%2Fkey-manager.git diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index 7744066..217d0cd 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -19,148 +19,222 @@ * @version 1.0 * @brief Sample service implementation. */ -#include #include #include #include #include #include #include -#include #include #include - -#ifndef VCONFKEY_SECURITY_MDPP_STATE -#define VCONFKEY_SECURITY_MDPP_STATE = "file/security_mdpp/security_mdpp_state"; -#endif +#include +#include +#include +#include +#include +#include +#include +#include namespace { -const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs"; - -const char* const MDPP_MODE_ENFORCING = "Enforcing"; -const char* const MDPP_MODE_ENABLED = "Enabled"; +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 { -CKMLogic::CKMLogic() : m_ccMode(false) +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); - if (CKM_API_SUCCESS != m_certStore.setSystemCertificateDir(CERT_SYSTEM_DIR)) { - LogError("Fatal error in CertificateStore::setSystemCertificateDir. Chain creation will not work"); + // 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); } - updateCCMode_internal(); + // 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 Password &password) { - // TODO try catch for all errors that should be supported by error code - int retCode = CKM_API_SUCCESS; +void CKMLogic::loadDKEKFile(uid_t user, const Password &password) { + auto &handle = m_userDataMap[user]; - try { - if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) { - auto &handle = m_userDataMap[user]; - FileSystem fs(user); - auto wrappedDomainKEK = fs.getDKEK(); - - if (wrappedDomainKEK.empty()) { - wrappedDomainKEK = KeyProvider::generateDomainKEK(std::to_string(user), password); - fs.saveDKEK(wrappedDomainKEK); - } + FileSystem fs(user); - handle.keyProvider = KeyProvider(wrappedDomainKEK, password); + auto wrappedDKEK = fs.getDKEK(); - auto wrappedDatabaseDEK = fs.getDBDEK(); + if (wrappedDKEK.empty()) { + wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password); + fs.saveDKEK(wrappedDKEK); + } - if (wrappedDatabaseDEK.empty()) { - wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user)); - fs.saveDBDEK(wrappedDatabaseDEK); - } + 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)) + ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked"); - char *mdppState = vconf_get_str(VCONFKEY_SECURITY_MDPP_STATE); - newMode = ( mdppState && (!strcmp(mdppState, MDPP_MODE_ENABLED) || - !strcmp(mdppState, MDPP_MODE_ENFORCING)) ); - if (newMode == m_ccMode) - return; + if (0 != incoming_label.compare(OWNER_ID_SYSTEM)) + return m_userDataMap[cred.clientUid]; + } - m_ccMode = newMode; + // system database selected, modify the label + if (CKM_API_SUCCESS != unlockSystemDB() ) + ThrowErr(Exc::DatabaseLocked, "can not unlock system database"); + return m_userDataMap[SYSTEM_DB_UID]; +} - fipsModeStatus = FIPS_mode(); +RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) +{ + int retCode = CKM_API_SUCCESS; - if(m_ccMode) { - if(fipsModeStatus == 0) { // If FIPS mode off - rc = FIPS_mode_set(1); // Change FIPS_mode from off to on - if(rc == 0) { - LogError("Error in FIPS_mode_set function"); - } - } - } else { - if(fipsModeStatus == 1) { // If FIPS mode on - rc = FIPS_mode_set(0); // Change FIPS_mode from on to off - if(rc == 0) { - LogError("Error in FIPS_mode_set function"); - } - } + 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() { - updateCCMode_internal(); + m_accessControl.updateCCMode(); return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop(); } -RawBuffer CKMLogic::lockUserKey(uid_t user) { +RawBuffer CKMLogic::lockUserKey(uid_t user) +{ int retCode = CKM_API_SUCCESS; - // TODO try catch for all errors that should be supported by error code - m_userDataMap.erase(user); + 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(); @@ -168,7 +242,10 @@ RawBuffer CKMLogic::lockUserKey(uid_t user) { 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); @@ -177,27 +254,31 @@ RawBuffer CKMLogic::removeUserData(uid_t user) { 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 Password &oldPassword, const Password &newPassword) { int retCode = CKM_API_SUCCESS; - try { - FileSystem fs(user); - auto wrappedDomainKEK = fs.getDKEK(); - if (wrappedDomainKEK.empty()) { - retCode = CKM_API_ERROR_BAD_REQUEST; - } else { - wrappedDomainKEK = KeyProvider::reencrypt(wrappedDomainKEK, oldPassword, newPassword); - fs.saveDKEK(wrappedDomainKEK); - } - } 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; + try + { + retCode = changeUserPasswordHelper(user, oldPassword, newPassword); + } catch (const Exc::Exception &e) { + retCode = e.error(); } catch (const CKM::Exception &e) { LogError("CKM::Exception: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; @@ -206,24 +287,47 @@ RawBuffer CKMLogic::changeUserPassword( return MessageBuffer::Serialize(retCode).Pop(); } -RawBuffer CKMLogic::resetUserPassword( +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; - // TODO try-catch - if (0 == m_userDataMap.count(user)) { - retCode = CKM_API_ERROR_BAD_REQUEST; - } else { - auto &handler = m_userDataMap[user]; + if (0 == m_userDataMap.count(user)) + { + // Check if key exists. If exists we must return error FileSystem fs(user); - fs.saveDKEK(handler.keyProvider.getWrappedDomainKEK(newPassword)); + auto wrappedDKEKMain = fs.getDKEK(); + if (!wrappedDKEKMain.empty()) + retCode = CKM_API_ERROR_BAD_REQUEST; + } else { + saveDKEKFile(user, newPassword); + } + + return retCode; +} + +RawBuffer CKMLogic::resetUserPassword( + uid_t user, + const Password &newPassword) +{ + int retCode = CKM_API_SUCCESS; + try { + retCode = resetUserPasswordHelper(user, newPassword); + } catch (const Exc::Exception &e) { + retCode = e.error(); + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } return MessageBuffer::Serialize(retCode).Pop(); } -RawBuffer CKMLogic::removeApplicationData(const std::string &smackLabel) { +RawBuffer CKMLogic::removeApplicationData(const Label &smackLabel) { int retCode = CKM_API_SUCCESS; try { @@ -238,135 +342,204 @@ RawBuffer CKMLogic::removeApplicationData(const std::string &smackLabel) { fs.addRemovedApp(smackLabel); } else { auto &handle = m_userDataMap[userId]; + handle.crypto.removeKey(smackLabel); handle.database.deleteKey(smackLabel); } } } - } catch (const DBCrypto::Exception::InternalError &e) { - LogError("DBCrypto couldn't remove data: " << e.GetMessage()); + } catch (const DB::Crypto::Exception::InternalError &e) { + LogError("DB::Crypto couldn't remove data: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; - } 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 Exc::Exception &e) { + retCode = e.error(); + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } return MessageBuffer::Serialize(retCode).Pop(); } -int CKMLogic::saveDataHelper( - Credentials &cred, - DBDataType dataType, - const Alias &alias, - const RawBuffer &key, - const PolicySerializable &policy) +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)) { + LogDebug("Invalid parameter passed to key-manager"); + return CKM_API_ERROR_INPUT_PARAM; + } + + // check if allowed to save using ownerLabel + int access_ec = m_accessControl.canSave(cred, ownerLabel); + if( access_ec != CKM_API_SUCCESS) + { + LogDebug("label " << cred.smackLabel << " can not save rows using label " << ownerLabel); + return access_ec; + } - // proceed to data save - DBRow row = { alias, cred.smackLabel, - policy.extractable, dataType, DBCMAlgType::NONE, - 0, RawBuffer(), static_cast(key.size()), key, RawBuffer() }; + // check if not a duplicate + if( handler.database.isNameLabelPresent(name, ownerLabel)) + return CKM_API_ERROR_DB_ALIAS_EXISTS; - 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); + // 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); } - // Do not encrypt data with password during cc_mode on - if(m_ccMode) { - handler.crypto.encryptRow("", row); + 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 +{ + Crypto::GStore& store = m_decider.getStore(dataType, policy.extractable); + Token token = store.import(dataType, data); + + DB::Row row(std::move(token), name, label, static_cast(policy.extractable)); + + // do not encrypt data with password during cc_mode on + if(m_accessControl.isCCMode()) { + crypto.encryptRow("", row); } else { - handler.crypto.encryptRow(policy.password, row); + crypto.encryptRow(policy.password, row); } + return row; +} - handler.database.saveDBRow(row); - transaction.commit(); - return CKM_API_SUCCESS; +int CKMLogic::verifyBinaryData(DataType dataType, RawBuffer &input_data) const +{ + RawBuffer dummy; + return toBinaryData(dataType, input_data, dummy); } -void CKMLogic::verifyBinaryData(DBDataType dataType, const RawBuffer &input_data) const +int CKMLogic::toBinaryData(DataType dataType, + const RawBuffer &input_data, + RawBuffer &output_data) const { // verify the data integrity - switch(dataType) + if (dataType.isKey()) { - case DBDataType::KEY_RSA_PUBLIC: - case DBDataType::KEY_RSA_PRIVATE: - case DBDataType::KEY_ECDSA_PUBLIC: - case DBDataType::KEY_ECDSA_PRIVATE: - case DBDataType::KEY_DSA_PUBLIC: - case DBDataType::KEY_DSA_PRIVATE: - case DBDataType::KEY_AES: + 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) { - KeyShPtr output_key = CKM::Key::create(input_data); - if(output_key.get() == NULL) - ThrowMsg(CKMLogic::Exception::InputDataInvalid, "provided binary data is not valid key data"); - break; + LogDebug("provided binary data is not valid key data"); + return CKM_API_ERROR_INPUT_PARAM; } - - case DBDataType::CERTIFICATE: + 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) { - CertificateShPtr cert = CKM::Certificate::create(input_data, DataFormat::FORM_DER); - if(cert.get() == NULL) - ThrowMsg(CKMLogic::Exception::InputDataInvalid, "provided binary data is not valid certificate data"); - break; + LogDebug("provided binary data is not valid certificate data"); + return CKM_API_ERROR_INPUT_PARAM; } - - // TODO: add here BINARY_DATA verification, i.e: max size etc. - - default: break; + output_data = cert->getDER(); } + else + output_data = input_data; + // TODO: add here BINARY_DATA verification, i.e: max size etc. + return CKM_API_SUCCESS; } -RawBuffer CKMLogic::saveData( - Credentials &cred, - int commandId, - DBDataType dataType, - const Alias &alias, - const RawBuffer &key, +int CKMLogic::verifyAndSaveDataHelper( + const Credentials &cred, + const Name &name, + const Label &label, + const RawBuffer &data, + DataType dataType, const PolicySerializable &policy) { - int retCode = CKM_API_SUCCESS; - try { - verifyBinaryData(dataType, key); + int retCode = CKM_API_ERROR_UNKNOWN; - retCode = saveDataHelper(cred, dataType, alias, key, policy); - LogDebug("SaveDataHelper returned: " << retCode); - } catch (const CKMLogic::Exception::InputDataInvalid &e) { - LogError("Provided data invalid: " << e.GetMessage()); - retCode = CKM_API_ERROR_INPUT_PARAM; - } 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 DBCrypto::Exception::InternalError &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + 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 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 Exc::Exception &e) { + retCode = e.error(); + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + return retCode; +} + +int CKMLogic::getKeyForService( + const Credentials &cred, + const Name &name, + const Label &label, + const Password &pass, + Crypto::GKeyShPtr &key) +{ + DB::Row row; + try { + // Key is for internal service use. It won't be exported to the client + int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, label, pass, row); + if (retCode == CKM_API_SUCCESS) + key = m_decider.getStore(row).getKey(row); + return retCode; + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); + return CKM_API_ERROR_DB_ERROR; + } catch (const Exc::Exception &e) { + return e.error(); + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + return CKM_API_ERROR_SERVER_ERROR; } +} +RawBuffer CKMLogic::saveData( + const Credentials &cred, + int commandId, + const Name &name, + const Label &label, + const RawBuffer &data, + DataType dataType, + const PolicySerializable &policy) +{ + int retCode = verifyAndSaveDataHelper(cred, name, label, data, dataType, policy); auto response = MessageBuffer::Serialize(static_cast(LogicCommand::SAVE), commandId, retCode, @@ -374,316 +547,884 @@ RawBuffer CKMLogic::saveData( return response.Pop(); } -RawBuffer CKMLogic::removeData( - Credentials &cred, - int commandId, - DBDataType dataType, - const Alias &alias) +int CKMLogic::extractPKCS12Data( + CryptoLogic &crypto, + const Name &name, + const Label &ownerLabel, + const PKCS12Serializable &pkcs, + const PolicySerializable &keyPolicy, + const PolicySerializable &certPolicy, + DB::RowVector &output) const { - int retCode = CKM_API_SUCCESS; + // 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)); - if (0 < m_userDataMap.count(cred.uid)) { - Try { - auto erased = m_userDataMap[cred.uid].database.deleteDBRow(alias, cred.smackLabel); - // check if the data existed or not - if(!erased) { - LogError("No row for given alias and label"); - retCode = CKM_API_ERROR_DB_ALIAS_UNKNOWN; - } - } Catch (DBCrypto::Exception::PermissionDenied) { - LogError("Error: not enough permissions!"); - retCode = CKM_API_ERROR_ACCESS_DENIED; - } Catch (CKM::Exception) { - LogError("Error in deleting row!"); - retCode = CKM_API_ERROR_DB_ERROR; - } - } else { - retCode = CKM_API_ERROR_DB_LOCKED; + // 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)); } - auto response = MessageBuffer::Serialize(static_cast(LogicCommand::REMOVE), + 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, name, label, pkcs, keyPolicy, certPolicy); + } catch (const Exc::Exception &e) { + retCode = e.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 CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::SAVE_PKCS12), commandId, - retCode, - static_cast(dataType)); + retCode); return response.Pop(); } -int CKMLogic::getDataHelper( - Credentials &cred, - DBDataType dataType, - const Alias &alias, - const Password &password, - DBRow &row) + +int CKMLogic::removeDataHelper( + const Credentials &cred, + const Name &name, + const Label &label) { - if (0 == m_userDataMap.count(cred.uid)) - return CKM_API_ERROR_DB_LOCKED; + 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)) { + LogDebug("Invalid label or name format"); + return CKM_API_ERROR_INPUT_PARAM; + } - auto &handler = m_userDataMap[cred.uid]; + DB::Crypto::Transaction transaction(&handler.database); - 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))) + // 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) { - row_optional = handler.database.getKeyDBRow(alias, cred.smackLabel); - } else { - LogError("Unknown type of requested data" << (int)dataType); - return CKM_API_ERROR_BAD_REQUEST; + LogWarning("access control check result: " << retCode); + return retCode; } - if(!row_optional) { - LogError("No row for given alias, label and type"); + + // get all matching rows + DB::RowVector rows; + handler.database.getRows(name, ownerLabel, DataType::DB_FIRST, DataType::DB_LAST, rows); + if (rows.empty()) { + LogDebug("No row for given name and label"); return CKM_API_ERROR_DB_ALIAS_UNKNOWN; - } else { - row = *row_optional; } - if (!handler.crypto.haveKey(row.smackLabel)) { - RawBuffer key; - auto key_optional = handler.database.getKey(row.smackLabel); - if(!key_optional) { - LogError("No key for given label in database"); - return CKM_API_ERROR_DB_ERROR; + // load app key if needed + retCode = loadAppKey(handler, rows.front().ownerLabel); + if(CKM_API_SUCCESS != retCode) + return retCode; + + // destroy it in store + for(auto& r : rows) { + /* + * TODO: If row is encrypted with user password we won't be able to decrypt it (tz id). + * Encryption/decryption with user password and with app key should both be done inside the + * store (import, getKey and generateXKey). + */ + try { + handler.crypto.decryptRow(Password(), r); + } catch (const Exc::AuthenticationFailed&) { + LogDebug("Authentication failed when removing data. Ignored."); } - key = *key_optional; - key = handler.keyProvider.getPureDEK(key); - handler.crypto.pushKey(cred.smackLabel, key); + m_decider.getStore(r.dataType, r.exportable).destroy(r); } - handler.crypto.decryptRow(password, row); + + // delete row in db + handler.database.deleteRow(name, ownerLabel); + transaction.commit(); return CKM_API_SUCCESS; } -RawBuffer CKMLogic::getData( - Credentials &cred, +RawBuffer CKMLogic::removeData( + const Credentials &cred, int commandId, - DBDataType dataType, - const Alias &alias, - const Password &password) + const Name &name, + const Label &label) { - int retCode = CKM_API_SUCCESS; - DBRow row; - - try { - retCode = getDataHelper(cred, dataType, alias, password, row); - } catch (const KeyProvider::Exception::Base &e) { - LogError("KeyProvider failed with error: " << 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 DBCrypto::Exception::PermissionDenied &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_ACCESS_DENIED; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_DB_ERROR; - } + int retCode = CKM_API_ERROR_UNKNOWN; - if (CKM_API_SUCCESS != retCode) { - row.data.clear(); - row.dataType = dataType; + try + { + retCode = removeDataHelper(cred, name, label); } - - if ((CKM_API_SUCCESS == retCode) && (row.exportable == 0)) { - row.data.clear(); - retCode = CKM_API_ERROR_NOT_EXPORTABLE; + catch (const Exc::Exception &e) + { + retCode = e.error(); } - - // Prevent extracting private keys during cc-mode on - if((m_ccMode) && (row.dataType == DBDataType::KEY_RSA_PRIVATE || - row.dataType == DBDataType::KEY_ECDSA_PRIVATE || - row.dataType == DBDataType::KEY_DSA_PRIVATE)) + catch (const CKM::Exception &) { - row.data.clear(); - retCode = CKM_API_ERROR_BAD_REQUEST; + LogError("Error in deleting row!"); + retCode = CKM_API_ERROR_DB_ERROR; } - auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET), + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::REMOVE), commandId, - retCode, - static_cast(row.dataType), - row.data); + retCode); return response.Pop(); } -RawBuffer CKMLogic::getDataList( - Credentials &cred, - int commandId, - DBDataType dataType) +int CKMLogic::readSingleRow(const Name &name, + const Label &ownerLabel, + DataType dataType, + DB::Crypto & database, + DB::Row &row) { - int retCode = CKM_API_SUCCESS; - AliasVector aliasVector; + DB::Crypto::RowOptional row_optional; + if (dataType.isKey()) + { + // read all key types + row_optional = database.getRow(name, + ownerLabel, + DataType::DB_KEY_FIRST, + DataType::DB_KEY_LAST); + } else { + // read anything else + row_optional = database.getRow(name, + ownerLabel, + dataType); + } - 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(cred.smackLabel, dataType, aliasVector); - } else { - handler.database.getKeyAliases(cred.smackLabel, aliasVector); - } - } Catch (CKM::Exception) { - LogError("Failed to get aliases"); - retCode = CKM_API_ERROR_DB_ERROR; - } + if(!row_optional) { + LogDebug("No row for given name, label and type"); + return CKM_API_ERROR_DB_ALIAS_UNKNOWN; } else { - retCode = CKM_API_ERROR_DB_LOCKED; + row = *row_optional; } - auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET_LIST), - commandId, - retCode, - static_cast(dataType), - aliasVector); - return response.Pop(); + return CKM_API_SUCCESS; } -int CKMLogic::createKeyPairHelper( - Credentials &cred, - const KeyType key_type, - const int additional_param, - const Alias &aliasPrivate, - const Alias &aliasPublic, - const PolicySerializable &policyPrivate, - const PolicySerializable &policyPublic) +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()) { + LogDebug("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; + + // load app key if needed + retCode = loadAppKey(handler, firstRow.ownerLabel); + if(CKM_API_SUCCESS != retCode) + return retCode; + + // decrypt row + 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) { - if (0 >= m_userDataMap.count(cred.uid)) - return CKM_API_ERROR_DB_LOCKED; + 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; + + // load app key if needed + retCode = loadAppKey(handler, row.ownerLabel); + if(CKM_API_SUCCESS != retCode) + return retCode; - auto &handler = m_userDataMap[cred.uid]; - KeyImpl prv, pub; + // decrypt row + handler.crypto.decryptRow(password, row); + + return CKM_API_SUCCESS; +} + +RawBuffer CKMLogic::getData( + const Credentials &cred, + int commandId, + DataType dataType, + const Name &name, + const Label &label, + const Password &password) +{ + int retCode = CKM_API_SUCCESS; + DB::Row row; + + try { + retCode = readDataHelper(true, cred, dataType, name, label, password, row); + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const Exc::Exception &e) { + retCode = e.error(); + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; + } + + if (CKM_API_SUCCESS != retCode) { + row.data.clear(); + row.dataType = dataType; + } + + auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET), + commandId, + retCode, + static_cast(row.dataType), + row.data); + return response.Pop(); +} + +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; - switch(key_type) + + // 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 DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } catch (const Exc::Exception &e) { + retCode = e.error(); + } 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)) { - case KeyType::KEY_RSA_PUBLIC: - case KeyType::KEY_RSA_PRIVATE: - retCode = CryptoService::createKeyPairRSA(additional_param, prv, pub); - break; - - case KeyType::KEY_DSA_PUBLIC: - case KeyType::KEY_DSA_PRIVATE: - retCode = CryptoService::createKeyPairDSA(additional_param, prv, pub); - break; - - case KeyType::KEY_ECDSA_PUBLIC: - case KeyType::KEY_ECDSA_PRIVATE: - retCode = CryptoService::createKeyPairECDSA(static_cast(additional_param), prv, pub); - break; - - default: - return CKM_API_ERROR_INPUT_PARAM; + auto &database = m_userDataMap[cred.clientUid].database; + + Try { + LabelNameVector tmpVector; + if (dataType.isKey()) { + // list all key types + database.listNames(cred.smackLabel, + tmpVector, + DataType::DB_KEY_FIRST, + DataType::DB_KEY_LAST); + } else { + // list anything else + database.listNames(cred.smackLabel, + tmpVector, + dataType); + } + 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; + } } + return retCode; +} + +RawBuffer CKMLogic::getDataList( + const Credentials &cred, + int commandId, + DataType dataType) +{ + LabelNameVector systemVector; + LabelNameVector userVector; + LabelNameVector labelNameVector; - if (CKM_CRYPTO_CREATEKEY_SUCCESS != retCode) + 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, + OWNER_ID_SYSTEM), + 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) +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); + + // use client label if not explicitly provided + const Label &ownerLabel = label.empty() ? cred.smackLabel : label; + if( m_accessControl.isSystemService(cred) && ownerLabel.compare(OWNER_ID_SYSTEM)!=0) + return CKM_API_ERROR_INPUT_PARAM; + + // 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; - retCode = saveDataHelper(cred, - toDBDataType(pub.getType()), - aliasPublic, - pub.getDER(), - policyPublic); + // save the data + DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, ownerLabel, dataType, data, policy); + handler.database.saveRow(encryptedRow); - if (CKM_API_SUCCESS != retCode) + transaction.commit(); + return CKM_API_SUCCESS; +} + +int CKMLogic::saveDataHelper( + const Credentials &cred, + const Name &name, + const Label &label, + const PKCS12Serializable &pkcs, + const PolicySerializable &keyPolicy, + const PolicySerializable &certPolicy) +{ + auto &handler = selectDatabase(cred, label); + + // use client label if not explicitly provided + const Label &ownerLabel = label.empty() ? cred.smackLabel : label; + if( m_accessControl.isSystemService(cred) && ownerLabel.compare(OWNER_ID_SYSTEM)!=0) + return CKM_API_ERROR_INPUT_PARAM; + + // 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; + + // 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; + // save the data + handler.database.saveRows(name, ownerLabel, encryptedRows); transaction.commit(); - return retCode; + return CKM_API_SUCCESS; +} + + +int CKMLogic::createKeyAESHelper( + const Credentials &cred, + const int size, + const Name &name, + const Label &label, + const PolicySerializable &policy) +{ + CryptoAlgorithm keyGenAlgorithm; + keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN); + keyGenAlgorithm.setParam(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); +} + + +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)) + ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found."); + DataType dt(keyType); + if(!dt.isKey()) + ThrowErr(Exc::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, + namePublic, + labelPublic, + keys.second.dataType, + keys.second.data, + policyPublic); + if (CKM_API_SUCCESS != retCode) + return retCode; + + transactionPub.commit(); + transactionPriv.commit(); + return CKM_API_SUCCESS; } RawBuffer CKMLogic::createKeyPair( - Credentials &cred, - LogicCommand protocol_cmd, + const Credentials &cred, int commandId, - const int additional_param, - 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; - KeyType key_type = KeyType::KEY_NONE; - switch(protocol_cmd) - { - case LogicCommand::CREATE_KEY_PAIR_RSA: - key_type = KeyType::KEY_RSA_PUBLIC; - break; - case LogicCommand::CREATE_KEY_PAIR_DSA: - key_type = KeyType::KEY_DSA_PUBLIC; - break; - case LogicCommand::CREATE_KEY_PAIR_ECDSA: - key_type = KeyType::KEY_ECDSA_PUBLIC; - break; - default: - break; - } - try { retCode = createKeyPairHelper( cred, - key_type, - additional_param, - aliasPrivate, - aliasPublic, + keyGenParams, + namePrivate, + labelPrivate, + namePublic, + labelPublic, 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()); + } catch(const Exc::Exception &e) { + retCode = e.error(); + } 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 (DBCrypto::Exception::InternalError &e) { - LogDebug("DBCrypto internal error: " << e.GetMessage()); + } catch (DB::Crypto::Exception::InternalError &e) { + LogDebug("DB::Crypto internal error: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const CKM::Exception &e) { + LogError("CKM::Exception: " << e.GetMessage()); + retCode = CKM_API_ERROR_SERVER_ERROR; } - return MessageBuffer::Serialize(static_cast(protocol_cmd), commandId, retCode).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 Exc::Exception &e) { + retCode = e.error(); + } 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 (DB::Crypto::Exception::InternalError &e) { + LogDebug("DB::Crypto internal error: " << e.GetMessage()); + retCode = CKM_API_ERROR_DB_ERROR; + } 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) - untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER)); + if (cert.empty()) + return CKM_API_ERROR_INPUT_PARAM; - LogDebug("Cert is empty: " << cert.empty()); + for (auto &e: untrustedCertificates) { + CertificateImpl c(e, DataFormat::FORM_DER); + if(c.empty()) + return CKM_API_ERROR_INPUT_PARAM; + untrustedCertVector.push_back(std::move(c)); + } + for (auto &e: trustedCertificates) { + CertificateImpl c(e, DataFormat::FORM_DER); + if(c.empty()) + return CKM_API_ERROR_INPUT_PARAM; + trustedCertVector.push_back(std::move(c)); + } - int retCode = m_certStore.verifyCertificate(cert, untrustedCertVector, chainVector); + CertificateStore store; + int retCode = store.verifyCertificate(cert, + untrustedCertVector, + trustedCertVector, + useTrustedSystemCertificates, + m_accessControl.isCCMode(), + chainVector); + if (retCode != CKM_API_SUCCESS) + return retCode; - if (retCode == CKM_API_SUCCESS) { - for (auto &e : chainVector) - chainRawVector.push_back(e.getDER()); + for (auto &e : chainVector) + chainRawVector.push_back(e.getDER()); + return CKM_API_SUCCESS; +} + +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 (cert.empty()) + return CKM_API_ERROR_INPUT_PARAM; + + 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( + const Credentials & /*cred*/, + int commandId, + const RawBuffer &certificate, + const RawBufferVector &untrustedCertificates, + const RawBufferVector &trustedCertificates, + bool useTrustedSystemCertificates) +{ + CertificateImpl cert(certificate, DataFormat::FORM_DER); + RawBufferVector chainRawVector; + int retCode = CKM_API_ERROR_UNKNOWN; + try { + retCode = getCertificateChainHelper(cert, + untrustedCertificates, + trustedCertificates, + useTrustedSystemCertificates, + chainRawVector); + } catch (const Exc::Exception &e) { + retCode = e.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."); } auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET_CHAIN_CERT), @@ -694,55 +1435,35 @@ RawBuffer CKMLogic::getCertificateChain( } RawBuffer CKMLogic::getCertificateChain( - Credentials &cred, + const Credentials &cred, int commandId, const RawBuffer &certificate, - const AliasVector &aliasVector) + const LabelNameVector &untrustedCertificates, + const LabelNameVector &trustedCertificates, + bool useTrustedSystemCertificates) { - int retCode = CKM_API_SUCCESS; + int retCode = CKM_API_ERROR_UNKNOWN; + CertificateImpl cert(certificate, DataFormat::FORM_DER); RawBufferVector chainRawVector; 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, Password(), 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; - - for (auto &i: chainVector) - chainRawVector.push_back(i.getDER()); - - } catch (const CryptoLogic::Exception::Base &e) { - LogError("DBCyptorModule failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCrypto::Exception::PermissionDenied &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_ACCESS_DENIED; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + retCode = getCertificateChainHelper(cred, + cert, + untrustedCertificates, + trustedCertificates, + useTrustedSystemCertificates, + chainRawVector); + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const Exc::Exception &e) { + retCode = e.error(); + } catch (const std::exception& e) { + LogError("STD exception " << e.what()); + retCode = CKM_API_ERROR_SERVER_ERROR; } catch (...) { LogError("Unknown error."); } -senderror: auto response = MessageBuffer::Serialize(static_cast(LogicCommand::GET_CHAIN_ALIAS), commandId, retCode, @@ -751,46 +1472,33 @@ senderror: } RawBuffer CKMLogic::createSignature( - Credentials &cred, + const Credentials &cred, int commandId, - const Alias &privateKeyAlias, + 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.setParam(ParamName::SV_HASH_ALGO, hash); + cryptoAlg.setParam(ParamName::SV_RSA_PADDING, padding); int retCode = CKM_API_SUCCESS; try { - do { - retCode = getDataHelper(cred, DBDataType::DB_KEY_FIRST, privateKeyAlias, password, row); - if (CKM_API_SUCCESS != retCode) { - LogError("getDataHelper return error"); - break; - } - - KeyImpl keyParsed(row.data, Password()); - if (keyParsed.empty()) - retCode = CKM_API_ERROR_SERVER_ERROR; - else - retCode = cs.createSignature(keyParsed, message, hash, padding, signature); - } while(0); - } 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 DBCrypto::Exception::PermissionDenied &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_ACCESS_DENIED; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + 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 DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; + } catch (const Exc::Exception &e) { + retCode = e.error(); } catch (const CKM::Exception &e) { LogError("Unknown CKM::Exception: " << e.GetMessage()); retCode = CKM_API_ERROR_SERVER_ERROR; @@ -804,9 +1512,10 @@ RawBuffer CKMLogic::createSignature( } RawBuffer CKMLogic::verifySignature( - Credentials &cred, + const Credentials &cred, int commandId, - const Alias &publicKeyOrCertAlias, + const Name &publicKeyOrCertName, + const Label & ownerLabel, const Password &password, // password for public_key (optional) const RawBuffer &message, const RawBuffer &signature, @@ -816,49 +1525,27 @@ RawBuffer CKMLogic::verifySignature( int retCode = CKM_API_ERROR_VERIFICATION_FAILED; try { - do { - CryptoService cs; - DBRow row; - KeyImpl key; - - retCode = getDataHelper(cred, DBDataType::DB_KEY_FIRST, publicKeyOrCertAlias, password, row); - - if (retCode == CKM_API_SUCCESS) { - key = KeyImpl(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.getKeyImpl(); - } else { - break; - } - - if (key.empty()) { - retCode = CKM_API_ERROR_SERVER_ERROR; - break; - } + DB::Row row; + + CryptoAlgorithm params; + params.setParam(ParamName::SV_HASH_ALGO, hash); + params.setParam(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()); - 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 CryptoLogic::Exception::Base &e) { - LogError("CryptoLogic failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_SERVER_ERROR; - } catch (const DBCrypto::Exception::PermissionDenied &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); - retCode = CKM_API_ERROR_ACCESS_DENIED; - } catch (const DBCrypto::Exception::Base &e) { - LogError("DBCrypto failed with message: " << e.GetMessage()); + if (retCode == CKM_API_SUCCESS) { + retCode = m_decider.getStore(row).getKey(row)->verify(params, message, signature); + } + } catch (const Exc::Exception &e) { + retCode = e.error(); + } catch (const DB::Crypto::Exception::Base &e) { + LogError("DB::Crypto failed with message: " << e.GetMessage()); retCode = CKM_API_ERROR_DB_ERROR; } catch (const CKM::Exception &e) { LogError("Unknown CKM::Exception: " << e.GetMessage()); @@ -871,66 +1558,96 @@ RawBuffer CKMLogic::verifySignature( return response.Pop(); } -RawBuffer CKMLogic::allowAccess( - Credentials &cred, - int command, - int msgID, - const Alias &item_alias, - const std::string &accessor_label, - const AccessRight req_rights) +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) { - int retCode = CKM_API_ERROR_VERIFICATION_FAILED; + 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; - if (0 < m_userDataMap.count(cred.uid)) + // 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(OWNER_ID_SYSTEM)) && + (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) { - Try { - retCode = m_userDataMap[cred.uid].database.setAccessRights(cred.smackLabel, item_alias, accessor_label, req_rights); - } Catch (DBCrypto::Exception::InvalidArgs) { - LogError("Error: invalid args!"); - retCode = CKM_API_ERROR_INPUT_PARAM; - } Catch (DBCrypto::Exception::PermissionDenied) { - LogError("Error: not enough permissions!"); - retCode = CKM_API_ERROR_ACCESS_DENIED; - } Catch (CKM::Exception) { - LogError("Error in set row!"); - retCode = CKM_API_ERROR_DB_ERROR; - } - } else { - retCode = CKM_API_ERROR_DB_LOCKED; + if(!handler.database.getPermissionRow(name, ownerLabel, accessorLabel)) + return CKM_API_ERROR_INPUT_PARAM; } - return MessageBuffer::Serialize(command, msgID, retCode).Pop(); + // 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::denyAccess( - Credentials &cred, - int command, - int msgID, - const Alias &item_alias, - const std::string &accessor_label) +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 = CKM_API_ERROR_VERIFICATION_FAILED; - - if (0 < m_userDataMap.count(cred.uid)) - { - Try { - retCode = m_userDataMap[cred.uid].database.clearAccessRights(cred.smackLabel, item_alias, accessor_label); - } Catch (DBCrypto::Exception::PermissionDenied) { - LogError("Error: not enough permissions!"); - retCode = CKM_API_ERROR_ACCESS_DENIED; - } Catch (DBCrypto::Exception::InvalidArgs) { - LogError("Error: permission not found!"); - retCode = CKM_API_ERROR_INPUT_PARAM; - } Catch (CKM::Exception) { - LogError("Error in deleting row!"); - retCode = CKM_API_ERROR_DB_ERROR; - } - } else { - retCode = CKM_API_ERROR_DB_LOCKED; + int retCode; + Try { + retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask); + } catch (const Exc::Exception &e) { + retCode = e.error(); + } Catch (CKM::Exception) { + LogError("Error in set row!"); + retCode = CKM_API_ERROR_DB_ERROR; } return MessageBuffer::Serialize(command, msgID, retCode).Pop(); } +int CKMLogic::loadAppKey(UserData& handle, const Label& appLabel) +{ + if (!handle.crypto.haveKey(appLabel)) { + RawBuffer key; + auto key_optional = handle.database.getKey(appLabel); + if(!key_optional) { + LogError("No key for given label in database"); + return CKM_API_ERROR_DB_ERROR; + } + key = *key_optional; + key = handle.keyProvider.getPureDEK(key); + handle.crypto.pushKey(appLabel, key); + } + return CKM_API_SUCCESS; +} + } // namespace CKM