From a47bdebc87bb3695664d65fa9b8bcfbec4b4bc60 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Mon, 31 Aug 2026 15:28:49 +0800 Subject: [PATCH] Extended T=1 support Extended T=1 support with TA1=95 and T1_IFSD_WANTED 254 --- armsrc/i2c.c | 36 +++++++++++- armsrc/i2c.h | 21 +++++++ armsrc/sam_common.c | 90 ++++++++++++++++++++++++----- armsrc/sam_sc.c | 3 + client/resources/sim023.bin | Bin 0 -> 7160 bytes client/resources/sim023.sha512.txt | 1 + 6 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 client/resources/sim023.bin create mode 100644 client/resources/sim023.sha512.txt diff --git a/armsrc/i2c.c b/armsrc/i2c.c index cd57934fa..d9bac2f7e 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -65,6 +65,13 @@ static bool s_proto_announced = false; // keep the T=0 they had before. static uint8_t s_pps_proto_cmd = 0; +#if SAM_SC_FORCE_T1_TA1_95 +// One-shot request used by the SAM secure-channel path. Keep it separate +// from generic SmartCardRaw PPS selection so the performance policy does not +// alter unrelated contact-card commands. +static bool s_sam_t1_profile_requested = false; +#endif + // A negotiated rate lives in two places that reset independently: the module's // UART divisor, which any I2C_Reset_EnterMainProgram() wipes, and the card, // which only an RST pulse clears. Left alone the two drift apart and every @@ -1143,6 +1150,12 @@ uint8_t sc_active_device_cmd(void) { return (s_pps_proto_cmd != 0) ? s_pps_proto_cmd : I2C_DEVICE_CMD_SEND_T0; } +void sc_request_sam_t1_profile(void) { +#if SAM_SC_FORCE_T1_TA1_95 + s_sam_t1_profile_requested = true; +#endif +} + void sc_pps_remember(const uint8_t *atr, uint8_t atr_len, uint8_t proto, uint8_t ta1) { if ((atr_len == 0) || (atr_len > sizeof(s_pps.atr))) { return; @@ -1217,6 +1230,15 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) { s_card_protocols = atr_protocols(card_ptr->atr, card_ptr->atr_len); s_proto_announced = false; +#if SAM_SC_FORCE_T1_TA1_95 + const bool request_sam_t1 = s_sam_t1_profile_requested; + s_sam_t1_profile_requested = false; + if (request_sam_t1) { + // This reset starts a fresh SAM session. Do not restore an older + // cached T=0 PPS entry before the one PPS below selects T=1. + sc_pps_forget(); + } +#endif if (g_dbglevel >= DBG_INFO) { // What the ATR advertises, and which of them the card actually runs // until something negotiates otherwise. Saying only "offers T=0 T=1" @@ -1264,17 +1286,25 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) { // once - a refusal is remembered so every later ATR does not retry it. if (s_pps.reapply && (s_pps.tried == false)) { + uint8_t want_proto = atr_first_proto(card_ptr->atr, card_ptr->atr_len); uint8_t want = sc_pps_best_ta1(card_ptr->atr, card_ptr->atr_len); +#if SAM_SC_FORCE_T1_TA1_95 + if (request_sam_t1 && (s_card_protocols & SC_PROTO_T1)) { + want_proto = 1; + want = SAM_SC_T1_TA1; + } +#endif + memcpy(s_pps.atr, card_ptr->atr, card_ptr->atr_len); s_pps.atr_len = card_ptr->atr_len; s_pps.tried = true; - if (want && sc_pps(atr_first_proto(card_ptr->atr, card_ptr->atr_len), want)) { + if (want && sc_pps(want_proto, want)) { s_pps.ta1 = want; - s_pps.proto = atr_first_proto(card_ptr->atr, card_ptr->atr_len); + s_pps.proto = want_proto; if (g_dbglevel >= DBG_INFO) { - Dbprintf("SC: negotiated TA1 %02X", want); + Dbprintf("SC: negotiated T=%u TA1 %02X", want_proto, want); } } } diff --git a/armsrc/i2c.h b/armsrc/i2c.h index c40f94653..828f95440 100644 --- a/armsrc/i2c.h +++ b/armsrc/i2c.h @@ -34,6 +34,15 @@ // LRC/CRC - the same way SEND_T0 handles the T=0 procedure bytes. #define I2C_DEVICE_CMD_SEND_T1 0x08 #define I2C_DEVICE_CMD_PPS 0x09 +// SIM module firmware v4.65 and up. A compatibility alias for T=0 in the +// current SIM_C build. Grace response assembly remains PM3-side. +#define I2C_DEVICE_CMD_SEND_T0_AUTORESP 0x0A + +// Disabled: live testing showed that opcode 0x0A itself is not reliable on the +// PM3<->SIM I2C path, even when the SIM handler is an exact SEND_T0 pass-through. +// Keep T=0 traffic on the established 0x07 transport until that low-level issue +// is understood. +#define SAM_T0_AUTORESP 0 // SIM module firmware versions this build knows about. // @@ -46,6 +55,13 @@ #define SIM_MODULE_VERS_T1_HI 4 #define SIM_MODULE_VERS_T1_LO 51 +// SAM secure-channel transport policy for the performance build. Artemis +// offers T=0 first in its ATR; request its advertised T=1 service explicitly +// and use the validated Fi=512/Di=16 rate. This is protocol selection only: +// it does not enable APDU dumps or other bring-up diagnostics. +#define SAM_SC_FORCE_T1_TA1_95 1 +#define SAM_SC_T1_TA1 0x95 + // The SIM module v4 supports up to 384 bytes for the length. #define ISO7816_MAX_FRAME 270 @@ -117,6 +133,11 @@ uint8_t sc_raw_device_cmd(smartcard_command_t flags); // otherwise. uint8_t sc_active_device_cmd(void); +// Request the configured T=1 profile for the next SAM-only GetATR(). The +// request is consumed once, so unrelated SmartCardRaw traffic still follows +// its own ATR/PPS policy. +void sc_request_sam_t1_profile(void); + // Log one smartcard frame, timestamped from the tick counter. Start is where // the previous frame ended, so a Tag frame's span is how long the card took to // answer and a Rdr frame's is how long the host took to ask. diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c index 93804dd27..309ccb655 100644 --- a/armsrc/sam_common.c +++ b/armsrc/sam_common.c @@ -204,7 +204,19 @@ int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen) // Whatever protocol GetATR()/PPS left the card on, rather than an assumed // T=0. Resolved once per exchange so the GET RESPONSE round below cannot // end up on a different protocol than the command it belongs to. - const uint8_t dev_cmd = sc_active_device_cmd(); + const uint8_t active_cmd = sc_active_device_cmd(); + const bool t1 = (active_cmd == I2C_DEVICE_CMD_SEND_T1); + // Use the v4.65+ compatibility T=0 opcode when available. Grace responses + // still assemble their 61xx/9Fxx continuations below on the PM3: they may + // carry material response data before the continuation status. T=1 already + // returns its whole APDU response through the module's block layer. +#if SAM_T0_AUTORESP + const uint8_t dev_cmd = (active_cmd == I2C_DEVICE_CMD_SEND_T0) + ? I2C_DEVICE_CMD_SEND_T0_AUTORESP + : active_cmd; +#else + const uint8_t dev_cmd = active_cmd; +#endif bool res = I2C_BufferWrite(data, n, dev_cmd, I2C_DEVICE_ADDRESS_MAIN); if (res == false) { @@ -261,10 +273,21 @@ int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen) *resplen = 0; } - uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, more_len}; - sc_log_trace(cmd_getresp, sizeof(cmd_getresp), true); + // Grace T=1 exchanges use extended APDUs. The normal short T=0 GET + // RESPONSE is invalid on that path, so use an extended Le when a T=1 + // response explicitly asks for more data. + uint8_t cmd_getresp_t0[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, more_len}; + uint16_t want = more_len ? more_len : 256; + uint8_t cmd_getresp_t1[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, + 0x00, (uint8_t)(want >> 8), (uint8_t)want}; + const uint8_t *cmd_getresp = t1 ? cmd_getresp_t1 : cmd_getresp_t0; + const uint16_t cmd_getresp_len = t1 ? sizeof(cmd_getresp_t1) : sizeof(cmd_getresp_t0); + sc_log_trace(cmd_getresp, cmd_getresp_len, true); - res = I2C_BufferWrite(cmd_getresp, sizeof(cmd_getresp), dev_cmd, I2C_DEVICE_ADDRESS_MAIN); + // Keep response assembly at the PM3, and use the ordinary active protocol + // opcode for the continuation rather than recursively selecting the + // compatibility alias. + res = I2C_BufferWrite(cmd_getresp, cmd_getresp_len, active_cmd, I2C_DEVICE_ADDRESS_MAIN); if (res == false) { DbpString("failed to send to SIM CARD 2"); goto out; @@ -341,29 +364,52 @@ int sam_send_payload_ex( int res = PM3_SUCCESS; uint8_t *buf = response; + const uint16_t inner_len = (uint16_t)(SAM_TX_ASN1_PREFIX_LENGTH + *payload_len); + const bool t1 = (sc_active_device_cmd() == I2C_DEVICE_CMD_SEND_T1); + uint16_t payload_offset = SAM_TX_APDU_PREFIX_LENGTH; + + if ((uint32_t)inner_len + (t1 ? 9u : 5u) > ISO7816_MAX_FRAME) { + return PM3_EINVARG; + } + if (!t1 && inner_len > 0xff) { + return PM3_EINVARG; + } buf[0] = 0xA0; // CLA buf[1] = 0xDA; // INS (PUT DATA) buf[2] = 0x02; // P1 (TLV format?) buf[3] = 0x63; // P2 - buf[4] = SAM_TX_ASN1_PREFIX_LENGTH + (uint8_t) * payload_len; // LEN + if (t1) { + // The Artemis T=1 service accepts Grace in extended APDU form. This + // matches the working ACR39U exchange: 00 ... 0000. + buf[4] = 0x00; + buf[5] = (uint8_t)(inner_len >> 8); + buf[6] = (uint8_t)inner_len; + payload_offset = 7; + } else { + buf[4] = (uint8_t)inner_len; + } // Grace routing header: FROM, TO, REPLY-TO, 0x00, 0x00, scFlag - buf[5] = addr_src; - buf[6] = addr_dest; - buf[7] = addr_reply; + buf[payload_offset] = addr_src; + buf[payload_offset + 1] = addr_dest; + buf[payload_offset + 2] = addr_reply; - buf[8] = 0x00; - buf[9] = 0x00; - buf[10] = scFlag; + buf[payload_offset + 3] = 0x00; + buf[payload_offset + 4] = 0x00; + buf[payload_offset + 5] = scFlag; memcpy( - &buf[11], + &buf[payload_offset + SAM_TX_ASN1_PREFIX_LENGTH], payload, *payload_len ); - uint16_t length = SAM_TX_ASN1_PREFIX_LENGTH + SAM_TX_APDU_PREFIX_LENGTH + (uint8_t) * payload_len; + uint16_t length = (uint16_t)(payload_offset + inner_len); + if (t1) { + buf[length++] = 0x00; // extended Le = 65536 (maximum response) + buf[length++] = 0x00; + } sc_log_trace(buf, length, true); if (g_dbglevel >= DBG_INFO) { @@ -413,7 +459,7 @@ int sam_get_version(bool info) { }; uint16_t payload_len = sizeof(payload); - sam_send_payload( + int exchange = sam_send_payload( 0x44, 0x0a, 0x44, payload, &payload_len, @@ -421,6 +467,22 @@ int sam_get_version(bool info) { &response_len ); + if (exchange != PM3_SUCCESS) { + res = exchange; + goto out; + } + + // The Artemis T=1 endpoint accepts the extended GetVersion warmup with a + // bare 9000 (unlike the T=0 endpoint, it does not return the version TLV). + // It is only a link-settling ping here, so a successful status is enough; + // the following InitAuth exchange performs the actual authentication. + if ((sc_active_device_cmd() == I2C_DEVICE_CMD_SEND_T1) && + (response_len >= 2) && + (response[response_len - 2] == 0x90) && + (response[response_len - 1] == 0x00)) { + goto out; + } + // resp: // c1 64 00 00 00 // bd 11 <- SAM response diff --git a/armsrc/sam_sc.c b/armsrc/sam_sc.c index d73cea345..5ea4f22ab 100644 --- a/armsrc/sam_sc.c +++ b/armsrc/sam_sc.c @@ -522,6 +522,9 @@ void sam_sc_handler(const PacketCommandNG *c) { s_sam_sc_session_active = false; I2C_Reset_EnterMainProgram(); StartTicks(); +#if SAM_SC_FORCE_T1_TA1_95 + sc_request_sam_t1_profile(); +#endif smart_card_atr_t card; if (GetATR(&card, false) == false) { res = PM3_ECARDEXCHANGE; diff --git a/client/resources/sim023.bin b/client/resources/sim023.bin new file mode 100644 index 0000000000000000000000000000000000000000..a49746fdfde3465ab1c4404d541f29604f20d1a2 GIT binary patch literal 7160 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 I0FFE*0OW}aegFUf literal 0 HcmV?d00001 diff --git a/client/resources/sim023.sha512.txt b/client/resources/sim023.sha512.txt new file mode 100644 index 000000000..09451cf3f --- /dev/null +++ b/client/resources/sim023.sha512.txt @@ -0,0 +1 @@ +200F13C2834E4096B56EDD0A1A5A59C7D60141818FEAA9F59821E1E1D074296904CDD2BECA6B408ABF21B36BF4DC20342C347F116F76CD957AF5EBD5AA5617E9 \ No newline at end of file