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 <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <inttypes.h>
 
 #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,      "<APDU (hex)>", 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",     "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
+        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,       "<APDU (hex) | data (hex)>", "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",     "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
+        arg_str0("mM",  "make",     "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
         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 (int)>", "Le apdu parameter if `m` parameter included"),
         arg_strx1(NULL, NULL,       "<APDU (hex) | data (hex)>", "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 <stdbool.h>
 #include <inttypes.h>
 
+#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 <endian.h>
 #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)