aboutsummaryrefslogtreecommitdiffstats
path: root/src/ap
diff options
context:
space:
mode:
authorMichael Braun <michael-dev@fami-braun.de>2011-12-11 11:01:57 (GMT)
committerJouni Malinen <j@w1.fi>2011-12-11 11:01:57 (GMT)
commit05ab9712b9977192b713f01f07c3b14ca4d1ba78 (patch)
tree1e97b6daa1f6f5053e97b58be2955bd65a30c696 /src/ap
parentc3daaf3325563ccbe0d8c3a8c8b729683a9d68c2 (diff)
downloadhostap-05ab9712b9977192b713f01f07c3b14ca4d1ba78.zip
hostap-05ab9712b9977192b713f01f07c3b14ca4d1ba78.tar.gz
hostap-05ab9712b9977192b713f01f07c3b14ca4d1ba78.tar.bz2
Allow WPA passphrase to be fetched with RADIUS Tunnel-Password attribute
This allows per-device PSK to be configured for WPA-Personal using a RADIUS authentication server. This uses RADIUS-based MAC address ACL (macaddr_acl=2), i.e., Access-Request uses the MAC address of the station as the User-Name and User-Password. The WPA passphrase is returned in Tunnel-Password attribute in Access-Accept. This functionality can be enabled with the new hostapd.conf parameter, wpa_psk_radius. Signed-hostap: Michael Braun <michael-dev@fami-braun.de>
Diffstat (limited to 'src/ap')
-rw-r--r--src/ap/ap_config.h5
-rw-r--r--src/ap/ieee802_11.c16
-rw-r--r--src/ap/ieee802_11_auth.c50
-rw-r--r--src/ap/ieee802_11_auth.h3
-rw-r--r--src/ap/sta_info.c1
-rw-r--r--src/ap/sta_info.h1
-rw-r--r--src/ap/wpa_auth_glue.c3
7 files changed, 74 insertions, 5 deletions
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 637c929..cc7122c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -219,6 +219,11 @@ struct hostapd_bss_config {
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
+ enum {
+ PSK_RADIUS_IGNORED = 0,
+ PSK_RADIUS_ACCEPTED = 1,
+ PSK_RADIUS_REQUIRED = 2
+ } wpa_psk_radius;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 0352599..617a035 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -313,6 +313,8 @@ static void handle_auth(struct hostapd_data *hapd,
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
int vlan_id = 0;
+ u8 psk[PMK_LEN];
+ int has_psk = 0;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
@@ -375,7 +377,9 @@ static void handle_auth(struct hostapd_data *hapd,
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
- &acct_interim_interval, &vlan_id);
+ &acct_interim_interval, &vlan_id,
+ psk, &has_psk);
+
if (res == HOSTAPD_ACL_REJECT) {
printf("Station " MACSTR " not allowed to authenticate.\n",
MAC2STR(mgmt->sa));
@@ -413,6 +417,16 @@ static void handle_auth(struct hostapd_data *hapd,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
}
+ if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ os_free(sta->psk);
+ sta->psk = os_malloc(PMK_LEN);
+ if (sta->psk)
+ os_memcpy(sta->psk, psk, PMK_LEN);
+ } else {
+ os_free(sta->psk);
+ sta->psk = NULL;
+ }
+
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 9b558fa..f3f313d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -21,6 +21,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "crypto/sha1.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
@@ -40,6 +41,8 @@ struct hostapd_cached_radius_acl {
u32 session_timeout;
u32 acct_interim_interval;
int vlan_id;
+ int has_psk;
+ u8 psk[PMK_LEN];
};
@@ -68,7 +71,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id)
+ u32 *acct_interim_interval, int *vlan_id,
+ u8 *psk, int *has_psk)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
@@ -89,6 +93,10 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
+ if (psk)
+ os_memcpy(psk, entry->psk, PMK_LEN);
+ if (has_psk)
+ *has_psk = entry->has_psk;
return entry->accepted;
}
@@ -210,11 +218,14 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID
+ * @psk: Buffer for returning WPA PSK
+ * @has_psk: Buffer for indicating whether psk was filled
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id)
+ u32 *acct_interim_interval, int *vlan_id,
+ u8 *psk, int *has_psk)
{
if (session_timeout)
*session_timeout = 0;
@@ -222,6 +233,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
*acct_interim_interval = 0;
if (vlan_id)
*vlan_id = 0;
+ if (has_psk)
+ *has_psk = 0;
+ if (psk)
+ os_memset(psk, 0, PMK_LEN);
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
@@ -246,7 +261,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
- vlan_id);
+ vlan_id, psk, has_psk);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -438,6 +453,9 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->timestamp = t.sec;
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+ int passphraselen;
+ char *passphrase;
+
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
@@ -456,6 +474,32 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
cache->vlan_id = radius_msg_get_vlanid(msg);
+
+ passphrase = radius_msg_get_tunnel_password(
+ msg, &passphraselen,
+ hapd->conf->radius->auth_server->shared_secret,
+ hapd->conf->radius->auth_server->shared_secret_len,
+ req);
+ cache->has_psk = passphrase != NULL;
+ if (passphrase != NULL) {
+ /* passphrase does not contain the NULL termination.
+ * Add it here as pbkdf2_sha1 requires it. */
+ char *strpassphrase = os_zalloc(passphraselen + 1);
+ if (strpassphrase) {
+ os_memcpy(strpassphrase, passphrase,
+ passphraselen);
+ pbkdf2_sha1(strpassphrase,
+ hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len, 4096,
+ cache->psk, PMK_LEN);
+ os_free(strpassphrase);
+ }
+ os_free(passphrase);
+ }
+
+ if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
+ cache->psk == NULL)
+ cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index b2971e5..a90571f 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -24,7 +24,8 @@ enum {
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id);
+ u32 *acct_interim_interval, int *vlan_id,
+ u8 *psk, int *has_psk);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 61cb9f1..d9c348e 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -228,6 +228,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->p2p_ie);
os_free(sta->ht_capabilities);
+ os_free(sta->psk);
os_free(sta);
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 3ad00e2..4d3b5e9 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -98,6 +98,7 @@ struct sta_info {
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
+ u8 *psk; /* PSK from RADIUS authentication server */
struct ieee80211_ht_capabilities *ht_capabilities;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 1e9d422..56bab23 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -186,6 +186,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *prev_psk)
{
struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ if (sta && sta->psk)
+ return sta->psk;
return hostapd_get_psk(hapd->conf, addr, prev_psk);
}