diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c15f5b5ee90..da84f586e975 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -654,13 +654,6 @@ if(BUILD_TESTS) snp_ioctl_test ${CMAKE_CURRENT_SOURCE_DIR}/src/pal/test/snp_ioctl_test.cpp ) - - add_unit_test( - snp_attestation_verification - ${CMAKE_CURRENT_SOURCE_DIR}/src/node/test/snp_attestation_verification.cpp - ${CCF_DIR}/src/node/quote.cpp - ) - target_link_libraries(snp_attestation_verification PRIVATE ccf_kv.host) endif() add_unit_test(map_test ${CMAKE_CURRENT_SOURCE_DIR}/src/ds/test/map_test.cpp) diff --git a/include/ccf/pal/attestation_sev_snp.h b/include/ccf/pal/attestation_sev_snp.h index 77413974a46a..89f8ed93c330 100644 --- a/include/ccf/pal/attestation_sev_snp.h +++ b/include/ccf/pal/attestation_sev_snp.h @@ -6,6 +6,7 @@ #include "ccf/pal/attestation_sev_snp_endorsements.h" #include "ccf/pal/measurement.h" #include "ccf/pal/report_data.h" +#include "ccf/pal/hardware_info.h" #include #include @@ -278,33 +279,33 @@ QPHfbkH0CyPfhl1jWhJFZasCAwEAAQ== uint8_t extended_model : 4; uint8_t extended_family : 8; uint8_t reserved2 : 4; - }; - static_assert( - sizeof(CPUID) == sizeof(uint32_t), "Can't cast CPUID to uint32_t"); - struct AttestChipModel - { - uint8_t family; - uint8_t model; - uint8_t stepping; - - bool operator==(const AttestChipModel&) const = default; + bool operator==(const CPUID&) const = default; std::string hex_str() const { auto begin = reinterpret_cast(this); - return ccf::ds::to_hex(begin, begin + sizeof(AttestChipModel)); + return ccf::ds::to_hex(begin, begin + sizeof(CPUID)); + } + inline uint8_t get_family_id() const + { + return this->base_family + this->extended_family; + } + inline uint8_t get_model_id() const + { + return (this->extended_model << 4) | this->base_model; } }; + static_assert( + sizeof(CPUID) == sizeof(uint32_t), "Can't cast CPUID to uint32_t"); #pragma pack(pop) - DECLARE_JSON_TYPE(AttestChipModel); - DECLARE_JSON_REQUIRED_FIELDS(AttestChipModel, family, model, stepping); - constexpr AttestChipModel get_attest_chip_model(const CPUID& cpuid) + DECLARE_JSON_TYPE(CPUID); + DECLARE_JSON_REQUIRED_FIELDS(CPUID, stepping, base_model, base_family, extended_model, extended_family); + + static CPUID get_cpuid() { - AttestChipModel model; - model.family = cpuid.base_family + cpuid.extended_family; - model.model = (cpuid.extended_model << 4) | cpuid.base_model; - model.stepping = cpuid.stepping; - return model; + CpuidInfo cpuid_info{}; + cpuid(&cpuid_info, 1, 0); + return *reinterpret_cast(&cpuid_info.eax); // TODO validate } } @@ -313,24 +314,24 @@ namespace ccf::kv::serialisers // Use hex string to ensure uniformity between the endpoint perspective and // the kv's key template <> - struct BlitSerialiser + struct BlitSerialiser { static SerialisedEntry to_serialised( - const ccf::pal::snp::AttestChipModel& chip) + const ccf::pal::snp::CPUID& chip) { auto hex_str = chip.hex_str(); return SerialisedEntry(hex_str.begin(), hex_str.end()); } - static ccf::pal::snp::AttestChipModel from_serialised( + static ccf::pal::snp::CPUID from_serialised( const SerialisedEntry& data) { - ccf::pal::snp::AttestChipModel ret; + ccf::pal::snp::CPUID ret; auto buf_ptr = reinterpret_cast(&ret); ccf::ds::from_hex( std::string(data.data(), data.end()), buf_ptr, - buf_ptr + sizeof(ccf::pal::snp::AttestChipModel)); + buf_ptr + sizeof(ccf::pal::snp::CPUID)); return ret; } }; diff --git a/include/ccf/service/tables/tcb_verification.h b/include/ccf/service/tables/tcb_verification.h index c4bd985244a6..d1ca42b64ef9 100644 --- a/include/ccf/service/tables/tcb_verification.h +++ b/include/ccf/service/tables/tcb_verification.h @@ -9,7 +9,7 @@ namespace ccf { using SnpTcbVersionMap = - ServiceMap; + ServiceMap; namespace Tables { diff --git a/src/node/gov/handlers/service_state.h b/src/node/gov/handlers/service_state.h index 7fe0e3f6a636..c3f5c4909ac9 100644 --- a/src/node/gov/handlers/service_state.h +++ b/src/node/gov/handlers/service_state.h @@ -615,6 +615,19 @@ namespace ccf::gov::endpoints }); snp_policy["uvmEndorsements"] = snp_endorsements; + auto snp_tcb_versions = nlohmann::json::object(); + auto tcb_versions_handle = + ctx.tx.template ro( + ccf::Tables::SNP_TCB_VERSIONS); + tcb_versions_handle->foreach( + [&snp_tcb_versions]( + const pal::snp::CPUID& cpuid, + const pal::snp::TcbVersion& tcb_version) { + snp_tcb_versions[cpuid.hex_str()] = tcb_version; + return true; + }); + snp_policy["tcbVersions"] = snp_tcb_versions; + response_body["snp"] = snp_policy; } diff --git a/src/node/quote.cpp b/src/node/quote.cpp index 322d668221d5..f70cf71fb9b8 100644 --- a/src/node/quote.cpp +++ b/src/node/quote.cpp @@ -275,13 +275,20 @@ namespace ccf return QuoteVerificationResult::Verified; } - pal::snp::AttestChipModel cpuid = { - .family = attestation.cpuid_fam_id, - .model = attestation.cpuid_mod_id, - .stepping = attestation.cpuid_step}; + std::optional min_tcb_opt = std::nullopt; + + auto h = tx.ro(Tables::SNP_TCB_VERSIONS); + // expensive but there should not be many entries in this table only one per cpu + h->foreach([&min_tcb_opt, &attestation](const pal::snp::CPUID& cpuid, const pal::snp::TcbVersion& v) { + if (cpuid.get_family_id() == attestation.cpuid_fam_id && + cpuid.get_model_id() == attestation.cpuid_mod_id && + cpuid.stepping == attestation.cpuid_step) { + min_tcb_opt = v; + return false; + } + return true; + }); - auto min_tcb_opt = - tx.ro(Tables::SNP_TCB_VERSIONS)->get(cpuid); if (!min_tcb_opt.has_value()) { return QuoteVerificationResult::FailedInvalidCPUID; diff --git a/src/node/rpc/member_frontend.h b/src/node/rpc/member_frontend.h index 2ba72af23780..50cca8c178e1 100644 --- a/src/node/rpc/member_frontend.h +++ b/src/node/rpc/member_frontend.h @@ -510,7 +510,7 @@ namespace ccf if constexpr ( std::is_same_v || pal::is_attestation_measurement::value || - std::is_same_v) + std::is_same_v) { response_body[k.hex_str()] = v; } diff --git a/src/node/rpc/node_frontend.h b/src/node/rpc/node_frontend.h index b9e89178c514..b345a8439875 100644 --- a/src/node/rpc/node_frontend.h +++ b/src/node/rpc/node_frontend.h @@ -1638,6 +1638,9 @@ namespace ccf LOG_FAIL_FMT("Unable to extract host data from virtual quote"); } break; + + InternalTablesAccess::trust_static_snp_tcb_version(ctx.tx); + } case QuoteFormat::amd_sev_snp_v1: diff --git a/src/node/test/snp_attestation_verification.cpp b/src/node/test/snp_attestation_verification.cpp deleted file mode 100644 index 0c5937a92d63..000000000000 --- a/src/node/test/snp_attestation_verification.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache 2.0 License. - -#include "ccf/ds/quote_info.h" -#include "ccf/node/quote.h" -#include "ccf/pal/attestation_sev_snp.h" -#include "ccf/pal/snp_ioctl.h" -#include "ccf/service/tables/tcb_verification.h" -#include "kv/store.h" -#include "kv/test/null_encryptor.h" -#include "pal/quote_generation.h" - -#include -#include -#include - -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include - -using namespace ccf; - -TEST_CASE("E2E") -{ - kv::Store kv_store; - auto encryptor = std::make_shared(); - kv_store.set_encryptor(encryptor); - - auto tx = kv_store.create_tx(); - auto h = tx.wo(Tables::SNP_TCB_VERSIONS); - - REQUIRE(pal::snp::is_sev_snp()); - - auto attest_intf = pal::snp::get_attestation({}); - QuoteInfo quote_info = {}; - quote_info.format = QuoteFormat::amd_sev_snp_v1; - quote_info.quote = attest_intf->get_raw(); - - auto rc = verify_tcb_version_against_store(tx, quote_info); - CHECK_EQ(rc, QuoteVerificationResult::FailedInvalidCPUID); - - auto attestation = attest_intf->get(); - - // populate store with info from current attestation - auto current_tcb = attestation.reported_tcb; - pal::snp::AttestChipModel chip_id{ - .family = attestation.cpuid_fam_id, - .model = attestation.cpuid_mod_id, - .stepping = attestation.cpuid_step, - }; - h->put(chip_id, current_tcb); - - rc = verify_tcb_version_against_store(tx, quote_info); - CHECK_EQ(rc, QuoteVerificationResult::Verified); - - auto new_tcb_snp = current_tcb; - new_tcb_snp.snp += 1; - h->put(chip_id, new_tcb_snp); - rc = verify_tcb_version_against_store(tx, quote_info); - CHECK_EQ(rc, QuoteVerificationResult::FailedInvalidTcbVersion); - - auto new_tcb_microcode = current_tcb; - new_tcb_microcode.microcode += 1; - h->put(chip_id, new_tcb_microcode); - rc = verify_tcb_version_against_store(tx, quote_info); - CHECK_EQ(rc, QuoteVerificationResult::FailedInvalidTcbVersion); -} \ No newline at end of file diff --git a/src/pal/quote_generation.h b/src/pal/quote_generation.h index 347da0fff7c3..e81736e51ac8 100644 --- a/src/pal/quote_generation.h +++ b/src/pal/quote_generation.h @@ -4,6 +4,7 @@ #include "ccf/crypto/hash_provider.h" #include "ds/files.h" +#include "ccf/pal/attestation.h" #include #include diff --git a/src/service/internal_tables_access.h b/src/service/internal_tables_access.h index 1c82ab70223a..9e1e06e31b60 100644 --- a/src/service/internal_tables_access.h +++ b/src/service/internal_tables_access.h @@ -827,14 +827,13 @@ namespace ccf { auto h = tx.wo(Tables::SNP_TCB_VERSIONS); - constexpr auto milan_chip_id = pal::snp::get_attest_chip_model( - {.stepping = 0x1, + constexpr pal::snp::CPUID milan_chip_id {.stepping = 0x1, .base_model = 0x1, .base_family = 0xF, .reserved = 0, .extended_model = 0x0, .extended_family = 0x0A, - .reserved2 = 0}); + .reserved2 = 0}; constexpr pal::snp::TcbVersion milan_tcb_version = { .boot_loader = 0, .tee = 0, @@ -843,14 +842,13 @@ namespace ccf .microcode = 0xDB}; h->put(milan_chip_id, milan_tcb_version); - constexpr auto milan_x_chip_id = pal::snp::get_attest_chip_model( - {.stepping = 0x2, + constexpr pal::snp::CPUID milan_x_chip_id {.stepping = 0x2, .base_model = 0x1, .base_family = 0xF, .reserved = 0, .extended_model = 0x0, .extended_family = 0x0A, - .reserved2 = 0}); + .reserved2 = 0}; constexpr pal::snp::TcbVersion milan_x_tcb_version = { .boot_loader = 0, .tee = 0, @@ -859,14 +857,13 @@ namespace ccf .microcode = 0x44}; h->put(milan_x_chip_id, milan_x_tcb_version); - constexpr auto genoa_chip_id = pal::snp::get_attest_chip_model( - {.stepping = 0x1, + constexpr pal::snp::CPUID genoa_chip_id {.stepping = 0x1, .base_model = 0x1, .base_family = 0xF, .reserved = 0, .extended_model = 0x1, .extended_family = 0x0A, - .reserved2 = 0}); + .reserved2 = 0}; constexpr pal::snp::TcbVersion genoa_tcb_version = { .boot_loader = 0, .tee = 0, @@ -875,14 +872,13 @@ namespace ccf .microcode = 0x54}; h->put(genoa_chip_id, genoa_tcb_version); - constexpr auto genoa_x_chip_id = pal::snp::get_attest_chip_model( - {.stepping = 0x2, + constexpr pal::snp::CPUID genoa_x_chip_id {.stepping = 0x2, .base_model = 0x1, .base_family = 0xF, .reserved = 0, .extended_model = 0x1, .extended_family = 0x0A, - .reserved2 = 0}); + .reserved2 = 0}; constexpr pal::snp::TcbVersion genoa_x_tcb_version = { .boot_loader = 0, .tee = 0, @@ -897,13 +893,9 @@ namespace ccf { if (attestation.version >= pal::snp::MIN_TCB_VERIF_VERSION) { - pal::snp::AttestChipModel chip_id{ - .family = attestation.cpuid_fam_id, - .model = attestation.cpuid_mod_id, - .stepping = attestation.cpuid_step, - }; + auto cpuid = pal::snp::get_cpuid(); auto h = tx.wo(Tables::SNP_TCB_VERSIONS); - h->put(chip_id, attestation.reported_tcb); + h->put(cpuid, attestation.reported_tcb); } }