From ebefc4e358721ee7bf5ad0f0d3bf0788492440a0 Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 11 Jun 2026 11:01:57 -0700 Subject: [PATCH] refactor(applet): retire AliroApplet INS_EXCHANGE stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stub was added earlier this session as an X-CUBE-ALIRO compat shim back when we (incorrectly) believed the vendor firmware ignored the §10.2 step-up AID SELECT requirement and routed EXCHANGE directly to the Expedited AID (ACCE5501). Today's Path X work proved the vendor firmware actually DOES the §10.2 SELECT correctly once the upstream crypto interop is right. With M1B.1 / M1C.1 now landing the real EXCHANGE and ENVELOPE handlers on StepUpApplet (ACCE5502), the AliroApplet stub is strictly wrong: it would let stale expedited_device_counter state confuse the vendor library if the reader ever hit it. Spec-conformant readers route EXCHANGE to ACCE5502 after the step-up SELECT and never touch ACCE5501 with INS=0xC9. So AliroApplet returns SW_INS_NOT_SUPPORTED (0x6D00) for INS=0xC9 like any other unknown INS, and we ship one less compat shim. Co-Authored-By: Claude Opus 4.7 --- .../dangerousthings/aliro/AliroApplet.java | 29 ------------------- .../aliro/AliroAppletTest.java | 15 ++++++++++ 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/applet/src/main/java/com/dangerousthings/aliro/AliroApplet.java b/applet/src/main/java/com/dangerousthings/aliro/AliroApplet.java index 6935c45..988e6e0 100644 --- a/applet/src/main/java/com/dangerousthings/aliro/AliroApplet.java +++ b/applet/src/main/java/com/dangerousthings/aliro/AliroApplet.java @@ -33,7 +33,6 @@ public class AliroApplet extends Applet { private static final byte CLA_EXPEDITED = (byte) 0x80; private static final byte INS_AUTH0 = (byte) 0x80; private static final byte INS_AUTH1 = (byte) 0x81; - private static final byte INS_EXCHANGE = (byte) 0xC9; // §8.3.3.5 / Table 8-14 // Diagnostic INSes (CLA=0x80) for profiling AUTH1 sub-operations. // DEV / PERFORMANCE-DEBUG ONLY. Set DIAGNOSTICS_ENABLED = false for any @@ -521,34 +520,6 @@ public class AliroApplet extends Applet { case INS_AUTH1: processAuth1(apdu); return; - case INS_EXCHANGE: - // EXCHANGE stub for the Reader Status sub-event variant of - // §8.3.3.5 -- the post-AUTH1 "transaction reporting" handshake - // X-CUBE-ALIRO always sends regardless of signaling_bitmap. - // We don't implement the Step-up phase (no CBOR / mdoc / - // ENVELOPE / GET RESPONSE), so we can't decrypt or honour the - // Reader Status payload. But returning 6D00 here makes the - // vendor firmware mark DOOR OPERATION FAILED even though - // AUTH1 succeeded (§10.2 line 5660 says the access decision - // SHOULD be independent of post-AUTH1 reporting -- vendor - // ignores that). So we ACK with 9000 + empty payload to let - // the demo terminate cleanly. Discards the inbound encrypted - // Reader Status bytes without parsing them; they're a - // status report the reader wanted to give us, not an access - // gate we need to satisfy. - // - // TODO (Step-Up impl): once StepUpApplet handles ENVELOPE / - // GET RESPONSE properly and signaling_bitmap honestly - // reflects capability, this stub becomes either dead code - // (spec-conformant readers route EXCHANGE to ACCE5502 after - // the step-up AID SELECT) or replaceable with a proper - // encrypted "Reader Status response sub-event" reply (for - // readers like X-CUBE-ALIRO that violate the §10.2 SHALL - // and bypass the step-up SELECT). See - // docs/plans/2026-06-07-step-up-implementation.md. - apdu.setIncomingAndReceive(); - apdu.setOutgoingAndSend((short) 0, (short) 0); - return; case INS_DIAG_HMAC: case INS_DIAG_ECDH: case INS_DIAG_ECDSA_SIGN: diff --git a/applet/src/test/java/com/dangerousthings/aliro/AliroAppletTest.java b/applet/src/test/java/com/dangerousthings/aliro/AliroAppletTest.java index 543b802..3ee363d 100644 --- a/applet/src/test/java/com/dangerousthings/aliro/AliroAppletTest.java +++ b/applet/src/test/java/com/dangerousthings/aliro/AliroAppletTest.java @@ -92,4 +92,19 @@ class AliroAppletTest { assertEquals(0x01, versions[0] & 0xFF, "expected first protocol version high byte 0x01"); assertEquals(0x00, versions[1] & 0xFF, "expected first protocol version low byte 0x00"); } + + @Test + void auth1ExchangeInsRejectedNowThatStepUpAppletOwnsIt() { + // Once M1B.1 / M1C.1 land StepUpApplet (ACCE5502) as the proper owner + // of INS_EXCHANGE (0xC9), AliroApplet must NOT also answer 0xC9 — a + // spec-conformant reader routes EXCHANGE to ACCE5502 after the §10.2 + // step-up AID SELECT. AliroApplet receiving 0xC9 is a reader bug or + // a stale flow, and must be rejected with SW_INS_NOT_SUPPORTED so it + // can never accidentally interact with expedited session state. + selectExpedited(); + CommandAPDU exchange = new CommandAPDU(0x80, 0xC9, 0x00, 0x00); + ResponseAPDU resp = sim.transmitCommand(exchange); + assertEquals(0x6D00, resp.getSW(), + "AliroApplet must reject INS_EXCHANGE (0xC9) — StepUpApplet (ACCE5502) owns it now"); + } }