pldm oem: implement certificate handler
This commit adds code to handle the ceritificate request and
certificate transfer between the host and bmc following pldm oem
file i/o protocol
Change-Id: I8095e0f5ad8c3c5cc796da1cfbe4bb9946af31cf
Signed-off-by: Sampa Misra <sampmisr@in.ibm.com>
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index c178269..bb0d10c 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -27,7 +27,8 @@
'../oem/ibm/libpldmresponder/file_table.cpp',
'../oem/ibm/libpldmresponder/file_io_by_type.cpp',
'../oem/ibm/libpldmresponder/file_io_type_pel.cpp',
- '../oem/ibm/libpldmresponder/file_io_type_dump.cpp'
+ '../oem/ibm/libpldmresponder/file_io_type_dump.cpp',
+ '../oem/ibm/libpldmresponder/file_io_type_cert.cpp'
]
endif
diff --git a/oem/ibm/libpldm/file_io.c b/oem/ibm/libpldm/file_io.c
index 16b56e6..69aed29 100644
--- a/oem/ibm/libpldm/file_io.c
+++ b/oem/ibm/libpldm/file_io.c
@@ -598,7 +598,7 @@
return PLDM_ERROR_INVALID_DATA;
}
- if (payload_length != PLDM_RW_FILE_BY_TYPE_REQ_BYTES) {
+ if (payload_length < PLDM_RW_FILE_BY_TYPE_REQ_BYTES) {
return PLDM_ERROR_INVALID_LENGTH;
}
diff --git a/oem/ibm/libpldm/file_io.h b/oem/ibm/libpldm/file_io.h
index 53f4343..aebe315 100644
--- a/oem/ibm/libpldm/file_io.h
+++ b/oem/ibm/libpldm/file_io.h
@@ -52,6 +52,9 @@
PLDM_FILE_TYPE_LID_PERM = 1,
PLDM_FILE_TYPE_LID_TEMP = 2,
PLDM_FILE_TYPE_DUMP = 3,
+ PLDM_FILE_TYPE_CERT_SIGNING_REQUEST = 4,
+ PLDM_FILE_TYPE_SIGNED_CERT = 5,
+ PLDM_FILE_TYPE_ROOT_CERT = 6,
};
#define PLDM_RW_FILE_MEM_REQ_BYTES 20
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index 9322d9d..ff7f0ee 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -616,7 +616,7 @@
Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
- if (payloadLength != PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
+ if (payloadLength < PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
{
encode_rw_file_by_type_resp(request->hdr.instance_id,
PLDM_WRITE_FILE_BY_TYPE,
@@ -653,7 +653,7 @@
}
rc = handler->write(reinterpret_cast<const char*>(
- request->payload + PLDM_RW_FILE_BY_TYPE_RESP_BYTES),
+ request->payload + PLDM_RW_FILE_BY_TYPE_REQ_BYTES),
offset, length);
encode_rw_file_by_type_resp(request->hdr.instance_id,
PLDM_WRITE_FILE_BY_TYPE, rc, length,
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.cpp b/oem/ibm/libpldmresponder/file_io_by_type.cpp
index 2ecc3d9..540937c 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.cpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.cpp
@@ -2,6 +2,7 @@
#include "file_io_by_type.hpp"
+#include "file_io_type_cert.hpp"
#include "file_io_type_dump.hpp"
#include "file_io_type_lid.hpp"
#include "file_io_type_pel.hpp"
@@ -126,6 +127,13 @@
return std::make_unique<DumpHandler>(fileHandle);
break;
}
+ case PLDM_FILE_TYPE_CERT_SIGNING_REQUEST:
+ case PLDM_FILE_TYPE_SIGNED_CERT:
+ case PLDM_FILE_TYPE_ROOT_CERT:
+ {
+ return std::make_unique<CertHandler>(fileHandle, fileType);
+ break;
+ }
default:
{
throw InternalFailure();
diff --git a/oem/ibm/libpldmresponder/file_io_type_cert.cpp b/oem/ibm/libpldmresponder/file_io_type_cert.cpp
new file mode 100644
index 0000000..aef3f4c
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_io_type_cert.cpp
@@ -0,0 +1,132 @@
+#include "file_io_type_cert.hpp"
+
+#include "utils.hpp"
+
+#include <stdint.h>
+
+#include <iostream>
+
+#include "libpldm/base.h"
+#include "oem/ibm/libpldm/file_io.h"
+
+namespace pldm
+{
+namespace responder
+{
+
+static constexpr auto csrFilePath = "/var/lib/bmcweb/CSR";
+static constexpr auto rootCertPath = "/var/lib/bmcweb/RootCert";
+static constexpr auto clientCertPath = "/var/lib/bmcweb/ClientCert";
+
+CertMap CertHandler::certMap;
+
+int CertHandler::writeFromMemory(uint32_t offset, uint32_t length,
+ uint64_t address)
+{
+ auto it = certMap.find(certType);
+ if (it == certMap.end())
+ {
+ std::cerr << "file for type " << certType << " doesn't exist\n";
+ 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)
+{
+ if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
+ {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ return transferFileData(csrFilePath, true, offset, length, address);
+}
+
+int CertHandler::read(uint32_t offset, uint32_t& length, Response& response)
+{
+ if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
+ {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ return readFile(csrFilePath, offset, length, response);
+}
+
+int CertHandler::write(const char* buffer, uint32_t offset, uint32_t& length)
+{
+ auto it = certMap.find(certType);
+ if (it == certMap.end())
+ {
+ std::cerr << "file for type " << certType << " doesn't exist\n";
+ return PLDM_ERROR;
+ }
+
+ auto fd = std::get<0>(it->second);
+ int rc = lseek(fd, offset, SEEK_SET);
+ if (rc == -1)
+ {
+ std::cerr << "lseek failed, ERROR=" << errno << ", OFFSET=" << offset
+ << "\n";
+ return PLDM_ERROR;
+ }
+ rc = ::write(fd, buffer, length);
+ if (rc == -1)
+ {
+ std::cerr << "file write failed, ERROR=" << errno
+ << ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
+ return PLDM_ERROR;
+ }
+ length = rc;
+ auto& remSize = std::get<1>(it->second);
+ remSize -= length;
+ if (!remSize)
+ {
+ close(fd);
+ certMap.erase(it);
+ }
+ return PLDM_SUCCESS;
+}
+
+int CertHandler::newFileAvailable(uint64_t length)
+{
+ static constexpr auto vmiCertPath = "/var/lib/bmcweb";
+ fs::create_directories(vmiCertPath);
+ int fileFd = -1;
+ int flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+ if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
+ {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
+ {
+ fileFd = open(clientCertPath, flags);
+ }
+ else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
+ {
+ fileFd = open(rootCertPath, flags);
+ }
+ if (fileFd == -1)
+ {
+ std::cerr << "failed to open file for type " << certType
+ << " ERROR=" << errno << "\n";
+ return PLDM_ERROR;
+ }
+ certMap.emplace(certType, std::tuple(fileFd, length));
+ return PLDM_SUCCESS;
+}
+
+} // namespace responder
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io_type_cert.hpp b/oem/ibm/libpldmresponder/file_io_type_cert.hpp
new file mode 100644
index 0000000..a981fab
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_io_type_cert.hpp
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "file_io_by_type.hpp"
+
+#include <tuple>
+
+namespace pldm
+{
+namespace responder
+{
+
+using Fd = int;
+using RemainingSize = uint64_t;
+using CertDetails = std::tuple<Fd, RemainingSize>;
+using CertType = uint16_t;
+using CertMap = std::map<CertType, CertDetails>;
+
+/** @class CertHandler
+ *
+ * @brief Inherits and implements FileHandler. This class is used
+ * to read/write certificates and certificate signing requests
+ */
+class CertHandler : public FileHandler
+{
+ public:
+ /** @brief CertHandler constructor
+ */
+ CertHandler(uint32_t fileHandle, uint16_t fileType) :
+ FileHandler(fileHandle), certType(fileType)
+ {
+ }
+
+ virtual int writeFromMemory(uint32_t offset, uint32_t length,
+ uint64_t address);
+ virtual int readIntoMemory(uint32_t offset, uint32_t& length,
+ uint64_t address);
+ virtual int read(uint32_t offset, uint32_t& length, Response& response);
+
+ virtual int write(const char* buffer, uint32_t offset, uint32_t& length);
+
+ virtual int fileAck(uint8_t /*fileStatus*/)
+ {
+ return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+ }
+
+ virtual int newFileAvailable(uint64_t length);
+
+ /** @brief CertHandler destructor
+ */
+ ~CertHandler()
+ {
+ }
+
+ private:
+ uint16_t certType; //!< type of the certificate
+ static CertMap certMap; //!< holds the fd and remaining read/write size for
+ //!< each certificate
+};
+} // namespace responder
+} // namespace pldm
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index a8d0722..c19d769 100644
--- a/oem/ibm/test/libpldmresponder_fileio_test.cpp
+++ b/oem/ibm/test/libpldmresponder_fileio_test.cpp
@@ -1,5 +1,6 @@
#include "libpldmresponder/file_io.hpp"
#include "libpldmresponder/file_io_by_type.hpp"
+#include "libpldmresponder/file_io_type_cert.hpp"
#include "libpldmresponder/file_io_type_dump.hpp"
#include "libpldmresponder/file_io_type_lid.hpp"
#include "libpldmresponder/file_io_type_pel.hpp"
@@ -800,6 +801,18 @@
auto dumpType = dynamic_cast<DumpHandler*>(handler.get());
ASSERT_TRUE(dumpType != nullptr);
+ handler = getHandlerByType(PLDM_FILE_TYPE_CERT_SIGNING_REQUEST, fileHandle);
+ auto certType = dynamic_cast<CertHandler*>(handler.get());
+ ASSERT_TRUE(certType != nullptr);
+
+ handler = getHandlerByType(PLDM_FILE_TYPE_SIGNED_CERT, fileHandle);
+ certType = dynamic_cast<CertHandler*>(handler.get());
+ ASSERT_TRUE(certType != nullptr);
+
+ handler = getHandlerByType(PLDM_FILE_TYPE_ROOT_CERT, fileHandle);
+ certType = dynamic_cast<CertHandler*>(handler.get());
+ ASSERT_TRUE(certType != nullptr);
+
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
ASSERT_THROW(getHandlerByType(0xFFFF, fileHandle), InternalFailure);
}