HS 2.0: Terms and Conditions testing feature in authentication server

Allow hostapd RADIUS authentication server with SQLite EAP user DB to be
used for testing Terms and Conditions functionality. This could be used
for the HO AAA part of functionality (merging HO AAA and SP AAA into a
single component to avoid separate RADIUS proxy in testing setup).

A T&C server with HTTPS processing is needed to allow this to be used
for full over-the-air testing. This commit adds sufficient functionality
to allow hwsim test cases to cover the RADIUS server part.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2018-04-26 00:57:44 +03:00 committed by Jouni Malinen
parent 045c7c6817
commit 4526038092
6 changed files with 69 additions and 1 deletions

View File

@ -3,7 +3,8 @@ CREATE TABLE users(
methods TEXT, methods TEXT,
password TEXT, password TEXT,
remediation TEXT, remediation TEXT,
phase2 INTEGER phase2 INTEGER,
t_c_timestamp INTEGER
); );
CREATE TABLE wildcards( CREATE TABLE wildcards(

View File

@ -169,6 +169,7 @@ struct hostapd_eap_user {
unsigned int macacl:1; unsigned int macacl:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
struct hostapd_radius_attr *accept_attr; struct hostapd_radius_attr *accept_attr;
u32 t_c_timestamp;
}; };
struct hostapd_radius_attr { struct hostapd_radius_attr {

View File

@ -83,6 +83,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
user->ttls_auth = eap_user->ttls_auth; user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation; user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr; user->accept_attr = eap_user->accept_attr;
user->t_c_timestamp = eap_user->t_c_timestamp;
rv = 0; rv = 0;
out: out:

View File

@ -91,6 +91,8 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
set_user_methods(user, argv[i]); set_user_methods(user, argv[i]);
} else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) { } else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
user->remediation = strlen(argv[i]) > 0; user->remediation = strlen(argv[i]) > 0;
} else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
user->t_c_timestamp = strtol(argv[i], 0, 10);
} }
} }

View File

@ -38,6 +38,7 @@ struct eap_user {
int ttls_auth; /* bitfield of int ttls_auth; /* bitfield of
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */ * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
struct hostapd_radius_attr *accept_attr; struct hostapd_radius_attr *accept_attr;
u32 t_c_timestamp;
}; };
struct eap_eapol_interface { struct eap_eapol_interface {

View File

@ -92,8 +92,11 @@ struct radius_session {
unsigned int remediation:1; unsigned int remediation:1;
unsigned int macacl:1; unsigned int macacl:1;
unsigned int t_c_filtering:1;
struct hostapd_radius_attr *accept_attr; struct hostapd_radius_attr *accept_attr;
u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
}; };
/** /**
@ -821,6 +824,16 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem"); RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
} }
} }
if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) {
u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
buf, sizeof(buf))) {
RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
}
}
#endif /* CONFIG_HS20 */ #endif /* CONFIG_HS20 */
if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
@ -1003,6 +1016,51 @@ static int radius_server_reject(struct radius_server_data *data,
} }
static void radius_server_hs20_t_c_check(struct radius_session *sess,
struct radius_msg *msg)
{
#ifdef CONFIG_HS20
u8 *buf, *pos, *end, type, sublen, *timestamp = NULL;
size_t len;
buf = NULL;
for (;;) {
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
&buf, &len, buf) < 0)
break;
if (len < 6)
continue;
pos = buf;
end = buf + len;
if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
continue;
pos += 4;
type = *pos++;
sublen = *pos++;
if (sublen < 2)
continue; /* invalid length */
sublen -= 2; /* skip header */
if (pos + sublen > end)
continue; /* invalid WFA VSA */
if (type == RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP && len >= 4) {
timestamp = pos;
break;
}
}
if (!timestamp)
return;
RADIUS_DEBUG("HS20-Timestamp: %u", WPA_GET_BE32(timestamp));
if (sess->t_c_timestamp != WPA_GET_BE32(timestamp)) {
RADIUS_DEBUG("Last read T&C timestamp does not match HS20-Timestamp --> require filtering");
sess->t_c_filtering = 1;
}
#endif /* CONFIG_HS20 */
}
static int radius_server_request(struct radius_server_data *data, static int radius_server_request(struct radius_server_data *data,
struct radius_msg *msg, struct radius_msg *msg,
struct sockaddr *from, socklen_t fromlen, struct sockaddr *from, socklen_t fromlen,
@ -1138,6 +1196,9 @@ static int radius_server_request(struct radius_server_data *data,
else if (sess->eap_if->eapSuccess) else if (sess->eap_if->eapSuccess)
srv_log(sess, "EAP authentication succeeded"); srv_log(sess, "EAP authentication succeeded");
if (sess->eap_if->eapSuccess)
radius_server_hs20_t_c_check(sess, msg);
reply = radius_server_encapsulate_eap(data, client, sess, msg); reply = radius_server_encapsulate_eap(data, client, sess, msg);
send_reply: send_reply:
@ -2059,6 +2120,7 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity,
sess->accept_attr = user->accept_attr; sess->accept_attr = user->accept_attr;
sess->remediation = user->remediation; sess->remediation = user->remediation;
sess->macacl = user->macacl; sess->macacl = user->macacl;
sess->t_c_timestamp = user->t_c_timestamp;
} }
if (ret) { if (ret) {