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>
This commit is contained in:
2026-05-02 10:17:46 -07:00
commit 782074f6ae
8786 changed files with 2902373 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
"""APDU constructors for PersonalizationApplet.
Mirrors the INS table in applet/INSTALL.md. See AliroAids.PROVISIONING for
the AID and PersonalizationApplet.java for the INS handlers.
"""
CLA_PROPRIETARY = 0x80
INS_SET_CRED_PRIV = 0x20
INS_SET_CRED_PUBK = 0x21
INS_SET_READER_PUBK = 0x22
INS_WRITE_ACCESS_DOC = 0x23
INS_FINALIZE_ACCESS_DOC = 0x24
INS_COMMIT = 0x2C
# Provisioning AID — must match AliroAids.PROVISIONING in the applet.
# (CSA RID + ACCE 55 99 01 — DT-internal, namespaced under the CSA RID so
# all three applets fit in one CAP.)
PROVISIONING_AID = bytes.fromhex("A000000909ACCE559901")
CRED_PRIV_LEN = 32
CRED_PUBK_LEN = 64
READER_PUBK_LEN = 64
def select_provisioning_apdu() -> bytes:
"""ISO 7816-4 SELECT by name: 00 A4 04 00 Lc <AID>."""
return bytes([0x00, 0xA4, 0x04, 0x00, len(PROVISIONING_AID)]) + PROVISIONING_AID
def set_credential_priv_apdu(priv: bytes) -> bytes:
if len(priv) != CRED_PRIV_LEN:
raise ValueError(f"credential_PrivK must be {CRED_PRIV_LEN}B, got {len(priv)}")
return _short_apdu(INS_SET_CRED_PRIV, 0, 0, priv)
def set_credential_pubk_apdu(pubk_xy: bytes) -> bytes:
if len(pubk_xy) != CRED_PUBK_LEN:
raise ValueError(f"credential_PubK must be {CRED_PUBK_LEN}B (x||y), got {len(pubk_xy)}")
return _short_apdu(INS_SET_CRED_PUBK, 0, 0, pubk_xy)
def set_reader_pubk_apdu(pubk_xy: bytes) -> bytes:
if len(pubk_xy) != READER_PUBK_LEN:
raise ValueError(f"reader_PubK must be {READER_PUBK_LEN}B (x||y), got {len(pubk_xy)}")
return _short_apdu(INS_SET_READER_PUBK, 0, 0, pubk_xy)
def commit_apdu() -> bytes:
return bytes([CLA_PROPRIETARY, INS_COMMIT, 0x00, 0x00])
def _short_apdu(ins: int, p1: int, p2: int, data: bytes) -> bytes:
"""Short-form APDU: CLA INS P1 P2 Lc data."""
if not data:
return bytes([CLA_PROPRIETARY, ins, p1, p2])
if len(data) > 255:
raise ValueError(f"data too long for short-form APDU: {len(data)}B")
return bytes([CLA_PROPRIETARY, ins, p1, p2, len(data)]) + data