added: hf 14b apdu

This commit is contained in:
iceman1001 2020-09-30 17:06:19 +02:00
commit 181bb3bc74
4 changed files with 483 additions and 93 deletions

View file

@ -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;
}

View file

@ -44,12 +44,15 @@
# 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.
@ -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,7 +895,6 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
return false;
}
/*
* Demodulate the samples we received from the tag, also log to tracebuffer
*/
@ -905,12 +905,6 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
// 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();
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;
}
return retlen;
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 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);
}

View file

@ -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);

View file

@ -10,12 +10,14 @@
//-----------------------------------------------------------------------------
#include "cmdhf14b.h"
#include <ctype.h>
#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", "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
arg_int0("l", "le", "<Le (int)>", "Le apdu parameter if `m` parameter included"),
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "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"},