From patchwork Tue Jul 2 10:05:00 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 256315 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from maxx.maxx.shmoo.com (maxx.shmoo.com [205.134.188.171]) by ozlabs.org (Postfix) with ESMTP id 7D3822C00A1 for ; Tue, 2 Jul 2013 20:08:18 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id E0D269C20E; Tue, 2 Jul 2013 06:07:51 -0400 (EDT) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id U4wKGRBy2h74; Tue, 2 Jul 2013 06:07:51 -0400 (EDT) Received: from maxx.shmoo.com (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id D09D39C1D8; Tue, 2 Jul 2013 06:07:22 -0400 (EDT) X-Original-To: mailman-post+hostap@maxx.shmoo.com Delivered-To: mailman-post+hostap@maxx.shmoo.com Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 48A179C1B8 for ; Tue, 2 Jul 2013 06:07:21 -0400 (EDT) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jyINzD-pJz2r for ; Tue, 2 Jul 2013 06:07:17 -0400 (EDT) Received: from diserzione.investici.org (diserzione.investici.org [82.221.99.153]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "smtp.autistici.org", Issuer "Autistici/Inventati Certification Authority" (not verified)) by maxx.maxx.shmoo.com (Postfix) with ESMTPS id 108769C1B9 for ; Tue, 2 Jul 2013 06:07:15 -0400 (EDT) Received: from [82.221.99.153] (diserzione [82.221.99.153]) (Authenticated sender: ordex@autistici.org) by localhost (Postfix) with ESMTPSA id 362911806B5; Tue, 2 Jul 2013 10:07:13 +0000 (UTC) X-DKIM: Sendmail DKIM Filter v2.8.2 diserzione.investici.org 362911806B5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1372759634; bh=xzqpYNcvvp89Nh46MyZwJ4xQX7kQyK2qdBndjQhFy5U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=mcaijKIKoeyJMyQvheNg7s5cK7wkKOfhkGt7/FYRoqQNiirU1vRbw3EJQDXwNh7Vc ut187cgMkggeSZP4/W1AdI0+y6Gvu57FcK3LPL9rDTcbqlwX4vGrw96EUD/1DKiOhA UV4PBjaLEmnDM7vmXDXCMVyScPynNnuZBKHICAFI= From: Antonio Quartulli To: hostap Subject: [PATCHv2 3/3] Improve the IBSS/RSN mechanism Date: Tue, 2 Jul 2013 12:05:00 +0200 Message-Id: <1372759500-4002-4-git-send-email-ordex@autistici.org> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1372759500-4002-1-git-send-email-ordex@autistici.org> References: <1372759500-4002-1-git-send-email-ordex@autistici.org> Cc: Antonio Quartulli X-BeenThere: hostap@lists.shmoo.com X-Mailman-Version: 2.1.11 Precedence: list List-Id: HostAP Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: hostap-bounces@lists.shmoo.com Errors-To: hostap-bounces@lists.shmoo.com From: Antonio Quartulli To better support the IBSS/RSN mechanism, wpa_supplicant has to be able to detect a possible peer reboot and in this case it should start a new EAPOL handshake. To perform such reboot detection wpa_supplicant has to perform an Open Authentication by sending an AUTH message and then replying to it. Is an AUTH message is received when the key have already been exchanged, wpa_supplicant understands that the peer has rebooted and can reset its state machine. Whenever a new peer is added to the IBSS wpa_supplicant will start the Open Authentication and only after having accomplished it will start the key exchange. The Open Authentication was partly supported by the kernel but now wpa_supplicant can register for AUTH frames, handle it in userspace and so avoid any possible race condition. Signed-hostap: Nicolas Cavallari Signed-hostap: Antonio Quartulli --- wpa_supplicant/events.c | 31 +++++- wpa_supplicant/ibss_rsn.c | 234 ++++++++++++++++++++++++++++++++++++++++------ wpa_supplicant/ibss_rsn.h | 12 +++ 3 files changed, 246 insertions(+), 31 deletions(-) diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index f757c72..b5ca1a7 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2300,6 +2300,22 @@ static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s, ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer); } + +static void wpa_supplicant_event_ibss_auth(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (ssid == NULL) + return; + + /* check if the ssid is correctly configured as IBSS/RSN */ + if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt)) + return; + + ibss_rsn_handle_auth(wpa_s->ibss_rsn, data->rx_mgmt.frame, + data->rx_mgmt.frame_len); +} #endif /* CONFIG_IBSS_RSN */ @@ -2694,6 +2710,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.ch_offset); #endif /* CONFIG_AP */ break; +#endif /* CONFIG_AP */ +#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN) case EVENT_RX_MGMT: { u16 fc, stype; const struct ieee80211_mgmt *mgmt; @@ -2703,7 +2721,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, fc = le_to_host16(mgmt->frame_control); stype = WLAN_FC_GET_STYPE(fc); +#ifdef CONFIG_AP if (wpa_s->ap_iface == NULL) { +#endif /* CONFIG_AP */ #ifdef CONFIG_P2P if (stype == WLAN_FC_STYPE_PROBE_REQ && data->rx_mgmt.frame_len > 24) { @@ -2719,9 +2739,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } #endif /* CONFIG_P2P */ +#ifdef CONFIG_IBSS_RSN + if (stype == WLAN_FC_STYPE_AUTH && + data->rx_mgmt.frame_len >= 30) { + wpa_supplicant_event_ibss_auth(wpa_s, data); + break; + } +#endif /* CONFIG_IBSS_RSN */ wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received " "management frame in non-AP mode"); break; +#ifdef CONFIG_AP } if (stype == WLAN_FC_STYPE_PROBE_REQ && @@ -2737,9 +2765,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } ap_mgmt_rx(wpa_s, &data->rx_mgmt); +#endif /* CONFIG_AP */ break; } -#endif /* CONFIG_AP */ +#endif /* CONFIG_AP || CONFIG_IBSS_RSN */ case EVENT_RX_ACTION: wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR " Category=%u DataLen=%d freq=%d MHz", diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 687c042..05ad5f2 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -15,6 +15,7 @@ #include "ap/wpa_auth.h" #include "wpa_supplicant_i.h" #include "driver_i.h" +#include "common/ieee802_11_defs.h" #include "ibss_rsn.h" @@ -437,48 +438,123 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, return 0; } +static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8* da, int seq) +{ + struct ieee80211_mgmt auth; + const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth); + struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; -int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) + if (wpa_s->driver->send_frame == NULL) + return -1; + + memset(&auth, 0, sizeof(auth)); + + auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_AUTH); + memcpy(auth.da, da, ETH_ALEN); + memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN); + memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN); + + auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN); + auth.u.auth.auth_transaction = host_to_le16(seq); + auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS); + + wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR, + seq, MAC2STR(da)); + + return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *)&auth, + auth_length, 0); +} + +static int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer) { - struct ibss_rsn_peer *peer; + return peer->authentication_status & + (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US); +} +static struct ibss_rsn_peer * +ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr) +{ + struct ibss_rsn_peer *peer; if (ibss_rsn == NULL) - return -1; + return NULL; - if (ibss_rsn_get_peer(ibss_rsn, addr)) { - wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant " - "for peer " MACSTR " already running", - MAC2STR(addr)); - return 0; + peer = ibss_rsn_get_peer(ibss_rsn, addr); + if (peer) { + wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR + " already running", MAC2STR(addr)); + return peer; } - wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " - "Supplicant for peer " MACSTR, MAC2STR(addr)); + wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR, + MAC2STR(addr)); peer = os_zalloc(sizeof(*peer)); - if (peer == NULL) - return -1; + if (peer == NULL) { + wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory."); + return NULL; + } peer->ibss_rsn = ibss_rsn; os_memcpy(peer->addr, addr, ETH_ALEN); + peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED; - if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) - < 0) { + if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, + ibss_rsn->psk) < 0) { ibss_rsn_free(peer); - return -1; - } - - if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) { - ibss_rsn_free(peer); - return -1; + return NULL; } peer->next = ibss_rsn->peers; ibss_rsn->peers = peer; + return peer; +} + + +int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) +{ + struct ibss_rsn_peer *peer; + + /* if the peer already exists, exit immediately */ + peer = ibss_rsn_get_peer(ibss_rsn, addr); + if (peer) + return 0; + + peer = ibss_rsn_peer_init(ibss_rsn, addr); + if (peer == NULL) + return -1; + + /* Open Authentication: send first AUTH frame */ + ibss_rsn_send_auth(ibss_rsn, addr, 1); + return 0; } +static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn, + struct ibss_rsn_peer * peer, + int reason) +{ + int already_started; + + if (ibss_rsn == NULL || peer == NULL) + return -1; + + already_started = ibss_rsn_is_auth_started(peer); + peer->authentication_status |= reason; + + if (already_started) { + wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already " + "started for peer " MACSTR, MAC2STR(peer->addr)); + return 0; + } + + wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator " + "for now-authenticated peer " MACSTR, MAC2STR(peer->addr)); + + return ibss_rsn_auth_init(ibss_rsn, peer); +} + void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) { @@ -605,27 +681,43 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer, const u8 *buf, size_t len) { - int supp; - u8 *tmp; + int supp, ret = -1; + u8 *tmp = NULL; supp = ibss_rsn_eapol_dst_supp(buf, len); if (supp < 0) - return -1; + goto out; tmp = os_malloc(len); if (tmp == NULL) - return -1; + goto out; + os_memcpy(tmp, buf, len); + if (supp) { - wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant"); + peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER; + wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from " + MACSTR, MAC2STR(peer->addr)); wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); } else { - wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator"); + if (ibss_rsn_is_auth_started(peer) == 0) { + wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for " + "Authenticator dropped as " MACSTR " is not " + "authenticated", MAC2STR(peer->addr)); + + goto out; + } + + wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator " + "from "MACSTR, MAC2STR(peer->addr)); wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len); } - os_free(tmp); + ret = 1; +out: + if (tmp) + os_free(tmp); - return 1; + return ret; } @@ -646,8 +738,16 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, * Create new IBSS peer based on an EAPOL message from the peer * Authenticator. */ - if (ibss_rsn_start(ibss_rsn, src_addr) < 0) + peer = ibss_rsn_peer_init(ibss_rsn, src_addr); + if (peer == NULL) return -1; + + /* assume the peer is authenticated already */ + wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer " + MACSTR, MAC2STR(src_addr)); + ibss_rsn_peer_authenticated(ibss_rsn, peer, + IBSS_RSN_AUTH_EAPOL_BY_US); + return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, buf, len); } @@ -655,10 +755,84 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, return 0; } - void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) { if (ibss_rsn == NULL) return; os_memcpy(ibss_rsn->psk, psk, PMK_LEN); } + +static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, + struct ibss_rsn_peer *peer, + const u8* addr) { + wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR, + MAC2STR(addr)); + + if (peer && + peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) { + /* A peer sent us an AUTH message even if it already started an + * EAPOL session. We should reinit state machines here, but it's + * much more complicated than just deleting and recreating the + * state machine + */ + wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station " MACSTR, + MAC2STR(addr)); + + ibss_rsn_stop(ibss_rsn, addr); + peer = NULL; + } + + if (!peer) { + peer = ibss_rsn_peer_init(ibss_rsn, addr); + if (!peer) + return; + + wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR, + MAC2STR(addr)); + } + + /* reply with an AUTH frame now, before sending an EAPOL */ + ibss_rsn_send_auth(ibss_rsn, addr, 2); + /* no need to start another AUTH challenge in the other way.. */ + ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US); +} + + +void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, + size_t len) { + const struct ieee80211_mgmt *header; + struct ibss_rsn_peer *peer; + size_t auth_length; + + header = (const struct ieee80211_mgmt *)auth_frame; + auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth); + + if (ibss_rsn == NULL || len < auth_length) + return; + + if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN || + le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS) + return; + + peer = ibss_rsn_get_peer(ibss_rsn, header->sa); + + switch (le_to_host16(header->u.auth.auth_transaction)) { + case 1: + ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa); + break; + case 2: + wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from " + MACSTR, MAC2STR(header->sa)); + if (!peer) { + wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from " + "unknown sta " MACSTR, MAC2STR(header->sa)); + break; + } + + /* authentication has been completed */ + wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with "MACSTR, + MAC2STR(header->sa)); + ibss_rsn_peer_authenticated(ibss_rsn, peer, + IBSS_RSN_AUTH_BY_US); + } +} diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h index 1da94ab..5a8eda4 100644 --- a/wpa_supplicant/ibss_rsn.h +++ b/wpa_supplicant/ibss_rsn.h @@ -11,6 +11,15 @@ struct ibss_rsn; +/* not authenticated */ +#define IBSS_RSN_AUTH_NOT_AUTHENTICATED 0x00 +/* remote peer sent an EAPOL message */ +#define IBSS_RSN_AUTH_EAPOL_BY_PEER 0x01 +/* we sent an AUTH message with seq 1 */ +#define IBSS_RSN_AUTH_BY_US 0x02 +/* we sent an EAPOL message */ +#define IBSS_RSN_AUTH_EAPOL_BY_US 0x04 + struct ibss_rsn_peer { struct ibss_rsn_peer *next; struct ibss_rsn *ibss_rsn; @@ -23,6 +32,7 @@ struct ibss_rsn_peer { size_t supp_ie_len; struct wpa_state_machine *auth; + int authentication_status; }; struct ibss_rsn { @@ -40,5 +50,7 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac); int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, const u8 *buf, size_t len); void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk); +void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, + size_t len); #endif /* IBSS_RSN_H */