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; }