Cumulative patch from commit 390b92913a9a1b3a6aaf70e8b5971a7b7c76cabc
390b929 TLS testing: Allow hostapd to be used as a TLS testing tool
994afe3 RADIUS server: Allow TLS implementation add log entries
01f7fe1 RADIUS server: Allow EAP methods to log into SQLite DB
8a57da7 RADIUS server: Add option for storing log information to SQLite DB
f3ef7a2 TLS client: Send decrypt_error on verify_data validation error
129b9b9 TLS: Share a helper function for verifying Signature
6531963 TLS: Use a helper function for calculating ServerKeyExchange hash
65074a2 TLS: Add support for DHE-RSA cipher suites
41ebfe9 TLS server: Enable SHA256-based cipher suites
60b893d wpa_supplicant: Allow external management frame processing for testing
ec33bc6 Enable RADIUS message dumps with excessive debug verbosity
226e357 Revert "bridge: Track inter-BSS usage"
d0ee16e Allow arbitrary RADIUS attributes to be added into Access-Accept
0ac3876 Fix PMF protect disconnection on session timeout
49021c1 Fix hostapd error path regression
Change-Id: Ie0710c036cca2fb370d28684cc5a5d28a075dfc1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 6b86932..c929fe1 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -8,11 +8,16 @@
#include "includes.h"
#include <net/if.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "common.h"
#include "radius.h"
#include "eloop.h"
#include "eap_server/eap.h"
+#include "ap/ap_config.h"
+#include "crypto/tls.h"
#include "radius_server.h"
/**
@@ -68,6 +73,8 @@
unsigned int sess_id;
struct eap_sm *eap;
struct eap_eapol_interface *eap_if;
+ char *username; /* from User-Name attribute */
+ char *nas_ip;
struct radius_msg *last_msg;
char *last_from_addr;
@@ -79,6 +86,8 @@
u8 last_authenticator[16];
unsigned int remediation:1;
+
+ struct hostapd_radius_attr *accept_attr;
};
/**
@@ -312,6 +321,10 @@
char *subscr_remediation_url;
u8 subscr_remediation_method;
+
+#ifdef CONFIG_SQLITE
+ sqlite3 *db;
+#endif /* CONFIG_SQLITE */
};
@@ -329,6 +342,52 @@
static void radius_server_session_remove_timeout(void *eloop_ctx,
void *timeout_ctx);
+void srv_log(struct radius_session *sess, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
+void srv_log(struct radius_session *sess, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ va_start(ap, fmt);
+ vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+
+ RADIUS_DEBUG("[0x%x %s] %s", sess->sess_id, sess->nas_ip, buf);
+
+#ifdef CONFIG_SQLITE
+ if (sess->server->db) {
+ char *sql;
+ sql = sqlite3_mprintf("INSERT INTO authlog"
+ "(timestamp,session,nas_ip,username,note)"
+ " VALUES ("
+ "strftime('%%Y-%%m-%%d %%H:%%M:%%f',"
+ "'now'),%u,%Q,%Q,%Q)",
+ sess->sess_id, sess->nas_ip,
+ sess->username, buf);
+ if (sql) {
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
+ NULL) != SQLITE_OK) {
+ RADIUS_ERROR("Failed to add authlog entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+ }
+ }
+#endif /* CONFIG_SQLITE */
+
+ os_free(buf);
+}
+
static struct radius_client *
radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
@@ -394,6 +453,8 @@
radius_msg_free(sess->last_msg);
os_free(sess->last_from_addr);
radius_msg_free(sess->last_reply);
+ os_free(sess->username);
+ os_free(sess->nas_ip);
os_free(sess);
data->num_sess--;
}
@@ -473,47 +534,104 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+static void radius_server_testing_options_tls(struct radius_session *sess,
+ const char *tls,
+ struct eap_config *eap_conf)
+{
+ int test = atoi(tls);
+
+ switch (test) {
+ case 1:
+ srv_log(sess, "TLS test - break VerifyData");
+ eap_conf->tls_test_flags = TLS_BREAK_VERIFY_DATA;
+ break;
+ case 2:
+ srv_log(sess, "TLS test - break ServerKeyExchange ServerParams hash");
+ eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_HASH;
+ break;
+ case 3:
+ srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature");
+ eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE;
+ break;
+ default:
+ srv_log(sess, "Unrecognized TLS test");
+ break;
+ }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+static void radius_server_testing_options(struct radius_session *sess,
+ struct eap_config *eap_conf)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ const char *pos;
+
+ pos = os_strstr(sess->username, "@test-");
+ if (pos == NULL)
+ return;
+ pos += 6;
+ if (os_strncmp(pos, "tls-", 4) == 0)
+ radius_server_testing_options_tls(sess, pos + 4, eap_conf);
+ else
+ srv_log(sess, "Unrecognized test: %s", pos);
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
static struct radius_session *
radius_server_get_new_session(struct radius_server_data *data,
struct radius_client *client,
- struct radius_msg *msg)
+ struct radius_msg *msg, const char *from_addr)
{
u8 *user;
size_t user_len;
int res;
struct radius_session *sess;
struct eap_config eap_conf;
+ struct eap_user tmp;
RADIUS_DEBUG("Creating a new session");
- user = os_malloc(256);
- if (user == NULL) {
- return NULL;
- }
- res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
- if (res < 0 || res > 256) {
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &user,
+ &user_len, NULL) < 0) {
RADIUS_DEBUG("Could not get User-Name");
- os_free(user);
return NULL;
}
- user_len = res;
RADIUS_DUMP_ASCII("User-Name", user, user_len);
- res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
- os_free(user);
+ os_memset(&tmp, 0, sizeof(tmp));
+ res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp);
+ os_free(tmp.password);
- if (res == 0) {
- RADIUS_DEBUG("Matching user entry found");
- sess = radius_server_new_session(data, client);
- if (sess == NULL) {
- RADIUS_DEBUG("Failed to create a new session");
- return NULL;
- }
- } else {
+ if (res != 0) {
RADIUS_DEBUG("User-Name not found from user database");
return NULL;
}
+ RADIUS_DEBUG("Matching user entry found");
+ sess = radius_server_new_session(data, client);
+ if (sess == NULL) {
+ RADIUS_DEBUG("Failed to create a new session");
+ return NULL;
+ }
+ sess->accept_attr = tmp.accept_attr;
+
+ sess->username = os_malloc(user_len * 2 + 1);
+ if (sess->username == NULL) {
+ radius_server_session_free(data, sess);
+ return NULL;
+ }
+ printf_encode(sess->username, user_len * 2 + 1, user, user_len);
+
+ sess->nas_ip = os_strdup(from_addr);
+ if (sess->nas_ip == NULL) {
+ radius_server_session_free(data, sess);
+ return NULL;
+ }
+
+ srv_log(sess, "New session created");
+
os_memset(&eap_conf, 0, sizeof(eap_conf));
eap_conf.ssl_ctx = data->ssl_ctx;
eap_conf.msg_ctx = data->msg_ctx;
@@ -533,6 +651,7 @@
eap_conf.pwd_group = data->pwd_group;
eap_conf.server_id = (const u8 *) data->server_id;
eap_conf.server_id_len = os_strlen(data->server_id);
+ radius_server_testing_options(sess, &eap_conf);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
&eap_conf);
if (sess->eap == NULL) {
@@ -661,6 +780,19 @@
return NULL;
}
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+ struct hostapd_radius_attr *attr;
+ for (attr = sess->accept_attr; attr; attr = attr->next) {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+ }
+ }
+ }
+
if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
client->shared_secret_len,
hdr->authenticator) < 0) {
@@ -769,7 +901,8 @@
from_addr, from_port);
return -1;
} else {
- sess = radius_server_get_new_session(data, client, msg);
+ sess = radius_server_get_new_session(data, client, msg,
+ from_addr);
if (sess == NULL) {
RADIUS_DEBUG("Could not create a new session");
radius_server_reject(data, client, msg, from, fromlen,
@@ -855,6 +988,10 @@
if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
is_complete = 1;
+ if (sess->eap_if->eapFail)
+ srv_log(sess, "EAP authentication failed");
+ else if (sess->eap_if->eapSuccess)
+ srv_log(sess, "EAP authentication succeeded");
reply = radius_server_encapsulate_eap(data, client, sess, msg);
@@ -869,10 +1006,12 @@
switch (radius_msg_get_hdr(reply)->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
+ srv_log(sess, "Sending Access-Accept");
data->counters.access_accepts++;
client->counters.access_accepts++;
break;
case RADIUS_CODE_ACCESS_REJECT:
+ srv_log(sess, "Sending Access-Reject");
data->counters.access_rejects++;
client->counters.access_rejects++;
break;
@@ -1482,6 +1621,17 @@
os_strdup(conf->subscr_remediation_url);
}
+#ifdef CONFIG_SQLITE
+ if (conf->sqlite_file) {
+ if (sqlite3_open(conf->sqlite_file, &data->db)) {
+ RADIUS_ERROR("Could not open SQLite file '%s'",
+ conf->sqlite_file);
+ radius_server_deinit(data);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_SQLITE */
+
#ifdef CONFIG_RADIUS_TEST
if (conf->dump_msk_file)
data->dump_msk_file = os_strdup(conf->dump_msk_file);
@@ -1569,6 +1719,12 @@
os_free(data->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
os_free(data->subscr_remediation_url);
+
+#ifdef CONFIG_SQLITE
+ if (data->db)
+ sqlite3_close(data->db);
+#endif /* CONFIG_SQLITE */
+
os_free(data);
}
@@ -1725,8 +1881,10 @@
ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
phase2, user);
- if (ret == 0 && user)
+ if (ret == 0 && user) {
+ sess->accept_attr = user->accept_attr;
sess->remediation = user->remediation;
+ }
return ret;
}
@@ -1740,10 +1898,18 @@
}
+static void radius_server_log_msg(void *ctx, const char *msg)
+{
+ struct radius_session *sess = ctx;
+ srv_log(sess, "EAP: %s", msg);
+}
+
+
static struct eapol_callbacks radius_server_eapol_cb =
{
.get_eap_user = radius_server_get_eap_user,
.get_eap_req_id_text = radius_server_get_eap_req_id_text,
+ .log_msg = radius_server_log_msg,
};