]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RADIUS ACL/PSK check during 4-way handshake
authorJouni Malinen <j@w1.fi>
Sat, 2 Apr 2022 10:12:43 +0000 (13:12 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 2 Apr 2022 14:52:32 +0000 (17:52 +0300)
Add an alternative sequence for performing the RADIUS ACL check and PSK
fetch. The previously used (macaddr_acl=2, wpa_psk_radius=2) combination
does this during IEEE 802.11 Authentication frame exchange while the new
option (wpa_psk_radius=3) does this during the 4-way handshake. This
allows some more information to be provided to the RADIUS authentication
server.

Signed-off-by: Jouni Malinen <j@w1.fi>
12 files changed:
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_auth.c
src/ap/ieee802_11_auth.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_i.h

index a45fadbaa4991d88994cce6416c19d5fff1192c3..442c757f14168d32475bf0585b294a9b40691380 100644 (file)
@@ -2929,7 +2929,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->wpa_psk_radius = atoi(pos);
                if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
                    bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
-                   bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+                   bss->wpa_psk_radius != PSK_RADIUS_REQUIRED &&
+                   bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS) {
                        wpa_printf(MSG_ERROR,
                                   "Line %d: unknown wpa_psk_radius %d",
                                   line, bss->wpa_psk_radius);
index 9b0c809ea73fb350f736dfcd45389a554c2cf22c..71c11989e6acc0bdfbdd9c7f4b682fa2d8d1583f 100644 (file)
@@ -1655,12 +1655,15 @@ own_ip_addr=127.0.0.1
 #wpa_psk_file=/etc/hostapd.wpa_psk
 
 # Optionally, WPA passphrase can be received from RADIUS authentication server
-# This requires macaddr_acl to be set to 2 (RADIUS)
+# This requires macaddr_acl to be set to 2 (RADIUS) for wpa_psk_radius values
+# 1 and 2.
 # 0 = disabled (default)
 # 1 = optional; use default passphrase/psk if RADIUS server does not include
 #      Tunnel-Password
 # 2 = required; reject authentication if RADIUS server does not include
 #      Tunnel-Password
+# 3 = ask RADIUS server during 4-way handshake if there is no locally
+#      configured PSK/passphrase for the STA
 #wpa_psk_radius=0
 
 # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
index efbb87b9f309d702b4e5f49b2266865347e9f3f8..f2d13ea713ff4da1f8b1258059539d511bb8007b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration helper functions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -1243,6 +1243,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
 
        if (full_config && bss->wpa &&
            bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+           bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
            bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
                wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
                           "RADIUS checking (macaddr_acl=2) enabled.");
@@ -1253,6 +1254,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
            wpa_key_mgmt_wpa_psk_no_sae(bss->wpa_key_mgmt) &&
            bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
            bss->ssid.wpa_psk_file == NULL &&
+           bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
            (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
             bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
                wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
index 5a4c98f3447185a6155ca313abfe590eaaa9c74c..4b37a5c59e87609c8a5704c9bf97e12e3e14602f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -364,7 +364,8 @@ struct hostapd_bss_config {
        enum {
                PSK_RADIUS_IGNORED = 0,
                PSK_RADIUS_ACCEPTED = 1,
-               PSK_RADIUS_REQUIRED = 2
+               PSK_RADIUS_REQUIRED = 2,
+               PSK_RADIUS_DURING_4WAY_HS = 3,
        } wpa_psk_radius;
        int wpa_pairwise;
        int group_cipher; /* wpa_group value override from configuation */
index 147b0a67053338fd38f33a244702f07b86948447..c722242ebdb0dc502615c91bc2991f04cb653152 100644 (file)
@@ -2325,9 +2325,8 @@ static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
-static int
-ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
-                          int res, struct radius_sta *info)
+int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+                              int res, struct radius_sta *info)
 {
        u32 session_timeout = info->session_timeout;
        u32 acct_interim_interval = info->acct_interim_interval;
index 923cd520b281c9c4f3dcaa77593f1b97a6154cba..ccc8d8f5d79516e696ebd8429c99435555f8c400 100644 (file)
@@ -198,5 +198,7 @@ u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
                    const u8 *ext_capab_ie, size_t ext_capab_ie_len);
 size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type);
 u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type);
+int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+                              int res, struct radius_sta *info);
 
 #endif /* IEEE802_11_H */
index cf13008a1df81b5bf82eee79fde80ff38958c736..b9d9ea119f9abe556688878ad76689914528138f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -20,6 +20,8 @@
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "wpa_auth.h"
 #include "ieee802_11.h"
 #include "ieee802_1x.h"
 #include "ieee802_11_auth.h"
@@ -43,6 +45,8 @@ struct hostapd_acl_query_data {
        u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
        size_t auth_msg_len;
        struct hostapd_acl_query_data *next;
+       bool radius_psk;
+       int akm;
 };
 
 
@@ -153,6 +157,13 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
                goto fail;
        }
 
+       if (query->akm &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
+                                      wpa_akm_to_suite(query->akm))) {
+               wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite");
+               goto fail;
+       }
+
        if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
                goto fail;
        return 0;
@@ -557,17 +568,40 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
        cache->next = hapd->acl_cache;
        hapd->acl_cache = cache;
 
+       if (query->radius_psk) {
+               struct sta_info *sta;
+               bool success = cache->accepted == HOSTAPD_ACL_ACCEPT;
+
+               sta = ap_get_sta(hapd, query->addr);
+               if (!sta || !sta->wpa_sm) {
+                       wpa_printf(MSG_DEBUG,
+                                  "No STA/SM entry found for the RADIUS PSK response");
+                       goto done;
+               }
+#ifdef NEED_AP_MLME
+               if (success &&
+                   (ieee802_11_set_radius_info(hapd, sta, cache->accepted,
+                                               info) < 0 ||
+                    ap_sta_bind_vlan(hapd, sta) < 0))
+                       success = false;
+#endif /* NEED_AP_MLME */
+               wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success);
+       } else {
 #ifdef CONFIG_DRIVER_RADIUS_ACL
-       hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
-                                       info->session_timeout);
+               hostapd_drv_set_radius_acl_auth(hapd, query->addr,
+                                               cache->accepted,
+                                               info->session_timeout);
 #else /* CONFIG_DRIVER_RADIUS_ACL */
 #ifdef NEED_AP_MLME
-       /* Re-send original authentication frame for 802.11 processing */
-       wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
-                  "successful RADIUS ACL query");
-       ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
+               /* Re-send original authentication frame for 802.11 processing
+                */
+               wpa_printf(MSG_DEBUG,
+                          "Re-sending authentication frame after successful RADIUS ACL query");
+               ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
+                               NULL);
 #endif /* NEED_AP_MLME */
 #endif /* CONFIG_DRIVER_RADIUS_ACL */
+       }
 
  done:
        if (prev == NULL)
@@ -649,3 +683,31 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
                bin_clear_free(prev, sizeof(*prev));
        }
 }
+
+
+#ifndef CONFIG_NO_RADIUS
+void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
+                               int key_mgmt, const u8 *anonce,
+                               const u8 *eapol, size_t eapol_len)
+{
+       struct hostapd_acl_query_data *query;
+
+       query = os_zalloc(sizeof(*query));
+       if (!query)
+               return;
+
+       query->radius_psk = true;
+       query->akm = key_mgmt;
+       os_get_reltime(&query->timestamp);
+       os_memcpy(query->addr, addr, ETH_ALEN);
+       if (hostapd_radius_acl_query(hapd, addr, query)) {
+               wpa_printf(MSG_DEBUG,
+                          "Failed to send Access-Request for RADIUS PSK/ACL query");
+               hostapd_acl_query_free(query);
+               return;
+       }
+
+       query->next = hapd->acl_queries;
+       hapd->acl_queries = query;
+}
+#endif /* CONFIG_NO_RADIUS */
index 9410f55c5807fa7d3dab98e22182a1a6467628c8..22ae1a9d3dbab1167d649b7dc915c25082e5c7e0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -36,5 +36,8 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
 void hostapd_acl_expire(struct hostapd_data *hapd);
 void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
                           struct hostapd_sta_wpa_psk_short *src);
+void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
+                               int key_mgmt, const u8 *anonce,
+                               const u8 *eapol, size_t eapol_len);
 
 #endif /* IEEE802_11_AUTH_H */
index 6c58c2113d5dd49054dd8535502aa3977e7221d2..7da102e908efc783946245bc971b428dcf93d4f2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -1481,6 +1481,12 @@ static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
        struct wpa_authenticator *wpa_auth = eloop_ctx;
        struct wpa_state_machine *sm = timeout_ctx;
 
+       if (sm->waiting_radius_psk) {
+               wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+                               "Ignore EAPOL-Key timeout while waiting for RADIUS PSK");
+               return;
+       }
+
        sm->pending_1_of_4_timeout = 0;
        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
        sm->TimeoutEvt = true;
@@ -3017,6 +3023,19 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                        break;
        }
 
+       if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
+           wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk &&
+           !sm->waiting_radius_psk) {
+               wpa_printf(MSG_DEBUG, "No PSK available - ask RADIUS server");
+               wpa_auth->cb->request_radius_psk(wpa_auth->cb_ctx, sm->addr,
+                                                sm->wpa_key_mgmt,
+                                                sm->ANonce,
+                                                sm->last_rx_eapol_key,
+                                                sm->last_rx_eapol_key_len);
+               sm->waiting_radius_psk = 1;
+               return;
+       }
+
        if (!ok) {
                wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
                                "invalid MIC in msg 2/4 of 4-Way Handshake");
@@ -3776,6 +3795,11 @@ SM_STEP(WPA_PTK)
                } else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
                        SM_ENTER(WPA_PTK, PTKSTART);
 #endif /* CONFIG_SAE */
+               } else if (wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
+                          wpa_auth->conf.radius_psk) {
+                       wpa_printf(MSG_DEBUG,
+                                  "INITPSK: No PSK yet available for STA - use RADIUS later");
+                       SM_ENTER(WPA_PTK, PTKSTART);
                } else {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "no PSK configured for the STA");
@@ -5689,3 +5713,28 @@ void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
 }
 
 #endif /* CONFIG_TESTING_OPTIONS */
+
+
+void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success)
+{
+       if (!sm->waiting_radius_psk) {
+               wpa_printf(MSG_DEBUG,
+                          "Ignore RADIUS PSK response for " MACSTR
+                          " that did not wait one",
+                          MAC2STR(sm->addr));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "RADIUS PSK response for " MACSTR " (%s)",
+                  MAC2STR(sm->addr), success ? "success" : "fail");
+       sm->waiting_radius_psk = 0;
+
+       if (success) {
+               /* Try to process the EAPOL-Key msg 2/4 again */
+               sm->EAPOLKeyReceived = true;
+       } else {
+               sm->Disconnect = true;
+       }
+
+       eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
+}
index fe47723b9e6bb8b81161fe744d2aed8a8ae6c93e..d2a36006a9c47a2ad2869d9f8f14e5e032dcc328 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -273,6 +273,8 @@ struct wpa_auth_config {
         * PTK derivation regardless of advertised capabilities.
         */
        bool force_kdk_derivation;
+
+       bool radius_psk;
 };
 
 typedef enum {
@@ -320,6 +322,9 @@ struct wpa_auth_callbacks {
        void (*store_ptksa)(void *ctx, const u8 *addr, int cipher,
                            u32 life_time, const struct wpa_ptk *ptk);
        void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher);
+       void (*request_radius_psk)(void *ctx, const u8 *addr, int key_mgmt,
+                                  const u8 *anonce,
+                                  const u8 *eapol, size_t eapol_len);
 #ifdef CONFIG_IEEE80211R_AP
        struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
        int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
@@ -572,4 +577,6 @@ void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
                                    enum wpa_auth_ocv_override_frame frame,
                                    unsigned int freq);
 
+void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success);
+
 #endif /* WPA_AUTH_H */
index 1103a48d7e200b4ed0723e0f73d767443939c694..71a487161cf4fd229f5dd5d212277e016adb8ba6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,6 +29,7 @@
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 #include "ieee802_11.h"
+#include "ieee802_11_auth.h"
 #include "pmksa_cache_auth.h"
 #include "wpa_auth.h"
 #include "wpa_auth_glue.h"
@@ -214,6 +215,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
        wconf->force_kdk_derivation = conf->force_kdk_derivation;
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_PASN */
+
+       wconf->radius_psk = conf->wpa_psk_radius == PSK_RADIUS_DURING_4WAY_HS;
 }
 
 
@@ -1443,6 +1446,23 @@ static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd)
 #endif /* CONFIG_IEEE80211R_AP */
 
 
+#ifndef CONFIG_NO_RADIUS
+static void hostapd_request_radius_psk(void *ctx, const u8 *addr, int key_mgmt,
+                                      const u8 *anonce,
+                                      const u8 *eapol, size_t eapol_len)
+{
+       struct hostapd_data *hapd = ctx;
+
+       wpa_printf(MSG_DEBUG, "RADIUS PSK request for " MACSTR " key_mgmt=0x%x",
+                  MAC2STR(addr), key_mgmt);
+       wpa_hexdump(MSG_DEBUG, "ANonce", anonce, WPA_NONCE_LEN);
+       wpa_hexdump(MSG_DEBUG, "EAPOL", eapol, eapol_len);
+       hostapd_acl_req_radius_psk(hapd, addr, key_mgmt, anonce, eapol,
+                                  eapol_len);
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
 int hostapd_setup_wpa(struct hostapd_data *hapd)
 {
        struct wpa_auth_config _conf;
@@ -1486,6 +1506,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
                .set_session_timeout = hostapd_wpa_auth_set_session_timeout,
                .get_session_timeout = hostapd_wpa_auth_get_session_timeout,
 #endif /* CONFIG_IEEE80211R_AP */
+#ifndef CONFIG_NO_RADIUS
+               .request_radius_psk = hostapd_request_radius_psk,
+#endif /* CONFIG_NO_RADIUS */
        };
        const u8 *wpa_ie;
        size_t wpa_ie_len;
index a6dc1a59185d4756e3600e371eb2ca5f46517940..7e93e5ab8c8b935124ef20f75894b2e2b0da84ae 100644 (file)
@@ -89,6 +89,7 @@ struct wpa_state_machine {
        unsigned int rx_eapol_key_secure:1;
        unsigned int update_snonce:1;
        unsigned int alt_snonce_valid:1;
+       unsigned int waiting_radius_psk:1;
 #ifdef CONFIG_IEEE80211R_AP
        unsigned int ft_completed:1;
        unsigned int pmk_r1_name_valid:1;