From 2472a76bad8cedc891bbdcd75661743c5d54b583 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 8 Jan 2019 08:05:58 +0100 Subject: [PATCH] Add support for standard USB Smartcard Readers * add PCSC interface (pcsc.c and pcsc.h) * new command 'sc select' to choose an USB Smartcard Reader * updated CI/.travis.yml accordingly --- CI/.travis.yml | 2 +- armsrc/appmain.c | 17 +++- client/Makefile | 17 +++- client/cmdhw.c | 10 +- client/cmdhw.h | 3 + client/cmdsmartcard.c | 46 ++++++++- client/pcsc.c | 228 ++++++++++++++++++++++++++++++++++++++++++ client/pcsc.h | 20 ++++ client/proxmark3.c | 3 + client/util.c | 17 +++- client/util.h | 5 + include/usb_cmd.h | 15 +-- 12 files changed, 365 insertions(+), 18 deletions(-) create mode 100644 client/pcsc.c create mode 100644 client/pcsc.h diff --git a/CI/.travis.yml b/CI/.travis.yml index f5fed7a6..0c02c250 100644 --- a/CI/.travis.yml +++ b/CI/.travis.yml @@ -26,7 +26,7 @@ before_install: echo $REPOSITORY_EP; if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq; - sudo apt-get install -y gcc-arm-none-eabi; + sudo apt-get install -y gcc-arm-none-eabi libpcsclite-dev; elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; if [[ "$REPOSITORY_EP" == "" ]]; then diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 1348ef04..cdc784c0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -34,6 +34,7 @@ #include "LCD.h" #endif +static uint32_t hw_capabilities; // Craig Young - 14a stand-alone code #ifdef WITH_ISO14443a @@ -312,8 +313,22 @@ extern struct version_information version_information; extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__; +void set_hw_capabilities(void) +{ + if (I2C_is_available()) { + hw_capabilities |= HAS_SMARTCARD_SLOT; + } + + if (false) { // TODO: implement a test + hw_capabilities |= HAS_EXTRA_FLASH_MEM; + } +} + + void SendVersion(void) { + set_hw_capabilities(); + char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */ char VersionString[USB_CMD_DATA_SIZE] = { '\0' }; @@ -347,7 +362,7 @@ void SendVersion(void) // Send Chip ID and used flash memory uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start; uint32_t compressed_data_section_size = common_area.arg1; - cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, 0, VersionString, strlen(VersionString)); + cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString)); } // measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. diff --git a/client/Makefile b/client/Makefile index 9ad8efdd..88982299 100644 --- a/client/Makefile +++ b/client/Makefile @@ -35,13 +35,22 @@ APP_CFLAGS = include ../common/Makefile_Enabled_Options.common CFLAGS += $(APP_CFLAGS) ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS))) - SRC_SMARTCARD = cmdsmartcard.c + SRC_SMARTCARD = cmdsmartcard.c pcsc.c else SRC_SMARTCARD = endif -LUAPLATFORM = generic platform = $(shell uname) + +ifneq (,$(findstring MINGW,$(platform))) + PCSC_INCLUDES := + PCSC_LIBS = -lwinscard +else + PCSC_INCLUDES := $(shell pkg-config --cflags libpcsclite) + PCSC_LIBS := $(shell pkg-config --libs libpcsclite) +endif + +LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) LUAPLATFORM = mingw else @@ -258,7 +267,7 @@ all: lua_build jansson_build mbedtls_build cbor_build $(BINS) all-static: LDLIBS:=-static $(LDLIBS) all-static: proxmark3 flasher fpga_compress -proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) +proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) $(PCSC_LIBS) proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua $(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ @@ -327,7 +336,7 @@ $(OBJDIR)/%_AVX512.o : %.c $(OBJDIR)/%.d %.o: %.c $(OBJDIR)/%.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $< + $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) $(PCSC_INCLUDES) -c -o $@ $< $(POSTCOMPILE) %.o: %.cpp diff --git a/client/cmdhw.c b/client/cmdhw.c index f994e938..b6a0d11f 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -20,7 +20,8 @@ #include "cmdmain.h" #include "cmddata.h" -/* low-level hardware control */ + +static uint32_t hw_capabilities = 0; static int CmdHelp(const char *Cmd); @@ -403,6 +404,10 @@ int CmdTune(const char *Cmd) return CmdTuneSamples(Cmd); } +bool PM3hasSmartcardSlot(void) { + return (hw_capabilities & HAS_SMARTCARD_SLOT); +} + int CmdVersion(const char *Cmd) { @@ -411,10 +416,11 @@ int CmdVersion(const char *Cmd) UsbCommand resp = {0, {0, 0, 0}}; SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { PrintAndLog("Prox/RFID mark3 RFID instrument"); PrintAndLog((char*)resp.d.asBytes); lookupChipID(resp.arg[0], resp.arg[1]); + hw_capabilities = resp.arg[2]; } return 0; } diff --git a/client/cmdhw.h b/client/cmdhw.h index b8e10f74..2db2fecc 100644 --- a/client/cmdhw.h +++ b/client/cmdhw.h @@ -11,6 +11,8 @@ #ifndef CMDHW_H__ #define CMDHW_H__ +#include + int CmdHW(const char *Cmd); int CmdDetectReader(const char *Cmd); @@ -23,5 +25,6 @@ int CmdSetDivisor(const char *Cmd); int CmdSetMux(const char *Cmd); int CmdTune(const char *Cmd); int CmdVersion(const char *Cmd); +bool PM3hasSmartcardSlot(void); #endif diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 2eed6d3d..54876b4e 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -18,14 +18,18 @@ #include "smartcard.h" #include "comms.h" #include "protocols.h" +#include "cmdhw.h" #include "cmdhflist.h" #include "emv/apduinfo.h" // APDUcode description #include "emv/emvcore.h" // decodeTVL #include "crypto/libpcrypto.h" // sha512hash #include "emv/dump.h" // dump_buffer +#include "pcsc.h" #define SC_UPGRADE_FILES_DIRECTORY "sc_upgrade_firmware/" +static bool UseAlternativeSmartcardReader = false; // default: use PM3 RDV40 Smartcard Slot (if available) + static int CmdHelp(const char *Cmd); static int usage_sm_raw(void) { @@ -44,6 +48,17 @@ static int usage_sm_raw(void) { return 0; } +static int usage_sm_select(void) { + PrintAndLogEx(NORMAL, "Usage: sc select [h|] "); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " : a card reader's name, wildcards allowed, leave empty to pick from available readers"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc select : list available card readers and pick"); + PrintAndLogEx(NORMAL, " sc select Gemalto* : select a connected Gemalto card reader" ); + return 0; +} + static int usage_sm_reader(void) { PrintAndLogEx(NORMAL, "Usage: sc reader [h|s]"); PrintAndLogEx(NORMAL, " h : this help"); @@ -379,6 +394,32 @@ static int smart_response(uint8_t *data) { return datalen; } + +int CmdSmartSelect(const char *Cmd) { + + const char *readername; + + if (tolower(param_getchar(Cmd, 0)) == 'h') { + return usage_sm_select(); + } + + if (!PM3hasSmartcardSlot() && !pcscCheckForCardReaders()) { + PrintAndLogEx(WARNING, "No Smartcard Readers available"); + UseAlternativeSmartcardReader = false; + return 1; + } + + int bg, en; + if (param_getptr(Cmd, &bg, &en, 0)) { + UseAlternativeSmartcardReader = pcscSelectAlternativeCardReader(NULL); + } else { + readername = Cmd + bg; + UseAlternativeSmartcardReader = pcscSelectAlternativeCardReader(readername); + } + + return 0; +} + int CmdSmartRaw(const char *Cmd) { int hexlen = 0; @@ -584,7 +625,7 @@ int CmdSmartUpgrade(const char *Cmd) { return 1; } - char sha512filename[FILE_PATH_SIZE]; + char sha512filename[FILE_PATH_SIZE] = {'\0'}; char *bin_extension = filename; char *dot_position = NULL; while ((dot_position = strchr(bin_extension, '.')) != NULL) { @@ -595,7 +636,7 @@ int CmdSmartUpgrade(const char *Cmd) { || !strcmp(bin_extension, "bin") #endif ) { - strncpy(sha512filename, filename, strlen(filename) - strlen("bin")); + memcpy(sha512filename, filename, strlen(filename) - strlen("bin")); strcat(sha512filename, "sha512.txt"); } else { PrintAndLogEx(FAILED, "Filename extension of Firmware Upgrade File must be .BIN"); @@ -970,6 +1011,7 @@ int CmdSmartBruteforceSFI(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, + {"select", CmdSmartSelect, 1, "Select the Smartcard Reader to use"}, {"list", CmdSmartList, 0, "List ISO 7816 history"}, {"info", CmdSmartInfo, 0, "Tag information"}, {"reader", CmdSmartReader, 0, "Act like an IS07816 reader"}, diff --git a/client/pcsc.c b/client/pcsc.c new file mode 100644 index 00000000..e7bdb186 --- /dev/null +++ b/client/pcsc.c @@ -0,0 +1,228 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 piwi +// +// 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. +//----------------------------------------------------------------------------- +// PCSC functions to use alternative Smartcard Readers +//----------------------------------------------------------------------------- + +#include "pcsc.h" + +#include +#include +#include +#include +#include "util.h" + +#ifdef __APPLE__ +#include +#include +#else +#include +#endif + +#include "ui.h" + +static SCARDCONTEXT hContext; +static char* AlternativeSmartcardReader = NULL; + + +char *getAlternativeSmartcardReader(void) +{ + return AlternativeSmartcardReader; +} + + +bool pcscCheckForCardReaders(void) +{ + int res = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); + if (res != SCARD_S_SUCCESS) { + return false; + } + + DWORD pcchReaders; + res = SCardListReaders(hContext, NULL, NULL, &pcchReaders); + if (res != SCARD_S_SUCCESS) { + SCardReleaseContext(hContext); + return false; + } + + if (res == SCARD_E_NO_READERS_AVAILABLE || res == SCARD_E_NO_SERVICE) { + SCardReleaseContext(hContext); + return false; + } + + return true; +} + + +static char *pickReader(LPTSTR readerlist) +{ + PrintAndLogEx(NORMAL, "Please select one of these:"); + PrintAndLogEx(NORMAL, " [0] PM3 RDV40 Smartcard Slot"); + + int num = 1; + for (LPTSTR p = readerlist; *p != '\0'; ) { + PrintAndLogEx(NORMAL, " [%1d] %s", num++, p); + while (*p++ != '\0') ; // advance to next entry + } + + num--; + + if (num == 1) { + printf("Your choice (0 or 1)?"); + } else { + printf("Your choice (0...%d)? ", num); + } + int selection = getch() - '0'; + printf("\n"); + + if (selection == 0) { + PrintAndLogEx(INFO, "Selected RDV40 Smartcard Slot"); + return NULL; + } + + if (selection >= 1 && selection <= num) { + LPTSTR p = readerlist; + for (int i = 1; i < selection; i++) { + while (*p++ != '\0') ; // advance to next entry + } + PrintAndLogEx(INFO, "Selected %s", p); + return p; + } + + PrintAndLogEx(INFO, "Invalid selection. Using RDV40 Smartcard Slot"); + return NULL; + +} + + +char *matchString(LPTSTR readerlist, const char *readername) +{ + return pickReader(readerlist); +} + + +bool pcscSelectAlternativeCardReader(const char *readername) +{ + DWORD readerlist_len; + int res = SCardListReaders(hContext, NULL, NULL, &readerlist_len); + if (res != SCARD_S_SUCCESS) { + return false; + } + + LPTSTR readerlist = calloc(readerlist_len, sizeof(char)); + res = SCardListReaders(hContext, NULL, readerlist, &readerlist_len); + if (res != SCARD_S_SUCCESS) { + free(readerlist); + return false; + } + + char *selected_readername = NULL; + if (readername) { + selected_readername = matchString(readerlist, readername); + } else { + selected_readername = pickReader(readerlist); + } + + if (selected_readername == NULL) { + free(readerlist); + return false; + } + + free(AlternativeSmartcardReader); + AlternativeSmartcardReader = malloc((strlen(selected_readername) + 1) * sizeof(char)); + strcpy(AlternativeSmartcardReader, selected_readername); + + return true; +} + +/* +int main(void) +{ + LONG rv; + + SCARDCONTEXT hContext; + LPTSTR mszReaders; + SCARDHANDLE hCard; + DWORD dwReaders, dwActiveProtocol, dwRecvLength; + + SCARD_IO_REQUEST pioSendPci; + BYTE pbRecvBuffer[258]; + BYTE cmd1[] = { 0x00, 0xA4, 0x04, 0x00, 0x0A, 0xA0, + 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01 }; + BYTE cmd2[] = { 0x00, 0x00, 0x00, 0x00 }; + + unsigned int i; + + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); + CHECK("SCardEstablishContext", rv) + +#ifdef SCARD_AUTOALLOCATE + dwReaders = SCARD_AUTOALLOCATE; + + rv = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders); + CHECK("SCardListReaders", rv) +#else + CHECK("SCardListReaders", rv) + + mszReaders = calloc(dwReaders, sizeof(char)); + rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); + CHECK("SCardListReaders", rv) +#endif + printf("reader name: %s\n", mszReaders); + + rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); + CHECK("SCardConnect", rv) + + switch(dwActiveProtocol) + { + case SCARD_PROTOCOL_T0: + pioSendPci = *SCARD_PCI_T0; + break; + + case SCARD_PROTOCOL_T1: + pioSendPci = *SCARD_PCI_T1; + break; + } + dwRecvLength = sizeof(pbRecvBuffer); + rv = SCardTransmit(hCard, &pioSendPci, cmd1, sizeof(cmd1), + NULL, pbRecvBuffer, &dwRecvLength); + CHECK("SCardTransmit", rv) + + printf("response: "); + for(i=0; i + +char *getAlternativeSmartcardReader(void); +bool pcscCheckForCardReaders(void); +bool pcscSelectAlternativeCardReader(const char *readername); + +#endif diff --git a/client/proxmark3.c b/client/proxmark3.c index 6fb066e8..a25ecb41 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -28,6 +28,8 @@ #include "cmdhw.h" #include "whereami.h" #include "comms.h" +#include "pcsc.h" + void #ifdef __has_attribute @@ -48,6 +50,7 @@ main_loop(char *script_cmds_file, char *script_cmd, bool usb_present) { SetOffline(true); } + // file with script FILE *script_file = NULL; char script_cmd_buf[256] = {0}; // iceman, needs lua script the same file_path_buffer as the rest diff --git a/client/util.c b/client/util.c index dec7c5a1..f13d730c 100644 --- a/client/util.c +++ b/client/util.c @@ -52,7 +52,22 @@ int ukbhit(void) return ( error == 0 ? cnt : -1 ); } -#else +char getch(void) +{ + char c; + int error; + struct termios Otty, Ntty; + if ( tcgetattr(STDIN_FILENO, &Otty) == -1 ) return -1; + Ntty = Otty; + Ntty.c_lflag &= ~ICANON; /* disable buffered i/o */ + if (0 == (error = tcsetattr(STDIN_FILENO, TCSANOW, &Ntty))) { // set new attributes + c = getchar(); + error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes + } + return ( error == 0 ? c : -1 ); +} + +#else // _WIN32 #include int ukbhit(void) { diff --git a/client/util.h b/client/util.h index e3549c02..29dd7d5c 100644 --- a/client/util.h +++ b/client/util.h @@ -76,6 +76,11 @@ #endif extern int ukbhit(void); +#ifndef _WIN32 +extern char getch(void); +#else +#include +#endif extern void AddLogLine(char *fileName, char *extData, char *c); extern void AddLogHex(char *fileName, char *extData, const uint8_t * data, const size_t len); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 785435f0..4c27ac85 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -33,6 +33,7 @@ typedef struct { uint32_t asDwords[USB_CMD_DATA_SIZE/4]; } d; } PACKED UsbCommand; + // A struct used to send sample-configs over USB typedef struct{ uint8_t decimation; @@ -63,6 +64,9 @@ typedef struct{ #define CMD_STATUS 0x0108 #define CMD_PING 0x0109 +// controlling the ADC input multiplexer +#define CMD_SET_ADC_MUX 0x020F + // RDV40, Smart card operations #define CMD_SMART_RAW 0x0140 #define CMD_SMART_UPGRADE 0x0141 @@ -86,7 +90,6 @@ typedef struct{ #define CMD_HID_SIM_TAG 0x020C #define CMD_SET_LF_DIVISOR 0x020D #define CMD_LF_SIMULATE_BIDIR 0x020E -#define CMD_SET_ADC_MUX 0x020F #define CMD_HID_CLONE_TAG 0x0210 #define CMD_EM410X_WRITE_TAG 0x0211 #define CMD_INDALA_CLONE_TAG 0x0212 @@ -112,12 +115,8 @@ typedef struct{ #define CMD_VIKING_CLONE_TAG 0x0223 #define CMD_T55XX_WAKEUP 0x0224 #define CMD_COTAG 0x0225 -// misc extra #define CMD_PARADOX_CLONE_TAG 0x0226 - -/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ - // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 #define CMD_READ_SRI512_TAG 0x0303 @@ -136,7 +135,6 @@ typedef struct{ #define CMD_SNOOP_HITAG 0x0370 #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 - #define CMD_SIMULATE_HITAG_S 0x0368 #define CMD_TEST_HITAGS_TRACES 0x0367 #define CMD_READ_HITAG_S 0x0373 @@ -144,7 +142,6 @@ typedef struct{ #define CMD_WR_HITAG_S 0x0375 #define CMD_EMU_HITAG_S 0x0376 - #define CMD_SIMULATE_TAG_ISO_14443B 0x0381 #define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 @@ -251,6 +248,10 @@ typedef struct{ #define FLAG_TUNE_HF 2 #define FLAG_TUNE_ALL 3 +// Hardware capabilities +#define HAS_EXTRA_FLASH_MEM (1 << 0) +#define HAS_SMARTCARD_SLOT (1 << 1) + // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */