PLDM : Multiple vmi certificate exchange

With this story PLDM detects interface added signal on interface
xyz.openbmc_project.Certs.Entry and saves the value of CSR property.
This CSR string is then sent to the host. Once the host responds to it
the response is verified and a client certificate received from host
is updates/saved in a dbus property - ClientCertificate.

For multiple certificate exchange, new dbus objects are
created for signing requests from different clients. Each dbus
object has properties such has CSR and Client certificate that get
updated with the certificate string when a valid CSR request is
sent to host and client certficate is received successfully.

After the dbus property (ClientCertificate) has a valid client
certificate string, status property of the dbus interface
xyz.openbmc_project.Certs.Entry is updated from pending to complete.

Signed-off-by: Varsha Kaverappa <vkaverap@in.ibm.com>
Change-Id: I63afb15190ae9c21eb86421d75f51618b358c074
diff --git a/oem/ibm/libpldmresponder/file_io_type_cert.cpp b/oem/ibm/libpldmresponder/file_io_type_cert.cpp
index f21cdf2..3fe123e 100644
--- a/oem/ibm/libpldmresponder/file_io_type_cert.cpp
+++ b/oem/ibm/libpldmresponder/file_io_type_cert.cpp
@@ -14,9 +14,7 @@
 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";
+static constexpr auto certFilePath = "/var/lib/ibm/bmcweb/";
 
 CertMap CertHandler::certMap;
 
@@ -50,21 +48,37 @@
                                 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;
     }
-    return transferFileData(csrFilePath, true, offset, length, address);
+    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*/)
 {
+    std::string filePath = certFilePath;
+    filePath += "CSR_" + std::to_string(fileHandle);
     if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
     {
         return PLDM_ERROR_INVALID_DATA;
     }
-    return readFile(csrFilePath, offset, length, response);
+    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,
@@ -100,15 +114,90 @@
         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)
+            {
+                std::cerr << "failed to set Client certificate, "
+                             "ERROR="
+                          << e.what() << "\n";
+                return PLDM_ERROR;
+            }
+            PropertyValue valueStatus{
+                "xyz.openbmc_project.Certs.Entry.State.Complete"};
+            DBusMapping dbusMappingStatus{certObjPath +
+                                              std::to_string(fileHandle),
+                                          certEntryIntf, "Status", "string"};
+            try
+            {
+                pldm::utils::DBusHandler().setDbusProperty(dbusMappingStatus,
+                                                           valueStatus);
+            }
+            catch (const std::exception& e)
+            {
+                std::cerr
+                    << "failed to set status property of certicate entry, "
+                       "ERROR="
+                    << e.what() << "\n";
+                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
+            {
+                pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
+            }
+            catch (const std::exception& e)
+            {
+                std::cerr
+                    << "failed to set status property of certicate entry, "
+                       "ERROR="
+                    << e.what() << "\n";
+                return PLDM_ERROR;
+            }
+        }
+    }
     return PLDM_SUCCESS;
 }
 
 int CertHandler::newFileAvailable(uint64_t length)
 {
-    static constexpr auto vmiCertPath = "/var/lib/bmcweb";
-    fs::create_directories(vmiCertPath);
+    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)
     {
@@ -116,11 +205,14 @@
     }
     if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
     {
-        fileFd = open(clientCertPath, flags, S_IRUSR | S_IWUSR);
+        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(rootCertPath, flags, S_IRUSR | S_IWUSR);
+        fileFd =
+            open((filePath + "RootCert").c_str(), flags, S_IRUSR | S_IWUSR);
     }
     if (fileFd == -1)
     {