commit 1a73664e17928a746d6995e029512672e0ea0c2e
Author: mbr <mbr@wlan-nfs.fem.tu-ilmenau.de>
Date: Tue Nov 29 20:29:22 2011 +0100
add PSK-from-RADIUS support
Signed-hostap: Michael Braun <michael-dev@fami-braun.de>
@@ -350,6 +350,11 @@ TODO
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
#wpa_passphrase=secret passphrase
+# Optionally, WPA PSKs can be read from RADIUS (to be used with macaddr_acl set to RADIUS)
+# 0 no
+# 1 may (falls back to the above if no radius attribute is found)
+#wpa_psk_radius=0
+
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space.
#wpa_key_mgmt=WPA-PSK WPA-EAP
@@ -1629,6 +1629,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
hostapd_config_parse_key_mgmt(line, pos);
if (bss->wpa_key_mgmt == -1)
errors++;
+ } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
+ bss->wpa_psk_radius = atoi(pos);
} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
bss->wpa_pairwise =
hostapd_config_parse_cipher(line, pos);
@@ -700,6 +700,11 @@ own_ip_addr=127.0.0.1
# configuration reloads.
#wpa_psk_file=/etc/hostapd.wpa_psk
+# Optionally, WPA PSKs can be read from RADIUS (to be used with macaddr_acl set to RADIUS)
+# 0 no
+# 1 may (falls back to the above if no radius attribute is found)
+#wpa_psk_radius=0
+
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
# added to enable SHA256-based stronger algorithms.
new file mode 100644
@@ -0,0 +1,10 @@
+To fetch PSK from radius, set macaddr_acl to radius and wpa_psk_radius=1 in hostapd.conf
+Add the following definition to freeradius vendor list
+
+ VENDOR Hostapd 39014
+ ATTRIBUTE Hostapd-PSK 1 integer Hostapd
+ ATTRIBUTE Hostapd-Passphrase 2 string Hostapd
+
+and add either a Hostapd-PSK or Hostapd-Passphrase to the radius reply (PSK overriders Passphrase).
+PSK is the hex encoded 64 character dump of the psk.
+
@@ -57,6 +57,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->broadcast_key_idx_max = 2;
bss->eap_reauth_period = 3600;
+ bss->wpa_psk_radius = 0;
+
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
@@ -219,6 +219,7 @@ struct hostapd_bss_config {
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
+ int wpa_psk_radius;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
@@ -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,7 @@ 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));
@@ -412,6 +414,12 @@ static void handle_auth(struct hostapd_data *hapd,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
}
+ if (has_psk) {
+ sta->psk = os_zalloc(PMK_LEN);
+ os_memcpy(sta->psk, psk, PMK_LEN);
+ } else {
+ sta->psk = 0;
+ }
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
@@ -40,6 +40,8 @@ struct hostapd_cached_radius_acl {
u32 session_timeout;
u32 acct_interim_interval;
int vlan_id;
+ int with_psk;
+ u8 psk[PMK_LEN];
};
@@ -68,7 +70,7 @@ 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, int* with_psk, u8* psk[], int* has_psk)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
@@ -89,6 +91,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;
}
@@ -214,7 +220,7 @@ static int hostapd_radius_acl_query(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,
- 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 +228,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)
+ *hash_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 +256,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;
@@ -396,6 +406,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
void *data)
{
struct hostapd_data *hapd = data;
+ struct hostapd_ssid *ssid = &(hapd->conf->ssid);
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
@@ -456,6 +467,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
cache->vlan_id = radius_msg_get_vlanid(msg);
+ cache->has_psk = radius_msg_get_psk(msg, cache->psk, ssid);
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
@@ -24,7 +24,7 @@ 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);
@@ -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);
}
@@ -98,6 +98,7 @@ struct sta_info {
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
+ u8* psk;
struct ieee80211_ht_capabilities *ht_capabilities;
@@ -132,6 +132,7 @@ struct wpa_auth_config {
int wpa;
int wpa_key_mgmt;
int wpa_pairwise;
+ int wpa_psk_radius;
int wpa_group;
int wpa_group_rekey;
int wpa_strict_rekey;
@@ -39,6 +39,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->wpa = conf->wpa;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
+ wconf->wpa_psk_radius = conf->wpa_psk_radius;
wconf->wpa_group = conf->wpa_group;
wconf->wpa_group_rekey = conf->wpa_group_rekey;
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
@@ -186,7 +187,10 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *prev_psk)
{
struct hostapd_data *hapd = ctx;
- return hostapd_get_psk(hapd->conf, addr, prev_psk);
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ if (sta == NULL || sta->psk == NULL)
+ return hostapd_get_psk(hapd->conf, addr, prev_psk);
+ return sta->psk;
}
@@ -17,9 +17,10 @@
#include "utils/common.h"
#include "utils/wpabuf.h"
#include "crypto/md5.h"
+#include "crypto/sha1.h"
#include "crypto/crypto.h"
#include "radius.h"
-
+#include "ap/ap_config.h"
/**
* struct radius_msg - RADIUS message structure for new and parsed messages
@@ -1275,6 +1276,40 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
}
+/**
+ * radius_msg_get_psk - Parse RADIUS attributes for PSK/Passphrase (WPA)
+ * @msg: RADIUS message
+ * @psk: buffer for PSK (len: PMK_LEN)
+ * Returns: 1 if psk found, 0 else
+ */
+int radius_msg_get_psk(struct radius_msg *msg, u8* psk, struct hostapd_ssid *ssid)
+{
+ char* key;
+ size_t keylen;
+
+ key = (char*) radius_msg_get_vendor_attr( msg, RADIUS_VENDOR_ID_HOSTAPD, RADIUS_VENDOR_ATTR_HAP_PSK, &keylen );
+ if (key) {
+ // PSK found, expect hex encoding
+ int len = os_strlen(key);
+ if (len == 64 && hexstr2bin(key, psk, PMK_LEN) == 0) {
+ os_free(key); key=NULL;
+ return 1;
+ }
+ // PSK had wrong length...
+ os_free(key); key=NULL;
+ }
+
+ key = (char*) radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_HOSTAPD, RADIUS_VENDOR_ATTR_HAP_PASSPHRASE, &keylen );
+ if (key) {
+ // Passphrase found
+ pbkdf2_sha1(key, ssid->ssid, ssid->ssid_len, 4096, psk, PMK_LEN);
+ os_free(key); key=NULL;
+ return 1;
+ }
+ return 0;
+}
+
+
void radius_free_class(struct radius_class_data *c)
{
size_t i;
@@ -15,6 +15,8 @@
#ifndef RADIUS_H
#define RADIUS_H
+struct hostapd_ssid;
+
/* RFC 2865 - RADIUS */
#ifdef _MSC_VER
@@ -172,6 +174,11 @@ struct radius_ms_mppe_keys {
size_t recv_len;
};
+/* hostapd specific RADIUS Attributes */
+#define RADIUS_VENDOR_ID_HOSTAPD 39014
+enum { RADIUS_VENDOR_ATTR_HAP_PSK = 1,
+ RADIUS_VENDOR_ATTR_HAP_PASSPHRASE = 2
+};
struct radius_msg;
@@ -231,6 +238,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
const u8 *secret, size_t secret_len);
int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
int radius_msg_get_vlanid(struct radius_msg *msg);
+int radius_msg_get_psk(struct radius_msg *msg, u8* psk, struct hostapd_ssid *ssid);
static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
u32 value)