Skip to content

Commit

Permalink
SEV-SNP: support for multiple measurement types on same node (#5063)
Browse files Browse the repository at this point in the history
  • Loading branch information
jumaffre authored Feb 28, 2023
1 parent 47fa9d0 commit 23dfa31
Show file tree
Hide file tree
Showing 31 changed files with 679 additions and 499 deletions.
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

0 comments on commit 23dfa31

Please sign in to comment.