xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 828252d54597049ef67e4ff43050eae312b70f07)
15968caeeSMarri Devender Rao #pragma once
25968caeeSMarri Devender Rao 
39b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp"
49b12d1f9SKrzysztof Grobelny 
57e860f15SJohn Edward Broadbent #include <app.hpp>
6d9f6c621SEd Tanous #include <async_resp.hpp>
790d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp>
8168e20c1SEd Tanous #include <dbus_utility.hpp>
9d9f6c621SEd Tanous #include <http_response.hpp>
1045ca1b86SEd Tanous #include <query.hpp>
11ed398213SEd Tanous #include <registries/privilege_registry.hpp>
129b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
139b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
141214b7e7SGunnar Mills 
155968caeeSMarri Devender Rao namespace redfish
165968caeeSMarri Devender Rao {
175968caeeSMarri Devender Rao namespace certs
185968caeeSMarri Devender Rao {
195968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
205968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
2107a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
225968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
235968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
245968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
2537cce918SMarri Devender Rao constexpr char const* httpsServiceName =
2637cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
2737cce918SMarri Devender Rao constexpr char const* ldapServiceName =
2837cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
29cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
30cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
31c6a8dfb1SJiaqing Zhao constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
32c6a8dfb1SJiaqing Zhao constexpr char const* httpsObjectPath =
33c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
34c6a8dfb1SJiaqing Zhao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
35cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
36cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
375968caeeSMarri Devender Rao } // namespace certs
385968caeeSMarri Devender Rao 
395968caeeSMarri Devender Rao /**
405968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
415968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
425968caeeSMarri Devender Rao  * are installed.
435968caeeSMarri Devender Rao  */
447e860f15SJohn Edward Broadbent 
455968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate
464e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish
475968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF
485968caeeSMarri Devender Rao // publish Privilege details for certificate service
495968caeeSMarri Devender Rao 
508d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
518d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5258eb238fSKowalski, Kamil     const crow::Request& req)
5358eb238fSKowalski, Kamil {
5458eb238fSKowalski, Kamil     nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
5558eb238fSKowalski, Kamil 
5658eb238fSKowalski, Kamil     if (reqJson.is_discarded())
5758eb238fSKowalski, Kamil     {
5858eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
5958eb238fSKowalski, Kamil         return req.body;
6058eb238fSKowalski, Kamil     }
6158eb238fSKowalski, Kamil 
6258eb238fSKowalski, Kamil     std::string certificate;
6358eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
6458eb238fSKowalski, Kamil 
6515ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
6615ed6780SWilly Tu                                   certificate, "CertificateType",
6715ed6780SWilly Tu                                   certificateType))
6858eb238fSKowalski, Kamil     {
6958eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
7058eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
71abb93cddSEd Tanous         return {};
7258eb238fSKowalski, Kamil     }
7358eb238fSKowalski, Kamil 
7458eb238fSKowalski, Kamil     if (*certificateType != "PEM")
7558eb238fSKowalski, Kamil     {
7658eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
7758eb238fSKowalski, Kamil                                          "CertificateType");
78abb93cddSEd Tanous         return {};
7958eb238fSKowalski, Kamil     }
8058eb238fSKowalski, Kamil 
8158eb238fSKowalski, Kamil     return certificate;
8258eb238fSKowalski, Kamil }
8358eb238fSKowalski, Kamil 
845968caeeSMarri Devender Rao /**
855968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
865968caeeSMarri Devender Rao  */
875968caeeSMarri Devender Rao class CertificateFile
885968caeeSMarri Devender Rao {
895968caeeSMarri Devender Rao   public:
905968caeeSMarri Devender Rao     CertificateFile() = delete;
915968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
925968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
935968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
945968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
954e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
965968caeeSMarri Devender Rao     {
9772d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
985207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
995207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1005207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
101e662eae8SEd Tanous         if (tempDirectory != nullptr)
1025968caeeSMarri Devender Rao         {
1035968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1045968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1055968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1065968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1075968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1085968caeeSMarri Devender Rao             out << certString;
1095968caeeSMarri Devender Rao             out.close();
1108cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Creating certificate file"
1118cc8edecSEd Tanous                              << certificateFile.string();
1125968caeeSMarri Devender Rao         }
1135968caeeSMarri Devender Rao     }
1145968caeeSMarri Devender Rao     ~CertificateFile()
1155968caeeSMarri Devender Rao     {
1165968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1175968caeeSMarri Devender Rao         {
1188cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Removing certificate file"
1198cc8edecSEd Tanous                              << certificateFile.string();
12023a21a1cSEd Tanous             std::error_code ec;
12123a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
12223a21a1cSEd Tanous             if (ec)
1235968caeeSMarri Devender Rao             {
1245968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1258cc8edecSEd Tanous                                  << certDirectory.string();
1265968caeeSMarri Devender Rao             }
1275968caeeSMarri Devender Rao         }
1285968caeeSMarri Devender Rao     }
1295968caeeSMarri Devender Rao     std::string getCertFilePath()
1305968caeeSMarri Devender Rao     {
1315968caeeSMarri Devender Rao         return certificateFile;
1325968caeeSMarri Devender Rao     }
1335968caeeSMarri Devender Rao 
1345968caeeSMarri Devender Rao   private:
1355968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1365968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1375968caeeSMarri Devender Rao };
1385968caeeSMarri Devender Rao 
1395968caeeSMarri Devender Rao /**
1404e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1415968caeeSMarri Devender Rao  *
1425968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1435968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1445968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1455968caeeSMarri Devender Rao  * @return None
1465968caeeSMarri Devender Rao  */
1475968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
1485968caeeSMarri Devender Rao                                       const std::string_view value)
1495968caeeSMarri Devender Rao {
1505968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1515968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1525968caeeSMarri Devender Rao     while (i != value.end())
1535968caeeSMarri Devender Rao     {
1545968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1555968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1565968caeeSMarri Devender Rao         {
15717a897dfSManojkiran Eda             ++i;
1585968caeeSMarri Devender Rao         }
1595968caeeSMarri Devender Rao         if (i == value.end())
1605968caeeSMarri Devender Rao         {
1615968caeeSMarri Devender Rao             break;
1625968caeeSMarri Devender Rao         }
163271584abSEd Tanous         const std::string_view key(tokenBegin,
164271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
16517a897dfSManojkiran Eda         ++i;
1665968caeeSMarri Devender Rao         tokenBegin = i;
1675968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
1685968caeeSMarri Devender Rao         {
16917a897dfSManojkiran Eda             ++i;
1705968caeeSMarri Devender Rao         }
171271584abSEd Tanous         const std::string_view val(tokenBegin,
172271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
1735968caeeSMarri Devender Rao         if (key == "L")
1745968caeeSMarri Devender Rao         {
1755968caeeSMarri Devender Rao             out["City"] = val;
1765968caeeSMarri Devender Rao         }
1775968caeeSMarri Devender Rao         else if (key == "CN")
1785968caeeSMarri Devender Rao         {
1795968caeeSMarri Devender Rao             out["CommonName"] = val;
1805968caeeSMarri Devender Rao         }
1815968caeeSMarri Devender Rao         else if (key == "C")
1825968caeeSMarri Devender Rao         {
1835968caeeSMarri Devender Rao             out["Country"] = val;
1845968caeeSMarri Devender Rao         }
1855968caeeSMarri Devender Rao         else if (key == "O")
1865968caeeSMarri Devender Rao         {
1875968caeeSMarri Devender Rao             out["Organization"] = val;
1885968caeeSMarri Devender Rao         }
1895968caeeSMarri Devender Rao         else if (key == "OU")
1905968caeeSMarri Devender Rao         {
1915968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
1925968caeeSMarri Devender Rao         }
1935968caeeSMarri Devender Rao         else if (key == "ST")
1945968caeeSMarri Devender Rao         {
1955968caeeSMarri Devender Rao             out["State"] = val;
1965968caeeSMarri Devender Rao         }
1975968caeeSMarri Devender Rao         // skip comma character
1985968caeeSMarri Devender Rao         if (i != value.end())
1995968caeeSMarri Devender Rao         {
20017a897dfSManojkiran Eda             ++i;
2015968caeeSMarri Devender Rao         }
2025968caeeSMarri Devender Rao     }
2035968caeeSMarri Devender Rao }
2045968caeeSMarri Devender Rao 
2055968caeeSMarri Devender Rao /**
206d3f92ce7SJiaqing Zhao  * @brief Retrieve the installed certificate list
207d3f92ce7SJiaqing Zhao  *
208d3f92ce7SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
209d3f92ce7SJiaqing Zhao  * @param[in] basePath DBus object path to search
210d3f92ce7SJiaqing Zhao  * @param[in] listPtr Json pointer to the list in asyncResp
211d3f92ce7SJiaqing Zhao  * @param[in] countPtr Json pointer to the count in asyncResp
212d3f92ce7SJiaqing Zhao  * @return None
213d3f92ce7SJiaqing Zhao  */
214d3f92ce7SJiaqing Zhao static void
215d3f92ce7SJiaqing Zhao     getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
216d3f92ce7SJiaqing Zhao                        const std::string& basePath,
217d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& listPtr,
218d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& countPtr)
219d3f92ce7SJiaqing Zhao {
220d3f92ce7SJiaqing Zhao     crow::connections::systemBus->async_method_call(
221d3f92ce7SJiaqing Zhao         [asyncResp, listPtr, countPtr](
222d3f92ce7SJiaqing Zhao             const boost::system::error_code ec,
223d3f92ce7SJiaqing Zhao             const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
224d3f92ce7SJiaqing Zhao         if (ec)
225d3f92ce7SJiaqing Zhao         {
226d3f92ce7SJiaqing Zhao             BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
227d3f92ce7SJiaqing Zhao             messages::internalError(asyncResp->res);
228d3f92ce7SJiaqing Zhao             return;
229d3f92ce7SJiaqing Zhao         }
230d3f92ce7SJiaqing Zhao 
231d3f92ce7SJiaqing Zhao         nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
232d3f92ce7SJiaqing Zhao         links = nlohmann::json::array();
233d3f92ce7SJiaqing Zhao         for (const auto& certPath : certPaths)
234d3f92ce7SJiaqing Zhao         {
235d3f92ce7SJiaqing Zhao             sdbusplus::message::object_path objPath(certPath);
236d3f92ce7SJiaqing Zhao             std::string certId = objPath.filename();
237d3f92ce7SJiaqing Zhao             if (certId.empty())
238d3f92ce7SJiaqing Zhao             {
239d3f92ce7SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
240d3f92ce7SJiaqing Zhao                 continue;
241d3f92ce7SJiaqing Zhao             }
242d3f92ce7SJiaqing Zhao 
243d3f92ce7SJiaqing Zhao             boost::urls::url certURL;
244d3f92ce7SJiaqing Zhao             if (objPath.parent_path() == certs::httpsObjectPath)
245d3f92ce7SJiaqing Zhao             {
246d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
247d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
248d3f92ce7SJiaqing Zhao                     "HTTPS", "Certificates", certId);
249d3f92ce7SJiaqing Zhao             }
250d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::ldapObjectPath)
251d3f92ce7SJiaqing Zhao             {
252d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces("redfish", "v1",
253d3f92ce7SJiaqing Zhao                                                        "AccountService", "LDAP",
254d3f92ce7SJiaqing Zhao                                                        "Certificates", certId);
255d3f92ce7SJiaqing Zhao             }
256d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::authorityObjectPath)
257d3f92ce7SJiaqing Zhao             {
258d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
259d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "Truststore",
260d3f92ce7SJiaqing Zhao                     "Certificates", certId);
261d3f92ce7SJiaqing Zhao             }
262d3f92ce7SJiaqing Zhao             else
263d3f92ce7SJiaqing Zhao             {
264d3f92ce7SJiaqing Zhao                 continue;
265d3f92ce7SJiaqing Zhao             }
266d3f92ce7SJiaqing Zhao 
267d3f92ce7SJiaqing Zhao             nlohmann::json::object_t link;
268d3f92ce7SJiaqing Zhao             link["@odata.id"] = certURL;
269d3f92ce7SJiaqing Zhao             links.emplace_back(std::move(link));
270d3f92ce7SJiaqing Zhao         }
271d3f92ce7SJiaqing Zhao 
272d3f92ce7SJiaqing Zhao         asyncResp->res.jsonValue[countPtr] = links.size();
273d3f92ce7SJiaqing Zhao         },
274d3f92ce7SJiaqing Zhao         "xyz.openbmc_project.ObjectMapper",
275d3f92ce7SJiaqing Zhao         "/xyz/openbmc_project/object_mapper",
276d3f92ce7SJiaqing Zhao         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", basePath, 0,
277d3f92ce7SJiaqing Zhao         std::array<const char*, 1>{certs::certPropIntf});
278d3f92ce7SJiaqing Zhao }
279d3f92ce7SJiaqing Zhao 
280d3f92ce7SJiaqing Zhao /**
2815968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
2825968caeeSMarri Devender Rao  * message
2835968caeeSMarri Devender Rao  *
2845968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
2855968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
2865968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
2875968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
2885968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
2895968caeeSMarri Devender Rao  * @return None
2905968caeeSMarri Devender Rao  */
2915968caeeSMarri Devender Rao static void getCertificateProperties(
2928d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
293e19e97e2SJiaqing Zhao     const std::string& objectPath, const std::string& service,
2941e312598SJiaqing Zhao     const std::string& certId, const boost::urls::url& certURL,
295e19e97e2SJiaqing Zhao     const std::string& name)
2965968caeeSMarri Devender Rao {
2975968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
2985968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
2999b12d1f9SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
3009b12d1f9SKrzysztof Grobelny         *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
301b9d36b47SEd Tanous         [asyncResp, certURL, certId,
302b9d36b47SEd Tanous          name](const boost::system::error_code ec,
303b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
3045968caeeSMarri Devender Rao         if (ec)
3055968caeeSMarri Devender Rao         {
3065968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
307d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", certId);
3085968caeeSMarri Devender Rao             return;
3095968caeeSMarri Devender Rao         }
3109b12d1f9SKrzysztof Grobelny 
3119b12d1f9SKrzysztof Grobelny         const std::string* certificateString = nullptr;
3129b12d1f9SKrzysztof Grobelny         const std::vector<std::string>* keyUsage = nullptr;
3139b12d1f9SKrzysztof Grobelny         const std::string* issuer = nullptr;
3149b12d1f9SKrzysztof Grobelny         const std::string* subject = nullptr;
3159b12d1f9SKrzysztof Grobelny         const uint64_t* validNotAfter = nullptr;
3169b12d1f9SKrzysztof Grobelny         const uint64_t* validNotBefore = nullptr;
3179b12d1f9SKrzysztof Grobelny 
3189b12d1f9SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
3199b12d1f9SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "CertificateString",
3209b12d1f9SKrzysztof Grobelny             certificateString, "KeyUsage", keyUsage, "Issuer", issuer,
3219b12d1f9SKrzysztof Grobelny             "Subject", subject, "ValidNotAfter", validNotAfter,
3229b12d1f9SKrzysztof Grobelny             "ValidNotBefore", validNotBefore);
3239b12d1f9SKrzysztof Grobelny 
3249b12d1f9SKrzysztof Grobelny         if (!success)
3259b12d1f9SKrzysztof Grobelny         {
3269b12d1f9SKrzysztof Grobelny             messages::internalError(asyncResp->res);
3279b12d1f9SKrzysztof Grobelny             return;
3289b12d1f9SKrzysztof Grobelny         }
3299b12d1f9SKrzysztof Grobelny 
3301476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = certURL;
3311476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
3321476687dSEd Tanous             "#Certificate.v1_0_0.Certificate";
333e19e97e2SJiaqing Zhao         asyncResp->res.jsonValue["Id"] = certId;
3341476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = name;
3351476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = name;
3365968caeeSMarri Devender Rao         asyncResp->res.jsonValue["CertificateString"] = "";
3379b12d1f9SKrzysztof Grobelny         asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
3389b12d1f9SKrzysztof Grobelny 
3399b12d1f9SKrzysztof Grobelny         if (certificateString != nullptr)
3405968caeeSMarri Devender Rao         {
3419b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["CertificateString"] = *certificateString;
3425968caeeSMarri Devender Rao         }
3439b12d1f9SKrzysztof Grobelny 
3449b12d1f9SKrzysztof Grobelny         if (keyUsage != nullptr)
3455968caeeSMarri Devender Rao         {
3469b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
3475968caeeSMarri Devender Rao         }
3489b12d1f9SKrzysztof Grobelny 
3499b12d1f9SKrzysztof Grobelny         if (issuer != nullptr)
3505968caeeSMarri Devender Rao         {
3519b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
3529b12d1f9SKrzysztof Grobelny                                       *issuer);
3535968caeeSMarri Devender Rao         }
3549b12d1f9SKrzysztof Grobelny 
3559b12d1f9SKrzysztof Grobelny         if (subject != nullptr)
3565968caeeSMarri Devender Rao         {
3579b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
3589b12d1f9SKrzysztof Grobelny                                       *subject);
3595968caeeSMarri Devender Rao         }
3609b12d1f9SKrzysztof Grobelny 
3619b12d1f9SKrzysztof Grobelny         if (validNotAfter != nullptr)
3625968caeeSMarri Devender Rao         {
3635968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotAfter"] =
3649b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotAfter);
3655968caeeSMarri Devender Rao         }
3669b12d1f9SKrzysztof Grobelny 
3679b12d1f9SKrzysztof Grobelny         if (validNotBefore != nullptr)
3685968caeeSMarri Devender Rao         {
3695968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotBefore"] =
3709b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotBefore);
3715968caeeSMarri Devender Rao         }
3729b12d1f9SKrzysztof Grobelny 
3731e312598SJiaqing Zhao         asyncResp->res.addHeader(
374d9f6c621SEd Tanous             boost::beast::http::field::location,
375d9f6c621SEd Tanous             std::string_view(certURL.data(), certURL.size()));
3769b12d1f9SKrzysztof Grobelny         });
3775968caeeSMarri Devender Rao }
3785968caeeSMarri Devender Rao 
379*828252d5SJiaqing Zhao inline void handleCertificateServiceGet(
380*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
381*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3825968caeeSMarri Devender Rao {
383*828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
384*828252d5SJiaqing Zhao     {
385*828252d5SJiaqing Zhao         return;
386*828252d5SJiaqing Zhao     }
387*828252d5SJiaqing Zhao 
388*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
389*828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
390*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
391*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
392*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
393*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
394*828252d5SJiaqing Zhao         "Actions available to manage certificates";
395*828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
396*828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
397*828252d5SJiaqing Zhao     // has permissions ConfigureManager
398*828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
399*828252d5SJiaqing Zhao         redfish::getUserPrivileges(req.userRole);
400*828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
401*828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
402*828252d5SJiaqing Zhao     {
403*828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
404*828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
405*828252d5SJiaqing Zhao     }
406*828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
407*828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
408*828252d5SJiaqing Zhao     replace["target"] =
409*828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
410*828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
411*828252d5SJiaqing Zhao     allowed.push_back("PEM");
412*828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
413*828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
414*828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
415*828252d5SJiaqing Zhao }
416*828252d5SJiaqing Zhao 
417*828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
418*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
419*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
420*828252d5SJiaqing Zhao {
421*828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
422*828252d5SJiaqing Zhao     {
423*828252d5SJiaqing Zhao         return;
424*828252d5SJiaqing Zhao     }
425*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
426*828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
427*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
428*828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
429*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
430*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
431*828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
432*828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
433*828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
434*828252d5SJiaqing Zhao 
435*828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
436*828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
437*828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
438*828252d5SJiaqing Zhao }
439*828252d5SJiaqing Zhao 
440*828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
441*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
442*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
443*828252d5SJiaqing Zhao {
4443ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
44545ca1b86SEd Tanous     {
44645ca1b86SEd Tanous         return;
44745ca1b86SEd Tanous     }
4485968caeeSMarri Devender Rao     std::string certificate;
4495968caeeSMarri Devender Rao     nlohmann::json certificateUri;
4505968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
4518d1b46d7Szhanghch05 
452002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
453002d39b4SEd Tanous                                    certificate, "CertificateUri",
454002d39b4SEd Tanous                                    certificateUri, "CertificateType",
455002d39b4SEd Tanous                                    certificateType))
4565968caeeSMarri Devender Rao     {
4575968caeeSMarri Devender Rao         BMCWEB_LOG_ERROR << "Required parameters are missing";
4585968caeeSMarri Devender Rao         messages::internalError(asyncResp->res);
4595968caeeSMarri Devender Rao         return;
4605968caeeSMarri Devender Rao     }
4615968caeeSMarri Devender Rao 
4625968caeeSMarri Devender Rao     if (!certificateType)
4635968caeeSMarri Devender Rao     {
4645968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
4655968caeeSMarri Devender Rao         return;
4665968caeeSMarri Devender Rao     }
4675968caeeSMarri Devender Rao     if (certificateType != "PEM")
4685968caeeSMarri Devender Rao     {
469*828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
470*828252d5SJiaqing Zhao                                               "ReplaceCertificate");
4715968caeeSMarri Devender Rao         return;
4725968caeeSMarri Devender Rao     }
4735968caeeSMarri Devender Rao 
4745968caeeSMarri Devender Rao     std::string certURI;
4755968caeeSMarri Devender Rao     if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
4765968caeeSMarri Devender Rao                                       "@odata.id", certURI))
4775968caeeSMarri Devender Rao     {
478*828252d5SJiaqing Zhao         messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
479*828252d5SJiaqing Zhao                                          "CertificateUri");
4805968caeeSMarri Devender Rao         return;
4815968caeeSMarri Devender Rao     }
48275b63a2cSJiaqing Zhao     BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI;
4835968caeeSMarri Devender Rao 
48475b63a2cSJiaqing Zhao     boost::urls::result<boost::urls::url_view> parsedUrl =
48575b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
48675b63a2cSJiaqing Zhao     if (!parsedUrl)
4875968caeeSMarri Devender Rao     {
488*828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
489*828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
4905968caeeSMarri Devender Rao         return;
4915968caeeSMarri Devender Rao     }
49275b63a2cSJiaqing Zhao 
49375b63a2cSJiaqing Zhao     std::string id;
49475b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
4955968caeeSMarri Devender Rao     std::string name;
49637cce918SMarri Devender Rao     std::string service;
497*828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
498*828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
499*828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5005968caeeSMarri Devender Rao     {
501002d39b4SEd Tanous         objectPath =
50275b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::httpsObjectPath) / id;
5035968caeeSMarri Devender Rao         name = "HTTPS certificate";
50437cce918SMarri Devender Rao         service = certs::httpsServiceName;
50537cce918SMarri Devender Rao     }
50675b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
50775b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
50875b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
50937cce918SMarri Devender Rao     {
510002d39b4SEd Tanous         objectPath =
51175b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::ldapObjectPath) / id;
51237cce918SMarri Devender Rao         name = "LDAP certificate";
51337cce918SMarri Devender Rao         service = certs::ldapServiceName;
5145968caeeSMarri Devender Rao     }
51575b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
51675b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
51775b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
518cfcd5f6bSMarri Devender Rao     {
51975b63a2cSJiaqing Zhao         objectPath =
520*828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
521cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
522cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
523cfcd5f6bSMarri Devender Rao     }
5245968caeeSMarri Devender Rao     else
5255968caeeSMarri Devender Rao     {
526*828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
527*828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5285968caeeSMarri Devender Rao         return;
5295968caeeSMarri Devender Rao     }
5305968caeeSMarri Devender Rao 
5315968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
5325968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
5335968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
5341e312598SJiaqing Zhao         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
5355968caeeSMarri Devender Rao          name](const boost::system::error_code ec) {
5365968caeeSMarri Devender Rao         if (ec)
5375968caeeSMarri Devender Rao         {
5385968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
53990d2d1e8SJiaqing Zhao             if (ec.value() ==
54090d2d1e8SJiaqing Zhao                 boost::system::linux_error::bad_request_descriptor)
54190d2d1e8SJiaqing Zhao             {
542*828252d5SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
5435968caeeSMarri Devender Rao                 return;
5445968caeeSMarri Devender Rao             }
54590d2d1e8SJiaqing Zhao             messages::internalError(asyncResp->res);
54690d2d1e8SJiaqing Zhao             return;
54790d2d1e8SJiaqing Zhao         }
548*828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, service, id, url, name);
5495968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
5505968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
5515968caeeSMarri Devender Rao         },
5525968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
5535968caeeSMarri Devender Rao         certFile->getCertFilePath());
554*828252d5SJiaqing Zhao }
5555968caeeSMarri Devender Rao 
556*828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
5575968caeeSMarri Devender Rao /**
558*828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
559*828252d5SJiaqing Zhao  *
560*828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
561*828252d5SJiaqing Zhao  * @param[in] certURI Link to certifiate collection URI
562*828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
563*828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
564*828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
565*828252d5SJiaqing Zhao  * @return None
5665968caeeSMarri Devender Rao  */
567*828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
568*828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
569*828252d5SJiaqing Zhao                    const std::string& certObjPath,
570*828252d5SJiaqing Zhao                    const std::string& csrObjPath)
5715968caeeSMarri Devender Rao {
572*828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
573*828252d5SJiaqing Zhao                      << " CSRObjectPath=" << csrObjPath
574*828252d5SJiaqing Zhao                      << " service=" << service;
575*828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
576*828252d5SJiaqing Zhao         [asyncResp, certURI](const boost::system::error_code ec,
577*828252d5SJiaqing Zhao                              const std::string& csr) {
578*828252d5SJiaqing Zhao         if (ec)
579*828252d5SJiaqing Zhao         {
580*828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
581*828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
582*828252d5SJiaqing Zhao             return;
583*828252d5SJiaqing Zhao         }
584*828252d5SJiaqing Zhao         if (csr.empty())
585*828252d5SJiaqing Zhao         {
586*828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "CSR read is empty";
587*828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
588*828252d5SJiaqing Zhao             return;
589*828252d5SJiaqing Zhao         }
590*828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CSRString"] = csr;
591*828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
592*828252d5SJiaqing Zhao             certURI;
593*828252d5SJiaqing Zhao         },
594*828252d5SJiaqing Zhao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
595*828252d5SJiaqing Zhao }
596*828252d5SJiaqing Zhao 
597*828252d5SJiaqing Zhao inline void
598*828252d5SJiaqing Zhao     handleGenerateCSRAction(App& app, const crow::Request& req,
599*828252d5SJiaqing Zhao                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
600*828252d5SJiaqing Zhao {
6013ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
60245ca1b86SEd Tanous     {
60345ca1b86SEd Tanous         return;
60445ca1b86SEd Tanous     }
605*828252d5SJiaqing Zhao     static const int rsaKeyBitLength = 2048;
6065968caeeSMarri Devender Rao 
607*828252d5SJiaqing Zhao     // Required parameters
608*828252d5SJiaqing Zhao     std::string city;
609*828252d5SJiaqing Zhao     std::string commonName;
610*828252d5SJiaqing Zhao     std::string country;
611*828252d5SJiaqing Zhao     std::string organization;
612*828252d5SJiaqing Zhao     std::string organizationalUnit;
613*828252d5SJiaqing Zhao     std::string state;
614*828252d5SJiaqing Zhao     nlohmann::json certificateCollection;
615*828252d5SJiaqing Zhao 
616*828252d5SJiaqing Zhao     // Optional parameters
617*828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optAlternativeNames =
618*828252d5SJiaqing Zhao         std::vector<std::string>();
619*828252d5SJiaqing Zhao     std::optional<std::string> optContactPerson = "";
620*828252d5SJiaqing Zhao     std::optional<std::string> optChallengePassword = "";
621*828252d5SJiaqing Zhao     std::optional<std::string> optEmail = "";
622*828252d5SJiaqing Zhao     std::optional<std::string> optGivenName = "";
623*828252d5SJiaqing Zhao     std::optional<std::string> optInitials = "";
624*828252d5SJiaqing Zhao     std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
625*828252d5SJiaqing Zhao     std::optional<std::string> optKeyCurveId = "secp384r1";
626*828252d5SJiaqing Zhao     std::optional<std::string> optKeyPairAlgorithm = "EC";
627*828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optKeyUsage =
628*828252d5SJiaqing Zhao         std::vector<std::string>();
629*828252d5SJiaqing Zhao     std::optional<std::string> optSurname = "";
630*828252d5SJiaqing Zhao     std::optional<std::string> optUnstructuredName = "";
631*828252d5SJiaqing Zhao     if (!json_util::readJsonAction(
632*828252d5SJiaqing Zhao             req, asyncResp->res, "City", city, "CommonName", commonName,
633*828252d5SJiaqing Zhao             "ContactPerson", optContactPerson, "Country", country,
634*828252d5SJiaqing Zhao             "Organization", organization, "OrganizationalUnit",
635*828252d5SJiaqing Zhao             organizationalUnit, "State", state, "CertificateCollection",
636*828252d5SJiaqing Zhao             certificateCollection, "AlternativeNames", optAlternativeNames,
637*828252d5SJiaqing Zhao             "ChallengePassword", optChallengePassword, "Email", optEmail,
638*828252d5SJiaqing Zhao             "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
639*828252d5SJiaqing Zhao             optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
640*828252d5SJiaqing Zhao             optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
641*828252d5SJiaqing Zhao             "UnstructuredName", optUnstructuredName))
642*828252d5SJiaqing Zhao     {
643*828252d5SJiaqing Zhao         return;
6445968caeeSMarri Devender Rao     }
6455968caeeSMarri Devender Rao 
646*828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
647*828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
648*828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
649*828252d5SJiaqing Zhao     // value
650*828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
6515968caeeSMarri Devender Rao     {
652*828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
653*828252d5SJiaqing Zhao                                               "ChallengePassword");
654*828252d5SJiaqing Zhao         return;
655*828252d5SJiaqing Zhao     }
656*828252d5SJiaqing Zhao 
657*828252d5SJiaqing Zhao     std::string certURI;
658*828252d5SJiaqing Zhao     if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
659*828252d5SJiaqing Zhao                                       "@odata.id", certURI))
660*828252d5SJiaqing Zhao     {
661*828252d5SJiaqing Zhao         return;
662*828252d5SJiaqing Zhao     }
663*828252d5SJiaqing Zhao 
664*828252d5SJiaqing Zhao     std::string objectPath;
665*828252d5SJiaqing Zhao     std::string service;
666*828252d5SJiaqing Zhao     if (certURI.starts_with(
667*828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
668*828252d5SJiaqing Zhao     {
669*828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
670*828252d5SJiaqing Zhao         service = certs::httpsServiceName;
671*828252d5SJiaqing Zhao     }
672*828252d5SJiaqing Zhao     else if (certURI.starts_with(
673*828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
674*828252d5SJiaqing Zhao     {
675*828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
676*828252d5SJiaqing Zhao         service = certs::ldapServiceName;
677*828252d5SJiaqing Zhao     }
678*828252d5SJiaqing Zhao     else
679*828252d5SJiaqing Zhao     {
680*828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
681*828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
682*828252d5SJiaqing Zhao         return;
683*828252d5SJiaqing Zhao     }
684*828252d5SJiaqing Zhao 
685*828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
686*828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
687*828252d5SJiaqing Zhao     {
688*828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
689*828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
690*828252d5SJiaqing Zhao         return;
691*828252d5SJiaqing Zhao     }
692*828252d5SJiaqing Zhao 
693*828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
694*828252d5SJiaqing Zhao     // time consumed in generating private key
695*828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
696*828252d5SJiaqing Zhao     {
697*828252d5SJiaqing Zhao         messages::propertyValueNotInList(
698*828252d5SJiaqing Zhao             asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength");
699*828252d5SJiaqing Zhao         return;
700*828252d5SJiaqing Zhao     }
701*828252d5SJiaqing Zhao 
702*828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
703*828252d5SJiaqing Zhao     if (certURI.starts_with(
704*828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
705*828252d5SJiaqing Zhao     {
706*828252d5SJiaqing Zhao         if (optKeyUsage->empty())
707*828252d5SJiaqing Zhao         {
708*828252d5SJiaqing Zhao             optKeyUsage->push_back("ServerAuthentication");
709*828252d5SJiaqing Zhao         }
710*828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
711*828252d5SJiaqing Zhao         {
712*828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
713*828252d5SJiaqing Zhao             {
714*828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
715*828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
716*828252d5SJiaqing Zhao                 return;
717*828252d5SJiaqing Zhao             }
718*828252d5SJiaqing Zhao         }
719*828252d5SJiaqing Zhao         else
720*828252d5SJiaqing Zhao         {
721*828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
722*828252d5SJiaqing Zhao                                                   "GenerateCSR");
723*828252d5SJiaqing Zhao             return;
724*828252d5SJiaqing Zhao         }
725*828252d5SJiaqing Zhao     }
726*828252d5SJiaqing Zhao     else if (certURI.starts_with(
727*828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
728*828252d5SJiaqing Zhao     {
729*828252d5SJiaqing Zhao         if (optKeyUsage->empty())
730*828252d5SJiaqing Zhao         {
731*828252d5SJiaqing Zhao             optKeyUsage->push_back("ClientAuthentication");
732*828252d5SJiaqing Zhao         }
733*828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
734*828252d5SJiaqing Zhao         {
735*828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
736*828252d5SJiaqing Zhao             {
737*828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
738*828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
739*828252d5SJiaqing Zhao                 return;
740*828252d5SJiaqing Zhao             }
741*828252d5SJiaqing Zhao         }
742*828252d5SJiaqing Zhao         else
743*828252d5SJiaqing Zhao         {
744*828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
745*828252d5SJiaqing Zhao                                                   "GenerateCSR");
746*828252d5SJiaqing Zhao             return;
747*828252d5SJiaqing Zhao         }
748*828252d5SJiaqing Zhao     }
749*828252d5SJiaqing Zhao 
750*828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
751*828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
752*828252d5SJiaqing Zhao     static const int timeOut = 10;
753*828252d5SJiaqing Zhao     if (csrMatcher)
754*828252d5SJiaqing Zhao     {
755*828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
756*828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
757*828252d5SJiaqing Zhao         return;
758*828252d5SJiaqing Zhao     }
759*828252d5SJiaqing Zhao 
760*828252d5SJiaqing Zhao     // Make this static so it survives outside this method
761*828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
762*828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
763*828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
764*828252d5SJiaqing Zhao         csrMatcher = nullptr;
765*828252d5SJiaqing Zhao         if (ec)
766*828252d5SJiaqing Zhao         {
767*828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
768*828252d5SJiaqing Zhao             // before completion.
769*828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
770*828252d5SJiaqing Zhao             {
771*828252d5SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
772*828252d5SJiaqing Zhao             }
773*828252d5SJiaqing Zhao             return;
774*828252d5SJiaqing Zhao         }
775*828252d5SJiaqing Zhao         BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
776*828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
777*828252d5SJiaqing Zhao     });
778*828252d5SJiaqing Zhao 
779*828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
780*828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
781*828252d5SJiaqing Zhao     std::string match("type='signal',"
782*828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
783*828252d5SJiaqing Zhao                       "path='" +
784*828252d5SJiaqing Zhao                       objectPath +
785*828252d5SJiaqing Zhao                       "',"
786*828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
787*828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
788*828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
789*828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
790*828252d5SJiaqing Zhao         timeout.cancel();
791*828252d5SJiaqing Zhao         if (m.is_method_error())
792*828252d5SJiaqing Zhao         {
793*828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "Dbus method error!!!";
794*828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
795*828252d5SJiaqing Zhao             return;
796*828252d5SJiaqing Zhao         }
797*828252d5SJiaqing Zhao 
798*828252d5SJiaqing Zhao         dbus::utility::DBusInteracesMap interfacesProperties;
799*828252d5SJiaqing Zhao 
800*828252d5SJiaqing Zhao         sdbusplus::message::object_path csrObjectPath;
801*828252d5SJiaqing Zhao         m.read(csrObjectPath, interfacesProperties);
802*828252d5SJiaqing Zhao         BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
803*828252d5SJiaqing Zhao         for (const auto& interface : interfacesProperties)
804*828252d5SJiaqing Zhao         {
805*828252d5SJiaqing Zhao             if (interface.first == "xyz.openbmc_project.Certs.CSR")
806*828252d5SJiaqing Zhao             {
807*828252d5SJiaqing Zhao                 getCSR(asyncResp, certURI, service, objectPath,
808*828252d5SJiaqing Zhao                        csrObjectPath.str);
809*828252d5SJiaqing Zhao                 break;
810*828252d5SJiaqing Zhao             }
811*828252d5SJiaqing Zhao         }
812*828252d5SJiaqing Zhao         });
813*828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
814*828252d5SJiaqing Zhao         [asyncResp](const boost::system::error_code ec, const std::string&) {
815*828252d5SJiaqing Zhao         if (ec)
816*828252d5SJiaqing Zhao         {
817*828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
818*828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
819*828252d5SJiaqing Zhao             return;
820*828252d5SJiaqing Zhao         }
821*828252d5SJiaqing Zhao         },
822*828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
823*828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
824*828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
825*828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
826*828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
827*828252d5SJiaqing Zhao         *optUnstructuredName);
828*828252d5SJiaqing Zhao }
829*828252d5SJiaqing Zhao 
830*828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
831*828252d5SJiaqing Zhao {
832*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
833*828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
834002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
835*828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
836*828252d5SJiaqing Zhao 
837*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
838*828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
839*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
840*828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
841*828252d5SJiaqing Zhao 
842*828252d5SJiaqing Zhao     BMCWEB_ROUTE(
843*828252d5SJiaqing Zhao         app,
844*828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
845*828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
846*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
847*828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
848*828252d5SJiaqing Zhao 
849*828252d5SJiaqing Zhao     BMCWEB_ROUTE(
850*828252d5SJiaqing Zhao         app,
851*828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
852*828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
853*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
854*828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
855*828252d5SJiaqing Zhao } // requestRoutesCertificateService
856*828252d5SJiaqing Zhao 
857*828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
858*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
859*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
860*828252d5SJiaqing Zhao {
8613ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
86245ca1b86SEd Tanous     {
86345ca1b86SEd Tanous         return;
86445ca1b86SEd Tanous     }
8651476687dSEd Tanous 
8661476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
8671476687dSEd Tanous         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
8681476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
8691476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
8701476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8711476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
8721476687dSEd Tanous         "A Collection of HTTPS certificate instances";
8738d1b46d7Szhanghch05 
874d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
875d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
876d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
877*828252d5SJiaqing Zhao }
8785968caeeSMarri Devender Rao 
879*828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
880*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
881*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
882*828252d5SJiaqing Zhao {
8833ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
88445ca1b86SEd Tanous     {
88545ca1b86SEd Tanous         return;
88645ca1b86SEd Tanous     }
8875968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
8888d1b46d7Szhanghch05 
8891476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
8901476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
8915968caeeSMarri Devender Rao 
892002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
89358eb238fSKowalski, Kamil 
89458eb238fSKowalski, Kamil     if (certFileBody.empty())
89558eb238fSKowalski, Kamil     {
8960fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
897a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
89858eb238fSKowalski, Kamil         return;
89958eb238fSKowalski, Kamil     }
90058eb238fSKowalski, Kamil 
9015968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
90258eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
9035968caeeSMarri Devender Rao 
9045968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
905656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
906656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9075968caeeSMarri Devender Rao         if (ec)
9085968caeeSMarri Devender Rao         {
9095968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9105968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
9115968caeeSMarri Devender Rao             return;
9125968caeeSMarri Devender Rao         }
913717b9802SJiaqing Zhao 
914717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
915717b9802SJiaqing Zhao         std::string certId = path.filename();
9161e312598SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
9171e312598SJiaqing Zhao             "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
9181e312598SJiaqing Zhao             "Certificates", certId);
919*828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
920*828252d5SJiaqing Zhao                                  certId, certURL, "HTTPS Certificate");
9215968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9225968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
9235968caeeSMarri Devender Rao         },
924*828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
925*828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
926*828252d5SJiaqing Zhao }
9275968caeeSMarri Devender Rao 
928*828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
929*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
930*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
9317e860f15SJohn Edward Broadbent {
9323ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
93345ca1b86SEd Tanous     {
93445ca1b86SEd Tanous         return;
93545ca1b86SEd Tanous     }
9367e860f15SJohn Edward Broadbent 
937*828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id;
938*828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
939*828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
940*828252d5SJiaqing Zhao         "Certificates", id);
941*828252d5SJiaqing Zhao     std::string objPath =
942*828252d5SJiaqing Zhao         sdbusplus::message::object_path(certs::httpsObjectPath) / id;
943*828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
944*828252d5SJiaqing Zhao                              certURL, "HTTPS Certificate");
9457e860f15SJohn Edward Broadbent }
94637cce918SMarri Devender Rao 
947*828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
94837cce918SMarri Devender Rao {
949*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
950*828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
951ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
952*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
953*828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
954*828252d5SJiaqing Zhao 
955*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
956*828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
957*828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
958*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
959*828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
960*828252d5SJiaqing Zhao 
961*828252d5SJiaqing Zhao     BMCWEB_ROUTE(
962*828252d5SJiaqing Zhao         app,
963*828252d5SJiaqing Zhao         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
964*828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
965002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
966*828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
967*828252d5SJiaqing Zhao }
968*828252d5SJiaqing Zhao 
969*828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
970*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
971*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
972*828252d5SJiaqing Zhao {
9733ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
97445ca1b86SEd Tanous     {
97545ca1b86SEd Tanous         return;
97645ca1b86SEd Tanous     }
9771476687dSEd Tanous 
9781476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
9791476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
9801476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
9811476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
9821476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
9831476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
9841476687dSEd Tanous         "A Collection of LDAP certificate instances";
9858d1b46d7Szhanghch05 
986d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
987d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
988d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
989*828252d5SJiaqing Zhao }
99037cce918SMarri Devender Rao 
991*828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
992*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
993*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
994*828252d5SJiaqing Zhao {
9953ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
99645ca1b86SEd Tanous     {
99745ca1b86SEd Tanous         return;
99845ca1b86SEd Tanous     }
999002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
100058eb238fSKowalski, Kamil 
100158eb238fSKowalski, Kamil     if (certFileBody.empty())
100258eb238fSKowalski, Kamil     {
1003002d39b4SEd Tanous         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1004a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
100558eb238fSKowalski, Kamil         return;
100658eb238fSKowalski, Kamil     }
100758eb238fSKowalski, Kamil 
100858eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
100958eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
101058eb238fSKowalski, Kamil 
101137cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
1012656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
1013656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
101437cce918SMarri Devender Rao         if (ec)
101537cce918SMarri Devender Rao         {
101637cce918SMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
101737cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
101837cce918SMarri Devender Rao             return;
101937cce918SMarri Devender Rao         }
1020717b9802SJiaqing Zhao 
1021717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1022717b9802SJiaqing Zhao         std::string certId = path.filename();
1023*828252d5SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
1024*828252d5SJiaqing Zhao             "redfish", "v1", "AccountService", "LDAP", "Certificates", certId);
1025*828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1026*828252d5SJiaqing Zhao                                  certId, certURL, "LDAP Certificate");
102737cce918SMarri Devender Rao         BMCWEB_LOG_DEBUG << "LDAP certificate install file="
102837cce918SMarri Devender Rao                          << certFile->getCertFilePath();
102937cce918SMarri Devender Rao         },
1030*828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1031*828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1032*828252d5SJiaqing Zhao }
103337cce918SMarri Devender Rao 
1034*828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1035*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1036*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
103737cce918SMarri Devender Rao {
10383ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
103945ca1b86SEd Tanous     {
104045ca1b86SEd Tanous         return;
104145ca1b86SEd Tanous     }
1042717b9802SJiaqing Zhao 
1043717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id;
10441e312598SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
10451e312598SJiaqing Zhao         "redfish", "v1", "AccountService", "LDAP", "Certificates", id);
1046717b9802SJiaqing Zhao     std::string objPath =
1047717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1048717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1049717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1050*828252d5SJiaqing Zhao }
1051*828252d5SJiaqing Zhao 
1052*828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1053cfcd5f6bSMarri Devender Rao {
1054*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1055*828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1056*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1057*828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1058*828252d5SJiaqing Zhao 
1059*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1060*828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1061*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1062*828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1063*828252d5SJiaqing Zhao 
1064*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1065ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1066002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1067*828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
1068*828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1069*828252d5SJiaqing Zhao 
1070*828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1071*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1072*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1073*828252d5SJiaqing Zhao {
10743ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
107545ca1b86SEd Tanous     {
107645ca1b86SEd Tanous         return;
107745ca1b86SEd Tanous     }
10781476687dSEd Tanous 
10791476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
10801476687dSEd Tanous         "/redfish/v1/Managers/bmc/Truststore/Certificates/";
10811476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
10821476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1083002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
10841476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
10851476687dSEd Tanous         "A Collection of TrustStore certificate instances";
10868d1b46d7Szhanghch05 
1087d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1088d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1089d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1090*828252d5SJiaqing Zhao }
1091cfcd5f6bSMarri Devender Rao 
1092*828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1093*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1094*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1095*828252d5SJiaqing Zhao {
10963ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
109745ca1b86SEd Tanous     {
109845ca1b86SEd Tanous         return;
109945ca1b86SEd Tanous     }
1100002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1101a08752f5SZbigniew Kurzynski 
1102a08752f5SZbigniew Kurzynski     if (certFileBody.empty())
1103a08752f5SZbigniew Kurzynski     {
11040fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1105a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1106a08752f5SZbigniew Kurzynski         return;
1107a08752f5SZbigniew Kurzynski     }
1108a08752f5SZbigniew Kurzynski 
1109a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1110a08752f5SZbigniew Kurzynski         std::make_shared<CertificateFile>(certFileBody);
1111cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
1112656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
1113656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1114cfcd5f6bSMarri Devender Rao         if (ec)
1115cfcd5f6bSMarri Devender Rao         {
1116cfcd5f6bSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1117cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1118cfcd5f6bSMarri Devender Rao             return;
1119cfcd5f6bSMarri Devender Rao         }
1120656ec7e3SZbigniew Kurzynski 
1121717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1122717b9802SJiaqing Zhao         std::string certId = path.filename();
1123*828252d5SJiaqing Zhao         const boost::urls::url certURL =
1124*828252d5SJiaqing Zhao             crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1125*828252d5SJiaqing Zhao                                          "Truststore", "Certificates", certId);
1126717b9802SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath,
1127*828252d5SJiaqing Zhao                                  certs::authorityServiceName, certId, certURL,
1128*828252d5SJiaqing Zhao                                  "TrustStore Certificate");
11290fda0f12SGeorge Liu         BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1130cfcd5f6bSMarri Devender Rao                          << certFile->getCertFilePath();
1131cfcd5f6bSMarri Devender Rao         },
1132cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
11330fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1134*828252d5SJiaqing Zhao }
1135cfcd5f6bSMarri Devender Rao 
1136*828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1137*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1138*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1139cfcd5f6bSMarri Devender Rao {
11403ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
114145ca1b86SEd Tanous     {
114245ca1b86SEd Tanous         return;
114345ca1b86SEd Tanous     }
1144717b9802SJiaqing Zhao 
1145717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id;
1146*828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
1147*828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id);
1148717b9802SJiaqing Zhao     std::string objPath =
1149717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1150*828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1151*828252d5SJiaqing Zhao                              id, certURL, "TrustStore Certificate");
1152*828252d5SJiaqing Zhao }
115307a60299SZbigniew Kurzynski 
1154*828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1155*828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1156*828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1157*828252d5SJiaqing Zhao {
11583ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
115945ca1b86SEd Tanous     {
116045ca1b86SEd Tanous         return;
116145ca1b86SEd Tanous     }
116207a60299SZbigniew Kurzynski 
1163717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id;
1164717b9802SJiaqing Zhao     std::string objPath =
1165717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
116607a60299SZbigniew Kurzynski 
116707a60299SZbigniew Kurzynski     crow::connections::systemBus->async_method_call(
116807a60299SZbigniew Kurzynski         [asyncResp, id](const boost::system::error_code ec) {
116907a60299SZbigniew Kurzynski         if (ec)
117007a60299SZbigniew Kurzynski         {
1171d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", id);
117207a60299SZbigniew Kurzynski             return;
117307a60299SZbigniew Kurzynski         }
117407a60299SZbigniew Kurzynski         BMCWEB_LOG_INFO << "Certificate deleted";
1175002d39b4SEd Tanous         asyncResp->res.result(boost::beast::http::status::no_content);
117607a60299SZbigniew Kurzynski         },
1177*828252d5SJiaqing Zhao         certs::authorityServiceName, objPath, certs::objDeleteIntf, "Delete");
1178*828252d5SJiaqing Zhao }
1179*828252d5SJiaqing Zhao 
1180*828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1181*828252d5SJiaqing Zhao {
1182*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1183*828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1184*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1185*828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1186*828252d5SJiaqing Zhao 
1187*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1188*828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1189*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1190*828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1191*828252d5SJiaqing Zhao 
1192*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1193*828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1194*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1195*828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1196*828252d5SJiaqing Zhao 
1197*828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1198*828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1199*828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1200*828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
12017e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
12025968caeeSMarri Devender Rao } // namespace redfish
1203