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

Check TCB version to ensure it is up to date enough #6837

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0ea57ab
Parse cpuid bytes of attestation
cjen1-msft Feb 18, 2025
1f3cb19
Check that the firmware version of SNP chips is correct
cjen1-msft Feb 21, 2025
962b0f8
Reformat
cjen1-msft Feb 21, 2025
86a375e
Add base case if nothing matches
cjen1-msft Feb 21, 2025
b149874
Move validation to tables
cjen1-msft Feb 21, 2025
1f3e567
Tmp
cjen1-msft Feb 24, 2025
71888d8
Add minimal hacky getter
cjen1-msft Feb 24, 2025
f8196d8
fmt
cjen1-msft Feb 24, 2025
38ca2f5
Trust host's tcb
cjen1-msft Feb 24, 2025
910a24a
Use MIN_TCB_VERIF_VERSION
cjen1-msft Feb 24, 2025
349e03e
Make build
cjen1-msft Feb 24, 2025
1ebec9f
Use hex represntation of AttestChipModel as key
cjen1-msft Feb 25, 2025
012462c
AttestChipModel should have json representation
cjen1-msft Feb 26, 2025
7f909c1
0 out remainder of TcbVersion
cjen1-msft Feb 26, 2025
b8fa350
Initialize members
cjen1-msft Feb 26, 2025
0881d28
Add test for verify_tcb_against_store
cjen1-msft Feb 28, 2025
85dcbed
Move get_tcb_version out of attestation_provider. FIx import of logge…
cjen1-msft Feb 28, 2025
0ab54d7
poke the birds
cjen1-msft Feb 28, 2025
b639a71
Reformat
cjen1-msft Feb 28, 2025
824346a
Store cpuid in kv. Check attestation against it.
cjen1-msft Mar 3, 2025
3e294e5
Fix cpuid request
cjen1-msft Mar 4, 2025
7b136f0
fmt
cjen1-msft Mar 4, 2025
8512235
Add governance action for tcb_versions
cjen1-msft Mar 4, 2025
09a2d13
Add test for tcb_versions table
cjen1-msft Mar 4, 2025
c3c14f9
fmt
cjen1-msft Mar 4, 2025
f6a03bb
fixup
cjen1-msft Mar 5, 2025
df38f54
Fix formatting of cpuid
cjen1-msft Mar 5, 2025
f1cc568
TMP store hex string of cpuid
cjen1-msft Mar 6, 2025
15b50cb
Fix converters
cjen1-msft Mar 7, 2025
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
6 changes: 3 additions & 3 deletions .snpcc_canary
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
___ ___ ___ \/
(. =) Y (0 0) (x X) Y (vv)
O \ o | / |
___ ___ ___ \_/
(. =) Y (0 0) (x X) Y (___)
O \ o | / |
/-xXx--//-----x=x--/-xXx--/---x-/--->>>--/
...
3 changes: 2 additions & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"configurations": [
{
"name": "Linux",
"compileCommands": "${workspaceFolder}/build/compile_commands.json"
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
"includePath": ["${workspaceFolder}/include", "${workspaceFolder}/src"]
}
],
"version": 4
Expand Down
9 changes: 9 additions & 0 deletions include/ccf/node/quote.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "ccf/ccf_deprecated.h"
#include "ccf/ds/quote_info.h"
#include "ccf/pal/attestation_sev_snp.h"
#include "ccf/pal/measurement.h"
#include "ccf/service/tables/host_data.h"
#include "ccf/tx.h"
Expand All @@ -22,6 +23,8 @@ namespace ccf
FailedInvalidHostData,
FailedInvalidQuotedPublicKey,
FailedUVMEndorsementsNotFound,
FailedInvalidCPUID,
FailedInvalidTcbVersion
};

class AttestationProvider
Expand All @@ -35,10 +38,16 @@ namespace ccf

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

static std::optional<pal::snp::Attestation> get_snp_attestation(
const QuoteInfo& quote_info);

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

}
88 changes: 87 additions & 1 deletion include/ccf/pal/attestation_sev_snp.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ QPHfbkH0CyPfhl1jWhJFZasCAwEAAQ==
static_assert(
sizeof(TcbVersion) == sizeof(uint64_t),
"Can't cast TcbVersion to uint64_t");
DECLARE_JSON_TYPE(TcbVersion);
DECLARE_JSON_REQUIRED_FIELDS(TcbVersion, boot_loader, tee, snp, microcode);

#pragma pack(push, 1)
struct Signature
Expand Down Expand Up @@ -141,7 +143,10 @@ QPHfbkH0CyPfhl1jWhJFZasCAwEAAQ==
uint8_t report_id[32]; /* 0x140 */
uint8_t report_id_ma[32]; /* 0x160 */
struct TcbVersion reported_tcb; /* 0x180 */
uint8_t reserved1[24]; /* 0x188 */
uint8_t cpuid_fam_id; /* 0x188*/
uint8_t cpuid_mod_id; /* 0x189 */
uint8_t cpuid_step; /* 0x18A */
uint8_t reserved1[21]; /* 0x18B */
uint8_t chip_id[64]; /* 0x1A0 */
struct TcbVersion committed_tcb; /* 0x1E0 */
uint8_t current_minor; /* 0x1E8 */
Expand Down Expand Up @@ -261,4 +266,85 @@ QPHfbkH0CyPfhl1jWhJFZasCAwEAAQ==

virtual ~AttestationInterface() = default;
};

static uint8_t MIN_TCB_VERIF_VERSION = 3;
#pragma pack(push, 1)
struct CPUID
{
uint8_t stepping : 4;
uint8_t base_model : 4;
uint8_t base_family : 4;
uint8_t reserved : 4;
uint8_t extended_model : 4;
uint8_t extended_family : 8;
uint8_t reserved2 : 4;

bool operator==(const CPUID&) const = default;
std::string hex_str() const
{
CPUID buf = *this;
auto buf_ptr = reinterpret_cast<uint8_t*>(&buf);
std::reverse(buf_ptr, buf_ptr + sizeof(CPUID));
return ccf::ds::to_hex(buf_ptr, buf_ptr + 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;
}
};
#pragma pack(pop)
DECLARE_JSON_TYPE(CPUID);
DECLARE_JSON_REQUIRED_FIELDS(
CPUID, stepping, base_model, base_family, extended_model, extended_family);
static_assert(
sizeof(CPUID) == sizeof(uint32_t), "Can't cast CPUID to uint32_t");
static CPUID cpuid_from_hex(const std::string& hex_str)
{
CPUID ret;
auto buf_ptr = reinterpret_cast<uint8_t*>(&ret);
ccf::ds::from_hex(
hex_str, buf_ptr, buf_ptr + sizeof(CPUID));
std::reverse(buf_ptr, buf_ptr + sizeof(CPUID)); //fix little endianness of AMD
return ret;
}

static CPUID get_cpuid()
{
uint32_t ieax = 1;
uint64_t iebx = 0;
uint64_t iecx = 0;
uint64_t iedx = 0;
uint32_t oeax = 0;
uint64_t oebx = 0;
uint64_t oecx = 0;
uint64_t oedx = 0;
// pass in e{b,c,d}x to prevent cpuid from blatting other registers
asm volatile("cpuid" : "=a"(oeax), "=b"(oebx), "=c"(oecx), "=d"(oedx): "a"(ieax), "b"(iebx), "c"(iecx), "d"(iedx));
auto cpuid = *reinterpret_cast<CPUID*>(&oeax);
return cpuid;
}
}

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::CPUID>
{
static SerialisedEntry to_serialised(const ccf::pal::snp::CPUID& chip)
{
auto hex_str = chip.hex_str();
return SerialisedEntry(hex_str.begin(), hex_str.end());
}

static ccf::pal::snp::CPUID from_serialised(const SerialisedEntry& data)
{
return ccf::pal::snp::cpuid_from_hex(std::string(data.data(), data.end()));
}
};
}
1 change: 1 addition & 0 deletions include/ccf/pal/snp_ioctl5.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache 2.0 License.
#pragma once

#include "ccf/ds/logger.h"
#include "ccf/pal/attestation_sev_snp.h"

#include <fcntl.h>
Expand Down
1 change: 1 addition & 0 deletions include/ccf/pal/snp_ioctl6.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache 2.0 License.
#pragma once

#include "ccf/ds/logger.h"
#include "ccf/pal/attestation_sev_snp.h"

#include <algorithm>
Expand Down
18 changes: 18 additions & 0 deletions include/ccf/service/tables/tcb_verification.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once

#include "ccf/ds/json.h"
#include "ccf/pal/attestation_sev_snp.h"
#include "ccf/service/map.h"

namespace ccf
{
using SnpTcbVersionMap = ServiceMap<std::string, pal::snp::TcbVersion>;

namespace Tables
{
static constexpr auto SNP_TCB_VERSIONS =
"public:ccf.gov.nodes.snp.tcb_versions";
}
}
3 changes: 3 additions & 0 deletions js/ccf-app/src/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,9 @@ export interface SnpAttestationResult {
report_id: ArrayBuffer;
report_id_ma: ArrayBuffer;
reported_tcb: TcbVersion;
cpuid_fam_id: number;
cpuid_mod_id: number;
cpuid_step: number;
chip_id: ArrayBuffer;
committed_tcb: TcbVersion;
current_minor: number;
Expand Down
48 changes: 48 additions & 0 deletions samples/constitutions/default/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,37 @@ const actions = new Map([
},
),
],
[
"add_snp_tcb_version",
new Action(
function (args) {
checkType(args.cpuid, "string", "cpuid");
checkLength(ccf.strToBuf(args.cpuid), 8, 8, "cpuid");

checkType(args.tcb_version, "object", "tcb_version");
checkType(
args.tcb_version?.boot_loader,
"number",
"tcb_version.boot_loader",
);
checkType(args.tcb_version?.tee, "number", "tcb_version.tee");
checkType(args.tcb_version?.snp, "number", "tcb_version.snp");
checkType(
args.tcb_version?.microcode,
"number",
"tcb_version.microcode",
);
},
function (args, proposalId) {
ccf.kv["public:ccf.gov.nodes.snp.tcb_versions"].set(
ccf.strToBuf(args.cpuid),
ccf.jsonCompatibleToBuf(args.tcb_version),
);

invalidateOtherOpenProposals(proposalId);
},
),
],
[
"remove_snp_host_data",
new Action(
Expand Down Expand Up @@ -1151,6 +1182,23 @@ const actions = new Map([
},
),
],
[
"remove_snp_tcb_version",
new Action(
function (args) {
checkType(args.cpuid, "string", "cpuid");
checkLength(ccf.strToBuf(args.cpuid), 8, 8, "cpuid");
},
function (args) {
const cpuid = ccf.strToBuf(args.cpuid);
if ( ccf.kv["public:ccf.gov.nodes.snp.tcb_versions"].has(cpuid)) {
ccf.kv["public:ccf.gov.nodes.snp.tcb_versions"].delete(cpuid);
} else {
throw new Error("CPUID not found");
}
},
),
],
[
"set_node_data",
new Action(
Expand Down
3 changes: 3 additions & 0 deletions src/js/extensions/ccf/converters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
#include "ccf/js/extensions/ccf/converters.h"

#include "ccf/js/core/context.h"
#include "ccf/pal/attestation_sev_snp.h"
#include "ccf/version.h"
#include "js/checks.h"
#include "node/rpc/jwt_management.h"

#include <nlohmann/json.hpp>
#include <quickjs/quickjs.h>

namespace ccf::js::extensions
Expand Down Expand Up @@ -217,5 +219,6 @@ namespace ccf::js::extensions
ctx.new_c_function(js_enable_metrics_logging, "enableMetricsLogging", 1));

ccf.set("pemToId", ctx.new_c_function(js_pem_to_id, "pemToId", 1));

}
}
4 changes: 4 additions & 0 deletions src/js/extensions/snp_attestation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ namespace ccf::js::extensions
JS_CHECK_EXC(reported_tcb);
JS_CHECK_SET(a.set("reported_tcb", std::move(reported_tcb)));

JS_CHECK_SET(a.set_uint32("cpuid_fam_id", attestation.cpuid_fam_id));
JS_CHECK_SET(a.set_uint32("cpuid_mod_id", attestation.cpuid_mod_id));
JS_CHECK_SET(a.set_uint32("cpuid_step", attestation.cpuid_step));

auto attestation_chip_id = jsctx.new_array_buffer_copy(attestation.chip_id);
JS_CHECK_EXC(attestation_chip_id);
JS_CHECK_SET(a.set("chip_id", std::move(attestation_chip_id)));
Expand Down
14 changes: 14 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,20 @@ 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 std::string& cpuid,
const pal::snp::TcbVersion& tcb_version) {
snp_tcb_versions[cpuid] = tcb_version;
return true;
});
snp_policy["tcbVersions"] = snp_tcb_versions;

response_body["snp"] = snp_policy;
}

Expand Down
Loading
Loading