| #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}), |
| }))) |
| .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(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 |