Use address functions instead of ADDRESS macros in asn1 and epan
[metze/wireshark/wip.git] / epan / dissectors / packet-iso7816.c
index a20e6f6819b052aeb892c9aa1cba9de0f301b10c..2b35a425fe91b309ab26dcb21f3cf6c6a1207f1e 100644 (file)
@@ -2,8 +2,6 @@
  * Routines for packet dissection of generic ISO 7816 smart card messages
  * Copyright 2012-2013 by Martin Kaiser <martin@kaiser.cx>
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
 
 #include "config.h"
 
-#include <glib.h>
-
 #include <epan/packet.h>
 #include <epan/expert.h>
-#include <epan/wmem/wmem.h>
+void proto_register_iso7816(void);
+void proto_reg_handoff_iso7816(void);
 
 static int proto_iso7816 = -1;
 static int proto_iso7816_atr = -1;
@@ -53,11 +50,16 @@ static int ett_iso7816_param = -1;
 static int ett_iso7816_p1 = -1;
 static int ett_iso7816_p2 = -1;
 static int ett_iso7816_atr = -1;
+static int ett_iso7816_atr_ta = -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;
+/* these two fields hold the converted values Fi and Di,
+   not the binary representations FI and DI */
+static int hf_iso7816_atr_ta1_fi = -1;
+static int hf_iso7816_atr_ta1_di = -1;
 static int hf_iso7816_atr_tb = -1;
 static int hf_iso7816_atr_tc = -1;
 static int hf_iso7816_atr_td = -1;
@@ -86,6 +88,10 @@ static int hf_iso7816_sw2 = -1;
 static int hf_iso7816_sel_file_ctrl = -1;
 static int hf_iso7816_sel_file_fci_req = -1;
 static int hf_iso7816_sel_file_occ = -1;
+static int hf_iso7816_get_resp = -1;
+static int hf_iso7816_offset_first_byte = -1;
+static int hf_iso7816_rfu = -1;
+static int hf_iso7816_application_data = -1;
 
 static expert_field ie_iso7816_atr_tck_not1 = EI_INIT;
 
@@ -159,8 +165,6 @@ static const value_string iso7816_ins[] = {
 };
 static value_string_ext iso7816_ins_ext = VALUE_STRING_EXT_INIT(iso7816_ins);
 
-#define P1P2 (p1<<8|p2)
-
 static const value_string iso7816_sel_file_ctrl[] = {
     { 0x00, "Select MF, DF or EF" },
     { 0x01, "Select child DF" },
@@ -202,6 +206,89 @@ static const range_string iso7816_sw1[] = {
   { 0,0,  NULL }
 };
 
+static const range_string iso7816_class_rvals[] = {
+    {0x00, 0x0F, "structure and coding according to ISO/IEC 7816" },
+    {0x10, 0x7F, "reserved for future use" },
+    {0x80, 0x8F, "structure and coding according to ISO/IEC 7816" },
+    {0xA0, 0xAF, "structure and coding according to ISO/IEC 7816 unless specified otherwise by the application context" },
+    {0xB0, 0xCF, "structure and coding according to ISO/IEC 7816" },
+    {0xD0, 0xFE, "proprietary structure and coding" },
+    {0xFF, 0xFF, "reserved for Protocol Type Selection" },
+    {0, 0,   NULL}
+};
+
+static inline
+guint16 FI_to_Fi(guint8 FI)
+{
+    if (FI<=1)
+        return 372;
+    else if (FI<=6)
+        return (FI-1) * 372;
+    else if (FI==9)
+        return 512;
+    else if (FI==10)
+        return 768;
+    else if (FI==11)
+        return 1024;
+    else if (FI==12)
+        return 1536;
+    else if (FI==13)
+        return 2048;
+
+    return 0; /* 0 means RFU (reserved for future use) here */
+}
+
+static inline
+guint8 DI_to_Di(guint8 DI)
+{
+    if (DI>=1 && DI<=6)
+        return 1 << (DI-1);
+    else if (DI==8)
+        return 12;
+    else if (DI==9)
+        return 20;
+
+    return 0; /* 0 means RFU (reserved for future use) here */
+}
+
+/* dissect TA(ta_index) */
+static void
+dissect_iso7816_atr_ta(tvbuff_t *tvb, gint offset, guint ta_index,
+        packet_info *pinfo _U_, proto_tree *tree)
+{
+    guint8      ta, FI, DI;
+    guint16     Fi;
+    guint8      Di;
+    proto_item *ta_it;
+    proto_tree *ta_tree;
+
+    ta = tvb_get_guint8(tvb, offset);
+    ta_it = proto_tree_add_uint_format(tree, hf_iso7816_atr_ta,
+            tvb, offset, 1, ta,
+            "Interface character TA(%d): 0x%02x", ta_index, ta);
+    ta_tree = proto_item_add_subtree(ta_it, ett_iso7816_atr_ta);
+
+    if (ta_index==1) {
+        FI = (tvb_get_guint8(tvb, offset) & 0xF0) >> 4;
+        Fi = FI_to_Fi(FI);
+        if (Fi>0) {
+            proto_tree_add_uint_format(ta_tree, hf_iso7816_atr_ta1_fi,
+                    tvb, offset, 1, Fi,
+                    "Clock rate conversion factor Fi: %d (FI 0x%x)",
+                    Fi, FI);
+        }
+
+        DI = tvb_get_guint8(tvb, offset) & 0x0F;
+        Di = DI_to_Di(DI);
+        if (Di>0) {
+            proto_tree_add_uint_format(ta_tree, hf_iso7816_atr_ta1_di,
+                    tvb, offset, 1, Di,
+                    "Baud rate adjustment factor Di: %d (DI 0x%x)",
+                    Di, DI);
+        }
+    }
+}
+
 static int
 dissect_iso7816_atr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
@@ -210,9 +297,8 @@ dissect_iso7816_atr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d
     guint       i=0;  /* loop index for TA(i)...TD(i) */
     proto_item *proto_it;
     proto_tree *proto_tr;
-    guint8      ta, tb, tc, td, k=0;
+    guint8      tb, tc, td, k=0;
     gint        tck_len;
-    proto_item *err_it;
 
     init_char = tvb_get_guint8(tvb, offset);
     if (init_char!=0x3B && init_char!=0x3F)
@@ -279,11 +365,8 @@ dissect_iso7816_atr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d
         offset++;
 
         if (td&0x10) {
-            ta = tvb_get_guint8(tvb, offset);
             /* we read TA(i+1), see comment above */
-            proto_tree_add_uint_format(proto_tr, hf_iso7816_atr_ta,
-                    tvb, offset, 1, ta,
-                    "Interface character TA(%d): 0x%02x", i+1, ta);
+            dissect_iso7816_atr_ta(tvb, offset, i+1, pinfo, proto_tr);
             offset++;
         }
         if (td&0x20) {
@@ -318,9 +401,8 @@ dissect_iso7816_atr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d
         offset++;
     }
     else if (tck_len>1) {
-        err_it = proto_tree_add_text(proto_tr, tvb, offset, tck_len,
-                "Invalid TCK byte");
-        expert_add_info(pinfo, err_it, &ie_iso7816_atr_tck_not1);
+        proto_tree_add_expert(proto_tr, pinfo, &ie_iso7816_atr_tck_not1,
+                tvb, offset, tck_len);
     }
 
     proto_item_set_len(proto_it, offset);
@@ -337,7 +419,6 @@ dissect_iso7816_class(tvbuff_t *tvb, gint offset,
     proto_item *class_item;
     proto_tree *class_tree;
     guint8      dev_class;
-    proto_item *enc_item;
     guint8      channel;
     proto_item *ch_item;
 
@@ -348,26 +429,13 @@ dissect_iso7816_class(tvbuff_t *tvb, gint offset,
     dev_class = tvb_get_guint8(tvb, offset);
 
     if (dev_class>=0x10 && dev_class<=0x7F) {
-        enc_item = proto_tree_add_text(class_tree,
-                tvb, offset, 1, "reserved for future use");
     }
     else if (dev_class>=0xD0 && dev_class<=0xFE) {
-        enc_item = proto_tree_add_text(class_tree,
-                tvb, offset, 1, "proprietary structure and coding");
         ret_fct = -1;
     }
     else if (dev_class==0xFF) {
-        enc_item = proto_tree_add_text(class_tree,
-                tvb, offset, 1, "reserved for Protocol Type Selection");
     }
     else {
-        enc_item = proto_tree_add_text(class_tree, tvb, offset, 1,
-                "structure and coding according to ISO/IEC 7816");
-        if (dev_class>=0xA0 && dev_class<=0xAF) {
-            proto_item_append_text(enc_item,
-                    " unless specified otherwise by the application context");
-        }
-
         if (dev_class<=0x0F || (dev_class>=0x80 && dev_class<=0xAF)) {
             proto_tree_add_item(class_tree, hf_iso7816_cla_sm,
                     tvb, offset, 1, ENC_BIG_ENDIAN);
@@ -380,8 +448,6 @@ dissect_iso7816_class(tvbuff_t *tvb, gint offset,
         }
     }
 
-    PROTO_ITEM_SET_GENERATED(enc_item);
-
     return ret_fct;
 }
 
@@ -392,17 +458,17 @@ dissect_iso7816_params(guint8 ins, tvbuff_t *tvb, gint offset,
                  packet_info *pinfo _U_, proto_tree *tree)
 {
     gint        offset_start, p1_offset, p2_offset;
-    proto_item *ti;
-    proto_tree *params_tree = NULL;
+    proto_tree *params_tree;
     guint8      p1, p2;
     proto_item *p1_it = NULL, *p2_it = NULL;
     proto_tree *p1_tree = NULL, *p2_tree = NULL;
     proto_item *p1_p2_it = NULL;
+    guint16     P1P2;
 
     offset_start = offset;
 
-    ti = proto_tree_add_text(tree, tvb, offset_start, 2, "Parameters");
-    params_tree = proto_item_add_subtree(ti, ett_iso7816_param);
+    params_tree = proto_tree_add_subtree(tree, tvb, offset_start, 2,
+                                ett_iso7816_param, NULL, "Parameters");
 
     p1 = tvb_get_guint8(tvb,offset);
     p1_it = proto_tree_add_item(params_tree, hf_iso7816_p1, tvb,
@@ -414,6 +480,7 @@ dissect_iso7816_params(guint8 ins, tvbuff_t *tvb, gint offset,
             tvb, offset, 1, ENC_BIG_ENDIAN);
     p2_offset = offset;
     offset++;
+    P1P2 = (p1<<8|p2);
 
     switch (ins) {
         case INS_EXT_AUTH:
@@ -441,27 +508,25 @@ dissect_iso7816_params(guint8 ins, tvbuff_t *tvb, gint offset,
                 /* XXX - P2 == offset for the read */
             }
             else {
-                p1_p2_it = proto_tree_add_text(
-                        params_tree, tvb, offset_start, offset-offset_start,
-                        "Offset of the first byte to read: %d", P1P2);
+                p1_p2_it = proto_tree_add_uint(params_tree, hf_iso7816_offset_first_byte,
+                        tvb, offset_start, offset-offset_start, P1P2);
                 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL,
                         "offset %d", P1P2);
             }
             break;
         case INS_GET_RESP:
-            p1_p2_it = proto_tree_add_text(
-                    params_tree, tvb, offset_start, offset-offset_start,
+            p1_p2_it = proto_tree_add_uint_format(params_tree, hf_iso7816_get_resp,
+                    tvb, offset_start, offset-offset_start, P1P2,
                     "Both should be 0x00, other values are RFU");
             break;
         case INS_GET_DATA:
             if (P1P2<=0x003F || (0x0300<=P1P2 && P1P2<=0x3FFF)) {
-                p1_p2_it = proto_tree_add_text(params_tree,
-                        tvb, offset_start, offset-offset_start, "RFU");
+                p1_p2_it = proto_tree_add_uint(params_tree, hf_iso7816_rfu,
+                        tvb, offset_start, offset-offset_start, P1P2);
             }
             else if (0x0100<=P1P2 && P1P2<=0x01FF) {
-                p1_p2_it = proto_tree_add_text(
-                        params_tree, tvb, offset_start, offset-offset_start,
-                        "Application data (proprietary coding)");
+                p1_p2_it = proto_tree_add_uint(params_tree, hf_iso7816_application_data,
+                        tvb, offset_start, offset-offset_start, P1P2);
             }
             break;
         default:
@@ -524,7 +589,7 @@ dissect_iso7816_cmd_apdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                     iso7816_trans->cmd_frame, (void *)iso7816_trans);
         }
     }
+
     ret = dissect_iso7816_class(tvb, offset, pinfo, tree);
     if (ret==-1) {
         /* the class byte says that the remaining APDU is not
@@ -611,7 +676,7 @@ dissect_iso7816_resp_apdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
             }
         }
     }
-           
+
     /* - 2 bytes SW1, SW2 */
     body_len = tvb_reported_length_remaining(tvb, offset) - 2;
 
@@ -654,17 +719,17 @@ dissect_iso7816(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
     /* per our definition, sent/received is from the perspective of the interface
        i.e sent is from interface to card, received is from card to interface */
     if (pinfo->p2p_dir==P2P_DIR_SENT) {
-        SET_ADDRESS(&pinfo->src, AT_STRINGZ,
+        set_address(&pinfo->src, AT_STRINGZ,
                 (int)strlen(ADDR_INTF)+1, ADDR_INTF);
-        SET_ADDRESS(&pinfo->dst, AT_STRINGZ,
+        set_address(&pinfo->dst, AT_STRINGZ,
                 (int)strlen(ADDR_CARD)+1, ADDR_CARD);
         proto_item_append_text(tree_ti, " Command APDU");
         offset = dissect_iso7816_cmd_apdu(tvb, pinfo, iso7816_tree);
     }
     else if (pinfo->p2p_dir==P2P_DIR_RECV) {
-        SET_ADDRESS(&pinfo->src, AT_STRINGZ,
+        set_address(&pinfo->src, AT_STRINGZ,
                 (int)strlen(ADDR_CARD)+1, ADDR_CARD);
-        SET_ADDRESS(&pinfo->dst, AT_STRINGZ,
+        set_address(&pinfo->dst, AT_STRINGZ,
                 (int)strlen(ADDR_INTF)+1, ADDR_INTF);
 
         if (iso7816_atr_handle) {
@@ -698,6 +763,14 @@ proto_register_iso7816(void)
             { "Interface character TA(i)", "iso7816.atr.ta",
                 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
         },
+        { &hf_iso7816_atr_ta1_fi,
+            { "Fi", "iso7816.atr.ta1.fi",
+                FT_UINT16, BASE_DEC, NULL, 0xF0, NULL, HFILL }
+        },
+        { &hf_iso7816_atr_ta1_di,
+            { "Di", "iso7816.atr.ta1.di",
+                FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }
+        },
         { &hf_iso7816_atr_tb,
             { "Interface character TB(i)", "iso7816.atr.tb",
                 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
@@ -754,7 +827,7 @@ proto_register_iso7816(void)
         },
         { &hf_iso7816_cla,
             { "Class", "iso7816.apdu.cla",
-                FT_UINT8, BASE_HEX, NULL, 0, NULL , HFILL }
+                FT_UINT8, BASE_HEX|BASE_RANGE_STRING, RVALS(iso7816_class_rvals), 0, NULL , HFILL }
         },
         { &hf_iso7816_cla_sm,
             { "Secure Messaging", "iso7816.apdu.cla.sm",
@@ -810,7 +883,23 @@ proto_register_iso7816(void)
             { "Occurrence", "iso7816.apdu.select_file.occurrence",
                 FT_UINT8, BASE_HEX | BASE_EXT_STRING,
                 &ext_iso7816_sel_file_occ, 0x03, NULL, HFILL }
-        }
+        },
+        { &hf_iso7816_offset_first_byte,
+            { "Offset of the first byte to read", "iso7816.offset_first_byte",
+                FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_get_resp,
+            { "GetResp", "iso7816.get_resp",
+                FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_rfu,
+            { "RFU", "iso7816.rfu",
+                FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
+        { &hf_iso7816_application_data,
+            { "Application data (proprietary coding)", "iso7816.application_data",
+                FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }
+        },
     };
     static gint *ett[] = {
         &ett_iso7816,
@@ -819,6 +908,7 @@ proto_register_iso7816(void)
         &ett_iso7816_p1,
         &ett_iso7816_p2,
         &ett_iso7816_atr,
+        &ett_iso7816_atr_ta,
         &ett_iso7816_atr_td
     };