Files
aliro-project/harness/tests/test_reader_tlv.py
Dangerous Things 782074f6ae Initial snapshot: Aliro applet, harness, Nucleo NFC10A1 reader port
Three components, all bench-validated to varying depths:

- applet/: CSA Aliro v1.0 Java Card applet for J3R180. AUTH0 + AUTH1
  expedited-standard flow end-to-end green via PC/SC bench reader
  (aliro-bench-test). Userland AES-256-GCM and HMAC-SHA-256 layered
  on top of J3R180's primitives because the card lacks both natively.
  P-256 curve params seeded explicitly per J3R180's quirk.

- harness/: Python orchestrator (aliro-trustgen, aliro-personalize,
  aliro-bench-test) for trust-bundle generation, card personalization
  via PersonalizationApplet, and PC/SC AUTH0+AUTH1 transactions. 126
  pytest cases passing.

- reader/STM32CubeExpansion_ALIRO_V1_0_0/: ST X-CUBE-ALIRO V1.0.0
  with our NFC10A1 port (NUCLEO-U545RE-Q + X-NUCLEO-NFC10A1, ST25R200
  shared with NFC09A1). nfc10-only/ project, NFC10A1 BSP shim,
  ALIRO_TRUST_OVERRIDE include into vendor's provisioning.c, and an
  ALIRO_APDU_TRACE wrapper around demoTransceiveBlocking. Boots,
  detects the J3R180, completes SELECT + AUTH0; AUTH1 currently fails
  with RFAL ERR_PROTO (0xB) — under investigation, see
  docs/plans/2026-04-20-nucleo-nfc10a1-port.md and bench-notes/.

Excluded: x-cube-aliro.zip vendor archive, harness/.venv, build dirs,
generated aliro_trust.h (contains private reader scalar), all PEMs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:17:46 -07:00

63 lines
2.2 KiB
Python

from aliro_harness.reader.tlv import find_top_level
def test_find_top_level_returns_value_bytes():
# 86 41 [65B value] 9D 02 [2B value]
blob = bytes([0x86, 0x41]) + b"\xaa" * 65 + bytes([0x9D, 0x02, 0xff, 0xee])
assert find_top_level(blob, 0x86) == b"\xaa" * 65
assert find_top_level(blob, 0x9D) == bytes([0xff, 0xee])
assert find_top_level(blob, 0x42) is None
def test_short_form_length_under_128():
value = b"\xbb" * 100
blob = bytes([0x9E, 100]) + value
assert find_top_level(blob, 0x9E) == value
def test_long_form_0x81_length_128_to_255():
value = b"\xcc" * 200
blob = bytes([0x9E, 0x81, 200]) + value
assert find_top_level(blob, 0x9E) == value
def test_long_form_0x82_length_256_or_more():
value = b"\xdd" * 1000
blob = bytes([0x9E, 0x82, (1000 >> 8) & 0xFF, 1000 & 0xFF]) + value
assert find_top_level(blob, 0x9E) == value
def test_returns_none_when_tag_absent():
blob = bytes([0x86, 0x02, 0x01, 0x02, 0x9D, 0x01, 0x03])
assert find_top_level(blob, 0x42) is None
def test_skips_over_unmatched_tags_to_find_later_match():
# Three TLVs: 0x86, 0x9D, 0x9E. Ask for the third.
tlv1 = bytes([0x86, 0x03, 0x11, 0x22, 0x33])
tlv2 = bytes([0x9D, 0x02, 0x44, 0x55])
tlv3 = bytes([0x9E, 0x04, 0x66, 0x77, 0x88, 0x99])
blob = tlv1 + tlv2 + tlv3
assert find_top_level(blob, 0x9E) == bytes([0x66, 0x77, 0x88, 0x99])
def test_zero_length_value_returns_empty_bytes():
"""Pin the 0-length contract — easy to break with a `if length > 0` micro-opt."""
blob = bytes([0x86, 0x00, 0x9D, 0x02, 0x11, 0x22])
assert find_top_level(blob, 0x86) == b""
assert find_top_level(blob, 0x9D) == bytes([0x11, 0x22])
def test_empty_input_returns_none():
assert find_top_level(b"", 0x9E) is None
def test_skips_long_form_unmatched_to_find_later_match():
"""Make sure the 0x82-length skip path advances correctly when the
matched tag comes AFTER a long-form TLV (the current `skips_over_…`
test only exercises short-form skips)."""
skip_value = b"\x99" * 1000
skip_tlv = bytes([0x86, 0x82, (1000 >> 8) & 0xFF, 1000 & 0xFF]) + skip_value
target = bytes([0x9E, 0x02, 0xAB, 0xCD])
assert find_top_level(skip_tlv + target, 0x9E) == bytes([0xAB, 0xCD])