X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/980417eacd9a054b999ffdd3f83008f543b80c41..8019540b19fe60be30a4a003727260892934a242:/client/cmdhf14a.c diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 472f2fe4..336cb0d2 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 { @@ -556,16 +556,14 @@ int CmdHF14ASnoop(const char *Cmd) { int CmdHF14AAPDU(const char *cmd) { uint8_t data[USB_CMD_DATA_SIZE]; - uint16_t datalen = 0; + int 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) { + 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"); @@ -573,13 +571,11 @@ int CmdHF14AAPDU(const char *cmd) { 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]) { + int cmdp = 0; + while(param_getchar(cmd, cmdp) != 0x00) { + char c = param_getchar(cmd, cmdp); + if ((c == '-') && (param_getlength(cmd, cmdp) == 2)) + switch (param_getchar_indx(cmd, 1, cmdp)) { case 's': case 'S': activateField = true; @@ -593,69 +589,62 @@ int CmdHF14AAPDU(const char *cmd) { decodeTLV = true; break; default: - PrintAndLog("Invalid option"); + PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp)); 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++; - } + + if (isxdigit(c)) { + switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data), &datalen)) { + case 1: + PrintAndLog("Invalid HEX value."); + return 1; + case 2: + PrintAndLog("APDU too large."); + return 1; + case 3: + PrintAndLog("Hex must have even number of digits."); + return 1; } - continue; + + // we get all the hex to end of line with spaces + break; } - PrintAndLog("Invalid char on input"); - return 1; + + cmdp++; } - if (*buf) { - PrintAndLog("Hex must have even number of digits. Detected %d symbols.", datalen * 2 + strlen(buf)); - return 1; - } - PrintAndLog("--%s %s %s >>>> %s", activateField ? "sel": "", leaveSignalON ? "keep": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); - 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_APDU | ISO14A_SET_TIMEOUT | cmdc, (datalen & 0xFFFF), 1000 * 1000 * 1.06 / 100}}; - -// uint8_t first, second; -// ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second); -// data[datalen++] = first; -// data[datalen++] = second; - + 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; - char *hexout; 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)) { @@ -663,22 +652,36 @@ int CmdHF14AAPDU(const char *cmd) { uint8_t iLen = resp.arg[0]; if(!iLen) return 2; - hexout = (char *)malloc(iLen * 3 + 1); - if (hexout != NULL) { - for (int i = 0; i < iLen; i++) { // data in hex - sprintf(&hexout[i * 3], "%02X ", recv[i]); - } - PrintAndLog("<<<< %s", hexout); - - // here TLV decoder... - - free(hexout); - } else { - PrintAndLog("malloc failed..."); - 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("Reply timeout."); + PrintAndLog("ERROR: Reply timeout."); return 3; } @@ -845,17 +848,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; @@ -865,7 +868,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 @@ -875,10 +878,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[] =