Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / asn1 / goose / packet-goose-template.c
blob325f4ebc38f2fb31a3e17acd74658e2751982e47
1 /* packet-goose.c
2 * Routines for IEC 61850 GOOSE packet dissection
3 * Martin Lutz 2008
5 * Routines for IEC 61850 R-GOOSE packet dissection
6 * Dordije Manojlovic 2020
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
17 #include <epan/packet.h>
18 #include <epan/asn1.h>
19 #include <epan/proto_data.h>
20 #include <epan/etypes.h>
21 #include <epan/expert.h>
22 #include <wsutil/array.h>
24 #include "packet-ber.h"
25 #include "packet-acse.h"
27 #define GOOSE_PNAME "GOOSE"
28 #define GOOSE_PSNAME "GOOSE"
29 #define GOOSE_PFNAME "goose"
31 #define R_GOOSE_PNAME "R-GOOSE"
32 #define R_GOOSE_PSNAME "R-GOOSE"
33 #define R_GOOSE_PFNAME "r-goose"
35 void proto_register_goose(void);
36 void proto_reg_handoff_goose(void);
38 /* Initialize the protocol and registered fields */
39 static int proto_goose;
40 static int proto_r_goose;
42 static int hf_goose_session_header;
43 static int hf_goose_spdu_id;
44 static int hf_goose_session_hdr_length;
45 static int hf_goose_hdr_length;
46 static int hf_goose_content_id;
47 static int hf_goose_spdu_lenth;
48 static int hf_goose_spdu_num;
49 static int hf_goose_version;
50 static int hf_goose_security_info;
51 static int hf_goose_current_key_t;
52 static int hf_goose_next_key_t;
53 static int hf_goose_key_id;
54 static int hf_goose_init_vec_length;
55 static int hf_goose_init_vec;
56 static int hf_goose_session_user_info;
57 static int hf_goose_payload;
58 static int hf_goose_payload_length;
59 static int hf_goose_apdu_tag;
60 static int hf_goose_apdu_simulation;
61 static int hf_goose_apdu_appid;
62 static int hf_goose_apdu_length;
63 static int hf_goose_padding_tag;
64 static int hf_goose_padding_length;
65 static int hf_goose_padding;
66 static int hf_goose_hmac;
67 static int hf_goose_appid;
68 static int hf_goose_length;
69 static int hf_goose_reserve1;
70 static int hf_goose_reserve1_s_bit;
71 static int hf_goose_reserve2;
72 static int hf_goose_float_value;
75 /* Bit fields in the Reserved fields */
76 #define F_RESERVE1_S_BIT 0x8000
78 /* GOOSE stored data for expert info verifications */
79 typedef struct _goose_chk_data{
80 bool s_bit;
81 }goose_chk_data_t;
82 #define GOOSE_CHK_DATA_LEN (sizeof(goose_chk_data_t))
84 static expert_field ei_goose_mal_utctime;
85 static expert_field ei_goose_zero_pdu;
86 static expert_field ei_goose_invalid_sim;
87 static expert_field ei_goose_bogus_length;
89 #define SINGLE_FLOAT_EXP_BITS 8
90 #define FLOAT_ENC_LENGTH 5
92 #include "packet-goose-hf.c"
94 /* Initialize the subtree pointers */
95 static int ett_r_goose;
96 static int ett_session_header;
97 static int ett_security_info;
98 static int ett_session_user_info;
99 static int ett_payload;
100 static int ett_padding;
101 static int ett_goose;
102 static int ett_reserve1;
103 static int ett_expert_inf_sim;
105 #include "packet-goose-ett.c"
107 #include "packet-goose-fn.c"
109 static dissector_handle_t goose_handle;
112 #define OSI_SPDU_TUNNELED 0xA0 /* Tunneled */
113 #define OSI_SPDU_GOOSE 0xA1 /* GOOSE */
114 #define OSI_SPDU_SV 0xA2 /* Sample Value */
115 #define OSI_SPDU_MNGT 0xA3 /* Management */
117 static const value_string ositp_spdu_id[] = {
118 { OSI_SPDU_TUNNELED, "Tunneled" },
119 { OSI_SPDU_GOOSE, "GOOSE" },
120 { OSI_SPDU_SV, "Sample value" },
121 { OSI_SPDU_MNGT, "Management" },
122 { 0, NULL }
125 #define OSI_PDU_GOOSE 0x81
126 #define OSI_PDU_SV 0x82
127 #define OSI_PDU_TUNNELED 0x83
128 #define OSI_PDU_MNGT 0x84
130 static const value_string ositp_pdu_id[] = {
131 { OSI_PDU_GOOSE, "GOOSE" },
132 { OSI_PDU_SV, "SV" },
133 { OSI_PDU_TUNNELED, "Tunnel" },
134 { OSI_PDU_MNGT, "MNGT" },
135 { 0, NULL }
138 #define APDU_HEADER_SIZE 6
141 * Dissect GOOSE PDUs inside a PPDU.
143 static int
144 dissect_goose(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
145 void* data _U_)
147 uint32_t offset = 0;
148 uint32_t old_offset;
149 uint32_t length;
150 uint32_t reserve1_val;
151 proto_item *item = NULL;
152 proto_item *tree_item = NULL;
153 proto_tree *tree = NULL;
154 goose_chk_data_t *data_chk = NULL;
155 asn1_ctx_t asn1_ctx;
156 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, true, pinfo);
158 static int * const reserve1_flags[] = {
159 &hf_goose_reserve1_s_bit,
160 NULL
163 asn1_ctx.private_data = wmem_alloc(pinfo->pool, GOOSE_CHK_DATA_LEN);
164 data_chk = (goose_chk_data_t *)asn1_ctx.private_data;
166 col_set_str(pinfo->cinfo, COL_PROTOCOL, GOOSE_PNAME);
167 col_clear(pinfo->cinfo, COL_INFO);
169 tree_item = proto_tree_add_item(parent_tree, proto_goose, tvb, 0, -1, ENC_NA);
170 tree = proto_item_add_subtree(tree_item, ett_goose);
171 add_ber_encoded_label(tvb, pinfo, parent_tree);
174 /* APPID */
175 proto_tree_add_item(tree, hf_goose_appid, tvb, offset, 2, ENC_BIG_ENDIAN);
177 /* Length */
178 item = proto_tree_add_item_ret_uint(tree, hf_goose_length, tvb, offset + 2, 2,
179 ENC_BIG_ENDIAN, &length);
180 if (length < 8) {
181 expert_add_info(pinfo, item, &ei_goose_bogus_length);
183 set_actual_length(tvb, length);
184 proto_item_set_len(tree_item, length);
186 /* Reserved 1 */
187 reserve1_val = tvb_get_uint16(tvb, offset + 4, ENC_BIG_ENDIAN);
188 proto_tree_add_bitmask_value(tree, tvb, offset + 4, hf_goose_reserve1, ett_reserve1,
189 reserve1_flags, reserve1_val);
191 /* Store the header sim value for later expert info checks */
192 if(data_chk){
193 if(reserve1_val & F_RESERVE1_S_BIT){
194 data_chk->s_bit = true;
195 }else{
196 data_chk->s_bit = false;
201 /* Reserved 2 */
202 proto_tree_add_item(tree, hf_goose_reserve2, tvb, offset + 6, 2,
203 ENC_BIG_ENDIAN);
205 offset = 8;
206 while (offset < length){
207 old_offset = offset;
208 offset = dissect_goose_GOOSEpdu(false, tvb, offset, &asn1_ctx , tree, -1);
209 if (offset == old_offset) {
210 proto_tree_add_expert(tree, pinfo, &ei_goose_zero_pdu, tvb, offset, -1);
211 break;
215 return tvb_captured_length(tvb);
219 * Dissect RGOOSE PDUs inside ISO 8602/X.234 CLTP ConnecteionLess
220 * Transport Protocol.
222 static int
223 dissect_rgoose(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
224 void* data _U_)
226 unsigned offset = 0, old_offset = 0;
227 uint32_t init_v_length, payload_tag, padding_length, length;
228 uint32_t payload_length, apdu_offset = 0, apdu_length, apdu_simulation;
229 proto_item *item = NULL;
230 proto_tree *tree = NULL, *r_goose_tree = NULL, *sess_user_info_tree = NULL;
231 goose_chk_data_t *data_chk = NULL;
232 asn1_ctx_t asn1_ctx;
233 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, true, pinfo);
235 asn1_ctx.private_data = wmem_alloc(pinfo->pool, GOOSE_CHK_DATA_LEN);
236 data_chk = (goose_chk_data_t *)asn1_ctx.private_data;
238 col_set_str(pinfo->cinfo, COL_PROTOCOL, R_GOOSE_PNAME);
239 col_clear(pinfo->cinfo, COL_INFO);
241 item = proto_tree_add_item(parent_tree, proto_r_goose, tvb, 0, -1, ENC_NA);
242 r_goose_tree = proto_item_add_subtree(item, ett_r_goose);
244 /* Session header subtree */
245 item = proto_tree_add_item(r_goose_tree, hf_goose_session_header, tvb, 0,
246 -1, ENC_NA);
247 tree = proto_item_add_subtree(item, ett_session_header);
249 /* SPDU ID */
250 proto_tree_add_item(tree, hf_goose_spdu_id, tvb, offset++, 1,
251 ENC_BIG_ENDIAN);
252 /* Session header length */
253 proto_tree_add_item_ret_uint(tree, hf_goose_session_hdr_length, tvb, offset++, 1,
254 ENC_BIG_ENDIAN, &length);
255 proto_item_set_len(item, length + 2);
257 /* Header content indicator */
258 proto_tree_add_item(tree, hf_goose_content_id, tvb, offset++, 1,
259 ENC_BIG_ENDIAN);
260 /* Length */
261 proto_tree_add_item(tree, hf_goose_hdr_length, tvb, offset++, 1,
262 ENC_BIG_ENDIAN);
263 /* SPDU length */
264 proto_tree_add_item(tree, hf_goose_spdu_lenth, tvb, offset, 4,
265 ENC_BIG_ENDIAN);
266 offset += 4;
267 /* SPDU number */
268 proto_tree_add_item(tree, hf_goose_spdu_num, tvb, offset, 4,
269 ENC_BIG_ENDIAN);
270 offset += 4;
271 /* Version */
272 proto_tree_add_item(tree, hf_goose_version, tvb, offset, 2, ENC_BIG_ENDIAN);
273 offset += 2;
275 /* Security information subtree */
276 item = proto_tree_add_item(tree, hf_goose_security_info, tvb, offset, -1,
277 ENC_NA);
278 tree = proto_item_add_subtree(item, ett_security_info);
279 /* Time of current key */
280 proto_tree_add_item(tree, hf_goose_current_key_t, tvb, offset, 4,
281 ENC_BIG_ENDIAN);
282 offset += 4;
283 /* Time of next key */
284 proto_tree_add_item(tree, hf_goose_next_key_t, tvb, offset, 2,
285 ENC_BIG_ENDIAN);
286 offset += 2;
287 /* Key ID */
288 proto_tree_add_item(tree, hf_goose_key_id, tvb, offset, 4, ENC_BIG_ENDIAN);
289 offset += 4;
290 /* Initialization vector length */
291 proto_tree_add_item_ret_uint(tree, hf_goose_init_vec_length, tvb, offset++, 1,
292 ENC_BIG_ENDIAN, &init_v_length);
293 proto_item_set_len(item, init_v_length + 11);
295 if (init_v_length > 0) {
296 /* Initialization vector bytes */
297 proto_tree_add_item(tree, hf_goose_init_vec, tvb, offset, init_v_length,
298 ENC_NA);
300 offset += init_v_length;
302 /* Session user information subtree */
303 item = proto_tree_add_item(r_goose_tree, hf_goose_session_user_info, tvb,
304 offset, -1, ENC_NA);
305 sess_user_info_tree = proto_item_add_subtree(item, ett_payload);
307 /* Payload subtree */
308 item = proto_tree_add_item(sess_user_info_tree, hf_goose_payload, tvb,
309 offset, -1, ENC_NA);
310 tree = proto_item_add_subtree(item, ett_payload);
311 /* Payload length */
312 proto_tree_add_item_ret_uint(tree, hf_goose_payload_length, tvb, offset, 4,
313 ENC_BIG_ENDIAN, &payload_length);
314 offset += 4;
316 while (apdu_offset < payload_length){
317 /* APDU tag */
318 proto_tree_add_item_ret_uint(tree, hf_goose_apdu_tag, tvb, offset++, 1,
319 ENC_BIG_ENDIAN, &payload_tag);
320 /* Simulation flag */
321 proto_tree_add_item_ret_uint(tree, hf_goose_apdu_simulation, tvb, offset++,
322 1, ENC_BIG_ENDIAN, &apdu_simulation);
323 /* APPID */
324 proto_tree_add_item(tree, hf_goose_apdu_appid, tvb, offset, 2,
325 ENC_BIG_ENDIAN);
326 offset += 2;
328 if (payload_tag != OSI_PDU_GOOSE) {
329 return tvb_captured_length(tvb);
332 /* Store the header sim value for later expert info checks */
333 if(data_chk){
334 if(apdu_simulation){
335 data_chk->s_bit = true;
336 }else{
337 data_chk->s_bit = false;
341 /* APDU length */
342 proto_tree_add_item_ret_uint(tree, hf_goose_apdu_length, tvb, offset, 2,
343 ENC_BIG_ENDIAN, &apdu_length);
345 apdu_offset += (APDU_HEADER_SIZE + apdu_length);
346 offset += 2;
348 old_offset = offset;
349 offset = dissect_goose_GOOSEpdu(false, tvb, offset, &asn1_ctx , tree, -1);
350 if (offset == old_offset) {
351 proto_tree_add_expert(tree, pinfo, &ei_goose_zero_pdu, tvb, offset, -1);
352 break;
356 /* Check do we have padding bytes */
357 if ((tvb_captured_length(tvb) > offset) &&
358 (tvb_get_uint8(tvb, offset) == 0xAF)) {
359 /* Padding subtree */
360 item = proto_tree_add_item(sess_user_info_tree, hf_goose_padding, tvb,
361 offset, -1, ENC_NA);
362 tree = proto_item_add_subtree(item, ett_padding);
364 /* Padding tag */
365 proto_tree_add_item(tree, hf_goose_padding_tag, tvb, offset++, 1,
366 ENC_NA);
367 /* Padding length */
368 proto_tree_add_item_ret_uint(tree, hf_goose_padding_length, tvb, offset++, 1,
369 ENC_BIG_ENDIAN, &padding_length);
370 proto_item_set_len(item, padding_length + 1);
372 /* Padding bytes */
373 proto_tree_add_item(tree, hf_goose_padding, tvb, offset, padding_length,
374 ENC_NA);
375 offset += padding_length;
378 /* Check do we have HMAC bytes */
379 if (tvb_captured_length(tvb) > offset) {
380 /* HMAC bytes */
381 proto_tree_add_item(sess_user_info_tree, hf_goose_hmac, tvb, offset,
382 tvb_captured_length(tvb) - offset, ENC_NA);
385 return tvb_captured_length(tvb);
388 static bool
389 dissect_rgoose_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
390 void *data)
392 uint8_t spdu;
394 /* Check do we have at least min size of Session header bytes */
395 if (tvb_captured_length(tvb) < 27) {
396 return false;
399 /* Is it R-GOOSE? */
400 spdu = tvb_get_uint8(tvb, 0);
401 if (spdu != OSI_SPDU_GOOSE) {
402 return false;
405 dissect_rgoose(tvb, pinfo, parent_tree, data);
406 return true;
409 /*--- proto_register_goose -------------------------------------------*/
410 void proto_register_goose(void) {
412 /* List of fields */
413 static hf_register_info hf[] =
415 { &hf_goose_session_header,
416 { "Session header", "rgoose.session_hdr",
417 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
419 { &hf_goose_spdu_id,
420 { "Session identifier", "rgoose.spdu_id",
421 FT_UINT8, BASE_HEX_DEC, VALS(ositp_spdu_id), 0x0, NULL, HFILL }},
423 { &hf_goose_session_hdr_length,
424 { "Session header length", "rgoose.session_hdr_len",
425 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
427 { &hf_goose_content_id,
428 { "Common session header identifier", "rgoose.common_session_id",
429 FT_UINT8, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
431 { &hf_goose_hdr_length,
432 { "Header length", "rgoose.hdr_len",
433 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
435 { &hf_goose_spdu_lenth,
436 { "SPDU length", "rgoose.spdu_len",
437 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
439 { &hf_goose_spdu_num,
440 { "SPDU number", "rgoose.spdu_num",
441 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
443 { &hf_goose_version,
444 { "Version", "rgoose.version",
445 FT_UINT16, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
447 { &hf_goose_security_info,
448 { "Security information", "rgoose.sec_info",
449 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
451 { &hf_goose_current_key_t,
452 { "Time of current key", "rgoose.curr_key_t",
453 FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
455 { &hf_goose_next_key_t,
456 { "Time of next key", "rgoose.next_key_t",
457 FT_UINT16, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
459 { &hf_goose_key_id,
460 { "Key ID", "rgoose.key_id",
461 FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
463 { &hf_goose_init_vec_length,
464 { "Initialization vector length", "rgoose.init_v_len",
465 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
467 { &hf_goose_init_vec,
468 { "Initialization vector", "rgoose.init_v",
469 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
471 { &hf_goose_session_user_info,
472 { "Session user information", "rgoose.session_user_info",
473 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
475 { &hf_goose_payload,
476 { "Payload", "rgoose.payload",
477 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
479 { &hf_goose_payload_length,
480 { "Payload length", "rgoose.payload_len",
481 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
483 { &hf_goose_apdu_tag,
484 { "Payload type tag", "rgoose.pdu_tag",
485 FT_UINT8, BASE_HEX_DEC, VALS(ositp_pdu_id), 0x0, NULL, HFILL }},
487 { &hf_goose_apdu_simulation,
488 { "Simulation flag", "rgoose.simulation",
489 FT_UINT8, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
491 { &hf_goose_apdu_appid,
492 { "APPID", "rgoose.appid",
493 FT_UINT16, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
495 { &hf_goose_apdu_length,
496 { "APDU length", "rgoose.apdu_len",
497 FT_UINT16, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
499 { &hf_goose_padding_tag,
500 { "Padding", "rgoose.padding_tag",
501 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
503 { &hf_goose_padding_length,
504 { "Padding length", "rgoose.padding_len",
505 FT_UINT8, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
507 { &hf_goose_padding,
508 { "Padding", "rgoose.padding",
509 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
511 { &hf_goose_hmac,
512 { "HMAC", "rgoose.hmac",
513 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
515 { &hf_goose_appid,
516 { "APPID", "goose.appid",
517 FT_UINT16, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
519 { &hf_goose_length,
520 { "Length", "goose.length",
521 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
523 { &hf_goose_reserve1,
524 { "Reserved 1", "goose.reserve1",
525 FT_UINT16, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
527 { &hf_goose_reserve1_s_bit,
528 { "Simulated", "goose.reserve1.s_bit",
529 FT_BOOLEAN, 16, NULL, F_RESERVE1_S_BIT, NULL, HFILL } },
531 { &hf_goose_reserve2,
532 { "Reserved 2", "goose.reserve2",
533 FT_UINT16, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
535 { &hf_goose_float_value,
536 { "float value", "goose.float_value",
537 FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }},
539 #include "packet-goose-hfarr.c"
542 /* List of subtrees */
543 static int *ett[] = {
544 &ett_r_goose,
545 &ett_session_header,
546 &ett_security_info,
547 &ett_session_user_info,
548 &ett_payload,
549 &ett_padding,
550 &ett_goose,
551 &ett_reserve1,
552 &ett_expert_inf_sim,
553 #include "packet-goose-ettarr.c"
556 static ei_register_info ei[] = {
557 { &ei_goose_mal_utctime,
558 { "goose.malformed.utctime", PI_MALFORMED, PI_WARN,
559 "BER Error: malformed UTCTime encoding", EXPFILL }},
560 { &ei_goose_zero_pdu,
561 { "goose.zero_pdu", PI_PROTOCOL, PI_ERROR,
562 "Internal error, zero-byte GOOSE PDU", EXPFILL }},
563 { &ei_goose_invalid_sim,
564 { "goose.invalid_sim", PI_PROTOCOL, PI_WARN,
565 "Invalid GOOSE: S bit set and Simulation attribute clear", EXPFILL }},
566 { &ei_goose_bogus_length,
567 { "goose.bogus_length", PI_PROTOCOL, PI_ERROR,
568 "GOOSE length must be at least 8 (includes header)", EXPFILL }},
571 expert_module_t* expert_goose;
573 /* Register protocol */
574 proto_goose = proto_register_protocol(GOOSE_PNAME, GOOSE_PSNAME, GOOSE_PFNAME);
575 proto_r_goose = proto_register_protocol(R_GOOSE_PNAME, R_GOOSE_PSNAME, R_GOOSE_PFNAME);
577 goose_handle = register_dissector("goose", dissect_goose, proto_goose);
579 /* Register fields and subtrees */
580 proto_register_field_array(proto_goose, hf, array_length(hf));
581 proto_register_subtree_array(ett, array_length(ett));
582 expert_goose = expert_register_protocol(proto_goose);
583 expert_register_field_array(expert_goose, ei, array_length(ei));
587 /*--- proto_reg_handoff_goose --- */
588 void proto_reg_handoff_goose(void) {
590 dissector_add_uint("ethertype", ETHERTYPE_IEC61850_GOOSE, goose_handle);
592 heur_dissector_add("cltp", dissect_rgoose_heur,
593 "R-GOOSE (GOOSE over CLTP)", "rgoose_cltp", proto_goose, HEURISTIC_ENABLE);