📄 wpa.c
字号:
/* * Host AP (software wireless LAN access point) user space daemon for * Host AP kernel driver / WPA Authenticator * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <netinet/in.h>#include <sys/time.h>#include <time.h>#include <unistd.h>#include "hostapd.h"#include "eapol_sm.h"#include "wpa.h"#include "driver.h"#include "sha1.h"#include "md5.h"#include "rc4.h"#include "aes_wrap.h"#include "ieee802_1x.h"#include "ieee802_11.h"#include "eloop.h"#include "sta_info.h"#include "l2_packet.h"static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);static void wpa_sm_step(struct wpa_state_machine *sm);static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);static void wpa_group_sm_step(struct hostapd_data *hapd);static void pmksa_cache_free(struct hostapd_data *hapd);static struct rsn_pmksa_cache * pmksa_cache_get(struct hostapd_data *hapd, u8 *spa, u8 *pmkid);/* Default timeouts are 100 ms, but this seems to be a bit too fast for most * WPA Supplicants, so use a bit longer timeout. */static const u32 dot11RSNAConfigGroupUpdateTimeOut = 1000; /* ms */static const u32 dot11RSNAConfigGroupUpdateCount = 3;static const u32 dot11RSNAConfigPairwiseUpdateTimeOut = 1000; /* ms */static const u32 dot11RSNAConfigPairwiseUpdateCount = 3;/* TODO: make these configurable */static const int dot11RSNAConfigPMKLifetime = 43200;static const int dot11RSNAConfigPMKReauthThreshold = 70;static const int dot11RSNAConfigSATimeout = 60;static const int pmksa_cache_max_entries = 1024;static const int WPA_SELECTOR_LEN = 4;static const u8 WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };static const u16 WPA_VERSION = 1;static const u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };static const u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };static const u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };static const u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };static const u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };static const u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };static const u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };static const u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };static const int RSN_SELECTOR_LEN = 4;static const u16 RSN_VERSION = 1;static const u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };static const u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };static const u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };static const u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };static const u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };static const u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };static const u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };static const u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };/* EAPOL-Key Key Data Encapsulation * GroupKey and STAKey require encryption, otherwise, encryption is optional. */static const u8 RSN_KEY_DATA_GROUPKEY[] = { 0x00, 0x0f, 0xac, 1 };static const u8 RSN_KEY_DATA_STAKEY[] = { 0x00, 0x0f, 0xac, 2 };static const u8 RSN_KEY_DATA_MAC_ADDR[] = { 0x00, 0x0f, 0xac, 3 };static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };/* 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) */struct wpa_ie_hdr { u8 elem_id; u8 len; u8 oui[3]; u8 oui_type; u16 version;} __attribute__ ((packed));/* 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) */struct rsn_ie_hdr { u8 elem_id; /* WLAN_EID_RSN */ u8 len; u16 version;} __attribute__ ((packed));static int wpa_write_wpa_ie(struct hostapd_data *hapd, u8 *buf, size_t len){ struct wpa_ie_hdr *hdr; int num_suites; u8 *pos, *count; hdr = (struct wpa_ie_hdr *) buf; hdr->elem_id = WLAN_EID_GENERIC; memcpy(&hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN); hdr->version = host_to_le16(WPA_VERSION); pos = (u8 *) (hdr + 1); if (hapd->conf->wpa_group == WPA_CIPHER_CCMP) { memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN); } else if (hapd->conf->wpa_group == WPA_CIPHER_TKIP) { memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN); } else if (hapd->conf->wpa_group == WPA_CIPHER_WEP104) { memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN); } else if (hapd->conf->wpa_group == WPA_CIPHER_WEP40) { memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN); } else { printf("Invalid group cipher (%d).\n", hapd->conf->wpa_group); return -1; } pos += WPA_SELECTOR_LEN; num_suites = 0; count = pos; pos += 2; if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) { memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN); pos += WPA_SELECTOR_LEN; num_suites++; } if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) { memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN); pos += WPA_SELECTOR_LEN; num_suites++; } if (hapd->conf->wpa_pairwise & WPA_CIPHER_NONE) { memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN); pos += WPA_SELECTOR_LEN; num_suites++; } if (num_suites == 0) { printf("Invalid pairwise cipher (%d).\n", hapd->conf->wpa_pairwise); return -1; } *count++ = num_suites & 0xff; *count = (num_suites >> 8) & 0xff; num_suites = 0; count = pos; pos += 2; if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN); pos += WPA_SELECTOR_LEN; num_suites++; } if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN); pos += WPA_SELECTOR_LEN; num_suites++; } if (num_suites == 0) { printf("Invalid key management type (%d).\n", hapd->conf->wpa_key_mgmt); return -1; } *count++ = num_suites & 0xff; *count = (num_suites >> 8) & 0xff; /* WPA Capabilities; use defaults, so no need to include it */ hdr->len = (pos - buf) - 2; return pos - buf;}static int wpa_write_rsn_ie(struct hostapd_data *hapd, u8 *buf, size_t len){ struct rsn_ie_hdr *hdr; int num_suites; u8 *pos, *count; hdr = (struct rsn_ie_hdr *) buf; hdr->elem_id = WLAN_EID_RSN; pos = (u8 *) &hdr->version; *pos++ = RSN_VERSION & 0xff; *pos++ = RSN_VERSION >> 8; pos = (u8 *) (hdr + 1); if (hapd->conf->wpa_group == WPA_CIPHER_CCMP) { memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN); } else if (hapd->conf->wpa_group == WPA_CIPHER_TKIP) { memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN); } else if (hapd->conf->wpa_group == WPA_CIPHER_WEP104) { memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN); } else if (hapd->conf->wpa_group == WPA_CIPHER_WEP40) { memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN); } else { printf("Invalid group cipher (%d).\n", hapd->conf->wpa_group); return -1; } pos += RSN_SELECTOR_LEN; num_suites = 0; count = pos; pos += 2; if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) { memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN); pos += RSN_SELECTOR_LEN; num_suites++; } if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) { memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN); pos += RSN_SELECTOR_LEN; num_suites++; } if (hapd->conf->wpa_pairwise & WPA_CIPHER_NONE) { memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN); pos += RSN_SELECTOR_LEN; num_suites++; } if (num_suites == 0) { printf("Invalid pairwise cipher (%d).\n", hapd->conf->wpa_pairwise); return -1; } *count++ = num_suites & 0xff; *count = (num_suites >> 8) & 0xff; num_suites = 0; count = pos; pos += 2; if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN); pos += RSN_SELECTOR_LEN; num_suites++; } if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN); pos += RSN_SELECTOR_LEN; num_suites++; } if (num_suites == 0) { printf("Invalid key management type (%d).\n", hapd->conf->wpa_key_mgmt); return -1; } *count++ = num_suites & 0xff; *count = (num_suites >> 8) & 0xff; /* RSN Capabilities */ *pos++ = hapd->conf->rsn_preauth ? BIT(0) : 0; *pos++ = 0; hdr->len = (pos - buf) - 2; return pos - buf;}static int wpa_gen_wpa_ie(struct hostapd_data *hapd){ u8 *pos, buf[100]; int res; pos = buf; if (hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA2) { res = wpa_write_rsn_ie(hapd, pos, buf + sizeof(buf) - pos); if (res < 0) return res; pos += res; } if (hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA) { res = wpa_write_wpa_ie(hapd, pos, buf + sizeof(buf) - pos); if (res < 0) return res; pos += res; } free(hapd->wpa_ie); hapd->wpa_ie = malloc(pos - buf); if (hapd->wpa_ie == NULL) return -1; memcpy(hapd->wpa_ie, buf, pos - buf); hapd->wpa_ie_len = pos - buf; return 0;}static void wpa_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta){ hostapd_sta_deauth(hapd, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED); eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta); sta->timeout_next = STA_REMOVE;}static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx){ struct hostapd_data *hapd = eloop_ctx; if (hapd->wpa_auth) { if (hostapd_get_rand(hapd->wpa_auth->GMK, WPA_GMK_LEN)) { printf("Failed to get random data for WPA " "initialization.\n"); } else { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "GMK rekeyd"); } } if (hapd->conf->wpa_gmk_rekey) { eloop_register_timeout(hapd->conf->wpa_gmk_rekey, 0, wpa_rekey_gmk, hapd, NULL); }}static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx){ struct hostapd_data *hapd = eloop_ctx; if (hapd->wpa_auth) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "rekeying GTK"); hapd->wpa_auth->GTKReKey = TRUE; do { hapd->wpa_auth->changed = FALSE; wpa_group_sm_step(hapd); } while (hapd->wpa_auth->changed); } if (hapd->conf->wpa_group_rekey) { eloop_register_timeout(hapd->conf->wpa_group_rekey, 0, wpa_rekey_gtk, hapd, NULL); }}#ifdef CONFIG_RSN_PREAUTHstatic void rsn_preauth_receive(void *ctx, unsigned char *src_addr, unsigned char *buf, size_t len){ struct rsn_preauth_interface *piface = ctx; struct hostapd_data *hapd = piface->hapd; struct ieee802_1x_hdr *hdr; struct sta_info *sta; struct l2_ethhdr *ethhdr; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: receive pre-auth packet " "from interface '%s'\n", piface->ifname); if (len < sizeof(*ethhdr) + sizeof(*hdr)) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: too short pre-auth " "packet (len=%lu)\n", (unsigned long) len); return; } ethhdr = (struct l2_ethhdr *) buf; hdr = (struct ieee802_1x_hdr *) (ethhdr + 1); if (memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for " "foreign address " MACSTR "\n", MAC2STR(ethhdr->h_dest)); return; } sta = ap_get_sta(hapd, ethhdr->h_source); if (sta && (sta->flags & WLAN_STA_ASSOC)) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for " "already association STA " MACSTR "\n", MAC2STR(sta->addr)); return; } if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) { sta = (struct sta_info *) malloc(sizeof(struct sta_info)); if (sta == NULL) return; memset(sta, 0, sizeof(*sta)); memcpy(sta->addr, ethhdr->h_source, ETH_ALEN); sta->flags = WLAN_STA_PREAUTH; sta->next = hapd->sta_list; sta->wpa = WPA_VERSION_WPA2; hapd->sta_list = sta; hapd->num_sta++; ap_sta_hash_add(hapd, sta); ieee802_1x_new_station(hapd, sta); if (sta->eapol_sm == NULL) { ap_free_sta(hapd, sta); sta = NULL; } else { sta->eapol_sm->radius_identifier = -1; sta->eapol_sm->portValid = TRUE; sta->eapol_sm->flags |= EAPOL_SM_PREAUTH; } } if (sta == NULL) return; sta->preauth_iface = piface; ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1), len - sizeof(*ethhdr));}static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname){ struct rsn_preauth_interface *piface; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN pre-auth interface '%s'\n", ifname); piface = malloc(sizeof(*piface)); if (piface == NULL) return -1; memset(piface, 0, sizeof(*piface)); piface->hapd = hapd; piface->ifname = strdup(ifname); if (piface->ifname == NULL) { goto fail1; } piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH, rsn_preauth_receive, piface); if (piface->l2 == NULL) { printf("Failed to open register layer 2 access to " "ETH_P_PREAUTH\n"); goto fail2; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -