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