Skip to content
Merged
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
74 changes: 56 additions & 18 deletions tools/test_tls_record.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,6 @@

from c64_test_harness import (
Labels,
ViceConfig,
ViceInstanceManager,
read_bytes,
write_bytes,
Expand All@@ -33,6 +32,8 @@
wait_for_text,
)

from _vice_helpers import default_vice_config

# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
Expand DownExpand Up@@ -75,6 +76,32 @@
"tls_seq_increment",
]

# Names the 6502 processor-status register can appear under in a
# harness register dict. VICE's binary monitor calls it "FL"; other
# backends use "P" / "FLAGS" / "SR". The original code only looked for
# "P", so on VICE the lookup never matched and test 4b silently fell
# through to a weaker oracle.
STATUS_REG_NAMES = ("FL", "P", "FLAGS", "SR")


def carry_from_regs(regs):
"""Return the carry flag (0/1) from a harness register dict.

Returns ``None`` when no processor-status register is present. A
caller that cannot read the carry has *not* observed the routine's
accept/reject decision, so ``None`` must be treated as a failed
test, never as a pass: the tag-comparison fallback this replaces
asserted only that the computed tag differed from the record's tag,
which is true of any tampered input whether or not ``aead_decrypt``
rejected it (audit finding F1).
"""
if not regs:
return None
for name in STATUS_REG_NAMES:
if name in regs:
return regs[name] & 0x01
return None


# ---------------------------------------------------------------------------
# Python reference implementations
Expand DownExpand Up@@ -487,27 +514,35 @@ def test_record_decrypt(transport, labels, rng):
regs = jsr(transport, labels["tls_record_decrypt"],
timeout=120.0)

# Expect carry flag set (C=1) indicating AEAD failure
# The carry flag is bit 0 of the status register (P)
if regs and "P" in regs:
carry = regs["P"] & 0x01
if carry:
passed += 1
print(" PASS: decrypt returned C=1 (tag mismatch)")
else:
failed += 1
print(" FAIL: decrypt returned C=0 (should be C=1 "
"for tampered data)")
# The ONLY sound oracle here is the carry flag returned by
# tls_record_decrypt: C=1 means the record was rejected. There is
# deliberately no fallback oracle -- see carry_from_regs() and the
# note above it.
carry = carry_from_regs(regs)
if carry is None:
failed += 1
print(" FAIL: could not read the 6502 status register "
f"(register names seen: {sorted(regs) if regs else 'none'}; "
f"looked for {'/'.join(STATUS_REG_NAMES)}). The tamper "
"rejection could not be evaluated, which is not a pass.")
elif carry:
passed += 1
print(" PASS: decrypt returned C=1 (tag mismatch)")
else:
# If we can't read P, check if tag comparison area differs
failed += 1
print(" FAIL: decrypt returned C=0 (should be C=1 "
"for tampered data)")
# Diagnostic only -- never a pass criterion. Differing tags
# say the tamper was *detectable*, not that decrypt rejected
# the record.
c64_tag = read_bytes(transport, labels["poly1305_tag"], 16)
aead_tag = read_bytes(transport, labels["aead_tag"], 16)
if c64_tag != aead_tag:
passed += 1
print(" PASS: tags differ (tamper detected)")
print(" (computed tag != record tag, so the "
"tamper was detectable but not rejected)")
else:
failed += 1
print(" FAIL: tags match despite tampered ciphertext")
print(" (computed tag == record tag: the tag "
"was never recomputed over the tampered ciphertext)")
except Exception as e:
failed += 1
print(f" FAIL: {e}")
Expand DownExpand Up@@ -765,7 +800,10 @@ def main():
print(f" Labels loaded: {len(REQUIRED_LABELS)} required labels verified")

# Launch VICE
config = ViceConfig(prg_path=PRG_PATH, warp=True, ntsc=True, sound=False)
# default_vice_config() applies the mandatory -reu/-reusize=512 flags;
# see tools/_vice_helpers.py for the rationale.
config = default_vice_config(prg_path=PRG_PATH, warp=True, ntsc=True,
sound=False)
print(f"\n=== Starting VICE ===")

with ViceInstanceManager(config=config) as mgr:
Expand Down