diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 50cefc256..605b27450 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1025,9 +1025,8 @@ void UsbPacketReceived(uint8_t *packet, int len) { #ifdef WITH_SMARTCARD case CMD_SMART_SEND: { - I2C_init(); - // sending to smart card. - I2C_Reset_EnterMainProgram(); + I2C_init(); + I2C_Reset_EnterMainProgram(); // sample: // [C0 02] A0 A4 00 00 02 @@ -1041,7 +1040,30 @@ void UsbPacketReceived(uint8_t *packet, int len) { cmd_send(CMD_ACK, len, 0, 0, resp, len); break; - } + } + case CMD_SMART_UPGRADE: { + + I2C_init(); + I2C_Reset_EnterBootloader(); + + uint16_t length = 640; + uint16_t pos = 0; + uint8_t resp[64] = {0}; + while (length) { + + uint8_t msb = (pos >> 8) & 0xFF; + uint8_t lsb = pos & 0xFF; + Dbprintf("FW %02X %02X", msb, lsb); + bool isok = I2C_ReadFW(resp, msb, lsb, I2C_DEVICE_ADDRESS_BOOT); + if (isok) + Dbhexdump(len, resp, false); + + length -= 64; + pos += 64; + } + cmd_send(CMD_ACK, len, 0, 0, resp, sizeof(resp)); + break; + } #endif case CMD_BUFF_CLEAR: diff --git a/client/Makefile b/client/Makefile index c30c36692..e3edb0b08 100644 --- a/client/Makefile +++ b/client/Makefile @@ -82,7 +82,7 @@ else endif # RDV40 flag enables flashmemory commands in client. comment out if you don't have rdv40 -CFLAGS += -DWITH_FLASH +CFLAGS += -DWITH_FLASH -DWITH_SMARTCARD # Flags to generate temporary dependency files DEPFLAGS = -MT $@ -MMD -MP -MF $(OBJDIR)/$*.Td @@ -185,6 +185,7 @@ CMDSRCS = crapto1/crapto1.c \ cmdlfvisa2000.c \ cmdtrace.c \ cmdflashmem.c \ + cmdsmartcard.c \ cmdparser.c \ cmdmain.c \ pm3_binlib.c \ diff --git a/client/cmdmain.c b/client/cmdmain.c index 4b3178289..8cc6a0b60 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -36,8 +36,11 @@ static command_t CommandTable[] = { {"script", CmdScript, 1, "{ Scripting commands }"}, {"trace", CmdTrace, 1, "{ Trace manipulation... }"}, #ifdef WITH_FLASH - {"mem", CmdFlashMem,1, "{ RDV40, Flash Memory manipulation... }"}, -#endif + {"mem", CmdFlashMem, 1, "{ RDV40, Flash Memory manipulation... }"}, +#endif +#ifdef WITH_SMARTCARD + {"sc", CmdSmartcard, 1, "{ RDV40, Smart card ISO7816 commands... }"}, +#endif {"quit", CmdQuit, 1, ""}, {"exit", CmdQuit, 1, "Exit program"}, {NULL, NULL, 0, NULL} diff --git a/client/cmdmain.h b/client/cmdmain.h index 87d303d08..de728e11c 100644 --- a/client/cmdmain.h +++ b/client/cmdmain.h @@ -34,6 +34,7 @@ #include "cmdcrc.h" #include "cmdanalyse.h" #include "cmdflashmem.h" // rdv40 flashmem commands +#include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands //For storing command that are received from the device #define CMD_BUFFER_SIZE 100 diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c new file mode 100644 index 000000000..8853e9180 --- /dev/null +++ b/client/cmdsmartcard.c @@ -0,0 +1,301 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 iceman +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Proxmark3 RDV40 Smartcard module commands +//----------------------------------------------------------------------------- +#include "cmdsmartcard.h" + +static int CmdHelp(const char *Cmd); + +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, " c : calculate and append CRC"); + PrintAndLogEx(NORMAL, " d : bytes to send"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc raw d 11223344"); + return 0; +} +int usage_sm_reader(void) { + PrintAndLogEx(NORMAL, "Usage: s reader [h|s]"); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " s : silent (no messages)"); + return 0; +} +int usage_sm_upgrade(void) { + PrintAndLogEx(NORMAL, "Upgrade firmware"); + PrintAndLogEx(NORMAL, "Usage: sc upgrade f "); + PrintAndLogEx(NORMAL, " f : file name"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc upgrade f myfile"); + return 0; +} + +int CmdSmartRaw(const char *Cmd) { + + int hexlen = 0; + uint8_t cmdp = 0; + bool errors = false; + uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'd': + param_gethex_ex(Cmd, cmdp+1, data, &hexlen); + hexlen >>= 1; + cmdp += 2; + break; + case 'h': + return usage_sm_raw(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0 ) return usage_sm_raw(); + + + UsbCommand c = {CMD_SMART_SEND, {hexlen, 0, 0}}; + memcpy(c.d.asBytes, data, hexlen ); + clearCommandBuffer(); + SendCommand(&c); + + // reading response from smart card + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + PrintAndLogEx(WARNING, "smart card response failed"); + return 1; + } + PrintAndLogEx(SUCCESS,"resp: %s", sprint_hex(resp.d.asBytes, resp.arg[0])); + return 0;; +} +int CmdSmartUpgrade(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_sm_upgrade(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) return usage_sm_upgrade(); + + UsbCommand c = {CMD_SMART_UPGRADE, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + + // reading response from smart card + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + PrintAndLogEx(WARNING, "smart card response failed"); + return 1; + } + //PrintAndLogEx(SUCCESS,"resp: %s", sprint_hex(resp.d.asBytes, resp.arg[0])); + return 0;; +} +/* +int CmdSmartUpgrade(const char *Cmd){ + + FILE *f; + char filename[FILE_PATH_SIZE] = {0}; + uint8_t cmdp = 0; + bool errors = false; + uint32_t start_index = 0; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'f': + //File handling and reading + if ( param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE ) { + PrintAndLogEx(FAILED, "Filename too long"); + errors = true; + break; + } + cmdp += 2; + break; + case 'h': + return usage_sm_upgrade(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0 ) return usage_sm_upgrade(); + + // load file + f = fopen(filename, "rb"); + if ( !f ){ + PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); + return 1; + } + + // get filesize in order to malloc memory + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + if (fsize < 0) { + PrintAndLogDevice(WARNING, "error, when getting filesize"); + fclose(f); + return 1; + } + + if (fsize > FLASH_MEM_MAX_SIZE) { + PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); + fclose(f); + return 1; + } + + uint8_t *dump = calloc(fsize, sizeof(uint8_t)); + if (!dump) { + PrintAndLogDevice(WARNING, "error, cannot allocate memory "); + fclose(f); + return 1; + } + + size_t bytes_read = fread(dump, 1, fsize, f); + if (f) + fclose(f); + + //Send to device + uint32_t bytes_sent = 0; + uint32_t bytes_remaining = bytes_read; + + while (bytes_remaining > 0){ + uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); + + UsbCommand c = {CMD_SMART_UPGRADE, {start_index + bytes_sent, bytes_in_packet, 0}}; + + memcpy(c.d.asBytes, dump + bytes_sent, bytes_in_packet); + clearCommandBuffer(); + SendCommand(&c); + + bytes_remaining -= bytes_in_packet; + bytes_sent += bytes_in_packet; + + UsbCommand resp; + if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + free(dump); + return 1; + } + + uint8_t isok = resp.arg[0] & 0xFF; + if (!isok) + PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); + + } + free(dump); + + PrintAndLogEx(SUCCESS, "Wrote %u bytes to offset %u", bytes_read, start_index); + return 0; +} +*/ +int CmdSmartInfo(const char *Cmd){ + +// char filename[FILE_PATH_SIZE] = {0}; + uint8_t cmdp = 0; + bool errors = false; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_sm_reader(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0 ) return usage_sm_reader(); +/* + PrintAndLogEx(NORMAL, "downloading %u bytes from flashmem", len); + if ( !GetFromDevice(SMARTCARD_FW, dump, len, start_index, NULL, -1, true) ) { + PrintAndLogEx(FAILED, "ERROR; downloading firmware"); + free(dump); + return 1; + } + + saveFile(filename, "bin", dump, len); + free(dump); + */ + return 0; +} +int CmdSmartReader(const char *Cmd){ + + uint8_t cmdp = 0; + bool errors = false; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_sm_reader(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors ) return usage_sm_reader(); + + UsbCommand c = {CMD_SMART_SEND, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return 1; + } + + uint8_t isok = resp.arg[0] & 0xFF; + if (!isok) { + PrintAndLogEx(FAILED, "failed"); + return 1; + } + + // print header + PrintAndLogEx(INFO, "\n--- Smartcard Information ---------"); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + return 0; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"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]"}, + {NULL, NULL, 0, NULL} +}; + +int CmdSmartcard(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdsmartcard.h b/client/cmdsmartcard.h new file mode 100644 index 000000000..d86f63e15 --- /dev/null +++ b/client/cmdsmartcard.h @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 iceman +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Proxmark3 RDV40 Smartcard module commands +//----------------------------------------------------------------------------- + +#ifndef CMDSMARTCARD_H__ +#define CMDSMARTCARD_H__ + +#include +#include +#include +#include +#include "proxmark3.h" +#include "ui.h" +#include "cmdparser.h" +#include "common.h" +#include "util.h" +#include "loclass/fileutils.h" // saveFile +#include "cmdmain.h" // getfromdevice + +extern int CmdSmartcard(const char *Cmd); + +extern int CmdSmartRaw(const char* cmd); +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_upgrade(void); +#endif \ No newline at end of file diff --git a/common/i2c.c b/common/i2c.c index f5e537bfc..c0394200c 100644 --- a/common/i2c.c +++ b/common/i2c.c @@ -316,6 +316,7 @@ uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d if (!I2C_Start()) return 0; + // 0xB0 or 0xC0 i2c write I2C_SendByte(device_address & 0xFE); if (!I2C_WaitAck()) @@ -325,6 +326,7 @@ uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d if (!I2C_WaitAck()) break; + // 0xB1 or 0xC1 read I2C_Start(); I2C_SendByte(device_address | 1); if (!I2C_WaitAck()) @@ -361,6 +363,70 @@ uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d return readcount; } +uint8_t I2C_ReadFW(uint8_t *data, uint8_t msb, uint8_t lsb, uint8_t device_address) { + //START, 0xB0, 0x00, 0x00, START, 0xB1, xx, yy, zz, ......, STOP + + bool bBreak = true; + uint8_t readcount = 0; + + // sending + do { + if (!I2C_Start()) + return 0; + + // 0xB0 or 0xC0 i2c write + I2C_SendByte(device_address & 0xFE); + if (!I2C_WaitAck()) + break; + + // msb + I2C_SendByte(msb); + if (!I2C_WaitAck()) + break; + + // lsb + I2C_SendByte(lsb); + if (!I2C_WaitAck()) + break; + + // 0xB1 or 0xC1 read + I2C_Start(); + I2C_SendByte(device_address | 1); + if (!I2C_WaitAck()) + break; + + bBreak = false; + } while (false); + + if (bBreak) { + I2C_Stop(); + DbpString("I2C_WaitAck Error"); + return 0; + } + + // reading + uint8_t len = 64; + while (len) { + len--; + *data = I2C_ReadByte(); + // 读取的第一个字节为后续长度 + // The first byte read is the message length + if (!readcount && (len > *data)) + len = *data; + + if (len == 0) + I2C_NoAck(); + else + I2C_Ack(); + + data++; + readcount++; + } + + I2C_Stop(); + return readcount; +} + void I2C_print_status(void) { I2C_init(); I2C_Reset_EnterMainProgram(); diff --git a/common/i2c.h b/common/i2c.h index 00850f4a6..03634d658 100644 --- a/common/i2c.h +++ b/common/i2c.h @@ -29,5 +29,8 @@ bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address); bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address); uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address); +// for firmware +uint8_t I2C_ReadFW(uint8_t *data, uint8_t msb, uint8_t lsb, uint8_t device_address); + void I2C_print_status(void); #endif \ No newline at end of file