From Martin Kaiser via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7275 :
authorPascal Quantin <pascal.quantin@gmail.com>
Wed, 23 May 2012 20:51:38 +0000 (20:51 -0000)
committerPascal Quantin <pascal.quantin@gmail.com>
Wed, 23 May 2012 20:51:38 +0000 (20:51 -0000)
iso7816: dissect ATR (answer to reset)

svn path=/trunk/; revision=42814

epan/dissectors/packet-iso7816.c

index 1b7f15ec961824545a53e6fe0af1bbdfebdbf9da..b28d335ec092e17d73be4b600efcee63ea22ab47 100644 (file)
 #include <glib.h>
 
 #include <epan/packet.h>
+#include <epan/expert.h>
 
 static int proto_iso7816 = -1;
 
 static int ett_iso7816 = -1;
-
-static int hf_iso7816_atr = -1;
+static int ett_iso7816_atr_td = -1;
+
+static int hf_iso7816_atr_init_char = -1;
+static int hf_iso7816_atr_t0 = -1;
+static int hf_iso7816_atr_ta = -1;
+static int hf_iso7816_atr_tb = -1;
+static int hf_iso7816_atr_tc = -1;
+static int hf_iso7816_atr_td = -1;
+static int hf_iso7816_atr_next_ta_present = -1;
+static int hf_iso7816_atr_next_tb_present = -1;
+static int hf_iso7816_atr_next_tc_present = -1;
+static int hf_iso7816_atr_next_td_present = -1;
+static int hf_iso7816_atr_k = -1;
+static int hf_iso7816_atr_t = -1;
+static int hf_iso7816_atr_hist_bytes = -1;
+static int hf_iso7816_atr_tck = -1;
 static int hf_iso7816_cla = -1;
 static int hf_iso7816_ins = -1;
 static int hf_iso7816_p1 = -1;
@@ -55,6 +70,12 @@ static int hf_iso7816_sw2 = -1;
 #define ADDR_INTF "Interface"
 #define ADDR_CARD "Card"
 
+static const value_string iso7816_atr_init_char[] = {
+    { 0x3B, "Direct convention (A==0, Z==1, MSB==m9)" },
+    { 0x3F, "Inverse convention (A==1, Z==0, MSB==m2)" },
+    { 0, NULL }
+};
+
 static const value_string iso7816_ins[] = {
     { 0x0E, "Erase binary" },
     { 0x20, "Verify" },
@@ -69,13 +90,102 @@ static const value_string iso7816_ins[] = {
 static int
 dissect_iso7816_atr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-    gint  offset = 0;
+    gint        offset=0;
+    guint       i=0;  /* loop index for TA(i)...TD(i) */
+    proto_item *td_it;
+    proto_tree *td_tree=NULL;
+    guint8      ta, tb, tc, td, k=0;
+    gint        tck_len;
+    proto_item *err_it;
 
     col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "ATR sequence");
 
-    proto_tree_add_item(tree, hf_iso7816_atr, tvb, offset,
-            tvb_reported_length_remaining(tvb, offset), ENC_NA);
-    offset += tvb_reported_length_remaining(tvb, offset);
+    /* ISO 7816-4, section 4 indicates that concatenations are big endian */
+    proto_tree_add_item(tree, hf_iso7816_atr_init_char,
+            tvb, offset, 1, ENC_BIG_ENDIAN);
+    offset++;
+
+    do {
+        /* for i==0, this is the T0 byte, otherwise it's the TD(i) byte
+           in each loop, we dissect T0/TD(i) and TA(i+1), TB(i+1), TC(i+1) */
+        td = tvb_get_guint8(tvb, offset);
+        if (i==0) {
+            td_it = proto_tree_add_item(tree, hf_iso7816_atr_t0,
+                    tvb, offset, 1, ENC_BIG_ENDIAN);
+        }
+        else {
+            td_it = proto_tree_add_uint_format(tree, hf_iso7816_atr_td,
+                    tvb, offset, 1, td,
+                    "Interface character TD(%d): 0x%02x", i, td);
+        }
+        td_tree = proto_item_add_subtree(td_it, ett_iso7816_atr_td);
+
+        proto_tree_add_boolean_format(td_tree, hf_iso7816_atr_next_ta_present,
+                tvb, offset, 1, td&0x10,
+                "TA(%d) present: %s", i+1, td&0x10 ? "True" : "False");
+        proto_tree_add_boolean_format(td_tree, hf_iso7816_atr_next_tb_present,
+                tvb, offset, 1, td&0x20,
+                "TB(%d) present: %s", i+1, td&0x20 ? "True" : "False");
+        proto_tree_add_boolean_format(td_tree, hf_iso7816_atr_next_tc_present,
+                tvb, offset, 1, td&0x40,
+                "TC(%d) present: %s", i+1, td&0x40 ? "True" : "False");
+        proto_tree_add_boolean_format(td_tree, hf_iso7816_atr_next_td_present,
+                tvb, offset, 1, td&0x80,
+                "TD(%d) present: %s", i+1, td&0x80 ? "True" : "False");
+
+        if (i==0) {
+            k = td&0x0F;   /* number of historical bytes */
+            proto_tree_add_item(td_tree, hf_iso7816_atr_k,
+                    tvb, offset, 1, ENC_BIG_ENDIAN);
+        }
+        else {
+            proto_tree_add_item(td_tree, hf_iso7816_atr_t,
+                    tvb, offset, 1, ENC_BIG_ENDIAN);
+        }
+        offset++;
+
+        if (td&0x10) {
+            ta = tvb_get_guint8(tvb, offset);
+            /* we read TA(i+1), see comment above */
+            proto_tree_add_uint_format(tree, hf_iso7816_atr_ta, tvb, offset, 1,
+                    ta, "Interface character TA(%d): 0x%02x", i+1, ta);
+            offset++;
+        }
+        if (td&0x20) {
+            tb = tvb_get_guint8(tvb, offset);
+            proto_tree_add_uint_format(tree, hf_iso7816_atr_tb, tvb, offset, 1,
+                    tb, "Interface character TB(%d): 0x%02x", i+1, tb);
+            offset++;
+        }
+        if (td&0x40) {
+            tc = tvb_get_guint8(tvb, offset);
+            proto_tree_add_uint_format(tree, hf_iso7816_atr_tc, tvb, offset, 1,
+                    tc, "Interface character TC(%d): 0x%02x", i+1, tc);
+            offset++;
+        }
+
+        i++;
+    } while (td&0x80);
+
+    if (k>0) {
+        proto_tree_add_item(tree, hf_iso7816_atr_hist_bytes,
+                tvb, offset, k, ENC_NA);
+        offset += k;
+    }
+
+    tck_len = tvb_reported_length_remaining(tvb, offset);
+    /* tck is either absent or exactly one byte */
+    if (tck_len==1) {
+        proto_tree_add_item(tree, hf_iso7816_atr_tck,
+                tvb, offset, 1, ENC_BIG_ENDIAN);
+        offset++;
+    }
+    else if (tck_len>1) {
+        err_it = proto_tree_add_text(tree, tvb, offset, tck_len,
+                "Invalid TCK byte");
+        expert_add_info_format(pinfo, err_it, PI_PROTOCOL, PI_WARN,
+                "TCK byte must either be absent or exactly one byte");
+    }
 
     return offset;
 }
@@ -212,9 +322,61 @@ void
 proto_register_iso7816(void)
 {
     static hf_register_info hf[] = {
-        { &hf_iso7816_atr,
-          { "ATR", "iso7816.atr",
-            FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
+        { &hf_iso7816_atr_init_char,
+            { "Initial character", "iso7816.atr.init_char",
+                FT_UINT8, BASE_HEX, VALS(iso7816_atr_init_char), 0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_t0,
+            { "Format character T0", "iso7816.atr.t0",
+                FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_ta,
+            { "Interface character TA(i)", "iso7816.atr.ta",
+                FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_tb,
+            { "Interface character TB(i)", "iso7816.atr.tb",
+                FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_tc,
+            { "Interface character TC(i)", "iso7816.atr.tc",
+                FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_td,
+            { "Interface character TD(i)", "iso7816.atr.td",
+                FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_next_ta_present,
+            { "TA(i+1) present", "iso7816.atr.next_ta_present",
+                FT_BOOLEAN, BASE_HEX, NULL, 0x10, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_next_tb_present,
+            { "TB(i+1) present", "iso7816.atr.next_tb_present",
+                FT_BOOLEAN, BASE_HEX, NULL, 0x20, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_next_tc_present,
+            { "TC(i+1) present", "iso7816.atr.next_tc_present",
+                FT_BOOLEAN, BASE_HEX, NULL, 0x40, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_next_td_present,
+            { "TD(i+1) present", "iso7816.atr.next_td_present",
+                FT_BOOLEAN, BASE_HEX, NULL, 0x80, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_k,
+            { "Number K of historical bytes", "iso7816.atr.k",
+                FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_t,
+            { "Protocol reference T", "iso7816.atr.t",
+                FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_hist_bytes,
+            { "Historical bytes", "iso7816.atr.historical_bytes",
+                FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_tck,
+            { "Check character TCK", "iso7816.atr.tck",
+                FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
         },
         { &hf_iso7816_cla,
             { "Class", "iso7816.apdu.cla",
@@ -254,7 +416,8 @@ proto_register_iso7816(void)
         }
     };
     static gint *ett[] = {
-        &ett_iso7816
+        &ett_iso7816,
+        &ett_iso7816_atr_td
     };
 
     proto_iso7816 = proto_register_protocol(