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/hostapd/config_file.c b/hostapd/config_file.c
index bd66474..949a9d1 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -22,6 +22,14 @@
#include "config_file.h"
+#ifndef CONFIG_NO_RADIUS
+#ifdef EAP_SERVER
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value);
+#endif /* EAP_SERVER */
+#endif /* CONFIG_NO_RADIUS */
+
+
#ifndef CONFIG_NO_VLAN
static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
const char *fname)
@@ -208,7 +216,7 @@
FILE *f;
char buf[512], *pos, *start, *pos2;
int line = 0, ret = 0, num_methods;
- struct hostapd_eap_user *user, *tail = NULL;
+ struct hostapd_eap_user *user = NULL, *tail = NULL;
if (!fname)
return 0;
@@ -242,6 +250,27 @@
if (buf[0] == '\0')
continue;
+#ifndef CONFIG_NO_RADIUS
+ if (user && os_strncmp(buf, "radius_accept_attr=", 19) == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(buf + 19);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
+ buf + 19);
+ goto failed;
+ }
+ if (user->accept_attr == NULL) {
+ user->accept_attr = attr;
+ } else {
+ a = user->accept_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ continue;
+ }
+#endif /* CONFIG_NO_RADIUS */
+
user = NULL;
if (buf[0] != '"' && buf[0] != '*') {
@@ -468,11 +497,8 @@
continue;
failed:
- if (user) {
- os_free(user->password);
- os_free(user->identity);
- os_free(user);
- }
+ if (user)
+ hostapd_config_free_eap_user(user);
ret = -1;
break;
}
diff --git a/hostapd/hostapd.eap_user b/hostapd/hostapd.eap_user
index 12a2c61..00edc95 100644
--- a/hostapd/hostapd.eap_user
+++ b/hostapd/hostapd.eap_user
@@ -48,6 +48,12 @@
# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
# hash.
+#
+# Arbitrary RADIUS attributes can be added into Access-Accept packets similarly
+# to the way radius_auth_req_attr is used for Access-Request packet in
+# hostapd.conf. For EAP server, this is configured separately for each user
+# entry with radius_accept_attr=<value> line(s) following the main user entry
+# line.
# Phase 1 users
"user" MD5 "password"
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
index 2c1f130..826db34 100644
--- a/hostapd/hostapd.eap_user_sqlite
+++ b/hostapd/hostapd.eap_user_sqlite
@@ -16,3 +16,11 @@
INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
+
+CREATE TABLE authlog(
+ timestamp TEXT,
+ session TEXT,
+ nas_ip TEXT,
+ username TEXT,
+ note TEXT
+);
diff --git a/hostapd/main.c b/hostapd/main.c
index 68bc9b5..a9d7da5 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -729,6 +729,8 @@
hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++) {
+ if (!interfaces.iface[i])
+ continue;
interfaces.iface[i]->driver_ap_teardown =
!!(interfaces.iface[i]->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index b995892..f744985 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -388,8 +388,9 @@
}
-static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
+void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
+ hostapd_config_free_radius_attr(user->accept_attr);
os_free(user->identity);
os_free(user->password);
os_free(user);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index e1e34e2..f6ca8b1 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -128,6 +128,7 @@
* nt_password_hash() */
unsigned int remediation:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
+ struct hostapd_radius_attr *accept_attr;
};
struct hostapd_radius_attr {
@@ -601,6 +602,7 @@
int hostapd_mac_comp_empty(const void *a);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 7691012..6e3decd 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -81,6 +81,7 @@
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
+ user->accept_attr = eap_user->accept_attr;
return 0;
}
@@ -114,6 +115,7 @@
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
srv.pwd_group = conf->pwd_group;
srv.server_id = conf->server_id ? conf->server_id : "hostapd";
+ srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index bfa3c49..bc5bb6c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -760,7 +760,7 @@
return -1;
}
- if (wpa_debug_level == MSG_MSGDUMP)
+ if (wpa_debug_level <= MSG_MSGDUMP)
conf->radius->msg_dumps = 1;
#ifndef CONFIG_NO_RADIUS
hapd->radius = radius_client_init(hapd, conf->radius);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index be7df51..9a705a4 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -24,7 +24,6 @@
union wps_event_data;
struct hostapd_iface;
-struct hostapd_dynamic_iface;
struct hapd_interfaces {
int (*reload_config)(struct hostapd_iface *iface);
@@ -37,7 +36,6 @@
int (*driver_init)(struct hostapd_iface *iface);
size_t count;
- size_t count_dynamic;
int global_ctrl_sock;
char *global_iface_path;
char *global_iface_name;
@@ -45,7 +43,6 @@
gid_t ctrl_iface_group;
#endif /* CONFIG_NATIVE_WINDOWS */
struct hostapd_iface **iface;
- struct hostapd_dynamic_iface **dynamic_iface;
size_t terminate_on_error;
};
@@ -358,16 +355,6 @@
void (*scan_cb)(struct hostapd_iface *iface);
};
-/**
- * struct hostapd_dynamic_iface - hostapd per dynamically allocated
- * or added interface data structure
- */
-struct hostapd_dynamic_iface {
- char parent[IFNAMSIZ + 1];
- char iface[IFNAMSIZ + 1];
- unsigned int usage;
-};
-
/* hostapd.c */
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 0b90e3b..c7d051b 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -473,7 +473,6 @@
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
- u8 addr[ETH_ALEN];
if (!(sta->flags & WLAN_STA_AUTH)) {
if (sta->flags & WLAN_STA_GAS) {
@@ -484,6 +483,8 @@
return;
}
+ hostapd_drv_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -491,9 +492,7 @@
"session timeout");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
- os_memcpy(addr, sta->addr, ETH_ALEN);
ap_free_sta(hapd, sta);
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
}
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 509e557..4e4a352 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -474,123 +474,6 @@
#endif /* CONFIG_VLAN_NETLINK */
-/**
- * Increase the usage counter for given parent/ifname combination.
- * If create is set, then this iface is added to the global list.
- * Returns
- * -1 on error
- * 0 if iface is not in list
- * 1 if iface is in list (was there or has been added)
- */
-static int hapd_get_dynamic_iface(const char *parent, const char *ifname,
- int create, struct hostapd_data *hapd)
-{
- size_t i;
- struct hostapd_dynamic_iface *j = NULL, **tmp;
- struct hapd_interfaces *hapd_global = hapd->iface->interfaces;
-
- if (!parent)
- parent = "";
-
- for (i = 0; i < hapd_global->count_dynamic; i++) {
- j = hapd_global->dynamic_iface[i];
- if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
- os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
- break;
- }
- if (i < hapd_global->count_dynamic) {
- j->usage++;
- return 1;
- }
-
- /* new entry required */
- if (!create)
- return 0;
-
- j = os_zalloc(sizeof(*j));
- if (!j)
- return -1;
- os_strlcpy(j->iface, ifname, sizeof(j->iface));
- os_strlcpy(j->parent, parent, sizeof(j->parent));
-
- tmp = os_realloc_array(hapd_global->dynamic_iface, i + 1,
- sizeof(*hapd_global->dynamic_iface));
- if (!tmp) {
- wpa_printf(MSG_ERROR, "VLAN: Failed to allocate memory in %s",
- __func__);
- return -1;
- }
- hapd_global->count_dynamic++;
- hapd_global->dynamic_iface = tmp;
- hapd_global->dynamic_iface[i] = j;
-
- return 1;
-}
-
-
-/**
- * Decrease the usage counter for given ifname.
- * Returns
- * -1 on error or if iface was not found
- * 0 if iface was found and is still present
- * 1 if iface was removed from global list
- */
-static int hapd_put_dynamic_iface(const char *parent, const char *ifname,
- struct hostapd_data *hapd)
-{
- size_t i;
- struct hostapd_dynamic_iface *j = NULL, **tmp;
- struct hapd_interfaces *hapd_glob = hapd->iface->interfaces;
-
- if (!parent)
- parent = "";
-
- for (i = 0; i < hapd_glob->count_dynamic; i++) {
- j = hapd_glob->dynamic_iface[i];
- if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
- os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
- break;
- }
-
- if (i == hapd_glob->count_dynamic) {
- /*
- * Interface not in global list. This can happen if alloc in
- * _get_ failed.
- */
- return -1;
- }
-
- if (j->usage > 0) {
- j->usage--;
- return 0;
- }
-
- os_free(j);
- for (; i < hapd_glob->count_dynamic - 1; i++)
- hapd_glob->dynamic_iface[i] = hapd_glob->dynamic_iface[i + 1];
- hapd_glob->dynamic_iface[hapd_glob->count_dynamic - 1] = NULL;
- hapd_glob->count_dynamic--;
-
- if (hapd_glob->count_dynamic == 0) {
- os_free(hapd_glob->dynamic_iface);
- hapd_glob->dynamic_iface = NULL;
- return 1;
- }
-
- tmp = os_realloc_array(hapd_glob->dynamic_iface,
- hapd_glob->count_dynamic,
- sizeof(*hapd_glob->dynamic_iface));
- if (!tmp) {
- wpa_printf(MSG_ERROR, "VLAN: Failed to release memory in %s",
- __func__);
- return -1;
- }
- hapd_glob->dynamic_iface = tmp;
-
- return 1;
-}
-
-
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
{
char vlan_ifname[IFNAMSIZ];
@@ -598,7 +481,6 @@
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
- int ret;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
@@ -618,9 +500,7 @@
"brvlan%d", vlan->vlan_id);
}
- ret = br_addbr(br_name);
- if (hapd_get_dynamic_iface(NULL, br_name, ret == 0,
- hapd))
+ if (!br_addbr(br_name))
vlan->clean |= DVLAN_CLEAN_BR;
ifconfig_up(br_name);
@@ -638,24 +518,17 @@
"vlan%d", vlan->vlan_id);
ifconfig_up(tagged_interface);
- ret = vlan_add(tagged_interface, vlan->vlan_id,
- vlan_ifname);
- if (hapd_get_dynamic_iface(NULL, vlan_ifname,
- ret == 0, hapd))
+ if (!vlan_add(tagged_interface, vlan->vlan_id,
+ vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN;
- ret = br_addif(br_name, vlan_ifname);
- if (hapd_get_dynamic_iface(br_name,
- vlan_ifname,
- ret == 0, hapd))
+ if (!br_addif(br_name, vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
ifconfig_up(vlan_ifname);
}
- ret = br_addif(br_name, ifname);
- if (hapd_get_dynamic_iface(br_name, ifname, ret == 0,
- hapd))
+ if (!br_addif(br_name, ifname))
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
ifconfig_up(ifname);
@@ -694,8 +567,7 @@
"brvlan%d", vlan->vlan_id);
}
- if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) &&
- hapd_put_dynamic_iface(br_name, vlan->ifname, hapd))
+ if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
br_delif(br_name, vlan->ifname);
if (tagged_interface) {
@@ -709,20 +581,15 @@
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
- if ((vlan->clean & DVLAN_CLEAN_VLAN_PORT) &&
- hapd_put_dynamic_iface(br_name, vlan_ifname,
- hapd))
+ if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
br_delif(br_name, vlan_ifname);
ifconfig_down(vlan_ifname);
- if ((vlan->clean & DVLAN_CLEAN_VLAN) &&
- hapd_put_dynamic_iface(NULL, vlan_ifname,
- hapd))
+ if (vlan->clean & DVLAN_CLEAN_VLAN)
vlan_rem(vlan_ifname);
}
if ((vlan->clean & DVLAN_CLEAN_BR) &&
- hapd_put_dynamic_iface(NULL, br_name, hapd) &&
br_getnumports(br_name) == 0) {
ifconfig_down(br_name);
br_delbr(br_name);
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 88afae4..81e588f 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -537,4 +537,14 @@
void *tls_ctx, struct tls_connection *conn,
tls_session_ticket_cb cb, void *ctx);
+void tls_connection_set_log_cb(struct tls_connection *conn,
+ void (*log_cb)(void *ctx, const char *msg),
+ void *ctx);
+
+#define TLS_BREAK_VERIFY_DATA BIT(0)
+#define TLS_BREAK_SRV_KEY_X_HASH BIT(1)
+#define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2)
+
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
+
#endif /* TLS_H */
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 91f0690..6563ed2 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -28,6 +28,7 @@
struct tls_connection {
struct tlsv1_client *client;
struct tlsv1_server *server;
+ struct tls_global *global;
};
@@ -85,6 +86,7 @@
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->global = global;
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (!global->server) {
@@ -109,6 +111,28 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags)
+{
+ if (conn->server)
+ tlsv1_server_set_test_flags(conn->server, flags);
+}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void tls_connection_set_log_cb(struct tls_connection *conn,
+ void (*log_cb)(void *ctx, const char *msg),
+ void *ctx)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ tlsv1_server_set_log_cb(conn->server, log_cb, ctx);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+}
+
+
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
{
if (conn == NULL)
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 197b232..698a5ac 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -35,6 +35,7 @@
unsigned int remediation:1;
int ttls_auth; /* bitfield of
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
+ struct hostapd_radius_attr *accept_attr;
};
struct eap_eapol_interface {
@@ -80,6 +81,7 @@
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
+ void (*log_msg)(void *ctx, const char *msg);
};
struct eap_config {
@@ -108,6 +110,10 @@
const u8 *server_id;
size_t server_id_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u32 tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
};
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 003e202..3a6802b 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -191,10 +191,16 @@
const u8 *server_id;
size_t server_id_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u32 tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
};
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
int phase2);
+void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len);
#endif /* EAP_I_H */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 233e272..65d00dd 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -119,6 +119,32 @@
}
+void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+
+ if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->log_msg == NULL)
+ return;
+
+ 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);
+
+ sm->eapol_cb->log_msg(sm->eapol_ctx, buf);
+
+ os_free(buf);
+}
+
+
SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
@@ -366,6 +392,7 @@
}
if (sm->m == NULL) {
wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method");
+ eap_log_msg(sm, "Could not find suitable EAP method");
sm->decision = DECISION_FAILURE;
return;
}
@@ -377,6 +404,8 @@
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u", vendor, sm->currentMethod);
+ eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
+ vendor, sm->currentMethod);
}
@@ -693,6 +722,7 @@
"respMethod=%d currentMethod=%d",
sm->rxResp, sm->respId, sm->currentId,
sm->respMethod, sm->currentMethod);
+ eap_log_msg(sm, "Discard received EAP message");
SM_ENTER(EAP, DISCARD);
}
break;
@@ -1297,6 +1327,10 @@
sm->server_id = conf->server_id;
sm->server_id_len = conf->server_id_len;
+#ifdef CONFIG_TESTING_OPTIONS
+ sm->tls_test_flags = conf->tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
+
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
return sm;
diff --git a/src/eap_server/eap_server_identity.c b/src/eap_server/eap_server_identity.c
index 51dc4e8..b3c2087 100644
--- a/src/eap_server/eap_server_identity.c
+++ b/src/eap_server/eap_server_identity.c
@@ -102,6 +102,7 @@
struct eap_identity_data *data = priv;
const u8 *pos;
size_t len;
+ char *buf;
if (data->pick_up) {
if (eap_identity_check(sm, data, respData)) {
@@ -119,6 +120,12 @@
return; /* Should not happen - frame already validated */
wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
+ buf = os_malloc(len * 3 + 1);
+ if (buf) {
+ printf_encode(buf, len * 3 + 1, pos, len);
+ eap_log_msg(sm, "EAP-Response/Identity '%s'", buf);
+ os_free(buf);
+ }
if (sm->identity)
sm->update_user = TRUE;
os_free(sm->identity);
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 3153d2e..790c719 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -290,6 +290,7 @@
const u8 *username, *user;
size_t username_len, user_len;
int res;
+ char *buf;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
&len);
@@ -329,6 +330,13 @@
wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
+ buf = os_malloc(name_len * 3 + 1);
+ if (buf) {
+ printf_encode(buf, name_len * 3 + 1, name, name_len);
+ eap_log_msg(sm, "EAP-MSCHAPV2 Name '%s'", buf);
+ os_free(buf);
+ }
+
/* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present). */
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index de5ab0d..01853e6 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -34,6 +34,15 @@
}
+#ifdef CONFIG_TLS_INTERNAL
+static void eap_server_tls_log_cb(void *ctx, const char *msg)
+{
+ struct eap_sm *sm = ctx;
+ eap_log_msg(sm, "TLS: %s", msg);
+}
+#endif /* CONFIG_TLS_INTERNAL */
+
+
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer)
{
@@ -52,6 +61,13 @@
return -1;
}
+#ifdef CONFIG_TLS_INTERNAL
+ tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm);
+#ifdef CONFIG_TESTING_OPTIONS
+ tls_connection_set_test_flags(data->conn, sm->tls_test_flags);
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_TLS_INTERNAL */
+
if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 647bd2f..24225a4 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -984,6 +984,16 @@
}
if (parse.user_name) {
+ char *nbuf;
+ nbuf = os_malloc(parse.user_name_len * 3 + 1);
+ if (nbuf) {
+ printf_encode(nbuf, parse.user_name_len * 3 + 1,
+ parse.user_name,
+ parse.user_name_len);
+ eap_log_msg(sm, "TTLS-User-Name '%s'", nbuf);
+ os_free(nbuf);
+ }
+
os_free(sm->identity);
sm->identity = os_malloc(parse.user_name_len);
if (sm->identity == NULL) {
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 525bdee..a76fa13 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1023,7 +1023,8 @@
static struct eapol_callbacks eapol_cb =
{
eapol_sm_get_eap_user,
- eapol_sm_get_eap_req_id_text
+ eapol_sm_get_eap_req_id_text,
+ NULL
};
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,
};
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index e85d009..46ac312 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -40,6 +40,11 @@
char *client_file;
/**
+ * sqlite_file - SQLite database for storing debug log information
+ */
+ const char *sqlite_file;
+
+ /**
* conf_ctx - Context pointer for callbacks
*
* This is used as the ctx argument in get_eap_user() calls.
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 12148b6..4a4f0b6 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -459,10 +459,15 @@
count = 0;
suites = conn->cipher_suites;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 3269ecf..8367e36 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -410,9 +410,11 @@
static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ tls_key_exchange key_exchange)
{
- const u8 *pos, *end;
+ const u8 *pos, *end, *server_params, *server_params_end;
+ u8 alert;
tlsv1_client_free_dh(conn);
@@ -421,6 +423,7 @@
if (end - pos < 3)
goto fail;
+ server_params = pos;
conn->dh_p_len = WPA_GET_BE16(pos);
pos += 2;
if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
@@ -465,6 +468,59 @@
pos += conn->dh_ys_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
conn->dh_ys, conn->dh_ys_len);
+ server_params_end = pos;
+
+ if (key_exchange == TLS_KEY_X_DHE_RSA) {
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+ int hlen;
+
+ if (conn->rl.tls_version == TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used
+ * signature and hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ if (end - pos < 2)
+ goto fail;
+ if (pos[0] != TLS_HASH_ALG_SHA256 ||
+ pos[1] != TLS_SIGN_ALG_RSA) {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
+ pos[0], pos[1]);
+ goto fail;
+ }
+ pos += 2;
+
+ hlen = tlsv12_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ server_params_end - server_params, hash);
+#else /* CONFIG_TLSV12 */
+ goto fail;
+#endif /* CONFIG_TLSV12 */
+ } else {
+ hlen = tls_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ server_params_end - server_params, hash);
+ }
+
+ if (hlen < 0)
+ goto fail;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
+ hash, hlen);
+
+ if (tls_verify_signature(conn->rl.tls_version,
+ conn->server_rsa_key,
+ hash, hlen, pos, end - pos,
+ &alert) < 0)
+ goto fail;
+ }
return 0;
@@ -543,8 +599,10 @@
wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
- if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
- if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+ if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon ||
+ suite->key_exchange == TLS_KEY_X_DHE_RSA)) {
+ if (tlsv1_process_diffie_hellman(conn, pos, len,
+ suite->key_exchange) < 0) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -873,6 +931,8 @@
if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
return -1;
}
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index d789efb..839eb90 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -205,7 +205,7 @@
}
-static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
{
/* ClientDiffieHellmanPublic */
u8 *csecret, *csecret_start, *dh_yc, *shared;
@@ -399,8 +399,8 @@
hs_length = pos;
pos += 3;
/* body - ClientKeyExchange */
- if (keyx == TLS_KEY_X_DH_anon) {
- if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+ if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) {
+ if (tlsv1_key_x_dh(conn, &pos, end) < 0)
return -1;
} else {
if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 4578b22..8a4645b 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -1,6 +1,6 @@
/*
* TLSv1 common routines
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "x509v3.h"
@@ -33,6 +34,10 @@
TLS_HASH_SHA },
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_DHE_RSA, TLS_CIPHER_DES_CBC,
+ TLS_HASH_SHA},
+ { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
@@ -41,16 +46,24 @@
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
@@ -319,3 +332,163 @@
return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
outlen);
}
+
+
+#ifdef CONFIG_TLSV12
+int tlsv12_key_x_server_params_hash(u16 tls_version,
+ const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash)
+{
+ size_t hlen;
+ struct crypto_hash *ctx;
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
+ if (ctx == NULL)
+ return -1;
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_params, server_params_len);
+ hlen = SHA256_MAC_LEN;
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+ return -1;
+
+ return hlen;
+}
+#endif /* CONFIG_TLSV12 */
+
+
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash)
+{
+ u8 *hpos;
+ size_t hlen;
+ enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+ struct crypto_hash *ctx;
+
+ hpos = hash;
+
+ if (alg == SIGN_ALG_RSA) {
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+ if (ctx == NULL)
+ return -1;
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_params, server_params_len);
+ hlen = MD5_MAC_LEN;
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+ return -1;
+ hpos += hlen;
+ }
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+ if (ctx == NULL)
+ return -1;
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_params, server_params_len);
+ hlen = hash + sizeof(hash) - hpos;
+ if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
+ return -1;
+ hpos += hlen;
+ return hpos - hash;
+}
+
+
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+ const u8 *data, size_t data_len,
+ const u8 *pos, size_t len, u8 *alert)
+{
+ u8 *buf;
+ const u8 *end = pos + len;
+ const u8 *decrypted;
+ u16 slen;
+ size_t buflen;
+
+ if (end - pos < 2) {
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ slen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < slen) {
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ if (end - pos > slen) {
+ wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
+ pos + slen, end - pos - slen);
+ end = pos + slen;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+ if (pk == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ buflen = end - pos;
+ buf = os_malloc(end - pos);
+ if (buf == NULL) {
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+ if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+ decrypted = buf;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+ decrypted, buflen);
+
+#ifdef CONFIG_TLSV12
+ if (tls_version >= TLS_VERSION_1_2) {
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+ * H
+ */
+ if (buflen >= 19 + 32 &&
+ os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+ "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+ {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
+ decrypted = buf + 19;
+ buflen -= 19;
+ } else {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+ }
+#endif /* CONFIG_TLSV12 */
+
+ if (buflen != data_len || os_memcmp(decrypted, data, data_len) != 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+
+ os_free(buf);
+
+ return 0;
+}
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index f28c0cd..26e68af 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -1,6 +1,6 @@
/*
* TLSv1 common definitions
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -257,5 +257,16 @@
const char * tls_version_str(u16 ver);
int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
+int tlsv12_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash);
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash);
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+ const u8 *data, size_t data_len,
+ const u8 *pos, size_t len, u8 *alert);
#endif /* TLSV1_COMMON_H */
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 2880309..4aeccf6 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,6 +21,31 @@
*/
+void tlsv1_server_log(struct tlsv1_server *conn, 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);
+
+ wpa_printf(MSG_DEBUG, "TLSv1: %s", buf);
+ if (conn->log_cb)
+ conn->log_cb(conn->log_cb_ctx, buf);
+
+ os_free(buf);
+}
+
+
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
{
conn->alert_level = level;
@@ -250,8 +275,7 @@
used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
out_pos, &olen, &alert);
if (used < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
- "failed");
+ tlsv1_server_log(conn, "Record layer processing failed");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
@@ -265,14 +289,13 @@
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (olen < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Alert "
- "underflow");
+ tlsv1_server_log(conn, "Alert underflow");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
- out_pos[0], out_pos[1]);
+ tlsv1_server_log(conn, "Received alert %d:%d",
+ out_pos[0], out_pos[1]);
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
/* Continue processing */
pos += used;
@@ -285,13 +308,23 @@
}
if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
- "0x%x", pos[0]);
+ tlsv1_server_log(conn, "Unexpected content type 0x%x",
+ pos[0]);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &&
+ (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH |
+ TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client ApplData received after invalid handshake");
+ conn->test_failure_reported = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -361,8 +394,15 @@
count = 0;
suites = conn->cipher_suites;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
@@ -618,3 +658,19 @@
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
}
+
+
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+ void (*cb)(void *ctx, const char *msg), void *ctx)
+{
+ conn->log_cb = cb;
+ conn->log_cb_ctx = ctx;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
+{
+ conn->test_flags = flags;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index a18c69e..b2b28d1 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -45,4 +45,9 @@
tlsv1_server_session_ticket_cb cb,
void *ctx);
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+ void (*cb)(void *ctx, const char *msg), void *ctx);
+
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
+
#endif /* TLSV1_SERVER_H */
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 1f61533..9a36d8f 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -51,13 +51,24 @@
tlsv1_server_session_ticket_cb session_ticket_cb;
void *session_ticket_cb_ctx;
+ void (*log_cb)(void *ctx, const char *msg);
+ void *log_cb_ctx;
+
int use_session_ticket;
u8 *dh_secret;
size_t dh_secret_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u32 test_flags;
+ int test_failure_reported;
+#endif /* CONFIG_TESTING_OPTIONS */
};
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
int tlsv1_server_derive_keys(struct tlsv1_server *conn,
const u8 *pre_master_secret,
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 6f6539b..04622b5 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,23 @@
size_t *in_len);
+static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+ suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
+ suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
+ suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
+ suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
+ suite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ return 1;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return 0;
+}
+
+
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -38,8 +55,8 @@
u16 ext_type, ext_len;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -53,13 +70,13 @@
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ClientHello)", *pos);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientHello)",
+ *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
+ tlsv1_server_log(conn, "Received ClientHello");
pos++;
/* uint24 length */
len = WPA_GET_BE24(pos);
@@ -78,13 +95,13 @@
if (end - pos < 2)
goto decode_error;
conn->client_version = WPA_GET_BE16(pos);
- wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
- conn->client_version >> 8, conn->client_version & 0xff);
+ tlsv1_server_log(conn, "Client version %d.%d",
+ conn->client_version >> 8,
+ conn->client_version & 0xff);
if (conn->client_version < TLS_VERSION_1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
- "ClientHello %u.%u",
- conn->client_version >> 8,
- conn->client_version & 0xff);
+ tlsv1_server_log(conn, "Unexpected protocol version in ClientHello %u.%u",
+ conn->client_version >> 8,
+ conn->client_version & 0xff);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
@@ -101,8 +118,8 @@
conn->rl.tls_version = TLS_VERSION_1_1;
else
conn->rl.tls_version = conn->client_version;
- wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
- tls_version_str(conn->rl.tls_version));
+ tlsv1_server_log(conn, "Using TLS v%s",
+ tls_version_str(conn->rl.tls_version));
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
@@ -137,6 +154,8 @@
cipher_suite = 0;
for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+ if (testing_cipher_suite_filter(conn, conn->cipher_suites[i]))
+ continue;
c = pos;
for (j = 0; j < num_suites; j++) {
u16 tmp = WPA_GET_BE16(c);
@@ -149,8 +168,7 @@
}
pos += num_suites * 2;
if (!cipher_suite) {
- wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
- "available");
+ tlsv1_server_log(conn, "No supported cipher suite available");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
@@ -180,16 +198,15 @@
compr_null_found = 1;
}
if (!compr_null_found) {
- wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
- "compression");
+ tlsv1_server_log(conn, "Client does not accept NULL compression");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
if (end - pos == 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
- "end of ClientHello: 0x%02x", *pos);
+ tlsv1_server_log(conn, "Unexpected extra octet in the end of ClientHello: 0x%02x",
+ *pos);
goto decode_error;
}
@@ -198,12 +215,11 @@
ext_len = WPA_GET_BE16(pos);
pos += 2;
- wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
- "extensions", ext_len);
+ tlsv1_server_log(conn, "%u bytes of ClientHello extensions",
+ ext_len);
if (end - pos != ext_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
- "extension list length %u (expected %u)",
- ext_len, (unsigned int) (end - pos));
+ tlsv1_server_log(conn, "Invalid ClientHello extension list length %u (expected %u)",
+ ext_len, (unsigned int) (end - pos));
goto decode_error;
}
@@ -216,8 +232,7 @@
while (pos < end) {
if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_type field");
+ tlsv1_server_log(conn, "Invalid extension_type field");
goto decode_error;
}
@@ -225,8 +240,7 @@
pos += 2;
if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_data length field");
+ tlsv1_server_log(conn, "Invalid extension_data length field");
goto decode_error;
}
@@ -234,13 +248,12 @@
pos += 2;
if (end - pos < ext_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_data field");
+ tlsv1_server_log(conn, "Invalid extension_data field");
goto decode_error;
}
- wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
- "type %u", ext_type);
+ tlsv1_server_log(conn, "ClientHello Extension type %u",
+ ext_type);
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
"Extension data", pos, ext_len);
@@ -260,14 +273,13 @@
*in_len = end - in_data;
- wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
- "ServerHello");
+ tlsv1_server_log(conn, "ClientHello OK - proceed to ServerHello");
conn->state = SERVER_HELLO;
return 0;
decode_error:
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
+ tlsv1_server_log(conn, "Failed to decode ClientHello");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -284,8 +296,8 @@
int reason;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -295,8 +307,8 @@
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
- "(len=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short Certificate message (len=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -308,9 +320,8 @@
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Unexpected Certificate message length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -318,8 +329,7 @@
if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
if (conn->verify_peer) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
- "Certificate");
+ tlsv1_server_log(conn, "Client did not include Certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -329,17 +339,15 @@
in_len);
}
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected Certificate/"
- "ClientKeyExchange)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected Certificate/ClientKeyExchange)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG,
- "TLSv1: Received Certificate (certificate_list len %lu)",
- (unsigned long) len);
+ tlsv1_server_log(conn, "Received Certificate (certificate_list len %lu)",
+ (unsigned long) len);
/*
* opaque ASN.1Cert<2^24-1>;
@@ -352,8 +360,8 @@
end = pos + len;
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
- "(left=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short Certificate (left=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -363,10 +371,9 @@
pos += 3;
if ((size_t) (end - pos) != list_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
- "length (len=%lu left=%lu)",
- (unsigned long) list_len,
- (unsigned long) (end - pos));
+ tlsv1_server_log(conn, "Unexpected certificate_list length (len=%lu left=%lu)",
+ (unsigned long) list_len,
+ (unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -375,8 +382,7 @@
idx = 0;
while (pos < end) {
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "certificate_list");
+ tlsv1_server_log(conn, "Failed to parse certificate_list");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
@@ -387,25 +393,23 @@
pos += 3;
if ((size_t) (end - pos) < cert_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
- "length (len=%lu left=%lu)",
- (unsigned long) cert_len,
- (unsigned long) (end - pos));
+ tlsv1_server_log(conn, "Unexpected certificate length (len=%lu left=%lu)",
+ (unsigned long) cert_len,
+ (unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
- (unsigned long) idx, (unsigned long) cert_len);
+ tlsv1_server_log(conn, "Certificate %lu (len %lu)",
+ (unsigned long) idx, (unsigned long) cert_len);
if (idx == 0) {
crypto_public_key_free(conn->client_rsa_key);
if (tls_parse_cert(pos, cert_len,
&conn->client_rsa_key)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
+ tlsv1_server_log(conn, "Failed to parse the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
@@ -415,8 +419,7 @@
cert = x509_certificate_parse(pos, cert_len);
if (cert == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
+ tlsv1_server_log(conn, "Failed to parse the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
@@ -436,8 +439,8 @@
if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
&reason, 0) < 0) {
int tls_reason;
- wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
- "validation failed (reason=%d)", reason);
+ tlsv1_server_log(conn, "Server certificate chain validation failed (reason=%d)",
+ reason);
switch (reason) {
case X509_VALIDATE_BAD_CERTIFICATE:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -494,9 +497,8 @@
encr_len = WPA_GET_BE16(pos);
pos += 2;
if (pos + encr_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
- "format: encr_len=%u left=%u",
- encr_len, (unsigned int) (end - pos));
+ tlsv1_server_log(conn, "Invalid ClientKeyExchange format: encr_len=%u left=%u",
+ encr_len, (unsigned int) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -539,15 +541,13 @@
}
if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
- "length %lu", (unsigned long) outlen);
+ tlsv1_server_log(conn, "Unexpected PreMasterSecret length %lu",
+ (unsigned long) outlen);
use_random = 1;
}
if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
- "ClientKeyExchange does not match with version in "
- "ClientHello");
+ tlsv1_server_log(conn, "Client version in ClientKeyExchange does not match with version in ClientHello");
use_random = 1;
}
@@ -582,7 +582,7 @@
}
-static int tls_process_client_key_exchange_dh_anon(
+static int tls_process_client_key_exchange_dh(
struct tlsv1_server *conn, const u8 *pos, const u8 *end)
{
const u8 *dh_yc;
@@ -600,6 +600,7 @@
* } ClientDiffieHellmanPublic;
*/
+ tlsv1_server_log(conn, "ClientDiffieHellmanPublic received");
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
pos, end - pos);
@@ -612,8 +613,7 @@
}
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
- "length");
+ tlsv1_server_log(conn, "Invalid client public value length");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -623,8 +623,8 @@
dh_yc = pos + 2;
if (dh_yc + dh_yc_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
- "(length %d)", dh_yc_len);
+ tlsv1_server_log(conn, "Client public value overflow (length %d)",
+ dh_yc_len);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -695,8 +695,8 @@
const struct tls_cipher_suite *suite;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -706,8 +706,8 @@
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
- "(Left=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short ClientKeyExchange (Left=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -719,9 +719,8 @@
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Mismatch in ClientKeyExchange length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -730,14 +729,14 @@
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ClientKeyExchange)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientKeyExchange)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
+ tlsv1_server_log(conn, "Received ClientKeyExchange");
wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
@@ -747,11 +746,11 @@
else
keyx = suite->key_exchange;
- if (keyx == TLS_KEY_X_DH_anon &&
- tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
+ if ((keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) &&
+ tls_process_client_key_exchange_dh(conn, pos, end) < 0)
return -1;
- if (keyx != TLS_KEY_X_DH_anon &&
+ if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA &&
tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
return -1;
@@ -769,15 +768,14 @@
const u8 *pos, *end;
size_t left, len;
u8 type;
- size_t hlen, buflen;
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
+ size_t hlen;
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
- u16 slen;
+ u8 alert;
if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
if (conn->verify_peer) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
- "CertificateVerify");
+ tlsv1_server_log(conn, "Client did not include CertificateVerify");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -788,8 +786,8 @@
}
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -799,8 +797,8 @@
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
- "message (len=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short CertificateVerify message (len=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -812,9 +810,8 @@
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
- "message length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Unexpected CertificateVerify message length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -823,14 +820,14 @@
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected CertificateVerify)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected CertificateVerify)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
+ tlsv1_server_log(conn, "Received CertificateVerify");
/*
* struct {
@@ -917,89 +914,12 @@
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
- if (end - pos < 2) {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
+ if (tls_verify_signature(conn->rl.tls_version, conn->client_rsa_key,
+ hash, hlen, pos, end - pos, &alert) < 0) {
+ tlsv1_server_log(conn, "Invalid Signature in CertificateVerify");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
- slen = WPA_GET_BE16(pos);
- pos += 2;
- if (end - pos < slen) {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
- if (conn->client_rsa_key == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
- "signature");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- buflen = end - pos;
- buf = os_malloc(end - pos);
- if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
- pos, end - pos, buf, &buflen) < 0)
- {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
-
- wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
- buf, buflen);
-
-#ifdef CONFIG_TLSV12
- if (conn->rl.tls_version >= TLS_VERSION_1_2) {
- /*
- * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
- *
- * DigestInfo ::= SEQUENCE {
- * digestAlgorithm DigestAlgorithm,
- * digest OCTET STRING
- * }
- *
- * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
- *
- * DER encoded DigestInfo for SHA256 per RFC 3447:
- * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
- * H
- */
- if (buflen >= 19 + 32 &&
- os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
- "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
- {
- wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
- "SHA-256");
- os_memmove(buf, buf + 19, buflen - 19);
- buflen -= 19;
- } else {
- wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
- "DigestInfo");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
- }
-#endif /* CONFIG_TLSV12 */
-
- if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
- "CertificateVerify - did not match with calculated "
- "hash");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
-
- os_free(buf);
*in_len = end - in_data;
@@ -1017,8 +937,8 @@
size_t left;
if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected ChangeCipherSpec; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -1028,21 +948,21 @@
left = *in_len;
if (left < 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+ tlsv1_server_log(conn, "Too short ChangeCipherSpec");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
if (*pos != TLS_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received data 0x%x", *pos);
+ tlsv1_server_log(conn, "Expected ChangeCipherSpec; received data 0x%x",
+ *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+ tlsv1_server_log(conn, "Received ChangeCipherSpec");
if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
"for record layer");
@@ -1067,9 +987,18 @@
u8 verify_data[TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange");
+ conn->test_failure_reported = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Finished; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -1079,9 +1008,8 @@
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
- "Finished",
- (unsigned long) left);
+ tlsv1_server_log(conn, "Too short record (left=%lu) forFinished",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -1101,18 +1029,16 @@
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
- "(len=%lu > left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Too short buffer for Finished (len=%lu > left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (len != TLS_VERIFY_DATA_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
- "in Finished: %lu (expected %d)",
- (unsigned long) len, TLS_VERIFY_DATA_LEN);
+ tlsv1_server_log(conn, "Unexpected verify_data length in Finished: %lu (expected %d)",
+ (unsigned long) len, TLS_VERIFY_DATA_LEN);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -1175,18 +1101,17 @@
verify_data, TLS_VERIFY_DATA_LEN);
if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
- wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ tlsv1_server_log(conn, "Mismatch in verify_data");
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+ tlsv1_server_log(conn, "Received Finished");
*in_len = end - in_data;
if (conn->use_session_ticket) {
/* Abbreviated handshake using session ticket; RFC 4507 */
- wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
- "successfully");
+ tlsv1_server_log(conn, "Abbreviated handshake completed successfully");
conn->state = ESTABLISHED;
} else {
/* Full handshake */
@@ -1202,13 +1127,12 @@
{
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (*len < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+ tlsv1_server_log(conn, "Alert underflow");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
- buf[0], buf[1]);
+ tlsv1_server_log(conn, "Received alert %d:%d", buf[0], buf[1]);
*len = 2;
conn->state = FAILED;
return -1;
@@ -1240,9 +1164,8 @@
return -1;
break;
default:
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
- "while processing received message",
- conn->state);
+ tlsv1_server_log(conn, "Unexpected state %d while processing received message",
+ conn->state);
return -1;
}
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index 6d8e55e..619b9ab 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -48,7 +48,7 @@
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+ tlsv1_server_log(conn, "Send ServerHello");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -104,8 +104,7 @@
conn->client_random, conn->server_random,
conn->master_secret);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
- "indicated failure");
+ tlsv1_server_log(conn, "SessionTicket callback indicated failure");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_HANDSHAKE_FAILURE);
return -1;
@@ -170,7 +169,7 @@
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+ tlsv1_server_log(conn, "Send Certificate");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -245,7 +244,7 @@
{
tls_key_exchange keyx;
const struct tls_cipher_suite *suite;
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
size_t rlen;
u8 *dh_ys;
size_t dh_ys_len;
@@ -261,8 +260,7 @@
return 0;
}
- if (keyx != TLS_KEY_X_DH_anon) {
- /* TODO? */
+ if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
"supported with key exchange type %d", keyx);
return -1;
@@ -354,7 +352,7 @@
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+ tlsv1_server_log(conn, "Send ServerKeyExchange");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -369,6 +367,7 @@
pos += 3;
/* body - ServerDHParams */
+ server_params = pos;
/* dh_p */
if (pos + 2 + conn->cred->dh_p_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
@@ -412,6 +411,138 @@
pos += dh_ys_len;
os_free(dh_ys);
+ /*
+ * select (SignatureAlgorithm)
+ * { case anonymous: struct { };
+ * case rsa:
+ * digitally-signed struct {
+ * opaque md5_hash[16];
+ * opaque sha_hash[20];
+ * };
+ * case dsa:
+ * digitally-signed struct {
+ * opaque sha_hash[20];
+ * };
+ * } Signature;
+ *
+ * md5_hash
+ * MD5(ClientHello.random + ServerHello.random + ServerParams);
+ *
+ * sha_hash
+ * SHA(ClientHello.random + ServerHello.random + ServerParams);
+ */
+
+ if (keyx == TLS_KEY_X_DHE_RSA) {
+ u8 hash[100];
+ u8 *signed_start;
+ size_t clen;
+ int hlen;
+
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+ hlen = tlsv12_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ pos - server_params, hash + 19);
+
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used
+ * signature and hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ if (hlen < 0 || pos + 2 > end) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ *pos++ = TLS_HASH_ALG_SHA256;
+ *pos++ = TLS_SIGN_ALG_RSA;
+
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
+ * 04 20 || H
+ */
+ hlen += 19;
+ os_memcpy(hash,
+ "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+ "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+
+#else /* CONFIG_TLSV12 */
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+#endif /* CONFIG_TLSV12 */
+ } else {
+ hlen = tls_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ pos - server_params, hash);
+ }
+
+ if (hlen < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
+ hash, hlen);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
+ tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
+ hash[hlen - 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /*
+ * RFC 2246, 4.7:
+ * In digital signing, one-way hash functions are used as input
+ * for a signing algorithm. A digitally-signed element is
+ * encoded as an opaque vector <0..2^16-1>, where the length is
+ * specified by the signing algorithm and key.
+ *
+ * In RSA signing, a 36-byte structure of two hashes (one SHA
+ * and one MD5) is signed (encrypted with the private key). It
+ * is encoded with PKCS #1 block type 0 or type 1 as described
+ * in [PKCS1].
+ */
+ signed_start = pos; /* length to be filled */
+ pos += 2;
+ clen = end - pos;
+ if (conn->cred == NULL ||
+ crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+ pos, &clen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE16(signed_start, clen);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
+ tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
+ pos[clen - 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ pos += clen;
+ }
+
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
@@ -445,7 +576,7 @@
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+ tlsv1_server_log(conn, "Send CertificateRequest");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -505,7 +636,7 @@
size_t rlen;
u8 payload[4];
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+ tlsv1_server_log(conn, "Send ServerHelloDone");
/* opaque fragment[TLSPlaintext.length] */
@@ -541,7 +672,7 @@
size_t rlen;
u8 payload[1];
- wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+ tlsv1_server_log(conn, "Send ChangeCipherSpec");
payload[0] = TLS_CHANGE_CIPHER_SPEC;
@@ -578,7 +709,7 @@
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+ tlsv1_server_log(conn, "Send Finished");
/* Encrypted Handshake Message: Finished */
@@ -635,6 +766,12 @@
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
+ tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
+ verify_data[1 + 3 + 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
/* Handshake */
pos = hs_start = verify_data;
@@ -736,7 +873,7 @@
*out_len = pos - msg;
- wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+ tlsv1_server_log(conn, "Handshake completed successfully");
conn->state = ESTABLISHED;
return msg;
@@ -755,8 +892,8 @@
/* Abbreviated handshake was already completed. */
return NULL;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
- "generating reply", conn->state);
+ tlsv1_server_log(conn, "Unexpected state %d while generating reply",
+ conn->state);
return NULL;
}
}
@@ -767,7 +904,7 @@
{
u8 *alert, *pos, *length;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+ tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
*out_len = 0;
alert = os_malloc(10);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 2935ce7..fdf8ac3 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -40,6 +40,7 @@
#include "blacklist.h"
#include "autoscan.h"
#include "wnm_sta.h"
+#include "offchannel.h"
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
@@ -452,6 +453,10 @@
ret = set_disallow_aps(wpa_s, value);
} else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
wpa_s->no_keep_alive = !!atoi(value);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
+ wpa_s->ext_mgmt_frame_handling = !!atoi(value);
+#endif /* CONFIG_TESTING_OPTIONS */
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -5591,6 +5596,8 @@
#ifdef CONFIG_INTERWORKING
hs20_cancel_fetch_osu(wpa_s);
#endif /* CONFIG_INTERWORKING */
+
+ wpa_s->ext_mgmt_frame_handling = 0;
}
@@ -5879,6 +5886,103 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+
+static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result
+ result)
+{
+ wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
+ " src=" MACSTR " bssid=" MACSTR " result=%s",
+ freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
+ "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
+ "NO_ACK" : "FAILED"));
+}
+
+
+static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
+ int res, used;
+ int freq = 0, no_cck = 0, wait_time = 0;
+
+ /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
+ * <action=Action frame payload> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, da);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+ used = hwaddr_aton2(pos, bssid);
+ if (used < 0)
+ return -1;
+ pos += used;
+
+ param = os_strstr(pos, " freq=");
+ if (param) {
+ param += 6;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " no_cck=");
+ if (param) {
+ param += 8;
+ no_cck = atoi(param);
+ }
+
+ param = os_strstr(pos, " wait_time=");
+ if (param) {
+ param += 11;
+ wait_time = atoi(param);
+ }
+
+ param = os_strstr(pos, " action=");
+ if (param == NULL)
+ return -1;
+ param += 8;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
+ buf, len, wait_time,
+ wpas_ctrl_iface_mgmt_tx_cb, no_cck);
+ os_free(buf);
+ return res;
+}
+
+
+static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
+ offchannel_send_action_done(wpa_s);
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -6421,6 +6525,13 @@
} else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
reply_size);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
+ if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
+ wpas_ctrl_iface_mgmt_tx_done(wpa_s);
+#endif /* CONFIG_TESTING_OPTIONS */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index bea7f8a..65c162e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3141,6 +3141,23 @@
u16 fc, stype;
const struct ieee80211_mgmt *mgmt;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ext_mgmt_frame_handling) {
+ struct rx_mgmt *rx = &data->rx_mgmt;
+ size_t hex_len = 2 * rx->frame_len + 1;
+ char *hex = os_malloc(hex_len);
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len,
+ rx->frame, rx->frame_len);
+ wpa_msg(wpa_s, MSG_INFO, "MGMT-RX freq=%d datarate=%u ssi_signal=%d %s",
+ rx->freq, rx->datarate, rx->ssi_signal,
+ hex);
+ os_free(hex);
+ }
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
mgmt = (const struct ieee80211_mgmt *)
data->rx_mgmt.frame;
fc = le_to_host16(mgmt->frame_control);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 376a250..fd162d7 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -818,6 +818,7 @@
u8 last_gas_dialog_token, prev_gas_dialog_token;
unsigned int no_keep_alive:1;
+ unsigned int ext_mgmt_frame_handling:1;
#ifdef CONFIG_WNM
u8 wnm_dialog_token;