1
0
mirror of https://github.com/Proxmark/proxmark3.git synced 2025-03-12 04:35:36 -07:00

Emv commands work with smartcard interface (RfidResearchGroup PR67 by @Merlokk) ()

* replace 'hf emv' commands by 'emv' commands
* Enable smartcard commands by default (-DWITH_SMARTCARD)
* update i2c.c from RfidResearchGroup repository
* update smartcard.c from RfidResearchGroup repository
This commit is contained in:
pwpiwi 2019-01-05 09:47:12 +01:00 committed by GitHub
parent 968ad67280
commit 8d7d7b6187
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 811 additions and 750 deletions

@ -22,6 +22,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `lf hitag reader 03` - read block (instead of pages)
- Added `lf hitag reader 04` - read block (instead of pages)
- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok)
- Added `emv` commmands working for both contactless and smart cards (Merlok)
## [v3.1.0][2018-10-10]

@ -24,7 +24,6 @@
#endif
// 定义连接引脚
#define GPIO_RST AT91C_PIO_PA1
#define GPIO_SCL AT91C_PIO_PA5
#define GPIO_SDA AT91C_PIO_PA7
@ -49,14 +48,41 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
for (c = delay * 2; c; c--) {};
}
// 通讯延迟函数 communication delay function
// communication delay functions
#define I2C_DELAY_1CLK I2CSpinDelayClk(1)
#define I2C_DELAY_2CLK I2CSpinDelayClk(2)
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
#define ISO7618_MAX_FRAME 255
// try i2c bus recovery at 100kHz = 5uS high, 5uS low
static void I2C_recovery(void) {
DbpString("Performing i2c bus recovery");
// reset I2C
SDA_H; SCL_H;
//9nth cycle acts as NACK
for (int i = 0; i < 10; i++) {
SCL_H; WaitUS(5);
SCL_L; WaitUS(5);
}
//a STOP signal (SDA from low to high while CLK is high)
SDA_L; WaitUS(5);
SCL_H; WaitUS(2);
SDA_H; WaitUS(2);
bool isok = (SCL_read && SDA_read);
if (!SDA_read)
DbpString("I2C bus recovery error: SDA still LOW");
if (!SCL_read)
DbpString("I2C bus recovery error: SCL still LOW");
if (isok)
DbpString("I2C bus recovery complete");
}
static void I2C_init(void) {
// Configure reset pin
AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST; // disable pull up resistor
@ -72,10 +98,13 @@ static void I2C_init(void) {
// configure all three pins as output, controlled by PIOA
AT91C_BASE_PIOA->PIO_OER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
bool isok = (SCL_read && SDA_read);
if ( !isok )
I2C_recovery();
}
// 设置复位状态
// set the reset state
static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) {
if (LineRST)
@ -94,19 +123,19 @@ static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA
LOW(GPIO_SDA);
}
// 复位进入主程序
// Reset the SIM_Adapter, then enter the main program
// Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter.
static void I2C_Reset_EnterMainProgram(void) {
I2C_SetResetStatus(0, 0, 0); // 拉低复位线
SpinDelay(30);
I2C_SetResetStatus(1, 0, 0); // 解除复位
SpinDelay(30);
I2C_SetResetStatus(1, 1, 1); // 拉高数据线
SpinDelay(10);
StartTicks();
I2C_init();
I2C_SetResetStatus(0, 0, 0);
WaitMS(30);
I2C_SetResetStatus(1, 0, 0);
WaitMS(30);
I2C_SetResetStatus(1, 1, 1);
WaitMS(10);
}
// 等待时钟变高
// Wait for the clock to go High.
static bool WaitSCL_H_delay(uint32_t delay) {
while (delay--) {
@ -184,7 +213,8 @@ static void I2C_SendByte(uint8_t data) {
uint8_t bits = 8;
while (bits--) {
SCL_L; I2C_DELAY_1CLK;
SCL_L;
I2C_DELAY_1CLK;
if (data & 0x80)
SDA_H;
@ -205,7 +235,6 @@ static void I2C_SendByte(uint8_t data) {
}
bool I2C_is_available(void) {
I2C_init();
I2C_Reset_EnterMainProgram();
if (!I2C_Start()) // some other device is active on the bus
return true;
@ -219,14 +248,13 @@ bool I2C_is_available(void) {
}
#ifdef WITH_SMARTCARD
// 复位进入引导模式
// Reset the SIM_Adapter, then enter the bootloader program
// Reserve£ºFor firmware update.
static void I2C_Reset_EnterBootloader(void) {
I2C_SetResetStatus(0, 1, 1); // 拉低复位线
SpinDelay(100);
I2C_SetResetStatus(1, 1, 1); // 解除复位
SpinDelay(10);
I2C_SetResetStatus(0, 1, 1);
WaitMS(100);
I2C_SetResetStatus(1, 1, 1);
WaitMS(10);
}
// Wait max 300ms or until SCL goes LOW.
@ -238,7 +266,7 @@ static bool WaitSCL_L_300ms(void) {
if (!SCL_read)
return true;
SpinDelay(1);
WaitMS(1);
}
return (delay == 0);
}
@ -303,7 +331,7 @@ static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
do {
if (!I2C_Start())
return false;
//[C0]
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
@ -323,7 +351,6 @@ static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
return true;
}
// 写入1字节数据 (待写入数据,待写入地址,器件类型)
// Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ).
static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true;
@ -354,7 +381,6 @@ static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_addre
return true;
}
// 写入1串数据待写入数组地址待写入长度待写入地址器件类型
//Sends a string of data (Array, length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to write 256bytes)
static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
@ -393,7 +419,6 @@ static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint
return true;
}
// 读出1串数据存放读出数据待读出长度带读出地址器件类型
// read 1 strings of data (Data array, Readout length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to read 256bytes)
static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
@ -403,7 +428,7 @@ static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, ui
// extra wait 500us (514us measured)
// 200us (xx measured)
SpinDelayUs(600);
WaitUS(600);
bool bBreak = true;
uint16_t readcount = 0;
@ -462,6 +487,7 @@ static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, ui
}
I2C_Stop();
// return bytecount - first byte (which is length byte)
return --readcount;
}
@ -481,12 +507,10 @@ static int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb,
if (!I2C_WaitAck())
break;
// msb
I2C_SendByte(msb);
if (!I2C_WaitAck())
break;
// lsb
I2C_SendByte(lsb);
if (!I2C_WaitAck())
break;
@ -543,12 +567,10 @@ static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, ui
if (!I2C_WaitAck())
break;
// msb
I2C_SendByte(msb);
if (!I2C_WaitAck())
break;
// lsb
I2C_SendByte(lsb);
if (!I2C_WaitAck())
break;
@ -577,7 +599,6 @@ static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, ui
void I2C_print_status(void) {
DbpString("Smart card module (ISO 7816)");
uint8_t resp[] = {0,0,0,0};
I2C_init();
I2C_Reset_EnterMainProgram();
uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN);
if ( len > 0 )
@ -624,8 +645,6 @@ static bool GetATR(smart_card_atr_t *card_ptr) {
// Send ATR
// start [C0 01] stop start C1 len aa bb cc stop]
I2C_WriteCmd(I2C_DEVICE_CMD_GENERATE_ATR, I2C_DEVICE_ADDRESS_MAIN);
uint8_t cmd[1] = {1};
LogTrace(cmd, 1, 0, 0, NULL, true);
// wait for sim card to answer.
// 1byte = 1ms, max frame 256bytes. Should wait 256ms at least just in case.
@ -659,19 +678,6 @@ static bool GetATR(smart_card_atr_t *card_ptr) {
}
}
// for some reason we only get first byte of atr, if that is so, send dummy command to retrieve the rest of the atr
if (len == 1) {
uint8_t data[1] = {0};
I2C_BufferWrite(data, len, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
if ( !I2C_WaitForSim() )
return false;
uint8_t len2 = I2C_BufferRead(card_ptr->atr + len, sizeof(card_ptr->atr) - len, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
len = len + len2;
}
card_ptr->atr_len = len;
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
@ -683,7 +689,6 @@ void SmartCardAtr(void) {
LED_D_ON();
clear_trace();
set_tracing(true);
I2C_init();
I2C_Reset_EnterMainProgram();
bool isOK = GetATR( &card );
cmd_send(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
@ -706,10 +711,9 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) {
if ((flags & SC_CONNECT)) {
I2C_init();
I2C_Reset_EnterMainProgram();
if ( !(flags & SC_NO_SELECT) ) {
if (flags & SC_SELECT) {
smart_card_atr_t card;
bool gotATR = GetATR( &card );
//cmd_send(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
@ -725,18 +729,21 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) {
// Send raw bytes
// asBytes = A0 A4 00 00 02
// arg1 = len 5
I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
if ( !I2C_WaitForSim() )
goto OUT;
bool res = I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
if ( !res && MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
// read bytes from module
len = ISO7618_MAX_FRAME;
sc_rx_bytes(resp, &len);
LogTrace(resp, len, 0, 0, NULL, false);
res = sc_rx_bytes(resp, &len);
if ( res ) {
LogTrace(resp, len, 0, 0, NULL, false);
} else {
len = 0;
}
}
OUT:
cmd_send(CMD_ACK, len, 0, 0, resp, len);
BigBuf_free();
set_tracing(false);
LEDsoff();
}
@ -749,7 +756,6 @@ void SmartCardUpgrade(uint64_t arg0) {
// write. Sector0, with 11,22,33,44
// erase is 128bytes, and takes 50ms to execute
I2C_init();
I2C_Reset_EnterBootloader();
bool isOK = true;
@ -777,7 +783,7 @@ void SmartCardUpgrade(uint64_t arg0) {
}
// writing takes time.
SpinDelay(50);
WaitMS(50);
// read
res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
@ -799,6 +805,7 @@ void SmartCardUpgrade(uint64_t arg0) {
}
cmd_send(CMD_ACK, isOK, pos, 0, 0, 0);
LED_C_OFF();
BigBuf_free();
}
// unfinished (or not needed?)
@ -808,7 +815,6 @@ void SmartCardUpgrade(uint64_t arg0) {
void SmartCardSetClock(uint64_t arg0) {
LED_D_ON();
set_tracing(true);
I2C_init();
I2C_Reset_EnterMainProgram();
// Send SIM CLC

@ -415,6 +415,8 @@ int CmdHFList(const char *Cmd)
protocol = ISO_14443B;
} else if(strcmp(type,"topaz") == 0) {
protocol = TOPAZ;
} else if(strcmp(type, "7816") == 0) {
protocol = ISO_7816_4;
} else if(strcmp(type,"raw") == 0) {
protocol = -1; //No crc, no annotations
} else if (strcmp(type, "save") == 0) {
@ -592,7 +594,6 @@ static command_t CommandTable[] =
{"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"},
{"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"},
{"epa", CmdHFEPA, 1, "{ German Identification Card... }"},
{"emv", CmdHFEMV, 1, "{ EMV cards... }"},
{"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"},
{"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"},
{"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"},

@ -26,6 +26,7 @@
#include "util.h"
#include "util_posix.h"
#include "cmdscript.h"
#include "emv/cmdemv.h" // EMV
#ifdef WITH_SMARTCARD
#include "cmdsmartcard.h"
#endif
@ -36,18 +37,21 @@ static int CmdQuit(const char *Cmd);
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help. Use '<command> help' for details of a particular command."},
{"data", CmdData, 1, "{ Plot window / data buffer manipulation... }"},
{"hf", CmdHF, 1, "{ High Frequency commands... }"},
{"hw", CmdHW, 1, "{ Hardware commands... }"},
{"lf", CmdLF, 1, "{ Low Frequency commands... }"},
{"help", CmdHelp, 1, "This help. Use '<command> help' for details of a particular command."},
{"data", CmdData, 1, "{ Plot window / data buffer manipulation... }"},
{"hf", CmdHF, 1, "{ High Frequency commands... }"},
{"hw", CmdHW, 1, "{ Hardware commands... }"},
{"lf", CmdLF, 1, "{ Low Frequency commands... }"},
#ifdef WITH_SMARTCARD
{"sc", CmdSmartcard,1,"{ Smartcard commands... }"},
{"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"},
{"sc", CmdSmartcard,1,"{ Smartcard commands... }"},
#else
{"emv", CmdEMV, 1, "{ EMV iso14443 }"},
#endif
{"script",CmdScript,1, "{ Scripting commands }"},
{"quit", CmdQuit, 1, "Exit program"},
{"exit", CmdQuit, 1, "Exit program"},
{NULL, NULL, 0, NULL}
{"script",CmdScript,1, "{ Scripting commands }"},
{"quit", CmdQuit, 1, "Exit program"},
{"exit", CmdQuit, 1, "Exit program"},
{NULL, NULL, 0, NULL}
};
command_t* getTopLevelCommandTable()

@ -8,66 +8,161 @@
// Proxmark3 RDV40 Smartcard module commands
//-----------------------------------------------------------------------------
#include "cmdsmartcard.h"
#include <ctype.h>
#include "ui.h"
#include "cmdparser.h"
#include "util.h"
#include "smartcard.h"
#include "comms.h"
#include "protocols.h"
#include "cmdhf.h" // CmdHFlist
#include "emv/apduinfo.h" // APDUcode description
#include "emv/emvcore.h" // decodeTVL
static int CmdHelp(const char *Cmd);
int usage_sm_raw(void) {
PrintAndLog("Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>");
PrintAndLog(" h : this help");
PrintAndLog(" r : do not read response");
PrintAndLog(" a : active signal field ON without select");
PrintAndLog(" s : active signal field ON with select");
PrintAndLog(" t : executes TLV decoder if it is possible");
PrintAndLog(" d <bytes> : bytes to send");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" sc raw d 11223344");
static int usage_sm_raw(void) {
PrintAndLogEx(NORMAL, "Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " r : do not read response");
PrintAndLogEx(NORMAL, " a : active smartcard without select");
PrintAndLogEx(NORMAL, " s : active smartcard with select");
PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible");
PrintAndLogEx(NORMAL, " d <bytes> : bytes to send");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc raw d 00a404000e315041592e5359532e444446303100 - `1PAY.SYS.DDF01` PPSE directory");
PrintAndLogEx(NORMAL, " sc raw d 00a404000e325041592e5359532e444446303100 - `2PAY.SYS.DDF01` PPSE directory");
return 0;
}
int usage_sm_reader(void) {
PrintAndLog("Usage: sc reader [h|s]");
PrintAndLog(" h : this help");
PrintAndLog(" s : silent (no messages)");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" sc reader");
static int usage_sm_reader(void) {
PrintAndLogEx(NORMAL, "Usage: sc reader [h|s]");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " s : silent (no messages)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc reader");
return 0;
}
int usage_sm_info(void) {
PrintAndLog("Usage: sc info [h|s]");
PrintAndLog(" h : this help");
PrintAndLog(" s : silent (no messages)");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" sc info");
static int usage_sm_info(void) {
PrintAndLogEx(NORMAL, "Usage: s info [h|s]");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " s : silent (no messages)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc info");
return 0;
}
int usage_sm_upgrade(void) {
PrintAndLog("Upgrade firmware");
PrintAndLog("Usage: sc upgrade f <file name>");
PrintAndLog(" h : this help");
PrintAndLog(" f <filename> : firmware file name");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" sc upgrade f myfile");
PrintAndLog("");
PrintAndLog("WARNING - Dangerous command, do wrong and you will brick the smart card socket");
static int usage_sm_upgrade(void) {
PrintAndLogEx(NORMAL, "Upgrade firmware");
PrintAndLogEx(NORMAL, "Usage: sc upgrade f <file name>");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " f <filename> : firmware file name");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc upgrade f myfile");
return 0;
}
int usage_sm_setclock(void) {
PrintAndLog("Usage: sc setclock [h] c <clockspeed>");
PrintAndLog(" h : this help");
PrintAndLog(" c <> : clockspeed (0 = 16mhz, 1=8mhz, 2=4mhz) ");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" sc setclock c 2");
static int usage_sm_setclock(void) {
PrintAndLogEx(NORMAL, "Usage: sc setclock [h] c <clockspeed>");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " c <> : clockspeed (0 = 16mhz, 1=8mhz, 2=4mhz) ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc setclock c 2");
return 0;
}
static int usage_sm_brute(void) {
PrintAndLogEx(NORMAL, "Tries to bruteforce SFI, ");
PrintAndLogEx(NORMAL, "Usage: sc brute [h]");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc brute");
return 0;
}
static bool smart_select(bool silent) {
UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}};
clearCommandBuffer();
SendCommand(&c);
UsbCommand resp;
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return false;
}
uint8_t isok = resp.arg[0] & 0xFF;
if (!isok) {
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return false;
}
if (!silent) {
smart_card_atr_t card;
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
}
return true;
}
static int smart_wait(uint8_t *data) {
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
PrintAndLogEx(WARNING, "smart card response failed");
return -1;
}
uint32_t len = resp.arg[0];
if ( !len ) {
PrintAndLogEx(WARNING, "smart card response failed");
return -2;
}
memcpy(data, resp.d.asBytes, len);
PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 32));
if (len >= 2) {
PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1]));
}
return len;
}
static int smart_response(uint8_t *data) {
int len = -1;
int datalen = smart_wait(data);
if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) {
len = data[datalen - 1];
}
if (len == -1 ) {
goto out;
}
PrintAndLogEx(INFO, "Requesting response. len=0x%x", len);
uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len};
UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}};
memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) );
clearCommandBuffer();
SendCommand(&cStatus);
datalen = smart_wait(data);
out:
return datalen;
}
int CmdSmartRaw(const char *Cmd) {
int hexlen = 0;
@ -99,13 +194,13 @@ int CmdSmartRaw(const char *Cmd) {
case 'd': {
switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) {
case 1:
PrintAndLog("Invalid HEX value.");
PrintAndLogEx(WARNING, "Invalid HEX value.");
return 1;
case 2:
PrintAndLog("Too many bytes. Max %d bytes", sizeof(data));
PrintAndLogEx(WARNING, "Too many bytes. Max %d bytes", sizeof(data));
return 1;
case 3:
PrintAndLog("Hex must have an even number of digits.");
PrintAndLogEx(WARNING, "Hex must have even number of digits.");
return 1;
}
cmdp++;
@ -113,7 +208,7 @@ int CmdSmartRaw(const char *Cmd) {
break;
}
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
@ -130,13 +225,13 @@ int CmdSmartRaw(const char *Cmd) {
UsbCommand c = {CMD_SMART_RAW, {0, hexlen, 0}};
if (active || active_select) {
c.arg[0] |= SC_CONNECT;
if (active)
c.arg[0] |= SC_NO_SELECT;
}
c.arg[0] |= SC_CONNECT;
if (active_select)
c.arg[0] |= SC_SELECT;
}
if (hexlen > 0) {
c.arg[0] |= SC_RAW;
c.arg[0] |= SC_RAW;
}
memcpy(c.d.asBytes, data, hexlen );
@ -145,45 +240,67 @@ int CmdSmartRaw(const char *Cmd) {
// reading response from smart card
if ( reply ) {
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
PrintAndLog("smart card response failed");
return 1;
}
uint32_t datalen = resp.arg[0];
if ( !datalen ) {
PrintAndLog("smart card response failed");
return 1;
}
PrintAndLog("received %i bytes", datalen);
if (!datalen)
uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t));
if ( !buf )
return 1;
uint8_t *data = resp.d.asBytes;
// TLV decoder
if (decodeTLV ) {
if (datalen >= 2) {
PrintAndLog("%02x %02x | %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
}
if (datalen > 4) {
TLVPrintFromBuffer(data, datalen - 2);
}
} else {
PrintAndLog("%s", sprint_hex(data, datalen));
int len = smart_response(buf);
if ( len < 0 ) {
free(buf);
return 2;
}
if ( buf[0] == 0x6C ) {
data[4] = buf[1];
memcpy(c.d.asBytes, data, sizeof(data) );
clearCommandBuffer();
SendCommand(&c);
len = smart_response(buf);
data[4] = 0;
}
if (decodeTLV && len > 4)
TLVPrintFromBuffer(buf+1, len-3);
free(buf);
}
return 0;
}
int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
*dataoutlen = 0;
if (activateCard)
smart_select(false);
printf("* APDU SC\n");
UsbCommand c = {CMD_SMART_RAW, {SC_RAW | SC_CONNECT, datainlen, 0}};
if (activateCard) {
c.arg[0] |= SC_SELECT;
}
memcpy(c.d.asBytes, datain, datainlen);
clearCommandBuffer();
SendCommand(&c);
int len = smart_response(dataout);
if ( len < 0 ) {
return 2;
}
*dataoutlen = len;
return 0;
}
int CmdSmartUpgrade(const char *Cmd) {
PrintAndLog("WARNING - Smartcard socket firmware upgrade.");
PrintAndLog("Dangerous command, do wrong and you will brick the smart card socket");
PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade.");
PrintAndLogEx(WARNING, "A dangerous command, do wrong and you will brick the smart card socket");
FILE *f;
char filename[FILE_PATH_SIZE] = {0};
@ -195,7 +312,7 @@ int CmdSmartUpgrade(const char *Cmd) {
case 'f':
//File handling and reading
if ( param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE ) {
PrintAndLog("Filename too long");
PrintAndLogEx(FAILED, "Filename too long");
errors = true;
break;
}
@ -204,7 +321,7 @@ int CmdSmartUpgrade(const char *Cmd) {
case 'h':
return usage_sm_upgrade();
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
@ -215,8 +332,8 @@ int CmdSmartUpgrade(const char *Cmd) {
// load file
f = fopen(filename, "rb");
if ( !f ) {
PrintAndLog("File: %s: not found or locked.", filename);
if ( !f ){
PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename);
return 1;
}
@ -225,15 +342,15 @@ int CmdSmartUpgrade(const char *Cmd) {
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize < 0) {
PrintAndLog("error, when getting filesize");
if (fsize < 0) {
PrintAndLogEx(WARNING, "error, when getting filesize");
fclose(f);
return 1;
}
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
if (!dump) {
PrintAndLog("error, cannot allocate memory ");
PrintAndLogEx(WARNING, "error, cannot allocate memory ");
fclose(f);
return 1;
}
@ -242,7 +359,7 @@ int CmdSmartUpgrade(const char *Cmd) {
if (f)
fclose(f);
PrintAndLog("Smartcard socket firmware uploading to PM3");
PrintAndLogEx(SUCCESS, "Smartcard socket firmware uploading to PM3");
//Send to device
uint32_t index = 0;
uint32_t bytes_sent = 0;
@ -258,7 +375,7 @@ int CmdSmartUpgrade(const char *Cmd) {
clearCommandBuffer();
SendCommand(&c);
if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000) ) {
PrintAndLog("timeout while waiting for reply.");
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
free(dump);
return 1;
}
@ -269,7 +386,7 @@ int CmdSmartUpgrade(const char *Cmd) {
}
free(dump);
printf("\n");
PrintAndLog("Smartcard socket firmware updating, don\'t turn off your PM3!");
PrintAndLogEx(SUCCESS, "Smartcard socket firmware updating, don\'t turn off your PM3!");
// trigger the firmware upgrade
UsbCommand c = {CMD_SMART_UPGRADE, {bytes_read, 0, 0}};
@ -277,13 +394,13 @@ int CmdSmartUpgrade(const char *Cmd) {
SendCommand(&c);
UsbCommand resp;
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
PrintAndLog("timeout while waiting for reply.");
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1;
}
if ( (resp.arg[0] && 0xFF ) )
PrintAndLog("Smartcard socket firmware upgraded successful");
if ( (resp.arg[0] & 0xFF ) )
PrintAndLogEx(SUCCESS, "Smartcard socket firmware upgraded successful");
else
PrintAndLog("Smartcard socket firmware updating failed");
PrintAndLogEx(FAILED, "Smartcard socket firmware updating failed");
return 0;
}
@ -294,11 +411,11 @@ int CmdSmartInfo(const char *Cmd){
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': return usage_sm_info();
case 's':
case 's':
silent = true;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
@ -313,13 +430,13 @@ int CmdSmartInfo(const char *Cmd){
SendCommand(&c);
UsbCommand resp;
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
if (!silent) PrintAndLog("smart card select failed");
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return 1;
}
uint8_t isok = resp.arg[0] & 0xFF;
if (!isok) {
if (!silent) PrintAndLog("smart card select failed");
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return 1;
}
@ -327,11 +444,11 @@ int CmdSmartInfo(const char *Cmd){
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
// print header
PrintAndLog("\n--- Smartcard Information ---------");
PrintAndLog("-------------------------------------------------------------");
PrintAndLog("ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len));
PrintAndLog("look up ATR");
PrintAndLog("http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) );
PrintAndLogEx(INFO, "\n--- Smartcard Information ---------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, "ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len));
PrintAndLogEx(INFO, "look up ATR");
PrintAndLogEx(INFO, "http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) );
return 0;
}
@ -342,11 +459,11 @@ int CmdSmartReader(const char *Cmd){
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': return usage_sm_reader();
case 's':
case 's':
silent = true;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
@ -361,18 +478,19 @@ int CmdSmartReader(const char *Cmd){
SendCommand(&c);
UsbCommand resp;
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
if (!silent) PrintAndLog("smart card select failed");
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return 1;
}
uint8_t isok = resp.arg[0] & 0xFF;
if (!isok) {
if (!silent) PrintAndLog("smart card select failed");
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return 1;
}
smart_card_atr_t card;
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
PrintAndLog("ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
return 0;
}
@ -383,15 +501,15 @@ int CmdSmartSetClock(const char *Cmd){
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': return usage_sm_setclock();
case 'c':
case 'c':
clock = param_get8ex(Cmd, cmdp+1, 2, 10);
if ( clock > 2)
errors = true;
cmdp += 2;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
@ -405,25 +523,25 @@ int CmdSmartSetClock(const char *Cmd){
SendCommand(&c);
UsbCommand resp;
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
PrintAndLog("smart card select failed");
PrintAndLogEx(WARNING, "smart card select failed");
return 1;
}
uint8_t isok = resp.arg[0] & 0xFF;
if (!isok) {
PrintAndLog("smart card set clock failed");
PrintAndLogEx(WARNING, "smart card set clock failed");
return 1;
}
switch (clock) {
case 0:
PrintAndLog("Clock changed to 16mhz giving 10800 baudrate");
PrintAndLogEx(SUCCESS, "Clock changed to 16mhz giving 10800 baudrate");
break;
case 1:
PrintAndLog("Clock changed to 8mhz giving 21600 baudrate");
PrintAndLogEx(SUCCESS, "Clock changed to 8mhz giving 21600 baudrate");
break;
case 2:
PrintAndLog("Clock changed to 4mhz giving 86400 baudrate");
PrintAndLogEx(SUCCESS, "Clock changed to 4mhz giving 86400 baudrate");
break;
default:
break;
@ -431,267 +549,77 @@ int CmdSmartSetClock(const char *Cmd){
return 0;
}
// iso 7816-3
void annotateIso7816(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
// S-block
if ( (cmd[0] & 0xC0) && (cmdsize == 3) ) {
switch ( (cmd[0] & 0x3f) ) {
case 0x00 : snprintf(exp, size, "S-block RESYNCH req"); break;
case 0x20 : snprintf(exp, size, "S-block RESYNCH resp"); break;
case 0x01 : snprintf(exp, size, "S-block IFS req"); break;
case 0x21 : snprintf(exp, size, "S-block IFS resp"); break;
case 0x02 : snprintf(exp, size, "S-block ABORT req"); break;
case 0x22 : snprintf(exp, size, "S-block ABORT resp"); break;
case 0x03 : snprintf(exp, size, "S-block WTX reqt"); break;
case 0x23 : snprintf(exp, size, "S-block WTX resp"); break;
default : snprintf(exp, size, "S-block"); break;
}
}
// R-block (ack)
else if ( ((cmd[0] & 0xD0) == 0x80) && ( cmdsize > 2) ) {
if ( (cmd[0] & 0x10) == 0 )
snprintf(exp, size, "R-block ACK");
else
snprintf(exp, size, "R-block NACK");
}
// I-block
else {
int pos = (cmd[0] == 2 || cmd[0] == 3) ? 2 : 3;
switch ( cmd[pos] ) {
case ISO7816_READ_BINARY :snprintf(exp, size, "READ BIN");break;
case ISO7816_WRITE_BINARY :snprintf(exp, size, "WRITE BIN");break;
case ISO7816_UPDATE_BINARY :snprintf(exp, size, "UPDATE BIN");break;
case ISO7816_ERASE_BINARY :snprintf(exp, size, "ERASE BIN");break;
case ISO7816_READ_RECORDS :snprintf(exp, size, "READ RECORDS");break;
case ISO7816_WRITE_RECORDS :snprintf(exp, size, "WRITE RECORDS");break;
case ISO7816_APPEND_RECORD :snprintf(exp, size, "APPEND RECORD");break;
case ISO7816_UPDATE_RECORD :snprintf(exp, size, "UPDATE RECORD");break;
case ISO7816_GET_DATA :snprintf(exp, size, "GET DATA");break;
case ISO7816_PUT_DATA :snprintf(exp, size, "PUT DATA");break;
case ISO7816_SELECT_FILE :snprintf(exp, size, "SELECT FILE");break;
case ISO7816_VERIFY :snprintf(exp, size, "VERIFY");break;
case ISO7816_INTERNAL_AUTHENTICATION :snprintf(exp, size, "INTERNAL AUTH");break;
case ISO7816_EXTERNAL_AUTHENTICATION :snprintf(exp, size, "EXTERNAL AUTH");break;
case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break;
case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");break;
default :snprintf(exp, size, "?"); break;
}
}
}
uint16_t printScTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace) {
// sanity check
if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen;
bool isResponse;
uint16_t data_len, parity_len;
uint32_t duration, timestamp, first_timestamp, EndOfTransmissionTimestamp;
char explanation[30] = {0};
first_timestamp = *((uint32_t *)(trace));
timestamp = *((uint32_t *)(trace + tracepos));
tracepos += 4;
duration = *((uint16_t *)(trace + tracepos));
tracepos += 2;
data_len = *((uint16_t *)(trace + tracepos));
tracepos += 2;
if (data_len & 0x8000) {
data_len &= 0x7fff;
isResponse = true;
} else {
isResponse = false;
}
parity_len = (data_len-1)/8 + 1;
if (tracepos + data_len + parity_len > traceLen) {
return traceLen;
}
uint8_t *frame = trace + tracepos;
tracepos += data_len;
//uint8_t *parityBytes = trace + tracepos;
tracepos += parity_len;
//--- Draw the data column
char line[18][110];
if (data_len == 0 ) {
sprintf(line[0],"<empty trace - possible error>");
return tracepos;
}
for (int j = 0; j < data_len && j/18 < 18; j++) {
snprintf(line[j/18]+(( j % 18) * 4),110, "%02x ", frame[j]);
}
EndOfTransmissionTimestamp = timestamp + duration;
annotateIso7816(explanation,sizeof(explanation),frame,data_len);
int num_lines = MIN((data_len - 1)/18 + 1, 18);
for (int j = 0; j < num_lines ; j++) {
if (j == 0) {
PrintAndLog(" %10u | %10u | %s |%-72s | %s| %s",
(timestamp - first_timestamp),
(EndOfTransmissionTimestamp - first_timestamp),
(isResponse ? "Tag" : "Rdr"),
line[j],
" ",
(j == num_lines-1) ? explanation : "");
} else {
PrintAndLog(" | | |%-72s | %s| %s",
line[j],
" ",
(j == num_lines-1) ? explanation : "");
}
}
// if is last record
if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen) return traceLen;
return tracepos;
}
int ScTraceList(const char *Cmd) {
bool loadFromFile = false;
bool saveToFile = false;
char type[5] = {0};
char filename[FILE_PATH_SIZE] = {0};
// parse command line
param_getstr(Cmd, 0, type, sizeof(type));
param_getstr(Cmd, 1, filename, sizeof(filename));
bool errors = false;
if(type[0] == 'h') {
errors = true;
}
if(!errors) {
if (strcmp(type, "s") == 0) {
saveToFile = true;
} else if (strcmp(type,"l") == 0) {
loadFromFile = true;
}
}
if ((loadFromFile || saveToFile) && strlen(filename) == 0) {
errors = true;
}
if (loadFromFile && saveToFile) {
errors = true;
}
if (errors) {
PrintAndLog("List or save protocol data.");
PrintAndLog("Usage: sc list [l <filename>]");
PrintAndLog(" sc list [s <filename>]");
PrintAndLog(" l - load data from file instead of trace buffer");
PrintAndLog(" s - save data to file");
PrintAndLog("");
PrintAndLog("example: sc list");
PrintAndLog("example: sc list save myCardTrace.trc");
PrintAndLog("example: sc list l myCardTrace.trc");
return 0;
}
uint8_t *trace;
uint32_t tracepos = 0;
uint32_t traceLen = 0;
if (loadFromFile) {
#define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions
FILE *tracefile = NULL;
size_t bytes_read;
trace = malloc(TRACE_CHUNK_SIZE);
if (trace == NULL) {
PrintAndLog("Cannot allocate memory for trace");
return 2;
}
if ((tracefile = fopen(filename,"rb")) == NULL) {
PrintAndLog("Could not open file %s", filename);
free(trace);
return 0;
}
while (!feof(tracefile)) {
bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile);
traceLen += bytes_read;
if (!feof(tracefile)) {
uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE);
if (p == NULL) {
PrintAndLog("Cannot allocate memory for trace");
free(trace);
fclose(tracefile);
return 2;
}
trace = p;
}
}
fclose(tracefile);
} else {
trace = malloc(USB_CMD_DATA_SIZE);
// Query for the size of the trace
UsbCommand response;
GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false);
traceLen = response.arg[2];
if (traceLen > USB_CMD_DATA_SIZE) {
uint8_t *p = realloc(trace, traceLen);
if (p == NULL) {
PrintAndLog("Cannot allocate memory for trace");
free(trace);
return 2;
}
trace = p;
GetFromBigBuf(trace, traceLen, 0, NULL, -1, false);
}
}
if (saveToFile) {
FILE *tracefile = NULL;
if ((tracefile = fopen(filename,"wb")) == NULL) {
PrintAndLog("Could not create file %s", filename);
return 1;
}
fwrite(trace, 1, traceLen, tracefile);
PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename);
fclose(tracefile);
} else {
PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen);
PrintAndLog("");
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
PrintAndLog("");
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |");
PrintAndLog("------------|------------|-----|-------------------------------------------------------------------------|-----|--------------------|");
while(tracepos < traceLen)
{
tracepos = printScTraceLine(tracepos, traceLen, trace);
}
}
free(trace);
int CmdSmartList(const char *Cmd) {
CmdHFList("7816");
return 0;
}
int CmdSmartList(const char *Cmd) {
ScTraceList(Cmd);
int CmdSmartBruteforceSFI(const char *Cmd) {
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_sm_brute();
uint8_t data[5] = {0x00, 0xB2, 0x00, 0x00, 0x00};
PrintAndLogEx(INFO, "Selecting card");
if ( !smart_select(false) ) {
return 1;
}
PrintAndLogEx(INFO, "Selecting PPSE aid");
CmdSmartRaw("d 00a404000e325041592e5359532e444446303100");
CmdSmartRaw("d 00a4040007a000000004101000");
PrintAndLogEx(INFO, "starting");
UsbCommand c = {CMD_SMART_RAW, {SC_RAW, sizeof(data), 0}};
uint8_t* buf = malloc(USB_CMD_DATA_SIZE);
if ( !buf )
return 1;
for (uint8_t i=1; i < 4; i++) {
for (int p1=1; p1 < 5; p1++) {
data[2] = p1;
data[3] = (i << 3) + 4;
memcpy(c.d.asBytes, data, sizeof(data) );
clearCommandBuffer();
SendCommand(&c);
smart_response(buf);
// if 0x6C
if ( buf[0] == 0x6C ) {
data[4] = buf[1];
memcpy(c.d.asBytes, data, sizeof(data) );
clearCommandBuffer();
SendCommand(&c);
uint8_t len = smart_response(buf);
// TLV decoder
if (len > 4)
TLVPrintFromBuffer(buf+1, len-3);
data[4] = 0;
}
memset(buf, 0x00, USB_CMD_DATA_SIZE);
}
}
free(buf);
return 0;
}
static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"},
{"list", CmdSmartList, 0, "List ISO 7816 history"},
{"info", CmdSmartInfo, 1, "Tag information [rdv40]"},
{"reader", CmdSmartReader, 1, "Act like an IS07816 reader [rdv40]"},
{"raw", CmdSmartRaw, 1, "Send raw hex data to tag [rdv40]"},
{"upgrade", CmdSmartUpgrade, 1, "Upgrade firmware [rdv40]"},
{"setclock",CmdSmartSetClock, 1, "Set clock speed"},
{"help", CmdHelp, 1, "This help"},
{"list", CmdSmartList, 0, "List ISO 7816 history"},
{"info", CmdSmartInfo, 1, "Tag information"},
{"reader", CmdSmartReader, 1, "Act like an IS07816 reader"},
{"raw", CmdSmartRaw, 1, "Send raw hex data to tag"},
{"upgrade", CmdSmartUpgrade, 1, "Upgrade firmware"},
{"setclock", CmdSmartSetClock, 1, "Set clock speed"},
{"brute", CmdSmartBruteforceSFI, 1, "Bruteforce SFI"},
{NULL, NULL, 0, NULL}
};

@ -11,19 +11,8 @@
#ifndef CMDSMARTCARD_H__
#define CMDSMARTCARD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "util.h"
#include "loclass/fileutils.h" // saveFile
#include "cmdmain.h" // getfromdevice
#include "emv/emvcore.h" // decodeTVL
#include "emv/apduinfo.h" // APDUcode description
#include <stdint.h>
#include <stdbool.h>
extern int CmdSmartcard(const char *Cmd);
@ -32,8 +21,6 @@ extern int CmdSmartUpgrade(const char* cmd);
extern int CmdSmartInfo(const char* cmd);
extern int CmdSmartReader(const char *Cmd);
extern int usage_sm_raw(void);
extern int usage_sm_reader(void);
extern int usage_sm_info(void);
extern int usage_sm_upgrade(void);
extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
#endif

File diff suppressed because it is too large Load Diff

@ -26,7 +26,13 @@
#include "emvcore.h"
#include "apduinfo.h"
int CmdHFEMV(const char *Cmd);
int CmdEMV(const char *Cmd);
extern int CmdEMVSelect(const char *cmd);
extern int CmdEMVSearch(const char *cmd);
extern int CmdEMVPPSE(const char *cmd);
extern int CmdEMVExec(const char *cmd);
extern int CmdEMVGetrng(const char *Cmd);
extern int CmdEMVList(const char *Cmd);
#endif
#endif

@ -11,6 +11,9 @@
#include "emvcore.h"
#include "emvjson.h"
#include "util_posix.h"
#ifdef WITH_SMARTCARD
#include "cmdsmartcard.h"
#endif
// Got from here. Thanks)
// https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix
@ -230,12 +233,13 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) {
return tlvdb_fixed(0x02, dCVVlen, dCVV);
}
int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
uint8_t data[APDU_RES_LEN] = {0};
*ResultLen = 0;
if (sw) *sw = 0;
uint16_t isw = 0;
int res = 0;
if (ActivateField){
DropField();
@ -250,16 +254,32 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ
if (APDULogging)
PrintAndLog(">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc));
// 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le(?IncludeLe)
int res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
if (res) {
return res;
switch(channel) {
case ECC_CONTACTLESS:
// 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le(?IncludeLe)
res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
if (res) {
return res;
}
break;
case ECC_CONTACT:
//int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
#ifdef WITH_SMARTCARD
res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
if (res) {
return res;
}
#endif
break;
}
if (APDULogging)
PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen));
if (*ResultLen < 2) {
return 200;
}
*ResultLen -= 2;
isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1];
if (sw)
@ -285,15 +305,15 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ
return 0;
}
int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchangeEx(false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv);
int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchangeEx(channel, false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv);
}
int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv);
int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv);
}
int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
uint8_t buf[APDU_AID_LEN] = {0};
*ResultLen = 0;
int len = 0;
@ -310,19 +330,19 @@ int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t
}
// select
res = EMVSelect(ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL);
res = EMVSelect(channel, ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL);
return res;
}
int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
uint8_t data[APDU_RES_LEN] = {0};
size_t datalen = 0;
uint16_t sw = 0;
int res;
// select PPSE
res = EMVSelectPSE(ActivateField, true, 2, data, sizeof(data), &datalen, &sw);
res = EMVSelectPSE(channel, ActivateField, true, 2, data, sizeof(data), &datalen, &sw);
if (!res){
struct tlvdb *t = NULL;
@ -336,7 +356,7 @@ int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct t
while (ttmp) {
const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL);
if (tgAID) {
res = EMVSelect(false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv);
res = EMVSelect(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv);
// retry if error and not returned sw error
if (res && res != 5) {
@ -383,7 +403,7 @@ int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct t
return res;
}
int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
uint8_t aidbuf[APDU_AID_LEN] = {0};
int aidlen = 0;
uint8_t data[APDU_RES_LEN] = {0};
@ -394,15 +414,15 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd
int retrycnt = 0;
for(int i = 0; i < AIDlistLen; i ++) {
param_gethex_to_eol(AIDlist[i].aid, 0, aidbuf, sizeof(aidbuf), &aidlen);
res = EMVSelect((i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv);
res = EMVSelect(channel, (i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv);
// retry if error and not returned sw error
if (res && res != 5) {
if (++retrycnt < 3){
i--;
} else {
// card select error, proxmark error
if (res == 1) {
PrintAndLog("Exit...");
// (1) - card select error, proxmark error OR (200) - result length = 0
if (res == 1 || res == 200) {
PrintAndLogEx(WARNING, "Exit...");
return 1;
}
@ -464,38 +484,38 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
return 0;
}
int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
}
int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
if (*sw == 0x6700) {
PrintAndLog(">>> trying to reissue command withouth Le...");
res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le...");
res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
}
return res;
}
int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
}
int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
if (*sw == 0x6700) {
PrintAndLog(">>> trying to reissue command withouth Le...");
res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le...");
res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
}
return res;
}
int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
}
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
}
// Authentication
@ -565,7 +585,7 @@ int trSDA(struct tlvdb *tlv) {
static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
int trDDA(bool decodeTLV, struct tlvdb *tlv) {
int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
@ -705,9 +725,9 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
PrintAndLog("\n* Internal Authenticate");
int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
int res = EMVInternalAuthenticate(channel, true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
if (res) {
PrintAndLog("Internal Authenticate error(%d): %4x. Exit...", res, sw);
PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw);
free(ddol_data_tlv);
emv_pk_free(pk);
emv_pk_free(issuer_pk);

@ -32,6 +32,11 @@
#define APDU_RES_LEN 260
#define APDU_AID_LEN 50
typedef enum {
ECC_CONTACTLESS,
ECC_CONTACT
} EMVCommandChannel;
enum TransactionType {
TT_MSD,
TT_VSDC, // not standart for contactless!!!!
@ -71,29 +76,29 @@ extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2);
extern void SetAPDULogging(bool logging);
// exchange
extern int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// search application
extern int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
extern int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
extern int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// select application
extern int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen);
// Get Processing Options
extern int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// AC
extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// DDA
extern int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
extern int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// Mastercard
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// Auth
extern int trSDA(struct tlvdb *tlv);
extern int trDDA(bool decodeTLV, struct tlvdb *tlv);
extern int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv);
extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv);
extern int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root);

@ -170,17 +170,17 @@ char *fido2GetCmdMemberDescription(uint8_t cmdCode, bool isResponse, int memberN
int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01};
return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL);
return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL);
}
int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
int res = EMVExchange(true, apdu, Result, MaxResultLen, ResultLen, sw, NULL);
int res = EMVExchange(ECC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw, NULL);
if (res == 5) // apdu result (sw) not a 0x9000
res = 0;
// software chaining
while (!res && (*sw >> 8) == 0x61) {
size_t oldlen = *ResultLen;
res = EMVExchange(true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL);
res = EMVExchange(ECC_CONTACTLESS, true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL);
if (res == 5) // apdu result (sw) not a 0x9000
res = 0;

@ -13,6 +13,7 @@ APP_CFLAGS += -DWITH_ISO14443a_StandAlone \
-DWITH_HITAG \
-DWITH_CRC \
-DWITH_HFSNOOP \
-DWITH_SMARTCARD \
-DWITH_GUI
#END

@ -262,6 +262,7 @@ NXP/Philips CUSTOM COMMANDS
#define ISO7816_EXTERNAL_AUTHENTICATION 0x82
#define ISO7816_GET_CHALLENGE 0xB4
#define ISO7816_MANAGE_CHANNEL 0x70
#define ISO7816_GETSTATUS 0xC0
// ISO7816-4 For response APDU's
#define ISO7816_OK 0x9000
// 6x xx = ERROR

@ -22,7 +22,7 @@ typedef enum SMARTCARD_COMMAND {
SC_CONNECT = (1 << 0),
SC_NO_DISCONNECT = (1 << 1),
SC_RAW = (1 << 2),
SC_NO_SELECT = (1 << 3)
SC_SELECT = (1 << 3)
} smartcard_command_t;