* 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;
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;
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;
};
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" },
{ 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_)
{
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)
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) {
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);
proto_item *class_item;
proto_tree *class_tree;
guint8 dev_class;
- proto_item *enc_item;
guint8 channel;
proto_item *ch_item;
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);
}
}
- PROTO_ITEM_SET_GENERATED(enc_item);
-
return ret_fct;
}
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,
tvb, offset, 1, ENC_BIG_ENDIAN);
p2_offset = offset;
offset++;
+ P1P2 = (p1<<8|p2);
switch (ins) {
case INS_EXT_AUTH:
/* 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:
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
}
}
}
-
+
/* - 2 bytes SW1, SW2 */
body_len = tvb_reported_length_remaining(tvb, offset) - 2;
/* 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) {
{ "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 }
},
{ &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",
{ "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,
&ett_iso7816_p1,
&ett_iso7816_p2,
&ett_iso7816_atr,
+ &ett_iso7816_atr_ta,
&ett_iso7816_atr_td
};