Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-c1222.c
blobfb2a9f4dd45b098c5df50c6268f65cb2d17105de
1 /* Do not modify this file. Changes will be overwritten. */
2 /* Generated automatically by the ASN.1 to Wireshark dissector compiler */
3 /* packet-c1222.c */
4 /* asn2wrs.py -b -q -L -p c1222 -c ./c1222.cnf -s ./packet-c1222-template -D . -O ../.. c1222.asn */
6 /* packet-c1222.c
7 * Routines for ANSI C12.22 packet dissection
8 * Copyright 2010, Edward J. Beroset, edward.beroset@elster.com
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include "config.h"
19 #include <epan/packet.h>
20 #include <epan/conversation.h>
21 #include <epan/expert.h>
22 #include <epan/prefs.h>
23 #include <epan/strutil.h>
24 #include <epan/uat.h>
25 #include <epan/oids.h>
26 #include <wsutil/eax.h>
27 #include <wsutil/array.h>
28 #include "packet-ber.h"
29 #include "packet-tcp.h"
30 #include "packet-c1222.h"
32 #define PNAME "ANSI C12.22"
33 #define PSNAME "C12.22"
34 #define PFNAME "c1222"
35 #define C1222_PORT 1153 /* TCP port */
37 /* C12.22 flag definitions */
38 #define C1222_EPSEM_FLAG_RESERVED 0x80
39 #define C1222_EPSEM_FLAG_RECOVERY_SESSION 0x40
40 #define C1222_EPSEM_FLAG_PROXY_SERVICE_USED 0x20
41 #define C1222_EPSEM_FLAG_ED_CLASS_INCLUDED 0x10
42 #define C1222_EPSEM_FLAG_SECURITY_MODE 0x0c
43 #define C1222_EPSEM_FLAG_RESPONSE_CONTROL 0x03
45 #define C1222_PROCEDURE_RESPONSE 0xf000
46 #define C1222_PROCEDURE_MFG 0x0800
47 #define C1222_PROCEDURE_NUMBER 0x07ff
49 /* if the packet is encrypted, it can be
50 * good, bad, or simply not checked
52 #define C1222_EPSEM_CRYPTO_GOOD 0x01
53 #define C1222_EPSEM_CRYPTO_BAD 0x02
55 /* these defines are for each of the C12.22 services */
56 #define C1222_CMD_IDENTIFY 0x20
57 #define C1222_CMD_TERMINATE 0x21
58 #define C1222_CMD_DISCONNECT 0x22
59 #define C1222_CMD_FULL_READ 0x30
60 #define C1222_CMD_DEFAULT_READ 0x3E
61 #define C1222_CMD_PARTIAL_READ_OFFSET 0x3F
62 #define C1222_CMD_FULL_WRITE 0x40
63 #define C1222_CMD_DEFAULT_WRITE 0x4E
64 #define C1222_CMD_PARTIAL_WRITE_OFFSET 0x4F
65 #define C1222_CMD_LOGON 0x50
66 #define C1222_CMD_SECURITY 0x51
67 #define C1222_CMD_LOGOFF 0x52
68 #define C1222_CMD_AUTHENTICATE 0x53
69 #define C1222_CMD_NEGOTIATE 0x60
70 #define C1222_CMD_WAIT 0x70
71 #define C1222_CMD_TIMING_SETUP 0x71
73 void proto_register_c1222(void);
75 static dissector_handle_t c1222_handle;
76 static dissector_handle_t c1222_udp_handle;
78 /* Initialize the protocol and registered fields */
79 static int proto_c1222;
81 static int hf_c1222_MESSAGE_PDU; /* MESSAGE */
82 static int hf_c1222_aSO_context; /* ASO_qualifier */
83 static int hf_c1222_called_AP_title; /* Called_AP_title */
84 static int hf_c1222_called_AP_invocation_id; /* Called_AP_invocation_id */
85 static int hf_c1222_calling_AP_title; /* Calling_AP_title */
86 static int hf_c1222_calling_AE_qualifier; /* Calling_AE_qualifier */
87 static int hf_c1222_calling_AP_invocation_id; /* Calling_AP_invocation_id */
88 static int hf_c1222_mechanism_name; /* Mechanism_name */
89 static int hf_c1222_calling_authentication_value; /* Calling_authentication_value */
90 static int hf_c1222_user_information; /* User_information */
91 static int hf_c1222_called_ap_title_abs; /* OBJECT_IDENTIFIER */
92 static int hf_c1222_called_ap_title_rel; /* RELATIVE_OID */
93 static int hf_c1222_calling_ap_title_abs; /* OBJECT_IDENTIFIER */
94 static int hf_c1222_calling_ap_title_rel; /* RELATIVE_OID */
95 static int hf_c1222_calling_authentication_value_indirect; /* INTEGER */
96 static int hf_c1222_calling_authentication_value_encoding; /* Authentication_value_encoding */
97 static int hf_c1222_calling_authentication_value_single_asn1; /* Calling_authentication_value_single_asn1 */
98 static int hf_c1222_calling_authentication_value_octet_aligned; /* OCTET_STRING */
99 static int hf_c1222_calling_authentication_value_c1222; /* Calling_authentication_value_c1222 */
100 static int hf_c1222_calling_authentication_value_c1221; /* Calling_authentication_value_c1221 */
101 static int hf_c1222_key_id_element; /* Key_id_element */
102 static int hf_c1222_iv_element; /* Iv_element */
103 static int hf_c1222_c1221_auth_identification; /* OCTET_STRING_SIZE_CONSTR001 */
104 static int hf_c1222_c1221_auth_request; /* OCTET_STRING_SIZE_1_255 */
105 static int hf_c1222_c1221_auth_response; /* OCTET_STRING_SIZE_CONSTR002 */
106 /* These are the EPSEM pieces */
107 /* first, the flag components */
108 static int hf_c1222_epsem_flags;
109 static int hf_c1222_epsem_flags_reserved;
110 static int hf_c1222_epsem_flags_recovery;
111 static int hf_c1222_epsem_flags_proxy;
112 static int hf_c1222_epsem_flags_ed_class;
113 static int hf_c1222_epsem_flags_security_modes;
114 static int hf_c1222_epsem_flags_response_control;
115 /* and the structure of the flag components */
116 static int * const c1222_flags[] = {
117 &hf_c1222_epsem_flags_reserved,
118 &hf_c1222_epsem_flags_recovery,
119 &hf_c1222_epsem_flags_proxy,
120 &hf_c1222_epsem_flags_ed_class,
121 &hf_c1222_epsem_flags_security_modes,
122 &hf_c1222_epsem_flags_response_control,
123 NULL
125 /* next the optional ed_class */
126 static int hf_c1222_epsem_ed_class;
127 /* now the aggregate epsem */
128 static int hf_c1222_epsem_total;
129 /* generic command */
130 static int hf_c1222_cmd;
131 static int hf_c1222_err;
132 static int hf_c1222_data;
133 /* individual epsem fields */
134 static int hf_c1222_logon_id;
135 static int hf_c1222_logon_user;
136 static int hf_c1222_security_password;
137 static int hf_c1222_auth_len;
138 static int hf_c1222_auth_data;
139 static int hf_c1222_read_table;
140 static int hf_c1222_read_offset;
141 static int hf_c1222_read_count;
142 static int hf_c1222_write_table;
143 static int hf_c1222_write_offset;
144 static int hf_c1222_write_size;
145 static int hf_c1222_write_data;
146 static int hf_c1222_procedure_response;
147 static int hf_c1222_procedure_mfg;
148 static int hf_c1222_procedure_num;
149 static int hf_c1222_procedure_sequence;
150 static int hf_c1222_write_chksum;
151 static int hf_c1222_write_chksum_status;
152 static int hf_c1222_wait_secs;
153 static int hf_c1222_neg_pkt_size;
154 static int hf_c1222_neg_nbr_pkts;
155 static int hf_c1222_timing_setup_traffic;
156 static int hf_c1222_timing_setup_inter_char;
157 static int hf_c1222_timing_setup_resp_to;
158 static int hf_c1222_timing_setup_nbr_retries;
160 /* the MAC */
161 static int hf_c1222_epsem_mac;
163 /* crypto result flags */
164 static int hf_c1222_epsem_crypto_good;
165 static int hf_c1222_epsem_crypto_bad;
167 /* Initialize the subtree pointers */
168 static int ett_c1222;
169 static int ett_c1222_epsem;
170 static int ett_c1222_flags;
171 static int ett_c1222_crypto;
172 static int ett_c1222_cmd;
174 /* these pointers are for the header elements that may be needed to verify the crypto */
175 static uint8_t *aSO_context;
176 static uint8_t *called_AP_title;
177 static uint8_t *called_AP_invocation_id;
178 static uint8_t *calling_AE_qualifier;
179 static uint8_t *calling_AP_invocation_id;
180 static uint8_t *mechanism_name;
181 static uint8_t *calling_authentication_value;
182 static uint8_t *user_information;
183 static uint8_t *calling_AP_title;
184 static uint8_t *key_id_element;
185 static uint8_t *iv_element;
187 /* these are the related lengths */
188 static uint32_t aSO_context_len;
189 static uint32_t called_AP_title_len;
190 static uint32_t called_AP_invocation_id_len;
191 static uint32_t calling_AE_qualifier_len;
192 static uint32_t calling_AP_invocation_id_len;
193 static uint32_t mechanism_name_len;
194 static uint32_t calling_authentication_value_len;
195 static uint32_t user_information_len;
196 static uint32_t calling_AP_title_len;
197 static uint32_t key_id_element_len;
198 static uint32_t iv_element_len;
200 /* these are the related allocation sizes (which might be different from the lengths) */
201 static uint32_t aSO_context_allocated;
202 static uint32_t called_AP_title_allocated;
203 static uint32_t called_AP_invocation_id_allocated;
204 static uint32_t calling_AE_qualifier_allocated;
205 static uint32_t calling_AP_invocation_id_allocated;
206 static uint32_t mechanism_name_allocated;
207 static uint32_t calling_authentication_value_allocated;
208 static uint32_t user_information_allocated;
209 static uint32_t calling_AP_title_allocated;
210 static uint32_t key_id_element_allocated;
211 static uint32_t iv_element_allocated;
213 static int ett_c1222_MESSAGE_U;
214 static int ett_c1222_Called_AP_title;
215 static int ett_c1222_Calling_AP_title;
216 static int ett_c1222_Calling_authentication_value_U;
217 static int ett_c1222_Authentication_value_encoding;
218 static int ett_c1222_Calling_authentication_value_single_asn1;
219 static int ett_c1222_Calling_authentication_value_c1222_U;
220 static int ett_c1222_Calling_authentication_value_c1221_U;
222 static expert_field ei_c1222_command_truncated;
223 static expert_field ei_c1222_bad_checksum;
224 static expert_field ei_c1222_epsem_missing;
225 static expert_field ei_c1222_epsem_failed_authentication;
226 static expert_field ei_c1222_epsem_not_decrypted;
227 static expert_field ei_c1222_ed_class_missing;
228 static expert_field ei_c1222_epsem_ber_length_error;
229 static expert_field ei_c1222_epsem_field_length_error;
230 static expert_field ei_c1222_mac_missing;
232 /* Preferences */
233 static bool c1222_desegment = true;
234 static bool c1222_decrypt = true;
235 static bool c1222_big_endian;
236 static const char *c1222_baseoid_str;
237 static uint8_t *c1222_baseoid;
238 static unsigned c1222_baseoid_len;
240 /*------------------------------
241 * Data Structures
242 *------------------------------
244 static const value_string c1222_security_modes[] = {
245 { 0x00, "Cleartext"},
246 { 0x01, "Cleartext with authentication"},
247 { 0x02, "Ciphertext with authentication"},
248 { 0, NULL }
251 static const value_string c1222_response_control[] = {
252 { 0x00, "Always respond"},
253 { 0x01, "Respond on exception"},
254 { 0x02, "Never respond"},
255 { 0, NULL }
258 static const value_string tableflags[] = {
259 { 0x00, "ST" },
260 { 0x08, "MT" },
261 { 0x10, "Pending ST" },
262 { 0x18, "Pending MT" },
263 { 0x20, "UDT" },
264 { 0x30, "Pending UDT" },
265 { 0, NULL }
268 static const value_string procflags[] = {
269 { 0x00, "SF" },
270 { 0x08, "MF" },
271 { 0, NULL }
274 static const value_string c1222_proc_response_control[] = {
275 { 0x00, "Post response in ST-8 on completion" },
276 { 0x01, "Post response in ST-8 on exception" },
277 { 0x02, "Do not post response in ST-8" },
278 { 0x03, "Post response in ST-8 now, and on completion" },
279 { 0, NULL }
282 static const value_string commandnames[] = {
283 /* error codes are in the range 0x00 - 0x1f inclusive */
284 { 0x00, "OK" },
285 { 0x01, "Error" },
286 { 0x02, "Service Not Supported" },
287 { 0x03, "Insufficient Security Clearance" },
288 { 0x04, "Operation Not Possible" },
289 { 0x05, "Inappropriate Action Requested" },
290 { 0x06, "Device Busy" },
291 { 0x07, "Data Not Ready" },
292 { 0x08, "Data Locked" },
293 { 0x09, "Renegotiate Request" },
294 { 0x0A, "Invalid Service Sequence State" },
295 { 0x0B, "Security Mechanism Error" },
296 { 0x0C, "Unknown Application Title" },
297 { 0x0D, "Network Time-out" },
298 { 0x0E, "Network Not Reachable" },
299 { 0x0F, "Request Too Large" },
300 { 0x10, "Response Too Large" },
301 { 0x11, "Segmentation Not Possible" },
302 { 0x12, "Segmentation Error" },
303 /* commands are in the range 0x20 - 0x7f inclusive */
304 {C1222_CMD_IDENTIFY, "Identify" },
305 {C1222_CMD_TERMINATE, "Terminate" },
306 {C1222_CMD_DISCONNECT, "Disconnect" },
307 {C1222_CMD_FULL_READ, "Full Read" },
308 {C1222_CMD_DEFAULT_READ, "Default Read" },
309 {C1222_CMD_PARTIAL_READ_OFFSET, "Partial Read Offset" },
310 {C1222_CMD_FULL_WRITE, "Full Write" },
311 {C1222_CMD_DEFAULT_WRITE, "Default Write" },
312 {C1222_CMD_PARTIAL_WRITE_OFFSET, "Partial Write Offset" },
313 {C1222_CMD_LOGON, "Logon" },
314 {C1222_CMD_SECURITY, "Security" },
315 {C1222_CMD_LOGOFF, "Logoff" },
316 {C1222_CMD_AUTHENTICATE, "Authenticate" },
317 {C1222_CMD_NEGOTIATE, "Negotiate" },
318 {C1222_CMD_NEGOTIATE | 0x1, "Negotiate w/ 1 Baud Rate" },
319 {C1222_CMD_NEGOTIATE | 0x2, "Negotiate w/ 2 Baud Rates" },
320 {C1222_CMD_NEGOTIATE | 0x3, "Negotiate w/ 3 Baud Rates" },
321 {C1222_CMD_NEGOTIATE | 0x4, "Negotiate w/ 4 Baud Rates" },
322 {C1222_CMD_NEGOTIATE | 0x5, "Negotiate w/ 5 Baud Rates" },
323 {C1222_CMD_NEGOTIATE | 0x6, "Negotiate w/ 6 Baud Rates" },
324 {C1222_CMD_NEGOTIATE | 0x7, "Negotiate w/ 7 Baud Rates" },
325 {C1222_CMD_NEGOTIATE | 0x8, "Negotiate w/ 8 Baud Rates" },
326 {C1222_CMD_NEGOTIATE | 0x9, "Negotiate w/ 9 Baud Rates" },
327 {C1222_CMD_NEGOTIATE | 0xA, "Negotiate w/ 10 Baud Rates" },
328 {C1222_CMD_NEGOTIATE | 0xB, "Negotiate w/ 11 Baud Rates" },
329 {C1222_CMD_WAIT, "Wait" },
330 {C1222_CMD_TIMING_SETUP, "Timing Setup" },
331 { 0, NULL }
334 /* these are for the key tables */
335 typedef struct _c1222_uat_data {
336 unsigned keynum;
337 unsigned char *key;
338 unsigned keylen;
339 } c1222_uat_data_t;
341 UAT_HEX_CB_DEF(c1222_users, keynum, c1222_uat_data_t)
342 UAT_BUFFER_CB_DEF(c1222_users, key, c1222_uat_data_t, key, keylen)
344 static c1222_uat_data_t *c1222_uat_data;
345 static unsigned num_c1222_uat_data;
346 static uat_t *c1222_uat;
348 /* these macros ares used to populate fields needed to verify crypto */
349 #define FILL_START int length, start_offset = offset;
350 #define FILL_TABLE(fieldname) \
351 length = offset - start_offset; \
352 fieldname = (uint8_t *)tvb_memdup(actx->pinfo->pool, tvb, start_offset, length); \
353 fieldname##_len = length; \
354 fieldname##_allocated = length;
355 #define FILL_TABLE_TRUNCATE(fieldname, len) \
356 length = 1 + 2*(offset - start_offset); \
357 fieldname = (uint8_t *)tvb_memdup(actx->pinfo->pool, tvb, start_offset, length); \
358 fieldname##_len = len; \
359 fieldname##_allocated = length;
360 #define FILL_TABLE_APTITLE(fieldname) \
361 length = offset - start_offset; \
362 switch (tvb_get_uint8(tvb, start_offset)) { \
363 case 0x80: /* relative OID */ \
364 tvb_ensure_bytes_exist(tvb, start_offset, length); \
365 fieldname##_len = length + c1222_baseoid_len; \
366 fieldname = (uint8_t *)wmem_alloc(actx->pinfo->pool, fieldname##_len); \
367 fieldname##_allocated = fieldname##_len; \
368 fieldname[0] = 0x06; /* create absolute OID tag */ \
369 fieldname[1] = (fieldname##_len - 2) & 0xff; \
370 memcpy(&(fieldname[2]), c1222_baseoid, c1222_baseoid_len); \
371 tvb_memcpy(tvb, &(fieldname[c1222_baseoid_len+2]), start_offset+2, length-2); \
372 break; \
373 case 0x06: /* absolute OID */ \
374 default: \
375 fieldname = (uint8_t *)tvb_memdup(actx->pinfo->pool, tvb, start_offset, length); \
376 fieldname##_len = length; \
377 fieldname##_allocated = length; \
378 break; \
381 /*------------------------------
382 * Function Prototypes
383 *------------------------------
385 void proto_reg_handoff_c1222(void);
388 /*------------------------------
389 * Code
390 *------------------------------
394 * Calculates simple one's complement checksum.
396 * \param tvb pointer to tvbuff containing data to be checksummed
397 * \param offset offset within tvbuff to beginning of data
398 * \param len length of data to be checksummed
399 * \returns calculated checksum
401 static uint8_t
402 c1222_cksum(tvbuff_t *tvb, int offset, int len)
404 uint8_t sum;
405 for (sum = 0; len; offset++, len--)
406 sum += tvb_get_uint8(tvb, offset);
407 return ~sum + 1;
410 * Dissects C12.22 packet in detail (with a tree).
412 * \param tvb input buffer containing packet to be dissected
413 * \param pinfo the packet info of the current data
414 * \param tree the tree to append this item to
415 * \param length length of data
416 * \param offset the offset in the tvb
418 static void
419 parse_c1222_detailed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int cmd, uint32_t *length, int *offset)
421 uint16_t user_id = 0;
422 const uint8_t *user_name = NULL;
423 const uint8_t *password = NULL;
424 uint8_t auth_len = 0;
425 char *auth_req = NULL;
426 uint16_t table = 0;
427 uint16_t tblsize = 0;
428 uint16_t calcsum = 0;
429 uint8_t wait_seconds = 0;
430 uint8_t proc_seq = 0;
431 int numrates = 0;
432 uint16_t packet_size;
433 uint16_t procedure_num = 0;
434 uint8_t nbr_packet;
435 /* timing setup parameters */
436 uint8_t traffic;
437 uint8_t inter_char;
438 uint8_t resp_to;
439 uint8_t nbr_retries;
441 /* special case to simplify handling of Negotiate service */
442 if ((cmd & 0xF0) == C1222_CMD_NEGOTIATE) {
443 numrates = cmd & 0x0F;
444 cmd = C1222_CMD_NEGOTIATE;
446 proto_tree_add_uint(tree, cmd >= 0x20 ? hf_c1222_cmd : hf_c1222_err, tvb, *offset, 1, cmd);
447 (*offset)++;
448 (*length)--;
449 switch (cmd) {
450 case C1222_CMD_LOGON:
451 if (*length >= 12) {
452 user_id = tvb_get_ntohs(tvb, *offset);
453 proto_tree_add_uint(tree, hf_c1222_logon_id, tvb, *offset, 2, user_id);
454 *offset += 2;
455 proto_tree_add_item_ret_string(tree, hf_c1222_logon_user, tvb, *offset, 10, ENC_ASCII|ENC_NA, pinfo->pool, &user_name);
456 *offset += 10;
457 *length -= 12;
458 proto_item_set_text(tree, "C12.22 EPSEM: %s (id %d, user \"%s\")",
459 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), user_id, user_name);
460 } else {
461 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 LOGON command truncated");
463 break;
464 case C1222_CMD_SECURITY:
465 if (*length >= 20) {
466 proto_tree_add_item_ret_string(tree, hf_c1222_security_password, tvb, *offset, 20, ENC_ASCII|ENC_NA, pinfo->pool, &password);
467 *offset += 20;
468 *length -= 20;
469 if (*length >= 2) {
470 user_id = tvb_get_ntohs(tvb, *offset);
471 proto_tree_add_uint(tree, hf_c1222_logon_id, tvb, *offset, 2, user_id);
472 *offset += 2;
473 *length -= 2;
474 proto_item_set_text(tree, "C12.22 EPSEM: %s (password \"%s\", id %d)",
475 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), password, user_id);
476 } else {
477 proto_item_set_text(tree, "C12.22 EPSEM: %s (password \"%s\")",
478 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), password);
480 } else {
481 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 SECURITY command truncated");
483 break;
484 case C1222_CMD_AUTHENTICATE:
485 if (*length >= 1) {
486 auth_len = tvb_get_uint8(tvb, *offset);
487 proto_tree_add_uint(tree, hf_c1222_auth_len, tvb, *offset, 1, auth_len);
488 *offset += 1;
489 if (*length >= auth_len) {
490 auth_req = tvb_bytes_to_str(pinfo->pool, tvb, *offset, auth_len);
491 proto_tree_add_item(tree, hf_c1222_auth_data, tvb, *offset, auth_len, ENC_NA);
492 *offset += auth_len;
493 *length -= auth_len + 1;
494 proto_item_set_text(tree, "C12.22 EPSEM: %s (%d bytes: %s)",
495 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), auth_len, auth_req);
496 } else {
497 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 AUTHENTICATE command truncated");
499 } else {
500 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 AUTHENTICATE command truncated");
502 break;
503 case C1222_CMD_FULL_READ:
504 if (*length >= 2) {
505 table = tvb_get_ntohs(tvb, *offset);
506 proto_tree_add_uint(tree, hf_c1222_read_table, tvb, *offset, 2, table);
507 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
508 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
509 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
510 *offset += 2;
511 *length -= 2;
512 } else {
513 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 READ command truncated");
515 break;
516 case C1222_CMD_PARTIAL_READ_OFFSET:
517 if (*length >= 7) {
518 table = tvb_get_ntohs(tvb, *offset);
519 proto_tree_add_uint(tree, hf_c1222_read_table, tvb, *offset, 2, table);
520 *offset += 2;
521 *length -= 2;
522 proto_tree_add_item(tree, hf_c1222_read_offset, tvb, *offset, 3, ENC_BIG_ENDIAN);
523 *offset += 3;
524 *length -= 3;
525 proto_tree_add_item(tree, hf_c1222_read_count, tvb, *offset, 2, ENC_BIG_ENDIAN);
526 *offset += 2;
527 *length -= 2;
528 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
529 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
530 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
531 } else {
532 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 READ command truncated");
534 break;
535 case C1222_CMD_FULL_WRITE:
536 if (*length >= 5) {
537 table = tvb_get_ntohs(tvb, *offset);
538 proto_tree_add_uint(tree, hf_c1222_write_table, tvb, *offset, 2, table);
539 *offset += 2;
540 *length -= 2;
541 tblsize = tvb_get_ntohs(tvb, *offset);
542 proto_tree_add_uint(tree, hf_c1222_write_size, tvb, *offset, 2, tblsize);
543 *offset += 2;
544 *length -= 2;
545 if (*length >= tblsize+1U) {
546 if (table == 7) {/* is it a procedure call? */
547 procedure_num = tvb_get_uint16(tvb, *offset, c1222_big_endian ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN);
548 proto_tree_add_uint(tree, hf_c1222_procedure_response, tvb, *offset, 2, procedure_num);
549 proto_tree_add_uint(tree, hf_c1222_procedure_mfg, tvb, *offset, 2, procedure_num);
550 proto_tree_add_uint(tree, hf_c1222_procedure_num, tvb, *offset, 2, procedure_num);
551 *offset += 2;
552 *length -= 2;
553 proc_seq = tvb_get_uint8(tvb, *offset);
554 proto_tree_add_uint(tree, hf_c1222_procedure_sequence, tvb, *offset, 1, proc_seq);
555 *offset += 1;
556 *length -= 1;
557 tblsize -= 3;
559 proto_tree_add_item(tree, hf_c1222_write_data, tvb, *offset, tblsize, ENC_NA);
560 *offset += tblsize;
561 *length -= tblsize;
562 if (table == 7) {/* is it a procedure call? */
563 calcsum = c1222_cksum(tvb, (*offset)-tblsize-3, tblsize+3);
564 } else {
565 calcsum = c1222_cksum(tvb, (*offset)-tblsize, tblsize);
567 proto_tree_add_checksum(tree, tvb, *offset, hf_c1222_write_chksum, hf_c1222_write_chksum_status,
568 &ei_c1222_bad_checksum, pinfo, calcsum, ENC_NA, PROTO_CHECKSUM_VERIFY);
570 if (table == 7) {/* is it a procedure call? */
571 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d, %s-%d)",
572 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
573 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF,
574 val_to_str((procedure_num >> 8) & 0x08, procflags,"Unknown (0x%04x)"), procedure_num & 0x7FF);
575 } else {
576 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
577 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
578 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
580 *offset += 1;
581 *length -= 1;
582 } else {
583 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
585 } else {
586 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
588 break;
589 case C1222_CMD_PARTIAL_WRITE_OFFSET:
590 if (*length >= 8) {
591 table = tvb_get_ntohs(tvb, *offset);
592 proto_tree_add_uint(tree, hf_c1222_write_table, tvb, *offset, 2, table);
593 *offset += 2;
594 *length -= 2;
595 proto_tree_add_item(tree, hf_c1222_write_offset, tvb, *offset, 3, ENC_BIG_ENDIAN);
596 *offset += 3;
597 *length -= 3;
598 tblsize = tvb_get_ntohs(tvb, *offset);
599 proto_tree_add_uint(tree, hf_c1222_write_size, tvb, *offset, 2, tblsize);
600 *offset += 2;
601 *length -= 2;
602 if (*length >= tblsize+1U) {
603 proto_tree_add_item(tree, hf_c1222_write_data, tvb, *offset, tblsize, ENC_NA);
604 *offset += tblsize;
605 *length -= tblsize;
606 calcsum = c1222_cksum(tvb, (*offset)-tblsize, tblsize);
607 proto_tree_add_checksum(tree, tvb, *offset, hf_c1222_write_chksum, hf_c1222_write_chksum_status,
608 &ei_c1222_bad_checksum, pinfo, calcsum, ENC_NA, PROTO_CHECKSUM_VERIFY);
609 proto_item_set_text(tree, "C12.22 EPSEM: %s (%s-%d)",
610 val_to_str(cmd,commandnames,"Unknown (0x%02x)"),
611 val_to_str((table >> 8) & 0xF8, tableflags,"Unknown (0x%04x)"), table & 0x7FF);
612 *offset += 1;
613 *length -= 1;
614 } else {
615 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
617 } else {
618 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WRITE command truncated");
620 break;
621 case C1222_CMD_WAIT:
622 if (*length >= 1) {
623 wait_seconds = tvb_get_uint8(tvb, *offset);
624 proto_tree_add_uint(tree, hf_c1222_wait_secs, tvb, *offset, 1, wait_seconds);
625 *offset += 1;
626 *length -= 1;
627 proto_item_set_text(tree, "C12.22 EPSEM: %s (%d seconds)",
628 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), wait_seconds);
629 } else {
630 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 WAIT command truncated");
632 break;
633 case C1222_CMD_NEGOTIATE:
634 if (*length >= 3) {
635 packet_size = tvb_get_ntohs(tvb, *offset);
636 proto_tree_add_uint(tree, hf_c1222_neg_pkt_size, tvb, *offset, 2, packet_size);
637 *offset += 2;
638 *length -= 2;
639 nbr_packet = tvb_get_uint8(tvb, *offset);
640 proto_tree_add_uint(tree, hf_c1222_neg_nbr_pkts, tvb, *offset, 1, nbr_packet);
641 *offset += 1;
642 *length -= 1;
643 proto_item_set_text(tree, "C12.22 EPSEM: %s (pkt size %d, num pkts %d, with %d baud rates)",
644 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), packet_size, nbr_packet, numrates);
645 } else {
646 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 NEGOTIATE command truncated");
648 break;
649 case C1222_CMD_TIMING_SETUP:
650 if (*length >= 4) {
651 traffic = tvb_get_uint8(tvb, *offset);
652 proto_tree_add_uint(tree, hf_c1222_timing_setup_traffic, tvb, *offset, 1, traffic);
653 *offset += 1;
654 *length -= 1;
655 inter_char = tvb_get_uint8(tvb, *offset);
656 proto_tree_add_uint(tree, hf_c1222_timing_setup_inter_char, tvb, *offset, 1, inter_char);
657 *offset += 1;
658 *length -= 1;
659 resp_to = tvb_get_uint8(tvb, *offset);
660 proto_tree_add_uint(tree, hf_c1222_timing_setup_resp_to, tvb, *offset, 1, resp_to);
661 *offset += 1;
662 *length -= 1;
663 nbr_retries = tvb_get_uint8(tvb, *offset);
664 proto_tree_add_uint(tree, hf_c1222_timing_setup_nbr_retries, tvb, *offset, 1, nbr_retries);
665 *offset += 1;
666 *length -= 1;
667 proto_item_set_text(tree, "C12.22 EPSEM: %s (traffic to %d s, inter-char to %d s, response to %d s, %d retries)",
668 val_to_str(cmd,commandnames,"Unknown (0x%02x)"), traffic, inter_char, resp_to, nbr_retries);
669 } else {
670 expert_add_info_format(pinfo, tree, &ei_c1222_command_truncated, "C12.22 NEGOTIATE command truncated");
672 break;
674 default:
675 /* don't do anything */
676 proto_item_set_text(tree, "C12.22 EPSEM: %s", val_to_str(cmd, commandnames, "Unknown (0x%02x)"));
677 if (*length) {
678 proto_tree_add_item(tree, hf_c1222_data, tvb, *offset, *length, ENC_NA);
680 break;
684 typedef struct tagTOP_ELEMENT_CONTROL
686 /* true if this tag is required */
687 bool required;
688 /* true if we must truncate this tag */
689 bool truncate;
690 /* actual hex value of the tag we're seeking */
691 uint8_t tag;
692 /* if true, add tag and length before copying */
693 bool addtag;
694 /* pointer to pointer to memory copy of element */
695 uint8_t **element;
696 /* pointer to element length */
697 uint32_t *length;
698 /* pointer to element allocated size */
699 uint32_t *allocated;
700 } TOP_ELEMENT_CONTROL;
702 static const TOP_ELEMENT_CONTROL canonifyTable[] = {
703 { false, false, 0xA1, true, &aSO_context, &aSO_context_len, &aSO_context_allocated },
704 { true , false, 0xA2, true, &called_AP_title, &called_AP_title_len, &called_AP_title_allocated },
705 { false, false, 0xA4, true, &called_AP_invocation_id, &called_AP_invocation_id_len, &called_AP_invocation_id_allocated },
706 { false, false, 0xA7, true, &calling_AE_qualifier, &calling_AE_qualifier_len, &calling_AE_qualifier_allocated },
707 { true, false, 0xA8, true, &calling_AP_invocation_id, &calling_AP_invocation_id_len, &calling_AP_invocation_id_allocated },
708 { false, false, 0x8B, true, &mechanism_name, &mechanism_name_len, &mechanism_name_allocated },
709 { false, false, 0xAC, true, &calling_authentication_value, &calling_authentication_value_len, &calling_authentication_value_allocated },
710 { true , true , 0xBE, true, &user_information, &user_information_len, &user_information_allocated },
711 { false, false, 0xA6, true, &calling_AP_title, &calling_AP_title_len, &calling_AP_title_allocated },
712 { false, false, 0xAC, false, &key_id_element, &key_id_element_len, &key_id_element_allocated },
713 { false, false, 0xAC, false, &iv_element, &iv_element_len, &iv_element_allocated },
714 { false, false, 0x0, true, NULL, NULL, NULL }
717 static void
718 clear_canon(void)
720 const TOP_ELEMENT_CONTROL *t = canonifyTable;
722 for (t = canonifyTable; t->element != NULL; t++) {
723 *(t->length) = 0;
724 *(t->element) = NULL;
729 * Calculates the size of the passed number n as encoded as a BER length field.
731 * \param n is the length value to be BER encoded
732 * \returns the sized of the encoding
734 static uint32_t
735 get_ber_len_size(uint32_t n)
737 uint32_t len = 1;
738 if (n > 0x7f) len++;
739 if (n > 0xff) len++;
740 if (n > 0xffff) len++;
741 if (n > 0xffffff) len++;
742 return len;
745 * Encodes the passed value n as a BER-encoded length at puts it in memory.
747 * \param ptr points to the buffer to be written
748 * \param n is the length to be BER encoded
749 * \param maxsize is the maximum number of bytes we're allowed to write
750 * \returns length of encoded value in bytes
752 static int
753 encode_ber_len(uint8_t *ptr, uint32_t n, int maxsize)
755 int len = get_ber_len_size(n);
756 if (len > maxsize) return 0;
757 if (len == 1) {
758 *ptr = 0x7f & n;
759 } else {
760 *ptr = (len -1) | 0x80;
761 for (ptr += len-1; n; n >>= 8)
762 *ptr-- = n & 0xff;
764 return len;
768 static void*
769 c1222_uat_data_copy_cb(void *dest, const void *source, size_t len _U_)
771 const c1222_uat_data_t* o = (const c1222_uat_data_t*)source;
772 c1222_uat_data_t* d = (c1222_uat_data_t*)dest;
774 d->keynum = o->keynum;
775 d->keylen = o->keylen;
776 d->key = (unsigned char *)g_memdup2(o->key, o->keylen);
778 return dest;
782 * Checks a new encryption table item for validity.
784 * \param n points to the new record
785 * \param err is updated to point to an error string if needed
786 * \return false if error; true otherwise
788 static bool
789 c1222_uat_data_update_cb(void* n, char** err)
791 c1222_uat_data_t* new_rec = (c1222_uat_data_t *)n;
793 if (new_rec->keynum > 0xff) {
794 *err = g_strdup("Invalid key number; must be less than 256");
795 return false;
797 if (new_rec->keylen != EAX_SIZEOF_KEY) {
798 *err = g_strdup("Invalid key size; must be 16 bytes");
799 return false;
801 return true;
804 static void
805 c1222_uat_data_free_cb(void *r)
807 c1222_uat_data_t *rec = (c1222_uat_data_t *)r;
808 g_free(rec->key);
812 * Canonifies header fields in preparation for authenticating and/or decrypting the packet.
814 * \param buff points to the allocated canonization buffer
815 * \param offset points to start of unallocated space in buffer and
816 is updated as we put bytes into buffer
817 * \param buffsize total size of allocated buffer
818 * \return false if element is required and not present; otherwise true
820 static bool
821 canonify_unencrypted_header(unsigned char *buff, uint32_t *offset, uint32_t buffsize)
823 const TOP_ELEMENT_CONTROL *t = canonifyTable;
824 uint32_t len, allocated;
826 for (t = canonifyTable; t->element != NULL; t++)
828 len = *(t->length);
829 allocated = *(t->allocated);
830 if (t->required && *(t->element) == NULL)
831 return false;
832 if (*(t->element) != NULL) {
833 if (t->addtag) {
834 /* recreate original tag and length */
835 buff[(*offset)++] = t->tag;
836 (*offset) += encode_ber_len(&buff[*offset], len, 4);
838 if (t->truncate) {
839 len = 3+2*get_ber_len_size(len);
841 /* bail out if the cannonization buffer is too small */
842 /* this should never happen! */
843 if (buffsize < *offset + len) {
844 return false;
846 /* bail out if our we're trying to read past the end of our element */
847 /* the network is always hostile */
848 if (allocated < len) {
849 return false;
851 memcpy(&buff[*offset], *(t->element), len);
852 (*offset) += len;
853 if (t->addtag) {
854 *(t->element) = NULL;
858 return true;
862 * Looks up the required key in the key table.
864 * \param keybuff is updated with a copy of the key data if successful lookup.
865 * \param keyid is the ID number of the desired key
866 * \returns true if key was found; otherwise false
868 static bool
869 keylookup(uint8_t *keybuff, uint8_t keyid)
871 unsigned i;
873 if (c1222_uat_data == NULL)
874 return false;
875 for (i = 0; i < num_c1222_uat_data; i++) {
876 if (c1222_uat_data[i].keynum == keyid) {
877 memcpy(keybuff, c1222_uat_data[i].key, EAX_SIZEOF_KEY);
878 return true;
881 return false;
885 * Authenticates and decrypts the passed packet.
887 * \param buffer points to a memory copy of the packet to be authenticated/decrypted
888 * and contains the decrypted value on successful return.
889 * \param length lenth of input packet
890 * \param decrypt true if packet is to be authenticated and decrypted; false if authentication only is requested
891 * \returns true if the requested operation was successful; otherwise false
893 static bool
894 decrypt_packet(unsigned char *buffer, uint32_t length, bool decrypt)
896 #define CANONBUFFSIZE 300U
897 unsigned char canonbuff[CANONBUFFSIZE];
898 uint8_t c1222_key[EAX_SIZEOF_KEY];
899 unsigned char key_id = 0;
900 uint32_t offset = 0;
901 bool status = false;
903 /* must be at least 4 bytes long to include the MAC */
904 if (length < 4)
905 return status;
906 if (key_id_element != NULL)
907 key_id = key_id_element[0];
908 /* extract unencrypted header information */
909 if (!canonify_unencrypted_header(canonbuff, &offset, CANONBUFFSIZE))
910 return status;
911 /* decrypt and authenticate in place */
912 /* PARAMETERS: pN : Pointer to ClearText (Input, Canonified form). */
913 /* pK : Pointer to secret key (Input). */
914 /* pC : Pointer to CipherText (Input/Output). */
915 /* SizeN : Byte length of ClearText buffer. */
916 /* SizeK : Byte length of secret key. */
917 /* SizeC : Byte length of CipherText buffer. */
918 /* pMac : Four byte Message Authentication Code. */
919 /* Mode : Operating mode (See EAX_MODE_xxx). */
920 /* RETURNS: true if message has been authenticated. */
921 /* false if not authenticated, invalid Mode, or error. */
922 if (offset) {
923 if (!keylookup((uint8_t *)&c1222_key, key_id))
924 return false;
925 status = Eax_Decrypt(canonbuff, c1222_key, buffer,
926 offset, EAX_SIZEOF_KEY, length-4,
927 (MAC_T *)&buffer[length-4],
928 decrypt ? EAX_MODE_CIPHERTEXT_AUTH : EAX_MODE_CLEARTEXT_AUTH);
930 return status;
934 * Checks to make sure that a complete, valid BER-encoded length is in the buffer.
936 * \param tvb contains the buffer to be examined
937 * \param offset is the offset within the buffer at which the BER-encoded length begins
938 * \returns true if a complete, valid BER-encoded length is in the buffer; otherwise false
940 static bool
941 ber_len_ok(tvbuff_t *tvb, int offset)
943 uint8_t ch;
945 if (tvb_offset_exists(tvb, offset)) {
946 ch = tvb_get_uint8(tvb, offset);
947 offset++;
948 if (!(ch & 0x80)) {
949 return true;
950 } else if (tvb_offset_exists(tvb, offset)) {
951 ch = tvb_get_uint8(tvb, offset);
952 offset++;
953 if (!(ch & 0x80)) {
954 return true;
955 } else if (tvb_offset_exists(tvb, offset)) {
956 ch = tvb_get_uint8(tvb, offset);
957 offset++;
958 if (!(ch & 0x80)) {
959 return true;
960 } else if (tvb_offset_exists(tvb, offset)) {
961 ch = tvb_get_uint8(tvb, offset);
962 /*offset++;*/
963 if (!(ch & 0x80)) {
964 return true;
970 return false;
974 * Dissects the EPSEM portion of the User-information part of a C12.22 message.
976 * \param tvb the tv buffer of the current data
977 * \param offset the offset in the tvb
978 * \param len length of data
979 * \param pinfo the packet info of the current data
980 * \param tree the tree to append this item to
982 static int
983 dissect_epsem(tvbuff_t *tvb, int offset, uint32_t len, packet_info *pinfo, proto_tree *tree)
985 proto_tree *cmd_tree = NULL;
986 proto_tree *ct = NULL;
987 proto_tree *crypto_tree = NULL;
988 proto_tree *yt = NULL;
989 proto_item *item = NULL;
990 uint8_t flags;
991 int local_offset;
992 int len2;
993 int cmd_err;
994 bool ind;
995 unsigned char *buffer;
996 tvbuff_t *epsem_buffer = NULL;
997 bool crypto_good = false;
998 bool crypto_bad = false;
999 bool hasmac = false;
1000 bool encrypted = false;
1002 if ((tvb == NULL) && (len == 0)) {
1003 expert_add_info(pinfo, tree, &ei_c1222_epsem_missing);
1004 return offset;
1006 /* parse the flags byte which is always unencrypted */
1007 flags = tvb_get_uint8(tvb, offset);
1008 proto_tree_add_bitmask(tree, tvb, offset, hf_c1222_epsem_flags, ett_c1222_flags, c1222_flags, ENC_BIG_ENDIAN);
1009 offset++;
1010 switch ((flags & C1222_EPSEM_FLAG_SECURITY_MODE) >> 2) {
1011 case EAX_MODE_CIPHERTEXT_AUTH:
1012 /* mode is ciphertext with authentication */
1013 hasmac = true;
1014 len2 = tvb_reported_length_remaining(tvb, offset);
1015 if (len2 <= 0)
1016 return offset;
1017 encrypted = true;
1018 if (c1222_decrypt) {
1019 buffer = (unsigned char *)tvb_memdup(pinfo->pool, tvb, offset, len2);
1020 if (!decrypt_packet(buffer, len2, true)) {
1021 crypto_bad = true;
1022 } else {
1023 epsem_buffer = tvb_new_real_data(buffer, len2, len2);
1024 tvb_set_child_real_data_tvbuff(tvb, epsem_buffer);
1025 add_new_data_source(pinfo, epsem_buffer, "Decrypted EPSEM Data");
1026 crypto_good = true;
1027 encrypted = false;
1030 break;
1031 case EAX_MODE_CLEARTEXT_AUTH:
1032 /* mode is cleartext with authentication */
1033 hasmac = true;
1034 len2 = tvb_reported_length_remaining(tvb, offset);
1035 if (len2 <= 0)
1036 return offset;
1037 epsem_buffer = tvb_new_subset_remaining(tvb, offset);
1038 buffer = (unsigned char *)tvb_memdup(pinfo->pool, tvb, offset, len2);
1039 if (c1222_decrypt) {
1040 if (!decrypt_packet(buffer, len2, false)) {
1041 crypto_bad = true;
1042 expert_add_info(pinfo, tree, &ei_c1222_epsem_failed_authentication);
1043 } else {
1044 crypto_good = true;
1047 break;
1048 default:
1049 /* it's not encrypted */
1050 epsem_buffer = tvb_new_subset_remaining(tvb, offset);
1052 /* it's only encrypted if we have an undecrypted payload */
1053 if (encrypted) {
1054 proto_tree_add_item(tree, hf_c1222_epsem_total, tvb, offset, -1, ENC_NA);
1055 expert_add_info(pinfo, tree, &ei_c1222_epsem_not_decrypted);
1056 local_offset = offset+len2-4;
1057 epsem_buffer = tvb;
1058 } else { /* it's not (now) encrypted */
1059 local_offset = 0;
1060 /* retrieve the ed_class if it's there */
1061 if (flags & C1222_EPSEM_FLAG_ED_CLASS_INCLUDED) {
1062 if (tvb_offset_exists(epsem_buffer, local_offset+4-1)) {
1063 proto_tree_add_item(tree, hf_c1222_epsem_ed_class, epsem_buffer, local_offset, 4, ENC_NA);
1064 local_offset += 4;
1065 } else {
1066 expert_add_info(pinfo, tree, &ei_c1222_ed_class_missing);
1069 /* what follows are one or more <epsem-data> elements possibly followed by
1070 * a <mac>. Each <epsem-data> element is defined as <service-length><res-req>,
1071 * so we fetch such pairs until there isn't anything left (except possibly
1072 * the <mac>).
1074 while (tvb_offset_exists(epsem_buffer, local_offset+(hasmac?5:1))) {
1075 if (ber_len_ok(epsem_buffer, local_offset)) {
1076 local_offset = dissect_ber_length(pinfo, tree, epsem_buffer, local_offset, (uint32_t *)&len2, &ind);
1077 } else {
1078 expert_add_info(pinfo, tree, &ei_c1222_epsem_ber_length_error);
1079 return offset+len;
1081 if (tvb_offset_exists(epsem_buffer, local_offset+len2-1)) {
1082 cmd_err = tvb_get_uint8(epsem_buffer, local_offset);
1083 ct = proto_tree_add_item(tree, hf_c1222_epsem_total, epsem_buffer, local_offset, len2, ENC_NA);
1084 cmd_tree = proto_item_add_subtree(ct, ett_c1222_cmd);
1085 parse_c1222_detailed(epsem_buffer, pinfo, cmd_tree, cmd_err, (uint32_t *)&len2, &local_offset);
1086 local_offset += len2;
1087 } else {
1088 expert_add_info(pinfo, tree, &ei_c1222_epsem_field_length_error);
1089 return offset+len;
1093 if (hasmac) {
1094 if (tvb_offset_exists(epsem_buffer, local_offset+4-1)) {
1095 yt = proto_tree_add_item(tree, hf_c1222_epsem_mac, epsem_buffer, local_offset, 4, ENC_NA);
1096 /* now we have enough information to fill in the crypto subtree */
1097 crypto_tree = proto_item_add_subtree(yt, ett_c1222_crypto);
1098 item = proto_tree_add_boolean(crypto_tree, hf_c1222_epsem_crypto_good, tvb, local_offset, 4, crypto_good);
1099 proto_item_set_generated(item);
1100 item = proto_tree_add_boolean(crypto_tree, hf_c1222_epsem_crypto_bad, tvb, local_offset, 4, crypto_bad);
1101 proto_item_set_generated(item);
1102 } else {
1103 expert_add_info(pinfo, tree, &ei_c1222_mac_missing);
1104 return offset+len;
1107 return offset;
1112 static int
1113 dissect_c1222_ASO_qualifier(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1114 FILL_START;
1115 offset = dissect_ber_object_identifier(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
1117 FILL_TABLE(aSO_context);
1120 return offset;
1125 static int
1126 dissect_c1222_OBJECT_IDENTIFIER(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1127 offset = dissect_ber_object_identifier(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
1129 return offset;
1134 static int
1135 dissect_c1222_RELATIVE_OID(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1136 offset = dissect_ber_relative_oid(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
1138 return offset;
1142 static const value_string c1222_Called_AP_title_vals[] = {
1143 { 0, "called-ap-title-abs" },
1144 { 1, "called-ap-title-rel" },
1145 { 0, NULL }
1148 static const ber_choice_t Called_AP_title_choice[] = {
1149 { 0, &hf_c1222_called_ap_title_abs, BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_c1222_OBJECT_IDENTIFIER },
1150 { 1, &hf_c1222_called_ap_title_rel, BER_CLASS_CON, 0, BER_FLAGS_IMPLTAG, dissect_c1222_RELATIVE_OID },
1151 { 0, NULL, 0, 0, 0, NULL }
1154 static int
1155 dissect_c1222_Called_AP_title(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1156 FILL_START;
1157 offset = dissect_ber_choice(actx, tree, tvb, offset,
1158 Called_AP_title_choice, hf_index, ett_c1222_Called_AP_title,
1159 NULL);
1161 FILL_TABLE_APTITLE(called_AP_title);
1164 return offset;
1169 static int
1170 dissect_c1222_AP_invocation_id(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1171 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
1172 NULL);
1174 return offset;
1179 static int
1180 dissect_c1222_Called_AP_invocation_id(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1181 FILL_START;
1182 offset = dissect_c1222_AP_invocation_id(implicit_tag, tvb, offset, actx, tree, hf_index);
1184 FILL_TABLE(called_AP_invocation_id);
1187 return offset;
1191 static const value_string c1222_Calling_AP_title_vals[] = {
1192 { 0, "calling-ap-title-abs" },
1193 { 1, "calling-ap-title-rel" },
1194 { 0, NULL }
1197 static const ber_choice_t Calling_AP_title_choice[] = {
1198 { 0, &hf_c1222_calling_ap_title_abs, BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_c1222_OBJECT_IDENTIFIER },
1199 { 1, &hf_c1222_calling_ap_title_rel, BER_CLASS_CON, 0, BER_FLAGS_IMPLTAG, dissect_c1222_RELATIVE_OID },
1200 { 0, NULL, 0, 0, 0, NULL }
1203 static int
1204 dissect_c1222_Calling_AP_title(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1205 FILL_START;
1206 offset = dissect_ber_choice(actx, tree, tvb, offset,
1207 Calling_AP_title_choice, hf_index, ett_c1222_Calling_AP_title,
1208 NULL);
1210 FILL_TABLE_APTITLE(calling_AP_title);
1213 return offset;
1218 static int
1219 dissect_c1222_AE_qualifier(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1220 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
1221 NULL);
1223 return offset;
1228 static int
1229 dissect_c1222_Calling_AE_qualifier(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1230 FILL_START;
1231 offset = dissect_c1222_AE_qualifier(implicit_tag, tvb, offset, actx, tree, hf_index);
1233 FILL_TABLE(calling_AE_qualifier);
1236 return offset;
1241 static int
1242 dissect_c1222_Calling_AP_invocation_id(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1243 FILL_START;
1244 offset = dissect_c1222_AP_invocation_id(implicit_tag, tvb, offset, actx, tree, hf_index);
1246 FILL_TABLE(calling_AP_invocation_id);
1249 return offset;
1254 static int
1255 dissect_c1222_Mechanism_name(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1256 FILL_START;
1257 offset = dissect_ber_object_identifier(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
1259 FILL_TABLE(mechanism_name);
1262 return offset;
1267 static int
1268 dissect_c1222_INTEGER(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1269 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
1270 NULL);
1272 return offset;
1277 static int
1278 dissect_c1222_Key_id_element(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1279 FILL_START;
1280 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
1281 NULL);
1283 FILL_TABLE(key_id_element);
1286 return offset;
1291 static int
1292 dissect_c1222_Iv_element(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1293 FILL_START;
1294 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
1295 NULL);
1297 FILL_TABLE(iv_element);
1300 return offset;
1304 static const ber_sequence_t Calling_authentication_value_c1222_U_sequence[] = {
1305 { &hf_c1222_key_id_element, BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL|BER_FLAGS_IMPLTAG, dissect_c1222_Key_id_element },
1306 { &hf_c1222_iv_element , BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL|BER_FLAGS_IMPLTAG, dissect_c1222_Iv_element },
1307 { NULL, 0, 0, 0, NULL }
1310 static int
1311 dissect_c1222_Calling_authentication_value_c1222_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1312 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
1313 Calling_authentication_value_c1222_U_sequence, hf_index, ett_c1222_Calling_authentication_value_c1222_U);
1315 return offset;
1320 static int
1321 dissect_c1222_Calling_authentication_value_c1222(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1322 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
1323 hf_index, BER_CLASS_CON, 1, true, dissect_c1222_Calling_authentication_value_c1222_U);
1325 return offset;
1330 static int
1331 dissect_c1222_OCTET_STRING_SIZE_CONSTR001(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1332 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
1333 NULL);
1335 return offset;
1340 static int
1341 dissect_c1222_OCTET_STRING_SIZE_1_255(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1342 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
1343 NULL);
1345 return offset;
1350 static int
1351 dissect_c1222_OCTET_STRING_SIZE_CONSTR002(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1352 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
1353 NULL);
1355 return offset;
1359 static const value_string c1222_Calling_authentication_value_c1221_U_vals[] = {
1360 { 0, "c1221-auth-identification" },
1361 { 1, "c1221-auth-request" },
1362 { 2, "c1221-auth-response" },
1363 { 0, NULL }
1366 static const ber_choice_t Calling_authentication_value_c1221_U_choice[] = {
1367 { 0, &hf_c1222_c1221_auth_identification, BER_CLASS_CON, 0, BER_FLAGS_IMPLTAG, dissect_c1222_OCTET_STRING_SIZE_CONSTR001 },
1368 { 1, &hf_c1222_c1221_auth_request, BER_CLASS_CON, 1, BER_FLAGS_IMPLTAG, dissect_c1222_OCTET_STRING_SIZE_1_255 },
1369 { 2, &hf_c1222_c1221_auth_response, BER_CLASS_CON, 2, BER_FLAGS_IMPLTAG, dissect_c1222_OCTET_STRING_SIZE_CONSTR002 },
1370 { 0, NULL, 0, 0, 0, NULL }
1373 static int
1374 dissect_c1222_Calling_authentication_value_c1221_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1375 offset = dissect_ber_choice(actx, tree, tvb, offset,
1376 Calling_authentication_value_c1221_U_choice, hf_index, ett_c1222_Calling_authentication_value_c1221_U,
1377 NULL);
1379 return offset;
1384 static int
1385 dissect_c1222_Calling_authentication_value_c1221(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1386 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
1387 hf_index, BER_CLASS_CON, 0, true, dissect_c1222_Calling_authentication_value_c1221_U);
1389 return offset;
1393 static const value_string c1222_Calling_authentication_value_single_asn1_vals[] = {
1394 { 1, "calling-authentication-value-c1222" },
1395 { 0, "calling-authentication-value-c1221" },
1396 { 0, NULL }
1399 static const ber_choice_t Calling_authentication_value_single_asn1_choice[] = {
1400 { 1, &hf_c1222_calling_authentication_value_c1222, BER_CLASS_CON, 1, BER_FLAGS_NOOWNTAG, dissect_c1222_Calling_authentication_value_c1222 },
1401 { 0, &hf_c1222_calling_authentication_value_c1221, BER_CLASS_CON, 0, BER_FLAGS_NOOWNTAG, dissect_c1222_Calling_authentication_value_c1221 },
1402 { 0, NULL, 0, 0, 0, NULL }
1405 static int
1406 dissect_c1222_Calling_authentication_value_single_asn1(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1407 offset = dissect_ber_choice(actx, tree, tvb, offset,
1408 Calling_authentication_value_single_asn1_choice, hf_index, ett_c1222_Calling_authentication_value_single_asn1,
1409 NULL);
1411 return offset;
1416 static int
1417 dissect_c1222_OCTET_STRING(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1418 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
1419 NULL);
1421 return offset;
1425 static const value_string c1222_Authentication_value_encoding_vals[] = {
1426 { 0, "calling-authentication-value-single-asn1" },
1427 { 1, "calling-authentication-value-octet-aligned" },
1428 { 0, NULL }
1431 static const ber_choice_t Authentication_value_encoding_choice[] = {
1432 { 0, &hf_c1222_calling_authentication_value_single_asn1, BER_CLASS_CON, 0, 0, dissect_c1222_Calling_authentication_value_single_asn1 },
1433 { 1, &hf_c1222_calling_authentication_value_octet_aligned, BER_CLASS_CON, 1, BER_FLAGS_IMPLTAG, dissect_c1222_OCTET_STRING },
1434 { 0, NULL, 0, 0, 0, NULL }
1437 static int
1438 dissect_c1222_Authentication_value_encoding(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1439 offset = dissect_ber_choice(actx, tree, tvb, offset,
1440 Authentication_value_encoding_choice, hf_index, ett_c1222_Authentication_value_encoding,
1441 NULL);
1443 return offset;
1447 static const ber_sequence_t Calling_authentication_value_U_sequence[] = {
1448 { &hf_c1222_calling_authentication_value_indirect, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_OPTIONAL|BER_FLAGS_NOOWNTAG, dissect_c1222_INTEGER },
1449 { &hf_c1222_calling_authentication_value_encoding, BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG|BER_FLAGS_NOTCHKTAG, dissect_c1222_Authentication_value_encoding },
1450 { NULL, 0, 0, 0, NULL }
1453 static int
1454 dissect_c1222_Calling_authentication_value_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1455 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
1456 Calling_authentication_value_U_sequence, hf_index, ett_c1222_Calling_authentication_value_U);
1458 return offset;
1463 static int
1464 dissect_c1222_Calling_authentication_value(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1465 FILL_START;
1466 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
1467 hf_index, BER_CLASS_CON, 2, true, dissect_c1222_Calling_authentication_value_U);
1469 FILL_TABLE(calling_authentication_value);
1472 return offset;
1477 static int
1478 dissect_c1222_User_information(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1479 int8_t end_device_class;
1480 bool pc, ind;
1481 int32_t tag;
1482 uint32_t len;
1483 proto_item *tf = NULL;
1484 proto_tree *epsem_tree = NULL;
1485 FILL_START;
1487 /* get Tag and Length */
1488 offset = dissect_ber_identifier(actx->pinfo, tree, tvb, offset, &end_device_class, &pc, &tag);
1489 offset = dissect_ber_length(actx->pinfo, tree, tvb, offset, &len, &ind);
1490 FILL_TABLE_TRUNCATE(user_information, len+offset-start_offset);
1491 if (tag == 0x8) { /* BER_TAG_EXTERNAL */
1492 offset = dissect_ber_identifier(actx->pinfo, tree, tvb, offset, &end_device_class, &pc, &tag);
1493 offset = dissect_ber_length(actx->pinfo, tree, tvb, offset, &len, &ind);
1494 if (tag == 0x1) { /* implicit octet string */
1495 tf = proto_tree_add_item(tree, hf_c1222_user_information, tvb, offset, len, ENC_NA);
1496 epsem_tree = proto_item_add_subtree(tf, ett_c1222_epsem);
1497 dissect_epsem(tvb, offset, len, actx->pinfo, epsem_tree);
1498 offset += len;
1503 return offset;
1507 static const ber_sequence_t MESSAGE_U_sequence[] = {
1508 { &hf_c1222_aSO_context , BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_c1222_ASO_qualifier },
1509 { &hf_c1222_called_AP_title, BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL|BER_FLAGS_NOTCHKTAG, dissect_c1222_Called_AP_title },
1510 { &hf_c1222_called_AP_invocation_id, BER_CLASS_CON, 4, BER_FLAGS_OPTIONAL, dissect_c1222_Called_AP_invocation_id },
1511 { &hf_c1222_calling_AP_title, BER_CLASS_CON, 6, BER_FLAGS_OPTIONAL|BER_FLAGS_NOTCHKTAG, dissect_c1222_Calling_AP_title },
1512 { &hf_c1222_calling_AE_qualifier, BER_CLASS_CON, 7, BER_FLAGS_OPTIONAL, dissect_c1222_Calling_AE_qualifier },
1513 { &hf_c1222_calling_AP_invocation_id, BER_CLASS_CON, 8, 0, dissect_c1222_Calling_AP_invocation_id },
1514 { &hf_c1222_mechanism_name, BER_CLASS_CON, 11, BER_FLAGS_OPTIONAL|BER_FLAGS_IMPLTAG, dissect_c1222_Mechanism_name },
1515 { &hf_c1222_calling_authentication_value, BER_CLASS_CON, 12, BER_FLAGS_OPTIONAL, dissect_c1222_Calling_authentication_value },
1516 { &hf_c1222_user_information, BER_CLASS_CON, 30, 0, dissect_c1222_User_information },
1517 { NULL, 0, 0, 0, NULL }
1520 static int
1521 dissect_c1222_MESSAGE_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1522 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
1523 MESSAGE_U_sequence, hf_index, ett_c1222_MESSAGE_U);
1525 return offset;
1530 static int
1531 dissect_c1222_MESSAGE(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
1532 clear_canon();
1533 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
1534 hf_index, BER_CLASS_APP, 0, true, dissect_c1222_MESSAGE_U);
1537 return offset;
1540 /*--- PDUs ---*/
1542 static int dissect_MESSAGE_PDU(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_) {
1543 int offset = 0;
1544 asn1_ctx_t asn1_ctx;
1545 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, true, pinfo);
1546 offset = dissect_c1222_MESSAGE(false, tvb, offset, &asn1_ctx, tree, hf_c1222_MESSAGE_PDU);
1547 return offset;
1552 * Dissects a a full (reassembled) C12.22 message.
1554 * \param tvb the tv buffer of the current data
1555 * \param pinfo the packet info of the current data
1556 * \param tree the tree to append this item to
1558 static int
1559 dissect_c1222_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1561 proto_item *c1222_item = NULL;
1562 proto_tree *c1222_tree = NULL;
1564 /* make entry in the Protocol column on summary display */
1565 col_set_str(pinfo->cinfo, COL_PROTOCOL, PNAME);
1567 /* create the c1222 protocol tree */
1568 c1222_item = proto_tree_add_item(tree, proto_c1222, tvb, 0, -1, ENC_NA);
1569 c1222_tree = proto_item_add_subtree(c1222_item, ett_c1222);
1570 return dissect_MESSAGE_PDU(tvb, pinfo, c1222_tree, NULL);
1574 * Fetches the length of an entire C12.22 message to assist in reassembly.
1576 * \param pinfo the packet info of the current data
1577 * \param tvb the tv buffer of the current data
1578 * \param offset the offset in the tvb
1579 * \returns length of entire C12.22 message
1581 static unsigned
1582 get_c1222_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_)
1584 int orig_offset;
1585 unsigned length;
1586 bool ind;
1588 orig_offset = offset;
1589 /* note that this assumes a Tag length of 1 which is always valid for C12.22 */
1590 offset = dissect_ber_length(pinfo, NULL, tvb, offset+1, &length, &ind);
1591 return length+(offset - orig_offset);
1595 * Reassembles and dissects C12.22 messages.
1597 * \param tvb the tv buffer of the current data
1598 * \param pinfo the packet info of the current data
1599 * \param tree the tree to append this item to
1601 static int
1602 dissect_c1222(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1604 tcp_dissect_pdus(tvb, pinfo, tree, c1222_desegment, 5,
1605 get_c1222_message_len, dissect_c1222_common, data);
1606 return tvb_captured_length(tvb);
1609 /*--- proto_register_c1222 -------------------------------------------*/
1610 void proto_register_c1222(void) {
1612 /* List of fields */
1613 static hf_register_info hf[] = {
1614 { &hf_c1222_epsem_flags,
1615 { "C12.22 EPSEM Flags", "c1222.epsem.flags",
1616 FT_UINT8, BASE_HEX,
1617 NULL, 0x0,
1618 NULL, HFILL }
1620 { &hf_c1222_epsem_flags_reserved,
1621 { "C12.22 Reserved Flag", "c1222.epsem.flags.reserved",
1622 FT_BOOLEAN, 8,
1623 NULL, C1222_EPSEM_FLAG_RESERVED,
1624 NULL, HFILL }
1626 { &hf_c1222_epsem_flags_recovery,
1627 { "C12.22 Recovery Flag", "c1222.epsem.flags.recovery",
1628 FT_BOOLEAN, 8,
1629 NULL, C1222_EPSEM_FLAG_RECOVERY_SESSION,
1630 NULL, HFILL }
1632 { &hf_c1222_epsem_flags_proxy,
1633 { "C12.22 Proxy Service Used Flag", "c1222.epsem.flags.proxy",
1634 FT_BOOLEAN, 8,
1635 NULL, C1222_EPSEM_FLAG_PROXY_SERVICE_USED,
1636 NULL, HFILL }
1638 { &hf_c1222_epsem_flags_ed_class,
1639 { "C12.22 ED Class Flag", "c1222.epsem.flags.ed_class",
1640 FT_BOOLEAN, 8,
1641 NULL, C1222_EPSEM_FLAG_ED_CLASS_INCLUDED,
1642 NULL, HFILL }
1644 { &hf_c1222_epsem_flags_security_modes,
1645 { "C12.22 Security Mode Flags", "c1222.epsem.flags.security",
1646 FT_UINT8, BASE_HEX,
1647 VALS(c1222_security_modes), C1222_EPSEM_FLAG_SECURITY_MODE,
1648 NULL, HFILL }
1650 { &hf_c1222_epsem_flags_response_control,
1651 { "C12.22 Response Control Flags", "c1222.epsem.flags.response_control",
1652 FT_UINT8, BASE_HEX,
1653 VALS(c1222_response_control), C1222_EPSEM_FLAG_RESPONSE_CONTROL,
1654 NULL, HFILL }
1656 { &hf_c1222_epsem_ed_class,
1657 { "C12.22 EPSEM ED Class", "c1222.epsem.edclass",
1658 FT_BYTES, BASE_NONE,
1659 NULL, 0x0,
1660 NULL, HFILL }
1662 { &hf_c1222_epsem_total,
1663 { "C12.22 EPSEM", "c1222.epsem.data",
1664 FT_BYTES, BASE_NONE,
1665 NULL, 0x0,
1666 NULL, HFILL }
1668 { &hf_c1222_epsem_mac,
1669 { "C12.22 EPSEM MAC", "c1222.epsem.mac",
1670 FT_BYTES, BASE_NONE,
1671 NULL, 0x0,
1672 NULL, HFILL }
1674 { &hf_c1222_cmd,
1675 { "C12.22 Command", "c1222.cmd",
1676 FT_UINT8, BASE_HEX,
1677 VALS(commandnames), 0x0,
1678 NULL, HFILL }
1680 { &hf_c1222_err,
1681 { "C12.22 Response", "c1222.err",
1682 FT_UINT8, BASE_HEX,
1683 VALS(commandnames), 0x0,
1684 NULL, HFILL }
1686 { &hf_c1222_logon_id,
1687 { "C12.22 Logon User-Id", "c1222.logon.id",
1688 FT_UINT16, BASE_DEC,
1689 NULL, 0x0,
1690 NULL, HFILL }
1692 { &hf_c1222_logon_user,
1693 { "C12.22 Logon User", "c1222.logon.user",
1694 FT_STRING, BASE_NONE,
1695 NULL, 0x0,
1696 NULL, HFILL }
1698 { &hf_c1222_security_password,
1699 { "C12.22 Security Password", "c1222.security.password",
1700 FT_STRING, BASE_NONE,
1701 NULL, 0x0,
1702 NULL, HFILL }
1704 { &hf_c1222_auth_len,
1705 { "C12.22 Authenticate Request Length", "c1222.authenticate.len",
1706 FT_UINT8, BASE_DEC,
1707 NULL, 0x0,
1708 NULL, HFILL }
1710 { &hf_c1222_auth_data,
1711 { "C12.22 Authenticate Data", "c1222.authenticate.data",
1712 FT_BYTES, BASE_NONE,
1713 NULL, 0x0,
1714 NULL, HFILL }
1716 { &hf_c1222_read_table,
1717 { "C12.22 Table", "c1222.read.table",
1718 FT_UINT16, BASE_HEX,
1719 NULL, 0x0,
1720 NULL, HFILL }
1722 { &hf_c1222_read_offset,
1723 { "C12.22 Offset", "c1222.read.offset",
1724 FT_UINT24, BASE_HEX,
1725 NULL, 0x0,
1726 NULL, HFILL }
1728 { &hf_c1222_read_count,
1729 { "C12.22 Count", "c1222.read.count",
1730 FT_UINT16, BASE_DEC,
1731 NULL, 0x0,
1732 NULL, HFILL }
1734 { &hf_c1222_write_table,
1735 { "C12.22 Table", "c1222.write.table",
1736 FT_UINT16, BASE_HEX,
1737 NULL, 0x0,
1738 NULL, HFILL }
1740 { &hf_c1222_write_offset,
1741 { "C12.22 Offset", "c1222.write.offset",
1742 FT_UINT24, BASE_HEX,
1743 NULL, 0x0,
1744 NULL, HFILL }
1746 { &hf_c1222_write_size,
1747 { "C12.22 Table Size", "c1222.write.size",
1748 FT_UINT16, BASE_HEX,
1749 NULL, 0x0,
1750 NULL, HFILL }
1752 { &hf_c1222_write_data,
1753 { "C12.22 Table Data", "c1222.write.data",
1754 FT_BYTES, BASE_NONE,
1755 NULL, 0x0,
1756 NULL, HFILL }
1758 { &hf_c1222_write_chksum,
1759 { "C12.22 Table Data Checksum", "c1222.write.chksum",
1760 FT_UINT8, BASE_HEX,
1761 NULL, 0x0,
1762 NULL, HFILL }
1764 { &hf_c1222_write_chksum_status,
1765 { "C12.22 Table Data Checksum Status", "c1222.write.chksum.status",
1766 FT_UINT8, BASE_NONE,
1767 VALS(proto_checksum_vals), 0x0,
1768 NULL, HFILL }
1770 { &hf_c1222_procedure_response,
1771 { "C12.22 Procedure Response", "c1222.procedure.response",
1772 FT_UINT16, BASE_DEC,
1773 VALS(c1222_proc_response_control), C1222_PROCEDURE_RESPONSE,
1774 NULL, HFILL }
1776 { &hf_c1222_procedure_mfg,
1777 { "C12.22 Procedure Mfg", "c1222.procedure.mfg",
1778 FT_UINT16, BASE_DEC,
1779 NULL, C1222_PROCEDURE_MFG,
1780 NULL, HFILL }
1782 { &hf_c1222_procedure_num,
1783 { "C12.22 Procedure Number", "c1222.procedure.num",
1784 FT_UINT16, BASE_DEC,
1785 NULL, C1222_PROCEDURE_NUMBER,
1786 NULL, HFILL }
1788 { &hf_c1222_procedure_sequence,
1789 { "C12.22 Procedure Sequence Number", "c1222.procedure.sequence",
1790 FT_UINT8, BASE_DEC,
1791 NULL, 0x0,
1792 NULL, HFILL }
1794 { &hf_c1222_neg_pkt_size,
1795 { "C12.22 Negotiate Packet Size", "c1222.negotiate.pktsize",
1796 FT_UINT16, BASE_DEC,
1797 NULL, 0x0,
1798 NULL, HFILL }
1800 { &hf_c1222_neg_nbr_pkts,
1801 { "C12.22 Negotiate Number of Packets", "c1222.negotiate.numpkts",
1802 FT_UINT8, BASE_DEC,
1803 NULL, 0x0,
1804 NULL, HFILL }
1806 { &hf_c1222_wait_secs,
1807 { "C12.22 Wait Seconds", "c1222.wait.seconds",
1808 FT_UINT8, BASE_DEC,
1809 NULL, 0x0,
1810 NULL, HFILL }
1812 { &hf_c1222_timing_setup_traffic,
1813 { "C12.22 Timing Setup Channel Traffic Timeout", "c1222.timingsetup.traffic",
1814 FT_UINT8, BASE_DEC,
1815 NULL, 0x0,
1816 NULL, HFILL }
1818 { &hf_c1222_timing_setup_inter_char,
1819 { "C12.22 Timing Setup Intercharacter Timeout", "c1222.timingsetup.interchar",
1820 FT_UINT8, BASE_DEC,
1821 NULL, 0x0,
1822 NULL, HFILL }
1824 { &hf_c1222_timing_setup_resp_to,
1825 { "C12.22 Timing Setup Response Timeout", "c1222.timingsetup.respto",
1826 FT_UINT8, BASE_DEC,
1827 NULL, 0x0,
1828 NULL, HFILL }
1830 { &hf_c1222_timing_setup_nbr_retries,
1831 { "C12.22 Timing Setup Number of Retries", "c1222.timingsetup.nbrretries",
1832 FT_UINT8, BASE_DEC,
1833 NULL, 0x0,
1834 NULL, HFILL }
1836 { &hf_c1222_data,
1837 { "C12.22 data", "c1222.data",
1838 FT_BYTES, BASE_NONE,
1839 NULL, 0x0,
1840 NULL, HFILL }
1842 { &hf_c1222_epsem_crypto_good,
1843 { "Crypto good", "c1222.crypto_good",
1844 FT_BOOLEAN, BASE_NONE,
1845 NULL, 0x0,
1846 "True: crypto ok; False: doesn't match or not checked", HFILL }
1848 { &hf_c1222_epsem_crypto_bad,
1849 { "Crypto bad", "c1222.crypto_bad",
1850 FT_BOOLEAN, BASE_NONE,
1851 NULL, 0x0,
1852 "True: crypto bad; False: crypto ok or not checked", HFILL }
1854 { &hf_c1222_MESSAGE_PDU,
1855 { "MESSAGE", "c1222.MESSAGE_element",
1856 FT_NONE, BASE_NONE, NULL, 0,
1857 NULL, HFILL }},
1858 { &hf_c1222_aSO_context,
1859 { "aSO-context", "c1222.aSO_context",
1860 FT_OID, BASE_NONE, NULL, 0,
1861 "ASO_qualifier", HFILL }},
1862 { &hf_c1222_called_AP_title,
1863 { "called-AP-title", "c1222.called_AP_title",
1864 FT_UINT32, BASE_DEC, VALS(c1222_Called_AP_title_vals), 0,
1865 NULL, HFILL }},
1866 { &hf_c1222_called_AP_invocation_id,
1867 { "called-AP-invocation-id", "c1222.called_AP_invocation_id",
1868 FT_UINT32, BASE_DEC, NULL, 0,
1869 NULL, HFILL }},
1870 { &hf_c1222_calling_AP_title,
1871 { "calling-AP-title", "c1222.calling_AP_title",
1872 FT_UINT32, BASE_DEC, VALS(c1222_Calling_AP_title_vals), 0,
1873 NULL, HFILL }},
1874 { &hf_c1222_calling_AE_qualifier,
1875 { "calling-AE-qualifier", "c1222.calling_AE_qualifier",
1876 FT_UINT32, BASE_DEC, NULL, 0,
1877 NULL, HFILL }},
1878 { &hf_c1222_calling_AP_invocation_id,
1879 { "calling-AP-invocation-id", "c1222.calling_AP_invocation_id",
1880 FT_UINT32, BASE_DEC, NULL, 0,
1881 NULL, HFILL }},
1882 { &hf_c1222_mechanism_name,
1883 { "mechanism-name", "c1222.mechanism_name",
1884 FT_OID, BASE_NONE, NULL, 0,
1885 NULL, HFILL }},
1886 { &hf_c1222_calling_authentication_value,
1887 { "calling-authentication-value", "c1222.calling_authentication_value_element",
1888 FT_NONE, BASE_NONE, NULL, 0,
1889 NULL, HFILL }},
1890 { &hf_c1222_user_information,
1891 { "user-information", "c1222.user_information_element",
1892 FT_NONE, BASE_NONE, NULL, 0,
1893 NULL, HFILL }},
1894 { &hf_c1222_called_ap_title_abs,
1895 { "called-ap-title-abs", "c1222.called_ap_title_abs",
1896 FT_OID, BASE_NONE, NULL, 0,
1897 "OBJECT_IDENTIFIER", HFILL }},
1898 { &hf_c1222_called_ap_title_rel,
1899 { "called-ap-title-rel", "c1222.called_ap_title_rel",
1900 FT_REL_OID, BASE_NONE, NULL, 0,
1901 "RELATIVE_OID", HFILL }},
1902 { &hf_c1222_calling_ap_title_abs,
1903 { "calling-ap-title-abs", "c1222.calling_ap_title_abs",
1904 FT_OID, BASE_NONE, NULL, 0,
1905 "OBJECT_IDENTIFIER", HFILL }},
1906 { &hf_c1222_calling_ap_title_rel,
1907 { "calling-ap-title-rel", "c1222.calling_ap_title_rel",
1908 FT_REL_OID, BASE_NONE, NULL, 0,
1909 "RELATIVE_OID", HFILL }},
1910 { &hf_c1222_calling_authentication_value_indirect,
1911 { "calling-authentication-value-indirect", "c1222.calling_authentication_value_indirect",
1912 FT_INT32, BASE_DEC, NULL, 0,
1913 "INTEGER", HFILL }},
1914 { &hf_c1222_calling_authentication_value_encoding,
1915 { "calling-authentication-value-encoding", "c1222.calling_authentication_value_encoding",
1916 FT_UINT32, BASE_DEC, VALS(c1222_Authentication_value_encoding_vals), 0,
1917 "Authentication_value_encoding", HFILL }},
1918 { &hf_c1222_calling_authentication_value_single_asn1,
1919 { "calling-authentication-value-single-asn1", "c1222.calling_authentication_value_single_asn1",
1920 FT_UINT32, BASE_DEC, VALS(c1222_Calling_authentication_value_single_asn1_vals), 0,
1921 NULL, HFILL }},
1922 { &hf_c1222_calling_authentication_value_octet_aligned,
1923 { "calling-authentication-value-octet-aligned", "c1222.calling_authentication_value_octet_aligned",
1924 FT_BYTES, BASE_NONE, NULL, 0,
1925 "OCTET_STRING", HFILL }},
1926 { &hf_c1222_calling_authentication_value_c1222,
1927 { "calling-authentication-value-c1222", "c1222.calling_authentication_value_c1222_element",
1928 FT_NONE, BASE_NONE, NULL, 0,
1929 NULL, HFILL }},
1930 { &hf_c1222_calling_authentication_value_c1221,
1931 { "calling-authentication-value-c1221", "c1222.calling_authentication_value_c1221",
1932 FT_UINT32, BASE_DEC, VALS(c1222_Calling_authentication_value_c1221_U_vals), 0,
1933 NULL, HFILL }},
1934 { &hf_c1222_key_id_element,
1935 { "key-id-element", "c1222.key_id_element",
1936 FT_BYTES, BASE_NONE, NULL, 0,
1937 NULL, HFILL }},
1938 { &hf_c1222_iv_element,
1939 { "iv-element", "c1222.iv_element",
1940 FT_BYTES, BASE_NONE, NULL, 0,
1941 NULL, HFILL }},
1942 { &hf_c1222_c1221_auth_identification,
1943 { "c1221-auth-identification", "c1222.c1221_auth_identification",
1944 FT_BYTES, BASE_NONE, NULL, 0,
1945 "OCTET_STRING_SIZE_CONSTR001", HFILL }},
1946 { &hf_c1222_c1221_auth_request,
1947 { "c1221-auth-request", "c1222.c1221_auth_request",
1948 FT_BYTES, BASE_NONE, NULL, 0,
1949 "OCTET_STRING_SIZE_1_255", HFILL }},
1950 { &hf_c1222_c1221_auth_response,
1951 { "c1221-auth-response", "c1222.c1221_auth_response",
1952 FT_BYTES, BASE_NONE, NULL, 0,
1953 "OCTET_STRING_SIZE_CONSTR002", HFILL }},
1956 /* List of subtrees */
1957 static int *ett[] = {
1958 &ett_c1222,
1959 &ett_c1222_epsem,
1960 &ett_c1222_flags,
1961 &ett_c1222_crypto,
1962 &ett_c1222_cmd,
1963 &ett_c1222_MESSAGE_U,
1964 &ett_c1222_Called_AP_title,
1965 &ett_c1222_Calling_AP_title,
1966 &ett_c1222_Calling_authentication_value_U,
1967 &ett_c1222_Authentication_value_encoding,
1968 &ett_c1222_Calling_authentication_value_single_asn1,
1969 &ett_c1222_Calling_authentication_value_c1222_U,
1970 &ett_c1222_Calling_authentication_value_c1221_U,
1973 static ei_register_info ei[] = {
1974 { &ei_c1222_command_truncated, { "c1222.command_truncated", PI_MALFORMED, PI_ERROR, "C12.22 command truncated", EXPFILL }},
1975 { &ei_c1222_bad_checksum, { "c1222.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1976 { &ei_c1222_epsem_missing, { "c1222.epsem.missing", PI_MALFORMED, PI_ERROR, "C12.22 EPSEM missing", EXPFILL }},
1977 { &ei_c1222_epsem_failed_authentication, { "c1222.epsem.failed_authentication", PI_SECURITY, PI_ERROR, "C12.22 EPSEM failed authentication", EXPFILL }},
1978 { &ei_c1222_epsem_not_decrypted, { "c1222.epsem.not_decrypted", PI_UNDECODED, PI_WARN, "C12.22 EPSEM could not be decrypted", EXPFILL }},
1979 { &ei_c1222_ed_class_missing, { "c1222.ed_class_missing", PI_SECURITY, PI_ERROR, "C12.22 ED Class missing", EXPFILL }},
1980 { &ei_c1222_epsem_ber_length_error, { "c1222.epsem.ber_length_error", PI_MALFORMED, PI_ERROR, "C12.22 EPSEM BER length error", EXPFILL }},
1981 { &ei_c1222_epsem_field_length_error, { "c1222.epsem.field_length_error", PI_MALFORMED, PI_ERROR, "C12.22 EPSEM field length error", EXPFILL }},
1982 { &ei_c1222_mac_missing, { "c1222.mac_missing", PI_MALFORMED, PI_ERROR, "C12.22 MAC missing", EXPFILL }},
1985 expert_module_t* expert_c1222;
1986 module_t *c1222_module;
1988 static uat_field_t c1222_uat_flds[] = {
1989 UAT_FLD_HEX(c1222_users,keynum,"Key ID","Key identifier in hexadecimal"),
1990 UAT_FLD_BUFFER(c1222_users, key, "Key", "Encryption key as 16-byte hex string"),
1991 UAT_END_FIELDS
1994 /* Register protocol */
1995 proto_c1222 = proto_register_protocol(PNAME, PSNAME, PFNAME);
1996 /* Register fields and subtrees */
1997 proto_register_field_array(proto_c1222, hf, array_length(hf));
1998 proto_register_subtree_array(ett, array_length(ett));
1999 expert_c1222 = expert_register_protocol(proto_c1222);
2000 expert_register_field_array(expert_c1222, ei, array_length(ei));
2001 /* Register dissectors */
2002 c1222_handle = register_dissector("c1222.tcp", dissect_c1222, proto_c1222);
2003 c1222_udp_handle = register_dissector("c1222.udp", dissect_c1222_common, proto_c1222);
2004 /* Register dissection preferences */
2005 c1222_module = prefs_register_protocol(proto_c1222, proto_reg_handoff_c1222);
2006 prefs_register_bool_preference(c1222_module, "desegment",
2007 "Reassemble all C12.22 messages spanning multiple TCP segments",
2008 "Whether the C12.22 dissector should reassemble all messages spanning multiple TCP segments",
2009 &c1222_desegment);
2010 prefs_register_string_preference(c1222_module, "baseoid", "Base OID to use for relative OIDs",
2011 "Base object identifier for use in resolving relative object identifiers",
2012 &c1222_baseoid_str);
2013 prefs_register_bool_preference(c1222_module, "decrypt",
2014 "Verify crypto for all applicable C12.22 messages",
2015 "Whether the C12.22 dissector should verify the crypto for all relevant messages",
2016 &c1222_decrypt);
2017 prefs_register_bool_preference(c1222_module, "big_endian",
2018 "Interpret multibyte numbers as big endian",
2019 "Whether the C12.22 dissector should interpret procedure numbers as big-endian",
2020 &c1222_big_endian);
2022 c1222_uat = uat_new("Decryption Table",
2023 sizeof(c1222_uat_data_t), /* record size */
2024 "c1222_decryption_table", /* filename */
2025 true, /* from_profile */
2026 &c1222_uat_data, /* data_ptr */
2027 &num_c1222_uat_data, /* numitems_ptr */
2028 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
2029 NULL, /* help */
2030 c1222_uat_data_copy_cb, /* copy callback */
2031 c1222_uat_data_update_cb, /* update callback */
2032 c1222_uat_data_free_cb, /* free callback */
2033 NULL, /* post update callback */
2034 NULL, /* reset callback */
2035 c1222_uat_flds); /* UAT field definitions */
2037 prefs_register_uat_preference(c1222_module,
2038 "decryption_table",
2039 "Decryption Table",
2040 "Table of security parameters for decryption of C12.22 packets",
2041 c1222_uat);
2044 /*--- proto_reg_handoff_c1222 ---------------------------------------*/
2045 void
2046 proto_reg_handoff_c1222(void)
2048 static bool initialized = false;
2049 uint8_t *temp = NULL;
2051 if( !initialized ) {
2052 dissector_add_uint_with_preference("tcp.port", C1222_PORT, c1222_handle);
2053 dissector_add_uint_with_preference("udp.port", C1222_PORT, c1222_udp_handle);
2054 initialized = true;
2056 if (c1222_baseoid_str && (c1222_baseoid_str[0] != '\0') &&
2057 ((c1222_baseoid_len = oid_string2encoded(NULL, c1222_baseoid_str, &temp)) != 0)) {
2058 c1222_baseoid = (uint8_t *)wmem_realloc(wmem_epan_scope(), c1222_baseoid, c1222_baseoid_len);
2059 memcpy(c1222_baseoid, temp, c1222_baseoid_len);
2060 wmem_free(NULL, temp);
2061 } else if (c1222_baseoid) {
2062 wmem_free(wmem_epan_scope(), c1222_baseoid);
2063 c1222_baseoid = NULL;
2064 c1222_baseoid_len = 0;
2068 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2070 * Local variables:
2071 * c-basic-offset: 2
2072 * tab-width: 8
2073 * indent-tabs-mode: nil
2074 * End:
2076 * vi: set shiftwidth=2 tabstop=8 expandtab:
2077 * :indentSize=2:tabSize=8:noTabs=true: