From 8a05a4d1d7c24b49caa94bb72f5ff037a0ab8718 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 8 Apr 2021 09:34:11 +0200 Subject: [PATCH] smart raw - now use NG.\nhf iclass config - added more support for keyrollning (WIP)\n --- armsrc/Standalone/hf_iceclass.c | 6 +- armsrc/appmain.c | 2 +- armsrc/i2c.c | 71 ++++---- armsrc/i2c.h | 4 +- armsrc/iclass.c | 22 +-- armsrc/iclass.h | 4 +- client/src/cmdhficlass.c | 296 ++++++++++++++++++++++++-------- client/src/cmdhficlass.h | 5 +- client/src/cmdsmartcard.c | 271 +++++++++++++++++------------ client/src/cmdsmartcard.h | 2 +- client/src/fileutils.c | 4 +- common/cardhelper.c | 13 +- include/mifare.h | 18 -- include/pm3_cmd.h | 29 +++- 14 files changed, 485 insertions(+), 262 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index bbebcab6e..ee34b98e8 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -109,7 +109,7 @@ static bool have_aa2(void) { return memcmp(aa2_key, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8); } -static uint8_t get_pagemap(const picopass_hdr *hdr) { +static uint8_t get_pagemap(const picopass_hdr_t *hdr) { return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; } @@ -322,7 +322,7 @@ static int reader_dump_mode(void) { set_tracing(false); - picopass_hdr *hdr = (picopass_hdr *)card_data; + picopass_hdr_t *hdr = (picopass_hdr_t *)card_data; // select tag. uint32_t eof_time = 0; @@ -458,7 +458,7 @@ static int dump_sim_mode(void) { set_tracing(false); - picopass_hdr *hdr = (picopass_hdr *)card_data; + picopass_hdr_t *hdr = (picopass_hdr_t *)card_data; // select tag. uint32_t eof_time = 0; diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c64a61cbc..7c1bde05b 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1746,7 +1746,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_SMART_RAW: { - SmartCardRaw(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + SmartCardRaw((smart_card_raw_t*)packet->data.asBytes); break; } case CMD_SMART_UPLOAD: { diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 49136d364..dab9108cc 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -32,15 +32,13 @@ #define I2C_ERROR "I2C_WaitAck Error" -//static - // Direct use the loop to delay. 6 instructions loop, Masterclock 48MHz, // delay=1 is about 200kbps // timer. // I2CSpinDelayClk(4) = 12.31us // I2CSpinDelayClk(1) = 3.07us +static volatile uint32_t c; static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) { - volatile uint32_t c; for (c = delay * 2; c; c--) {}; } @@ -101,7 +99,7 @@ void I2C_init(void) { AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST); bool isok = (SCL_read && SDA_read); - if (!isok) + if (isok == false) I2C_recovery(); } @@ -161,7 +159,7 @@ static bool WaitSCL_H_delay(uint32_t delay) { // 5000 * 3.07us = 15350us. 15.35ms // 15000 * 3.07us = 46050us. 46.05ms static bool WaitSCL_H(void) { - return WaitSCL_H_delay(10000); + return WaitSCL_H_delay(15000); } static bool WaitSCL_L_delay(uint32_t delay) { @@ -175,14 +173,14 @@ static bool WaitSCL_L_delay(uint32_t delay) { } // 5000 * 3.07us = 15350us. 15.35ms static bool WaitSCL_L(void) { - return WaitSCL_L_delay(10000); + return WaitSCL_L_delay(15000); } // Wait max 1800ms or until SCL goes LOW. // It timeout reading response from card // Which ever comes first static bool WaitSCL_L_timeout(void) { - volatile uint32_t delay = 1800; + volatile uint32_t delay = 1700; while (delay--) { // exit on SCL LOW if (!SCL_read) @@ -195,7 +193,8 @@ static bool WaitSCL_L_timeout(void) { static bool I2C_Start(void) { - I2C_DELAY_XCLK(4); + I2C_DELAY_2CLK; + I2C_DELAY_2CLK; SDA_H; I2C_DELAY_1CLK; SCL_H; @@ -220,7 +219,7 @@ static bool I2C_WaitForSim(void) { // 8051 speaks with smart card. // 1000*50*3.07 = 153.5ms // 1byte transfer == 1ms with max frame being 256bytes - return WaitSCL_H_delay(10 * 1000 * 50); + return WaitSCL_H_delay(1000 * 300); } // send i2c STOP @@ -233,7 +232,10 @@ static void I2C_Stop(void) { I2C_DELAY_2CLK; if (!WaitSCL_H()) return; SDA_H; - I2C_DELAY_XCLK(8); + I2C_DELAY_2CLK; + I2C_DELAY_2CLK; + I2C_DELAY_2CLK; + I2C_DELAY_2CLK; } // Send i2c ACK @@ -653,7 +655,7 @@ bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) { bool GetATR(smart_card_atr_t *card_ptr, bool verbose) { - if (!card_ptr) + if (card_ptr == NULL) return false; card_ptr->atr_len = 0; @@ -710,53 +712,62 @@ void SmartCardAtr(void) { set_tracing(true); I2C_Reset_EnterMainProgram(); smart_card_atr_t card; - int res = GetATR(&card, true) ? PM3_SUCCESS : PM3_ETIMEOUT; - if (res == PM3_ETIMEOUT) { - I2C_Reset_EnterMainProgram(); + if (GetATR(&card, true)) { + reply_ng(CMD_SMART_ATR, PM3_SUCCESS, (uint8_t *)&card, sizeof(smart_card_atr_t)); + } else { + reply_ng(CMD_SMART_ATR, PM3_ETIMEOUT, NULL, 0); } - reply_ng(CMD_SMART_ATR, res, (uint8_t *)&card, sizeof(smart_card_atr_t)); set_tracing(false); LEDsoff(); +// StopTicks(); } -void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) { - +void SmartCardRaw(smart_card_raw_t *p) { LED_D_ON(); uint8_t len = 0; uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME); - smartcard_command_t flags = arg0; + // check if alloacted... + smartcard_command_t flags = p->flags; if ((flags & SC_CLEARLOG) == SC_CLEARLOG) clear_trace(); if ((flags & SC_LOG) == SC_LOG) set_tracing(true); - else + else set_tracing(false); - if ((flags & SC_CONNECT)) { + if ((flags & SC_CONNECT) == SC_CONNECT) { I2C_Reset_EnterMainProgram(); - if ((flags & SC_SELECT)) { + if ((flags & SC_SELECT) == SC_SELECT) { smart_card_atr_t card; bool gotATR = GetATR(&card, true); //reply_old(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); - if (!gotATR) + if (gotATR == false) { + reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0); goto OUT; + } } } if ((flags & SC_RAW) || (flags & SC_RAW_T0)) { - LogTrace(data, arg1, 0, 0, NULL, true); + LogTrace(p->data, p->len, 0, 0, NULL, true); - // Send raw bytes - // asBytes = A0 A4 00 00 02 - // arg1 = len 5 - bool res = I2C_BufferWrite(data, arg1, ((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), I2C_DEVICE_ADDRESS_MAIN); - if (!res && DBGLEVEL > 3) DbpString(I2C_ERROR); + bool res = I2C_BufferWrite( + p->data, + p->len, + ((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), + I2C_DEVICE_ADDRESS_MAIN + ); + if (res == false && DBGLEVEL > 3) { + DbpString(I2C_ERROR); + reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0); + goto OUT; + } // read bytes from module len = ISO7618_MAX_FRAME; @@ -767,8 +778,10 @@ void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) { len = 0; } } + + reply_ng(CMD_SMART_RAW, PM3_SUCCESS, resp, len); + OUT: - reply_mix(CMD_ACK, len, 0, 0, resp, len); BigBuf_free(); set_tracing(false); LEDsoff(); diff --git a/armsrc/i2c.h b/armsrc/i2c.h index 5f0f6dd18..bf80585eb 100644 --- a/armsrc/i2c.h +++ b/armsrc/i2c.h @@ -2,7 +2,7 @@ #define __I2C_H #include "common.h" -#include "mifare.h" +#include "pm3_cmd.h" #define I2C_DEVICE_ADDRESS_BOOT 0xB0 #define I2C_DEVICE_ADDRESS_MAIN 0xC0 @@ -39,7 +39,7 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose); // generice functions void SmartCardAtr(void); -void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data); +void SmartCardRaw(smart_card_raw_t *packet); void SmartCardUpgrade(uint64_t arg0); void SmartCardSetBaud(uint64_t arg0); void SmartCardSetClock(uint64_t arg0); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index e149254f7..856db35f7 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -35,7 +35,7 @@ #include "ticks.h" #include "iso15693.h" -static uint8_t get_pagemap(const picopass_hdr *hdr) { +static uint8_t get_pagemap(const picopass_hdr_t *hdr) { return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; } @@ -217,7 +217,7 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ //This is 'full sim' mode, where we use the emulator storage for data. //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command - picopass_hdr *hdr = (picopass_hdr *)BigBuf_get_EM_addr(); + picopass_hdr_t *hdr = (picopass_hdr_t *)BigBuf_get_EM_addr(); uint8_t pagemap = get_pagemap(hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { do_iclass_simulation_nonsec(); @@ -1275,7 +1275,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t * * @return false = fail * true = Got all. */ -static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { +static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; @@ -1393,7 +1393,7 @@ static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_ return true; } -bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time) { +bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time) { uint8_t result = 0; return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result); } @@ -1402,7 +1402,7 @@ bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_tim // turn off afterwards void ReaderIClass(uint8_t flags) { - picopass_hdr hdr = {0}; + picopass_hdr_t hdr = {0}; // uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; memset(resp, 0xFF, sizeof(resp)); @@ -1470,7 +1470,7 @@ void ReaderIClass(uint8_t flags) { switch_off(); } -bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out) { +bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out) { uint8_t cmd_check[9] = { ICLASS_CMD_CHECK }; uint8_t mac[4] = {0}; @@ -1538,7 +1538,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; // select card / e-purse - picopass_hdr hdr = {0}; + picopass_hdr_t hdr = {0}; iclass_premac_t *keys = (iclass_premac_t *)datain; @@ -1628,7 +1628,7 @@ void iClass_ReadBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; - picopass_hdr hdr = {0}; + picopass_hdr_t hdr = {0}; bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time); if (res == false) { if (payload->send_reply) { @@ -1701,7 +1701,7 @@ void iClass_Dump(uint8_t *msg) { // select tag. uint32_t eof_time = 0; - picopass_hdr hdr = {0}; + picopass_hdr_t hdr = {0}; bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time); if (res == false) { if (req->send_reply) { @@ -1828,7 +1828,7 @@ void iClass_WriteBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; - picopass_hdr hdr = {0}; + picopass_hdr_t hdr = {0}; uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time); if (res == false) { goto out; @@ -1950,7 +1950,7 @@ void iClass_Restore(iclass_restore_req_t *msg) { uint16_t written = 0; uint32_t eof_time = 0; - picopass_hdr hdr = {0}; + picopass_hdr_t hdr = {0}; // select bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time); diff --git a/armsrc/iclass.h b/armsrc/iclass.h index b41b79ce8..83d6df302 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -34,6 +34,6 @@ bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out); void iClass_ReadBlock(uint8_t *msg); bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time); -bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time); -bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out); +bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time); +bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out); #endif diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 0d785d8df..e40cde2a1 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -30,12 +30,18 @@ #include "cardhelper.h" #include "wiegand_formats.h" #include "wiegand_formatutils.h" +#include "cmdsmartcard.h" // smart select fct #define NUM_CSNS 9 #define ICLASS_KEYS_MAX 8 #define ICLASS_AUTH_RETRY 10 #define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" +static picopass_hdr_t iclass_last_known_card; +static void iclass_set_last_known_card(picopass_hdr_t *card) { + memcpy(&iclass_last_known_card, card, sizeof(picopass_hdr_t)); +} + static uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static int CmdHelp(const char *Cmd); @@ -129,21 +135,21 @@ uint8_t card_app2_limit[] = { }; iclass_config_card_item_t iclass_config_types[14]= { - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, - {"", "", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, + {"", ""}, // must be the last entry - {"no config card info available", "", ""} + {"no config card info available", ""} }; static bool check_config_card(const iclass_config_card_item_t *o) { @@ -156,14 +162,15 @@ static bool check_config_card(const iclass_config_card_item_t *o) { } static int load_config_cards(void) { - PrintAndLogEx(INFO, "Detecting cardhelper..."); - - if (IsCardHelperPresent(false) == false) + PrintAndLogEx(INFO, "detecting cardhelper..."); + if (IsCardHelperPresent(false) == false) { + PrintAndLogEx(FAILED, "failed to detect cardhelper"); return PM3_ENODATA; + } for (int i = 0; i < ARRAYLEN(iclass_config_types); ++i) { - PrintAndLogEx(INPLACE, "loading idx %i", i); + PrintAndLogEx(INPLACE, "loading setting %i", i); iclass_config_card_item_t *ret = &iclass_config_types[i]; uint8_t desc[70] = {0}; @@ -173,8 +180,7 @@ static int load_config_cards(void) { uint8_t blocks[16] = {0}; if (GetConfigCardByIdx(i, blocks) == PM3_SUCCESS) { - memcpy(ret->blk6, blocks, sizeof(ret->blk6)); - memcpy(ret->blk7, blocks + sizeof(ret->blk6), sizeof(ret->blk7)); + memcpy(ret->data, blocks, sizeof(blocks)); } } PrintAndLogEx(NORMAL, ""); @@ -182,9 +188,11 @@ static int load_config_cards(void) { return PM3_SUCCESS; } -static const iclass_config_card_item_t *get_config_card_item(uint8_t idx) { - iclass_config_card_item_t *ret = &iclass_config_types[idx]; - return ret; +static const iclass_config_card_item_t *get_config_card_item(int idx) { + if (idx < 0 && idx > 13) { + idx = 13; + } + return &iclass_config_types[idx]; } static void print_config_cards(void) { @@ -200,15 +208,134 @@ static void print_config_cards(void) { static void print_config_card(const iclass_config_card_item_t *o) { if (check_config_card(o)) { PrintAndLogEx(INFO, "description... %s", o->desc); - PrintAndLogEx(INFO, "block 6....... " _YELLOW_("%s"), sprint_hex_inrow(o->blk6, sizeof(o->blk6))); - PrintAndLogEx(INFO, "block 7....... " _YELLOW_("%s"), sprint_hex_inrow(o->blk7, sizeof(o->blk7))); + PrintAndLogEx(INFO, "data....... " _YELLOW_("%s"), sprint_hex_inrow(o->data, sizeof(o->data))); } } -static void generate_config_card(const iclass_config_card_item_t *o) { - if (check_config_card(o)) { - PrintAndLogEx(INFO, "to be implemented..."); +static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *key, bool got_kr) { + if (check_config_card(o) == false) { + return PM3_EINVARG; } + // get header from card + //bool have = memcmp(iclass_last_known_card.csn, "\x00\x00\x00\x00\x00\x00\x00\x00", 8); + PrintAndLogEx(INFO, "trying to read a card.."); + int res = read_iclass_csn(false, false); + if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Put a card on antenna and try again..."); + return res; + } + + // generate dump file + uint8_t app1_limit = iclass_last_known_card.conf.app_limit; + uint8_t old_limit = app1_limit; + uint8_t tot_bytes = (app1_limit + 1) * 8; + + // normal size + uint8_t *data = calloc(1, tot_bytes); + if (data == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + memset(data, 0xFF, tot_bytes); + + // Keyrolling configuration cards are special. + if (strstr(o->desc, "Keyroll") != NULL) { + + if (got_kr == false) { + PrintAndLogEx(ERR, "please specifiy KEYROLL key!"); + return PM3_EINVARG; + } + + if (app1_limit < 0x16) { + // if card wasn't large enough before, adapt to new size + PrintAndLogEx(WARNING, "Adapting applimit1 for KEY rolling.."); + + app1_limit = 0x16; + iclass_last_known_card.conf.app_limit = 0x16; + tot_bytes = (app1_limit + 1) * 8; + + uint8_t *p; + p = realloc(data, tot_bytes); + if (p == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + free(data); + return PM3_EMALLOC; + } + data = p; + memset(data, 0xFF, tot_bytes); + } + + // need to encrypt + PrintAndLogEx(INFO, "Detecting cardhelper..."); + if (IsCardHelperPresent(false) == false) { + PrintAndLogEx(FAILED, "failed to detect cardhelper"); + return PM3_ENODATA; + } + + uint8_t ffs[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; + if (Encrypt(ffs, ffs) == false) { + PrintAndLogEx(WARNING, "failed to encrypt FF"); + } + + uint8_t enckey1[8]; + if (Encrypt(key, enckey1) == false) { + PrintAndLogEx(WARNING, "failed to encrypt key1"); + } + + memcpy(data, &iclass_last_known_card, sizeof(picopass_hdr_t)); + memcpy(data + (6 * 8), o->data, sizeof(o->data)); + + // encrypted keyroll key 0D + memcpy(data + (0xD * 8), enckey1, sizeof(enckey1)); + // encrypted 0xFF + for (uint8_t i = 0xe; i < 0x14; i++) { + memcpy(data + (i*8), ffs, sizeof(ffs)); + } + + // encrypted partial keyroll key 14 + uint8_t foo[8] = {0x15}; + memcpy(foo + 1, key, 7); + uint8_t enckey2[8]; + if (Encrypt(foo, enckey2) == false) { + PrintAndLogEx(WARNING, "failed to encrypt partial 1"); + } + memcpy(data + (0x14 * 8), enckey2, sizeof(enckey2)); + + // encrypted partial keyroll key 15 + memset(foo, 0xFF, sizeof(foo)); + foo[0] = key[7]; + if (Encrypt(foo, enckey2) == false) { + PrintAndLogEx(WARNING, "failed to encrypt partial 2"); + } + memcpy(data + (0x15 * 8), enckey2, sizeof(enckey2)); + + // encrypted 0xFF + for (uint8_t i = 0x16; i <= app1_limit; i++) { + memcpy(data + (i * 8), ffs, sizeof(ffs)); + } + + + // revert potential modified app1_limit + iclass_last_known_card.conf.app_limit = old_limit; + + } else { + memcpy(data, &iclass_last_known_card, sizeof(picopass_hdr_t)); + memcpy(data + (6*8), o->data, sizeof(o->data)); + } + + // create filename + char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; + fptr += snprintf(fptr, sizeof(filename), "hf-iclass-"); + FillFileNameByUID(fptr, data, "-dump", 8); + + // save dump file + saveFile(filename, ".bin", data, tot_bytes); + saveFileEML(filename, data, tot_bytes, 8); + saveFileJSON(filename, jsfIclass, data, tot_bytes, NULL); + + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f %s.bin") "` to view dump file", filename); + return PM3_SUCCESS; } static uint8_t isset(uint8_t val, uint8_t mask) { @@ -219,11 +346,11 @@ static uint8_t notset(uint8_t val, uint8_t mask) { return !(val & mask); } -uint8_t get_pagemap(const picopass_hdr *hdr) { +uint8_t get_pagemap(const picopass_hdr_t *hdr) { return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; } -static void fuse_config(const picopass_hdr *hdr) { +static void fuse_config(const picopass_hdr_t *hdr) { uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]); @@ -308,7 +435,7 @@ static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, } } -static uint8_t get_mem_config(const picopass_hdr *hdr) { +static uint8_t get_mem_config(const picopass_hdr_t *hdr) { // three configuration bits that decides sizes uint8_t type = (hdr->conf.chip_config & 0x10) >> 2; // 16K bit 0 == 1== @@ -320,7 +447,7 @@ static uint8_t get_mem_config(const picopass_hdr *hdr) { return type; } -static void mem_app_config(const picopass_hdr *hdr) { +static void mem_app_config(const picopass_hdr_t *hdr) { uint8_t mem = hdr->conf.mem_config; uint8_t chip = hdr->conf.chip_config; uint8_t kb = 2; @@ -365,13 +492,13 @@ static void mem_app_config(const picopass_hdr *hdr) { } } -static void print_picopass_info(const picopass_hdr *hdr) { +static void print_picopass_info(const picopass_hdr_t *hdr) { PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------"); fuse_config(hdr); mem_app_config(hdr); } -static void print_picopass_header(const picopass_hdr *hdr) { +static void print_picopass_header(const picopass_hdr_t *hdr) { PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------"); PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); @@ -555,7 +682,7 @@ static int CmdHFiClassSim(const char *Cmd) { saveFile("iclass_mac_attack", ".bin", dump, datalen); free(dump); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -h") "` to recover elite key"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack.bin") "` to recover elite key"); break; } case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: { @@ -621,7 +748,8 @@ static int CmdHFiClassSim(const char *Cmd) { saveFile("iclass_mac_attack_keyroll_B", ".bin", dump, datalen); free(dump); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -h") "` to recover elite key"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack_keyroll_A.bin") "` to recover elite key"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack_keyroll_B.bin") "` to recover elite key"); break; } case ICLASS_SIM_MODE_CSN: @@ -683,9 +811,16 @@ int read_iclass_csn(bool loop, bool verbose) { } } - picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes; - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(hdr->csn, sizeof(hdr->csn))); + picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t)); + if (card) { + memcpy(card, (picopass_hdr_t *)resp.data.asBytes, sizeof(picopass_hdr_t)); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn))); + iclass_set_last_known_card(card); + free(card); + } else { + PrintAndLogEx(FAILED, "failed to allocate memory"); + } } } while (loop && kbd_enter_pressed() == false); @@ -800,8 +935,8 @@ static int CmdHFiClassELoad(const char *Cmd) { dump = newdump; } - print_picopass_header((picopass_hdr *) dump); - print_picopass_info((picopass_hdr *) dump); + print_picopass_header((picopass_hdr_t *) dump); + print_picopass_info((picopass_hdr_t *) dump); // fast push mode conn.block_after_ACK = true; @@ -882,7 +1017,7 @@ static int CmdHFiClassESave(const char *Cmd) { saveFileJSON(filename, jsfIclass, dump, bytes, NULL); free(dump); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view") "` to view dump file"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f %s.bin") "` to view dump file", filename); return PM3_SUCCESS; } @@ -935,8 +1070,8 @@ static int CmdHFiClassEView(const char *Cmd) { } if (verbose) { - print_picopass_header((picopass_hdr *) dump); - print_picopass_info((picopass_hdr *) dump); + print_picopass_header((picopass_hdr_t *) dump); + print_picopass_info((picopass_hdr_t *) dump); } PrintAndLogEx(NORMAL, ""); @@ -1056,7 +1191,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { if (have_file) { - picopass_hdr *hdr = (picopass_hdr *)decrypted; + picopass_hdr_t *hdr = (picopass_hdr_t *)decrypted; uint8_t mem = hdr->conf.mem_config; uint8_t chip = hdr->conf.chip_config; @@ -1291,7 +1426,7 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { return false; } - picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes; + picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes; if (CSN != NULL) memcpy(CSN, hdr->csn, 8); @@ -1436,7 +1571,7 @@ static int CmdHFiClassDump(const char *Cmd) { DropField(); uint8_t readStatus = resp.oldarg[0] & 0xff; - picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes; + picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes; if (readStatus == 0) { PrintAndLogEx(FAILED, "no tag found"); @@ -1645,8 +1780,8 @@ write_dump: saveFileEML(filename, tag_data, bytes_got, 8); saveFileJSON(filename, jsfIclass, tag_data, bytes_got, NULL); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt") "` to decrypt dump file"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view") "` to view dump file"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt -f %s.bin") "` to decrypt dump file", filename); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f %s.bin") "` to view dump file", filename); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -1941,7 +2076,7 @@ static int CmdHFiClassRestore(const char *Cmd) { if (resp.status == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful")); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl ") "` to verify data on card"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl") "` to verify data on card"); } else { PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed")); } @@ -2201,8 +2336,8 @@ static int CmdHFiClass_loclass(const char *Cmd) { void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) { - picopass_hdr *hdr = (picopass_hdr *)iclass_dump; -// picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)iclass_dump; + picopass_hdr_t *hdr = (picopass_hdr_t *)iclass_dump; +// picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)iclass_dump; // uint8_t pagemap = get_pagemap(hdr); // if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { } @@ -2357,8 +2492,8 @@ static int CmdHFiClassView(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - print_picopass_header((picopass_hdr *) dump); - print_picopass_info((picopass_hdr *) dump); + print_picopass_header((picopass_hdr_t *) dump); + print_picopass_info((picopass_hdr_t *) dump); printIclassDumpContents(dump, startblock, endblock, bytes_read); free(dump); return PM3_SUCCESS; @@ -2700,7 +2835,7 @@ static void add_key(uint8_t *key) { if (i == ICLASS_KEYS_MAX) { PrintAndLogEx(INFO, "Couldn't find an empty keyslot"); } else { - PrintAndLogEx(HINT, "Try " _YELLOW_("`hf iclass managekeys -p`") " to view keys"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass managekeys -p") "` to view keys"); } } @@ -3578,14 +3713,17 @@ static int CmdHFiClassConfigCard(const char * Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass configcard", "Manage reader configuration card via Cardhelper", - "hf iclass configcard -l --> download config cards " - "hf iclass configcard -p --> print config card" - "hf iclass configcard -g --ki 1 --> generate config dump file based on idx 1" + "hf iclass configcard -l --> download config cards\n" + "hf iclass configcard -p --> print config card\n" + "hf iclass configcard --ci 1 --> use config card in slot 1\n" + "hf iclass configcard -g --ci 0 --> generate config file from slot 0" + ); void *argtable[] = { arg_param_begin, - arg_int0(NULL, "ki", "", "select index in list"), + arg_int0(NULL, "ci", "", "use config slot at index"), + arg_int0(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), arg_lit0("g", NULL, "generate card dump file"), arg_lit0("l", NULL, "load available cards"), arg_lit0("p", NULL, "print available cards"), @@ -3593,12 +3731,26 @@ static int CmdHFiClassConfigCard(const char * Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - int idx = arg_get_int_def(ctx, 1, -1); - bool generate = arg_get_lit(ctx, 2); - bool load = arg_get_lit(ctx, 3); - bool print = arg_get_lit(ctx, 4); + int ccidx = arg_get_int_def(ctx, 1, -1); + int kidx = arg_get_int_def(ctx, 2, -1); + bool generate = arg_get_lit(ctx, 3); + bool load = arg_get_lit(ctx, 4); + bool print = arg_get_lit(ctx, 5); CLIParserFree(ctx); + bool got_kr = false; + uint8_t key[8] = {0}; + if (kidx >= 0) { + if (kidx < ICLASS_KEYS_MAX) { + got_kr = true; + memcpy(key, iClass_Key_Table[kidx], 8); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), kidx, sprint_hex(iClass_Key_Table[kidx], 8)); + } else { + PrintAndLogEx(ERR, "--ki number is invalid"); + return PM3_EINVARG; + } + } + if (load) { if (load_config_cards() != PM3_SUCCESS) { PrintAndLogEx(INFO, "failed to load, check your cardhelper"); @@ -3609,14 +3761,20 @@ static int CmdHFiClassConfigCard(const char * Cmd) { print_config_cards(); } - if (idx > -1 && idx < 14) { - const iclass_config_card_item_t *item = get_config_card_item(idx); + if (ccidx > -1 && ccidx < 14) { + const iclass_config_card_item_t *item = get_config_card_item(ccidx); print_config_card(item); } if (generate) { - const iclass_config_card_item_t *item = get_config_card_item(idx); - generate_config_card(item); + const iclass_config_card_item_t *item = get_config_card_item(ccidx); + if (strstr(item->desc, "Keyroll") != NULL) { + if (got_kr == false) { + PrintAndLogEx(ERR, "please specifiy KEYROLL key!"); + return PM3_EINVARG; + } + } + generate_config_card(item, key, got_kr); } return PM3_SUCCESS; @@ -3700,8 +3858,8 @@ int info_iclass(void) { return PM3_EOPABORTED; } - picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes; - picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)resp.data.asBytes; + picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes; + picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)resp.data.asBytes; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------"); diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index 06a55122c..f96c9b1b2 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -30,8 +30,7 @@ typedef struct iclass_prekey { typedef struct { char desc[70]; - uint8_t blk6[8]; - uint8_t blk7[8]; + uint8_t data[16]; } iclass_config_card_item_t; int CmdHFiClass(const char *Cmd); @@ -46,6 +45,6 @@ void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elit void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list); void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt); -uint8_t get_pagemap(const picopass_hdr *hdr); +uint8_t get_pagemap(const picopass_hdr_t *hdr); bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key); #endif diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c index c69404432..00d730d62 100644 --- a/client/src/cmdsmartcard.c +++ b/client/src/cmdsmartcard.c @@ -255,28 +255,44 @@ static void PrintATR(uint8_t *atr, size_t atrlen) { } } -static int smart_wait(uint8_t *data, bool verbose) { - int i = 5; +static int smart_wait(uint8_t *out, int maxoutlen, bool verbose) { + int i = 4; uint32_t len = 0; do { clearCommandBuffer(); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_SMART_RAW, &resp, 1000)) { + + if (resp.status != PM3_SUCCESS) { + if (verbose) PrintAndLogEx(WARNING, "smart card response status failed"); + return -3; + } - len = resp.oldarg[0]; + len = resp.length; if (len == 0) { if (verbose) PrintAndLogEx(WARNING, "smart card response failed"); return -2; } - memcpy(data, resp.data.asBytes, len); + if (len > maxoutlen) { + if (verbose) PrintAndLogEx(ERR, "Response too large. Got %u, expected %d", len, maxoutlen); + return -4; + } + + memcpy(out, resp.data.asBytes, len); if (len >= 2) { if (verbose) { - PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1])); + + + if (out[len - 2] == 0x90 && out[len - 1] == 0x00) { + PrintAndLogEx(SUCCESS, _GREEN_("%02X%02X") " | %s", out[len - 2], out[len - 1], GetAPDUCodeDescription(out[len - 2], out[len - 1])); + } else { + PrintAndLogEx(SUCCESS, "%02X%02X | %s", out[len - 2], out[len - 1], GetAPDUCodeDescription(out[len - 2], out[len - 1])); + } } } else { if (verbose) { - PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8)); + PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(out, len, 8)); } } return len; @@ -289,29 +305,35 @@ static int smart_wait(uint8_t *data, bool verbose) { return -1; } -static int smart_responseEx(uint8_t *data, bool verbose) { +static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) { - int datalen = smart_wait(data, verbose); + int datalen = smart_wait(out, maxoutlen, verbose); bool needGetData = false; if (datalen < 2) { goto out; } - if (data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F) { + if (out[datalen - 2] == 0x61 || out[datalen - 2] == 0x9F) { needGetData = true; } if (needGetData) { - int len = data[datalen - 1]; + int len = out[datalen - 1]; - if (verbose) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len); + if (verbose) PrintAndLogEx(INFO, "Requesting " _YELLOW_("0x%02X") " bytes response", len); + + uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len}; + smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(cmd_getresp)); + payload->flags = SC_RAW | SC_LOG; + payload->len = sizeof(cmd_getresp); + memcpy(payload->data, cmd_getresp, sizeof(cmd_getresp)); - uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len}; clearCommandBuffer(); - SendCommandMIX(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus)); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(cmd_getresp)); + free(payload); - datalen = smart_wait(data, verbose); + datalen = smart_wait(out, maxoutlen, verbose); if (datalen < 2) { goto out; @@ -321,16 +343,16 @@ static int smart_responseEx(uint8_t *data, bool verbose) { if (datalen != len + 2) { // data with ACK if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK - if (data[0] != ISO7816_GET_RESPONSE) { + if (out[0] != ISO7816_GET_RESPONSE) { if (verbose) { - PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]); + PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, out[0]); } datalen = 0; goto out; } datalen--; - memmove(data, &data[1], datalen); + memmove(out, &out[1], datalen); } else { // wrong length if (verbose) { @@ -344,8 +366,8 @@ out: return datalen; } -static int smart_response(uint8_t *data) { - return smart_responseEx(data, true); +static int smart_response(uint8_t *out, int maxoutlen) { + return smart_responseEx(out, maxoutlen, true); } static int CmdSmartRaw(const char *Cmd) { @@ -386,61 +408,76 @@ static int CmdSmartRaw(const char *Cmd) { return PM3_EINVARG; } - uint8_t flags = SC_LOG; + smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + dlen); + if (payload == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + payload->len = dlen; + memcpy(payload->data, data, dlen); + + payload->flags = SC_LOG; if (active || active_select) { - flags |= (SC_CONNECT | SC_CLEARLOG); + payload->flags |= (SC_CONNECT | SC_CLEARLOG); if (active_select) - flags |= SC_SELECT; + payload->flags |= SC_SELECT; } - if (dlen > 0) { + if (dlen > 0) { if (use_t0) - flags |= SC_RAW_T0; + payload->flags |= SC_RAW_T0; else - flags |= SC_RAW; + payload->flags |= SC_RAW; + } + + uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); + if (buf == NULL) { + PrintAndLogEx(DEBUG, "failed to allocate memory"); + return PM3_EMALLOC; } clearCommandBuffer(); - SendCommandOLD(CMD_SMART_RAW, flags, dlen, 0, data, dlen); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + dlen); + + if (reply == false) { + goto out; + } // reading response from smart card - if (reply) { - - uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); - if (!buf) - return PM3_EMALLOC; - - int len = smart_response(buf); - if (len < 0) { - free(buf); - return PM3_ESOFT; - } - - if (buf[0] == 0x6C) { - data[4] = buf[1]; - - clearCommandBuffer(); - SendCommandMIX(CMD_SMART_RAW, 0, dlen, 0, data, dlen); - len = smart_response(buf); - - data[4] = 0; - } - - if (decode_tlv && len > 4) - TLVPrintFromBuffer(buf, len - 2); - else { - if (len > 16) { - for (int i = 0; i < len; i += 16) { - PrintAndLogEx(SUCCESS, "%s", sprint_hex_ascii(buf + i, 16)) ; - } - } else { - PrintAndLogEx(SUCCESS, "%s", sprint_hex_ascii(buf, len)) ; - } - } - + int len = smart_response(buf, PM3_CMD_DATA_SIZE); + if (len < 0) { free(buf); + return PM3_ESOFT; } + + if (buf[0] == 0x6C) { + + // request more bytes to download + data[4] = buf[1]; + memcpy(payload->data, data, dlen); + clearCommandBuffer(); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + dlen); + + len = smart_response(buf, PM3_CMD_DATA_SIZE); + + data[4] = 0; + } + + if (decode_tlv && len > 4) + TLVPrintFromBuffer(buf, len - 2); + else { + if (len > 2) { + PrintAndLogEx(INFO, "Response data:"); + PrintAndLogEx(INFO, " # | bytes | ascii"); + PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------"); + print_hex_break(buf, len, 16); + } + } + PrintAndLogEx(NORMAL, ""); +out: + free(payload); + free(buf); return PM3_SUCCESS; } @@ -632,7 +669,7 @@ static int CmdSmartInfo(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_SMART_ATR, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) { + if (WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500) == false) { if (verbose) { PrintAndLogEx(WARNING, "smart card timeout"); } @@ -683,7 +720,6 @@ static int CmdSmartInfo(const char *Cmd) { } static int CmdSmartReader(const char *Cmd) { - CLIParserContext *ctx; CLIParserInit(&ctx, "smart reader", "Act as a smart card reader.", @@ -702,7 +738,7 @@ static int CmdSmartReader(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_SMART_ATR, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) { + if (WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500) == false) { if (verbose) { PrintAndLogEx(WARNING, "smart card select failed"); } @@ -715,10 +751,8 @@ static int CmdSmartReader(const char *Cmd) { } return PM3_ESOFT; } - smart_card_atr_t card; - memcpy(&card, (smart_card_atr_t *)resp.data.asBytes, sizeof(smart_card_atr_t)); - - PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); + smart_card_atr_t *card = (smart_card_atr_t *)resp.data.asBytes; + PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card->atr, card->atr_len)); return PM3_SUCCESS; } @@ -816,17 +850,18 @@ static void smart_brute_prim(void) { for (int i = 0; i < ARRAYLEN(get_card_data); i += 5) { + smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + 5); + payload->flags = SC_RAW_T0; + payload->len = 5; + memcpy(payload->data, get_card_data + i, 5); + clearCommandBuffer(); - SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, 5, 0, get_card_data + i, 5); - - int len = smart_responseEx(buf, false); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + 5); + free(payload); + int len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false); if (len > 2) { - // if ( decodeTLV ) { - // if (!TLVPrintFromBuffer(buf, len-2)) { PrintAndLogEx(SUCCESS, "\tHEX %d |: %s", len, sprint_hex(buf, len)); - // } - // } } } free(buf); @@ -858,21 +893,29 @@ static int smart_brute_sfi(bool decodeTLV) { READ_RECORD[2] = rec; READ_RECORD[3] = (sfi << 3) | 4; - clearCommandBuffer(); - SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD)); + smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(READ_RECORD)); + payload->flags = SC_RAW_T0; + payload->len = sizeof(READ_RECORD); + memcpy(payload->data, READ_RECORD, sizeof(READ_RECORD)); - len = smart_responseEx(buf, false); + clearCommandBuffer(); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(READ_RECORD)); + + len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false); if (buf[0] == 0x6C) { READ_RECORD[4] = buf[1]; + memcpy(payload->data, READ_RECORD, sizeof(READ_RECORD)); clearCommandBuffer(); - SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD)); - len = smart_responseEx(buf, false); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(READ_RECORD)); + len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false); READ_RECORD[4] = 0; } + free(payload); + if (len > 4) { PrintAndLogEx(SUCCESS, "\n\t file %02d, record %02d found", sfi, rec); @@ -898,13 +941,19 @@ static void smart_brute_options(bool decodeTLV) { if (!buf) return; + // Get processing options command uint8_t GET_PROCESSING_OPTIONS[] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00}; - // Get processing options command - clearCommandBuffer(); - SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(GET_PROCESSING_OPTIONS), 0, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS)); + smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(GET_PROCESSING_OPTIONS)); + payload->flags = SC_RAW_T0; + payload->len = sizeof(GET_PROCESSING_OPTIONS); + memcpy(payload->data, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS)); - int len = smart_responseEx(buf, false); + clearCommandBuffer(); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(GET_PROCESSING_OPTIONS)); + free(payload); + + int len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false); if (len > 4) { PrintAndLogEx(SUCCESS, "Got processing options"); if (decodeTLV) { @@ -997,10 +1046,16 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { if (res) continue; - clearCommandBuffer(); - SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, hexlen, 0, cmddata, hexlen); + smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + hexlen); + payload->flags = SC_RAW_T0; + payload->len = hexlen; - int len = smart_responseEx(buf, false); + memcpy(payload->data, cmddata, hexlen); + clearCommandBuffer(); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + hexlen); + free(payload); + + int len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false); if (len < 3) continue; @@ -1072,43 +1127,38 @@ int ExchangeAPDUSC(bool verbose, uint8_t *datain, int datainlen, bool activateCa *dataoutlen = 0; + smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + datainlen); + payload->flags = (SC_RAW_T0 | SC_LOG); if (activateCard) { - if (smart_select(false, NULL) == false) { - PrintAndLogEx(DEBUG, "APDU SC - select card failed"); - return 1; - } - } - - PrintAndLogEx(DEBUG, "APDU SC"); - - uint8_t flags = SC_RAW_T0; - if (activateCard) { - flags |= SC_SELECT | SC_CONNECT; + payload->flags |= (SC_SELECT | SC_CONNECT); } + payload->len = datainlen; + memcpy(payload->data, datain, datainlen); clearCommandBuffer(); - SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + datainlen); - int len = smart_responseEx(dataout, verbose); + int len = smart_responseEx(dataout, maxdataoutlen, verbose); if (len < 0) { return 1; } // retry if (len > 1 && dataout[len - 2] == 0x6c && datainlen > 4) { - uint8_t data [5]; - memcpy(data, datain, 5); + payload->flags = SC_RAW_T0; + payload->len = 5; // transfer length via T=0 - data[4] = dataout[len - 1]; - + datain[4] = dataout[len - 1]; + memcpy(payload->data, datain, 5); clearCommandBuffer(); - // something fishy: we have only 5 bytes but we put datainlen in arg1? - SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data)); - - len = smart_responseEx(dataout, verbose); + SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + 5); + datain[4] = 0; + len = smart_responseEx(dataout, maxdataoutlen, verbose); } + free(payload); + *dataoutlen = len; return 0; } @@ -1120,9 +1170,8 @@ bool smart_select(bool verbose, smart_card_atr_t *atr) { clearCommandBuffer(); SendCommandNG(CMD_SMART_ATR, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) { - - if (verbose) PrintAndLogEx(WARNING, "smart card select failed"); + if (WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500) == false) { + if (verbose) PrintAndLogEx(WARNING, "smart card select timeouted"); return false; } diff --git a/client/src/cmdsmartcard.h b/client/src/cmdsmartcard.h index ca4733724..8bd70b2bd 100644 --- a/client/src/cmdsmartcard.h +++ b/client/src/cmdsmartcard.h @@ -12,7 +12,7 @@ #define CMDSMARTCARD_H__ #include "common.h" -#include "mifare.h" // structs +#include "pm3_cmd.h" // structs int CmdSmartcard(const char *Cmd); diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 6cc29d867..24538497e 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -466,13 +466,13 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, case jsfIclass: { JsonSaveStr(root, "FileType", "iclass"); - picopass_hdr *hdr = (picopass_hdr *)data; + picopass_hdr_t *hdr = (picopass_hdr_t *)data; JsonSaveBufAsHexCompact(root, "$.Card.CSN", hdr->csn, sizeof(hdr->csn)); JsonSaveBufAsHexCompact(root, "$.Card.Configuration", (uint8_t *)&hdr->conf, sizeof(hdr->conf)); uint8_t pagemap = get_pagemap(hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)data; + picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)data; JsonSaveBufAsHexCompact(root, "$.Card.AIA", ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area)); } else { JsonSaveBufAsHexCompact(root, "$.Card.Epurse", hdr->epurse, sizeof(hdr->epurse)); diff --git a/common/cardhelper.c b/common/cardhelper.c index c2206da20..9b7ea9e9e 100644 --- a/common/cardhelper.c +++ b/common/cardhelper.c @@ -23,7 +23,6 @@ #define CARD_INS_PINSIZE 0x08 #define CARD_INS_CC 0x81 #define CARD_INS_CC_DESC 0x82 -static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // look for CardHelper bool IsCardHelperPresent(bool verbose) { @@ -31,7 +30,7 @@ bool IsCardHelperPresent(bool verbose) { if (IfPm3Smartcard()) { int resp_len = 0; uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00}; - uint8_t resp[20] = {0}; + uint8_t resp[30] = {0}; ExchangeAPDUSC(verbose, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); if (resp_len < 8) { @@ -49,14 +48,12 @@ bool IsCardHelperPresent(bool verbose) { } static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) { - int resp_len = 0; - uint8_t dec[11] = {0}; - - cmd[1] = ins; + uint8_t cmd[] = {0x96, ins, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(cmd + 5, src, 8); - ExchangeAPDUSC(false, cmd, sizeof(cmd), false, false, dec, sizeof(dec), &resp_len); - + int resp_len = 0; + uint8_t dec[11] = {0}; + ExchangeAPDUSC(false, cmd, sizeof(cmd), false, true, dec, sizeof(dec), &resp_len); if (resp_len == 10) { memcpy(dest, dec, 8); return true; diff --git a/include/mifare.h b/include/mifare.h index 50bf94861..d31368102 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -121,23 +121,5 @@ typedef struct { } state; } PACKED nonces_t; -//----------------------------------------------------------------------------- -// ISO 7618 Smart Card -//----------------------------------------------------------------------------- -typedef struct { - uint8_t atr_len; - uint8_t atr[50]; -} PACKED smart_card_atr_t; - -typedef enum SMARTCARD_COMMAND { - SC_CONNECT = (1 << 0), - SC_NO_DISCONNECT = (1 << 1), - SC_RAW = (1 << 2), - SC_SELECT = (1 << 3), - SC_RAW_T0 = (1 << 4), - SC_CLEARLOG = (1 << 5), - SC_LOG = (1 << 6), -} smartcard_command_t; - #endif // _MIFARE_H_ diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index a2193a85b..8459bdd22 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -368,14 +368,14 @@ typedef struct { uint8_t key_d[8]; uint8_t key_c[8]; uint8_t app_issuer_area[8]; -} PACKED picopass_hdr; +} PACKED picopass_hdr_t; // iCLASS non-secure mode memory mapping typedef struct { uint8_t csn[8]; picopass_conf_block_t conf; uint8_t app_issuer_area[8]; -} PACKED picopass_ns_hdr; +} PACKED picopass_ns_hdr_t; typedef struct { @@ -393,6 +393,31 @@ typedef struct { uint8_t data[]; } PACKED flashmem_write_t; +//----------------------------------------------------------------------------- +// ISO 7618 Smart Card +//----------------------------------------------------------------------------- +typedef struct { + uint8_t atr_len; + uint8_t atr[50]; +} PACKED smart_card_atr_t; + +typedef enum SMARTCARD_COMMAND { + SC_CONNECT = (1 << 0), + SC_NO_DISCONNECT = (1 << 1), + SC_RAW = (1 << 2), + SC_SELECT = (1 << 3), + SC_RAW_T0 = (1 << 4), + SC_CLEARLOG = (1 << 5), + SC_LOG = (1 << 6), +} smartcard_command_t; + +typedef struct { + uint8_t flags; + uint16_t len; + uint8_t data[]; +} PACKED smart_card_raw_t; + + // For the bootloader #define CMD_DEVICE_INFO 0x0000 //#define CMD_SETUP_WRITE 0x0001