| Ed Tanous | 40e9b92 | 2024-09-10 13:50:16 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: Apache-2.0 | 
|  | 2 | // SPDX-FileCopyrightText: Copyright OpenBMC Authors | 
| Feras Aldahlawi | 735ef6d | 2021-03-19 14:01:46 -0700 | [diff] [blame] | 3 | #pragma once | 
|  | 4 |  | 
| Ed Tanous | 3ccb3ad | 2023-01-13 17:40:03 -0800 | [diff] [blame] | 5 | #include "app.hpp" | 
|  | 6 | #include "async_resp.hpp" | 
|  | 7 | #include "dbus_utility.hpp" | 
|  | 8 | #include "error_messages.hpp" | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 9 | #include "http_request.hpp" | 
|  | 10 | #include "logging.hpp" | 
| Ed Tanous | 3ccb3ad | 2023-01-13 17:40:03 -0800 | [diff] [blame] | 11 | #include "utils/collection.hpp" | 
|  | 12 | #include "utils/hex_utils.hpp" | 
|  | 13 | #include "utils/json_utils.hpp" | 
|  | 14 |  | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 15 | #include <boost/beast/http/verb.hpp> | 
| George Liu | e99073f | 2022-12-09 11:06:16 +0800 | [diff] [blame] | 16 | #include <boost/system/error_code.hpp> | 
| Ed Tanous | ef4c65b | 2023-04-24 15:28:50 -0700 | [diff] [blame] | 17 | #include <boost/url/format.hpp> | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 18 | #include <boost/url/url.hpp> | 
| Feras Aldahlawi | 735ef6d | 2021-03-19 14:01:46 -0700 | [diff] [blame] | 19 | #include <nlohmann/json.hpp> | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 20 | #include <sdbusplus/message/native_types.hpp> | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 21 |  | 
| George Liu | 7a1dbc4 | 2022-12-07 16:03:22 +0800 | [diff] [blame] | 22 | #include <array> | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 23 | #include <cstdint> | 
|  | 24 | #include <functional> | 
|  | 25 | #include <memory> | 
| George Liu | 7a1dbc4 | 2022-12-07 16:03:22 +0800 | [diff] [blame] | 26 | #include <string_view> | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 27 | #include <utility> | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 28 | #include <vector> | 
| Feras Aldahlawi | 735ef6d | 2021-03-19 14:01:46 -0700 | [diff] [blame] | 29 |  | 
|  | 30 | namespace crow | 
|  | 31 | { | 
|  | 32 | namespace google_api | 
|  | 33 | { | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 34 |  | 
| Patrick Williams | 504af5a | 2025-02-03 14:29:03 -0500 | [diff] [blame] | 35 | inline void handleGoogleV1Get( | 
|  | 36 | const crow::Request& /*req*/, | 
|  | 37 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 38 | { | 
|  | 39 | asyncResp->res.jsonValue["@odata.type"] = | 
|  | 40 | "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot"; | 
|  | 41 | asyncResp->res.jsonValue["@odata.id"] = "/google/v1"; | 
|  | 42 | asyncResp->res.jsonValue["Id"] = "Google Rest RootService"; | 
|  | 43 | asyncResp->res.jsonValue["Name"] = "Google Service Root"; | 
|  | 44 | asyncResp->res.jsonValue["Version"] = "1.0.0"; | 
|  | 45 | asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] = | 
| Nan Zhou | cd02759 | 2022-07-03 05:18:29 +0000 | [diff] [blame] | 46 | "/google/v1/RootOfTrustCollection"; | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 47 | } | 
|  | 48 |  | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 49 | inline void handleRootOfTrustCollectionGet( | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 50 | const crow::Request& /*req*/, | 
|  | 51 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) | 
|  | 52 | { | 
| Nan Zhou | cd02759 | 2022-07-03 05:18:29 +0000 | [diff] [blame] | 53 | asyncResp->res.jsonValue["@odata.id"] = "/google/v1/RootOfTrustCollection"; | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 54 | asyncResp->res.jsonValue["@odata.type"] = | 
|  | 55 | "#RootOfTrustCollection.RootOfTrustCollection"; | 
| George Liu | 7a1dbc4 | 2022-12-07 16:03:22 +0800 | [diff] [blame] | 56 | const std::array<std::string_view, 1> interfaces{ | 
|  | 57 | "xyz.openbmc_project.Control.Hoth"}; | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 58 | redfish::collection_util::getCollectionMembers( | 
| Willy Tu | ae9031f | 2022-09-27 05:48:07 +0000 | [diff] [blame] | 59 | asyncResp, boost::urls::url("/google/v1/RootOfTrustCollection"), | 
| George Liu | 7a1dbc4 | 2022-12-07 16:03:22 +0800 | [diff] [blame] | 60 | interfaces, "/xyz/openbmc_project"); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 61 | } | 
|  | 62 |  | 
|  | 63 | // Helper struct to identify a resolved D-Bus object interface | 
|  | 64 | struct ResolvedEntity | 
|  | 65 | { | 
|  | 66 | std::string id; | 
|  | 67 | std::string service; | 
|  | 68 | std::string object; | 
| Nan Zhou | 16a5535 | 2022-07-03 05:06:08 +0000 | [diff] [blame] | 69 | std::string interface; | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 70 | }; | 
|  | 71 |  | 
|  | 72 | using ResolvedEntityHandler = std::function<void( | 
|  | 73 | const std::string&, const std::shared_ptr<bmcweb::AsyncResp>&, | 
|  | 74 | const ResolvedEntity&)>; | 
|  | 75 |  | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 76 | inline void hothGetSubtreeCallback( | 
|  | 77 | const std::string& command, | 
|  | 78 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 79 | const std::string& rotId, const ResolvedEntityHandler& entityHandler, | 
| Ed Tanous | 5e7e2dc | 2023-02-16 10:37:01 -0800 | [diff] [blame] | 80 | const boost::system::error_code& ec, | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 81 | const dbus::utility::MapperGetSubTreeResponse& subtree) | 
|  | 82 | { | 
|  | 83 | if (ec) | 
|  | 84 | { | 
|  | 85 | redfish::messages::internalError(asyncResp->res); | 
|  | 86 | return; | 
|  | 87 | } | 
| Nan Zhou | 5600f02 | 2022-07-03 16:22:38 +0000 | [diff] [blame] | 88 | for (const auto& [path, services] : subtree) | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 89 | { | 
| Nan Zhou | 5600f02 | 2022-07-03 16:22:38 +0000 | [diff] [blame] | 90 | sdbusplus::message::object_path objPath(path); | 
|  | 91 | if (objPath.filename() != rotId || services.empty()) | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 92 | { | 
|  | 93 | continue; | 
|  | 94 | } | 
|  | 95 |  | 
| Nan Zhou | cd02759 | 2022-07-03 05:18:29 +0000 | [diff] [blame] | 96 | ResolvedEntity resolvedEntity = { | 
|  | 97 | .id = rotId, | 
| Nan Zhou | 5600f02 | 2022-07-03 16:22:38 +0000 | [diff] [blame] | 98 | .service = services[0].first, | 
|  | 99 | .object = path, | 
| Nan Zhou | cd02759 | 2022-07-03 05:18:29 +0000 | [diff] [blame] | 100 | .interface = "xyz.openbmc_project.Control.Hoth"}; | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 101 | entityHandler(command, asyncResp, resolvedEntity); | 
|  | 102 | return; | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | // Couldn't find an object with that name.  return an error | 
| Jiaqing Zhao | d8a5d5d | 2022-08-05 16:21:51 +0800 | [diff] [blame] | 106 | redfish::messages::resourceNotFound(asyncResp->res, "RootOfTrust", rotId); | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 107 | } | 
|  | 108 |  | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 109 | inline void resolveRoT(const std::string& command, | 
|  | 110 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 111 | const std::string& rotId, | 
|  | 112 | ResolvedEntityHandler&& entityHandler) | 
|  | 113 | { | 
| George Liu | 7a1dbc4 | 2022-12-07 16:03:22 +0800 | [diff] [blame] | 114 | constexpr std::array<std::string_view, 1> hothIfaces = { | 
| Nan Zhou | cd02759 | 2022-07-03 05:18:29 +0000 | [diff] [blame] | 115 | "xyz.openbmc_project.Control.Hoth"}; | 
| George Liu | e99073f | 2022-12-09 11:06:16 +0800 | [diff] [blame] | 116 | dbus::utility::getSubTree( | 
|  | 117 | "/xyz/openbmc_project", 0, hothIfaces, | 
| Ed Tanous | 8cb2c02 | 2024-03-27 16:31:46 -0700 | [diff] [blame] | 118 | [command, asyncResp, rotId, entityHandler{std::move(entityHandler)}]( | 
| George Liu | e99073f | 2022-12-09 11:06:16 +0800 | [diff] [blame] | 119 | const boost::system::error_code& ec, | 
| Ed Tanous | 002d39b | 2022-05-31 08:59:27 -0700 | [diff] [blame] | 120 | const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 121 | hothGetSubtreeCallback(command, asyncResp, rotId, entityHandler, ec, | 
|  | 122 | subtree); | 
|  | 123 | }); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 124 | } | 
|  | 125 |  | 
|  | 126 | inline void populateRootOfTrustEntity( | 
|  | 127 | const std::string& /*unused*/, | 
|  | 128 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 129 | const ResolvedEntity& resolvedEntity) | 
|  | 130 | { | 
|  | 131 | asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust"; | 
| Ed Tanous | ef4c65b | 2023-04-24 15:28:50 -0700 | [diff] [blame] | 132 | asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( | 
|  | 133 | "/google/v1/RootOfTrustCollection/{}", resolvedEntity.id); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 134 |  | 
|  | 135 | asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; | 
|  | 136 | asyncResp->res.jsonValue["Id"] = resolvedEntity.id; | 
|  | 137 | // Need to fix this later to a stabler property. | 
|  | 138 | asyncResp->res.jsonValue["Name"] = resolvedEntity.id; | 
|  | 139 | asyncResp->res.jsonValue["Description"] = "Google Root Of Trust"; | 
|  | 140 | asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] = | 
|  | 141 | "/google/v1/RootOfTrustCollection/" + resolvedEntity.id + | 
|  | 142 | "/Actions/RootOfTrust.SendCommand"; | 
|  | 143 |  | 
|  | 144 | asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = | 
|  | 145 | resolvedEntity.id; | 
|  | 146 | asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] = | 
|  | 147 | "Embedded"; | 
|  | 148 | } | 
|  | 149 |  | 
| Patrick Williams | 504af5a | 2025-02-03 14:29:03 -0500 | [diff] [blame] | 150 | inline void handleRootOfTrustGet( | 
|  | 151 | const crow::Request& /*req*/, | 
|  | 152 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 153 | const std::string& param) | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 154 | { | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 155 | std::string emptyCommand; | 
|  | 156 | resolveRoT(emptyCommand, asyncResp, param, populateRootOfTrustEntity); | 
|  | 157 | } | 
|  | 158 |  | 
| Patrick Williams | 504af5a | 2025-02-03 14:29:03 -0500 | [diff] [blame] | 159 | inline void invocationCallback( | 
|  | 160 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 161 | const boost::system::error_code& ec, | 
|  | 162 | const std::vector<uint8_t>& responseBytes) | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 163 | { | 
|  | 164 | if (ec) | 
|  | 165 | { | 
| Ed Tanous | 62598e3 | 2023-07-17 17:06:25 -0700 | [diff] [blame] | 166 | BMCWEB_LOG_ERROR("RootOfTrust.Actions.SendCommand failed: {}", | 
|  | 167 | ec.message()); | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 168 | redfish::messages::internalError(asyncResp->res); | 
|  | 169 | return; | 
|  | 170 | } | 
|  | 171 |  | 
|  | 172 | asyncResp->res.jsonValue["CommandResponse"] = | 
|  | 173 | bytesToHexString(responseBytes); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 174 | } | 
|  | 175 |  | 
| Patrick Williams | 504af5a | 2025-02-03 14:29:03 -0500 | [diff] [blame] | 176 | inline void invokeRoTCommand( | 
|  | 177 | const std::string& command, | 
|  | 178 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 179 | const ResolvedEntity& resolvedEntity) | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 180 | { | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 181 | std::vector<uint8_t> bytes = hexStringToBytes(command); | 
|  | 182 | if (bytes.empty()) | 
|  | 183 | { | 
| Ed Tanous | 62598e3 | 2023-07-17 17:06:25 -0700 | [diff] [blame] | 184 | BMCWEB_LOG_DEBUG("Invalid command: {}", command); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 185 | redfish::messages::actionParameterValueTypeError(command, "Command", | 
|  | 186 | "SendCommand"); | 
|  | 187 | return; | 
|  | 188 | } | 
|  | 189 |  | 
| Ed Tanous | 177612a | 2025-02-14 15:16:09 -0800 | [diff] [blame] | 190 | dbus::utility::async_method_call( | 
|  | 191 | asyncResp, | 
| Ed Tanous | 5e7e2dc | 2023-02-16 10:37:01 -0800 | [diff] [blame] | 192 | [asyncResp{asyncResp}](const boost::system::error_code& ec, | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 193 | const std::vector<uint8_t>& responseBytes) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 194 | invocationCallback(asyncResp, ec, responseBytes); | 
|  | 195 | }, | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 196 | resolvedEntity.service, resolvedEntity.object, resolvedEntity.interface, | 
|  | 197 | "SendHostCommand", bytes); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 198 | } | 
|  | 199 |  | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 200 | inline void handleRoTSendCommandPost( | 
|  | 201 | const crow::Request& request, | 
|  | 202 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 203 | const std::string& rotId) | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 204 | { | 
|  | 205 | std::string command; | 
|  | 206 | if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command", | 
|  | 207 | command)) | 
|  | 208 | { | 
| Ed Tanous | 62598e3 | 2023-07-17 17:06:25 -0700 | [diff] [blame] | 209 | BMCWEB_LOG_DEBUG("Missing property Command."); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 210 | redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand", | 
|  | 211 | "Command"); | 
|  | 212 | return; | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | resolveRoT(command, asyncResp, rotId, invokeRoTCommand); | 
|  | 216 | } | 
| Feras Aldahlawi | 735ef6d | 2021-03-19 14:01:46 -0700 | [diff] [blame] | 217 |  | 
|  | 218 | inline void requestRoutes(App& app) | 
|  | 219 | { | 
|  | 220 | BMCWEB_ROUTE(app, "/google/v1/") | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 221 | .methods(boost::beast::http::verb::get)(handleGoogleV1Get); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 222 |  | 
|  | 223 | BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection") | 
|  | 224 | .privileges({{"ConfigureManager"}}) | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 225 | .methods(boost::beast::http::verb::get)(handleRootOfTrustCollectionGet); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 226 |  | 
|  | 227 | BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>") | 
|  | 228 | .privileges({{"ConfigureManager"}}) | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 229 | .methods(boost::beast::http::verb::get)(handleRootOfTrustGet); | 
| Vidya Satyamsetti | 4cee35e | 2022-04-21 14:53:44 -0700 | [diff] [blame] | 230 |  | 
|  | 231 | BMCWEB_ROUTE( | 
|  | 232 | app, | 
|  | 233 | "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand") | 
|  | 234 | .privileges({{"ConfigureManager"}}) | 
| Nan Zhou | 30aacdd | 2022-07-03 05:02:36 +0000 | [diff] [blame] | 235 | .methods(boost::beast::http::verb::post)(handleRoTSendCommandPost); | 
| Feras Aldahlawi | 735ef6d | 2021-03-19 14:01:46 -0700 | [diff] [blame] | 236 | } | 
|  | 237 |  | 
|  | 238 | } // namespace google_api | 
|  | 239 | } // namespace crow |