| File: | builds/wireshark/wireshark/epan/dissectors/packet-mka.c |
| Warning: | line 1017, column 5 Value stored to 'offset' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* packet-mka.c |
| 2 | * Routines for EAPOL-MKA IEEE 802.1X-2010 / IEEE 802.1bx-2014 / |
| 3 | * IEEE Std 802.1Xck-2018 / IEEE 802.1X-2020 MKPDU dissection |
| 4 | * Copyright 2014, Hitesh K Maisheri <[email protected]> |
| 5 | * |
| 6 | * Wireshark - Network traffic analyzer |
| 7 | * By Gerald Combs <[email protected]> |
| 8 | * Copyright 1998 Gerald Combs |
| 9 | * |
| 10 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 11 | */ |
| 12 | |
| 13 | #include "config.h" |
| 14 | #define WS_LOG_DOMAIN"MKA" "MKA" |
| 15 | |
| 16 | #include <epan/packet.h> |
| 17 | #include <epan/expert.h> |
| 18 | #include <epan/proto_data.h> |
| 19 | #include <epan/uat.h> |
| 20 | #include <epan/etypes.h> |
| 21 | |
| 22 | #include <wsutil/pint.h> |
| 23 | #include <wsutil/wsgcrypt.h> |
| 24 | #include <wsutil/ws_padding_to.h> |
| 25 | #include <wsutil/to_str.h> |
| 26 | |
| 27 | #include "packet-eapol.h" |
| 28 | #include "packet-mka.h" |
| 29 | |
| 30 | /*** UAT: CKN INFO ***/ |
| 31 | #define DATAFILE_CKN_INFO"mka_ckn_info" "mka_ckn_info" |
| 32 | |
| 33 | #define LIVE_PEER_LIST_TYPE1 1 |
| 34 | #define POTENTIAL_PEER_LIST_TYPE2 2 |
| 35 | #define MACSEC_SAK_USE_TYPE3 3 |
| 36 | #define DISTRIBUTED_SAK_TYPE4 4 |
| 37 | #define DISTRIBUTED_CAK_TYPE5 5 |
| 38 | #define KMD_TYPE6 6 |
| 39 | #define ANNOUNCEMENT_TYPE7 7 |
| 40 | #define XPN_TYPE8 8 |
| 41 | #define ICV_TYPE255 255 |
| 42 | |
| 43 | #define CIPHER_SUITE_LEN8 8 |
| 44 | #define AES_CMAC_LEN16 16 |
| 45 | #define WRAPPED_KEY_IV_LEN8 8 |
| 46 | #define WRAPPED_KEY_LEN(kl)((kl) + 8) ((kl) + WRAPPED_KEY_IV_LEN8) |
| 47 | |
| 48 | #define MKA_MI_LEN12U 12U |
| 49 | #define MKA_MAX_CKN_LEN32 32 |
| 50 | |
| 51 | #define KDF_LABEL_LEN12 12 |
| 52 | #define KDF_CTX_LEN16 16 |
| 53 | |
| 54 | #define DEFAULT_ICV_LEN16 16 |
| 55 | |
| 56 | #define BASIC_PARAMSET_BODY_LENGTH28 28 |
| 57 | #define DISTRIBUTED_SAK_AES128_BODY_LEN28 28 |
| 58 | #define DISTRIBUTED_SAK_AES256_BODY_LEN52 52 |
| 59 | #define DISTRIBUTED_SAK_AES128_XPN_BODY_LEN36 36 |
| 60 | |
| 61 | /* keys for p_[add|get]_proto_data */ |
| 62 | #define CKN_KEY0 0 |
| 63 | #define ICV_KEY1 1 |
| 64 | #define MI_KEY2 2 |
| 65 | #define SAK_KEY3 3 |
| 66 | #define PEER_SCI_KEY4 4 |
| 67 | #define PEER_MI_KEY5 5 |
| 68 | #define LATEST_KEY6 6 |
| 69 | #define OLD_KEY7 7 |
| 70 | |
| 71 | void proto_register_mka(void); |
| 72 | void proto_reg_handoff_mka(void); |
| 73 | |
| 74 | static int proto_mka; |
| 75 | static int proto_eapol; |
| 76 | |
| 77 | static int hf_mka_version_id; |
| 78 | static int hf_mka_basic_param_set; |
| 79 | static int hf_mka_live_peer_list_set; |
| 80 | static int hf_mka_potential_peer_list_set; |
| 81 | static int hf_mka_macsec_sak_use_set; |
| 82 | static int hf_mka_distributed_sak_set; |
| 83 | static int hf_mka_distributed_cak_set; |
| 84 | static int hf_mka_kmd_set; |
| 85 | static int hf_mka_announcement_set; |
| 86 | static int hf_mka_xpn_set; |
| 87 | static int hf_mka_unknown_set; |
| 88 | static int hf_mka_unknown_param_set; |
| 89 | static int hf_mka_icv_set; |
| 90 | static int hf_mka_param_set_type; |
| 91 | |
| 92 | static int hf_mka_keyserver_priority; |
| 93 | static int hf_mka_key_server; |
| 94 | static int hf_mka_macsec_desired; |
| 95 | static int hf_mka_macsec_capability; |
| 96 | static int hf_mka_param_body_length; |
| 97 | static int hf_mka_sci; |
| 98 | static int hf_mka_sci_system_identifier; |
| 99 | static int hf_mka_sci_port_identifier; |
| 100 | static int hf_mka_actor_mi; |
| 101 | static int hf_mka_actor_mn; |
| 102 | static int hf_mka_algo_agility; |
| 103 | static int hf_mka_cak_name; |
| 104 | static int hf_mka_cak_name_info; |
| 105 | |
| 106 | static int hf_mka_padding; |
| 107 | |
| 108 | static int hf_mka_key_server_ssci; |
| 109 | static int hf_mka_peer_mi; |
| 110 | static int hf_mka_peer_mn; |
| 111 | |
| 112 | static int hf_mka_latest_key_an; |
| 113 | static int hf_mka_latest_key_tx; |
| 114 | static int hf_mka_latest_key_rx; |
| 115 | static int hf_mka_old_key_an; |
| 116 | static int hf_mka_old_key_tx; |
| 117 | static int hf_mka_old_key_rx; |
| 118 | static int hf_mka_plain_tx; |
| 119 | static int hf_mka_plain_rx; |
| 120 | static int hf_mka_delay_protect; |
| 121 | static int hf_mka_latest_key_server_mi; |
| 122 | static int hf_mka_latest_key_number; |
| 123 | static int hf_mka_latest_lowest_acceptable_pn; |
| 124 | static int hf_mka_old_key_server_mi; |
| 125 | static int hf_mka_old_key_number; |
| 126 | static int hf_mka_old_lowest_acceptable_pn; |
| 127 | |
| 128 | static int hf_mka_distributed_an; |
| 129 | static int hf_mka_confidentiality_offset; |
| 130 | static int hf_mka_key_number; |
| 131 | static int hf_mka_aes_key_wrap_sak; |
| 132 | static int hf_mka_aes_key_wrap_unwrapped_sak; |
| 133 | static int hf_mka_macsec_cipher_suite; |
| 134 | static int hf_mka_aes_key_wrap_cak; |
| 135 | |
| 136 | static int hf_mka_kmd; |
| 137 | |
| 138 | static int hf_mka_suspension_time; |
| 139 | static int hf_mka_latest_lowest_accept_pn_msb; |
| 140 | static int hf_mka_old_lowest_accept_pn_msb; |
| 141 | |
| 142 | static int hf_mka_icv; |
| 143 | static int hf_mka_icv_status; |
| 144 | |
| 145 | static int hf_mka_tlv_entry; |
| 146 | static int hf_mka_tlv_type; |
| 147 | static int hf_mka_tlv_info_string_length; |
| 148 | static int hf_mka_tlv_data; |
| 149 | static int hf_mka_tlv_cipher_suite_impl_cap; |
| 150 | |
| 151 | static expert_field ei_mka_icv_bad; |
| 152 | static expert_field ei_mka_undecoded; |
| 153 | static expert_field ei_unexpected_data; |
| 154 | static expert_field ei_mka_unimplemented; |
| 155 | |
| 156 | static int ett_mka; |
| 157 | static int ett_mka_sci; |
| 158 | static int ett_mka_basic_param_set; |
| 159 | static int ett_mka_live_peer_list_set; |
| 160 | static int ett_mka_potential_peer_list_set; |
| 161 | static int ett_mka_sak_use_set; |
| 162 | static int ett_mka_distributed_sak_set; |
| 163 | static int ett_mka_distributed_cak_set; |
| 164 | static int ett_mka_kmd_set; |
| 165 | static int ett_mka_announcement_set; |
| 166 | static int ett_mka_xpn_set; |
| 167 | static int ett_mka_unknown_set; |
| 168 | static int ett_mka_icv_set; |
| 169 | static int ett_mka_tlv; |
| 170 | static int ett_mka_cipher_suite_entry; |
| 171 | |
| 172 | static const value_string param_set_type_vals[] = { |
| 173 | { LIVE_PEER_LIST_TYPE1, "Live Peer List" }, |
| 174 | { POTENTIAL_PEER_LIST_TYPE2, "Potential Peer List" }, |
| 175 | { MACSEC_SAK_USE_TYPE3, "MACsec SAK Use" }, |
| 176 | { DISTRIBUTED_SAK_TYPE4, "Distributed SAK" }, |
| 177 | { DISTRIBUTED_CAK_TYPE5, "Distributed CAK" }, |
| 178 | { KMD_TYPE6, "KMD" }, |
| 179 | { ANNOUNCEMENT_TYPE7, "Announcement" }, |
| 180 | { XPN_TYPE8, "XPN" }, |
| 181 | { ICV_TYPE255, "ICV Indicator" }, |
| 182 | { 0, NULL((void*)0) } |
| 183 | }; |
| 184 | |
| 185 | static const value_string macsec_capability_type_vals[] = { |
| 186 | { 0, "MACsec not implemented" }, |
| 187 | { 1, "MACsec Integrity without confidentiality" }, |
| 188 | { 2, "MACsec Integrity with/without confidentiality, no confidentiality offset" }, |
| 189 | { 3, "MACsec Integrity with/without confidentiality, confidentiality offset 0, 30, or 50" }, |
| 190 | { 0, NULL((void*)0) } |
| 191 | }; |
| 192 | |
| 193 | static const value_string algo_agility_vals[] = { |
| 194 | { 0x0080C201, "IEEE Std 802.1X-2020" }, |
| 195 | { 0, NULL((void*)0) } |
| 196 | }; |
| 197 | |
| 198 | static const value_string confidentiality_offset_vals[] = { |
| 199 | { 0, "No confidentiality" }, |
| 200 | { 1, "No confidentiality offset" }, |
| 201 | { 2, "Confidentiality offset 30 octets" }, |
| 202 | { 3, "Confidentiality offset 50 octets" }, |
| 203 | { 0, NULL((void*)0) } |
| 204 | }; |
| 205 | |
| 206 | /* The incorrect value can appear in the MACsec Cipher Suites TLV in the |
| 207 | * Announcement parameter set, but not in the Distributed SAK parameter set, |
| 208 | * which is the agreed upon value shared with the MACsec dissector. */ |
| 209 | static const val64_string macsec_cipher_suite_vals[] = { |
| 210 | { INT64_C(0x0080020001000001)0x0080020001000001L, "GCM-AES-128" }, // Original, incorrect value in IEEE 802.1AE-2006 and IEEE 802.1X-2010 |
| 211 | { MACSEC_GCM_AES_1280x0080C20001000001UL, "GCM-AES-128" }, |
| 212 | { MACSEC_GCM_AES_2560x0080C20001000002UL, "GCM-AES-256" }, |
| 213 | { MACSEC_GCM_AES_XPN_1280x0080C20001000003UL, "GCM-AES-XPN-128" }, |
| 214 | { MACSEC_GCM_AES_XPN_2560x0080C20001000004UL, "GCM-AES-XPN-256" }, |
| 215 | { 0, NULL((void*)0) } |
| 216 | }; |
| 217 | |
| 218 | |
| 219 | static const value_string macsec_tlvs[] = { |
| 220 | // 0 - 110 reserved |
| 221 | { 111, "Access Information" }, |
| 222 | { 112, "MACsec Cipher Suites" }, |
| 223 | { 113, "Key Management Domain" }, |
| 224 | { 114, "NID (Network Identifier)" }, |
| 225 | // 115 - 125 reserved |
| 226 | { 126, "Organizationally Specific Set TLV" }, |
| 227 | { 127, "Organizationally Specific TLVs" }, |
| 228 | { 0, NULL((void*)0) } |
| 229 | }; |
| 230 | |
| 231 | static wmem_map_t *mka_mi_sci_map; |
| 232 | static wmem_multimap_t *mka_ckn_sak_map; |
| 233 | static wmem_map_t *mka_ki_pn_map; |
| 234 | |
| 235 | static const char *mka_ckn_info_uat_defaults_[] = { NULL((void*)0), "", "" }; |
| 236 | |
| 237 | static mka_ckn_info_t *mka_ckn_uat_data = NULL((void*)0); |
| 238 | static unsigned num_mka_ckn_uat_data = 0; |
| 239 | static GHashTable *ht_mka_ckn = NULL((void*)0); |
| 240 | |
| 241 | UAT_BUFFER_CB_DEF(mka_ckn_uat_data, cak, mka_ckn_info_t, cak, cak_len)static void mka_ckn_uat_data_cak_set_cb(void* rec, const char * buf, unsigned len, const void* u1 __attribute__((unused)), const void* u2 __attribute__((unused))) { unsigned char* new_buf = len ? (unsigned char *)g_memdup2(buf,len) : ((void*)0); g_free ((((mka_ckn_info_t*)rec)->cak)); (((mka_ckn_info_t*)rec)-> cak) = new_buf; (((mka_ckn_info_t*)rec)->cak_len) = len; } static void mka_ckn_uat_data_cak_tostr_cb(void* rec, char** out_ptr , unsigned* out_len, const void* u1 __attribute__((unused)), const void* u2 __attribute__((unused))) { *out_ptr = ((mka_ckn_info_t *)rec)->cak ? (char*)g_memdup2(((mka_ckn_info_t*)rec)-> cak,((mka_ckn_info_t*)rec)->cak_len) : g_strdup_inline ("" ); *out_len = ((mka_ckn_info_t*)rec)->cak_len; } |
| 242 | UAT_BUFFER_CB_DEF(mka_ckn_uat_data, ckn, mka_ckn_info_t, ckn, ckn_len)static void mka_ckn_uat_data_ckn_set_cb(void* rec, const char * buf, unsigned len, const void* u1 __attribute__((unused)), const void* u2 __attribute__((unused))) { unsigned char* new_buf = len ? (unsigned char *)g_memdup2(buf,len) : ((void*)0); g_free ((((mka_ckn_info_t*)rec)->ckn)); (((mka_ckn_info_t*)rec)-> ckn) = new_buf; (((mka_ckn_info_t*)rec)->ckn_len) = len; } static void mka_ckn_uat_data_ckn_tostr_cb(void* rec, char** out_ptr , unsigned* out_len, const void* u1 __attribute__((unused)), const void* u2 __attribute__((unused))) { *out_ptr = ((mka_ckn_info_t *)rec)->ckn ? (char*)g_memdup2(((mka_ckn_info_t*)rec)-> ckn,((mka_ckn_info_t*)rec)->ckn_len) : g_strdup_inline ("" ); *out_len = ((mka_ckn_info_t*)rec)->ckn_len; } |
| 243 | UAT_CSTRING_CB_DEF(mka_ckn_uat_data, name, mka_ckn_info_t)static void mka_ckn_uat_data_name_set_cb(void* rec, const char * buf, unsigned len, const void* u1 __attribute__((unused)), const void* u2 __attribute__((unused))) { char* new_buf = g_strndup (buf,len); g_free((((mka_ckn_info_t*)rec)->name)); (((mka_ckn_info_t *)rec)->name) = new_buf; } static void mka_ckn_uat_data_name_tostr_cb (void* rec, char** out_ptr, unsigned* out_len, const void* u1 __attribute__((unused)), const void* u2 __attribute__((unused ))) { if (((mka_ckn_info_t*)rec)->name ) { *out_ptr = g_strdup_inline ((((mka_ckn_info_t*)rec)->name)); *out_len = (unsigned)strlen ((((mka_ckn_info_t*)rec)->name)); } else { *out_ptr = g_strdup_inline (""); *out_len = 0; } } |
| 244 | |
| 245 | /* Derive the ICK or KEK from the CAK and label. */ |
| 246 | static unsigned |
| 247 | mka_derive_key(const uint8_t *label, uint8_t *out, void *k) { |
| 248 | mka_ckn_info_t *rec = (mka_ckn_info_t *)k; |
| 249 | uint8_t *cak = (uint8_t *)rec->cak; |
| 250 | uint8_t *ckn = (uint8_t *)rec->ckn; |
| 251 | |
| 252 | unsigned ckn_len = rec->ckn_len; |
| 253 | unsigned cak_len = rec->cak_len; |
| 254 | |
| 255 | /* Build context. */ |
| 256 | /* Context is the first 16 bytes of the CAK name. */ |
| 257 | uint8_t context[16] = {0}; |
| 258 | memcpy(context, ckn, MIN(ckn_len, 16)(((ckn_len) < (16)) ? (ckn_len) : (16))); |
| 259 | |
| 260 | gcry_mac_hd_t hd; |
| 261 | |
| 262 | if (ws_log_msg_is_active(WS_LOG_DOMAIN"MKA", LOG_LEVEL_DEBUG)) { |
| 263 | char *cak_str = bytes_to_str_maxlen(NULL((void*)0), cak, cak_len, 0); |
| 264 | ws_debug("cak: %s", cak_str)do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 264, __func__, "cak: %s", cak_str); } } while (0); |
| 265 | g_free(cak_str); |
| 266 | |
| 267 | char *lbl_str = bytes_to_str_maxlen(NULL((void*)0), label, KDF_LABEL_LEN12, 0); |
| 268 | ws_debug("lbl: %s", lbl_str)do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 268, __func__, "lbl: %s", lbl_str); } } while (0); |
| 269 | g_free(lbl_str); |
| 270 | |
| 271 | char *ctx_str = bytes_to_str_maxlen(NULL((void*)0), context, KDF_CTX_LEN16, 0); |
| 272 | ws_debug("ctx: %s", ctx_str)do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 272, __func__, "ctx: %s", ctx_str); } } while (0); |
| 273 | g_free(ctx_str); |
| 274 | } |
| 275 | |
| 276 | /* Format input data for cmac. |
| 277 | Input data length is (1 byte counter + 12 bytes label + 1 byte for 0x00 + 16 bytes for context + 2 bytes for length) = 32 */ |
| 278 | #define INPUT_DATA_LENGTH(1 + 12 + 1 + 16 + 2) (1 + KDF_LABEL_LEN12 + 1 + KDF_CTX_LEN16 + 2) |
| 279 | uint8_t inputdata[INPUT_DATA_LENGTH(1 + 12 + 1 + 16 + 2)]; |
| 280 | |
| 281 | size_t clen = AES_CMAC_LEN16; |
| 282 | unsigned klen = cak_len * 8; |
| 283 | unsigned iterations = cak_len / AES_CMAC_LEN16; |
| 284 | unsigned outlen = 0; |
| 285 | |
| 286 | /* Open the cmac context. */ |
| 287 | if (gcry_mac_open(&hd, GCRY_MAC_CMAC_AES, 0, NULL((void*)0))) { |
| 288 | ws_warning("failed to open CMAC context")do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 288, __func__, "failed to open CMAC context"); } } while (0 ); |
| 289 | return 0; |
| 290 | } |
| 291 | |
| 292 | /* Set key to use. */ |
| 293 | if (gcry_mac_setkey(hd, cak, cak_len)) { |
| 294 | ws_warning("failed to set CMAC key")do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 294, __func__, "failed to set CMAC key"); } } while (0); |
| 295 | gcry_mac_close(hd); |
| 296 | return 0; |
| 297 | } |
| 298 | |
| 299 | for (unsigned i = 0; i < iterations; i++) |
| 300 | { |
| 301 | /* Reset cmac context, if needed */ |
| 302 | if ((i > 0) && gcry_mac_reset(hd)gcry_mac_ctl ((hd), GCRYCTL_RESET, ((void*)0), 0)) { |
| 303 | ws_warning("failed CMAC reset")do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 303, __func__, "failed CMAC reset"); } } while (0); |
| 304 | gcry_mac_close(hd); |
| 305 | return 0; |
| 306 | } |
| 307 | |
| 308 | inputdata[0] = (i + 1); // Iteration |
| 309 | memcpy(&inputdata[1], label, KDF_LABEL_LEN12); // Key label - must be 12 bytes |
| 310 | inputdata[13] = 0x00; // Always 0x00 |
| 311 | memcpy(&inputdata[14], context, KDF_CTX_LEN16); // Context data - must be 16 bytes |
| 312 | inputdata[30] = (klen & 0xFF00) >> 8; // MSB of key length in bits |
| 313 | inputdata[31] = (klen & 0xFF); // LSB of key length in bits |
| 314 | |
| 315 | /* Write the formatted input data to the CMAC. */ |
| 316 | if (gcry_mac_write(hd, inputdata, INPUT_DATA_LENGTH(1 + 12 + 1 + 16 + 2))) { |
| 317 | ws_warning("failed CMAC write")do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 317, __func__, "failed CMAC write"); } } while (0); |
| 318 | gcry_mac_close(hd); |
| 319 | return 0; |
| 320 | } |
| 321 | |
| 322 | /* Read the CMAC result. */ |
| 323 | gcry_mac_read(hd, (out + (i * clen)), &clen); |
| 324 | outlen += (unsigned)clen; |
| 325 | } |
| 326 | |
| 327 | /* Close the context. */ |
| 328 | gcry_mac_close(hd); |
| 329 | |
| 330 | if (ws_log_msg_is_active(WS_LOG_DOMAIN"MKA", LOG_LEVEL_DEBUG)) { |
| 331 | char *key_str = bytes_to_str_maxlen(NULL((void*)0), out, cak_len, 0); |
| 332 | ws_debug("key: %s", key_str)do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 332, __func__, "key: %s", key_str); } } while (0); |
| 333 | g_free(key_str); |
| 334 | } |
| 335 | |
| 336 | return outlen; |
| 337 | } |
| 338 | |
| 339 | static void |
| 340 | mka_derive_kek(void * k) { |
| 341 | mka_ckn_info_t *rec = (mka_ckn_info_t *)k; |
| 342 | |
| 343 | const uint8_t label[KDF_LABEL_LEN12 + 1] = "IEEE8021 KEK"; |
| 344 | rec->key.kek_len = mka_derive_key(label, rec->key.kek, rec); |
| 345 | } |
| 346 | |
| 347 | static void |
| 348 | mka_derive_ick(void * k) { |
| 349 | mka_ckn_info_t *rec = (mka_ckn_info_t *)k; |
| 350 | |
| 351 | const uint8_t label[KDF_LABEL_LEN12 + 1] = "IEEE8021 ICK"; |
| 352 | rec->key.ick_len = mka_derive_key(label, rec->key.ick, rec); |
| 353 | } |
| 354 | |
| 355 | static unsigned |
| 356 | ckn_key_hash_func(const void *k) { |
| 357 | const mka_ckn_info_t *rec = (const mka_ckn_info_t *)k; |
| 358 | size_t i; |
| 359 | unsigned hash = 0; |
| 360 | uint8_t *tmp = (uint8_t *)rec->ckn; |
| 361 | |
| 362 | /* Reduce to uint32_t by XOR */ |
| 363 | for (i = 0; i < rec->ckn_len; i++) { |
| 364 | hash ^= tmp[i] << 8 * (i % 4); |
| 365 | } |
| 366 | |
| 367 | return hash; |
| 368 | } |
| 369 | |
| 370 | static int |
| 371 | ckn_key_equal_func(const void *c1, const void *c2) { |
| 372 | const mka_ckn_info_t *ckn1 = (const mka_ckn_info_t *)c1; |
| 373 | const mka_ckn_info_t *ckn2 = (const mka_ckn_info_t *)c2; |
| 374 | if (ckn1->ckn_len != ckn2->ckn_len) return 0; |
| 375 | if (memcmp(ckn1->ckn, ckn2->ckn, ckn1->ckn_len) != 0) return 0; |
| 376 | |
| 377 | return 1; |
| 378 | } |
| 379 | |
| 380 | static void * |
| 381 | ckn_info_copy_cb(void *n, const void *o, size_t size _U___attribute__((unused))) { |
| 382 | mka_ckn_info_t *new_rec = (mka_ckn_info_t *)n; |
| 383 | const mka_ckn_info_t *old_rec = (const mka_ckn_info_t *)o; |
| 384 | |
| 385 | new_rec->cak = (unsigned char *)g_memdup2(old_rec->cak, old_rec->cak_len); |
| 386 | new_rec->cak_len = old_rec->cak_len; |
| 387 | new_rec->ckn = (unsigned char *)g_memdup2(old_rec->ckn, old_rec->ckn_len); |
| 388 | new_rec->ckn_len = old_rec->ckn_len; |
| 389 | new_rec->name = g_strdup(old_rec->name)g_strdup_inline (old_rec->name); |
| 390 | |
| 391 | return new_rec; |
| 392 | } |
| 393 | |
| 394 | static bool_Bool |
| 395 | ckn_info_update_cb(void *r, char **err) { |
| 396 | mka_ckn_info_t *rec = (mka_ckn_info_t *)r; |
| 397 | |
| 398 | if ((0 != rec->cak_len) && ((AES128_KEY_LEN16 != rec->cak_len) && (AES256_KEY_LEN32 != rec->cak_len))) { |
| 399 | *err = ws_strdup("Invalid CAK length! CAKs need to be 16 or 32 bytes when specified.")wmem_strdup(((void*)0), "Invalid CAK length! CAKs need to be 16 or 32 bytes when specified." ); |
| 400 | return false0; |
| 401 | } |
| 402 | |
| 403 | if ((0 == rec->ckn_len) || (rec->ckn_len > MKA_MAX_CKN_LEN32)) { |
| 404 | *err = ws_strdup("Invalid CKN length! CKNs need to be from 1 to 32 bytes.")wmem_strdup(((void*)0), "Invalid CKN length! CKNs need to be from 1 to 32 bytes." ); |
| 405 | return false0; |
| 406 | } |
| 407 | |
| 408 | if (0 == strlen(rec->name)) { |
| 409 | *err = ws_strdup("Missing name! A name must be specified for this CAK/CKN entry.")wmem_strdup(((void*)0), "Missing name! A name must be specified for this CAK/CKN entry." ); |
| 410 | return false0; |
| 411 | } |
| 412 | |
| 413 | /* XXX - The CKN must be unique for pre-shared CAKs (IEEE 802.1X-2020 6.3.3, |
| 414 | * 9.3.1). Can that be validated here? */ |
| 415 | |
| 416 | return true1; |
| 417 | } |
| 418 | |
| 419 | static void |
| 420 | ckn_info_free_cb(void *r) { |
| 421 | mka_ckn_info_t *rec = (mka_ckn_info_t *)r; |
| 422 | |
| 423 | g_free(rec->cak); |
| 424 | g_free(rec->ckn); |
| 425 | g_free(rec->name); |
| 426 | } |
| 427 | |
| 428 | static void |
| 429 | ckn_info_reset_cb(void) { |
| 430 | if (NULL((void*)0) != ht_mka_ckn) { |
| 431 | g_hash_table_destroy(ht_mka_ckn); |
| 432 | ht_mka_ckn = NULL((void*)0); |
| 433 | } |
| 434 | } |
| 435 | |
| 436 | static void |
| 437 | ckn_info_post_update_cb(void) { |
| 438 | ckn_info_reset_cb(); |
| 439 | |
| 440 | ht_mka_ckn = g_hash_table_new(&ckn_key_hash_func, &ckn_key_equal_func); |
| 441 | |
| 442 | for (size_t i = 0; i < num_mka_ckn_uat_data; i++) { |
| 443 | /* Derive the KEK and ICK and store with the CAK/CKN for this table entry. */ |
| 444 | ws_info("deriving ICK for CKN table entry %zu (%s)", i, mka_ckn_uat_data[i].name)do { if (1) { ws_log_full("MKA", LOG_LEVEL_INFO, ((void*)0), - 1, ((void*)0), "deriving ICK for CKN table entry %zu (%s)", i , mka_ckn_uat_data[i].name); } } while (0); |
| 445 | mka_derive_ick(&(mka_ckn_uat_data[i])); |
| 446 | |
| 447 | ws_info("deriving KEK for CKN table entry %zu (%s)", i, mka_ckn_uat_data[i].name)do { if (1) { ws_log_full("MKA", LOG_LEVEL_INFO, ((void*)0), - 1, ((void*)0), "deriving KEK for CKN table entry %zu (%s)", i , mka_ckn_uat_data[i].name); } } while (0); |
| 448 | mka_derive_kek(&(mka_ckn_uat_data[i])); |
| 449 | |
| 450 | /* The disadvantage of using hash tables like this is that it's not |
| 451 | * possible to have multiple entries with the same CKN without more |
| 452 | * changes. */ |
| 453 | g_hash_table_insert(ht_mka_ckn, &(mka_ckn_uat_data[i]), &(mka_ckn_uat_data[i])); |
| 454 | } |
| 455 | } |
| 456 | |
| 457 | |
| 458 | /* Find a table entry for the given CKN string */ |
| 459 | static mka_ckn_info_t * |
| 460 | ckn_info_lookup(uint8_t ckn[], uint32_t ckn_len) { |
| 461 | mka_ckn_info_t tmp_key = { .ckn = ckn, .ckn_len = ckn_len }; |
| 462 | |
| 463 | if (ht_mka_ckn == NULL((void*)0)) { |
| 464 | ws_debug("No hash table")do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 464, __func__, "No hash table"); } } while (0); |
| 465 | return NULL((void*)0); |
| 466 | } |
| 467 | |
| 468 | return (mka_ckn_info_t *)g_hash_table_lookup(ht_mka_ckn, &tmp_key); |
| 469 | } |
| 470 | |
| 471 | /* Get the entire table's contents. */ |
| 472 | const mka_ckn_info_t * |
| 473 | get_mka_ckn_table(void) { |
| 474 | return (const mka_ckn_info_t *)mka_ckn_uat_data; |
| 475 | } |
| 476 | |
| 477 | /* Get the size of the table. */ |
| 478 | unsigned |
| 479 | get_mka_ckn_table_count(void) { |
| 480 | return num_mka_ckn_uat_data; |
| 481 | } |
| 482 | |
| 483 | static unsigned |
| 484 | mka_sci_hash(const void *key) { |
| 485 | return wmem_strong_hash(key, MACSEC_SCI_LEN8U); |
| 486 | } |
| 487 | |
| 488 | static gboolean |
| 489 | mka_sci_equal(const void *k1, const void *k2) { |
| 490 | return memcmp(k1, k2, MACSEC_SCI_LEN8U) == 0; |
| 491 | } |
| 492 | |
| 493 | static unsigned |
| 494 | mka_mi_hash(const void *key) { |
| 495 | return wmem_strong_hash(key, MKA_MI_LEN12U); |
| 496 | } |
| 497 | |
| 498 | static gboolean |
| 499 | mka_mi_equal(const void *k1, const void *k2) { |
| 500 | return memcmp(k1, k2, MKA_MI_LEN12U) == 0; |
| 501 | } |
| 502 | |
| 503 | typedef struct _mka_ki_pn_t { |
| 504 | uint8_t ki[MKA_KI_LEN16U]; |
| 505 | uint64_t pn; |
| 506 | } mka_ki_pn_t; |
| 507 | |
| 508 | typedef struct _mka_ki_pn_value_t { |
| 509 | wmem_tree_t *all_sci_lpn_tree; |
| 510 | wmem_multimap_t *sci_lpn_multimap; |
| 511 | } mka_ki_value_t; |
| 512 | |
| 513 | static unsigned |
| 514 | mka_ki_hash(const void *k) { |
| 515 | mka_ki_pn_t *key = (mka_ki_pn_t*)k; |
| 516 | return wmem_strong_hash(key->ki, MKA_KI_LEN16U); |
| 517 | } |
| 518 | |
| 519 | static gboolean |
| 520 | mka_ki_equal(const void *k1, const void *k2) { |
| 521 | mka_ki_pn_t *key1 = (mka_ki_pn_t*)k1; |
| 522 | mka_ki_pn_t *key2 = (mka_ki_pn_t*)k2; |
| 523 | |
| 524 | return memcmp(key1->ki, key2->ki, MKA_KI_LEN16U) == 0; |
| 525 | } |
| 526 | |
| 527 | /* For use by other dissectors (MACsec), this looks for the most recent |
| 528 | * Lowest Acceptable Packet Number for a given Key Identifier (in the |
| 529 | * SAK info) and SCI (SecY). sci is allowed to be NULL, in which case |
| 530 | * the most recent value for any SCI is given, if known. The result is |
| 531 | * only accurate to the top 33 significant digits, as that is all that |
| 532 | * is required by the PN recovery algorithm in 802.1AE-2018 10.6.2. */ |
| 533 | uint64_t |
| 534 | mka_get_lpn(const mka_sak_info_key_t *sak_info, const uint8_t *sci, uint32_t frame_num) { |
| 535 | mka_ki_value_t *value = wmem_map_lookup(mka_ki_pn_map, sak_info->ki); |
| 536 | uint64_t *lpn_p; |
| 537 | if (!value) { |
| 538 | return 0; |
| 539 | } |
| 540 | if (sci) { |
| 541 | lpn_p = wmem_multimap_lookup32_le(value->sci_lpn_multimap, sci, frame_num); |
| 542 | } else { |
| 543 | lpn_p = wmem_tree_lookup32_le(value->all_sci_lpn_tree, frame_num); |
| 544 | } |
| 545 | |
| 546 | return lpn_p ? *lpn_p : 0; |
| 547 | } |
| 548 | |
| 549 | static void |
| 550 | update_lpn(const mka_ki_pn_t *tmp_value, const uint8_t *sci, uint32_t frame_num) { |
| 551 | // Shortcut: Don't bother creating the structures for zero values. |
| 552 | if ((tmp_value->pn >> 31) == 0) { |
| 553 | return; |
| 554 | } |
| 555 | |
| 556 | mka_ki_value_t *value = wmem_map_lookup(mka_ki_pn_map, tmp_value->ki); |
| 557 | uint64_t lpn, *lpn_p, *perm_lpn_p = NULL((void*)0); |
| 558 | if (!value) { |
| 559 | value = wmem_new(wmem_file_scope(), mka_ki_value_t)((mka_ki_value_t*)wmem_alloc((wmem_file_scope()), sizeof(mka_ki_value_t ))); |
| 560 | value->all_sci_lpn_tree = wmem_tree_new(wmem_file_scope()); |
| 561 | value->sci_lpn_multimap = wmem_multimap_new(wmem_file_scope(), mka_sci_hash, mka_sci_equal); |
| 562 | uint8_t *perm_ki = wmem_memdup(wmem_file_scope(), tmp_value->ki, MKA_KI_LEN16U); |
| 563 | wmem_map_insert(mka_ki_pn_map, perm_ki, value); |
| 564 | } |
| 565 | lpn_p = wmem_tree_lookup32_le(value->all_sci_lpn_tree, frame_num); |
| 566 | lpn = lpn_p ? *lpn_p : 0; |
| 567 | if ((tmp_value->pn >> 31) > (lpn >> 31)) { |
| 568 | /* Due to the algorithm for PN recovery (802.1AE-2018 10.6.2), we only |
| 569 | * need to update the value when the upper 33 bits change. */ |
| 570 | perm_lpn_p = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t)) ); |
| 571 | *perm_lpn_p = tmp_value->pn; |
| 572 | wmem_tree_insert32(value->all_sci_lpn_tree, frame_num, perm_lpn_p); |
| 573 | } |
| 574 | lpn_p = wmem_multimap_lookup32_le(value->sci_lpn_multimap, sci, frame_num); |
| 575 | lpn = lpn_p ? *lpn_p : 0; |
| 576 | if ((tmp_value->pn >> 31) > (lpn >> 31)) { |
| 577 | if (perm_lpn_p == NULL((void*)0)) { |
| 578 | // We can share the values here, as they have the same scope |
| 579 | perm_lpn_p = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t)) ); |
| 580 | *perm_lpn_p = tmp_value->pn; |
| 581 | } |
| 582 | wmem_multimap_insert32(value->sci_lpn_multimap, sci, frame_num, perm_lpn_p); |
| 583 | } |
| 584 | } |
| 585 | |
| 586 | typedef struct _mka_sak_key_t { |
| 587 | const mka_ckn_info_t *ckn_info; |
| 588 | uint8_t an; |
| 589 | } mka_sak_key_t; |
| 590 | |
| 591 | static unsigned |
| 592 | mka_sak_key_hash(const void *k) { |
| 593 | const mka_sak_key_t *key = (const mka_sak_key_t*)k; |
| 594 | |
| 595 | return ckn_key_hash_func(key->ckn_info) ^ key->an; |
| 596 | } |
| 597 | |
| 598 | static gboolean |
| 599 | mka_sak_key_equal(const void *k1, const void *k2) { |
| 600 | const mka_sak_key_t *key1 = (const mka_sak_key_t*)k1; |
| 601 | const mka_sak_key_t *key2 = (const mka_sak_key_t*)k2; |
| 602 | |
| 603 | return (key1->an == key2->an) && |
| 604 | ckn_key_equal_func(key1->ckn_info, key2->ckn_info); |
| 605 | } |
| 606 | |
| 607 | /* For use by other dissectors (MACsec), this looks for the most recent |
| 608 | * SAK with a given CKN and AN. */ |
| 609 | mka_sak_info_key_t * |
| 610 | mka_get_sak_info(const mka_ckn_info_t *ckn, unsigned an, uint32_t frame_num) { |
| 611 | mka_sak_key_t key = {ckn, an}; |
| 612 | return wmem_multimap_lookup32_le(mka_ckn_sak_map, &key, frame_num); |
| 613 | } |
| 614 | |
| 615 | /* This static function is used internally on the second pass and requires an |
| 616 | * exact match on the frame number. */ |
| 617 | static mka_sak_info_key_t * |
| 618 | get_sak_info(const mka_ckn_info_t *ckn, unsigned an, uint32_t frame_num) { |
| 619 | mka_sak_key_t tmp_key = {ckn, an}; |
| 620 | mka_sak_info_key_t *sak_info = wmem_multimap_lookup32(mka_ckn_sak_map, &tmp_key, frame_num); |
| 621 | return sak_info; |
| 622 | } |
| 623 | |
| 624 | static mka_sak_info_key_t * |
| 625 | get_or_create_sak_info(const mka_ckn_info_t *ckn, unsigned an, uint32_t frame_num) { |
| 626 | mka_sak_info_key_t *sak_info = get_sak_info(ckn, an, frame_num); |
| 627 | if (sak_info == NULL((void*)0)) { |
| 628 | mka_sak_key_t *perm_key = wmem_new(wmem_file_scope(), mka_sak_key_t)((mka_sak_key_t*)wmem_alloc((wmem_file_scope()), sizeof(mka_sak_key_t ))); |
| 629 | perm_key->ckn_info = ckn; |
| 630 | perm_key->an = an; |
| 631 | sak_info = wmem_new0(wmem_file_scope(), mka_sak_info_key_t)((mka_sak_info_key_t*)wmem_alloc0((wmem_file_scope()), sizeof (mka_sak_info_key_t))); |
| 632 | sak_info->sci_map = wmem_map_new(wmem_file_scope(), mka_sci_hash, mka_sci_equal); |
| 633 | sak_info->mi_array = wmem_array_new(wmem_file_scope(), MKA_MI_LEN12U); |
| 634 | wmem_multimap_insert32(mka_ckn_sak_map, perm_key, frame_num, sak_info); |
| 635 | } |
| 636 | return sak_info; |
| 637 | } |
| 638 | |
| 639 | static mka_ckn_info_t * |
| 640 | mka_add_ckn_info(proto_tree *tree, tvbuff_t *tvb, int offset, uint16_t ckn_len) { |
| 641 | proto_item *ti; |
| 642 | |
| 643 | uint8_t ckn[MKA_MAX_CKN_LEN32]; /* Only accept CKN between 1 and 32 bytes! */ |
| 644 | if (1 <= ckn_len && ckn_len <= MKA_MAX_CKN_LEN32) { |
| 645 | tvb_memcpy(tvb, ckn, offset, ckn_len); |
| 646 | |
| 647 | mka_ckn_info_t *rec = ckn_info_lookup(ckn, ckn_len); |
| 648 | if (rec != NULL((void*)0)) { |
| 649 | ti = proto_tree_add_string(tree, hf_mka_cak_name_info, tvb, offset, ckn_len, rec->name); |
| 650 | proto_item_set_generated(ti); |
| 651 | } |
| 652 | return rec; |
| 653 | } |
| 654 | return NULL((void*)0); |
| 655 | } |
| 656 | |
| 657 | static proto_tree * |
| 658 | dissect_basic_paramset(proto_tree *mka_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 659 | unsigned sci_offset; |
| 660 | proto_tree *basic_param_set_tree, *sci_tree; |
| 661 | proto_item *ti; |
| 662 | uint16_t ckn_len; |
| 663 | uint8_t *mi, *sci; |
| 664 | |
| 665 | ti = proto_tree_add_item(mka_tree, hf_mka_basic_param_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 666 | basic_param_set_tree = proto_item_add_subtree(ti, ett_mka_basic_param_set); |
| 667 | |
| 668 | proto_tree_add_item(basic_param_set_tree, hf_mka_version_id, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 669 | offset += 1; |
| 670 | |
| 671 | proto_tree_add_item(basic_param_set_tree, hf_mka_keyserver_priority, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 672 | offset += 1; |
| 673 | |
| 674 | proto_tree_add_item(basic_param_set_tree, hf_mka_key_server, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 675 | proto_tree_add_item(basic_param_set_tree, hf_mka_macsec_desired, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 676 | proto_tree_add_item(basic_param_set_tree, hf_mka_macsec_capability, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 677 | |
| 678 | if (tvb_get_uint8(tvb, offset) & 0x80) |
| 679 | { |
| 680 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), "Key Server"); |
| 681 | } |
| 682 | |
| 683 | proto_tree_add_uint(basic_param_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 684 | offset += 2; |
| 685 | |
| 686 | ti = proto_tree_add_item(basic_param_set_tree, hf_mka_sci, tvb, offset, 8, ENC_NA0x00000000); |
| 687 | sci_offset = offset; |
| 688 | sci_tree = proto_item_add_subtree(ti, ett_mka_sci); |
| 689 | proto_tree_add_item(sci_tree, hf_mka_sci_system_identifier, tvb, offset, 6, ENC_NA0x00000000); |
| 690 | offset += 6; |
| 691 | proto_tree_add_item(sci_tree, hf_mka_sci_port_identifier, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000); |
| 692 | offset += 2; |
| 693 | |
| 694 | proto_tree_add_item(basic_param_set_tree, hf_mka_actor_mi, tvb, offset, MKA_MI_LEN12U, ENC_NA0x00000000); |
| 695 | mi = tvb_memdup(pinfo->pool, tvb, offset, MKA_MI_LEN12U); |
| 696 | p_add_proto_data(pinfo->pool, pinfo, proto_mka, MI_KEY2, mi); |
| 697 | if (!wmem_map_contains(mka_mi_sci_map, mi)) { |
| 698 | /* We will assume that the 96-bit randomly chosen MIs do not collide. |
| 699 | * However note that an SCI can choose multiple MI over a lifetime if |
| 700 | * the Message Number would wrap. (IEEE 802.1X-2020 9.4.2) */ |
| 701 | mi = tvb_memdup(wmem_file_scope(), tvb, offset, MKA_MI_LEN12U); |
| 702 | sci = tvb_memdup(wmem_file_scope(), tvb, sci_offset, MACSEC_SCI_LEN8U); |
| 703 | wmem_map_insert(mka_mi_sci_map, mi, sci); |
| 704 | } |
| 705 | offset += MKA_MI_LEN12U; |
| 706 | |
| 707 | proto_tree_add_item(basic_param_set_tree, hf_mka_actor_mn, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 708 | offset += 4; |
| 709 | |
| 710 | proto_tree_add_item(basic_param_set_tree, hf_mka_algo_agility, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 711 | offset += 4; |
| 712 | |
| 713 | ckn_len = param_body_len - BASIC_PARAMSET_BODY_LENGTH28; |
| 714 | proto_tree_add_item(basic_param_set_tree, hf_mka_cak_name, tvb, offset, ckn_len, ENC_NA0x00000000); |
| 715 | |
| 716 | /* look up the CAK/CKN in the CKN table, and add a private hash table entry if it does not yet exist there */ |
| 717 | mka_ckn_info_t *rec = mka_add_ckn_info(basic_param_set_tree, tvb, offset, ckn_len); |
| 718 | |
| 719 | if (NULL((void*)0) != rec) { |
| 720 | /* add the record to the private hash table for this packet to tell ourselves about the CKN and its keys later on */ |
| 721 | p_add_proto_data(pinfo->pool, pinfo, proto_mka, CKN_KEY0, rec); |
| 722 | } |
| 723 | |
| 724 | return basic_param_set_tree; |
| 725 | } |
| 726 | |
| 727 | static int |
| 728 | sort_mi_by_sci(const void* a, const void* b) { |
| 729 | uint8_t *sci_a = wmem_map_lookup(mka_mi_sci_map, a); |
| 730 | uint8_t *sci_b = wmem_map_lookup(mka_mi_sci_map, b); |
| 731 | |
| 732 | DISSECTOR_ASSERT(sci_a && sci_b)((void) ((sci_a && sci_b) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-mka.c" , 732, "sci_a && sci_b")))); |
| 733 | // Numerically greatest SCI uses the SSCI value 0x01, etc. |
| 734 | return -memcmp(sci_a, sci_b, MACSEC_SCI_LEN8U); |
| 735 | } |
| 736 | |
| 737 | static proto_tree * |
| 738 | dissect_live_peer_list(proto_tree *mka_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, uint16_t param_body_len, bool_Bool key_server_ssci_flag) { |
| 739 | proto_tree *live_peer_list_set_tree; |
| 740 | proto_item *ti; |
| 741 | mka_sak_info_key_t *sak_info = NULL((void*)0); |
| 742 | uint32_t ssci; |
| 743 | uint8_t server_ssci = 0; |
| 744 | uint8_t *mi = NULL((void*)0); |
| 745 | uint8_t *sci = NULL((void*)0); |
| 746 | |
| 747 | wmem_map_t *sci_map = NULL((void*)0); |
| 748 | wmem_array_t *mi_array = NULL((void*)0); |
| 749 | |
| 750 | sak_info = p_get_proto_data(pinfo->pool, pinfo, proto_mka, SAK_KEY3); |
| 751 | mi = p_get_proto_data(pinfo->pool, pinfo, proto_mka, MI_KEY2); |
| 752 | sci = wmem_map_lookup(mka_mi_sci_map, mi); |
| 753 | DISSECTOR_ASSERT(sci)((void) ((sci) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/dissectors/packet-mka.c", 753, "sci")))); |
| 754 | if (sak_info) { |
| 755 | // Distributed SAK parameter set already processed. |
| 756 | sci_map = sak_info->sci_map; |
| 757 | mi_array = sak_info->mi_array; |
| 758 | } else { |
| 759 | // Distributed SAK parameter set not already processed. |
| 760 | // It should not appear later, per 11.11.3, but in practice |
| 761 | // in many implementations it does. |
| 762 | sci_map = wmem_map_new(pinfo->pool, mka_sci_hash, mka_sci_equal); |
| 763 | p_add_proto_data(pinfo->pool, pinfo, proto_mka, PEER_SCI_KEY4, sci_map); |
| 764 | mi_array = wmem_array_new(pinfo->pool, MKA_MI_LEN12U); |
| 765 | p_add_proto_data(pinfo->pool, pinfo, proto_mka, PEER_MI_KEY5, mi_array); |
| 766 | } |
| 767 | |
| 768 | ti = proto_tree_add_item(mka_tree, hf_mka_live_peer_list_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 769 | live_peer_list_set_tree = proto_item_add_subtree(ti, ett_mka_live_peer_list_set); |
| 770 | |
| 771 | proto_tree_add_uint(live_peer_list_set_tree, hf_mka_param_set_type, tvb, offset, 1, LIVE_PEER_LIST_TYPE1); |
| 772 | offset += 1; |
| 773 | |
| 774 | if (key_server_ssci_flag) |
| 775 | { |
| 776 | /* XXX - The presence of this field is non-trivial to find out. See IEEE 802.1X-2020, Section 11.11.3 |
| 777 | * Only present in MKPDU's with: |
| 778 | * - MKA version 3 (that's covered), and |
| 779 | * - In Live Peer list parameter set (that's covered), and |
| 780 | * - A Distributed SAK parameter set present (which could be before or after this parameter set*), but only |
| 781 | * - A Distributed SAK parameter set with XPN Cipher suites (requires to look into the contents), |
| 782 | * otherwise 0. |
| 783 | * |
| 784 | * * - 802.1X-2010 and 802.1X-2020 both specify (11.11.3 Encoding MKPDUs) |
| 785 | * that implementations with a MKA Version Identifier of 1, 2, or 3 all |
| 786 | * shall encode the protocol parameters as follows: |
| 787 | * a) The Basic Parameter Set is encoded first. |
| 788 | * b) The remaining parameter sets, except for the Live Peer List, |
| 789 | * Potential Peer List, and ICV Indicator are then encoded in |
| 790 | * parameter set type ascending order. |
| 791 | * c) The Live Peer List, if present, is encoded next. |
| 792 | * d) The Potential Peer List, if present, is encoded next. |
| 793 | * e) The ICV Indicator, if present (i.e. the Algorithm Agility |
| 794 | * parameter indicates an ICV of length other than 16 octets) |
| 795 | * is encoded last. |
| 796 | * That would make our lives easier, but in practice, implementations |
| 797 | * do not do this. A common approach is to order *all* the parameter |
| 798 | * sets other than the Basic Parameter Set in ascending type order, |
| 799 | * which puts the Live Peer List before the Distributed SAK. Some |
| 800 | * implementations include the ICV Indicator even when not necessary. |
| 801 | * |
| 802 | * Since 0 is not used as an SSCI and even though the SSCI is 32-bits |
| 803 | * in practice it cannot be larger than 255 (9.10) or even 100 or less |
| 804 | * (see the NOTE in IEEE 802.1AE-2018 10.7.13), it suffices in normal |
| 805 | * operation to add it here iff the value is nonzero. |
| 806 | */ |
| 807 | server_ssci = tvb_get_uint8(tvb, offset); |
| 808 | if (server_ssci) { |
| 809 | proto_tree_add_item(live_peer_list_set_tree, hf_mka_key_server_ssci, tvb, offset, 1, ENC_NA0x00000000); |
| 810 | } |
| 811 | } |
| 812 | |
| 813 | bool_Bool know_all_sci = false0; |
| 814 | if (sci_map) { |
| 815 | know_all_sci = true1; |
| 816 | if (server_ssci) { |
| 817 | wmem_map_insert(sci_map, sci, GUINT_TO_POINTER(server_ssci)((gpointer) (gulong) (server_ssci))); |
| 818 | } else { |
| 819 | wmem_map_insert(sci_map, sci, GUINT_TO_POINTER(UINT32_MAX)((gpointer) (gulong) ((4294967295U)))); |
| 820 | } |
| 821 | if (server_ssci > 1) { |
| 822 | uint8_t *zeroes = wmem_alloc0(pinfo->pool, MKA_MI_LEN12U * (server_ssci - 1)); |
| 823 | wmem_array_append(mi_array, zeroes, server_ssci - 1); |
| 824 | } |
| 825 | wmem_array_append(mi_array, mi, 1); |
| 826 | } |
| 827 | |
| 828 | offset += 1; |
| 829 | |
| 830 | proto_tree_add_uint(live_peer_list_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 831 | offset += 2; |
| 832 | |
| 833 | unsigned index = 1; // SSCIs start at 1 |
| 834 | while (param_body_len >= 16) { |
| 835 | /* If this is MKA version 3 and a Live Peer List in a MKPDU that contains |
| 836 | * a Distributed SAK, then the MIs are ordered in order of their SCI. This, |
| 837 | * combined with the SSCI least significant octet of the Key Server (see |
| 838 | * above) can be used to determine the SCI->SSCI mapping for XPN cipher |
| 839 | * suites, provided that the MI->SCI mapping was also recorded from the |
| 840 | * MKPDUs sent by those actors. |
| 841 | * |
| 842 | * In practice, since the SSCIs are assigned incrementing from 1, we can |
| 843 | * record the number of peers in the Live Peer List (plus the Key Server |
| 844 | * itself) and try all of them in the MACsec dissector, if necessary. |
| 845 | */ |
| 846 | proto_tree_add_item(live_peer_list_set_tree, hf_mka_peer_mi, tvb, offset, MKA_MI_LEN12U, ENC_NA0x00000000); |
| 847 | if (sci_map) { |
| 848 | mi = tvb_memdup(pinfo->pool, tvb, offset, MKA_MI_LEN12U); |
| 849 | if (index >= server_ssci) { |
| 850 | // This is the correct 1-indexed position if server_ssci is 0 |
| 851 | // Because the server SCI was put at the first position. |
| 852 | ssci = index + 1; |
| 853 | } else { |
| 854 | ssci = index; |
| 855 | } |
| 856 | // Do we know the SCI for this MI? |
| 857 | sci = wmem_map_lookup(mka_mi_sci_map, mi); |
| 858 | if (sci) { |
| 859 | if (server_ssci) { |
| 860 | wmem_map_insert(sci_map, sci, GUINT_TO_POINTER(ssci)((gpointer) (gulong) (ssci))); |
| 861 | } else { |
| 862 | /* This value is to get around wmem_map_find() not being able to |
| 863 | * distinguish between finding 0 and not finding a result. |
| 864 | * (There's no equivalent of wmem_map_lookup_extended.) |
| 865 | */ |
| 866 | wmem_map_insert(sci_map, sci, GUINT_TO_POINTER(UINT32_MAX)((gpointer) (gulong) ((4294967295U)))); |
| 867 | } |
| 868 | } else { |
| 869 | know_all_sci = false0; |
| 870 | } |
| 871 | if (ssci == wmem_array_get_count(mi_array) + 1) { |
| 872 | wmem_array_append(mi_array, mi, 1); |
| 873 | } else if (ssci < wmem_array_get_count(mi_array)) { |
| 874 | memcpy(wmem_array_index(mi_array, ssci - 1), mi, MKA_MI_LEN12U); |
| 875 | } else { |
| 876 | DISSECTOR_ASSERT_NOT_REACHED()(proto_report_dissector_bug("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"" , "epan/dissectors/packet-mka.c", 876)); |
| 877 | } |
| 878 | } |
| 879 | offset += MKA_MI_LEN12U; |
| 880 | |
| 881 | proto_tree_add_item(live_peer_list_set_tree, hf_mka_peer_mn, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 882 | offset += 4; |
| 883 | |
| 884 | param_body_len -= 16; |
| 885 | index++; |
| 886 | } |
| 887 | |
| 888 | if (mi_array && know_all_sci && !server_ssci) { |
| 889 | // For the case before MKA version 3, we manually sort these. |
| 890 | // XXX - Should we try sorting them anyway? |
| 891 | wmem_array_sort(mi_array, sort_mi_by_sci); |
| 892 | for (ssci = 1; ssci <= wmem_array_get_count(mi_array); ++ssci) { |
| 893 | mi = wmem_array_index(mi_array, ssci - 1); |
| 894 | sci = wmem_map_lookup(mka_mi_sci_map, mi); |
| 895 | if (sci) { |
| 896 | wmem_map_insert(sci_map, sci, GUINT_TO_POINTER(ssci)((gpointer) (gulong) (ssci))); |
| 897 | } |
| 898 | } |
| 899 | } |
| 900 | |
| 901 | if (param_body_len != 0) { |
| 902 | proto_tree_add_expert(live_peer_list_set_tree, pinfo, &ei_mka_undecoded, tvb, offset, param_body_len); |
| 903 | } |
| 904 | |
| 905 | return live_peer_list_set_tree; |
| 906 | } |
| 907 | |
| 908 | static proto_tree * |
| 909 | dissect_potential_peer_list(proto_tree *mka_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 910 | proto_tree *potential_peer_list_set_tree; |
| 911 | proto_item *ti; |
| 912 | |
| 913 | ti = proto_tree_add_item(mka_tree, hf_mka_potential_peer_list_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 914 | potential_peer_list_set_tree = proto_item_add_subtree(ti, ett_mka_potential_peer_list_set); |
| 915 | |
| 916 | proto_tree_add_uint(potential_peer_list_set_tree, hf_mka_param_set_type, tvb, offset, 1, POTENTIAL_PEER_LIST_TYPE2); |
| 917 | offset += 2; |
| 918 | |
| 919 | proto_tree_add_uint(potential_peer_list_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 920 | offset += 2; |
| 921 | |
| 922 | while (param_body_len >= 16) { |
| 923 | proto_tree_add_item(potential_peer_list_set_tree, hf_mka_peer_mi, tvb, offset, MKA_MI_LEN12U, ENC_NA0x00000000); |
| 924 | offset += MKA_MI_LEN12U; |
| 925 | |
| 926 | proto_tree_add_item(potential_peer_list_set_tree, hf_mka_peer_mn, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 927 | offset += 4; |
| 928 | |
| 929 | param_body_len -= 16; |
| 930 | } |
| 931 | |
| 932 | if (param_body_len != 0) { |
| 933 | proto_tree_add_expert(potential_peer_list_set_tree, pinfo, &ei_mka_undecoded, tvb, offset, param_body_len); |
| 934 | } |
| 935 | |
| 936 | return potential_peer_list_set_tree; |
| 937 | } |
| 938 | |
| 939 | static proto_tree * |
| 940 | dissect_sak_use(proto_tree *mka_tree, packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 941 | proto_tree *sak_use_set_tree; |
| 942 | proto_item *ti; |
| 943 | bool_Bool latest_rx, old_rx; |
| 944 | uint32_t pn; |
| 945 | uint8_t ki[MKA_KI_LEN16U]; |
| 946 | mka_ki_pn_t *pn_key; |
| 947 | |
| 948 | ti = proto_tree_add_item(mka_tree, hf_mka_macsec_sak_use_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 949 | sak_use_set_tree = proto_item_add_subtree(ti, ett_mka_sak_use_set); |
| 950 | |
| 951 | proto_tree_add_item(sak_use_set_tree, hf_mka_param_set_type, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 952 | offset += 1; |
| 953 | |
| 954 | proto_tree_add_item(sak_use_set_tree, hf_mka_latest_key_an, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 955 | proto_tree_add_item(sak_use_set_tree, hf_mka_latest_key_tx, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 956 | proto_tree_add_item_ret_boolean(sak_use_set_tree, hf_mka_latest_key_rx, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &latest_rx); |
| 957 | |
| 958 | proto_tree_add_item(sak_use_set_tree, hf_mka_old_key_an, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 959 | proto_tree_add_item(sak_use_set_tree, hf_mka_old_key_tx, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 960 | proto_tree_add_item_ret_boolean(sak_use_set_tree, hf_mka_old_key_rx, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &old_rx); |
| 961 | offset += 1; |
| 962 | |
| 963 | proto_tree_add_item(sak_use_set_tree, hf_mka_plain_tx, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 964 | proto_tree_add_item(sak_use_set_tree, hf_mka_plain_rx, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 965 | proto_tree_add_item(sak_use_set_tree, hf_mka_delay_protect, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 966 | |
| 967 | proto_tree_add_uint(sak_use_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 968 | offset += 2; |
| 969 | |
| 970 | /* |
| 971 | * 802.1X-2020 specifies only 0 or 40 are valid! See Figure 11-10 Note d |
| 972 | */ |
| 973 | if (param_body_len == 0) /* MACsec not supported */ |
| 974 | { |
| 975 | /* Nothing */ |
| 976 | } |
| 977 | else if (param_body_len == 40) /* MACsec supported */ |
| 978 | { |
| 979 | proto_tree_add_item(sak_use_set_tree, hf_mka_latest_key_server_mi, tvb, offset, 12, ENC_NA0x00000000); |
| 980 | if (latest_rx && !PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { |
| 981 | tvb_memcpy(tvb, ki, offset, MKA_KI_LEN16U); |
| 982 | } |
| 983 | offset += 12; |
| 984 | |
| 985 | proto_tree_add_item(sak_use_set_tree, hf_mka_latest_key_number, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 986 | offset += 4; |
| 987 | if (latest_rx && !PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { |
| 988 | proto_tree_add_item_ret_uint(sak_use_set_tree, hf_mka_latest_lowest_acceptable_pn, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &pn); |
| 989 | |
| 990 | pn_key = wmem_new(pinfo->pool, mka_ki_pn_t)((mka_ki_pn_t*)wmem_alloc((pinfo->pool), sizeof(mka_ki_pn_t ))); |
| 991 | memcpy(pn_key->ki, ki, MKA_KI_LEN16U); |
| 992 | pn_key->pn = pn; |
| 993 | p_add_proto_data(pinfo->pool, pinfo, proto_mka, LATEST_KEY6, pn_key); |
| 994 | } else { |
| 995 | proto_tree_add_item(sak_use_set_tree, hf_mka_latest_lowest_acceptable_pn, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 996 | } |
| 997 | offset += 4; |
| 998 | |
| 999 | proto_tree_add_item(sak_use_set_tree, hf_mka_old_key_server_mi, tvb, offset, 12, ENC_NA0x00000000); |
| 1000 | if (old_rx && !PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { |
| 1001 | tvb_memcpy(tvb, ki, offset, MKA_KI_LEN16U); |
| 1002 | } |
| 1003 | offset += 12; |
| 1004 | |
| 1005 | proto_tree_add_item(sak_use_set_tree, hf_mka_old_key_number, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 1006 | offset += 4; |
| 1007 | |
| 1008 | if (old_rx && !PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { |
| 1009 | proto_tree_add_item_ret_uint(sak_use_set_tree, hf_mka_old_lowest_acceptable_pn, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &pn); |
| 1010 | pn_key = wmem_new(pinfo->pool, mka_ki_pn_t)((mka_ki_pn_t*)wmem_alloc((pinfo->pool), sizeof(mka_ki_pn_t ))); |
| 1011 | memcpy(pn_key->ki, ki, MKA_KI_LEN16U); |
| 1012 | pn_key->pn = pn; |
| 1013 | p_add_proto_data(pinfo->pool, pinfo, proto_mka, OLD_KEY7, pn_key); |
| 1014 | } else { |
| 1015 | proto_tree_add_item(sak_use_set_tree, hf_mka_old_lowest_acceptable_pn, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 1016 | } |
| 1017 | offset += 4; |
Value stored to 'offset' is never read | |
| 1018 | } |
| 1019 | else |
| 1020 | { |
| 1021 | proto_tree_add_expert(sak_use_set_tree, pinfo, &ei_mka_undecoded, tvb, offset, param_body_len); |
| 1022 | } |
| 1023 | |
| 1024 | return sak_use_set_tree; |
| 1025 | } |
| 1026 | |
| 1027 | static void |
| 1028 | mka_sci_map_copy(void *key, void *value, void *user_data) { |
| 1029 | wmem_map_t *target_map = (wmem_map_t*)user_data; |
| 1030 | uint8_t *sci = (uint8_t*)key; |
| 1031 | |
| 1032 | // The key here (SCI) is already in file scope (a pointer to a result in |
| 1033 | // the dissector global MI->SCI map), and the value is a GUINT_TO_POINTER, |
| 1034 | // so we don't need to wmem_memdup anything. |
| 1035 | wmem_map_insert(target_map, sci, value); |
| 1036 | } |
| 1037 | |
| 1038 | static proto_tree * |
| 1039 | dissect_distributed_sak(proto_tree *mka_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 1040 | proto_tree *distributed_sak_tree; |
| 1041 | proto_item *ti; |
| 1042 | |
| 1043 | ti = proto_tree_add_item(mka_tree, hf_mka_distributed_sak_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 1044 | distributed_sak_tree = proto_item_add_subtree(ti, ett_mka_distributed_sak_set); |
| 1045 | |
| 1046 | proto_tree_add_uint(distributed_sak_tree, hf_mka_param_set_type, tvb, offset, 1, DISTRIBUTED_SAK_TYPE4); |
| 1047 | offset += 1; |
| 1048 | |
| 1049 | /* distributed AN is used later if use of MKA is enabled */ |
| 1050 | uint8_t distributed_an = ((tvb_get_uint8(tvb, offset) & 0xC0) >> 6); |
| 1051 | |
| 1052 | proto_tree_add_item(distributed_sak_tree, hf_mka_distributed_an, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 1053 | proto_tree_add_item(distributed_sak_tree, hf_mka_confidentiality_offset, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); |
| 1054 | /* XXX - The offset > 0 (2, 3) here must match the macsec capability (3) in the basic parameter set. */ |
| 1055 | offset += 1; |
| 1056 | |
| 1057 | proto_tree_add_uint(distributed_sak_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 1058 | offset += 2; |
| 1059 | |
| 1060 | if (param_body_len == 0) // Plain text |
| 1061 | { |
| 1062 | // Nothing |
| 1063 | } |
| 1064 | else if ((DISTRIBUTED_SAK_AES128_BODY_LEN28 == param_body_len) || (DISTRIBUTED_SAK_AES128_XPN_BODY_LEN36 <= param_body_len)) { // GCM-AES-128, GCM-AES-XPN-128, GCM-AES-256, GCM-AES-XPN-256 |
| 1065 | uint64_t cipher_suite = MACSEC_GCM_AES_1280x0080C20001000001UL; // Default if not specified |
| 1066 | uint16_t wrappedlen = WRAPPED_KEY_LEN(AES128_KEY_LEN)((16) + 8); |
| 1067 | uint32_t kn; |
| 1068 | mka_sak_info_key_t *sak_info; |
| 1069 | uint8_t *sak; |
| 1070 | |
| 1071 | proto_tree_add_item_ret_uint(distributed_sak_tree, hf_mka_key_number, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &kn); |
| 1072 | offset += 4; |
| 1073 | |
| 1074 | /* For AES256, the wrapped key is longer and an 8 byte cipher suite is inserted before the wrapped key data. */ |
| 1075 | if (DISTRIBUTED_SAK_AES128_XPN_BODY_LEN36 <= param_body_len) { |
| 1076 | proto_tree_add_item_ret_uint64(distributed_sak_tree, hf_mka_macsec_cipher_suite, tvb, offset, CIPHER_SUITE_LEN8, ENC_BIG_ENDIAN0x00000000, &cipher_suite); |
| 1077 | offset += CIPHER_SUITE_LEN8; |
| 1078 | switch (cipher_suite) { |
| 1079 | case MACSEC_GCM_AES_XPN_1280x0080C20001000003UL: |
| 1080 | break; |
| 1081 | |
| 1082 | case MACSEC_GCM_AES_XPN_2560x0080C20001000004UL: |
| 1083 | case MACSEC_GCM_AES_2560x0080C20001000002UL: |
| 1084 | wrappedlen = WRAPPED_KEY_LEN(AES256_KEY_LEN)((32) + 8); |
| 1085 | break; |
| 1086 | default: |
| 1087 | proto_tree_add_expert(distributed_sak_tree, pinfo, &ei_mka_undecoded, tvb, offset, param_body_len - 12); |
| 1088 | goto out; |
| 1089 | } |
| 1090 | } |
| 1091 | |
| 1092 | /* Add the wrapped key data. */ |
| 1093 | const uint8_t *wrappedkey = tvb_memdup(pinfo->pool, tvb, offset, wrappedlen); |
| 1094 | proto_tree_add_item(distributed_sak_tree, hf_mka_aes_key_wrap_sak, tvb, offset, wrappedlen, ENC_NA0x00000000); |
| 1095 | offset += wrappedlen; |
| 1096 | |
| 1097 | /* Attempt to unwrap the key using the KEK for the CKN. */ |
| 1098 | /* Fetch the KEK for the CKN in the basic parameter set. */ |
| 1099 | mka_ckn_info_t *rec = p_get_proto_data(pinfo->pool, pinfo, proto_mka, CKN_KEY0); |
| 1100 | if (NULL((void*)0) == rec) { |
| 1101 | ws_info("no record for CKN")do { if (1) { ws_log_full("MKA", LOG_LEVEL_INFO, ((void*)0), - 1, ((void*)0), "no record for CKN"); } } while (0); |
| 1102 | goto out; |
| 1103 | } |
| 1104 | |
| 1105 | /* Look up the CKN and if found in the table, use the KEK associated with it. */ |
| 1106 | ws_debug("CKN entry name: %s", rec->name)do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 1106, __func__, "CKN entry name: %s", rec->name); } } while (0); |
| 1107 | |
| 1108 | /* If no KEK available, skip the decode. */ |
| 1109 | mka_ckn_info_key_t *key = &(rec->key); |
| 1110 | if ((NULL((void*)0) == key) || (0 == key->kek_len)) { |
| 1111 | goto out; |
| 1112 | } |
| 1113 | |
| 1114 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { |
| 1115 | /* Open the cipher context. */ |
| 1116 | gcry_cipher_hd_t hd; |
| 1117 | if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0)) { |
| 1118 | ws_warning("failed to open cipher context")do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 1118, __func__, "failed to open cipher context"); } } while (0); |
| 1119 | goto out; |
| 1120 | } |
| 1121 | |
| 1122 | if (gcry_cipher_setkey(hd, key->kek, key->kek_len)) { |
| 1123 | ws_warning("failed to set KEK")do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 1123, __func__, "failed to set KEK"); } } while (0); |
| 1124 | gcry_cipher_close(hd); |
| 1125 | goto out; |
| 1126 | } |
| 1127 | |
| 1128 | sak_info = get_or_create_sak_info(rec, distributed_an, pinfo->num); |
| 1129 | |
| 1130 | /* Unwrap the key with the KEK. */ |
| 1131 | sak = sak_info->sak; |
| 1132 | sak_info->sak_len = wrappedlen - WRAPPED_KEY_IV_LEN8; |
| 1133 | if (gcry_cipher_decrypt(hd, sak, sak_info->sak_len, wrappedkey, wrappedlen) ) { |
| 1134 | ws_info("failed to unwrap SAK")do { if (1) { ws_log_full("MKA", LOG_LEVEL_INFO, ((void*)0), - 1, ((void*)0), "failed to unwrap SAK"); } } while (0); |
| 1135 | memset(sak, 0, MKA_MAX_SAK_LEN((32))); |
| 1136 | sak_info->sak_len = 0; |
| 1137 | gcry_cipher_close(hd); |
| 1138 | goto out; |
| 1139 | } |
| 1140 | |
| 1141 | /* Add the Key Identifier */ |
| 1142 | uint8_t *mi = p_get_proto_data(pinfo->pool, pinfo, proto_mka, MI_KEY2); |
| 1143 | /* This is added in the Basic Parameter Set, which is always dissected. */ |
| 1144 | DISSECTOR_ASSERT(mi != NULL)((void) ((mi != ((void*)0)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-mka.c" , 1144, "mi != ((void*)0)")))); |
| 1145 | memcpy(sak_info->ki, mi, MKA_MI_LEN12U); |
| 1146 | phtonu32(&sak_info->ki[MKA_MI_LEN12U], kn); |
| 1147 | |
| 1148 | sak_info->cipher_suite = cipher_suite; |
| 1149 | wmem_map_t *sci_map = p_get_proto_data(pinfo->pool, pinfo, proto_mka, PEER_SCI_KEY4); |
| 1150 | if (sci_map) { |
| 1151 | wmem_map_foreach(sci_map, mka_sci_map_copy, sak_info->sci_map); |
| 1152 | } |
| 1153 | wmem_array_t *mi_array = p_get_proto_data(pinfo->pool, pinfo, proto_mka, PEER_MI_KEY5); |
| 1154 | if (mi_array) { |
| 1155 | wmem_array_append(sak_info->mi_array, wmem_array_get_raw(mi_array), wmem_array_get_count(mi_array)); |
| 1156 | } |
| 1157 | if (cipher_suite == MACSEC_GCM_AES_XPN_1280x0080C20001000003UL || cipher_suite == MACSEC_GCM_AES_XPN_2560x0080C20001000004UL) { |
| 1158 | /* 802.1AE-2018 10.7.8 SAK creation |
| 1159 | * "The 64 least significant bits of the Salt are the 64 least significant |
| 1160 | * bits of the MKA Key Server’s Member Identifier (MI), the 16 next most |
| 1161 | * significant bits of the Salt comprise the exclusive-or of the 16 next |
| 1162 | * most significant bits of that MI with the 16 most significant bits of |
| 1163 | * the 32-bit MKA Key Number (KN), and the 16 most significant bits of |
| 1164 | * the Salt comprise the exclusive-or of the 16 most significant bits of |
| 1165 | * that MI with the 16 least significant bits of the KN. |
| 1166 | */ |
| 1167 | uint32_t mi_upper = pntohu32(mi); |
| 1168 | mi_upper ^= (kn >> 16); |
| 1169 | mi_upper ^= (kn & UINT16_MAX(65535)) << 16; |
| 1170 | phtonu32(mi, mi_upper); |
| 1171 | memcpy(sak_info->salt, mi, MACSEC_XPN_SALT_LEN12U); |
| 1172 | } |
| 1173 | |
| 1174 | /* Close the cipher context. */ |
| 1175 | gcry_cipher_close(hd); |
| 1176 | |
| 1177 | p_add_proto_data(pinfo->pool, pinfo, proto_mka, SAK_KEY3, sak_info); |
| 1178 | |
| 1179 | if (ws_log_msg_is_active(WS_LOG_DOMAIN"MKA", LOG_LEVEL_DEBUG)) { |
| 1180 | char *sak_str = bytes_to_str_maxlen(pinfo->pool, sak, sak_info->sak_len, 0); |
| 1181 | ws_debug("unwrapped sak: %s", sak_str)do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 1181, __func__, "unwrapped sak: %s", sak_str); } } while (0 ); |
| 1182 | } |
| 1183 | } else { |
| 1184 | /* Do not try to create on the second pass, only retrieve. */ |
| 1185 | sak_info = get_sak_info(rec, distributed_an, pinfo->num); |
| 1186 | if (!sak_info) |
| 1187 | goto out; |
| 1188 | } |
| 1189 | |
| 1190 | /* Add the unwrapped SAK to the output. */ |
| 1191 | tvbuff_t *sak_tvb = tvb_new_child_real_data(tvb, sak_info->sak, sak_info->sak_len, sak_info->sak_len); |
| 1192 | add_new_data_source(pinfo, sak_tvb, "Unwrapped SAK"); |
| 1193 | proto_tree_add_item(distributed_sak_tree, hf_mka_aes_key_wrap_unwrapped_sak, sak_tvb, 0, sak_info->sak_len, ENC_NA0x00000000); |
| 1194 | } |
| 1195 | else |
| 1196 | { |
| 1197 | proto_tree_add_expert(distributed_sak_tree, pinfo, &ei_mka_undecoded, tvb, offset, param_body_len); |
| 1198 | } |
| 1199 | |
| 1200 | out: |
| 1201 | return distributed_sak_tree; |
| 1202 | } |
| 1203 | |
| 1204 | static proto_tree * |
| 1205 | dissect_distributed_cak(proto_tree *mka_tree, packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 1206 | proto_tree *distributed_cak_tree; |
| 1207 | proto_item *ti; |
| 1208 | uint16_t cak_len; |
| 1209 | |
| 1210 | ti = proto_tree_add_item(mka_tree, hf_mka_distributed_cak_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 1211 | distributed_cak_tree = proto_item_add_subtree(ti, ett_mka_distributed_cak_set); |
| 1212 | |
| 1213 | proto_tree_add_uint(distributed_cak_tree, hf_mka_param_set_type, tvb, offset, 1, DISTRIBUTED_CAK_TYPE5); |
| 1214 | offset += 2; |
| 1215 | |
| 1216 | proto_tree_add_uint(distributed_cak_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 1217 | offset += 2; |
| 1218 | |
| 1219 | proto_tree_add_item(distributed_cak_tree, hf_mka_aes_key_wrap_cak, tvb, offset, 24, ENC_NA0x00000000); |
| 1220 | offset += 24; |
| 1221 | |
| 1222 | cak_len = param_body_len - 24; |
| 1223 | proto_tree_add_item(distributed_cak_tree, hf_mka_cak_name, tvb, offset, cak_len, ENC_NA0x00000000); |
| 1224 | mka_add_ckn_info(distributed_cak_tree, tvb, offset, cak_len); |
| 1225 | |
| 1226 | return distributed_cak_tree; |
| 1227 | } |
| 1228 | |
| 1229 | static proto_tree * |
| 1230 | dissect_kmd(proto_tree *mka_tree, packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 1231 | proto_tree *kmd_set_tree; |
| 1232 | proto_item *ti; |
| 1233 | |
| 1234 | ti = proto_tree_add_item(mka_tree, hf_mka_kmd_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 1235 | kmd_set_tree = proto_item_add_subtree(ti, ett_mka_kmd_set); |
| 1236 | |
| 1237 | proto_tree_add_uint(kmd_set_tree, hf_mka_param_set_type, tvb, offset, 1, KMD_TYPE6); |
| 1238 | offset += 2; |
| 1239 | |
| 1240 | proto_tree_add_uint(kmd_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 1241 | offset += 2; |
| 1242 | |
| 1243 | // Ref 802.1X-2020, 12.6 KMD: A string of up to 253 UTF-8 characters. |
| 1244 | proto_tree_add_item(kmd_set_tree, hf_mka_kmd, tvb, offset, param_body_len, ENC_UTF_80x00000002); |
| 1245 | |
| 1246 | return kmd_set_tree; |
| 1247 | } |
| 1248 | |
| 1249 | static proto_tree * |
| 1250 | dissect_announcement(proto_tree *mka_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 1251 | proto_tree *announcement_set_tree; |
| 1252 | proto_item *ti; |
| 1253 | int offset2; |
| 1254 | |
| 1255 | ti = proto_tree_add_item(mka_tree, hf_mka_announcement_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 1256 | announcement_set_tree = proto_item_add_subtree(ti, ett_mka_announcement_set); |
| 1257 | |
| 1258 | proto_tree_add_uint(announcement_set_tree, hf_mka_param_set_type, tvb, offset, 1, ANNOUNCEMENT_TYPE7); |
| 1259 | offset += 2; |
| 1260 | |
| 1261 | proto_tree_add_uint(announcement_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 1262 | offset += 2; |
| 1263 | |
| 1264 | offset2 = 0; |
| 1265 | while (offset2 + 2 <= param_body_len) { |
| 1266 | proto_tree *tlv_tree; |
| 1267 | uint8_t tlv_type = ((tvb_get_uint8(tvb, offset + offset2)) & 0xfe ) >> 1; |
| 1268 | uint16_t tlv_length = (tvb_get_ntohs(tvb, offset + offset2)) & 0x01ff; |
| 1269 | |
| 1270 | if (offset2 + 2 + tlv_length > param_body_len) { |
| 1271 | break; |
| 1272 | } |
| 1273 | |
| 1274 | ti = proto_tree_add_none_format(announcement_set_tree, hf_mka_tlv_entry, tvb, offset + offset2, tlv_length + 2, "TLV entry: %s", |
| 1275 | val_to_str(pinfo->pool, tlv_type, macsec_tlvs, "unknown TLV type: %d")); |
| 1276 | tlv_tree = proto_item_add_subtree(ti, ett_mka_tlv); |
| 1277 | |
| 1278 | proto_tree_add_item(tlv_tree, hf_mka_tlv_type, tvb, offset + offset2, 1, ENC_NA0x00000000); |
| 1279 | proto_tree_add_item(tlv_tree, hf_mka_tlv_info_string_length, tvb, offset + offset2, 2, ENC_BIG_ENDIAN0x00000000); |
| 1280 | offset2 += 2; |
| 1281 | |
| 1282 | if (tlv_length > 0) { |
| 1283 | // See IEEE 802.1X-2010, Section 11.11.1, Figure 11-15 and Section 11.12 |
| 1284 | switch (tlv_type) { |
| 1285 | case 112: // MACsec Cipher Suites |
| 1286 | for (uint16_t tlv_item_offset = 0; tlv_item_offset + 10 <= tlv_length; tlv_item_offset += 8) { |
| 1287 | proto_tree *cipher_suite_entry; |
| 1288 | uint64_t cipher_suite_id = tvb_get_uint64(tvb, offset + offset2 + tlv_item_offset + 2, ENC_BIG_ENDIAN0x00000000); |
| 1289 | uint16_t cipher_suite_cap = tvb_get_uint16(tvb, offset + offset2 + tlv_item_offset, ENC_BIG_ENDIAN0x00000000) & 0x0003; |
| 1290 | |
| 1291 | ti = proto_tree_add_none_format(tlv_tree, hf_mka_tlv_entry, tvb, offset + offset2, tlv_length + 2, "Cipher Suite: %s, %s", |
| 1292 | val64_to_str_wmem(pinfo->pool, cipher_suite_id, macsec_cipher_suite_vals, "Unknown Cipher Suite (0x%" PRIx64"l" "x" ")"), |
| 1293 | val_to_str(pinfo->pool, cipher_suite_cap, macsec_capability_type_vals, "Unknown Capability (%d)")); |
| 1294 | cipher_suite_entry = proto_item_add_subtree(ti, ett_mka_cipher_suite_entry); |
| 1295 | |
| 1296 | proto_tree_add_item(cipher_suite_entry, hf_mka_tlv_cipher_suite_impl_cap, tvb, offset + offset2 + tlv_item_offset, 2, ENC_BIG_ENDIAN0x00000000); |
| 1297 | tlv_item_offset += 2; |
| 1298 | proto_tree_add_item(cipher_suite_entry, hf_mka_macsec_cipher_suite, tvb, offset + offset2 + tlv_item_offset, 8, ENC_BIG_ENDIAN0x00000000); |
| 1299 | } |
| 1300 | break; |
| 1301 | |
| 1302 | case 113: // Key Management Domain |
| 1303 | proto_tree_add_item(tlv_tree, hf_mka_kmd, tvb, offset + offset2, tlv_length, ENC_UTF_80x00000002); |
| 1304 | break; |
| 1305 | |
| 1306 | case 111: // Access Information |
| 1307 | case 114: // NID (Network Identifier) |
| 1308 | proto_tree_add_expert(tlv_tree, pinfo, &ei_mka_unimplemented, tvb, offset + offset2, tlv_length); |
| 1309 | proto_tree_add_item(tlv_tree, hf_mka_tlv_data, tvb, offset + offset2, tlv_length, ENC_NA0x00000000); |
| 1310 | break; |
| 1311 | |
| 1312 | default: |
| 1313 | proto_tree_add_item(tlv_tree, hf_mka_tlv_data, tvb, offset + offset2, tlv_length, ENC_NA0x00000000); |
| 1314 | } |
| 1315 | offset2 += tlv_length; |
| 1316 | } |
| 1317 | } |
| 1318 | |
| 1319 | return announcement_set_tree;; |
| 1320 | } |
| 1321 | |
| 1322 | static proto_tree * |
| 1323 | dissect_xpn(proto_tree *mka_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 1324 | proto_tree *xpn_set_tree; |
| 1325 | proto_item *ti; |
| 1326 | uint32_t pn_msb; |
| 1327 | mka_ki_pn_t *pn_key; |
| 1328 | uint8_t *mi, *sci = NULL((void*)0); |
| 1329 | |
| 1330 | ti = proto_tree_add_item(mka_tree, hf_mka_xpn_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 1331 | xpn_set_tree = proto_item_add_subtree(ti, ett_mka_xpn_set); |
| 1332 | |
| 1333 | proto_tree_add_uint(xpn_set_tree, hf_mka_param_set_type, tvb, offset, 1, XPN_TYPE8); |
| 1334 | offset += 1; |
| 1335 | |
| 1336 | proto_tree_add_item(xpn_set_tree, hf_mka_suspension_time, tvb, offset, 1, ENC_NA0x00000000); |
| 1337 | offset += 1; |
| 1338 | |
| 1339 | proto_tree_add_uint(xpn_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 1340 | offset += 2; |
| 1341 | |
| 1342 | /* Based on samples, we should be able to assume that the spec is followed |
| 1343 | * and the XPN parameter set appears after the MACsec SAK Use set */ |
| 1344 | pn_key = p_get_proto_data(pinfo->pool, pinfo, proto_mka, LATEST_KEY6); |
| 1345 | if (pn_key) { |
| 1346 | proto_tree_add_item_ret_uint(xpn_set_tree, hf_mka_latest_lowest_accept_pn_msb, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &pn_msb); |
| 1347 | pn_key->pn |= ((uint64_t)pn_msb << 32); |
| 1348 | mi = p_get_proto_data(pinfo->pool, pinfo, proto_mka, MI_KEY2); |
| 1349 | sci = wmem_map_lookup(mka_mi_sci_map, mi); |
| 1350 | DISSECTOR_ASSERT(sci)((void) ((sci) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/dissectors/packet-mka.c", 1350, "sci")))); |
| 1351 | update_lpn(pn_key, sci, pinfo->num); |
| 1352 | } else { |
| 1353 | proto_tree_add_item(xpn_set_tree, hf_mka_latest_lowest_accept_pn_msb, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 1354 | } |
| 1355 | offset += 4; |
| 1356 | |
| 1357 | pn_key = p_get_proto_data(pinfo->pool, pinfo, proto_mka, OLD_KEY7); |
| 1358 | if (pn_key) { |
| 1359 | proto_tree_add_item_ret_uint(xpn_set_tree, hf_mka_old_lowest_accept_pn_msb, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &pn_msb); |
| 1360 | pn_key->pn |= ((uint64_t)pn_msb << 32); |
| 1361 | if (sci == NULL((void*)0)) { |
| 1362 | mi = p_get_proto_data(pinfo->pool, pinfo, proto_mka, MI_KEY2); |
| 1363 | sci = wmem_map_lookup(mka_mi_sci_map, mi); |
| 1364 | DISSECTOR_ASSERT(sci)((void) ((sci) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/dissectors/packet-mka.c", 1364, "sci")))); |
| 1365 | } |
| 1366 | update_lpn(pn_key, sci, pinfo->num); |
| 1367 | } else { |
| 1368 | proto_tree_add_item(xpn_set_tree, hf_mka_old_lowest_accept_pn_msb, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); |
| 1369 | } |
| 1370 | |
| 1371 | return xpn_set_tree; |
| 1372 | } |
| 1373 | |
| 1374 | static proto_tree * |
| 1375 | dissect_icv(proto_tree *mka_tree, packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, uint16_t param_body_len) { |
| 1376 | proto_tree *icv_set_tree; |
| 1377 | proto_item *ti; |
| 1378 | |
| 1379 | ti = proto_tree_add_item(mka_tree, hf_mka_icv_set, tvb, offset, 4, ENC_NA0x00000000); |
| 1380 | icv_set_tree = proto_item_add_subtree(ti, ett_mka_icv_set); |
| 1381 | |
| 1382 | proto_tree_add_uint(icv_set_tree, hf_mka_param_set_type, tvb, offset, 1, ICV_TYPE255); |
| 1383 | offset += 2; |
| 1384 | |
| 1385 | proto_tree_add_uint(icv_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 1386 | |
| 1387 | return icv_set_tree; |
| 1388 | } |
| 1389 | |
| 1390 | static proto_tree * |
| 1391 | dissect_unknown_param_set(proto_tree *mka_tree, packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, uint16_t param_body_len, uint8_t param_set_type) { |
| 1392 | proto_tree *param_set_tree; |
| 1393 | proto_item *ti; |
| 1394 | |
| 1395 | ti = proto_tree_add_item(mka_tree, hf_mka_unknown_set, tvb, offset, param_body_len + 4, ENC_NA0x00000000); |
| 1396 | param_set_tree = proto_item_add_subtree(ti, ett_mka_unknown_set); |
| 1397 | |
| 1398 | proto_tree_add_uint(param_set_tree, hf_mka_param_set_type, tvb, offset, 1, param_set_type); |
| 1399 | offset += 2; |
| 1400 | |
| 1401 | proto_tree_add_uint(param_set_tree, hf_mka_param_body_length, tvb, offset, 2, param_body_len); |
| 1402 | offset += 2; |
| 1403 | |
| 1404 | proto_tree_add_item(param_set_tree, hf_mka_unknown_param_set, tvb, offset, param_body_len, ENC_NA0x00000000); |
| 1405 | |
| 1406 | return param_set_tree; |
| 1407 | } |
| 1408 | |
| 1409 | static uint8_t* |
| 1410 | calculate_icv(packet_info *pinfo, size_t icv_len) { |
| 1411 | /* IEEE Std 802.1X-2020 9.4.1 Message authentication |
| 1412 | * |
| 1413 | * Each protocol data unit (MKPDU) transmitted is integrity protected by an |
| 1414 | * 128 bit ICV, generated by AES-CMAC using the ICK (9.3): |
| 1415 | * |
| 1416 | * ICV = AES-CMAC(ICK, M, 128) |
| 1417 | * M = DA + SA + (MSDU – ICV) |
| 1418 | * |
| 1419 | * In other words, M comprises the concatenation of the destination and source |
| 1420 | * MAC addresses, each represented by a sequence of 6 octets in canonical |
| 1421 | * format order, with the MSDU (MAC Service Data Unit) of the MKPDU including |
| 1422 | * the allocated Ethertype, and up to but not including, the generated ICV. |
| 1423 | * |
| 1424 | * NOTE—M comprises the whole of what is often referred to as ‘the frame’ |
| 1425 | * considered from the point of view of the MAC Service provided by Common |
| 1426 | * Port of the SecY (Figure 6-2) or PAC (Figure 6-6) supporting MKPDU |
| 1427 | * transmission. The description does not use the term ‘frame’, because that |
| 1428 | * Common Port could be supported by additional VLAN tags or other tags |
| 1429 | * (consider the upper SecY shown in Figure 7-17) prior to transmission of a |
| 1430 | * MAC frame by a system. Any such additional tags would not be covered by |
| 1431 | * the ICV, and would be removed prior to MKPDU reception by a peer PAE. |
| 1432 | */ |
| 1433 | |
| 1434 | if (PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { |
| 1435 | return p_get_proto_data(wmem_file_scope(), pinfo, proto_mka, ICV_KEY1); |
| 1436 | } |
| 1437 | |
| 1438 | gcry_error_t err; |
| 1439 | mka_ckn_info_t *rec = p_get_proto_data(pinfo->pool, pinfo, proto_mka, CKN_KEY0); |
| 1440 | proto_eapol_key_frame_t *eapol_frame = p_get_proto_data(pinfo->pool, pinfo, proto_eapol, EAPOL_KEY_FRAME_KEY0); |
| 1441 | |
| 1442 | if (rec == NULL((void*)0) || eapol_frame == NULL((void*)0) || pinfo->dl_dst.type != AT_ETHER || pinfo->dl_src.type != AT_ETHER) { |
| 1443 | return NULL((void*)0); |
| 1444 | } |
| 1445 | |
| 1446 | if (eapol_frame->len < icv_len) { |
| 1447 | return NULL((void*)0); |
| 1448 | } |
| 1449 | |
| 1450 | /* Look up the CKN and if found, use the ICK associated with it. */ |
| 1451 | ws_debug("CKN entry name: %s", rec->name)do { if (1) { ws_log_full("MKA", LOG_LEVEL_DEBUG, "epan/dissectors/packet-mka.c" , 1451, __func__, "CKN entry name: %s", rec->name); } } while (0); |
| 1452 | |
| 1453 | /* If no ICK available, skip the calculation. */ |
| 1454 | mka_ckn_info_key_t *key = &(rec->key); |
| 1455 | if ((NULL((void*)0) == key) || (0 == key->ick_len)) { |
| 1456 | return NULL((void*)0); |
| 1457 | } |
| 1458 | |
| 1459 | /* Open the MAC context. */ |
| 1460 | gcry_mac_hd_t hd; |
| 1461 | if ((err = gcry_mac_open(&hd, GCRY_MAC_CMAC_AES, 0, NULL((void*)0)))) { |
| 1462 | ws_warning("failed to open MAC context: %s", gcry_strerror(err))do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 1462, __func__, "failed to open MAC context: %s", gcry_strerror (err)); } } while (0); |
| 1463 | return NULL((void*)0); |
| 1464 | } |
| 1465 | |
| 1466 | if ((err = gcry_mac_setkey(hd, key->ick, key->ick_len))) { |
| 1467 | ws_warning("failed to set ICK: %s", gcry_strerror(err))do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 1467, __func__, "failed to set ICK: %s", gcry_strerror(err) ); } } while (0); |
| 1468 | goto failed; |
| 1469 | } |
| 1470 | |
| 1471 | uint8_t *icv_calc = (uint8_t*)wmem_alloc0(wmem_file_scope(), icv_len); |
| 1472 | uint8_t eapol_ethertype[2]; |
| 1473 | phtonu16(eapol_ethertype, ETHERTYPE_EAPOL0x888E); |
| 1474 | wmem_array_t *ethhdr = wmem_array_sized_new(pinfo->pool, sizeof(uint8_t), pinfo->dst.len + pinfo->src.len + 2); |
| 1475 | wmem_array_append(ethhdr, pinfo->dst.data, pinfo->dst.len); |
| 1476 | wmem_array_append(ethhdr, pinfo->src.data, pinfo->src.len); |
| 1477 | wmem_array_append(ethhdr, eapol_ethertype, sizeof(eapol_ethertype)); |
| 1478 | if ((err = gcry_mac_write(hd, wmem_array_get_raw(ethhdr), wmem_array_get_count(ethhdr)))) { |
| 1479 | ws_warning("failed to update MAC: %s", gcry_strerror(err))do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 1479, __func__, "failed to update MAC: %s", gcry_strerror(err )); } } while (0); |
| 1480 | goto failed; |
| 1481 | } |
| 1482 | if ((err = gcry_mac_write(hd, eapol_frame->data, eapol_frame->len - icv_len))) { |
| 1483 | ws_warning("failed to update MAC: %s", gcry_strerror(err))do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 1483, __func__, "failed to update MAC: %s", gcry_strerror(err )); } } while (0); |
| 1484 | goto failed; |
| 1485 | } |
| 1486 | if ((err = gcry_mac_read(hd, icv_calc, &icv_len))) { |
| 1487 | ws_warning("failed to read MAC: %s", gcry_strerror(err))do { if (1) { ws_log_full("MKA", LOG_LEVEL_WARNING, "epan/dissectors/packet-mka.c" , 1487, __func__, "failed to read MAC: %s", gcry_strerror(err )); } } while (0); |
| 1488 | goto failed; |
| 1489 | } |
| 1490 | |
| 1491 | /* Close the MAC context. */ |
| 1492 | gcry_mac_close(hd); |
| 1493 | p_add_proto_data(wmem_file_scope(), pinfo, proto_mka, ICV_KEY1, icv_calc); |
| 1494 | return icv_calc; |
| 1495 | |
| 1496 | failed: |
| 1497 | gcry_mac_close(hd); |
| 1498 | return NULL((void*)0); |
| 1499 | } |
| 1500 | |
| 1501 | /* |
| 1502 | * Ref 802.1X-2020, Figure 11-7 |
| 1503 | */ |
| 1504 | static uint8_t |
| 1505 | start_parameter_set(tvbuff_t *tvb, int offset, uint16_t *param_body_len) { |
| 1506 | *param_body_len = tvb_get_ntohs(tvb, offset + 2) & 0x0fff; |
| 1507 | return tvb_get_uint8(tvb, offset); |
| 1508 | } |
| 1509 | |
| 1510 | static int |
| 1511 | finalize_parameter_set(proto_tree *param_set_tree, tvbuff_t *tvb, int offset, uint8_t param_set_type, uint16_t param_body_len) { |
| 1512 | if (param_set_type != ICV_TYPE255) { |
| 1513 | unsigned padding_len; |
| 1514 | |
| 1515 | offset += 4 + param_body_len; |
| 1516 | padding_len = WS_PADDING_TO_4(param_body_len)((4U - ((param_body_len) % 4U)) % 4U); |
| 1517 | if (padding_len != 0) { |
| 1518 | proto_tree_add_item(param_set_tree, hf_mka_padding, tvb, offset, padding_len, ENC_NA0x00000000); |
| 1519 | |
| 1520 | offset += padding_len; |
| 1521 | } |
| 1522 | } else { |
| 1523 | offset += 4; |
| 1524 | } |
| 1525 | |
| 1526 | return offset; |
| 1527 | } |
| 1528 | |
| 1529 | static int |
| 1530 | dissect_mka(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) { |
| 1531 | int offset = 0; |
| 1532 | uint8_t mka_version_type; |
| 1533 | uint8_t param_set_type; |
| 1534 | proto_tree *param_set_tree; |
| 1535 | uint16_t param_body_len; |
| 1536 | uint16_t icv_len = DEFAULT_ICV_LEN16; |
| 1537 | proto_item *ti; |
| 1538 | proto_tree *mka_tree; |
| 1539 | |
| 1540 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAPOL-MKA"); |
| 1541 | col_clear(pinfo->cinfo, COL_INFO); |
| 1542 | |
| 1543 | ti = proto_tree_add_item(tree, proto_mka, tvb, 0, -1, ENC_NA0x00000000); |
| 1544 | mka_tree = proto_item_add_subtree(ti, ett_mka); |
| 1545 | |
| 1546 | /* |
| 1547 | * Basic Parameter set is always the first parameter set, dissect it first ! |
| 1548 | */ |
| 1549 | mka_version_type = start_parameter_set(tvb, offset, ¶m_body_len); |
| 1550 | |
| 1551 | /* |
| 1552 | * The 802.1X-2010 spec specifies support for MKA version 1 only. |
| 1553 | * The 802.1Xbx-2014 spec specifies support for MKA version 2. |
| 1554 | * The 802.1Xck-2018 spec specifies support for MKA version 3. |
| 1555 | */ |
| 1556 | mka_version_type = tvb_get_uint8(tvb, offset); |
| 1557 | if ((mka_version_type < 1) || (mka_version_type > 3)) { |
| 1558 | expert_add_info(pinfo, ti, &ei_unexpected_data); |
| 1559 | } |
| 1560 | |
| 1561 | param_set_tree = dissect_basic_paramset(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1562 | offset = finalize_parameter_set(param_set_tree, tvb, offset, 0, param_body_len); |
| 1563 | |
| 1564 | while(tvb_reported_length_remaining(tvb, offset) > icv_len) { |
| 1565 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "%s", |
| 1566 | val_to_str_const(tvb_get_uint8(tvb, offset), param_set_type_vals, "Unknown")); |
| 1567 | param_set_type = start_parameter_set(tvb, offset, ¶m_body_len); |
| 1568 | switch (param_set_type) { |
| 1569 | case LIVE_PEER_LIST_TYPE1: |
| 1570 | param_set_tree = dissect_live_peer_list(mka_tree, pinfo, tvb, offset, param_body_len, (mka_version_type == 3)); |
| 1571 | break; |
| 1572 | |
| 1573 | case POTENTIAL_PEER_LIST_TYPE2: |
| 1574 | param_set_tree = dissect_potential_peer_list(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1575 | break; |
| 1576 | |
| 1577 | case MACSEC_SAK_USE_TYPE3: |
| 1578 | param_set_tree = dissect_sak_use(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1579 | break; |
| 1580 | |
| 1581 | case DISTRIBUTED_SAK_TYPE4: |
| 1582 | param_set_tree = dissect_distributed_sak(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1583 | break; |
| 1584 | |
| 1585 | case DISTRIBUTED_CAK_TYPE5: |
| 1586 | param_set_tree = dissect_distributed_cak(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1587 | break; |
| 1588 | |
| 1589 | case KMD_TYPE6: |
| 1590 | param_set_tree = dissect_kmd(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1591 | break; |
| 1592 | |
| 1593 | case ANNOUNCEMENT_TYPE7: |
| 1594 | param_set_tree = dissect_announcement(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1595 | break; |
| 1596 | |
| 1597 | case XPN_TYPE8: |
| 1598 | param_set_tree = dissect_xpn(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1599 | break; |
| 1600 | |
| 1601 | case ICV_TYPE255: |
| 1602 | // This ICV indicator does not include the ICV itself, see IEEE 802.1X-2010, Section 11.11.1 |
| 1603 | param_set_tree = dissect_icv(mka_tree, pinfo, tvb, offset, param_body_len); |
| 1604 | icv_len = param_body_len; |
| 1605 | break; |
| 1606 | |
| 1607 | default: |
| 1608 | param_set_tree = dissect_unknown_param_set(mka_tree, pinfo, tvb, offset, param_body_len, param_set_type); |
| 1609 | break; |
| 1610 | } |
| 1611 | |
| 1612 | offset = finalize_parameter_set(param_set_tree, tvb, offset, param_set_type, param_body_len); |
| 1613 | } |
| 1614 | |
| 1615 | const uint8_t *icv_calc = calculate_icv(pinfo, icv_len); |
| 1616 | proto_tree_add_checksum_bytes(mka_tree, tvb, offset, hf_mka_icv, hf_mka_icv_status, &ei_mka_icv_bad, pinfo, icv_calc, icv_len, icv_calc ? PROTO_CHECKSUM_VERIFY0x01 : PROTO_CHECKSUM_NO_FLAGS0x00); |
| 1617 | |
| 1618 | return tvb_captured_length(tvb); |
| 1619 | } |
| 1620 | |
| 1621 | void |
| 1622 | proto_register_mka(void) { |
| 1623 | module_t *mka_module; |
| 1624 | expert_module_t *expert_mka = NULL((void*)0); |
| 1625 | |
| 1626 | uat_t *mka_ckn_info_uat = NULL((void*)0); |
| 1627 | |
| 1628 | static ei_register_info ei[] = { |
| 1629 | { &ei_mka_icv_bad, { |
| 1630 | "mka.icv.bad", PI_CHECKSUM0x01000000, PI_ERROR0x00800000, "Bad ICV", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }}, |
| 1631 | |
| 1632 | { &ei_mka_undecoded, { |
| 1633 | "mka.expert.undecoded_data", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Undecoded data", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }}, |
| 1634 | { &ei_unexpected_data, { |
| 1635 | "mka.expert.unexpected_data", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Unexpected data", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }}, |
| 1636 | { &ei_mka_unimplemented, { |
| 1637 | "mka.expert.unimplemented", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Announcement TLV not handled, if you want this implemented please contact the wireshark developers", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }} |
| 1638 | }; |
| 1639 | |
| 1640 | static hf_register_info hf[] = { |
| 1641 | { &hf_mka_version_id, { "MKA Version Identifier", "mka.version_id", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1642 | { &hf_mka_basic_param_set, { "Basic Parameter set", "mka.basic_param_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1643 | { &hf_mka_live_peer_list_set, { "Live Peer List Parameter set", "mka.live_peer_list_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1644 | { &hf_mka_potential_peer_list_set, { "Potential Peer List Parameter set", "mka.potential_peer_list_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1645 | { &hf_mka_macsec_sak_use_set, { "MACsec SAK Use parameter set", "mka.macsec_sak_use_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1646 | { &hf_mka_distributed_sak_set, { "Distributed SAK parameter set", "mka.distributed_sak_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1647 | { &hf_mka_distributed_cak_set, { "Distributed CAK parameter set", "mka.distributed_cak_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1648 | { &hf_mka_kmd_set, { "Key Management Domain set", "mka.kmd_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1649 | { &hf_mka_announcement_set, { "Announcement parameter set", "mka.announcement_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1650 | { &hf_mka_xpn_set, { "Extended Packet Numbering set", "mka.xpn_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1651 | { &hf_mka_unknown_set, { "Unknown parameter set", "mka.unknown_set", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1652 | { &hf_mka_unknown_param_set, { "Unknown parameter set", "mka.unknown_param_set", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1653 | { &hf_mka_icv_set, { "Integrity Check Value Indicator", "mka.icv_indicator", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1654 | { &hf_mka_param_set_type, { "Parameter set type", "mka.param_set_type", FT_UINT8, BASE_DEC, VALS(param_set_type_vals)((0 ? (const struct _value_string*)0 : ((param_set_type_vals) ))), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1655 | |
| 1656 | { &hf_mka_keyserver_priority, { "Key Server Priority", "mka.ks_prio", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1657 | { &hf_mka_key_server, { "Key Server", "mka.key_server", FT_BOOLEAN, 8, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1658 | { &hf_mka_macsec_desired, { "MACsec Desired", "mka.macsec_desired", FT_BOOLEAN, 8, NULL((void*)0), 0x40, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1659 | { &hf_mka_macsec_capability, { "MACsec Capability", "mka.macsec_capability", FT_UINT8, BASE_DEC, VALS(macsec_capability_type_vals)((0 ? (const struct _value_string*)0 : ((macsec_capability_type_vals )))), 0x30, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1660 | { &hf_mka_param_body_length, { "Parameter set body length", "mka.param_body_length", FT_UINT16, BASE_DEC, NULL((void*)0), 0x0fff, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1661 | { &hf_mka_sci, { "SCI", "mka.sci", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1662 | { &hf_mka_sci_system_identifier, { "System Identifier", "mka.sci.system_identifier", FT_ETHER, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1663 | { &hf_mka_sci_port_identifier, { "Port Identifier", "mka.sci.port_identifier", FT_UINT16, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1664 | { &hf_mka_actor_mi, { "Actor Member Identifier", "mka.actor_mi", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1665 | { &hf_mka_actor_mn, { "Actor Message Number", "mka.actor_mn", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1666 | { &hf_mka_algo_agility, { "Algorithm Agility", "mka.algo_agility", FT_UINT32, BASE_HEX, VALS(algo_agility_vals)((0 ? (const struct _value_string*)0 : ((algo_agility_vals))) ), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1667 | { &hf_mka_cak_name, { "CAK Name", "mka.cak_name", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1668 | { &hf_mka_cak_name_info, { "CAK Name Info", "mka.cak_name.info", FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1669 | |
| 1670 | { &hf_mka_padding, { "Padding", "mka.padding", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1671 | |
| 1672 | { &hf_mka_key_server_ssci, { "Key Server SSCI (LSB)", "mka.key_server_ssci", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0, "Only present combined with Distributed SAK parameter set with XPN cipher suite", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1673 | { &hf_mka_peer_mi, { "Peer Member Identifier", "mka.peer_mi", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1674 | { &hf_mka_peer_mn, { "Peer Message Number", "mka.peer_mn", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1675 | |
| 1676 | { &hf_mka_latest_key_an, { "Latest Key AN", "mka.latest_key_an", FT_UINT8, BASE_DEC, NULL((void*)0), 0xc0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1677 | { &hf_mka_latest_key_tx, { "Latest Key tx", "mka.latest_key_tx", FT_BOOLEAN, 8, NULL((void*)0), 0x20, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1678 | { &hf_mka_latest_key_rx, { "Latest Key rx", "mka.latest_key_rx", FT_BOOLEAN, 8, NULL((void*)0), 0x10, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1679 | { &hf_mka_old_key_an, { "Old Key AN", "mka.old_key_an", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0c, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1680 | { &hf_mka_old_key_tx, { "Old Key tx", "mka.old_key_tx", FT_BOOLEAN, 8, NULL((void*)0), 0x02, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1681 | { &hf_mka_old_key_rx, { "Old Key rx", "mka.old_key_rx", FT_BOOLEAN, 8, NULL((void*)0), 0x01, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1682 | { &hf_mka_plain_tx, { "Plain tx", "mka.plain_tx", FT_BOOLEAN, 8, NULL((void*)0), 0x80, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1683 | { &hf_mka_plain_rx, { "Plain rx", "mka.plain_rx", FT_BOOLEAN, 8, NULL((void*)0), 0x40, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1684 | { &hf_mka_delay_protect, { "Delay protect", "mka.delay_protect", FT_BOOLEAN, 8, NULL((void*)0), 0x10, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1685 | { &hf_mka_latest_key_server_mi, { "Latest Key: Key Server Member Identifier", "mka.latest_key_server_mi", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1686 | { &hf_mka_latest_key_number, { "Latest Key: Key Number", "mka.latest_key_number", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1687 | { &hf_mka_latest_lowest_acceptable_pn, { "Latest Key: Lowest Acceptable PN (32 LSB)", "mka.latest_lowest_acceptable_pn", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1688 | { &hf_mka_old_key_server_mi, { "Old Key: Key Server Member Identifier", "mka.old_key_server_mi", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1689 | { &hf_mka_old_key_number, { "Old Key: Key Number", "mka.old_key_number", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1690 | { &hf_mka_old_lowest_acceptable_pn, { "Old Key: Lowest Acceptable PN (32 LSB)", "mka.old_lowest_acceptable_pn", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1691 | |
| 1692 | { &hf_mka_distributed_an, { "Distributed AN", "mka.distributed_an", FT_UINT8, BASE_DEC, NULL((void*)0), 0xc0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1693 | { &hf_mka_confidentiality_offset, { "Confidentiality Offset", "mka.confidentiality_offset", FT_UINT8, BASE_DEC, VALS(confidentiality_offset_vals)((0 ? (const struct _value_string*)0 : ((confidentiality_offset_vals )))), 0x30, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1694 | { &hf_mka_key_number, { "Key Number", "mka.key_number", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1695 | { &hf_mka_aes_key_wrap_sak, { "AES Key Wrap of SAK", "mka.aes_key_wrap_sak", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1696 | { &hf_mka_aes_key_wrap_unwrapped_sak, { "Unwrapped SAK", "mka.aes_key_wrap_unwrapped_sak", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1697 | { &hf_mka_aes_key_wrap_cak, { "AES Key Wrap of CAK", "mka.aes_key_wrap_cak", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1698 | { &hf_mka_macsec_cipher_suite, { "MACsec Cipher Suite", "mka.macsec_cipher_suite", FT_UINT64, BASE_HEX|BASE_VAL64_STRING0x00000400, VALS64(macsec_cipher_suite_vals)((0 ? (const struct _val64_string*)0 : ((macsec_cipher_suite_vals )))), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1699 | |
| 1700 | { &hf_mka_kmd, { "Key Management Domain", "mka.kmd", FT_STRING, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1701 | |
| 1702 | { &hf_mka_suspension_time, { "Suspension time", "mka.suspension_time", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1703 | { &hf_mka_latest_lowest_accept_pn_msb, { "Latest Key: Lowest Acceptable PN (32 MSB)", "mka.latest_lowest_acceptable_pn_msb", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1704 | { &hf_mka_old_lowest_accept_pn_msb, { "Old Key: Lowest Acceptable PN (32 MSB)", "mka.old_lowest_acceptable_pn_msb", FT_UINT32, BASE_DEC_HEX, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1705 | |
| 1706 | { &hf_mka_icv, { "Integrity Check Value", "mka.icv", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1707 | { &hf_mka_icv_status, { "ICV Status", "mka.icv.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals)((0 ? (const struct _value_string*)0 : ((proto_checksum_vals) ))), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1708 | |
| 1709 | { &hf_mka_tlv_entry, { "TLV Entry", "mka.tlv_entry", FT_NONE, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1710 | { &hf_mka_tlv_type, { "TLV Type", "mka.tlv_type", FT_UINT8, BASE_DEC, VALS(macsec_tlvs)((0 ? (const struct _value_string*)0 : ((macsec_tlvs)))), 0xfe, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1711 | { &hf_mka_tlv_info_string_length, { "TLV Info String Length", "mka.tlv_info_string_len", FT_UINT16, BASE_DEC, NULL((void*)0), 0x01ff, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1712 | { &hf_mka_tlv_data, { "TLV Data", "mka.tlv_data", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1713 | { &hf_mka_tlv_cipher_suite_impl_cap, { "Cipher Suite Implementation Capabilities", "mka.tlv.cipher_suite_impl_cap", FT_UINT16, BASE_DEC, VALS(macsec_capability_type_vals)((0 ? (const struct _value_string*)0 : ((macsec_capability_type_vals )))), 0x0003, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, |
| 1714 | }; |
| 1715 | |
| 1716 | static int *ett[] = { |
| 1717 | &ett_mka, |
| 1718 | &ett_mka_sci, |
| 1719 | &ett_mka_basic_param_set, |
| 1720 | &ett_mka_live_peer_list_set, |
| 1721 | &ett_mka_potential_peer_list_set, |
| 1722 | &ett_mka_sak_use_set, |
| 1723 | &ett_mka_distributed_sak_set, |
| 1724 | &ett_mka_distributed_cak_set, |
| 1725 | &ett_mka_kmd_set, |
| 1726 | &ett_mka_announcement_set, |
| 1727 | &ett_mka_xpn_set, |
| 1728 | &ett_mka_unknown_set, |
| 1729 | &ett_mka_icv_set, |
| 1730 | &ett_mka_tlv, |
| 1731 | &ett_mka_cipher_suite_entry |
| 1732 | }; |
| 1733 | |
| 1734 | proto_mka = proto_register_protocol("MACsec Key Agreement", "EAPOL-MKA", "mka"); |
| 1735 | register_dissector("mka", dissect_mka, proto_mka); |
| 1736 | |
| 1737 | proto_register_field_array(proto_mka, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0])); |
| 1738 | proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0])); |
| 1739 | |
| 1740 | expert_mka = expert_register_protocol(proto_mka); |
| 1741 | expert_register_field_array(expert_mka, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0])); |
| 1742 | |
| 1743 | mka_module = prefs_register_protocol(proto_mka, NULL((void*)0)); |
| 1744 | |
| 1745 | mka_mi_sci_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), mka_mi_hash, mka_mi_equal); |
| 1746 | |
| 1747 | mka_ckn_sak_map = wmem_multimap_new_autoreset(wmem_epan_scope(), wmem_file_scope(), mka_sak_key_hash, mka_sak_key_equal); |
| 1748 | mka_ki_pn_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), mka_ki_hash, mka_ki_equal); |
| 1749 | |
| 1750 | /* UAT: CKN info */ |
| 1751 | static uat_field_t mka_ckn_uat_fields[] = { |
| 1752 | UAT_FLD_BUFFER(mka_ckn_uat_data, ckn, "CKN", "The CKN as byte array"){"ckn", "CKN", PT_TXTMOD_HEXBYTES,{0,mka_ckn_uat_data_ckn_set_cb ,mka_ckn_uat_data_ckn_tostr_cb},{0,0,0},0,"The CKN as byte array" ,((void*)0)}, |
| 1753 | UAT_FLD_CSTRING(mka_ckn_uat_data, name, "Info", "CKN information string to be displayed"){"name", "Info", PT_TXTMOD_STRING,{uat_fld_chk_str,mka_ckn_uat_data_name_set_cb ,mka_ckn_uat_data_name_tostr_cb},{0,0,0},0,"CKN information string to be displayed" ,((void*)0)}, |
| 1754 | UAT_FLD_BUFFER(mka_ckn_uat_data, cak, "CAK", "The CAK as byte array"){"cak", "CAK", PT_TXTMOD_HEXBYTES,{0,mka_ckn_uat_data_cak_set_cb ,mka_ckn_uat_data_cak_tostr_cb},{0,0,0},0,"The CAK as byte array" ,((void*)0)}, |
| 1755 | UAT_END_FIELDS{((void*)0),((void*)0),PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,((void *)0)} |
| 1756 | }; |
| 1757 | |
| 1758 | mka_ckn_info_uat = uat_new("CKN/CAK Info", |
| 1759 | sizeof(mka_ckn_info_t), /* record size */ |
| 1760 | DATAFILE_CKN_INFO"mka_ckn_info", /* filename */ |
| 1761 | true1, /* from profile */ |
| 1762 | (void **) &mka_ckn_uat_data, /* data_ptr */ |
| 1763 | &num_mka_ckn_uat_data, /* numitems_ptr */ |
| 1764 | UAT_AFFECTS_DISSECTION0x00000001, /* but not fields */ |
| 1765 | NULL((void*)0), /* help */ |
| 1766 | ckn_info_copy_cb, /* copy callback */ |
| 1767 | ckn_info_update_cb, /* update callback */ |
| 1768 | ckn_info_free_cb, /* free callback */ |
| 1769 | ckn_info_post_update_cb, /* post update callback */ |
| 1770 | ckn_info_reset_cb, /* reset callback */ |
| 1771 | mka_ckn_uat_fields /* UAT field definitions */ |
| 1772 | ); |
| 1773 | |
| 1774 | uat_set_default_values(mka_ckn_info_uat, mka_ckn_info_uat_defaults_); |
| 1775 | prefs_register_uat_preference(mka_module, "ckn_info", "CKN/CAK Info", "A table to define CKNs and CAKs", mka_ckn_info_uat); |
| 1776 | } |
| 1777 | |
| 1778 | void |
| 1779 | proto_reg_handoff_mka(void) { |
| 1780 | static dissector_handle_t mka_handle; |
| 1781 | |
| 1782 | mka_handle = create_dissector_handle(dissect_mka, proto_mka); |
| 1783 | dissector_add_uint("eapol.type", EAPOL_MKA5, mka_handle); |
| 1784 | |
| 1785 | proto_eapol = proto_get_id_by_filter_name("eapol"); |
| 1786 | } |
| 1787 | |
| 1788 | /* |
| 1789 | * Editor modelines |
| 1790 | * |
| 1791 | * Local Variables: |
| 1792 | * c-basic-offset: 2 |
| 1793 | * tab-width: 8 |
| 1794 | * indent-tabs-mode: nil |
| 1795 | * End: |
| 1796 | * |
| 1797 | * ex: set shiftwidth=2 tabstop=8 expandtab: |
| 1798 | * :indentSize=2:tabSize=8:noTabs=true: |
| 1799 | */ |