mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-09-09 16:05:59 +00:00
Extended T=1 support
Extended T=1 support with TA1=95 and T1_IFSD_WANTED 254
This commit is contained in:
+33
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
@@ -0,0 +1 @@
|
||||
200F13C2834E4096B56EDD0A1A5A59C7D60141818FEAA9F59821E1E1D074296904CDD2BECA6B408ABF21B36BF4DC20342C347F116F76CD957AF5EBD5AA5617E9
|
||||
Reference in New Issue
Block a user