Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SEV-SNP: support for multiple measurement types on same node #5063

Merged
merged 29 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .daily_canary
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
___ ___
(~ ~) (o o) | Y & +
(- -) (o o) | Y & +
( V ) z O z O +---'---'
/--x-m- /--m-m---xXx--/--yy------
2 changes: 1 addition & 1 deletion .snpcc_canary
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
___ ___ ___
(O o) Y (9 3) (* *) Y
(O =) Y (9 3) (* *) Y
O / O O /
/-xXx--//-----x=x--/-xXx--/---x---->xxxxxx
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

- Additional logging of historical query flow in `UNSAFE` builds.
- Historical query system will re-request entries if the host fails to provide them within a fixed time.
- Renamed `ccf::CodeDigest` to `ccf:pal::PlatformAttestationMeasurement` and `get_code_id()` to `get_measurement()` (#5063).

### Dependencies

Expand Down
75 changes: 49 additions & 26 deletions doc/schemas/gov_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,29 +63,6 @@
},
"type": "object"
},
"CodeDigest": {
"format": "hex",
"pattern": "^[a-f0-9]+$",
"type": "string"
},
"CodeDigest_to_CodeStatus": {
"items": {
"items": {
"oneOf": [
{
"$ref": "#/components/schemas/CodeDigest"
},
{
"$ref": "#/components/schemas/CodeStatus"
}
]
},
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"type": "array"
},
"CodeStatus": {
"enum": [
"AllowedToJoin"
Expand Down Expand Up @@ -951,6 +928,29 @@
],
"type": "string"
},
"SgxAttestationMeasurement": {
"format": "hex",
"pattern": "^[a-f0-9]64$",
"type": "string"
},
"SgxAttestationMeasurement_to_CodeStatus": {
"items": {
"items": {
"oneOf": [
{
"$ref": "#/components/schemas/SgxAttestationMeasurement"
},
{
"$ref": "#/components/schemas/CodeStatus"
}
]
},
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"type": "array"
},
"Sha256Digest": {
"format": "hex",
"pattern": "^[a-f0-9]{32}$",
Expand Down Expand Up @@ -1001,6 +1001,29 @@
],
"type": "object"
},
"SnpAttestationMeasurement": {
"format": "hex",
"pattern": "^[a-f0-9]96$",
"type": "string"
},
"SnpAttestationMeasurement_to_CodeStatus": {
"items": {
"items": {
"oneOf": [
{
"$ref": "#/components/schemas/SnpAttestationMeasurement"
},
{
"$ref": "#/components/schemas/CodeStatus"
}
]
},
"maxItems": 2,
"minItems": 2,
"type": "array"
},
"type": "array"
},
"StateDigest": {
"properties": {
"state_digest": {
Expand Down Expand Up @@ -1182,7 +1205,7 @@
"info": {
"description": "This API is used to submit and query proposals which affect CCF's public governance tables.",
"title": "CCF Governance API",
"version": "2.22.0"
"version": "2.23.0"
},
"openapi": "3.0.0",
"paths": {
Expand Down Expand Up @@ -1725,7 +1748,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CodeDigest_to_CodeStatus"
"$ref": "#/components/schemas/SgxAttestationMeasurement_to_CodeStatus"
}
}
},
Expand Down Expand Up @@ -1813,7 +1836,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CodeDigest_to_CodeStatus"
"$ref": "#/components/schemas/SnpAttestationMeasurement_to_CodeStatus"
}
}
},
Expand Down
7 changes: 4 additions & 3 deletions include/ccf/node/quote.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "ccf/ccf_deprecated.h"
#include "ccf/ds/quote_info.h"
#include "ccf/service/code_digest.h"
#include "ccf/pal/measurement.h"
#include "ccf/service/tables/host_data.h"
#include "ccf/tx.h"

Expand All @@ -30,15 +30,16 @@ namespace ccf
/// In SGX case, extracts the MRENCLAVE from an OE quote. This fails on
/// quotes with expired collateral, so it is recommended to cache code IDs
/// once they have been successfully extracted.
static std::optional<CodeDigest> get_code_id(const QuoteInfo& quote_info);
static std::optional<pal::PlatformAttestationMeasurement> get_measurement(
const QuoteInfo& quote_info);

static std::optional<HostData> get_host_data(const QuoteInfo& quote_info);

static QuoteVerificationResult verify_quote_against_store(
kv::ReadOnlyTx& tx,
const QuoteInfo& quote_info,
const std::vector<uint8_t>& expected_node_public_key_der,
CodeDigest& code_digest);
pal::PlatformAttestationMeasurement& measurement);
};

using EnclaveAttestationProvider CCF_DEPRECATED("Will be removed in 4.x") =
Expand Down
86 changes: 45 additions & 41 deletions include/ccf/pal/attestation.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "ccf/ds/logger.h"
#include "ccf/ds/quote_info.h"
#include "ccf/pal/attestation_sev_snp.h"
#include "ccf/pal/measurement.h"

#include <fcntl.h>
#include <functional>
Expand All @@ -33,8 +34,8 @@ namespace ccf::pal
// SGX, this does not require external dependencies (Open Enclave for SGX).
static void verify_snp_attestation_report(
const QuoteInfo& quote_info,
attestation_measurement& unique_id,
attestation_report_data& report_data)
PlatformAttestationMeasurement& measurement,
PlatformAttestationReportData& report_data)
{
if (quote_info.format != QuoteFormat::amd_sev_snp_v1)
{
Expand Down Expand Up @@ -75,14 +76,8 @@ namespace ccf::pal
fmt::format("SEV-SNP: Mask chip key must not be set"));
}

std::copy(
std::begin(quote.report_data),
std::end(quote.report_data),
report_data.begin());
std::copy(
std::begin(quote.measurement),
std::end(quote.measurement),
unique_id.begin());
report_data = SnpAttestationReportData(quote.report_data);
measurement = SnpAttestationMeasurement(quote.measurement);

auto certificates = crypto::split_x509_cert_bundle(std::string_view(
reinterpret_cast<const char*>(quote_info.endorsements.data()),
Expand Down Expand Up @@ -151,7 +146,7 @@ namespace ccf::pal
}

// We should check this (although not security critical) but the guest
// policy ABI is currently set to 0.31, although we are targetting 1.54
// policy ABI is currently set to 0.31, although we are targeting 1.54
// if (quote.policy.abi_major < snp::attestation_policy_abi_major)
// {
// throw std::logic_error(fmt::format(
Expand Down Expand Up @@ -202,7 +197,7 @@ namespace ccf::pal
#if defined(PLATFORM_VIRTUAL)

static void generate_quote(
attestation_report_data& report_data,
PlatformAttestationReportData& report_data,
RetrieveEndorsementCallback endorsement_cb,
const snp::EndorsementsServers& endorsements_servers = {})
{
Expand All @@ -216,7 +211,7 @@ namespace ccf::pal
#elif defined(PLATFORM_SNP)

static void generate_quote(
attestation_report_data& report_data,
PlatformAttestationReportData& report_data,
RetrieveEndorsementCallback endorsement_cb,
const snp::EndorsementsServers& endorsements_servers = {})
{
Expand All @@ -234,7 +229,9 @@ namespace ccf::pal

// Arbitrary report data
memcpy(
req.report_data, report_data.data(), snp_attestation_report_data_size);
req.report_data,
report_data.data.data(),
snp_attestation_report_data_size);

// Documented at
// https://www.kernel.org/doc/html/latest/virt/coco/sev-guest.html
Expand Down Expand Up @@ -274,8 +271,8 @@ namespace ccf::pal

static void verify_quote(
const QuoteInfo& quote_info,
attestation_measurement& unique_id,
attestation_report_data& report_data)
PlatformAttestationMeasurement& measurement,
PlatformAttestationReportData& report_data)
{
auto is_sev_snp = access(snp::DEVICE, F_OK) == 0;

Expand All @@ -286,8 +283,9 @@ namespace ccf::pal
throw std::logic_error(
"Cannot verify virtual attestation report if node is SEV-SNP");
}
unique_id = {};
report_data = {};
// For now, virtual resembles SGX (mostly for historical reasons)
measurement = SgxAttestationMeasurement();
report_data = SgxAttestationReportData();
}
else if (quote_info.format == QuoteFormat::amd_sev_snp_v1)
{
Expand All @@ -297,7 +295,7 @@ namespace ccf::pal
"Cannot verify SEV-SNP attestation report if node is virtual");
}

verify_snp_attestation_report(quote_info, unique_id, report_data);
verify_snp_attestation_report(quote_info, measurement, report_data);
}
else
{
Expand All @@ -317,7 +315,7 @@ namespace ccf::pal
#else // SGX

static void generate_quote(
attestation_report_data& report_data,
PlatformAttestationReportData& report_data,
RetrieveEndorsementCallback endorsement_cb,
const snp::EndorsementsServers& endorsements_servers = {})
{
Expand All @@ -328,12 +326,11 @@ namespace ccf::pal
sgx::Endorsements endorsements;
sgx::SerialisedClaims serialised_custom_claims;

// Serialise hash of node's public key as a custom claim
const size_t custom_claim_length = 1;
oe_claim_t custom_claim;
custom_claim.name = const_cast<char*>(sgx::report_data_claim_name);
custom_claim.value = report_data.data();
custom_claim.value_size = report_data.size();
custom_claim.value = report_data.data.data();
custom_claim.value_size = report_data.data.size();

auto rc = oe_serialize_custom_claims(
&custom_claim,
Expand Down Expand Up @@ -377,8 +374,8 @@ namespace ccf::pal

static void verify_quote(
const QuoteInfo& quote_info,
attestation_measurement& unique_id,
attestation_report_data& report_data)
PlatformAttestationMeasurement& measurement,
PlatformAttestationReportData& report_data)
{
if (quote_info.format == QuoteFormat::insecure_virtual)
{
Expand All @@ -387,7 +384,7 @@ namespace ccf::pal
}
else if (quote_info.format == QuoteFormat::amd_sev_snp_v1)
{
verify_snp_attestation_report(quote_info, unique_id, report_data);
verify_snp_attestation_report(quote_info, measurement, report_data);
return;
}

Expand All @@ -410,17 +407,23 @@ namespace ccf::pal
oe_result_str(rc)));
}

bool unique_id_found = false;
bool sgx_report_data_found = false;
std::optional<SgxAttestationMeasurement> claim_measurement = std::nullopt;
std::optional<SgxAttestationReportData> custom_claim_report_data =
std::nullopt;
for (size_t i = 0; i < claims.length; i++)
{
auto& claim = claims.data[i];
auto claim_name = std::string(claim.name);
if (claim_name == OE_CLAIM_UNIQUE_ID)
{
std::copy(
claim.value, claim.value + claim.value_size, unique_id.begin());
unique_id_found = true;
if (claim.value_size != SgxAttestationMeasurement::size())
{
throw std::logic_error(
fmt::format("SGX measurement claim is not of expected size"));
}

claim_measurement =
SgxAttestationMeasurement({claim.value, claim.value_size});
}
else if (claim_name == OE_CLAIM_CUSTOM_CLAIMS_BUFFER)
{
Expand All @@ -443,37 +446,38 @@ namespace ccf::pal
auto& custom_claim = custom_claims.data[j];
if (std::string(custom_claim.name) == sgx::report_data_claim_name)
{
if (custom_claim.value_size != report_data.size())
if (custom_claim.value_size != SgxAttestationReportData::size())
{
throw std::logic_error(fmt::format(
"Expected {} of size {}, had size {}",
"Expected claim {} of size {}, had size {}",
sgx::report_data_claim_name,
report_data.size(),
SgxAttestationReportData::size(),
custom_claim.value_size));
}

std::copy(
custom_claim.value,
custom_claim.value + custom_claim.value_size,
report_data.begin());
sgx_report_data_found = true;
custom_claim_report_data = SgxAttestationReportData(
{custom_claim.value, custom_claim.value_size});

break;
}
}
}
}

if (!unique_id_found)
if (!claim_measurement.has_value())
{
throw std::logic_error(
"Could not find measurement in SGX attestation report");
}

if (!sgx_report_data_found)
if (!custom_claim_report_data.has_value())
{
throw std::logic_error(
"Could not find report data in SGX attestation report");
}

measurement = claim_measurement.value();
report_data = custom_claim_report_data.value();
}

#endif
Expand Down
Loading