diff options
Diffstat (limited to 'epan/dissectors/packet-eap.c')
-rw-r--r-- | epan/dissectors/packet-eap.c | 3383 |
1 files changed, 3383 insertions, 0 deletions
diff --git a/epan/dissectors/packet-eap.c b/epan/dissectors/packet-eap.c new file mode 100644 index 00000000..d3417a53 --- /dev/null +++ b/epan/dissectors/packet-eap.c @@ -0,0 +1,3383 @@ +/* packet-eap.c + * Routines for EAP Extensible Authentication Protocol dissection + * RFC 2284, RFC 3748 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <stdio.h> /* for sscanf() */ + +#include <epan/packet.h> +#include <epan/conversation.h> +#include <epan/ppptypes.h> +#include <epan/reassemble.h> +#include <epan/eap.h> +#include <epan/expert.h> +#include <epan/proto_data.h> + +#include "packet-eapol.h" +#include "packet-wps.h" +#include "packet-e212.h" +#include "packet-tls-utils.h" + +void proto_register_eap(void); +void proto_reg_handoff_eap(void); + +static int proto_eap = -1; +static int hf_eap_code = -1; +static int hf_eap_identifier = -1; +static int hf_eap_len = -1; +static int hf_eap_type = -1; +static int hf_eap_type_nak = -1; + +static int hf_eap_identity = -1; +static int hf_eap_identity_full = -1; +static int hf_eap_identity_actual_len = -1; +static int hf_eap_identity_prefix = -1; +static int hf_eap_identity_type = -1; +static int hf_eap_identity_certificate_sn = -1; +static int hf_eap_identity_mcc = -1; +static int hf_eap_identity_mcc_mnc_2digits = -1; +static int hf_eap_identity_mcc_mnc_3digits = -1; +static int hf_eap_identity_padding = -1; + +static int hf_eap_notification = -1; + +static int hf_eap_md5_value_size = -1; +static int hf_eap_md5_value = -1; +static int hf_eap_md5_extra_data = -1; + +static int hf_eap_sim_subtype = -1; +static int hf_eap_sim_reserved = -1; +static int hf_eap_sim_subtype_attribute = -1; +static int hf_eap_sim_subtype_type = -1; +static int hf_eap_sim_subtype_length = -1; +static int hf_eap_sim_notification_type = -1; +static int hf_eap_sim_error_code_type = -1; +static int hf_eap_sim_subtype_value = -1; + +static int hf_eap_aka_subtype = -1; +static int hf_eap_aka_reserved = -1; +static int hf_eap_aka_subtype_attribute = -1; +static int hf_eap_aka_subtype_type = -1; +static int hf_eap_aka_subtype_length = -1; +static int hf_eap_aka_notification_type = -1; +static int hf_eap_aka_error_code_type = -1; +static int hf_eap_aka_subtype_value = -1; + +static int hf_eap_leap_version = -1; +static int hf_eap_leap_reserved = -1; +static int hf_eap_leap_count = -1; +static int hf_eap_leap_peer_challenge = -1; +static int hf_eap_leap_peer_response = -1; +static int hf_eap_leap_ap_challenge = -1; +static int hf_eap_leap_ap_response = -1; +static int hf_eap_leap_data = -1; +static int hf_eap_leap_name = -1; + +static int hf_eap_ms_chap_v2_opcode = -1; +static int hf_eap_ms_chap_v2_id = -1; +static int hf_eap_ms_chap_v2_length = -1; +static int hf_eap_ms_chap_v2_value_size = -1; +static int hf_eap_ms_chap_v2_challenge = -1; +static int hf_eap_ms_chap_v2_name = -1; +static int hf_eap_ms_chap_v2_peer_challenge = -1; +static int hf_eap_ms_chap_v2_reserved = -1; +static int hf_eap_ms_chap_v2_nt_response = -1; +static int hf_eap_ms_chap_v2_flags = -1; +static int hf_eap_ms_chap_v2_response = -1; +static int hf_eap_ms_chap_v2_message = -1; +static int hf_eap_ms_chap_v2_failure_request = -1; +static int hf_eap_ms_chap_v2_data = -1; + +static int hf_eap_pax_opcode = -1; +static int hf_eap_pax_flags = -1; +static int hf_eap_pax_flags_mf = -1; +static int hf_eap_pax_flags_ce = -1; +static int hf_eap_pax_flags_ai = -1; +static int hf_eap_pax_flags_reserved = -1; +static int hf_eap_pax_mac_id = -1; +static int hf_eap_pax_dh_group_id = -1; +static int hf_eap_pax_public_key_id = -1; +static int hf_eap_pax_a_len = -1; +static int hf_eap_pax_a = -1; +static int hf_eap_pax_b_len = -1; +static int hf_eap_pax_b = -1; +static int hf_eap_pax_cid_len = -1; +static int hf_eap_pax_cid = -1; +static int hf_eap_pax_mac_ck_len = -1; +static int hf_eap_pax_mac_ck = -1; +static int hf_eap_pax_ade_len = -1; +static int hf_eap_pax_ade = -1; +static int hf_eap_pax_mac_icv = -1; + +static int hf_eap_psk_flags = -1; +static int hf_eap_psk_flags_t = -1; +static int hf_eap_psk_flags_reserved = -1; +static int hf_eap_psk_rand_p = -1; +static int hf_eap_psk_rand_s = -1; +static int hf_eap_psk_mac_p = -1; +static int hf_eap_psk_mac_s = -1; +static int hf_eap_psk_id_p = -1; +static int hf_eap_psk_id_s = -1; +static int hf_eap_psk_pchannel = -1; + +static int hf_eap_sake_version = -1; +static int hf_eap_sake_session_id = -1; +static int hf_eap_sake_subtype = -1; +static int hf_eap_sake_attr_type = -1; +static int hf_eap_sake_attr_len = -1; +static int hf_eap_sake_attr_value = -1; +static int hf_eap_sake_attr_value_str = -1; +static int hf_eap_sake_attr_value_uint48 = -1; + +static int hf_eap_gpsk_opcode = -1; +static int hf_eap_gpsk_id_server_len = -1; +static int hf_eap_gpsk_id_server = -1; +static int hf_eap_gpsk_id_peer_len = -1; +static int hf_eap_gpsk_id_peer = -1; +static int hf_eap_gpsk_rand_server = -1; +static int hf_eap_gpsk_rand_peer = -1; +static int hf_eap_gpsk_csuite_list_len = -1; +static int hf_eap_gpsk_csuite_vendor = -1; +static int hf_eap_gpsk_csuite_specifier = -1; +static int hf_eap_gpsk_pd_payload_len = -1; +static int hf_eap_gpsk_pd_payload = -1; +static int hf_eap_gpsk_payload_mac = -1; +static int hf_eap_gpsk_failure_code = -1; + +static int hf_eap_msauth_tlv_mandatory = -1; +static int hf_eap_msauth_tlv_reserved = -1; +static int hf_eap_msauth_tlv_type = -1; +static int hf_eap_msauth_tlv_len = -1; +static int hf_eap_msauth_tlv_val = -1; +static int hf_eap_msauth_tlv_status = -1; +static int hf_eap_msauth_tlv_crypto_reserved = -1; +static int hf_eap_msauth_tlv_crypto_version = -1; +static int hf_eap_msauth_tlv_crypto_rcv_version = -1; +static int hf_eap_msauth_tlv_crypto_subtype = -1; +static int hf_eap_msauth_tlv_crypto_nonce = -1; +static int hf_eap_msauth_tlv_crypto_cmac = -1; + +static int hf_eap_data = -1; + +static gint ett_eap = -1; +static gint ett_eap_pax_flags = -1; +static gint ett_eap_psk_flags = -1; +static gint ett_eap_sake_attr = -1; +static gint ett_eap_gpsk_csuite_list = -1; +static gint ett_eap_gpsk_csuite = -1; +static gint ett_eap_gpsk_csuite_sel = -1; +static gint ett_eap_msauth_tlv = -1; +static gint ett_eap_msauth_tlv_tree = -1; + +static expert_field ei_eap_ms_chap_v2_length = EI_INIT; +static expert_field ei_eap_mitm_attacks = EI_INIT; +static expert_field ei_eap_md5_value_size_overflow = EI_INIT; +static expert_field ei_eap_dictionary_attacks = EI_INIT; +static expert_field ei_eap_identity_nonascii = EI_INIT; +static expert_field ei_eap_identity_invalid = EI_INIT; +static expert_field ei_eap_retransmission = EI_INIT; +static expert_field ei_eap_bad_length = EI_INIT; + +static dissector_table_t eap_expanded_type_dissector_table; + +static dissector_handle_t eap_handle; + +static dissector_handle_t tls_handle; +static dissector_handle_t diameter_avps_handle; +static dissector_handle_t peap_handle; +static dissector_handle_t teap_handle; + +static dissector_handle_t isakmp_handle; + +const value_string eap_code_vals[] = { + { EAP_REQUEST, "Request" }, + { EAP_RESPONSE, "Response" }, + { EAP_SUCCESS, "Success" }, + { EAP_FAILURE, "Failure" }, + { EAP_INITIATE, "Initiate" }, /* [RFC5296] */ + { EAP_FINISH, "Finish" }, /* [RFC5296] */ + { 0, NULL } +}; + +/* +References: + 1) https://www.iana.org/assignments/ppp-numbers PPP EAP REQUEST/RESPONSE TYPES + 2) https://tools.ietf.org/html/draft-ietf-pppext-rfc2284bis-02 + 3) RFC2284 + 4) RFC3748 + 5) https://www.iana.org/assignments/eap-numbers EAP registry (updated 2011-02-22) + 6) https://tools.ietf.org/html/draft-bersani-eap-synthesis-sharedkeymethods-00 +*/ + +static const value_string eap_type_vals[] = { + { 1, "Identity" }, + { 2, "Notification" }, + { 3, "Legacy Nak (Response Only)" }, + { 4, "MD5-Challenge EAP (EAP-MD5-CHALLENGE)" }, + { 5, "One-Time Password EAP (EAP-OTP)" }, + { 6, "Generic Token Card EAP (EAP-GTC)" }, + { 7, "Allocated" }, + { 8, "Allocated" }, + { 9, "RSA Public Key Authentication EAP (EAP-RSA-PKA)" }, + { 10, "DSS Unilateral EAP (EAP-DSS)" }, + { 11, "KEA EAP (EAP-KEA)" }, + { 12, "KEA Validate EAP (EAP-KEA-VALIDATE)" }, + { 13, "TLS EAP (EAP-TLS)" }, + { 14, "Defender Token EAP (EAP-AXENT)" }, + { 15, "RSA Security SecurID EAP (EAP-RSA-SECURID)" }, + { 16, "Arcot Systems EAP (EAP-ARCOT-SYSTEMS)" }, + { 17, "Cisco Wireless EAP / Lightweight EAP (EAP-LEAP)" }, + { 18, "GSM Subscriber Identity Modules EAP (EAP-SIM)" }, + { 19, "Secure Remote Password SHA1 Part 1 EAP (EAP-SRP-SHA1-PART1)" }, + { 20, "Secure Remote Password SHA1 Part 2 EAP (EAP-SRP-SHA1-PART2)" }, + { 21, "Tunneled TLS EAP (EAP-TTLS)" }, + { 22, "Remote Access Service EAP (EAP-RAS)" }, + { 23, "UMTS Authentication and Key Agreement EAP (EAP-AKA)" }, + { 24, "3Com Wireless EAP (EAP-3COM-WIRELESS)" }, + { 25, "Protected EAP (EAP-PEAP)" }, + { 26, "MS-Authentication EAP (EAP-MS-AUTH)" }, + { 27, "Mutual Authentication w/Key Exchange EAP (EAP-MAKE)" }, + { 28, "CRYPTOCard EAP (EAP-CRYPTOCARD)" }, + { 29, "MS-CHAP-v2 EAP (EAP-MS-CHAP-V2)" }, + { 30, "DynamID EAP (EAP-DYNAMID)" }, + { 31, "Rob EAP (EAP-ROB)" }, + { 32, "Protected One-Time Password EAP (EAP-POTP)" }, + { 33, "MS-Authentication TLV EAP (EAP-MS-AUTH-TLV)" }, + { 34, "SentriNET (EAP-SENTRINET)" }, + { 35, "Actiontec Wireless EAP (EAP-ACTIONTEC-WIRELESS)" }, + { 36, "Cogent Systems Biometrics Authentication EAP (EAP-COGENT-BIOMETRIC)" }, + { 37, "AirFortress EAP (EAP-AIRFORTRESS)" }, + { 38, "HTTP Digest EAP (EAP-HTTP-DIGEST)" }, + { 39, "SecureSuite EAP (EAP-SECURESUITE)" }, + { 40, "DeviceConnect EAP (EAP-DEVICECONNECT)" }, + { 41, "Simple Password Exponential Key Exchange EAP (EAP-SPEKE)" }, + { 42, "MOBAC EAP (EAP-MOBAC)" }, + { 43, "Flexible Authentication via Secure Tunneling EAP (EAP-FAST)" }, + { 44, "ZoneLabs EAP (EAP-ZLXEAP)" }, + { 45, "Link EAP (EAP-LINK)" }, + { 46, "Password Authenticated eXchange EAP (EAP-PAX)" }, + { 47, "Pre-Shared Key EAP (EAP-PSK)" }, + { 48, "Shared-secret Authentication and Key Establishment EAP (EAP-SAKE)" }, + { 49, "Internet Key Exchange v2 EAP (EAP-IKEv2)" }, + { 50, "UMTS Authentication and Key Agreement' EAP (EAP-AKA')" }, + { 51, "Generalized Pre-Shared Key EAP (EAP-GPSK)" }, + { 52, "Password EAP (EAP-pwd)" }, + { 53, "Encrypted Key Exchange v1 EAP (EAP-EKEv1)" }, + { 55, "Tunneled EAP protocol" }, + { 254, "Expanded Type" }, + { 255, "Experimental" }, + { 0, NULL } +}; +value_string_ext eap_type_vals_ext = VALUE_STRING_EXT_INIT(eap_type_vals); + +static const value_string eap_identity_prefix_vals[] = { + { 0x00, "Encrypted IMSI" }, + { '0', "EAP-AKA Permanent" }, + { '1', "EAP-SIM Permanent" }, + { '2', "EAP-AKA Pseudonym" }, + { '3', "EAP-SIM Pseudonym" }, + { '4', "EAP-AKA Reauth ID" }, + { '5', "EAP-SIM Reauth ID" }, + { '6', "EAP-AKA Prime Permanent" }, + { '7', "EAP-AKA Prime Pseudonym" }, + { '8', "EAP-AKA Prime Reauth ID" }, + { 'C', "Conservative Peer" }, + { 'a', "Anonymous Identity" }, + { 0, NULL } +}; + +const value_string eap_sim_subtype_vals[] = { + { SIM_START, "Start" }, + { SIM_CHALLENGE, "Challenge" }, + { SIM_NOTIFICATION, "Notification" }, + { SIM_RE_AUTHENTICATION, "Re-authentication" }, + { SIM_CLIENT_ERROR, "Client-Error" }, + { 0, NULL } +}; + +const value_string eap_aka_subtype_vals[] = { + { AKA_CHALLENGE, "AKA-Challenge" }, + { AKA_AUTHENTICATION_REJECT, "AKA-Authentication-Reject" }, + { AKA_SYNCHRONIZATION_FAILURE, "AKA-Synchronization-Failure" }, + { AKA_IDENTITY, "AKA-Identity" }, + { AKA_NOTIFICATION, "Notification" }, + { AKA_REAUTHENTICATION, "Re-authentication" }, + { AKA_CLIENT_ERROR, "Client-Error" }, + { 0, NULL } +}; + +/* +References: + 1) http://www.iana.org/assignments/eapsimaka-numbers/eapsimaka-numbers.xml + 3) RFC4186 + 3) RFC4187 + 4) RFC5448 + 5) 3GPP TS 24.302 +*/ + +#define AT_NOTIFICATION 12 +#define AT_IDENTITY 14 +#define AT_CLIENT_ERROR_CODE 22 + +static const value_string eap_sim_aka_attribute_vals[] = { + { 1, "AT_RAND" }, + { 2, "AT_AUTN" }, + { 3, "AT_RES" }, + { 4, "AT_AUTS" }, + { 6, "AT_PADDING" }, + { 7, "AT_NONCE_MT" }, + { 10, "AT_PERMANENT_ID_REQ" }, + { 11, "AT_MAC" }, + { 12, "AT_NOTIFICATION" }, + { 13, "AT_ANY_ID_REQ" }, + { 14, "AT_IDENTITY" }, + { 15, "AT_VERSION_LIST" }, + { 16, "AT_SELECTED_VERSION" }, + { 17, "AT_FULLAUTH_ID_REQ" }, + { 19, "AT_COUNTER" }, + { 20, "AT_COUNTER_TOO_SMALL" }, + { 21, "AT_NONCE_S" }, + { 22, "AT_CLIENT_ERROR_CODE" }, + { 23, "AT_KDF_INPUT"}, + { 24, "AT_KDF"}, + { 128, "Unassigned" }, + { 129, "AT_IV" }, + { 130, "AT_ENCR_DATA" }, + { 131, "Unassigned" }, + { 132, "AT_NEXT_PSEUDONYM" }, + { 133, "AT_NEXT_REAUTH_ID" }, + { 134, "AT_CHECKCODE" }, + { 135, "AT_RESULT_IND" }, + { 136, "AT_BIDDING" }, + { 137, "AT_IPMS_IND" }, + { 138, "AT_IPMS_RES" }, + { 139, "AT_TRUST_IND" }, + { 140, "AT_SHORT_NAME_FOR_NETWORK" }, + { 141, "AT_FULL_NAME_FOR_NETWORK" }, + { 142, "AT_RQSI_IND" }, + { 143, "AT_RQSI_RES" }, + { 144, "AT_TWAN_CONN_MODE" }, + { 145, "AT_VIRTUAL_NETWORK_ID" }, + { 146, "AT_VIRTUAL_NETWORK_REQ" }, + { 147, "AT_CONNECTIVITY_TYPE" }, + { 148, "AT_HANDOVER_INDICATION" }, + { 149, "AT_HANDOVER_SESSION_ID" }, + { 150, "AT_MN_SERIAL_ID" }, + { 151, "AT_DEVICE_IDENTITY" }, + { 0, NULL } +}; +static value_string_ext eap_sim_aka_attribute_vals_ext = VALUE_STRING_EXT_INIT(eap_sim_aka_attribute_vals); + +static const value_string eap_sim_aka_notification_vals[] = { + { 0, "General Failure after Authentication" }, + { 1026, "User has been temporarily denied access" }, + { 1031, "User has not subscribed to the requested service" }, + { 8192, "Failure to Terminate the Authentication Exchange" }, + {16384, "General Failure" }, + {32768, "Success" }, + {0, NULL } +}; + +static const value_string eap_sim_aka_client_error_codes[] = { + { 0, "Unable to process packet" }, + { 1, "Unsupported version" }, + { 2, "Insufficient number of challenges" }, + { 3, "RANDs are not fresh" }, + { 0, NULL } +}; + +const value_string eap_ms_chap_v2_opcode_vals[] = { + { MS_CHAP_V2_CHALLENGE, "Challenge" }, + { MS_CHAP_V2_RESPONSE, "Response" }, + { MS_CHAP_V2_SUCCESS, "Success" }, + { MS_CHAP_V2_FAILURE, "Failure" }, + { MS_CHAP_V2_CHANGE_PASSWORD, "Change-Password" }, + { 0, NULL } +}; + +#define PAX_STD_1 0x01 +#define PAX_STD_2 0x02 +#define PAX_STD_3 0x03 +#define PAX_SEC_1 0x11 +#define PAX_SEC_2 0x12 +#define PAX_SEC_3 0x13 +#define PAX_SEC_4 0x14 +#define PAX_SEC_5 0x15 +#define PAX_ACK 0x21 + +static const value_string eap_pax_opcode_vals[] = { + { PAX_STD_1, "STD-1" }, + { PAX_STD_2, "STD-2" }, + { PAX_STD_3, "STD-3" }, + { PAX_SEC_1, "SEC-1" }, + { PAX_SEC_2, "SEC-2" }, + { PAX_SEC_3, "SEC-3" }, + { PAX_SEC_4, "SEC-4" }, + { PAX_SEC_5, "SEC-5" }, + { PAX_ACK, "ACK" }, + { 0, NULL } +}; + +#define EAP_PAX_FLAG_MF 0x01 /* more fragments */ +#define EAP_PAX_FLAG_CE 0x02 /* certificate enabled */ +#define EAP_PAX_FLAG_AI 0x04 /* ADE included */ +#define EAP_PAX_FLAG_RESERVED 0xF8 /* reserved */ + +#define PAX_MAC_ID_HMAC_SHA1_128 0x01 +#define PAX_MAC_ID_HMAC_SHA256_128 0x02 + +static const value_string eap_pax_mac_id_vals[] = { + { PAX_MAC_ID_HMAC_SHA1_128, "HMAC_SHA1_128" }, + { PAX_MAC_ID_HMAC_SHA256_128, "HMAXĆ_SHA256_128" }, + { 0, NULL } +}; + +#define PAX_DH_GROUP_ID_NONE 0x00 +#define PAX_DH_GROUP_ID_DH_14 0x01 +#define PAX_DH_GROUP_ID_DH_15 0x02 +#define PAX_DH_GROUP_ID_ECC_P256 0x03 + +static const value_string eap_pax_dh_group_id_vals[] = { + { PAX_DH_GROUP_ID_NONE, "NONE" }, + { PAX_DH_GROUP_ID_DH_14, "2048-bit MODP Group (IANA DH Group 14)" }, + { PAX_DH_GROUP_ID_DH_15, "3072-bit MODP Group (IANA DH Group 15)" }, + { PAX_DH_GROUP_ID_ECC_P256, "NIST ECC Group P-256" }, + { 0, NULL } +}; + +#define PAX_PUBLIC_KEY_ID_NONE 0x00 +#define PAX_PUBLIC_KEY_ID_RSAES_OAEP 0x01 +#define PAX_PUBLIC_KEY_ID_RSA_PKCS1_V1_5 0x02 +#define PAX_PUBLIC_KEY_ID_EL_GAMAL_ECC_P256 0x03 + +static const value_string eap_pax_public_key_id_vals[] = { + { PAX_PUBLIC_KEY_ID_NONE, "NONE" }, + { PAX_PUBLIC_KEY_ID_RSAES_OAEP, "RSAES-OAEP" }, + { PAX_PUBLIC_KEY_ID_RSA_PKCS1_V1_5, "RSA-PKCS1-V1_5" }, + { PAX_PUBLIC_KEY_ID_EL_GAMAL_ECC_P256, "El-Gamal Over NIST ECC Group P-256" }, + { 0, NULL } +}; + +#define EAP_PSK_FLAGS_T_MASK 0xC0 + +#define SAKE_CHALLENGE 1 +#define SAKE_CONFIRM 2 +#define SAKE_AUTH_REJECT 3 +#define SAKE_IDENTITY 4 + +static const value_string eap_sake_subtype_vals[] = { + { SAKE_CHALLENGE, "SAKE/Challenge" }, + { SAKE_CONFIRM, "SAKE/Confirm" }, + { SAKE_AUTH_REJECT, "SAKE/Auth-Reject" }, + { SAKE_IDENTITY, "SAKE/Identity" }, + { 0, NULL } +}; + +#define SAKE_AT_RAND_S 1 +#define SAKE_AT_RAND_P 2 +#define SAKE_AT_MIC_S 3 +#define SAKE_AT_MIC_P 4 +#define SAKE_AT_SERVERID 5 +#define SAKE_AT_PEERID 6 +#define SAKE_AT_SPI_S 7 +#define SAKE_AT_SPI_P 8 +#define SAKE_AT_ANY_ID_REQ 9 +#define SAKE_AT_PERM_ID_REQ 10 +#define SAKE_AT_ENCR_DATA 128 +#define SAKE_AT_IV 129 +#define SAKE_AT_PADDING 130 +#define SAKE_AT_NEXT_TMPID 131 +#define SAKE_AT_MSK_LIFE 132 + +static const value_string eap_sake_attr_type_vals[] = { + { SAKE_AT_RAND_S, "Server Nonce RAND_S" }, + { SAKE_AT_RAND_P, "Peer Nonce RAND_P" }, + { SAKE_AT_MIC_S, "Server MIC" }, + { SAKE_AT_MIC_P, "Peer MIC" }, + { SAKE_AT_SERVERID, "Server FQDN" }, + { SAKE_AT_PEERID, "Peer NAI (tmp, perm)" }, + { SAKE_AT_SPI_S, "Server chosen SPI SPI_S" }, + { SAKE_AT_SPI_P, "Peer SPI list SPI_P" }, + { SAKE_AT_ANY_ID_REQ, "Requires any Peer Id (tmp, perm)" }, + { SAKE_AT_PERM_ID_REQ, "Requires Peer's permanent Id/NAI" }, + { SAKE_AT_ENCR_DATA, "Contains encrypted attributes" }, + { SAKE_AT_IV, "IV for encrypted attributes" }, + { SAKE_AT_PADDING, "Padding for encrypted attributes" }, + { SAKE_AT_NEXT_TMPID, "TempID for next EAP-SAKE phase" }, + { SAKE_AT_MSK_LIFE, "MSK Lifetime" }, + { 0, NULL } +}; + +#define GPSK_RESERVED 0 +#define GPSK_GPSK_1 1 +#define GPSK_GPSK_2 2 +#define GPSK_GPSK_3 3 +#define GPSK_GPSK_4 4 +#define GPSK_FAIL 5 +#define GPSK_PROTECTED_FAIL 6 + +static const value_string eap_gpsk_opcode_vals[] = { + { GPSK_RESERVED, "Reserved" }, + { GPSK_GPSK_1, "GPSK-1" }, + { GPSK_GPSK_2, "GPSK-2" }, + { GPSK_GPSK_3, "GPSK-3" }, + { GPSK_GPSK_4, "GPSK-4" }, + { GPSK_FAIL, "Fail" }, + { GPSK_PROTECTED_FAIL, "Protected Fail" }, + { 0, NULL } +}; + +static const value_string eap_gpsk_failure_code_vals[] = { + { 0x00000000, "Reserved" }, + { 0x00000001, "PSK Not Found" }, + { 0x00000002, "Authentication Failure" }, + { 0x00000003, "Authorization Failure" }, + { 0, NULL } +}; + +#define MSAUTH_TLV_MANDATORY 0x8000 +#define MSAUTH_TLV_RESERVED 0x4000 +#define MSAUTH_TLV_TYPE 0x3FFF + +#define MSAUTH_TLV_TYPE_EXTENSION_UNASSIGNED 0 +#define MSAUTH_TLV_TYPE_EXTENSION_RESULT 3 +#define MSAUTH_TLV_TYPE_EXTENSION_CRYPTOBINDING 12 + +#define MSAUTH_TLV_TYPE_EXPANDED_SOH 33 + +static const value_string eap_msauth_tlv_type_vals[] = { + { MSAUTH_TLV_TYPE_EXTENSION_UNASSIGNED, "Unassigned" }, + { MSAUTH_TLV_TYPE_EXTENSION_RESULT, "Result" }, + { MSAUTH_TLV_TYPE_EXTENSION_CRYPTOBINDING, "Cryptobinding" }, + { 0, NULL } +}; + +static const value_string eap_msauth_tlv_status_vals[] = { + { 1, "Success" }, + { 2, "Failure" }, + { 0, NULL } +}; + +static const value_string eap_msauth_tlv_crypto_subtype_vals[] = { + { 0, "Binding Request" }, + { 1, "Binding Response" }, + { 0, NULL } +}; + +/* + * State information for EAP-TLS (RFC2716) and Lightweight EAP: + * + * http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt + * + * Attach to all conversations: + * + * a sequence number to be handed to "fragment_add_seq()" as + * the fragment sequence number - if it's -1, no reassembly + * is in progress, but if it's not, it's the sequence number + * to use for the current fragment; + * + * a value to be handed to "fragment_add_seq()" as the + * reassembly ID - when a reassembly is started, it's set to + * the frame number of the current frame, i.e. the frame + * that starts the reassembly; + * + * an indication of the current state of LEAP negotiation, + * with -1 meaning no LEAP negotiation is in progress. + * + * Attach to frames containing fragments of EAP-TLS messages the + * reassembly ID for those fragments, so we can find the reassembled + * data after the first pass through the packets. + * + * Attach to LEAP frames the state of the LEAP negotiation when the + * frame was processed, so we can properly dissect + * the LEAP message after the first pass through the packets. + * + * Attach to all conversations both pieces of information, to keep + * track of EAP-TLS reassembly and the LEAP state machine. + */ + +typedef struct { + int eap_tls_seq; + guint32 eap_reass_cookie; + int leap_state; + gint16 last_eap_id_req; /* Last ID of the request from the authenticator. */ + gint16 last_eap_id_resp; /* Last ID of the response from the peer. */ +} conv_state_t; + +typedef struct { + int info; /* interpretation depends on EAP message type */ +} frame_state_t; + +/* +from RFC5216, pg 21 + + Flags + + 0 1 2 3 4 5 6 7 8 + +-+-+-+-+-+-+-+-+ + |L M S R R R R R| TLS (RFC5216) + +-+-+-+-+-+-+-+-+ + |L M S R R| V | TTLS (RFC5281) and FAST (RFC4851) + +-+-+-+-+-+-+-+-+ + |L M S O R| V | TEAP (RFC7170) + +-+-+-+-+-+-+-+-+ + |L M S R R R| V | PEAPv0 (draft-kamath-pppext-peapv0) + +-+-+-+-+-+-+-+-+ + |L M S R R| V | PEAPv1 (draft-josefsson-pppext-eap-tls-eap-06) and PEAPv2 (draft-josefsson-pppext-eap-tls-eap-10) + +-+-+-+-+-+-+-+-+ + + L = Length included + M = More fragments + S = EAP-TLS start + O = Outer TLV length included (TEAP only) + R = Reserved + V = TTLS/FAST/TEAP/PEAP version (Reserved for TLS) +*/ + +#define EAP_TLS_FLAG_L 0x80 /* Length included */ +#define EAP_TLS_FLAG_M 0x40 /* More fragments */ +#define EAP_TLS_FLAG_S 0x20 /* EAP-TLS start */ +#define EAP_TLS_FLAG_O 0x10 /* Outer TLV length included */ + +#define EAP_TLS_FLAGS_VERSION 0x07 /* Version mask */ + +/* + * reassembly of EAP-TLS + */ +static reassembly_table eap_tls_reassembly_table; + +static int hf_eap_tls_flags = -1; +static int hf_eap_tls_flag_l = -1; +static int hf_eap_tls_flag_m = -1; +static int hf_eap_tls_flag_s = -1; +static int hf_eap_tls_flag_o = -1; +static int hf_eap_tls_flags_version = -1; +static int hf_eap_tls_len = -1; +static int hf_eap_tls_outer_tlvs_len = -1; +static int hf_eap_tls_fragment = -1; +static int hf_eap_tls_fragments = -1; +static int hf_eap_tls_fragment_overlap = -1; +static int hf_eap_tls_fragment_overlap_conflict = -1; +static int hf_eap_tls_fragment_multiple_tails = -1; +static int hf_eap_tls_fragment_too_long_fragment = -1; +static int hf_eap_tls_fragment_error = -1; +static int hf_eap_tls_fragment_count = -1; +static int hf_eap_tls_reassembled_in = -1; +static int hf_eap_tls_reassembled_length = -1; +static int hf_eap_fast_type = -1; +static int hf_eap_fast_length = -1; +static int hf_eap_fast_aidd = -1; +static gint ett_eap_tls_fragment = -1; +static gint ett_eap_tls_fragments = -1; +static gint ett_eap_sim_attr = -1; +static gint ett_eap_aka_attr = -1; +static gint ett_eap_exp_attr = -1; +static gint ett_eap_tls_flags = -1; +static gint ett_identity = -1; +static gint ett_eap_ikev2_flags = -1; + +static const fragment_items eap_tls_frag_items = { + &ett_eap_tls_fragment, + &ett_eap_tls_fragments, + &hf_eap_tls_fragments, + &hf_eap_tls_fragment, + &hf_eap_tls_fragment_overlap, + &hf_eap_tls_fragment_overlap_conflict, + &hf_eap_tls_fragment_multiple_tails, + &hf_eap_tls_fragment_too_long_fragment, + &hf_eap_tls_fragment_error, + &hf_eap_tls_fragment_count, + &hf_eap_tls_reassembled_in, + &hf_eap_tls_reassembled_length, + /* Reassembled data field */ + NULL, + "fragments" +}; + + +/* + * EAP-IKE2, RFC5106 + */ + + /* + RFC5106, 8.1, page 17 + + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |L M I 0 0 0 0 0| + +-+-+-+-+-+-+-+-+ + + L = Length included + M = More fragments + I = Integrity Checksum Data included + */ +#define EAP_IKEV2_FLAG_L 0x80 /* Length included */ +#define EAP_IKEV2_FLAG_M 0x40 /* More fragments */ +#define EAP_IKEV2_FLAG_I 0x20 /* Integrity checksum data included */ + +static int hf_eap_ikev2_flags = -1; +static int hf_eap_ikev2_flag_l = -1; +static int hf_eap_ikev2_flag_m = -1; +static int hf_eap_ikev2_flag_i = -1; +static int hf_eap_ikev2_len = -1; +static int hf_eap_ikev2_int_chk_data = -1; + +/********************************************************************** + Support for EAP Expanded Type. + + Currently this is limited to WifiProtectedSetup. Maybe we need + a generic method to support EAP extended types ? +*********************************************************************/ +static int hf_eap_ext_vendor_id = -1; +static int hf_eap_ext_vendor_type = -1; + +static const value_string eap_ext_vendor_id_vals[] = { + { WFA_VENDOR_ID, "WFA" }, + { 0, NULL } +}; + +static const value_string eap_ext_vendor_type_vals[] = { + { WFA_SIMPLECONFIG_TYPE, "SimpleConfig" }, + { 0, NULL } +}; + +static void +dissect_exteap(proto_tree *eap_tree, tvbuff_t *tvb, int offset, + gint size _U_, packet_info* pinfo, guint8 eap_code, guint8 eap_identifier) +{ + tvbuff_t *next_tvb; + guint32 vendor_id; + guint32 vendor_type; + eap_vendor_context *vendor_context; + + vendor_context = wmem_new(pinfo->pool, eap_vendor_context); + + proto_tree_add_item_ret_uint(eap_tree, hf_eap_ext_vendor_id, tvb, offset, 3, ENC_BIG_ENDIAN, &vendor_id); + offset += 3; + + proto_tree_add_item_ret_uint(eap_tree, hf_eap_ext_vendor_type, tvb, offset, 4, ENC_BIG_ENDIAN, &vendor_type); + offset += 4; + + vendor_context->eap_code = eap_code; + vendor_context->eap_identifier = eap_identifier; + vendor_context->vendor_id = vendor_id; + vendor_context->vendor_type = vendor_type; + + next_tvb = tvb_new_subset_remaining(tvb, offset); + if (!dissector_try_uint_new(eap_expanded_type_dissector_table, + vendor_id, next_tvb, pinfo, eap_tree, + FALSE, vendor_context)) { + call_data_dissector(next_tvb, pinfo, eap_tree); + } +} +/* ********************************************************************* +********************************************************************* */ + +static void +dissect_eap_mschapv2(proto_tree *eap_tree, tvbuff_t *tvb, packet_info *pinfo, int offset, + gint size) +{ + proto_item *item; + gint left = size; + gint ms_len; + guint8 value_size; + guint8 opcode; + + /* OpCode (1 byte), MS-CHAPv2-ID (1 byte), MS-Length (2 bytes), Data */ + opcode = tvb_get_guint8(tvb, offset); + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_opcode, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + left -= 1; + if (left <= 0) + return; + + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_id, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + left -= 1; + if (left <= 0) + return; + + item = proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_length, tvb, offset, 2, ENC_BIG_ENDIAN); + ms_len = tvb_get_ntohs(tvb, offset); + if (ms_len != size) + expert_add_info(pinfo, item, &ei_eap_ms_chap_v2_length); + offset += 2; + left -= 2; + + switch (opcode) { + case MS_CHAP_V2_CHALLENGE: + if (left <= 0) + break; + value_size = tvb_get_guint8(tvb, offset); + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_value_size, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + left -= 1; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_challenge, + tvb, offset, value_size, ENC_NA); + offset += value_size; + left -= value_size; + if (left <= 0) + break; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_name, + tvb, offset, left, ENC_ASCII); + break; + case MS_CHAP_V2_RESPONSE: + if (left <= 0) + break; + value_size = tvb_get_guint8(tvb, offset); + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_value_size, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + left -= 1; + if (value_size == 49) { + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_peer_challenge, + tvb, offset, 16, ENC_NA); + offset += 16; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_reserved, + tvb, offset, 8, ENC_NA); + offset += 8; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_nt_response, + tvb, offset, 24, ENC_NA); + offset += 24; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_flags, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + left -= value_size; + } else { + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_response, tvb, offset, value_size, ENC_NA); + offset += value_size; + left -= value_size; + } + if (left <= 0) + break; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_name, tvb, offset, left, ENC_ASCII); + break; + case MS_CHAP_V2_SUCCESS: + if (left <= 0) + break; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_message, + tvb, offset, left, ENC_ASCII); + break; + case MS_CHAP_V2_FAILURE: + if (left <= 0) + break; + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_failure_request, + tvb, offset, left, ENC_ASCII); + break; + default: + proto_tree_add_item(eap_tree, hf_eap_ms_chap_v2_data, tvb, offset, left, ENC_NA); + break; + } +} + +/* Dissect the WLAN identity */ +static gboolean +dissect_eap_identity_wlan(tvbuff_t *tvb, packet_info* pinfo, proto_tree* tree, int offset, gint size) +{ + guint mnc = 0; + guint mcc = 0; + guint mcc_mnc = 0; + proto_tree* eap_identity_tree = NULL; + guint8 eap_identity_prefix = 0; + const gchar* eap_identity_value; + guint8* identity = NULL; + gchar** tokens = NULL; + gchar** realm_tokens = NULL; + gchar** cert_tokens = NULL; + guint ntokens = 0; + guint nrealm_tokens = 0; + guint ncert_tokens = 0; + gboolean ret = TRUE; + gboolean enc_imsi = FALSE; + int hf_eap_identity_mcc_mnc; + proto_item* item; + + /* Check for Encrypted IMSI - NULL prefix byte */ + if (tvb_get_guint8(tvb, offset) == 0x00) { + /* Check if identity string complies with ASCII character set. Encrypted IMSI + * identities use Base64 encoding and should therefore be ASCII-compliant. + */ + if (tvb_ascii_isprint(tvb, offset + 1, size - 1) == FALSE) { + item = proto_tree_add_item(tree, hf_eap_identity, tvb, offset + 1, size - 1, ENC_ASCII || ENC_NA); + expert_add_info(pinfo, item, &ei_eap_identity_nonascii); + goto end; + } + identity = tvb_get_string_enc(pinfo->pool, tvb, offset + 1, size - 1, ENC_ASCII); + /* Encrypted IMSIs must be delimited twice: + * (1) Once to tokenize the 3GPP realm from the Certificate Serial Number + * using the ',' character + * (2) Once to tokenize the 3GPP realm using the '@' character + */ + tokens = g_strsplit_set(identity, ",", -1); + enc_imsi = TRUE; + } else { + /* Check if identity string complies with ASCII character set */ + if (tvb_ascii_isprint(tvb, offset, size) == FALSE) { + item = proto_tree_add_item(tree, hf_eap_identity, tvb, offset, size, ENC_ASCII || ENC_NA); + expert_add_info(pinfo, item, &ei_eap_identity_nonascii); + goto end; + } + /* All other identities may be delimited with the '@' character */ + identity = tvb_get_string_enc(pinfo->pool, tvb, offset, size, ENC_ASCII); + tokens = g_strsplit_set(identity, "@", -1); + } + + while(tokens[ntokens]) + ntokens++; + + /* Check for valid EAP Identity strings based on tokens and 3GPP-format */ + if (enc_imsi) { + if (ntokens < 2 || g_ascii_strncasecmp(tokens[1], "CertificateSerialNumber", 23)) { + ret = FALSE; + proto_tree_add_item(tree, hf_eap_identity, tvb, offset + 1, size - 1, ENC_ASCII); + goto end; + } + } else { + /* tokens[0] is the identity, tokens[1] is the NAI Realm */ + if (ntokens != 2) { + ret = FALSE; + proto_tree_add_item(tree, hf_eap_identity, tvb, offset, size, ENC_ASCII); + goto end; + } + + realm_tokens = g_strsplit_set(tokens[1], ".", -1); + + while(realm_tokens[nrealm_tokens]) + nrealm_tokens++; + + /* The WLAN identity must have the form of + <imsi>@wlan.mnc<mnc>.mcc<mcc>.3gppnetwork.org + If not, we don't have a wlan identity + */ + if (ntokens != 2 || nrealm_tokens != 5 || g_ascii_strncasecmp(realm_tokens[0], "wlan", 4) || + g_ascii_strncasecmp(realm_tokens[3], "3gppnetwork", 11) || + g_ascii_strncasecmp(realm_tokens[4], "org", 3)) { + ret = FALSE; + proto_tree_add_item(tree, hf_eap_identity, tvb, offset, size, ENC_ASCII); + goto end; + } + } + + /* It is very likely that we have a WLAN identity (EAP-AKA/EAP-SIM) */ + /* Go on with the dissection */ + eap_identity_tree = proto_item_add_subtree(tree, ett_identity); + proto_tree_add_item(eap_identity_tree, hf_eap_identity_prefix, tvb, offset, 1, ENC_NA); + eap_identity_prefix = tvb_get_guint8(tvb, offset); + eap_identity_value = try_val_to_str(eap_identity_prefix, eap_identity_prefix_vals); + item = proto_tree_add_string(eap_identity_tree, hf_eap_identity_type, + tvb, offset, 1, eap_identity_value ? eap_identity_value : "Unknown"); + + switch(eap_identity_prefix) { + case 0x00: /* Encrypted IMSI */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity_full, tvb, offset + 1, size - 1, ENC_ASCII || ENC_NA); + /* Account for wide characters that increase the byte count + * despite the character count (i.e., strlen() fails to return + * the proper character count, leading to offset errors. */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity, tvb, offset + 1, (guint)strlen(tokens[0]), ENC_ASCII); + break; + case '0': /* EAP-AKA Permanent */ + case '1': /* EAP-SIM Permanent */ + case '6': /* EAP-AKA' Permanent */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity_full, tvb, offset + 1, size - 1, ENC_ASCII || ENC_NA); + dissect_e212_utf8_imsi(tvb, pinfo, eap_identity_tree, offset + 1, (guint)strlen(tokens[0]) - 1); + break; + case '2': /* EAP-AKA Pseudonym */ + case '3': /* EAP-SIM Pseudonym */ + case '7': /* EAP-AKA' Pseudonym */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity_full, tvb, offset + 1, size - 1, ENC_ASCII || ENC_NA); + proto_tree_add_item(eap_identity_tree, hf_eap_identity, tvb, offset + 1, (guint)strlen(tokens[0]) - 1, ENC_ASCII); + break; + case '4': /* EAP-AKA Reauth ID */ + case '5': /* EAP-SIM Reauth ID */ + case '8': /* EAP-AKA' Reauth ID */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity_full, tvb, offset + 1, size - 1, ENC_ASCII || ENC_NA); + proto_tree_add_item(eap_identity_tree, hf_eap_identity, tvb, offset + 1, (guint)strlen(tokens[0]) - 1, ENC_ASCII); + break; + case 'C': /* Conservative Peer */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity_full, tvb, offset + 1, size - 1, ENC_ASCII || ENC_NA); + proto_tree_add_item(eap_identity_tree, hf_eap_identity, tvb, offset + 1, (guint)strlen(tokens[0]) - 1, ENC_ASCII); + break; + case 'a': /* Anonymous User */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity_full, tvb, offset, size, ENC_ASCII || ENC_NA); + proto_tree_add_item(eap_identity_tree, hf_eap_identity, tvb, offset, (guint)strlen(tokens[0]), ENC_ASCII); + break; + case 'G': /* TODO: 'G' Unknown */ + case 'I': /* TODO: 'I' Unknown */ + default: + proto_tree_add_item(eap_identity_tree, hf_eap_identity_full, tvb, offset + 1, size - 1, ENC_ASCII || ENC_NA); + proto_tree_add_item(eap_identity_tree, hf_eap_identity, tvb, offset + 1, (guint)strlen(tokens[0]) - 1, ENC_ASCII); + expert_add_info(pinfo, item, &ei_eap_identity_invalid); + } + + /* If the identity is an Encrypted IMSI, parse the Certificate Serial Number */ + if (enc_imsi) { + /* Tokenize the Certificate string */ + cert_tokens = g_strsplit_set(tokens[1], "=", -1); + + while(cert_tokens[ncert_tokens]) + ncert_tokens++; + + /* Add Certificate Serial Number to the tree */ + proto_tree_add_item(eap_identity_tree, hf_eap_identity_certificate_sn, tvb, + offset + 1 + (guint)strlen(tokens[0]) + 1 + (guint)strlen("CertificateSerialNumber="), + (guint)strlen(tokens[1]) - (guint)strlen("CertificateSerialNumber="), ENC_ASCII); + + /* Check for the optional NAI Realm string */ + if (ntokens != 3 || g_ascii_strncasecmp(tokens[2], "Realm", 5)) { + goto end; + } + + realm_tokens = g_strsplit_set(tokens[2], "@.", -1); + + while (realm_tokens[nrealm_tokens]) + nrealm_tokens++; + + /* The realm string must have the form of + wlan.mnc<mnc>.mcc<mcc>.3gppnetwork.org + If not, we don't have a proper realm. + */ + if (nrealm_tokens != 5 || g_ascii_strncasecmp(realm_tokens[0], "wlan", 4) || + g_ascii_strncasecmp(realm_tokens[1], "mnc", 3) || + g_ascii_strncasecmp(realm_tokens[2], "mcc", 3) || + g_ascii_strncasecmp(realm_tokens[3], "3gppnetwork", 11) || + g_ascii_strncasecmp(realm_tokens[4], "org", 3)) { + ret = FALSE; + goto end; + } + + /* EAP identities do not always equate to IMSIs. We should + * still add the MCC and MNC values for non-permanent EAP + * identities. */ + if (!sscanf(realm_tokens[2] + 3, "%u", &mnc) || !sscanf(realm_tokens[3] + 3, "%u", &mcc)) { + ret = FALSE; + goto end; + } + } else { + /* Not an encrypted IMSI, but still need to make sure the realm tokens are + * consistent with the 3GPP format. */ + if (!sscanf(realm_tokens[1] + 3, "%u", &mnc) || !sscanf(realm_tokens[2] + 3, "%u", &mcc)) { + ret = FALSE; + goto end; + } + } + + if (!try_val_to_str_ext(mcc * 100 + mnc, &mcc_mnc_2digits_codes_ext)) { + /* May have + * (1) an invalid 2-digit MNC so it won't resolve, + * (2) an invalid 3-digit MNC so it won't resolve, or + * (3) a valid 3-digit MNC. + * For all cases we treat as 3-digit MNC and continue. */ + mcc_mnc = 1000 * mcc + mnc; + hf_eap_identity_mcc_mnc = hf_eap_identity_mcc_mnc_3digits; + } else { + /* We got a 2-digit MNC match */ + mcc_mnc = 100 * mcc + mnc; + hf_eap_identity_mcc_mnc = hf_eap_identity_mcc_mnc_2digits; + } + + /* Handle encrypted IMSI indices first */ + if(realm_tokens[0] && realm_tokens[1] && realm_tokens[2] && realm_tokens[3]) { + if (enc_imsi) { + /* Add MNC to tree */ + proto_tree_add_uint(eap_identity_tree, hf_eap_identity_mcc_mnc, tvb, + offset + 1 + (guint)strlen(tokens[0]) + 1 + (guint)strlen(tokens[1]) + 1 + + (guint)strlen("Realm=@wlan.mnc"), (guint)strlen(realm_tokens[2]) - + (guint)strlen("mnc"), mcc_mnc); + /* Add MCC to tree */ + proto_tree_add_uint(eap_identity_tree, hf_eap_identity_mcc, tvb, + offset + 1 + (guint)strlen(tokens[0]) + 1 + (guint)strlen(tokens[1]) + 1 + + (guint)strlen(realm_tokens[0]) + (guint)strlen("@wlan.") + + (guint)strlen(realm_tokens[2]) + (guint)strlen(".mcc"), + (guint)strlen(realm_tokens[3]) - (guint)strlen("mcc"), mcc); + } else { + /* Add MNC to tree */ + proto_tree_add_uint(eap_identity_tree, hf_eap_identity_mcc_mnc, + tvb, offset + (guint)strlen(tokens[0]) + (guint)strlen("@wlan.") + + (guint)strlen("mnc"), (guint)strlen(realm_tokens[1]) - (guint)strlen("mnc"), + mcc_mnc); + /* Add MCC to tree */ + proto_tree_add_uint(eap_identity_tree, hf_eap_identity_mcc, + tvb, offset + (guint)(strlen(tokens[0]) + (guint)strlen("@wlan.") + + (guint)strlen(realm_tokens[1]) + 1 + strlen("mcc")), + (guint)strlen(realm_tokens[2]) - (guint)strlen("mcc"), mcc); + } + } + +end: + g_strfreev(tokens); + g_strfreev(realm_tokens); + g_strfreev(cert_tokens); + + return ret; +} + +static void +dissect_eap_identity(tvbuff_t *tvb, packet_info* pinfo, proto_tree* tree, int offset, gint size) +{ + /* + * Try to dissect as WLAN identity. + * + * XXX - what other types of identity are there? + * + * XXX - dissect_eap_identity_wlan() speaks of EAP-AKA and EAP-SIM, + * and neither RFC 4187 for EAP-AKA nor RFC 4186 for EAP-SIM speak + * of those being used solely on WLANs. For that matter, 802.1X + * was originally designed for wired networks (Ethernet, Token Ring, + * FDDI), and later adapted for 802.11. + * + * If dissecting EAP identities must be done differently for wired + * networks and 802.11, this should dissect them based on the link-layer + * type of the network on which the packet arrived. + * + * If dissecting EAP identities does *not* need to be done differently + * for wired networks and 802.11, dissect_eap_identity_wlan() should + * just be incorporated within this routine. + */ + if (dissect_eap_identity_wlan(tvb, pinfo, tree, offset, size)) + return; +} + +static void +dissect_eap_sim(proto_tree *eap_tree, tvbuff_t *tvb, packet_info* pinfo, int offset, gint size) +{ + gint left = size; + + proto_tree_add_item(eap_tree, hf_eap_sim_subtype, tvb, offset, 1, ENC_BIG_ENDIAN); + + offset += 1; + left -= 1; + + if (left < 2) + return; + proto_tree_add_item(eap_tree, hf_eap_sim_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + left -= 2; + + /* Rest of EAP-SIM data is in Type-Len-Value format. */ + while (left >= 2) { + guint8 type, length; + gint padding; + proto_item *pi; + proto_tree *attr_tree; + int aoffset; + gint aleft; + + aoffset = offset; + type = tvb_get_guint8(tvb, aoffset); + length = tvb_get_guint8(tvb, aoffset + 1); + aleft = 4 * length; + + pi = proto_tree_add_none_format(eap_tree, hf_eap_sim_subtype_attribute, tvb, + aoffset, aleft, "EAP-SIM Attribute: %s (%d)", + val_to_str_ext_const(type, + &eap_sim_aka_attribute_vals_ext, + "Unknown"), + type); + attr_tree = proto_item_add_subtree(pi, ett_eap_sim_attr); + proto_tree_add_uint(attr_tree, hf_eap_sim_subtype_type, tvb, aoffset, 1, type); + aoffset += 1; + aleft -= 1; + + if (aleft <= 0) + break; + proto_tree_add_item(attr_tree, hf_eap_sim_subtype_length, tvb, aoffset, 1, ENC_BIG_ENDIAN); + aoffset += 1; + aleft -= 1; + + switch(type){ + case AT_IDENTITY: + proto_tree_add_item(attr_tree, hf_eap_identity_actual_len, tvb, aoffset, 2, ENC_BIG_ENDIAN); + dissect_eap_identity(tvb, pinfo, attr_tree, aoffset + 2, tvb_get_ntohs(tvb, aoffset)); + /* If we have a disparity between the EAP-SIM length (minus the + * first 4 bytes of header fields) * 4 and the Identity Actual + * Length then it's padding and we need to adjust for that + * accurately before looking at the next EAP-SIM attribute. */ + padding = ((length - 1) * 4) - tvb_get_ntohs(tvb, aoffset); + if (padding != 0) { + proto_tree_add_item(attr_tree, hf_eap_identity_padding, tvb, + aoffset + 2 + tvb_get_ntohs(tvb, aoffset), padding, ENC_NA); + } + break; + case AT_NOTIFICATION: + proto_tree_add_item(attr_tree, hf_eap_sim_notification_type, tvb, aoffset, 2, ENC_BIG_ENDIAN); + break; + case AT_CLIENT_ERROR_CODE: + proto_tree_add_item(attr_tree, hf_eap_sim_error_code_type, tvb, aoffset, 2, ENC_BIG_ENDIAN); + break; + default: + proto_tree_add_item(attr_tree, hf_eap_sim_subtype_value, tvb, aoffset, aleft, ENC_NA); + } + + offset += 4 * length; + left -= 4 * length; + } +} + +static void +dissect_eap_aka(proto_tree *eap_tree, tvbuff_t *tvb, packet_info* pinfo, int offset, gint size) +{ + gint left = size; + + proto_tree_add_item(eap_tree, hf_eap_aka_subtype, tvb, offset, 1, ENC_BIG_ENDIAN); + + offset += 1; + left -= 1; + + if (left < 2) + return; + proto_tree_add_item(eap_tree, hf_eap_aka_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + left -= 2; + + /* Rest of EAP-AKA data is in Type-Len-Value format. */ + while (left >= 2) { + guint8 type, length; + gint padding; + proto_item *pi; + proto_tree *attr_tree; + int aoffset; + gint aleft; + + aoffset = offset; + type = tvb_get_guint8(tvb, aoffset); + length = tvb_get_guint8(tvb, aoffset + 1); + aleft = 4 * length; + + pi = proto_tree_add_none_format(eap_tree, hf_eap_aka_subtype_attribute, tvb, + aoffset, aleft, "EAP-AKA Attribute: %s (%d)", + val_to_str_ext_const(type, + &eap_sim_aka_attribute_vals_ext, + "Unknown"), + type); + attr_tree = proto_item_add_subtree(pi, ett_eap_aka_attr); + proto_tree_add_uint(attr_tree, hf_eap_aka_subtype_type, tvb, aoffset, 1, type); + aoffset += 1; + aleft -= 1; + + if (aleft <= 0) + break; + proto_tree_add_item(attr_tree, hf_eap_aka_subtype_length, tvb, aoffset, 1, ENC_BIG_ENDIAN); + aoffset += 1; + aleft -= 1; + + switch(type){ + case AT_IDENTITY: + proto_tree_add_item(attr_tree, hf_eap_identity_actual_len, tvb, aoffset, 2, ENC_BIG_ENDIAN); + dissect_eap_identity(tvb, pinfo, attr_tree, aoffset + 2, tvb_get_ntohs(tvb, aoffset)); + /* If we have a disparity between the EAP-AKA length (minus the + * first 4 bytes of header fields) * 4 and the Identity Actual + * Length then it's padding and we need to adjust for that + * accurately before looking at the next EAP-AKA attribute. */ + padding = ((length - 1) * 4) - tvb_get_ntohs(tvb, aoffset); + if (padding != 0) { + proto_tree_add_item(attr_tree, hf_eap_identity_padding, tvb, + aoffset + 2 + tvb_get_ntohs(tvb, aoffset), padding, ENC_NA); + } + break; + case AT_NOTIFICATION: + proto_tree_add_item(attr_tree, hf_eap_aka_notification_type, tvb, aoffset, 2, ENC_BIG_ENDIAN); + break; + case AT_CLIENT_ERROR_CODE: + proto_tree_add_item(attr_tree, hf_eap_aka_error_code_type, tvb, aoffset, 2, ENC_BIG_ENDIAN); + break; + default: + proto_tree_add_item(attr_tree, hf_eap_aka_subtype_value, tvb, aoffset, aleft, ENC_NA); + } + + offset += 4 * length; + left -= 4 * length; + } +} + +static int +dissect_eap_pax(proto_tree *eap_tree, tvbuff_t *tvb, packet_info *pinfo, int offset, gint size) +{ + static int * const pax_flags[] = { + &hf_eap_pax_flags_mf, + &hf_eap_pax_flags_ce, + &hf_eap_pax_flags_ai, + &hf_eap_pax_flags_reserved, + NULL + }; + guint32 opcode; + guint64 flags; + guint32 len; + + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_opcode, tvb, offset, 1, ENC_NA, &opcode); + offset++; + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + val_to_str(opcode, eap_pax_opcode_vals, "Unknown opcode (0x%02X)")); + + proto_tree_add_bitmask_ret_uint64(eap_tree, tvb, offset, hf_eap_pax_flags, ett_eap_pax_flags, + pax_flags, ENC_BIG_ENDIAN, &flags); + offset++; + + proto_tree_add_item(eap_tree, hf_eap_pax_mac_id, tvb, offset, 1, ENC_NA); + offset++; + + proto_tree_add_item(eap_tree, hf_eap_pax_dh_group_id, tvb, offset, 1, ENC_NA); + offset++; + + proto_tree_add_item(eap_tree, hf_eap_pax_public_key_id, tvb, offset, 1, ENC_NA); + offset++; + + switch (opcode) { + case PAX_STD_1: + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_a_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_a, tvb, offset, len, ENC_NA); + offset += len; + len = 5 + size - offset; + proto_tree_add_item(eap_tree, hf_eap_pax_mac_icv, tvb, offset, len, ENC_NA); + offset += len; + break; + case PAX_STD_2: + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_b_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_b, tvb, offset, len, ENC_NA); + offset += len; + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_cid_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_cid, tvb, offset, len, ENC_ASCII | ENC_NA); + offset += len; + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_mac_ck_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_mac_ck, tvb, offset, len, ENC_NA); + offset += len; + if (flags & EAP_PAX_FLAG_AI) { + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_ade_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_ade, tvb, offset, len, ENC_NA); + offset += len; + } + len = 5 + size - offset; + proto_tree_add_item(eap_tree, hf_eap_pax_mac_icv, tvb, offset, len, ENC_NA); + offset += len; + break; + case PAX_STD_3: + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_mac_ck_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_mac_ck, tvb, offset, len, ENC_NA); + offset += len; + if (flags & EAP_PAX_FLAG_AI) { + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_ade_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_ade, tvb, offset, len, ENC_NA); + offset += len; + } + len = 5 + size - offset; + proto_tree_add_item(eap_tree, hf_eap_pax_mac_icv, tvb, offset, len, ENC_NA); + offset += len; + break; + case PAX_ACK: + if (flags & EAP_PAX_FLAG_AI) { + proto_tree_add_item_ret_uint(eap_tree, hf_eap_pax_ade_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_pax_ade, tvb, offset, len, ENC_NA); + offset += len; + } + len = 5 + size - offset; + proto_tree_add_item(eap_tree, hf_eap_pax_mac_icv, tvb, offset, len, ENC_NA); + offset += len; + break; + case PAX_SEC_1: + case PAX_SEC_2: + case PAX_SEC_3: + case PAX_SEC_4: + case PAX_SEC_5: + /* TODO implement */ + default: + break; + } + + return offset; +} + +static int +dissect_eap_psk_pchannel(proto_tree *eap_tree, tvbuff_t *tvb, int offset, gint size) +{ + /* The protected channel (PCHANNEL) content is encrypted so for now just present + * it as a binary blob */ + proto_tree_add_item(eap_tree, hf_eap_psk_pchannel, tvb, offset, size, ENC_NA); + offset += size; + return offset; +} + +static int +dissect_eap_psk(proto_tree *eap_tree, tvbuff_t *tvb, packet_info *pinfo, int offset, gint size) +{ + static int * const psk_flags[] = { + &hf_eap_psk_flags_t, + &hf_eap_psk_flags_reserved, + NULL + }; + guint64 flags; + + proto_tree_add_bitmask_ret_uint64(eap_tree, tvb, offset, hf_eap_psk_flags, ett_eap_psk_flags, + psk_flags, ENC_NA, &flags); + offset++; + + switch (flags & EAP_PSK_FLAGS_T_MASK) { + case 0x00: /* T == 0 - EAP-PSK First Message */ + col_append_str(pinfo->cinfo, COL_INFO, " First Message"); + proto_tree_add_item(eap_tree, hf_eap_psk_rand_s, tvb, offset, 16, ENC_NA); + offset += 16; + proto_tree_add_item(eap_tree, hf_eap_psk_id_s, tvb, offset, size + 5 - offset, ENC_ASCII | ENC_NA); + offset = size; + break; + case 0x40: /* T == 1 - EAP-PSK Second Message */ + col_append_str(pinfo->cinfo, COL_INFO, " Second Message"); + proto_tree_add_item(eap_tree, hf_eap_psk_rand_s, tvb, offset, 16, ENC_NA); + offset += 16; + proto_tree_add_item(eap_tree, hf_eap_psk_rand_p, tvb, offset, 16, ENC_NA); + offset += 16; + proto_tree_add_item(eap_tree, hf_eap_psk_mac_p, tvb, offset, 16, ENC_NA); + offset += 16; + proto_tree_add_item(eap_tree, hf_eap_psk_id_p, tvb, offset, size + 5 - offset, ENC_ASCII | ENC_NA); + offset = size; + break; + case 0x80: /* T == 2 - EAP-PSK Third Message */ + col_append_str(pinfo->cinfo, COL_INFO, " Third Message"); + proto_tree_add_item(eap_tree, hf_eap_psk_rand_s, tvb, offset, 16, ENC_NA); + offset += 16; + proto_tree_add_item(eap_tree, hf_eap_psk_mac_s, tvb, offset, 16, ENC_NA); + offset += 16; + offset = dissect_eap_psk_pchannel(eap_tree, tvb, offset, size + 5 - offset); + break; + case 0xC0: /* T == 3 - EAP-PSK Fourth Message */ + col_append_str(pinfo->cinfo, COL_INFO, " Fourth Message"); + proto_tree_add_item(eap_tree, hf_eap_psk_rand_s, tvb, offset, 16, ENC_NA); + offset += 16; + offset = dissect_eap_psk_pchannel(eap_tree, tvb, offset, size + 5 - offset); + break; + default: + break; + } + + return offset; +} + +static gint +dissect_eap_gpsk_csuite_sel(proto_tree *eap_tree, tvbuff_t *tvb, int offset) +{ + proto_tree *csuite_tree; + csuite_tree = proto_tree_add_subtree(eap_tree, tvb, offset, 6, ett_eap_gpsk_csuite_sel, + NULL, "EAP-GPSK CSuite_Sel"); + proto_tree_add_item(csuite_tree, hf_eap_gpsk_csuite_vendor, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(csuite_tree, hf_eap_gpsk_csuite_specifier, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + return offset; +} + +static gint +dissect_eap_gpsk_csuite_list(proto_tree *eap_tree, tvbuff_t *tvb, int offset) +{ + gint start_offset = offset; + guint16 len; + proto_tree *list_tree, *csuite_tree; + + len = tvb_get_ntohs(tvb, offset) + 2; + list_tree = proto_tree_add_subtree(eap_tree, tvb, offset, len, ett_eap_gpsk_csuite_list, + NULL, "EAP-GPSK CSuite List"); + proto_tree_add_item(list_tree, hf_eap_gpsk_csuite_list_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + while (offset < start_offset + len) { + csuite_tree = proto_tree_add_subtree(list_tree, tvb, offset, 6, ett_eap_gpsk_csuite, + NULL, "CSuite"); + proto_tree_add_item(csuite_tree, hf_eap_gpsk_csuite_vendor, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(csuite_tree, hf_eap_gpsk_csuite_specifier, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + return offset; +} + +static gint +dissect_eap_sake_attribute(proto_tree *eap_tree, tvbuff_t *tvb, int offset, gint size) +{ + gint start_offset = offset; + guint8 type; + guint8 len; + proto_tree *attr_tree; + + type = tvb_get_guint8(tvb, offset); + len = tvb_get_guint8(tvb, offset + 1); + + if (len < 2 || len > size) { + return -1; + } + attr_tree = proto_tree_add_subtree_format(eap_tree, tvb, offset, len, ett_eap_sake_attr, NULL, + "EAP-SAKE Attribute: %s", + val_to_str(type, eap_sake_attr_type_vals, + "Unknown (%d)")); + + proto_tree_add_item(attr_tree, hf_eap_sake_attr_type, tvb, offset, 1, ENC_NA); + offset++; + proto_tree_add_item(attr_tree, hf_eap_sake_attr_len, tvb, offset, 1, ENC_NA); + offset++; + len -= 2; + + switch (type) { + case SAKE_AT_SERVERID: + case SAKE_AT_PEERID: + proto_tree_add_item(attr_tree, hf_eap_sake_attr_value_str, tvb, offset, len, ENC_ASCII | ENC_NA); + offset += len; + break; + case SAKE_AT_MSK_LIFE: + proto_tree_add_item(attr_tree, hf_eap_sake_attr_value_uint48, tvb, offset, len, + ENC_BIG_ENDIAN); + offset += len; + break; + case SAKE_AT_RAND_S: + case SAKE_AT_RAND_P: + case SAKE_AT_MIC_S: + case SAKE_AT_MIC_P: + case SAKE_AT_SPI_S: + case SAKE_AT_SPI_P: + case SAKE_AT_ANY_ID_REQ: + case SAKE_AT_PERM_ID_REQ: + case SAKE_AT_ENCR_DATA: + case SAKE_AT_IV: + case SAKE_AT_PADDING: + case SAKE_AT_NEXT_TMPID: + default: + proto_tree_add_item(attr_tree, hf_eap_sake_attr_value, tvb, offset, len, ENC_NA); + offset += len; + break; + } + return offset - start_offset; +} + +static void +dissect_eap_sake_attributes(proto_tree *eap_tree, tvbuff_t *tvb, int offset, gint size) +{ + gint attr_size; + while (offset < size) { + attr_size = dissect_eap_sake_attribute(eap_tree, tvb, offset, size); + if (attr_size == -1) { + break; + } + offset += attr_size; + } +} + +static void +dissect_eap_sake(proto_tree *eap_tree, tvbuff_t *tvb, packet_info *pinfo _U_, int offset, gint size) +{ + guint32 version; + guint32 subtype; + + proto_tree_add_item_ret_uint(eap_tree, hf_eap_sake_version, tvb, offset, 1, ENC_NA, &version); + offset++; + if (version != 2) { + /* RFC 4763 specify version 2. Everything else is unsupported */ + return; + } + proto_tree_add_item(eap_tree, hf_eap_sake_session_id, tvb, offset, 1, ENC_NA); + offset++; + proto_tree_add_item_ret_uint(eap_tree, hf_eap_sake_subtype, tvb, offset, 1, ENC_NA, &subtype); + offset++; + + switch (subtype) { + case SAKE_CHALLENGE: + case SAKE_CONFIRM: + case SAKE_AUTH_REJECT: + case SAKE_IDENTITY: + dissect_eap_sake_attributes(eap_tree, tvb, offset, size + 5 - offset); + break; + default: + break; + } +} + +static int +dissect_eap_gpsk(proto_tree *eap_tree, tvbuff_t *tvb, packet_info *pinfo, int offset, gint size) +{ + guint32 opcode; + guint32 len; + + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_opcode, tvb, offset, 1, ENC_NA, &opcode); + offset++; + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + val_to_str(opcode, eap_gpsk_opcode_vals, "Unknown opcode (0x%02X)")); + + switch (opcode) { + case GPSK_GPSK_1: + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_id_server_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_gpsk_id_server, tvb, offset, len, ENC_ASCII | ENC_NA); + offset += len; + proto_tree_add_item(eap_tree, hf_eap_gpsk_rand_server, tvb, offset, 32, ENC_NA); + offset += 32; + offset = dissect_eap_gpsk_csuite_list(eap_tree, tvb, offset); + break; + case GPSK_GPSK_2: + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_id_peer_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_gpsk_id_peer, tvb, offset, len, ENC_ASCII | ENC_NA); + offset += len; + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_id_server_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_gpsk_id_server, tvb, offset, len, ENC_ASCII | ENC_NA); + offset += len; + proto_tree_add_item(eap_tree, hf_eap_gpsk_rand_peer, tvb, offset, 32, ENC_NA); + offset += 32; + proto_tree_add_item(eap_tree, hf_eap_gpsk_rand_server, tvb, offset, 32, ENC_NA); + offset += 32; + offset = dissect_eap_gpsk_csuite_list(eap_tree, tvb, offset); + offset = dissect_eap_gpsk_csuite_sel(eap_tree, tvb, offset); + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_pd_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + if (len > 0) { + proto_tree_add_item(eap_tree, hf_eap_gpsk_pd_payload, tvb, offset, len, ENC_NA); + offset += len; + } + len = size + 5 - offset; + proto_tree_add_item(eap_tree, hf_eap_gpsk_payload_mac, tvb, offset, len, ENC_NA); + offset += len; + break; + case GPSK_GPSK_3: + proto_tree_add_item(eap_tree, hf_eap_gpsk_rand_peer, tvb, offset, 32, ENC_NA); + offset += 32; + proto_tree_add_item(eap_tree, hf_eap_gpsk_rand_server, tvb, offset, 32, ENC_NA); + offset += 32; + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_id_server_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + proto_tree_add_item(eap_tree, hf_eap_gpsk_id_server, tvb, offset, len, ENC_ASCII | ENC_NA); + offset += len; + offset = dissect_eap_gpsk_csuite_sel(eap_tree, tvb, offset); + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_pd_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + if (len > 0) { + proto_tree_add_item(eap_tree, hf_eap_gpsk_pd_payload, tvb, offset, len, ENC_NA); + offset += len; + } + len = size + 5 - offset; + proto_tree_add_item(eap_tree, hf_eap_gpsk_payload_mac, tvb, offset, len, ENC_NA); + offset += len; + break; + case GPSK_GPSK_4: + proto_tree_add_item_ret_uint(eap_tree, hf_eap_gpsk_pd_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + if (len > 0) { + proto_tree_add_item(eap_tree, hf_eap_gpsk_pd_payload, tvb, offset, len, ENC_NA); + offset += len; + } + len = size + 5 - offset; + proto_tree_add_item(eap_tree, hf_eap_gpsk_payload_mac, tvb, offset, len, ENC_NA); + offset += len; + break; + case GPSK_FAIL: + proto_tree_add_item(eap_tree, hf_eap_gpsk_failure_code, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case GPSK_PROTECTED_FAIL: + proto_tree_add_item(eap_tree, hf_eap_gpsk_failure_code, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + len = size + 5 - offset; + proto_tree_add_item(eap_tree, hf_eap_gpsk_payload_mac, tvb, offset, len, ENC_NA); + offset += len; + break; + default: + break; + } + + return offset; +} + +static int +dissect_eap_msauth_tlv(proto_tree *eap_tree, tvbuff_t *tvb, packet_info *pinfo, int offset, gint size) +{ + guint tlv_type, tlv_len; + proto_tree *tlv_tree, *tree, *ti_len; + + tlv_tree = proto_tree_add_subtree(eap_tree, tvb, offset, size, ett_eap_msauth_tlv, + NULL, "Tag Length Values"); + +next_tlv: + tlv_type = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN) & MSAUTH_TLV_TYPE; + tlv_len = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN); + + tree = proto_tree_add_subtree_format(tlv_tree, tvb, offset, 4 + tlv_len, + ett_eap_msauth_tlv_tree, NULL, "TLV: t=%s(%d) l=%d", + val_to_str_const(tlv_type, eap_msauth_tlv_type_vals, "Unknown"), + tlv_type, 4 + tlv_len); + + proto_tree_add_item(tree, hf_eap_msauth_tlv_mandatory, tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_eap_msauth_tlv_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_eap_msauth_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_eap_msauth_tlv_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + switch (tlv_type) { + case MSAUTH_TLV_TYPE_EXTENSION_RESULT: + proto_tree_add_item(tree, hf_eap_msauth_tlv_status, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + + case MSAUTH_TLV_TYPE_EXTENSION_CRYPTOBINDING: + proto_tree_add_item(tree, hf_eap_msauth_tlv_crypto_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(tree, hf_eap_msauth_tlv_crypto_version, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(tree, hf_eap_msauth_tlv_crypto_rcv_version, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(tree, hf_eap_msauth_tlv_crypto_subtype, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(tree, hf_eap_msauth_tlv_crypto_nonce, tvb, offset, 32, ENC_NA); + offset += 32; + proto_tree_add_item(tree, hf_eap_msauth_tlv_crypto_cmac, tvb, offset, 20, ENC_NA); + offset += 20; + break; + + default: + ti_len = proto_tree_add_item(tree, hf_eap_msauth_tlv_val, tvb, offset, tlv_len, ENC_NA); + if (4 + tlv_len > (guint)size - offset) { + expert_add_info(pinfo, ti_len, &ei_eap_bad_length); + } + offset += tlv_len; + } + + if (offset < size) { + goto next_tlv; + } + + return offset; +} + + +static int +dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + guint8 eap_code; + guint8 eap_identifier; + guint16 eap_len; + guint8 eap_type; + gint len; + conversation_t *conversation = NULL; + conv_state_t *conversation_state = NULL; + frame_state_t *packet_state; + int leap_state; + proto_tree *ti, *ti_id, *ti_len; + proto_tree *eap_tree; + proto_tree *eap_tls_flags_tree; + proto_item *eap_type_item; + static address null_address = ADDRESS_INIT_NONE; + static guint8 pae_group_address_mac_addr[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; + static address pae_group_address = ADDRESS_INIT(AT_ETHER, sizeof(pae_group_address_mac_addr), pae_group_address_mac_addr); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAP"); + col_clear(pinfo->cinfo, COL_INFO); + + eap_code = tvb_get_guint8(tvb, 0); + eap_identifier = tvb_get_guint8(tvb, 1); + + col_add_str(pinfo->cinfo, COL_INFO, + val_to_str(eap_code, eap_code_vals, "Unknown code (0x%02X)")); + + /* + * Find a conversation to which we belong; create one if we don't find it. + * + * EAP runs over RADIUS (which runs over UDP), EAPOL (802.1X Authentication) + * or other transports. In case of RADIUS, a single "session" may consist + * of two UDP associations (one for authorization, one for accounting) which + * results in two separate conversations. This wastes memory, but won't affect + * the use cases below. In case of EAPOL, there are no ports. In any case, + * force a new conversation when the EAP-Request/Identity message is found. + * + * Conversation tracking is required for 1) EAP-TLS reassembly and 2) tracking + * the stage in the LEAP protocol. In both cases, the protocol starts with an + * EAP-Request/Identity message which cannot be found in the middle of the + * session. Use it as a signal to start a new conversation. This ensures that + * the TLS dissector associates new TLS messages with a unique TLS session. + * + * For EAPOL frames we need to massage the source/destination addresses into + * something stable for the TLS decoder as wireshark typically thinks there + * are three conversations occurring when there is only one: + * * src ether = server mac -> dst ether = PAE multicast group address + * * src ether = server mac -> dst ether = client mac + * * src ether = client mac -> dst ether = PAE multicast group address + * We set the port so the TLS decoder can figure out which side is the server + */ + address conv_src, conv_dst; + guint32 tls_group = pinfo->curr_proto_layer_num << 16; + uint32_t conv_srcport = pinfo->srcport; + uint32_t conv_destport = pinfo->destport; + if (pinfo->src.type == AT_ETHER) { + if (eap_code == EAP_REQUEST) { /* server -> client */ + copy_address_shallow(&conv_src, &null_address); + copy_address_shallow(&conv_dst, &pae_group_address); + conv_srcport = 443; + } else { /* client -> server */ + copy_address_shallow(&conv_src, &pae_group_address); + copy_address_shallow(&conv_dst, &null_address); + conv_destport = 443; + } + } + else { + copy_address_shallow(&conv_src, &pinfo->src); + copy_address_shallow(&conv_dst, &pinfo->dst); + } + + /* + * To support tunneled EAP-TLS (e.g. {TTLS,PEAP,TEAP,...}/EAP-TLS) we + * group our TLS frames by the depth they are found at and use this + * as offsets for p_get_proto_data/p_add_proto_data and as done for + * EAPOL above we massage the client port using this too + */ + + if (eap_code == EAP_REQUEST) { /* server -> client */ + conv_destport |= tls_group; + } + else { /* client -> server */ + conv_srcport |= tls_group; + } + + conversation_set_conv_addr_port_endpoints(pinfo, &conv_src, &conv_dst, + conversation_pt_to_conversation_type(pinfo->ptype), conv_srcport, conv_destport); + + if (PINFO_FD_VISITED(pinfo) || !(eap_code == EAP_REQUEST && tvb_get_guint8(tvb, 4) == EAP_TYPE_ID)) { + conversation = find_or_create_conversation(pinfo); + } + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &conv_src, + &conv_dst, conversation_pt_to_conversation_type(pinfo->ptype), + conv_srcport, conv_destport, 0); + } + + /* + * Get the state information for the conversation; attach some if + * we don't find it. + */ + conversation_state = (conv_state_t *)conversation_get_proto_data(conversation, proto_eap); + if (conversation_state == NULL) { + /* + * Attach state information to the conversation. + */ + conversation_state = wmem_new(wmem_file_scope(), conv_state_t); + conversation_state->eap_tls_seq = -1; + conversation_state->eap_reass_cookie = 0; + conversation_state->leap_state = -1; + conversation_state->last_eap_id_req = -1; + conversation_state->last_eap_id_resp = -1; + conversation_add_proto_data(conversation, proto_eap, conversation_state); + } + + /* + * Set this now, so that it gets remembered even if we throw an exception + * later. + */ + if (eap_code == EAP_FAILURE) + conversation_state->leap_state = -1; + + eap_len = tvb_get_ntohs(tvb, 2); + len = eap_len; + + ti = proto_tree_add_item(tree, proto_eap, tvb, 0, len, ENC_NA); + eap_tree = proto_item_add_subtree(ti, ett_eap); + + proto_tree_add_item(eap_tree, hf_eap_code, tvb, 0, 1, ENC_BIG_ENDIAN); + ti_id = proto_tree_add_item(eap_tree, hf_eap_identifier, tvb, 1, 1, ENC_BIG_ENDIAN); + ti_len = proto_tree_add_item(eap_tree, hf_eap_len, tvb, 2, 2, ENC_BIG_ENDIAN); + if (len < 4 || (guint)len > tvb_reported_length(tvb)) { + expert_add_info(pinfo, ti_len, &ei_eap_bad_length); + } + + /* Detect message retransmissions. Since the protocol proceeds in lock-step, + * reordering is not expected. If retransmissions somehow occur, we would have + * to detect retransmissions via a bitmap. */ + gboolean is_duplicate_id = FALSE; + if (conversation_state) { + if (eap_code == EAP_REQUEST || eap_code == EAP_RESPONSE || + eap_code == EAP_INITIATE || eap_code == EAP_FINISH) { + if (!PINFO_FD_VISITED(pinfo)) { + gint16 *last_eap_id = eap_code == EAP_REQUEST || eap_code == EAP_INITIATE ? + &conversation_state->last_eap_id_req : + &conversation_state->last_eap_id_resp; + is_duplicate_id = *last_eap_id == eap_identifier; + *last_eap_id = eap_identifier; + if (is_duplicate_id) { + // Use a dummy value to remember that this packet is a duplicate. + p_add_proto_data(wmem_file_scope(), pinfo, proto_eap, PROTO_DATA_EAP_DUPLICATE_ID | tls_group, GINT_TO_POINTER(1)); + } + } else { + is_duplicate_id = !!p_get_proto_data(wmem_file_scope(), pinfo, proto_eap, PROTO_DATA_EAP_DUPLICATE_ID | tls_group); + } + if (is_duplicate_id) { + expert_add_info(pinfo, ti_id, &ei_eap_retransmission); + } + } + } + + switch (eap_code) { + + case EAP_SUCCESS: + case EAP_FAILURE: + break; + + case EAP_REQUEST: + case EAP_RESPONSE: + eap_type = tvb_get_guint8(tvb, 4); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext(eap_type, &eap_type_vals_ext, + "Unknown type (0x%02x)")); + eap_type_item = proto_tree_add_item(eap_tree, hf_eap_type, tvb, 4, 1, ENC_BIG_ENDIAN); + + if ((len > 5) || ((len == 5) && (eap_type == EAP_TYPE_ID))) { + int offset = 5; + gint size = len - offset; + + switch (eap_type) { + /********************************************************************* + **********************************************************************/ + case EAP_TYPE_ID: + if (size > 0) { + dissect_eap_identity(tvb, pinfo, eap_tree, offset, size); + } + if (conversation_state && !PINFO_FD_VISITED(pinfo)) { + conversation_state->leap_state = 0; + conversation_state->eap_tls_seq = -1; + } + break; + + /********************************************************************* + **********************************************************************/ + case EAP_TYPE_NOTIFY: + proto_tree_add_item(eap_tree, hf_eap_notification, tvb, + offset, size, ENC_ASCII); + break; + + /********************************************************************* + **********************************************************************/ + case EAP_TYPE_NAK: + proto_tree_add_item(eap_tree, hf_eap_type_nak, tvb, + offset, 1, ENC_BIG_ENDIAN); + break; + /********************************************************************* + **********************************************************************/ + case EAP_TYPE_MD5: + { + guint8 value_size = tvb_get_guint8(tvb, offset); + gint extra_len = size - 1 - value_size; + proto_item *item; + + /* Warn that this is an insecure EAP type. */ + expert_add_info(pinfo, eap_type_item, &ei_eap_mitm_attacks); + + item = proto_tree_add_item(eap_tree, hf_eap_md5_value_size, tvb, offset, 1, ENC_BIG_ENDIAN); + if (value_size > (size - 1)) + { + expert_add_info(pinfo, item, &ei_eap_md5_value_size_overflow); + value_size = size - 1; + } + + offset += 1; + proto_tree_add_item(eap_tree, hf_eap_md5_value, tvb, offset, value_size, ENC_NA); + offset += value_size; + if (extra_len > 0) { + proto_tree_add_item(eap_tree, hf_eap_md5_extra_data, tvb, offset, extra_len, ENC_NA); + } + } + break; + + /********************************************************************* + EAP-TLS + **********************************************************************/ + case EAP_TYPE_FAST: + case EAP_TYPE_PEAP: + case EAP_TYPE_TTLS: + case EAP_TYPE_TLS: + case EAP_TYPE_TEAP: + { + gboolean more_fragments; + gboolean has_length; + gboolean is_start; + gboolean outer_tlvs = false; + gint outer_tlvs_length = 0; + int eap_tls_seq = -1; + guint32 eap_reass_cookie = 0; + gboolean needs_reassembly = FALSE; + + if (!conversation_state) { + // XXX expert info? There cannot be another EAP-TTLS message within + // the EAP-Message inside EAP-TTLS. + break; + } + + /* Flags field, 1 byte */ + ti = proto_tree_add_item(eap_tree, hf_eap_tls_flags, tvb, offset, 1, ENC_BIG_ENDIAN); + eap_tls_flags_tree = proto_item_add_subtree(ti, ett_eap_tls_flags); + proto_tree_add_item_ret_boolean(eap_tls_flags_tree, hf_eap_tls_flag_l, tvb, offset, 1, ENC_BIG_ENDIAN, &has_length); + proto_tree_add_item_ret_boolean(eap_tls_flags_tree, hf_eap_tls_flag_m, tvb, offset, 1, ENC_BIG_ENDIAN, &more_fragments); + proto_tree_add_item_ret_boolean(eap_tls_flags_tree, hf_eap_tls_flag_s, tvb, offset, 1, ENC_BIG_ENDIAN, &is_start); + + switch (eap_type) { + case EAP_TYPE_TEAP: + proto_tree_add_item_ret_boolean(eap_tls_flags_tree, hf_eap_tls_flag_o, tvb, offset, 1, ENC_BIG_ENDIAN, &outer_tlvs); + /* FALLTHROUGH */ + case EAP_TYPE_TTLS: + case EAP_TYPE_FAST: + case EAP_TYPE_PEAP: + proto_tree_add_item(eap_tls_flags_tree, hf_eap_tls_flags_version, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + } + size -= 1; + offset += 1; + + /* Length field, 4 bytes, OPTIONAL. */ + if (has_length) { + proto_tree_add_item(eap_tree, hf_eap_tls_len, tvb, offset, 4, ENC_BIG_ENDIAN); + size -= 4; + offset += 4; + } + + /* Outer TLV Length field, 4 bytes, OPTIONAL. */ + if (outer_tlvs) { + proto_tree_add_item_ret_uint(eap_tree, hf_eap_tls_outer_tlvs_len, tvb, offset, 4, ENC_BIG_ENDIAN, &outer_tlvs_length); + size -= 4; + offset += 4; + } + + if (is_start) + conversation_state->eap_tls_seq = -1; + + /* 4.1.1 Authority ID Data https://datatracker.ietf.org/doc/html/rfc4851#section-4.1.1 */ + if (eap_type == EAP_TYPE_FAST && is_start) { + guint32 length, type; + + proto_tree_add_item_ret_uint(eap_tree, hf_eap_fast_type, tvb, offset, 2, ENC_BIG_ENDIAN, &type); + size -= 2; + offset += 2; + + proto_tree_add_item_ret_uint(eap_tree, hf_eap_fast_length, tvb, offset, 2, ENC_BIG_ENDIAN, &length); + size -= 2; + offset += 2; + + proto_tree_add_item(eap_tree, hf_eap_data, tvb, offset, length, ENC_NA); + + switch (type) { + case 4: + proto_tree_add_item(eap_tree, hf_eap_fast_aidd, tvb, offset, length, ENC_NA); + break; + } + size -= length; + offset += length; + + } + + if (size > 0) { + + tvbuff_t *next_tvb = NULL; + gint tvb_len; + gboolean save_fragmented; + + tvb_len = tvb_captured_length_remaining(tvb, offset); + if (size < tvb_len) + tvb_len = size; + + /* If this is a retransmission, do not save the fragment. */ + if (is_duplicate_id) { + next_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_len, size); + call_data_dissector(next_tvb, pinfo, eap_tree); + break; + } + + /* + EAP/TLS is weird protocol (it comes from + Microsoft after all). + + If we have series of fragmented packets, + then there's no way of knowing that from + the packet itself, if it is the last packet + in series, that is that the packet part of + bigger fragmented set of data. + + The only way to know is, by knowing + that we are already in defragmentation + "mode" and we are expecing packet + carrying fragment of data. (either + because we have not received expected + amount of data, or because the packet before + had "F"ragment flag set.) + + The situation is alleviated by fact that it + is simple ack/nack protcol so there's no + place for out-of-order packets like it is + possible with IP. + + Anyway, point of this lengthy essay is that + we have to keep state information in the + conversation, so that we can put ourselves in + defragmenting mode and wait for the last packet, + and have to attach state to frames as well, so + that we can handle defragmentation after the + first pass through the capture. + */ + /* See if we have a remembered defragmentation EAP ID. */ + packet_state = (frame_state_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_eap, PROTO_DATA_EAP_FRAME_STATE | tls_group); + if (packet_state == NULL) { + /* + * We haven't - does this message require reassembly? + */ + if (!pinfo->fd->visited) { + /* + * This is the first time we've looked at this frame, + * so it wouldn't have any remembered information. + * + * Therefore, we check whether this conversation has + * a reassembly operation in progress, or whether + * this frame has the Fragment flag set. + */ + if (conversation_state->eap_tls_seq != -1) { + /* + * There's a reassembly in progress; the sequence number + * of the previous fragment is + * "conversation_state->eap_tls_seq", and the reassembly + * ID is "conversation_state->eap_reass_cookie". + * + * We must include this frame in the reassembly. + * We advance the sequence number, giving us the + * sequence number for this fragment. + */ + needs_reassembly = TRUE; + conversation_state->eap_tls_seq++; + + eap_reass_cookie = conversation_state->eap_reass_cookie; + eap_tls_seq = conversation_state->eap_tls_seq; + } else if (more_fragments && has_length) { + /* + * This message has the Fragment flag set, so it requires + * reassembly. It's the message containing the first + * fragment (if it's a later fragment, the sequence + * number in the conversation state would not be -1). + * + * If it doesn't include a length, however, we can't + * do reassembly (either the message is in error, as + * the first fragment *must* contain a length, or we + * didn't capture the first fragment, and this just + * happens to be the first fragment we saw), so we + * also check that we have a length; + */ + needs_reassembly = TRUE; + conversation_state->eap_reass_cookie = pinfo->num; + + /* + * Start the reassembly sequence number at 0. + */ + conversation_state->eap_tls_seq = 0; + + eap_tls_seq = conversation_state->eap_tls_seq; + eap_reass_cookie = conversation_state->eap_reass_cookie; + } + + if (needs_reassembly) { + /* + * This frame requires reassembly; remember the reassembly + * ID for subsequent accesses to it. + */ + packet_state = wmem_new(wmem_file_scope(), frame_state_t); + packet_state->info = eap_reass_cookie; + p_add_proto_data(wmem_file_scope(), pinfo, proto_eap, PROTO_DATA_EAP_FRAME_STATE | tls_group, packet_state); + } + } + } else { + /* + * This frame has a reassembly cookie associated with it, so + * it requires reassembly. We've already done the + * reassembly in the first pass, so "fragment_add_seq()" + * won't look at the sequence number; set it to 0. + * + * XXX - a frame isn't supposed to have more than one + * EAP message in it, but if it includes both an EAP-TLS + * message and a LEAP message, we might be mistakenly + * concluding it requires reassembly because the "info" + * field isn't -1. We could, I guess, pack both EAP-TLS + * ID and LEAP state into the structure, but that doesn't + * work if you have multiple EAP-TLS or LEAP messages in + * the frame. + * + * But it's not clear how much work we should do to handle + * a bogus message such as that; as long as we don't crash + * or do something else equally horrible, we may not + * have to worry about this at all. + */ + needs_reassembly = TRUE; + eap_reass_cookie = packet_state->info; + eap_tls_seq = 0; + } + + /* + We test here to see whether EAP-TLS packet + carry fragmented of TLS data. + + If this is the case, we do reasembly below, + otherwise we just call dissector. + */ + if (needs_reassembly) { + fragment_head *fd_head; + + /* + * Yes, this frame contains a fragment that requires + * reassembly. + */ + save_fragmented = pinfo->fragmented; + pinfo->fragmented = TRUE; + fd_head = fragment_add_seq(&eap_tls_reassembly_table, + tvb, offset, + pinfo, eap_reass_cookie, NULL, + eap_tls_seq, + size, + more_fragments, 0); + + if (fd_head != NULL) { + if (fd_head->reassembled_in == pinfo->num) { + /* Reassembled */ + proto_item* frag_tree_item; + + next_tvb = tvb_new_chain(tvb, fd_head->tvb_data); + add_new_data_source(pinfo, next_tvb, "Reassembled EAP-TLS"); + + show_fragment_seq_tree(fd_head, &eap_tls_frag_items, + eap_tree, pinfo, next_tvb, &frag_tree_item); + + /* + * We're finished reassembing this frame. + * Reinitialize the reassembly state. + */ + if (!pinfo->fd->visited) + conversation_state->eap_tls_seq = -1; + } else { + ti = proto_tree_add_uint(eap_tree, hf_eap_tls_reassembled_in, tvb, + 0, 0, fd_head->reassembled_in); + proto_item_set_generated(ti); + } + } + + pinfo->fragmented = save_fragmented; + + } else { /* this data is NOT fragmented */ + next_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_len, size); + } + + if (next_tvb) { + switch (eap_type) { + case EAP_TYPE_TTLS: + tls_set_appdata_dissector(tls_handle, pinfo, diameter_avps_handle); + break; + case EAP_TYPE_PEAP: + p_add_proto_data(pinfo->pool, pinfo, proto_eap, PROTO_DATA_EAP_TVB | tls_group, tvb); + tls_set_appdata_dissector(tls_handle, pinfo, peap_handle); + break; + case EAP_TYPE_TEAP: + if (outer_tlvs) { /* https://www.rfc-editor.org/rfc/rfc7170.html#section-4.1 */ + tvbuff_t *teap_tvb = tvb_new_subset_length(tvb, offset + size - outer_tlvs_length, outer_tlvs_length); + call_dissector(teap_handle, teap_tvb, pinfo, eap_tree); + if (size == outer_tlvs_length) goto skip_tls_dissector; + next_tvb = tvb_new_subset_length(next_tvb, 0, size - outer_tlvs_length); + } + tls_set_appdata_dissector(tls_handle, pinfo, teap_handle); + break; + } + call_dissector(tls_handle, next_tvb, pinfo, eap_tree); + } + } + } +skip_tls_dissector: + break; /* EAP_TYPE_TLS */ + + /********************************************************************* + Cisco's Lightweight EAP (LEAP) + https://web.archive.org/web/20070623090417if_/http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt + **********************************************************************/ + case EAP_TYPE_LEAP: + { + guint8 count, namesize; + + /* Warn that this is an insecure EAP type. */ + expert_add_info(pinfo, eap_type_item, &ei_eap_dictionary_attacks); + + /* Version (byte) */ + proto_tree_add_item(eap_tree, hf_eap_leap_version, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Unused (byte) */ + proto_tree_add_item(eap_tree, hf_eap_leap_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Count (byte) */ + count = tvb_get_guint8(tvb, offset); + proto_tree_add_item(eap_tree, hf_eap_leap_count, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Data (byte*Count) */ + /* This part is state-dependent. */ + + if (!conversation_state) { + // XXX expert info? LEAP is not expected within the EAP-Message within EAP-TTLS. + break; + } + /* XXX - are duplicates possible (is_duplicate_id)? + * If so, should we stop here to avoid modifying conversation_state? */ + + /* See if we've already remembered the state. */ + packet_state = (frame_state_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_eap, PROTO_DATA_EAP_FRAME_STATE | tls_group); + if (packet_state == NULL) { + /* + * We haven't - compute the state based on the current + * state in the conversation. + */ + leap_state = conversation_state->leap_state; + + /* Advance the state machine. */ + if (leap_state==0) leap_state = 1; else + if (leap_state==1) leap_state = 2; else + if (leap_state==2) leap_state = 3; else + if (leap_state==3) leap_state = 4; else + if (leap_state==4) leap_state = -1; + + /* + * Remember the state for subsequent accesses to this + * frame. + */ + packet_state = wmem_new(wmem_file_scope(), frame_state_t); + packet_state->info = leap_state; + p_add_proto_data(wmem_file_scope(), pinfo, proto_eap, PROTO_DATA_EAP_FRAME_STATE | tls_group, packet_state); + + /* + * Update the conversation's state. + */ + conversation_state->leap_state = leap_state; + } + + /* Get the remembered state. */ + leap_state = packet_state->info; + + switch (leap_state) { + case 1: + proto_tree_add_item(eap_tree, hf_eap_leap_peer_challenge, tvb, offset, count, ENC_NA); + break; + + case 2: + proto_tree_add_item(eap_tree, hf_eap_leap_peer_response, tvb, offset, count, ENC_NA); + break; + + case 3: + proto_tree_add_item(eap_tree, hf_eap_leap_ap_challenge, tvb, offset, count, ENC_NA); + break; + + case 4: + proto_tree_add_item(eap_tree, hf_eap_leap_ap_response, tvb, offset, count, ENC_NA); + break; + + default: + proto_tree_add_item(eap_tree, hf_eap_leap_data, tvb, offset, count, ENC_NA); + break; + } + + offset += count; + + /* Name (Length-(8+Count)) */ + namesize = eap_len - (8+count); + proto_tree_add_item(eap_tree, hf_eap_leap_name, tvb, offset, namesize, ENC_ASCII); + } + + break; /* EAP_TYPE_LEAP */ + + /********************************************************************* + EAP-MSCHAPv2 - draft-kamath-pppext-eap-mschapv2-00.txt + **********************************************************************/ + case EAP_TYPE_MSCHAPV2: + dissect_eap_mschapv2(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_MSCHAPV2 */ + + /********************************************************************* + EAP-SIM - draft-haverinen-pppext-eap-sim-13.txt + **********************************************************************/ + case EAP_TYPE_SIM: + dissect_eap_sim(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_SIM */ + + /********************************************************************* + EAP-AKA - draft-arkko-pppext-eap-aka-12.txt + **********************************************************************/ + case EAP_TYPE_AKA: + case EAP_TYPE_AKA_PRIME: + dissect_eap_aka(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_AKA */ + + /********************************************************************* + EAP Expanded Type + **********************************************************************/ + case EAP_TYPE_EXT: + { + proto_tree *exptree; + + exptree = proto_tree_add_subtree(eap_tree, tvb, offset, size, ett_eap_exp_attr, NULL, "Expanded Type"); + dissect_exteap(exptree, tvb, offset, size, pinfo, eap_code, eap_identifier); + } + break; + + /********************************************************************* + EAP-PAX - RFC 4746 + **********************************************************************/ + case EAP_TYPE_PAX: + dissect_eap_pax(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_PAX */ + + /********************************************************************* + EAP-PSK - RFC 4764 + **********************************************************************/ + case EAP_TYPE_PSK: + dissect_eap_psk(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_PSK */ + + /********************************************************************* + EAP-SAKE - RFC 4763 + **********************************************************************/ + case EAP_TYPE_SAKE: + dissect_eap_sake(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_SAKE */ + + /********************************************************************* + EAP-GPSK - RFC 5433 + **********************************************************************/ + case EAP_TYPE_GPSK: + dissect_eap_gpsk(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_GPSK */ + + /********************************************************************* + EAP-IKEv2 - RFC 5106 + **********************************************************************/ + case EAP_TYPE_IKEV2: + { + gboolean more_fragments; + gboolean has_length; + gboolean icv_present; + + /* Flags field, 1 byte */ + ti = proto_tree_add_item(eap_tree, hf_eap_ikev2_flags, tvb, offset, 1, ENC_BIG_ENDIAN); + eap_tls_flags_tree = proto_item_add_subtree(ti, hf_eap_ikev2_flags); + proto_tree_add_item_ret_boolean(eap_tls_flags_tree, hf_eap_ikev2_flag_l, tvb, offset, 1, ENC_BIG_ENDIAN, &has_length); + proto_tree_add_item_ret_boolean(eap_tls_flags_tree, hf_eap_ikev2_flag_m, tvb, offset, 1, ENC_BIG_ENDIAN, &more_fragments); + proto_tree_add_item_ret_boolean(eap_tls_flags_tree, hf_eap_ikev2_flag_i, tvb, offset, 1, ENC_BIG_ENDIAN, &icv_present); + + size -= 1; + offset += 1; + + /* Length field, 4 bytes, OPTIONAL. */ + if (has_length) { + proto_tree_add_item(eap_tree, hf_eap_ikev2_len, tvb, offset, 4, ENC_BIG_ENDIAN); + size -= 4; + offset += 4; + } + + if (size > 0) { + tvbuff_t* next_tvb = NULL; + gint tvb_len; + + tvb_len = tvb_captured_length_remaining(tvb, offset); + if (size < tvb_len) { + tvb_len = size; + } + + if (has_length || more_fragments) { + /* TODO: Add fragmentation support + * Length of integrity check data needs to be determined in case of fragmentation. Chosen INTEG transform? + */ + } else { + next_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_len, size); + guint tmp = call_dissector(isakmp_handle, next_tvb, pinfo, eap_tree); + size -= tmp; + offset += tmp; + + if (icv_present && size > 0) { + /* We assume that all data present is integrity check data. We cannot detect too short/long right now. */ + proto_tree_add_item(eap_tree, hf_eap_ikev2_int_chk_data, tvb, offset, size, ENC_NA); + } + } + } + + break; + } /* EAP_TYPE_IKEV2 */ + + /********************************************************************* + MS-Authentication-TLV - MS-PEAP section 2.2.8.1 + **********************************************************************/ + case EAP_TYPE_MSAUTH_TLV: + dissect_eap_msauth_tlv(eap_tree, tvb, pinfo, offset, size); + break; /* EAP_TYPE_MSAUTH_TLV */ + + /********************************************************************* + **********************************************************************/ + default: + proto_tree_add_item(eap_tree, hf_eap_data, tvb, offset, size, ENC_NA); + break; + /********************************************************************* + **********************************************************************/ + } /* switch (eap_type) */ + + } + + } /* switch (eap_code) */ + + return tvb_captured_length(tvb); +} + +void +proto_register_eap(void) +{ + static hf_register_info hf[] = { + { &hf_eap_code, { + "Code", "eap.code", + FT_UINT8, BASE_DEC, VALS(eap_code_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_identifier, { + "Id", "eap.id", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_len, { + "Length", "eap.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_type, { + "Type", "eap.type", + FT_UINT8, BASE_DEC|BASE_EXT_STRING, &eap_type_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_eap_type_nak, { + "Desired Auth Type", "eap.desired_type", + FT_UINT8, BASE_DEC|BASE_EXT_STRING, &eap_type_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_eap_identity, { + "Identity", "eap.identity", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_identity_prefix, { + "Identity Prefix", "eap.identity.prefix", + FT_CHAR, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_identity_type, { + "Identity Type", "eap.identity.type", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_identity_full, { + "Identity (Full)", "eap.identity.full", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_identity_certificate_sn, { + "Certificate Serial Number", "eap.identity.cert_sn", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_identity_mcc, { + "Identity Mobile Country Code", "eap.identity.mcc", + FT_UINT16, BASE_DEC|BASE_EXT_STRING, &E212_codes_ext, 0x0, NULL, HFILL }}, + + { &hf_eap_identity_mcc_mnc_2digits, { + "Identity Mobile Network Code", "eap.identity.mnc", + FT_UINT16, BASE_DEC|BASE_EXT_STRING, &mcc_mnc_2digits_codes_ext, 0x0, NULL, HFILL }}, + + { &hf_eap_identity_mcc_mnc_3digits, { + "Identity Mobile Network Code", "eap.identity.mnc", + FT_UINT16, BASE_DEC|BASE_EXT_STRING, &mcc_mnc_3digits_codes_ext, 0x0, NULL, HFILL }}, + + { &hf_eap_identity_padding, { + "Padding", "eap.identity.padding", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_identity_actual_len, { + "Identity Actual Length", "eap.identity.actual_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_notification, { + "Notification", "eap.notification", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_md5_value_size, { + "EAP-MD5 Value-Size", "eap.md5.value_size", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_md5_value, { + "EAP-MD5 Value", "eap.md5.value", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_md5_extra_data, { + "EAP-MD5 Extra Data", "eap.md5.extra_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_tls_flags, { + "EAP-TLS Flags", "eap.tls.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_tls_flag_l, { + "Length Included", "eap.tls.flags.len_included", + FT_BOOLEAN, 8, NULL, EAP_TLS_FLAG_L, + NULL, HFILL }}, + + { &hf_eap_tls_flag_m, { + "More Fragments", "eap.tls.flags.more_fragments", + FT_BOOLEAN, 8, NULL, EAP_TLS_FLAG_M, + NULL, HFILL }}, + + { &hf_eap_tls_flag_s, { + "Start", "eap.tls.flags.start", + FT_BOOLEAN, 8, NULL, EAP_TLS_FLAG_S, + NULL, HFILL }}, + + { &hf_eap_tls_flag_o, { + "Outer TLV Length Included", "eap.tls.flags.outer_tlv_len_included", + FT_BOOLEAN, 8, NULL, EAP_TLS_FLAG_O, + NULL, HFILL }}, + + { &hf_eap_tls_flags_version, { + "Version", "eap.tls.flags.version", + FT_UINT8, BASE_DEC, NULL, EAP_TLS_FLAGS_VERSION, + NULL, HFILL }}, + + { &hf_eap_tls_len, { + "EAP-TLS Length", "eap.tls.len", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_tls_outer_tlvs_len, { + "TEAP Outer TLVs Length", "eap.tls.outer_tlvs_len", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_tls_fragment, { + "EAP-TLS Fragment", "eap.tls.fragment", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_tls_fragments, { + "EAP-TLS Fragments", "eap.tls.fragments", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_tls_fragment_overlap, { + "Fragment Overlap", "eap.tls.fragment.overlap", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment overlaps with other fragments", HFILL }}, + + { &hf_eap_tls_fragment_overlap_conflict, { + "Conflicting Data In Fragment Overlap", "eap.tls.fragment.overlap_conflict", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Overlapping fragments contained conflicting data", HFILL }}, + + { &hf_eap_tls_fragment_multiple_tails, { + "Multiple Tail Fragments Found", "eap.tls.fragment.multiple_tails", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Several tails were found when defragmenting the packet", HFILL }}, + + { &hf_eap_tls_fragment_too_long_fragment,{ + "Fragment Too Long", "eap.tls.fragment.fragment.too_long", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment contained data past end of packet", HFILL }}, + + { &hf_eap_tls_fragment_error, { + "Defragmentation Error", "eap.tls.fragment.error", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "Defragmentation error due to illegal fragments", HFILL }}, + + { &hf_eap_tls_fragment_count, { + "Fragment Count", "eap.tls.fragment.count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_tls_reassembled_in, { + "Reassembled EAP-TLS PDU in frame", "eap.tls.reassembled_in", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "A PDU with a fragment from this frame is reassembled in this frame", HFILL } }, + + { &hf_eap_tls_reassembled_length, { + "Reassembled EAP-TLS Length", "eap.tls.reassembled.len", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Total length of the reassembled payload", HFILL }}, + + { &hf_eap_sim_subtype, { + "EAP-SIM Subtype", "eap.sim.subtype", + FT_UINT8, BASE_DEC, VALS(eap_sim_subtype_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_sim_reserved, { + "EAP-SIM Reserved", "eap.sim.reserved", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sim_subtype_attribute, { + "EAP-SIM Attribute", "eap.sim.subtype.attribute", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sim_subtype_type, { + "EAP-SIM Type", "eap.sim.subtype.type", + FT_UINT8, BASE_DEC|BASE_EXT_STRING, &eap_sim_aka_attribute_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_eap_sim_subtype_length, { + "EAP-SIM Length", "eap.sim.subtype.len", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sim_notification_type, { + "EAP-SIM Notification Type", "eap.sim.notification_type", + FT_UINT16, BASE_DEC, VALS(eap_sim_aka_notification_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_sim_error_code_type, { + "EAP-SIM Error Code", "eap.sim.error_code", + FT_UINT16, BASE_DEC, VALS(eap_sim_aka_client_error_codes), 0x0, + NULL, HFILL }}, + + { &hf_eap_sim_subtype_value, { + "EAP-SIM Value", "eap.sim.subtype.value", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_subtype, { + "EAP-AKA Subtype", "eap.aka.subtype", + FT_UINT8, BASE_DEC, VALS(eap_aka_subtype_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_reserved, { + "EAP-AKA Reserved", "eap.aka.reserved", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_subtype_attribute, { + "EAP-AKA Attribute", "eap.aka.subtype.attribute", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_subtype_type, { + "EAP-AKA Type", "eap.aka.subtype.type", + FT_UINT8, BASE_DEC|BASE_EXT_STRING, &eap_sim_aka_attribute_vals_ext, 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_subtype_length, { + "EAP-AKA Length", "eap.aka.subtype.len", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_notification_type, { + "EAP-AKA Notification Type", "eap.aka.notification_type", + FT_UINT16, BASE_DEC, VALS(eap_sim_aka_notification_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_error_code_type, { + "EAP-AKA Error Code", "eap.aka.error_code", + FT_UINT16, BASE_DEC, VALS(eap_sim_aka_client_error_codes), 0x0, + NULL, HFILL }}, + + { &hf_eap_aka_subtype_value, { + "EAP-AKA Value", "eap.aka.subtype.value", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_version, { + "EAP-LEAP Version", "eap.leap.version", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_reserved, { + "EAP-LEAP Reserved", "eap.leap.reserved", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_count, { + "EAP-LEAP Count", "eap.leap.count", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_peer_challenge, { + "EAP-LEAP Peer-Challenge", "eap.leap.peer_challenge", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_peer_response, { + "EAP-LEAP Peer-Response", "eap.leap.peer_response", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_ap_challenge, { + "EAP-LEAP AP-Challenge", "eap.leap.ap_challenge", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_ap_response, { + "EAP-LEAP AP-Response", "eap.leap.ap_response", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_data, { + "EAP-LEAP Data", "eap.leap.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_leap_name, { + "EAP-LEAP Name", "eap.leap.name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_opcode, { + "EAP-MS-CHAP-v2 OpCode", "eap.ms_chap_v2.opcode", + FT_UINT8, BASE_DEC, VALS(eap_ms_chap_v2_opcode_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_id, { + "EAP-MS-CHAP-v2 Id", "eap.ms_chap_v2.id", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_length, { + "EAP-MS-CHAP-v2 Length", "eap.ms_chap_v2.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_value_size, { + "EAP-MS-CHAP-v2 Value-Size", "eap.ms_chap_v2.value_size", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_challenge, { + "EAP-MS-CHAP-v2 Challenge", "eap.ms_chap_v2.challenge", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_name, { + "EAP-MS-CHAP-v2 Name", "eap.ms_chap_v2.name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_peer_challenge, { + "EAP-MS-CHAP-v2 Peer-Challenge", "eap.ms_chap_v2.peer_challenge", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_reserved, { + "EAP-MS-CHAP-v2 Reserved", "eap.ms_chap_v2.reserved", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_nt_response, { + "EAP-MS-CHAP-v2 NT-Response", "eap.ms_chap_v2.nt_response", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_flags, { + "EAP-MS-CHAP-v2 Flags", "eap.ms_chap_v2.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_response, { + "EAP-MS-CHAP-v2 Response (Unknown Length)", "eap.ms_chap_v2.response", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_message, { + "EAP-MS-CHAP-v2 Message", "eap.ms_chap_v2.message", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_failure_request, { + "EAP-MS-CHAP-v2 Failure-Request", "eap.ms_chap_v2.failure_request", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_ms_chap_v2_data, { + "EAP-MS-CHAP-v2 Data", "eap.ms_chap_v2.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_opcode, { + "EAP-PAX OP-Code", "eap.pax.opcode", + FT_UINT8, BASE_HEX, VALS(eap_pax_opcode_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_flags, { + "EAP-PAX Flags", "eap.pax.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_flags_mf, { + "more fragments", "eap.pax.flags.mf", + FT_BOOLEAN, 8, NULL, EAP_PAX_FLAG_MF, + NULL, HFILL }}, + + { &hf_eap_pax_flags_ce, { + "certificate enabled", "eap.pax.flags.ce", + FT_BOOLEAN, 8, NULL, EAP_PAX_FLAG_CE, + NULL, HFILL }}, + + { &hf_eap_pax_flags_ai, { + "ADE Included", "eap.pax.flags.ai", + FT_BOOLEAN, 8, NULL, EAP_PAX_FLAG_AI, + NULL, HFILL }}, + + { &hf_eap_pax_flags_reserved, { + "reserved", "eap.pax.flags.reserved", + FT_BOOLEAN, 8, NULL, EAP_PAX_FLAG_RESERVED, + NULL, HFILL }}, + + { &hf_eap_pax_mac_id, { + "EAP-PAX MAC ID", "eap.pax.mac_id", + FT_UINT8, BASE_HEX, VALS(eap_pax_mac_id_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_dh_group_id, { + "EAP-PAX DH Group ID", "eap.pax.dh_group_id", + FT_UINT8, BASE_HEX, VALS(eap_pax_dh_group_id_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_public_key_id, { + "EAP-PAX Public Key ID", "eap.pax.public_key_id", + FT_UINT8, BASE_HEX, VALS(eap_pax_public_key_id_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_a_len, { + "EAP-PAX A len", "eap.pax.a.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_a, { + "EAP-PAX A", "eap.pax.a", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_b_len, { + "EAP-PAX B len", "eap.pax.b.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_b, { + "EAP-PAX B", "eap.pax.b", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_cid_len, { + "EAP-PAX CID len", "eap.pax.cid.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_cid, { + "EAP-PAX CID", "eap.pax.cid", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_mac_ck_len, { + "EAP-PAX MAC_CK len", "eap.pax.mac_ck.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_mac_ck, { + "EAP-PAX MAC_CK", "eap.pax.mac_ck", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_ade_len, { + "EAP-PAX ADE len", "eap.pax.ade.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_ade, { + "EAP-PAX ADE", "eap.pax.ade", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_pax_mac_icv, { + "EAP-PAX ICV", "eap.pax.icv", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_flags, { + "EAP-PSK Flags", "eap.psk.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_flags_t, { + "T", "eap.psk.flags.t", + FT_UINT8, BASE_HEX, NULL, EAP_PSK_FLAGS_T_MASK, + NULL, HFILL }}, + + { &hf_eap_psk_flags_reserved, { + "Reserved", "eap.psk.flags.reserved", + FT_UINT8, BASE_HEX, NULL, 0x3F, + NULL, HFILL }}, + + { &hf_eap_psk_rand_p, { + "EAP-PSK RAND_P", "eap.psk.rand_p", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_rand_s, { + "EAP-PSK RAND_S", "eap.psk.rand_s", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_mac_p, { + "EAP-PSK MAC_P", "eap.psk.mac_p", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_mac_s, { + "EAP-PSK MAC_S", "eap.psk.mac_s", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_id_p, { + "EAP-PSK ID_P", "eap.psk.id_p", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_id_s, { + "EAP-PSK ID_S", "eap.psk.id_s", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_psk_pchannel, { + "EAP-PSK Protected Channel (encrypted)", "eap.psk.pchannel", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_version, { + "EAP-SAKE Version", "eap.sake.version", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_session_id, { + "EAP-SAKE Session ID", "eap.sake.session_id", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_subtype, { + "EAP-SAKE Subtype", "eap.sake.subtype", + FT_UINT8, BASE_HEX, VALS(eap_sake_subtype_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_attr_type, { + "Attribute Type", "eap.sake.attr.type", + FT_UINT8, BASE_HEX, VALS(eap_sake_attr_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_attr_len, { + "Attribute Length", "eap.sake.attr.len", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_attr_value, { + "Attribute Value", "eap.sake.attr.val", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_attr_value_str, { + "Attribute Value", "eap.sake.attr.val_str", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_sake_attr_value_uint48, { + "Attribute Value", "eap.sake.attr.val_uint48", + FT_UINT48, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_opcode, { + "EAP-GPSK OP-Code", "eap.gpsk.opcode", + FT_UINT8, BASE_HEX, VALS(eap_gpsk_opcode_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_id_server_len, { + "EAP-GPSK ID_Server len", "eap.gpsk.id_server.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_id_server, { + "EAP-GPSK ID_Server", "eap.gpsk.id_server", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_id_peer_len, { + "EAP-GPSK ID_Peer len", "eap.gpsk.id_peer.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_id_peer, { + "EAP-GPSK ID_Peer", "eap.gpsk.id_peer", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_rand_server, { + "EAP-GPSK Rand_Server", "eap.gpsk.rand_server", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_rand_peer, { + "EAP-GPSK Rand_Peer", "eap.gpsk.rand_peer", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_csuite_list_len, { + "Len", "eap.gpsk.csuite_list_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_csuite_vendor, { + "Vendor", "eap.gpsk.csuite.vendor", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_csuite_specifier, { + "Specifier", "eap.gpsk.csuite.specifier", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_pd_payload_len, { + "EAP-GPSK PD_Payload len", "eap.gpsk.pd_payload.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_pd_payload, { + "EAP-GPSK PD_Payload", "eap.gpsk.pd_payload", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_payload_mac, { + "EAP-GPSK Payload MAC", "eap.gpsk.payload_mac", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_gpsk_failure_code, { + "EAP-GPSK Failure code", "eap.gpsk.failure_code", + FT_UINT32, BASE_HEX, VALS(eap_gpsk_failure_code_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_data, { + "EAP Data", "eap.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_fast_type, { + "EAP-FAST Type", "eap.fast.type", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_fast_length, { + "EAP-FAST Length", "eap.fast.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_fast_aidd, { + "Authority ID Data", "eap.fast.authority_id_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_mandatory, { + "Mandatory", "eap.msauth-tlv.mandatory", + FT_BOOLEAN, 16, NULL, MSAUTH_TLV_MANDATORY, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_reserved, { + "Reserved", "eap.msauth-tlv.reserved", + FT_BOOLEAN, 16, NULL, MSAUTH_TLV_RESERVED, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_type, { + "Type", "eap.msauth-tlv.type", + FT_UINT16, BASE_DEC, VALS(eap_msauth_tlv_type_vals), MSAUTH_TLV_TYPE, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_len, { + "Length", "eap.msauth-tlv.len", + FT_UINT16, BASE_DEC, NULL, 0x00, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_val, { + "Value", "eap.msauth-tlv.val", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_status, { + "Status", "eap.msauth-tlv.status", + FT_UINT16, BASE_DEC, VALS(eap_msauth_tlv_status_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_crypto_reserved, { + "Reserved", "eap.msauth-tlv.crypto.reserved", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_crypto_version, { + "Version", "eap.msauth-tlv.crypto.version", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_crypto_rcv_version, { + "Received Version", "eap.msauth-tlv.crypto.received-version", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_crypto_subtype, { + "Subtype", "eap.msauth-tlv.crypto.subtype", + FT_UINT8, BASE_DEC, VALS(eap_msauth_tlv_crypto_subtype_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_crypto_nonce, { + "Nonce", "eap.msauth-tlv.crypto.nonce", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_eap_msauth_tlv_crypto_cmac, { + "Compound MAC", "eap.msauth-tlv.crypto.cmac", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + /* Expanded type fields */ + { &hf_eap_ext_vendor_id, { + "EAP-EXT Vendor Id", "eap.ext.vendor_id", + FT_UINT24, BASE_HEX, VALS(eap_ext_vendor_id_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_ext_vendor_type, { + "EAP-EXT Vendor Type", "eap.ext.vendor_type", + FT_UINT32, BASE_HEX, VALS(eap_ext_vendor_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_eap_ikev2_flags, { + "EAP-IKEv2 Flags", "eap.ikev2.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } }, + + { &hf_eap_ikev2_flag_l, { + "Length Included", "eap.ikve2.flags.len_included", + FT_BOOLEAN, 8, NULL, EAP_IKEV2_FLAG_L, + NULL, HFILL } }, + + { &hf_eap_ikev2_flag_m, { + "More Fragments", "eap.ikev2.flags.more_fragments", + FT_BOOLEAN, 8, NULL, EAP_IKEV2_FLAG_M, + NULL, HFILL } }, + + { &hf_eap_ikev2_flag_i, { + "Integrity Checksum Data present", "eap.ikev2.flags.icv_present", + FT_BOOLEAN, 8, NULL, EAP_IKEV2_FLAG_I, + NULL, HFILL } }, + + { &hf_eap_ikev2_len, { + "EAP-IKEv2 Length", "eap.ikev2.len", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } }, + + { &hf_eap_ikev2_int_chk_data, { + "EAP-IKEv2 Integrity Checksum Data", "eap.ikev2.integrity_checksum_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } }, + }; + static gint *ett[] = { + &ett_eap, + &ett_eap_pax_flags, + &ett_eap_psk_flags, + &ett_eap_gpsk_csuite_list, + &ett_eap_gpsk_csuite, + &ett_eap_gpsk_csuite_sel, + &ett_eap_sake_attr, + &ett_eap_msauth_tlv, + &ett_eap_msauth_tlv_tree, + &ett_eap_tls_fragment, + &ett_eap_tls_fragments, + &ett_eap_sim_attr, + &ett_eap_aka_attr, + &ett_eap_exp_attr, + &ett_eap_tls_flags, + &ett_identity, + &ett_eap_ikev2_flags, + }; + static ei_register_info ei[] = { + { &ei_eap_ms_chap_v2_length, { "eap.ms_chap_v2.length.invalid", PI_PROTOCOL, PI_WARN, "Invalid Length", EXPFILL }}, + { &ei_eap_mitm_attacks, { "eap.mitm_attacks", PI_SECURITY, PI_WARN, "Vulnerable to MITM attacks. If possible, change EAP type.", EXPFILL }}, + { &ei_eap_md5_value_size_overflow, { "eap.md5.value_size.overflow", PI_PROTOCOL, PI_WARN, "Overflow", EXPFILL }}, + { &ei_eap_dictionary_attacks, { "eap.dictionary_attacks", PI_SECURITY, PI_WARN, + "Vulnerable to dictionary attacks. If possible, change EAP type." + " See http://www.cisco.com/warp/public/cc/pd/witc/ao350ap/prodlit/2331_pp.pdf", EXPFILL }}, + { &ei_eap_identity_nonascii, { "eap.identity.nonascii", PI_PROTOCOL, PI_WARN, "Non-ASCII characters within identity", EXPFILL }}, + { &ei_eap_identity_invalid, { "eap.identity.invalid", PI_PROTOCOL, PI_WARN, "Invalid identity code", EXPFILL }}, + { &ei_eap_retransmission, { "eap.retransmission", PI_SEQUENCE, PI_NOTE, "This packet is a retransmission", EXPFILL }}, + { &ei_eap_bad_length, { "eap.bad_length", PI_PROTOCOL, PI_WARN, "Bad length (too small or too large)", EXPFILL }}, + }; + + expert_module_t* expert_eap; + + proto_eap = proto_register_protocol("Extensible Authentication Protocol", + "EAP", "eap"); + proto_register_field_array(proto_eap, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_eap = expert_register_protocol(proto_eap); + expert_register_field_array(expert_eap, ei, array_length(ei)); + + eap_handle = register_dissector("eap", dissect_eap, proto_eap); + + reassembly_table_register(&eap_tls_reassembly_table, + &addresses_reassembly_table_functions); + + eap_expanded_type_dissector_table = register_dissector_table("eap.ext.vendor_id", + "EAP-EXT Vendor Id", + proto_eap, FT_UINT24, + BASE_HEX); + +} + +void +proto_reg_handoff_eap(void) +{ + /* + * Get a handle for the SSL/TLS dissector. + */ + tls_handle = find_dissector_add_dependency("tls", proto_eap); + diameter_avps_handle = find_dissector_add_dependency("diameter_avps", proto_eap); + peap_handle = find_dissector_add_dependency("peap", proto_eap); + teap_handle = find_dissector_add_dependency("teap", proto_eap); + + isakmp_handle = find_dissector_add_dependency("isakmp", proto_eap); + + dissector_add_uint("ppp.protocol", PPP_EAP, eap_handle); + dissector_add_uint("eapol.type", EAPOL_EAP, eap_handle); +} +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */ |