Skip to content
Open
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
14 changes: 14 additions & 0 deletions src/ca2a_verify/sev_snp.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ def verify_sev_snp_report(
``agent_manifest.PLATFORM_INFO_BITS``. Both default to ``None``, which
appraises nothing and leaves prior behaviour unchanged.
"""
if expected_measurement is not None and (
not isinstance(expected_measurement, (bytes, bytearray, memoryview))
or len(expected_measurement) != 48
):
raise ValueError("expected_measurement must be a 48-byte SNP measurement")
if expected_report_data is not None and (
not isinstance(expected_report_data, (bytes, bytearray, memoryview))
or len(expected_report_data) != 64
):
raise ValueError("expected_report_data must be a 64-byte SNP report_data value")
if not isinstance(reject_unrecognized_platform_bits, bool):
raise ValueError("reject_unrecognized_platform_bits must be a boolean")
report = SevSnpReport.parse(report_bytes)

if report.signature_algo != SIG_ALGO_ECDSA_P384_SHA384:
Expand Down Expand Up @@ -155,6 +167,8 @@ def sev_snp_verifier(
raise ValueError("expected_measurement must be a 48-byte SNP measurement")
if type(min_guest_svn) is not int or not 0 <= min_guest_svn <= 0xFFFFFFFF:
raise ValueError("min_guest_svn must be an unsigned 32-bit integer")
if not isinstance(reject_unrecognized_platform_bits, bool):
raise ValueError("reject_unrecognized_platform_bits must be a boolean")
roots, chain = list(trusted_roots), list(vcek_chain)
required, forbidden = set(require_platform), set(forbid_platform)

Expand Down
13 changes: 13 additions & 0 deletions src/ca2a_verify/tdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,21 @@ def verify_tdx_quote(
expected_report_data: bytes | None = None,
) -> TdxQuote:
"""Appraise a TDX quote offline. Raises AttestationFailed on any failure."""
if expected_mrtd is not None and (
not isinstance(expected_mrtd, (bytes, bytearray, memoryview)) or len(expected_mrtd) != 48
):
raise ValueError("expected_mrtd must be a 48-byte TDX MRTD")
if expected_report_data is not None and (
not isinstance(expected_report_data, (bytes, bytearray, memoryview))
or len(expected_report_data) != 64
):
raise ValueError("expected_report_data must be a 64-byte TDX report_data value")
quote = TdxQuote.parse(quote_bytes)

if quote.version != 4:
raise AttestationFailed(
"unsupported TDX quote version", detail=f"version={quote.version}, expected 4"
)
if quote.tee_type != TEE_TYPE_TDX:
raise AttestationFailed("quote is not a TDX quote", detail=f"tee_type={quote.tee_type:#x}")

Expand Down
51 changes: 51 additions & 0 deletions tests/unit/test_tdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,54 @@ def test_trailing_padding_after_the_signature_section_is_ignored(quote_and_root)
expected_mrtd=quote_and_root["mrtd"],
expected_report_data=quote_and_root["rd"],
)


@pytest.mark.parametrize("bad_version", [3, 5, 0])
def test_verify_tdx_quote_rejects_non_v4_version(quote_and_root, bad_version: int) -> None:
q = bytearray(quote_and_root["quote"])
struct.pack_into("<H", q, 0, bad_version)
with pytest.raises(AttestationFailed, match="unsupported TDX quote version"):
verify_tdx_quote(bytes(q), trusted_roots=[quote_and_root["root"]])


@pytest.mark.parametrize(
("bad_mrtd", "bad_rd"),
[
(b"\x11" * 47, None),
(b"\x11" * 49, None),
("not-bytes", None),
(None, b"\x22" * 63),
(None, b"\x22" * 65),
(None, "not-bytes"),
],
)
def test_verify_tdx_quote_and_sev_snp_reject_malformed_expected_digests(
quote_and_root, bad_mrtd, bad_rd
) -> None:
from ca2a_verify.sev_snp import sev_snp_verifier, verify_sev_snp_report

with pytest.raises(ValueError):
verify_tdx_quote(
quote_and_root["quote"],
trusted_roots=[quote_and_root["root"]],
expected_mrtd=bad_mrtd,
expected_report_data=bad_rd,
)
with pytest.raises(ValueError):
verify_sev_snp_report(
b"\x00" * 1184,
[],
trusted_roots=[],
expected_measurement=bad_mrtd,
expected_report_data=bad_rd,
)
with pytest.raises(ValueError, match="reject_unrecognized_platform_bits"):
sev_snp_verifier(
trusted_roots=[],
vcek_chain=[],
expected_measurement=b"\x11" * 48,
min_guest_svn=1,
require_platform=set(),
forbid_platform=set(),
reject_unrecognized_platform_bits="yes", # type: ignore[arg-type]
)
Loading