Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-macsec.c
blobc5de4aa60d4aef0bdd21d5b530ed84fc10237069
1 /* packet-macsec.c
2 * Routines for IEEE 802.1AE MACsec dissection
3 * Copyright 2013, Allan W. Nielsen <anielsen@vitesse.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <epan/packet.h>
15 #include <epan/etypes.h>
16 #include <epan/tfs.h>
17 #include <wsutil/array.h>
18 #include <wsutil/wsgcrypt.h>
20 void proto_register_macsec(void);
21 void proto_reg_handoff_macsec(void);
23 static dissector_handle_t macsec_handle;
24 static dissector_handle_t ethertype_handle;
26 /* TCI/AN field masks */
27 #define TCI_MASK 0xFC
28 #define TCI_V_MASK 0x80
29 #define TCI_ES_MASK 0x40
30 #define TCI_SC_MASK 0x20
31 #define TCI_SCB_MASK 0x10
32 #define TCI_E_MASK 0x08
33 #define TCI_C_MASK 0x04
34 #define AN_MASK 0x03
36 #define AES_KEY_LEN (16)
37 #define ICV_LEN (16)
38 #define IV_LEN (12)
40 #define HWADDR_LEN (6)
41 #define ETHERTYPE_LEN (2)
42 #define ETHHDR_LEN ((HWADDR_LEN * 2) + ETHERTYPE_LEN)
44 #define SECTAG_LEN_WITH_SC (14)
45 #define SECTAG_LEN_WITHOUT_SC (6)
47 #define AAD_ENCRYPTED_LEN (28)
49 #define MAX_PAYLOAD_LEN (1500)
52 static int proto_macsec;
53 static int hf_macsec_TCI;
54 static int hf_macsec_TCI_V;
55 static int hf_macsec_TCI_ES;
56 static int hf_macsec_TCI_SC;
57 static int hf_macsec_TCI_SCB;
58 static int hf_macsec_TCI_E;
59 static int hf_macsec_TCI_C;
60 static int hf_macsec_AN;
61 static int hf_macsec_SL;
62 static int hf_macsec_PN;
63 static int hf_macsec_SCI_system_identifier;
64 static int hf_macsec_SCI_port_identifier;
65 static int hf_macsec_etype;
66 static int hf_macsec_eth_padding;
67 static int hf_macsec_ICV;
68 static int hf_macsec_ICV_check_success;
69 static int hf_macsec_decrypted_data;
71 /* Initialize the subtree pointers */
72 static int ett_macsec;
73 static int ett_macsec_tci;
75 /* Decrypting payload buffer */
76 static uint8_t macsec_payload[MAX_PAYLOAD_LEN];
78 /* AAD buffer */
79 static uint8_t aad[MAX_PAYLOAD_LEN];
81 static const char *psk = NULL;
82 static unsigned char *psk_bin = NULL;
84 /* convert a 0-terminated preference key_string that contains a hex number
85 * into its binary representation
86 * e.g. key_string "abcd" will be converted into two bytes 0xab, 0xcd
87 * return the number of binary bytes or -1 for error */
88 static int
89 pref_key_string_to_bin(const char *key_string, unsigned char **key_bin)
91 int key_string_len;
92 int i, j;
93 char input[3];
95 ws_return_val_if(key_bin == NULL, -1);
97 if (NULL == key_string) {
98 *key_bin = NULL;
99 return -1;
102 key_string_len = (int)strlen(key_string);
103 if (key_string_len != 2 * AES_KEY_LEN) {
104 *key_bin = NULL;
105 return (key_string_len / 2);
108 *key_bin = (unsigned char *)g_malloc(key_string_len / 2);
110 input[2] = '\0';
111 for (i = 0, j = 0; i < (key_string_len - 1); i += 2, j++) {
112 input[0] = key_string[0 + i];
113 input[1] = key_string[1 + i];
115 /* attention, brackets are required */
116 (*key_bin)[j] = (unsigned char)strtoul((const char *)&input, NULL, 16);
119 return (key_string_len / 2);
122 /* Code to actually dissect the packets */
123 static int dissect_macsec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
124 unsigned sectag_length, data_length, short_length, icv_length;
125 unsigned fcs_length = 0;
126 unsigned data_offset, icv_offset;
127 uint8_t tci_an_field;
129 int icv_check_success = PROTO_CHECKSUM_E_BAD;
130 bool key_provided = false;
131 bool encrypted = false;
132 unsigned payload_len;
133 unsigned offset;
135 gcry_cipher_hd_t handle = 0;
137 proto_item *macsec_item;
138 proto_tree *macsec_tree = NULL;
140 tvbuff_t *next_tvb;
142 /* Construct the 14-byte ethernet header (6-byte dst MAC, 6-byte src MAC, 2-byte ethernet type)(part of aad) */
143 uint8_t header[ETHHDR_LEN] = {0};
144 if (pinfo->dl_dst.data != NULL)
146 memcpy(header, pinfo->dl_dst.data, HWADDR_LEN);
148 if (pinfo->dl_src.data != NULL)
150 memcpy((header + HWADDR_LEN), pinfo->dl_src.data, HWADDR_LEN);
153 uint8_t e_type[ETHERTYPE_LEN] = {(uint8_t)(ETHERTYPE_MACSEC >> 8), (uint8_t)(ETHERTYPE_MACSEC & 0xff)};
154 memcpy(header + (ETHHDR_LEN - ETHERTYPE_LEN), &e_type, ETHERTYPE_LEN);
156 /* Parse the encryption key, and set the flag to indicate if the key is provided*/
157 if (pref_key_string_to_bin(psk, &psk_bin) == AES_KEY_LEN) {
158 key_provided = true;
161 tci_an_field = tvb_get_uint8(tvb, 0);
163 /* if the frame is an encrypted MACsec frame, remember that */
164 if (((tci_an_field & TCI_E_MASK) == TCI_E_MASK) || ((tci_an_field & TCI_C_MASK) == TCI_C_MASK)) {
165 encrypted = true;
168 if ((tci_an_field & TCI_V_MASK) != 0) { /* version must be zero */
169 return 0;
172 icv_length = ICV_LEN; /* Fixed size for version 0 */
174 if (tci_an_field & TCI_SC_MASK) {
175 sectag_length = SECTAG_LEN_WITH_SC; /* optional SCI present */
176 } else {
177 sectag_length = SECTAG_LEN_WITHOUT_SC;
180 /* Check for length too short */
181 if (tvb_captured_length(tvb) <= (sectag_length + icv_length)) {
182 return 0;
185 /* short length field: 1..47 bytes, 0 means 48 bytes or more */
186 short_length = (uint32_t)tvb_get_uint8(tvb, 1);
188 /* Get the payload section */
189 if (short_length != 0) {
190 data_length = short_length;
191 fcs_length = tvb_reported_length(tvb) - sectag_length - icv_length - short_length;
194 * We know the length, so set it here for the previous ethertype
195 * dissector. This will allow us to calculate the FCS correctly.
197 set_actual_length(tvb, short_length + sectag_length + icv_length);
198 } else {
200 * This assumes that no FCS is present after the ICV, which might not be true!
201 * Workaround: turn Ethernet "Assume packets have FCS" = Always, when FCS present.
202 * If there's another (non FCS) trailer afterwards, set Ethernet
203 * "Fixed ethernet trailer length".
205 * TODO: Find better heuristic to detect presence of FCS / trailers.
207 data_length = tvb_reported_length(tvb) - sectag_length - icv_length;
209 data_offset = sectag_length;
210 icv_offset = data_length + data_offset;
212 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MACSEC");
213 col_set_str(pinfo->cinfo, COL_INFO, "MACsec frame");
215 if (tree) {
216 if (encrypted) {
217 macsec_item = proto_tree_add_item(tree, proto_macsec, tvb, 0, sectag_length, ENC_NA);
218 } else {
219 /* Add the EtherType too since this is authentication only. */
220 macsec_item = proto_tree_add_item(tree, proto_macsec, tvb, 0, sectag_length + ETHERTYPE_LEN, ENC_NA);
222 macsec_tree = proto_item_add_subtree(macsec_item, ett_macsec);
224 static int * const flags[] = {
225 &hf_macsec_TCI_V,
226 &hf_macsec_TCI_ES,
227 &hf_macsec_TCI_SC,
228 &hf_macsec_TCI_SCB,
229 &hf_macsec_TCI_E,
230 &hf_macsec_TCI_C,
231 NULL
234 proto_tree_add_bitmask_with_flags(macsec_tree, tvb, 0,
235 hf_macsec_TCI, ett_macsec_tci, flags, ENC_NA, BMT_NO_TFS);
237 offset = 0;
238 proto_tree_add_item(macsec_tree, hf_macsec_AN, tvb, offset, 1, ENC_NA);
239 offset += 1;
241 proto_tree_add_item(macsec_tree, hf_macsec_SL, tvb, offset, 1, ENC_NA);
242 offset += 1;
244 proto_tree_add_item(macsec_tree, hf_macsec_PN, tvb, offset, 4, ENC_BIG_ENDIAN);
245 offset += 4;
247 if (sectag_length == SECTAG_LEN_WITH_SC) {
248 proto_tree_add_item(macsec_tree, hf_macsec_SCI_system_identifier, tvb, offset, HWADDR_LEN, ENC_NA);
249 offset += HWADDR_LEN;
251 proto_tree_add_item(macsec_tree, hf_macsec_SCI_port_identifier, tvb, offset, 2, ENC_BIG_ENDIAN);
255 next_tvb = tvb_new_subset_length(tvb, data_offset, data_length);
257 /* Try to decrypt/authenticate the data if a key is provided */
258 if (key_provided) {
259 /* Build the IV */
260 uint8_t iv[IV_LEN] = {0};
261 tvb_memcpy(tvb, iv, 6, HWADDR_LEN); // SI System identifier (source MAC)
262 tvb_memcpy(tvb, iv + 6, 12, 2); // PI Port identifier
263 tvb_memcpy(tvb, iv + 8, 2, 4); // PN Packet number
265 if (gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_GCM, 0))
267 ws_warning("gcry_cipher_open fail");
268 goto out;
271 if (gcry_cipher_setkey(handle, psk_bin, AES_KEY_LEN))
273 ws_warning("gcry_cipher_setkey fail");
274 goto out;
277 if (gcry_cipher_setiv(handle, iv, sizeof(iv)))
279 ws_warning("gcry_cipher_setiv fail");
280 goto out;
283 if (encrypted) {
284 payload_len = tvb_captured_length(next_tvb);
286 /* For authenticated and encrypted data, the AAD is always 28 bytes and consists of the
287 header data and security tag. */
288 const uint8_t *buf = tvb_get_ptr(tvb, 0, SECTAG_LEN_WITH_SC);
290 memcpy(aad, header, ETHHDR_LEN);
291 memcpy(aad + ETHHDR_LEN, buf, SECTAG_LEN_WITH_SC);
293 /* Authenticate with the AAD. */
294 if (gcry_cipher_authenticate(handle, aad, AAD_ENCRYPTED_LEN))
296 ws_warning("gcry_cipher_authenticate fail");
297 goto out;
300 tvb_memcpy(next_tvb, macsec_payload, 0, payload_len);
302 /* Attempt to decrypt into the local buffer. */
303 if (gcry_cipher_decrypt(handle, macsec_payload, payload_len, NULL, 0))
305 ws_warning("gcry_cipher_decrypt fail");
306 goto out;
309 } else {
310 /* the frame length for the AAD is the complete frame including ethernet header but without the ICV */
311 unsigned frame_len = (ETHHDR_LEN + tvb_captured_length(tvb)) - ICV_LEN;
313 // For authenticated-only data, the aad is the frame minus the ICV
314 // We have to build the AAD since the incoming TVB payload does not have the Ethernet header.
315 payload_len = frame_len - ETHHDR_LEN;
317 // Copy the header we built previously, then the frame data up to the ICV.
318 memcpy(aad, header, ETHHDR_LEN);
319 memcpy((aad + ETHHDR_LEN), tvb_get_ptr(tvb, 0, payload_len), payload_len);
321 /* Authenticate with the AAD. */
322 if (gcry_cipher_authenticate(handle, aad, frame_len))
324 ws_warning("gcry_cipher_authenticate fail");
325 goto out;
329 /* Fetch the ICV and use it to verify the decrypted data. */
330 uint8_t icv[ICV_LEN] = {0};
331 tvb_memcpy(tvb, icv, icv_offset, icv_length);
332 if (gcry_cipher_checktag(handle, icv, sizeof(icv)))
334 ws_info("gcry_cipher_checktag fail");
335 goto out;
338 /* Everything checks out! */
339 icv_check_success = PROTO_CHECKSUM_E_GOOD;
342 out:
343 if (0 != handle) {
344 gcry_cipher_close(handle);
346 // Show the original data.
347 call_data_dissector(next_tvb, pinfo, tree);
349 ethertype_data_t ethertype_data;
351 /* default the next tv_buff to remove ICV */
352 /* lets hand over a buffer without ICV to limit effect of wrong padding calculation */
353 next_tvb = tvb_new_subset_length(tvb, data_offset + 2, data_length - 2);
354 ethertype_data.etype = tvb_get_ntohs(tvb, data_offset);
356 // If the data are ok, attempt to continue dissection.
357 if (PROTO_CHECKSUM_E_GOOD == icv_check_success)
359 if (encrypted) {
360 tvbuff_t *plain_tvb;
362 plain_tvb = tvb_new_child_real_data(next_tvb, (uint8_t *)wmem_memdup(pinfo->pool, macsec_payload, payload_len),
363 payload_len, payload_len);
364 ethertype_data.etype = tvb_get_ntohs(plain_tvb, 0);
366 /* lets hand over a buffer without ICV to limit effect of wrong padding calculation */
367 next_tvb = tvb_new_subset_length(plain_tvb, 2, payload_len - 2);
369 /* show the decrypted data and original ethertype */
370 proto_tree_add_item(tree, hf_macsec_decrypted_data, plain_tvb, 0, payload_len, ENC_NA);
372 /* add the decrypted data as a data source for the next dissectors */
373 add_new_data_source(pinfo, plain_tvb, "Decrypted Data");
375 /* The ethertype is the one from the start of the decrypted data. */
376 proto_tree_add_item(tree, hf_macsec_etype, plain_tvb, 0, 2, ENC_BIG_ENDIAN);
378 } else {
379 /* lets hand over a buffer without ICV to limit effect of wrong padding calculation */
380 next_tvb = tvb_new_subset_length(tvb, data_offset + 2, data_length - 2);
382 /* The ethertype is the original from the unencrypted data. */
383 proto_tree_add_item(tree, hf_macsec_etype, tvb, data_offset, 2, ENC_BIG_ENDIAN);
387 /* add the ICV to the sectag subtree */
388 proto_tree_add_item(macsec_tree, hf_macsec_ICV, tvb, icv_offset, icv_length, ENC_NA);
389 proto_tree_set_appendix(macsec_tree, tvb, icv_offset, icv_length);
391 /* If the frame decoded, or was not encrypted, continue dissection */
392 if ((PROTO_CHECKSUM_E_GOOD == icv_check_success) || (false == encrypted)) {
393 /* help eth padding calculation by subtracting length of the sectag, ethertype, icv, and fcs */
394 int pkt_len_saved = pinfo->fd->pkt_len;
396 pinfo->fd->pkt_len -= (sectag_length + 2 + icv_length + fcs_length);
398 /* continue dissection */
399 ethertype_data.payload_offset = 0;
400 ethertype_data.fh_tree = macsec_tree;
401 /* XXX: This could be another trailer, a FCS, or the Ethernet dissector
402 * incorrectly detecting padding if we don't have short_length. */
403 ethertype_data.trailer_id = hf_macsec_eth_padding;
404 ethertype_data.fcs_len = 0;
406 call_dissector_with_data(ethertype_handle, next_tvb, pinfo, tree, &ethertype_data);
408 /* restore original value */
409 pinfo->fd->pkt_len = pkt_len_saved;
412 /* Set icv_check_success to the correct status */
413 if (!key_provided) {
414 icv_check_success = PROTO_CHECKSUM_E_UNVERIFIED;
417 /* If the frame was not verified correctly, append this string to the info line
418 * after dissection completes.
420 if (PROTO_CHECKSUM_E_BAD == icv_check_success) {
421 col_append_str(pinfo->cinfo, COL_INFO, " [Authentication fail]");
424 /* add a flag indicating the frame is or is not verified. */
425 macsec_item = proto_tree_add_uint(macsec_tree, hf_macsec_ICV_check_success, tvb, 0, 0, icv_check_success);
426 proto_item_set_generated(macsec_item);
428 /* We called set_actual length if fcs_length !=0, so length is adjusted. */
429 return tvb_captured_length(tvb);
432 void
433 proto_register_macsec(void)
435 module_t *module;
436 static hf_register_info hf[] = {
437 { &hf_macsec_TCI,
438 { "TCI", "macsec.TCI", FT_UINT8, BASE_HEX,
439 NULL, TCI_MASK, "TAG Control Information", HFILL }
441 { &hf_macsec_TCI_V,
442 { "VER", "macsec.TCI.V", FT_UINT8, BASE_HEX,
443 NULL, TCI_V_MASK, "Version", HFILL }
445 { &hf_macsec_TCI_ES,
446 { "ES", "macsec.TCI.ES", FT_BOOLEAN, 8,
447 TFS(&tfs_set_notset), TCI_ES_MASK, "End Station", HFILL }
449 { &hf_macsec_TCI_SC,
450 { "SC", "macsec.TCI.SC", FT_BOOLEAN, 8,
451 TFS(&tfs_set_notset), TCI_SC_MASK, "Secure Channel", HFILL }
453 { &hf_macsec_TCI_SCB,
454 { "SCB", "macsec.TCI.SCB", FT_BOOLEAN, 8,
455 TFS(&tfs_set_notset), TCI_SCB_MASK, "Single Copy Broadcast", HFILL }
457 { &hf_macsec_TCI_E,
458 { "E", "macsec.TCI.E", FT_BOOLEAN, 8,
459 TFS(&tfs_set_notset), TCI_E_MASK, "Encryption", HFILL }
461 { &hf_macsec_TCI_C,
462 { "C", "macsec.TCI.C", FT_BOOLEAN, 8,
463 TFS(&tfs_set_notset), TCI_C_MASK, "Changed Text", HFILL }
465 { &hf_macsec_AN,
466 { "AN", "macsec.AN", FT_UINT8, BASE_HEX,
467 NULL, AN_MASK, "Association Number", HFILL }
469 { &hf_macsec_SL,
470 { "Short length", "macsec.SL", FT_UINT8, BASE_DEC,
471 NULL, 0, NULL, HFILL }
473 { &hf_macsec_PN,
474 { "Packet number", "macsec.PN", FT_UINT32, BASE_DEC,
475 NULL, 0, NULL, HFILL }
477 { &hf_macsec_SCI_system_identifier,
478 { "System Identifier", "macsec.SCI.system_identifier", FT_ETHER, BASE_NONE,
479 NULL, 0, NULL, HFILL }
481 { &hf_macsec_SCI_port_identifier,
482 { "Port Identifier", "macsec.SCI.port_identifier", FT_UINT16, BASE_DEC,
483 NULL, 0, NULL, HFILL }
485 { &hf_macsec_etype,
486 { "Ethertype", "macsec.etype", FT_UINT16, BASE_HEX,
487 NULL, 0, NULL, HFILL }
489 { &hf_macsec_eth_padding,
490 { "Padding", "macsec.eth_padding", FT_BYTES, BASE_NONE,
491 NULL, 0, NULL, HFILL }
493 { &hf_macsec_ICV,
494 { "ICV", "macsec.ICV", FT_BYTES, BASE_NONE,
495 NULL, 0, NULL, HFILL }
497 { &hf_macsec_ICV_check_success,
498 { "Frame authentication status", "macsec.auth_status", FT_UINT8, BASE_DEC,
499 NULL, 0, NULL, HFILL }
501 { &hf_macsec_decrypted_data,
502 { "Decrypted Data", "macsec.decrypted_data", FT_BYTES, BASE_NONE,
503 NULL, 0, NULL, HFILL }
507 /* Setup protocol subtree array */
508 static int *ett[] = {
509 &ett_macsec,
510 &ett_macsec_tci
513 /* Register the protocol name and description */
514 proto_macsec = proto_register_protocol("802.1AE Security tag", "MACsec", "macsec");
516 /* Required function calls to register the header fields and subtrees used */
517 proto_register_field_array(proto_macsec, hf, array_length(hf));
518 proto_register_subtree_array(ett, array_length(ett));
520 /* Register the dissector */
521 macsec_handle = register_dissector("macsec", dissect_macsec, proto_macsec);
523 /* Register the text box to enter the pre-shared key */
524 module = prefs_register_protocol(proto_macsec, NULL);
525 prefs_register_string_preference(module, "psk", "MACsec Pre-Shared Key",
526 "Pre-Shared AES-GCM-128 Key as a HEX string (16 bytes).",
527 &psk);
530 void
531 proto_reg_handoff_macsec(void)
533 dissector_add_uint("ethertype", ETHERTYPE_MACSEC, macsec_handle);
535 ethertype_handle = find_dissector("ethertype");
539 * Editor modelines - https://www.wireshark.org/tools/modelines.html
541 * Local variables:
542 * c-basic-offset: 4
543 * tab-width: 8
544 * indent-tabs-mode: nil
545 * End:
547 * vi: set shiftwidth=4 tabstop=8 expandtab:
548 * :indentSize=4:tabSize=8:noTabs=true: