Skip to content

Commit

Permalink
Store cpuid in kv. Check attestation against it.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjen1-msft committed Mar 3, 2025
1 parent 8d6f848 commit b7e3813
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 123 deletions.
7 changes: 0 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
49 changes: 25 additions & 24 deletions include/ccf/pal/attestation_sev_snp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <array>
#include <map>
Expand Down Expand Up @@ -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<const uint8_t*>(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*>(&cpuid_info.eax); // TODO validate
}
}

Expand All @@ -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<ccf::pal::snp::AttestChipModel>
struct BlitSerialiser<ccf::pal::snp::CPUID>
{
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<uint8_t*>(&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;
}
};
Expand Down
2 changes: 1 addition & 1 deletion include/ccf/service/tables/tcb_verification.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace ccf
{
using SnpTcbVersionMap =
ServiceMap<pal::snp::AttestChipModel, pal::snp::TcbVersion>;
ServiceMap<pal::snp::CPUID, pal::snp::TcbVersion>;

namespace Tables
{
Expand Down
13 changes: 13 additions & 0 deletions src/node/gov/handlers/service_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -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::SnpTcbVersionMap>(
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;
}

Expand Down
19 changes: 13 additions & 6 deletions src/node/quote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<pal::snp::TcbVersion> min_tcb_opt = std::nullopt;

auto h = tx.ro<SnpTcbVersionMap>(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<SnpTcbVersionMap>(Tables::SNP_TCB_VERSIONS)->get(cpuid);
if (!min_tcb_opt.has_value())
{
return QuoteVerificationResult::FailedInvalidCPUID;
Expand Down
2 changes: 1 addition & 1 deletion src/node/rpc/member_frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ namespace ccf
if constexpr (
std::is_same_v<typename T::Key, ccf::crypto::Sha256Hash> ||
pal::is_attestation_measurement<typename T::Key>::value ||
std::is_same_v<typename T::Key, ccf::pal::snp::AttestChipModel>)
std::is_same_v<typename T::Key, ccf::pal::snp::CPUID>)
{
response_body[k.hex_str()] = v;
}
Expand Down
3 changes: 3 additions & 0 deletions src/node/rpc/node_frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
66 changes: 0 additions & 66 deletions src/node/test/snp_attestation_verification.cpp

This file was deleted.

1 change: 1 addition & 0 deletions src/pal/quote_generation.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "ccf/crypto/hash_provider.h"
#include "ds/files.h"
#include "ccf/pal/attestation.h"

#include <nlohmann/json.hpp>
#include <string>
Expand Down
28 changes: 10 additions & 18 deletions src/service/internal_tables_access.h
Original file line number Diff line number Diff line change
Expand Up @@ -827,14 +827,13 @@ namespace ccf
{
auto h = tx.wo<ccf::SnpTcbVersionMap>(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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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<ccf::SnpTcbVersionMap>(Tables::SNP_TCB_VERSIONS);
h->put(chip_id, attestation.reported_tcb);
h->put(cpuid, attestation.reported_tcb);
}
}

Expand Down

0 comments on commit b7e3813

Please sign in to comment.