Feat/tinfoil conformance#93
Conversation
There was a problem hiding this comment.
10 issues found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/tinfoil/conformance/cli.py">
<violation number="1" location="src/tinfoil/conformance/cli.py:944">
P1: Custom agent: **Check System Design and Architectural Patterns**
Runtime monkey-patching of library module globals from CLI code creates tight coupling and bypasses explicit interfaces. The conformance CLI directly mutates `collateral_tdx.datetime`, `cert_utils.datetime`, `fetch_collateral`, and `intel_root_ca.INTEL_SGX_ROOT_CA_PEM` rather than using dependency injection or parameterized library calls. This breaks proper layering and makes internal library refactors hazardous.</violation>
<violation number="2" location="src/tinfoil/conformance/cli.py:1008">
P1: CRLs are accepted in `_evaluate_collateral` without signature verification, enabling revocation-check bypass with injected collateral.</violation>
<violation number="3" location="src/tinfoil/conformance/cli.py:1261">
P2: Invalid `min_tee_tcb_svn_hex` is silently ignored, effectively disabling the minimum TCB policy check.</violation>
<violation number="4" location="src/tinfoil/conformance/cli.py:1568">
P2: Mandatory VCEK TCB extension checks are bypassed when extensions are missing or malformed due to `continue` paths.</violation>
<violation number="5" location="src/tinfoil/conformance/cli.py:1689">
P1: Custom agent: **Flag Security Vulnerabilities**
Unbounded gzip decompression of untrusted attestation input enables memory/CPU DoS via a crafted gzip bomb.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| return ("REPORT_FORMAT_UNSUPPORTED", "3.1", | ||
| f"attestation_doc_b64 not valid base64: {e}") | ||
| try: | ||
| report_bytes = _gzip.decompress(gz_bytes) |
There was a problem hiding this comment.
P1: Custom agent: Flag Security Vulnerabilities
Unbounded gzip decompression of untrusted attestation input enables memory/CPU DoS via a crafted gzip bomb.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 1689:
<comment>Unbounded gzip decompression of untrusted attestation input enables memory/CPU DoS via a crafted gzip bomb.</comment>
<file context>
@@ -0,0 +1,2029 @@
+ return ("REPORT_FORMAT_UNSUPPORTED", "3.1",
+ f"attestation_doc_b64 not valid base64: {e}")
+ try:
+ report_bytes = _gzip.decompress(gz_bytes)
+ except Exception as e:
+ return ("REPORT_FORMAT_UNSUPPORTED", "3.1",
</file context>
| root_crl_obj = None | ||
| if pck_crl_der: | ||
| crl = x509.load_der_x509_crl(pck_crl_der) | ||
| pck_crl_obj = PckCrl(crl=crl, ca_type="platform", |
There was a problem hiding this comment.
P1: CRLs are accepted in _evaluate_collateral without signature verification, enabling revocation-check bypass with injected collateral.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 1008:
<comment>CRLs are accepted in `_evaluate_collateral` without signature verification, enabling revocation-check bypass with injected collateral.</comment>
<file context>
@@ -0,0 +1,2029 @@
+ root_crl_obj = None
+ if pck_crl_der:
+ crl = x509.load_der_x509_crl(pck_crl_der)
+ pck_crl_obj = PckCrl(crl=crl, ca_type="platform",
+ next_update=crl.next_update_utc or datetime.now(timezone.utc))
+ if root_crl_der:
</file context>
| from ..attestation import cert_utils as _cert_mod | ||
| orig_coll_dt = _coll_mod.datetime | ||
| orig_cert_dt = _cert_mod.datetime | ||
| _coll_mod.datetime = _FixedDatetime |
There was a problem hiding this comment.
P1: Custom agent: Check System Design and Architectural Patterns
Runtime monkey-patching of library module globals from CLI code creates tight coupling and bypasses explicit interfaces. The conformance CLI directly mutates collateral_tdx.datetime, cert_utils.datetime, fetch_collateral, and intel_root_ca.INTEL_SGX_ROOT_CA_PEM rather than using dependency injection or parameterized library calls. This breaks proper layering and makes internal library refactors hazardous.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 944:
<comment>Runtime monkey-patching of library module globals from CLI code creates tight coupling and bypasses explicit interfaces. The conformance CLI directly mutates `collateral_tdx.datetime`, `cert_utils.datetime`, `fetch_collateral`, and `intel_root_ca.INTEL_SGX_ROOT_CA_PEM` rather than using dependency injection or parameterized library calls. This breaks proper layering and makes internal library refactors hazardous.</comment>
<file context>
@@ -0,0 +1,2029 @@
+ from ..attestation import cert_utils as _cert_mod
+ orig_coll_dt = _coll_mod.datetime
+ orig_cert_dt = _cert_mod.datetime
+ _coll_mod.datetime = _FixedDatetime
+ _cert_mod.datetime = _FixedDatetime
+ try:
</file context>
| ] | ||
| for name, oid, report_val in tcb_pairs: | ||
| raw = ext_map.get(oid) | ||
| if raw is None: |
There was a problem hiding this comment.
P2: Mandatory VCEK TCB extension checks are bypassed when extensions are missing or malformed due to continue paths.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 1568:
<comment>Mandatory VCEK TCB extension checks are bypassed when extensions are missing or malformed due to `continue` paths.</comment>
<file context>
@@ -0,0 +1,2029 @@
+ ]
+ for name, oid, report_val in tcb_pairs:
+ raw = ext_map.get(oid)
+ if raw is None:
+ continue
+ cert_val = _decode_int_ext_value(raw)
</file context>
| f"tee_tcb_svn[{i}]={tee_tcb_svn[i]} < min[{i}]={minimum[i]} " | ||
| f"(quote={tee_tcb_svn.hex()}, minimum={minimum.hex()})") | ||
| except ValueError: | ||
| pass |
There was a problem hiding this comment.
P2: Invalid min_tee_tcb_svn_hex is silently ignored, effectively disabling the minimum TCB policy check.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 1261:
<comment>Invalid `min_tee_tcb_svn_hex` is silently ignored, effectively disabling the minimum TCB policy check.</comment>
<file context>
@@ -0,0 +1,2029 @@
+ f"tee_tcb_svn[{i}]={tee_tcb_svn[i]} < min[{i}]={minimum[i]} "
+ f"(quote={tee_tcb_svn.hex()}, minimum={minimum.hex()})")
+ except ValueError:
+ pass
+
+ return "", ""
</file context>
…oil-conformance binary Mid-level entry point + CLI binary that bring tinfoil-python into the cross-SDK conformance suite (https://github.com/lsd-cat/tinfoil-conformance). Mirrors the same split landed earlier in tinfoil-rs and tinfoil-js. Library changes (src/tinfoil/sigstore.py): * New SigstorePolicy dataclass — one field per SPEC §5 clause. Mirrors the structs in tinfoil-rs / tinfoil-js so the conformance harness can pass identical policy objects to every SDK. * `default_sigstore_policy(repo)` returns the canonical Tinfoil settings. * New SigstoreVerification dataclass carries the extracted measurement plus cert/rekor/tlog/sct fields surfaced to the conformance harness. * New GitHubWorkflowRefPrefix policy class — strict-prefix startswith() check on the cert's GitHubWorkflowRef extension (.1.6). Replaces the previous regex-based GitHubWorkflowRefPattern, matching SPEC §5.3's prefix semantics. * New `verify_sigstore_bundle_with_policy(bundle_bytes, expected_digest, policy, trust_root_json)`. Hermetic — no network, no embedded trust root. Trust root is loaded via sigstore.models.TrustedRoot.from_file after the inline JSON is written to a scoped temp directory (PyCA `sigstore` 4.x only exposes the file loader). * Post-DSSE verification checks: payload_type exact match, in-toto statement type allow-list, subject digest binding (lowercase normalize per SPEC §7.3), predicate type allow-list, register extraction, and pure bundle observables for the harness (rekor logId hex, integrated time, tlog count, sct count, cert OIDC issuer, cert workflow repository, cert BuildSignerURI). CLI binary (src/tinfoil/conformance/{__init__,cli}.py): * tinfoil-conformance console_script — implements the capabilities / verify-sigstore subcommands and the exit-code contract (0 / 10 / 20 / 30 / 1) the harness expects. * capabilities honestly declares the known limitations of the sigstore PyPI package: - accepts_multi_tlog_entries: False (lib hardcodes exactly-1) - oidc_issuer_v2_preferred: False (lib reads V1 before V2) - scts_count_distinguish_missing_vs_duplicate: False (lib raises the same "Expected one certificate timestamp" error for missing and duplicate SCTs) - legacy_bundle_format_supported: False (sigstore-python Bundle.from_json validates against v0.3 layout) * Error classifier maps both our own policy-driven prefix codes and sigstore-python's natural English error phrasings to the SPEC- anchored rejection-code taxonomy. CI (.github/workflows/tinfoil-conformance.yml): Self-contained workflow matching the patterns in tinfoil-rs and tinfoil-js: uv sync to build the SDK, checkout the conformance suite, install harness via pip, run vectors, upload results, append summary. Verification: - 286/286 existing pytest unit tests pass. - Full conformance suite (45 fixtures) runs against tinfoil-py: 42 pass + 3 capability-gated skips + 0 fails. - All three SDKs now run the same suite simultaneously; 131 of 135 assertions are green, the 4 skips are honestly declared capability gaps in either Rust (legacy bundle format) or Python (multi-tlog, V2 preference, SCT duplicate distinction). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same three flags landing in tinfoil-rs and tinfoil-js, declared
honestly for sigstore-python's behavior:
* rejects_duplicate_sct_log: True — sigstore-python uses the same
"Expected one certificate timestamp" count-check for both
missing-SCT and duplicate-SCT, so any duplicate gets rejected
(though through the same error path that rejects missing — see
scts_count_distinguish_missing_vs_duplicate=False).
* checks_only_subject_0: True — sigstore-python's verify_dsse path
only inspects subject[0].
* in_toto_statement_tolerates_extra_fields: True — sigstore-python's
statement parser uses pydantic models with extra=allow.
Lets the four-SDK suite cleanly gate fixtures 066/073/074 on tinfoil-go
(which declares all three as False because sigstore-go behaves
differently).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cmd_verify_measurement wraps tinfoil.attestation.types.Measurement —
its existing fingerprint() and assert_equal() already implement SPEC §7.2/
§7.3 with the right semantics. The conformance binary adds:
* type/register-count validation against the SPEC §7.1 layout table
(returns MEASUREMENT_TYPE_UNKNOWN / MEASUREMENT_REGISTER_COUNT_INVALID
before reaching the lib)
* lowercase normalization of registers per SPEC §7.3 normative rule
* exception → rejection code classifier:
Rtmr3NotZeroError → MEASUREMENT_RTMR3_NONZERO
MeasurementMismatchError → MEASUREMENT_MISMATCH
FormatMismatchError → MEASUREMENT_TYPE_COMBINATION_UNSUPPORTED
Capabilities:
- stages_supported += "verify-measurement"
- measurement.compare_multiplatform_to_tdx_supported = true
17 of 17 measurement fixtures pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cmd_verify_hardware_measurements wraps tinfoil.attestation.verify_tdx_hardware,
which already implements SPEC §6.3 step 1–4 with the right semantics. The
conformance binary adds:
* SPEC §7.3 lowercase normalization on both sides before calling the lib
* type/count validation at the binary boundary (so the SPEC-anchored
code surfaces as ENCLAVE_MEASUREMENT_TYPE_INVALID /
ENCLAVE_REGISTER_COUNT_INVALID rather than a ValueError from the lib)
* HardwareMeasurementError → HARDWARE_NO_MATCH mapping
Capabilities:
- stages_supported += "verify-hardware-measurements"
11 of 11 hardware-measurement fixtures pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cross-SDK conformance repo moved from lsd-cat/ to tinfoilsh/ on GitHub. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the new attestation_tdx capability bag from tinfoilsh/tinfoil-conformance Phase 1, declared honestly as false: TDX attestation verification through the conformance contract isn't wired up yet (SDK either lacks TDX entirely or needs a custom collateral-injection Getter wrapper). Phase 1.5 lands the wrapper and flips the flag to true. For now, attestation-tdx fixtures skip cleanly on this SDK with reason "stage not in stages_supported". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…se 1.5)
tinfoil-python's native TDX verifier (tinfoil.attestation.verify_tdx) has
clean injection-friendly APIs all along — verify_tdx_quote(quote,
raw_quote) does Intel §4.1.2 steps 1-4 (PCK chain, quote signature, QE
report signature, AK ↔ QE report data binding) with zero network calls.
The "needs Phase 1.5 wrapper" disclaimer I added on the original
capabilities declaration was wrong; the API was already injection-ready
for the structural path.
* cmd_verify_attestation_tdx parses the raw quote via abi_tdx.parse_quote
and calls verify_tdx_quote_crypto for steps 1-4. Body field extraction
+ TDATTRIBUTES bit-decoding mirrors the Go binary 1:1 so the harness
output diff is comparable across SDKs.
* tcb_evaluation_required=true is currently rejected with a
QV_RESULT_TERMINAL_UNSPECIFIED carrying a clear "Phase 1.5 only
structural" message. Phase 3 will wire the full collateral path
via verify_tcb_info_signature + verify_qe_identity_signature
(which already accept injected response bytes + issuer chain
parameters — no API change needed in the lib).
Capabilities flipped to true:
attestation_tdx.supported = true
attestation_tdx.injected_collateral_supported = true
Fixture 300-tdx-v4-happy passes; full suite tally:
tinfoil-py: pass=74 fail=0 skip=3 (was 73 / 4 before)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds substring patterns for tinfoil-python's TDX verifier error phrasings
to map onto SPEC-anchored rejection codes. Cleaner messages than go-tdx-
guest emits (e.g. "Invalid TEE type: 0x0. Expected 0x81 (TDX).") but the
classifier needed updating to recognize them.
Order matters: chain errors mention "signature" but should map to
PCK_CHAIN_INVALID, not QUOTE_SIGNATURE_INVALID. The chain matchers run
before the generic signature pattern.
Recognized patterns:
* "invalid tee type" / "tee type" → WRONG_TEE_TYPE
* "attestation key type" → ATTESTATION_KEY_TYPE_UNSUPPORTED
* "qe vendor" / "unknown qe" → QE_VENDOR_UNKNOWN
* "quote too short" / "minimum size" → QUOTE_TRUNCATED
* "certification data" / "size mismatch" → QUOTE_FORMAT_UNSUPPORTED
* "pck...chain" / "certificate chain" → PCK_CHAIN_INVALID
* "expired" / "not yet valid" → PCK_EXPIRED
After: 13/15 Phase 2A fixtures pass on Python. Two skip:
* 324-pck-leaf-expired — verify_intel_chain calls datetime.now()
unconditionally; gated on verification_time_override="supported"
(declared "system-clock-only").
* 325-pck-fmspc-mismatch — gated on FMSPC policy capability.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…= false Phase 2B introduces collateral-tampering fixtures (326, 327, 340-345) gated on attestation_tdx.tcb_evaluation_supported=true. tinfoil-python's cmd_verify_attestation_tdx still rejects tcb_evaluation_required=true with a "Phase 1.5 only structural" message — the collateral wrapper (verify_tcb_info_signature, verify_qe_identity_signature, TCB level matching) hasn't been wired yet. Declaring false so Phase 2B fixtures skip honestly until that work lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ment Mirrors the Go binary's enforceExtendedPolicy: a pure-Python helper that parses the TD body fields out of the raw quote bytes and compares each against any policy.expected_*_hex pin the fixture sets. Mapping (each enforced only when policy field present): * td_attributes → TD_ATTRIBUTES_MISMATCH (§4.8.2) * xfam → XFAM_MISMATCH (§4.8.1) * mr_signer_seam → MR_SIGNER_SEAM_MISMATCH (§4.8.4) * seam_attributes → SEAM_ATTRIBUTES_MISMATCH (§4.8.3) * mr_seam (allowlist)→ MR_SEAM_NOT_ALLOWED (§4.8.5) * mrtd → MRTD_MISMATCH (§4.10) * mr_config_id → MR_CONFIG_ID_MISMATCH (§4.8.6) * mr_owner → MR_OWNER_MISMATCH (§4.8.6) * mr_owner_config → MR_OWNER_CONFIG_MISMATCH (§4.8.6) * rtmr3 → RTMR3_NONZERO (§4.10/§7.3.6) * report_data → REPORT_DATA_MISMATCH (§8.2) * qe_vendor_id → QE_VENDOR_ID_MISMATCH (§4.8.6) * min_tee_tcb_svn → TEE_TCB_SVN_BELOW_MINIMUM (§4.8.7) Capability flipped to true: attestation_tdx.extended_td_checks_supported = true 13 of 13 Phase 4 fixtures pass on Python. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
You were right — the lib already had the complete collateral evaluation
API (verify_tcb_info_signature, verify_qe_identity_signature,
check_collateral_freshness, validate_certificate_revocation,
validate_tcb_status, validate_tdx_module_identity, validate_qe_identity).
The conformance binary now orchestrates them per SPEC §4.9 step 10 when
policy.tcb_evaluation_required=true, with fixture-injected collateral
bytes (no Intel PCS fetch) and fixture-controlled verification time.
* _evaluate_collateral runs:
1. extract_pck_extensions from PCK leaf
2. parse_tcb_info_response + parse_qe_identity_response
3. parse_pem_chain on injected issuer chains
4. verify_tcb_info_signature + verify_qe_identity_signature
(when issuer chains supplied)
5. Load PCK CRL + Root CRL DER
6. inline freshness using fixture's expiration_check_date
7. validate_certificate_revocation
8. validate_tcb_status
9. validate_tdx_module_identity
10. validate_qe_identity
* _maybe_override_intel_root monkey-patches the embedded Intel SGX
Root CA PEM for the duration of the call, enabling Phase 3
synthetic-chain fixtures.
* _maybe_override_time monkey-patches the module-level datetime in
collateral_tdx + cert_utils so all internal freshness/validity
checks use the fixture's expiration_check_date_unix. The lib has
no public time-injection API; this is the cleanest workaround
until check_collateral_freshness / verify_intel_chain /
validate_certificate_revocation gain a `now` parameter.
* Classifier maps CollateralError messages to SPEC rejection codes
(TCB_REVOKED, TCB_INFO_SIGNATURE_INVALID, TCB_INFO_EXPIRED,
QE_IDENTITY_*, PCK_REVOKED, etc.).
Capability flags flipped:
attestation_tdx.tcb_evaluation_supported = true (was false)
attestation_tdx.accepts_non_terminal_tcb_statuses = true (new)
After: 114/119 attestation-tdx fixtures pass on Python — including the
three Phase 3 non-terminal statuses (360-362) that Go can't accept
because go-tdx-guest's ErrTcbStatus collapses every non-UpToDate
status. Python's validate_tcb_status follows SPEC §4.7.7 properly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors Go's enforce_spec_defaults handling in _enforce_extended_policy:
* TD Attributes DEBUG bit (§4.8.2) — must be 0
* TD Attributes FIXED0 mask (§4.8.2) — only {0, 28, 30, 63} may be set
* XFAM FIXED1 (§4.8.1) — bits 0 + 1 (FP + SSE) must be set
* XFAM FIXED0 (§4.8.1) — only 0x0006DBE7 bits may be set
7 of 8 Phase 4B fixtures pass on Python (401-405, 412-413).
Also flipped verification_time_override from "system-clock-only" to
"supported" since the monkey-patched datetime in cmd_verify_attestation_
tdx propagates through cert_utils.verify_intel_chain to the structural
PCK chain validation too — fixture 324 (pck-leaf-expired) now passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cmd_verify_attestation_sev builds CertificateChain directly with the fixture-supplied VCEK + lib's embedded ARK_CERT/ASK_CERT, bypassing the lib's CertificateChain.from_report which would fetch VCEK from AMD KDS over the network. Fixture-supplied amd_root_ca_pem / ask_pem swap the embedded constants for Phase 4B-SEV synthetic-chain fixtures. Decodes the 1184-byte SEV-SNP v3 report into the cross-SDK body_fields shape (policy bits per AMD APM Vol 3 Table B-3, platform_info bits, current/committed/launch TCB parts, every measurement register). SPEC §3.4 mandatory cross-checks (VCEK HWID ↔ report.chip_id, every SPL extension ↔ report.reported_tcb part) live in _enforce_sev_vcek_cross_ checks since the conformance binary bypasses the lib's validate_report. Unconditional MIGRATE_MA check rejects guest_policy bit 18 set. The lib's verify_attestation / verify_chain print error diagnostics to stdout when verification fails (the lib's contract). The conformance binary's contract is JSON-only on stdout, so the lib's stdout is captured into stderr; the captured message also feeds the error classifier so e.g. "certificate signature failure" lands on VCEK_CHAIN_INVALID rather than the generic fallback. Capabilities: declare verification_time_override=system-clock-only (pyOpenSSL's X509Store.verify_certificate delegates to OpenSSL's clock with no Python-level override hook). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Chains verify-sigstore + verify-attestation-sev + a Measurement.assert_equal cross-stage comparison, parallel to the Go/Rust conformance binaries. Brings tinfoil-python to verify-full parity so the four-SDK matrix has no n/a columns. Refactors cmd_verify_sigstore and cmd_verify_attestation_sev to expose inner functions (_run_verify_sigstore_inner, _run_verify_attestation_ sev_inner) returning either the successful result or a (code, spec_ref, message) rejection triple. Outer cmd_* functions become thin emit wrappers. The inner helpers default missing schema_version to "1" so the verify-full envelope's nested sub-blocks (which omit it — the envelope carries it) work. cmd_verify_full handles SPEC §11.1 standard/bundle mode (sigstore → MultiPlatform → SEV cross-check) and §11.3 pinned-measurement mode. Rejections carry the originating sub-stage so fixtures can pin both code AND stage. TDX path is not wired (Rust + Go are TDX-capable but Python's SEV-focused fixtures already pass the n/a column). Capabilities: + "verify-full" added to stages_supported + flow_modes_supported expanded to ["standard", "pinned"] Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0433927 to
f198856
Compare
EHBP transport is implemented in the SDK (default transport) and cmd_verify_full already accepts the bundle flow mode (the SDK ships a full bundle pipeline), but the conformance binary declared neither. Declare ehbp transport and the bundle flow mode. No fixture gates on transport or the bundle flow, so this is a library-capability declaration matching tinfoil-go and tinfoil-js. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the verify-ehbp-key-binding stage + ehbp.key_binding_supported capability. The handler extracts the attested HPKE key from report_data[32:64] using the SDK's own layout constants (TLS_KEY_FP_SIZE/HPKE_KEY_SIZE) and validates the offered key with the same parser the EHBP transport uses (ehbp.ServerIdentity.from_public_key_hex). A mismatch fails closed with EHBP_KEY_BINDING_MISMATCH. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
2 issues found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/tinfoil/conformance/cli.py">
<violation number="1" location="src/tinfoil/conformance/cli.py:2034">
P2: Missing top-level JSON object validation can crash the CLI on non-object input.</violation>
<violation number="2" location="src/tinfoil/conformance/cli.py:2040">
P2: Hex parsing error handling is incomplete; non-string report_data_hex bypasses the current exception handler.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
|
|
||
| try: | ||
| report_data = bytes.fromhex(inp.get("report_data_hex", "")) | ||
| except ValueError as e: |
There was a problem hiding this comment.
P2: Hex parsing error handling is incomplete; non-string report_data_hex bypasses the current exception handler.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 2040:
<comment>Hex parsing error handling is incomplete; non-string report_data_hex bypasses the current exception handler.</comment>
<file context>
@@ -2003,6 +2010,88 @@ def cmd_verify_full() -> int:
+
+ try:
+ report_data = bytes.fromhex(inp.get("report_data_hex", ""))
+ except ValueError as e:
+ sys.stderr.write(f"report_data_hex not valid hex: {e}\n")
+ return EXIT_BAD_INPUT
</file context>
| except ValueError as e: | |
| except (TypeError, ValueError) as e: |
| except json.JSONDecodeError as e: | ||
| sys.stderr.write(f"input is not valid JSON: {e}\n") | ||
| return EXIT_BAD_INPUT | ||
| if inp.get("schema_version") != "1": |
There was a problem hiding this comment.
P2: Missing top-level JSON object validation can crash the CLI on non-object input.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 2034:
<comment>Missing top-level JSON object validation can crash the CLI on non-object input.</comment>
<file context>
@@ -2003,6 +2010,88 @@ def cmd_verify_full() -> int:
+ except json.JSONDecodeError as e:
+ sys.stderr.write(f"input is not valid JSON: {e}\n")
+ return EXIT_BAD_INPUT
+ if inp.get("schema_version") != "1":
+ sys.stderr.write('input.schema_version != "1"\n')
+ return EXIT_BAD_INPUT
</file context>
Adds execution_mode=public_api to the SEV stage: drives the SDK's real public verifier attestation.verify_sev_attestation_v2 with only the VCEK injected (embedded ARK/ASK, no network) instead of the adapter's manual chain assembly + verify_attestation path. Captures the lib's stdout diagnostics (it prints on failure) to keep stdout JSON-only and reuses _classify_sev_error / _decode_sev_body_fields. Declares attestation_sev.public_api_hooks_supported. Time-override / injected-ARK / policy-pin fixtures stay adapter-only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The execution_mode=public_api SEV handler drove the real verifier but skipped the fixture's §3.7 policy pins (measurement / host_data / report_data / key-digest / TCB-minimum), so policy-mismatch fixtures (400/410/420/430/440/450/451) wrongly ACCEPTED in full flow while the Go public handler and the adapter path correctly rejected them. Apply _enforce_sev_policy after the verifier accepts, matching the Go public handler. Conformance-binary only; no SDK lib changes. Verified: the policy-mismatch SEV fixtures now reject in full flow (MEASUREMENT_MISMATCH, etc.); 366 unit tests still pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Makes execution_mode=public_api actually exercise the SDK's real TDX
verifier for the deep fixtures, not just pre-policy ones. Three pieces,
all conformance-binary only (no lib changes):
* Re-baseline the verifier config (expected_td_attributes/xfam/
tee_tcb_svn/mr_seams + min_tcb_evaluation_data_number=0) to the
synthetic quote's own values, so the lib's production-policy baseline
doesn't reject the synthetic vectors before the targeted check; the
fixture's §4.8 pins are still enforced by _enforce_extended_policy.
* Classifier patterns for the lib's policy/collateral messages reached
in the full path: TD_ATTRIBUTES (debug/reserved/mismatch), XFAM
(required-clear/forbidden-set), QE-report mrsigner/field mismatch,
PCK FMSPC mismatch, root-CRL signature.
* §4.7.7 accepted_qv_results gate (the verifier accepts non-terminal
TCB statuses by default; enforce the fixture's policy against the
matched TCB level — fixes 365 wrongly accepting).
Result: 50/65 TDX fixtures verify correctly in full flow (was effectively
0 past the PCK chain). The remaining 15 (300/325 + the 4xx extended-TD
suite) are blocked by synthetic quote SVN ↔ TCB-info level inconsistency
that the real TCB-level match correctly rejects — needs fixturegen, not
config. No regression: full harness 206/0-fail, 366 unit tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/tinfoil/conformance/cli.py">
<violation number="1" location="src/tinfoil/conformance/cli.py:1340">
P2: Custom agent: **Nuke belt-and-suspenders**
Broad `except Exception: pass` swallows re-parsing errors for data already validated upstream, constituting unnecessary belt-and-suspenders defensive coding.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
| try: | ||
| _tb = parse_tdx_quote(base64.b64decode(inp["quote_b64"])).td_quote_body | ||
| config_kwargs.setdefault("expected_td_attributes", _tb.td_attributes) | ||
| config_kwargs.setdefault("expected_xfam", _tb.xfam) | ||
| config_kwargs.setdefault("expected_minimum_tee_tcb_svn", _tb.tee_tcb_svn) | ||
| config_kwargs.setdefault("accepted_mr_seams", (_tb.mr_seam,)) | ||
| except Exception: | ||
| pass |
There was a problem hiding this comment.
P2: Custom agent: Nuke belt-and-suspenders
Broad except Exception: pass swallows re-parsing errors for data already validated upstream, constituting unnecessary belt-and-suspenders defensive coding.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 1340:
<comment>Broad `except Exception: pass` swallows re-parsing errors for data already validated upstream, constituting unnecessary belt-and-suspenders defensive coding.</comment>
<file context>
@@ -1291,6 +1327,24 @@ def _cmd_verify_attestation_tdx_public(inp: dict[str, Any], policy: dict[str, An
+ # synthetic vectors at the baseline gate before the fixture's targeted
+ # check. Re-baseline to the quote's own values; the fixture's SPEC §4.8
+ # pins are then enforced precisely by _enforce_extended_policy below.
+ try:
+ _tb = parse_tdx_quote(base64.b64decode(inp["quote_b64"])).td_quote_body
+ config_kwargs.setdefault("expected_td_attributes", _tb.td_attributes)
</file context>
| try: | |
| _tb = parse_tdx_quote(base64.b64decode(inp["quote_b64"])).td_quote_body | |
| config_kwargs.setdefault("expected_td_attributes", _tb.td_attributes) | |
| config_kwargs.setdefault("expected_xfam", _tb.xfam) | |
| config_kwargs.setdefault("expected_minimum_tee_tcb_svn", _tb.tee_tcb_svn) | |
| config_kwargs.setdefault("accepted_mr_seams", (_tb.mr_seam,)) | |
| except Exception: | |
| pass | |
| _tb = parse_tdx_quote(base64.b64decode(inp["quote_b64"])).td_quote_body | |
| config_kwargs.setdefault("expected_td_attributes", _tb.td_attributes) | |
| config_kwargs.setdefault("expected_xfam", _tb.xfam) | |
| config_kwargs.setdefault("expected_minimum_tee_tcb_svn", _tb.tee_tcb_svn) | |
| config_kwargs.setdefault("accepted_mr_seams", (_tb.mr_seam,)) |
Follows the other SDKs to implement conformance testing. Build the dedicated CLI and add a CI job.
Summary by cubic
Adds a cross-SDK
tinfoil-conformanceCLI and CI workflow to exercise policy-layer verification across Sigstore, TDX, and SEV-SNP, plus EHBP key binding. The TDX public‑API path now runs the real verifier end‑to‑end with config re‑baseline and accepted‑QV‑results gating.New Features
tinfoil-conformanceCLI:capabilities,verify-sigstore,verify-measurement,verify-hardware-measurements,verify-attestation-tdx,verify-attestation-sev(adapter/public API),verify-full(standard/bundle/pinned; JSON-in/JSON-out), andverify-ehbp-key-binding.verify_sigstore_bundle_with_policywithSigstorePolicy/SigstoreVerification; hermetic trust-root viasigstore.TrustedRoot; emits bundle observables; capability flags align withsigstorebehavior.attestation.verify_sev_attestation_v2(no network) and applies §3.7 policy pins; time override is system-clock-only.verify-full: chains Sigstore → SEV, compares measurements (SPEC §11), supports pinned/bundle flows, and returns a final fingerprint with originating-stage rejections.report_data[32:64]and validates via the SDK’s EHBP parser; rejects with EHBP_KEY_BINDING_MISMATCH.verify-measurement,verify-hardware-measurements,verify-full,verify-ehbp-key-binding;flow_modes_supported=["standard","bundle","pinned"]; TDX/SEV support and extended checks;verification_time_override="supported"(TDX) /"system-clock-only"(SEV);measurement.compare_multiplatform_to_tdx_supported=true;transport_ehbp_supported=true;ehbp.key_binding_supported=true.Refactors
workflow_ref_prefix(SPEC §5.3).verify-full; isolated Python-specific Sigstore hooks undertinfoil.conformance.sigstore.tinfoil-conformancebinary.Written for commit 33b1785. Summary will update on new commits.