diff --git a/armsrc/epa.c b/armsrc/epa.c index dd7dfb57d..317f2ce7b 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -118,7 +118,7 @@ static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t re case 'a': return iso14_apdu(apdu, (uint16_t) length, false, response, NULL); case 'b': - return iso14443b_apdu(apdu, length, response, respmaxlen); + return iso14443b_apdu(apdu, length, false, response, respmaxlen); default: return 0; } diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index e91fce41a..88e117672 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -41,15 +41,18 @@ // defaults to 2000ms #ifndef FWT_TIMEOUT_14B -# define FWT_TIMEOUT_14B 35312 +# define FWT_TIMEOUT_14B 35312 #endif +// 1 tick == 1/13.56 mhz +// 1 us = 1.5 tick + // 330/848kHz = 1558us / 4 == 400us, -#define ISO14443B_READER_TIMEOUT 1700 //330 +#define ISO14443B_READER_TIMEOUT 10000 //330 // 1024/3.39MHz = 302.1us between end of tag response and next reader cmd -#define DELAY_ISO14443B_VICC_TO_VCD_READER 600 // 1024 -#define DELAY_ISO14443B_VCD_TO_VICC_READER 600// 1056 +#define DELAY_ISO14443B_VICC_TO_VCD_READER (28*9) // 1024 ( counting from start of PICC EOF 14 ETU's) +#define DELAY_ISO14443B_VCD_TO_VICC_READER (28*9) // 1056 #ifndef RECEIVE_MASK # define RECEIVE_MASK (DMA_BUFFER_SIZE - 1) @@ -57,7 +60,7 @@ // Guard Time (per 14443-2) #ifndef TR0 -# define TR0 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA +# define TR0 32 // TR0 max is 151/fs = 151/(848kHz) = 302us or 64 samples from FPGA #endif // Synchronization time (per 14443-2) @@ -76,10 +79,9 @@ static void iso14b_set_timeout(uint32_t timeout); static void iso14b_set_maxframesize(uint16_t size); // the block number for the ISO14443-4 PCB (used with APDUs) -static uint8_t pcb_blocknum = 0; +static uint8_t iso14b_pcb_blocknum = 0; static uint32_t iso14b_timeout = FWT_TIMEOUT_14B; - /* ISO 14443 B * * Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig) @@ -306,7 +308,6 @@ static void Demod14bInit(uint8_t *data, uint16_t max_len) { Demod14bReset(); } - /* * 9.4395 us = 1 ETU and clock is about 1.5 us * 13560000Hz @@ -740,7 +741,7 @@ void SimulateIso14443bTag(uint32_t pupi) { */ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { - int v; + int v = 0; // The soft decision on the bit uses an estimate of just the // quadrant of the reference angle, not the exact angle. @@ -757,7 +758,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { } \ } -#define SUBCARRIER_DETECT_THRESHOLD 8 +#define SUBCARRIER_DETECT_THRESHOLD 8 // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) #define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2)) @@ -797,7 +798,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; Demod.posCount = 0; // start of SOF sequence } else { - if (Demod.posCount > 200 / 4) { // maximum length of TR1 = 200 1/fs + if (Demod.posCount > 200/4) { // maximum length of TR1 = 200 1/fs Demod.state = DEMOD_UNSYNCD; } } @@ -820,7 +821,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { Demod.state = DEMOD_AWAITING_START_BIT; } } else { - if (Demod.posCount > 14 * 2) { // low phase of SOF too long (> 12 etu) + if (Demod.posCount > 12 * 2) { // low phase of SOF too long (> 12 etu) Demod.state = DEMOD_UNSYNCD; LED_C_OFF(); } @@ -831,7 +832,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { Demod.posCount++; MAKE_SOFT_DECISION(); if (v > 0) { - if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs + if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs LED_C_OFF(); if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass return true; @@ -873,7 +874,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { Demod.bitCount = 0; Demod.state = DEMOD_AWAITING_START_BIT; } else { - Demod.state = DEMOD_UNSYNCD; + Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; LED_C_OFF(); if (s == 0x000) { // This is EOF (start, stop and all data bits == '0' @@ -894,23 +895,16 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { return false; } - /* * Demodulate the samples we received from the tag, also log to tracebuffer */ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeout, uint32_t *eof_time) { - + int samples = 0, ret = 0; // Set up the demodulator for tag -> reader responses. Demod14bInit(response, max_len); - - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {}; - - // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); - + // Setup and start DMA. FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); @@ -924,6 +918,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo uint32_t dma_start_time = 0; uint16_t *upTo = dma->buf; + // Put FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); + for (;;) { volatile uint16_t behindBy = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); @@ -971,7 +968,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo if (Handle14443bSamplesFromTag(ci, cq)) { - *eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM; // end of EOF + *eof_time = dma_start_time + (samples ) - DELAY_TAG_TO_ARM; // end of EOF if (Demod.len > Demod.max_len) { ret = -2; // overflow @@ -986,19 +983,17 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo } FpgaDisableSscDma(); - if (ret < 0) { return ret; } if (Demod.len > 0) { uint32_t sof_time = *eof_time - - (Demod.len * 8 * 8 * 16) // time for byte transfers - - (32 * 16) // time for SOF transfer - - 0; // time for EOF transfer + - (Demod.len * (8 + 2)) // time for byte transfers + - (12) // time for SOF transfer + - (12); // time for EOF transfer LogTrace(Demod.output, Demod.len, (sof_time * 4), (*eof_time * 4), NULL, false); } - return Demod.len; } @@ -1011,6 +1006,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); + // TR2 minimum 14 ETUs if (*start_time < DELAY_ARM_TO_TAG) { *start_time = DELAY_ARM_TO_TAG; } @@ -1018,21 +1014,20 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) { *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; if (GetCountSspClk() > *start_time) { // we may miss the intended time - *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time + *start_time = (GetCountSspClk() + 32) & 0xfffffff0; // next possible time } - + // wait - while (GetCountSspClk() < *start_time) ; + while (GetCountSspClk() < *start_time); LED_B_ON(); for (int c = 0; c < ts->max; c++) { volatile uint8_t data = ts->buf[c]; - for (int i = 0; i < 8; i++) { - uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; + for (uint8_t i = 0; i < 8; i++) { + volatile uint16_t send_word = (data & 0x80) ? 0x0000 : 0xFFFF; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; @@ -1045,6 +1040,9 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) { LED_B_OFF(); *start_time += DELAY_ARM_TO_TAG; + + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {}; } //----------------------------------------------------------------------------- @@ -1061,32 +1059,38 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { * - no modulation ONES * * 1 ETU == 1 BIT! - * TR0 - 8 ETUS minimum. + * TR0 - 8 ETU's minimum. + * TR0 - 32 ETU's maximum for ATQB only + * TR0 - FWT for all other commands * * QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode? * 1 "stuffbit" = 1ETU (9us) + * + * TR2 - After the PICC response, the PCD is required to wait the Frame Delay Time (TR2) + before transmission of the next command. The minimum frame delay time required for + all commands is 14 ETUs + * */ - + int i; tosend_reset(); - + // Send SOF // 10-11 ETUs of ZERO - for (int i = 0; i < 10; i++) + for (i = 0; i < 10; i++) { tosend_stuffbit(0); - - + } // 2-3 ETUs of ONE tosend_stuffbit(1); tosend_stuffbit(1); // Sending cmd, LSB // from here we add BITS - for (int i = 0; i < len; i++) { + for (i = 0; i < len; i++) { // Start bit tosend_stuffbit(0); - // Data bits - uint8_t b = cmd[i]; + // Data bits + volatile uint8_t b = cmd[i]; tosend_stuffbit(b & 1); tosend_stuffbit((b >> 1) & 1); tosend_stuffbit((b >> 2) & 1); @@ -1098,28 +1102,28 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // Stop bit tosend_stuffbit(1); - // EGT extra guard time - // For PCD it ranges 0-57us (1etu = 9us) -// tosend_stuffbit(1); -// tosend_stuffbit(1); -// tosend_stuffbit(1); + // EGT extra guard time 1 ETU = 9us + // For PCD it ranges 0-57us === 0 - 6 ETU + // FOR PICC it ranges 0-19us == 0 - 2 ETU } // Send EOF // 10-11 ETUs of ZERO - for (int i = 0; i < 10; i++) + for (i = 0; i < 10; i++) { tosend_stuffbit(0); + } - // Transition time. TR0 - guard time - // 8ETUS minum? - // Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF. - // I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode + tosend_stuffbit(1); + /* Transition time. TR0 - guard time + * TR0 - 8 ETU's minimum. + * TR0 - 32 ETU's maximum for ATQB only + * TR0 - FWT for all other commands + * 32,64,128,256,512, ... , 262144, 524288 ETU + */ - // ensure that last byte is filled up - for (int i = 0; i < 8 ; ++i) + for (i = 0; i < 8 ; ++i) tosend_stuffbit(1); - // TR1 - Synchronization time // Convert from last character reference to length tosend_t *ts = get_tosend(); ts->max++; @@ -1132,54 +1136,100 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t tosend_t *ts = get_tosend(); CodeIso14443bAsReader(cmd, len); TransmitFor14443b_AsReader(start_time); - *eof_time = *start_time + (32 * (8 * ts->max)); + *eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10; LogTrace(cmd, len, *start_time, *eof_time, NULL, true); } /* Sends an APDU to the tag * TODO: check CRC and preamble */ -int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen) { +int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen) { - LED_A_ON(); - uint8_t message_frame[message_length + 4]; - // PCB - message_frame[0] = 0x0A | pcb_blocknum; - pcb_blocknum ^= 1; - // CID - message_frame[1] = 0; - // INF - memcpy(message_frame + 2, message, message_length); - // EDC (CRC) - AddCrc14B(message_frame, message_length + 2); + uint8_t real_cmd[msg_len + 4]; + + if (msg_len) { + // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 + real_cmd[0] = 0x02; // bnr, nad, cid, chn=0; i-block(0x00) + if (send_chaining) { + real_cmd[0] |= 0x10; + } + // put block number into the PCB + real_cmd[0] |= iso14b_pcb_blocknum; + memcpy(real_cmd + 1, msg, msg_len); + } else { + // R-block. ACK + real_cmd[0] = 0xA2; // r-block + ACK + real_cmd[0] |= iso14b_pcb_blocknum; + } + + AddCrc14B(real_cmd, msg_len + 1); // send uint32_t start_time = 0; uint32_t eof_time = 0; - CodeAndTransmit14443bAsReader(message_frame, sizeof(message_frame), &start_time, &eof_time); - - // Get response? - if (response == NULL) { - LED_A_OFF(); - return 0; - } + CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time); eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; - int retlen = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); + int len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); FpgaDisableTracing(); - if (retlen < 3) { - LED_A_OFF(); - return -1; + uint8_t *data_bytes = (uint8_t *) response; + + if (len <= 0) { + return 0; //DATA LINK ERROR + } else { + // S-Block WTX + while (len && ((data_bytes[0] & 0xF2) == 0xF2)) { + uint32_t save_iso14b_timeout = iso14b_timeout; + // temporarily increase timeout + iso14b_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14b_timeout, ISO14443B_READER_TIMEOUT)); + // Transmit WTX back + // byte1 - WTXM [1..59]. command FWT=FWT*WTXM + data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b + // now need to fix CRC. + AddCrc14B(data_bytes, len - 2); + + // transmit S-Block + CodeAndTransmit14443bAsReader(data_bytes, len, &start_time, &eof_time); + + // retrieve the result again (with increased timeout) + eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; + len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); + FpgaDisableTracing(); + + data_bytes = response; + // restore timeout + iso14b_set_timeout(save_iso14b_timeout); + } + + // if we received an I- or R(ACK)-Block with a block number equal to the + // current block number, toggle the current block number + if (len >= 3 // PCB+CRC = 3 bytes + && ((data_bytes[0] & 0xC0) == 0 // I-Block + || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 + && (data_bytes[0] & 0x01) == iso14b_pcb_blocknum) { // equal block numbers + iso14b_pcb_blocknum ^= 1; + } + + // if we received I-block with chaining we need to send ACK and receive another block of data + if (response) + *response = data_bytes[0]; + + // crc check + if (len >= 3 && !check_crc(CRC_14443_B, data_bytes, len)) { + return -1; + } } - // VALIDATE CRC - if (!check_crc(CRC_14443_B, response, retlen)) { - if (DBGLEVEL > DBG_DEBUG) DbpString("CRC fail"); - return -2; + if (len) { + // cut frame byte + len -= 1; + // memmove(data_bytes, data_bytes + 1, len); + for (int i = 0; i < len; i++) + data_bytes[i] = data_bytes[i + 1]; } - return retlen; + return len; } /** @@ -1272,7 +1322,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) { int iso14443b_select_card(iso14b_card_select_t *card) { // WUPB command (including CRC) // Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state - static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; + // WUTB or REQB is denoted in the third byte, lower nibble. 0 vs 8 + //static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; + static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xff }; + // ATTRIB command (with space for CRC) uint8_t attrib[] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}; @@ -1350,7 +1403,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) { } } // reset PCB block number - pcb_blocknum = 0; + iso14b_pcb_blocknum = 0; return 0; } @@ -1720,7 +1773,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { if ((param & ISO14B_APDU) == ISO14B_APDU) { uint8_t buf[100] = {0}; - status = iso14443b_apdu(cmd, len, buf, sizeof(buf)); + status = iso14443b_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, sizeof(buf)); reply_mix(CMD_HF_ISO14443B_COMMAND, status, status, 0, buf, status); } diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h index 199e5c63f..84c264c92 100644 --- a/armsrc/iso14443b.h +++ b/armsrc/iso14443b.h @@ -27,7 +27,7 @@ #endif void iso14443b_setup(void); -int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen); +int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen); int iso14443b_select_card(iso14b_card_select_t *card); int iso14443b_select_card_srx(iso14b_card_select_t *card); diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 51558bcd4..8a355073d 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -10,12 +10,14 @@ //----------------------------------------------------------------------------- #include "cmdhf14b.h" - #include #include "fileutils.h" #include "cmdparser.h" // command_t +#include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer +#include "emv/emvcore.h" // TLVPrintFromBuffer #include "cmdtrace.h" +#include "cliparser.h" #include "crc16.h" #include "cmdhf14a.h" #include "protocols.h" // definitions of ISO14B/7816 protocol @@ -24,6 +26,11 @@ #define TIMEOUT 2000 +// iso14b apdu input frame length +static uint16_t apdu_frame_length = 0; +uint16_t ats_fsc[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; +bool apdu_in_framing_enable = true; + static int CmdHelp(const char *Cmd); static int usage_hf_14b_info(void) { @@ -145,7 +152,6 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { static bool waitCmd14b(bool verbose) { PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { uint16_t len = (resp.oldarg[1] & 0xFFFF); @@ -1270,6 +1276,336 @@ static int srix4kValid(const char *Cmd) { } */ +static int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { + + PacketResponseNG resp; + if (card) + memset(card, 0, sizeof(iso14b_card_select_t)); + + switch_off_field_14b(); + + // Anticollision + SELECT STD card + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD, 0, 0, NULL, 0); + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { + PrintAndLogEx(INFO, "Trying 14B Select SR"); + + // Anticollision + SELECT SR card + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR, 0, 0, NULL, 0); + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { + PrintAndLogEx(ERR, "connection timeout"); + switch_off_field_14b(); + return PM3_ESOFT; + } + } + + // check result + int status = resp.oldarg[0]; + if (status < 0) { + PrintAndLogEx(ERR, "No card in field."); + switch_off_field_14b(); + return PM3_ESOFT; + } + + apdu_frame_length = 0; + // get frame length from ATS in card data structure + iso14b_card_select_t *vcard = (iso14b_card_select_t *) resp.data.asBytes; +// uint8_t fsci = vcard->atqb[1] & 0x0f; +// if (fsci < ARRAYLEN(ats_fsc)) { +// apdu_frame_length = ats_fsc[fsci]; +// } + + if (card) { + memcpy(card, vcard, sizeof(iso14b_card_select_t)); + } + + if (disconnect) { + switch_off_field_14b(); + } + return PM3_SUCCESS; +} + +static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) { + *chainingout = false; + + if (activateField) { + // select with no disconnect and set frameLength + int selres = select_card_14443b_4(false, NULL); + if (selres != PM3_SUCCESS) + return selres; + } + + uint16_t flags = 0; + + // Don't support 14B chaining yet + if (chainingin) + flags = ISO14B_SEND_CHAINING; + + // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes + // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size + // here length PM3_CMD_DATA_SIZE=512 + // timeout must be authomatically set by "get ATS" + if (datain) + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, (datainlen & 0xFFFF), 0, datain, datainlen & 0xFFFF); + else + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, 0, NULL, 0); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { + uint8_t *recv = resp.data.asBytes; + int iLen = resp.oldarg[0]; + uint8_t res = resp.oldarg[1]; + + int dlen = iLen - 2; + if (dlen < 0) { + dlen = 0; + } + *dataoutlen += dlen; + + if (maxdataoutlen && *dataoutlen > maxdataoutlen) { + PrintAndLogEx(ERR, "APDU: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); + return PM3_ESOFT; + } + + // I-block ACK + if ((res & 0xf2) == 0xa2) { + *dataoutlen = 0; + *chainingout = true; + return PM3_SUCCESS; + } + + if (!iLen) { + PrintAndLogEx(ERR, "APDU: No APDU response."); + return PM3_ESOFT; + } + + // check apdu length + if (iLen < 2 && iLen >= 0) { + PrintAndLogEx(ERR, "APDU: Small APDU response. Len=%d", iLen); + return PM3_ESOFT; + } + + // check block TODO + if (iLen == -2) { + PrintAndLogEx(ERR, "APDU: Block type mismatch."); + return PM3_ESOFT; + } + + memcpy(dataout, recv, dlen); + + // chaining + if ((res & 0x10) != 0) { + *chainingout = true; + } + + // CRC Check + if (iLen == -1) { + PrintAndLogEx(ERR, "APDU: ISO 14443A CRC error."); + return PM3_ESOFT; + } + } else { + PrintAndLogEx(ERR, "APDU: Reply timeout."); + return PM3_ETIMEOUT; + } + + return PM3_SUCCESS; +} + +static int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + *dataoutlen = 0; + bool chaining = false; + int res; + + // 3 byte here - 1b framing header, 2b crc16 + if (apdu_in_framing_enable && + ((apdu_frame_length && (datainlen > apdu_frame_length - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) { + int clen = 0; + + bool v_activate_field = activate_field; + + do { + int vlen = MIN(apdu_frame_length - 3, datainlen - clen); + bool chainBlockNotLast = ((clen + vlen) < datainlen); + + *dataoutlen = 0; + res = handle_14b_apdu(chainBlockNotLast, &datain[clen], vlen, v_activate_field, dataout, maxdataoutlen, dataoutlen, &chaining); + if (res) { + if (leave_signal_on == false) + switch_off_field_14b(); + + return 200; + } + + // check R-block ACK +//TODO check this one... + if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) { // *dataoutlen!=0. 'A && (!A || B)' is equivalent to 'A && B' + if (leave_signal_on == false) { + switch_off_field_14b(); + } + return 201; + } + + clen += vlen; + v_activate_field = false; + if (*dataoutlen) { + if (clen != datainlen) + PrintAndLogEx(ERR, "APDU: I-block/R-block sequence error. Data len=%d, Sent=%d, Last packet len=%d", datainlen, clen, *dataoutlen); + break; + } + } while (clen < datainlen); + + } else { + + res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining); + if (res != PM3_SUCCESS) { + if (leave_signal_on == false) { + switch_off_field_14b(); + } + return res; + } + } + + while (chaining) { + // I-block with chaining + res = handle_14b_apdu(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); + if (res != PM3_SUCCESS) { + if (leave_signal_on == false) { + switch_off_field_14b(); + } + return 100; + } + } + + if (leave_signal_on == false) { + switch_off_field_14b(); + } + + return PM3_SUCCESS; +} + +// ISO14443-4. 7. Half-duplex block transmission protocol +static int CmdHF14BAPDU(const char *Cmd) { + uint8_t data[PM3_CMD_DATA_SIZE]; + int datalen = 0; + uint8_t header[PM3_CMD_DATA_SIZE]; + int headerlen = 0; + bool activate_field = false; + bool leave_signal_on = false; + bool decode_TLV = false; + bool decode_APDU = false; + bool make_APDU = false; + bool extended_APDU = false; + int le = 0; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14b apdu", + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013", + "hf 14b apdu -s 94a40800043f000002\n" + "hf 14b apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu\n" + "hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n" + "hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("s", "select", "activate field and select card"), + arg_lit0("k", "keep", "leave the signal field ON after receive response"), + arg_lit0("t", "tlv", "executes TLV decoder if it possible"), + arg_lit0("d", "decode", "decode apdu request if it possible"), + arg_str0("m", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), + arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"), + arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"), + arg_strx1(NULL, NULL, "", "data if `m` parameter included"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + activate_field = arg_get_lit(ctx, 1); + leave_signal_on = arg_get_lit(ctx, 2); + decode_TLV = arg_get_lit(ctx, 3); + decode_APDU = arg_get_lit(ctx, 4); + + CLIGetHexWithReturn(ctx, 5, header, &headerlen); + make_APDU = headerlen > 0; + if (make_APDU && headerlen != 4) { + PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + extended_APDU = arg_get_lit(ctx, 6); + le = arg_get_int_def(ctx, 7, 0); + + if (make_APDU) { + uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0}; + int apdudatalen = 0; + + CLIGetHexBLessWithReturn(ctx, 8, apdudata, &apdudatalen, 1 + 2); + + APDUStruct apdu; + apdu.cla = header[0]; + apdu.ins = header[1]; + apdu.p1 = header[2]; + apdu.p2 = header[3]; + + apdu.lc = apdudatalen; + apdu.data = apdudata; + + apdu.extended_apdu = extended_APDU; + apdu.le = le; + + if (APDUEncode(&apdu, data, &datalen)) { + PrintAndLogEx(ERR, "can't make apdu with provided parameters."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + } else { + if (extended_APDU) { + PrintAndLogEx(ERR, "make mode not set but here `e` option."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (le > 0) { + PrintAndLogEx(ERR, "make mode not set but here `l` option."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + // len = data + PCB(1b) + CRC(2b) + CLIGetHexBLessWithReturn(ctx, 8, data, &datalen, 1 + 2); + } + CLIParserFree(ctx); + + PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", + activate_field ? "sel " : "", + leave_signal_on ? "keep " : "", + decode_TLV ? "TLV" : "", + sprint_hex(data, datalen) + ); + + if (decode_APDU) { + APDUStruct apdu; + if (APDUDecode(data, datalen, &apdu) == 0) + APDUPrint(apdu); + else + PrintAndLogEx(WARNING, "can't decode APDU."); + } + + int res = exchange_14b_apdu(data, datalen, activate_field, leave_signal_on, data, PM3_CMD_DATA_SIZE, &datalen); + if (res != PM3_SUCCESS) { + return res; + } + + PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(data, datalen)); + PrintAndLogEx(SUCCESS, "APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); + + // TLV decoder + if (decode_TLV && datalen > 4) { + TLVPrintFromBuffer(data, datalen - 2); + } + + return PM3_SUCCESS; +} + static int CmdHF14BNdef(const char *Cmd) { char c = tolower(param_getchar(Cmd, 0)); if (c == 'h' || c == 0x00) return usage_hf_14b_ndef(); @@ -1352,6 +1688,7 @@ static int CmdHF14BNdef(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"}, {"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO14443-B tag, save to file"}, {"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"}, {"list", CmdHF14BList, AlwaysAvailable, "List ISO 14443B history"},