2 * Dissector for the Integrated Circuit Card Interface Device Class
5 * http://www.usb.org/developers/devclass_docs/DWG_Smart-Card_CCID_Rev110.pdf
7 * Copyright 2011, Tyson Key <tyson.key@gmail.com>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include <epan/packet.h>
36 #include <epan/dissectors/packet-usb.h>
38 static int proto_ccid = -1;
40 static int hf_ccid_bMessageType = -1;
41 static int hf_ccid_dwLength = -1;
42 static int hf_ccid_bSlot = -1;
43 static int hf_ccid_bSeq = -1;
44 static int hf_ccid_bStatus = -1;
45 static int hf_ccid_bError = -1;
46 static int hf_ccid_bChainParameter = -1;
47 static int hf_ccid_bPowerSelect = -1;
48 static int hf_ccid_bClockStatus = -1;
49 static int hf_ccid_bProtocolNum = -1;
50 static int hf_ccid_bBWI = -1;
51 static int hf_ccid_wLevelParameter = -1;
53 /* Standardised Bulk Out message types */
54 #define PC_RDR_SET_PARAMS 0x61
55 #define PC_RDR_ICC_ON 0x62
56 #define PC_RDR_ICC_OFF 0x63
57 #define PC_RDR_GET_SLOT_STATUS 0x65
58 #define PC_RDR_SECURE 0x69
59 #define PC_RDR_T0APDU 0x6A
60 #define PC_RDR_ESCAPE 0x6B
61 #define PC_RDR_GET_PARAMS 0x6C
62 #define PC_RDR_RESET_PARAMS 0x6D
63 #define PC_RDR_ICC_CLOCK 0x6E
64 #define PC_RDR_XFR_BLOCK 0x6F
65 #define PC_RDR_MECH 0x71
66 #define PC_RDR_ABORT 0x72
67 #define PC_RDR_DATA_CLOCK 0x73
69 /* Standardised Bulk In message types */
70 #define RDR_PC_DATA_BLOCK 0x80
71 #define RDR_PC_SLOT_STATUS 0x81
72 #define RDR_PC_PARAMS 0x82
73 #define RDR_PC_ESCAPE 0x83
74 #define RDR_PC_DATA_CLOCK 0x84
76 static const value_string ccid_messagetypes_vals[] = {
77 /* Standardised Bulk Out message types */
78 {PC_RDR_SET_PARAMS, "PC_to_RDR_SetParameters"},
79 {PC_RDR_ICC_ON, "PC_to_RDR_IccPowerOn"},
80 {PC_RDR_ICC_OFF, "PC_to_RDR_IccPowerOff"},
81 {PC_RDR_GET_SLOT_STATUS, "PC_to_RDR_GetSlotStatus"},
82 {PC_RDR_SECURE, "PC_to_RDR_Secure"},
83 {PC_RDR_T0APDU, "PC_to_RDR_T0APDU"},
84 {PC_RDR_ESCAPE, "PC_to_RDR_Escape"},
85 {PC_RDR_GET_PARAMS, "PC_to_RDR_GetParameters"},
86 {PC_RDR_RESET_PARAMS, "PC_to_RDR_ResetParameters"},
87 {PC_RDR_ICC_CLOCK, "PC_to_RDR_IccClock"},
88 {PC_RDR_XFR_BLOCK, "PC_to_RDR_XfrBlock"},
89 {PC_RDR_MECH, "PC_to_RDR_Mechanical"},
90 {PC_RDR_ABORT, "PC_to_RDR_Abort"},
91 {PC_RDR_DATA_CLOCK, "PC_to_RDR_SetDataRateAndClockFrequency"},
93 /* Standardised Bulk In message types */
94 {RDR_PC_DATA_BLOCK, "RDR_to_PC_DataBlock"},
95 {RDR_PC_SLOT_STATUS, "RDR_to_PC_SlotStatus"},
96 {RDR_PC_PARAMS, "RDR_to_PC_Parameters"},
97 {RDR_PC_ESCAPE, "RDR_to_PC_Escape"},
98 {RDR_PC_DATA_CLOCK, "RDR_to_PC_DataRateAndClockFrequency"},
100 /* End of message types */
104 static const value_string ccid_voltage_levels_vals[] = {
105 /* Standardised voltage levels */
106 {0x00, "Automatic Voltage Selection"},
111 /* End of voltage levels */
115 static const value_string ccid_clock_states_vals[] = {
116 /* Standardised clock states */
117 {0x00, "Clock running"},
118 {0x01, "Clock stopped in state L"},
119 {0x02, "Clock stopped in state H"},
120 {0x03, "Clock stopped in an unknown state"},
122 /* End of clock states */
126 static const value_string ccid_proto_structs_vals[] = {
127 /* Standardised clock states */
128 {0x00, "Structure for protocol T=0"},
129 {0x01, "Structure for protocol T=1"},
131 /* Marked as RFU, but added for completeness: */
132 {0x80, "Structure for 2-wire protocol"},
133 {0x81, "Structure for 3-wire protocol"},
134 {0x82, "Structure for I2C protocol"},
136 /* End of protocol structures */
140 static dissector_handle_t data_handle=NULL;
141 static dissector_handle_t usb_ccid_bulk_handle;
142 static dissector_table_t ccid_dissector_table;
144 /* Forward-declare the dissector functions */
145 static void dissect_ccid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
147 /* Subtree handles: set by register_subtree_array */
148 static gint ett_ccid = -1;
150 static void dissect_ccid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
153 proto_tree *ccid_tree;
155 tvbuff_t *next_tvb = NULL;
157 col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBCCID");
158 col_set_str(pinfo->cinfo, COL_INFO, "CCID Packet");
161 /* Start with a top-level item to add everything else to */
163 item = proto_tree_add_item(tree, proto_ccid, tvb, 0, -1, ENC_NA);
164 ccid_tree = proto_item_add_subtree(item, ett_ccid);
166 proto_tree_add_item(ccid_tree, hf_ccid_bMessageType, tvb, 0, 1, ENC_NA);
167 cmd = tvb_get_guint8(tvb, 0);
171 case PC_RDR_SET_PARAMS:
172 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
173 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
174 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
175 proto_tree_add_item(ccid_tree, hf_ccid_bProtocolNum, tvb, 7, 1, ENC_LITTLE_ENDIAN);
177 /* Placeholder for abRFU */
178 proto_tree_add_text(ccid_tree, tvb, 8, 2, "Reserved for Future Use");
180 next_tvb = tvb_new_subset_remaining(tvb, 10);
182 call_dissector(data_handle, next_tvb, pinfo, ccid_tree);
184 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Set Parameters");
188 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
189 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
190 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
191 proto_tree_add_item(ccid_tree, hf_ccid_bPowerSelect, tvb, 7, 1, ENC_LITTLE_ENDIAN);
193 /* Placeholder for abRFU */
194 proto_tree_add_text(ccid_tree, tvb, 8, 2, "Reserved for Future Use");
196 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: ICC Power On");
200 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
201 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
202 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
204 /* Placeholder for abRFU */
205 proto_tree_add_text(ccid_tree, tvb, 7, 3, "Reserved for Future Use");
207 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: ICC Power Off");
210 case PC_RDR_GET_SLOT_STATUS:
211 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
212 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
213 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
215 /* Placeholder for abRFU */
216 proto_tree_add_text(ccid_tree, tvb, 7, 3, "Reserved for Future Use");
218 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Get Slot Status");
222 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Secure");
226 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: T=0 APDU");
230 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Escape");
233 case PC_RDR_GET_PARAMS:
234 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
235 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
236 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
238 /* Placeholder for abRFU */
239 proto_tree_add_text(ccid_tree, tvb, 7, 3, "Reserved for Future Use");
241 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Get Parameters");
244 case PC_RDR_RESET_PARAMS:
245 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Reset Parameters");
248 case PC_RDR_ICC_CLOCK:
249 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: ICC Clock");
252 case PC_RDR_XFR_BLOCK:
253 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
254 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
255 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
256 proto_tree_add_item(ccid_tree, hf_ccid_bBWI, tvb, 7, 1, ENC_LITTLE_ENDIAN);
257 proto_tree_add_item(ccid_tree, hf_ccid_wLevelParameter, tvb, 8, 2, ENC_LITTLE_ENDIAN);
259 next_tvb = tvb_new_subset_remaining(tvb, 10);
260 call_dissector(data_handle, next_tvb, pinfo, tree);
262 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Transfer Block");
266 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Mechanical");
270 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Abort");
273 case PC_RDR_DATA_CLOCK:
274 col_set_str(pinfo->cinfo, COL_INFO, "PC to Reader: Set Data Rate and Clock Frequency");
277 case RDR_PC_DATA_BLOCK:
278 col_set_str(pinfo->cinfo, COL_INFO, "Reader to PC: Data Block");
279 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
280 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
281 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
282 proto_tree_add_item(ccid_tree, hf_ccid_bStatus, tvb, 7, 1, ENC_LITTLE_ENDIAN);
283 proto_tree_add_item(ccid_tree, hf_ccid_bError, tvb, 8, 1, ENC_LITTLE_ENDIAN);
284 proto_tree_add_item(ccid_tree, hf_ccid_bChainParameter, tvb, 9, 1, ENC_LITTLE_ENDIAN);
286 next_tvb = tvb_new_subset_remaining(tvb, 10);
287 call_dissector(data_handle, next_tvb, pinfo, ccid_tree);
290 case RDR_PC_SLOT_STATUS:
291 proto_tree_add_item(ccid_tree, hf_ccid_dwLength, tvb, 1, 4, ENC_LITTLE_ENDIAN);
292 proto_tree_add_item(ccid_tree, hf_ccid_bSlot, tvb, 5, 1, ENC_LITTLE_ENDIAN);
293 proto_tree_add_item(ccid_tree, hf_ccid_bSeq, tvb, 6, 1, ENC_LITTLE_ENDIAN);
294 proto_tree_add_item(ccid_tree, hf_ccid_bStatus, tvb, 7, 1, ENC_LITTLE_ENDIAN);
295 proto_tree_add_item(ccid_tree, hf_ccid_bError, tvb, 8, 1, ENC_LITTLE_ENDIAN);
296 proto_tree_add_item(ccid_tree, hf_ccid_bClockStatus, tvb, 9, 1, ENC_LITTLE_ENDIAN);
298 col_set_str(pinfo->cinfo, COL_INFO, "Reader to PC: Slot Status");
302 col_set_str(pinfo->cinfo, COL_INFO, "Reader to PC: Parameters");
306 col_set_str(pinfo->cinfo, COL_INFO, "Reader to PC: Escape");
309 case RDR_PC_DATA_CLOCK:
310 col_set_str(pinfo->cinfo, COL_INFO, "Reader to PC: Data Rate and Clock Frequency");
314 col_set_str(pinfo->cinfo, COL_INFO, "Unknown type");
321 proto_register_ccid(void)
323 static hf_register_info hf[] = {
325 {&hf_ccid_bMessageType,
326 { "Message Type", "ccid.bMessageType", FT_UINT8, BASE_HEX,
327 VALS(ccid_messagetypes_vals), 0x0, NULL, HFILL }},
329 { "Packet Length", "ccid.dwLength", FT_UINT8, BASE_DEC,
330 NULL, 0x0, NULL, HFILL }},
332 { "Slot", "ccid.bSlot", FT_UINT8, BASE_DEC,
333 NULL, 0x0, NULL, HFILL }},
335 { "Sequence", "ccid.bSeq", FT_UINT8, BASE_DEC,
336 NULL, 0x0, NULL, HFILL }},
338 { "Status", "ccid.bStatus", FT_UINT8, BASE_DEC,
339 NULL, 0x0, NULL, HFILL }},
341 { "Error", "ccid.bError", FT_UINT8, BASE_DEC,
342 NULL, 0x0, NULL, HFILL }},
343 {&hf_ccid_bChainParameter,
344 { "Chain Parameter", "ccid.bChainParameter", FT_UINT8, BASE_DEC,
345 NULL, 0x0, NULL, HFILL }},
346 {&hf_ccid_bPowerSelect,
347 { "Voltage Level", "ccid.bPowerSelect", FT_UINT8, BASE_HEX,
348 VALS(ccid_voltage_levels_vals), 0x0, NULL, HFILL }},
349 {&hf_ccid_bClockStatus,
350 { "Clock Status", "ccid.bClockStatus", FT_UINT8, BASE_HEX,
351 VALS(ccid_clock_states_vals), 0x0, NULL, HFILL }},
352 {&hf_ccid_bProtocolNum,
353 { "Data Structure Type", "ccid.bProtocolNum", FT_UINT8, BASE_HEX,
354 VALS(ccid_proto_structs_vals), 0x0, NULL, HFILL }},
356 { "Block Wait Time Integer", "ccid.bBWI", FT_UINT8, BASE_HEX,
357 NULL, 0x0, NULL, HFILL }},
358 {&hf_ccid_wLevelParameter,
359 { "Level Parameter", "ccid.wLevelParameter", FT_UINT8, BASE_HEX,
360 NULL, 0x0, NULL, HFILL }}
364 static gint *ett[] = {
368 proto_ccid = proto_register_protocol("USB CCID", "USBCCID", "ccid");
369 proto_register_field_array(proto_ccid, hf, array_length(hf));
370 proto_register_subtree_array(ett, array_length(ett));
372 ccid_dissector_table = register_dissector_table("ccid.payload",
373 "CCID Payload", FT_UINT8, BASE_DEC);
375 register_dissector("ccid", dissect_ccid, proto_ccid);
378 /* Handler registration */
380 proto_reg_handoff_ccid(void)
382 data_handle = find_dissector("data");
383 usb_ccid_bulk_handle = find_dissector("ccid");
384 dissector_add_uint("usb.bulk", IF_CLASS_SMART_CARD, usb_ccid_bulk_handle);
389 * Editor modelines - http://www.wireshark.org/tools/modelines.html
394 * indent-tabs-mode: nil
397 * ex: set shiftwidth=4 tabstop=8 expandtab:
398 * :indentSize=4:tabSize=8:noTabs=true: