Browse Source

wlantest: Parse EAPOL-Key frames

Jouni Malinen 14 years ago
parent
commit
32234bba52
1 changed files with 300 additions and 1 deletions
  1. 300 1
      wlantest/rx_data.c

+ 300 - 1
wlantest/rx_data.c

@@ -16,6 +16,8 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/eapol_common.h"
+#include "common/wpa_common.h"
 #include "wlantest.h"
 
 
@@ -57,16 +59,309 @@ static const char * data_stype(u16 stype)
 }
 
 
+static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst,
+				     const u8 *src, const u8 *data, size_t len)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL-Key 1/4 " MACSTR " -> " MACSTR,
+		   MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
+				     const u8 *src, const u8 *data, size_t len)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL-Key 2/4 " MACSTR " -> " MACSTR,
+		   MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
+				     const u8 *src, const u8 *data, size_t len)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL-Key 3/4 " MACSTR " -> " MACSTR,
+		   MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst,
+				     const u8 *src, const u8 *data, size_t len)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
+		   MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
+				     const u8 *src, const u8 *data, size_t len)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR,
+		   MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_2_of_2(struct wlantest *wt, const u8 *dst,
+				     const u8 *src, const u8 *data, size_t len)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL-Key 2/2 " MACSTR " -> " MACSTR,
+		   MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst,
+			      const u8 *src, const u8 *data, size_t len,
+			      int prot)
+{
+	const struct wpa_eapol_key *hdr;
+	u16 key_info, key_length, ver, key_data_length;
+
+	wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key", data, len);
+	if (len < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "Too short EAPOL-Key frame from " MACSTR,
+			   MAC2STR(src));
+		return;
+	}
+	hdr = (const struct wpa_eapol_key *) data;
+
+	if (hdr->type == EAPOL_KEY_TYPE_RC4) {
+		/* TODO: EAPOL-Key RC4 for WEP */
+		return;
+	}
+
+	if (hdr->type != EAPOL_KEY_TYPE_RSN &&
+	    hdr->type != EAPOL_KEY_TYPE_WPA) {
+		wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key type %u",
+			   hdr->type);
+		return;
+	}
+
+	key_info = WPA_GET_BE16(hdr->key_info);
+	key_length = WPA_GET_BE16(hdr->key_length);
+	key_data_length = WPA_GET_BE16(hdr->key_data_length);
+	ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+	wpa_printf(MSG_DEBUG, "EAPOL-Key ver=%u %c idx=%u%s%s%s%s%s%s%s%s "
+		   "datalen=%u",
+		   ver, key_info & WPA_KEY_INFO_KEY_TYPE ? 'P' : 'G',
+		   (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+		   WPA_KEY_INFO_KEY_INDEX_SHIFT,
+		   (key_info & WPA_KEY_INFO_INSTALL) ? " Install" : "",
+		   (key_info & WPA_KEY_INFO_ACK) ? " ACK" : "",
+		   (key_info & WPA_KEY_INFO_MIC) ? " MIC" : "",
+		   (key_info & WPA_KEY_INFO_SECURE) ? " Secure" : "",
+		   (key_info & WPA_KEY_INFO_ERROR) ? " Error" : "",
+		   (key_info & WPA_KEY_INFO_REQUEST) ? " Request" : "",
+		   (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) ? " Encr" : "",
+		   (key_info & WPA_KEY_INFO_SMK_MESSAGE) ? " SMK" : "",
+		   key_data_length);
+
+	if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+	    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+		wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key Key Descriptor "
+			   "Version %u", ver);
+		return;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Replay Counter",
+		    hdr->replay_counter, WPA_REPLAY_COUNTER_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Nonce",
+		    hdr->key_nonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key IV",
+		    hdr->key_iv, 16);
+	wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key RSC",
+		    hdr->key_nonce, WPA_KEY_RSC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key MIC",
+		    hdr->key_mic, 16);
+
+	if (key_info & (WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST))
+		return;
+
+	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+		return;
+
+	if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+		/* 4-Way Handshake */
+		switch (key_info & (WPA_KEY_INFO_SECURE |
+				    WPA_KEY_INFO_MIC |
+				    WPA_KEY_INFO_ACK |
+				    WPA_KEY_INFO_INSTALL)) {
+		case WPA_KEY_INFO_ACK:
+			rx_data_eapol_key_1_of_4(wt, dst, src, data, len);
+			break;
+		case WPA_KEY_INFO_MIC:
+			rx_data_eapol_key_2_of_4(wt, dst, src, data, len);
+			break;
+		case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL:
+			rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
+			break;
+		case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+			rx_data_eapol_key_4_of_4(wt, dst, src, data, len);
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
+			break;
+		}
+	} else {
+		/* Group Key Handshake */
+		switch (key_info & (WPA_KEY_INFO_SECURE |
+				    WPA_KEY_INFO_MIC |
+				    WPA_KEY_INFO_ACK)) {
+		case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			WPA_KEY_INFO_ACK:
+			rx_data_eapol_key_1_of_2(wt, dst, src, data, len);
+			break;
+		case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+			rx_data_eapol_key_2_of_2(wt, dst, src, data, len);
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
+			break;
+		}
+	}
+}
+
+
+static void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src,
+			  const u8 *data, size_t len, int prot)
+{
+	const struct ieee802_1x_hdr *hdr;
+	u16 length;
+	const u8 *p;
+
+	wpa_hexdump(MSG_EXCESSIVE, "EAPOL", data, len);
+	if (len < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "Too short EAPOL frame from " MACSTR,
+			   MAC2STR(src));
+		return;
+	}
+
+	hdr = (const struct ieee802_1x_hdr *) data;
+	length = be_to_host16(hdr->length);
+	wpa_printf(MSG_DEBUG, "RX EAPOL: " MACSTR " -> " MACSTR "%s ver=%u "
+		   "type=%u len=%u",
+		   MAC2STR(src), MAC2STR(dst), prot ? " Prot" : "",
+		   hdr->version, hdr->type, length);
+	if (sizeof(*hdr) + length > len) {
+		wpa_printf(MSG_INFO, "Truncated EAPOL frame from " MACSTR,
+			   MAC2STR(src));
+		return;
+	}
+
+	if (sizeof(*hdr) + length < len) {
+		wpa_printf(MSG_INFO, "EAPOL frame with %d extra bytes",
+			   (int) (len - sizeof(*hdr) - length));
+	}
+	p = (const u8 *) (hdr + 1);
+
+	switch (hdr->type) {
+	case IEEE802_1X_TYPE_EAP_PACKET:
+		wpa_hexdump(MSG_MSGDUMP, "EAPOL - EAP packet", p, length);
+		break;
+	case IEEE802_1X_TYPE_EAPOL_START:
+		wpa_hexdump(MSG_MSGDUMP, "EAPOL-Start", p, length);
+		break;
+	case IEEE802_1X_TYPE_EAPOL_LOGOFF:
+		wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length);
+		break;
+	case IEEE802_1X_TYPE_EAPOL_KEY:
+		rx_data_eapol_key(wt, dst, src, p, length, prot);
+		break;
+	case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
+		wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert",
+			    p, length);
+		break;
+	default:
+		wpa_hexdump(MSG_MSGDUMP, "Unknown EAPOL payload", p, length);
+		break;
+	}
+}
+
+
+static void rx_data_eth(struct wlantest *wt, const u8 *dst, const u8 *src,
+			u16 ethertype, const u8 *data, size_t len, int prot)
+{
+	if (ethertype == ETH_P_PAE)
+		rx_data_eapol(wt, dst, src, data, len, prot);
+}
+
+
+static void rx_data_process(struct wlantest *wt, const u8 *dst, const u8 *src,
+			    const u8 *data, size_t len, int prot)
+{
+	if (len >= 8 && os_memcmp(data, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) {
+		rx_data_eth(wt, dst, src, WPA_GET_BE16(data + 6),
+			    data + 8, len - 8, prot);
+		return;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? len : 7);
+}
+
+
+static void rx_data_bss_prot(struct wlantest *wt,
+			     const struct ieee80211_hdr *hdr, const u8 *qos,
+			     const u8 *dst, const u8 *src, const u8 *data,
+			     size_t len)
+{
+	/* TODO: Try to decrypt and if success, call rx_data_process() with
+	 * prot = 1 */
+}
+
+
+static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr,
+			const u8 *qos, const u8 *dst, const u8 *src,
+			const u8 *data, size_t len)
+{
+	u16 fc = le_to_host16(hdr->frame_control);
+	int prot = !!(fc & WLAN_FC_ISWEP);
+
+	if (qos) {
+		u8 ack = (qos[0] & 0x60) >> 5;
+		wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
+			   " len=%u%s tid=%u%s%s",
+			   MAC2STR(src), MAC2STR(dst), (unsigned int) len,
+			   prot ? " Prot" : "", qos[0] & 0x0f,
+			   (qos[0] & 0x10) ? " EOSP" : "",
+			   ack == 0 ? "" :
+			   (ack == 1 ? " NoAck" :
+			    (ack == 2 ? " NoExpAck" : " BA")));
+	} else {
+		wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
+			   " len=%u%s",
+			   MAC2STR(src), MAC2STR(dst), (unsigned int) len,
+			   prot ? " Prot" : "");
+	}
+
+	if (prot)
+		rx_data_bss_prot(wt, hdr, qos, dst, src, data, len);
+	else
+		rx_data_process(wt, dst, src, data, len, 0);
+}
+
+
 void rx_data(struct wlantest *wt, const u8 *data, size_t len)
 {
 	const struct ieee80211_hdr *hdr;
-	u16 fc;
+	u16 fc, stype;
+	size_t hdrlen;
+	const u8 *qos = NULL;
 
 	if (len < 24)
 		return;
 
 	hdr = (const struct ieee80211_hdr *) data;
 	fc = le_to_host16(hdr->frame_control);
+	stype = WLAN_FC_GET_STYPE(fc);
+	hdrlen = 24;
+	if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
+	    (WLAN_FC_TODS | WLAN_FC_FROMDS))
+		hdrlen += ETH_ALEN;
+	if (stype & 0x08) {
+		qos = data + hdrlen;
+		hdrlen += 2;
+	}
+	if (len < hdrlen)
+		return;
 	wt->rx_data++;
 
 	switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
@@ -87,6 +382,8 @@ void rx_data(struct wlantest *wt, const u8 *data, size_t len)
 			   fc & WLAN_FC_ISWEP ? " Prot" : "",
 			   MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
 			   MAC2STR(hdr->addr3));
+		rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2,
+			    data + hdrlen, len - hdrlen);
 		break;
 	case WLAN_FC_TODS:
 		wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR
@@ -96,6 +393,8 @@ void rx_data(struct wlantest *wt, const u8 *data, size_t len)
 			   fc & WLAN_FC_ISWEP ? " Prot" : "",
 			   MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
 			   MAC2STR(hdr->addr3));
+		rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2,
+			    data + hdrlen, len - hdrlen);
 		break;
 	case WLAN_FC_TODS | WLAN_FC_FROMDS:
 		wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA="