📄 wpa.c
字号:
/* * hostapd - IEEE 802.11i-2004 / WPA Authenticator * Copyright (c) 2004-2008, Jouni Malinen <j@w1.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 "includes.h"#ifndef CONFIG_NATIVE_WINDOWS#include "common.h"#include "config.h"#include "eapol_sm.h"#include "wpa.h"#include "sha1.h"#include "sha256.h"#include "rc4.h"#include "aes_wrap.h"#include "crypto.h"#include "eloop.h"#include "ieee802_11.h"#include "pmksa_cache.h"#include "state_machine.h"#include "wpa_auth_i.h"#include "wpa_auth_ie.h"#define STATE_MACHINE_DATA struct wpa_state_machine#define STATE_MACHINE_DEBUG_PREFIX "WPA"#define STATE_MACHINE_ADDR sm->addrstatic 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 wpa_authenticator *wpa_auth, struct wpa_group *group);static void wpa_request_new_ptk(struct wpa_state_machine *sm);static const u32 dot11RSNAConfigGroupUpdateCount = 4;static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;static const u32 eapol_key_timeout_first = 100; /* ms */static const u32 eapol_key_timeout_subseq = 1000; /* ms *//* TODO: make these configurable */static const int dot11RSNAConfigPMKLifetime = 43200;static const int dot11RSNAConfigPMKReauthThreshold = 70;static const int dot11RSNAConfigSATimeout = 60;static inline void wpa_auth_mic_failure_report( struct wpa_authenticator *wpa_auth, const u8 *addr){ if (wpa_auth->cb.mic_failure_report) wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);}static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, wpa_eapol_variable var, int value){ if (wpa_auth->cb.set_eapol) wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);}static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, wpa_eapol_variable var){ if (wpa_auth->cb.get_eapol == NULL) return -1; return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);}static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *prev_psk){ if (wpa_auth->cb.get_psk == NULL) return NULL; return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk);}static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, const u8 *addr, u8 *msk, size_t *len){ if (wpa_auth->cb.get_msk == NULL) return -1; return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len);}static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, const char *alg, const u8 *addr, int idx, u8 *key, size_t key_len){ if (wpa_auth->cb.set_key == NULL) return -1; return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx, key, key_len);}static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, const u8 *addr, int idx, u8 *seq){ if (wpa_auth->cb.get_seqnum == NULL) return -1; return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);}static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator *wpa_auth, const u8 *addr, int idx, u8 *seq){ if (wpa_auth->cb.get_seqnum_igtk == NULL) return -1; return wpa_auth->cb.get_seqnum_igtk(wpa_auth->cb.ctx, addr, idx, seq);}static inline intwpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *data, size_t data_len, int encrypt){ if (wpa_auth->cb.send_eapol == NULL) return -1; return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len, encrypt);}int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, int (*cb)(struct wpa_state_machine *sm, void *ctx), void *cb_ctx){ if (wpa_auth->cb.for_each_sta == NULL) return 0; return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);}int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, int (*cb)(struct wpa_authenticator *a, void *ctx), void *cb_ctx){ if (wpa_auth->cb.for_each_auth == NULL) return 0; return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx);}void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, logger_level level, const char *txt){ if (wpa_auth->cb.logger == NULL) return; wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);}void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, logger_level level, const char *fmt, ...){ char *format; int maxlen; va_list ap; if (wpa_auth->cb.logger == NULL) return; maxlen = os_strlen(fmt) + 100; format = os_malloc(maxlen); if (!format) return; va_start(ap, fmt); vsnprintf(format, maxlen, fmt, ap); va_end(ap); wpa_auth_logger(wpa_auth, addr, level, format); os_free(format);}static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, const u8 *addr){ if (wpa_auth->cb.disconnect == NULL) return; wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);}static int wpa_use_aes_cmac(struct wpa_state_machine *sm){ int ret = 0;#ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) ret = 1;#endif /* CONFIG_IEEE80211R */#ifdef CONFIG_IEEE80211W if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt)) ret = 1;#endif /* CONFIG_IEEE80211W */ return ret;}static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx){ struct wpa_authenticator *wpa_auth = eloop_ctx; if (os_get_random(wpa_auth->group->GMK, WPA_GMK_LEN)) { wpa_printf(MSG_ERROR, "Failed to get random data for WPA " "initialization."); } else { wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd"); } if (wpa_auth->conf.wpa_gmk_rekey) { eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0, wpa_rekey_gmk, wpa_auth, NULL); }}static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx){ struct wpa_authenticator *wpa_auth = eloop_ctx; struct wpa_group *group; wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK"); for (group = wpa_auth->group; group; group = group->next) { group->GTKReKey = TRUE; do { group->changed = FALSE; wpa_group_sm_step(wpa_auth, group); } while (group->changed); } if (wpa_auth->conf.wpa_group_rekey) { eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0, wpa_rekey_gtk, wpa_auth, NULL); }}static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx){ struct wpa_authenticator *wpa_auth = eloop_ctx; struct wpa_state_machine *sm = timeout_ctx; wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK"); wpa_request_new_ptk(sm); wpa_sm_step(sm);}static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx){ if (sm->pmksa == ctx) sm->pmksa = NULL; return 0;}static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, void *ctx){ struct wpa_authenticator *wpa_auth = ctx; wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);}static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, int vlan_id){ struct wpa_group *group; u8 buf[ETH_ALEN + 8 + sizeof(group)]; u8 rkey[32]; group = os_zalloc(sizeof(struct wpa_group)); if (group == NULL) return NULL; group->GTKAuthenticator = TRUE; group->vlan_id = vlan_id; switch (wpa_auth->conf.wpa_group) { case WPA_CIPHER_CCMP: group->GTK_len = 16; break; case WPA_CIPHER_TKIP: group->GTK_len = 32; break; case WPA_CIPHER_WEP104: group->GTK_len = 13; break; case WPA_CIPHER_WEP40: group->GTK_len = 5; break; } /* Counter = PRF-256(Random number, "Init Counter", * Local MAC Address || Time) */ os_memcpy(buf, wpa_auth->addr, ETH_ALEN); wpa_get_ntp_timestamp(buf + ETH_ALEN); os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group)); if (os_get_random(rkey, sizeof(rkey)) || os_get_random(group->GMK, WPA_GMK_LEN)) { wpa_printf(MSG_ERROR, "Failed to get random data for WPA " "initialization."); os_free(group); return NULL; } sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf), group->Counter, WPA_NONCE_LEN); group->GInit = TRUE; wpa_group_sm_step(wpa_auth, group); group->GInit = FALSE; wpa_group_sm_step(wpa_auth, group); return group;}/** * wpa_init - Initialize WPA authenticator * @addr: Authenticator address * @conf: Configuration for WPA authenticator * @cb: Callback functions for WPA authenticator * Returns: Pointer to WPA authenticator data or %NULL on failure */struct wpa_authenticator * wpa_init(const u8 *addr, struct wpa_auth_config *conf, struct wpa_auth_callbacks *cb){ struct wpa_authenticator *wpa_auth; wpa_auth = os_zalloc(sizeof(struct wpa_authenticator)); if (wpa_auth == NULL) return NULL; os_memcpy(wpa_auth->addr, addr, ETH_ALEN); os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); os_memcpy(&wpa_auth->cb, cb, sizeof(*cb)); if (wpa_auth_gen_wpa_ie(wpa_auth)) { wpa_printf(MSG_ERROR, "Could not generate WPA IE."); os_free(wpa_auth); return NULL; } wpa_auth->group = wpa_group_init(wpa_auth, 0); if (wpa_auth->group == NULL) { os_free(wpa_auth->wpa_ie); os_free(wpa_auth); return NULL; } wpa_auth->pmksa = pmksa_cache_init(wpa_auth_pmksa_free_cb, wpa_auth); if (wpa_auth->pmksa == NULL) { wpa_printf(MSG_ERROR, "PMKSA cache initialization failed."); os_free(wpa_auth->wpa_ie); os_free(wpa_auth); return NULL; }#ifdef CONFIG_IEEE80211R wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init(); if (wpa_auth->ft_pmk_cache == NULL) { wpa_printf(MSG_ERROR, "FT PMK cache initialization failed."); os_free(wpa_auth->wpa_ie); pmksa_cache_deinit(wpa_auth->pmksa); os_free(wpa_auth); return NULL; }#endif /* CONFIG_IEEE80211R */ if (wpa_auth->conf.wpa_gmk_rekey) { eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0, wpa_rekey_gmk, wpa_auth, NULL); } if (wpa_auth->conf.wpa_group_rekey) { eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0, wpa_rekey_gtk, wpa_auth, NULL); } return wpa_auth;}/** * wpa_deinit - Deinitialize WPA authenticator * @wpa_auth: Pointer to WPA authenticator data from wpa_init() */void wpa_deinit(struct wpa_authenticator *wpa_auth){ struct wpa_group *group, *prev; eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL); eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);#ifdef CONFIG_PEERKEY while (wpa_auth->stsl_negotiations) wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);#endif /* CONFIG_PEERKEY */ pmksa_cache_deinit(wpa_auth->pmksa);#ifdef CONFIG_IEEE80211R wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache); wpa_auth->ft_pmk_cache = NULL;#endif /* CONFIG_IEEE80211R */ os_free(wpa_auth->wpa_ie); group = wpa_auth->group; while (group) { prev = group; group = group->next; os_free(prev); } os_free(wpa_auth);}/** * wpa_reconfig - Update WPA authenticator configuration * @wpa_auth: Pointer to WPA authenticator data from wpa_init() * @conf: Configuration for WPA authenticator */int wpa_reconfig(struct wpa_authenticator *wpa_auth, struct wpa_auth_config *conf){ if (wpa_auth == NULL) return 0; os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); if (wpa_auth_gen_wpa_ie(wpa_auth)) { wpa_printf(MSG_ERROR, "Could not generate WPA IE."); return -1; } return 0;}struct wpa_state_machine *wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr){ struct wpa_state_machine *sm; sm = os_zalloc(sizeof(struct wpa_state_machine)); if (sm == NULL) return NULL; os_memcpy(sm->addr, addr, ETH_ALEN); sm->wpa_auth = wpa_auth; sm->group = wpa_auth->group; return sm;}void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm){ if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) return;#ifdef CONFIG_IEEE80211R
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -