@@ -1867,6 +1867,12 @@ own_ip_addr=127.0.0.1
# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK
# uses the wpa_passphrase value.
#
+# If no sae_password matches, RADIUS supplied Tunnel-Password are used with
+# higher priority than wpa_passphrase if wpa_psk_radius > 0 except. Thought,
+# the WPA-PSK constraints (8..63 chars) apply here was well.
+# The corresponding SAE password identifier can optionally be supplied using
+# Tunnel-Client-Auth-ID.
+#
# Each sae_password entry is added to a list of available passwords. This
# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
# starts with the password (dot11RSNAConfigPasswordCredential). That value can
@@ -1588,6 +1588,11 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
if (conf->ssid.wpa_passphrase)
without_id = 1;
+ if (conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ with_id = 1;
+ without_id = 1;
+ }
+
for (pw = conf->sae_passwords; pw; pw = pw->next) {
if (pw->identifier)
with_id = 1;
@@ -1627,6 +1632,9 @@ bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
if (conf->ssid.wpa_passphrase)
return false;
+ if (conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+ return false;
+
for (pw = conf->sae_passwords; pw; pw = pw->next) {
if (!pw->pk)
return false;
@@ -148,9 +148,12 @@ struct hostapd_vlan {
#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];
+ u8 *psk;
+ char *passphrase;
+#ifdef CONFIG_SAE
+ char *sae_identifier;
+ struct sae_pt *sae_pt;
+#endif /* CONFIG_SAE */
int ref; /* (number of references held) - 1 */
};
@@ -487,6 +487,56 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
}
+static void sae_derive_pt_from_psk(struct hostapd_data *hapd,
+ struct hostapd_sta_wpa_psk_short *psk)
+{
+ struct hostapd_ssid *ssid;
+
+ if (!psk->passphrase)
+ return;
+ if (psk->sae_pt)
+ return;
+
+ ssid = &hapd->conf->ssid;
+
+ psk->sae_pt = sae_derive_pt(hapd->conf->sae_groups, ssid->ssid,
+ ssid->ssid_len, (u8 *) psk->passphrase,
+ os_strlen(psk->passphrase),
+ psk->sae_identifier);
+
+}
+
+
+static const char * sae_get_password_from_psk(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const char *rx_id,
+ struct sae_pt **s_pt)
+{
+ struct hostapd_sta_wpa_psk_short *pos;
+
+ for (pos = sta->psk; pos; pos = pos->next) {
+ if ((rx_id && !pos->sae_identifier) ||
+ (!rx_id && pos->sae_identifier))
+ continue;
+ if (rx_id && pos->sae_identifier &&
+ os_strcmp(rx_id, pos->sae_identifier) != 0)
+ continue;
+
+ sae_derive_pt_from_psk(hapd, pos);
+
+ if (!pos->sae_pt)
+ continue;
+
+ if (s_pt)
+ *s_pt = pos->sae_pt;
+
+ return pos->passphrase;
+ }
+
+ return NULL;
+}
+
+
static const char * sae_get_password(struct hostapd_data *hapd,
struct sta_info *sta,
const char *rx_id,
@@ -514,6 +564,10 @@ static const char * sae_get_password(struct hostapd_data *hapd,
pk = pw->pk;
break;
}
+
+ if (!password)
+ password = sae_get_password_from_psk(hapd, sta, rx_id, &pt);
+
if (!password) {
password = hapd->conf->ssid.wpa_passphrase;
pt = hapd->conf->ssid.pt;
@@ -23,6 +23,7 @@
#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
+#include "common/sae.h"
#define RADIUS_ACL_TIMEOUT 30
@@ -368,72 +369,133 @@ void hostapd_acl_expire(struct hostapd_data *hapd)
hostapd_acl_expire_queries(hapd, &now);
}
+#ifdef CONFIG_SAE
+static int get_tunnel_sae_id(struct radius_msg *msg, u8 tag, u8** buf,
+ size_t *len, size_t idx, size_t *next_idx)
+{
+ const u8 type = RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID;
-static void decode_tunnel_passwords(struct hostapd_data *hapd,
- const u8 *shared_secret,
- size_t shared_secret_len,
- struct radius_msg *msg,
- struct radius_msg *req,
- struct hostapd_cached_radius_acl *cache)
+ return radius_msg_get_attr_tag_ptr(msg, type, tag, buf, len, idx,
+ next_idx);
+}
+#endif /* CONFIG_SAE */
+
+
+static void decode_tunnel_password(struct hostapd_data *hapd,
+ const u8 *shared_secret,
+ size_t shared_secret_len,
+ struct radius_msg *msg,
+ struct radius_msg *req,
+ struct hostapd_cached_radius_acl *cache,
+ size_t psk_idx, size_t *psk_next)
{
int passphraselen;
char *passphrase;
- size_t i;
struct hostapd_sta_wpa_psk_short *psk;
-
+ int has_sae_id = 0;
+ u8 tag;
+#ifdef CONFIG_SAE
+ u8 *sae_id;
+ size_t sae_id_len;
+ size_t sae_idx = 0, sae_idx_next;
+#endif /* CONFIG_SAE */
+
+ passphrase = radius_msg_get_tunnel_password(
+ msg, &passphraselen, shared_secret, shared_secret_len,
+ req, psk_idx, &tag, psk_next);
/*
- * Decode all tunnel passwords as PSK and save them into a linked list.
+ * Passphrase is NULL iff there is no i-th Tunnel-Password
+ * attribute in msg.
*/
- for (i = 0; ; i++) {
- passphrase = radius_msg_get_tunnel_password(
- msg, &passphraselen, shared_secret, shared_secret_len,
- req, i);
- /*
- * Passphrase is NULL iff there is no i-th Tunnel-Password
- * attribute in msg.
- */
- if (passphrase == NULL)
- break;
+ if (passphrase == NULL) {
+ *psk_next = 0;
+ return;
+ }
- /*
- * Passphase should be 8..63 chars (to be hashed with SSID)
- * or 64 chars hex string (no separate hashing with SSID).
- */
+ /*
+ * Passphase should be 8..63 chars (to be hashed with SSID)
+ * or 64 chars hex string (no separate hashing with SSID).
+ */
- if (passphraselen < MIN_PASSPHRASE_LEN ||
- passphraselen > MAX_PASSPHRASE_LEN + 1)
- goto free_pass;
+ if (passphraselen < MIN_PASSPHRASE_LEN ||
+ passphraselen > MAX_PASSPHRASE_LEN + 1)
+ goto free_pass;
+ do {
/*
* passphrase does not contain the NULL termination.
* Add it here as pbkdf2_sha1() requires it.
*/
psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
- if (psk) {
- if ((passphraselen == MAX_PASSPHRASE_LEN + 1) &&
- (hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) {
+ if (!psk)
+ goto skip;
+ if (passphraselen == MAX_PASSPHRASE_LEN + 1) {
+ psk->psk = os_zalloc(PMK_LEN);
+ if (!psk->psk)
+ goto skip;
+ if (hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0) {
hostapd_logger(hapd, cache->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_WARNING,
"invalid hex string (%d chars) in Tunnel-Password",
passphraselen);
goto skip;
- } else if (passphraselen <= MAX_PASSPHRASE_LEN) {
- os_memcpy(psk->passphrase, passphrase,
- passphraselen);
- psk->is_passphrase = 1;
}
- psk->next = cache->info.psk;
- cache->info.psk = psk;
- psk = NULL;
+ } else {
+ psk->passphrase = os_zalloc(passphraselen + 1);
+ os_memcpy(psk->passphrase, passphrase, passphraselen);
+#ifdef CONFIG_SAE
+ /*
+ * Lookup Tunnel-Client-Auth-ID by tag
+ */
+ has_sae_id = !get_tunnel_sae_id(msg, tag, &sae_id,
+ &sae_id_len, sae_idx,
+ &sae_idx_next);
+ if (has_sae_id) {
+ psk->sae_identifier = os_zalloc(sae_id_len+1);
+ if (!psk->sae_identifier)
+ goto skip;
+ os_memcpy(psk->sae_identifier, sae_id, sae_id_len);
+ sae_idx = sae_idx_next;
+ } else if (sae_idx > 0)
+ goto skip;
+#endif /* CONFIG_SAE */
}
+ psk->next = cache->info.psk;
+ cache->info.psk = psk;
+ psk = NULL;
+ } while (has_sae_id);
+
skip:
+ if (psk) {
+ os_free(psk->psk);
+ os_free(psk->passphrase);
os_free(psk);
-free_pass:
- os_free(passphrase);
}
+free_pass:
+ os_free(passphrase);
}
+static void decode_tunnel_passwords(struct hostapd_data *hapd,
+ const u8 *shared_secret,
+ size_t shared_secret_len,
+ struct radius_msg *msg,
+ struct radius_msg *req,
+ struct hostapd_cached_radius_acl *cache)
+{
+ size_t psk_idx = 0, psk_next;
+
+ /*
+ * Decode all tunnel passwords as PSK and save them into a linked list.
+ */
+ while (1) {
+ decode_tunnel_password(hapd, shared_secret, shared_secret_len,
+ msg, req, cache, psk_idx, &psk_next);
+ if (psk_next == 0)
+ break;
+ psk_idx = psk_next;
+ }
+}
/**
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
@@ -646,6 +708,13 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
+#ifdef CONFIG_SAE
+ if (prev->sae_pt)
+ sae_deinit_pt(prev->sae_pt);
+ os_free(prev->sae_identifier);
+ os_free(prev->psk);
+ os_free(prev->passphrase);
+#endif /* CONFIG_SAE */
os_free(prev);
}
}
@@ -381,23 +381,35 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
* logic list (all hostapd_get_psk; all sta->psk)
*/
if (sta && sta->psk && !psk) {
- struct hostapd_sta_wpa_psk_short *pos;
+ struct hostapd_sta_wpa_psk_short *pos, *prev = NULL;
if (vlan_id)
*vlan_id = 0;
- psk = sta->psk->psk;
+
for (pos = sta->psk; pos; pos = pos->next) {
- if (pos->is_passphrase) {
+ if (pos->passphrase && !pos->psk) {
+ if (prev && prev->psk && prev->passphrase &&
+ !os_strcmp(pos->passphrase, prev->passphrase))
+ continue;
+
+ pos->psk = os_zalloc(PMK_LEN);
+ if (!pos->psk)
+ continue;
+
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;
+ } else if (!pos->psk)
+ continue;
+
+ if (prev_psk && (!prev || prev->psk != prev_psk)) {
+ prev = pos;
+ continue;
}
+
+ psk = pos->psk;
+ break;
}
}
return psk;
@@ -165,101 +165,108 @@ struct radius_attr_type {
RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
} data_type;
+ enum {
+ RADIUS_ATTR_F_TAGGED = BIT(0),
+ RADIUS_ATTR_F_TAGGED_LIM = BIT(1),
+ } flags;
};
static const struct radius_attr_type radius_attrs[] =
{
- { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
- { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
- { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP },
- { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
- { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
- { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
- { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST, 0},
+ { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP, 0},
+ { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP, 0},
+ { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST, 0},
+ { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST, 0},
+ { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST, 0},
+ { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
- RADIUS_ATTR_TEXT },
+ RADIUS_ATTR_TEXT, 0},
{ RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
- RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
+ RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST, 0},
{ RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
- RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
- RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
- RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
- RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP },
- { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP, 0},
+ { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP,
+ RADIUS_ATTR_F_TAGGED},
{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
- RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_F_TAGGED},
{ RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
- RADIUS_ATTR_UNDIST },
- { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
+ RADIUS_ATTR_UNDIST, RADIUS_ATTR_F_TAGGED},
+ { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST, 0},
{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
- RADIUS_ATTR_UNDIST },
+ RADIUS_ATTR_UNDIST, 0},
{ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
- RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_F_TAGGED_LIM },
{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
- RADIUS_ATTR_TEXT },
- { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
- { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP },
- { RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT },
+ RADIUS_ATTR_TEXT, 0},
+ { RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID, "Tunnel-Client-Auth-ID",
+ RADIUS_ATTR_TEXT, RADIUS_ATTR_F_TAGGED},
+ { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6, 0},
+ { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP, 0},
+ { RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT, 0},
{ RADIUS_ATTR_LOCATION_INFO, "Location-Information",
- RADIUS_ATTR_HEXDUMP },
- { RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_HEXDUMP, 0},
+ { RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP, 0},
{ RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES,
- "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
+ "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP, 0},
{ RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES,
- "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
- { RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32 },
+ "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP, 0},
+ { RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_REQUESTED_LOCATION_INFO, "Requested-Location-Info",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
- RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
+ RADIUS_ATTR_INT32, 0},
+ { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT, 0},
{ RADIUS_ATTR_WLAN_REASON_CODE, "WLAN-Reason-Code",
- RADIUS_ATTR_INT32 },
+ RADIUS_ATTR_INT32, 0},
{ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher",
- RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_HEXDUMP, 0},
{ RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher",
- RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_HEXDUMP, 0},
{ RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite",
- RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_HEXDUMP, 0},
{ RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher",
- RADIUS_ATTR_HEXDUMP },
+ RADIUS_ATTR_HEXDUMP, 0},
};
#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
@@ -295,6 +302,18 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
len = hdr->length - sizeof(struct radius_attr_hdr);
pos = (unsigned char *) (hdr + 1);
+ if (len > 0 && (attr->flags & RADIUS_ATTR_F_TAGGED)) {
+ wpa_printf(MSG_INFO, " Tag: %u", pos[0]);
+ pos++;
+ len--;
+ }
+ if (len > 0 && (attr->flags & RADIUS_ATTR_F_TAGGED_LIM) &&
+ pos[0] <= 0x1F) {
+ wpa_printf(MSG_INFO, " Tag: %u", pos[0]);
+ pos++;
+ len--;
+ }
+
switch (attr->data_type) {
case RADIUS_ATTR_TEXT:
printf_encode(buf, sizeof(buf), pos, len);
@@ -1379,6 +1398,39 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
}
+int radius_msg_get_attr_tag_ptr(struct radius_msg *msg, u8 type, u8 tag,
+ u8 **buf, size_t *len, size_t idx,
+ size_t *next_idx)
+{
+ size_t i;
+ struct radius_attr_hdr *attr;
+
+ for (i = idx; i < msg->attr_used; i++) {
+ attr = radius_get_attr_hdr(msg, i);
+ if (attr->type != type ||
+ attr->length <= sizeof(*attr))
+ continue;
+
+ *buf = (u8 *) (attr + 1);
+ *len = attr->length - sizeof(*attr) - 1;
+
+ if (*buf[0] != tag)
+ continue;
+
+ (*buf)++; // skip tag from output
+ if (next_idx)
+ *next_idx = i + 1;
+
+ return 0;
+ }
+
+ *buf = NULL;
+ *len = 0;
+
+ return -1;
+}
+
+
int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
size_t *len, const u8 *start)
{
@@ -1554,7 +1606,8 @@ int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
*/
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
const u8 *secret, size_t secret_len,
- struct radius_msg *sent_msg, size_t n)
+ struct radius_msg *sent_msg, size_t idx,
+ u8 *out_tag, size_t *next_idx)
{
u8 *buf = NULL;
size_t buflen;
@@ -1564,7 +1617,7 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
size_t len[3];
u8 hash[16];
u8 *pos;
- size_t i, j = 0;
+ size_t i;
struct radius_attr_hdr *attr;
const u8 *data;
size_t dlen;
@@ -1573,7 +1626,7 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
char *ret = NULL;
/* find n-th valid Tunnel-Password attribute */
- for (i = 0; i < msg->attr_used; i++) {
+ for (i = idx; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
if (attr == NULL ||
attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
@@ -1585,9 +1638,8 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
dlen = attr->length - sizeof(*attr);
if (dlen <= 3 || dlen % 16 != 3)
continue;
- j++;
- if (j <= n)
- continue;
+ if (next_idx)
+ *next_idx = i + 1;
fdata = data;
fdlen = dlen;
@@ -1603,6 +1655,8 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
buflen = fdlen;
/* init pointers */
+ if (out_tag)
+ *out_tag = *buf;
salt = buf + 1;
str = buf + 3;
@@ -92,6 +92,7 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
+ RADIUS_ATTR_TUNNEL_CLIENT_AUTH_ID = 90,
RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
RADIUS_ATTR_ERROR_CAUSE = 101,
RADIUS_ATTR_EAP_KEY_NAME = 102,
@@ -297,7 +298,8 @@ int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
int *tagged);
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
const u8 *secret, size_t secret_len,
- struct radius_msg *sent_msg, size_t n);
+ struct radius_msg *sent_msg, size_t idx,
+ u8 *out_tag, size_t *next_idx);
static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
u32 value)
@@ -321,6 +323,9 @@ static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type,
int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
size_t *len, const u8 *start);
int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len);
+int radius_msg_get_attr_tag_ptr(struct radius_msg *msg, u8 type, u8 tag,
+ u8 **buf, size_t *len, size_t idx,
+ size_t *next_idx);
struct radius_attr_data {