]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wlantest: Parse EAPOL-Key frames
authorJouni Malinen <j@w1.fi>
Sat, 6 Nov 2010 19:49:57 +0000 (21:49 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 7 Nov 2010 21:29:01 +0000 (23:29 +0200)
wlantest/rx_data.c

index e6b1d61fc152f9e69a52dc93a0d1aa98577e5427..f67498200824e26c14b2d712bda856807c70d75f 100644 (file)
@@ -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="