X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/138927dd7b9be11990ac7073cdd1906b78683a76..f2b0169cc69c9bb963c58d419bb8e313dcbe5b24:/client/cmdhf14a.c?ds=sidebyside diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index bab3591e..c16a64bd 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -29,7 +29,7 @@ #include "mifarehost.h" static int CmdHelp(const char *Cmd); -static void waitCmd(uint8_t iLen); +static int waitCmd(uint8_t iLen); // structure and database for uid -> tagtype lookups typedef struct { @@ -405,22 +405,8 @@ int CmdHF14AReader(const char *Cmd) // try to see if card responses to "chinese magic backdoor" commands. - c.cmd = CMD_MIFARE_CIDENT; - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("Answers to chinese magic backdoor commands: %s", (isOK ? "YES" : "NO") ); + mfCIdentify(); - // disconnect - c.cmd = CMD_READER_ISO_14443a; - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - return select_status; } @@ -437,7 +423,7 @@ int CmdHF14ACUIDs(const char *Cmd) // repeat n times for (int i = 0; i < n; i++) { // execute anticollision procedure - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}}; SendCommand(&c); UsbCommand resp; @@ -568,6 +554,154 @@ int CmdHF14ASnoop(const char *Cmd) { return 0; } +int CmdHF14AAPDU(const char *cmd) { + uint8_t data[USB_CMD_DATA_SIZE]; + uint16_t datalen = 0; + uint8_t cmdc = 0; + char buf[5] = {0}; + int i = 0; + uint32_t temp; + uint8_t first, second; + bool activateField = false; + bool leaveSignalON = false; + bool decodeTLV = false; + + if (strlen(cmd)<2) { + PrintAndLog("Usage: hf 14a apdu [-s] [-k] [-t] "); + PrintAndLog(" -s activate field and select card"); + PrintAndLog(" -k leave the signal field ON after receive response"); + PrintAndLog(" -t executes TLV decoder if it possible"); + return 0; + } + + // strip + while (*cmd==' ' || *cmd=='\t') cmd++; + + while (cmd[i]!='\0') { + if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; } + if (cmd[i]=='-') { + switch (cmd[i + 1]) { + case 's': + case 'S': + activateField = true; + break; + case 'k': + case 'K': + leaveSignalON = true; + break; + case 't': + case 'T': + decodeTLV = true; + break; + default: + PrintAndLog("Invalid option"); + return 1; + } + i += 2; + continue; + } + if ((cmd[i] >= '0' && cmd[i] <= '9') || + (cmd[i] >= 'a' && cmd[i] <= 'f') || + (cmd[i] >= 'A' && cmd[i] <= 'F') ) { + buf[strlen(buf) + 1] = 0x00; + buf[strlen(buf)] = cmd[i]; + i++; + + if (strlen(buf) >= 2) { + sscanf(buf, "%x", &temp); + data[datalen] = (uint8_t)(temp & 0xff); + *buf = 0; + if (datalen > sizeof(data) - 2) { + PrintAndLog("Buffer is full..."); + break; + } else { + datalen++; + } + } + continue; + } + PrintAndLog("Invalid char on input"); + return 1; + } + if (*buf) { + PrintAndLog("Hex must have even number of digits. Detected %d symbols.", datalen * 2 + strlen(buf)); + return 1; + } + + if (activateField) + cmdc |= ISO14A_CONNECT; + if (leaveSignalON) + cmdc |= ISO14A_NO_DISCONNECT; + + // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 + memmove(data + 1, data, datalen); + data[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) + datalen++; + + ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second); + data[datalen++] = first; + data[datalen++] = second; + + PrintAndLog("--%s %s %s >>>> %s", activateField ? "sel": "", leaveSignalON ? "keep": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); + + // "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 USB_CMD_DATA_SIZE=512 + // timeout timeout14a * 1.06 / 100, true, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106 + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_SET_TIMEOUT | cmdc, (datalen & 0xFFFF), 1000 * 1000 * 1.06 / 100}}; + memcpy(c.d.asBytes, data, datalen); + SendCommand(&c); + + uint8_t *recv; + UsbCommand resp; + + if (activateField) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) + return 2; + if (resp.arg[0] != 1) + return 2; + } + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + recv = resp.d.asBytes; + uint8_t iLen = resp.arg[0]; + if(!iLen) + return 2; + + PrintAndLog("<<<< %s", sprint_hex(recv, iLen)); + + // check apdu length + if (iLen < 5) { + PrintAndLog("ERROR: Small APDU response."); + return 3; + } + + // check block + if (data[0] != recv[0]) { + PrintAndLog("ERROR: Block type mismatch: %02x-%02x", data[0], recv[0]); + return 3; + } + + // CRC Check + ComputeCrc14443(CRC_14443_A, recv, iLen, &first, &second); + if (first || second) { + PrintAndLog("ERROR: ISO 14443A CRC error."); + return 3; + } + + PrintAndLog("APDU response: %02x %02x", recv[iLen - 4], recv[iLen - 3]); // TODO add APDU descriptions + + // here TLV decoder... + if (decodeTLV) { + } + + } else { + PrintAndLog("ERROR: Reply timeout."); + return 3; + } + + return 0; +} int CmdHF14ACmdRaw(const char *cmd) { UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; @@ -576,6 +710,7 @@ int CmdHF14ACmdRaw(const char *cmd) { bool power = false; bool active = false; bool active_select = false; + bool no_rats = false; uint16_t numbits = 0; bool bTimeout = false; uint32_t timeout = 0; @@ -596,6 +731,7 @@ int CmdHF14ACmdRaw(const char *cmd) { PrintAndLog(" -b number of bits to send. Useful for send partial byte"); PrintAndLog(" -t timeout in ms"); PrintAndLog(" -T use Topaz protocol to send command"); + PrintAndLog(" -3 ISO14443-3 select only (skip RATS)"); return 0; } @@ -640,6 +776,9 @@ int CmdHF14ACmdRaw(const char *cmd) { case 'T': topazmode = true; break; + case '3': + no_rats = true; + break; default: PrintAndLog("Invalid option"); return 0; @@ -713,6 +852,10 @@ int CmdHF14ACmdRaw(const char *cmd) { c.arg[0] |= ISO14A_TOPAZMODE; } + if(no_rats) { + c.arg[0] |= ISO14A_NO_RATS; + } + // Max buffer is USB_CMD_DATA_SIZE (512) c.arg[1] = (datalen & 0xFFFF) | ((uint32_t)numbits << 16); memcpy(c.d.asBytes,data,datalen); @@ -720,17 +863,17 @@ int CmdHF14ACmdRaw(const char *cmd) { SendCommand(&c); if (reply) { - if(active_select) - waitCmd(1); - if(datalen>0) + int res = 0; + if (active_select) + res = waitCmd(1); + if (!res && datalen > 0) waitCmd(0); } // if reply return 0; } -static void waitCmd(uint8_t iSelect) -{ +static int waitCmd(uint8_t iSelect) { uint8_t *recv; UsbCommand resp; char *hexout; @@ -740,7 +883,7 @@ static void waitCmd(uint8_t iSelect) uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0]; PrintAndLog("received %i octets", iLen); if(!iLen) - return; + return 1; hexout = (char *)malloc(iLen * 3 + 1); if (hexout != NULL) { for (int i = 0; i < iLen; i++) { // data in hex @@ -750,10 +893,13 @@ static void waitCmd(uint8_t iSelect) free(hexout); } else { PrintAndLog("malloc failed your client has low memory?"); + return 2; } } else { PrintAndLog("timeout while waiting for reply."); + return 3; } + return 0; } static command_t CommandTable[] = @@ -764,6 +910,7 @@ static command_t CommandTable[] = {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443a tag"}, {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, + {"apdu", CmdHF14AAPDU, 0, "Send ISO 1443-4 APDU to tag"}, {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, {NULL, NULL, 0, NULL} };