| #include "google/google_service_root.hpp" | |
| #include <cstdint> | |
| #include <memory> | |
| #include <string> | |
| #include <string_view> | |
| #include <system_error> | |
| #include <utility> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "absl/functional/any_invocable.h" | |
| #include "boost/beast/http/field.hpp" // NOLINT | |
| #include "boost/beast/http/message.hpp" // NOLINT | |
| #include "boost/beast/http/status.hpp" // NOLINT | |
| #include "boost/beast/http/string_body.hpp" // NOLINT | |
| #include "boost/beast/http/verb.hpp" // NOLINT | |
| #include "boost/system/error_code.hpp" // NOLINT | |
| #include "app.hpp" | |
| #include "http_request.hpp" | |
| #include "http_response.hpp" | |
| #include "async_resp.hpp" | |
| #include "dbus_utility.hpp" | |
| #include "test/redfish-core/lib/snapshot_fixture.hpp" | |
| #include <nlohmann/json.hpp> | |
| #include "managed_store.hpp" | |
| #include "managed_store_types.hpp" | |
| #include "test/g3/mock_managed_store.hpp" | |
| #include "test/g3/mock_managed_store_test.hpp" | |
| #include "sdbusplus/message/native_types.hpp" | |
| namespace crow::google_api { | |
| namespace { | |
| void validateServiceRootGet(crow::Response& res) { | |
| nlohmann::json& json = res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], "/google/v1"); | |
| EXPECT_EQ(json["@odata.type"], "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot"); | |
| EXPECT_EQ(json["@odata.id"], "/google/v1"); | |
| EXPECT_EQ(json["Id"], "Google Rest RootService"); | |
| EXPECT_EQ(json["Name"], "Google Service Root"); | |
| EXPECT_EQ(json["Version"], "1.0.0"); | |
| EXPECT_EQ(json["RootOfTrustCollection"]["@odata.id"], | |
| "/google/v1/RootOfTrustCollection"); | |
| EXPECT_EQ(json["NVMe"]["@odata.id"], "/google/v1/NVMe"); | |
| } | |
| TEST(HandleGoogleV1Get, OnSuccess) { | |
| App app(/*allowSessionEmpty=*/true); | |
| std::error_code ec; | |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); | |
| asyncResp->res.setCompleteRequestHandler(validateServiceRootGet); | |
| crow::Request dummyRequest{{boost::beast::http::verb::get, "", 11}, ec}; | |
| handleGoogleV1Get(app, dummyRequest, asyncResp); | |
| } | |
| } // namespace | |
| } // namespace crow::google_api | |
| namespace redfish { | |
| namespace { | |
| using ::dbus::utility::DBusPropertiesMap; | |
| using managedStore::KeyType; | |
| using managedStore::ManagedType; | |
| crow::Request CreateJsonRequest(std::string_view body = "") { | |
| boost::beast::http::request<boost::beast::http::string_body> reqIn; | |
| reqIn.set(boost::beast::http::field::content_type, "application/json"); | |
| std::error_code ec; | |
| crow::Request req(reqIn, ec); | |
| req.req.body() = body; | |
| return req; | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, | |
| HandleRootOfTrustGetCorrectLocation) { | |
| crow::google_api::handleRootOfTrustGet(app_, CreateRequest(), | |
| share_async_resp_, "Hoth"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], "/google/v1/RootOfTrustCollection/Hoth"); | |
| EXPECT_EQ(json["Location"]["PartLocation"]["LocationType"], "Embedded"); | |
| EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "Hoth"); | |
| EXPECT_EQ(json["Location"]["PartLocationContext"], "DC_SCM"); | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, HandleRootOfTrustGet) { | |
| EXPECT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| KeyType(ManagedType::kManagedPropertyMap, | |
| "xyz.openbmc_project.Control.Hoth", | |
| sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/Control/Hoth"), | |
| "xyz.openbmc_project.Control.Hoth.State"), | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| DBusPropertiesMap({ | |
| std::make_pair("BootloaderUpdateFailureCode", | |
| uint32_t{0}), | |
| std::make_pair("FirmwareUpdateFailedMinor", uint32_t{0}), | |
| std::make_pair("FirmwareUpdateFailureCode", uint32_t{4}), | |
| std::make_pair("ResetFlags", uint32_t{0}), | |
| std::make_pair("RoInfoStrikes", uint32_t{0}), | |
| std::make_pair("RwInfoStrikes", uint32_t{0}), | |
| std::make_pair("UpTime", uint64_t{19441701616}), | |
| std::make_pair("HasPersistentPanicInfo", false), | |
| std::make_pair("PayloadConfirmFailureCode", uint32_t{0}), | |
| std::make_pair("PayloadUpdateFailureCode", uint32_t{0}), | |
| std::make_pair("HasValidAuthRecord", false), | |
| std::make_pair("AuthRecordCapabilities", uint64_t{0}), | |
| std::make_pair("SecureBootEnforced", true), | |
| std::make_pair("KeyRotationVersion", uint32_t{1}), | |
| std::make_pair("KeyRotationImageFamily", uint16_t{2}), | |
| std::make_pair("KeyRotationImageFamilyVariant", | |
| uint16_t{3}), | |
| std::make_pair("KeyRotationValidationMethod", | |
| uint32_t{4}), | |
| std::make_pair("KeyRotationValidationKeyData", | |
| uint32_t{5}), | |
| std::make_pair("KeyRotationValidationHashData", | |
| uint32_t{6}), | |
| std::make_pair("ChipRevision", std::string("TI02")), | |
| }))) | |
| .ok()); | |
| EXPECT_CALL( | |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()), | |
| PostDbusCallWithObjectPath( | |
| testing::_, | |
| testing::An<absl::AnyInvocable<void( | |
| const boost::system::error_code&, // NOLINT(misc-include-cleaner) | |
| const std::string&)>&&>(), | |
| "xyz.openbmc_project.securityd.TpmAttestationService", | |
| "/xyz/openbmc_project/securityd/tpm_attestation_service", | |
| "xyz.openbmc_project.securityd.TpmAttestationService", | |
| "ReadPcrValues", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/Control/Hoth"))) | |
| .Times(1) | |
| .WillOnce( | |
| managedStore:: | |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< | |
| std::string>:: | |
| SimulateSuccessfulAsyncPostDbusCallWithValue( | |
| std::make_shared<std::string>("pcr-values-string"))); | |
| crow::google_api::handleRootOfTrustGet(app_, CreateRequest(), | |
| share_async_resp_, "Hoth"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["Status"]["Oem"]["BootloaderUpdateFailureCode"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["FirmwareUpdateFailedMinor"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["FirmwareUpdateFailureCode"], 4); | |
| EXPECT_EQ(json["Status"]["Oem"]["ResetFlags"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["RoInfoStrikes"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["RwInfoStrikes"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["UpTime"], 19441701616); | |
| EXPECT_EQ(json["Status"]["Oem"]["HasPersistentPanicInfo"], false); | |
| EXPECT_EQ(json["Status"]["Oem"]["Payload"]["ConfirmFailureCode"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["Payload"]["UpdateFailureCode"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["Authorization"]["Valid"], false); | |
| EXPECT_EQ(json["Status"]["Oem"]["Authorization"]["Capabilities"], 0); | |
| EXPECT_EQ(json["Status"]["Oem"]["SecureBootEnforced"], true); | |
| EXPECT_EQ(json["Status"]["Oem"]["KeyRotation"]["Version"], 1); | |
| EXPECT_EQ(json["Status"]["Oem"]["KeyRotation"]["ImageFamily"], 2); | |
| EXPECT_EQ(json["Status"]["Oem"]["KeyRotation"]["ImageFamilyVariant"], 3); | |
| EXPECT_EQ(json["Status"]["Oem"]["KeyRotation"]["ValidationMethod"], 4); | |
| EXPECT_EQ(json["Status"]["Oem"]["KeyRotation"]["ValidationKeyData"], 5); | |
| EXPECT_EQ(json["Status"]["Oem"]["KeyRotation"]["ValidationHashData"], 6); | |
| EXPECT_EQ(json["Status"]["Oem"]["ChipRevision"], "TI02"); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, HandleGetSignedMeasurementsPost) { | |
| nlohmann::json requestJson; | |
| requestJson["Nonce"] = "0123456789ABCDEF"; | |
| requestJson["PCRSelection"] = "pcrSelectionBase64"; | |
| EXPECT_CALL( | |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()), | |
| PostDbusCallWithObjectPathAndTwoStrings( | |
| testing::_, | |
| testing::An<absl::AnyInvocable<void( | |
| const boost::system::error_code&, // NOLINT(misc-include-cleaner) | |
| const std::string&)>&&>(), | |
| "xyz.openbmc_project.securityd.TpmAttestationService", | |
| "/xyz/openbmc_project/securityd/tpm_attestation_service", | |
| "xyz.openbmc_project.securityd.TpmAttestationService", "GetPcrQuote", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/Control/Hoth"), | |
| "pcrSelectionBase64", testing::_)) | |
| .Times(1) | |
| .WillOnce( | |
| managedStore:: | |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< | |
| std::string>:: | |
| SimulateSuccessfulAsyncPostDbusCallWithValue( | |
| std::make_shared<std::string>("quote-string"))); | |
| crow::google_api::handleGetSignedMeasurementsPost( | |
| app_, CreateJsonRequest(requestJson.dump()), share_async_resp_, "Hoth"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["SignedMeasurements"], "quote-string"); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, HandleRootOfTrustCertificatesGet) { | |
| EXPECT_CALL( | |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()), | |
| PostDbusCallWithObjectPath( | |
| testing::_, | |
| testing::An<absl::AnyInvocable<void( | |
| const boost::system::error_code&, // NOLINT(misc-include-cleaner) | |
| const std::string&)>&&>(), | |
| "xyz.openbmc_project.securityd.TpmAttestationService", | |
| "/xyz/openbmc_project/securityd/tpm_attestation_service", | |
| "xyz.openbmc_project.securityd.TpmAttestationService", | |
| "GetEkCertChain", | |
| sdbusplus::message::object_path("/xyz/openbmc_project/Control/Hoth"))) | |
| .Times(1) | |
| .WillOnce( | |
| managedStore:: | |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< | |
| std::string>:: | |
| SimulateSuccessfulAsyncPostDbusCallWithValue( | |
| std::make_shared<std::string>("cert-chain-string"))); | |
| crow::google_api::handleRootOfTrustCertificatesGet(app_, CreateRequest(), | |
| share_async_resp_, "Hoth"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.type"], "#Certificate.v1_0_0.Certificate"); | |
| EXPECT_EQ(json["@odata.id"], | |
| "/google/v1/RootOfTrustCollection/Hoth/Certificates"); | |
| EXPECT_EQ(json["Id"], "Certificates"); | |
| EXPECT_EQ(json["Name"], "Root Of Trust Certificates"); | |
| EXPECT_EQ(json["CertUsageTypes"], nlohmann::json::array({"Device"})); | |
| EXPECT_EQ(json["CertificateType"], "DICE_FEK"); | |
| EXPECT_EQ(json["CertString"], "cert-chain-string"); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, | |
| HandleRootOfTrustCertificatesGetRoTNotFound) { | |
| crow::google_api::handleRootOfTrustCertificatesGet( | |
| app_, CreateRequest(), share_async_resp_, "NonExistentHoth"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, | |
| HandleGetSignedMeasurementsPostMissingNonce) { | |
| nlohmann::json requestJson; | |
| requestJson["PCRSelection"] = "pcrSelectionBase64"; | |
| crow::google_api::handleGetSignedMeasurementsPost( | |
| app_, CreateJsonRequest(requestJson.dump()), share_async_resp_, "Hoth"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::bad_request); | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, | |
| HandleGetSignedMeasurementsPostMissingPCRSelection) { | |
| nlohmann::json requestJson; | |
| requestJson["Nonce"] = "0123456789ABCDEF"; | |
| crow::google_api::handleGetSignedMeasurementsPost( | |
| app_, CreateJsonRequest(requestJson.dump()), share_async_resp_, "Hoth"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::bad_request); | |
| } | |
| TEST_F(SnapshotFixture_Platform11_Config8, | |
| HandleGetSignedMeasurementsPostRoTNotFound) { | |
| nlohmann::json requestJson; | |
| requestJson["Nonce"] = "0123456789ABCDEF"; | |
| requestJson["PCRSelection"] = "pcrSelectionBase64"; | |
| crow::google_api::handleGetSignedMeasurementsPost( | |
| app_, CreateJsonRequest(requestJson.dump()), share_async_resp_, | |
| "NonExistentHoth"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| } // namespace | |
| } // namespace redfish |