From 571d66fe4222578d8191a0eb61e197b5cc6fc35e Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Thu, 15 Aug 2019 12:52:15 -0500 Subject: [PATCH] monitor: Dump PAE frames from CONTROL_PORT_FRAME events --- monitor/nlmon.c | 564 +++++++++++++++++++++++++----------------------- 1 file changed, 299 insertions(+), 265 deletions(-) diff --git a/monitor/nlmon.c b/monitor/nlmon.c index 1845f569..b25a0ce7 100644 --- a/monitor/nlmon.c +++ b/monitor/nlmon.c @@ -4500,6 +4500,297 @@ static void print_wiphy_bands(unsigned int level, const char *label, } } +static void print_eapol_key(unsigned int level, const void *data, uint32_t size) +{ + const struct eapol_key *ek = (struct eapol_key *)data; + size_t mic_lengths[] = { 16, 24, 32 }; + size_t mic_len = 0; + int i; + + /* + * The MIC length is not encoded anywhere in the frame, and should be + * determined by AKM. To even further complicate things, some non + * 802.11 AKMs define their own MIC lengths. But since the only valid + * lengths are 16, 24 and 32 its trivial to try each until we find a + * matching length. + */ + for (i = 0; i < 3; i++) { + size_t mlen = mic_lengths[i]; + + if (size < EAPOL_FRAME_LEN(mlen)) + break; + + if (size == EAPOL_FRAME_LEN(mlen) + + EAPOL_KEY_DATA_LEN(ek, mlen)) { + mic_len = mlen; + break; + } + } + + /* could not determine MIC length, malformed packet? */ + if (!mic_len) + return; + + ek = eapol_key_validate(data, size, mic_len); + if (!ek) + return; + + print_attr(level, "Descriptor Type: %u", ek->descriptor_type); + print_attr(level, "Key MIC: %s", ek->key_mic ? "true" : "false"); + print_attr(level, "Secure: %s", ek->secure ? "true" : "false"); + print_attr(level, "Error: %s", ek->error ? "true" : "false"); + print_attr(level, "Request: %s", ek->request ? "true" : "false"); + print_attr(level, "Encrypted Key Data: %s", + ek->encrypted_key_data ? "true" : "false"); + print_attr(level, "SMK Message: %s", + ek->smk_message ? "true" : "false"); + print_attr(level, "Key Descriptor Version: %d (%02x)", + ek->key_descriptor_version, + ek->key_descriptor_version); + print_attr(level, "Key Type: %s", ek->key_type ? "true" : "false"); + + if (ek->descriptor_type == EAPOL_DESCRIPTOR_TYPE_WPA) + print_attr(level, "Key Id: %u", ek->wpa_key_id); + + print_attr(level, "Install: %s", ek->install ? "true" : "false"); + print_attr(level, "Key ACK: %s", ek->key_ack ? "true" : "false"); + print_attr(level, "Key Length: %d", L_BE16_TO_CPU(ek->key_length)); + print_attr(level, "Key Replay Counter: %" PRIu64, + L_BE64_TO_CPU(ek->key_replay_counter)); + print_attr(level, "Key NONCE"); + print_hexdump(level + 1, ek->key_nonce, 32); + print_attr(level, "Key IV"); + print_hexdump(level + 1, ek->eapol_key_iv, 16); + print_attr(level, "Key RSC "); + print_hexdump(level + 1, ek->key_rsc, 8); + + print_attr(level, "Key MIC Data"); + + print_hexdump(level + 1, EAPOL_KEY_MIC(ek), mic_len); + + if (ek->encrypted_key_data) { + print_attr(level, "Key Data: len %d", + EAPOL_KEY_DATA_LEN(ek, mic_len)); + print_hexdump(level + 1, EAPOL_KEY_DATA(ek, mic_len), + EAPOL_KEY_DATA_LEN(ek, mic_len)); + return; + } + + print_ie(level, "Key Data", EAPOL_KEY_DATA(ek, mic_len), + EAPOL_KEY_DATA_LEN(ek, mic_len)); +} + +static void print_eap_wsc(unsigned int level, + const uint8_t *eap_wsc, uint32_t size) +{ + const char *str; + + if (size < 2) + return; + + switch (eap_wsc[0]) { + case 0x01: + str = "WSC-Start"; + break; + case 0x02: + str = "WSC-Ack"; + break; + case 0x03: + str = "WSC-Nack"; + break; + case 0x04: + str = "WSC-Msg"; + break; + case 0x05: + str = "WSC-Done"; + break; + case 0x06: + str = "WSC-Frag-Ack"; + break; + default: + str = "Reserved"; + break; + } + + print_attr(level, "Op-Code: %u (%s)", eap_wsc[0], str); + print_attr(level, "Flags: %02x", eap_wsc[1]); + + if (eap_wsc[1] == 0) + print_wsc_attributes(level + 1, "EAP-WSC Payload", + eap_wsc + 2, size - 2); +} + +static void print_eap(unsigned int level, const void *data, uint32_t size) +{ + static const uint8_t wfa_smi[3] = { 0x00, 0x37, 0x2a }; + const uint8_t *eap = data; + const char *str; + + if (size < 5) + return; + + switch (eap[0]) { + case 0x01: + str = "Request"; + break; + case 0x02: + str = "Response"; + break; + case 0x03: + str = "Success"; + break; + case 0x04: + str = "Failure"; + break; + default: + str = "Reserved"; + break; + }; + + print_attr(level, "Code: %u (%s)", eap[0], str); + print_attr(level, "Identifier: %u", eap[1]); + print_attr(level, "Length: %u", l_get_be16(eap + 2)); + + switch (eap[4]) { + case 1: + str = "Identity"; + break; + case 2: + str = "Notification"; + break; + case 3: + str = "Nak"; + break; + case 4: + str = "MD5 Challenge"; + break; + case 13: + str = "TLS EAP"; + break; + case 21: + str = "TTLS"; + break; + case 254: + str = "Expanded"; + break; + default: + str = "Reserved"; + break; + } + + print_attr(level, "Type: %u (%s)", eap[4], str); + + if (eap[4] == 254) { + if (size < 12) + return; + + if (memcmp(eap + 5, wfa_smi, 3)) + return; + + if (l_get_be32(eap + 8) == 1) + print_eap_wsc(level, eap + 12, size - 12); + } +} + +static void print_eapol(unsigned int level, const char *label, + const void *data, uint16_t size) +{ + const struct eapol_header *eh; + const char *str; + + print_attr(level, "%s: len %u", label, size); + + if (size < 4) + return; + + eh = data; + + switch (eh->protocol_version) { + case 0x01: + str = "802.1X-2001"; + break; + case 0x02: + str = "802.1X-2004"; + break; + case 0x03: + str = "802.1X-2010"; + break; + default: + str = "Reserved"; + break; + } + + print_attr(level + 1, "Protocol Version: %u (%s)", + eh->protocol_version, str); + + switch (eh->packet_type) { + case 0x00: + str = "EAP"; + break; + case 0x01: + str = "Start"; + break; + case 0x02: + str = "Logoff"; + break; + case 0x03: + str = "Key"; + break; + case 0x04: + str = "Encapsulated-ASF-Alert"; + break; + case 0x05: + str = "MKA"; + break; + case 0x06: + str = "Announcement (Generic)"; + break; + case 0x07: + str = "Announcement (Specific)"; + break; + case 0x08: + str = "Announcement-Req"; + break; + default: + str = "Reserved"; + break; + } + + print_attr(level + 1, "Type: %u (%s)", eh->packet_type, str); + print_attr(level + 1, "Length: %d", L_BE16_TO_CPU(eh->packet_len)); + + switch (eh->packet_type) { + case 0x03: + print_eapol_key(level + 1, data, size); + break; + case 0x00: + print_eap(level + 1, data + 4, size - 4); + } + + print_hexdump(level + 1, data, size); +} + +/* + * Control Port sends a EAPoL frame inside ATTR_FRAME and not a management + * frame. So a separate table with all the possible attributes is provided + */ +static const struct attr_entry control_port_attr_table[] = { + { NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + "Control Port Ethertype", ATTR_FLAG_OR_U16 }, + { NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + "Control Port No Encrypt", ATTR_FLAG }, + { NL80211_ATTR_MAC, + "MAC Address", ATTR_ADDRESS }, + { NL80211_ATTR_FRAME, + "Frame", ATTR_CUSTOM, { .function = print_eapol } }, + { NL80211_ATTR_WDEV, + "Wireless Device", ATTR_U64 }, + { NL80211_ATTR_IFINDEX, + "Interface Index", ATTR_U32 }, + { NL80211_ATTR_WIPHY, + "Wiphy", ATTR_U32 }, +}; + static const struct attr_entry attr_table[] = { { NL80211_ATTR_WIPHY, "Wiphy", ATTR_U32 }, @@ -4721,10 +5012,6 @@ static const struct attr_entry attr_table[] = { { NL80211_ATTR_FRAME_TYPE, "Frame Type", ATTR_CUSTOM, { .function = print_frame_type } }, - { NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - "Control Port Ethertype", ATTR_FLAG_OR_U16 }, - { NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, - "Control Port No Encrypt", ATTR_FLAG }, { NL80211_ATTR_SUPPORT_IBSS_RSN, "Support IBSS RSN", ATTR_FLAG }, { NL80211_ATTR_WIPHY_ANTENNA_TX, @@ -5214,85 +5501,6 @@ static void print_attributes(int indent, const struct attr_entry *table, } } -static void print_eapol_key(const void *data, uint32_t size) -{ - const struct eapol_key *ek = (struct eapol_key *)data; - size_t mic_lengths[] = { 16, 24, 32 }; - size_t mic_len = 0; - int i; - - /* - * The MIC length is not encoded anywhere in the frame, and should be - * determined by AKM. To even further complicate things, some non - * 802.11 AKMs define their own MIC lengths. But since the only valid - * lengths are 16, 24 and 32 its trivial to try each until we find a - * matching length. - */ - for (i = 0; i < 3; i++) { - size_t mlen = mic_lengths[i]; - - if (size < EAPOL_FRAME_LEN(mlen)) - break; - - if (size == EAPOL_FRAME_LEN(mlen) + - EAPOL_KEY_DATA_LEN(ek, mlen)) { - mic_len = mlen; - break; - } - } - - /* could not determine MIC length, malformed packet? */ - if (!mic_len) - return; - - ek = eapol_key_validate(data, size, mic_len); - if (!ek) - return; - - print_attr(1, "Descriptor Type: %u", ek->descriptor_type); - print_attr(1, "Key MIC: %s", ek->key_mic ? "true" : "false"); - print_attr(1, "Secure: %s", ek->secure ? "true" : "false"); - print_attr(1, "Error: %s", ek->error ? "true" : "false"); - print_attr(1, "Request: %s", ek->request ? "true" : "false"); - print_attr(1, "Encrypted Key Data: %s", - ek->encrypted_key_data ? "true" : "false"); - print_attr(1, "SMK Message: %s", ek->smk_message ? "true" : "false"); - print_attr(1, "Key Descriptor Version: %d (%02x)", - ek->key_descriptor_version, - ek->key_descriptor_version); - print_attr(1, "Key Type: %s", ek->key_type ? "true" : "false"); - - if (ek->descriptor_type == EAPOL_DESCRIPTOR_TYPE_WPA) - print_attr(1, "Key Id: %u", ek->wpa_key_id); - - print_attr(1, "Install: %s", ek->install ? "true" : "false"); - print_attr(1, "Key ACK: %s", ek->key_ack ? "true" : "false"); - print_attr(1, "Key Length: %d", L_BE16_TO_CPU(ek->key_length)); - print_attr(1, "Key Replay Counter: %" PRIu64, - L_BE64_TO_CPU(ek->key_replay_counter)); - print_attr(1, "Key NONCE"); - print_hexdump(2, ek->key_nonce, 32); - print_attr(1, "Key IV"); - print_hexdump(2, ek->eapol_key_iv, 16); - print_attr(1, "Key RSC "); - print_hexdump(2, ek->key_rsc, 8); - - print_attr(1, "Key MIC Data"); - - print_hexdump(2, EAPOL_KEY_MIC(ek), mic_len); - - if (ek->encrypted_key_data) { - print_attr(1, "Key Data: len %d", - EAPOL_KEY_DATA_LEN(ek, mic_len)); - print_hexdump(2, EAPOL_KEY_DATA(ek, mic_len), - EAPOL_KEY_DATA_LEN(ek, mic_len)); - return; - } - - print_ie(1, "Key Data", EAPOL_KEY_DATA(ek, mic_len), - EAPOL_KEY_DATA_LEN(ek, mic_len)); -} - static void netlink_str(char *str, size_t size, uint16_t type, uint16_t flags, uint32_t len) { @@ -5441,7 +5649,13 @@ static void print_message(struct nlmon *nlmon, const struct timeval *tv, case MSG_REQUEST: case MSG_RESULT: case MSG_EVENT: - print_attributes(0, attr_table, data, len); + switch (cmd) { + case NL80211_CMD_CONTROL_PORT_FRAME: + print_attributes(0, control_port_attr_table, data, len); + break; + default: + print_attributes(0, attr_table, data, len); + } break; case MSG_RESPONSE: print_field("Status: %s (%d)", strerror(status), status); @@ -6505,124 +6719,11 @@ static struct l_io *open_packet(const char *name) return io; } -static void print_eap_wsc(const uint8_t *eap_wsc, uint32_t size) -{ - const char *str; - - if (size < 2) - return; - - switch (eap_wsc[0]) { - case 0x01: - str = "WSC-Start"; - break; - case 0x02: - str = "WSC-Ack"; - break; - case 0x03: - str = "WSC-Nack"; - break; - case 0x04: - str = "WSC-Msg"; - break; - case 0x05: - str = "WSC-Done"; - break; - case 0x06: - str = "WSC-Frag-Ack"; - break; - default: - str = "Reserved"; - break; - } - - print_attr(1, "Op-Code: %u (%s)", eap_wsc[0], str); - print_attr(1, "Flags: %02x", eap_wsc[1]); - - if (eap_wsc[1] == 0) - print_wsc_attributes(2, "EAP-WSC Payload", - eap_wsc + 2, size - 2); -} - -static void print_eap(const void *data, uint32_t size) -{ - static const uint8_t wfa_smi[3] = { 0x00, 0x37, 0x2a }; - const uint8_t *eap = data; - const char *str; - - if (size < 5) - return; - - switch (eap[0]) { - case 0x01: - str = "Request"; - break; - case 0x02: - str = "Response"; - break; - case 0x03: - str = "Success"; - break; - case 0x04: - str = "Failure"; - break; - default: - str = "Reserved"; - break; - }; - - print_attr(1, "Code: %u (%s)", eap[0], str); - print_attr(1, "Identifier: %u", eap[1]); - print_attr(1, "Length: %u", l_get_be16(eap + 2)); - - switch (eap[4]) { - case 1: - str = "Identity"; - break; - case 2: - str = "Notification"; - break; - case 3: - str = "Nak"; - break; - case 4: - str = "MD5 Challenge"; - break; - case 13: - str = "TLS EAP"; - break; - case 21: - str = "TTLS"; - break; - case 254: - str = "Expanded"; - break; - default: - str = "Reserved"; - break; - } - - print_attr(1, "Type: %u (%s)", eap[4], str); - - if (eap[4] == 254) { - if (size < 12) - return; - - if (memcmp(eap + 5, wfa_smi, 3)) - return; - - if (l_get_be32(eap + 8) == 1) - print_eap_wsc(eap + 12, size - 12); - } -} - void nlmon_print_pae(struct nlmon *nlmon, const struct timeval *tv, uint8_t type, int index, const void *data, uint32_t size) { char extra_str[16]; - const char *str; - const struct eapol_header *eh; update_time_offset(tv); @@ -6633,74 +6734,7 @@ void nlmon_print_pae(struct nlmon *nlmon, const struct timeval *tv, if (index >= 0) print_attr(0, "Interface Index: %u", index); - if (size < 4) - return; - - print_attr(0, "EAPoL: len %u", size); - print_hexdump(0, data, size); - - eh = data; - - switch (eh->protocol_version) { - case 0x01: - str = "802.1X-2001"; - break; - case 0x02: - str = "802.1X-2004"; - break; - case 0x03: - str = "802.1X-2010"; - break; - default: - str = "Reserved"; - break; - } - - print_attr(1, "Protocol Version: %u (%s)", eh->protocol_version, str); - - switch (eh->packet_type) { - case 0x00: - str = "EAP"; - break; - case 0x01: - str = "Start"; - break; - case 0x02: - str = "Logoff"; - break; - case 0x03: - str = "Key"; - break; - case 0x04: - str = "Encapsulated-ASF-Alert"; - break; - case 0x05: - str = "MKA"; - break; - case 0x06: - str = "Announcement (Generic)"; - break; - case 0x07: - str = "Announcement (Specific)"; - break; - case 0x08: - str = "Announcement-Req"; - break; - default: - str = "Reserved"; - break; - } - - print_attr(1, "Type: %u (%s)", eh->packet_type, str); - print_attr(1, "Length: %d", L_BE16_TO_CPU(eh->packet_len)); - - switch (eh->packet_type) { - case 0x03: - print_eapol_key(data, size); - break; - case 0x00: - print_eap(data + 4, size - 4); - } + print_eapol(0, "EAPoL", data, size); } static bool pae_receive(struct l_io *io, void *user_data)