Convert ASN.1 dissectors to use filterable expert info.
[metze/wireshark/wip.git] / asn1 / c1222 / packet-c1222-template.c
1 /* packet-c1222.c
2  * Routines for ANSI C12.22 packet dissection
3  * Copyright 2010, Edward J. Beroset, edward.j.beroset@us.elster.com
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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.
24  */
25
26 #include "config.h"
27
28 #include <glib.h>
29 #include <epan/conversation.h>
30 #include <epan/expert.h>
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
33 #include <epan/strutil.h>
34 #include <epan/dissectors/packet-ber.h>
35 #include <epan/dissectors/packet-tcp.h>
36 #include <epan/uat.h>
37 #include <epan/crypt/eax.h>
38
39 #include <stdio.h>
40 #include <string.h>
41
42 #include "packet-c1222.h"
43
44 #define PNAME  "ANSI C12.22"
45 #define PSNAME "C12.22"
46 #define PFNAME "c1222"
47 #define C1222_PORT 1153    /* TCP port */
48
49 /* C12.22 flag definitions */
50 #define C1222_EPSEM_FLAG_RESERVED 0x80
51 #define C1222_EPSEM_FLAG_RECOVERY_SESSION 0x40
52 #define C1222_EPSEM_FLAG_PROXY_SERVICE_USED 0x20
53 #define C1222_EPSEM_FLAG_ED_CLASS_INCLUDED 0x10
54 #define C1222_EPSEM_FLAG_SECURITY_MODE 0x0c
55 #define C1222_EPSEM_FLAG_RESPONSE_CONTROL 0x03
56
57 /* if the packet is encrypted, it can be
58  * good, bad, or simply not checked
59  */
60 #define C1222_EPSEM_CRYPTO_GOOD 0x01
61 #define C1222_EPSEM_CRYPTO_BAD 0x02
62
63 /* these defines are for each of the C12.22 services */
64 #define C1222_CMD_IDENTIFY 0x20
65 #define C1222_CMD_TERMINATE 0x21
66 #define C1222_CMD_DISCONNECT 0x22
67 #define C1222_CMD_FULL_READ 0x30
68 #define C1222_CMD_DEFAULT_READ 0x3E
69 #define C1222_CMD_PARTIAL_READ_OFFSET 0x3F
70 #define C1222_CMD_FULL_WRITE 0x40
71 #define C1222_CMD_DEFAULT_WRITE 0x4E
72 #define C1222_CMD_PARTIAL_WRITE_OFFSET 0x4F
73 #define C1222_CMD_LOGON 0x50
74 #define C1222_CMD_SECURITY 0x51
75 #define C1222_CMD_LOGOFF 0x52
76 #define C1222_CMD_AUTHENTICATE 0x53
77 #define C1222_CMD_NEGOTIATE 0x60
78 #define C1222_CMD_WAIT 0x70
79 #define C1222_CMD_TIMING_SETUP 0x71
80
81 static dissector_handle_t c1222_handle=NULL;
82 static dissector_handle_t c1222_udp_handle=NULL;
83
84 /* Initialize the protocol and registered fields */
85 static int proto_c1222 = -1;
86 static int global_c1222_port = C1222_PORT;
87 static gboolean c1222_desegment = TRUE;
88 static gboolean c1222_decrypt = TRUE;
89
90 #include "packet-c1222-hf.c"
91 /* These are the EPSEM pieces */
92 /* first, the flag components */
93 static int hf_c1222_epsem_flags = -1;
94 static int hf_c1222_epsem_flags_reserved = -1;
95 static int hf_c1222_epsem_flags_recovery = -1;
96 static int hf_c1222_epsem_flags_proxy = -1;
97 static int hf_c1222_epsem_flags_ed_class = -1;
98 static int hf_c1222_epsem_flags_security_modes = -1;
99 static int hf_c1222_epsem_flags_response_control = -1;
100 /* and the structure of the flag components */
101 static const int *c1222_flags[] = {
102   &hf_c1222_epsem_flags_reserved,
103   &hf_c1222_epsem_flags_recovery,
104   &hf_c1222_epsem_flags_proxy,
105   &hf_c1222_epsem_flags_ed_class,
106   &hf_c1222_epsem_flags_security_modes,
107   &hf_c1222_epsem_flags_response_control,
108   NULL
109 };
110 /* next the optional ed_class */
111 static int hf_c1222_epsem_ed_class = -1;
112 /* now the aggregate epsem */
113 static int hf_c1222_epsem_total = -1;
114 /* generic command */
115 static int hf_c1222_cmd = -1;
116 static int hf_c1222_err = -1;
117 static int hf_c1222_data = -1;
118 /* individual epsem fields */
119 static int hf_c1222_logon_id = -1;
120 static int hf_c1222_logon_user = -1;
121 static int hf_c1222_security_password = -1;
122 static int hf_c1222_auth_len = -1;
123 static int hf_c1222_auth_data = -1;
124 static int hf_c1222_read_table = -1;
125 static int hf_c1222_read_offset = -1;
126 static int hf_c1222_read_count = -1;
127 static int hf_c1222_write_table = -1;
128 static int hf_c1222_write_offset = -1;
129 static int hf_c1222_write_size = -1;
130 static int hf_c1222_write_data = -1;
131 static int hf_c1222_write_chksum = -1;
132 static int hf_c1222_wait_secs = -1;
133 static int hf_c1222_neg_pkt_size = -1;
134 static int hf_c1222_neg_nbr_pkts = -1;
135 static int hf_c1222_timing_setup_traffic = -1;
136 static int hf_c1222_timing_setup_inter_char = -1;
137 static int hf_c1222_timing_setup_resp_to = -1;
138 static int hf_c1222_timing_setup_nbr_retries = -1;
139
140 /* the MAC */
141 static int hf_c1222_epsem_mac = -1;
142
143 /* crypto result flags */
144 static int hf_c1222_epsem_crypto_good = -1;
145 static int hf_c1222_epsem_crypto_bad = -1;
146
147 /* Initialize the subtree pointers */
148 static int ett_c1222 = -1;
149 static int ett_c1222_epsem = -1;
150 static int ett_c1222_flags = -1;
151 static int ett_c1222_crypto = -1;
152 static int ett_c1222_cmd = -1;
153
154 #ifdef HAVE_LIBGCRYPT
155 /* these pointers are for the header elements that may be needed to verify the crypto */
156 static guint8 *aSO_context = NULL;
157 static guint8 *called_AP_title = NULL;
158 static guint8 *called_AP_invocation_id = NULL;
159 static guint8 *calling_AE_qualifier = NULL;
160 static guint8 *calling_AP_invocation_id = NULL;
161 static guint8 *mechanism_name = NULL;
162 static guint8 *calling_authentication_value = NULL;
163 static guint8 *user_information = NULL;
164 static guint8 *calling_AP_title = NULL;
165 static guint8 *key_id_element = NULL;
166 static guint8 *iv_element = NULL;
167
168 /* these are the related lengths */
169 static guint32 aSO_context_len = 0;
170 static guint32 called_AP_title_len = 0;
171 static guint32 called_AP_invocation_id_len = 0;
172 static guint32 calling_AE_qualifier_len = 0;
173 static guint32 calling_AP_invocation_id_len = 0;
174 static guint32 mechanism_name_len = 0;
175 static guint32 calling_authentication_value_len = 0;
176 static guint32 user_information_len = 0;
177 static guint32 calling_AP_title_len = 0;
178 static guint32 key_id_element_len = 0;
179 static guint32 iv_element_len = 0;
180 #endif /* HAVE_LIBGCRYPT */
181
182 #include "packet-c1222-ett.c"
183
184 static expert_field ei_c1222_command_truncated = EI_INIT;
185 static expert_field ei_c1222_bad_checksum = EI_INIT;
186 static expert_field ei_c1222_epsem_missing = EI_INIT;
187 #ifdef HAVE_LIBGCRYPT
188 static expert_field ei_c1222_epsem_failed_authentication = EI_INIT;
189 #else
190 static expert_field ei_c1222_epsem_not_authenticated = EI_INIT;
191 #endif
192 static expert_field ei_c1222_epsem_not_decryped = EI_INIT;
193 static expert_field ei_c1222_ed_class_missing = EI_INIT;
194 static expert_field ei_c1222_epsem_ber_length_error = EI_INIT;
195 static expert_field ei_c1222_epsem_field_length_error = EI_INIT;
196 static expert_field ei_c1222_mac_missing = EI_INIT;
197
198 /*------------------------------
199  * Data Structures
200  *------------------------------
201  */
202 typedef struct _c1222_uat_data {
203   guint keynum;
204   guchar *key;
205   guint  keylen;
206 } c1222_uat_data_t;
207
208 static const value_string c1222_security_modes[] = {
209   { 0x00, "Cleartext"},
210   { 0x01, "Cleartext with authentication"},
211   { 0x02, "Ciphertext with authentication"},
212   { 0, NULL }
213 };
214
215 static const value_string c1222_response_control[] = {
216   { 0x00, "Always respond"},
217   { 0x01, "Respond on exception"},
218   { 0x02, "Never respond"},
219   { 0, NULL }
220 };
221
222 static const value_string tableflags[] = {
223   { 0x00, "ST" },
224   { 0x08, "MT" },
225   { 0x10, "Pending ST" },
226   { 0x18, "Pending MT" },
227   { 0, NULL }
228 };
229
230 static const value_string procflags[] = {
231   { 0x00, "SF" },
232   { 0x01, "MF" },
233   { 0, NULL }
234 };
235
236 static const value_string commandnames[] = {
237 /* error codes are in the range 0x00 - 0x1f inclusive */
238   { 0x00, "OK" },
239   { 0x01, "Error" },
240   { 0x02, "Service Not Supported" },
241   { 0x03, "Insufficient Security Clearance" },
242   { 0x04, "Operation Not Possible" },
243   { 0x05, "Inappropriate Action Requested" },
244   { 0x06, "Device Busy" },
245   { 0x07, "Data Not Ready" },
246   { 0x08, "Data Locked" },
247   { 0x09, "Renegotiate Request" },
248   { 0x0A, "Invalid Service Sequence State" },
249   { 0x0B, "Security Mechanism Error" },
250   { 0x0C, "Unknown Application Title" },
251   { 0x0D, "Network Time-out" },
252   { 0x0E, "Network Not Reachable" },
253   { 0x0F, "Request Too Large" },
254   { 0x10, "Response Too Large" },
255   { 0x11, "Segmentation Not Possible" },
256   { 0x12, "Segmentation Error" },
257 /* commands are in the range 0x20 - 0x7f inclusive */
258   {C1222_CMD_IDENTIFY, "Identify" },
259   {C1222_CMD_TERMINATE, "Terminate" },
260   {C1222_CMD_DISCONNECT, "Disconnect" },
261   {C1222_CMD_FULL_READ, "Full Read" },
262   {C1222_CMD_DEFAULT_READ, "Default Read" },
263   {C1222_CMD_PARTIAL_READ_OFFSET, "Partial Read Offset" },
264   {C1222_CMD_FULL_WRITE, "Full Write" },
265   {C1222_CMD_DEFAULT_WRITE, "Default Write" },
266   {C1222_CMD_PARTIAL_WRITE_OFFSET, "Partial Write Offset" },
267   {C1222_CMD_LOGON, "Logon" },
268   {C1222_CMD_SECURITY, "Security" },
269   {C1222_CMD_LOGOFF, "Logoff" },
270   {C1222_CMD_AUTHENTICATE, "Authenticate" },
271   {C1222_CMD_NEGOTIATE, "Negotiate" },
272   {C1222_CMD_NEGOTIATE | 0x1, "Negotiate w/ 1 Baud Rate" },
273   {C1222_CMD_NEGOTIATE | 0x2, "Negotiate w/ 2 Baud Rates" },
274   {C1222_CMD_NEGOTIATE | 0x3, "Negotiate w/ 3 Baud Rates" },
275   {C1222_CMD_NEGOTIATE | 0x4, "Negotiate w/ 4 Baud Rates" },
276   {C1222_CMD_NEGOTIATE | 0x5, "Negotiate w/ 5 Baud Rates" },
277   {C1222_CMD_NEGOTIATE | 0x6, "Negotiate w/ 6 Baud Rates" },
278   {C1222_CMD_NEGOTIATE | 0x7, "Negotiate w/ 7 Baud Rates" },
279   {C1222_CMD_NEGOTIATE | 0x8, "Negotiate w/ 8 Baud Rates" },
280   {C1222_CMD_NEGOTIATE | 0x9, "Negotiate w/ 9 Baud Rates" },
281   {C1222_CMD_NEGOTIATE | 0xA, "Negotiate w/ 10 Baud Rates" },
282   {C1222_CMD_NEGOTIATE | 0xB, "Negotiate w/ 11 Baud Rates" },
283   {C1222_CMD_WAIT, "Wait" },
284   {C1222_CMD_TIMING_SETUP, "Timing Setup" },
285   { 0, NULL }
286 };
287
288 #ifdef HAVE_LIBGCRYPT
289 /* these are for the key tables */
290 UAT_HEX_CB_DEF(c1222_users, keynum, c1222_uat_data_t)
291 UAT_BUFFER_CB_DEF(c1222_users, key, c1222_uat_data_t, key, keylen)
292
293 static c1222_uat_data_t *c1222_uat_data = NULL;
294 static guint num_c1222_uat_data = 0;
295 static uat_t *c1222_uat;
296
297 /* these macros ares used to populate fields needed to verify crypto */
298 #define FILL_START int length, start_offset = offset;
299 #define FILL_TABLE(fieldname)  \
300   length = offset - start_offset; \
301   fieldname = (guint8 *)tvb_memdup(tvb, start_offset, length); \
302   fieldname##_len = length;
303 #define FILL_TABLE_TRUNCATE(fieldname, len)  \
304   length = 1 + 2*(offset - start_offset); \
305   fieldname = (guint8 *)tvb_memdup(tvb, start_offset, length); \
306   fieldname##_len = len;
307 #else /* HAVE_LIBGCRYPT */
308 #define FILL_TABLE(fieldname)
309 #define FILL_TABLE_TRUNCATE(fieldname, len)
310 #define FILL_START
311 #endif /* HAVE_LIBGCRYPT */
312
313 /*------------------------------
314  * Function Prototypes
315  *------------------------------
316  */
317 void proto_reg_handoff_c1222(void);
318
319
320 /*------------------------------
321  * Code
322  *------------------------------
323  */
324
325 /**
326  * Calculates simple one's complement checksum.
327  *
328  * \param tvb pointer to tvbuff containing data to be checksummed
329  * \param offset offset within tvbuff to beginning of data
330  * \param len length of data to be checksummed
331  * \returns calculated checksum
332  */
333 static guint8
334 c1222_cksum(tvbuff_t *tvb, gint offset, int len)
335 {
336   guint8 sum;
337   for (sum = 0; len; offset++, len--)
338     sum += tvb_get_guint8(tvb, offset);
339   return ~sum + 1;
340 }
341 /**
342  * Dissects C12.22 packet in detail (with a tree).
343  *
344  * \param tvb input buffer containing packet to be dissected
345  * \param pinfo
346  * \param tree
347  * \param length
348  * \param offset
349  */
350 static void
351 parse_c1222_detailed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int cmd, guint32 *length, int *offset)
352 {
353   guint16 user_id = 0;
354   guint8 *user_name = NULL;
355   guint8 *password = NULL;
356   guint8 auth_len = 0;
357   gchar *auth_req = NULL;
358   guint16 table = 0;
359   guint16 tblsize = 0;
360   guint8 chksum = 0;
361   guint16 calcsum = 0;
362   guint8 wait_seconds = 0;
363   int numrates = 0;
364   guint16 packet_size;
365   guint8 nbr_packet;
366   /* timing setup parameters */
367   guint8 traffic;
368   guint8 inter_char;
369   guint8 resp_to;
370   guint8 nbr_retries;
371   proto_item *item = NULL;
372
373   /* special case to simplify handling of Negotiate service */
374   if ((cmd & 0xF0) == C1222_CMD_NEGOTIATE) {
375     numrates = cmd & 0x0F;
376     cmd = C1222_CMD_NEGOTIATE;
377   }
378   proto_tree_add_uint(tree, cmd >= 0x20 ? hf_c1222_cmd : hf_c1222_err, tvb, *offset, 1, cmd);
379   (*offset)++;
380   (*length)--;
381   switch (cmd) {
382     case C1222_CMD_LOGON:
383         if (*length >= 12) {
384             user_id = tvb_get_ntohs(tvb, *offset);
385             proto_tree_add_uint(tree, hf_c1222_logon_id, tvb, *offset, 2, user_id);
386             *offset += 2;
387             user_name = tvb_get_ephemeral_string(tvb, *offset, 10);
388             proto_tree_add_string(tree, hf_c1222_logon_user, tvb, *offset, 10, user_name);
389             *offset += 10;
390             *length -= 12;
391             proto_item_set_text(tree, "C12.22 EPSEM: %s (id %d, user \"%s\")",
392                     val_to_str(cmd,commandnames,"Unknown (0x%02x)"), user_id, user_name);
393         } else {
394             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 LOGON command truncated");
395         }
396         break;
397     case C1222_CMD_SECURITY:
398         if (*length >= 20) {
399             password = tvb_get_ephemeral_string(tvb, *offset, 20);
400             proto_tree_add_string(tree, hf_c1222_security_password, tvb, *offset, 20, password);
401             *offset += 20;
402             *length -= 20;
403             if (*length >= 2) {
404               user_id = tvb_get_ntohs(tvb, *offset);
405               proto_tree_add_uint(tree, hf_c1222_logon_id, tvb, *offset, 2, user_id);
406               *offset += 2;
407               *length -= 2;
408               proto_item_set_text(tree, "C12.22 EPSEM: %s (password \"%s\", id %d)",
409                       val_to_str(cmd,commandnames,"Unknown (0x%02x)"), password, user_id);
410             } else {
411               proto_item_set_text(tree, "C12.22 EPSEM: %s (password \"%s\")",
412                       val_to_str(cmd,commandnames,"Unknown (0x%02x)"), password);
413             }
414         } else {
415             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 SECURITY command truncated");
416         }
417         break;
418     case C1222_CMD_AUTHENTICATE:
419         if (*length >= 1) {
420             auth_len = tvb_get_guint8(tvb, *offset);
421             proto_tree_add_uint(tree, hf_c1222_auth_len, tvb, *offset, 1, auth_len);
422             *offset += 1;
423             if (*length >= auth_len) {
424                 auth_req = tvb_bytes_to_str(tvb, *offset, auth_len);
425                 proto_tree_add_item(tree, hf_c1222_auth_data, tvb, *offset, auth_len, ENC_NA);
426                 *offset += auth_len;
427                 *length -= auth_len + 1;
428                 proto_item_set_text(tree, "C12.22 EPSEM: %s (%d bytes: %s)",
429                     val_to_str(cmd,commandnames,"Unknown (0x%02x)"), auth_len, auth_req);
430             } else {
431                 expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 AUTHENTICATE command truncated");
432             }
433         } else {
434             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 AUTHENTICATE command truncated");
435         }
436         break;
437     case C1222_CMD_FULL_READ:
438         if (*length >= 2) {
439             table = tvb_get_ntohs(tvb, *offset);
440             proto_tree_add_uint(tree, hf_c1222_read_table, tvb, *offset, 2, table);
441             proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
442                     val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
443                     val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
444             *offset += 2;
445             *length -= 2;
446         } else {
447             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 READ command truncated");
448         }
449         break;
450     case C1222_CMD_PARTIAL_READ_OFFSET:
451         if (*length >= 7) {
452             table = tvb_get_ntohs(tvb, *offset);
453             proto_tree_add_uint(tree, hf_c1222_read_table, tvb, *offset, 2, table);
454             *offset += 2;
455             *length -= 2;
456             proto_tree_add_item(tree, hf_c1222_read_offset, tvb, *offset, 3, ENC_BIG_ENDIAN);
457             *offset += 3;
458             *length -= 3;
459             proto_tree_add_item(tree, hf_c1222_read_count, tvb, *offset, 2, ENC_BIG_ENDIAN);
460             *offset += 2;
461             *length -= 2;
462             proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
463                     val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
464                     val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
465         } else {
466             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 READ command truncated");
467         }
468         break;
469     case C1222_CMD_FULL_WRITE:
470         if (*length >= 5) {
471             table = tvb_get_ntohs(tvb, *offset);
472             proto_tree_add_uint(tree, hf_c1222_write_table, tvb, *offset, 2, table);
473             *offset += 2;
474             *length -= 2;
475             tblsize = tvb_get_ntohs(tvb, *offset);
476             proto_tree_add_uint(tree, hf_c1222_write_size, tvb, *offset, 2, tblsize);
477             *offset += 2;
478             *length -= 2;
479             if (*length >= tblsize+1U) {
480                 proto_tree_add_item(tree, hf_c1222_write_data, tvb, *offset, tblsize, ENC_NA);
481                 *offset += tblsize;
482                 *length -= tblsize;
483                 chksum = tvb_get_guint8(tvb, *offset);
484                 item = proto_tree_add_uint(tree, hf_c1222_write_chksum, tvb, *offset, 1, chksum);
485                 calcsum = c1222_cksum(tvb, (*offset)-tblsize, tblsize);
486                 if (chksum != calcsum) {
487                   expert_add_info_format_text(pinfo, item, &ei_c1222_bad_checksum, "Bad checksum [should be 0x%02x]", calcsum);
488                 }
489                 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
490                         val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
491                         val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
492                 *offset += 1;
493                 *length -= 1;
494             } else {
495                 expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
496             }
497         } else {
498             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
499         }
500         break;
501     case C1222_CMD_PARTIAL_WRITE_OFFSET:
502         if (*length >= 8) {
503             table = tvb_get_ntohs(tvb, *offset);
504             proto_tree_add_uint(tree, hf_c1222_write_table, tvb, *offset, 2, table);
505             *offset += 2;
506             *length -= 2;
507             proto_tree_add_item(tree, hf_c1222_write_offset, tvb, *offset, 3, ENC_BIG_ENDIAN);
508             *offset += 3;
509             *length -= 3;
510             tblsize = tvb_get_ntohs(tvb, *offset);
511             proto_tree_add_uint(tree, hf_c1222_write_size, tvb, *offset, 2, tblsize);
512             *offset += 2;
513             *length -= 2;
514             if (*length >= tblsize+1U) {
515                 proto_tree_add_item(tree, hf_c1222_write_data, tvb, *offset, tblsize, ENC_NA);
516                 *offset += tblsize;
517                 *length -= tblsize;
518                 chksum = tvb_get_guint8(tvb, *offset);
519                 item = proto_tree_add_uint(tree, hf_c1222_write_chksum, tvb, *offset, 1, chksum);
520                 calcsum = c1222_cksum(tvb, (*offset)-tblsize, tblsize);
521                 if (chksum != calcsum) {
522                   expert_add_info_format_text(pinfo, item, &ei_c1222_bad_checksum, "Bad checksum [should be 0x%02x]", calcsum);
523                 }
524                 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
525                         val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
526                         val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
527                 *offset += 1;
528                 *length -= 1;
529             } else {
530                 expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
531             }
532         } else {
533             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
534         }
535         break;
536     case C1222_CMD_WAIT:
537         if (*length >= 1) {
538             wait_seconds = tvb_get_guint8(tvb, *offset);
539             proto_tree_add_uint(tree, hf_c1222_wait_secs, tvb, *offset, 1, wait_seconds);
540             *offset += 1;
541             *length -= 1;
542             proto_item_set_text(tree, "C12.22 EPSEM: %s (%d seconds)",
543                 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), wait_seconds);
544         } else {
545             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WAIT command truncated");
546         }
547         break;
548     case C1222_CMD_NEGOTIATE:
549         if (*length >= 3) {
550             packet_size = tvb_get_ntohs(tvb, *offset);
551             proto_tree_add_uint(tree, hf_c1222_neg_pkt_size, tvb, *offset, 2, packet_size);
552             *offset += 2;
553             *length -= 2;
554             nbr_packet = tvb_get_guint8(tvb, *offset);
555             proto_tree_add_uint(tree, hf_c1222_neg_nbr_pkts, tvb, *offset, 1, nbr_packet);
556             *offset += 1;
557             *length -= 1;
558             proto_item_set_text(tree, "C12.22 EPSEM: %s (pkt size %d, num pkts %d, with %d baud rates)",
559                     val_to_str(cmd,commandnames,"Unknown (0x%02x)"), packet_size, nbr_packet, numrates);
560         } else {
561             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 NEGOTIATE command truncated");
562         }
563         break;
564     case C1222_CMD_TIMING_SETUP:
565         if (*length >= 4) {
566             traffic = tvb_get_guint8(tvb, *offset);
567             proto_tree_add_uint(tree, hf_c1222_timing_setup_traffic, tvb, *offset, 1, traffic);
568             *offset += 1;
569             *length -= 1;
570             inter_char = tvb_get_guint8(tvb, *offset);
571             proto_tree_add_uint(tree, hf_c1222_timing_setup_inter_char, tvb, *offset, 1, inter_char);
572             *offset += 1;
573             *length -= 1;
574             resp_to = tvb_get_guint8(tvb, *offset);
575             proto_tree_add_uint(tree, hf_c1222_timing_setup_resp_to, tvb, *offset, 1, resp_to);
576             *offset += 1;
577             *length -= 1;
578             nbr_retries = tvb_get_guint8(tvb, *offset);
579             proto_tree_add_uint(tree, hf_c1222_timing_setup_nbr_retries, tvb, *offset, 1, nbr_retries);
580             *offset += 1;
581             *length -= 1;
582             proto_item_set_text(tree, "C12.22 EPSEM: %s (traffic to %d s, inter-char to %d s, response to %d s, %d retries)",
583                     val_to_str(cmd,commandnames,"Unknown (0x%02x)"), traffic, inter_char, resp_to, nbr_retries);
584         } else {
585             expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 NEGOTIATE command truncated");
586         }
587         break;
588
589     default:
590         /* don't do anything */
591         proto_item_set_text(tree, "C12.22 EPSEM: %s", val_to_str(cmd, commandnames, "Unknown (0x%02x)"));
592         if (*length) {
593             if (*length >= *length) {
594               proto_tree_add_item(tree, hf_c1222_data, tvb, *offset, *length, ENC_NA);
595             } else {
596                 expert_add_info_format_text(pinfo, tree, &ei_c1222_command_truncated, "C12.22 unknown command truncated");
597             }
598         }
599         break;
600   }
601 }
602
603 #ifdef HAVE_LIBGCRYPT
604 typedef struct tagTOP_ELEMENT_CONTROL
605 {
606   /* TRUE if this tag is required */
607   gboolean required;
608   /* TRUE if we must truncate this tag */
609   gboolean truncate;
610   /* actual hex value of the tag we're seeking */
611   guint8 tag;
612   /* if TRUE, add tag and length before copying */
613   gboolean addtag;
614   /* pointer to pointer to memory copy of element */
615   guint8 **element;
616   /* pointer to element length */
617   guint32 *length;
618 } TOP_ELEMENT_CONTROL;
619
620 static const TOP_ELEMENT_CONTROL canonifyTable[] = {
621   { FALSE, FALSE, 0xA1, TRUE, &aSO_context, &aSO_context_len },
622   { TRUE , FALSE, 0xA2, TRUE, &called_AP_title, &called_AP_title_len },
623   { FALSE, FALSE, 0xA4, TRUE, &called_AP_invocation_id, &called_AP_invocation_id_len },
624   { FALSE, FALSE, 0xA3, TRUE, &calling_AE_qualifier, &calling_AE_qualifier_len },
625   { TRUE,  FALSE, 0xA8, TRUE, &calling_AP_invocation_id, &calling_AP_invocation_id_len },
626   { FALSE, FALSE, 0x8B, TRUE, &mechanism_name, &mechanism_name_len },
627   { FALSE, FALSE, 0xAC, TRUE, &calling_authentication_value, &calling_authentication_value_len },
628   { TRUE , TRUE , 0xBE, TRUE, &user_information, &user_information_len },
629   { FALSE, FALSE, 0xA6, TRUE, &calling_AP_title, &calling_AP_title_len },
630   { FALSE, FALSE, 0xAC, FALSE, &key_id_element, &key_id_element_len },
631   { FALSE, FALSE, 0xAC, FALSE, &iv_element, &iv_element_len },
632   { FALSE, FALSE, 0x0,  TRUE, NULL, NULL }
633 };
634
635 /**
636  * Calculates the size of the passed number n as encoded as a BER length field.
637  *
638  * \param n is the length value to be BER encoded
639  * \returns the sized of the encoding
640  */
641 static guint32
642 get_ber_len_size(guint32 n)
643 {
644   guint32 len = 1;
645   if (n > 0x7f) len++;
646   if (n > 0xff) len++;
647   if (n > 0xffff) len++;
648   if (n > 0xffffff) len++;
649   return len;
650 }
651 /**
652  * Encodes the passed value n as a BER-encoded length at puts it in memory.
653  *
654  * \param ptr points to the buffer to be written
655  * \param n is the length to be BER encoded
656  * \maxsize is the maximum number of bytes we're allowed to write
657  * \returns length of encoded value in bytes
658  */
659 static int
660 encode_ber_len(guint8 *ptr, guint32 n, int maxsize)
661 {
662   int len = get_ber_len_size(n);
663   if (len > maxsize) return 0;
664   if (len == 1) {
665     *ptr = 0x7f & n;
666   } else {
667     *ptr = (len -1) | 0x80;
668     for (ptr += len-1; n; n >>= 8)
669       *ptr-- = n & 0xff;
670   }
671   return len;
672
673 }
674
675 /**
676  * Checks a new encryption table item for validity.
677  *
678  * \param n points to the new record
679  * \param err is updated to point to an error string if needed
680  */
681 static void
682 c1222_uat_data_update_cb(void* n, const char** err)
683 {
684   c1222_uat_data_t* new_rec = (c1222_uat_data_t *)n;
685
686   if (new_rec->keynum > 0xff) {
687     *err = "Invalid key number; must be less than 256";
688   }
689   if (new_rec->keylen != EAX_SIZEOF_KEY) {
690     *err = "Invalid key size; must be 16 bytes";
691   }
692 }
693
694 /**
695  * Canonifies header fields in preparation for authenticating and/or decrypting the packet.
696  *
697  * \param buff points to the allocated canonization buffer
698  * \param offset points to start of unallocated space in buffer and
699       is updated as we put bytes into buffer
700  * \param buffsize total size of allocated buffer
701  * \return FALSE if element is required and not present; otherwise TRUE
702  */
703 static gboolean
704 canonify_unencrypted_header(guchar *buff, guint32 *offset, guint32 buffsize)
705 {
706   const TOP_ELEMENT_CONTROL *t = canonifyTable;
707   guint32 len;
708
709   for (t = canonifyTable; t->element != NULL; t++)
710   {
711     len = *(t->length);
712     if (t->required && *(t->element) == NULL)
713       return FALSE;
714     if (*(t->element) != NULL) {
715       if (t->addtag) {
716         /* recreate original tag and length */
717         buff[(*offset)++] = t->tag;
718         (*offset) += encode_ber_len(&buff[*offset], len, 4);
719       }
720       if (t->truncate) {
721         len = 3+2*get_ber_len_size(len);
722       }
723       /* bail out if the cannonization buffer is too small */
724       /* this should never happen! */
725       if (buffsize < *offset + len) {
726         return FALSE;
727       }
728       memcpy(&buff[*offset], *(t->element), len);
729       (*offset) += len;
730       g_free(*(t->element));
731       *(t->element) = NULL;
732     }
733   }
734   return TRUE;
735 }
736
737 /**
738  * Looks up the required key in the key table.
739  *
740  * \param keybuf is updated with a copy of the key data if successful lookup.
741  * \param keyid is the ID number of the desired key
742  * \returns TRUE if key was found; otherwise FALSE
743  */
744 static gboolean
745 keylookup(guint8 *keybuff, guint8 keyid)
746 {
747   guint i;
748
749   if (c1222_uat_data == NULL)
750     return FALSE;
751   for (i = 0; i < num_c1222_uat_data; i++) {
752     if (c1222_uat_data[i].keynum == keyid) {
753       memcpy(keybuff, c1222_uat_data[i].key, EAX_SIZEOF_KEY);
754       return TRUE;
755     }
756   }
757   return FALSE;
758 }
759 #endif /* HAVE_LIBGCRYPT */
760
761 /**
762  * Authenticates and decrypts the passed packet.
763  *
764  * \param buffer points to a memory copy of the packet to be authenticated/decrypted
765  *      and contains the decrypted value on successful return.
766  * \param length lenth of input packet
767  * \param decrypt TRUE if packet is to be authenticated and decrypted; FALSE if authentication only is requested
768  * \returns TRUE if the requested operation was successful; otherwise FALSE
769  */
770 #ifdef HAVE_LIBGCRYPT
771 static gboolean
772 decrypt_packet(guchar *buffer, guint32 length, gboolean decrypt)
773 {
774 #define CANONBUFFSIZE 300U
775   guchar canonbuff[CANONBUFFSIZE];
776   guint8 c1222_key[EAX_SIZEOF_KEY];
777   guchar key_id = 0;
778   guint32 offset = 0;
779   gboolean status = FALSE;
780
781   /* must be at least 4 bytes long to include the MAC */
782   if (length < 4)
783     return status;
784   if (key_id_element != NULL)
785     key_id = key_id_element[0];
786   /* extract unencrypted header information */
787   if (!canonify_unencrypted_header(canonbuff, &offset, CANONBUFFSIZE))
788     return status;
789   /* decrypt and authenticate in place */
790 /* PARAMETERS:     pN     : Pointer to ClearText (Input, Canonified form).    */
791 /*                 pK     : Pointer to secret key (Input).                    */
792 /*                 pC     : Pointer to CipherText (Input/Output).             */
793 /*                 SizeN  : Byte length of ClearText buffer.                  */
794 /*                 SizeK  : Byte length of secret key.                        */
795 /*                 SizeC  : Byte length of CipherText buffer.                 */
796 /*                 pMac   : Four byte Message Authentication Code.            */
797 /*                 Mode   : Operating mode (See EAX_MODE_xxx).                */
798 /* RETURNS:        TRUE if message has been authenticated.                    */
799 /*                 FALSE if not authenticated, invalid Mode, or error.        */
800   if (offset) {
801     if (!keylookup((guint8 *)&c1222_key, key_id))
802       return FALSE;
803     status = Eax_Decrypt(canonbuff, c1222_key, buffer,
804                   offset, EAX_SIZEOF_KEY, length-4,
805                   (MAC_T *)&buffer[length-4],
806                   decrypt ? EAX_MODE_CIPHERTEXT_AUTH : EAX_MODE_CLEARTEXT_AUTH);
807   }
808   return status;
809 }
810 #else /* HAVE_LIBCRYPT */
811 static gboolean
812 decrypt_packet(guchar *buffer _U_, guint32 length _U_, gboolean decrypt _U_)
813 {
814   return FALSE;
815 }
816 #endif /* HAVE_LIBGCRYPT */
817
818 /**
819  * Checks to make sure that a complete, valid BER-encoded length is in the buffer.
820  *
821  * \param tvb contains the buffer to be examined
822  * \param offset is the offset within the buffer at which the BER-encded length begins
823  * \returns TRUE if a complete, valid BER-encoded length is in the buffer; otherwise FALSE
824  */
825 static gboolean
826 ber_len_ok(tvbuff_t *tvb, int offset)
827 {
828   guint8 ch;
829
830   if (tvb_offset_exists(tvb, offset)) {
831     ch = tvb_get_guint8(tvb, offset);
832     offset++;
833     if (!(ch & 0x80)) {
834       return TRUE;
835     } else if (tvb_offset_exists(tvb, offset)) {
836       ch = tvb_get_guint8(tvb, offset);
837       offset++;
838       if (!(ch & 0x80)) {
839         return TRUE;
840       } else if (tvb_offset_exists(tvb, offset)) {
841         ch = tvb_get_guint8(tvb, offset);
842         offset++;
843         if (!(ch & 0x80)) {
844           return TRUE;
845         } else if (tvb_offset_exists(tvb, offset)) {
846           ch = tvb_get_guint8(tvb, offset);
847           /*offset++;*/
848           if (!(ch & 0x80)) {
849             return TRUE;
850           }
851         }
852       }
853     }
854   }
855   return FALSE;
856 }
857
858 /**
859  * Dissects the EPSEM portion of the User-information part of a C12.22 message.
860  *
861  * \param tvb
862  * \param offset
863  * \param len
864  * \param pinfo
865  * \param tree
866  */
867 static int
868 dissect_epsem(tvbuff_t *tvb, int offset, guint32 len, packet_info *pinfo, proto_tree *tree)
869 {
870   proto_tree *cmd_tree = NULL;
871   proto_tree *ct = NULL;
872   proto_tree *crypto_tree = NULL;
873   proto_tree *yt = NULL;
874   proto_item *item = NULL;
875   guint8 flags;
876   int local_offset;
877   gint len2;
878   int cmd_err;
879   gboolean ind;
880   guchar *buffer;
881   tvbuff_t *epsem_buffer = NULL;
882   gboolean crypto_good = FALSE;
883   gboolean crypto_bad = FALSE;
884   gboolean hasmac = FALSE;
885   gboolean encrypted = FALSE;
886
887   if ((tvb == NULL) && (len == 0)) {
888       expert_add_info(pinfo, tree, &ei_c1222_epsem_missing);
889       return offset;
890   }
891   /* parse the flags byte which is always unencrypted */
892   flags = tvb_get_guint8(tvb, offset);
893   proto_tree_add_bitmask(tree, tvb, offset, hf_c1222_epsem_flags, ett_c1222_flags, c1222_flags, ENC_BIG_ENDIAN);
894   offset++;
895   switch ((flags & C1222_EPSEM_FLAG_SECURITY_MODE) >> 2) {
896     case EAX_MODE_CIPHERTEXT_AUTH:
897       /* mode is ciphertext with authentication */
898       hasmac = TRUE;
899       len2 = tvb_length_remaining(tvb, offset);
900       if (len2 <= 0)
901         return offset;
902       encrypted = TRUE;
903       if (c1222_decrypt) {
904         buffer = (guchar *)tvb_memdup(tvb, offset, len2);
905         if (!decrypt_packet(buffer, len2, TRUE)) {
906           g_free(buffer);
907           crypto_bad = TRUE;
908         } else {
909           epsem_buffer = tvb_new_real_data(buffer, len2, len2);
910           tvb_set_child_real_data_tvbuff(tvb, epsem_buffer);
911           add_new_data_source(pinfo, epsem_buffer, "Decrypted EPSEM Data");
912           crypto_good = TRUE;
913           encrypted = FALSE;
914         }
915       }
916       break;
917     case EAX_MODE_CLEARTEXT_AUTH:
918       /* mode is cleartext with authentication */
919       hasmac = TRUE;
920       len2 = tvb_length_remaining(tvb, offset);
921       if (len2 <= 0)
922         return offset;
923       buffer = (guchar *)tvb_memdup(tvb, offset, len2);
924       epsem_buffer = tvb_new_subset_remaining(tvb, offset);
925       if (c1222_decrypt) {
926         if (!decrypt_packet(buffer, len2, FALSE)) {
927 #ifdef HAVE_LIBGCRYPT
928           crypto_bad = TRUE;
929           expert_add_info(pinfo, tree, &ei_c1222_epsem_failed_authentication);
930 #else /* HAVE_LIBGCRYPT */
931           expert_add_info(pinfo, tree, &ei_c1222_epsem_not_authenticated);
932 #endif /* HAVE_LIBGCRYPT */
933         } else {
934           crypto_good = TRUE;
935         }
936       }
937       break;
938     default:
939       /* it's not encrypted */
940       epsem_buffer = tvb_new_subset_remaining(tvb, offset);
941   }
942   /* it's only encrypted if we have an undecrypted payload */
943   if (encrypted) {
944     proto_tree_add_item(tree, hf_c1222_epsem_total, tvb, offset, -1, ENC_NA);
945     expert_add_info(pinfo, tree, &ei_c1222_epsem_not_decryped);
946     local_offset = offset+len2-4;
947     epsem_buffer = tvb;
948   } else {  /* it's not (now) encrypted */
949     local_offset = 0;
950     /* retrieve the ed_class if it's there */
951     if (flags & C1222_EPSEM_FLAG_ED_CLASS_INCLUDED) {
952       if (tvb_offset_exists(epsem_buffer, local_offset+4-1)) {
953         proto_tree_add_item(tree, hf_c1222_epsem_ed_class, epsem_buffer, local_offset, 4, ENC_NA);
954         local_offset += 4;
955       } else {
956         expert_add_info(pinfo, tree, &ei_c1222_ed_class_missing);
957       }
958     }
959     /* what follows are one or more <epsem-data> elements possibly followed by
960      * a <mac>.  Each <epsem-data> element is defined as <service-length><res-req>,
961      * so we fetch such pairs until there isn't anything left (except possibly
962      * the <mac>).
963      */
964     while (tvb_offset_exists(epsem_buffer, local_offset+(hasmac?5:1))) {
965       if (ber_len_ok(epsem_buffer, local_offset)) {
966         local_offset = dissect_ber_length(pinfo, tree, epsem_buffer, local_offset, (guint32 *)&len2, &ind);
967       } else {
968         expert_add_info(pinfo, tree, &ei_c1222_epsem_ber_length_error);
969         return offset+len;
970       }
971       if (tvb_offset_exists(epsem_buffer, local_offset+len2-1)) {
972         cmd_err = tvb_get_guint8(epsem_buffer, local_offset);
973         ct = proto_tree_add_item(tree, hf_c1222_epsem_total, epsem_buffer, local_offset, len2, ENC_NA);
974         cmd_tree = proto_item_add_subtree(ct, ett_c1222_cmd);
975         parse_c1222_detailed(epsem_buffer, pinfo, cmd_tree, cmd_err, (guint32 *)&len2, &local_offset);
976         local_offset += len2;
977       } else {
978         expert_add_info(pinfo, tree, &ei_c1222_epsem_field_length_error);
979         return offset+len;
980       }
981     }
982   }
983   if (hasmac) {
984     if (tvb_offset_exists(epsem_buffer, local_offset+4-1)) {
985       yt = proto_tree_add_item(tree, hf_c1222_epsem_mac, epsem_buffer, local_offset, 4, ENC_NA);
986       /* now we have enough information to fill in the crypto subtree */
987       crypto_tree = proto_item_add_subtree(yt, ett_c1222_crypto);
988       item = proto_tree_add_boolean(crypto_tree, hf_c1222_epsem_crypto_good, tvb, local_offset, 4, crypto_good);
989       PROTO_ITEM_SET_GENERATED(item);
990       item = proto_tree_add_boolean(crypto_tree, hf_c1222_epsem_crypto_bad, tvb, local_offset, 4, crypto_bad);
991       PROTO_ITEM_SET_GENERATED(item);
992     } else {
993       expert_add_info(pinfo, tree, &ei_c1222_mac_missing);
994       return offset+len;
995     }
996   }
997   return offset;
998 }
999
1000 #include "packet-c1222-fn.c"
1001
1002 /**
1003  * Dissects a a full (reassembled) C12.22 message.
1004  *
1005  * \param tvb
1006  * \param pinfo
1007  * \param tree
1008  */
1009 static void
1010 dissect_c1222_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1011 {
1012     proto_item      *c1222_item = NULL;
1013     proto_tree      *c1222_tree = NULL;
1014
1015     /* make entry in the Protocol column on summary display */
1016     col_set_str(pinfo->cinfo, COL_PROTOCOL, PNAME);
1017
1018     /* create the c1222 protocol tree */
1019     if (tree) {
1020         c1222_item = proto_tree_add_item(tree, proto_c1222, tvb, 0, -1, ENC_NA);
1021         c1222_tree = proto_item_add_subtree(c1222_item, ett_c1222);
1022         dissect_C1222_MESSAGE_PDU(tvb, pinfo, c1222_tree);
1023     }
1024 }
1025
1026 /**
1027  * Fetches the length of an entire C12.22 message to assist in reassembly.
1028  *
1029  * \param pinfo
1030  * \param tvb
1031  * \param offset
1032  * \returns length of entire C12.22 message
1033  */
1034 static guint
1035 get_c1222_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
1036 {
1037   int orig_offset;
1038   guint length;
1039   gboolean ind;
1040
1041   orig_offset = offset;
1042   /* note that this assumes a Tag length of 1 which is always valid for C12.22 */
1043   offset = dissect_ber_length(pinfo, NULL, tvb, offset+1, &length, &ind);
1044   return length+(offset - orig_offset);
1045 }
1046
1047 /**
1048  * Reassembles and dissects C12.22 messages.
1049  *
1050  * \param tvb
1051  * \param pinfo
1052  * \param tree
1053  */
1054 static void
1055 dissect_c1222(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1056 {
1057     tcp_dissect_pdus(tvb, pinfo, tree, c1222_desegment, 5,
1058             get_c1222_message_len, dissect_c1222_common);
1059 }
1060
1061 /*--- proto_register_c1222 -------------------------------------------*/
1062 void proto_register_c1222(void) {
1063
1064   /* List of fields */
1065   static hf_register_info hf[] = {
1066    { &hf_c1222_epsem_flags,
1067     { "C12.22 EPSEM Flags", "c1222.epsem.flags",
1068     FT_UINT8, BASE_HEX,
1069     NULL, 0x0,
1070     NULL, HFILL }
1071    },
1072    { &hf_c1222_epsem_flags_reserved,
1073     { "C12.22 Reserved Flag", "c1222.epsem.flags.reserved",
1074     FT_BOOLEAN, 8,
1075     NULL, C1222_EPSEM_FLAG_RESERVED,
1076     NULL, HFILL }
1077    },
1078    { &hf_c1222_epsem_flags_recovery,
1079     { "C12.22 Recovery Flag", "c1222.epsem.flags.recovery",
1080     FT_BOOLEAN, 8,
1081     NULL, C1222_EPSEM_FLAG_RECOVERY_SESSION,
1082     NULL, HFILL }
1083    },
1084    { &hf_c1222_epsem_flags_proxy,
1085     { "C12.22 Proxy Service Used Flag", "c1222.epsem.flags.proxy",
1086     FT_BOOLEAN, 8,
1087     NULL, C1222_EPSEM_FLAG_PROXY_SERVICE_USED,
1088     NULL, HFILL }
1089    },
1090    { &hf_c1222_epsem_flags_ed_class,
1091     { "C12.22 ED Class Flag", "c1222.epsem.flags.ed_class",
1092     FT_BOOLEAN, 8,
1093     NULL, C1222_EPSEM_FLAG_ED_CLASS_INCLUDED,
1094     NULL, HFILL }
1095    },
1096    { &hf_c1222_epsem_flags_security_modes,
1097     { "C12.22 Security Mode Flags", "c1222.epsem.flags.security",
1098     FT_UINT8, BASE_HEX,
1099     VALS(c1222_security_modes), C1222_EPSEM_FLAG_SECURITY_MODE,
1100     NULL, HFILL }
1101    },
1102    { &hf_c1222_epsem_flags_response_control,
1103     { "C12.22 Response Control Flags", "c1222.epsem.flags.response_control",
1104     FT_UINT8, BASE_HEX,
1105     VALS(c1222_response_control), C1222_EPSEM_FLAG_RESPONSE_CONTROL,
1106     NULL, HFILL }
1107    },
1108    { &hf_c1222_epsem_ed_class,
1109     { "C12.22 EPSEM ED Class", "c1222.epsem.edclass",
1110     FT_BYTES, BASE_NONE,
1111     NULL, 0x0,
1112     NULL, HFILL }
1113    },
1114    { &hf_c1222_epsem_total,
1115     { "C12.22 EPSEM", "c1222.epsem.data",
1116     FT_BYTES, BASE_NONE,
1117     NULL, 0x0,
1118     NULL, HFILL }
1119    },
1120    { &hf_c1222_epsem_mac,
1121     { "C12.22 EPSEM MAC", "c1222.epsem.mac",
1122     FT_BYTES, BASE_NONE,
1123     NULL, 0x0,
1124     NULL, HFILL }
1125    },
1126    { &hf_c1222_cmd,
1127     { "C12.22 Command", "c1222.cmd",
1128     FT_UINT8, BASE_HEX,
1129     VALS(commandnames), 0x0,
1130     NULL, HFILL }
1131    },
1132    { &hf_c1222_err,
1133     { "C12.22 Response", "c1222.err",
1134     FT_UINT8, BASE_HEX,
1135     VALS(commandnames), 0x0,
1136     NULL, HFILL }
1137    },
1138    { &hf_c1222_logon_id,
1139     { "C12.22 Logon User-Id", "c1222.logon.id",
1140     FT_UINT16, BASE_DEC,
1141     NULL, 0x0,
1142     NULL, HFILL }
1143    },
1144    { &hf_c1222_logon_user,
1145     { "C12.22 Logon User", "c1222.logon.user",
1146     FT_STRING, BASE_NONE,
1147     NULL, 0x0,
1148     NULL, HFILL }
1149    },
1150    { &hf_c1222_security_password,
1151     { "C12.22 Security Password", "c1222.security.password",
1152     FT_STRING, BASE_NONE,
1153     NULL, 0x0,
1154     NULL, HFILL }
1155    },
1156    { &hf_c1222_auth_len,
1157     { "C12.22 Authenticate Request Length", "c1222.authenticate.len",
1158     FT_UINT8, BASE_DEC,
1159     NULL, 0x0,
1160     NULL, HFILL }
1161    },
1162    { &hf_c1222_auth_data,
1163     { "C12.22 Authenticate Data", "c1222.authenticate.data",
1164     FT_BYTES, BASE_NONE,
1165     NULL, 0x0,
1166     NULL, HFILL }
1167    },
1168    { &hf_c1222_read_table,
1169     { "C12.22 Table", "c1222.read.table",
1170     FT_UINT16, BASE_HEX,
1171     NULL, 0x0,
1172     NULL, HFILL }
1173    },
1174    { &hf_c1222_read_offset,
1175     { "C12.22 Offset", "c1222.read.offset",
1176     FT_UINT24, BASE_HEX,
1177     NULL, 0x0,
1178     NULL, HFILL }
1179    },
1180    { &hf_c1222_read_count,
1181     { "C12.22 Count", "c1222.read.count",
1182     FT_UINT16, BASE_DEC,
1183     NULL, 0x0,
1184     NULL, HFILL }
1185    },
1186    { &hf_c1222_write_table,
1187     { "C12.22 Table", "c1222.write.table",
1188     FT_UINT16, BASE_HEX,
1189     NULL, 0x0,
1190     NULL, HFILL }
1191    },
1192    { &hf_c1222_write_offset,
1193     { "C12.22 Offset", "c1222.write.offset",
1194     FT_UINT24, BASE_HEX,
1195     NULL, 0x0,
1196     NULL, HFILL }
1197    },
1198    { &hf_c1222_write_size,
1199     { "C12.22 Table Size", "c1222.write.size",
1200     FT_UINT16, BASE_HEX,
1201     NULL, 0x0,
1202     NULL, HFILL }
1203    },
1204    { &hf_c1222_write_data,
1205     { "C12.22 Table Data", "c1222.write.data",
1206     FT_BYTES, BASE_NONE,
1207     NULL, 0x0,
1208     NULL, HFILL }
1209    },
1210    { &hf_c1222_write_chksum,
1211     { "C12.22 Table Data Checksum", "c1222.write.chksum",
1212     FT_UINT8, BASE_HEX,
1213     NULL, 0x0,
1214     NULL, HFILL }
1215    },
1216    { &hf_c1222_neg_pkt_size,
1217     { "C12.22 Negotiate Packet Size", "c1222.negotiate.pktsize",
1218     FT_UINT16, BASE_DEC,
1219     NULL, 0x0,
1220     NULL, HFILL }
1221    },
1222    { &hf_c1222_neg_nbr_pkts,
1223     { "C12.22 Negotiate Number of Packets", "c1222.negotiate.numpkts",
1224     FT_UINT8, BASE_DEC,
1225     NULL, 0x0,
1226     NULL, HFILL }
1227    },
1228    { &hf_c1222_wait_secs,
1229     { "C12.22 Wait Seconds", "c1222.wait.seconds",
1230     FT_UINT8, BASE_DEC,
1231     NULL, 0x0,
1232     NULL, HFILL }
1233    },
1234    { &hf_c1222_timing_setup_traffic,
1235     { "C12.22 Timing Setup Channel Traffic Timeout", "c1222.timingsetup.traffic",
1236     FT_UINT8, BASE_DEC,
1237     NULL, 0x0,
1238     NULL, HFILL }
1239    },
1240    { &hf_c1222_timing_setup_inter_char,
1241     { "C12.22 Timing Setup Intercharacter Timeout", "c1222.timingsetup.interchar",
1242     FT_UINT8, BASE_DEC,
1243     NULL, 0x0,
1244     NULL, HFILL }
1245    },
1246    { &hf_c1222_timing_setup_resp_to,
1247     { "C12.22 Timing Setup Response Timeout", "c1222.timingsetup.respto",
1248     FT_UINT8, BASE_DEC,
1249     NULL, 0x0,
1250     NULL, HFILL }
1251    },
1252    { &hf_c1222_timing_setup_nbr_retries,
1253     { "C12.22 Timing Setup Number of Retries", "c1222.timingsetup.nbrretries",
1254     FT_UINT8, BASE_DEC,
1255     NULL, 0x0,
1256     NULL, HFILL }
1257    },
1258    { &hf_c1222_data,
1259     { "C12.22 data", "c1222.data",
1260     FT_BYTES, BASE_NONE,
1261     NULL, 0x0,
1262     NULL, HFILL }
1263    },
1264    { &hf_c1222_epsem_crypto_good,
1265     { "Crypto good", "c1222.crypto_good",
1266     FT_BOOLEAN, BASE_NONE,
1267     NULL, 0x0,
1268     "True: crypto ok; False: doesn't match or not checked", HFILL }
1269    },
1270    { &hf_c1222_epsem_crypto_bad,
1271     { "Crypto bad", "c1222.crypto_bad",
1272     FT_BOOLEAN, BASE_NONE,
1273     NULL, 0x0,
1274     "True: crypto bad; False: crypto ok or not checked", HFILL }
1275    },
1276 #include "packet-c1222-hfarr.c"
1277   };
1278
1279   /* List of subtrees */
1280   static gint *ett[] = {
1281                   &ett_c1222,
1282                   &ett_c1222_epsem,
1283                   &ett_c1222_flags,
1284                   &ett_c1222_crypto,
1285                   &ett_c1222_cmd,
1286 #include "packet-c1222-ettarr.c"
1287   };
1288
1289   static ei_register_info ei[] = {
1290      { &ei_c1222_command_truncated, { "c1222.command_truncated", PI_MALFORMED, PI_ERROR, "C12.22 command truncated", EXPFILL }},
1291      { &ei_c1222_bad_checksum, { "c1222.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1292      { &ei_c1222_epsem_missing, { "c1222.epsem.missing", PI_MALFORMED, PI_ERROR, "C12.22 EPSEM missing", EXPFILL }},
1293 #ifdef HAVE_LIBGCRYPT
1294      { &ei_c1222_epsem_failed_authentication, { "c1222.epsem.failed_authentication", PI_SECURITY, PI_ERROR, "C12.22 EPSEM failed authentication", EXPFILL }},
1295 #else
1296      { &ei_c1222_epsem_not_authenticated, { "c1222.epsem.not_authenticated", PI_SECURITY, PI_WARN, "C12.22 EPSEM could not be authenticated", EXPFILL }},
1297 #endif
1298      { &ei_c1222_epsem_not_decryped, { "c1222.epsem.not_decryped", PI_UNDECODED, PI_WARN, "C12.22 EPSEM could not be decrypted", EXPFILL }},
1299      { &ei_c1222_ed_class_missing, { "c1222.ed_class_missing", PI_SECURITY, PI_ERROR, "C12.22 ED Class missing", EXPFILL }},
1300      { &ei_c1222_epsem_ber_length_error, { "c1222.epsem.ber_length_error", PI_MALFORMED, PI_ERROR, "C12.22 EPSEM BER length error", EXPFILL }},
1301      { &ei_c1222_epsem_field_length_error, { "c1222.epsem.field_length_error", PI_MALFORMED, PI_ERROR, "C12.22 EPSEM field length error", EXPFILL }},
1302      { &ei_c1222_mac_missing, { "c1222.mac_missing", PI_MALFORMED, PI_ERROR, "C12.22 MAC missing", EXPFILL }},
1303   };
1304
1305   expert_module_t* expert_c1222;
1306   module_t *c1222_module;
1307
1308 #ifdef HAVE_LIBGCRYPT
1309   static uat_field_t c1222_uat_flds[] = {
1310     UAT_FLD_HEX(c1222_users,keynum,"Key ID","Key identifier in hexadecimal"),
1311     UAT_FLD_BUFFER(c1222_users, key, "Key", "Encryption key as 16-byte hex string"),
1312     UAT_END_FIELDS
1313   };
1314 #endif /* HAVE_LIBGCRYPT */
1315
1316   /* Register protocol */
1317   proto_c1222 = proto_register_protocol(PNAME, PSNAME, PFNAME);
1318   /* Register fields and subtrees */
1319   proto_register_field_array(proto_c1222, hf, array_length(hf));
1320   proto_register_subtree_array(ett, array_length(ett));
1321   expert_c1222 = expert_register_protocol(proto_c1222);
1322   expert_register_field_array(expert_c1222, ei, array_length(ei));
1323   c1222_module = prefs_register_protocol(proto_c1222, proto_reg_handoff_c1222);
1324   prefs_register_bool_preference(c1222_module, "desegment",
1325         "Reassemble all C12.22 messages spanning multiple TCP segments",
1326         "Whether the C12.22 dissector should reassemble all messages spanning multiple TCP segments",
1327         &c1222_desegment);
1328 #ifdef HAVE_LIBGCRYPT
1329   prefs_register_bool_preference(c1222_module, "decrypt",
1330         "Verify crypto for all applicable C12.22 messages",
1331         "Whether the C12.22 dissector should verify the crypto for all relevant messages",
1332         &c1222_decrypt);
1333
1334   c1222_uat = uat_new("Decryption Table",
1335       sizeof(c1222_uat_data_t),         /* record size */
1336       "c1222_decryption_table",         /* filename */
1337       TRUE,                             /* from_profile */
1338       (void**)&c1222_uat_data,          /* data_ptr */
1339       &num_c1222_uat_data,              /* numitems_ptr */
1340       UAT_AFFECTS_DISSECTION,           /* affects dissection of packets, but not set of named fields */
1341       NULL,                             /* help */
1342       NULL,                             /* copy callback */
1343       c1222_uat_data_update_cb,         /* update callback */
1344       NULL,                             /* free callback */
1345       NULL,                             /* post update callback */
1346       c1222_uat_flds);                  /* UAT field definitions */
1347
1348   prefs_register_uat_preference(c1222_module,
1349       "decryption_table",
1350       "Decryption Table",
1351       "Table of security parameters for decryption of C12.22 packets",
1352       c1222_uat);
1353 #endif /* HAVE_LIBGCRYPT */
1354 }
1355
1356 /*--- proto_reg_handoff_c1222 ---------------------------------------*/
1357 void
1358 proto_reg_handoff_c1222(void)
1359 {
1360     static gboolean initialized = FALSE;
1361
1362     if( !initialized ) {
1363         c1222_handle = create_dissector_handle(dissect_c1222, proto_c1222);
1364                 c1222_udp_handle = create_dissector_handle(dissect_c1222_common, proto_c1222);
1365         dissector_add_uint("tcp.port", global_c1222_port, c1222_handle);
1366         dissector_add_uint("udp.port", global_c1222_port, c1222_udp_handle);
1367         initialized = TRUE;
1368     }
1369 }