mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-01-17 18:34:03 -05:00
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>
This commit is contained in:
parent
c3daaf3325
commit
05ab9712b9
@ -1050,9 +1050,18 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
|
||||||
|
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
|
||||||
|
wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
|
||||||
|
"RADIUS checking (macaddr_acl=2) enabled.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
|
if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
|
||||||
bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
|
bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
|
||||||
bss->ssid.wpa_psk_file == NULL) {
|
bss->ssid.wpa_psk_file == NULL &&
|
||||||
|
(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 "
|
wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
|
||||||
"is not configured.");
|
"is not configured.");
|
||||||
return -1;
|
return -1;
|
||||||
@ -1629,6 +1638,16 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
|||||||
hostapd_config_parse_key_mgmt(line, pos);
|
hostapd_config_parse_key_mgmt(line, pos);
|
||||||
if (bss->wpa_key_mgmt == -1)
|
if (bss->wpa_key_mgmt == -1)
|
||||||
errors++;
|
errors++;
|
||||||
|
} else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
|
||||||
|
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) {
|
||||||
|
wpa_printf(MSG_ERROR, "Line %d: unknown "
|
||||||
|
"wpa_psk_radius %d",
|
||||||
|
line, bss->wpa_psk_radius);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
|
} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
|
||||||
bss->wpa_pairwise =
|
bss->wpa_pairwise =
|
||||||
hostapd_config_parse_cipher(line, pos);
|
hostapd_config_parse_cipher(line, pos);
|
||||||
|
@ -676,6 +676,7 @@ own_ip_addr=127.0.0.1
|
|||||||
# Enable WPA. Setting this variable configures the AP to require WPA (either
|
# Enable WPA. Setting this variable configures the AP to require WPA (either
|
||||||
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
|
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
|
||||||
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
|
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
|
||||||
|
# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
|
||||||
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
|
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
|
||||||
# RADIUS authentication server must be configured, and WPA-EAP must be included
|
# RADIUS authentication server must be configured, and WPA-EAP must be included
|
||||||
# in wpa_key_mgmt.
|
# in wpa_key_mgmt.
|
||||||
@ -700,6 +701,15 @@ own_ip_addr=127.0.0.1
|
|||||||
# configuration reloads.
|
# configuration reloads.
|
||||||
#wpa_psk_file=/etc/hostapd.wpa_psk
|
#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)
|
||||||
|
# 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
|
||||||
|
#wpa_psk_radius=0
|
||||||
|
|
||||||
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
# 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
|
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
|
||||||
# added to enable SHA256-based stronger algorithms.
|
# added to enable SHA256-based stronger algorithms.
|
||||||
|
@ -219,6 +219,11 @@ struct hostapd_bss_config {
|
|||||||
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
|
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
|
||||||
int assoc_sa_query_retry_timeout;
|
int assoc_sa_query_retry_timeout;
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
enum {
|
||||||
|
PSK_RADIUS_IGNORED = 0,
|
||||||
|
PSK_RADIUS_ACCEPTED = 1,
|
||||||
|
PSK_RADIUS_REQUIRED = 2
|
||||||
|
} wpa_psk_radius;
|
||||||
int wpa_pairwise;
|
int wpa_pairwise;
|
||||||
int wpa_group;
|
int wpa_group;
|
||||||
int wpa_group_rekey;
|
int wpa_group_rekey;
|
||||||
|
@ -313,6 +313,8 @@ 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];
|
||||||
|
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;
|
||||||
|
|
||||||
@ -375,7 +377,9 @@ 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);
|
||||||
|
|
||||||
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",
|
||||||
MAC2STR(mgmt->sa));
|
MAC2STR(mgmt->sa));
|
||||||
@ -413,6 +417,16 @@ 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) {
|
||||||
|
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;
|
sta->flags &= ~WLAN_STA_PREAUTH;
|
||||||
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
|
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "utils/eloop.h"
|
#include "utils/eloop.h"
|
||||||
|
#include "crypto/sha1.h"
|
||||||
#include "radius/radius.h"
|
#include "radius/radius.h"
|
||||||
#include "radius/radius_client.h"
|
#include "radius/radius_client.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
@ -40,6 +41,8 @@ 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;
|
||||||
|
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,
|
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)
|
||||||
{
|
{
|
||||||
struct hostapd_cached_radius_acl *entry;
|
struct hostapd_cached_radius_acl *entry;
|
||||||
struct os_time now;
|
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;
|
entry->acct_interim_interval;
|
||||||
if (vlan_id)
|
if (vlan_id)
|
||||||
*vlan_id = entry->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;
|
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)
|
* @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
|
||||||
|
* @has_psk: Buffer for indicating whether psk was filled
|
||||||
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (session_timeout)
|
if (session_timeout)
|
||||||
*session_timeout = 0;
|
*session_timeout = 0;
|
||||||
@ -222,6 +233,10 @@ 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)
|
||||||
|
os_memset(psk, 0, PMK_LEN);
|
||||||
|
|
||||||
if (hostapd_maclist_found(hapd->conf->accept_mac,
|
if (hostapd_maclist_found(hapd->conf->accept_mac,
|
||||||
hapd->conf->num_accept_mac, addr, vlan_id))
|
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 */
|
/* 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);
|
vlan_id, psk, has_psk);
|
||||||
if (res == HOSTAPD_ACL_ACCEPT ||
|
if (res == HOSTAPD_ACL_ACCEPT ||
|
||||||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||||
return res;
|
return res;
|
||||||
@ -438,6 +453,9 @@ 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;
|
||||||
|
|
||||||
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
|
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
|
||||||
&cache->session_timeout) == 0)
|
&cache->session_timeout) == 0)
|
||||||
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
|
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);
|
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
|
} else
|
||||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||||
cache->next = hapd->acl_cache;
|
cache->next = hapd->acl_cache;
|
||||||
|
@ -24,7 +24,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);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -228,6 +228,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||||||
wpabuf_free(sta->p2p_ie);
|
wpabuf_free(sta->p2p_ie);
|
||||||
|
|
||||||
os_free(sta->ht_capabilities);
|
os_free(sta->ht_capabilities);
|
||||||
|
os_free(sta->psk);
|
||||||
|
|
||||||
os_free(sta);
|
os_free(sta);
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ struct sta_info {
|
|||||||
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
|
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
|
||||||
|
|
||||||
int vlan_id;
|
int vlan_id;
|
||||||
|
u8 *psk; /* PSK from RADIUS authentication server */
|
||||||
|
|
||||||
struct ieee80211_ht_capabilities *ht_capabilities;
|
struct ieee80211_ht_capabilities *ht_capabilities;
|
||||||
|
|
||||||
|
@ -186,6 +186,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
|||||||
const u8 *prev_psk)
|
const u8 *prev_psk)
|
||||||
{
|
{
|
||||||
struct hostapd_data *hapd = ctx;
|
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);
|
return hostapd_get_psk(hapd->conf, addr, prev_psk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +218,8 @@ static struct radius_attr_type radius_attrs[] =
|
|||||||
{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
|
{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
|
||||||
{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
|
{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
|
||||||
RADIUS_ATTR_HEXDUMP },
|
RADIUS_ATTR_HEXDUMP },
|
||||||
|
{ RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
|
||||||
|
RADIUS_ATTR_UNDIST },
|
||||||
{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
|
{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
|
||||||
{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
|
{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
|
||||||
{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
|
{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
|
||||||
@ -1275,6 +1277,120 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
|
||||||
|
* @msg: Received RADIUS message
|
||||||
|
* @keylen: Length of returned password
|
||||||
|
* @secret: RADIUS shared secret
|
||||||
|
* @secret_len: Length of secret
|
||||||
|
* @sent_msg: Sent RADIUS message
|
||||||
|
* Returns: pointer to password (free with os_free) or %NULL
|
||||||
|
*/
|
||||||
|
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
|
||||||
|
const u8 *secret, size_t secret_len,
|
||||||
|
struct radius_msg *sent_msg)
|
||||||
|
{
|
||||||
|
u8 *buf = NULL;
|
||||||
|
size_t buflen;
|
||||||
|
const u8 *salt;
|
||||||
|
u8 *str;
|
||||||
|
const u8 *addr[3];
|
||||||
|
size_t len[3];
|
||||||
|
u8 hash[16];
|
||||||
|
u8 *pos;
|
||||||
|
size_t i;
|
||||||
|
struct radius_attr_hdr *attr;
|
||||||
|
const u8 *data;
|
||||||
|
size_t dlen;
|
||||||
|
const u8 *fdata = NULL; /* points to found item */
|
||||||
|
size_t fdlen = -1;
|
||||||
|
char *ret = NULL;
|
||||||
|
|
||||||
|
/* find attribute with lowest tag and check it */
|
||||||
|
for (i = 0; i < msg->attr_used; i++) {
|
||||||
|
attr = radius_get_attr_hdr(msg, i);
|
||||||
|
if (attr == NULL ||
|
||||||
|
attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (attr->length <= 5)
|
||||||
|
continue;
|
||||||
|
data = (const u8 *) (attr + 1);
|
||||||
|
dlen = attr->length - sizeof(*attr);
|
||||||
|
if (dlen <= 3 || dlen % 16 != 3)
|
||||||
|
continue;
|
||||||
|
if (fdata != NULL && fdata[0] <= data[0])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fdata = data;
|
||||||
|
fdlen = dlen;
|
||||||
|
}
|
||||||
|
if (fdata == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* alloc writable memory for decryption */
|
||||||
|
buf = os_malloc(fdlen);
|
||||||
|
if (buf == NULL)
|
||||||
|
goto out;
|
||||||
|
os_memcpy(buf, fdata, fdlen);
|
||||||
|
buflen = fdlen;
|
||||||
|
|
||||||
|
/* init pointers */
|
||||||
|
salt = buf + 1;
|
||||||
|
str = buf + 3;
|
||||||
|
|
||||||
|
/* decrypt blocks */
|
||||||
|
pos = buf + buflen - 16; /* last block */
|
||||||
|
while (pos >= str + 16) { /* all but the first block */
|
||||||
|
addr[0] = secret;
|
||||||
|
len[0] = secret_len;
|
||||||
|
addr[1] = pos - 16;
|
||||||
|
len[1] = 16;
|
||||||
|
md5_vector(2, addr, len, hash);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
pos[i] ^= hash[i];
|
||||||
|
|
||||||
|
pos -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decrypt first block */
|
||||||
|
if (str != pos)
|
||||||
|
goto out;
|
||||||
|
addr[0] = secret;
|
||||||
|
len[0] = secret_len;
|
||||||
|
addr[1] = sent_msg->hdr->authenticator;
|
||||||
|
len[1] = 16;
|
||||||
|
addr[2] = salt;
|
||||||
|
len[2] = 2;
|
||||||
|
md5_vector(3, addr, len, hash);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
pos[i] ^= hash[i];
|
||||||
|
|
||||||
|
/* derive plaintext length from first subfield */
|
||||||
|
*keylen = (unsigned char) str[0];
|
||||||
|
if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
|
||||||
|
/* decryption error - invalid key length */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (*keylen == 0) {
|
||||||
|
/* empty password */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy passphrase into new buffer */
|
||||||
|
ret = os_malloc(*keylen);
|
||||||
|
if (ret)
|
||||||
|
os_memcpy(ret, str + 1, *keylen);
|
||||||
|
|
||||||
|
out:
|
||||||
|
/* return new buffer */
|
||||||
|
os_free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void radius_free_class(struct radius_class_data *c)
|
void radius_free_class(struct radius_class_data *c)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -82,6 +82,7 @@ enum { RADIUS_ATTR_USER_NAME = 1,
|
|||||||
RADIUS_ATTR_NAS_PORT_TYPE = 61,
|
RADIUS_ATTR_NAS_PORT_TYPE = 61,
|
||||||
RADIUS_ATTR_TUNNEL_TYPE = 64,
|
RADIUS_ATTR_TUNNEL_TYPE = 64,
|
||||||
RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
|
RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
|
||||||
|
RADIUS_ATTR_TUNNEL_PASSWORD = 69,
|
||||||
RADIUS_ATTR_CONNECT_INFO = 77,
|
RADIUS_ATTR_CONNECT_INFO = 77,
|
||||||
RADIUS_ATTR_EAP_MESSAGE = 79,
|
RADIUS_ATTR_EAP_MESSAGE = 79,
|
||||||
RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
|
RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
|
||||||
@ -231,6 +232,9 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
|
|||||||
const u8 *secret, size_t secret_len);
|
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_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_vlanid(struct radius_msg *msg);
|
||||||
|
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
|
||||||
|
const u8 *secret, size_t secret_len,
|
||||||
|
struct radius_msg *sent_msg);
|
||||||
|
|
||||||
static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
|
static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
|
||||||
u32 value)
|
u32 value)
|
||||||
|
Loading…
Reference in New Issue
Block a user