Extended T=1 support

Extended T=1 support with TA1=95 and T1_IFSD_WANTED 254
This commit is contained in:
Antiklesys
2026-08-31 15:28:49 +08:00
parent be7f55f72b
commit a47bdebc87
6 changed files with 134 additions and 17 deletions
+33 -3
View File
@@ -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);
}
}
}
+21
View File
@@ -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.
+76 -14
View File
@@ -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 <Lc-hi> <Lc-lo> ... 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
+3
View File
@@ -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;
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
200F13C2834E4096B56EDD0A1A5A59C7D60141818FEAA9F59821E1E1D074296904CDD2BECA6B408ABF21B36BF4DC20342C347F116F76CD957AF5EBD5AA5617E9