/* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2003-2004, Jouni Malinen * Sun elects to license this software under the BSD license. * See README for more details. */ #include #include #include #include #include #include #include #include #include "wpa_impl.h" #include "wpa_enc.h" #include "driver.h" #include "eloop.h" #include "l2_packet.h" static void pmksa_cache_set_expiration(struct wpa_supplicant *); /* * IEEE 802.11i/D3.0 */ static const int WPA_SELECTOR_LEN = 4; static const uint8_t WPA_OUI_AND_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; static const uint8_t WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 }; static const uint8_t WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 }; static const uint8_t WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 }; static const uint8_t WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 }; static const uint8_t WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 }; static const uint8_t WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 }; static const uint8_t WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 }; /* * WPA IE version 1 * 00-50-f2:1 (OUI:OUI type) * 0x01 0x00 (version; little endian) * (all following fields are optional:) * Group Suite Selector (4 octets) (default: TKIP) * Pairwise Suite Count (2 octets, little endian) (default: 1) * Pairwise Suite List (4 * n octets) (default: TKIP) * Authenticated Key Management Suite Count (2 octets, little endian) * (default: 1) * Authenticated Key Management Suite List (4 * n octets) * (default: unspec 802.1x) * WPA Capabilities (2 octets, little endian) (default: 0) */ #pragma pack(1) struct wpa_ie_hdr { uint8_t elem_id; uint8_t len; uint8_t oui[3]; uint8_t oui_type; uint16_t version; }; #pragma pack() /* * IEEE 802.11i/D9.0 */ static const int RSN_SELECTOR_LEN = 4; static const uint16_t RSN_VERSION = 1; static const uint8_t RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 }; static const uint8_t RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 }; static const uint8_t RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 }; static const uint8_t RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 }; static const uint8_t RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 }; static const uint8_t RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 }; static const uint8_t RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 }; /* * EAPOL-Key Key Data Encapsulation * GroupKey and STAKey require encryption, otherwise, encryption is optional. */ static const uint8_t RSN_KEY_DATA_GROUPKEY[] = { 0x00, 0x0f, 0xac, 1 }; static const uint8_t RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 }; /* * 1/4: PMKID * 2/4: RSN IE * 3/4: one or two RSN IEs + GTK IE (encrypted) * 4/4: empty * 1/2: GTK IE (encrypted) * 2/2: empty */ /* * RSN IE version 1 * 0x01 0x00 (version; little endian) * (all following fields are optional:) * Group Suite Selector (4 octets) (default: CCMP) * Pairwise Suite Count (2 octets, little endian) (default: 1) * Pairwise Suite List (4 * n octets) (default: CCMP) * Authenticated Key Management Suite Count (2 octets, little endian) * (default: 1) * Authenticated Key Management Suite List (4 * n octets) * (default: unspec 802.1x) * RSN Capabilities (2 octets, little endian) (default: 0) * PMKID Count (2 octets) (default: 0) * PMKID List (16 * n octets) */ #pragma pack(1) struct rsn_ie_hdr { uint8_t elem_id; /* WLAN_EID_RSN */ uint8_t len; uint16_t version; }; #pragma pack() static int random_get_pseudo_bytes(uint8_t *ptr, size_t len) { int fd; size_t resid = len; size_t bytes; fd = open("/dev/urandom", O_RDONLY); if (fd == -1) { wpa_printf(MSG_ERROR, "Could not open /dev/urandom.\n"); return (-1); } while (resid != 0) { bytes = read(fd, ptr, resid); ptr += bytes; resid -= bytes; } (void) close(fd); return (0); } static void inc_byte_array(uint8_t *counter, size_t len) { int pos = len - 1; while (pos >= 0) { counter[pos]++; if (counter[pos] != 0) break; pos--; } } static int wpa_selector_to_bitfield(uint8_t *s) { if (memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == 0) return (WPA_CIPHER_NONE); if (memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == 0) return (WPA_CIPHER_WEP40); if (memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == 0) return (WPA_CIPHER_TKIP); if (memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == 0) return (WPA_CIPHER_CCMP); if (memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == 0) return (WPA_CIPHER_WEP104); return (0); } static int wpa_key_mgmt_to_bitfield(uint8_t *s) { if (memcmp(s, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN) == 0) return (WPA_KEY_MGMT_IEEE8021X); if (memcmp(s, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN) == 0) return (WPA_KEY_MGMT_PSK); return (0); } static int rsn_selector_to_bitfield(uint8_t *s) { if (memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == 0) return (WPA_CIPHER_NONE); if (memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == 0) return (WPA_CIPHER_WEP40); if (memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == 0) return (WPA_CIPHER_TKIP); if (memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == 0) return (WPA_CIPHER_CCMP); if (memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == 0) return (WPA_CIPHER_WEP104); return (0); } static int rsn_key_mgmt_to_bitfield(uint8_t *s) { if (memcmp(s, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN) == 0) return (WPA_KEY_MGMT_IEEE8021X); if (memcmp(s, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN) == 0) return (WPA_KEY_MGMT_PSK); return (0); } static void pmksa_cache_free_entry(struct wpa_supplicant *wpa_s, struct rsn_pmksa_cache *entry) { wpa_s->pmksa_count--; if (wpa_s->cur_pmksa == entry) { wpa_printf(MSG_DEBUG, "RSN: removed current PMKSA entry"); wpa_s->cur_pmksa = NULL; } free(entry); } /* ARGSUSED */ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; time_t now; (void) time(&now); while (wpa_s->pmksa && wpa_s->pmksa->expiration <= now) { struct rsn_pmksa_cache *entry = wpa_s->pmksa; wpa_s->pmksa = entry->next; wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " MACSTR, MAC2STR(entry->aa)); pmksa_cache_free_entry(wpa_s, entry); } pmksa_cache_set_expiration(wpa_s); } static void pmksa_cache_set_expiration(struct wpa_supplicant *wpa_s) { int sec; eloop_cancel_timeout(pmksa_cache_expire, wpa_s, NULL); if (wpa_s->pmksa == NULL) return; sec = wpa_s->pmksa->expiration - time(NULL); if (sec < 0) sec = 0; (void) eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, wpa_s, NULL); } void pmksa_cache_free(struct wpa_supplicant *wpa_s) { struct rsn_pmksa_cache *entry, *prev; entry = wpa_s->pmksa; wpa_s->pmksa = NULL; while (entry) { prev = entry; entry = entry->next; free(prev); } pmksa_cache_set_expiration(wpa_s); wpa_s->cur_pmksa = NULL; } struct rsn_pmksa_cache * pmksa_cache_get(struct wpa_supplicant *wpa_s, uint8_t *aa, uint8_t *pmkid) { struct rsn_pmksa_cache *entry = wpa_s->pmksa; while (entry) { if ((aa == NULL || memcmp(entry->aa, aa, IEEE80211_ADDR_LEN) == 0) && (pmkid == NULL || memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) return (entry); entry = entry->next; } return (NULL); } int pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len) { int i, j; char *pos = buf; struct rsn_pmksa_cache *entry; time_t now; (void) time(&now); pos += snprintf(pos, buf + len - pos, "Index / AA / PMKID / expiration (in seconds)\n"); i = 0; entry = wpa_s->pmksa; while (entry) { i++; pos += snprintf(pos, buf + len - pos, "%d " MACSTR " ", i, MAC2STR(entry->aa)); for (j = 0; j < PMKID_LEN; j++) pos += snprintf(pos, buf + len - pos, "%02x", entry->pmkid[j]); pos += snprintf(pos, buf + len - pos, " %d\n", (int)(entry->expiration - now)); entry = entry->next; } return (pos - buf); } void pmksa_candidate_free(struct wpa_supplicant *wpa_s) { struct rsn_pmksa_candidate *entry, *prev; entry = wpa_s->pmksa_candidates; wpa_s->pmksa_candidates = NULL; while (entry) { prev = entry; entry = entry->next; free(prev); } } /* ARGSUSED */ static int wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data) { struct wpa_ie_hdr *hdr; uint8_t *pos; int left; int i, count; data->proto = WPA_PROTO_WPA; data->pairwise_cipher = WPA_CIPHER_TKIP; data->group_cipher = WPA_CIPHER_TKIP; data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; data->capabilities = 0; if (wpa_ie_len == 0) { /* No WPA IE - fail silently */ return (-1); } if (wpa_ie_len < sizeof (struct wpa_ie_hdr)) { wpa_printf(MSG_DEBUG, "%s: ie len too short %u", "wpa_parse_wpa_ie_wpa", wpa_ie_len); return (-1); } hdr = (struct wpa_ie_hdr *)wpa_ie; if (hdr->elem_id != GENERIC_INFO_ELEM || hdr->len != wpa_ie_len - 2 || memcmp(&hdr->oui, WPA_OUI_AND_TYPE, WPA_SELECTOR_LEN) != 0 || LE_16(hdr->version) != WPA_VERSION) { wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", "wpa_parse_wpa_ie_wpa"); return (-1); } pos = (uint8_t *)(hdr + 1); left = wpa_ie_len - sizeof (*hdr); if (left >= WPA_SELECTOR_LEN) { data->group_cipher = wpa_selector_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } else if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", "wpa_parse_wpa_ie_wpa", left); return (-1); } if (left >= 2) { data->pairwise_cipher = 0; count = pos[0] | (pos[1] << 8); pos += 2; left -= 2; if (count == 0 || left < count * WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", "wpa_parse_wpa_ie_wpa", count, left); return (-1); } for (i = 0; i < count; i++) { data->pairwise_cipher |= wpa_selector_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", "wpa_parse_wpa_ie_wpa"); return (-1); } if (left >= 2) { data->key_mgmt = 0; count = pos[0] | (pos[1] << 8); pos += 2; left -= 2; if (count == 0 || left < count * WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", "wpa_parse_wpa_ie_wpa", count, left); return (-1); } for (i = 0; i < count; i++) { data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", "wpa_parse_wpa_ie_wpa"); return (-1); } if (left >= 2) { data->capabilities = pos[0] | (pos[1] << 8); pos += 2; left -= 2; } if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes", "wpa_parse_wpa_ie_wpa", left); return (-1); } return (0); } /* ARGSUSED */ static int wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, uint8_t *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data) { struct rsn_ie_hdr *hdr; uint8_t *pos; int left; int i, count; data->proto = WPA_PROTO_RSN; data->pairwise_cipher = WPA_CIPHER_CCMP; data->group_cipher = WPA_CIPHER_CCMP; data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; data->capabilities = 0; if (rsn_ie_len == 0) { /* No RSN IE - fail silently */ return (-1); } if (rsn_ie_len < sizeof (struct rsn_ie_hdr)) { wpa_printf(MSG_DEBUG, "%s: ie len too short %u", "wpa_parse_wpa_ie_rsn", rsn_ie_len); return (-1); } hdr = (struct rsn_ie_hdr *)rsn_ie; if (hdr->elem_id != RSN_INFO_ELEM || hdr->len != rsn_ie_len - 2 || LE_16(hdr->version) != RSN_VERSION) { wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", "wpa_parse_wpa_ie_rsn"); return (-1); } pos = (uint8_t *)(hdr + 1); left = rsn_ie_len - sizeof (*hdr); if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } else if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", "wpa_parse_wpa_ie_rsn", left); return (-1); } if (left >= 2) { data->pairwise_cipher = 0; count = pos[0] | (pos[1] << 8); pos += 2; left -= 2; if (count == 0 || left < count * RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", "wpa_parse_wpa_ie_rsn", count, left); return (-1); } for (i = 0; i < count; i++) { data->pairwise_cipher |= rsn_selector_to_bitfield(pos); pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", "wpa_parse_wpa_ie_rsn"); return (-1); } if (left >= 2) { data->key_mgmt = 0; count = pos[0] | (pos[1] << 8); pos += 2; left -= 2; if (count == 0 || left < count * RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", "wpa_parse_wpa_ie_rsn", count, left); return (-1); } for (i = 0; i < count; i++) { data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", "wpa_parse_wpa_ie_rsn"); return (-1); } if (left >= 2) { data->capabilities = pos[0] | (pos[1] << 8); pos += 2; left -= 2; } if (left > 0) { /* * RSN IE could include PMKID data, but Authenticator should * never include it, so no need to parse it in the Supplicant. */ wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", "wpa_parse_wpa_ie_rsn", left); } return (0); } int wpa_parse_wpa_ie(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data) { if (wpa_ie_len >= 1 && wpa_ie[0] == RSN_INFO_ELEM) return (wpa_parse_wpa_ie_rsn(wpa_s, wpa_ie, wpa_ie_len, data)); else return (wpa_parse_wpa_ie_wpa(wpa_s, wpa_ie, wpa_ie_len, data)); } static int wpa_gen_wpa_ie_wpa(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie) { uint8_t *pos; struct wpa_ie_hdr *hdr; hdr = (struct wpa_ie_hdr *)wpa_ie; hdr->elem_id = GENERIC_INFO_ELEM; (void) memcpy(&hdr->oui, WPA_OUI_AND_TYPE, WPA_SELECTOR_LEN); hdr->version = LE_16(WPA_VERSION); pos = (uint8_t *)(hdr + 1); if (wpa_s->group_cipher == WPA_CIPHER_CCMP) { (void) memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN); } else if (wpa_s->group_cipher == WPA_CIPHER_TKIP) { (void) memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN); } else if (wpa_s->group_cipher == WPA_CIPHER_WEP104) { (void) memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN); } else if (wpa_s->group_cipher == WPA_CIPHER_WEP40) { (void) memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", wpa_s->group_cipher); return (-1); } pos += WPA_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) { (void) memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN); } else if (wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) { (void) memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN); } else if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) { (void) memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", wpa_s->pairwise_cipher); return (-1); } pos += WPA_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) { (void) memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN); } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) { (void) memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid key management type (%d).", wpa_s->key_mgmt); return (-1); } pos += WPA_SELECTOR_LEN; /* * WPA Capabilities; use defaults, so no need to include it */ hdr->len = (pos - wpa_ie) - 2; return (pos - wpa_ie); } static int wpa_gen_wpa_ie_rsn(struct wpa_supplicant *wpa_s, uint8_t *rsn_ie) { uint8_t *pos; struct rsn_ie_hdr *hdr; hdr = (struct rsn_ie_hdr *)rsn_ie; hdr->elem_id = RSN_INFO_ELEM; hdr->version = LE_16(RSN_VERSION); pos = (uint8_t *)(hdr + 1); if (wpa_s->group_cipher == WPA_CIPHER_CCMP) { (void) memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN); } else if (wpa_s->group_cipher == WPA_CIPHER_TKIP) { (void) memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN); } else if (wpa_s->group_cipher == WPA_CIPHER_WEP104) { (void) memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN); } else if (wpa_s->group_cipher == WPA_CIPHER_WEP40) { (void) memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", wpa_s->group_cipher); return (-1); } pos += RSN_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) { (void) memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN); } else if (wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) { (void) memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN); } else if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) { (void) memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", wpa_s->pairwise_cipher); return (-1); } pos += RSN_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) { (void) memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN); } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) { (void) memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid key management type (%d).", wpa_s->key_mgmt); return (-1); } pos += RSN_SELECTOR_LEN; /* RSN Capabilities */ *pos++ = 0; *pos++ = 0; if (wpa_s->cur_pmksa) { /* PMKID Count (2 octets, little endian) */ *pos++ = 1; *pos++ = 0; /* PMKID */ (void) memcpy(pos, wpa_s->cur_pmksa->pmkid, PMKID_LEN); pos += PMKID_LEN; } hdr->len = (pos - rsn_ie) - 2; return (pos - rsn_ie); } int wpa_gen_wpa_ie(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie) { if (wpa_s->proto == WPA_PROTO_RSN) return (wpa_gen_wpa_ie_rsn(wpa_s, wpa_ie)); else return (wpa_gen_wpa_ie_wpa(wpa_s, wpa_ie)); } static void wpa_pmk_to_ptk(uint8_t *pmk, uint8_t *addr1, uint8_t *addr2, uint8_t *nonce1, uint8_t *nonce2, uint8_t *ptk, size_t ptk_len) { uint8_t data[2 * IEEE80211_ADDR_LEN + 2 * WPA_PMK_LEN]; /* * PTK = PRF-X(PMK, "Pairwise key expansion", * Min(AA, SA) || Max(AA, SA) || * Min(ANonce, SNonce) || Max(ANonce, SNonce)) */ if (memcmp(addr1, addr2, IEEE80211_ADDR_LEN) < 0) { (void) memcpy(data, addr1, IEEE80211_ADDR_LEN); (void) memcpy(data + IEEE80211_ADDR_LEN, addr2, IEEE80211_ADDR_LEN); } else { (void) memcpy(data, addr2, IEEE80211_ADDR_LEN); (void) memcpy(data + IEEE80211_ADDR_LEN, addr1, IEEE80211_ADDR_LEN); } if (memcmp(nonce1, nonce2, WPA_PMK_LEN) < 0) { (void) memcpy(data + 2 * IEEE80211_ADDR_LEN, nonce1, WPA_PMK_LEN); (void) memcpy(data + 2 * IEEE80211_ADDR_LEN + WPA_PMK_LEN, nonce2, WPA_PMK_LEN); } else { (void) memcpy(data + 2 * IEEE80211_ADDR_LEN, nonce2, WPA_PMK_LEN); (void) memcpy(data + 2 * IEEE80211_ADDR_LEN + WPA_PMK_LEN, nonce1, WPA_PMK_LEN); } sha1_prf(pmk, WPA_PMK_LEN, "Pairwise key expansion", data, sizeof (data), ptk, ptk_len); wpa_hexdump(MSG_DEBUG, "WPA: PMK", pmk, WPA_PMK_LEN); wpa_hexdump(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); } struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s) { struct wpa_ssid *entry; uint8_t ssid[MAX_ESSID_LENGTH]; int ssid_len; uint8_t bssid[IEEE80211_ADDR_LEN]; (void) memset(ssid, 0, MAX_ESSID_LENGTH); ssid_len = wpa_s->driver->get_ssid(wpa_s->handle, wpa_s->linkid, (char *)ssid); if (ssid_len < 0) { wpa_printf(MSG_WARNING, "Could not read SSID from driver."); return (NULL); } if (wpa_s->driver->get_bssid(wpa_s->handle, wpa_s->linkid, (char *)bssid) < 0) { wpa_printf(MSG_WARNING, "Could not read BSSID from driver."); return (NULL); } entry = wpa_s->conf->ssid; wpa_printf(MSG_DEBUG, "entry len=%d ssid=%s," " driver len=%d ssid=%s", entry->ssid_len, entry->ssid, ssid_len, ssid); if (ssid_len == entry->ssid_len && memcmp(ssid, entry->ssid, ssid_len) == 0 && (!entry->bssid_set || memcmp(bssid, entry->bssid, IEEE80211_ADDR_LEN) == 0)) return (entry); return (NULL); } static void wpa_eapol_key_mic(uint8_t *key, int ver, uint8_t *buf, size_t len, uint8_t *mic) { if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { hmac_md5(key, 16, buf, len, mic); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { uint8_t hash[SHA1_MAC_LEN]; hmac_sha1(key, 16, buf, len, hash); (void) memcpy(mic, hash, MD5_MAC_LEN); } } void wpa_supplicant_key_request(struct wpa_supplicant *wpa_s, int error, int pairwise) { int rlen; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *reply; unsigned char *rbuf; struct l2_ethhdr *ethhdr; int key_info, ver; uint8_t bssid[IEEE80211_ADDR_LEN]; if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; if (wpa_s->driver->get_bssid(wpa_s->handle, wpa_s->linkid, (char *)bssid) < 0) { wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " "request"); return; } rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply); rbuf = malloc(rlen); if (rbuf == NULL) return; (void) memset(rbuf, 0, rlen); ethhdr = (struct l2_ethhdr *)rbuf; (void) memcpy(ethhdr->h_dest, bssid, IEEE80211_ADDR_LEN); (void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN); ethhdr->h_proto = htons(ETHERTYPE_EAPOL); hdr = (struct ieee802_1x_hdr *)(ethhdr + 1); hdr->version = wpa_s->conf->eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = htons(sizeof (*reply)); reply = (struct wpa_eapol_key *)(hdr + 1); reply->type = wpa_s->proto == WPA_PROTO_RSN ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info = WPA_KEY_INFO_REQUEST | ver; if (wpa_s->ptk_set) key_info |= WPA_KEY_INFO_MIC; if (error) key_info |= WPA_KEY_INFO_ERROR; if (pairwise) key_info |= WPA_KEY_INFO_KEY_TYPE; reply->key_info = BE_16(key_info); reply->key_length = 0; (void) memcpy(reply->replay_counter, wpa_s->request_counter, WPA_REPLAY_COUNTER_LEN); inc_byte_array(wpa_s->request_counter, WPA_REPLAY_COUNTER_LEN); reply->key_data_length = BE_16(0); if (key_info & WPA_KEY_INFO_MIC) { wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (uint8_t *)hdr, rlen - sizeof (*ethhdr), reply->key_mic); } wpa_printf(MSG_INFO, "WPA: Sending EAPOL-Key Request (error=%d " "pairwise=%d ptk_set=%d len=%d)", error, pairwise, wpa_s->ptk_set, rlen); wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key Request", rbuf, rlen); (void) l2_packet_send(wpa_s->l2, rbuf, rlen); free(rbuf); } static void wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s, unsigned char *src_addr, struct wpa_eapol_key *key, int ver) { int rlen; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *reply; unsigned char *rbuf; struct l2_ethhdr *ethhdr; struct wpa_ssid *ssid; struct wpa_ptk *ptk; uint8_t buf[8], wpa_ie_buf[80], *wpa_ie, *pmkid = NULL; int wpa_ie_len; wpa_s->wpa_state = WPA_4WAY_HANDSHAKE; wpa_printf(MSG_DEBUG, "WPA: RX message 1 of 4-Way Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); ssid = wpa_supplicant_get_ssid(wpa_s); if (ssid == NULL) { wpa_printf(MSG_WARNING, "WPA: No SSID info found (msg 1 of 4)."); return; } if (wpa_s->proto == WPA_PROTO_RSN) { /* RSN: msg 1/4 should contain PMKID for the selected PMK */ uint8_t *pos = (uint8_t *)(key + 1); uint8_t *end = pos + BE_16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", pos, BE_16(key->key_data_length)); while (pos + 1 < end) { if (pos + 2 + pos[1] > end) { wpa_printf(MSG_DEBUG, "RSN: key data " "underflow (ie=%d len=%d)", pos[0], pos[1]); break; } if (pos[0] == GENERIC_INFO_ELEM && pos + 1 + RSN_SELECTOR_LEN < end && pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && memcmp(pos + 2, RSN_KEY_DATA_PMKID, RSN_SELECTOR_LEN) == 0) { pmkid = pos + 2 + RSN_SELECTOR_LEN; wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " "Authenticator", pmkid, PMKID_LEN); break; } else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0) break; pos += 2 + pos[1]; } } wpa_ie = wpa_ie_buf; wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie); if (wpa_ie_len < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to generate " "WPA IE (for msg 2 of 4)."); return; } wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply) + wpa_ie_len; rbuf = malloc(rlen); if (rbuf == NULL) return; (void) memset(rbuf, 0, rlen); ethhdr = (struct l2_ethhdr *)rbuf; (void) memcpy(ethhdr->h_dest, src_addr, IEEE80211_ADDR_LEN); (void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN); ethhdr->h_proto = htons(ETHERTYPE_EAPOL); hdr = (struct ieee802_1x_hdr *)(ethhdr + 1); hdr->version = wpa_s->conf->eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = htons(sizeof (*reply) + wpa_ie_len); reply = (struct wpa_eapol_key *)(hdr + 1); reply->type = wpa_s->proto == WPA_PROTO_RSN ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; reply->key_info = BE_16(ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC); reply->key_length = key->key_length; (void) memcpy(reply->replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); reply->key_data_length = BE_16(wpa_ie_len); (void) memcpy(reply + 1, wpa_ie, wpa_ie_len); if (wpa_s->renew_snonce) { if (random_get_pseudo_bytes(wpa_s->snonce, WPA_NONCE_LEN)) { wpa_printf(MSG_WARNING, "WPA: Failed to get " "random data for SNonce"); free(rbuf); return; } wpa_s->renew_snonce = 0; wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", wpa_s->snonce, WPA_NONCE_LEN); } (void) memcpy(reply->key_nonce, wpa_s->snonce, WPA_NONCE_LEN); ptk = &wpa_s->tptk; (void) memcpy(wpa_s->anonce, key->key_nonce, WPA_NONCE_LEN); wpa_pmk_to_ptk(wpa_s->pmk, wpa_s->own_addr, src_addr, wpa_s->snonce, key->key_nonce, (uint8_t *)ptk, sizeof (*ptk)); /* * Supplicant: swap tx/rx Mic keys */ (void) memcpy(buf, ptk->u.auth.tx_mic_key, 8); (void) memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8); (void) memcpy(ptk->u.auth.rx_mic_key, buf, 8); wpa_s->tptk_set = 1; wpa_eapol_key_mic(wpa_s->tptk.mic_key, ver, (uint8_t *)hdr, rlen - sizeof (*ethhdr), reply->key_mic); wpa_hexdump(MSG_DEBUG, "WPA: EAPOL-Key MIC", reply->key_mic, 16); wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4"); wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 2/4", rbuf, rlen); (void) l2_packet_send(wpa_s->l2, rbuf, rlen); free(rbuf); } static void wpa_supplicant_process_3_of_4_gtk(struct wpa_supplicant *wpa_s, unsigned char *src_addr, struct wpa_eapol_key *key, uint8_t *gtk, int gtk_len) { int keyidx, tx, key_rsc_len = 0, alg; wpa_hexdump(MSG_DEBUG, "WPA: received GTK in pairwise handshake", gtk, gtk_len); keyidx = gtk[0] & 0x3; tx = !!(gtk[0] & BIT(2)); if (tx && wpa_s->pairwise_cipher != WPA_CIPHER_NONE) { /* * Ignore Tx bit in GTK IE if a pairwise key is used. * One AP seemed to set this bit (incorrectly, since Tx * is only when doing Group Key only APs) and without * this workaround, the data connection does not work * because wpa_supplicant configured non-zero keyidx to * be used for unicast. */ wpa_printf(MSG_INFO, "RSN: Tx bit set for GTK IE, but " "pairwise keys are used - ignore Tx bit"); tx = 0; } gtk += 2; gtk_len -= 2; wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gtk, gtk_len); switch (wpa_s->group_cipher) { case WPA_CIPHER_CCMP: if (gtk_len != 16) { wpa_printf(MSG_WARNING, "WPA: Unsupported CCMP" " Group Cipher key length %d.", gtk_len); return; } key_rsc_len = 6; alg = WPA_ALG_CCMP; break; case WPA_CIPHER_TKIP: if (gtk_len != 32) { wpa_printf(MSG_WARNING, "WPA: Unsupported TKIP" " Group Cipher key length %d.", gtk_len); return; } key_rsc_len = 6; alg = WPA_ALG_TKIP; break; case WPA_CIPHER_WEP104: if (gtk_len != 13) { wpa_printf(MSG_WARNING, "WPA: Unsupported " "WEP104 Group Cipher key length " "%d.", gtk_len); return; } alg = WPA_ALG_WEP; break; case WPA_CIPHER_WEP40: if (gtk_len != 5) { wpa_printf(MSG_WARNING, "WPA: Unsupported " "WEP40 Group Cipher key length %d.", gtk_len); return; } alg = WPA_ALG_WEP; break; default: wpa_printf(MSG_WARNING, "WPA: Unsupport Group Cipher " "%d", wpa_s->group_cipher); return; } wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver " "(keyidx=%d tx=%d).", keyidx, tx); wpa_hexdump(MSG_DEBUG, "WPA: RSC", key->key_rsc, key_rsc_len); if (wpa_s->group_cipher == WPA_CIPHER_TKIP) { uint8_t tmpbuf[8]; /* * Swap Tx/Rx keys for Michael MIC */ (void) memcpy(tmpbuf, gtk + 16, 8); (void) memcpy(gtk + 16, gtk + 24, 8); (void) memcpy(gtk + 24, tmpbuf, 8); } if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) { if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg, (uint8_t *)"\xff\xff\xff\xff\xff\xff", keyidx, 1, key->key_rsc, key_rsc_len, gtk, gtk_len) < 0) wpa_printf(MSG_WARNING, "WPA: Failed to set " "GTK to the driver (Group only)."); } else if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg, (uint8_t *)"\xff\xff\xff\xff\xff\xff", keyidx, tx, key->key_rsc, key_rsc_len, gtk, gtk_len) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to " "the driver."); } wpa_printf(MSG_INFO, "WPA: Key negotiation completed with " MACSTR, MAC2STR(src_addr)); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_s->wpa_state = WPA_COMPLETED; } static void wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s, unsigned char *src_addr, struct wpa_eapol_key *key, int extra_len, int ver) { int rlen; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *reply; unsigned char *rbuf; struct l2_ethhdr *ethhdr; int key_info, ie_len = 0, keylen, gtk_len = 0; uint8_t *ie = NULL, *gtk = NULL, *key_rsc; uint8_t null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; wpa_s->wpa_state = WPA_4WAY_HANDSHAKE; wpa_printf(MSG_DEBUG, "WPA: RX message 3 of 4-Way Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); key_info = BE_16(key->key_info); if (wpa_s->proto == WPA_PROTO_RSN) { uint8_t *pos = (uint8_t *)(key + 1); uint8_t *end = pos + BE_16(key->key_data_length); while (pos + 1 < end) { if (pos + 2 + pos[1] > end) { wpa_printf(MSG_DEBUG, "RSN: key data " "underflow (ie=%d len=%d)", pos[0], pos[1]); break; } if (*pos == RSN_INFO_ELEM) { ie = pos; ie_len = pos[1] + 2; } else if (pos[0] == GENERIC_INFO_ELEM && pos + 1 + RSN_SELECTOR_LEN < end && pos[1] > RSN_SELECTOR_LEN + 2 && memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN) == 0) { if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { wpa_printf(MSG_WARNING, "WPA: GTK IE " "in unencrypted key data"); return; } gtk = pos + 2 + RSN_SELECTOR_LEN; gtk_len = pos[1] - RSN_SELECTOR_LEN; } else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0) break; pos += 2 + pos[1]; } } else { ie = (uint8_t *)(key + 1); ie_len = BE_16(key->key_data_length); if (ie_len > extra_len) { wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:" " ie_len=%d > extra_len=%d", ie_len, extra_len); return; } } if (wpa_s->ap_wpa_ie && (wpa_s->ap_wpa_ie_len != ie_len || memcmp(wpa_s->ap_wpa_ie, ie, ie_len) != 0)) { wpa_printf(MSG_WARNING, "WPA: WPA IE in 3/4 msg does not match" " with WPA IE in Beacon/ProbeResp (src=" MACSTR ")", MAC2STR(src_addr)); wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp", wpa_s->ap_wpa_ie, wpa_s->ap_wpa_ie_len); wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg", ie, ie_len); wpa_supplicant_disassociate(wpa_s, REASON_IE_IN_4WAY_DIFFERS); wpa_supplicant_req_scan(wpa_s, 0, 0); return; } if (memcmp(wpa_s->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_WARNING, "WPA: ANonce from message 1 of 4-Way " "Handshake differs from 3 of 4-Way Handshake - drop" " packet (src=" MACSTR ")", MAC2STR(src_addr)); return; } keylen = BE_16(key->key_length); switch (wpa_s->pairwise_cipher) { case WPA_CIPHER_CCMP: if (keylen != 16) { wpa_printf(MSG_WARNING, "WPA: Invalid CCMP key length " "%d (src=" MACSTR ")", keylen, MAC2STR(src_addr)); return; } break; case WPA_CIPHER_TKIP: if (keylen != 32) { wpa_printf(MSG_WARNING, "WPA: Invalid TKIP key length " "%d (src=" MACSTR ")", keylen, MAC2STR(src_addr)); return; } break; } rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply); rbuf = malloc(rlen); if (rbuf == NULL) return; (void) memset(rbuf, 0, rlen); ethhdr = (struct l2_ethhdr *)rbuf; (void) memcpy(ethhdr->h_dest, src_addr, IEEE80211_ADDR_LEN); (void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN); ethhdr->h_proto = htons(ETHERTYPE_EAPOL); hdr = (struct ieee802_1x_hdr *)(ethhdr + 1); hdr->version = wpa_s->conf->eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = htons(sizeof (*reply)); reply = (struct wpa_eapol_key *)(hdr + 1); reply->type = wpa_s->proto == WPA_PROTO_RSN ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; reply->key_info = BE_16(ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC | (key_info & WPA_KEY_INFO_SECURE)); reply->key_length = key->key_length; (void) memcpy(reply->replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); reply->key_data_length = BE_16(0); (void) memcpy(reply->key_nonce, wpa_s->snonce, WPA_NONCE_LEN); wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (uint8_t *)hdr, rlen - sizeof (*ethhdr), reply->key_mic); wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 4/4", rbuf, rlen); (void) l2_packet_send(wpa_s->l2, rbuf, rlen); free(rbuf); /* * SNonce was successfully used in msg 3/4, so mark it to be renewed * for the next 4-Way Handshake. If msg 3 is received again, the old * SNonce will still be used to avoid changing PTK. */ wpa_s->renew_snonce = 1; if (key_info & WPA_KEY_INFO_INSTALL) { int alg, keylen, rsclen; wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver."); switch (wpa_s->pairwise_cipher) { case WPA_CIPHER_CCMP: alg = WPA_ALG_CCMP; keylen = 16; rsclen = 6; break; case WPA_CIPHER_TKIP: alg = WPA_ALG_TKIP; keylen = 32; rsclen = 6; break; case WPA_CIPHER_NONE: wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: " "NONE - do not use pairwise keys"); return; default: wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise " "cipher %d", wpa_s->pairwise_cipher); return; } if (wpa_s->proto == WPA_PROTO_RSN) { key_rsc = null_rsc; } else { key_rsc = key->key_rsc; wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen); } if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg, src_addr, 0, 1, key_rsc, rsclen, (uint8_t *)&wpa_s->ptk.tk1, keylen) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the" " driver."); } } wpa_printf(MSG_DEBUG, "%s: key_info=%x gtk=%p\n", "wpa_supplicant_process_3_of_4", key_info, gtk); wpa_s->wpa_state = WPA_GROUP_HANDSHAKE; if (gtk) wpa_supplicant_process_3_of_4_gtk(wpa_s, src_addr, key, gtk, gtk_len); } static void wpa_supplicant_process_1_of_2(struct wpa_supplicant *wpa_s, unsigned char *src_addr, struct wpa_eapol_key *key, int extra_len, int ver) { int rlen; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *reply; unsigned char *rbuf; struct l2_ethhdr *ethhdr; int key_info, keylen, keydatalen, maxkeylen, keyidx, key_rsc_len = 0; int alg, tx; uint8_t ek[32], tmpbuf[8], gtk[32]; uint8_t *gtk_ie = NULL; size_t gtk_ie_len = 0; wpa_s->wpa_state = WPA_GROUP_HANDSHAKE; wpa_printf(MSG_DEBUG, "WPA: RX message 1 of Group Key Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); key_info = BE_16(key->key_info); keydatalen = BE_16(key->key_data_length); if (wpa_s->proto == WPA_PROTO_RSN) { uint8_t *pos = (uint8_t *)(key + 1); uint8_t *end = pos + keydatalen; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) { wpa_printf(MSG_DEBUG, "RSN: key data " "underflow (ie=%d len=%d)", pos[0], pos[1]); break; } if (pos[0] == GENERIC_INFO_ELEM && pos + 1 + RSN_SELECTOR_LEN < end && pos[1] > RSN_SELECTOR_LEN + 2 && memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN) == 0) { if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { wpa_printf(MSG_WARNING, "WPA: GTK IE " "in unencrypted key data"); return; } gtk_ie = pos + 2 + RSN_SELECTOR_LEN; gtk_ie_len = pos[1] - RSN_SELECTOR_LEN; break; } else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0) { break; } pos += 2 + pos[1]; } if (gtk_ie == NULL) { wpa_printf(MSG_INFO, "WPA: No GTK IE in Group Key " "message 1/2"); return; } maxkeylen = keylen = gtk_ie_len - 2; } else { keylen = BE_16(key->key_length); maxkeylen = keydatalen; if (keydatalen > extra_len) { wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:" " key_data_length=%d > extra_len=%d", keydatalen, extra_len); return; } if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) maxkeylen -= 8; } switch (wpa_s->group_cipher) { case WPA_CIPHER_CCMP: if (keylen != 16 || maxkeylen < 16) { wpa_printf(MSG_WARNING, "WPA: Unsupported CCMP Group " "Cipher key length %d (%d).", keylen, maxkeylen); return; } key_rsc_len = 6; alg = WPA_ALG_CCMP; break; case WPA_CIPHER_TKIP: if (keylen != 32 || maxkeylen < 32) { wpa_printf(MSG_WARNING, "WPA: Unsupported TKIP Group " "Cipher key length %d (%d).", keylen, maxkeylen); return; } key_rsc_len = 6; /* key->key_data; */ alg = WPA_ALG_TKIP; break; case WPA_CIPHER_WEP104: if (keylen != 13 || maxkeylen < 13) { wpa_printf(MSG_WARNING, "WPA: Unsupported WEP104 Group" " Cipher key length %d (%d).", keylen, maxkeylen); return; } alg = WPA_ALG_WEP; break; case WPA_CIPHER_WEP40: if (keylen != 5 || maxkeylen < 5) { wpa_printf(MSG_WARNING, "WPA: Unsupported WEP40 Group " "Cipher key length %d (%d).", keylen, maxkeylen); return; } alg = WPA_ALG_WEP; break; default: wpa_printf(MSG_WARNING, "WPA: Unsupport Group Cipher %d", wpa_s->group_cipher); return; } if (wpa_s->proto == WPA_PROTO_RSN) { wpa_hexdump(MSG_DEBUG, "WPA: received GTK in group key handshake", gtk_ie, gtk_ie_len); keyidx = gtk_ie[0] & 0x3; tx = !!(gtk_ie[0] & BIT(2)); if (gtk_ie_len - 2 > sizeof (gtk)) { wpa_printf(MSG_INFO, "WPA: Too long GTK in GTK IE " "(len=%d)", gtk_ie_len - 2); return; } (void) memcpy(gtk, gtk_ie + 2, gtk_ie_len - 2); } else { keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> WPA_KEY_INFO_KEY_INDEX_SHIFT; if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { (void) memcpy(ek, key->key_iv, 16); (void) memcpy(ek + 16, wpa_s->ptk.encr_key, 16); rc4_skip(ek, 32, 256, (uint8_t *)(key + 1), keydatalen); (void) memcpy(gtk, key + 1, keylen); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { if (keydatalen % 8) { wpa_printf(MSG_WARNING, "WPA: Unsupported " "AES-WRAP len %d", keydatalen); return; } if (aes_unwrap(wpa_s->ptk.encr_key, maxkeylen / 8, (uint8_t *)(key + 1), gtk)) { wpa_printf(MSG_WARNING, "WPA: AES unwrap " "failed - could not decrypt GTK"); return; } } tx = !!(key_info & WPA_KEY_INFO_TXRX); if (tx && wpa_s->pairwise_cipher != WPA_CIPHER_NONE) { /* * Ignore Tx bit in Group Key message if a pairwise key * is used. Some APs seem to setting this bit * (incorrectly, since Tx is only when doing Group Key * only APs) and without this workaround, the data * connection does not work because wpa_supplicant * configured non-zero keyidx to be used for unicast. */ wpa_printf(MSG_INFO, "WPA: Tx bit set for GTK, but " "pairwise keys are used - ignore Tx bit"); tx = 0; } } wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gtk, keylen); wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver (keyidx=%d " "tx=%d).", keyidx, tx); wpa_hexdump(MSG_DEBUG, "WPA: RSC", key->key_rsc, key_rsc_len); if (wpa_s->group_cipher == WPA_CIPHER_TKIP) { /* * Swap Tx/Rx keys for Michael MIC */ (void) memcpy(tmpbuf, gtk + 16, 8); (void) memcpy(gtk + 16, gtk + 24, 8); (void) memcpy(gtk + 24, tmpbuf, 8); } if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) { if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg, (uint8_t *)"\xff\xff\xff\xff\xff\xff", keyidx, 1, key->key_rsc, key_rsc_len, gtk, keylen) < 0) wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the" " driver (Group only)."); } else if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg, (uint8_t *)"\xff\xff\xff\xff\xff\xff", keyidx, tx, key->key_rsc, key_rsc_len, gtk, keylen) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " "driver."); } rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply); rbuf = malloc(rlen); if (rbuf == NULL) return; (void) memset(rbuf, 0, rlen); ethhdr = (struct l2_ethhdr *)rbuf; (void) memcpy(ethhdr->h_dest, src_addr, IEEE80211_ADDR_LEN); (void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN); ethhdr->h_proto = htons(ETHERTYPE_EAPOL); hdr = (struct ieee802_1x_hdr *)(ethhdr + 1); hdr->version = wpa_s->conf->eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = htons(sizeof (*reply)); reply = (struct wpa_eapol_key *)(hdr + 1); reply->type = wpa_s->proto == WPA_PROTO_RSN ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; reply->key_info = BE_16(ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE | (key_info & WPA_KEY_INFO_KEY_INDEX_MASK)); reply->key_length = key->key_length; (void) memcpy(reply->replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); reply->key_data_length = BE_16(0); wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (uint8_t *)hdr, rlen - sizeof (*ethhdr), reply->key_mic); wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2"); wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 2/2", rbuf, rlen); (void) l2_packet_send(wpa_s->l2, rbuf, rlen); free(rbuf); wpa_printf(MSG_INFO, "WPA: Key negotiation completed with " MACSTR, MAC2STR(src_addr)); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_s->wpa_state = WPA_COMPLETED; wpa_printf(MSG_INFO, "-----------------------------------\n"); } static int wpa_supplicant_verify_eapol_key_mic(struct wpa_supplicant *wpa_s, struct wpa_eapol_key *key, int ver, uint8_t *buf, size_t len) { uint8_t mic[16]; int ok = 0; (void) memcpy(mic, key->key_mic, 16); if (wpa_s->tptk_set) { (void) memset(key->key_mic, 0, 16); wpa_eapol_key_mic(wpa_s->tptk.mic_key, ver, buf, len, key->key_mic); if (memcmp(mic, key->key_mic, 16) != 0) { wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC " "when using TPTK - ignoring TPTK"); } else { ok = 1; wpa_s->tptk_set = 0; wpa_s->ptk_set = 1; (void) memcpy(&wpa_s->ptk, &wpa_s->tptk, sizeof (wpa_s->ptk)); } } if (!ok && wpa_s->ptk_set) { (void) memset(key->key_mic, 0, 16); wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, buf, len, key->key_mic); if (memcmp(mic, key->key_mic, 16) != 0) { wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC " "- dropping packet"); return (-1); } ok = 1; } if (!ok) { wpa_printf(MSG_WARNING, "WPA: Could not verify EAPOL-Key MIC " "- dropping packet"); return (-1); } (void) memcpy(wpa_s->rx_replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); wpa_s->rx_replay_counter_set = 1; return (0); } /* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ static int wpa_supplicant_decrypt_key_data(struct wpa_supplicant *wpa_s, struct wpa_eapol_key *key, int ver) { int keydatalen = BE_16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", (uint8_t *)(key + 1), keydatalen); if (!wpa_s->ptk_set) { wpa_printf(MSG_WARNING, "WPA: PTK not available, " "cannot decrypt EAPOL-Key key data."); return (-1); } /* * Decrypt key data here so that this operation does not need * to be implemented separately for each message type. */ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { uint8_t ek[32]; (void) memcpy(ek, key->key_iv, 16); (void) memcpy(ek + 16, wpa_s->ptk.encr_key, 16); rc4_skip(ek, 32, 256, (uint8_t *)(key + 1), keydatalen); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { uint8_t *buf; if (keydatalen % 8) { wpa_printf(MSG_WARNING, "WPA: Unsupported " "AES-WRAP len %d", keydatalen); return (-1); } keydatalen -= 8; /* AES-WRAP adds 8 bytes */ buf = malloc(keydatalen); if (buf == NULL) { wpa_printf(MSG_WARNING, "WPA: No memory for " "AES-UNWRAP buffer"); return (-1); } if (aes_unwrap(wpa_s->ptk.encr_key, keydatalen / 8, (uint8_t *)(key + 1), buf)) { free(buf); wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - " "could not decrypt EAPOL-Key key data"); return (-1); } (void) memcpy(key + 1, buf, keydatalen); free(buf); key->key_data_length = BE_16(keydatalen); } wpa_hexdump(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", (uint8_t *)(key + 1), keydatalen); return (0); } static void wpa_sm_rx_eapol(struct wpa_supplicant *wpa_s, unsigned char *src_addr, unsigned char *buf, size_t len) { size_t plen, data_len, extra_len; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; int key_info, ver; wpa_printf(MSG_DEBUG, "WPA: EAPOL frame len %u\n ", len); hdr = (struct ieee802_1x_hdr *)buf; key = (struct wpa_eapol_key *)(hdr + 1); wpa_printf(MSG_DEBUG, "hdr_len=%u, key_len=%u", sizeof (*hdr), sizeof (*key)); if (len < sizeof (*hdr) + sizeof (*key)) { wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short, len %u, " "expecting at least %u", len, sizeof (*hdr) + sizeof (*key)); return; } plen = ntohs(hdr->length); data_len = plen + sizeof (*hdr); wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%d", hdr->version, hdr->type, plen); if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { wpa_printf(MSG_DEBUG, "WPA: EAPOL frame (type %u) discarded, " "not a Key frame", hdr->type); return; } if (plen > len - sizeof (*hdr) || plen < sizeof (*key)) { wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %u " "invalid (frame size %u)", plen, len); return; } wpa_printf(MSG_DEBUG, " EAPOL-Key type=%d", key->type); if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN) { wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key type (%d) unknown, " "discarded", key->type); return; } wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len); if (data_len < len) { wpa_printf(MSG_DEBUG, "WPA: ignoring %d bytes after the IEEE " "802.1X data", len - data_len); } key_info = BE_16(key->key_info); ver = key_info & WPA_KEY_INFO_TYPE_MASK; if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_printf(MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor " "version %d.", ver); return; } if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key " "descriptor version (%d) is not 2.", ver); if (wpa_s->group_cipher != WPA_CIPHER_CCMP && !(key_info & WPA_KEY_INFO_KEY_TYPE)) { /* * Earlier versions of IEEE 802.11i did not explicitly * require version 2 descriptor for all EAPOL-Key * packets, so allow group keys to use version 1 if * CCMP is not used for them. */ wpa_printf(MSG_INFO, "WPA: Backwards compatibility: " "allow invalid version for non-CCMP group keys"); } else return; } if (wpa_s->rx_replay_counter_set && memcmp(key->replay_counter, wpa_s->rx_replay_counter, WPA_REPLAY_COUNTER_LEN) <= 0) { wpa_printf(MSG_WARNING, "WPA: EAPOL-Key Replay Counter did not" " increase - dropping packet"); return; } if (!(key_info & WPA_KEY_INFO_ACK)) { wpa_printf(MSG_INFO, "WPA: No Ack bit in key_info"); return; } if (key_info & WPA_KEY_INFO_REQUEST) { wpa_printf(MSG_INFO, "WPA: EAPOL-Key with Request bit - " "dropped"); return; } if ((key_info & WPA_KEY_INFO_MIC) && wpa_supplicant_verify_eapol_key_mic(wpa_s, key, ver, buf, data_len)) { return; } extra_len = data_len - sizeof (*hdr) - sizeof (*key); if (wpa_s->proto == WPA_PROTO_RSN && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && wpa_supplicant_decrypt_key_data(wpa_s, key, ver)) return; if (key_info & WPA_KEY_INFO_KEY_TYPE) { if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { wpa_printf(MSG_WARNING, "WPA: Ignored EAPOL-Key " "(Pairwise) with non-zero key index"); return; } if (key_info & WPA_KEY_INFO_MIC) { /* 3/4 4-Way Handshake */ wpa_supplicant_process_3_of_4(wpa_s, src_addr, key, extra_len, ver); } else { /* 1/4 4-Way Handshake */ wpa_supplicant_process_1_of_4(wpa_s, src_addr, key, ver); } } else { if (key_info & WPA_KEY_INFO_MIC) { /* 1/2 Group Key Handshake */ wpa_supplicant_process_1_of_2(wpa_s, src_addr, key, extra_len, ver); } else { wpa_printf(MSG_WARNING, "WPA: EAPOL-Key (Group) " "without Mic bit - dropped"); } } } void wpa_supplicant_rx_eapol(void *ctx, unsigned char *src_addr, unsigned char *buf, size_t len) { struct wpa_supplicant *wpa_s = ctx; wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); if (wpa_s->eapol_received == 0) { /* Timeout for completing IEEE 802.1X and WPA authentication */ wpa_supplicant_req_auth_timeout( wpa_s, wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ? 70 : 10, 0); } wpa_s->eapol_received++; /* * Source address of the incoming EAPOL frame could be compared to the * current BSSID. However, it is possible that a centralized * Authenticator could be using another MAC address than the BSSID of * an AP, so just allow any address to be used for now. The replies are * still sent to the current BSSID (if available), though. */ wpa_sm_rx_eapol(wpa_s, src_addr, buf, len); }