Defer passphrase-to-PSK hashing out of 802.11 authentication ACL check
authorMichael Braun <michael-dev@fami-braun.de>
Wed, 24 Feb 2016 11:53:36 +0000 (12:53 +0100)
committerJouni Malinen <j@w1.fi>
Sun, 28 Feb 2016 16:46:05 +0000 (18:46 +0200)
Hashing takes quite some time (can be about one second on a low-power
CPU for each passphrase provided), so hostapd can easily hit the 900 ms
Wi-Fi client authentication deadline (mac80211 uses 3x 300 ms). This can
be fixed by storing the passphrase instead of PSK with the STA and defer
the hashing into the WPA/RSN 4-way handshake, when enumerating all PSKs.

This applies for the case where a RADIUS server is used to store the
per-STA passphrases and this passphrase is delivered as part of the MAC
ACL check during IEEE 802.11 Authentication frame processing.

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
src/ap/ap_config.h
src/ap/ieee802_11_auth.c
src/ap/wpa_auth_glue.c

index 9afca48..90405b4 100644 (file)
@@ -128,9 +128,12 @@ struct hostapd_vlan {
 };
 
 #define PMK_LEN 32
+#define MAX_PASSPHRASE_LEN 63
 struct hostapd_sta_wpa_psk_short {
        struct hostapd_sta_wpa_psk_short *next;
+       unsigned int is_passphrase:1;
        u8 psk[PMK_LEN];
+       char passphrase[MAX_PASSPHRASE_LEN + 1];
 };
 
 struct hostapd_wpa_psk {
index f280709..6afdc5d 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
-#include "crypto/sha1.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "hostapd.h"
@@ -443,7 +442,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
                                    struct hostapd_cached_radius_acl *cache)
 {
        int passphraselen;
-       char *passphrase, *strpassphrase;
+       char *passphrase;
        size_t i;
        struct hostapd_sta_wpa_psk_short *psk;
 
@@ -464,19 +463,16 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
                 * passphrase does not contain the NULL termination.
                 * Add it here as pbkdf2_sha1() requires it.
                 */
-               strpassphrase = os_zalloc(passphraselen + 1);
                psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
-               if (strpassphrase && psk) {
-                       os_memcpy(strpassphrase, passphrase, passphraselen);
-                       pbkdf2_sha1(strpassphrase,
-                                   hapd->conf->ssid.ssid,
-                                   hapd->conf->ssid.ssid_len, 4096,
-                                   psk->psk, PMK_LEN);
+               if (psk) {
+                       if (passphraselen > MAX_PASSPHRASE_LEN)
+                               passphraselen = MAX_PASSPHRASE_LEN;
+                       os_memcpy(psk->passphrase, passphrase, passphraselen);
+                       psk->is_passphrase = 1;
                        psk->next = cache->psk;
                        cache->psk = psk;
                        psk = NULL;
                }
-               os_free(strpassphrase);
                os_free(psk);
                os_free(passphrase);
        }
index fb830e9..e92415a 100644 (file)
@@ -12,6 +12,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/sae.h"
 #include "common/wpa_ctrl.h"
+#include "crypto/sha1.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
 #include "eap_server/eap.h"
@@ -246,6 +247,13 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
                struct hostapd_sta_wpa_psk_short *pos;
                psk = sta->psk->psk;
                for (pos = sta->psk; pos; pos = pos->next) {
+                       if (pos->is_passphrase) {
+                               pbkdf2_sha1(pos->passphrase,
+                                           hapd->conf->ssid.ssid,
+                                           hapd->conf->ssid.ssid_len, 4096,
+                                           pos->psk, PMK_LEN);
+                               pos->is_passphrase = 0;
+                       }
                        if (pos->psk == prev_psk) {
                                psk = pos->next ? pos->next->psk : NULL;
                                break;