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:
59
harness/src/aliro_harness/personalizer/apdus.py
Normal file
59
harness/src/aliro_harness/personalizer/apdus.py
Normal 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
|
||||
Reference in New Issue
Block a user