RADIUS: Preliminary support RADIUS/TLS as an alternative to RADIUS/UDP
This adds initial parts for RADIUS/TLS support in the RADIUS client. This can be used with eapol_test and hostapd. This functionality is not included by default and CONFIG_RADIUS_TLS=y in .config can be used to enable it. This version does not yet include all the needed functionality for TLS validation and the rules for dropping a TCP connection based on invalid RADIUS attributes. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
87f33c26b9
commit
95a825bc43
11 changed files with 715 additions and 22 deletions
|
@ -647,6 +647,11 @@ ifdef CHAP
|
||||||
OBJS += src/eap_common/chap.c
|
OBJS += src/eap_common/chap.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_RADIUS_TLS
|
||||||
|
TLS_FUNCS=y
|
||||||
|
L_CFLAGS += -DCONFIG_RADIUS_TLS
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef TLS_FUNCS
|
ifdef TLS_FUNCS
|
||||||
NEED_DES=y
|
NEED_DES=y
|
||||||
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
|
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
|
||||||
|
|
|
@ -682,6 +682,11 @@ ifdef CHAP
|
||||||
OBJS += ../src/eap_common/chap.o
|
OBJS += ../src/eap_common/chap.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_RADIUS_TLS
|
||||||
|
TLS_FUNCS=y
|
||||||
|
CFLAGS += -DCONFIG_RADIUS_TLS
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef TLS_FUNCS
|
ifdef TLS_FUNCS
|
||||||
NEED_DES=y
|
NEED_DES=y
|
||||||
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
|
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
|
||||||
|
|
|
@ -121,6 +121,9 @@ CONFIG_PKCS12=y
|
||||||
# Build IPv6 support for RADIUS operations
|
# Build IPv6 support for RADIUS operations
|
||||||
CONFIG_IPV6=y
|
CONFIG_IPV6=y
|
||||||
|
|
||||||
|
# Include support fo RADIUS/TLS into the RADIUS client
|
||||||
|
#CONFIG_RADIUS_TLS=y
|
||||||
|
|
||||||
# IEEE Std 802.11r-2008 (Fast BSS Transition)
|
# IEEE Std 802.11r-2008 (Fast BSS Transition)
|
||||||
#CONFIG_IEEE80211R=y
|
#CONFIG_IEEE80211R=y
|
||||||
|
|
||||||
|
|
|
@ -2869,6 +2869,37 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
os_free(bss->radius->auth_server->shared_secret);
|
os_free(bss->radius->auth_server->shared_secret);
|
||||||
bss->radius->auth_server->shared_secret = (u8 *) os_strdup(pos);
|
bss->radius->auth_server->shared_secret = (u8 *) os_strdup(pos);
|
||||||
bss->radius->auth_server->shared_secret_len = len;
|
bss->radius->auth_server->shared_secret_len = len;
|
||||||
|
} else if (bss->radius->auth_server &&
|
||||||
|
os_strcmp(buf, "auth_server_type") == 0) {
|
||||||
|
if (os_strcmp(pos, "UDP") == 0) {
|
||||||
|
bss->radius->auth_server->tls = false;
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
} else if (os_strcmp(pos, "TLS") == 0) {
|
||||||
|
bss->radius->auth_server->tls = true;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
} else {
|
||||||
|
wpa_printf(MSG_ERROR, "Line %d: unsupported RADIUS type '%s'",
|
||||||
|
line, pos);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
} else if (bss->radius->auth_server &&
|
||||||
|
os_strcmp(buf, "auth_server_ca_cert") == 0) {
|
||||||
|
os_free(bss->radius->auth_server->ca_cert);
|
||||||
|
bss->radius->auth_server->ca_cert = os_strdup(pos);
|
||||||
|
} else if (bss->radius->auth_server &&
|
||||||
|
os_strcmp(buf, "auth_server_client_cert") == 0) {
|
||||||
|
os_free(bss->radius->auth_server->client_cert);
|
||||||
|
bss->radius->auth_server->client_cert = os_strdup(pos);
|
||||||
|
} else if (bss->radius->auth_server &&
|
||||||
|
os_strcmp(buf, "auth_server_private_key") == 0) {
|
||||||
|
os_free(bss->radius->auth_server->private_key);
|
||||||
|
bss->radius->auth_server->private_key = os_strdup(pos);
|
||||||
|
} else if (bss->radius->auth_server &&
|
||||||
|
os_strcmp(buf, "auth_server_private_key_passwd") == 0) {
|
||||||
|
os_free(bss->radius->auth_server->private_key_passwd);
|
||||||
|
bss->radius->auth_server->private_key_passwd = os_strdup(pos);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
} else if (os_strcmp(buf, "acct_server_addr") == 0) {
|
} else if (os_strcmp(buf, "acct_server_addr") == 0) {
|
||||||
if (hostapd_config_read_radius_addr(
|
if (hostapd_config_read_radius_addr(
|
||||||
&bss->radius->acct_servers,
|
&bss->radius->acct_servers,
|
||||||
|
@ -2903,6 +2934,37 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
os_free(bss->radius->acct_server->shared_secret);
|
os_free(bss->radius->acct_server->shared_secret);
|
||||||
bss->radius->acct_server->shared_secret = (u8 *) os_strdup(pos);
|
bss->radius->acct_server->shared_secret = (u8 *) os_strdup(pos);
|
||||||
bss->radius->acct_server->shared_secret_len = len;
|
bss->radius->acct_server->shared_secret_len = len;
|
||||||
|
} else if (bss->radius->acct_server &&
|
||||||
|
os_strcmp(buf, "acct_server_type") == 0) {
|
||||||
|
if (os_strcmp(pos, "UDP") == 0) {
|
||||||
|
bss->radius->acct_server->tls = false;
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
} else if (os_strcmp(pos, "TLS") == 0) {
|
||||||
|
bss->radius->acct_server->tls = true;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
} else {
|
||||||
|
wpa_printf(MSG_ERROR, "Line %d: unsupported RADIUS type '%s'",
|
||||||
|
line, pos);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
} else if (bss->radius->acct_server &&
|
||||||
|
os_strcmp(buf, "acct_server_ca_cert") == 0) {
|
||||||
|
os_free(bss->radius->acct_server->ca_cert);
|
||||||
|
bss->radius->acct_server->ca_cert = os_strdup(pos);
|
||||||
|
} else if (bss->radius->acct_server &&
|
||||||
|
os_strcmp(buf, "acct_server_client_cert") == 0) {
|
||||||
|
os_free(bss->radius->acct_server->client_cert);
|
||||||
|
bss->radius->acct_server->client_cert = os_strdup(pos);
|
||||||
|
} else if (bss->radius->acct_server &&
|
||||||
|
os_strcmp(buf, "acct_server_private_key") == 0) {
|
||||||
|
os_free(bss->radius->acct_server->private_key);
|
||||||
|
bss->radius->acct_server->private_key = os_strdup(pos);
|
||||||
|
} else if (bss->radius->acct_server &&
|
||||||
|
os_strcmp(buf, "acct_server_private_key_passwd") == 0) {
|
||||||
|
os_free(bss->radius->acct_server->private_key_passwd);
|
||||||
|
bss->radius->acct_server->private_key_passwd = os_strdup(pos);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
} else if (os_strcmp(buf, "radius_retry_primary_interval") == 0) {
|
} else if (os_strcmp(buf, "radius_retry_primary_interval") == 0) {
|
||||||
bss->radius->retry_primary_interval = atoi(pos);
|
bss->radius->retry_primary_interval = atoi(pos);
|
||||||
} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) {
|
} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) {
|
||||||
|
|
|
@ -141,6 +141,9 @@ CONFIG_PKCS12=y
|
||||||
# Build IPv6 support for RADIUS operations
|
# Build IPv6 support for RADIUS operations
|
||||||
CONFIG_IPV6=y
|
CONFIG_IPV6=y
|
||||||
|
|
||||||
|
# Include support fo RADIUS/TLS into the RADIUS client
|
||||||
|
#CONFIG_RADIUS_TLS=y
|
||||||
|
|
||||||
# IEEE Std 802.11r-2008 (Fast BSS Transition)
|
# IEEE Std 802.11r-2008 (Fast BSS Transition)
|
||||||
#CONFIG_IEEE80211R=y
|
#CONFIG_IEEE80211R=y
|
||||||
|
|
||||||
|
|
|
@ -1581,6 +1581,16 @@ own_ip_addr=127.0.0.1
|
||||||
#acct_server_port=1813
|
#acct_server_port=1813
|
||||||
#acct_server_shared_secret=secret2
|
#acct_server_shared_secret=secret2
|
||||||
|
|
||||||
|
# RADIUS/TLS instead of RADIUS/UDP
|
||||||
|
#auth_server_addr=127.0.0.1
|
||||||
|
#auth_server_port=2083
|
||||||
|
#auth_server_type=TLS
|
||||||
|
#auth_server_shared_secret=radsec
|
||||||
|
#auth_server_ca_cert=<path to trusted CA certificate(s)>
|
||||||
|
#auth_server_client_cert=<path to client certificate>
|
||||||
|
#auth_server_private_key=<path to private key>
|
||||||
|
#auth_server_private_key_passwd=<password for decrypting private key>
|
||||||
|
|
||||||
# Retry interval for trying to return to the primary RADIUS server (in
|
# Retry interval for trying to return to the primary RADIUS server (in
|
||||||
# seconds). RADIUS client code will automatically try to use the next server
|
# seconds). RADIUS client code will automatically try to use the next server
|
||||||
# when the current server is not replying to requests. If this interval is set,
|
# when the current server is not replying to requests. If this interval is set,
|
||||||
|
|
|
@ -555,6 +555,10 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
|
||||||
|
|
||||||
for (i = 0; i < num_servers; i++) {
|
for (i = 0; i < num_servers; i++) {
|
||||||
os_free(servers[i].shared_secret);
|
os_free(servers[i].shared_secret);
|
||||||
|
os_free(servers[i].ca_cert);
|
||||||
|
os_free(servers[i].client_cert);
|
||||||
|
os_free(servers[i].private_key);
|
||||||
|
os_free(servers[i].private_key_passwd);
|
||||||
}
|
}
|
||||||
os_free(servers);
|
os_free(servers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
/*
|
/*
|
||||||
* RADIUS client
|
* RADIUS client
|
||||||
* Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
#include <fcntl.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "crypto/tls.h"
|
||||||
#include "radius.h"
|
#include "radius.h"
|
||||||
#include "radius_client.h"
|
#include "radius_client.h"
|
||||||
#include "eloop.h"
|
|
||||||
|
|
||||||
/* Defaults for RADIUS retransmit values (exponential backoff) */
|
/* Defaults for RADIUS retransmit values (exponential backoff) */
|
||||||
|
|
||||||
|
@ -173,11 +175,31 @@ struct radius_client_data {
|
||||||
*/
|
*/
|
||||||
int auth_sock;
|
int auth_sock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* auth_tls - Whether current authentication connection uses TLS
|
||||||
|
*/
|
||||||
|
bool auth_tls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* auth_tls_ready - Whether authentication TLS is ready
|
||||||
|
*/
|
||||||
|
bool auth_tls_ready;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acct_sock - Currently used socket for RADIUS accounting server
|
* acct_sock - Currently used socket for RADIUS accounting server
|
||||||
*/
|
*/
|
||||||
int acct_sock;
|
int acct_sock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acct_tls - Whether current accounting connection uses TLS
|
||||||
|
*/
|
||||||
|
bool acct_tls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acct_tls_ready - Whether accounting TLS is ready
|
||||||
|
*/
|
||||||
|
bool acct_tls_ready;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* auth_handlers - Authentication message handlers
|
* auth_handlers - Authentication message handlers
|
||||||
*/
|
*/
|
||||||
|
@ -222,6 +244,12 @@ struct radius_client_data {
|
||||||
* interim_error_cb_ctx - interim_error_cb() context data
|
* interim_error_cb_ctx - interim_error_cb() context data
|
||||||
*/
|
*/
|
||||||
void *interim_error_cb_ctx;
|
void *interim_error_cb_ctx;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
void *tls_ctx;
|
||||||
|
struct tls_connection *auth_tls_conn;
|
||||||
|
struct tls_connection *acct_tls_conn;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -354,9 +382,19 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
u8 *acct_delay_time;
|
u8 *acct_delay_time;
|
||||||
size_t acct_delay_time_len;
|
size_t acct_delay_time_len;
|
||||||
int num_servers;
|
int num_servers;
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
struct wpabuf *out = NULL;
|
||||||
|
struct tls_connection *conn = NULL;
|
||||||
|
bool acct = false;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
if (entry->msg_type == RADIUS_ACCT ||
|
if (entry->msg_type == RADIUS_ACCT ||
|
||||||
entry->msg_type == RADIUS_ACCT_INTERIM) {
|
entry->msg_type == RADIUS_ACCT_INTERIM) {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
acct = true;
|
||||||
|
if (radius->acct_tls)
|
||||||
|
conn = radius->acct_tls_conn;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
num_servers = conf->num_acct_servers;
|
num_servers = conf->num_acct_servers;
|
||||||
if (radius->acct_sock < 0)
|
if (radius->acct_sock < 0)
|
||||||
radius_client_init_acct(radius);
|
radius_client_init_acct(radius);
|
||||||
|
@ -374,6 +412,10 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
conf->acct_server->retransmissions++;
|
conf->acct_server->retransmissions++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (radius->auth_tls)
|
||||||
|
conn = radius->auth_tls_conn;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
num_servers = conf->num_auth_servers;
|
num_servers = conf->num_auth_servers;
|
||||||
if (radius->auth_sock < 0)
|
if (radius->auth_sock < 0)
|
||||||
radius_client_init_auth(radius);
|
radius_client_init_auth(radius);
|
||||||
|
@ -409,6 +451,15 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if ((acct && radius->acct_tls && !radius->acct_tls_ready) ||
|
||||||
|
(!acct && radius->auth_tls && !radius->auth_tls_ready)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: TLS connection not yet ready for TX");
|
||||||
|
goto not_ready;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
if (entry->msg_type == RADIUS_ACCT &&
|
if (entry->msg_type == RADIUS_ACCT &&
|
||||||
radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
|
radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
|
||||||
&acct_delay_time, &acct_delay_time_len,
|
&acct_delay_time, &acct_delay_time_len,
|
||||||
|
@ -453,11 +504,37 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
|
|
||||||
os_get_reltime(&entry->last_attempt);
|
os_get_reltime(&entry->last_attempt);
|
||||||
buf = radius_msg_get_buf(entry->msg);
|
buf = radius_msg_get_buf(entry->msg);
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (conn) {
|
||||||
|
out = tls_connection_encrypt(radius->tls_ctx, conn, buf);
|
||||||
|
if (!out) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Failed to encrypt RADIUS message (TLS)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: TLS encryption of %zu bytes of plaintext to %zu bytes of ciphertext",
|
||||||
|
wpabuf_len(buf), wpabuf_len(out));
|
||||||
|
buf = out;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: Send %zu bytes to the server",
|
||||||
|
wpabuf_len(buf));
|
||||||
if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
|
if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
|
||||||
if (radius_client_handle_send_error(radius, s, entry->msg_type)
|
if (radius_client_handle_send_error(radius, s, entry->msg_type)
|
||||||
> 0)
|
> 0) {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
wpabuf_free(out);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
wpabuf_free(out);
|
||||||
|
|
||||||
|
not_ready:
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
entry->next_try = now + entry->next_wait;
|
entry->next_try = now + entry->next_wait;
|
||||||
entry->next_wait *= 2;
|
entry->next_wait *= 2;
|
||||||
|
@ -714,6 +791,11 @@ static int radius_client_disable_pmtu_discovery(int s)
|
||||||
static void radius_close_auth_socket(struct radius_client_data *radius)
|
static void radius_close_auth_socket(struct radius_client_data *radius)
|
||||||
{
|
{
|
||||||
if (radius->auth_sock >= 0) {
|
if (radius->auth_sock >= 0) {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (radius->conf->auth_server->tls)
|
||||||
|
eloop_unregister_sock(radius->auth_sock,
|
||||||
|
EVENT_TYPE_WRITE);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
eloop_unregister_read_sock(radius->auth_sock);
|
eloop_unregister_read_sock(radius->auth_sock);
|
||||||
close(radius->auth_sock);
|
close(radius->auth_sock);
|
||||||
radius->auth_sock = -1;
|
radius->auth_sock = -1;
|
||||||
|
@ -724,6 +806,11 @@ static void radius_close_auth_socket(struct radius_client_data *radius)
|
||||||
static void radius_close_acct_socket(struct radius_client_data *radius)
|
static void radius_close_acct_socket(struct radius_client_data *radius)
|
||||||
{
|
{
|
||||||
if (radius->acct_sock >= 0) {
|
if (radius->acct_sock >= 0) {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (radius->conf->acct_server->tls)
|
||||||
|
eloop_unregister_sock(radius->acct_sock,
|
||||||
|
EVENT_TYPE_WRITE);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
eloop_unregister_read_sock(radius->acct_sock);
|
eloop_unregister_read_sock(radius->acct_sock);
|
||||||
close(radius->acct_sock);
|
close(radius->acct_sock);
|
||||||
radius->acct_sock = -1;
|
radius->acct_sock = -1;
|
||||||
|
@ -766,8 +853,18 @@ int radius_client_send(struct radius_client_data *radius,
|
||||||
char *name;
|
char *name;
|
||||||
int s, res;
|
int s, res;
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
struct wpabuf *out = NULL;
|
||||||
|
struct tls_connection *conn = NULL;
|
||||||
|
bool acct = false;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
|
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
acct = true;
|
||||||
|
if (radius->acct_tls)
|
||||||
|
conn = radius->acct_tls_conn;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
if (conf->acct_server && radius->acct_sock < 0)
|
if (conf->acct_server && radius->acct_sock < 0)
|
||||||
radius_client_init_acct(radius);
|
radius_client_init_acct(radius);
|
||||||
|
|
||||||
|
@ -786,6 +883,10 @@ int radius_client_send(struct radius_client_data *radius,
|
||||||
s = radius->acct_sock;
|
s = radius->acct_sock;
|
||||||
conf->acct_server->requests++;
|
conf->acct_server->requests++;
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (radius->auth_tls)
|
||||||
|
conn = radius->auth_tls_conn;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
if (conf->auth_server && radius->auth_sock < 0)
|
if (conf->auth_server && radius->auth_sock < 0)
|
||||||
radius_client_init_auth(radius);
|
radius_client_init_auth(radius);
|
||||||
|
|
||||||
|
@ -811,11 +912,42 @@ int radius_client_send(struct radius_client_data *radius,
|
||||||
if (conf->msg_dumps)
|
if (conf->msg_dumps)
|
||||||
radius_msg_dump(msg);
|
radius_msg_dump(msg);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if ((acct && radius->acct_tls && !radius->acct_tls_ready) ||
|
||||||
|
(!acct && radius->auth_tls && !radius->auth_tls_ready)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: TLS connection not yet ready for TX");
|
||||||
|
goto skip_send;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
buf = radius_msg_get_buf(msg);
|
buf = radius_msg_get_buf(msg);
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (conn) {
|
||||||
|
out = tls_connection_encrypt(radius->tls_ctx, conn, buf);
|
||||||
|
if (!out) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Failed to encrypt RADIUS message (TLS)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: TLS encryption of %zu bytes of plaintext to %zu bytes of ciphertext",
|
||||||
|
wpabuf_len(buf), wpabuf_len(out));
|
||||||
|
buf = out;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: Send %zu bytes to the server",
|
||||||
|
wpabuf_len(buf));
|
||||||
res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
|
res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
wpabuf_free(out);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
radius_client_handle_send_error(radius, s, msg_type);
|
radius_client_handle_send_error(radius, s, msg_type);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
skip_send:
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
radius_client_list_add(radius, msg, msg_type, shared_secret,
|
radius_client_list_add(radius, msg, msg_type, shared_secret,
|
||||||
shared_secret_len, addr);
|
shared_secret_len, addr);
|
||||||
|
|
||||||
|
@ -823,6 +955,137 @@ int radius_client_send(struct radius_client_data *radius,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
|
||||||
|
static void radius_client_close_tcp(struct radius_client_data *radius,
|
||||||
|
int sock, RadiusType msg_type)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: Closing TCP connection (sock %d)",
|
||||||
|
sock);
|
||||||
|
if (msg_type == RADIUS_ACCT) {
|
||||||
|
radius->acct_tls_ready = false;
|
||||||
|
radius_close_acct_socket(radius);
|
||||||
|
} else {
|
||||||
|
radius->auth_tls_ready = false;
|
||||||
|
radius_close_auth_socket(radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
radius_client_process_tls_handshake(struct radius_client_data *radius,
|
||||||
|
int sock, RadiusType msg_type,
|
||||||
|
u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct wpabuf *in, *out = NULL, *appl;
|
||||||
|
struct tls_connection *conn;
|
||||||
|
int res;
|
||||||
|
bool ready = false;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Process %zu bytes of received TLS handshake message",
|
||||||
|
len);
|
||||||
|
|
||||||
|
if (msg_type == RADIUS_ACCT)
|
||||||
|
conn = radius->acct_tls_conn;
|
||||||
|
else
|
||||||
|
conn = radius->auth_tls_conn;
|
||||||
|
|
||||||
|
in = wpabuf_alloc_copy(buf, len);
|
||||||
|
if (!in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
appl = NULL;
|
||||||
|
out = tls_connection_handshake(radius->tls_ctx, conn, in, &appl);
|
||||||
|
wpabuf_free(in);
|
||||||
|
if (!out) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Could not generate TLS handshake data");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tls_connection_get_failed(radius->tls_ctx, conn)) {
|
||||||
|
wpa_printf(MSG_INFO, "RADIUS: TLS handshake failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tls_connection_established(radius->tls_ctx, conn)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: TLS connection established (sock=%d)",
|
||||||
|
sock);
|
||||||
|
if (msg_type == RADIUS_ACCT)
|
||||||
|
radius->acct_tls_ready = true;
|
||||||
|
else
|
||||||
|
radius->auth_tls_ready = true;
|
||||||
|
ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: Sending %zu bytes of TLS handshake",
|
||||||
|
wpabuf_len(out));
|
||||||
|
res = send(sock, wpabuf_head(out), wpabuf_len(out), 0);
|
||||||
|
if (res < 0) {
|
||||||
|
wpa_printf(MSG_INFO, "RADIUS: send: %s", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((size_t) res != wpabuf_len(out)) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Could not send all data for TLS handshake: only %d bytes sent",
|
||||||
|
res);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
wpabuf_free(out);
|
||||||
|
|
||||||
|
if (ready) {
|
||||||
|
struct radius_msg_list *entry, *prev, *tmp;
|
||||||
|
struct os_reltime now;
|
||||||
|
|
||||||
|
/* Send all pending message of matching type since the TLS
|
||||||
|
* tunnel has now been established. */
|
||||||
|
|
||||||
|
os_get_reltime(&now);
|
||||||
|
|
||||||
|
entry = radius->msgs;
|
||||||
|
prev = NULL;
|
||||||
|
while (entry) {
|
||||||
|
if (entry->msg_type != msg_type) {
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius_client_retransmit(radius, entry, now.sec)) {
|
||||||
|
if (prev)
|
||||||
|
prev->next = entry->next;
|
||||||
|
else
|
||||||
|
radius->msgs = entry->next;
|
||||||
|
|
||||||
|
tmp = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
radius_client_msg_free(tmp);
|
||||||
|
radius->num_msgs--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
wpabuf_free(out);
|
||||||
|
tls_connection_deinit(radius->tls_ctx, conn);
|
||||||
|
if (msg_type == RADIUS_ACCT)
|
||||||
|
radius->acct_tls_conn = NULL;
|
||||||
|
else
|
||||||
|
radius->auth_tls_conn = NULL;
|
||||||
|
radius_client_close_tcp(radius, sock, msg_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
|
|
||||||
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
{
|
{
|
||||||
struct radius_client_data *radius = eloop_ctx;
|
struct radius_client_data *radius = eloop_ctx;
|
||||||
|
@ -840,12 +1103,28 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
struct os_reltime now;
|
struct os_reltime now;
|
||||||
struct hostapd_radius_server *rconf;
|
struct hostapd_radius_server *rconf;
|
||||||
int invalid_authenticator = 0;
|
int invalid_authenticator = 0;
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
struct tls_connection *conn = NULL;
|
||||||
|
bool tls, tls_ready;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
if (msg_type == RADIUS_ACCT) {
|
if (msg_type == RADIUS_ACCT) {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (radius->acct_tls)
|
||||||
|
conn = radius->acct_tls_conn;
|
||||||
|
tls = radius->acct_tls;
|
||||||
|
tls_ready = radius->acct_tls_ready;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
handlers = radius->acct_handlers;
|
handlers = radius->acct_handlers;
|
||||||
num_handlers = radius->num_acct_handlers;
|
num_handlers = radius->num_acct_handlers;
|
||||||
rconf = conf->acct_server;
|
rconf = conf->acct_server;
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (radius->auth_tls)
|
||||||
|
conn = radius->auth_tls_conn;
|
||||||
|
tls = radius->auth_tls;
|
||||||
|
tls_ready = radius->auth_tls_ready;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
handlers = radius->auth_handlers;
|
handlers = radius->auth_handlers;
|
||||||
num_handlers = radius->num_auth_handlers;
|
num_handlers = radius->num_auth_handlers;
|
||||||
rconf = conf->auth_server;
|
rconf = conf->auth_server;
|
||||||
|
@ -861,6 +1140,52 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
wpa_printf(MSG_INFO, "recvmsg[RADIUS]: %s", strerror(errno));
|
wpa_printf(MSG_INFO, "recvmsg[RADIUS]: %s", strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (tls && len == 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: No TCP data available");
|
||||||
|
goto close_tcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tls && !tls_ready) {
|
||||||
|
radius_client_process_tls_handshake(radius, sock, msg_type,
|
||||||
|
buf, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
struct wpabuf *out, *in;
|
||||||
|
|
||||||
|
in = wpabuf_alloc_copy(buf, len);
|
||||||
|
if (!in)
|
||||||
|
return;
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Process %d bytes of encrypted TLS data",
|
||||||
|
len);
|
||||||
|
out = tls_connection_decrypt(radius->tls_ctx, conn, in);
|
||||||
|
wpabuf_free(in);
|
||||||
|
if (!out) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Failed to decrypt TLS data");
|
||||||
|
goto close_tcp;
|
||||||
|
}
|
||||||
|
if (wpabuf_len(out) == 0) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Full message not yet received - continue waiting for additional TLS data");
|
||||||
|
wpabuf_free(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (wpabuf_len(out) > RADIUS_MAX_MSG_LEN) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Too long RADIUS message from TLS: %zu",
|
||||||
|
wpabuf_len(out));
|
||||||
|
wpabuf_free(out);
|
||||||
|
goto close_tcp;
|
||||||
|
}
|
||||||
|
os_memcpy(buf, wpabuf_head(out), wpabuf_len(out));
|
||||||
|
len = wpabuf_len(out);
|
||||||
|
wpabuf_free(out);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||||
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
|
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
|
||||||
|
@ -976,9 +1301,121 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
radius_msg_free(msg);
|
radius_msg_free(msg);
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
close_tcp:
|
||||||
|
radius_client_close_tcp(radius, sock, msg_type);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
static void radius_client_write_ready(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
|
{
|
||||||
|
struct radius_client_data *radius = eloop_ctx;
|
||||||
|
RadiusType msg_type = (uintptr_t) sock_ctx;
|
||||||
|
struct tls_connection *conn = NULL;
|
||||||
|
struct wpabuf *in, *out = NULL, *appl;
|
||||||
|
int res = -1;
|
||||||
|
struct tls_connection_params params;
|
||||||
|
struct hostapd_radius_server *server;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: TCP connection established - start TLS handshake (sock=%d)",
|
||||||
|
sock);
|
||||||
|
|
||||||
|
if (msg_type == RADIUS_ACCT) {
|
||||||
|
eloop_unregister_sock(sock, EVENT_TYPE_WRITE);
|
||||||
|
eloop_register_read_sock(sock, radius_client_receive, radius,
|
||||||
|
(void *) RADIUS_ACCT);
|
||||||
|
if (radius->acct_tls_conn) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Deinit previously used TLS connection");
|
||||||
|
tls_connection_deinit(radius->tls_ctx,
|
||||||
|
radius->acct_tls_conn);
|
||||||
|
radius->acct_tls_conn = NULL;
|
||||||
|
}
|
||||||
|
server = radius->conf->acct_server;
|
||||||
|
} else {
|
||||||
|
eloop_unregister_sock(sock, EVENT_TYPE_WRITE);
|
||||||
|
eloop_register_read_sock(sock, radius_client_receive, radius,
|
||||||
|
(void *) RADIUS_AUTH);
|
||||||
|
if (radius->auth_tls_conn) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Deinit previously used TLS connection");
|
||||||
|
tls_connection_deinit(radius->tls_ctx,
|
||||||
|
radius->auth_tls_conn);
|
||||||
|
radius->auth_tls_conn = NULL;
|
||||||
|
}
|
||||||
|
server = radius->conf->auth_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
conn = tls_connection_init(radius->tls_ctx);
|
||||||
|
if (!conn) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Failed to initiate TLS connection");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(¶ms, 0, sizeof(params));
|
||||||
|
params.ca_cert = server->ca_cert;
|
||||||
|
params.client_cert = server->client_cert;
|
||||||
|
params.private_key = server->private_key;
|
||||||
|
params.private_key_passwd = server->private_key_passwd;
|
||||||
|
params.flags = TLS_CONN_DISABLE_TLSv1_0 | TLS_CONN_DISABLE_TLSv1_1;
|
||||||
|
if (tls_connection_set_params(radius->tls_ctx, conn, ¶ms)) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Failed to set TLS connection parameters");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
in = NULL;
|
||||||
|
appl = NULL;
|
||||||
|
out = tls_connection_handshake(radius->tls_ctx, conn, in, &appl);
|
||||||
|
if (!out) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Could not generate TLS handshake data");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tls_connection_get_failed(radius->tls_ctx, conn)) {
|
||||||
|
wpa_printf(MSG_INFO, "RADIUS: TLS handshake failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: Sending %zu bytes of TLS handshake",
|
||||||
|
wpabuf_len(out));
|
||||||
|
res = send(sock, wpabuf_head(out), wpabuf_len(out), 0);
|
||||||
|
if (res < 0) {
|
||||||
|
wpa_printf(MSG_INFO, "RADIUS: send: %s", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((size_t) res != wpabuf_len(out)) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: Could not send all data for TLS handshake: only %d bytes sent",
|
||||||
|
res);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
wpabuf_free(out);
|
||||||
|
|
||||||
|
if (msg_type == RADIUS_ACCT)
|
||||||
|
radius->acct_tls_conn = conn;
|
||||||
|
else
|
||||||
|
radius->auth_tls_conn = conn;
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
wpa_printf(MSG_INFO, "RADIUS: Failed to perform TLS handshake");
|
||||||
|
tls_connection_deinit(radius->tls_ctx, conn);
|
||||||
|
wpabuf_free(out);
|
||||||
|
radius_client_close_tcp(radius, sock, msg_type);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* radius_client_get_id - Get an identifier for a new RADIUS message
|
* radius_client_get_id - Get an identifier for a new RADIUS message
|
||||||
* @radius: RADIUS client context from radius_client_init()
|
* @radius: RADIUS client context from radius_client_init()
|
||||||
|
@ -1095,6 +1532,17 @@ radius_change_server(struct radius_client_data *radius,
|
||||||
int sel_sock;
|
int sel_sock;
|
||||||
struct radius_msg_list *entry;
|
struct radius_msg_list *entry;
|
||||||
struct hostapd_radius_servers *conf = radius->conf;
|
struct hostapd_radius_servers *conf = radius->conf;
|
||||||
|
int type = SOCK_DGRAM;
|
||||||
|
bool tls = nserv->tls;
|
||||||
|
|
||||||
|
if (tls) {
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
type = SOCK_STREAM;
|
||||||
|
#else /* CONFIG_RADIUS_TLS */
|
||||||
|
wpa_printf(MSG_ERROR, "RADIUS: TLS not supported");
|
||||||
|
return -1;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
}
|
||||||
|
|
||||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||||
HOSTAPD_LEVEL_INFO,
|
HOSTAPD_LEVEL_INFO,
|
||||||
|
@ -1153,7 +1601,7 @@ radius_change_server(struct radius_client_data *radius,
|
||||||
serv.sin_port = htons(nserv->port);
|
serv.sin_port = htons(nserv->port);
|
||||||
addr = (struct sockaddr *) &serv;
|
addr = (struct sockaddr *) &serv;
|
||||||
addrlen = sizeof(serv);
|
addrlen = sizeof(serv);
|
||||||
sel_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
sel_sock = socket(PF_INET, type, 0);
|
||||||
if (sel_sock >= 0)
|
if (sel_sock >= 0)
|
||||||
radius_client_disable_pmtu_discovery(sel_sock);
|
radius_client_disable_pmtu_discovery(sel_sock);
|
||||||
break;
|
break;
|
||||||
|
@ -1166,7 +1614,7 @@ radius_change_server(struct radius_client_data *radius,
|
||||||
serv6.sin6_port = htons(nserv->port);
|
serv6.sin6_port = htons(nserv->port);
|
||||||
addr = (struct sockaddr *) &serv6;
|
addr = (struct sockaddr *) &serv6;
|
||||||
addrlen = sizeof(serv6);
|
addrlen = sizeof(serv6);
|
||||||
sel_sock = socket(PF_INET6, SOCK_DGRAM, 0);
|
sel_sock = socket(PF_INET6, type, 0);
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_IPV6 */
|
#endif /* CONFIG_IPV6 */
|
||||||
default:
|
default:
|
||||||
|
@ -1180,6 +1628,15 @@ radius_change_server(struct radius_client_data *radius,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (tls && fcntl(sel_sock, F_SETFL, O_NONBLOCK) != 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: fnctl(O_NONBLOCK) failed: %s",
|
||||||
|
strerror(errno));
|
||||||
|
close(sel_sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (conf->force_client_dev && conf->force_client_dev[0]) {
|
if (conf->force_client_dev && conf->force_client_dev[0]) {
|
||||||
if (setsockopt(sel_sock, SOL_SOCKET, SO_BINDTODEVICE,
|
if (setsockopt(sel_sock, SOL_SOCKET, SO_BINDTODEVICE,
|
||||||
|
@ -1233,9 +1690,16 @@ radius_change_server(struct radius_client_data *radius,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(sel_sock, addr, addrlen) < 0) {
|
if (connect(sel_sock, addr, addrlen) < 0) {
|
||||||
wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
|
if (nserv->tls && errno == EINPROGRESS) {
|
||||||
close(sel_sock);
|
wpa_printf(MSG_DEBUG,
|
||||||
return -2;
|
"RADIUS: TCP connection establishment in progress (sock %d)",
|
||||||
|
sel_sock);
|
||||||
|
} else {
|
||||||
|
wpa_printf(MSG_INFO, "connect[radius]: %s",
|
||||||
|
strerror(errno));
|
||||||
|
close(sel_sock);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_NATIVE_WINDOWS
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
|
@ -1273,9 +1737,26 @@ radius_change_server(struct radius_client_data *radius,
|
||||||
radius->acct_sock = sel_sock;
|
radius->acct_sock = sel_sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
eloop_register_read_sock(sel_sock, radius_client_receive, radius,
|
if (!tls)
|
||||||
auth ? (void *) RADIUS_AUTH :
|
eloop_register_read_sock(sel_sock, radius_client_receive,
|
||||||
(void *) RADIUS_ACCT);
|
radius,
|
||||||
|
auth ? (void *) RADIUS_AUTH :
|
||||||
|
(void *) RADIUS_ACCT);
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (tls)
|
||||||
|
eloop_register_sock(sel_sock, EVENT_TYPE_WRITE,
|
||||||
|
radius_client_write_ready, radius,
|
||||||
|
auth ? (void *) RADIUS_AUTH :
|
||||||
|
(void *) RADIUS_ACCT);
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
|
if (auth) {
|
||||||
|
radius->auth_tls = nserv->tls;
|
||||||
|
radius->auth_tls_ready = false;
|
||||||
|
} else {
|
||||||
|
radius->acct_tls = nserv->tls;
|
||||||
|
radius->acct_tls_ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1332,6 +1813,15 @@ static int radius_client_init_acct(struct radius_client_data *radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
static void radius_tls_event_cb(void *ctx, enum tls_event ev,
|
||||||
|
union tls_event_data *data)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS: TLS event %d", ev);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* radius_client_init - Initialize RADIUS client
|
* radius_client_init - Initialize RADIUS client
|
||||||
* @ctx: Callback context to be used in hostapd_logger() calls
|
* @ctx: Callback context to be used in hostapd_logger() calls
|
||||||
|
@ -1370,6 +1860,22 @@ radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
|
||||||
radius_retry_primary_timer, radius,
|
radius_retry_primary_timer, radius,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if ((conf->auth_server && conf->auth_server->tls) ||
|
||||||
|
(conf->acct_server && conf->acct_server->tls)) {
|
||||||
|
struct tls_config tls_conf;
|
||||||
|
|
||||||
|
os_memset(&tls_conf, 0, sizeof(tls_conf));
|
||||||
|
tls_conf.event_cb = radius_tls_event_cb;
|
||||||
|
radius->tls_ctx = tls_init(&tls_conf);
|
||||||
|
if (!radius->tls_ctx) {
|
||||||
|
radius_client_deinit(radius);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
|
|
||||||
|
|
||||||
return radius;
|
return radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1391,6 +1897,13 @@ void radius_client_deinit(struct radius_client_data *radius)
|
||||||
radius_client_flush(radius, 0);
|
radius_client_flush(radius, 0);
|
||||||
os_free(radius->auth_handlers);
|
os_free(radius->auth_handlers);
|
||||||
os_free(radius->acct_handlers);
|
os_free(radius->acct_handlers);
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
if (radius->tls_ctx) {
|
||||||
|
tls_connection_deinit(radius->tls_ctx, radius->auth_tls_conn);
|
||||||
|
tls_connection_deinit(radius->tls_ctx, radius->acct_tls_conn);
|
||||||
|
tls_deinit(radius->tls_ctx);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
os_free(radius);
|
os_free(radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* RADIUS client
|
* RADIUS client
|
||||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -35,6 +35,11 @@ struct hostapd_radius_server {
|
||||||
*/
|
*/
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tls - Whether to use RADIUS/TLS instead of RADIUS/UDP
|
||||||
|
*/
|
||||||
|
bool tls;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shared_secret - Shared secret for authenticating RADIUS messages
|
* shared_secret - Shared secret for authenticating RADIUS messages
|
||||||
*/
|
*/
|
||||||
|
@ -45,6 +50,26 @@ struct hostapd_radius_server {
|
||||||
*/
|
*/
|
||||||
size_t shared_secret_len;
|
size_t shared_secret_len;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ca_cert - Path to trusted CA certificate(s) for RADIUS/TLS
|
||||||
|
*/
|
||||||
|
char *ca_cert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* client_cert - Path to client certificate for RADIUS/TLS
|
||||||
|
*/
|
||||||
|
char *client_cert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private_key - Path to clienbt private key for RADIUS/TLS
|
||||||
|
*/
|
||||||
|
char *private_key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private_key_passwd - Password for the private key for RADIUS/TLS
|
||||||
|
*/
|
||||||
|
char *private_key_passwd;
|
||||||
|
|
||||||
/* Dynamic (not from configuration file) MIB data */
|
/* Dynamic (not from configuration file) MIB data */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1183,6 +1183,10 @@ ifdef CONFIG_TLSV12
|
||||||
CFLAGS += -DCONFIG_TLSV12
|
CFLAGS += -DCONFIG_TLSV12
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_RADIUS_TLS
|
||||||
|
TLS_FUNCS=y
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_TLS), wolfssl)
|
ifeq ($(CONFIG_TLS), wolfssl)
|
||||||
ifdef TLS_FUNCS
|
ifdef TLS_FUNCS
|
||||||
CFLAGS += -DWOLFSSL_DER_LOAD
|
CFLAGS += -DWOLFSSL_DER_LOAD
|
||||||
|
@ -1921,6 +1925,9 @@ OBJS += wpa_supplicant.o events.o bssid_ignore.o wpas_glue.o scan.o
|
||||||
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
|
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
|
||||||
OBJS_t += ../src/radius/radius_client.o
|
OBJS_t += ../src/radius/radius_client.o
|
||||||
OBJS_t += ../src/radius/radius.o
|
OBJS_t += ../src/radius/radius.o
|
||||||
|
ifdef CONFIG_RADIUS_TLS
|
||||||
|
CFLAGS += -DCONFIG_RADIUS_TLS
|
||||||
|
endif
|
||||||
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
|
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
|
||||||
|
|
||||||
OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
|
OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
|
||||||
|
|
|
@ -670,6 +670,10 @@ static void test_eapol_clean(struct eapol_test_data *e,
|
||||||
wpa_s->eapol = NULL;
|
wpa_s->eapol = NULL;
|
||||||
if (e->radius_conf && e->radius_conf->auth_server) {
|
if (e->radius_conf && e->radius_conf->auth_server) {
|
||||||
os_free(e->radius_conf->auth_server->shared_secret);
|
os_free(e->radius_conf->auth_server->shared_secret);
|
||||||
|
os_free(e->radius_conf->auth_server->ca_cert);
|
||||||
|
os_free(e->radius_conf->auth_server->client_cert);
|
||||||
|
os_free(e->radius_conf->auth_server->private_key);
|
||||||
|
os_free(e->radius_conf->auth_server->private_key_passwd);
|
||||||
os_free(e->radius_conf->auth_server);
|
os_free(e->radius_conf->auth_server);
|
||||||
}
|
}
|
||||||
os_free(e->radius_conf);
|
os_free(e->radius_conf);
|
||||||
|
@ -1007,7 +1011,10 @@ struct wpa_driver_ops eapol_test_drv_ops = {
|
||||||
|
|
||||||
static void wpa_init_conf(struct eapol_test_data *e,
|
static void wpa_init_conf(struct eapol_test_data *e,
|
||||||
struct wpa_supplicant *wpa_s, const char *authsrv,
|
struct wpa_supplicant *wpa_s, const char *authsrv,
|
||||||
int port, const char *secret,
|
int port, bool tls, const char *secret,
|
||||||
|
const char *ca_cert, const char *client_cert,
|
||||||
|
const char *private_key,
|
||||||
|
const char *private_key_passwd,
|
||||||
const char *cli_addr, const char *ifname)
|
const char *cli_addr, const char *ifname)
|
||||||
{
|
{
|
||||||
struct hostapd_radius_server *as;
|
struct hostapd_radius_server *as;
|
||||||
|
@ -1045,8 +1052,17 @@ static void wpa_init_conf(struct eapol_test_data *e,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
|
#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
|
||||||
as->port = port;
|
as->port = port;
|
||||||
|
as->tls = tls;
|
||||||
as->shared_secret = (u8 *) os_strdup(secret);
|
as->shared_secret = (u8 *) os_strdup(secret);
|
||||||
as->shared_secret_len = os_strlen(secret);
|
as->shared_secret_len = os_strlen(secret);
|
||||||
|
if (ca_cert)
|
||||||
|
as->ca_cert = os_strdup(ca_cert);
|
||||||
|
if (client_cert)
|
||||||
|
as->client_cert = os_strdup(client_cert);
|
||||||
|
if (private_key)
|
||||||
|
as->private_key = os_strdup(private_key);
|
||||||
|
if (private_key_passwd)
|
||||||
|
as->private_key_passwd = os_strdup(private_key_passwd);
|
||||||
e->radius_conf->auth_server = as;
|
e->radius_conf->auth_server = as;
|
||||||
e->radius_conf->auth_servers = as;
|
e->radius_conf->auth_servers = as;
|
||||||
e->radius_conf->msg_dumps = 1;
|
e->radius_conf->msg_dumps = 1;
|
||||||
|
@ -1256,11 +1272,16 @@ static void usage(void)
|
||||||
{
|
{
|
||||||
printf("usage:\n"
|
printf("usage:\n"
|
||||||
"eapol_test [-enWSv] -c<conf> [-a<AS IP>] [-p<AS port>] "
|
"eapol_test [-enWSv] -c<conf> [-a<AS IP>] [-p<AS port>] "
|
||||||
"[-s<AS secret>]\\\n"
|
"[-s<AS secret>] \\\n"
|
||||||
|
" [-X<RADIUS protocol> \\\n"
|
||||||
" [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
|
" [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
|
||||||
" [-M<client MAC address>] [-o<server cert file] \\\n"
|
" [-M<client MAC address>] [-o<server cert file] \\\n"
|
||||||
" [-N<attr spec>] [-R<PC/SC reader>] "
|
" [-N<attr spec>] [-R<PC/SC reader>] "
|
||||||
"[-P<PC/SC PIN>] \\\n"
|
"[-P<PC/SC PIN>] \\\n"
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
" [-j<CA cert>] [-J<client cert>] \\\n"
|
||||||
|
"[-k<private key] [-K<private key passwd>] \\\n"
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
" [-A<client IP>] [-i<ifname>] [-T<ctrl_iface>]\n"
|
" [-A<client IP>] [-i<ifname>] [-T<ctrl_iface>]\n"
|
||||||
"eapol_test scard\n"
|
"eapol_test scard\n"
|
||||||
"eapol_test sim <PIN> <num triplets> [debug]\n"
|
"eapol_test sim <PIN> <num triplets> [debug]\n"
|
||||||
|
@ -1269,10 +1290,11 @@ static void usage(void)
|
||||||
" -c<conf> = configuration file\n"
|
" -c<conf> = configuration file\n"
|
||||||
" -a<AS IP> = IP address of the authentication server, "
|
" -a<AS IP> = IP address of the authentication server, "
|
||||||
"default 127.0.0.1\n"
|
"default 127.0.0.1\n"
|
||||||
" -p<AS port> = UDP port of the authentication server, "
|
" -p<AS port> = Port of the authentication server,\n"
|
||||||
"default 1812\n"
|
" default 1812 for RADIUS/UDP and 2083 for RADIUS/TLS\n"
|
||||||
" -s<AS secret> = shared secret with the authentication "
|
" -s<AS secret> = shared secret with the authentication server,\n"
|
||||||
"server, default 'radius'\n"
|
" default 'radius' for RADIUS/UDP and 'radsec' for RADIUS/TLS\n"
|
||||||
|
" -X<RADIUS protocol> = RADIUS protocol to use: UDP (default) or TLS\n"
|
||||||
" -A<client IP> = IP address of the client, default: select "
|
" -A<client IP> = IP address of the client, default: select "
|
||||||
"automatically\n"
|
"automatically\n"
|
||||||
" -r<count> = number of re-authentications\n"
|
" -r<count> = number of re-authentications\n"
|
||||||
|
@ -1310,8 +1332,11 @@ int main(int argc, char *argv[])
|
||||||
struct wpa_supplicant wpa_s;
|
struct wpa_supplicant wpa_s;
|
||||||
int c, ret = 1, wait_for_monitor = 0, save_config = 0;
|
int c, ret = 1, wait_for_monitor = 0, save_config = 0;
|
||||||
char *as_addr = "127.0.0.1";
|
char *as_addr = "127.0.0.1";
|
||||||
int as_port = 1812;
|
int as_port = -1;
|
||||||
char *as_secret = "radius";
|
char *as_secret = NULL;
|
||||||
|
char *ca_cert = NULL, *client_cert = NULL;
|
||||||
|
char *private_key = NULL, *private_key_passwd = NULL;
|
||||||
|
bool tls = false;
|
||||||
char *cli_addr = NULL;
|
char *cli_addr = NULL;
|
||||||
char *conf = NULL;
|
char *conf = NULL;
|
||||||
int timeout = 30;
|
int timeout = 30;
|
||||||
|
@ -1334,7 +1359,8 @@ int main(int argc, char *argv[])
|
||||||
wpa_debug_show_keys = 1;
|
wpa_debug_show_keys = 1;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:vW");
|
c = getopt(argc, argv,
|
||||||
|
"a:A:c:C:ei:j:J:k:K:M:nN:o:p:P:r:R:s:St:T:vWX:");
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
break;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -1356,6 +1382,20 @@ int main(int argc, char *argv[])
|
||||||
case 'i':
|
case 'i':
|
||||||
ifname = optarg;
|
ifname = optarg;
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_RADIUS_TLS
|
||||||
|
case 'j':
|
||||||
|
ca_cert = optarg;
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
client_cert = optarg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
private_key = optarg;
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
private_key_passwd = optarg;
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_RADIUS_TLS */
|
||||||
case 'M':
|
case 'M':
|
||||||
if (hwaddr_aton(optarg, eapol_test.own_addr)) {
|
if (hwaddr_aton(optarg, eapol_test.own_addr)) {
|
||||||
usage();
|
usage();
|
||||||
|
@ -1406,6 +1446,16 @@ int main(int argc, char *argv[])
|
||||||
case 'W':
|
case 'W':
|
||||||
wait_for_monitor++;
|
wait_for_monitor++;
|
||||||
break;
|
break;
|
||||||
|
case 'X':
|
||||||
|
if (os_strcmp(optarg, "UDP") == 0) {
|
||||||
|
tls = false;
|
||||||
|
} else if (os_strcmp(optarg, "TLS") == 0) {
|
||||||
|
tls = true;
|
||||||
|
} else {
|
||||||
|
usage();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
p1 = os_zalloc(sizeof(*p1));
|
p1 = os_zalloc(sizeof(*p1));
|
||||||
if (p1 == NULL)
|
if (p1 == NULL)
|
||||||
|
@ -1440,6 +1490,11 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!as_secret)
|
||||||
|
as_secret = tls ? "radsec" : "radius";
|
||||||
|
if (as_port < 0)
|
||||||
|
as_port = tls ? 2083 : 1812;
|
||||||
|
|
||||||
if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
|
if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
|
||||||
return scard_test(&eapol_test);
|
return scard_test(&eapol_test);
|
||||||
}
|
}
|
||||||
|
@ -1489,7 +1544,8 @@ int main(int argc, char *argv[])
|
||||||
wpa_s.conf->pcsc_reader = os_strdup(eapol_test.pcsc_reader);
|
wpa_s.conf->pcsc_reader = os_strdup(eapol_test.pcsc_reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
|
wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, tls, as_secret,
|
||||||
|
ca_cert, client_cert, private_key, private_key_passwd,
|
||||||
cli_addr, ifname);
|
cli_addr, ifname);
|
||||||
wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
|
wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
|
||||||
if (wpa_s.ctrl_iface == NULL) {
|
if (wpa_s.ctrl_iface == NULL) {
|
||||||
|
|
Loading…
Reference in a new issue