#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;
#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" },
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;
}
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",
}
};
static gint *ett[] = {
- &ett_iso7816
+ &ett_iso7816,
+ &ett_iso7816_atr_td
};
proto_iso7816 = proto_register_protocol(