Skip to content

Commit b502534

Browse files
authored
Accept UVM endorsements with integer SVN (#7316)
1 parent 3061031 commit b502534

File tree

5 files changed

+101
-20
lines changed

5 files changed

+101
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1414
- Added `ccf.gov.validateConstitution` function to JS API, which can be used to confirm some basic properties of a proposed constitution (it is a string, parseable by our JS interpreter, exporting functions named `validate`, `resolve` and `apply` with the correct number of arguments). This is called in the default sample constitution's `set_constitution.validate`.
1515
- Added logging of the initial node attestation value ("Initial node attestation...") (#7256).
1616
- Improved handling of socket errors in curlm callbacks (#7308)
17+
- Accept UVM endorsements with SVNs encoded as integers (#7316)
1718

1819
### Fixed
1920

src/node/test/endorsements.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,43 @@ TEST_CASE("Check ECDSA Test endorsement")
6868
REQUIRE(endorsements == ccf::default_uvm_roots_of_trust[1]);
6969
}
7070

71+
TEST_CASE("Check Test endorsement with integer SVN")
72+
{
73+
char* end_path = std::getenv("TEST_ENDORSEMENTS_PATH");
74+
REQUIRE(end_path != nullptr);
75+
76+
auto endorsement = files::slurp(fmt::format("{}/int_svn.cose", end_path));
77+
REQUIRE(!endorsement.empty());
78+
79+
ccf::pal::SnpAttestationMeasurement measurement(
80+
"d0c9e2be22046e60779be88868cff64c2aa22047c15d3127ba495cee3fbc2854c5633f9da2"
81+
"096e6c64ae2b69bbff8082");
82+
ccf::pal::PlatformAttestationMeasurement uvm_measurement(measurement);
83+
84+
std::vector<ccf::pal::UVMEndorsements> custom_roots_of_trust = {
85+
ccf::pal::UVMEndorsements{
86+
"did:x509:0:sha256:I__iuL25oXEVFdTP_aBLx_eT1RPHbCQ_ECBQfYZpt9s::eku:1.3."
87+
"6.1.4.1.311.76.59.1.5",
88+
"Malicious-ConfAKS-AMD-UVM",
89+
"1"}};
90+
REQUIRE_THROWS_WITH_AS(
91+
ccf::verify_uvm_endorsements_against_roots_of_trust(
92+
endorsement, uvm_measurement, custom_roots_of_trust),
93+
"UVM endorsements did "
94+
"did:x509:0:sha256:I__iuL25oXEVFdTP_aBLx_eT1RPHbCQ_ECBQfYZpt9s::eku:1.3.6."
95+
"1.4.1.311.76.59.1.2, feed ContainerPlat-AMD-UVM, svn 102 do not match any "
96+
"of the "
97+
"known UVM roots of trust",
98+
std::logic_error);
99+
100+
auto endorsements = ccf::verify_uvm_endorsements_against_roots_of_trust(
101+
endorsement, uvm_measurement, ccf::default_uvm_roots_of_trust);
102+
103+
REQUIRE(endorsements.did == ccf::default_uvm_roots_of_trust[0].did);
104+
REQUIRE(endorsements.feed == ccf::default_uvm_roots_of_trust[0].feed);
105+
REQUIRE(endorsements.svn == "102");
106+
}
107+
71108
TEST_CASE("Check UVM roots of trust matching")
72109
{
73110
ccf::pal::UVMEndorsements old{"issuer1", "subject1", "0"};

src/node/uvm_endorsements.cpp

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,32 @@ namespace ccf
1313
{
1414
return std::ranges::any_of(
1515
uvm_roots_of_trust, [&](const auto& uvm_root_of_trust) {
16+
size_t root_of_trust_svn = 0;
17+
auto result = std::from_chars(
18+
uvm_root_of_trust.svn.data(),
19+
uvm_root_of_trust.svn.data() + uvm_root_of_trust.svn.size(),
20+
root_of_trust_svn);
21+
if (result.ec != std::errc())
22+
{
23+
throw std::runtime_error(fmt::format(
24+
"Unable to parse svn value {} to unsigned in UVM root of trust",
25+
uvm_root_of_trust.svn));
26+
}
27+
size_t endorsement_svn = 0;
28+
result = std::from_chars(
29+
endorsements.svn.data(),
30+
endorsements.svn.data() + endorsements.svn.size(),
31+
endorsement_svn);
32+
if (result.ec != std::errc())
33+
{
34+
throw std::runtime_error(fmt::format(
35+
"Unable to parse svn value {} to unsigned in UVM endorsements",
36+
endorsements.svn));
37+
}
38+
1639
return uvm_root_of_trust.did == endorsements.did &&
1740
uvm_root_of_trust.feed == endorsements.feed &&
18-
uvm_root_of_trust.svn <= endorsements.svn;
41+
root_of_trust_svn <= endorsement_svn;
1942
});
2043
}
2144

@@ -269,25 +292,58 @@ namespace ccf
269292
cose::headers::CONTENT_TYPE_APPLICATION_JSON_VALUE));
270293
}
271294

272-
UVMEndorsementsPayload payload = nlohmann::json::parse(raw_payload);
273-
if (payload.sevsnpvm_launch_measurement != uvm_measurement.hex_str())
295+
auto payload = nlohmann::json::parse(raw_payload);
296+
std::string sevsnpvm_launch_measurement =
297+
payload["x-ms-sevsnpvm-launchmeasurement"].get<std::string>();
298+
auto sevsnpvm_guest_svn_obj = payload["x-ms-sevsnpvm-guestsvn"];
299+
std::string sevsnpvm_guest_svn;
300+
if (sevsnpvm_guest_svn_obj.is_string())
301+
{
302+
sevsnpvm_guest_svn = sevsnpvm_guest_svn_obj.get<std::string>();
303+
size_t uintval = 0;
304+
auto result = std::from_chars(
305+
sevsnpvm_guest_svn.data(),
306+
sevsnpvm_guest_svn.data() + sevsnpvm_guest_svn.size(),
307+
uintval);
308+
if (result.ec != std::errc())
309+
{
310+
throw std::logic_error(fmt::format(
311+
"Unable to parse sevsnpvm_guest_svn value {} to unsigned in UVM "
312+
"endorsements "
313+
"payload",
314+
sevsnpvm_guest_svn));
315+
}
316+
}
317+
else if (sevsnpvm_guest_svn_obj.is_number_unsigned())
318+
{
319+
sevsnpvm_guest_svn = std::to_string(sevsnpvm_guest_svn_obj.get<size_t>());
320+
}
321+
else
322+
{
323+
throw std::logic_error(fmt::format(
324+
"Unexpected type {} for sevsnpvm_guest_svn in UVM endorsements "
325+
"payload, expected string or unsigned integer",
326+
sevsnpvm_guest_svn_obj.type_name()));
327+
}
328+
329+
if (sevsnpvm_launch_measurement != uvm_measurement.hex_str())
274330
{
275331
throw std::logic_error(fmt::format(
276332
"Launch measurement in UVM endorsements payload {} is not equal "
277333
"to UVM attestation measurement {}",
278-
payload.sevsnpvm_launch_measurement,
334+
sevsnpvm_launch_measurement,
279335
uvm_measurement.hex_str()));
280336
}
281337

282338
LOG_INFO_FMT(
283339
"Successfully verified endorsements for attested measurement {} against "
284340
"{}, feed {}, svn {}",
285-
payload.sevsnpvm_launch_measurement,
341+
sevsnpvm_launch_measurement,
286342
did,
287343
phdr.feed,
288-
payload.sevsnpvm_guest_svn);
344+
sevsnpvm_guest_svn);
289345

290-
pal::UVMEndorsements end{did, phdr.feed, payload.sevsnpvm_guest_svn};
346+
pal::UVMEndorsements end{did, phdr.feed, sevsnpvm_guest_svn};
291347

292348
if (
293349
enforce_uvm_roots_of_trust &&

src/node/uvm_endorsements.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,6 @@
1919

2020
namespace ccf
2121
{
22-
struct UVMEndorsementsPayload
23-
{
24-
std::string sevsnpvm_guest_svn;
25-
std::string sevsnpvm_launch_measurement;
26-
};
27-
DECLARE_JSON_TYPE(UVMEndorsementsPayload);
28-
DECLARE_JSON_REQUIRED_FIELDS_WITH_RENAMES(
29-
UVMEndorsementsPayload,
30-
sevsnpvm_guest_svn,
31-
"x-ms-sevsnpvm-guestsvn",
32-
sevsnpvm_launch_measurement,
33-
"x-ms-sevsnpvm-launchmeasurement");
34-
3522
struct UvmEndorsementsProtectedHeader
3623
{
3724
int64_t alg;
10.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)