X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/f1a983a330c983e2858c5b97012c949b243a4db1..2a537311063d3e49479ff4cc8b94287a10c37266:/client/cmdhf14a.c diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 94c3ad2c..94eb8ff3 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2011, Merlok +// 2011, 2017 Merlok // Copyright (C) 2010 iZsh , Hagen Fritsch // // This code is licensed to you under the terms of the GNU GPL, version 2 or, @@ -9,24 +9,28 @@ // High frequency ISO14443A commands //----------------------------------------------------------------------------- +#include "cmdhf14a.h" + #include #include #include #include #include +#include #include "util.h" #include "util_posix.h" #include "iso14443crc.h" -#include "data.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "cmdparser.h" -#include "cmdhf14a.h" #include "common.h" #include "cmdmain.h" #include "mifare.h" #include "cmdhfmfu.h" #include "mifarehost.h" +#include "cliparser/cliparser.h" +#include "emv/apduinfo.h" +#include "emv/emvcore.h" static int CmdHelp(const char *Cmd); static int waitCmd(uint8_t iLen); @@ -37,7 +41,7 @@ typedef struct { char* desc; } manufactureName; -const manufactureName manufactureMapping[] = { +static const manufactureName manufactureMapping[] = { // ID, "Vendor Country" { 0x01, "Motorola UK" }, { 0x02, "ST Microelectronics SA France" }, @@ -110,7 +114,6 @@ const manufactureName manufactureMapping[] = { { 0x00, "no tag-info available" } // must be the last entry }; - // get a product description based on the UID // uid[8] tag uid // returns description of the best match @@ -133,7 +136,78 @@ int CmdHF14AList(const char *Cmd) return 0; } -int CmdHF14AReader(const char *Cmd) +int CmdHF14AReader(const char *Cmd) { + uint32_t cm = ISO14A_CONNECT; + bool leaveSignalON = false; + + CLIParserInit("hf 14a reader", "Executes ISO1443A anticollision-select group of commands.", NULL); + void* argtable[] = { + arg_param_begin, + arg_lit0("kK", "keep", "keep the field active after command executed"), + arg_lit0("xX", "drop", "just drop the signal field"), + arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"), + arg_param_end + }; + if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){ + CLIParserFree(); + return 0; + } + + leaveSignalON = arg_get_lit(1); + if (arg_get_lit(2)) { + cm = cm - ISO14A_CONNECT; + } + if (arg_get_lit(3)) { + cm |= ISO14A_NO_RATS; + } + + CLIParserFree(); + + if (leaveSignalON) + cm |= ISO14A_NO_DISCONNECT; + + UsbCommand c = {CMD_READER_ISO_14443a, {cm, 0, 0}}; + SendCommand(&c); + + if (ISO14A_CONNECT & cm) { + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + if(select_status == 0) { + PrintAndLog("iso14443a card select failed"); + return 1; + } + + if(select_status == 3) { + PrintAndLog("Card doesn't support standard iso14443-3 anticollision"); + PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + return 1; + } + + PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); + if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); + } + if (leaveSignalON) { + PrintAndLog("Card is selected. You can now start sending commands"); + } + } + + if (!leaveSignalON) { + PrintAndLog("Field dropped."); + } + + return 0; +} + +int CmdHF14AInfo(const char *Cmd) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; SendCommand(&c); @@ -169,10 +243,12 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); + PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); + bool isMifareClassic = true; switch (card.sak) { case 0x00: + isMifareClassic = false; //***************************************test**************** // disconnect @@ -405,7 +481,20 @@ int CmdHF14AReader(const char *Cmd) // try to see if card responses to "chinese magic backdoor" commands. - mfCIdentify(); + (void)mfCIdentify(); + + if (isMifareClassic) { + switch(DetectClassicPrng()) { + case 0: + PrintAndLog("Prng detection: HARDENED (hardnested)"); + break; + case 1: + PrintAndLog("Prng detection: WEAK"); + break; + default: + PrintAndLog("Prng detection error."); + } + } return select_status; } @@ -554,139 +643,138 @@ 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; - 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; - } +void DropField() { + UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; + SendCommand(&c); +} - // 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; - } +int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint16_t cmdc = 0; - PrintAndLog("--%s %s %s >>>> %s", activateField ? "sel": "", leaveSignalON ? "keep": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); - - if (activateField) - cmdc |= ISO14A_CONNECT; + if (activateField) { + cmdc |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE; + } if (leaveSignalON) cmdc |= ISO14A_NO_DISCONNECT; - + // "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; - - memcpy(c.d.asBytes, data, datalen); - + // timeout must be authomatically set by "get ATS" + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | cmdc, (datainlen & 0xFFFF), 0}}; + memcpy(c.d.asBytes, datain, datainlen); 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)) { + PrintAndLog("APDU ERROR: Proxmark connection timeout."); + return 1; + } + if (resp.arg[0] != 1) { + PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]); + return 1; + } } if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { recv = resp.d.asBytes; - 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..."); + int iLen = resp.arg[0]; + + *dataoutlen = iLen - 2; + if (*dataoutlen < 0) + *dataoutlen = 0; + + if (maxdataoutlen && *dataoutlen > maxdataoutlen) { + PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); return 2; - } + } + + memcpy(dataout, recv, *dataoutlen); + + if(!iLen) { + PrintAndLog("APDU ERROR: No APDU response."); + return 1; + } + + // check block TODO + if (iLen == -2) { + PrintAndLog("APDU ERROR: Block type mismatch."); + return 2; + } + + // CRC Check + if (iLen == -1) { + PrintAndLog("APDU ERROR: ISO 14443A CRC error."); + return 3; + } + + // check apdu length + if (iLen < 4) { + PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen); + return 2; + } + } else { - PrintAndLog("Reply timeout."); - return 3; + PrintAndLog("APDU ERROR: Reply timeout."); + return 4; } return 0; } +// ISO14443-4. 7. Half-duplex block transmission protocol +int CmdHF14AAPDU(const char *cmd) { + uint8_t data[USB_CMD_DATA_SIZE]; + int datalen = 0; + bool activateField = false; + bool leaveSignalON = false; + bool decodeTLV = false; + + CLIParserInit("hf 14a apdu", + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", + "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("sS", "select", "activate field and select card"), + arg_lit0("kK", "keep", "leave the signal field ON after receive response"), + arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), + arg_strx1(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, false); + + activateField = arg_get_lit(1); + leaveSignalON = arg_get_lit(2); + decodeTLV = arg_get_lit(3); + // len = data + PCB(1b) + CRC(2b) + CLIGetStrBLessWithReturn(4, data, &datalen, 1 + 2); + + + CLIParserFree(); +// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]); + PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); + + int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); + + if (res) + return res; + + PrintAndLog("<<<< %s", sprint_hex(data, datalen)); + + PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); + + // TLV decoder + if (decodeTLV && datalen > 4) { + TLVPrintFromBuffer(data, datalen - 2); + } + + return 0; +} + int CmdHF14ACmdRaw(const char *cmd) { UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; bool reply=1; @@ -699,102 +787,57 @@ int CmdHF14ACmdRaw(const char *cmd) { bool bTimeout = false; uint32_t timeout = 0; bool topazmode = false; - char buf[5]=""; - int i = 0; uint8_t data[USB_CMD_DATA_SIZE]; - uint16_t datalen = 0; - uint32_t temp; - - if (strlen(cmd)<2) { - PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <0A 0B 0C ... hex>"); - PrintAndLog(" -r do not read response"); - PrintAndLog(" -c calculate and append CRC"); - PrintAndLog(" -p leave the signal field ON after receive"); - PrintAndLog(" -a active signal field ON without select"); - PrintAndLog(" -s active signal field ON with select"); - 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)"); + int datalen = 0; + + // extract parameters + CLIParserInit("hf 14a raw", "Send raw hex data to tag", + "Sample:\n"\ + "\thf 14a raw -pa -b7 -t1000 52 -- execute WUPA\n"\ + "\thf 14a raw -p 9320 -- anticollision\n"\ + "\thf 14a raw -psc 60 00 -- select and mifare AUTH\n"); + void* argtable[] = { + arg_param_begin, + arg_lit0("rR", "nreply", "do not read response"), + arg_lit0("cC", "crc", "calculate and append CRC"), + arg_lit0("pP", "power", "leave the signal field ON after receive"), + arg_lit0("aA", "active", "active signal field ON without select"), + arg_lit0("sS", "actives", "active signal field ON with select"), + arg_int0("bB", "bits", NULL, "number of bits to send. Useful for send partial byte"), + arg_int0("t", "timeout", NULL, "timeout in ms"), + arg_lit0("T", "topaz", "use Topaz protocol to send command"), + arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"), + arg_strx1(NULL, NULL, "", NULL), + arg_param_end + }; + // defaults + arg_get_int(6) = 0; + arg_get_int(7) = 0; + + if (CLIParserParseString(cmd, argtable, arg_getsize(argtable), false)){ + CLIParserFree(); 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 'r': - reply = false; - break; - case 'c': - crc = true; - break; - case 'p': - power = true; - break; - case 'a': - active = true; - break; - case 's': - active_select = true; - break; - case 'b': - sscanf(cmd+i+2,"%d",&temp); - numbits = temp & 0xFFFF; - i+=3; - while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } - i-=2; - break; - case 't': - bTimeout = true; - sscanf(cmd+i+2,"%d",&temp); - timeout = temp; - i+=3; - while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } - i-=2; - break; - case 'T': - topazmode = true; - break; - case '3': - no_rats = true; - break; - default: - PrintAndLog("Invalid option"); - return 0; - } - 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]=0; - 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)-1) { - if (crc) - PrintAndLog("Buffer is full, we can't add CRC to your data"); - break; - } else { - datalen++; - } - } - continue; - } - PrintAndLog("Invalid char on input"); - return 0; + + reply = !arg_get_lit(1); + crc = arg_get_lit(2); + power = arg_get_lit(3); + active = arg_get_lit(4); + active_select = arg_get_lit(5); + numbits = arg_get_int(6) & 0xFFFF; + timeout = arg_get_int(7); + bTimeout = (timeout > 0); + topazmode = arg_get_lit(8); + no_rats = arg_get_lit(9); + // len = data + CRC(2b) + if (CLIParamHexToBuf(arg_get_str(10), data, sizeof(data) -2, &datalen)) { + CLIParserFree(); + return 1; } - + + CLIParserFree(); + + // logic if(crc && datalen>0 && datalen 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"}, + {"apdu", CmdHF14AAPDU, 0, "Send an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol"}, {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, {NULL, NULL, 0, NULL} }; int CmdHF14A(const char *Cmd) { - // flush - WaitForResponseTimeout(CMD_ACK,NULL,100); - - // parse - CmdsParse(CommandTable, Cmd); - return 0; + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd)