From 032619c1f39791810c8b9e0012631b1d17ee5b7c Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sat, 4 Jan 2025 14:40:51 +0100 Subject: [PATCH 01/13] armsrc/ticks.c: disable TC2 on StopTicks (may be enabled by StartCountSspClk) --- common_arm/ticks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common_arm/ticks.c b/common_arm/ticks.c index 10c3dcb72..c078407ea 100644 --- a/common_arm/ticks.c +++ b/common_arm/ticks.c @@ -305,7 +305,7 @@ uint32_t GetTicks(void) { do { hi = AT91C_BASE_TC1->TC_CV; lo = AT91C_BASE_TC0->TC_CV; - } while (hi != AT91C_BASE_TC1->TC_CV); + } while (hi != AT91C_BASE_TC1->TC_CV); return (hi << 16) | lo; } @@ -336,4 +336,5 @@ void WaitUS(uint32_t us) { void StopTicks(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; } From 661b7bad22ac247acf184635c37591028d94a2b2 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sat, 4 Jan 2025 14:45:44 +0100 Subject: [PATCH 02/13] armsrc/sam_picopass.c: extract common routines to sam_common.c --- armsrc/Makefile | 2 +- armsrc/sam_common.c | 374 ++++++++++++++++++++++++++++++++++++++++++ armsrc/sam_common.h | 49 ++++++ armsrc/sam_mfc.c | 2 +- armsrc/sam_mfc.h | 1 + armsrc/sam_picopass.c | 175 +++++++++++--------- armsrc/sam_picopass.h | 1 + 7 files changed, 527 insertions(+), 77 deletions(-) create mode 100644 armsrc/sam_common.c create mode 100644 armsrc/sam_common.h diff --git a/armsrc/Makefile b/armsrc/Makefile index dedccd3e0..13a817dc9 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -37,7 +37,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \ SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c SRC_HF = hfops.c SRC_ISO15693 = iso15693.c iso15693tools.c -SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_mfc.c sam_seos.c +SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_common.c sam_mfc.c sam_seos.c #UNUSED: mifaresniff.c SRC_ISO14443b = iso14443b.c SRC_FELICA = felica.c diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c new file mode 100644 index 000000000..5c0acbe86 --- /dev/null +++ b/armsrc/sam_common.c @@ -0,0 +1,374 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// Routines to support MFC <-> SAM communication +//----------------------------------------------------------------------------- + + +#include +// #include "sam_picopass.h" +#include "sam_common.h" +#include "iclass.h" +// #include "crc16.h" +#include "proxmark3_arm.h" +#include "BigBuf.h" +// #include "cmd.h" +#include "commonutil.h" +#include "ticks.h" +#include "dbprint.h" +#include "i2c.h" +#include "iso15693.h" +#include "protocols.h" +// #include "optimized_cipher.h" +// #include "fpgaloader.h" + +/** + * @brief Transmits data to and receives data from a HID®'s iCLASS® SE™ Processor. + * + * This function sends a specified number of bytes to the SAM and receives a response. + * + * @param data Pointer to the data to be transmitted. + * @param n Number of bytes to be transmitted. + * @param resp Pointer to the buffer where the response will be stored. + * @param resplen Pointer to the variable where the length of the response will be stored. + * @return Status code indicating success or failure of the operation. + */ +int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen) { + bool res = I2C_BufferWrite(data, n, I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN); + if (res == false) { + DbpString("failed to send to SIM CARD"); + goto out; + } + + *resplen = ISO7816_MAX_FRAME; + + res = sc_rx_bytes(resp, resplen, SIM_WAIT_DELAY); + if (res == false) { + DbpString("failed to receive from SIM CARD"); + goto out; + } + + if (*resplen < 2) { + DbpString("received too few bytes from SIM CARD"); + res = false; + goto out; + } + + uint16_t more_len = 0; + + if (resp[*resplen - 2] == 0x61 || resp[*resplen - 2] == 0x9F) { + more_len = resp[*resplen - 1]; + } else { + // we done, return + goto out; + } + + // Don't discard data we already received except the SW code. + // If we only received 1 byte, this is the echo of INS, we discard it. + *resplen -= 2; + if (*resplen == 1) { + *resplen = 0; + } + + uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, more_len}; + + res = I2C_BufferWrite(cmd_getresp, sizeof(cmd_getresp), I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN); + if (res == false) { + DbpString("failed to send to SIM CARD 2"); + goto out; + } + + more_len = 255 - *resplen; + + res = sc_rx_bytes(resp + *resplen, &more_len, SIM_WAIT_DELAY); + if (res == false) { + DbpString("failed to receive from SIM CARD 2"); + goto out; + } + + *resplen += more_len; + + out: + return res; +} + + +static inline void swap_clock_counters(volatile unsigned int * a, unsigned int * b){ + unsigned int c = *a; + *a = *b; + *b = c; +} + +/** + * @brief Swaps the timer counter values. + * + * AT91SAM7S512 has a single Timer-Counter, that is reused in clocks Ticks + * and CountSspClk. This function stops the current clock and restores previous + * values. It is used to switch between different clock sources. + * It probably makes communication timing off, but at least makes it work. + */ +static void swap_clocks(void){ + static unsigned int tc0, tc1, tc2 = 0; + StopTicks(); + swap_clock_counters(&(AT91C_BASE_TC0->TC_CV), &tc0); + swap_clock_counters(&(AT91C_BASE_TC1->TC_CV), &tc1); + swap_clock_counters(&(AT91C_BASE_TC2->TC_CV), &tc2); +} + +void switch_clock_to_ticks(void){ + swap_clocks(); + StartTicks(); +} + +void switch_clock_to_countsspclk(void){ + swap_clocks(); + StartCountSspClk(); +} + + +/** + * @brief Sends a payload to the SAM + * + * This function prepends the payload with the necessary APDU and application + * headers and sends it to the SAM. + * + * @param addr_src 0x14 for command from NFC, 0x44 for command from application + * @param addr_dest 0x0A for command to SAM + * @param addr_reply same as add_src or 0x00 if no reply is expected + * @param payload Pointer to the data to be sent. + * @param payload_len Length of the data to be sent. + * @param response Pointer to the buffer where the response will be stored. + * @param response_len Pointer to the variable where the length of the response will be stored. + * @param length Length of the data to be sent. + * @return Status code indicating success or failure of the operation. + */ +int sam_send_payload( + uint8_t addr_src, + uint8_t addr_dest, + uint8_t addr_reply, + + uint8_t *payload, + uint16_t *payload_len, + + uint8_t *response, + uint16_t *response_len +){ + int res = PM3_SUCCESS; + + uint8_t * buf = response; + + buf[0] = 0xA0; // CLA + buf[1] = 0xDA; // INS (PUT DATA) + buf[2] = 0x02; // P1 (TLV format?) + buf[3] = 0x63; // P2 + buf[4] = SAM_TX_ASN1_PREFIX_LENGTH + (uint8_t) *payload_len; // LEN + + buf[5] = addr_src; + buf[6] = addr_dest; + buf[7] = addr_reply; + + buf[8] = 0x00; + buf[9] = 0x00; + buf[10] = 0x00; + + memcpy( + &buf[11], + payload, + *payload_len + ); + + uint16_t length = SAM_TX_ASN1_PREFIX_LENGTH + SAM_TX_APDU_PREFIX_LENGTH + (uint8_t) *payload_len; + + LogTrace(buf, length, 0, 0, NULL, true); + if (g_dbglevel >= DBG_INFO){ + DbpString("SAM REQUEST APDU: "); + Dbhexdump(length, buf, false); + } + + if (sam_rxtx(buf, length, response, response_len) == false) { + if (g_dbglevel >= DBG_ERROR) + DbpString("SAM ERROR"); + res = PM3_ECARDEXCHANGE; + goto out; + } + + LogTrace(response, *response_len, 0, 0, NULL, false); + if (g_dbglevel >= DBG_INFO){ + DbpString("SAM RESPONSE APDU: "); + Dbhexdump(*response_len, response, false); + } + + out: + return res; +} + + +/** + * @brief Retreives SAM firmware version. + * + * Used just as ping or sanity check here. + * + * @return Status code indicating success or failure of the operation. + */ +int sam_get_version(void){ + int res = PM3_SUCCESS; + + if (g_dbglevel >= DBG_DEBUG) + DbpString("start sam_get_version"); + + uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint16_t response_len = ISO7816_MAX_FRAME; + + uint8_t payload[] = { + 0xa0, 0x02, // <- SAM command + 0x82, 0x00 // <- get version + }; + uint16_t payload_len = sizeof(payload); + + sam_send_payload( + 0x44, 0x0a, 0x44, + payload, + &payload_len, + response, + &response_len + ); + + // resp: + // c1 64 00 00 00 + // bd 11 <- SAM response + // 8a 0f <- get version response + // 80 02 + // 01 29 <- version + // 81 06 + // 68 3d 05 20 26 b6 <- build ID + // 82 01 + // 01 + // 90 00 + if (g_dbglevel >= DBG_DEBUG) + DbpString("end sam_get_version"); + + if(response[5] != 0xbd){ + Dbprintf("Invalid SAM response"); + goto error; + }else{ + uint8_t * sam_response_an = sam_find_asn1_node(response + 5, 0x8a); + if(sam_response_an == NULL){ + if (g_dbglevel >= DBG_ERROR) + DbpString("SAM get response failed"); + goto error; + } + uint8_t * sam_version_an = sam_find_asn1_node(sam_response_an, 0x80); + if(sam_version_an == NULL){ + if (g_dbglevel >= DBG_ERROR) + DbpString("SAM get version failed"); + goto error; + } + uint8_t * sam_build_an = sam_find_asn1_node(sam_response_an, 0x81); + if(sam_build_an == NULL){ + if (g_dbglevel >= DBG_ERROR) + DbpString("SAM get firmware ID failed"); + goto error; + } + if (g_dbglevel >= DBG_INFO){ + DbpString("SAM get version successful"); + Dbprintf("Firmware version: %X.%X", sam_version_an[2], sam_version_an[3]); + Dbprintf("Firmware ID: "); + Dbhexdump(sam_build_an[1], sam_build_an+2, false); + } + goto out; + } + + error: + res = PM3_ESOFT; + + out: + BigBuf_free(); + + if (g_dbglevel >= DBG_DEBUG) + DbpString("end sam_get_version"); + + return res; +} + + + +/** + * @brief Finds an ASN.1 node of a specified type within a given root node. + * + * This function searches through a single level of the ASN.1 structure starting + * from the root node to find a node of the specified type. + * + * @param root Pointer to the root node of the ASN.1 structure. + * @param type The type of the ASN.1 node to find. + * @return Pointer to the ASN.1 node of the specified type if found, otherwise NULL. + */ +uint8_t * sam_find_asn1_node(uint8_t * root, const uint8_t type){ + const uint8_t * end = root + *(root+1); + uint8_t * current = root + 2; + while(current < end){ + if(*current == type){ + return current; + }else{ + current += 2 + *(current+1); + } + } + return NULL; +} + +// /** +// * @brief Appends an ASN.1 node to the end of a given node. +// * +// * This function appends an ASN.1 node of a specified type and length to the end of +// * the ASN.1 structure at specified node level. +// * It would make the code cleaner, but I can't get it to work - it calculates fields lengths incorrectly. +// * +// * @param root Pointer to the root node of the ASN.1 structure. +// * @param root Pointer to the node to be appended of the ASN.1 structure. +// * @param type The type of the ASN.1 node to append. +// * @param data Pointer to the data to be appended. +// * @param len The length of the data to be appended. +// */ +// void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len){ +// uint8_t * end = root + *(root+1); + +// *(end) = type; +// *(end+1) = len; +// memcpy(end+2, data, len); + +// for(uint8_t * current = root; current < node; current += 2){ +// *(current+1) += 2 + len; +// }; +// return; +// } + +void sam_send_ack(void){ + uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint16_t response_len = ISO7816_MAX_FRAME; + + uint8_t payload[] = { + 0xa0, 0 + }; + uint16_t payload_len = sizeof(payload); + + sam_send_payload( + 0x44, 0x0a, 0x00, + payload, + &payload_len, + response, + &response_len + ); + + BigBuf_free(); +} diff --git a/armsrc/sam_common.h b/armsrc/sam_common.h new file mode 100644 index 000000000..5aa0fe04d --- /dev/null +++ b/armsrc/sam_common.h @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +#ifndef __SAM_COMMON_H +#define __SAM_COMMON_H + +#include "common.h" + +static const uint8_t SAM_TX_APDU_PREFIX_LENGTH = 5; +static const uint8_t SAM_TX_ASN1_PREFIX_LENGTH = 6; +static const uint8_t SAM_RX_ASN1_PREFIX_LENGTH = 5; + +int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen); + +void switch_clock_to_ticks(void); +void switch_clock_to_countsspclk(void); + +int sam_send_payload( + uint8_t addr_src, + uint8_t addr_dest, + uint8_t addr_reply, + + uint8_t *payload, + uint16_t *payload_len, + + uint8_t *response, + uint16_t *response_len +); + +int sam_get_version(void); + +uint8_t * sam_find_asn1_node(uint8_t * root, const uint8_t type); +//void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len); + +void sam_send_ack(void); + +#endif diff --git a/armsrc/sam_mfc.c b/armsrc/sam_mfc.c index 090f4a781..5e2309437 100644 --- a/armsrc/sam_mfc.c +++ b/armsrc/sam_mfc.c @@ -16,7 +16,7 @@ // Routines to support MFC <-> SAM communication //----------------------------------------------------------------------------- #include "sam_mfc.h" -#include "sam_seos.h" +#include "sam_common.h" #include "iclass.h" #include "proxmark3_arm.h" diff --git a/armsrc/sam_mfc.h b/armsrc/sam_mfc.h index 5cf55d711..527bc77ff 100644 --- a/armsrc/sam_mfc.h +++ b/armsrc/sam_mfc.h @@ -17,5 +17,6 @@ #define __SAM_MFC_H #include "common.h" +#include "sam_common.h" #endif diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index fd465c992..882f03b9d 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -16,6 +16,7 @@ // Routines to support Picopass <-> SAM communication //----------------------------------------------------------------------------- #include "sam_picopass.h" +#include "sam_common.h" #include "iclass.h" #include "crc16.h" #include "proxmark3_arm.h" @@ -30,66 +31,79 @@ #include "optimized_cipher.h" #include "fpgaloader.h" -static int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen) { - StartTicks(); +/** + * @brief Sets the card detected status for the SAM (Secure Access Module). + * + * This function informs that a card has been detected by the reader and + * initializes SAM communication with the card. + * + * @param card_select Pointer to the descriptor of the detected card. + * @return Status code indicating success or failure of the operation. + */ +static int sam_set_card_detected(picopass_hdr_t * card_select){ + int res = PM3_SUCCESS; + if (g_dbglevel >= DBG_DEBUG) + DbpString("start sam_set_card_detected"); - bool res = I2C_BufferWrite(data, n, I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN); - if (res == false) { - DbpString("failed to send to SIM CARD"); + uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint16_t response_len = ISO7816_MAX_FRAME; + + // a0 12 + // ad 10 + // a0 0e + // 80 02 + // 00 04 <- Picopass + // 81 08 + // 9b fc a4 00 fb ff 12 e0 <- CSN + + uint8_t payload[] = { + 0xa0, 18, // <- SAM command + 0xad, 16, // <- set detected card + 0xa0, 4+10, + 0x80, 2, // <- protocol + 0x00, 0x04, // <- Picopass + 0x81, 8, // <- CSN + card_select->csn[0], card_select->csn[1], card_select->csn[2], card_select->csn[3], + card_select->csn[4], card_select->csn[5], card_select->csn[6], card_select->csn[7] + }; + uint16_t payload_len = sizeof(payload); + + sam_send_payload( + 0x44, 0x0a, 0x44, + payload, + &payload_len, + response, + &response_len + ); + + // resp: + // c1 64 00 00 00 + // bd 02 <- response + // 8a 00 <- empty response (accepted) + // 90 00 + + if(response[5] != 0xbd){ + if (g_dbglevel >= DBG_ERROR) + Dbprintf("Invalid SAM response"); + goto error; + }else{ + // uint8_t * sam_response_an = sam_find_asn1_node(response + 5, 0x8a); + // if(sam_response_an == NULL){ + // if (g_dbglevel >= DBG_ERROR) + // Dbprintf("Invalid SAM response"); + // goto error; + // } goto out; } + error: + res = PM3_ESOFT; - *resplen = ISO7816_MAX_FRAME; + out: + BigBuf_free(); - res = sc_rx_bytes(resp, resplen, SIM_WAIT_DELAY); - if (res == false) { - DbpString("failed to receive from SIM CARD"); - goto out; - } - - if (*resplen < 2) { - DbpString("received too few bytes from SIM CARD"); - res = false; - goto out; - } - - uint16_t more_len = 0; - - if (resp[*resplen - 2] == 0x61 || resp[*resplen - 2] == 0x9F) { - more_len = resp[*resplen - 1]; - } else { - // we done, return - goto out; - } - - // Don't discard data we already received except the SW code. - // If we only received 1 byte, this is the echo of INS, we discard it. - *resplen -= 2; - if (*resplen == 1) { - *resplen = 0; - } - - uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, more_len}; - - res = I2C_BufferWrite(cmd_getresp, sizeof(cmd_getresp), I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN); - if (res == false) { - DbpString("failed to send to SIM CARD 2"); - goto out; - } - - more_len = 255 - *resplen; - - res = sc_rx_bytes(resp + *resplen, &more_len, SIM_WAIT_DELAY); - if (res == false) { - DbpString("failed to receive from SIM CARD 2"); - goto out; - } - - *resplen += more_len; - -out: - StopTicks(); + if (g_dbglevel >= DBG_DEBUG) + DbpString("end sam_set_card_detected"); return res; } @@ -218,23 +232,19 @@ int sam_picopass_get_pacs(void) { uint8_t *sam_apdu = BigBuf_calloc(ISO7816_MAX_FRAME); // ----------------------------------------------------------------------------- - // first - // a0 da 02 63 1a 44 0a 44 00 00 00 a0 12 ad 10 a0 0e 80 02 00 04 81 08 9b fc a4 00 fb ff 12 e0 - hexstr_to_byte_array("a0da02631a440a44000000a012ad10a00e800200048108", sam_apdu, &sam_len); - memcpy(sam_apdu + sam_len, hdr.csn, sizeof(hdr.csn)); - sam_len += sizeof(hdr.csn); - - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 1", resp, resp_len); + // first - set detected card (0xAD) + switch_clock_to_ticks(); + sam_set_card_detected(&hdr); // ----------------------------------------------------------------------------- - // second - // a0 da 02 63 0d 44 0a 44 00 00 00 a0 05 a1 03 80 01 04 - hexstr_to_byte_array("a0da02630d440a44000000a005a103800104", sam_apdu, &sam_len); - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { + // second - get PACS (0xA1) + + // a0 05 + // a1 03 + // 80 01 + // 04 + hexstr_to_byte_array("a005a103800104", sam_apdu, &sam_len); + if(sam_send_payload(0x44, 0x0a, 0x44, sam_apdu, &sam_len, resp, &resp_len) != PM3_SUCCESS) { res = PM3_ECARDEXCHANGE; goto out; } @@ -245,7 +255,7 @@ int sam_picopass_get_pacs(void) { // Tag|c00a140a000000a110a10e8004 0c05de64 8102 0004 820201f4 // ----------------------------------------------------------------------------- - // third AIA block 5 + // third AIA block 5 (emulated tag <-> SAM exchange starts here) // a0da02631c140a00000000bd14a012a010800a ffffff0006fffffff88e 81020000 // picopass legacy is fixed. wants AIA and crc. ff ff ff ff ff ff ff ff ea f5 // picpoasss SE ff ff ff 00 06 ff ff ff f8 8e @@ -300,7 +310,7 @@ int sam_picopass_get_pacs(void) { } // start ssp clock again... - StartCountSspClk(); + switch_clock_to_countsspclk(); // NOW we auth against tag uint8_t cmd_check[9] = { ICLASS_CMD_CHECK }; @@ -325,6 +335,7 @@ int sam_picopass_get_pacs(void) { hexstr_to_byte_array("A0DA026316140A00000000BD0EA00CA00A8004311E32E981020000", sam_apdu, &sam_len); memcpy(sam_apdu + 19, mac, sizeof(mac)); + switch_clock_to_ticks(); if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { res = PM3_ECARDEXCHANGE; goto out; @@ -355,7 +366,7 @@ int sam_picopass_get_pacs(void) { // c1 61 c1 00 00 a1 10 a1 0e 80 04 0c 06 45 56 81 02 00 04 82 02 01 f4 90 00 // read block 6 - StartCountSspClk(); + switch_clock_to_countsspclk(); start_time = GetCountSspClk(); iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod); @@ -373,6 +384,7 @@ int sam_picopass_get_pacs(void) { hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A030303030003E017432381020000", sam_apdu, &sam_len); memcpy(sam_apdu + 19, resp, resp_len); + switch_clock_to_ticks(); if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { res = PM3_ECARDEXCHANGE; goto out; @@ -382,7 +394,7 @@ int sam_picopass_get_pacs(void) { // c161c10000a110a10e8004 0606455681020004820201f49000 // read the credential blocks - StartCountSspClk(); + switch_clock_to_countsspclk(); start_time = GetCountSspClk(); iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod); @@ -400,6 +412,7 @@ int sam_picopass_get_pacs(void) { hexstr_to_byte_array("A0DA026334140A00000000BD2CA02AA0288022030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C81020000", sam_apdu, &sam_len); memcpy(sam_apdu + 19, resp, resp_len); + switch_clock_to_ticks(); if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { res = PM3_ECARDEXCHANGE; goto out; @@ -409,7 +422,13 @@ int sam_picopass_get_pacs(void) { // ----------------------------------------------------------------------------- // TEN ask for PACS data - // A0DA02630C440A00000000BD04A0028200 + // A0 DA 02 63 0C + // 44 0A 00 00 00 00 + // BD 04 + // A0 02 + // 82 00 + + // (emulated tag <-> SAM exchange ends here) hexstr_to_byte_array("A0DA02630C440A00000000BD04A0028200", sam_apdu, &sam_len); memcpy(sam_apdu + 19, resp, resp_len); @@ -424,7 +443,12 @@ int sam_picopass_get_pacs(void) { goto out; } - // c164000000bd098a07 030506951f9a00 9000 + // resp: + // c1 64 00 00 00 + // bd 09 + // 8a 07 + // 03 05 06 95 1f 9a 00 <- decoded PACS data + // 90 00 uint8_t *pacs = BigBuf_calloc(resp[8]); memcpy(pacs, resp + 9, resp[8]); @@ -439,6 +463,7 @@ out: off: switch_off(); + StopTicks(); BigBuf_free(); return res; } diff --git a/armsrc/sam_picopass.h b/armsrc/sam_picopass.h index 7feef0bde..26d734d39 100644 --- a/armsrc/sam_picopass.h +++ b/armsrc/sam_picopass.h @@ -17,6 +17,7 @@ #define __SAM_PICOPASS_H #include "common.h" +#include "sam_common.h" int sam_picopass_get_pacs(void); From c08e6c47c8cc536a807efcb8f383af60f9240b97 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sat, 4 Jan 2025 14:49:39 +0100 Subject: [PATCH 03/13] sam_seos: add suppport for HID SAM communication with SEOS cards, based on bettse/seader project --- armsrc/appmain.c | 2 +- armsrc/sam_seos.c | 350 +++++++++++++++++++++++++++++++++++++++++ armsrc/sam_seos.h | 2 + client/src/cmdhfseos.c | 123 ++++++++++++++- 4 files changed, 475 insertions(+), 2 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6d42a0e0c..dbe929159 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -2246,7 +2246,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_SAM_SEOS: { -// sam_seos_get_pacs(); + sam_seos_get_pacs(); break; } diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 00e4da45b..0fe5c8670 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -14,9 +14,359 @@ // See LICENSE.txt for the text of the license. //----------------------------------------------------------------------------- // Routines to support SEOS <-> SAM communication +// communication and ASN.1 messages based on https://github.com/bettse/seader/blob/main/seader.asn1 //----------------------------------------------------------------------------- #include "sam_seos.h" +#include "sam_common.h" #include "iclass.h" #include "proxmark3_arm.h" +#include "iso14443a.h" + +#include "iclass.h" +#include "crc16.h" +#include "proxmark3_arm.h" +#include "BigBuf.h" #include "cmd.h" +#include "commonutil.h" +#include "ticks.h" +#include "dbprint.h" +#include "i2c.h" +#include "protocols.h" +#include "optimized_cipher.h" +#include "fpgaloader.h" + +#include "cmd.h" + + +/** + * @brief Sets the card detected status for the SAM (Secure Access Module). + * + * This function informs that a card has been detected by the reader and + * initializes SAM communication with the card. + * + * @param card_select Pointer to the descriptor of the detected card. + * @return Status code indicating success or failure of the operation. + */ +static int sam_set_card_detected(iso14a_card_select_t * card_select){ + int res = PM3_SUCCESS; + if (g_dbglevel >= DBG_DEBUG) + DbpString("start sam_set_card_detected"); + + if(card_select ->uidlen != 4) + return PM3_EFAILED; + + uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint16_t response_len = ISO7816_MAX_FRAME; + + uint8_t payload[] = { + 0xa0, (2+(2+(4*2 +2+4+2+1))), // <- SAM command + 0xad, (2+(4*2 +2+4+2+1)), // <- set detected card + 0xa0, (4*2 +2+4+2+1), + 0x80, 2, // <- protocol + 0x00, 0x02, // <- ISO14443A + 0x81, card_select->uidlen, // <- CSN + card_select->uid[0], card_select->uid[1], card_select->uid[2], card_select->uid[3], + 0x82, 2, // <- ATQA + card_select->atqa[0], card_select->atqa[1], + 0x83, 1, // <- SAK + card_select->sak + }; + uint16_t payload_len = sizeof(payload); + + sam_send_payload( + 0x44, 0x0a, 0x44, + payload, + &payload_len, + response, + &response_len + ); + + // resp: + // c1 64 00 00 00 + // bd 02 <- response + // 8a 00 <- empty response (accepted) + // 90 00 + + if(response[5] != 0xbd){ + if (g_dbglevel >= DBG_ERROR) + Dbprintf("Invalid SAM response"); + goto error; + }else{ + // uint8_t * sam_response_an = sam_find_asn1_node(response + 5, 0x8a); + // if(sam_response_an == NULL){ + // if (g_dbglevel >= DBG_ERROR) + // Dbprintf("Invalid SAM response"); + // goto error; + // } + goto out; + } + error: + res = PM3_ESOFT; + + out: + BigBuf_free(); + + if (g_dbglevel >= DBG_DEBUG) + DbpString("end sam_set_card_detected"); + return res; +} + +/** + * @brief Copies the payload from an NFC buffer to a SAM buffer. + * + * Wraps received data from NFC into an ASN1 tree, so it can be transmitted to the SAM . + * + * @param sam_tx Pointer to the SAM transmit buffer. + * @param nfc_rx Pointer to the NFC receive buffer. + * @param nfc_len Length of the data to be copied from the NFC buffer. + * + * @return Length of SAM APDU to be sent. + */ +inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t * nfc_rx, uint8_t nfc_len){ + // NFC resp: + // 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3 + + // SAM req: + // bd 1c + // a0 1a + // a0 18 + // 80 12 + // 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3 + // 81 02 + // 00 00 + + sam_tx[0] = 0xBD; + + sam_tx[2] = 0xA0; + + sam_tx[4] = 0xA0; + + sam_tx[6] = 0x80; + sam_tx[7] = nfc_len; + memcpy(sam_tx+8, nfc_rx, nfc_len); + + sam_tx[8+nfc_len] = 0x81; + sam_tx[9+nfc_len] = 0x02; + sam_tx[10+nfc_len] = 0x00; + sam_tx[11+nfc_len] = 0x00; + + // fix lengths + sam_tx[5] = 2 + nfc_len + 4; + sam_tx[3] = sam_tx[5] + 2; + sam_tx[1] = sam_tx[3] + 2; + return sam_tx[1] + 2; +} + +/** + * @brief Copies the payload from the SAM receive buffer to the NFC transmit buffer. + * + * Unpacks data to be transmitted from ASN1 tree in APDU received from SAM. + * + * @param nfc_tx_buf Pointer to the buffer where the NFC transmit data will be stored. + * @param sam_rx_buf Pointer to the buffer containing the data received from the SAM. + * @return Length of NFC APDU to be sent. + */ +inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t * nfc_tx_buf, uint8_t * sam_rx_buf){ + // SAM resp: + // c1 61 c1 00 00 + // a1 21 <- nfc command + // a1 1f <- nfc send + // 80 10 <- data + // 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00 + // 81 02 <- protocol + // 02 02 + // 82 02 <- timeout + // 01 2e + // 85 03 <- format + // 06 c0 00 + // 90 00 + + // NFC req: + // 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00 + + // copy data out of c1->a1>->a1->80 node + uint16_t nfc_tx_len = (uint8_t) *(sam_rx_buf + 10); + memcpy(nfc_tx_buf, sam_rx_buf+11, nfc_tx_len); + return nfc_tx_len; +} + +/** + * @brief Copies the payload from the SAM receive buffer to the NFC transmit buffer. + * + * Unpacks data to be transmitted from ASN1 tree in APDU received from SAM. + * + * @param pacs Pointer to the buffer where the decoded PACS data will be stored. + * @param pacs_len Pointer to the variable where the length of the PACS data will be stored. + * @return Status code indicating success or failure of the operation. + */ +static int sam_request_pacs(uint8_t * pacs, uint8_t * pacs_len){ + int res = PM3_SUCCESS; + if (g_dbglevel >= DBG_DEBUG) + DbpString("start sam_request_pacs"); + + uint8_t buf1[ISO7816_MAX_FRAME] = {0}; + uint8_t buf2[ISO7816_MAX_FRAME] = {0}; + + uint8_t * sam_tx_buf = buf1; + uint16_t sam_tx_len; + + uint8_t * sam_rx_buf = buf2; + uint16_t sam_rx_len; + + uint8_t * nfc_tx_buf = buf1; + uint16_t nfc_tx_len; + + uint8_t * nfc_rx_buf = buf2; + uint16_t nfc_rx_len; + + // send get pacs + static const uint8_t payload[] = { + 0xa0, 5, // <- SAM command + 0xa1, 3, // <- get PACS + 0x80, 1, + 0x04 + }; + sam_tx_len = sizeof(payload); + memcpy(sam_tx_buf, payload, sam_tx_len); + + sam_send_payload( + 0x44, 0x0a, 0x44, + sam_tx_buf, &sam_tx_len, + sam_rx_buf, &sam_rx_len + ); + + // tag <-> SAM exchange starts here + for(int i = 0; i < 20; i++){ + switch_clock_to_countsspclk(); + nfc_tx_len = sam_seos_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); + + nfc_rx_len = iso14_apdu( + nfc_tx_buf, + nfc_tx_len, + false, + nfc_rx_buf, + ISO7816_MAX_FRAME, + NULL + ); + + switch_clock_to_ticks(); + sam_tx_len = sam_seos_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len-2); + + sam_send_payload( + 0x14, 0x0a, 0x14, + sam_tx_buf, &sam_tx_len, + sam_rx_buf, &sam_rx_len + ); + + // last SAM->TAG + // c1 61 c1 00 00 a1 02 >>82<< 00 90 00 + if(sam_rx_buf[7] == 0x82){ + // tag <-> SAM exchange ends here + break; + } + + } + + static const uint8_t hfack[] = { + 0xbd, 0x04, 0xa0, 0x02, 0x82, 0x00 + }; + + sam_tx_len = sizeof(hfack); + memcpy(sam_tx_buf, hfack, sam_tx_len); + + sam_send_payload( + 0x14, 0x0a, 0x00, + sam_tx_buf, &sam_tx_len, + sam_rx_buf, &sam_rx_len + ); + + // resp: + // c1 64 00 00 00 + // bd 09 + // 8a 07 + // 03 05 <- include tag for pm3 client + // 06 85 80 6d c0 <- decoded PACS data + // 90 00 + if(sam_rx_buf[5+2] != 0x8a && sam_rx_buf[5+4] != 0x03){ + if (g_dbglevel >= DBG_ERROR) + Dbprintf("Invalid SAM response"); + goto err; + } + *pacs_len = sam_rx_buf[5+5] +2; + memcpy(pacs, sam_rx_buf+5+4, *pacs_len); + res=PM3_SUCCESS; + + goto out; + + err: + res=PM3_ESOFT; + out: + return res; +} + +/** + * @brief Retrieves PACS data from SEOS card using SAM. + * + * This function is called by appmain.c + * It sends a request to the SAM to get the PACS data from the SEOS card. + * The PACS data is then returned to the PM3 client. + * + * @return Status code indicating success or failure of the operation. + */ +int sam_seos_get_pacs(void){ + int res = PM3_EFAILED; + + clear_trace(); + I2C_Reset_EnterMainProgram(); + + set_tracing(true); + StartTicks(); + + // step 1: ping SAM + sam_get_version(); + + // step 2: get card information + iso14a_card_select_t card_a_info; + + // implicit StartSspClk() happens here + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + if (!iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)){ + goto err; + } + + switch_clock_to_ticks(); + + // step 3: SamCommand CardDetected + sam_set_card_detected(&card_a_info); + + // step 3: SamCommand RequestPACS, relay NFC communication + + uint8_t pacs[10] = { 0x00 }; + uint8_t pacs_len = 0; + res = sam_request_pacs(pacs, &pacs_len); + if(res != PM3_SUCCESS){ + goto err; + } + if (g_dbglevel >= DBG_INFO) + print_result("PACS data", pacs, pacs_len); + + sam_send_ack(); + + goto out; + goto off; + + err: + res = PM3_ENOPACS; + reply_ng(CMD_HF_SAM_SEOS, res, NULL, 0); + goto off; + out: + reply_ng(CMD_HF_SAM_SEOS, PM3_SUCCESS, pacs, pacs_len); + goto off; + off: + switch_off(); + set_tracing(false); + StopTicks(); + BigBuf_free(); + return res; +} \ No newline at end of file diff --git a/armsrc/sam_seos.h b/armsrc/sam_seos.h index c2100f07e..a1b637c80 100644 --- a/armsrc/sam_seos.h +++ b/armsrc/sam_seos.h @@ -18,4 +18,6 @@ #include "common.h" +int sam_seos_get_pacs(void); + #endif diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index fe57b7c76..74837134e 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -30,6 +30,9 @@ #include "ui.h" #include "cmdhf14a.h" // manufacture #include "protocols.h" // definitions of ISO14A/7816 protocol +#include "cardhelper.h" +#include "wiegand_formats.h" +#include "wiegand_formatutils.h" #include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "crypto/asn1utils.h" // ASN1 decode / print #include "crypto/libpcrypto.h" // AES decrypt @@ -1632,10 +1635,129 @@ static int CmdHfSeosList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf seos", "seos -c"); } +static int CmdHfSeosSAM(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf seos sam", + "Extract PACS via a HID SAM\n", + "hf seos sam\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool verbose = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + if (IsHIDSamPresent(verbose) == false) { + return PM3_ESOFT; + } + + clearCommandBuffer(); + SendCommandNG(CMD_HF_SAM_SEOS, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) { + PrintAndLogEx(WARNING, "SAM timeout"); + return PM3_ETIMEOUT; + } + + switch (resp.status) { + case PM3_SUCCESS: + break; + case PM3_ENOPACS: + PrintAndLogEx(SUCCESS, "No PACS data found. Card empty?"); + return resp.status; + default: + PrintAndLogEx(WARNING, "SAM select failed"); + return resp.status; + } + + // CSN, config, epurse, NR/MAC, AIA + // PACS + // first byte skip + // second byte length + // third padded + // fourth .. + uint8_t *d = resp.data.asBytes; + uint8_t n = d[1] - 1; // skip length byte + uint8_t pad = d[2]; + char *binstr = (char *)calloc((n * 8) + 1, sizeof(uint8_t)); + if (binstr == NULL) { + return PM3_EMALLOC; + } + + bytes_2_binstr(binstr, d + 3, n); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + 2, resp.length - 2)); + PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); + + binstr[strlen(binstr) - pad] = '\0'; + PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); + + size_t hexlen = 0; + uint8_t hex[16] = {0}; + binstr_2_bytes(hex, &hexlen, binstr); + PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen)); + + uint32_t top = 0, mid = 0, bot = 0; + if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) { + PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); + free(binstr); + return PM3_EINVARG; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Wiegand decode"); + wiegand_message_t packed = initialize_message_object(top, mid, bot, strlen(binstr)); + HIDTryUnpack(&packed); + + PrintAndLogEx(NORMAL, ""); + + if (strlen(binstr) >= 26 && verbose) { + + // iCLASS Legacy + PrintAndLogEx(INFO, "Clone to " _YELLOW_("iCLASS Legacy")); + PrintAndLogEx(SUCCESS, " hf iclass encode --ki 0 --bin %s", binstr); + PrintAndLogEx(NORMAL, ""); + + // HID Prox II + PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("HID Prox II")); + PrintAndLogEx(SUCCESS, " lf hid clone -w H10301 --bin %s", binstr); + PrintAndLogEx(NORMAL, ""); + + // MIFARE Classic + char mfcbin[28] = {0}; + mfcbin[0] = '1'; + memcpy(mfcbin + 1, binstr, strlen(binstr)); + binstr_2_bytes(hex, &hexlen, mfcbin); + + PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic") " (Pm3 simulation)"); + PrintAndLogEx(SUCCESS, " hf mf eclr;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 0 -d 049DBA42A23E80884400C82000000000;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 1 -d 1B014D48000000000000000000000000;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 5 -d 020000000000000000000000%s;", sprint_hex_inrow(hex, hexlen)); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 7 -d 484944204953787788AA204752454154;"); + PrintAndLogEx(SUCCESS, " hf mf sim --1k -i;"); + PrintAndLogEx(NORMAL, ""); + + PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic 1K")); + PrintAndLogEx(SUCCESS, " hf mf encodehid --bin %s", binstr); + PrintAndLogEx(NORMAL, ""); + } + free(binstr); + + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdHfSeosList, AlwaysAvailable, "List SEOS history"}, + {"sam", CmdHfSeosSAM, IfPm3Smartcard, "SAM tests"}, {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operations") " -----------------------"}, {"info", CmdHfSeosInfo, IfPm3NfcBarcode, "Tag information"}, {"pacs", CmdHfSeosPACS, AlwaysAvailable, "Extract PACS Information from card"}, @@ -1643,7 +1765,6 @@ static command_t CommandTable[] = { {"gdf", CmdHfSeosGDF, AlwaysAvailable, "Read an GDF from card"}, {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Utils") " -----------------------"}, {"managekeys", CmdHfSeosManageKeys, AlwaysAvailable, "Manage keys to use with SEOS commands"}, - {NULL, NULL, NULL, NULL} }; From 472d2e933007afb018ec6f541d900da0c0c9aba0 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 5 Jan 2025 20:42:32 +0100 Subject: [PATCH 04/13] armsrc/sam_common.c: fix sam_append_asn1_node --- armsrc/sam_common.c | 49 ++++++++++++++++++++++++--------------------- armsrc/sam_common.h | 2 +- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c index 5c0acbe86..3efa1574c 100644 --- a/armsrc/sam_common.c +++ b/armsrc/sam_common.c @@ -327,31 +327,34 @@ uint8_t * sam_find_asn1_node(uint8_t * root, const uint8_t type){ return NULL; } -// /** -// * @brief Appends an ASN.1 node to the end of a given node. -// * -// * This function appends an ASN.1 node of a specified type and length to the end of -// * the ASN.1 structure at specified node level. -// * It would make the code cleaner, but I can't get it to work - it calculates fields lengths incorrectly. -// * -// * @param root Pointer to the root node of the ASN.1 structure. -// * @param root Pointer to the node to be appended of the ASN.1 structure. -// * @param type The type of the ASN.1 node to append. -// * @param data Pointer to the data to be appended. -// * @param len The length of the data to be appended. -// */ -// void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len){ -// uint8_t * end = root + *(root+1); +/** + * @brief Appends an ASN.1 node to the end of a given node. + * + * This function appends an ASN.1 node of a specified type and length to the end of + * the ASN.1 structure at specified node level. + * + * It is the most naive solution that does not handle the case where the node to append is + * not the last node at the same level. It also does not also care about proper + * order of the nodes. + * + * @param root Pointer to the root node of the ASN.1 structure. + * @param root Pointer to the node to be appended of the ASN.1 structure. + * @param type The type of the ASN.1 node to append. + * @param data Pointer to the data to be appended. + * @param len The length of the data to be appended. + */ +void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len){ + uint8_t * end = root + *(root+1) + 2; -// *(end) = type; -// *(end+1) = len; -// memcpy(end+2, data, len); + *(end) = type; + *(end+1) = len; + memcpy(end+2, data, len); -// for(uint8_t * current = root; current < node; current += 2){ -// *(current+1) += 2 + len; -// }; -// return; -// } + for(uint8_t * current = root; current <= node; current += 2){ + *(current+1) += 2 + len; + }; + return; +} void sam_send_ack(void){ uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); diff --git a/armsrc/sam_common.h b/armsrc/sam_common.h index 5aa0fe04d..c84189f98 100644 --- a/armsrc/sam_common.h +++ b/armsrc/sam_common.h @@ -42,7 +42,7 @@ int sam_send_payload( int sam_get_version(void); uint8_t * sam_find_asn1_node(uint8_t * root, const uint8_t type); -//void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len); +void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len); void sam_send_ack(void); From 7b5ce7fbeff8f08fd0b9c717b80f1c32bc82186e Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 5 Jan 2025 20:43:52 +0100 Subject: [PATCH 05/13] armsrc/sam_seos.c: added support for cards with uid of length != 4 --- armsrc/sam_seos.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 0fe5c8670..8ee112eb0 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -53,31 +53,30 @@ static int sam_set_card_detected(iso14a_card_select_t * card_select){ if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_set_card_detected"); - if(card_select ->uidlen != 4) - return PM3_EFAILED; + uint8_t * request = BigBuf_malloc(ISO7816_MAX_FRAME); + uint16_t request_len = ISO7816_MAX_FRAME; uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; uint8_t payload[] = { - 0xa0, (2+(2+(4*2 +2+4+2+1))), // <- SAM command - 0xad, (2+(4*2 +2+4+2+1)), // <- set detected card - 0xa0, (4*2 +2+4+2+1), + 0xa0, 8, // <- SAM command + 0xad, 6, // <- set detected card + 0xa0, 4, // <- detected card details 0x80, 2, // <- protocol - 0x00, 0x02, // <- ISO14443A - 0x81, card_select->uidlen, // <- CSN - card_select->uid[0], card_select->uid[1], card_select->uid[2], card_select->uid[3], - 0x82, 2, // <- ATQA - card_select->atqa[0], card_select->atqa[1], - 0x83, 1, // <- SAK - card_select->sak + 0x00, 0x02 // <- ISO14443A }; - uint16_t payload_len = sizeof(payload); + + memcpy(request, payload, sizeof(payload)); + sam_append_asn1_node(request, request+4, 0x81, card_select->uid, card_select->uidlen); + sam_append_asn1_node(request, request+4, 0x82, card_select->atqa, 2); + sam_append_asn1_node(request, request+4, 0x83, &card_select->sak, 1); + request_len = request[1] + 2; sam_send_payload( 0x44, 0x0a, 0x44, - payload, - &payload_len, + request, + &request_len, response, &response_len ); From d8ebec6baab93effd929e7f7a0d5b9864aa10953 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 5 Jan 2025 20:45:30 +0100 Subject: [PATCH 06/13] armsrc/sam_seos.c: cleanup in sam_seos_copy_payload_nfc2sam --- armsrc/sam_seos.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 8ee112eb0..e1a968e60 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -135,26 +135,22 @@ inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t * // 81 02 // 00 00 - sam_tx[0] = 0xBD; + const uint8_t payload[] = { + 0xbd, 4, + 0xa0, 2, + 0xa0, 0 + }; - sam_tx[2] = 0xA0; + const uint8_t tag81[] = { + 0x00, 0x00 + }; - sam_tx[4] = 0xA0; + memcpy(sam_tx, payload, sizeof(payload)); - sam_tx[6] = 0x80; - sam_tx[7] = nfc_len; - memcpy(sam_tx+8, nfc_rx, nfc_len); - - sam_tx[8+nfc_len] = 0x81; - sam_tx[9+nfc_len] = 0x02; - sam_tx[10+nfc_len] = 0x00; - sam_tx[11+nfc_len] = 0x00; - - // fix lengths - sam_tx[5] = 2 + nfc_len + 4; - sam_tx[3] = sam_tx[5] + 2; - sam_tx[1] = sam_tx[3] + 2; - return sam_tx[1] + 2; + sam_append_asn1_node(sam_tx, sam_tx+4, 0x80, nfc_rx, nfc_len); + sam_append_asn1_node(sam_tx, sam_tx+4, 0x81, tag81, sizeof(tag81)); + + return sam_tx[1] + 2; // length of the ASN1 tree } /** From c28ddd1d563f90d6e8d81a5c2b8f2885ace23a09 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 5 Jan 2025 21:21:30 +0100 Subject: [PATCH 07/13] armsrc/sam_common.c: type cleanup --- armsrc/sam_common.c | 28 ++++++++++++---------------- armsrc/sam_common.h | 14 +++++++------- armsrc/sam_picopass.c | 2 +- armsrc/sam_seos.c | 2 +- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c index 3efa1574c..835428074 100644 --- a/armsrc/sam_common.c +++ b/armsrc/sam_common.c @@ -18,21 +18,17 @@ #include -// #include "sam_picopass.h" #include "sam_common.h" #include "iclass.h" -// #include "crc16.h" #include "proxmark3_arm.h" #include "BigBuf.h" -// #include "cmd.h" #include "commonutil.h" #include "ticks.h" #include "dbprint.h" #include "i2c.h" #include "iso15693.h" #include "protocols.h" -// #include "optimized_cipher.h" -// #include "fpgaloader.h" + /** * @brief Transmits data to and receives data from a HID®'s iCLASS® SE™ Processor. @@ -155,12 +151,12 @@ void switch_clock_to_countsspclk(void){ * @return Status code indicating success or failure of the operation. */ int sam_send_payload( - uint8_t addr_src, - uint8_t addr_dest, - uint8_t addr_reply, + const uint8_t addr_src, + const uint8_t addr_dest, + const uint8_t addr_reply, - uint8_t *payload, - uint16_t *payload_len, + const uint8_t * const payload, + const uint16_t *payload_len, uint8_t *response, uint16_t *response_len @@ -314,9 +310,9 @@ int sam_get_version(void){ * @param type The type of the ASN.1 node to find. * @return Pointer to the ASN.1 node of the specified type if found, otherwise NULL. */ -uint8_t * sam_find_asn1_node(uint8_t * root, const uint8_t type){ - const uint8_t * end = root + *(root+1); - uint8_t * current = root + 2; +uint8_t * sam_find_asn1_node(const uint8_t * root, const uint8_t type){ + const uint8_t * end = (uint8_t *) root + *(root+1); + uint8_t * current = (uint8_t *) root + 2; while(current < end){ if(*current == type){ return current; @@ -343,14 +339,14 @@ uint8_t * sam_find_asn1_node(uint8_t * root, const uint8_t type){ * @param data Pointer to the data to be appended. * @param len The length of the data to be appended. */ -void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len){ - uint8_t * end = root + *(root+1) + 2; +void sam_append_asn1_node(const uint8_t * root, const uint8_t * node, uint8_t type, const uint8_t * const data, uint8_t len){ + uint8_t * end = (uint8_t *) root + *(root+1) + 2; *(end) = type; *(end+1) = len; memcpy(end+2, data, len); - for(uint8_t * current = root; current <= node; current += 2){ + for(uint8_t * current = (uint8_t *) root; current <= node; current += 2){ *(current+1) += 2 + len; }; return; diff --git a/armsrc/sam_common.h b/armsrc/sam_common.h index c84189f98..5e243346c 100644 --- a/armsrc/sam_common.h +++ b/armsrc/sam_common.h @@ -28,12 +28,12 @@ void switch_clock_to_ticks(void); void switch_clock_to_countsspclk(void); int sam_send_payload( - uint8_t addr_src, - uint8_t addr_dest, - uint8_t addr_reply, + const uint8_t addr_src, + const uint8_t addr_dest, + const uint8_t addr_reply, - uint8_t *payload, - uint16_t *payload_len, + const uint8_t * const payload, + const uint16_t *payload_len, uint8_t *response, uint16_t *response_len @@ -41,8 +41,8 @@ int sam_send_payload( int sam_get_version(void); -uint8_t * sam_find_asn1_node(uint8_t * root, const uint8_t type); -void sam_append_asn1_node(uint8_t * root, uint8_t * node, uint8_t type, uint8_t * data, uint8_t len); +uint8_t * sam_find_asn1_node(const uint8_t * root, const uint8_t type); +void sam_append_asn1_node(const uint8_t * root, const uint8_t * node, uint8_t type, const uint8_t * const data, uint8_t len); void sam_send_ack(void); diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index 882f03b9d..055423f41 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -244,7 +244,7 @@ int sam_picopass_get_pacs(void) { // 80 01 // 04 hexstr_to_byte_array("a005a103800104", sam_apdu, &sam_len); - if(sam_send_payload(0x44, 0x0a, 0x44, sam_apdu, &sam_len, resp, &resp_len) != PM3_SUCCESS) { + if(sam_send_payload(0x44, 0x0a, 0x44, sam_apdu, (uint16_t *) &sam_len, resp, &resp_len) != PM3_SUCCESS) { res = PM3_ECARDEXCHANGE; goto out; } diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index e1a968e60..5ac73ceb9 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -59,7 +59,7 @@ static int sam_set_card_detected(iso14a_card_select_t * card_select){ uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; - uint8_t payload[] = { + const uint8_t payload[] = { 0xa0, 8, // <- SAM command 0xad, 6, // <- set detected card 0xa0, 4, // <- detected card details From dfb5fa3de4a4cf3df60194c3efcc2b24524d80e1 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 6 Jan 2025 12:15:59 +0100 Subject: [PATCH 08/13] armsrc/sam_seos.c: add SoRootOID in sam_request_pacs As described in 5326-903 OMNIKEY 5326 Software Developer Guide (https://www.hidglobal.com/documents/omnikey-5326-dfr-developers-guide). Seems like it should be here since the beginning, but worked fine without. --- armsrc/sam_seos.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 5ac73ceb9..f3afd568e 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -217,11 +217,14 @@ static int sam_request_pacs(uint8_t * pacs, uint8_t * pacs_len){ // send get pacs static const uint8_t payload[] = { - 0xa0, 5, // <- SAM command - 0xa1, 3, // <- get PACS + 0xa0, 19, // <- SAM command + 0xA1, 17, // <- SamCommandGetContentElement 0x80, 1, - 0x04 + 0x04, // <- implicitFormatPhysicalAccessBits + 0x84, 12, + 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x04 // <- SoRootOID }; + sam_tx_len = sizeof(payload); memcpy(sam_tx_buf, payload, sam_tx_len); From 0f7574c9822d752c46e166cf1cb6a062f1e7a974 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 6 Jan 2025 14:21:25 +0100 Subject: [PATCH 09/13] sam_seos: add option to send arbitrary requests --- armsrc/appmain.c | 2 +- armsrc/sam_seos.c | 185 ++++++++++++++++++++++----------------- armsrc/sam_seos.h | 3 +- client/src/cmdhficlass.c | 2 + client/src/cmdhfseos.c | 148 ++++++++++++++++++++----------- 5 files changed, 205 insertions(+), 135 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index dbe929159..359985cc3 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -2246,7 +2246,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_SAM_SEOS: { - sam_seos_get_pacs(); + sam_seos_get_pacs(packet); break; } diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index f3afd568e..866f62a63 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -35,6 +35,7 @@ #include "protocols.h" #include "optimized_cipher.h" #include "fpgaloader.h" +#include "pm3_cmd.h" #include "cmd.h" @@ -146,10 +147,10 @@ inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t * }; memcpy(sam_tx, payload, sizeof(payload)); - + sam_append_asn1_node(sam_tx, sam_tx+4, 0x80, nfc_rx, nfc_len); sam_append_asn1_node(sam_tx, sam_tx+4, 0x81, tag81, sizeof(tag81)); - + return sam_tx[1] + 2; // length of the ASN1 tree } @@ -187,18 +188,21 @@ inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t * nfc_tx_buf, uint8 } /** - * @brief Copies the payload from the SAM receive buffer to the NFC transmit buffer. + * @brief Sends a request to the SAM and retrieves the response. * - * Unpacks data to be transmitted from ASN1 tree in APDU received from SAM. + * Unpacks request to the SAM and relays ISO14A traffic to the card. + * If no request data provided, sends a request to get PACS data. * - * @param pacs Pointer to the buffer where the decoded PACS data will be stored. - * @param pacs_len Pointer to the variable where the length of the PACS data will be stored. + * @param request Pointer to the buffer containing the request to be sent to the SAM. + * @param request_len Length of the request to be sent to the SAM. + * @param response Pointer to the buffer where the retreived data will be stored. + * @param response_len Pointer to the variable where the length of the retreived data will be stored. * @return Status code indicating success or failure of the operation. */ -static int sam_request_pacs(uint8_t * pacs, uint8_t * pacs_len){ +static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t request_len, uint8_t * response, uint8_t * response_len){ int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) - DbpString("start sam_request_pacs"); + DbpString("start sam_send_request_iso14a"); uint8_t buf1[ISO7816_MAX_FRAME] = {0}; uint8_t buf2[ISO7816_MAX_FRAME] = {0}; @@ -215,18 +219,23 @@ static int sam_request_pacs(uint8_t * pacs, uint8_t * pacs_len){ uint8_t * nfc_rx_buf = buf2; uint16_t nfc_rx_len; - // send get pacs - static const uint8_t payload[] = { - 0xa0, 19, // <- SAM command - 0xA1, 17, // <- SamCommandGetContentElement - 0x80, 1, - 0x04, // <- implicitFormatPhysicalAccessBits - 0x84, 12, - 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x04 // <- SoRootOID - }; + if(request_len > 0){ + sam_tx_len = request_len; + memcpy(sam_tx_buf, request, sam_tx_len); + }else{ + // send get pacs + static const uint8_t payload[] = { + 0xa0, 19, // <- SAM command + 0xA1, 17, // <- SamCommandGetContentElement + 0x80, 1, + 0x04, // <- implicitFormatPhysicalAccessBits + 0x84, 12, + 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x04 // <- SoRootOID + }; - sam_tx_len = sizeof(payload); - memcpy(sam_tx_buf, payload, sam_tx_len); + sam_tx_len = sizeof(payload); + memcpy(sam_tx_buf, payload, sam_tx_len); + } sam_send_payload( 0x44, 0x0a, 0x44, @@ -234,51 +243,53 @@ static int sam_request_pacs(uint8_t * pacs, uint8_t * pacs_len){ sam_rx_buf, &sam_rx_len ); - // tag <-> SAM exchange starts here - for(int i = 0; i < 20; i++){ - switch_clock_to_countsspclk(); - nfc_tx_len = sam_seos_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); + if(sam_rx_buf[1] == 0x61){ // commands to be relayed to card starts with 0x61 + // tag <-> SAM exchange starts here + while(sam_rx_buf[1] == 0x61){ + switch_clock_to_countsspclk(); + nfc_tx_len = sam_seos_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); - nfc_rx_len = iso14_apdu( - nfc_tx_buf, - nfc_tx_len, - false, - nfc_rx_buf, - ISO7816_MAX_FRAME, - NULL - ); + nfc_rx_len = iso14_apdu( + nfc_tx_buf, + nfc_tx_len, + false, + nfc_rx_buf, + ISO7816_MAX_FRAME, + NULL + ); - switch_clock_to_ticks(); - sam_tx_len = sam_seos_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len-2); + switch_clock_to_ticks(); + sam_tx_len = sam_seos_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len-2); + + sam_send_payload( + 0x14, 0x0a, 0x14, + sam_tx_buf, &sam_tx_len, + sam_rx_buf, &sam_rx_len + ); + + // last SAM->TAG + // c1 61 c1 00 00 a1 02 >>82<< 00 90 00 + if(sam_rx_buf[7] == 0x82){ + // tag <-> SAM exchange ends here + break; + } + + } + + static const uint8_t hfack[] = { + 0xbd, 0x04, 0xa0, 0x02, 0x82, 0x00 + }; + + sam_tx_len = sizeof(hfack); + memcpy(sam_tx_buf, hfack, sam_tx_len); sam_send_payload( - 0x14, 0x0a, 0x14, + 0x14, 0x0a, 0x00, sam_tx_buf, &sam_tx_len, sam_rx_buf, &sam_rx_len ); - - // last SAM->TAG - // c1 61 c1 00 00 a1 02 >>82<< 00 90 00 - if(sam_rx_buf[7] == 0x82){ - // tag <-> SAM exchange ends here - break; - } - } - static const uint8_t hfack[] = { - 0xbd, 0x04, 0xa0, 0x02, 0x82, 0x00 - }; - - sam_tx_len = sizeof(hfack); - memcpy(sam_tx_buf, hfack, sam_tx_len); - - sam_send_payload( - 0x14, 0x0a, 0x00, - sam_tx_buf, &sam_tx_len, - sam_rx_buf, &sam_rx_len - ); - // resp: // c1 64 00 00 00 // bd 09 @@ -286,13 +297,16 @@ static int sam_request_pacs(uint8_t * pacs, uint8_t * pacs_len){ // 03 05 <- include tag for pm3 client // 06 85 80 6d c0 <- decoded PACS data // 90 00 - if(sam_rx_buf[5+2] != 0x8a && sam_rx_buf[5+4] != 0x03){ - if (g_dbglevel >= DBG_ERROR) - Dbprintf("Invalid SAM response"); - goto err; + if(request_len == 0){ + if(sam_rx_buf[5] != 0xbd && sam_rx_buf[5+2] != 0x8a && sam_rx_buf[5+4] != 0x03){ + if (g_dbglevel >= DBG_ERROR) + Dbprintf("Invalid SAM response"); + goto err; + } } - *pacs_len = sam_rx_buf[5+5] +2; - memcpy(pacs, sam_rx_buf+5+4, *pacs_len); + + *response_len = sam_rx_buf[5+1] +2; + memcpy(response, sam_rx_buf+5, *response_len); res=PM3_SUCCESS; goto out; @@ -312,7 +326,13 @@ static int sam_request_pacs(uint8_t * pacs, uint8_t * pacs_len){ * * @return Status code indicating success or failure of the operation. */ -int sam_seos_get_pacs(void){ +int sam_seos_get_pacs(PacketCommandNG *c) { + bool disconnectAfter = c->oldarg[0] & 0x01; + bool skipDetect = c->oldarg[1] & 0x01; + + uint8_t *cmd = c->data.asBytes; + uint16_t cmd_len = (uint16_t) c->oldarg[2]; + int res = PM3_EFAILED; clear_trace(); @@ -324,32 +344,31 @@ int sam_seos_get_pacs(void){ // step 1: ping SAM sam_get_version(); - // step 2: get card information - iso14a_card_select_t card_a_info; + if(!skipDetect){ + // step 2: get card information + iso14a_card_select_t card_a_info; - // implicit StartSspClk() happens here - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - if (!iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)){ - goto err; + // implicit StartSspClk() happens here + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + if (!iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)){ + goto err; + } + + switch_clock_to_ticks(); + + // step 3: SamCommand CardDetected + sam_set_card_detected(&card_a_info); } - switch_clock_to_ticks(); - - // step 3: SamCommand CardDetected - sam_set_card_detected(&card_a_info); - // step 3: SamCommand RequestPACS, relay NFC communication - - uint8_t pacs[10] = { 0x00 }; - uint8_t pacs_len = 0; - res = sam_request_pacs(pacs, &pacs_len); + uint8_t sam_response[ISO7816_MAX_FRAME] = { 0x00 }; + uint8_t sam_response_len = 0; + res = sam_send_request_iso14a(cmd, cmd_len, sam_response, &sam_response_len); if(res != PM3_SUCCESS){ goto err; } if (g_dbglevel >= DBG_INFO) - print_result("PACS data", pacs, pacs_len); - - sam_send_ack(); + print_result("Response data", sam_response, sam_response_len); goto out; goto off; @@ -359,10 +378,12 @@ int sam_seos_get_pacs(void){ reply_ng(CMD_HF_SAM_SEOS, res, NULL, 0); goto off; out: - reply_ng(CMD_HF_SAM_SEOS, PM3_SUCCESS, pacs, pacs_len); + reply_ng(CMD_HF_SAM_SEOS, PM3_SUCCESS, sam_response, sam_response_len); goto off; off: - switch_off(); + if(disconnectAfter){ + switch_off(); + } set_tracing(false); StopTicks(); BigBuf_free(); diff --git a/armsrc/sam_seos.h b/armsrc/sam_seos.h index a1b637c80..8a165f255 100644 --- a/armsrc/sam_seos.h +++ b/armsrc/sam_seos.h @@ -17,7 +17,8 @@ #define __SAM_SEOS_H #include "common.h" +#include "pm3_cmd.h" -int sam_seos_get_pacs(void); +int sam_seos_get_pacs(PacketCommandNG *c); #endif diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 29512e192..6acafb222 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5434,6 +5434,8 @@ static int CmdHFiClassSAM(const char *Cmd) { // CSN, config, epurse, NR/MAC, AIA // PACS + // 03 05 + // 06 85 80 6d c0 // first byte skip // second byte length // third padded diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 74837134e..6ef6a2a60 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1635,63 +1635,18 @@ static int CmdHfSeosList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf seos", "seos -c"); } -static int CmdHfSeosSAM(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf seos sam", - "Extract PACS via a HID SAM\n", - "hf seos sam\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_lit0("v", "verbose", "verbose output"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - bool verbose = arg_get_lit(ctx, 1); - CLIParserFree(ctx); - - if (IsHIDSamPresent(verbose) == false) { - return PM3_ESOFT; - } - - clearCommandBuffer(); - SendCommandNG(CMD_HF_SAM_SEOS, NULL, 0); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) { - PrintAndLogEx(WARNING, "SAM timeout"); - return PM3_ETIMEOUT; - } - - switch (resp.status) { - case PM3_SUCCESS: - break; - case PM3_ENOPACS: - PrintAndLogEx(SUCCESS, "No PACS data found. Card empty?"); - return resp.status; - default: - PrintAndLogEx(WARNING, "SAM select failed"); - return resp.status; - } - - // CSN, config, epurse, NR/MAC, AIA - // PACS - // first byte skip - // second byte length - // third padded - // fourth .. - uint8_t *d = resp.data.asBytes; - uint8_t n = d[1] - 1; // skip length byte - uint8_t pad = d[2]; - char *binstr = (char *)calloc((n * 8) + 1, sizeof(uint8_t)); +static int dump_PACS_bits(const uint8_t * const data, const uint8_t length, bool verbose){ + uint8_t n = length - 1; + uint8_t pad = data[0]; + char *binstr = (char *)calloc((length * 8) + 1, sizeof(uint8_t)); if (binstr == NULL) { return PM3_EMALLOC; } - bytes_2_binstr(binstr, d + 3, n); + bytes_2_binstr(binstr, data + 1, n); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + 2, resp.length - 2)); + PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(data, length)); PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); binstr[strlen(binstr) - pad] = '\0'; @@ -1749,7 +1704,98 @@ static int CmdHfSeosSAM(const char *Cmd) { PrintAndLogEx(NORMAL, ""); } free(binstr); + return PM3_SUCCESS; +} + +static int CmdHfSeosSAM(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf seos sam", + "Extract PACS via a HID SAM\n", + "hf seos sam\n" + "hd seos sam -d a005a103800104 -> get PACS data\n" + ); + + + + void *argtable[] = { + arg_param_begin, + arg_lit0("v", "verbose", "verbose output"), + arg_lit0("k", "keep", "keep the field active after command executed"), + arg_lit0("n", "nodetect", "skip selecting the card and sending card details to SAM"), + arg_lit0("t", "tlv", "decode TLV"), + arg_strx0("d", "data", "", "DER encoded command to send to SAM"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool verbose = false; + if (arg_get_lit(ctx, 1)) { + verbose = true; + } + bool disconnectAfter = true; + if(arg_get_lit(ctx, 2)){ + disconnectAfter = false; + } + bool skipDetect = false; + if(arg_get_lit(ctx, 3)){ + skipDetect = true; + } + bool decodeTLV = false; + if(arg_get_lit(ctx, 4)){ + decodeTLV = true; + } + + uint8_t data[PM3_CMD_DATA_SIZE] = {0}; + int datalen = 0; + CLIGetHexBLessWithReturn(ctx, 5, data, &datalen, 0); + + CLIParserFree(ctx); + + if (IsHIDSamPresent(verbose) == false) { + return PM3_ESOFT; + } + + clearCommandBuffer(); + // void SendCommandMIX(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len) { + SendCommandMIX(CMD_HF_SAM_SEOS, disconnectAfter, skipDetect, datalen, data, datalen); + // SendCommandNG(CMD_HF_SAM_SEOS, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) { + PrintAndLogEx(WARNING, "SAM timeout"); + return PM3_ETIMEOUT; + } + + switch (resp.status) { + case PM3_SUCCESS: + break; + case PM3_ENOPACS: + PrintAndLogEx(SUCCESS, "No PACS data found. Card empty?"); + return resp.status; + default: + PrintAndLogEx(WARNING, "SAM select failed"); + return resp.status; + } + uint8_t *d = resp.data.asBytes; + // check for standard SamCommandGetContentElement response + // bd 09 + // 8a 07 + // 03 05 <- tag + length + // 06 85 80 6d c0 <- decoded PACS data + if(d[0] == 0xbd && d[2] == 0x8a && d[4] == 0x03){ + uint8_t pacs_length = d[5]; + uint8_t * pacs_data = d + 6; + int res = dump_PACS_bits(pacs_data, pacs_length, verbose); + if(res != PM3_SUCCESS){ + return res; + } + } else { + print_hex(d, resp.length); + } + if (decodeTLV) { + asn1_print(d, d[1] + 2, " "); + } + return PM3_SUCCESS; } From 508b63fd2e3ace526094f36f95dba94396ec42c7 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 6 Jan 2025 14:59:26 +0100 Subject: [PATCH 10/13] sam_seos: switch to samCommandGetContentElement2 As PLT-03273 OMNIKEY 5023 Software Developer Guide (https://www.hidglobal.com/documents/omnikey-5023-software-developer-guide) describes a command that returns additional information about SIO object containing PACS data, switching to more verbose one. --- armsrc/sam_seos.c | 30 ++++++++++++++++------ client/src/cmdhfseos.c | 58 ++++++++++++++++++++++++++++++++++++++++-- client/src/cmdhfseos.h | 6 +++++ 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 866f62a63..37a2da259 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -226,7 +226,7 @@ static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t // send get pacs static const uint8_t payload[] = { 0xa0, 19, // <- SAM command - 0xA1, 17, // <- SamCommandGetContentElement + 0xBE, 17, // <- samCommandGetContentElement2 0x80, 1, 0x04, // <- implicitFormatPhysicalAccessBits 0x84, 12, @@ -290,29 +290,43 @@ static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t ); } - // resp: + // resp for SamCommandGetContentElement: // c1 64 00 00 00 // bd 09 // 8a 07 // 03 05 <- include tag for pm3 client // 06 85 80 6d c0 <- decoded PACS data // 90 00 + + // resp for samCommandGetContentElement2: + // c1 64 00 00 00 + // bd 1e + // b3 1c + // a0 1a + // 80 05 + // 06 85 80 6d c0 + // 81 0e + // 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff + // 82 01 + // 07 + // 90 00 if(request_len == 0){ - if(sam_rx_buf[5] != 0xbd && sam_rx_buf[5+2] != 0x8a && sam_rx_buf[5+4] != 0x03){ + if( + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5+2] == 0x8a && sam_rx_buf[5+4] == 0x03) + && + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5+2] == 0xb3 && sam_rx_buf[5+4] == 0xa0) + ){ if (g_dbglevel >= DBG_ERROR) - Dbprintf("Invalid SAM response"); - goto err; + Dbprintf("No PACS data in SAM response"); + res=PM3_ESOFT; } } *response_len = sam_rx_buf[5+1] +2; memcpy(response, sam_rx_buf+5, *response_len); - res=PM3_SUCCESS; goto out; - err: - res=PM3_ESOFT; out: return res; } diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 6ef6a2a60..bc96ad7d4 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -100,6 +100,17 @@ static const known_algo_t known_algorithm_map[] = { {9, "AES-128_CBC_MODE"}, }; +static const sioMediaTypeName_t sioMediaTypeMapping[] = { + { 0x00, "Unknown"}, + { 0x01, "DESFire"}, + { 0x02, "MIFARE"}, + { 0x03, "iCLASS (PicoPass)"}, + { 0x04, "ISO14443AL4"}, + { 0x06, "MIFARE Plus"}, + { 0x07, "Seos"}, + { 0xFF, "INVALID VALUE"} +}; + static int create_cmac (uint8_t* key, uint8_t* input, uint8_t* out, int input_len, int encryption_algorithm) { uint8_t iv[16] = {0x00}; @@ -1707,6 +1718,23 @@ static int dump_PACS_bits(const uint8_t * const data, const uint8_t length, bool return PM3_SUCCESS; } + +// get a SIO media type based on the UID +// uid[8] tag uid +// returns description of the best match +static const char *getSioMediaTypeInfo(uint8_t uid) { + + for (int i = 0; i < ARRAYLEN(sioMediaTypeMapping); ++i) { + if (uid == sioMediaTypeMapping[i].uid) { + return sioMediaTypeMapping[i].desc; + } + } + + //No match, return default + return sioMediaTypeMapping[ARRAYLEN(sioMediaTypeMapping) - 1].desc; +} + + static int CmdHfSeosSAM(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf seos sam", @@ -1756,9 +1784,7 @@ static int CmdHfSeosSAM(const char *Cmd) { } clearCommandBuffer(); - // void SendCommandMIX(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len) { SendCommandMIX(CMD_HF_SAM_SEOS, disconnectAfter, skipDetect, datalen, data, datalen); - // SendCommandNG(CMD_HF_SAM_SEOS, NULL, 0); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) { PrintAndLogEx(WARNING, "SAM timeout"); @@ -1789,6 +1815,34 @@ static int CmdHfSeosSAM(const char *Cmd) { if(res != PM3_SUCCESS){ return res; } + // check for standard samCommandGetContentElement2: + // bd 1e + // b3 1c + // a0 1a + // 80 05 + // 06 85 80 6d c0 + // 81 0e + // 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff + // 82 01 + // 07 + } else if(d[0]==0xbd && d[2]==0xb3 && d[4]==0xa0){ + const uint8_t * pacs = d + 6; + const uint8_t pacs_length = pacs[1]; + const uint8_t * pacs_data = pacs + 2; + int res = dump_PACS_bits(pacs_data, pacs_length, verbose); + if(res != PM3_SUCCESS){ + return res; + } + + const uint8_t * oid = pacs + 2 + pacs_length; + const uint8_t oid_length = oid[1]; + const uint8_t * oid_data = oid + 2; + PrintAndLogEx(SUCCESS, "SIO OID.......: " _GREEN_("%s"), sprint_hex_inrow(oid_data, oid_length)); + + const uint8_t * mediaType = oid + 2 + oid_length; + const uint8_t mediaType_data = mediaType[2]; + PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data)); + } else { print_hex(d, resp.length); } diff --git a/client/src/cmdhfseos.h b/client/src/cmdhfseos.h index 33e6d45f5..950346c04 100644 --- a/client/src/cmdhfseos.h +++ b/client/src/cmdhfseos.h @@ -21,6 +21,12 @@ #include "common.h" +// structure and database for uid -> tagtype lookups +typedef struct { + uint8_t uid; + const char *desc; +} sioMediaTypeName_t; + int infoSeos(bool verbose); int CmdHFSeos(const char *Cmd); int seos_kdf(bool encryption, uint8_t* masterKey, uint8_t keyslot, From dd30781608830fe00f4e77f317da614bb167abf1 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 6 Jan 2025 15:17:34 +0100 Subject: [PATCH 11/13] extract PACS-parsing routines to wiegand_formats.c --- client/src/cmdhficlass.c | 71 +-------------------------------- client/src/cmdhfseos.c | 77 +----------------------------------- client/src/wiegand_formats.c | 72 +++++++++++++++++++++++++++++++++ client/src/wiegand_formats.h | 1 + 4 files changed, 77 insertions(+), 144 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 6acafb222..ea53ebb83 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5441,75 +5441,8 @@ static int CmdHFiClassSAM(const char *Cmd) { // third padded // fourth .. uint8_t *d = resp.data.asBytes; - uint8_t n = d[1] - 1; // skip length byte - uint8_t pad = d[2]; - char *binstr = (char *)calloc((n * 8) + 1, sizeof(uint8_t)); - if (binstr == NULL) { - return PM3_EMALLOC; - } - - bytes_2_binstr(binstr, d + 3, n); - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + 2, resp.length - 2)); - PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); - - binstr[strlen(binstr) - pad] = '\0'; - PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); - - size_t hexlen = 0; - uint8_t hex[16] = {0}; - binstr_2_bytes(hex, &hexlen, binstr); - PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen)); - - uint32_t top = 0, mid = 0, bot = 0; - if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) { - PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); - free(binstr); - return PM3_EINVARG; - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Wiegand decode"); - wiegand_message_t packed = initialize_message_object(top, mid, bot, strlen(binstr)); - HIDTryUnpack(&packed); - - PrintAndLogEx(NORMAL, ""); - - if (strlen(binstr) >= 26 && verbose) { - - // iCLASS Legacy - PrintAndLogEx(INFO, "Clone to " _YELLOW_("iCLASS Legacy")); - PrintAndLogEx(SUCCESS, " hf iclass encode --ki 0 --bin %s", binstr); - PrintAndLogEx(NORMAL, ""); - - // HID Prox II - PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("HID Prox II")); - PrintAndLogEx(SUCCESS, " lf hid clone -w H10301 --bin %s", binstr); - PrintAndLogEx(NORMAL, ""); - - // MIFARE Classic - char mfcbin[28] = {0}; - mfcbin[0] = '1'; - memcpy(mfcbin + 1, binstr, strlen(binstr)); - binstr_2_bytes(hex, &hexlen, mfcbin); - - PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic") " (Pm3 simulation)"); - PrintAndLogEx(SUCCESS, " hf mf eclr;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 0 -d 049DBA42A23E80884400C82000000000;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 1 -d 1B014D48000000000000000000000000;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 5 -d 020000000000000000000000%s;", sprint_hex_inrow(hex, hexlen)); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 7 -d 484944204953787788AA204752454154;"); - PrintAndLogEx(SUCCESS, " hf mf sim --1k -i;"); - PrintAndLogEx(NORMAL, ""); - - PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic 1K")); - PrintAndLogEx(SUCCESS, " hf mf encodehid --bin %s", binstr); - PrintAndLogEx(NORMAL, ""); - } - free(binstr); - + HIDDumpPACSBits(d+2, d[1], verbose); + return PM3_SUCCESS; } diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index bc96ad7d4..c0a2891de 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1646,79 +1646,6 @@ static int CmdHfSeosList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf seos", "seos -c"); } -static int dump_PACS_bits(const uint8_t * const data, const uint8_t length, bool verbose){ - uint8_t n = length - 1; - uint8_t pad = data[0]; - char *binstr = (char *)calloc((length * 8) + 1, sizeof(uint8_t)); - if (binstr == NULL) { - return PM3_EMALLOC; - } - - bytes_2_binstr(binstr, data + 1, n); - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(data, length)); - PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); - - binstr[strlen(binstr) - pad] = '\0'; - PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); - - size_t hexlen = 0; - uint8_t hex[16] = {0}; - binstr_2_bytes(hex, &hexlen, binstr); - PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen)); - - uint32_t top = 0, mid = 0, bot = 0; - if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) { - PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); - free(binstr); - return PM3_EINVARG; - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Wiegand decode"); - wiegand_message_t packed = initialize_message_object(top, mid, bot, strlen(binstr)); - HIDTryUnpack(&packed); - - PrintAndLogEx(NORMAL, ""); - - if (strlen(binstr) >= 26 && verbose) { - - // iCLASS Legacy - PrintAndLogEx(INFO, "Clone to " _YELLOW_("iCLASS Legacy")); - PrintAndLogEx(SUCCESS, " hf iclass encode --ki 0 --bin %s", binstr); - PrintAndLogEx(NORMAL, ""); - - // HID Prox II - PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("HID Prox II")); - PrintAndLogEx(SUCCESS, " lf hid clone -w H10301 --bin %s", binstr); - PrintAndLogEx(NORMAL, ""); - - // MIFARE Classic - char mfcbin[28] = {0}; - mfcbin[0] = '1'; - memcpy(mfcbin + 1, binstr, strlen(binstr)); - binstr_2_bytes(hex, &hexlen, mfcbin); - - PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic") " (Pm3 simulation)"); - PrintAndLogEx(SUCCESS, " hf mf eclr;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 0 -d 049DBA42A23E80884400C82000000000;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 1 -d 1B014D48000000000000000000000000;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A;"); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 5 -d 020000000000000000000000%s;", sprint_hex_inrow(hex, hexlen)); - PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 7 -d 484944204953787788AA204752454154;"); - PrintAndLogEx(SUCCESS, " hf mf sim --1k -i;"); - PrintAndLogEx(NORMAL, ""); - - PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic 1K")); - PrintAndLogEx(SUCCESS, " hf mf encodehid --bin %s", binstr); - PrintAndLogEx(NORMAL, ""); - } - free(binstr); - return PM3_SUCCESS; -} - - // get a SIO media type based on the UID // uid[8] tag uid // returns description of the best match @@ -1811,7 +1738,7 @@ static int CmdHfSeosSAM(const char *Cmd) { if(d[0] == 0xbd && d[2] == 0x8a && d[4] == 0x03){ uint8_t pacs_length = d[5]; uint8_t * pacs_data = d + 6; - int res = dump_PACS_bits(pacs_data, pacs_length, verbose); + int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose); if(res != PM3_SUCCESS){ return res; } @@ -1829,7 +1756,7 @@ static int CmdHfSeosSAM(const char *Cmd) { const uint8_t * pacs = d + 6; const uint8_t pacs_length = pacs[1]; const uint8_t * pacs_data = pacs + 2; - int res = dump_PACS_bits(pacs_data, pacs_length, verbose); + int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose); if(res != PM3_SUCCESS){ return res; } diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c index bf08e0908..ecbf47000 100644 --- a/client/src/wiegand_formats.c +++ b/client/src/wiegand_formats.c @@ -1663,3 +1663,75 @@ void HIDUnpack(int idx, wiegand_message_t *packed) { hid_print_card(&card, FormatTable[idx]); } } + +int HIDDumpPACSBits(const uint8_t * const data, const uint8_t length, bool verbose){ + uint8_t n = length - 1; + uint8_t pad = data[0]; + char *binstr = (char *)calloc((length * 8) + 1, sizeof(uint8_t)); + if (binstr == NULL) { + return PM3_EMALLOC; + } + + bytes_2_binstr(binstr, data + 1, n); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(data, length)); + PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); + + binstr[strlen(binstr) - pad] = '\0'; + PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); + + size_t hexlen = 0; + uint8_t hex[16] = {0}; + binstr_2_bytes(hex, &hexlen, binstr); + PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen)); + + uint32_t top = 0, mid = 0, bot = 0; + if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) { + PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); + free(binstr); + return PM3_EINVARG; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Wiegand decode"); + wiegand_message_t packed = initialize_message_object(top, mid, bot, strlen(binstr)); + HIDTryUnpack(&packed); + + PrintAndLogEx(NORMAL, ""); + + if (strlen(binstr) >= 26 && verbose) { + + // iCLASS Legacy + PrintAndLogEx(INFO, "Clone to " _YELLOW_("iCLASS Legacy")); + PrintAndLogEx(SUCCESS, " hf iclass encode --ki 0 --bin %s", binstr); + PrintAndLogEx(NORMAL, ""); + + // HID Prox II + PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("HID Prox II")); + PrintAndLogEx(SUCCESS, " lf hid clone -w H10301 --bin %s", binstr); + PrintAndLogEx(NORMAL, ""); + + // MIFARE Classic + char mfcbin[28] = {0}; + mfcbin[0] = '1'; + memcpy(mfcbin + 1, binstr, strlen(binstr)); + binstr_2_bytes(hex, &hexlen, mfcbin); + + PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic") " (Pm3 simulation)"); + PrintAndLogEx(SUCCESS, " hf mf eclr;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 0 -d 049DBA42A23E80884400C82000000000;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 1 -d 1B014D48000000000000000000000000;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A;"); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 5 -d 020000000000000000000000%s;", sprint_hex_inrow(hex, hexlen)); + PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 7 -d 484944204953787788AA204752454154;"); + PrintAndLogEx(SUCCESS, " hf mf sim --1k -i;"); + PrintAndLogEx(NORMAL, ""); + + PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic 1K")); + PrintAndLogEx(SUCCESS, " hf mf encodehid --bin %s", binstr); + PrintAndLogEx(NORMAL, ""); + } + free(binstr); + return PM3_SUCCESS; +} \ No newline at end of file diff --git a/client/src/wiegand_formats.h b/client/src/wiegand_formats.h index 671795c9a..763edaba8 100644 --- a/client/src/wiegand_formats.h +++ b/client/src/wiegand_formats.h @@ -54,6 +54,7 @@ bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bo bool HIDTryUnpack(wiegand_message_t *packed); void HIDPackTryAll(wiegand_card_t *card, bool preamble); void HIDUnpack(int idx, wiegand_message_t *packed); +int HIDDumpPACSBits(const uint8_t * const data, const uint8_t length, bool verbose); void print_wiegand_code(wiegand_message_t *packed); void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed); #endif From 13e390ad3bd3a8efb19aa08c51578a1c13d2c239 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 6 Jan 2025 15:37:18 +0100 Subject: [PATCH 12/13] added sam_seos to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ebebd9c1..7207389e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] +- Added `hf seos sam` - Added support for HID SAM SEOS communications (@jkramarz) - Changed (extended) area accessible by spiffs into last page of FLASH (@piotrva) - Changed flash-stored key dictionaries (Mifare, iClass, T55XX) and T55XX configurations to SPIFFS files (@piotrva) - Changed `lf em 410x sim` to use default gap value of 0 and extended help (@piotrva) From 15a37ef9dfc724787932a0ce5805526d1a93c872 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Tue, 7 Jan 2025 00:30:49 +0100 Subject: [PATCH 13/13] seos_sam: ran make style --- armsrc/sam_common.c | 92 ++++++++++----------- armsrc/sam_common.h | 6 +- armsrc/sam_picopass.c | 32 ++++---- armsrc/sam_seos.c | 154 +++++++++++++++++------------------ client/src/cmdhficlass.c | 6 +- client/src/cmdhfseos.c | 48 +++++------ client/src/cmdhfseos.h | 4 +- client/src/wiegand_formats.c | 6 +- client/src/wiegand_formats.h | 2 +- common_arm/ticks.c | 2 +- 10 files changed, 176 insertions(+), 176 deletions(-) diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c index 835428074..76ca269e1 100644 --- a/armsrc/sam_common.c +++ b/armsrc/sam_common.c @@ -96,12 +96,12 @@ int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen) *resplen += more_len; - out: +out: return res; } -static inline void swap_clock_counters(volatile unsigned int * a, unsigned int * b){ +static inline void swap_clock_counters(volatile unsigned int *a, unsigned int *b) { unsigned int c = *a; *a = *b; *b = c; @@ -113,9 +113,9 @@ static inline void swap_clock_counters(volatile unsigned int * a, unsigned int * * AT91SAM7S512 has a single Timer-Counter, that is reused in clocks Ticks * and CountSspClk. This function stops the current clock and restores previous * values. It is used to switch between different clock sources. - * It probably makes communication timing off, but at least makes it work. + * It probably makes communication timing off, but at least makes it work. */ -static void swap_clocks(void){ +static void swap_clocks(void) { static unsigned int tc0, tc1, tc2 = 0; StopTicks(); swap_clock_counters(&(AT91C_BASE_TC0->TC_CV), &tc0); @@ -123,12 +123,12 @@ static void swap_clocks(void){ swap_clock_counters(&(AT91C_BASE_TC2->TC_CV), &tc2); } -void switch_clock_to_ticks(void){ +void switch_clock_to_ticks(void) { swap_clocks(); StartTicks(); } -void switch_clock_to_countsspclk(void){ +void switch_clock_to_countsspclk(void) { swap_clocks(); StartCountSspClk(); } @@ -155,21 +155,21 @@ int sam_send_payload( const uint8_t addr_dest, const uint8_t addr_reply, - const uint8_t * const payload, + const uint8_t *const payload, const uint16_t *payload_len, uint8_t *response, uint16_t *response_len -){ +) { int res = PM3_SUCCESS; - uint8_t * buf = response; + uint8_t *buf = response; buf[0] = 0xA0; // CLA buf[1] = 0xDA; // INS (PUT DATA) buf[2] = 0x02; // P1 (TLV format?) buf[3] = 0x63; // P2 - buf[4] = SAM_TX_ASN1_PREFIX_LENGTH + (uint8_t) *payload_len; // LEN + buf[4] = SAM_TX_ASN1_PREFIX_LENGTH + (uint8_t) * payload_len; // LEN buf[5] = addr_src; buf[6] = addr_dest; @@ -185,10 +185,10 @@ int sam_send_payload( *payload_len ); - uint16_t length = SAM_TX_ASN1_PREFIX_LENGTH + SAM_TX_APDU_PREFIX_LENGTH + (uint8_t) *payload_len; + uint16_t length = SAM_TX_ASN1_PREFIX_LENGTH + SAM_TX_APDU_PREFIX_LENGTH + (uint8_t) * payload_len; LogTrace(buf, length, 0, 0, NULL, true); - if (g_dbglevel >= DBG_INFO){ + if (g_dbglevel >= DBG_INFO) { DbpString("SAM REQUEST APDU: "); Dbhexdump(length, buf, false); } @@ -201,12 +201,12 @@ int sam_send_payload( } LogTrace(response, *response_len, 0, 0, NULL, false); - if (g_dbglevel >= DBG_INFO){ + if (g_dbglevel >= DBG_INFO) { DbpString("SAM RESPONSE APDU: "); Dbhexdump(*response_len, response, false); } - out: +out: return res; } @@ -218,18 +218,18 @@ int sam_send_payload( * * @return Status code indicating success or failure of the operation. */ -int sam_get_version(void){ +int sam_get_version(void) { int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_get_version"); - uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; uint8_t payload[] = { 0xa0, 0x02, // <- SAM command - 0x82, 0x00 // <- get version + 0x82, 0x00 // <- get version }; uint16_t payload_len = sizeof(payload); @@ -255,46 +255,46 @@ int sam_get_version(void){ if (g_dbglevel >= DBG_DEBUG) DbpString("end sam_get_version"); - if(response[5] != 0xbd){ + if (response[5] != 0xbd) { Dbprintf("Invalid SAM response"); goto error; - }else{ - uint8_t * sam_response_an = sam_find_asn1_node(response + 5, 0x8a); - if(sam_response_an == NULL){ + } else { + uint8_t *sam_response_an = sam_find_asn1_node(response + 5, 0x8a); + if (sam_response_an == NULL) { if (g_dbglevel >= DBG_ERROR) DbpString("SAM get response failed"); goto error; } - uint8_t * sam_version_an = sam_find_asn1_node(sam_response_an, 0x80); - if(sam_version_an == NULL){ + uint8_t *sam_version_an = sam_find_asn1_node(sam_response_an, 0x80); + if (sam_version_an == NULL) { if (g_dbglevel >= DBG_ERROR) DbpString("SAM get version failed"); goto error; } - uint8_t * sam_build_an = sam_find_asn1_node(sam_response_an, 0x81); - if(sam_build_an == NULL){ + uint8_t *sam_build_an = sam_find_asn1_node(sam_response_an, 0x81); + if (sam_build_an == NULL) { if (g_dbglevel >= DBG_ERROR) DbpString("SAM get firmware ID failed"); goto error; } - if (g_dbglevel >= DBG_INFO){ + if (g_dbglevel >= DBG_INFO) { DbpString("SAM get version successful"); Dbprintf("Firmware version: %X.%X", sam_version_an[2], sam_version_an[3]); Dbprintf("Firmware ID: "); - Dbhexdump(sam_build_an[1], sam_build_an+2, false); + Dbhexdump(sam_build_an[1], sam_build_an + 2, false); } goto out; } - error: +error: res = PM3_ESOFT; - out: +out: BigBuf_free(); if (g_dbglevel >= DBG_DEBUG) DbpString("end sam_get_version"); - + return res; } @@ -310,14 +310,14 @@ int sam_get_version(void){ * @param type The type of the ASN.1 node to find. * @return Pointer to the ASN.1 node of the specified type if found, otherwise NULL. */ -uint8_t * sam_find_asn1_node(const uint8_t * root, const uint8_t type){ - const uint8_t * end = (uint8_t *) root + *(root+1); - uint8_t * current = (uint8_t *) root + 2; - while(current < end){ - if(*current == type){ +uint8_t *sam_find_asn1_node(const uint8_t *root, const uint8_t type) { + const uint8_t *end = (uint8_t *) root + *(root + 1); + uint8_t *current = (uint8_t *) root + 2; + while (current < end) { + if (*current == type) { return current; - }else{ - current += 2 + *(current+1); + } else { + current += 2 + *(current + 1); } } return NULL; @@ -328,7 +328,7 @@ uint8_t * sam_find_asn1_node(const uint8_t * root, const uint8_t type){ * * This function appends an ASN.1 node of a specified type and length to the end of * the ASN.1 structure at specified node level. - * + * * It is the most naive solution that does not handle the case where the node to append is * not the last node at the same level. It also does not also care about proper * order of the nodes. @@ -339,21 +339,21 @@ uint8_t * sam_find_asn1_node(const uint8_t * root, const uint8_t type){ * @param data Pointer to the data to be appended. * @param len The length of the data to be appended. */ -void sam_append_asn1_node(const uint8_t * root, const uint8_t * node, uint8_t type, const uint8_t * const data, uint8_t len){ - uint8_t * end = (uint8_t *) root + *(root+1) + 2; +void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type, const uint8_t *const data, uint8_t len) { + uint8_t *end = (uint8_t *) root + *(root + 1) + 2; *(end) = type; - *(end+1) = len; - memcpy(end+2, data, len); + *(end + 1) = len; + memcpy(end + 2, data, len); - for(uint8_t * current = (uint8_t *) root; current <= node; current += 2){ - *(current+1) += 2 + len; + for (uint8_t *current = (uint8_t *) root; current <= node; current += 2) { + *(current + 1) += 2 + len; }; return; } -void sam_send_ack(void){ - uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); +void sam_send_ack(void) { + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; uint8_t payload[] = { diff --git a/armsrc/sam_common.h b/armsrc/sam_common.h index 5e243346c..645957a3c 100644 --- a/armsrc/sam_common.h +++ b/armsrc/sam_common.h @@ -32,7 +32,7 @@ int sam_send_payload( const uint8_t addr_dest, const uint8_t addr_reply, - const uint8_t * const payload, + const uint8_t *const payload, const uint16_t *payload_len, uint8_t *response, @@ -41,8 +41,8 @@ int sam_send_payload( int sam_get_version(void); -uint8_t * sam_find_asn1_node(const uint8_t * root, const uint8_t type); -void sam_append_asn1_node(const uint8_t * root, const uint8_t * node, uint8_t type, const uint8_t * const data, uint8_t len); +uint8_t *sam_find_asn1_node(const uint8_t *root, const uint8_t type); +void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type, const uint8_t *const data, uint8_t len); void sam_send_ack(void); diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index 055423f41..d396a31c5 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -41,12 +41,12 @@ * @param card_select Pointer to the descriptor of the detected card. * @return Status code indicating success or failure of the operation. */ -static int sam_set_card_detected(picopass_hdr_t * card_select){ +static int sam_set_card_detected(picopass_hdr_t *card_select) { int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_set_card_detected"); - uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; // a0 12 @@ -59,13 +59,13 @@ static int sam_set_card_detected(picopass_hdr_t * card_select){ uint8_t payload[] = { 0xa0, 18, // <- SAM command - 0xad, 16, // <- set detected card - 0xa0, 4+10, - 0x80, 2, // <- protocol - 0x00, 0x04, // <- Picopass - 0x81, 8, // <- CSN - card_select->csn[0], card_select->csn[1], card_select->csn[2], card_select->csn[3], - card_select->csn[4], card_select->csn[5], card_select->csn[6], card_select->csn[7] + 0xad, 16, // <- set detected card + 0xa0, 4 + 10, + 0x80, 2, // <- protocol + 0x00, 0x04, // <- Picopass + 0x81, 8, // <- CSN + card_select->csn[0], card_select->csn[1], card_select->csn[2], card_select->csn[3], + card_select->csn[4], card_select->csn[5], card_select->csn[6], card_select->csn[7] }; uint16_t payload_len = sizeof(payload); @@ -82,12 +82,12 @@ static int sam_set_card_detected(picopass_hdr_t * card_select){ // bd 02 <- response // 8a 00 <- empty response (accepted) // 90 00 - - if(response[5] != 0xbd){ + + if (response[5] != 0xbd) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Invalid SAM response"); goto error; - }else{ + } else { // uint8_t * sam_response_an = sam_find_asn1_node(response + 5, 0x8a); // if(sam_response_an == NULL){ // if (g_dbglevel >= DBG_ERROR) @@ -96,10 +96,10 @@ static int sam_set_card_detected(picopass_hdr_t * card_select){ // } goto out; } - error: +error: res = PM3_ESOFT; - out: +out: BigBuf_free(); if (g_dbglevel >= DBG_DEBUG) @@ -240,11 +240,11 @@ int sam_picopass_get_pacs(void) { // second - get PACS (0xA1) // a0 05 - // a1 03 + // a1 03 // 80 01 // 04 hexstr_to_byte_array("a005a103800104", sam_apdu, &sam_len); - if(sam_send_payload(0x44, 0x0a, 0x44, sam_apdu, (uint16_t *) &sam_len, resp, &resp_len) != PM3_SUCCESS) { + if (sam_send_payload(0x44, 0x0a, 0x44, sam_apdu, (uint16_t *) &sam_len, resp, &resp_len) != PM3_SUCCESS) { res = PM3_ECARDEXCHANGE; goto out; } diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 37a2da259..2e5c09349 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -49,29 +49,29 @@ * @param card_select Pointer to the descriptor of the detected card. * @return Status code indicating success or failure of the operation. */ -static int sam_set_card_detected(iso14a_card_select_t * card_select){ +static int sam_set_card_detected(iso14a_card_select_t *card_select) { int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_set_card_detected"); - uint8_t * request = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *request = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t request_len = ISO7816_MAX_FRAME; - uint8_t * response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; const uint8_t payload[] = { 0xa0, 8, // <- SAM command - 0xad, 6, // <- set detected card - 0xa0, 4, // <- detected card details - 0x80, 2, // <- protocol - 0x00, 0x02 // <- ISO14443A + 0xad, 6, // <- set detected card + 0xa0, 4, // <- detected card details + 0x80, 2, // <- protocol + 0x00, 0x02 // <- ISO14443A }; memcpy(request, payload, sizeof(payload)); - sam_append_asn1_node(request, request+4, 0x81, card_select->uid, card_select->uidlen); - sam_append_asn1_node(request, request+4, 0x82, card_select->atqa, 2); - sam_append_asn1_node(request, request+4, 0x83, &card_select->sak, 1); + sam_append_asn1_node(request, request + 4, 0x81, card_select->uid, card_select->uidlen); + sam_append_asn1_node(request, request + 4, 0x82, card_select->atqa, 2); + sam_append_asn1_node(request, request + 4, 0x83, &card_select->sak, 1); request_len = request[1] + 2; sam_send_payload( @@ -87,12 +87,12 @@ static int sam_set_card_detected(iso14a_card_select_t * card_select){ // bd 02 <- response // 8a 00 <- empty response (accepted) // 90 00 - - if(response[5] != 0xbd){ + + if (response[5] != 0xbd) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Invalid SAM response"); goto error; - }else{ + } else { // uint8_t * sam_response_an = sam_find_asn1_node(response + 5, 0x8a); // if(sam_response_an == NULL){ // if (g_dbglevel >= DBG_ERROR) @@ -101,10 +101,10 @@ static int sam_set_card_detected(iso14a_card_select_t * card_select){ // } goto out; } - error: +error: res = PM3_ESOFT; - out: +out: BigBuf_free(); if (g_dbglevel >= DBG_DEBUG) @@ -123,7 +123,7 @@ static int sam_set_card_detected(iso14a_card_select_t * card_select){ * * @return Length of SAM APDU to be sent. */ -inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t * nfc_rx, uint8_t nfc_len){ +inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t *nfc_rx, uint8_t nfc_len) { // NFC resp: // 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3 @@ -138,18 +138,18 @@ inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t * const uint8_t payload[] = { 0xbd, 4, - 0xa0, 2, - 0xa0, 0 + 0xa0, 2, + 0xa0, 0 }; const uint8_t tag81[] = { - 0x00, 0x00 + 0x00, 0x00 }; memcpy(sam_tx, payload, sizeof(payload)); - - sam_append_asn1_node(sam_tx, sam_tx+4, 0x80, nfc_rx, nfc_len); - sam_append_asn1_node(sam_tx, sam_tx+4, 0x81, tag81, sizeof(tag81)); + + sam_append_asn1_node(sam_tx, sam_tx + 4, 0x80, nfc_rx, nfc_len); + sam_append_asn1_node(sam_tx, sam_tx + 4, 0x81, tag81, sizeof(tag81)); return sam_tx[1] + 2; // length of the ASN1 tree } @@ -163,7 +163,7 @@ inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t * * @param sam_rx_buf Pointer to the buffer containing the data received from the SAM. * @return Length of NFC APDU to be sent. */ -inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t * nfc_tx_buf, uint8_t * sam_rx_buf){ +inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t *nfc_tx_buf, uint8_t *sam_rx_buf) { // SAM resp: // c1 61 c1 00 00 // a1 21 <- nfc command @@ -182,8 +182,8 @@ inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t * nfc_tx_buf, uint8 // 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00 // copy data out of c1->a1>->a1->80 node - uint16_t nfc_tx_len = (uint8_t) *(sam_rx_buf + 10); - memcpy(nfc_tx_buf, sam_rx_buf+11, nfc_tx_len); + uint16_t nfc_tx_len = (uint8_t) * (sam_rx_buf + 10); + memcpy(nfc_tx_buf, sam_rx_buf + 11, nfc_tx_len); return nfc_tx_len; } @@ -193,13 +193,13 @@ inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t * nfc_tx_buf, uint8 * Unpacks request to the SAM and relays ISO14A traffic to the card. * If no request data provided, sends a request to get PACS data. * - * @param request Pointer to the buffer containing the request to be sent to the SAM. + * @param request Pointer to the buffer containing the request to be sent to the SAM. * @param request_len Length of the request to be sent to the SAM. * @param response Pointer to the buffer where the retreived data will be stored. * @param response_len Pointer to the variable where the length of the retreived data will be stored. * @return Status code indicating success or failure of the operation. */ -static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t request_len, uint8_t * response, uint8_t * response_len){ +static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len) { int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_send_request_iso14a"); @@ -207,22 +207,22 @@ static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t uint8_t buf1[ISO7816_MAX_FRAME] = {0}; uint8_t buf2[ISO7816_MAX_FRAME] = {0}; - uint8_t * sam_tx_buf = buf1; + uint8_t *sam_tx_buf = buf1; uint16_t sam_tx_len; - uint8_t * sam_rx_buf = buf2; + uint8_t *sam_rx_buf = buf2; uint16_t sam_rx_len; - uint8_t * nfc_tx_buf = buf1; + uint8_t *nfc_tx_buf = buf1; uint16_t nfc_tx_len; - uint8_t * nfc_rx_buf = buf2; + uint8_t *nfc_rx_buf = buf2; uint16_t nfc_rx_len; - if(request_len > 0){ + if (request_len > 0) { sam_tx_len = request_len; memcpy(sam_tx_buf, request, sam_tx_len); - }else{ + } else { // send get pacs static const uint8_t payload[] = { 0xa0, 19, // <- SAM command @@ -243,23 +243,23 @@ static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t sam_rx_buf, &sam_rx_len ); - if(sam_rx_buf[1] == 0x61){ // commands to be relayed to card starts with 0x61 + if (sam_rx_buf[1] == 0x61) { // commands to be relayed to card starts with 0x61 // tag <-> SAM exchange starts here - while(sam_rx_buf[1] == 0x61){ + while (sam_rx_buf[1] == 0x61) { switch_clock_to_countsspclk(); nfc_tx_len = sam_seos_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); nfc_rx_len = iso14_apdu( - nfc_tx_buf, - nfc_tx_len, - false, - nfc_rx_buf, - ISO7816_MAX_FRAME, - NULL - ); + nfc_tx_buf, + nfc_tx_len, + false, + nfc_rx_buf, + ISO7816_MAX_FRAME, + NULL + ); switch_clock_to_ticks(); - sam_tx_len = sam_seos_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len-2); + sam_tx_len = sam_seos_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len - 2); sam_send_payload( 0x14, 0x0a, 0x14, @@ -267,13 +267,13 @@ static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t sam_rx_buf, &sam_rx_len ); - // last SAM->TAG + // last SAM->TAG // c1 61 c1 00 00 a1 02 >>82<< 00 90 00 - if(sam_rx_buf[7] == 0x82){ + if (sam_rx_buf[7] == 0x82) { // tag <-> SAM exchange ends here break; } - + } static const uint8_t hfack[] = { @@ -310,25 +310,25 @@ static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t // 82 01 // 07 // 90 00 - if(request_len == 0){ - if( - !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5+2] == 0x8a && sam_rx_buf[5+4] == 0x03) + if (request_len == 0) { + if ( + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0x8a && sam_rx_buf[5 + 4] == 0x03) && - !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5+2] == 0xb3 && sam_rx_buf[5+4] == 0xa0) - ){ + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0xb3 && sam_rx_buf[5 + 4] == 0xa0) + ) { if (g_dbglevel >= DBG_ERROR) Dbprintf("No PACS data in SAM response"); - res=PM3_ESOFT; + res = PM3_ESOFT; } } - *response_len = sam_rx_buf[5+1] +2; - memcpy(response, sam_rx_buf+5, *response_len); + *response_len = sam_rx_buf[5 + 1] + 2; + memcpy(response, sam_rx_buf + 5, *response_len); goto out; - out: - return res; +out: + return res; } /** @@ -337,7 +337,7 @@ static int sam_send_request_iso14a(const uint8_t * const request, const uint8_t * This function is called by appmain.c * It sends a request to the SAM to get the PACS data from the SEOS card. * The PACS data is then returned to the PM3 client. - * + * * @return Status code indicating success or failure of the operation. */ int sam_seos_get_pacs(PacketCommandNG *c) { @@ -346,7 +346,7 @@ int sam_seos_get_pacs(PacketCommandNG *c) { uint8_t *cmd = c->data.asBytes; uint16_t cmd_len = (uint16_t) c->oldarg[2]; - + int res = PM3_EFAILED; clear_trace(); @@ -358,13 +358,13 @@ int sam_seos_get_pacs(PacketCommandNG *c) { // step 1: ping SAM sam_get_version(); - if(!skipDetect){ + if (!skipDetect) { // step 2: get card information iso14a_card_select_t card_a_info; // implicit StartSspClk() happens here iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - if (!iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)){ + if (!iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) { goto err; } @@ -378,7 +378,7 @@ int sam_seos_get_pacs(PacketCommandNG *c) { uint8_t sam_response[ISO7816_MAX_FRAME] = { 0x00 }; uint8_t sam_response_len = 0; res = sam_send_request_iso14a(cmd, cmd_len, sam_response, &sam_response_len); - if(res != PM3_SUCCESS){ + if (res != PM3_SUCCESS) { goto err; } if (g_dbglevel >= DBG_INFO) @@ -387,19 +387,19 @@ int sam_seos_get_pacs(PacketCommandNG *c) { goto out; goto off; - err: - res = PM3_ENOPACS; - reply_ng(CMD_HF_SAM_SEOS, res, NULL, 0); - goto off; - out: - reply_ng(CMD_HF_SAM_SEOS, PM3_SUCCESS, sam_response, sam_response_len); - goto off; - off: - if(disconnectAfter){ - switch_off(); - } - set_tracing(false); - StopTicks(); - BigBuf_free(); - return res; -} \ No newline at end of file +err: + res = PM3_ENOPACS; + reply_ng(CMD_HF_SAM_SEOS, res, NULL, 0); + goto off; +out: + reply_ng(CMD_HF_SAM_SEOS, PM3_SUCCESS, sam_response, sam_response_len); + goto off; +off: + if (disconnectAfter) { + switch_off(); + } + set_tracing(false); + StopTicks(); + BigBuf_free(); + return res; +} diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index ea53ebb83..60c24fb49 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5434,15 +5434,15 @@ static int CmdHFiClassSAM(const char *Cmd) { // CSN, config, epurse, NR/MAC, AIA // PACS - // 03 05 + // 03 05 // 06 85 80 6d c0 // first byte skip // second byte length // third padded // fourth .. uint8_t *d = resp.data.asBytes; - HIDDumpPACSBits(d+2, d[1], verbose); - + HIDDumpPACSBits(d + 2, d[1], verbose); + return PM3_SUCCESS; } diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index c0a2891de..54e0ce550 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1688,15 +1688,15 @@ static int CmdHfSeosSAM(const char *Cmd) { verbose = true; } bool disconnectAfter = true; - if(arg_get_lit(ctx, 2)){ + if (arg_get_lit(ctx, 2)) { disconnectAfter = false; } bool skipDetect = false; - if(arg_get_lit(ctx, 3)){ + if (arg_get_lit(ctx, 3)) { skipDetect = true; } bool decodeTLV = false; - if(arg_get_lit(ctx, 4)){ + if (arg_get_lit(ctx, 4)) { decodeTLV = true; } @@ -1728,45 +1728,45 @@ static int CmdHfSeosSAM(const char *Cmd) { PrintAndLogEx(WARNING, "SAM select failed"); return resp.status; } - + uint8_t *d = resp.data.asBytes; // check for standard SamCommandGetContentElement response // bd 09 // 8a 07 // 03 05 <- tag + length // 06 85 80 6d c0 <- decoded PACS data - if(d[0] == 0xbd && d[2] == 0x8a && d[4] == 0x03){ + if (d[0] == 0xbd && d[2] == 0x8a && d[4] == 0x03) { uint8_t pacs_length = d[5]; - uint8_t * pacs_data = d + 6; + uint8_t *pacs_data = d + 6; int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose); - if(res != PM3_SUCCESS){ + if (res != PM3_SUCCESS) { return res; } - // check for standard samCommandGetContentElement2: - // bd 1e - // b3 1c - // a0 1a - // 80 05 - // 06 85 80 6d c0 - // 81 0e - // 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff - // 82 01 - // 07 - } else if(d[0]==0xbd && d[2]==0xb3 && d[4]==0xa0){ - const uint8_t * pacs = d + 6; + // check for standard samCommandGetContentElement2: + // bd 1e + // b3 1c + // a0 1a + // 80 05 + // 06 85 80 6d c0 + // 81 0e + // 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff + // 82 01 + // 07 + } else if (d[0] == 0xbd && d[2] == 0xb3 && d[4] == 0xa0) { + const uint8_t *pacs = d + 6; const uint8_t pacs_length = pacs[1]; - const uint8_t * pacs_data = pacs + 2; + const uint8_t *pacs_data = pacs + 2; int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose); - if(res != PM3_SUCCESS){ + if (res != PM3_SUCCESS) { return res; } - const uint8_t * oid = pacs + 2 + pacs_length; + const uint8_t *oid = pacs + 2 + pacs_length; const uint8_t oid_length = oid[1]; - const uint8_t * oid_data = oid + 2; + const uint8_t *oid_data = oid + 2; PrintAndLogEx(SUCCESS, "SIO OID.......: " _GREEN_("%s"), sprint_hex_inrow(oid_data, oid_length)); - const uint8_t * mediaType = oid + 2 + oid_length; + const uint8_t *mediaType = oid + 2 + oid_length; const uint8_t mediaType_data = mediaType[2]; PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data)); diff --git a/client/src/cmdhfseos.h b/client/src/cmdhfseos.h index 950346c04..f75e070d5 100644 --- a/client/src/cmdhfseos.h +++ b/client/src/cmdhfseos.h @@ -29,6 +29,6 @@ typedef struct { int infoSeos(bool verbose); int CmdHFSeos(const char *Cmd); -int seos_kdf(bool encryption, uint8_t* masterKey, uint8_t keyslot, - uint8_t* adfOid, size_t adfoid_len, uint8_t* diversifier, uint8_t diversifier_len, uint8_t* out, int encryption_algorithm, int hash_algorithm); +int seos_kdf(bool encryption, uint8_t *masterKey, uint8_t keyslot, + uint8_t *adfOid, size_t adfoid_len, uint8_t *diversifier, uint8_t diversifier_len, uint8_t *out, int encryption_algorithm, int hash_algorithm); #endif diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c index ecbf47000..e3e146153 100644 --- a/client/src/wiegand_formats.c +++ b/client/src/wiegand_formats.c @@ -1664,7 +1664,7 @@ void HIDUnpack(int idx, wiegand_message_t *packed) { } } -int HIDDumpPACSBits(const uint8_t * const data, const uint8_t length, bool verbose){ +int HIDDumpPACSBits(const uint8_t *const data, const uint8_t length, bool verbose) { uint8_t n = length - 1; uint8_t pad = data[0]; char *binstr = (char *)calloc((length * 8) + 1, sizeof(uint8_t)); @@ -1733,5 +1733,5 @@ int HIDDumpPACSBits(const uint8_t * const data, const uint8_t length, bool verbo PrintAndLogEx(NORMAL, ""); } free(binstr); - return PM3_SUCCESS; -} \ No newline at end of file + return PM3_SUCCESS; +} diff --git a/client/src/wiegand_formats.h b/client/src/wiegand_formats.h index 763edaba8..630d9cbb4 100644 --- a/client/src/wiegand_formats.h +++ b/client/src/wiegand_formats.h @@ -54,7 +54,7 @@ bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bo bool HIDTryUnpack(wiegand_message_t *packed); void HIDPackTryAll(wiegand_card_t *card, bool preamble); void HIDUnpack(int idx, wiegand_message_t *packed); -int HIDDumpPACSBits(const uint8_t * const data, const uint8_t length, bool verbose); +int HIDDumpPACSBits(const uint8_t *const data, const uint8_t length, bool verbose); void print_wiegand_code(wiegand_message_t *packed); void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed); #endif diff --git a/common_arm/ticks.c b/common_arm/ticks.c index c078407ea..4abda2689 100644 --- a/common_arm/ticks.c +++ b/common_arm/ticks.c @@ -305,7 +305,7 @@ uint32_t GetTicks(void) { do { hi = AT91C_BASE_TC1->TC_CV; lo = AT91C_BASE_TC0->TC_CV; - } while (hi != AT91C_BASE_TC1->TC_CV); + } while (hi != AT91C_BASE_TC1->TC_CV); return (hi << 16) | lo; }