From: merlokk <olegmsn@gmail.com>
Date: Wed, 1 Nov 2017 15:13:27 +0000 (+0200)
Subject: Merge branch 'master' of github.com:merlokk/proxmark3 into 14a_rework3
X-Git-Tag: v3.1.0~133^2~9
X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/bed3e4c20d2d885dbc560d21c1e954058145ae51?ds=sidebyside;hp=-c

Merge branch 'master' of github.com:merlokk/proxmark3 into 14a_rework3
---

bed3e4c20d2d885dbc560d21c1e954058145ae51
diff --combined armsrc/iso14443a.c
index 860af238,06a83feb..7d484015
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@@ -1698,6 -1698,13 +1698,13 @@@ int iso14443a_select_card(byte_t *uid_p
  	int cascade_level = 0;
  	int len;
  
+ 	// init card struct
+ 	if(p_hi14a_card) {
+ 		p_hi14a_card->uidlen = 0;
+ 		memset(p_hi14a_card->uid, 0, 10);
+ 		p_hi14a_card->ats_len = 0;
+ 	}
+ 
  	// Broadcast for a card, WUPA (0x52) will force response from all cards in the field
      ReaderTransmitBitsPar(wupa, 7, NULL, NULL);
  	
@@@ -1706,8 -1713,6 +1713,6 @@@
  
  	if(p_hi14a_card) {
  		memcpy(p_hi14a_card->atqa, resp, 2);
- 		p_hi14a_card->uidlen = 0;
- 		memset(p_hi14a_card->uid,0,10);
  	}
  
  	if (anticollision) {
@@@ -1813,12 -1818,10 +1818,11 @@@
  
  	if(p_hi14a_card) {
  		p_hi14a_card->sak = sak;
- 		p_hi14a_card->ats_len = 0;
  	}
  
  	// non iso14443a compliant tag
 -	if( (sak & 0x20) == 0) return 2; 
 +	// https://www.nxp.com/docs/en/application-note/AN10834.pdf page 7
 +	if( (sak & 0x20) != 0) return 2; 
  
  	if (!no_rats) {
  		// Request for answer to select
@@@ -1909,9 -1912,8 +1913,9 @@@ void ReaderIso14443a(UsbCommand *c
  	size_t lenbits = c->arg[1] >> 16;
  	uint32_t timeout = c->arg[2];
  	uint32_t arg0 = 0;
- 	byte_t buf[USB_CMD_DATA_SIZE];
+ 	byte_t buf[USB_CMD_DATA_SIZE] = {0};
  	uint8_t par[MAX_PARITY_SIZE];
 +	bool cantSELECT = false;
    
  	if(param & ISO14A_CONNECT) {
  		clear_trace();
@@@ -1924,19 -1926,11 +1928,19 @@@
  	}
  
  	if(param & ISO14A_CONNECT) {
 +		LED_A_ON();
 +		clear_trace();
  		iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
  		if(!(param & ISO14A_NO_SELECT)) {
  			iso14a_card_select_t *card = (iso14a_card_select_t*)buf;
  			arg0 = iso14443a_select_card(NULL, card, NULL, true, 0, param & ISO14A_NO_RATS);
 +
 +			// if we cant select then we cant send data
 +			cantSELECT = (arg0 != 1);
 +			
 +			LED_B_ON();
  			cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t));
 +			LED_B_OFF();
  		}
  	}
  
@@@ -1944,14 -1938,12 +1948,14 @@@
  		iso14a_set_timeout(timeout);
  	}
  
 -	if(param & ISO14A_APDU) {
 +	if(param & ISO14A_APDU && !cantSELECT) {
  		arg0 = iso14_apdu(cmd, len, buf);
 +		LED_B_ON();
  		cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf));
 +		LED_B_OFF();
  	}
  
 -	if(param & ISO14A_RAW) {
 +	if(param & ISO14A_RAW && !cantSELECT) {
  		if(param & ISO14A_APPEND_CRC) {
  			if(param & ISO14A_TOPAZMODE) {
  				AppendCrc14443b(cmd,len);
@@@ -1987,10 -1979,7 +1991,10 @@@
  			}
  		}
  		arg0 = ReaderReceive(buf, par);
 +
 +		LED_B_ON();
  		cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf));
 +		LED_B_OFF();
  	}
  
  	if(param & ISO14A_REQUEST_TRIGGER) {
diff --combined client/cmdhf14a.c
index 1a7f6970,3f103f5f..f3189c10
--- a/client/cmdhf14a.c
+++ b/client/cmdhf14a.c
@@@ -1,5 -1,5 +1,5 @@@
  //-----------------------------------------------------------------------------
 -// 2011, Merlok
 +// 2011, 2017 Merlok
  // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
  //
  // This code is licensed to you under the terms of the GNU GPL, version 2 or,
@@@ -9,10 -9,33 +9,10 @@@
  // High frequency ISO14443A commands
  //-----------------------------------------------------------------------------
  
 -#include <stdio.h>
 -#include <stdlib.h>
 -#include <inttypes.h>
 -#include <string.h>
 -#include <unistd.h>
 -#include "util.h"
 -#include "util_posix.h"
 -#include "iso14443crc.h"
 -#include "data.h"
 -#include "proxmark3.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"
  
  static int CmdHelp(const char *Cmd);
 -static void waitCmd(uint8_t iLen);
 -
 -// structure and database for uid -> tagtype lookups 
 -typedef struct { 
 -	uint8_t uid;
 -	char* desc;
 -} manufactureName; 
 +static int waitCmd(uint8_t iLen);
  
  const manufactureName manufactureMapping[] = {
  	// ID,  "Vendor Country"
@@@ -87,6 -110,7 +87,6 @@@
  	{ 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	
@@@ -109,7 -133,80 +109,80 @@@ int CmdHF14AList(const char *Cmd
  	return 0;
  }
  
- int CmdHF14AReader(const char *Cmd)
+ int CmdHF14AReader(const char *Cmd) {
+ 	uint32_t cm = ISO14A_CONNECT;
+ 	bool disconnectAfter = false;
+ 	
+ 	int cmdp = 0;
+ 	while(param_getchar(Cmd, cmdp) != 0x00) {
+ 		switch(param_getchar(Cmd, cmdp)) {
+ 		case 'h':
+ 		case 'H':
+ 			PrintAndLog("Usage: hf 14a reader [d] [3]");
+ 			PrintAndLog("       d    drop the signal field after command executed");
+ 			PrintAndLog("       x    just drop the signal field");
+ 			PrintAndLog("       3    ISO14443-3 select only (skip RATS)");
+ 			return 0;
+ 		case '3':
+ 			cm |= ISO14A_NO_RATS; 
+ 			break;
+ 		case 'd':
+ 		case 'D':
+ 			disconnectAfter = true;
+ 			break;
+ 		case 'x':
+ 		case 'X':
+ 			disconnectAfter = true;
+ 			cm = cm - ISO14A_CONNECT;
+ 			break;
+ 		default:
+ 			PrintAndLog("Unknown command.");
+ 			return 1;
+ 		}	
+ 		
+ 		cmdp++;
+ 	}
+ 
+ 	if (!disconnectAfter)
+ 		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 [%d]", 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));
+ 		}
+ 		PrintAndLog("Card is selected. You can now start sending commands");
+ 	} else {
+ 		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);
@@@ -530,170 -627,6 +603,170 @@@ int CmdHF14ASnoop(const char *Cmd) 
  	return 0;
  }
  
 +int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int *dataoutlen) {
 +	uint8_t data[USB_CMD_DATA_SIZE];
 +	int datalen;
 +	uint8_t cmdc = 0;
 +	uint8_t first, second;
 +	
 +	if (activateField)
 +		cmdc |= ISO14A_CONNECT;
 +	if (leaveSignalON)
 +		cmdc |= ISO14A_NO_DISCONNECT;
 +
 +	// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
 +	memcpy(data + 1, datain, datainlen);
 +	data[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00)	
 +	datalen = datainlen + 1;
 +	
 +	ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
 +	data[datalen++] = first;
 +	data[datalen++] = second;
 +
 +	// "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 1;
 +		if (resp.arg[0] != 1)
 +			return 1;
 +	}
 +
 +    if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
 +        recv = resp.d.asBytes;
 +        uint8_t iLen = resp.arg[0];
 +		
 +		*dataoutlen = iLen - 1 - 2;
 +		if (*dataoutlen < 0)
 +			*dataoutlen = 0;
 +		memcpy(dataout, recv + 1, *dataoutlen);
 +		
 +        if(!iLen)
 +            return 1;
 +
 +		// check apdu length
 +		if (iLen < 5) {
 +			PrintAndLog("APDU ERROR: Small APDU response.");
 +			return 2;
 +		}
 +		
 +		// check block
 +		if (data[0] != recv[0]) {
 +			PrintAndLog("APDU ERROR: Block type mismatch: %02x-%02x", data[0], recv[0]);
 +			return 2;
 +		}
 +		
 +		// CRC Check
 +		ComputeCrc14443(CRC_14443_A, recv, iLen, &first, &second);
 +		if (first || second) {
 +			PrintAndLog("APDU ERROR: ISO 14443A CRC error.");
 +			return 3;
 +		}
 +		
 +    } else {
 +        PrintAndLog("APDU ERROR: Reply timeout.");
 +		return 4;
 +    }
 +	
 +	return 0;
 +}
 +
 +int CmdHF14AAPDU(const char *cmd) {
 +	uint8_t data[USB_CMD_DATA_SIZE];
 +	int datalen = 0;
 +	bool activateField = false;
 +	bool leaveSignalON = false;
 +	bool decodeTLV = false;
 +	
 +	if (strlen(cmd) < 2) {
 +		PrintAndLog("Usage: hf 14a apdu [-s] [-k] [-t] <APDU (hex)>");
 +		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. TODO!!!!");
 +		return 0;
 +	}
 +
 +	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;
 +					break;
 +				case 'k':
 +				case 'K':
 +					leaveSignalON = true;
 +					break;
 +				case 't':
 +				case 'T':
 +					decodeTLV = true;
 +					break;
 +				default:
 +					PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
 +					return 1;
 +			}
 +			
 +		if (isxdigit(c)) {
 +			// len = data + PCB(1b) + CRC(2b)
 +			switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data) - 1 - 2, &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;
 +			}
 +			
 +			// we get all the hex to end of line with spaces
 +			break;
 +		}
 +		
 +		cmdp++;
 +	}
 +
 +	PrintAndLog("--%s %s %s >>>> %s", activateField ? "sel": "", leaveSignalON ? "keep": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
 +	
 +	switch(ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, &datalen)) {
 +		case 0:
 +			break;
 +		case 1:
 +			PrintAndLog("APDU ERROR: Send APDU error.");
 +			return 1;
 +		case 2:
 +			return 2;
 +		case 3:
 +			return 3;
 +		case 4:
 +			return 4;
 +		default:
 +			return 5;
 +	}
 +
 +	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])); 
 +
 +	// here 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}};
@@@ -855,27 -788,36 +928,36 @@@
  	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;
  
      if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
          recv = resp.d.asBytes;
-         uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0];
-         PrintAndLog("received %i octets", iLen);
+         uint8_t iLen = resp.arg[0];
+ 		if (iSelect){
+ 			iLen = resp.arg[1];
+ 			if (iLen){
+ 				PrintAndLog("Card selected. UID[%i]:", iLen);
+ 			} else {
+ 				PrintAndLog("Can't select card.");
+ 			}
+ 		} else {
+ 			PrintAndLog("received %i bytes:", 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
@@@ -885,24 -827,21 +967,25 @@@
              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[] = 
  {
    {"help",   CmdHelp,              1, "This help"},
    {"list",   CmdHF14AList,         0, "[Deprecated] List ISO 14443a history"},
-   {"reader", CmdHF14AReader,       0, "Act like an ISO14443 Type A reader"},
+   {"reader", CmdHF14AReader,       0, "Start acting like an ISO14443 Type A reader"},
+   {"info",   CmdHF14AInfo,         0, "Reads card and shows information about it"},
    {"cuids",  CmdHF14ACUIDs,        0, "<n> Collect n>0 ISO14443 Type A UIDs in one go"},
    {"sim",    CmdHF14ASim,          0, "<UID> -- 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}
  };
diff --combined client/cmdhf14a.h
index d11d17eb,2556678d..16e03574
--- a/client/cmdhf14a.h
+++ b/client/cmdhf14a.h
@@@ -12,41 -12,15 +12,42 @@@
  #ifndef CMDHF14A_H__
  #define CMDHF14A_H__
  
 +#include <stdio.h>
  #include <stdint.h>
 +#include <stdlib.h>
 +#include <inttypes.h>
 +#include <string.h>
 +#include <unistd.h>
 +#include "util.h"
 +#include "util_posix.h"
 +#include "iso14443crc.h"
 +#include "data.h"
 +#include "proxmark3.h"
 +#include "ui.h"
 +#include "cmdparser.h"
 +#include "common.h"
 +#include "cmdmain.h"
 +#include "mifare.h"
 +#include "cmdhfmfu.h"
 +#include "mifarehost.h"
 +#include "emv/apduinfo.h"
 +#include "emv/emvcore.h"
 +
 +// structure and database for uid -> tagtype lookups 
 +typedef struct { 
 +	uint8_t uid;
 +	char* desc;
 +} manufactureName; 
  
  int CmdHF14A(const char *Cmd);
  int CmdHF14AList(const char *Cmd);
  int CmdHF14AMifare(const char *Cmd);
  int CmdHF14AReader(const char *Cmd);
+ extern int CmdHF14AInfo(const char *Cmd);
  int CmdHF14ASim(const char *Cmd);
  int CmdHF14ASnoop(const char *Cmd);
  char* getTagInfo(uint8_t uid);
  
 +extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int *dataoutlen);
 +
  #endif