gave 14b commands some serious love and overhaul. package handling for APDU and different selects is improved. return codes now consequent

This commit is contained in:
iceman1001 2024-01-08 21:17:42 +01:00
commit 82aa6ac08c
11 changed files with 350 additions and 337 deletions

View file

@ -1429,7 +1429,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint8_t blockno; uint8_t blockno;
} PACKED; } PACKED;
struct p *payload = (struct p *) packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
ReadSTBlock(payload->blockno); read_14b_st_block(payload->blockno);
break; break;
} }
case CMD_HF_ISO14443B_SNIFF: { case CMD_HF_ISO14443B_SNIFF: {

View file

@ -155,7 +155,7 @@ static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t re
#endif #endif
case 'b': case 'b':
#ifdef WITH_ISO14443b #ifdef WITH_ISO14443b
return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL); return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL, NULL);
#else #else
(void) apdu; (void) apdu;
(void) length; (void) length;

View file

@ -183,6 +183,10 @@
# define ISO14B_TR2 HF14_ETU_TO_SSP(14) # define ISO14B_TR2 HF14_ETU_TO_SSP(14)
#endif #endif
#ifndef ISO14B_BLOCK_SIZE
# define ISO14B_BLOCK_SIZE 4
#endif
// 4sample // 4sample
#define SEND4STUFFBIT(x) tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x); #define SEND4STUFFBIT(x) tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);
@ -472,7 +476,9 @@ static void iso14b_set_maxframesize(uint16_t size) {
} }
Uart.byteCntMax = size; Uart.byteCntMax = size;
if (g_dbglevel >= DBG_DEBUG) Dbprintf("ISO14443B Max frame size set to %d bytes", Uart.byteCntMax); if (g_dbglevel >= DBG_DEBUG) {
Dbprintf("ISO14443B Max frame size set to %d bytes", Uart.byteCntMax);
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -662,7 +668,7 @@ static RAMFUNC int Handle14443bSampleFromReader(uint8_t bit) {
// Assume that we're called with the SSC (to the FPGA) and ADC path set // Assume that we're called with the SSC (to the FPGA) and ADC path set
// correctly. // correctly.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) { static bool GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) {
// Set FPGA mode to "simulated ISO 14443B tag", no modulation (listen // Set FPGA mode to "simulated ISO 14443B tag", no modulation (listen
// only, since we are receiving, not transmitting). // only, since we are receiving, not transmitting).
// Signal field is off with the appropriate LED // Signal field is off with the appropriate LED
@ -764,7 +770,7 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
tosend_t *ts = get_tosend(); tosend_t *ts = get_tosend();
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
// prepare "ATQB" tag answer (encoded): // prepare "ATQB" tag answer (encoded):
CodeIso14443bAsTag(respATQB, sizeof(respATQB)); CodeIso14443bAsTag(respATQB, sizeof(respATQB));
@ -797,10 +803,13 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
LED_A_ON(); LED_A_ON();
} }
} }
if (cardSTATE == SIM_NOFIELD) continue;
if (cardSTATE == SIM_NOFIELD) {
continue;
}
// Get reader command // Get reader command
if (!GetIso14443bCommandFromReader(receivedCmd, &len)) { if (GetIso14443bCommandFromReader(receivedCmd, &len) == false) {
Dbprintf("button pressed, received %d commands", cmdsReceived); Dbprintf("button pressed, received %d commands", cmdsReceived);
break; break;
} }
@ -810,9 +819,11 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
// WUP in HALTED state // WUP in HALTED state
if (len == 5) { if (len == 5) {
if ((receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8) == 0x8 && cardSTATE == SIM_HALTED) || if ((receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8) == 0x8 && cardSTATE == SIM_HALTED) ||
receivedCmd[0] == ISO14443B_REQB) { receivedCmd[0] == ISO14443B_REQB) {
LogTrace(receivedCmd, len, 0, 0, NULL, true); LogTrace(receivedCmd, len, 0, 0, NULL, true);
cardSTATE = SIM_SELECTING; cardSTATE = SIM_SELECTING;
} }
} }
@ -861,13 +872,14 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
// - SLOT MARKER // - SLOT MARKER
// - ISO7816 // - ISO7816
// - emulate with a memory dump // - emulate with a memory dump
if (g_dbglevel >= DBG_DEBUG) if (g_dbglevel >= DBG_DEBUG) {
Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived); Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived);
}
// CRC Check // CRC Check, if long enough
if (len >= 3) { // if crc exists if (len >= 3) {
if (!check_crc(CRC_14443_B, receivedCmd, len)) { if (check_crc(CRC_14443_B, receivedCmd, len) == false) {
if (g_dbglevel >= DBG_DEBUG) { if (g_dbglevel >= DBG_DEBUG) {
DbpString("CRC fail"); DbpString("CRC fail");
} }
@ -1000,7 +1012,7 @@ void Simulate_iso14443b_srx_tag(uint8_t *uid) {
if (cardSTATE == SIM_NOFIELD) continue; if (cardSTATE == SIM_NOFIELD) continue;
// Get reader command // Get reader command
if (!GetIso14443bCommandFromReader(receivedCmd, &len)) { if (GetIso14443bCommandFromReader(receivedCmd, &len) == false) {
Dbprintf("button pressed, received %d commands", cmdsReceived); Dbprintf("button pressed, received %d commands", cmdsReceived);
break; break;
} }
@ -1067,7 +1079,7 @@ void Simulate_iso14443b_srx_tag(uint8_t *uid) {
// CRC Check // CRC Check
if (len >= 3) { // if crc exists if (len >= 3) { // if crc exists
if (!check_crc(CRC_14443_B, receivedCmd, len)) { if (check_crc(CRC_14443_B, receivedCmd, len) == false) {
if (g_dbglevel >= DBG_DEBUG) { if (g_dbglevel >= DBG_DEBUG) {
DbpString("CRC fail"); DbpString("CRC fail");
} }
@ -1314,7 +1326,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) { if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) {
if (g_dbglevel > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting"); if (g_dbglevel > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting");
return -1; return PM3_EMALLOC;
} }
uint32_t dma_start_time = 0; uint32_t dma_start_time = 0;
@ -1328,8 +1340,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
for (;;) { for (;;) {
volatile uint16_t behindBy = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); volatile uint16_t behindBy = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1);
if (behindBy == 0) if (behindBy == 0) {
continue; continue;
}
samples++; samples++;
@ -1375,13 +1388,13 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
*eof_time = GetCountSspClkDelta(dma_start_time) - DELAY_TAG_TO_ARM; // end of EOF *eof_time = GetCountSspClkDelta(dma_start_time) - DELAY_TAG_TO_ARM; // end of EOF
if (Demod.len > Demod.max_len) { if (Demod.len > Demod.max_len) {
ret = -2; // overflow ret = PM3_EOVFLOW; // overflow
} }
break; break;
} }
if (((GetCountSspClkDelta(dma_start_time)) > timeout) && Demod.state < DEMOD_PHASE_REF_TRAINING) { if (((GetCountSspClkDelta(dma_start_time)) > timeout) && Demod.state < DEMOD_PHASE_REF_TRAINING) {
ret = -1; ret = PM3_ETIMEOUT;
break; break;
} }
} }
@ -1399,8 +1412,6 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
+ (10)); // time for EOF transfer + (10)); // time for EOF transfer
LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false); LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false);
} }
return Demod.len; return Demod.len;
} }
@ -1568,7 +1579,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
/* Sends an APDU to the tag /* Sends an APDU to the tag
* TODO: check CRC and preamble * TODO: check CRC and preamble
*/ */
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res) { int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int *reponselen) {
uint8_t real_cmd[msg_len + 4]; uint8_t real_cmd[msg_len + 4];
@ -1598,10 +1609,9 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
// Activation frame waiting time // Activation frame waiting time
// 65536/fc == 4833 µS // 65536/fc == 4833 µS
// SSP_CLK = 4833 µS * 3.39 = 16384 // SSP_CLK = 4833 µS * 3.39 = 16384
int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time); int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time);
FpgaDisableTracing(); FpgaDisableTracing();
@ -1609,7 +1619,8 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
uint8_t *data_bytes = (uint8_t *) rxdata; uint8_t *data_bytes = (uint8_t *) rxdata;
if (len <= 0) { if (len <= 0) {
return 0; //DATA LINK ERROR // DATA LINK ERROR
return PM3_ECARDEXCHANGE;
} else { } else {
// S-Block WTX // S-Block WTX
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) { while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
@ -1648,20 +1659,23 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
// if we received an I- or R(ACK)-Block with a block number equal to the // if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number // current block number, toggle the current block number
if (len >= 3 // PCB + CRC = 3 bytes
&& ((data_bytes[0] & 0xC0) == 0 // I-Block if ((len >= 3) && // PCB + CRC = 3 bytes
|| (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 (((data_bytes[0] & 0xC0) == 0) || (data_bytes[0] & 0xD0) == 0x80) && // I-Block OR R-Block with ACK bit set to 0
&& (data_bytes[0] & 0x01) == iso14b_pcb_blocknum) { // equal block numbers ((data_bytes[0] & 0x01) == iso14b_pcb_blocknum)) { // equal block numbers
iso14b_pcb_blocknum ^= 1; iso14b_pcb_blocknum ^= 1;
} }
// if we received I-block with chaining we need to send ACK and receive another block of data // if we received I-block with chaining we need to send ACK and receive another block of data
if (res) if (res) {
*res = data_bytes[0]; *res = data_bytes[0];
}
// crc check // crc check
if (len >= 3 && !check_crc(CRC_14443_B, data_bytes, len)) { if (len >= 3 && (check_crc(CRC_14443_B, data_bytes, len) == false)) {
return -1; return PM3_ECRC;
} }
} }
@ -1674,7 +1688,10 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
} }
} }
return len; if (reponselen) {
*reponselen = len;
}
return PM3_SUCCESS;
} }
/** /**
@ -1686,10 +1703,11 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
uint8_t cmdMSBUID[] = {ASK_SELECT, 0xFF, 0xFF, 0x00, 0x00}; uint8_t cmdMSBUID[] = {ASK_SELECT, 0xFF, 0xFF, 0x00, 0x00};
uint8_t cmdLSBUID[] = {0xC4, 0x00, 0x00}; uint8_t cmdLSBUID[] = {0xC4, 0x00, 0x00};
// iceman: todo static crc
AddCrc14B(cmdMSBUID, 3); AddCrc14B(cmdMSBUID, 3);
AddCrc14B(cmdLSBUID, 1); AddCrc14B(cmdLSBUID, 1);
uint8_t r[8]; uint8_t r[8] = { 0x00 };
uint32_t start_time = 0; uint32_t start_time = 0;
uint32_t eof_time = 0; uint32_t eof_time = 0;
@ -1700,10 +1718,10 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
FpgaDisableTracing(); FpgaDisableTracing();
if (retlen != 4) { if (retlen != 4) {
return -1; return PM3_ELENGTH;
} }
if (check_crc(CRC_14443_B, r, retlen) == false) { if (check_crc(CRC_14443_B, r, retlen) == false) {
return -2; return PM3_ECRC;
} }
if (card) { if (card) {
@ -1720,10 +1738,10 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
FpgaDisableTracing(); FpgaDisableTracing();
if (retlen != 4) { if (retlen != 4) {
return -1; return PM3_ELENGTH;
} }
if (check_crc(CRC_14443_B, r, retlen) == false) { if (check_crc(CRC_14443_B, r, retlen) == false) {
return -2; return PM3_ECRC;
} }
if (card) { if (card) {
@ -1738,17 +1756,17 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
FpgaDisableTracing(); FpgaDisableTracing();
if (retlen != 4) { if (retlen != 4) {
return -1; return PM3_ELENGTH;
} }
if (check_crc(CRC_14443_B, r, retlen) == false) { if (check_crc(CRC_14443_B, r, retlen) == false) {
return -2; return PM3_ECRC;
} }
if (card) { if (card) {
memcpy(card->uid + 2, r, 2); memcpy(card->uid + 2, r, 2);
} }
return 0; return PM3_SUCCESS;
} }
/** /**
* SRx Initialise. * SRx Initialise.
@ -1756,9 +1774,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
static int iso14443b_select_srx_card(iso14b_card_select_t *card) { static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
// INITIATE command: wake up the tag using the INITIATE // INITIATE command: wake up the tag using the INITIATE
static const uint8_t init_srx[] = { ISO14443B_INITIATE, 0x00, 0x97, 0x5b }; static const uint8_t init_srx[] = { ISO14443B_INITIATE, 0x00, 0x97, 0x5b };
uint8_t r_init[3] = {0x0}; uint8_t r_init[3] = { 0x00 };
uint8_t r_select[3] = {0x0}; uint8_t r_select[3] = { 0x00 };
uint8_t r_papid[10] = {0x0}; uint8_t r_papid[10] = { 0x00 };
uint32_t start_time = 0; uint32_t start_time = 0;
uint32_t eof_time = 0; uint32_t eof_time = 0;
@ -1769,7 +1787,7 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
FpgaDisableTracing(); FpgaDisableTracing();
if (retlen <= 0) { if (retlen <= 0) {
return -1; return PM3_ECARDEXCHANGE;
} }
// Randomly generated Chip ID // Randomly generated Chip ID
@ -1791,42 +1809,43 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
FpgaDisableTracing(); FpgaDisableTracing();
if (retlen != 3) { if (retlen != 3) {
return -1; return PM3_ELENGTH;
} }
if (check_crc(CRC_14443_B, r_select, retlen) == false) { if (check_crc(CRC_14443_B, r_select, retlen) == false) {
return -2; return PM3_ECRC;
} }
// Check response from the tag: should be the same UID as the command we just sent: // Check response from the tag: should be the same UID as the command we just sent:
if (select_srx[1] != r_select[0]) { if (select_srx[1] != r_select[0]) {
return -3; return PM3_EWRONGANSWER;
} }
// First get the tag's UID: // First get the tag's UID:
select_srx[0] = ISO14443B_GET_UID; select_srx[0] = ISO14443B_GET_UID;
select_srx[1] = 0xAB;
AddCrc14B(select_srx, 1); select_srx[2] = 0x4E;
start_time = eof_time + ISO14B_TR2; start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time, true); // Only first three bytes for this one CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time, true); // Only first three bytes for this one
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(r_papid, sizeof(r_papid), iso14b_timeout, &eof_time); retlen = Get14443bAnswerFromTag(r_papid, sizeof(r_papid), iso14b_timeout, &eof_time);
FpgaDisableTracing(); FpgaDisableTracing();
if (retlen != 10) { if (retlen != 10) {
return -1; return PM3_ELENGTH;
} }
if (!check_crc(CRC_14443_B, r_papid, retlen)) {
return -2; if (check_crc(CRC_14443_B, r_papid, retlen) == false) {
return PM3_ECRC;
} }
if (card) { if (card) {
card->uidlen = 8; card->uidlen = 8;
memcpy(card->uid, r_papid, 8); memcpy(card->uid, r_papid, 8);
} }
return PM3_SUCCESS;
return 0;
} }
// Xerox tag connect function: wup, anticoll, attrib, password // Xerox tag connect function: wup, anticoll, attrib, password
@ -1837,9 +1856,8 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
// AFI // AFI
static const uint8_t x_wup1[] = { 0x0D, 0x37, 0x21, 0x92, 0xf2 }; static const uint8_t x_wup1[] = { 0x0D, 0x37, 0x21, 0x92, 0xf2 };
static const uint8_t x_wup2[] = { 0x5D, 0x37, 0x21, 0x71, 0x71 }; static const uint8_t x_wup2[] = { 0x5D, 0x37, 0x21, 0x71, 0x71 };
uint8_t slot_mark[1]; uint8_t slot_mark[1] = { 0x00 };
uint8_t x_atqb[24] = { 0x00 }; // ATQB len = 18
uint8_t x_atqb[24] = {0x0}; // ATQB len = 18
uint32_t start_time = 0; uint32_t start_time = 0;
uint32_t eof_time = 0; uint32_t eof_time = 0;
@ -1870,7 +1888,7 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
Dbprintf("unexpected data %d", retlen); Dbprintf("unexpected data %d", retlen);
Dbprintf("crc %s", check_crc(CRC_14443_B, x_atqb, retlen) ? "OK" : "BAD"); Dbprintf("crc %s", check_crc(CRC_14443_B, x_atqb, retlen) ? "OK" : "BAD");
return 1; return PM3_ECARDEXCHANGE;
} }
// tx unframed slot-marker // tx unframed slot-marker
@ -1893,7 +1911,7 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
if (g_dbglevel >= DBG_DEBUG) { if (g_dbglevel >= DBG_DEBUG) {
DbpString("no answer to anticollision"); DbpString("no answer to anticollision");
} }
return 1; return PM3_ESOFT;
} }
} }
@ -1905,16 +1923,16 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
// ATQB too short? // ATQB too short?
if (retlen < 18) { if (retlen < 18) {
return 1; return PM3_ELENGTH;
} }
// VALIDATE CRC // VALIDATE CRC
if (check_crc(CRC_14443_B, x_atqb, 18) == false) { // use fixed len because unstable EOF catch if (check_crc(CRC_14443_B, x_atqb, 18) == false) { // use fixed len because unstable EOF catch
return 3; return PM3_ECRC;
} }
if (x_atqb[0] != 0x50) { if (x_atqb[0] != 0x50) {
return 1; return PM3_EWRONGANSWER;
} }
if (card) { if (card) {
@ -1944,15 +1962,15 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
FpgaDisableTracing(); FpgaDisableTracing();
if (retlen < 3) { if (retlen < 3) {
return 2; return PM3_ELENGTH;
} }
if (check_crc(CRC_14443_B, x_atqb, 3) == false) { if (check_crc(CRC_14443_B, x_atqb, 3) == false) {
return 3; return PM3_ECRC;
} }
if (x_atqb[0] != 0) { if (x_atqb[0] != 0) {
return 2; return PM3_EWRONGANSWER;
} }
// apply PASSWORD command // apply PASSWORD command
@ -1975,18 +1993,18 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time); retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time);
if (retlen < 4) { if (retlen < 4) {
return 4; return PM3_ELENGTH;
} }
if (check_crc(CRC_14443_B, x_atqb, 4) == false) { if (check_crc(CRC_14443_B, x_atqb, 4) == false) {
return 3; return PM3_ECRC;
} }
if (x_atqb[0] != 2 || x_atqb[1] != 0) { if (x_atqb[0] != 2 || x_atqb[1] != 0) {
return 4; return PM3_EWRONGANSWER;
} }
return 0; return PM3_SUCCESS;
} }
/* Perform the ISO 14443 B Card Selection procedure /* Perform the ISO 14443 B Card Selection procedure
@ -2003,10 +2021,9 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xff }; static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xff };
// ATTRIB command (with space for CRC) // ATTRIB command (with space for CRC)
uint8_t attrib[] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}; uint8_t attrib[11] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00};
uint8_t r_pupid[14] = { 0x00 };
uint8_t r_pupid[14] = {0x0}; uint8_t r_attrib[3] = { 0x00 };
uint8_t r_attrib[3] = {0x0};
// first, wake up the tag // first, wake up the tag
uint32_t start_time = 0; uint32_t start_time = 0;
@ -2019,12 +2036,12 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
// ATQB too short? // ATQB too short?
if (retlen < 14) { if (retlen < 14) {
return -1; return PM3_ELENGTH;
} }
// VALIDATE CRC // VALIDATE CRC
if (check_crc(CRC_14443_B, r_pupid, retlen) == false) { if (check_crc(CRC_14443_B, r_pupid, retlen) == false) {
return -2; return PM3_ECRC;
} }
if (card) { if (card) {
@ -2048,12 +2065,12 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
// Answer to ATTRIB too short? // Answer to ATTRIB too short?
if (retlen < 3) { if (retlen < 3) {
return -1; return PM3_ELENGTH;
} }
// VALIDATE CRC // VALIDATE CRC
if (check_crc(CRC_14443_B, r_attrib, retlen) == false) { if (check_crc(CRC_14443_B, r_attrib, retlen) == false) {
return -2; return PM3_ECRC;
} }
if (card) { if (card) {
@ -2079,7 +2096,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
} }
// reset PCB block number // reset PCB block number
iso14b_pcb_blocknum = 0; iso14b_pcb_blocknum = 0;
return 0; return PM3_SUCCESS;
} }
// Set up ISO 14443 Type B communication (similar to iso14443a_setup) // Set up ISO 14443 Type B communication (similar to iso14443a_setup)
@ -2128,8 +2145,9 @@ void iso14443b_setup(void) {
// //
// I tried to be systematic and check every answer of the tag, every CRC, etc... // I tried to be systematic and check every answer of the tag, every CRC, etc...
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static int read_srx_block(uint8_t blocknr, uint8_t *block) { static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) {
// iceman: todo add static CRC
uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00}; uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00};
AddCrc14B(cmd, 2); AddCrc14B(cmd, 2);
@ -2155,7 +2173,7 @@ static int read_srx_block(uint8_t blocknr, uint8_t *block) {
} }
if (block) { if (block) {
memcpy(block, r_block, 4); memcpy(block, r_block, ISO14B_BLOCK_SIZE);
} }
if (g_dbglevel >= DBG_DEBUG) { if (g_dbglevel >= DBG_DEBUG) {
@ -2169,25 +2187,25 @@ static int read_srx_block(uint8_t blocknr, uint8_t *block) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
void ReadSTBlock(uint8_t blocknr) { void read_14b_st_block(uint8_t blocknr) {
iso14443b_setup(); iso14443b_setup();
iso14b_card_select_t card;
int res = iso14443b_select_srx_card(&card); uint8_t *data = BigBuf_calloc(ISO14B_BLOCK_SIZE);
iso14b_card_select_t *card = (iso14b_card_select_t *) BigBuf_calloc(sizeof(iso14b_card_select_t));
int res = iso14443b_select_srx_card(card);
// 0: OK -1 wrong len, -2: attrib fail, -3:crc fail, // 0: OK -1 wrong len, -2: attrib fail, -3:crc fail,
switch (res) { switch (res) {
case -1: case PM3_ELENGTH:
case -3: { case PM3_EWRONGANSWER:
reply_ng(CMD_HF_SRI_READ, PM3_EWRONGANSWER, NULL, 0); case PM3_ECRC: {
goto out; reply_ng(CMD_HF_SRI_READ, res, NULL, 0);
}
case -2: {
reply_ng(CMD_HF_SRI_READ, PM3_ECRC, NULL, 0);
goto out; goto out;
} }
} }
uint8_t *data = BigBuf_malloc(4);
res = read_srx_block(blocknr, data); res = read_14b_srx_block(blocknr, data);
reply_ng(CMD_HF_SRI_READ, res, data, 4); reply_ng(CMD_HF_SRI_READ, res, data, ISO14B_BLOCK_SIZE);
out: out:
BigBuf_free(); BigBuf_free();
@ -2392,9 +2410,6 @@ static void iso14b_set_trigger(bool enable) {
void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) { void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
// receive buffer
uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00};
// turn on trigger (LED_A) // turn on trigger (LED_A)
if ((p->flags & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) { if ((p->flags & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) {
iso14b_set_trigger(true); iso14b_set_trigger(true);
@ -2414,68 +2429,76 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
} }
set_tracing(true); set_tracing(true);
// receive buffer
uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00};
int status = 0; int status = 0;
uint32_t sendlen = sizeof(iso14b_card_select_t); uint32_t sendlen = sizeof(iso14b_card_select_t);
iso14b_card_select_t *card = (iso14b_card_select_t *)buf; iso14b_card_select_t *card = (iso14b_card_select_t *)buf;
if ((p->flags & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { if ((p->flags & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) {
status = iso14443b_select_card(card); status = iso14443b_select_card(card);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&card, sendlen); reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)card, sendlen);
// 0: OK -1: attrib fail, -2:crc fail, if (status != PM3_SUCCESS) goto out;
if (status != 0) goto out;
} }
if ((p->flags & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) { if ((p->flags & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) {
memset(card, 0, sizeof(iso14b_card_select_t));
status = iso14443b_select_srx_card(card); status = iso14443b_select_srx_card(card);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&card, sendlen); reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)card, sendlen);
// 0: OK 2: demod fail, 3:crc fail, if (status != PM3_SUCCESS) goto out;
if (status > 0) goto out;
} }
if ((p->flags & ISO14B_SELECT_XRX) == ISO14B_SELECT_XRX) { if ((p->flags & ISO14B_SELECT_XRX) == ISO14B_SELECT_XRX) {
memset(card, 0, sizeof(iso14b_card_select_t));
status = iso14443b_select_xrx_card(card); status = iso14443b_select_xrx_card(card);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&card, sendlen); reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)card, sendlen);
// 0: OK, 1: select fail, 2: attrib fail, 3: crc fail, 4: password fail // 0: OK, 1: select fail, 2: attrib fail, 3: crc fail, 4: password fail
if (status != 0) goto out; if (status != PM3_SUCCESS) goto out;
} }
if ((p->flags & ISO14B_SELECT_CTS) == ISO14B_SELECT_CTS) { if ((p->flags & ISO14B_SELECT_CTS) == ISO14B_SELECT_CTS) {
iso14b_cts_card_select_t *cts = (iso14b_cts_card_select_t *)buf; iso14b_cts_card_select_t *cts = (iso14b_cts_card_select_t *)buf;
memset(cts, 0, sizeof(iso14b_cts_card_select_t));
sendlen = sizeof(iso14b_cts_card_select_t); sendlen = sizeof(iso14b_cts_card_select_t);
status = iso14443b_select_cts_card(cts); status = iso14443b_select_cts_card(cts);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&cts, sendlen); reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)cts, sendlen);
// 0: OK 2: demod fail, 3:crc fail, if (status > PM3_SUCCESS) goto out;
if (status > 0) goto out;
} }
if ((p->flags & ISO14B_APDU) == ISO14B_APDU) { if ((p->flags & ISO14B_APDU) == ISO14B_APDU) {
uint8_t res = 0;
status = iso14443b_apdu(p->raw, p->rawlen, (p->flags & ISO14B_SEND_CHAINING), buf, sizeof(buf), &res); iso14b_raw_apdu_response_t packet = {
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE_MIX); .response_byte = 0,
reply_mix(CMD_HF_ISO14443B_COMMAND, status, res, 0, buf, sendlen); .datalen = 0,
};
int responselen = 0;
status = iso14443b_apdu(p->raw, p->rawlen, (p->flags & ISO14B_SEND_CHAINING), buf, sizeof(buf), &packet.response_byte, &responselen);
packet.datalen = MIN(responselen, PM3_CMD_DATA_SIZE);
memcpy(packet.data, buf, packet.datalen);
reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t*)&packet, sizeof(iso14b_raw_apdu_response_t) + packet.datalen);
} }
if ((p->flags & ISO14B_RAW) == ISO14B_RAW) { if ((p->flags & ISO14B_RAW) == ISO14B_RAW) {
if ((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) { if (
if (p->rawlen > 0) { ((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) && (p->rawlen)) {
AddCrc14B(p->raw, p->rawlen); AddCrc14B(p->raw, p->rawlen);
p->rawlen += 2; p->rawlen += 2;
}
} }
uint32_t start_time = 0; uint32_t start_time = 0;
uint32_t eof_time = 0; uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(p->raw, p->rawlen, &start_time, &eof_time, true); CodeAndTransmit14443bAsReader(p->raw, p->rawlen, &start_time, &eof_time, true);
FpgaDisableTracing();
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
FpgaDisableTracing(); reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ETEAROFF, NULL, 0);
reply_mix(CMD_HF_ISO14443B_COMMAND, -2, 0, 0, NULL, 0);
} else { } else {
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
status = Get14443bAnswerFromTag(buf, sizeof(buf), iso14b_timeout, &eof_time); // raw status = Get14443bAnswerFromTag(buf, sizeof(buf), iso14b_timeout, &eof_time); // raw
FpgaDisableTracing(); sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE);
reply_ng(CMD_HF_ISO14443B_COMMAND, status, Demod.output, sendlen);
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE_MIX);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen);
} }
} }

View file

@ -35,13 +35,13 @@
#endif #endif
void iso14443b_setup(void); void iso14443b_setup(void);
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res); int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int * responselen);
int iso14443b_select_card(iso14b_card_select_t *card); int iso14443b_select_card(iso14b_card_select_t *card);
void SimulateIso14443bTag(const uint8_t *pupi); void SimulateIso14443bTag(const uint8_t *pupi);
void AcquireRawAdcSamplesIso14443b(uint32_t parameter); void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
void ReadSTBlock(uint8_t blocknr); void read_14b_st_block(uint8_t blocknr);
void SniffIso14443b(void); void SniffIso14443b(void);
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p); void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p);

View file

@ -29,6 +29,9 @@ Check there for details about data format and how commands are interpreted on th
device-side. device-side.
]] ]]
local PM3_SUCCESS = 0
-- iceman, todo: return payload from ISO14b APDU is a struct now. iso14b_raw_apdu_response_t
local function calypso_parse(result) local function calypso_parse(result)
if result.Oldarg0 >= 0 then if result.Oldarg0 >= 0 then
local len = result.Oldarg0 * 2 local len = result.Oldarg0 * 2
@ -112,9 +115,7 @@ end
local function calypso_send_cmd_raw(data, ignoreresponse ) local function calypso_send_cmd_raw(data, ignoreresponse )
local flags = lib14b.ISO14B_COMMAND.ISO14B_APDU local flags = lib14b.ISO14B_COMMAND.ISO14B_APDU
-- flags = lib14b.ISO14B_COMMAND.ISO14B_RAW +
-- lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC
local flags = lib14b.ISO14B_COMMAND.ISO14B_APDU
data = data or "" data = data or ""
-- LEN of data, half the length of the ASCII-string hex string -- LEN of data, half the length of the ASCII-string hex string
-- 2 bytes flags -- 2 bytes flags
@ -129,7 +130,7 @@ local function calypso_send_cmd_raw(data, ignoreresponse )
local c = Command:newNG{cmd = cmds.CMD_HF_ISO14443B_COMMAND, data = senddata} local c = Command:newNG{cmd = cmds.CMD_HF_ISO14443B_COMMAND, data = senddata}
local result, err = c:sendNG(ignoreresponse, 2000) local result, err = c:sendNG(ignoreresponse, 2000)
if result then if result then
if result.Oldarg0 >= 0 then if result.status == PM3_SUCCESS then
return calypso_parse(result) return calypso_parse(result)
else else
err = 'card response failed' err = 'card response failed'
@ -144,7 +145,7 @@ end
-- writes it in the tree in decimal format. -- writes it in the tree in decimal format.
local function calypso_card_num(card) local function calypso_card_num(card)
if not card then return end if not card then return end
local card_num = tonumber( card.uid:sub(1,8),16 ) local card_num = tonumber( card.uid:sub(1, 8), 16)
print('') print('')
print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset) print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset)
print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset) print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset)
@ -156,7 +157,7 @@ local function calypso_apdu_status(apdu)
-- last two is CRC -- last two is CRC
-- next two is APDU status bytes. -- next two is APDU status bytes.
local mess = 'FAIL' local mess = 'FAIL'
local sw = apdu:sub( #apdu-7, #apdu-4) local sw = apdu:sub( #apdu - 7 , #apdu - 4)
desc, err = iso7816.tostring(sw) desc, err = iso7816.tostring(sw)
--print ('SW', sw, desc, err ) --print ('SW', sw, desc, err )
local status = ( sw == '9000' ) local status = ( sw == '9000' )
@ -250,7 +251,7 @@ function main(args)
for i, apdu in spairs(_calypso_cmds) do for i, apdu in spairs(_calypso_cmds) do
print('>> '..ansicolors.yellow..i..ansicolors.reset) print('>> '..ansicolors.yellow..i..ansicolors.reset)
apdu = apdu:gsub('%s+', '') apdu = apdu:gsub('%s+', '')
data, err = calypso_send_cmd_raw(apdu , false) data, err = calypso_send_cmd_raw(apdu, false)
if err then if err then
print('<< '..err) print('<< '..err)
else else

View file

@ -30,6 +30,7 @@ Check there for details about data format and how commands are interpreted on th
device-side. device-side.
]] ]]
-- iceman, todo: return payload from ISO14b APDU is a struct now. iso14b_raw_apdu_response_t
local function mobib_parse(result) local function mobib_parse(result)
if result.Oldarg0 >= 0 then if result.Oldarg0 >= 0 then
local len = result.Oldarg0 * 2 local len = result.Oldarg0 * 2
@ -126,7 +127,7 @@ local function mobib_send_cmd_raw(data, ignoreresponse )
local result, err = c:sendNG(ignoreresponse, 2000) local result, err = c:sendNG(ignoreresponse, 2000)
if result then if result then
if result.Oldarg0 >= 0 then if result.status == PM3_SUCCESS then
return mobib_parse(result) return mobib_parse(result)
else else
err = 'card response failed' err = 'card response failed'

View file

@ -86,8 +86,10 @@ static void hf14b_aid_search(bool verbose) {
json_t *data = AIDSearchGetElm(root, elmindx); json_t *data = AIDSearchGetElm(root, elmindx);
uint8_t vaid[200] = {0}; uint8_t vaid[200] = {0};
int vaidlen = 0; int vaidlen = 0;
if (!AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) || !vaidlen)
if ((AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) == false) || (vaidlen == 0 )) {
continue; continue;
}
// COMPUTE APDU // COMPUTE APDU
@ -96,7 +98,7 @@ static void hf14b_aid_search(bool verbose) {
sAPDU_t apdu = (sAPDU_t) {0x00, 0xa4, 0x04, 0x00, vaidlen, vaid}; sAPDU_t apdu = (sAPDU_t) {0x00, 0xa4, 0x04, 0x00, vaidlen, vaid};
if (APDUEncodeS(&apdu, false, 0x00, apdu_data, &apdu_len)) { if (APDUEncodeS(&apdu, false, 0x00, apdu_data, &apdu_len)) {
PrintAndLogEx(ERR, "APDU encoding error."); PrintAndLogEx(ERR, "APDU encoding error");
return; return;
} }
@ -106,8 +108,9 @@ static void hf14b_aid_search(bool verbose) {
uint8_t result[1024] = {0}; uint8_t result[1024] = {0};
int res = exchange_14b_apdu(apdu_data, apdu_len, activate_field, leave_signal_on, result, sizeof(result), &resultlen, -1); int res = exchange_14b_apdu(apdu_data, apdu_len, activate_field, leave_signal_on, result, sizeof(result), &resultlen, -1);
activate_field = false; activate_field = false;
if (res) if (res) {
continue; continue;
}
uint16_t sw = get_sw(result, resultlen); uint16_t sw = get_sw(result, resultlen);
@ -128,9 +131,13 @@ static void hf14b_aid_search(bool verbose) {
if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) { if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) {
if (sw == ISO7816_OK) { if (sw == ISO7816_OK) {
if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )"); if (verbose) {
PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )");
}
} else { } else {
if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )"); if (verbose) {
PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )");
}
} }
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose); PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose);
@ -138,7 +145,9 @@ static void hf14b_aid_search(bool verbose) {
if (dfnamelen) { if (dfnamelen) {
if (dfnamelen == vaidlen) { if (dfnamelen == vaidlen) {
if (memcmp(dfname, vaid, vaidlen) == 0) { if (memcmp(dfname, vaid, vaidlen) == 0) {
if (verbose) PrintAndLogEx(INFO, "(DF) Name found and equal to AID"); if (verbose) {
PrintAndLogEx(INFO, "(DF) Name found and equal to AID");
}
} else { } else {
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen)); PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose); PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
@ -148,16 +157,21 @@ static void hf14b_aid_search(bool verbose) {
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose); PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
} }
} else { } else {
if (verbose) PrintAndLogEx(INFO, "(DF) Name not found"); if (verbose) {
PrintAndLogEx(INFO, "(DF) Name not found");
}
} }
if (verbose) PrintAndLogEx(SUCCESS, "----------------------------------------------------"); if (verbose) {
PrintAndLogEx(SUCCESS, "----------------------------------------------------");
}
found = true; found = true;
} }
} }
switch_off_field_14b(); switch_off_field_14b();
if (verbose == false && found) if (verbose == false && found) {
PrintAndLogEx(INFO, "----------------------------------------------------"); PrintAndLogEx(INFO, "----------------------------------------------------");
}
} }
static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) { static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) {
@ -168,15 +182,21 @@ static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) {
return false; return false;
} }
uint16_t len = (resp.oldarg[1] & 0xFFFF); if (resp.status == PM3_ETEAROFF) {
if (verbose) {
PrintAndLogEx(INFO, "Writing tear off triggered");
}
return true;
}
uint16_t len = resp.length;
uint8_t *data = resp.data.asBytes; uint8_t *data = resp.data.asBytes;
// handle select responses // handle select responses
if (is_select) { if (is_select) {
// 0: OK; -1: attrib fail; -2:crc fail // 0: OK; -1: attrib fail; -2:crc fail
int status = (int)resp.oldarg[0]; if (resp.status == PM3_SUCCESS) {
if (status == 0) {
if (verbose) { if (verbose) {
PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len); PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
@ -210,7 +230,7 @@ static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) {
} }
static int CmdHF14BList(const char *Cmd) { static int CmdHF14BList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "hf 14b", "14b"); return CmdTraceListAlias(Cmd, "hf 14b", "14b -c");
} }
static int CmdHF14BSim(const char *Cmd) { static int CmdHF14BSim(const char *Cmd) {
@ -306,29 +326,6 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
int user_timeout = arg_get_int_def(ctx, 8, -1); int user_timeout = arg_get_int_def(ctx, 8, -1);
bool verbose = arg_get_lit(ctx, 9); bool verbose = arg_get_lit(ctx, 9);
uint32_t flags = ISO14B_CONNECT;
if (add_crc) {
flags |= ISO14B_APPEND_CRC;
}
if (select_std) {
flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
if (verbose)
PrintAndLogEx(INFO, "using ISO14443-B select");
} else if (select_sr) {
flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
if (verbose)
PrintAndLogEx(INFO, "using ST/SRx select");
} else if (select_cts) {
flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
if (verbose)
PrintAndLogEx(INFO, "using ASK/C-ticket select");
} else if (select_xrx) {
flags |= (ISO14B_SELECT_XRX | ISO14B_CLEARTRACE);
if (verbose)
PrintAndLogEx(INFO, "using Fuji/Xerox select");
}
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
int datalen = 0; int datalen = 0;
int res = CLIParamHexToBuf(arg_get_str(ctx, 10), data, sizeof(data), &datalen); int res = CLIParamHexToBuf(arg_get_str(ctx, 10), data, sizeof(data), &datalen);
@ -337,6 +334,33 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
} }
CLIParserFree(ctx); CLIParserFree(ctx);
// FLAGS for device side
uint32_t flags = ISO14B_CONNECT;
if (add_crc) {
flags |= ISO14B_APPEND_CRC;
}
if (select_std) {
flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
if (verbose) {
PrintAndLogEx(INFO, "using ISO14443-B select");
}
} else if (select_sr) {
flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
if (verbose) {
PrintAndLogEx(INFO, "using ST/SRx select");
}
} else if (select_cts) {
flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
if (verbose) {
PrintAndLogEx(INFO, "using ASK/C-ticket select");
}
} else if (select_xrx) {
flags |= (ISO14B_SELECT_XRX | ISO14B_CLEARTRACE);
if (verbose) {
PrintAndLogEx(INFO, "using Fuji/Xerox select");
}
}
uint32_t time_wait = 0; uint32_t time_wait = 0;
if (user_timeout > 0) { if (user_timeout > 0) {
@ -354,11 +378,13 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout); PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout);
} }
if (keep_field_on == 0) if (keep_field_on == false) {
flags |= ISO14B_DISCONNECT; flags |= ISO14B_DISCONNECT;
}
if (datalen > 0) if (datalen > 0) {
flags |= ISO14B_RAW; flags |= ISO14B_RAW;
}
// Max buffer is PM3_CMD_DATA_SIZE // Max buffer is PM3_CMD_DATA_SIZE
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
@ -369,6 +395,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
PrintAndLogEx(FAILED, "failed to allocate memory"); PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC; return PM3_EMALLOC;
} }
packet->flags = flags; packet->flags = flags;
packet->timeout = time_wait; packet->timeout = time_wait;
packet->rawlen = datalen; packet->rawlen = datalen;
@ -388,26 +415,30 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
// Select, device will send back iso14b_card_select_t, don't print it. // Select, device will send back iso14b_card_select_t, don't print it.
if (select_std) { if (select_std) {
success = wait_cmd_14b(verbose, true, user_timeout); success = wait_cmd_14b(verbose, true, user_timeout);
if (verbose && success) if (verbose && success) {
PrintAndLogEx(SUCCESS, "Got response for standard select"); PrintAndLogEx(SUCCESS, "Got response for standard select");
}
} }
if (select_sr) { if (select_sr) {
success = wait_cmd_14b(verbose, true, user_timeout); success = wait_cmd_14b(verbose, true, user_timeout);
if (verbose && success) if (verbose && success) {
PrintAndLogEx(SUCCESS, "Got response for ST/SRx select"); PrintAndLogEx(SUCCESS, "Got response for ST/SRx select");
}
} }
if (select_cts) { if (select_cts) {
success = wait_cmd_14b(verbose, true, user_timeout); success = wait_cmd_14b(verbose, true, user_timeout);
if (verbose && success) if (verbose && success) {
PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select"); PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select");
}
} }
if (select_xrx) { if (select_xrx) {
success = wait_cmd_14b(verbose, true, user_timeout); success = wait_cmd_14b(verbose, true, user_timeout);
if (verbose && success) if (verbose && success) {
PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select"); PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select");
}
} }
// get back response from the raw bytes you sent. // get back response from the raw bytes you sent.
@ -438,7 +469,7 @@ static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) {
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
if (resp.oldarg[0] == 0) { if (resp.status == PM3_SUCCESS) {
memcpy(d, resp.data.asBytes, sizeof(iso14b_card_select_t)); memcpy(d, resp.data.asBytes, sizeof(iso14b_card_select_t));
iso14b_card_select_t *card = (iso14b_card_select_t *)d; iso14b_card_select_t *card = (iso14b_card_select_t *)d;
@ -457,7 +488,7 @@ static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) {
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
if (resp.oldarg[0] == 0) { if (resp.status == PM3_SUCCESS) {
memcpy(d, resp.data.asBytes, sizeof(iso14b_card_select_t)); memcpy(d, resp.data.asBytes, sizeof(iso14b_card_select_t));
*found_type = ISO14B_STANDARD; *found_type = ISO14B_STANDARD;
return true; return true;
@ -470,7 +501,7 @@ static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) {
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
if (resp.oldarg[0] == 0) { if (resp.status == PM3_SUCCESS) {
memcpy(d, resp.data.asBytes, sizeof(iso14b_cts_card_select_t)); memcpy(d, resp.data.asBytes, sizeof(iso14b_cts_card_select_t));
*found_type = ISO14B_CT; *found_type = ISO14B_CT;
return true; return true;
@ -860,12 +891,12 @@ static bool HF14B_Std_Info(bool verbose, bool do_aid_search) {
return false; return false;
} }
iso14b_card_select_t card; switch (resp.status) {
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); case PM3_SUCCESS: {
iso14b_card_select_t card;
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
int status = resp.oldarg[0];
switch (status) {
case 0: {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(SUCCESS, " UID : " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID : " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
@ -879,10 +910,10 @@ static bool HF14B_Std_Info(bool verbose, bool do_aid_search) {
return true; return true;
} }
case -1: case PM3_ELENGTH:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 STD ATTRIB fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 STD ATTRIB fail");
break; break;
case -2: case PM3_ECRC:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 STD CRC fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 STD CRC fail");
break; break;
default: default:
@ -912,15 +943,15 @@ static bool HF14B_ST_Info(bool verbose, bool do_aid_search) {
return false; return false;
} }
if (resp.status != PM3_SUCCESS) {
return false;
}
iso14b_card_select_t card; iso14b_card_select_t card;
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
int status = resp.oldarg[0];
if (status < 0)
return false;
uint8_t empty[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t empty[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if ((card.uidlen < 8) || (memcmp(card.uid, empty, card.uidlen) == 0)) { if ((card.uidlen != 8) || (memcmp(card.uid, empty, card.uidlen) == 0)) {
return false; return false;
} }
@ -972,26 +1003,25 @@ static bool HF14B_st_reader(bool verbose) {
return false; return false;
} }
iso14b_card_select_t card; switch (resp.status) {
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); case PM3_SUCCESS:{
iso14b_card_select_t card;
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
uint8_t empty[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t empty[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if ((card.uidlen < 8) || (memcmp(card.uid, empty, card.uidlen) == 0)) { if ((card.uidlen != 8) || (memcmp(card.uid, empty, card.uidlen) == 0)) {
return false; return false;
} }
int status = resp.oldarg[0];
switch (status) {
case 0:
print_st_general_info(card.uid, card.uidlen); print_st_general_info(card.uid, card.uidlen);
return true; return true;
case -1: }
case PM3_ELENGTH:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ST ATTRIB fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ST ATTRIB fail");
break; break;
case -2: case PM3_ECRC:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ST CRC fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ST CRC fail");
break; break;
case -3: case PM3_EWRONGANSWER:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ST random chip id fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ST random chip id fail");
break; break;
default: default:
@ -1018,18 +1048,16 @@ static bool HF14B_std_reader(bool verbose) {
} }
return false; return false;
} }
int status = resp.oldarg[0];
iso14b_card_select_t card; switch (resp.status) {
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); case PM3_SUCCESS: {
iso14b_card_select_t card;
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
uint8_t empty[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t empty[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if (memcmp(card.uid, empty, card.uidlen) == 0) { if (memcmp(card.uid, empty, card.uidlen) == 0) {
return false; return false;
} }
switch (status) {
case 0: {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " UID : " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID : " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
@ -1037,11 +1065,11 @@ static bool HF14B_std_reader(bool verbose) {
print_atqb_resp(card.atqb, card.cid); print_atqb_resp(card.atqb, card.cid);
return true; return true;
} }
case -1: { case PM3_ELENGTH: {
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
break; break;
} }
case -2: { case PM3_ECRC: {
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail");
break; break;
} }
@ -1070,10 +1098,8 @@ static bool HF14B_ask_ct_reader(bool verbose) {
return false; return false;
} }
int status = resp.oldarg[0]; switch (resp.status) {
case PM3_SUCCESS: {
switch (status) {
case 0: {
print_ct_general_info(resp.data.asBytes); print_ct_general_info(resp.data.asBytes);
return true; return true;
} }
@ -1109,29 +1135,11 @@ static bool HF14B_other_reader(bool verbose) {
// 14b get and print UID only (general info) // 14b get and print UID only (general info)
clearCommandBuffer(); clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) {
if (verbose) {
PrintAndLogEx(WARNING, "timeout while waiting for reply");
}
free(packet);
switch_off_field_14b();
return false;
}
int status = resp.oldarg[0];
PrintAndLogEx(DEBUG, "status %d", status);
if (status == 0) { if (wait_cmd_14b(verbose, true, -1)) {
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:"); PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
PrintAndLogEx(SUCCESS, "unknown tag type answered to a " _YELLOW_("0x000b3f80") " command ans:"); PrintAndLogEx(SUCCESS, "unknown tag type answered to a " _YELLOW_("0x000b3f80") " command");
switch_off_field_14b();
free(packet);
return true;
} else if (status > 0) {
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
PrintAndLogEx(SUCCESS, "unknown tag type answered to a " _YELLOW_("0x000b3f80") " command ans:");
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, status));
switch_off_field_14b(); switch_off_field_14b();
free(packet); free(packet);
return true; return true;
@ -1141,27 +1149,10 @@ static bool HF14B_other_reader(bool verbose) {
packet->raw[0] = ISO14443B_AUTHENTICATE; packet->raw[0] = ISO14443B_AUTHENTICATE;
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) {
if (verbose) {
PrintAndLogEx(WARNING, "timeout while waiting for reply");
}
switch_off_field_14b();
free(packet);
return false;
}
status = resp.oldarg[0];
PrintAndLogEx(DEBUG, "status %d", status);
if (status == 0) { if (wait_cmd_14b(verbose, false, -1)) {
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:"); PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
PrintAndLogEx(SUCCESS, "Unknown tag type answered to a " _YELLOW_("0x0A") " command ans:"); PrintAndLogEx(SUCCESS, "Unknown tag type answered to a " _YELLOW_("0x0A") " command");
switch_off_field_14b();
free(packet);
return true;
} else if (status > 0) {
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
PrintAndLogEx(SUCCESS, "unknown tag type answered to a " _YELLOW_("0x0A") " command ans:");
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, status));
switch_off_field_14b(); switch_off_field_14b();
free(packet); free(packet);
return true; return true;
@ -1171,25 +1162,9 @@ static bool HF14B_other_reader(bool verbose) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
free(packet); free(packet);
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { if (wait_cmd_14b(verbose, false, -1)) {
if (verbose) {
PrintAndLogEx(WARNING, "timeout while waiting for reply");
}
switch_off_field_14b();
return false;
}
status = resp.oldarg[0];
PrintAndLogEx(DEBUG, "status %d", status);
if (status == 0) {
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:"); PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
PrintAndLogEx(SUCCESS, "Unknown tag type answered to a " _YELLOW_("0x0C") " command ans:"); PrintAndLogEx(SUCCESS, "Unknown tag type answered to a " _YELLOW_("0x0C") " command");
switch_off_field_14b();
return true;
} else if (status > 0) {
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
PrintAndLogEx(SUCCESS, "unknown tag type answered to a " _YELLOW_("0x0C") " command ans:");
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, status));
switch_off_field_14b(); switch_off_field_14b();
return true; return true;
} }
@ -1362,7 +1337,6 @@ static int CmdHF14BWriteSri(const char *Cmd) {
} }
char str[36] = {0x00}; char str[36] = {0x00};
memset(str, 0x00, sizeof(str));
snprintf(str, sizeof(str), "--sr -c --data %02x%02x%02x%02x%02x%02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]); snprintf(str, sizeof(str), "--sr -c --data %02x%02x%02x%02x%02x%02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]);
return CmdHF14BCmdRaw(str); return CmdHF14BCmdRaw(str);
} }
@ -1449,6 +1423,7 @@ static int CmdHF14BDump(const char *Cmd) {
// detect blocksize from card :) // detect blocksize from card :)
PrintAndLogEx(INFO, "reading tag memory from UID " _GREEN_("%s"), sprint_hex_inrow(SwapEndian64(card.uid, card.uidlen, 8), card.uidlen)); PrintAndLogEx(INFO, "reading tag memory from UID " _GREEN_("%s"), sprint_hex_inrow(SwapEndian64(card.uid, card.uidlen, 8), card.uidlen));
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 2); iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 2);
if (packet == NULL) { if (packet == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory"); PrintAndLogEx(FAILED, "failed to allocate memory");
@ -1465,8 +1440,8 @@ static int CmdHF14BDump(const char *Cmd) {
// select SR tag // select SR tag
int status; int status;
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
status = resp.oldarg[0]; status = resp.status;
if (status < 0) { if (status != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "failed to select arg0[%" PRId64 "]", resp.oldarg[0]); PrintAndLogEx(FAILED, "failed to select arg0[%" PRId64 "]", resp.oldarg[0]);
free(packet); free(packet);
return switch_off_field_14b(); return switch_off_field_14b();
@ -1491,8 +1466,8 @@ static int CmdHF14BDump(const char *Cmd) {
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + 2); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + 2);
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
status = resp.oldarg[0]; status = resp.status;
if (status < 0) { if (status != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "retrying one more time"); PrintAndLogEx(FAILED, "retrying one more time");
continue; continue;
} }
@ -1665,8 +1640,9 @@ static int srix4kValid(const char *Cmd) {
*/ */
int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) {
if (card) if (card) {
memset(card, 0, sizeof(iso14b_card_select_t)); memset(card, 0, sizeof(iso14b_card_select_t));
}
switch_off_field_14b(); switch_off_field_14b();
@ -1699,12 +1675,12 @@ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) {
} }
// check result // check result
int status = resp.oldarg[0]; if (resp.status != PM3_SUCCESS) {
if (status < 0) {
PrintAndLogEx(WARNING, "No ISO14443-B Card in field"); PrintAndLogEx(WARNING, "No ISO14443-B Card in field");
switch_off_field_14b(); switch_off_field_14b();
return PM3_ESOFT; return PM3_ESOFT;
} }
SetISODEPState(ISODEP_NFCB); SetISODEPState(ISODEP_NFCB);
apdu_frame_length = 0; apdu_frame_length = 0;
// get frame length from ATS in card data structure // get frame length from ATS in card data structure
@ -1733,8 +1709,9 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen,
if (activateField) { if (activateField) {
// select with no disconnect and set frameLength // select with no disconnect and set frameLength
int selres = select_card_14443b_4(false, NULL); int selres = select_card_14443b_4(false, NULL);
if (selres != PM3_SUCCESS) if (selres != PM3_SUCCESS) {
return selres; return selres;
}
} }
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datainlen); iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datainlen);
@ -1746,8 +1723,9 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen,
packet->timeout = 0; packet->timeout = 0;
packet->rawlen = 0; packet->rawlen = 0;
if (chainingin) if (chainingin) {
packet->flags = (ISO14B_SEND_CHAINING | ISO14B_APDU); packet->flags = (ISO14B_SEND_CHAINING | ISO14B_APDU);
}
if (user_timeout > 0) { if (user_timeout > 0) {
packet->flags |= ISO14B_SET_TIMEOUT; packet->flags |= ISO14B_SET_TIMEOUT;
@ -1777,8 +1755,15 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen,
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
int rlen = resp.oldarg[0]; if ( resp.status != PM3_SUCCESS) {
int dlen = rlen - 2; PrintAndLogEx(ERR, "APDU: no APDU response");
return resp.status;
}
iso14b_raw_apdu_response_t *apdu = (iso14b_raw_apdu_response_t *)resp.data.asBytes;
// remove crc bytes
int dlen = apdu->datalen - 2;
if (dlen < 0) { if (dlen < 0) {
dlen = 0; dlen = 0;
} }
@ -1786,33 +1771,28 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen,
*dataoutlen += dlen; *dataoutlen += dlen;
if (maxdataoutlen && *dataoutlen > maxdataoutlen) { if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
PrintAndLogEx(ERR, "APDU: buffer too small(%d), needs %d bytes", maxdataoutlen, *dataoutlen); PrintAndLogEx(ERR, "APDU: buffer too small ( " _RED_("%d") " ), needs " _YELLOW_("%d") " bytes", maxdataoutlen, *dataoutlen);
return PM3_ESOFT; return PM3_ESOFT;
} }
// I-block ACK // I-block ACK
uint8_t res = resp.oldarg[1]; if ((apdu->response_byte & 0xF2) == 0xA2) {
if ((res & 0xF2) == 0xA2) {
*dataoutlen = 0; *dataoutlen = 0;
*chainingout = true; *chainingout = true;
return PM3_SUCCESS; return PM3_SUCCESS;
} }
if (rlen < 0) {
PrintAndLogEx(ERR, "APDU: no APDU response");
return PM3_ESOFT;
}
// check apdu length // check apdu length
if (rlen == 0 || rlen == 1) { if (apdu->datalen < 2) {
PrintAndLogEx(ERR, "APDU: small APDU response, len %d", rlen); PrintAndLogEx(ERR, "APDU: small APDU response, len " _RED_("%d"), apdu->datalen);
return PM3_ESOFT; return PM3_ESOFT;
} }
memcpy(dataout, resp.data.asBytes, dlen); // copy to output array
memcpy(dataout, apdu->data, dlen);
// chaining // chaining
if ((res & 0x10) != 0) { if ((apdu->response_byte & 0x10) != 0) {
*chainingout = true; *chainingout = true;
} }
return PM3_SUCCESS; return PM3_SUCCESS;
@ -2208,7 +2188,6 @@ static int CmdHF14BView(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"}, {"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"},

View file

@ -116,15 +116,16 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
if (resp.oldarg[0] == 0) { if (resp.status == PM3_SUCCESS) {
memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
return true; return true;
} }
} }
} // retry } // retry
if (retry <= 0) if (retry <= 0) {
PrintAndLogEx(FAILED, "command execution timeout"); PrintAndLogEx(FAILED, "command execution timeout");
}
return false; return false;
} }
@ -148,22 +149,20 @@ static int infoHFCryptoRF(bool verbose) {
return false; return false;
} }
iso14b_card_select_t card; switch (resp.status) {
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); case PM3_SUCCESS: {
iso14b_card_select_t card;
uint64_t status = resp.oldarg[0]; memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
switch (status) {
case 0:
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
return PM3_SUCCESS; return PM3_SUCCESS;
case 2: }
case PM3_ELENGTH:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
break; break;
case 3: case PM3_ECRC:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail");
break; break;
default: default:
@ -209,16 +208,16 @@ int readHFCryptoRF(bool loop, bool verbose) {
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
uint8_t status = resp.oldarg[0] & 0xFF;
if (loop) { if (loop) {
if (status != 0) { if (resp.status != PM3_SUCCESS) {
continue; continue;
} }
} else { } else {
// when not in continuous mode // when not in continuous mode
if (status != 0) { if (resp.status != PM3_SUCCESS) {
if (verbose) PrintAndLogEx(WARNING, "cryptoRF / ISO14443-b card select failed"); if (verbose) {
PrintAndLogEx(WARNING, "cryptoRF / ISO14443-b card select failed");
}
res = PM3_EOPABORTED; res = PM3_EOPABORTED;
break; break;
} }
@ -322,11 +321,9 @@ static int CmdHFCryptoRFDump(const char *Cmd) {
PacketResponseNG resp; PacketResponseNG resp;
// select // select
int status;
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
status = resp.oldarg[0]; if (resp.status != PM3_SUCCESS) {
if (status < 0) { PrintAndLogEx(FAILED, "failed to select %" PRId64 "]", resp.status);
PrintAndLogEx(FAILED, "failed to select %" PRId64 "]", resp.oldarg[0]);
free(packet); free(packet);
return switch_off_field_cryptorf(); return switch_off_field_cryptorf();
} }
@ -350,13 +347,12 @@ static int CmdHFCryptoRFDump(const char *Cmd) {
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t) + 2); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t) + 2);
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
status = resp.oldarg[0]; if (resp.status != PM3_SUCCESS) {
if (status < 0) {
PrintAndLogEx(FAILED, "retrying one more time"); PrintAndLogEx(FAILED, "retrying one more time");
continue; continue;
} }
uint16_t len = (resp.oldarg[1] & 0xFFFF); uint16_t len = resp.length;
uint8_t *recv = resp.data.asBytes; uint8_t *recv = resp.data.asBytes;
if (check_crc(CRC_14443_B, recv, len) == false) { if (check_crc(CRC_14443_B, recv, len) == false) {
@ -446,7 +442,7 @@ static int CmdHFCryptoRFELoad(const char *Cmd) {
size_t datalen = CRYPTORF_MEM_SIZE; size_t datalen = CRYPTORF_MEM_SIZE;
// set up buffer // set up buffer
uint8_t *data = calloc(datalen, sizeof(uint8_t)); uint8_t *data = calloc(datalen, sizeof(uint8_t));
if (!data) { if (data == NULL) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -477,7 +473,7 @@ static int CmdHFCryptoRFELoad(const char *Cmd) {
} }
*/ */
free(data); free(data);
PrintAndLogEx(SUCCESS, "sent %d bytes of data to device emulator memory", bytes_sent); PrintAndLogEx(SUCCESS, "sent " _YELLOW_("%d") " bytes of data to device emulator memory", bytes_sent);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -383,8 +383,9 @@ static int switch_off_field(void) {
static int findXerox(iso14b_card_select_t *card, bool disconnect) { static int findXerox(iso14b_card_select_t *card, bool disconnect) {
if (card == NULL) if (card == NULL) {
return PM3_EINVARG; return PM3_EINVARG;
}
int8_t retry = 3; int8_t retry = 3;
while (retry--) { while (retry--) {
@ -399,10 +400,10 @@ static int findXerox(iso14b_card_select_t *card, bool disconnect) {
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
if (resp.oldarg[0] == 0) { if (resp.status == PM3_SUCCESS) {
memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
} }
return resp.oldarg[0]; return resp.length;
} }
} // retry } // retry
@ -513,7 +514,7 @@ static int CmdHFXeroxInfo(const char *Cmd) {
if (verbose) { if (verbose) {
PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed"); PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed");
} }
return PM3_ERFTRANS; return status;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -551,7 +552,7 @@ static int CmdHFXeroxInfo(const char *Cmd) {
*/ */
// 14b raw command send data_len instead of status // 14b raw command send data_len instead of status
if (/*resp.status != 0 ||*/ resp.length < 7) { if (resp.length < 7) {
PrintAndLogEx(FAILED, "retrying one more time"); PrintAndLogEx(FAILED, "retrying one more time");
continue; continue;
} }
@ -655,7 +656,8 @@ static int CmdHFXeroxDump(const char *Cmd) {
resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2], resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2],
resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f'); resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f');
*/ */
if (/*resp.status != 0 ||*/ resp.length < 7) { // 14b raw command send data_len instead of status
if (resp.length < 7) {
PrintAndLogEx(FAILED, "retrying one more time"); PrintAndLogEx(FAILED, "retrying one more time");
continue; continue;
} }
@ -689,8 +691,9 @@ static int CmdHFXeroxDump(const char *Cmd) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
if (blocknum != 0x100) if (blocknum != 0x100) {
PrintAndLogEx(FAILED, "dump failed at block %d", blocknum); PrintAndLogEx(FAILED, "dump failed at block %d", blocknum);
}
if (decrypt) { if (decrypt) {
PrintAndLogEx(INFO, "Decrypting secret blocks..."); PrintAndLogEx(INFO, "Decrypting secret blocks...");
@ -744,12 +747,14 @@ static int CmdHFXeroxDump(const char *Cmd) {
uint16_t cs, csd; uint16_t cs, csd;
// calc checksum // calc checksum
for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) cs += decr[b] | (decr[b + 1] << 8); for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) {
cs += decr[b] | (decr[b + 1] << 8);
}
cs = ~cs; cs = ~cs;
csd = (decr[7] << 8) | decr[6]; csd = (decr[7] << 8) | decr[6];
if (cs != csd) { if (cs != csd) {
PrintAndLogEx(FAILED, "secret block %02X checksum failed.", dadr); PrintAndLogEx(FAILED, "Secret block %02X checksum " _RED_("failed"), dadr);
} }
} }
} }

View file

@ -64,6 +64,11 @@ typedef struct {
uint8_t raw[]; uint8_t raw[];
} PACKED iso14b_raw_cmd_t; } PACKED iso14b_raw_cmd_t;
typedef struct {
uint8_t response_byte;
uint16_t datalen;
uint8_t data[];
} PACKED iso14b_raw_apdu_response_t;
#define US_TO_SSP(x) ( (int32_t) ((x) * 3.39) ) #define US_TO_SSP(x) ( (int32_t) ((x) * 3.39) )
#define SSP_TO_US(x) ( (int32_t)((x) / 3.39) ) #define SSP_TO_US(x) ( (int32_t)((x) / 3.39) )

View file

@ -820,6 +820,9 @@ typedef struct {
// No PACS data pm3: when using HID SAM to retried PACS data // No PACS data pm3: when using HID SAM to retried PACS data
#define PM3_ENOPACS -26 #define PM3_ENOPACS -26
// Got wrong length error pm3: when received wrong length of data
#define PM3_ELENGTH -27
// No data pm3: no data available, no host frame available (not really an error) // No data pm3: no data available, no host frame available (not really an error)
#define PM3_ENODATA -98 #define PM3_ENODATA -98
// Quit program client: reserved, order to quit the program // Quit program client: reserved, order to quit the program