2 * Routines for ANSI C12.22 packet dissection
3 * Copyright 2010, Edward J. Beroset, edward.j.beroset@us.elster.com
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.
31 #include <epan/conversation.h>
32 #include <wsutil/crc16.h>
33 #include <epan/expert.h>
34 #include <epan/packet.h>
35 #include <epan/prefs.h>
36 #include <epan/strutil.h>
37 #include <epan/dissectors/packet-ber.h>
38 #include <epan/dissectors/packet-tcp.h>
40 #include <epan/crypt/eax.h>
45 #include "packet-c1222.h"
47 #define PNAME "ANSI C12.22"
48 #define PSNAME "C12.22"
49 #define PFNAME "c1222"
50 #define C1222_PORT 1153 /* TCP port */
52 /* C12.22 flag definitions */
53 #define C1222_EPSEM_FLAG_RESERVED 0x80
54 #define C1222_EPSEM_FLAG_RECOVERY_SESSION 0x40
55 #define C1222_EPSEM_FLAG_PROXY_SERVICE_USED 0x20
56 #define C1222_EPSEM_FLAG_ED_CLASS_INCLUDED 0x10
57 #define C1222_EPSEM_FLAG_SECURITY_MODE 0x0c
58 #define C1222_EPSEM_FLAG_RESPONSE_CONTROL 0x03
60 /* if the packet is encrypted, it can be
61 * good, bad, or simply not checked
63 #define C1222_EPSEM_CRYPTO_GOOD 0x01
64 #define C1222_EPSEM_CRYPTO_BAD 0x02
66 /* these defines are for each of the C12.22 services */
67 #define C1222_CMD_IDENTIFY 0x20
68 #define C1222_CMD_TERMINATE 0x21
69 #define C1222_CMD_DISCONNECT 0x22
70 #define C1222_CMD_FULL_READ 0x30
71 #define C1222_CMD_DEFAULT_READ 0x3E
72 #define C1222_CMD_PARTIAL_READ_OFFSET 0x3F
73 #define C1222_CMD_FULL_WRITE 0x40
74 #define C1222_CMD_DEFAULT_WRITE 0x4E
75 #define C1222_CMD_PARTIAL_WRITE_OFFSET 0x4F
76 #define C1222_CMD_LOGON 0x50
77 #define C1222_CMD_SECURITY 0x51
78 #define C1222_CMD_LOGOFF 0x52
79 #define C1222_CMD_AUTHENTICATE 0x53
80 #define C1222_CMD_NEGOTIATE 0x60
81 #define C1222_CMD_WAIT 0x70
82 #define C1222_CMD_TIMING_SETUP 0x71
84 static dissector_handle_t c1222_handle=NULL;
86 /* Initialize the protocol and registered fields */
87 static int proto_c1222 = -1;
88 static int global_c1222_port = C1222_PORT;
89 static gboolean c1222_desegment = TRUE;
90 static gboolean c1222_decrypt = TRUE;
92 #include "packet-c1222-hf.c"
93 /* These are the EPSEM pieces */
94 /* first, the flag components */
95 static int hf_c1222_epsem_flags = -1;
96 static int hf_c1222_epsem_flags_reserved = -1;
97 static int hf_c1222_epsem_flags_recovery = -1;
98 static int hf_c1222_epsem_flags_proxy = -1;
99 static int hf_c1222_epsem_flags_ed_class = -1;
100 static int hf_c1222_epsem_flags_security_modes = -1;
101 static int hf_c1222_epsem_flags_response_control = -1;
102 /* and the structure of the flag components */
103 static const int *c1222_flags[] = {
104 &hf_c1222_epsem_flags_reserved,
105 &hf_c1222_epsem_flags_recovery,
106 &hf_c1222_epsem_flags_proxy,
107 &hf_c1222_epsem_flags_ed_class,
108 &hf_c1222_epsem_flags_security_modes,
109 &hf_c1222_epsem_flags_response_control,
112 /* next the optional ed_class */
113 static int hf_c1222_epsem_ed_class = -1;
114 /* now the aggregate epsem */
115 static int hf_c1222_epsem_total = -1;
116 /* generic command */
117 static int hf_c1222_cmd = -1;
118 static int hf_c1222_err = -1;
119 static int hf_c1222_data = -1;
120 static int hf_c1222_crc = -1;
121 /* individual epsem fields */
122 static int hf_c1222_logon_id = -1;
123 static int hf_c1222_logon_user = -1;
124 static int hf_c1222_security_password = -1;
125 static int hf_c1222_auth_len = -1;
126 static int hf_c1222_auth_data = -1;
127 static int hf_c1222_read_table = -1;
128 static int hf_c1222_read_offset = -1;
129 static int hf_c1222_read_count = -1;
130 static int hf_c1222_write_table = -1;
131 static int hf_c1222_write_offset = -1;
132 static int hf_c1222_write_size = -1;
133 static int hf_c1222_write_data = -1;
134 static int hf_c1222_write_chksum = -1;
135 static int hf_c1222_wait_secs = -1;
136 static int hf_c1222_neg_pkt_size = -1;
137 static int hf_c1222_neg_nbr_pkts = -1;
138 static int hf_c1222_timing_setup_traffic = -1;
139 static int hf_c1222_timing_setup_inter_char = -1;
140 static int hf_c1222_timing_setup_resp_to = -1;
141 static int hf_c1222_timing_setup_nbr_retries = -1;
144 static int hf_c1222_epsem_mac = -1;
146 /* crypto result flags */
147 static int hf_c1222_epsem_crypto_good = -1;
148 static int hf_c1222_epsem_crypto_bad = -1;
150 /* Initialize the subtree pointers */
151 static int ett_c1222 = -1;
152 static int ett_c1222_epsem = -1;
153 static int ett_c1222_flags = -1;
154 static int ett_c1222_crypto = -1;
155 static int ett_c1222_cmd = -1;
157 #ifdef HAVE_LIBGCRYPT
158 /* these pointers are for the header elements that may be needed to verify the crypto */
159 static guint8 *aSO_context = NULL;
160 static guint8 *called_AP_title = NULL;
161 static guint8 *called_AP_invocation_id = NULL;
162 static guint8 *calling_AE_qualifier = NULL;
163 static guint8 *calling_AP_invocation_id = NULL;
164 static guint8 *mechanism_name = NULL;
165 static guint8 *calling_authentication_value = NULL;
166 static guint8 *user_information = NULL;
167 static guint8 *calling_AP_title = NULL;
168 static guint8 *key_id_element = NULL;
169 static guint8 *iv_element = NULL;
171 /* these are the related lengths */
172 static guint32 aSO_context_len = 0;
173 static guint32 called_AP_title_len = 0;
174 static guint32 called_AP_invocation_id_len = 0;
175 static guint32 calling_AE_qualifier_len = 0;
176 static guint32 calling_AP_invocation_id_len = 0;
177 static guint32 mechanism_name_len = 0;
178 static guint32 calling_authentication_value_len = 0;
179 static guint32 user_information_len = 0;
180 static guint32 calling_AP_title_len = 0;
181 static guint32 key_id_element_len = 0;
182 static guint32 iv_element_len = 0;
183 #endif /* HAVE_LIBGCRYPT */
185 #include "packet-c1222-ett.c"
188 /*------------------------------
190 *------------------------------
192 typedef struct _c1222_uat_data {
198 static const value_string c1222_security_modes[] = {
199 { 0x00, "Cleartext"},
200 { 0x01, "Cleartext with authentication"},
201 { 0x02, "Ciphertext with authentication"},
205 static const value_string c1222_response_control[] = {
206 { 0x00, "Always respond"},
207 { 0x01, "Respond on exception"},
208 { 0x02, "Never respond"},
212 static const value_string tableflags[] = {
215 { 0x10, "Pending ST" },
216 { 0x18, "Pending MT" },
220 static const value_string procflags[] = {
226 static const value_string commandnames[] = {
227 /* error codes are in the range 0x00 - 0x1f inclusive */
230 { 0x02, "Service Not Supported" },
231 { 0x03, "Insufficient Security Clearance" },
232 { 0x04, "Operation Not Possible" },
233 { 0x05, "Inappropriate Action Requested" },
234 { 0x06, "Device Busy" },
235 { 0x07, "Data Not Ready" },
236 { 0x08, "Data Locked" },
237 { 0x09, "Renegotiate Request" },
238 { 0x0A, "Invalid Service Sequence State" },
239 { 0x0B, "Security Mechanism Error" },
240 { 0x0C, "Unknown Application Title" },
241 { 0x0D, "Network Time-out" },
242 { 0x0E, "Network Not Reachable" },
243 { 0x0F, "Request Too Large" },
244 { 0x10, "Response Too Large" },
245 { 0x11, "Segmentation Not Possible" },
246 { 0x12, "Segmentation Error" },
247 /* commands are in the range 0x20 - 0x7f inclusive */
248 {C1222_CMD_IDENTIFY, "Identify" },
249 {C1222_CMD_TERMINATE, "Terminate" },
250 {C1222_CMD_DISCONNECT, "Disconnect" },
251 {C1222_CMD_FULL_READ, "Full Read" },
252 {C1222_CMD_DEFAULT_READ, "Default Read" },
253 {C1222_CMD_PARTIAL_READ_OFFSET, "Partial Read Offset" },
254 {C1222_CMD_FULL_WRITE, "Full Write" },
255 {C1222_CMD_DEFAULT_WRITE, "Default Write" },
256 {C1222_CMD_PARTIAL_WRITE_OFFSET, "Partial Write Offset" },
257 {C1222_CMD_LOGON, "Logon" },
258 {C1222_CMD_SECURITY, "Security" },
259 {C1222_CMD_LOGOFF, "Logoff" },
260 {C1222_CMD_AUTHENTICATE, "Authenticate" },
261 {C1222_CMD_NEGOTIATE, "Negotiate" },
262 {C1222_CMD_NEGOTIATE | 0x1, "Negotiate w/ 1 Baud Rate" },
263 {C1222_CMD_NEGOTIATE | 0x2, "Negotiate w/ 2 Baud Rates" },
264 {C1222_CMD_NEGOTIATE | 0x3, "Negotiate w/ 3 Baud Rates" },
265 {C1222_CMD_NEGOTIATE | 0x4, "Negotiate w/ 4 Baud Rates" },
266 {C1222_CMD_NEGOTIATE | 0x5, "Negotiate w/ 5 Baud Rates" },
267 {C1222_CMD_NEGOTIATE | 0x6, "Negotiate w/ 6 Baud Rates" },
268 {C1222_CMD_NEGOTIATE | 0x7, "Negotiate w/ 7 Baud Rates" },
269 {C1222_CMD_NEGOTIATE | 0x8, "Negotiate w/ 8 Baud Rates" },
270 {C1222_CMD_NEGOTIATE | 0x9, "Negotiate w/ 9 Baud Rates" },
271 {C1222_CMD_NEGOTIATE | 0xA, "Negotiate w/ 10 Baud Rates" },
272 {C1222_CMD_NEGOTIATE | 0xB, "Negotiate w/ 11 Baud Rates" },
273 {C1222_CMD_WAIT, "Wait" },
274 {C1222_CMD_TIMING_SETUP, "Timing Setup" },
278 #ifdef HAVE_LIBGCRYPT
279 /* these are for the key tables */
280 UAT_HEX_CB_DEF(c1222_users, keynum, c1222_uat_data_t)
281 UAT_BUFFER_CB_DEF(c1222_users, key, c1222_uat_data_t, key, keylen)
283 static c1222_uat_data_t *c1222_uat_data = NULL;
284 static guint num_c1222_uat_data = 0;
285 static uat_t *c1222_uat;
287 /* these macros ares used to populate fields needed to verify crypto */
288 #define FILL_START int length, start_offset = offset;
289 #define FILL_TABLE(fieldname) \
290 length = offset - start_offset; \
291 fieldname = tvb_memdup(tvb, start_offset, length); \
292 fieldname##_len = length;
293 #define FILL_TABLE_TRUNCATE(fieldname, len) \
294 length = 1 + 2*(offset - start_offset); \
295 fieldname = tvb_memdup(tvb, start_offset, length); \
296 fieldname##_len = len;
297 #else /* HAVE_LIBGCRYPT */
298 #define FILL_TABLE(fieldname)
299 #define FILL_TABLE_TRUNCATE(fieldname, len)
301 #endif /* HAVE_LIBGCRYPT */
303 /*------------------------------
304 * Function Prototypes
305 *------------------------------
307 void proto_reg_handoff_c1222(void);
310 /*------------------------------
312 *------------------------------
316 * Calculates simple one's complement checksum.
318 * \param tvb pointer to tvbuff containing data to be checksummed
319 * \param offset offset within tvbuff to beginning of data
320 * \param len length of data to be checksummed
321 * \returns calculated checksum
324 c1222_cksum(tvbuff_t *tvb, gint offset, int len)
327 for (sum = 0; len; offset++, len--)
328 sum += tvb_get_guint8(tvb, offset);
332 * Dissects C12.22 packet in detail (with a tree).
334 * \param tvb input buffer containing packet to be dissected
341 parse_c1222_detailed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int cmd, guint32 *length, int *offset)
344 guint8 *user_name = NULL;
345 guint8 *password = NULL;
347 gchar *auth_req = NULL;
352 guint8 wait_seconds = 0;
356 /* timing setup parameters */
361 proto_item *item = NULL;
363 /* special case to simplify handling of Negotiate service */
364 if ((cmd & 0xF0) == C1222_CMD_NEGOTIATE) {
365 numrates = cmd & 0x0F;
366 cmd = C1222_CMD_NEGOTIATE;
368 proto_tree_add_uint(tree, cmd >= 0x20 ? hf_c1222_cmd : hf_c1222_err, tvb, *offset, 1, cmd);
372 case C1222_CMD_LOGON:
374 user_id = tvb_get_ntohs(tvb, *offset);
375 proto_tree_add_uint(tree, hf_c1222_logon_id, tvb, *offset, 2, user_id);
377 user_name = tvb_get_ephemeral_string(tvb, *offset, 10);
378 proto_tree_add_string(tree, hf_c1222_logon_user, tvb, *offset, 10, user_name);
381 proto_item_set_text(tree, "C12.22 EPSEM: %s (id %d, user \"%s\")",
382 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), user_id, user_name);
384 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 LOGON command truncated");
387 case C1222_CMD_SECURITY:
389 password = tvb_get_ephemeral_string(tvb, *offset, 20);
390 proto_tree_add_string(tree, hf_c1222_security_password, tvb, *offset, 20, password);
394 user_id = tvb_get_ntohs(tvb, *offset);
395 proto_tree_add_uint(tree, hf_c1222_logon_id, tvb, *offset, 2, user_id);
398 proto_item_set_text(tree, "C12.22 EPSEM: %s (password \"%s\", id %d)",
399 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), password, user_id);
401 proto_item_set_text(tree, "C12.22 EPSEM: %s (password \"%s\")",
402 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), password);
405 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 SECURITY command truncated");
408 case C1222_CMD_AUTHENTICATE:
410 auth_len = tvb_get_guint8(tvb, *offset);
411 proto_tree_add_uint(tree, hf_c1222_auth_len, tvb, *offset, 1, auth_len);
413 if (*length >= auth_len) {
414 auth_req = tvb_bytes_to_str(tvb, *offset, auth_len);
415 proto_tree_add_item(tree, hf_c1222_auth_data, tvb, *offset, auth_len, ENC_NA);
417 *length -= auth_len + 1;
418 proto_item_set_text(tree, "C12.22 EPSEM: %s (%d bytes: %s)",
419 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), auth_len, auth_req);
421 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 AUTHENTICATE command truncated");
424 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 AUTHENTICATE command truncated");
427 case C1222_CMD_FULL_READ:
429 table = tvb_get_ntohs(tvb, *offset);
430 proto_tree_add_uint(tree, hf_c1222_read_table, tvb, *offset, 2, table);
431 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
432 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
433 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
437 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 READ command truncated");
440 case C1222_CMD_PARTIAL_READ_OFFSET:
442 table = tvb_get_ntohs(tvb, *offset);
443 proto_tree_add_uint(tree, hf_c1222_read_table, tvb, *offset, 2, table);
446 proto_tree_add_item(tree, hf_c1222_read_offset, tvb, *offset, 3, ENC_BIG_ENDIAN);
449 proto_tree_add_item(tree, hf_c1222_read_count, tvb, *offset, 2, ENC_BIG_ENDIAN);
452 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
453 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
454 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
456 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 READ command truncated");
459 case C1222_CMD_FULL_WRITE:
461 table = tvb_get_ntohs(tvb, *offset);
462 proto_tree_add_uint(tree, hf_c1222_write_table, tvb, *offset, 2, table);
465 tblsize = tvb_get_ntohs(tvb, *offset);
466 proto_tree_add_uint(tree, hf_c1222_write_size, tvb, *offset, 2, tblsize);
469 if (*length >= tblsize+1U) {
470 proto_tree_add_item(tree, hf_c1222_write_data, tvb, *offset, tblsize, ENC_NA);
473 chksum = tvb_get_guint8(tvb, *offset);
474 item = proto_tree_add_uint(tree, hf_c1222_write_chksum, tvb, *offset, 1, chksum);
475 calcsum = c1222_cksum(tvb, (*offset)-tblsize, tblsize);
476 if (chksum != calcsum) {
477 expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Bad checksum [should be 0x%02x]", calcsum);
479 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
480 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
481 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
485 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 WRITE command truncated");
488 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 WRITE command truncated");
491 case C1222_CMD_PARTIAL_WRITE_OFFSET:
493 table = tvb_get_ntohs(tvb, *offset);
494 proto_tree_add_uint(tree, hf_c1222_write_table, tvb, *offset, 2, table);
497 proto_tree_add_item(tree, hf_c1222_write_offset, tvb, *offset, 3, ENC_BIG_ENDIAN);
500 tblsize = tvb_get_ntohs(tvb, *offset);
501 proto_tree_add_uint(tree, hf_c1222_write_size, tvb, *offset, 2, tblsize);
504 if (*length >= tblsize+1U) {
505 proto_tree_add_item(tree, hf_c1222_write_data, tvb, *offset, tblsize, ENC_NA);
508 chksum = tvb_get_guint8(tvb, *offset);
509 item = proto_tree_add_uint(tree, hf_c1222_write_chksum, tvb, *offset, 1, chksum);
510 calcsum = c1222_cksum(tvb, (*offset)-tblsize, tblsize);
511 if (chksum != calcsum) {
512 expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Bad checksum [should be 0x%02x]", calcsum);
514 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
515 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
516 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
520 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 WRITE command truncated");
523 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 WRITE command truncated");
528 wait_seconds = tvb_get_guint8(tvb, *offset);
529 proto_tree_add_uint(tree, hf_c1222_wait_secs, tvb, *offset, 1, wait_seconds);
532 proto_item_set_text(tree, "C12.22 EPSEM: %s (%d seconds)",
533 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), wait_seconds);
535 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 WAIT command truncated");
538 case C1222_CMD_NEGOTIATE:
540 packet_size = tvb_get_ntohs(tvb, *offset);
541 proto_tree_add_uint(tree, hf_c1222_neg_pkt_size, tvb, *offset, 2, packet_size);
544 nbr_packet = tvb_get_guint8(tvb, *offset);
545 proto_tree_add_uint(tree, hf_c1222_neg_nbr_pkts, tvb, *offset, 1, nbr_packet);
548 proto_item_set_text(tree, "C12.22 EPSEM: %s (pkt size %d, num pkts %d, with %d baud rates)",
549 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), packet_size, nbr_packet, numrates);
551 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 NEGOTIATE command truncated");
554 case C1222_CMD_TIMING_SETUP:
556 traffic = tvb_get_guint8(tvb, *offset);
557 proto_tree_add_uint(tree, hf_c1222_timing_setup_traffic, tvb, *offset, 1, traffic);
560 inter_char = tvb_get_guint8(tvb, *offset);
561 proto_tree_add_uint(tree, hf_c1222_timing_setup_inter_char, tvb, *offset, 1, inter_char);
564 resp_to = tvb_get_guint8(tvb, *offset);
565 proto_tree_add_uint(tree, hf_c1222_timing_setup_resp_to, tvb, *offset, 1, resp_to);
568 nbr_retries = tvb_get_guint8(tvb, *offset);
569 proto_tree_add_uint(tree, hf_c1222_timing_setup_nbr_retries, tvb, *offset, 1, nbr_retries);
572 proto_item_set_text(tree, "C12.22 EPSEM: %s (traffic to %d s, inter-char to %d s, response to %d s, %d retries)",
573 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), traffic, inter_char, resp_to, nbr_retries);
575 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 NEGOTIATE command truncated");
580 /* don't do anything */
581 proto_item_set_text(tree, "C12.22 EPSEM: %s", val_to_str(cmd, commandnames, "Unknown (0x%02x)"));
583 if (*length >= *length) {
584 proto_tree_add_item(tree, hf_c1222_data, tvb, *offset, *length, ENC_NA);
586 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 unknown command truncated");
593 #ifdef HAVE_LIBGCRYPT
594 typedef struct tagTOP_ELEMENT_CONTROL
596 /* TRUE if this tag is required */
598 /* TRUE if we must truncate this tag */
600 /* actual hex value of the tag we're seeking */
602 /* if TRUE, add tag and length before copying */
604 /* pointer to pointer to memory copy of element */
606 /* pointer to element length */
608 } TOP_ELEMENT_CONTROL;
610 static const TOP_ELEMENT_CONTROL canonifyTable[] = {
611 { FALSE, FALSE, 0xA1, TRUE, &aSO_context, &aSO_context_len },
612 { TRUE , FALSE, 0xA2, TRUE, &called_AP_title, &called_AP_title_len },
613 { FALSE, FALSE, 0xA4, TRUE, &called_AP_invocation_id, &called_AP_invocation_id_len },
614 { FALSE, FALSE, 0xA3, TRUE, &calling_AE_qualifier, &calling_AE_qualifier_len },
615 { TRUE, FALSE, 0xA8, TRUE, &calling_AP_invocation_id, &calling_AP_invocation_id_len },
616 { FALSE, FALSE, 0x8B, TRUE, &mechanism_name, &mechanism_name_len },
617 { FALSE, FALSE, 0xAC, TRUE, &calling_authentication_value, &calling_authentication_value_len },
618 { TRUE , TRUE , 0xBE, TRUE, &user_information, &user_information_len },
619 { FALSE, FALSE, 0xA6, TRUE, &calling_AP_title, &calling_AP_title_len },
620 { FALSE, FALSE, 0xAC, FALSE, &key_id_element, &key_id_element_len },
621 { FALSE, FALSE, 0xAC, FALSE, &iv_element, &iv_element_len },
622 { FALSE, FALSE, 0x0, TRUE, NULL, NULL }
626 * Calculates the size of the passed number n as encoded as a BER length field.
628 * \param n is the length value to be BER encoded
629 * \returns the sized of the encoding
632 get_ber_len_size(guint32 n)
637 if (n > 0xffff) len++;
638 if (n > 0xffffff) len++;
642 * Encodes the passed value n as a BER-encoded length at puts it in memory.
644 * \param ptr points to the buffer to be written
645 * \param n is the length to be BER encoded
646 * \maxsize is the maximum number of bytes we're allowed to write
647 * \returns length of encoded value in bytes
650 encode_ber_len(guint8 *ptr, guint32 n, int maxsize)
652 int len = get_ber_len_size(n);
653 if (len > maxsize) return 0;
657 *ptr = (len -1) | 0x80;
658 for (ptr += len-1; n; n >>= 8)
666 * Checks a new encryption table item for validity.
668 * \param n points to the new record
669 * \param err is updated to point to an error string if needed
672 c1222_uat_data_update_cb(void* n, const char** err)
674 c1222_uat_data_t* new_rec = n;
676 if (new_rec->keynum > 0xff) {
677 *err = "Invalid key number; must be less than 256";
679 if (new_rec->keylen != EAX_SIZEOF_KEY) {
680 *err = "Invalid key size; must be 16 bytes";
685 * Canonifies header fields in preparation for authenticating and/or decrypting the packet.
687 * \param buff points to the allocated canonization buffer
688 * \param offset points to start of unallocated space in buffer and
689 is updated as we put bytes into buffer
690 * \param buffsize total size of allocated buffer
691 * \return FALSE if element is required and not present; otherwise TRUE
694 canonify_unencrypted_header(guchar *buff, guint32 *offset, guint32 buffsize)
696 const TOP_ELEMENT_CONTROL *t = canonifyTable;
699 for (t = canonifyTable; t->element != NULL; t++)
702 if (t->required && *(t->element) == NULL)
704 if (*(t->element) != NULL) {
706 /* recreate original tag and length */
707 buff[(*offset)++] = t->tag;
708 (*offset) += encode_ber_len(&buff[*offset], len, 4);
711 len = 3+2*get_ber_len_size(len);
713 /* bail out if the cannonization buffer is too small */
714 /* this should never happen! */
715 if (buffsize < *offset + len) {
718 memcpy(&buff[*offset], *(t->element), len);
720 g_free(*(t->element));
721 *(t->element) = NULL;
728 * Looks up the required key in the key table.
730 * \param keybuf is updated with a copy of the key data if successful lookup.
731 * \param keyid is the ID number of the desired key
732 * \returns TRUE if key was found; otherwise FALSE
735 keylookup(guint8 *keybuff, guint8 keyid)
739 if (c1222_uat_data == NULL)
741 for (i = 0; i < num_c1222_uat_data; i++) {
742 if (c1222_uat_data[i].keynum == keyid) {
743 memcpy(keybuff, c1222_uat_data[i].key, EAX_SIZEOF_KEY);
749 #endif /* HAVE_LIBGCRYPT */
752 * Authenticates and decrypts the passed packet.
754 * \param buffer points to a memory copy of the packet to be authenticated/decrypted
755 * and contains the decrypted value on successful return.
756 * \param length lenth of input packet
757 * \param decrypt TRUE if packet is to be authenticated and decrypted; FALSE if authentication only is requested
758 * \returns TRUE if the requested operation was successful; otherwise FALSE
760 #ifdef HAVE_LIBGCRYPT
762 decrypt_packet(guchar *buffer, guint32 length, gboolean decrypt)
764 #define CANONBUFFSIZE 300U
765 guchar canonbuff[CANONBUFFSIZE];
766 guint8 c1222_key[EAX_SIZEOF_KEY];
769 gboolean status = FALSE;
771 /* must be at least 4 bytes long to include the MAC */
774 if (key_id_element != NULL)
775 key_id = key_id_element[0];
776 /* extract unencrypted header information */
777 if (!canonify_unencrypted_header(canonbuff, &offset, CANONBUFFSIZE))
779 /* decrypt and authenticate in place */
780 /* PARAMETERS: pN : Pointer to ClearText (Input, Canonified form). */
781 /* pK : Pointer to secret key (Input). */
782 /* pC : Pointer to CipherText (Input/Output). */
783 /* SizeN : Byte length of ClearText buffer. */
784 /* SizeK : Byte length of secret key. */
785 /* SizeC : Byte length of CipherText buffer. */
786 /* pMac : Four byte Message Authentication Code. */
787 /* Mode : Operating mode (See EAX_MODE_xxx). */
788 /* RETURNS: TRUE if message has been authenticated. */
789 /* FALSE if not authenticated, invalid Mode, or error. */
791 if (!keylookup((guint8 *)&c1222_key, key_id))
793 status = Eax_Decrypt(canonbuff, c1222_key, buffer,
794 offset, EAX_SIZEOF_KEY, length-4,
795 (MAC_T *)&buffer[length-4],
796 decrypt ? EAX_MODE_CIPHERTEXT_AUTH : EAX_MODE_CLEARTEXT_AUTH);
800 #else /* HAVE_LIBCRYPT */
802 decrypt_packet(guchar *buffer _U_, guint32 length _U_, gboolean decrypt _U_)
806 #endif /* HAVE_LIBGCRYPT */
809 * Checks to make sure that a complete, valid BER-encoded length is in the buffer.
811 * \param tvb contains the buffer to be examined
812 * \param offset is the offset within the buffer at which the BER-encded length begins
813 * \returns TRUE if a complete, valid BER-encoded length is in the buffer; otherwise FALSE
816 ber_len_ok(tvbuff_t *tvb, int offset)
820 if (tvb_offset_exists(tvb, offset)) {
821 ch = tvb_get_guint8(tvb, offset);
825 } else if (tvb_offset_exists(tvb, offset)) {
826 ch = tvb_get_guint8(tvb, offset);
830 } else if (tvb_offset_exists(tvb, offset)) {
831 ch = tvb_get_guint8(tvb, offset);
835 } else if (tvb_offset_exists(tvb, offset)) {
836 ch = tvb_get_guint8(tvb, offset);
849 * Dissects the EPSEM portion of the User-information part of a C12.22 message.
858 dissect_epsem(tvbuff_t *tvb, int offset, guint32 len, packet_info *pinfo, proto_tree *tree)
860 proto_tree *cmd_tree = NULL;
861 proto_tree *ct = NULL;
862 proto_tree *crypto_tree = NULL;
863 proto_tree *yt = NULL;
864 proto_item *item = NULL;
871 tvbuff_t *epsem_buffer = NULL;
872 gboolean crypto_good = FALSE;
873 gboolean crypto_bad = FALSE;
874 gboolean hasmac = FALSE;
875 gboolean encrypted = FALSE;
877 if ((tvb == NULL) && (len == 0)) {
878 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 EPSEM missing");
881 /* parse the flags byte which is always unencrypted */
882 flags = tvb_get_guint8(tvb, offset);
883 proto_tree_add_bitmask(tree, tvb, offset, hf_c1222_epsem_flags, ett_c1222_flags, c1222_flags, ENC_BIG_ENDIAN);
885 switch ((flags & C1222_EPSEM_FLAG_SECURITY_MODE) >> 2) {
886 case EAX_MODE_CIPHERTEXT_AUTH:
887 /* mode is ciphertext with authentication */
889 len2 = tvb_length_remaining(tvb, offset);
894 buffer = tvb_memdup(tvb, offset, len2);
895 if (!decrypt_packet(buffer, len2, TRUE)) {
899 epsem_buffer = tvb_new_real_data(buffer, len2, len2);
900 tvb_set_child_real_data_tvbuff(tvb, epsem_buffer);
901 add_new_data_source(pinfo, epsem_buffer, "Decrypted EPSEM Data");
907 case EAX_MODE_CLEARTEXT_AUTH:
908 /* mode is cleartext with authentication */
910 len2 = tvb_length_remaining(tvb, offset);
913 buffer = tvb_memdup(tvb, offset, len2);
914 epsem_buffer = tvb_new_subset(tvb, offset, -1, -1);
916 if (!decrypt_packet(buffer, len2, FALSE)) {
917 #ifdef HAVE_LIBGCRYPT
919 expert_add_info_format(pinfo, tree, PI_SECURITY, PI_ERROR, "C12.22 EPSEM failed authentication");
920 #else /* HAVE_LIBGCRYPT */
921 expert_add_info_format(pinfo, tree, PI_SECURITY, PI_WARN, "C12.22 EPSEM could not be authenticated");
922 #endif /* HAVE_LIBGCRYPT */
929 /* it's not encrypted */
930 epsem_buffer = tvb_new_subset(tvb, offset, -1, -1);
932 /* it's only encrypted if we have an undecrypted payload */
934 proto_tree_add_item(tree, hf_c1222_epsem_total, tvb, offset, -1, ENC_NA);
935 expert_add_info_format(pinfo, tree, PI_UNDECODED, PI_WARN, "C12.22 EPSEM could not be decrypted");
936 local_offset = offset+len2-4;
938 } else { /* it's not (now) encrypted */
940 /* retrieve the ed_class if it's there */
941 if (flags & C1222_EPSEM_FLAG_ED_CLASS_INCLUDED) {
942 if (tvb_offset_exists(epsem_buffer, local_offset+4-1)) {
943 proto_tree_add_item(tree, hf_c1222_epsem_ed_class, epsem_buffer, local_offset, 4, ENC_NA);
946 expert_add_info_format(pinfo, tree, PI_SECURITY, PI_ERROR, "C12.22 ED Class missing");
949 /* what follows are one or more <epsem-data> elements possibly followed by
950 * a <mac>. Each <epsem-data> element is defined as <service-length><res-req>,
951 * so we fetch such pairs until there isn't anything left (except possibly
954 while (tvb_offset_exists(epsem_buffer, local_offset+(hasmac?5:1))) {
955 if (ber_len_ok(epsem_buffer, local_offset)) {
956 local_offset = dissect_ber_length(pinfo, tree, epsem_buffer, local_offset, &len2, &ind);
958 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 EPSEM BER length error");
961 if (tvb_offset_exists(epsem_buffer, local_offset+len2-1)) {
962 cmd_err = tvb_get_guint8(epsem_buffer, local_offset);
963 ct = proto_tree_add_item(tree, hf_c1222_epsem_total, epsem_buffer, local_offset, len2, ENC_NA);
964 cmd_tree = proto_item_add_subtree(ct, ett_c1222_cmd);
965 parse_c1222_detailed(epsem_buffer, pinfo, cmd_tree, cmd_err, &len2, &local_offset);
966 local_offset += len2;
968 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 EPSEM field length error");
974 if (tvb_offset_exists(epsem_buffer, local_offset+4-1)) {
975 yt = proto_tree_add_item(tree, hf_c1222_epsem_mac, epsem_buffer, local_offset, 4, ENC_NA);
976 /* now we have enough information to fill in the crypto subtree */
977 crypto_tree = proto_item_add_subtree(yt, ett_c1222_crypto);
978 item = proto_tree_add_boolean(crypto_tree, hf_c1222_epsem_crypto_good, tvb, local_offset, 4, crypto_good);
979 PROTO_ITEM_SET_GENERATED(item);
980 item = proto_tree_add_boolean(crypto_tree, hf_c1222_epsem_crypto_bad, tvb, local_offset, 4, crypto_bad);
981 PROTO_ITEM_SET_GENERATED(item);
983 expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, "C12.22 MAC missing");
990 #include "packet-c1222-fn.c"
993 * Dissects a a full (reassembled) C12.22 message.
1000 dissect_c1222_full(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1002 proto_item *c1222_item = NULL;
1003 proto_tree *c1222_tree = NULL;
1005 /* make entry in the Protocol column on summary display */
1006 col_set_str(pinfo->cinfo, COL_PROTOCOL, PNAME);
1008 /* create the c1222 protocol tree */
1010 c1222_item = proto_tree_add_item(tree, proto_c1222, tvb, 0, -1, ENC_NA);
1011 c1222_tree = proto_item_add_subtree(c1222_item, ett_c1222);
1012 dissect_C1222_MESSAGE_PDU(tvb, pinfo, c1222_tree);
1017 * Fetches the length of an entire C12.22 message to assist in reassembly.
1022 * \returns length of entire C12.22 message
1025 get_c1222_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
1031 orig_offset = offset;
1032 /* note that this assumes a Tag length of 1 which is always valid for C12.22 */
1033 offset = dissect_ber_length(pinfo, NULL, tvb, offset+1, &length, &ind);
1034 return length+(offset - orig_offset);
1038 * Reassembles and dissects C12.22 messages.
1045 dissect_c1222(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1047 tcp_dissect_pdus(tvb, pinfo, tree, c1222_desegment, 5,
1048 get_c1222_message_len, dissect_c1222_full);
1051 /*--- proto_register_c1222 -------------------------------------------*/
1052 void proto_register_c1222(void) {
1054 /* List of fields */
1055 static hf_register_info hf[] = {
1056 { &hf_c1222_epsem_flags,
1057 { "C12.22 EPSEM Flags", "c1222.epsem.flags",
1062 { &hf_c1222_epsem_flags_reserved,
1063 { "C12.22 Reserved Flag", "c1222.epsem.flags.reserved",
1065 NULL, C1222_EPSEM_FLAG_RESERVED,
1068 { &hf_c1222_epsem_flags_recovery,
1069 { "C12.22 Recovery Flag", "c1222.epsem.flags.recovery",
1071 NULL, C1222_EPSEM_FLAG_RECOVERY_SESSION,
1074 { &hf_c1222_epsem_flags_proxy,
1075 { "C12.22 Proxy Service Used Flag", "c1222.epsem.flags.proxy",
1077 NULL, C1222_EPSEM_FLAG_PROXY_SERVICE_USED,
1080 { &hf_c1222_epsem_flags_ed_class,
1081 { "C12.22 ED Class Flag", "c1222.epsem.flags.ed_class",
1083 NULL, C1222_EPSEM_FLAG_ED_CLASS_INCLUDED,
1086 { &hf_c1222_epsem_flags_security_modes,
1087 { "C12.22 Security Mode Flags", "c1222.epsem.flags.security",
1089 VALS(c1222_security_modes), C1222_EPSEM_FLAG_SECURITY_MODE,
1092 { &hf_c1222_epsem_flags_response_control,
1093 { "C12.22 Response Control Flags", "c1222.epsem.flags.response_control",
1095 VALS(c1222_response_control), C1222_EPSEM_FLAG_RESPONSE_CONTROL,
1098 { &hf_c1222_epsem_ed_class,
1099 { "C12.22 EPSEM ED Class", "c1222.epsem.edclass",
1100 FT_BYTES, BASE_NONE,
1104 { &hf_c1222_epsem_total,
1105 { "C12.22 EPSEM", "c1222.epsem.data",
1106 FT_BYTES, BASE_NONE,
1110 { &hf_c1222_epsem_mac,
1111 { "C12.22 EPSEM MAC", "c1222.epsem.mac",
1112 FT_BYTES, BASE_NONE,
1117 { "C12.22 Command", "c1222.cmd",
1119 VALS(commandnames), 0x0,
1123 { "C12.22 Response", "c1222.err",
1125 VALS(commandnames), 0x0,
1128 { &hf_c1222_logon_id,
1129 { "C12.22 Logon User-Id", "c1222.logon.id",
1130 FT_UINT16, BASE_DEC,
1134 { &hf_c1222_logon_user,
1135 { "C12.22 Logon User", "c1222.logon.user",
1136 FT_STRING, BASE_NONE,
1140 { &hf_c1222_security_password,
1141 { "C12.22 Security Password", "c1222.security.password",
1142 FT_STRING, BASE_NONE,
1146 { &hf_c1222_auth_len,
1147 { "C12.22 Authenticate Request Length", "c1222.authenticate.len",
1152 { &hf_c1222_auth_data,
1153 { "C12.22 Authenticate Data", "c1222.authenticate.data",
1154 FT_BYTES, BASE_NONE,
1158 { &hf_c1222_read_table,
1159 { "C12.22 Table", "c1222.read.table",
1160 FT_UINT16, BASE_HEX,
1164 { &hf_c1222_read_offset,
1165 { "C12.22 Offset", "c1222.read.offset",
1166 FT_UINT24, BASE_HEX,
1170 { &hf_c1222_read_count,
1171 { "C12.22 Count", "c1222.read.count",
1172 FT_UINT16, BASE_DEC,
1176 { &hf_c1222_write_table,
1177 { "C12.22 Table", "c1222.write.table",
1178 FT_UINT16, BASE_HEX,
1182 { &hf_c1222_write_offset,
1183 { "C12.22 Offset", "c1222.write.offset",
1184 FT_UINT24, BASE_HEX,
1188 { &hf_c1222_write_size,
1189 { "C12.22 Table Size", "c1222.write.size",
1190 FT_UINT16, BASE_HEX,
1194 { &hf_c1222_write_data,
1195 { "C12.22 Table Data", "c1222.write.data",
1196 FT_BYTES, BASE_NONE,
1200 { &hf_c1222_write_chksum,
1201 { "C12.22 Table Data Checksum", "c1222.write.chksum",
1206 { &hf_c1222_neg_pkt_size,
1207 { "C12.22 Negotiate Packet Size", "c1222.negotiate.pktsize",
1208 FT_UINT16, BASE_DEC,
1212 { &hf_c1222_neg_nbr_pkts,
1213 { "C12.22 Negotiate Number of Packets", "c1222.negotiate.numpkts",
1218 { &hf_c1222_wait_secs,
1219 { "C12.22 Wait Seconds", "c1222.wait.seconds",
1224 { &hf_c1222_timing_setup_traffic,
1225 { "C12.22 Timing Setup Channel Traffic Timeout", "c1222.timingsetup.traffic",
1230 { &hf_c1222_timing_setup_inter_char,
1231 { "C12.22 Timing Setup Intercharacter Timeout", "c1222.timingsetup.interchar",
1236 { &hf_c1222_timing_setup_resp_to,
1237 { "C12.22 Timing Setup Response Timeout", "c1222.timingsetup.respto",
1242 { &hf_c1222_timing_setup_nbr_retries,
1243 { "C12.22 Timing Setup Number of Retries", "c1222.timingsetup.nbrretries",
1249 { "C12.22 data", "c1222.data",
1250 FT_BYTES, BASE_NONE,
1255 { "C12.22 CRC", "c1222.crc",
1256 FT_UINT16, BASE_HEX,
1260 { &hf_c1222_epsem_crypto_good,
1261 { "Crypto good", "c1222.crypto_good",
1262 FT_BOOLEAN, BASE_NONE,
1264 "True: crypto ok; False: doesn't match or not checked", HFILL }
1266 { &hf_c1222_epsem_crypto_bad,
1267 { "Crypto bad", "c1222.crypto_bad",
1268 FT_BOOLEAN, BASE_NONE,
1270 "True: crypto bad; False: crypto ok or not checked", HFILL }
1272 #include "packet-c1222-hfarr.c"
1275 /* List of subtrees */
1276 static gint *ett[] = {
1282 #include "packet-c1222-ettarr.c"
1285 module_t *c1222_module;
1287 #ifdef HAVE_LIBGCRYPT
1288 static uat_field_t c1222_uat_flds[] = {
1289 UAT_FLD_HEX(c1222_users,keynum,"Key ID","Key identifier in hexadecimal"),
1290 UAT_FLD_BUFFER(c1222_users, key, "Key", "Encryption key as 16-byte hex string"),
1293 #endif /* HAVE_LIBGCRYPT */
1295 /* Register protocol */
1296 proto_c1222 = proto_register_protocol(PNAME, PSNAME, PFNAME);
1297 /* Register fields and subtrees */
1298 proto_register_field_array(proto_c1222, hf, array_length(hf));
1299 proto_register_subtree_array(ett, array_length(ett));
1300 c1222_module = prefs_register_protocol(proto_c1222, proto_reg_handoff_c1222);
1301 prefs_register_bool_preference(c1222_module, "desegment",
1302 "Reassemble all C12.22 messages spanning multiple TCP segments",
1303 "Whether the C12.22 dissector should reassemble all messages spanning multiple TCP segments",
1305 #ifdef HAVE_LIBGCRYPT
1306 prefs_register_bool_preference(c1222_module, "decrypt",
1307 "Verify crypto for all applicable C12.22 messages",
1308 "Whether the C12.22 dissector should verify the crypto for all relevant messages",
1311 c1222_uat = uat_new("Decryption Table",
1312 sizeof(c1222_uat_data_t), /* record size */
1313 "c1222_decryption_table", /* filename */
1314 TRUE, /* from_profile */
1315 (void*)&c1222_uat_data, /* data_ptr */
1316 &num_c1222_uat_data, /* numitems_ptr */
1317 UAT_CAT_CRYPTO, /* category */
1319 NULL, /* copy callback */
1320 c1222_uat_data_update_cb, /* update callback */
1321 NULL, /* free callback */
1322 NULL, /* post update callback */
1323 c1222_uat_flds); /* UAT field definitions */
1325 prefs_register_uat_preference(c1222_module,
1328 "Table of security parameters for decryption of C12.22 packets",
1330 #endif /* HAVE_LIBGCRYPT */
1333 /*--- proto_reg_handoff_c1222 ---------------------------------------*/
1335 proto_reg_handoff_c1222(void)
1337 static gboolean initialized = FALSE;
1339 if( !initialized ) {
1340 c1222_handle = create_dissector_handle(dissect_c1222, proto_c1222);
1341 dissector_add_uint("tcp.port", global_c1222_port, c1222_handle);