Cache a list of PSK entries for RADIUS-based PSK delivery

Signed-hostap: Michael Braun <michael-dev@fami-braun.de>
This commit is contained in:
Michael Braun 2012-11-25 17:41:13 +02:00 committed by Jouni Malinen
parent 14e919478e
commit 2ad3e6c858
4 changed files with 105 additions and 47 deletions

View file

@ -96,6 +96,11 @@ struct hostapd_vlan {
}; };
#define PMK_LEN 32 #define PMK_LEN 32
struct hostapd_sta_wpa_psk_short {
struct hostapd_sta_wpa_psk_short *next;
u8 psk[PMK_LEN];
};
struct hostapd_wpa_psk { struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next; struct hostapd_wpa_psk *next;
int group; int group;

View file

@ -461,8 +461,7 @@ static void handle_auth(struct hostapd_data *hapd,
const u8 *challenge = NULL; const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval; u32 session_timeout, acct_interim_interval;
int vlan_id = 0; int vlan_id = 0;
u8 psk[PMK_LEN]; struct hostapd_sta_wpa_psk_short *psk = NULL;
int has_psk = 0;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0; size_t resp_ies_len = 0;
char *identity = NULL; char *identity = NULL;
@ -532,7 +531,7 @@ static void handle_auth(struct hostapd_data *hapd,
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout, &session_timeout,
&acct_interim_interval, &vlan_id, &acct_interim_interval, &vlan_id,
psk, &has_psk, &identity, &radius_cui); &psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) { if (res == HOSTAPD_ACL_REJECT) {
printf("Station " MACSTR " not allowed to authenticate.\n", printf("Station " MACSTR " not allowed to authenticate.\n",
@ -571,11 +570,11 @@ static void handle_auth(struct hostapd_data *hapd,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
} }
if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { if (psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
os_free(sta->psk); os_free(sta->psk);
sta->psk = os_malloc(PMK_LEN); sta->psk = os_malloc(PMK_LEN);
if (sta->psk) if (sta->psk)
os_memcpy(sta->psk, psk, PMK_LEN); os_memcpy(sta->psk, psk->psk, PMK_LEN);
} else { } else {
os_free(sta->psk); os_free(sta->psk);
sta->psk = NULL; sta->psk = NULL;
@ -654,6 +653,11 @@ static void handle_auth(struct hostapd_data *hapd,
fail: fail:
os_free(identity); os_free(identity);
os_free(radius_cui); os_free(radius_cui);
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
os_free(prev);
}
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies, resp_ies_len); auth_transaction + 1, resp, resp_ies, resp_ies_len);

View file

@ -36,8 +36,7 @@ struct hostapd_cached_radius_acl {
u32 session_timeout; u32 session_timeout;
u32 acct_interim_interval; u32 acct_interim_interval;
int vlan_id; int vlan_id;
int has_psk; struct hostapd_sta_wpa_psk_short *psk;
u8 psk[PMK_LEN];
char *identity; char *identity;
char *radius_cui; char *radius_cui;
}; };
@ -56,8 +55,14 @@ struct hostapd_acl_query_data {
#ifndef CONFIG_NO_RADIUS #ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e) static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{ {
struct hostapd_sta_wpa_psk_short *psk = e->psk;
os_free(e->identity); os_free(e->identity);
os_free(e->radius_cui); os_free(e->radius_cui);
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
os_free(prev);
}
os_free(e); os_free(e);
} }
@ -74,11 +79,34 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
} }
static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src)
{
struct hostapd_sta_wpa_psk_short **copy_to;
struct hostapd_sta_wpa_psk_short *copy_from;
/* Copy PSK linked list */
copy_to = psk;
copy_from = src;
while (copy_from && copy_to) {
*copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
if (*copy_to == NULL)
break;
os_memcpy(*copy_to, copy_from,
sizeof(struct hostapd_sta_wpa_psk_short));
copy_from = copy_from->next;
copy_to = &((*copy_to)->next);
}
if (copy_to)
*copy_to = NULL;
}
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id, u32 *acct_interim_interval, int *vlan_id,
u8 *psk, int *has_psk, char **identity, struct hostapd_sta_wpa_psk_short **psk,
char **radius_cui) char **identity, char **radius_cui)
{ {
struct hostapd_cached_radius_acl *entry; struct hostapd_cached_radius_acl *entry;
struct os_time now; struct os_time now;
@ -99,10 +127,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
entry->acct_interim_interval; entry->acct_interim_interval;
if (vlan_id) if (vlan_id)
*vlan_id = entry->vlan_id; *vlan_id = entry->vlan_id;
if (psk) copy_psk_list(psk, entry->psk);
os_memcpy(psk, entry->psk, PMK_LEN);
if (has_psk)
*has_psk = entry->has_psk;
if (identity) { if (identity) {
if (entry->identity) if (entry->identity)
*identity = os_strdup(entry->identity); *identity = os_strdup(entry->identity);
@ -200,8 +225,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @session_timeout: Buffer for returning session timeout (from RADIUS) * @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS) * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID * @vlan_id: Buffer for returning VLAN ID
* @psk: Buffer for returning WPA PSK * @psk: Linked list buffer for returning WPA PSK
* @has_psk: Buffer for indicating whether psk was filled
* @identity: Buffer for returning identity (from RADIUS) * @identity: Buffer for returning identity (from RADIUS)
* @radius_cui: Buffer for returning CUI (from RADIUS) * @radius_cui: Buffer for returning CUI (from RADIUS)
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
@ -212,8 +236,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout, 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, char **identity, struct hostapd_sta_wpa_psk_short **psk,
char **radius_cui) char **identity, char **radius_cui)
{ {
if (session_timeout) if (session_timeout)
*session_timeout = 0; *session_timeout = 0;
@ -221,10 +245,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
*acct_interim_interval = 0; *acct_interim_interval = 0;
if (vlan_id) if (vlan_id)
*vlan_id = 0; *vlan_id = 0;
if (has_psk)
*has_psk = 0;
if (psk) if (psk)
os_memset(psk, 0, PMK_LEN); *psk = NULL;
if (identity) if (identity)
*identity = NULL; *identity = NULL;
if (radius_cui) if (radius_cui)
@ -253,7 +275,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
/* Check whether ACL cache has an entry for this station */ /* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout, int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval, acct_interim_interval,
vlan_id, psk, has_psk, vlan_id, psk,
identity, radius_cui); identity, radius_cui);
if (res == HOSTAPD_ACL_ACCEPT || if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT) res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
@ -396,6 +418,54 @@ static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
} }
static void decode_tunnel_passwords(struct hostapd_data *hapd,
struct radius_msg *msg,
struct radius_msg *req,
struct hostapd_cached_radius_acl *cache)
{
int passphraselen;
char *passphrase, *strpassphrase;
size_t i;
struct hostapd_sta_wpa_psk_short *psk;
/*
* Decode all tunnel passwords as PSK and save them into a linked list.
*/
for (i = 0; ; i++) {
passphrase = radius_msg_get_tunnel_password(
msg, &passphraselen,
hapd->conf->radius->auth_server->shared_secret,
hapd->conf->radius->auth_server->shared_secret_len,
req, i);
/*
* Passphrase is NULL iff there is no i-th Tunnel-Password
* attribute in msg.
*/
if (passphrase == NULL)
break;
/*
* 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);
psk->next = cache->psk;
cache->psk = psk;
psk = NULL;
}
os_free(strpassphrase);
os_free(psk);
os_free(passphrase);
}
}
/** /**
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
* @msg: RADIUS response message * @msg: RADIUS response message
@ -454,8 +524,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->timestamp = t.sec; cache->timestamp = t.sec;
os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
int passphraselen;
char *passphrase;
u8 *buf; u8 *buf;
size_t len; size_t len;
@ -478,27 +546,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->vlan_id = radius_msg_get_vlanid(msg); cache->vlan_id = radius_msg_get_vlanid(msg);
passphrase = radius_msg_get_tunnel_password( decode_tunnel_passwords(hapd, msg, req, cache);
msg, &passphraselen,
hapd->conf->radius->auth_server->shared_secret,
hapd->conf->radius->auth_server->shared_secret_len,
req, 0);
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 (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) { &buf, &len, NULL) == 0) {
cache->identity = os_zalloc(len + 1); cache->identity = os_zalloc(len + 1);
@ -514,7 +563,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
} }
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
!cache->has_psk) !cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT; cache->accepted = HOSTAPD_ACL_REJECT;
} else } else
cache->accepted = HOSTAPD_ACL_REJECT; cache->accepted = HOSTAPD_ACL_REJECT;

View file

@ -19,8 +19,8 @@ enum {
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout, 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, char **identity, struct hostapd_sta_wpa_psk_short **psk,
char **radius_cui); char **identity, char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd); int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd); void hostapd_acl_deinit(struct hostapd_data *hapd);