From 16b6d7e5290d8b991dc139b0f4a0a8937b8e3d87 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 10 Jul 2019 19:11:56 +0300 Subject: [PATCH 01/11] apdu universal parser --- client/emv/apduinfo.c | 112 ++++++++++++++++++++++++++++++++++++++++++ client/emv/apduinfo.h | 25 ++++++++++ 2 files changed, 137 insertions(+) diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index df44ef961..6deeb618b 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -314,3 +314,115 @@ const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { else return APDUCodeTable[0].Description; //empty string } + +int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu) +{ + EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data; + + apdu->cla = hapdu->cla; + apdu->ins = hapdu->ins; + apdu->p1 = hapdu->p1; + apdu->p2 = hapdu->p2; + + apdu->lc = 0; + apdu->data = NULL; + apdu->le = 0; + apdu->extended_apdu = false; + apdu->case_type = 0x00; + + uint8_t b0 = hapdu->lc[0]; + + // case 1 + if (len == 4) + { + apdu->case_type = 0x01; + } + + // case 2S (Le) + if (len == 5) + { + apdu->case_type = 0x02; + apdu->le = b0; + if (!apdu->le) + apdu->le = 0x100; + } + + // case 3S (Lc + data) + if (len == 5U + b0 && b0 != 0) + { + apdu->case_type = 0x03; + apdu->lc = b0; + } + + // case 4S (Lc + data + Le) + if (len == 5U + b0 + 1U && b0 != 0) + { + apdu->case_type = 0x04; + apdu->lc = b0; + apdu->le = data[len - 1]; + if (!apdu->le) + apdu->le = 0x100; + } + + // extended length apdu + if (len >= 7 && b0 == 0) + { + uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; + + // case 2E (Le) - extended + if (len == 7) + { + apdu->case_type = 0x12; + apdu->extended_apdu = true; + apdu->le = extlen; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 3E (Lc + data) - extended + if (len == 7U + extlen) + { + apdu->case_type = 0x13; + apdu->extended_apdu = true; + apdu->lc = extlen; + } + + // case 4E (Lc + data + Le) - extended 2-byte Le + if (len == 7U + extlen + 2U) + { + apdu->case_type = 0x14; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 4E (Lc + data + Le) - extended 3-byte Le + if (len == 7U + extlen + 3U && data[len - 3] == 0) + { + apdu->case_type = 0x24; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + } + + if (!apdu->case_type) + return 1; + + if (apdu->lc) + { + if (apdu->extended_apdu) + { + apdu->data = data + 7; + } else { + apdu->data = data + 5; + } + + } + + return 0; +} diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index 317d661ff..399fd44a1 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #define APDUCODE_TYPE_NONE 0 @@ -31,4 +32,28 @@ typedef struct { const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2); const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); +typedef struct +{ + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t lc[3]; +} __attribute__((packed)) EXT_APDU_HEADER; + +typedef struct +{ + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint16_t lc; + uint8_t *data; + uint32_t le; + bool extended_apdu; + uint8_t case_type; +} __attribute__((packed)) APDU_STRUCT; +extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu); + + #endif From 1169a6cf1b054ce1550f03b5d160bf5adc74ec9b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 10 Jul 2019 19:21:54 +0300 Subject: [PATCH 02/11] apdu rename and print --- client/emv/apduinfo.c | 16 ++++++++++++++-- client/emv/apduinfo.h | 8 +++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index 6deeb618b..8ea69437c 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -10,6 +10,8 @@ #include "apduinfo.h" +#include "util.h" + const APDUCode APDUCodeTable[] = { // ID Type Description {"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string @@ -315,9 +317,9 @@ const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { return APDUCodeTable[0].Description; //empty string } -int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu) +int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) { - EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data; + ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data; apdu->cla = hapdu->cla; apdu->ins = hapdu->ins; @@ -426,3 +428,13 @@ int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu) return 0; } + +int APDUEncode(APDUStruct apdu, uint8_t *data, size_t len) { + + return 0; +} + +void APDUPrint(APDUStruct apdu) { + PrintAndLogEx(INFO, "apdu: %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\n", + apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le); +} diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index 399fd44a1..ba4bf7b13 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -39,7 +39,7 @@ typedef struct uint8_t p1; uint8_t p2; uint8_t lc[3]; -} __attribute__((packed)) EXT_APDU_HEADER; +} __attribute__((packed)) ExtAPDUHeader; typedef struct { @@ -52,8 +52,10 @@ typedef struct uint32_t le; bool extended_apdu; uint8_t case_type; -} __attribute__((packed)) APDU_STRUCT; -extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu); +} __attribute__((packed)) APDUStruct; +extern int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu); +extern int APDUEncode(APDUStruct apdu, uint8_t *data, size_t len); +extern void APDUPrint(APDUStruct apdu); #endif From 4d8a4114136caee23de826b3e046aef741a187bb Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 11 Jul 2019 13:08:43 +0300 Subject: [PATCH 03/11] APDUEncode --- client/emv/apduinfo.c | 69 +++++++++++++++++++++++++++---------------- client/emv/apduinfo.h | 2 +- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index 8ea69437c..79b502816 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -317,8 +317,7 @@ const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { return APDUCodeTable[0].Description; //empty string } -int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) -{ +int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) { ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data; apdu->cla = hapdu->cla; @@ -335,14 +334,12 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) uint8_t b0 = hapdu->lc[0]; // case 1 - if (len == 4) - { + if (len == 4) { apdu->case_type = 0x01; } // case 2S (Le) - if (len == 5) - { + if (len == 5) { apdu->case_type = 0x02; apdu->le = b0; if (!apdu->le) @@ -350,15 +347,13 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) } // case 3S (Lc + data) - if (len == 5U + b0 && b0 != 0) - { + if (len == 5U + b0 && b0 != 0) { apdu->case_type = 0x03; apdu->lc = b0; } // case 4S (Lc + data + Le) - if (len == 5U + b0 + 1U && b0 != 0) - { + if (len == 5U + b0 + 1U && b0 != 0) { apdu->case_type = 0x04; apdu->lc = b0; apdu->le = data[len - 1]; @@ -367,13 +362,11 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) } // extended length apdu - if (len >= 7 && b0 == 0) - { + if (len >= 7 && b0 == 0) { uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; // case 2E (Le) - extended - if (len == 7) - { + if (len == 7) { apdu->case_type = 0x12; apdu->extended_apdu = true; apdu->le = extlen; @@ -382,16 +375,14 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) } // case 3E (Lc + data) - extended - if (len == 7U + extlen) - { + if (len == 7U + extlen) { apdu->case_type = 0x13; apdu->extended_apdu = true; apdu->lc = extlen; } // case 4E (Lc + data + Le) - extended 2-byte Le - if (len == 7U + extlen + 2U) - { + if (len == 7U + extlen + 2U) { apdu->case_type = 0x14; apdu->extended_apdu = true; apdu->lc = extlen; @@ -401,8 +392,7 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) } // case 4E (Lc + data + Le) - extended 3-byte Le - if (len == 7U + extlen + 3U && data[len - 3] == 0) - { + if (len == 7U + extlen + 3U && data[len - 3] == 0) { apdu->case_type = 0x24; apdu->extended_apdu = true; apdu->lc = extlen; @@ -415,10 +405,8 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) if (!apdu->case_type) return 1; - if (apdu->lc) - { - if (apdu->extended_apdu) - { + if (apdu->lc) { + if (apdu->extended_apdu) { apdu->data = data + 7; } else { apdu->data = data + 5; @@ -429,8 +417,39 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) return 0; } -int APDUEncode(APDUStruct apdu, uint8_t *data, size_t len) { +int APDUEncode(APDUStruct *apdu, uint8_t *data, size_t *len) { + size_t dptr = 0; + data[dptr++] = apdu->cla; + data[dptr++] = apdu->ins; + data[dptr++] = apdu->p1; + data[dptr++] = apdu->p2; + if (apdu->lc) { + if (apdu->extended_apdu || apdu->lc > 0xff || apdu->le > 0xff) { + data[dptr++] = 0x00; + data[dptr++] = (apdu->lc >> 8) & 0xff; + data[dptr++] = (apdu->lc) & 0xff; + memmove(&data[dptr], apdu->data, apdu->lc); + dptr += apdu->lc; + apdu->extended_apdu = true; + } else { + data[dptr++] = apdu->lc; + memmove(&data[dptr], apdu->data, apdu->lc); + dptr += apdu->lc; + } + } + + if (apdu->le) { + if (apdu->extended_apdu) { + data[dptr++] = 0x00; + data[dptr++] = (apdu->le >> 8) & 0xff; + data[dptr++] = (apdu->le) & 0xff; + } else { + data[dptr++] = apdu->le; + } + } + + *len = dptr; return 0; } diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index ba4bf7b13..e510492cf 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -55,7 +55,7 @@ typedef struct } __attribute__((packed)) APDUStruct; extern int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu); -extern int APDUEncode(APDUStruct apdu, uint8_t *data, size_t len); +extern int APDUEncode(APDUStruct *apdu, uint8_t *data, size_t *len); extern void APDUPrint(APDUStruct apdu); #endif From d94c74b24b4c680b778c8af3af9410d3ba7cb077 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 12 Jul 2019 13:58:38 +0300 Subject: [PATCH 04/11] make style --- client/comms.c | 2 +- client/emv/apduinfo.c | 98 +++++++++++++++++++++++++------------------ client/emv/apduinfo.h | 6 +-- client/util.c | 12 +++--- 4 files changed, 66 insertions(+), 52 deletions(-) diff --git a/client/comms.c b/client/comms.c index 5aa704728..6fd41ecad 100644 --- a/client/comms.c +++ b/client/comms.c @@ -136,7 +136,7 @@ static void SendCommandNG_internal(uint16_t cmd, uint8_t *data, size_t len, bool txBufferNG.pre.ng = ng; txBufferNG.pre.length = len; txBufferNG.pre.cmd = cmd; - if ( len > 0 && data ) + if (len > 0 && data) memcpy(&txBufferNG.data, data, len); if ((conn.send_via_fpc_usart && conn.send_with_crc_on_fpc) || ((!conn.send_via_fpc_usart) && conn.send_with_crc_on_usb)) { diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index 79b502816..3b3664e4b 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -319,39 +319,39 @@ const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) { ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data; - + apdu->cla = hapdu->cla; apdu->ins = hapdu->ins; apdu->p1 = hapdu->p1; apdu->p2 = hapdu->p2; - + apdu->lc = 0; apdu->data = NULL; apdu->le = 0; apdu->extended_apdu = false; apdu->case_type = 0x00; - + uint8_t b0 = hapdu->lc[0]; - + // case 1 if (len == 4) { apdu->case_type = 0x01; } - - // case 2S (Le) + + // case 2S (Le) if (len == 5) { apdu->case_type = 0x02; apdu->le = b0; if (!apdu->le) apdu->le = 0x100; } - + // case 3S (Lc + data) if (len == 5U + b0 && b0 != 0) { apdu->case_type = 0x03; apdu->lc = b0; } - + // case 4S (Lc + data + Le) if (len == 5U + b0 + 1U && b0 != 0) { apdu->case_type = 0x04; @@ -360,12 +360,12 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) { if (!apdu->le) apdu->le = 0x100; } - + // extended length apdu if (len >= 7 && b0 == 0) { uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; - - // case 2E (Le) - extended + + // case 2E (Le) - extended if (len == 7) { apdu->case_type = 0x12; apdu->extended_apdu = true; @@ -373,59 +373,65 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) { if (!apdu->le) apdu->le = 0x10000; } - - // case 3E (Lc + data) - extended - if (len == 7U + extlen) { + + // case 3E (Lc + data) - extended + if (len == 7U + extlen) { apdu->case_type = 0x13; apdu->extended_apdu = true; apdu->lc = extlen; } - // case 4E (Lc + data + Le) - extended 2-byte Le - if (len == 7U + extlen + 2U) { + // case 4E (Lc + data + Le) - extended 2-byte Le + if (len == 7U + extlen + 2U) { apdu->case_type = 0x14; apdu->extended_apdu = true; apdu->lc = extlen; apdu->le = (data[len - 2] << 8) + data[len - 1]; - if (!apdu->le) - apdu->le = 0x10000; + if (!apdu->le) + apdu->le = 0x10000; } - // case 4E (Lc + data + Le) - extended 3-byte Le - if (len == 7U + extlen + 3U && data[len - 3] == 0) { + // case 4E (Lc + data + Le) - extended 3-byte Le + if (len == 7U + extlen + 3U && data[len - 3] == 0) { apdu->case_type = 0x24; apdu->extended_apdu = true; apdu->lc = extlen; apdu->le = (data[len - 2] << 8) + data[len - 1]; - if (!apdu->le) - apdu->le = 0x10000; + if (!apdu->le) + apdu->le = 0x10000; } } - + if (!apdu->case_type) return 1; - + if (apdu->lc) { if (apdu->extended_apdu) { apdu->data = data + 7; } else { apdu->data = data + 5; } - - } - + + } + return 0; } int APDUEncode(APDUStruct *apdu, uint8_t *data, size_t *len) { + if (len) + *len = 0; + + if (apdu->le > 0x10000 || apdu->lc != 0xffff) + return 1; + size_t dptr = 0; data[dptr++] = apdu->cla; data[dptr++] = apdu->ins; data[dptr++] = apdu->p1; data[dptr++] = apdu->p2; - + if (apdu->lc) { - if (apdu->extended_apdu || apdu->lc > 0xff || apdu->le > 0xff) { + if (apdu->extended_apdu || apdu->lc > 0xff || apdu->le > 0x100) { data[dptr++] = 0x00; data[dptr++] = (apdu->lc >> 8) & 0xff; data[dptr++] = (apdu->lc) & 0xff; @@ -436,24 +442,34 @@ int APDUEncode(APDUStruct *apdu, uint8_t *data, size_t *len) { data[dptr++] = apdu->lc; memmove(&data[dptr], apdu->data, apdu->lc); dptr += apdu->lc; - } - } - + } + } + if (apdu->le) { if (apdu->extended_apdu) { - data[dptr++] = 0x00; - data[dptr++] = (apdu->le >> 8) & 0xff; - data[dptr++] = (apdu->le) & 0xff; + if (apdu->le != 0x10000) { + data[dptr++] = 0x00; + data[dptr++] = (apdu->le >> 8) & 0xff; + data[dptr++] = (apdu->le) & 0xff; + } else { + data[dptr++] = 0x00; + data[dptr++] = 0x00; + data[dptr++] = 0x00; + } } else { - data[dptr++] = apdu->le; - } + if (apdu->le != 0x100) + data[dptr++] = apdu->le; + else + data[dptr++] = 0x00; + } } - - *len = dptr; + + if (len) + *len = dptr; return 0; } void APDUPrint(APDUStruct apdu) { - PrintAndLogEx(INFO, "apdu: %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\n", - apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le); + PrintAndLogEx(INFO, "apdu: %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x Lc=%d Le=%d\n", + apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le); } diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index e510492cf..7f1e8fd72 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -32,8 +32,7 @@ typedef struct { const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2); const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); -typedef struct -{ +typedef struct { uint8_t cla; uint8_t ins; uint8_t p1; @@ -41,8 +40,7 @@ typedef struct uint8_t lc[3]; } __attribute__((packed)) ExtAPDUHeader; -typedef struct -{ +typedef struct { uint8_t cla; uint8_t ins; uint8_t p1; diff --git a/client/util.c b/client/util.c index 568a022f1..8121a7ed3 100644 --- a/client/util.c +++ b/client/util.c @@ -170,8 +170,8 @@ bool CheckStringIsHEXValue(const char *value) { void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase) { - if (buf == NULL ) return; - + if (buf == NULL) return; + char *tmp = (char *)buf; size_t i; memset(tmp, 0x00, hex_max_len); @@ -197,16 +197,16 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex // printing and converting functions void print_hex(const uint8_t *data, const size_t len) { - if (data == NULL || len == 0 ) return; - + if (data == NULL || len == 0) return; + for (size_t i = 0; i < len; i++) printf("%02x ", data[i]); printf("\n"); } void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) { - if (data == NULL || len == 0 ) return; - + if (data == NULL || len == 0) return; + int rownum = 0; printf("[%02d] | ", rownum); for (size_t i = 0; i < len; ++i) { From 68bfbde185e7bcad7757885f47d0ac9c5a5ded8a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 14 Jul 2019 14:59:59 +0300 Subject: [PATCH 05/11] CmdHF14AAPDU sketch --- client/cmdhf14a.c | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 018431a28..33bfa7cbe 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -839,17 +839,28 @@ static int CmdHF14AAPDU(const char *Cmd) { bool activateField = false; bool leaveSignalON = false; bool decodeTLV = false; + bool decodeAPDU = false; + bool makeAPDU = false; + bool extendedAPDU = false; + int le = 0; CLIParserInit("hf 14a apdu", - "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", - "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"); + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013", + "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n" + "\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode apdu\n" + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode extended apdu\n" + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode standard apdu\n"); void *argtable[] = { arg_param_begin, - arg_lit0("sS", "select", "activate field and select card"), - arg_lit0("kK", "keep", "leave the signal field ON after receive response"), - arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), - arg_strx1(NULL, NULL, "", NULL), + arg_lit0("sS", "select", "activate field and select card"), + arg_lit0("kK", "keep", "leave the signal field ON after receive response"), + arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), + arg_lit0("dD", "decapdu", "decode apdu request if it possible"), + arg_lit0("mM", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), + arg_lit0("eE", "extended", "make extended length apdu if `m` parameter included"), + arg_lit0("lL", "le", "Le apdu parameter if `m` parameter included"), + arg_strx1(NULL, NULL, "", "data if `m` parameter included"), arg_param_end }; CLIExecWithReturn(Cmd, argtable, false); @@ -857,8 +868,26 @@ static int CmdHF14AAPDU(const char *Cmd) { activateField = arg_get_lit(1); leaveSignalON = arg_get_lit(2); decodeTLV = arg_get_lit(3); - // len = data + PCB(1b) + CRC(2b) - CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2); + decodeAPDU = arg_get_lit(4); + makeAPDU = arg_get_lit(5); + extendedAPDU = arg_get_lit(6); + le = arg_get_lit(7); + + if (makeAPDU) { + + } else { + if (extendedAPDU) { + PrintAndLogEx(ERR, "make mode not set but here `e` option."); + return 1; + } + if (le > 0) { + PrintAndLogEx(ERR, "make mode not set but here `l` option."); + return 1; + } + + // len = data + PCB(1b) + CRC(2b) + CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2); + } CLIParserFree(); PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel " : "", leaveSignalON ? "keep " : "", decodeTLV ? "TLV" : "", sprint_hex(data, datalen)); From 51bcc80a2bffe0140a8d788bfe235d5af92c9f8a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 14 Jul 2019 15:00:40 +0300 Subject: [PATCH 06/11] small fix --- client/cmdhf14a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 33bfa7cbe..1ff54265c 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -848,8 +848,8 @@ static int CmdHF14AAPDU(const char *Cmd) { "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013", "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n" "\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode apdu\n" - "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode extended apdu\n" - "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode standard apdu\n"); + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode standard apdu\n" + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode extended apdu\n"); void *argtable[] = { arg_param_begin, From a9d15d85e613d231c044d6d22f5aa36cb91529c2 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 14 Jul 2019 15:14:54 +0300 Subject: [PATCH 07/11] sketch2 --- client/cmdhf14a.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 1ff54265c..fb8753921 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -836,6 +836,8 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea static int CmdHF14AAPDU(const char *Cmd) { uint8_t data[PM3_CMD_DATA_SIZE]; int datalen = 0; + uint8_t header[PM3_CMD_DATA_SIZE]; + int headerlen = 0; bool activateField = false; bool leaveSignalON = false; bool decodeTLV = false; @@ -874,24 +876,54 @@ static int CmdHF14AAPDU(const char *Cmd) { le = arg_get_lit(7); if (makeAPDU) { + uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0}; + int apdudatalen = 0; + + CLIGetHexBLessWithReturn(8, apdudata, &apdudatalen, 1 + 2); + + APDUStruct apdu; + apdu.cla = header[0]; + apdu.ins = header[1]; + apdu.p1 = header[2]; + apdu.p2 = header[3]; + + apdu.lc = apdudatalen; + apdu.data = apdudata; + + apdu.extended_apdu = extendedAPDU; + apdu.le = le; + + if (APDUEncode(&apdu, data, &datalen)) { + PrintAndLogEx(ERR, "can't make apdu with provided parameters."); + return 1; + } } else { if (extendedAPDU) { PrintAndLogEx(ERR, "make mode not set but here `e` option."); - return 1; + return 2; } if (le > 0) { PrintAndLogEx(ERR, "make mode not set but here `l` option."); - return 1; + return 2; } // len = data + PCB(1b) + CRC(2b) - CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2); + CLIGetHexBLessWithReturn(8, data, &datalen, 1 + 2); } CLIParserFree(); PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel " : "", leaveSignalON ? "keep " : "", decodeTLV ? "TLV" : "", sprint_hex(data, datalen)); + if (decodeAPDU) { + APDUStruct apdu; + + if (APDUDecode(data, datalen, &apdu) == 0) + APDUPrint(apdu); + else + PrintAndLogEx(WARNING, "can't decode APDU."); + } + int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, PM3_CMD_DATA_SIZE, &datalen); if (res) From df1dd71d14139e9c0e8fdb578ff17d603bb40c3c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 15 Jul 2019 17:26:42 +0300 Subject: [PATCH 08/11] apdu format and print works --- client/cmdhf14a.c | 20 +++++++++++++------- client/emv/apduinfo.c | 6 +++--- client/emv/apduinfo.h | 4 ++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index fb8753921..c7dc037a4 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -859,9 +859,9 @@ static int CmdHF14AAPDU(const char *Cmd) { arg_lit0("kK", "keep", "leave the signal field ON after receive response"), arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), arg_lit0("dD", "decapdu", "decode apdu request if it possible"), - arg_lit0("mM", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), + arg_str0("mM", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), arg_lit0("eE", "extended", "make extended length apdu if `m` parameter included"), - arg_lit0("lL", "le", "Le apdu parameter if `m` parameter included"), + arg_int0("lL", "le", "", "Le apdu parameter if `m` parameter included"), arg_strx1(NULL, NULL, "", "data if `m` parameter included"), arg_param_end }; @@ -871,9 +871,15 @@ static int CmdHF14AAPDU(const char *Cmd) { leaveSignalON = arg_get_lit(2); decodeTLV = arg_get_lit(3); decodeAPDU = arg_get_lit(4); - makeAPDU = arg_get_lit(5); + + CLIGetHexWithReturn(5, header, &headerlen); + makeAPDU = headerlen > 0; + if (makeAPDU && headerlen != 4) { + PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen); + return 1; + } extendedAPDU = arg_get_lit(6); - le = arg_get_lit(7); + le = arg_get_int_def(7, 0); if (makeAPDU) { uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0}; @@ -895,17 +901,17 @@ static int CmdHF14AAPDU(const char *Cmd) { if (APDUEncode(&apdu, data, &datalen)) { PrintAndLogEx(ERR, "can't make apdu with provided parameters."); - return 1; + return 2; } } else { if (extendedAPDU) { PrintAndLogEx(ERR, "make mode not set but here `e` option."); - return 2; + return 3; } if (le > 0) { PrintAndLogEx(ERR, "make mode not set but here `l` option."); - return 2; + return 3; } // len = data + PCB(1b) + CRC(2b) diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index 3b3664e4b..1e6975107 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -317,7 +317,7 @@ const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { return APDUCodeTable[0].Description; //empty string } -int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) { +int APDUDecode(uint8_t *data, int len, APDUStruct *apdu) { ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data; apdu->cla = hapdu->cla; @@ -417,11 +417,11 @@ int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu) { return 0; } -int APDUEncode(APDUStruct *apdu, uint8_t *data, size_t *len) { +int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len) { if (len) *len = 0; - if (apdu->le > 0x10000 || apdu->lc != 0xffff) + if (apdu->le > 0x10000 || apdu->lc > 0xffff) return 1; size_t dptr = 0; diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index 7f1e8fd72..5d5173e2f 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -52,8 +52,8 @@ typedef struct { uint8_t case_type; } __attribute__((packed)) APDUStruct; -extern int APDUDecode(uint8_t *data, size_t len, APDUStruct *apdu); -extern int APDUEncode(APDUStruct *apdu, uint8_t *data, size_t *len); +extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu); +extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len); extern void APDUPrint(APDUStruct apdu); #endif From d2a2acf69ce8a73813161f5d237eeb5d0672d4ea Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 15 Jul 2019 19:12:01 +0300 Subject: [PATCH 09/11] make style --- client/cmdhf14a.c | 30 +++++++++++++++--------------- client/emv/apduinfo.c | 10 ++++++++-- client/emv/apduinfo.h | 1 + 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index c7dc037a4..47586a94a 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -876,15 +876,15 @@ static int CmdHF14AAPDU(const char *Cmd) { makeAPDU = headerlen > 0; if (makeAPDU && headerlen != 4) { PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen); - return 1; + return 1; } extendedAPDU = arg_get_lit(6); le = arg_get_int_def(7, 0); - + if (makeAPDU) { uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0}; int apdudatalen = 0; - + CLIGetHexBLessWithReturn(8, apdudata, &apdudatalen, 1 + 2); APDUStruct apdu; @@ -892,28 +892,28 @@ static int CmdHF14AAPDU(const char *Cmd) { apdu.ins = header[1]; apdu.p1 = header[2]; apdu.p2 = header[3]; - + apdu.lc = apdudatalen; apdu.data = apdudata; - + apdu.extended_apdu = extendedAPDU; apdu.le = le; - + if (APDUEncode(&apdu, data, &datalen)) { PrintAndLogEx(ERR, "can't make apdu with provided parameters."); - return 2; + return 2; } - - } else { + + } else { if (extendedAPDU) { PrintAndLogEx(ERR, "make mode not set but here `e` option."); - return 3; + return 3; } if (le > 0) { PrintAndLogEx(ERR, "make mode not set but here `l` option."); - return 3; + return 3; } - + // len = data + PCB(1b) + CRC(2b) CLIGetHexBLessWithReturn(8, data, &datalen, 1 + 2); } @@ -922,12 +922,12 @@ static int CmdHF14AAPDU(const char *Cmd) { PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel " : "", leaveSignalON ? "keep " : "", decodeTLV ? "TLV" : "", sprint_hex(data, datalen)); if (decodeAPDU) { - APDUStruct apdu; - + APDUStruct apdu; + if (APDUDecode(data, datalen, &apdu) == 0) APDUPrint(apdu); else - PrintAndLogEx(WARNING, "can't decode APDU."); + PrintAndLogEx(WARNING, "can't decode APDU."); } int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, PM3_CMD_DATA_SIZE, &datalen); diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index 1e6975107..a7a8e1672 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -470,6 +470,12 @@ int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len) { } void APDUPrint(APDUStruct apdu) { - PrintAndLogEx(INFO, "apdu: %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x Lc=%d Le=%d\n", - apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le); + APDUPrintEx(apdu, 0); +} + +void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) { + PrintAndLogEx(INFO, "APDU: %scase=0x%02x cla=0x%02x ins=0x%02x p1=0x%02x p2=0x%02x Lc=0x%02x(%d) Le=0x%02x(%d)", + apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.lc, apdu.le, apdu.le); + if (maxdatalen > 0) + PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : ""); } diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index 5d5173e2f..1fbb3bf00 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -55,5 +55,6 @@ typedef struct { extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu); extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len); extern void APDUPrint(APDUStruct apdu); +extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen); #endif From 84c09ce88158bb5850a58103d1d97c490d453fd8 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 15 Jul 2019 19:21:19 +0300 Subject: [PATCH 10/11] added define PACKED --- client/emv/apduinfo.c | 2 -- client/emv/apduinfo.h | 6 ++++-- client/util.h | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index a7a8e1672..469078456 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -10,8 +10,6 @@ #include "apduinfo.h" -#include "util.h" - const APDUCode APDUCodeTable[] = { // ID Type Description {"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index 1fbb3bf00..b81877366 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -17,6 +17,8 @@ #include #include +#include "util.h" + #define APDUCODE_TYPE_NONE 0 #define APDUCODE_TYPE_INFO 1 #define APDUCODE_TYPE_WARNING 2 @@ -38,7 +40,7 @@ typedef struct { uint8_t p1; uint8_t p2; uint8_t lc[3]; -} __attribute__((packed)) ExtAPDUHeader; +} PACKED ExtAPDUHeader; typedef struct { uint8_t cla; @@ -50,7 +52,7 @@ typedef struct { uint32_t le; bool extended_apdu; uint8_t case_type; -} __attribute__((packed)) APDUStruct; +} PACKED APDUStruct; extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu); extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len); diff --git a/client/util.h b/client/util.h index e194bb5be..aade8bf96 100644 --- a/client/util.h +++ b/client/util.h @@ -21,6 +21,12 @@ #include "ui.h" // PrintAndLog #include "commonutil.h" +#ifdef _MSC_VER +#define PACKED +#else +#define PACKED __attribute__((packed)) +#endif + #ifdef ANDROID #include #endif From ecf7eda08f0399d0be4b51b309877b65a510cb17 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 15 Jul 2019 19:25:06 +0300 Subject: [PATCH 11/11] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d46c8222b..63e2e76d6 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 to `hf 14a apdu` print apdu and compose apdu (@merlokk) - Add check if bootloader segment is within bounds (@slurdge) - Add `hf 15 csetuid` - set UID on ISO-15693 Magic tags (@t0m4-null) - Change: Print help if unknown arg for hitag reader/writer (@ViRb3)