blob: a5b4e216d6bc09727e98d04e5f6ecfa441ef7d69 [file] [log] [blame]
#include "file_io_type_cert.hpp"
#include "common/utils.hpp"
#include <libpldm/base.h>
#include <libpldm/oem/ibm/file_io.h>
#include <stdint.h>
#include <phosphor-logging/lg2.hpp>
PHOSPHOR_LOG2_USING;
namespace pldm
{
using namespace utils;
namespace responder
{
constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/";
constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry";
static constexpr auto certFilePath = "/var/lib/ibm/bmcweb/";
CertMap CertHandler::certMap;
int CertHandler::writeFromMemory(uint32_t offset, uint32_t length,
uint64_t address,
oem_platform::Handler* /*oemPlatformHandler*/)
{
auto it = certMap.find(certType);
if (it == certMap.end())
{
error(
"CertHandler::writeFromMemory:file for type {CERT_TYPE} doesn't exist",
"CERT_TYPE", certType);
return PLDM_ERROR;
}
auto fd = std::get<0>(it->second);
auto& remSize = std::get<1>(it->second);
auto rc = transferFileData(fd, false, offset, length, address);
if (rc == PLDM_SUCCESS)
{
remSize -= length;
if (!remSize)
{
close(fd);
certMap.erase(it);
}
}
return rc;
}
int CertHandler::readIntoMemory(uint32_t offset, uint32_t& length,
uint64_t address,
oem_platform::Handler* /*oemPlatformHandler*/)
{
std::string filePath = certFilePath;
filePath += "CSR_" + std::to_string(fileHandle);
if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
{
return PLDM_ERROR_INVALID_DATA;
}
auto rc = transferFileData(filePath.c_str(), true, offset, length, address);
fs::remove(filePath);
if (rc)
{
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
int CertHandler::read(uint32_t offset, uint32_t& length, Response& response,
oem_platform::Handler* /*oemPlatformHandler*/)
{
info(
"CertHandler::read:Read file response for Sign CSR, file handle: {FILE_HANDLE}",
"FILE_HANDLE", fileHandle);
std::string filePath = certFilePath;
filePath += "CSR_" + std::to_string(fileHandle);
if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
{
return PLDM_ERROR_INVALID_DATA;
}
auto rc = readFile(filePath.c_str(), offset, length, response);
fs::remove(filePath);
if (rc)
{
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
int CertHandler::write(const char* buffer, uint32_t offset, uint32_t& length,
oem_platform::Handler* /*oemPlatformHandler*/)
{
auto it = certMap.find(certType);
if (it == certMap.end())
{
error("CertHandler::write:file for type {CERT_TYPE} doesn't exist",
"CERT_TYPE", certType);
return PLDM_ERROR;
}
auto fd = std::get<0>(it->second);
int rc = lseek(fd, offset, SEEK_SET);
if (rc == -1)
{
error("CertHandler::write:lseek failed, ERROR={ERR}, OFFSET={OFFSET}",
"ERR", errno, "OFFSET", offset);
return PLDM_ERROR;
}
rc = ::write(fd, buffer, length);
if (rc == -1)
{
error(
"CertHandler::write:file write failed, ERROR={ERR}, LENGTH={LEN}, OFFSET={OFFSET}",
"ERR", errno, "LEN", length, "OFFSET", offset);
return PLDM_ERROR;
}
length = rc;
auto& remSize = std::get<1>(it->second);
remSize -= length;
if (!remSize)
{
close(fd);
certMap.erase(it);
}
if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
{
constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/";
constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry";
std::string filePath = certFilePath;
filePath += "ClientCert_" + std::to_string(fileHandle);
std::ifstream inFile;
inFile.open(filePath);
std::stringstream strStream;
strStream << inFile.rdbuf();
std::string str = strStream.str();
inFile.close();
if (!str.empty())
{
PropertyValue value{str};
DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
certEntryIntf, "ClientCertificate",
"string"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
error(
"CertHandler::write:failed to set Client certificate, ERROR={ERR_EXCEP}",
"ERR_EXCEP", e.what());
return PLDM_ERROR;
}
PropertyValue valueStatus{
"xyz.openbmc_project.Certs.Entry.State.Complete"};
DBusMapping dbusMappingStatus{certObjPath +
std::to_string(fileHandle),
certEntryIntf, "Status", "string"};
try
{
info(
"CertHandler::write:Client cert write, status: complete. File handle: {FILE_HANDLE}",
"FILE_HANDLE", fileHandle);
pldm::utils::DBusHandler().setDbusProperty(dbusMappingStatus,
valueStatus);
}
catch (const std::exception& e)
{
error(
"CertHandler::write:failed to set status property of certicate entry, ERROR={ERR_EXCEP}",
"ERR_EXCEP", e.what());
return PLDM_ERROR;
}
fs::remove(filePath);
}
else
{
PropertyValue value{"xyz.openbmc_project.Certs.Entry.State.BadCSR"};
DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
certEntryIntf, "Status", "string"};
try
{
info(
"CertHandler::write:Client cert write, status: Bad CSR. File handle: {FILE_HANDLE}",
"FILE_HANDLE", fileHandle);
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
error(
"CertHandler::write:failed to set status property of certicate entry, {ERR_EXCEP}",
"ERR_EXCEP", e.what());
return PLDM_ERROR;
}
}
}
return PLDM_SUCCESS;
}
int CertHandler::newFileAvailable(uint64_t length)
{
fs::create_directories(certFilePath);
fs::permissions(certFilePath,
fs::perms::others_read | fs::perms::owner_write);
int fileFd = -1;
int flags = O_WRONLY | O_CREAT | O_TRUNC;
std::string filePath = certFilePath;
if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
{
return PLDM_ERROR_INVALID_DATA;
}
if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
{
info(
"CertHandler::newFileAvailable:new file available client cert file, file handle: {FILE_HANDLE}",
"FILE_HANDLE", fileHandle);
fileFd = open(
(filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(),
flags, S_IRUSR | S_IWUSR);
}
else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
{
fileFd = open((filePath + "RootCert").c_str(), flags,
S_IRUSR | S_IWUSR);
}
if (fileFd == -1)
{
error(
"CertHandler::newFileAvailable:failed to open file for type {CERT_TYPE} ERROR={ERR}",
"CERT_TYPE", certType, "ERR", errno);
return PLDM_ERROR;
}
certMap.emplace(certType, std::tuple(fileFd, length));
return PLDM_SUCCESS;
}
int CertHandler::newFileAvailableWithMetaData(uint64_t length,
uint32_t metaDataValue1,
uint32_t /*metaDataValue2*/,
uint32_t /*metaDataValue3*/,
uint32_t /*metaDataValue4*/)
{
fs::create_directories(certFilePath);
fs::permissions(certFilePath,
fs::perms::others_read | fs::perms::owner_write);
int fileFd = -1;
int flags = O_WRONLY | O_CREAT | O_TRUNC;
std::string filePath = certFilePath;
if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
{
return PLDM_ERROR_INVALID_DATA;
}
if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
{
if (metaDataValue1 == PLDM_SUCCESS)
{
error(
"CertHandler::newFileAvailableWithMetaData:new file available client cert file, file handle: {FILE_HANDLE}",
"FILE_HANDLE", fileHandle);
fileFd = open(
(filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(),
flags, S_IRUSR | S_IWUSR);
}
else if (metaDataValue1 == PLDM_INVALID_CERT_DATA)
{
error(
"newFileAvailableWithMetaData:client cert file Invalid data, file handle: {FILE_HANDLE}",
"FILE_HANDLE", fileHandle);
DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
certEntryIntf, "Status", "string"};
std::string status = "xyz.openbmc_project.Certs.Entry.State.BadCSR";
PropertyValue value{status};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
error(
"newFileAvailableWithMetaData:Failed to set status property of certicate entry, ERROR= {ERR_EXCEP}",
"ERR_EXCEP", e.what());
return PLDM_ERROR;
}
}
}
else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
{
fileFd = open((filePath + "RootCert").c_str(), flags,
S_IRUSR | S_IWUSR);
}
if (fileFd == -1)
{
error(
"newFileAvailableWithMetaData:failed to open file for type {CERT_TYPE} ERROR={ERR}",
"CERT_TYPE", certType, "ERR", errno);
return PLDM_ERROR;
}
certMap.emplace(certType, std::tuple(fileFd, length));
return PLDM_SUCCESS;
}
int CertHandler::fileAckWithMetaData(uint8_t fileStatus,
uint32_t /*metaDataValue1*/,
uint32_t /*metaDataValue2*/,
uint32_t /*metaDataValue3*/,
uint32_t /*metaDataValue4*/)
{
if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
{
DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
certEntryIntf, "Status", "string"};
PropertyValue value = "xyz.openbmc_project.Certs.Entry.State.Pending";
if (fileStatus == PLDM_ERROR_INVALID_DATA)
{
value = "xyz.openbmc_project.Certs.Entry.State.BadCSR";
}
else if (fileStatus == PLDM_ERROR_NOT_READY)
{
value = "xyz.openbmc_project.Certs.Entry.State.Pending";
}
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
error(
"CertHandler::fileAckWithMetaData:Failed to set status property of certicate entry, ERROR={ERR_EXCEP}",
"ERR_EXCEP", e.what());
return PLDM_ERROR;
}
}
return PLDM_SUCCESS;
}
} // namespace responder
} // namespace pldm