2 * Routines for packet dissection of generic ISO 7816 smart card messages
3 * Copyright 2012-2013 by Martin Kaiser <martin@kaiser.cx>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 /* This dissector supports the command and response apdu structure
27 * as defined in ISO 7816-4. Detailed dissection of the APDUs defined
28 * in the ISO 7816 specifications will be added in the future.
30 * The dissection of Answer To Reset (ATR) messages was made a separate
31 * protocol so that it can be shared easily.
39 #include <epan/packet.h>
40 #include <epan/expert.h>
41 #include <epan/wmem/wmem.h>
43 static int proto_iso7816
= -1;
44 static int proto_iso7816_atr
= -1;
46 static dissector_handle_t iso7816_atr_handle
;
48 static wmem_tree_t
*transactions
= NULL
;
50 static int ett_iso7816
= -1;
51 static int ett_iso7816_class
= -1;
52 static int ett_iso7816_param
= -1;
53 static int ett_iso7816_p1
= -1;
54 static int ett_iso7816_p2
= -1;
55 static int ett_iso7816_atr
= -1;
56 static int ett_iso7816_atr_td
= -1;
58 static int hf_iso7816_atr_init_char
= -1;
59 static int hf_iso7816_atr_t0
= -1;
60 static int hf_iso7816_atr_ta
= -1;
61 static int hf_iso7816_atr_tb
= -1;
62 static int hf_iso7816_atr_tc
= -1;
63 static int hf_iso7816_atr_td
= -1;
64 static int hf_iso7816_atr_next_ta_present
= -1;
65 static int hf_iso7816_atr_next_tb_present
= -1;
66 static int hf_iso7816_atr_next_tc_present
= -1;
67 static int hf_iso7816_atr_next_td_present
= -1;
68 static int hf_iso7816_atr_k
= -1;
69 static int hf_iso7816_atr_t
= -1;
70 static int hf_iso7816_atr_hist_bytes
= -1;
71 static int hf_iso7816_atr_tck
= -1;
73 static int hf_iso7816_resp_in
= -1;
74 static int hf_iso7816_resp_to
= -1;
75 static int hf_iso7816_cla
= -1;
76 static int hf_iso7816_cla_sm
= -1;
77 static int hf_iso7816_cla_channel
= -1;
78 static int hf_iso7816_ins
= -1;
79 static int hf_iso7816_p1
= -1;
80 static int hf_iso7816_p2
= -1;
81 static int hf_iso7816_lc
= -1;
82 static int hf_iso7816_le
= -1;
83 static int hf_iso7816_body
= -1;
84 static int hf_iso7816_sw1
= -1;
85 static int hf_iso7816_sw2
= -1;
86 static int hf_iso7816_sel_file_ctrl
= -1;
87 static int hf_iso7816_sel_file_fci_req
= -1;
88 static int hf_iso7816_sel_file_occ
= -1;
90 static expert_field ie_iso7816_atr_tck_not1
= EI_INIT
;
92 #define ADDR_INTF "Interface"
93 #define ADDR_CARD "Card"
95 typedef struct _iso7816_transaction_t
{
98 guint8 cmd_ins
; /* instruction byte in the command apdu */
99 /* no need to add the channel number,
100 the response contains no channel number to compare this to
101 and the spec explicitly prohibits interleaving of command-response
102 pairs, regardless of logical channels */
103 } iso7816_transaction_t
;
105 static const value_string iso7816_atr_init_char
[] = {
106 { 0x3B, "Direct convention (A==0, Z==1, MSB==m9)" },
107 { 0x3F, "Inverse convention (A==1, Z==0, MSB==m2)" },
111 static const value_string iso7816_cla_sm
[] = {
113 { 0x01, "Proprietary SM" },
114 { 0x02, "SM, command header not authenticated" },
115 { 0x03, "SM, command header authenticated" },
119 #define INS_ERASE_BIN 0x0E
120 #define INS_VRFY 0x20
121 #define INS_MANAGE_CHANNEL 0x70
122 #define INS_EXT_AUTH 0x82
123 #define INS_GET_CHALLENGE 0x84
124 #define INS_SELECT_FILE 0xA4
125 #define INS_READ_BIN 0xB0
126 #define INS_READ_REC 0xB2
127 #define INS_GET_RESP 0xC0
128 #define INS_ENVELOPE 0xC2
129 #define INS_GET_DATA 0xCA
130 #define INS_WRITE_BIN 0xD0
131 #define INS_WRITE_REC 0xD2
132 #define INS_UPDATE_BIN 0xD6
133 #define INS_PUT_DATA 0xDA
134 #define INS_UPDATE_REC 0xDC
135 #define INS_APPEND_REC 0xE2
136 /* for our transaction tracking, not defined in the specification */
137 #define INS_INVALID 0x00
139 static const value_string iso7816_ins
[] = {
140 /* instructions defined in ISO 7816-4 */
141 { INS_ERASE_BIN
, "Erase binary" },
142 { INS_VRFY
, "Verify" },
143 { INS_MANAGE_CHANNEL
, "Manage channel" },
144 { INS_EXT_AUTH
, "External authenticate" },
145 { INS_GET_CHALLENGE
, "Get challenge" },
146 { INS_SELECT_FILE
, "Select file" },
147 { INS_READ_BIN
, "Read binary" },
148 { INS_READ_REC
, "Read records" },
149 { INS_GET_RESP
, "Get response" },
150 { INS_ENVELOPE
, "Envelope" },
151 { INS_GET_DATA
, "Get data" },
152 { INS_WRITE_BIN
, "Write binary" },
153 { INS_WRITE_REC
, "Write record" },
154 { INS_UPDATE_BIN
, "Update binary" },
155 { INS_PUT_DATA
, "Put data" },
156 { INS_UPDATE_REC
, "Update record" },
157 { INS_APPEND_REC
, "Append record" },
160 static value_string_ext iso7816_ins_ext
= VALUE_STRING_EXT_INIT(iso7816_ins
);
162 #define P1P2 (p1<<8|p2)
164 static const value_string iso7816_sel_file_ctrl
[] = {
165 { 0x00, "Select MF, DF or EF" },
166 { 0x01, "Select child DF" },
167 { 0x02, "Select EF under current DF" },
168 { 0x03, "Select parent DF of the current DF" },
169 { 0x04, "Direct selection by DF name" },
170 { 0x08, "Selection by path from MF" },
171 { 0x09, "Selection by path from current DF" },
174 static value_string_ext ext_iso7816_sel_file_ctrl
=
175 VALUE_STRING_EXT_INIT(iso7816_sel_file_ctrl
);
177 static const value_string iso7816_sel_file_fci_req
[] = {
178 { 0x00, "Return FCI, optional template" },
179 { 0x01, "Return FCP template" },
180 { 0x02, "Return FMD template" },
183 static value_string_ext ext_iso7816_sel_file_fci_req
=
184 VALUE_STRING_EXT_INIT(iso7816_sel_file_fci_req
);
186 static const value_string iso7816_sel_file_occ
[] = {
187 { 0x00, "First or only occurrence" },
188 { 0x01, "Last occurrence" },
189 { 0x02, "Next occurrence" },
190 { 0x03, "Previous occurrence" },
193 static value_string_ext ext_iso7816_sel_file_occ
=
194 VALUE_STRING_EXT_INIT(iso7816_sel_file_occ
);
196 static const range_string iso7816_sw1
[] = {
197 { 0x61, 0x61, "Normal processing" },
198 { 0x62, 0x63, "Warning processing" },
199 { 0x64, 0x65, "Execution error" },
200 { 0x67, 0x6F, "Checking error" },
201 { 0x90, 0x90, "Normal processing" },
206 dissect_iso7816_atr(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
210 guint i
=0; /* loop index for TA(i)...TD(i) */
211 proto_item
*proto_it
;
212 proto_tree
*proto_tr
;
213 guint8 ta
, tb
, tc
, td
, k
=0;
217 init_char
= tvb_get_guint8(tvb
, offset
);
218 if (init_char
!=0x3B && init_char
!=0x3F)
219 return 0; /* no ATR sequence */
221 proto_it
= proto_tree_add_protocol_format(tree
, proto_iso7816_atr
,
222 tvb
, 0, -1, "ISO 7816 ATR");
223 proto_tr
= proto_item_add_subtree(proto_it
, ett_iso7816_atr
);
225 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "ATR");
227 /* ISO 7816-4, section 4 indicates that concatenations are big endian */
228 proto_tree_add_item(proto_tr
, hf_iso7816_atr_init_char
,
229 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
236 /* for i==0, this is the T0 byte, otherwise it's the TD(i) byte
237 in each loop, we dissect T0/TD(i) and TA(i+1), TB(i+1), TC(i+1) */
238 td
= tvb_get_guint8(tvb
, offset
);
240 td_it
= proto_tree_add_item(proto_tr
, hf_iso7816_atr_t0
,
241 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
244 td_it
= proto_tree_add_uint_format(proto_tr
, hf_iso7816_atr_td
,
246 "Interface character TD(%d): 0x%02x", i
, td
);
248 td_tree
= proto_item_add_subtree(td_it
, ett_iso7816_atr_td
);
250 proto_tree_add_boolean_format(td_tree
, hf_iso7816_atr_next_ta_present
,
251 tvb
, offset
, 1, td
&0x10,
252 "TA(%d) present: %s", i
+1, td
&0x10 ? "True" : "False");
253 proto_tree_add_boolean_format(td_tree
, hf_iso7816_atr_next_tb_present
,
254 tvb
, offset
, 1, td
&0x20,
255 "TB(%d) present: %s", i
+1, td
&0x20 ? "True" : "False");
256 proto_tree_add_boolean_format(td_tree
, hf_iso7816_atr_next_tc_present
,
257 tvb
, offset
, 1, td
&0x40,
258 "TC(%d) present: %s", i
+1, td
&0x40 ? "True" : "False");
259 proto_tree_add_boolean_format(td_tree
, hf_iso7816_atr_next_td_present
,
260 tvb
, offset
, 1, td
&0x80,
261 "TD(%d) present: %s", i
+1, td
&0x80 ? "True" : "False");
263 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
,
264 "TA(%d)=%s TB(%d)=%s TC(%d)=%s TD(%d)=%s",
265 i
+1, td
&0x10 ? "True" : "False",
266 i
+1, td
&0x20 ? "True" : "False",
267 i
+1, td
&0x40 ? "True" : "False",
268 i
+1, td
&0x80 ? "True" : "False");
271 k
= td
&0x0F; /* number of historical bytes */
272 proto_tree_add_item(td_tree
, hf_iso7816_atr_k
,
273 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
276 proto_tree_add_item(td_tree
, hf_iso7816_atr_t
,
277 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
282 ta
= tvb_get_guint8(tvb
, offset
);
283 /* we read TA(i+1), see comment above */
284 proto_tree_add_uint_format(proto_tr
, hf_iso7816_atr_ta
,
286 "Interface character TA(%d): 0x%02x", i
+1, ta
);
290 tb
= tvb_get_guint8(tvb
, offset
);
291 proto_tree_add_uint_format(proto_tr
, hf_iso7816_atr_tb
,
293 "Interface character TB(%d): 0x%02x", i
+1, tb
);
297 tc
= tvb_get_guint8(tvb
, offset
);
298 proto_tree_add_uint_format(proto_tr
, hf_iso7816_atr_tc
,
300 "Interface character TC(%d): 0x%02x", i
+1, tc
);
308 proto_tree_add_item(proto_tr
, hf_iso7816_atr_hist_bytes
,
309 tvb
, offset
, k
, ENC_NA
);
313 tck_len
= tvb_reported_length_remaining(tvb
, offset
);
314 /* tck is either absent or exactly one byte */
316 proto_tree_add_item(proto_tr
, hf_iso7816_atr_tck
,
317 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
320 else if (tck_len
>1) {
321 err_it
= proto_tree_add_text(proto_tr
, tvb
, offset
, tck_len
,
323 expert_add_info(pinfo
, err_it
, &ie_iso7816_atr_tck_not1
);
326 proto_item_set_len(proto_it
, offset
);
330 /* return 1 if the class byte says that the APDU is in ISO7816 format
331 or -1 if the APDU is in proprietary format */
333 dissect_iso7816_class(tvbuff_t
*tvb
, gint offset
,
334 packet_info
*pinfo _U_
, proto_tree
*tree
)
337 proto_item
*class_item
;
338 proto_tree
*class_tree
;
340 proto_item
*enc_item
;
344 class_item
= proto_tree_add_item(tree
, hf_iso7816_cla
,
345 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
346 class_tree
= proto_item_add_subtree(class_item
, ett_iso7816_class
);
348 dev_class
= tvb_get_guint8(tvb
, offset
);
350 if (dev_class
>=0x10 && dev_class
<=0x7F) {
351 enc_item
= proto_tree_add_text(class_tree
,
352 tvb
, offset
, 1, "reserved for future use");
354 else if (dev_class
>=0xD0 && dev_class
<=0xFE) {
355 enc_item
= proto_tree_add_text(class_tree
,
356 tvb
, offset
, 1, "proprietary structure and coding");
359 else if (dev_class
==0xFF) {
360 enc_item
= proto_tree_add_text(class_tree
,
361 tvb
, offset
, 1, "reserved for Protocol Type Selection");
364 enc_item
= proto_tree_add_text(class_tree
, tvb
, offset
, 1,
365 "structure and coding according to ISO/IEC 7816");
366 if (dev_class
>=0xA0 && dev_class
<=0xAF) {
367 proto_item_append_text(enc_item
,
368 " unless specified otherwise by the application context");
371 if (dev_class
<=0x0F || (dev_class
>=0x80 && dev_class
<=0xAF)) {
372 proto_tree_add_item(class_tree
, hf_iso7816_cla_sm
,
373 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
375 channel
= dev_class
& 0x03;
376 ch_item
= proto_tree_add_item(class_tree
, hf_iso7816_cla_channel
,
377 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
379 proto_item_append_text(ch_item
, " (or unused)");
383 PROTO_ITEM_SET_GENERATED(enc_item
);
388 /* dissect the parameters p1 and p2
389 return number of dissected bytes or -1 for error */
391 dissect_iso7816_params(guint8 ins
, tvbuff_t
*tvb
, gint offset
,
392 packet_info
*pinfo _U_
, proto_tree
*tree
)
394 gint offset_start
, p1_offset
, p2_offset
;
396 proto_tree
*params_tree
= NULL
;
398 proto_item
*p1_it
= NULL
, *p2_it
= NULL
;
399 proto_tree
*p1_tree
= NULL
, *p2_tree
= NULL
;
400 proto_item
*p1_p2_it
= NULL
;
402 offset_start
= offset
;
404 ti
= proto_tree_add_text(tree
, tvb
, offset_start
, 2, "Parameters");
405 params_tree
= proto_item_add_subtree(ti
, ett_iso7816_param
);
407 p1
= tvb_get_guint8(tvb
,offset
);
408 p1_it
= proto_tree_add_item(params_tree
, hf_iso7816_p1
, tvb
,
409 offset
, 1, ENC_BIG_ENDIAN
);
412 p2
= tvb_get_guint8(tvb
,offset
);
413 p2_it
= proto_tree_add_item(params_tree
, hf_iso7816_p2
,
414 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
421 proto_item_append_text(p1_it
,
422 " (reference of the algorithm on the card)");
424 proto_item_append_text(p2_it
, " (reference of the secret)");
426 case INS_SELECT_FILE
:
427 proto_item_append_text(p1_it
, " (selection control)");
428 p1_tree
= proto_item_add_subtree(p1_it
, ett_iso7816_p1
);
429 proto_tree_add_item(p1_tree
, hf_iso7816_sel_file_ctrl
,
430 tvb
, p1_offset
, 1, ENC_BIG_ENDIAN
);
431 proto_item_append_text(p2_it
, " (selection options)");
432 p2_tree
= proto_item_add_subtree(p2_it
, ett_iso7816_p2
);
433 proto_tree_add_item(p2_tree
, hf_iso7816_sel_file_fci_req
,
434 tvb
, p2_offset
, 1, ENC_BIG_ENDIAN
);
435 proto_tree_add_item(p2_tree
, hf_iso7816_sel_file_occ
,
436 tvb
, p2_offset
, 1, ENC_BIG_ENDIAN
);
440 /* XXX - b5-b1 of P1 == short ef identifier for the selected file */
441 /* XXX - P2 == offset for the read */
444 p1_p2_it
= proto_tree_add_text(
445 params_tree
, tvb
, offset_start
, offset
-offset_start
,
446 "Offset of the first byte to read: %d", P1P2
);
447 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
,
452 p1_p2_it
= proto_tree_add_text(
453 params_tree
, tvb
, offset_start
, offset
-offset_start
,
454 "Both should be 0x00, other values are RFU");
457 if (P1P2
<=0x003F || (0x0300<=P1P2
&& P1P2
<=0x3FFF)) {
458 p1_p2_it
= proto_tree_add_text(params_tree
,
459 tvb
, offset_start
, offset
-offset_start
, "RFU");
461 else if (0x0100<=P1P2
&& P1P2
<=0x01FF) {
462 p1_p2_it
= proto_tree_add_text(
463 params_tree
, tvb
, offset_start
, offset
-offset_start
,
464 "Application data (proprietary coding)");
471 PROTO_ITEM_SET_GENERATED(p1_p2_it
);
478 tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
, proto_tree
*tree
)
483 le
= tvb_get_guint8(tvb
, offset
);
484 le_item
= proto_tree_add_item(
485 tree
, hf_iso7816_le
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
487 proto_item_append_text(le_item
, " (maximum number of available bytes)");
494 dissect_iso7816_cmd_apdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
496 iso7816_transaction_t
*iso7816_trans
= NULL
;
497 proto_item
*trans_ti
= NULL
;
505 if (PINFO_FD_VISITED(pinfo
)) {
506 iso7816_trans
= (iso7816_transaction_t
*)wmem_tree_lookup32(
507 transactions
, PINFO_FD_NUM(pinfo
));
508 if (iso7816_trans
&& iso7816_trans
->cmd_frame
==PINFO_FD_NUM(pinfo
) &&
509 iso7816_trans
->resp_frame
!=0) {
510 trans_ti
= proto_tree_add_uint_format(tree
, hf_iso7816_resp_in
,
511 NULL
, 0, 0, iso7816_trans
->resp_frame
,
512 "Response in frame %d", iso7816_trans
->resp_frame
);
513 PROTO_ITEM_SET_GENERATED(trans_ti
);
518 iso7816_trans
= wmem_new(wmem_file_scope(), iso7816_transaction_t
);
519 iso7816_trans
->cmd_frame
= PINFO_FD_NUM(pinfo
);
520 iso7816_trans
->resp_frame
= 0;
521 iso7816_trans
->cmd_ins
= INS_INVALID
;
523 wmem_tree_insert32(transactions
,
524 iso7816_trans
->cmd_frame
, (void *)iso7816_trans
);
528 ret
= dissect_iso7816_class(tvb
, offset
, pinfo
, tree
);
530 /* the class byte says that the remaining APDU is not
532 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "%s",
533 "Command APDU using proprietary format");
535 return 1; /* we only dissected the class byte */
539 ins
= tvb_get_guint8(tvb
, offset
);
540 proto_tree_add_item(tree
, hf_iso7816_ins
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
541 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "%s",
542 val_to_str_ext_const(ins
, &iso7816_ins_ext
, "Unknown instruction"));
544 /* if we just created a new transaction, we can now fill in the cmd id */
545 if (iso7816_trans
&& iso7816_trans
->cmd_ins
==INS_INVALID
)
546 iso7816_trans
->cmd_ins
= ins
;
548 ret
= dissect_iso7816_params(ins
, tvb
, offset
, pinfo
, tree
);
552 /* for now, we support only short length fields
553 based on infos from the ATR, we could support extended length fields too */
554 body_len
= tvb_reported_length_remaining(tvb
, offset
);
556 /* nothing to do for body_len==0 */
558 offset
+= dissect_iso7816_le(tvb
, offset
, pinfo
, tree
);
560 else if (body_len
>1) {
561 lc
= tvb_get_guint8(tvb
, offset
);
563 tree
, hf_iso7816_lc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
566 proto_tree_add_item(tree
, hf_iso7816_body
, tvb
, offset
, lc
, ENC_NA
);
569 if (tvb_reported_length_remaining(tvb
, offset
)>0) {
570 offset
+= dissect_iso7816_le(tvb
, offset
, pinfo
, tree
);
578 dissect_iso7816_resp_apdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
580 iso7816_transaction_t
*iso7816_trans
;
581 proto_item
*trans_ti
= NULL
;
582 const gchar
*cmd_ins_str
;
586 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "Response APDU");
589 /* receive the largest key that is less than or equal to our frame
591 iso7816_trans
= (iso7816_transaction_t
*)wmem_tree_lookup32_le(
592 transactions
, PINFO_FD_NUM(pinfo
));
594 if (iso7816_trans
->resp_frame
==0) {
595 /* there's a pending request, this packet is the response */
596 iso7816_trans
->resp_frame
= PINFO_FD_NUM(pinfo
);
599 if (iso7816_trans
->resp_frame
== PINFO_FD_NUM(pinfo
)) {
600 /* we found the request that corresponds to our response */
601 cmd_ins_str
= val_to_str_const(iso7816_trans
->cmd_ins
,
602 iso7816_ins
, "Unknown instruction");
603 trans_ti
= proto_tree_add_uint_format(tree
, hf_iso7816_resp_to
,
604 NULL
, 0, 0, iso7816_trans
->cmd_frame
,
605 "Response to frame %d (%s)",
606 iso7816_trans
->cmd_frame
, cmd_ins_str
);
607 PROTO_ITEM_SET_GENERATED(trans_ti
);
609 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, " ",
610 "(to %s)", cmd_ins_str
);
615 /* - 2 bytes SW1, SW2 */
616 body_len
= tvb_reported_length_remaining(tvb
, offset
) - 2;
619 proto_tree_add_item(tree
, hf_iso7816_body
,
620 tvb
, offset
, body_len
, ENC_NA
);
624 if (tvb_reported_length_remaining(tvb
, offset
) >= 2) {
625 proto_tree_add_item(tree
, hf_iso7816_sw1
,
626 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
628 proto_tree_add_item(tree
, hf_iso7816_sw2
,
629 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
637 dissect_iso7816(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
640 proto_item
*tree_ti
= NULL
;
641 proto_tree
*iso7816_tree
= NULL
;
642 gboolean is_atr
= FALSE
;
644 if (pinfo
->p2p_dir
!=P2P_DIR_SENT
&& pinfo
->p2p_dir
!=P2P_DIR_RECV
)
647 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ISO 7816");
648 col_clear(pinfo
->cinfo
, COL_INFO
);
650 tree_ti
= proto_tree_add_protocol_format(tree
, proto_iso7816
,
651 tvb
, 0, tvb_reported_length(tvb
), "ISO 7816");
652 iso7816_tree
= proto_item_add_subtree(tree_ti
, ett_iso7816
);
654 /* per our definition, sent/received is from the perspective of the interface
655 i.e sent is from interface to card, received is from card to interface */
656 if (pinfo
->p2p_dir
==P2P_DIR_SENT
) {
657 SET_ADDRESS(&pinfo
->src
, AT_STRINGZ
,
658 (int)strlen(ADDR_INTF
)+1, ADDR_INTF
);
659 SET_ADDRESS(&pinfo
->dst
, AT_STRINGZ
,
660 (int)strlen(ADDR_CARD
)+1, ADDR_CARD
);
661 proto_item_append_text(tree_ti
, " Command APDU");
662 offset
= dissect_iso7816_cmd_apdu(tvb
, pinfo
, iso7816_tree
);
664 else if (pinfo
->p2p_dir
==P2P_DIR_RECV
) {
665 SET_ADDRESS(&pinfo
->src
, AT_STRINGZ
,
666 (int)strlen(ADDR_CARD
)+1, ADDR_CARD
);
667 SET_ADDRESS(&pinfo
->dst
, AT_STRINGZ
,
668 (int)strlen(ADDR_INTF
)+1, ADDR_INTF
);
670 if (iso7816_atr_handle
) {
671 offset
= call_dissector_only(iso7816_atr_handle
,
672 tvb
, pinfo
, iso7816_tree
, NULL
);
677 proto_item_append_text(tree_ti
, " Response APDU");
678 offset
= dissect_iso7816_resp_apdu(tvb
, pinfo
, iso7816_tree
);
686 proto_register_iso7816(void)
688 static hf_register_info hf
[] = {
689 { &hf_iso7816_atr_init_char
,
690 { "Initial character", "iso7816.atr.init_char",
691 FT_UINT8
, BASE_HEX
, VALS(iso7816_atr_init_char
), 0, NULL
, HFILL
}
693 { &hf_iso7816_atr_t0
,
694 { "Format character T0", "iso7816.atr.t0",
695 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
697 { &hf_iso7816_atr_ta
,
698 { "Interface character TA(i)", "iso7816.atr.ta",
699 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
701 { &hf_iso7816_atr_tb
,
702 { "Interface character TB(i)", "iso7816.atr.tb",
703 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
705 { &hf_iso7816_atr_tc
,
706 { "Interface character TC(i)", "iso7816.atr.tc",
707 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
709 { &hf_iso7816_atr_td
,
710 { "Interface character TD(i)", "iso7816.atr.td",
711 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
713 { &hf_iso7816_atr_next_ta_present
,
714 { "TA(i+1) present", "iso7816.atr.next_ta_present",
715 FT_BOOLEAN
, BASE_HEX
, NULL
, 0x10, NULL
, HFILL
}
717 { &hf_iso7816_atr_next_tb_present
,
718 { "TB(i+1) present", "iso7816.atr.next_tb_present",
719 FT_BOOLEAN
, BASE_HEX
, NULL
, 0x20, NULL
, HFILL
}
721 { &hf_iso7816_atr_next_tc_present
,
722 { "TC(i+1) present", "iso7816.atr.next_tc_present",
723 FT_BOOLEAN
, BASE_HEX
, NULL
, 0x40, NULL
, HFILL
}
725 { &hf_iso7816_atr_next_td_present
,
726 { "TD(i+1) present", "iso7816.atr.next_td_present",
727 FT_BOOLEAN
, BASE_HEX
, NULL
, 0x80, NULL
, HFILL
}
730 { "Number K of historical bytes", "iso7816.atr.k",
731 FT_UINT8
, BASE_DEC
, NULL
, 0x0F, NULL
, HFILL
}
734 { "Protocol reference T", "iso7816.atr.t",
735 FT_UINT8
, BASE_HEX
, NULL
, 0x0F, NULL
, HFILL
}
737 { &hf_iso7816_atr_hist_bytes
,
738 { "Historical bytes", "iso7816.atr.historical_bytes",
739 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
741 { &hf_iso7816_atr_tck
,
742 { "Check character TCK", "iso7816.atr.tck",
743 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
745 { &hf_iso7816_resp_in
,
746 { "Response In", "iso7816.resp_in",
747 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
748 "The response to this command is in this frame", HFILL
}
750 { &hf_iso7816_resp_to
,
751 { "Response To", "iso7816.resp_to",
752 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
753 "This is the response to the command in this frame", HFILL
}
756 { "Class", "iso7816.apdu.cla",
757 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
759 { &hf_iso7816_cla_sm
,
760 { "Secure Messaging", "iso7816.apdu.cla.sm",
761 FT_UINT8
, BASE_HEX
, VALS(iso7816_cla_sm
), 0x0C, NULL
, HFILL
}
763 { &hf_iso7816_cla_channel
,
764 { "Logical channel number", "iso7816.apdu.cla.channel",
765 FT_UINT8
, BASE_HEX
, NULL
, 0x03, NULL
, HFILL
}
768 { "Instruction", "iso7816.apdu.ins",
769 FT_UINT8
, BASE_HEX
| BASE_EXT_STRING
, &iso7816_ins_ext
, 0, NULL
, HFILL
}
772 { "Parameter 1", "iso7816.apdu.p1",
773 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
776 { "Parameter 2", "iso7816.apdu.p2",
777 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
780 { "Length field Lc", "iso7816.apdu.lc",
781 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
784 { "Expected response length Le", "iso7816.apdu.le",
785 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
788 { "APDU Body", "iso7816.apdu.body",
789 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
792 { "Status Word SW1", "iso7816.apdu.sw1", FT_UINT8
,
793 BASE_RANGE_STRING
|BASE_HEX
, RVALS(iso7816_sw1
), 0, NULL
, HFILL
}
796 { "Status Word SW2", "iso7816.apdu.sw2",
797 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
799 { &hf_iso7816_sel_file_ctrl
,
800 { "Selection control", "iso7816.apdu.select_file.ctrl",
801 FT_UINT8
, BASE_HEX
| BASE_EXT_STRING
,
802 &ext_iso7816_sel_file_ctrl
, 0, NULL
, HFILL
}
804 { &hf_iso7816_sel_file_fci_req
,
805 { "File control information request", "iso7816.apdu.select_file.fci_req",
806 FT_UINT8
, BASE_HEX
| BASE_EXT_STRING
,
807 &ext_iso7816_sel_file_fci_req
, 0x0C, NULL
, HFILL
}
809 { &hf_iso7816_sel_file_occ
,
810 { "Occurrence", "iso7816.apdu.select_file.occurrence",
811 FT_UINT8
, BASE_HEX
| BASE_EXT_STRING
,
812 &ext_iso7816_sel_file_occ
, 0x03, NULL
, HFILL
}
815 static gint
*ett
[] = {
825 static ei_register_info ei
[] = {
826 { &ie_iso7816_atr_tck_not1
, { "iso7816.atr.tck.not1", PI_PROTOCOL
, PI_WARN
, "TCK byte must either be absent or exactly one byte", EXPFILL
}}
829 expert_module_t
* expert_iso7816
;
831 proto_iso7816
= proto_register_protocol(
832 "ISO/IEC 7816", "ISO 7816", "iso7816");
833 proto_register_field_array(proto_iso7816
, hf
, array_length(hf
));
834 proto_register_subtree_array(ett
, array_length(ett
));
835 expert_iso7816
= expert_register_protocol(proto_iso7816
);
836 expert_register_field_array(expert_iso7816
, ei
, array_length(ei
));
838 new_register_dissector("iso7816", dissect_iso7816
, proto_iso7816
);
840 transactions
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
842 proto_iso7816_atr
= proto_register_protocol(
843 "ISO/IEC 7816-3", "ISO 7816-3", "iso7816.atr");
844 new_register_dissector("iso7816.atr", dissect_iso7816_atr
, proto_iso7816_atr
);
848 proto_reg_handoff_iso7816(void)
850 iso7816_atr_handle
= find_dissector("iso7816.atr");
854 * Editor modelines - http://www.wireshark.org/tools/modelines.html
859 * indent-tabs-mode: nil
862 * vi: set shiftwidth=4 tabstop=8 expandtab:
863 * :indentSize=4:tabSize=8:noTabs=true: