Redfish: Add TrustStore certificate support

1) Implements CertificateCollection schema to upload
CA certificates and to list existing CA certificates

2) Modified CertificateLocatons schema to list CA
certificates

3) Modified ReplaceCertificate action of CertificateService
schema to cater for replacing existing CA certificate

Tested:
1) No validation failure
2) Truststore CertificateCollection
curl -k -H "X-Auth-Token: $bmc_token" -X GET
https://${bmc}/redfish/v1/Managers/bmc/Truststore/Certificates/
{
  "@odata.context":
"/redfish/v1/$metadata#CertificateCollection.CertificateCollection",
  "@odata.id": "/redfish/v1/Managers/bmc/Truststore/Certificates/",
  "@odata.type": "#CertificateCollection.CertificateCollection",
  "Description": "A Collection of TrustStore certificate instances",
  "Members": [],
  "Members@odata.count": 0,
  "Name": "TrustStore Certificates Collection"
}

3) Upload certificate
curl -c cjar -b cjar -k -H "X-Auth-Token: $bmc_token" -H "Content-Type:
application/octet-stream" -X POST -T cert.pem
https://${bmc}/redfish/v1/Managers/bmc/Truststore/Certificates
{
  "@odata.context": "/redfish/v1/$metadata#Certificate.Certificate",
  "@odata.id": "/redfish/v1/Managers/bmc/Truststore/Certificates/1",
  "@odata.type": "#Certificate.v1_0_0.Certificate",
  "CertificateString": ----\n",
  "Id": "1",
  "Issuer": {
    "CommonName": "localhost",
    "Organization": "openbmc-project.xyz"
  },
}
4) Certificate Locations
curl -k -H "X-Auth-Token: $bmc_token" -X GET
https://${bmc}/redfish/v1/CertificateService/CertificateLocations/
{
  "@odata.context":
"/redfish/v1/$metadata#CertificateLocations.CertificateLocations",
  "@odata.id": "/redfish/v1/CertificateService/CertificateLocations",
  "@odata.type": "#CertificateLocations.v1_0_0.CertificateLocations",
  "Description": "Defines a resource that an administrator can use in order
tolocate all certificates installed on a given service",
  "Id": "CertificateLocations",
  "Links": {
    "Certificates": [
      {
        "@odata.id":
"/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
      },
      {
        "@odata.id": "/redfish/v1/AccountService/LDAP/Certificates/1"
      },
      {
        "@odata.id": "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
      }
    ],
    "Certificates@odata.count": 3
  },
  "Name": "Certificate Locations"
}

5)Replace certificate
curl -c cjar -b cjar -k -H "X-Auth-Token: $bmc_token" -X POST
https://${bmc}/redfish/v1/CertificateService/Actions/Certificateervice.ReplaceCertificate/
-d @data_auth.json
{
  "@odata.context": "/redfish/v1/$metadata#Certificate.Certificate",
  "@odata.id": "/redfish/v1/Managers/bmc/Truststore/Certificates/1",
  "@odata.type": "#Certificate.v1_0_0.Certificate",
  "CertificateString": "-----BEGIN CERTIFICATE--------\n",
  "Id": "1",
  "Issuer": {
    "CommonName": "localhost",
    "Organization": "openbmc-project.xyz"
  },

6)List CertificateCollection
curl -k -H "X-Auth-Token: $bmc_token" -X GET
https://${bmc}/redfish/v1/Managers/bmc/Truststore/Certificates/
{
  "@odata.context":
"/redfish/v1/$metadata#CertificateCollection.CertificateCollection",
  "@odata.id": "/redfish/v1/Managers/bmc/Truststore/Certificates/",
  "@odata.type": "#CertificateCollection.CertificateCollection",
  "Description": "A Collection of TrustStore certificate instances",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
    }
  ],
  "Members@odata.count": 1,
  "Name": "TrustStore Certificates Collection"
}

Change-Id: Ic9644fadfe6fe89b529e16336cc6bcd804810b3a
Signed-off-by: Marri Devender Rao <devenrao@in.ibm.com>
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 93418e4..ec6d0d7 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -135,6 +135,9 @@
         nodes.emplace_back(std::make_unique<LDAPCertificateCollection>(app));
         nodes.emplace_back(std::make_unique<LDAPCertificate>(app));
         nodes.emplace_back(std::make_unique<CertificateActionGenerateCSR>(app));
+        nodes.emplace_back(
+            std::make_unique<TrustStoreCertificateCollection>(app));
+        nodes.emplace_back(std::make_unique<TrustStoreCertificate>(app));
         nodes.emplace_back(std::make_unique<SystemPCIeFunction>(app));
         nodes.emplace_back(std::make_unique<SystemPCIeDevice>(app));
         for (const auto& node : nodes)
diff --git a/redfish-core/lib/certificate_service.hpp b/redfish-core/lib/certificate_service.hpp
index 10fe554..f2cd966 100644
--- a/redfish-core/lib/certificate_service.hpp
+++ b/redfish-core/lib/certificate_service.hpp
@@ -34,6 +34,10 @@
     "xyz.openbmc_project.Certs.Manager.Server.Https";
 constexpr char const *ldapServiceName =
     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
+constexpr char const *authorityServiceName =
+    "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
+constexpr char const *authorityObjectPath =
+    "/xyz/openbmc_project/certs/authority/ldap";
 } // namespace certs
 
 /**
@@ -738,6 +742,15 @@
             name = "LDAP certificate";
             service = certs::ldapServiceName;
         }
+        else if (boost::starts_with(
+                     certURI,
+                     "/redfish/v1/Managers/bmc/Truststore/Certificates/"))
+        {
+            objectPath = std::string(certs::authorityObjectPath) + "/" +
+                         std::to_string(id);
+            name = "TrustStore certificate";
+            service = certs::authorityServiceName;
+        }
         else
         {
             messages::actionParameterNotSupported(
@@ -961,6 +974,9 @@
         getCertificateLocations(asyncResp,
                                 "/redfish/v1/AccountService/LDAP/Certificates/",
                                 certs::ldapObjectPath, certs::ldapServiceName);
+        getCertificateLocations(
+            asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/",
+            certs::authorityObjectPath, certs::authorityServiceName);
     }
     /**
      * @brief Retrieve the certificates installed list and append to the
@@ -1138,4 +1154,142 @@
                                  id, certURL, "LDAP Certificate");
     }
 }; // LDAPCertificate
+/**
+ * Collection of TrustStoreCertificate certificates
+ */
+class TrustStoreCertificateCollection : public Node
+{
+  public:
+    template <typename CrowApp>
+    TrustStoreCertificateCollection(CrowApp &app) :
+        Node(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
+    {
+        entityPrivileges = {
+            {boost::beast::http::verb::get, {{"Login"}}},
+            {boost::beast::http::verb::head, {{"Login"}}},
+            {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+    }
+    void doGet(crow::Response &res, const crow::Request &req,
+               const std::vector<std::string> &params) override
+    {
+        res.jsonValue = {
+            {"@odata.id", "/redfish/v1/Managers/bmc/Truststore/Certificates/"},
+            {"@odata.type", "#CertificateCollection.CertificateCollection"},
+            {"@odata.context",
+             "/redfish/v1/"
+             "$metadata#CertificateCollection.CertificateCollection"},
+            {"Name", "TrustStore Certificates Collection"},
+            {"Description",
+             "A Collection of TrustStore certificate instances"}};
+        auto asyncResp = std::make_shared<AsyncResp>(res);
+        crow::connections::systemBus->async_method_call(
+            [asyncResp](const boost::system::error_code ec,
+                        const ManagedObjectType &certs) {
+                if (ec)
+                {
+                    BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
+                    messages::internalError(asyncResp->res);
+                    return;
+                }
+                nlohmann::json &members = asyncResp->res.jsonValue["Members"];
+                members = nlohmann::json::array();
+                for (const auto &cert : certs)
+                {
+                    long id = getIDFromURL(cert.first.str);
+                    if (id >= 0)
+                    {
+                        members.push_back(
+                            {{"@odata.id", "/redfish/v1/Managers/bmc/"
+                                           "Truststore/Certificates/" +
+                                               std::to_string(id)}});
+                    }
+                }
+                asyncResp->res.jsonValue["Members@odata.count"] =
+                    members.size();
+            },
+            certs::authorityServiceName, certs::authorityObjectPath,
+            certs::dbusObjManagerIntf, "GetManagedObjects");
+    }
+
+    void doPost(crow::Response &res, const crow::Request &req,
+                const std::vector<std::string> &params) override
+    {
+        std::shared_ptr<CertificateFile> certFile =
+            std::make_shared<CertificateFile>(req.body);
+        auto asyncResp = std::make_shared<AsyncResp>(res);
+        crow::connections::systemBus->async_method_call(
+            [asyncResp, certFile](const boost::system::error_code ec) {
+                if (ec)
+                {
+                    BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
+                    messages::internalError(asyncResp->res);
+                    return;
+                }
+                //// TODO: Issue#84 supporting only 1 certificate
+                long certId = 1;
+                std::string certURL = "/redfish/v1/Managers/bmc/"
+                                      "Truststore/Certificates/" +
+                                      std::to_string(certId);
+                std::string objectPath =
+                    std::string(certs::authorityObjectPath) + "/" +
+                    std::to_string(certId);
+                getCertificateProperties(asyncResp, objectPath,
+                                         certs::authorityServiceName, certId,
+                                         certURL, "TrustStore Certificate");
+                BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
+                                 << certFile->getCertFilePath();
+            },
+            certs::authorityServiceName, certs::authorityObjectPath,
+            certs::certInstallIntf, "Install", certFile->getCertFilePath());
+    }
+}; // TrustStoreCertificateCollection
+
+/**
+ * Certificate resource describes a certificate used to prove the identity
+ * of a component, account or service.
+ */
+class TrustStoreCertificate : public Node
+{
+  public:
+    template <typename CrowApp>
+    TrustStoreCertificate(CrowApp &app) :
+        Node(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/",
+             std::string())
+    {
+        entityPrivileges = {
+            {boost::beast::http::verb::get, {{"Login"}}},
+            {boost::beast::http::verb::head, {{"Login"}}},
+            {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+    }
+
+    void doGet(crow::Response &res, const crow::Request &req,
+               const std::vector<std::string> &params) override
+    {
+        auto asyncResp = std::make_shared<AsyncResp>(res);
+        long id = getIDFromURL(req.url);
+        if (id < 0)
+        {
+            BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
+            messages::internalError(asyncResp->res);
+            return;
+        }
+        BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID="
+                         << std::to_string(id);
+        std::string certURL =
+            "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
+            std::to_string(id);
+        std::string objectPath = certs::authorityObjectPath;
+        objectPath += "/";
+        objectPath += std::to_string(id);
+        getCertificateProperties(asyncResp, objectPath,
+                                 certs::authorityServiceName, id, certURL,
+                                 "TrustStore Certificate");
+    }
+}; // TrustStoreCertificate
 } // namespace redfish
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index 4ebff71..9db714b 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -1570,6 +1570,8 @@
         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
         oemOpenbmc["@odata.context"] =
             "/redfish/v1/$metadata#OemManager.OpenBmc";
+        oemOpenbmc["Certificates"] = {
+            {"@odata.id", "/redfish/v1/Managers/bmc/Truststore/Certificates"}};
 
         // Update Actions object.
         nlohmann::json& manager_reset =