feat(harness): aliro-bench-test --step-up + INSTALL.md install-recovery notes

Adds a PC/SC verification path for Step-Up Milestone 1 so M1 can be
validated against a personalized card without depending on Nucleo /
X-CUBE-ALIRO bring-up. Verdict run on J3R452 04555A4A0B2190 with M1
CAP installed: AUTH1 OK (3.4s), EXCHANGE 0xC9 OK, ENVELOPE 0xC3 OK
with response decrypting under StepUpSKDevice to the spec 0xA0 ack.

- crypto.py: derive_step_up_session_keys (HKDF parity with
  AliroCrypto.deriveStepUpSessionKeys)
- transaction.py: expose step_up_sk on TransactionResult
- step_up.py: verify_step_up_m1 -- SELECT 5502 + GCM-encrypted
  C9/C3 round-trip, IVs per StepUpApplet (0x00*8 || counter
  reader-side; 0x00*7 || 0x01 || counter device-side)
- cli.py: --step-up flag on aliro-bench-test
- tests: stdlib-RFC-5869 cross-check on the new KDF (122/122 green)
- INSTALL.md: fix multi-place PKG AID typo (missing 02 version byte),
  document partial-install recovery, document package-static
  credential store (aliro-personalize success !=> 5501/5502 installed)
This commit is contained in:
michael
2026-06-17 12:55:16 -07:00
parent 9189b41e7f
commit 9081990b0e
6 changed files with 173 additions and 7 deletions

View File

@@ -12,6 +12,7 @@ from pathlib import Path
import click
from aliro_harness.reader.step_up import verify_step_up_m1
from aliro_harness.reader.transaction import TrustBundle, run_aliro_transaction
@@ -38,7 +39,16 @@ from aliro_harness.reader.transaction import TrustBundle, run_aliro_transaction
is_flag=True,
help="List PC/SC readers visible to the host and exit.",
)
def main(trust_dir: Path | None, reader_index: int, list_readers: bool) -> None:
@click.option(
"--step-up",
is_flag=True,
help="After AUTH1, also exercise Step-Up Milestone 1: SELECT ACCE5502, "
"INS=0xC9 EXCHANGE, INS=0xC3 ENVELOPE. Verifies the StepUpApplet decrypts "
"with StepUpSKReader and encrypts the empty-CBOR-map ack with StepUpSKDevice.",
)
def main(
trust_dir: Path | None, reader_index: int, list_readers: bool, step_up: bool
) -> None:
"""Run a single Aliro AUTH0+AUTH1 transaction against a personalized
card via PC/SC. Decrypts the response and verifies the UD signature.
Exits 0 on success, non-zero with a clear error on any failure."""
@@ -82,6 +92,9 @@ def main(trust_dir: Path | None, reader_index: int, list_readers: bool) -> None:
return bytes(data), (sw1 << 8) | sw2
result = run_aliro_transaction(transmit=transmit, bundle=bundle)
step_up_verdict: tuple[bool, str] | None = None
if step_up and result.ok and result.step_up_sk is not None:
step_up_verdict = verify_step_up_m1(transmit, result.step_up_sk)
finally:
connection.disconnect()
@@ -115,6 +128,14 @@ def main(trust_dir: Path | None, reader_index: int, list_readers: bool) -> None:
_echo_tlv_breakdown(result)
_echo_latencies(result)
if step_up_verdict is not None:
ok, msg = step_up_verdict
if ok:
click.echo(f"STEP-UP M1: OK \u2014 {msg}")
else:
click.echo(f"STEP-UP M1: FAIL \u2014 {msg}", err=True)
raise click.exceptions.Exit(1)
def _echo_tlv_breakdown(result) -> None:
cred_pub_len = len(result.credential_pub) if result.credential_pub else 0