summaryrefslogtreecommitdiff
path: root/src/eap_server
diff options
context:
space:
mode:
authorAndrew Shadura <andrewsh@debian.org>2016-07-23 12:51:30 +0200
committerAndrew Shadura <andrewsh@debian.org>2016-07-23 12:51:30 +0200
commitaa5e2237f3bbd73853b3ffbb4bf693298c409792 (patch)
tree26bd471557f364e950d823e12e7d9d83a73778c0 /src/eap_server
parent2b2675a5c8455e6a7224b153a28a6c2b5f1acd70 (diff)
Imported Upstream version 2.5
Diffstat (limited to 'src/eap_server')
-rw-r--r--src/eap_server/Makefile19
-rw-r--r--src/eap_server/eap.h6
-rw-r--r--src/eap_server/eap_i.h3
-rw-r--r--src/eap_server/eap_server.c47
-rw-r--r--src/eap_server/eap_server_eke.c24
-rw-r--r--src/eap_server/eap_server_fast.c2
-rw-r--r--src/eap_server/eap_server_mschapv2.c13
-rw-r--r--src/eap_server/eap_server_peap.c147
-rw-r--r--src/eap_server/eap_server_pwd.c64
-rw-r--r--src/eap_server/eap_server_tls.c58
-rw-r--r--src/eap_server/eap_server_tls_common.c53
-rw-r--r--src/eap_server/eap_server_ttls.c111
-rw-r--r--src/eap_server/eap_tls_common.h2
13 files changed, 469 insertions, 80 deletions
diff --git a/src/eap_server/Makefile b/src/eap_server/Makefile
index adfd3df..1172b72 100644
--- a/src/eap_server/Makefile
+++ b/src/eap_server/Makefile
@@ -1,8 +1,21 @@
-all:
- @echo Nothing to be made.
+all: libeap_server.a
clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeap_server.a
install:
@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_HS20
+
+LIB_OBJS= \
+ eap_server.o \
+ eap_server_identity.o \
+ eap_server_methods.o
+
+libeap_server.a: $(LIB_OBJS)
+ $(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 9de6cb6..69eaab8 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -131,6 +131,7 @@ struct eap_config {
const u8 *server_id;
size_t server_id_len;
int erp;
+ unsigned int tls_session_lifetime;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
@@ -139,7 +140,7 @@ struct eap_config {
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
- struct eapol_callbacks *eapol_cb,
+ const struct eapol_callbacks *eapol_cb,
struct eap_config *eap_conf);
void eap_server_sm_deinit(struct eap_sm *sm);
int eap_server_sm_step(struct eap_sm *sm);
@@ -149,5 +150,8 @@ int eap_sm_method_pending(struct eap_sm *sm);
const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
void eap_server_clear_identity(struct eap_sm *sm);
+void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
+ const u8 *username, size_t username_len,
+ const u8 *challenge, const u8 *response);
#endif /* EAP_H */
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 7d72309..c90443d 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -155,7 +155,7 @@ struct eap_sm {
/* not defined in RFC 4137 */
Boolean changed;
void *eapol_ctx, *msg_ctx;
- struct eapol_callbacks *eapol_cb;
+ const struct eapol_callbacks *eapol_cb;
void *eap_method_priv;
u8 *identity;
size_t identity_len;
@@ -210,6 +210,7 @@ struct eap_sm {
Boolean initiate_reauth_start_sent;
Boolean try_initiate_reauth;
int erp;
+ unsigned int tls_session_lifetime;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index bd919e5..84ecafc 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -96,7 +96,8 @@ static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
plen += 2 + domain_len;
}
- msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH_START, plen,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (EapType) EAP_ERP_TYPE_REAUTH_START, plen,
EAP_CODE_INITIATE, id);
if (msg == NULL)
return NULL;
@@ -714,8 +715,8 @@ static void erp_send_finish_reauth(struct eap_sm *sm,
plen = 1 + 2 + 2 + os_strlen(nai);
if (hash_len)
plen += 1 + hash_len;
- msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH, plen,
- EAP_CODE_FINISH, id);
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ plen, EAP_CODE_FINISH, id);
if (msg == NULL)
return;
wpabuf_put_u8(msg, flags);
@@ -745,7 +746,7 @@ static void erp_send_finish_reauth(struct eap_sm *sm,
wpabuf_free(sm->lastReqData);
sm->lastReqData = NULL;
- if (flags & 0x80) {
+ if ((flags & 0x80) || !erp) {
sm->eap_if.eapFail = TRUE;
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
@@ -799,7 +800,7 @@ SM_STATE(EAP, INITIATE_RECEIVED)
sm->rxInitiate = FALSE;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
sm->eap_if.eapRespData, &len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
@@ -1246,6 +1247,17 @@ SM_STEP(EAP)
break;
}
SM_ENTER(EAP, SEND_REQUEST);
+ if (sm->eap_if.eapNoReq && !sm->eap_if.eapReq) {
+ /*
+ * This transition is not mentioned in RFC 4137, but it
+ * is needed to handle cleanly a case where EAP method
+ * buildReq fails.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Method did not return a request");
+ SM_ENTER(EAP, FAILURE);
+ break;
+ }
break;
case EAP_METHOD_RESPONSE:
/*
@@ -1802,7 +1814,7 @@ static void eap_user_free(struct eap_user *user)
* This function allocates and initializes an EAP state machine.
*/
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
- struct eapol_callbacks *eapol_cb,
+ const struct eapol_callbacks *eapol_cb,
struct eap_config *conf)
{
struct eap_sm *sm;
@@ -1853,6 +1865,7 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
sm->server_id = conf->server_id;
sm->server_id_len = conf->server_id_len;
sm->erp = conf->erp;
+ sm->tls_session_lifetime = conf->tls_session_lifetime;
#ifdef CONFIG_TESTING_OPTIONS
sm->tls_test_flags = conf->tls_test_flags;
@@ -1979,3 +1992,25 @@ void eap_server_clear_identity(struct eap_sm *sm)
os_free(sm->identity);
sm->identity = NULL;
}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
+ const u8 *username, size_t username_len,
+ const u8 *challenge, const u8 *response)
+{
+ char hex_challenge[30], hex_response[90], user[100];
+
+ /* Print out Challenge and Response in format supported by asleap. */
+ if (username)
+ printf_encode(user, sizeof(user), username, username_len);
+ else
+ user[0] = '\0';
+ wpa_snprintf_hex_sep(hex_challenge, sizeof(hex_challenge),
+ challenge, sizeof(challenge), ':');
+ wpa_snprintf_hex_sep(hex_response, sizeof(hex_response), response, 24,
+ ':');
+ wpa_printf(MSG_DEBUG, "[%s/user=%s] asleap -C %s -R %s",
+ source, user, hex_challenge, hex_response);
+}
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index 966f511..ba82be9 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -766,6 +766,29 @@ static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_eke_data *data = priv;
+ u8 *sid;
+ size_t sid_len;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid_len = 1 + 2 * data->sess.nonce_len;
+ sid = os_malloc(sid_len);
+ if (sid == NULL)
+ return NULL;
+ sid[0] = EAP_TYPE_EKE;
+ os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len);
+ os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s,
+ data->sess.nonce_len);
+ *len = sid_len;
+
+ return sid;
+}
+
+
int eap_server_eke_register(void)
{
struct eap_method *eap;
@@ -785,6 +808,7 @@ int eap_server_eke_register(void)
eap->getKey = eap_eke_getKey;
eap->isSuccess = eap_eke_isSuccess;
eap->get_emsk = eap_eke_get_emsk;
+ eap->getSessionId = eap_eke_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 6745100..bd9018e 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -428,7 +428,7 @@ static void * eap_fast_init(struct eap_sm *sm)
}
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_FAST)) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
eap_fast_reset(sm, data);
return NULL;
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 05848d2..98d74e0 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -360,6 +360,19 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
}
}
+#ifdef CONFIG_TESTING_OPTIONS
+ {
+ u8 challenge[8];
+
+ if (challenge_hash(peer_challenge, data->auth_challenge,
+ username, username_len, challenge) == 0) {
+ eap_server_mschap_rx_callback(sm, "EAP-MSCHAPV2",
+ username, username_len,
+ challenge, nt_response);
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (username_len != user_len ||
os_memcmp(username, user, username_len) != 0) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index faa0fd2..51062b0 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -95,6 +95,37 @@ static void eap_peap_state(struct eap_peap_data *data, int state)
eap_peap_state_txt(data->state),
eap_peap_state_txt(state));
data->state = state;
+ if (state == FAILURE || state == FAILURE_REQ)
+ tls_connection_remove_session(data->ssl.conn);
+}
+
+
+static void eap_peap_valid_session(struct eap_sm *sm,
+ struct eap_peap_data *data)
+{
+ struct wpabuf *buf;
+
+ if (!sm->tls_session_lifetime ||
+ tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ return;
+
+ buf = wpabuf_alloc(1 + 1 + sm->identity_len);
+ if (!buf)
+ return;
+ wpabuf_put_u8(buf, EAP_TYPE_PEAP);
+ if (sm->identity) {
+ u8 id_len;
+
+ if (sm->identity_len <= 255)
+ id_len = sm->identity_len;
+ else
+ id_len = 255;
+ wpabuf_put_u8(buf, id_len);
+ wpabuf_put_data(buf, sm->identity, id_len);
+ } else {
+ wpabuf_put_u8(buf, 0);
+ }
+ tls_connection_set_success_data(data->ssl.conn, buf);
}
@@ -151,7 +182,7 @@ static void * eap_peap_init(struct eap_sm *sm)
data->state = START;
data->crypto_binding = OPTIONAL_BINDING;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_PEAP)) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
eap_peap_reset(sm, data);
return NULL;
@@ -539,15 +570,14 @@ static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
- EapType eap_type)
+ int vendor, EapType eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -709,10 +739,12 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
if (status == EAP_TLV_RESULT_SUCCESS) {
wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
"- requested %s", requested);
- if (data->tlv_request == TLV_REQ_SUCCESS)
+ if (data->tlv_request == TLV_REQ_SUCCESS) {
eap_peap_state(data, SUCCESS);
- else
+ eap_peap_valid_session(sm, data);
+ } else {
eap_peap_state(data, FAILURE);
+ }
} else if (status == EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
@@ -737,7 +769,7 @@ static void eap_peap_process_phase2_soh(struct eap_sm *sm,
const u8 *soh_tlv = NULL;
size_t soh_tlv_len = 0;
int tlv_type, mandatory, tlv_len, vtlv_len;
- u8 next_type;
+ u32 next_type;
u32 vendor_id;
pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
@@ -852,8 +884,9 @@ auth_method:
eap_peap_state(data, PHASE2_METHOD);
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
- wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
- eap_peap_phase2_init(sm, data, next_type);
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d",
+ sm->user->methods[0].vendor, next_type);
+ eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type);
}
#endif /* EAP_SERVER_TNC */
@@ -862,7 +895,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
struct eap_peap_data *data,
struct wpabuf *in_data)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ u32 next_type = EAP_TYPE_NONE;
const struct eap_hdr *hdr;
const u8 *pos;
size_t left;
@@ -894,17 +928,23 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
"allowed types", pos + 1, left - 1);
eap_sm_process_nak(sm, pos + 1, left - 1);
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
- sm->user->methods[sm->user_eap_method_index].method !=
- EAP_TYPE_NONE) {
+ (sm->user->methods[sm->user_eap_method_index].vendor !=
+ EAP_VENDOR_IETF ||
+ sm->user->methods[sm->user_eap_method_index].method !=
+ EAP_TYPE_NONE)) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: try EAP vendor %d type 0x%x",
+ next_vendor, next_type);
} else {
eap_peap_req_failure(sm, data);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
}
- eap_peap_phase2_init(sm, data, next_type);
+ eap_peap_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -929,8 +969,9 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
eap_peap_req_failure(sm, data);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
- eap_peap_phase2_init(sm, data, next_type);
+ eap_peap_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -942,7 +983,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
"failed");
eap_peap_req_failure(sm, data);
- eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
+ eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_NONE);
return;
}
}
@@ -957,6 +999,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
"database",
sm->identity, sm->identity_len);
eap_peap_req_failure(sm, data);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
break;
}
@@ -967,18 +1010,22 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
eap_peap_state(data, PHASE2_SOH);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
"TNC (NAP SOH)");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
break;
}
#endif /* EAP_SERVER_TNC */
eap_peap_state(data, PHASE2_METHOD);
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
- wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
eap_peap_req_success(sm, data);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
break;
case FAILURE:
@@ -989,7 +1036,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
break;
}
- eap_peap_phase2_init(sm, data, next_type);
+ eap_peap_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1080,6 +1127,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
if (data->state == SUCCESS_REQ) {
eap_peap_state(data, SUCCESS);
+ eap_peap_valid_session(sm, data);
}
break;
case EAP_CODE_FAILURE:
@@ -1133,7 +1181,8 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
break;
case PHASE2_START:
eap_peap_state(data, PHASE2_ID);
- eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+ eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY);
break;
case PHASE1_ID2:
case PHASE2_ID:
@@ -1144,6 +1193,7 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
break;
case SUCCESS_REQ:
eap_peap_state(data, SUCCESS);
+ eap_peap_valid_session(sm, data);
break;
case FAILURE_REQ:
eap_peap_state(data, FAILURE);
@@ -1160,10 +1210,65 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
struct eap_peap_data *data = priv;
+ const struct wpabuf *buf;
+ const u8 *pos;
+ u8 id_len;
+
if (eap_server_tls_process(sm, &data->ssl, respData, data,
EAP_TYPE_PEAP, eap_peap_process_version,
- eap_peap_process_msg) < 0)
+ eap_peap_process_msg) < 0) {
eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ if (data->state == SUCCESS ||
+ !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ return;
+
+ buf = tls_connection_get_success_data(data->ssl.conn);
+ if (!buf || wpabuf_len(buf) < 2) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: No success data in resumed session - reject attempt");
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ pos = wpabuf_head(buf);
+ if (*pos != EAP_TYPE_PEAP) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Resumed session for another EAP type (%u) - reject attempt",
+ *pos);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ pos++;
+ id_len = *pos++;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Identity from cached session",
+ pos, id_len);
+ os_free(sm->identity);
+ sm->identity = os_malloc(id_len ? id_len : 1);
+ if (!sm->identity) {
+ sm->identity_len = 0;
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ os_memcpy(sm->identity, pos, id_len);
+ sm->identity_len = id_len;
+
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Phase2 Identity not found in the user database",
+ sm->identity, sm->identity_len);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Resuming previous session - skip Phase2");
+ eap_peap_state(data, SUCCESS_REQ);
+ tls_connection_set_success_data_resumed(data->ssl.conn);
}
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 943af0d..cb83ff7 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "crypto/sha256.h"
+#include "crypto/ms_funcs.h"
#include "eap_server/eap_i.h"
#include "eap_common/eap_pwd_common.h"
@@ -24,6 +25,7 @@ struct eap_pwd_data {
size_t id_server_len;
u8 *password;
size_t password_len;
+ int password_hash;
u32 token;
u16 group_num;
EAP_PWD_group *grp;
@@ -112,6 +114,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
}
data->password_len = sm->user->password_len;
os_memcpy(data->password, sm->user->password, data->password_len);
+ data->password_hash = sm->user->password_hash;
data->bnctx = BN_CTX_new();
if (data->bnctx == NULL) {
@@ -181,7 +184,8 @@ static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
- wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
+ wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS :
+ EAP_PWD_PREP_NONE);
wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
}
@@ -579,6 +583,10 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm,
const u8 *payload, size_t payload_len)
{
struct eap_pwd_id *id;
+ const u8 *password;
+ size_t password_len;
+ u8 pwhashhash[16];
+ int res;
if (payload_len < sizeof(struct eap_pwd_id)) {
wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
@@ -610,11 +618,25 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm,
"group");
return;
}
- if (compute_password_element(data->grp, data->group_num,
- data->password, data->password_len,
- data->id_server, data->id_server_len,
- data->id_peer, data->id_peer_len,
- (u8 *) &data->token)) {
+
+ if (data->password_hash) {
+ res = hash_nt_password_hash(data->password, pwhashhash);
+ if (res)
+ return;
+ password = pwhashhash;
+ password_len = sizeof(pwhashhash);
+ } else {
+ password = data->password;
+ password_len = data->password_len;
+ }
+
+ res = compute_password_element(data->grp, data->group_num,
+ password, password_len,
+ data->id_server, data->id_server_len,
+ data->id_peer, data->id_peer_len,
+ (u8 *) &data->token);
+ os_memset(pwhashhash, 0, sizeof(pwhashhash));
+ if (res) {
wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
"PWE");
return;
@@ -634,9 +656,21 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
EC_POINT *K = NULL, *point = NULL;
int res = 0;
+ size_t prime_len, order_len;
wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
+ prime_len = BN_num_bytes(data->grp->prime);
+ order_len = BN_num_bytes(data->grp->order);
+
+ if (payload_len != 2 * prime_len + order_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) (2 * prime_len + order_len));
+ goto fin;
+ }
+
if (((data->peer_scalar = BN_new()) == NULL) ||
((data->k = BN_new()) == NULL) ||
((cofactor = BN_new()) == NULL) ||
@@ -752,6 +786,13 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
int offset;
+ if (payload_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
+ (unsigned int) payload_len, SHA256_MAC_LEN);
+ goto fin;
+ }
+
/* build up the ciphersuite: group | random_function | prf */
grp = htons(data->group_num);
ptr = (u8 *) &cs;
@@ -901,17 +942,28 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
* the first fragment has a total length
*/
if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: Frame too short to contain Total-Length field");
+ return;
+ }
tot_len = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
"length = %d", tot_len);
if (tot_len > 15000)
return;
+ if (data->inbuf) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
+ return;
+ }
data->inbuf = wpabuf_alloc(tot_len);
if (data->inbuf == NULL) {
wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
"buffer fragments!");
return;
}
+ data->in_frag_pos = 0;
pos += sizeof(u16);
len -= sizeof(u16);
}
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 58cfe8a..bd18a4b 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -48,6 +48,23 @@ static void eap_tls_state(struct eap_tls_data *data, int state)
eap_tls_state_txt(data->state),
eap_tls_state_txt(state));
data->state = state;
+ if (state == FAILURE)
+ tls_connection_remove_session(data->ssl.conn);
+}
+
+
+static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data)
+{
+ struct wpabuf *buf;
+
+ if (!sm->tls_session_lifetime)
+ return;
+
+ buf = wpabuf_alloc(1);
+ if (!buf)
+ return;
+ wpabuf_put_u8(buf, data->eap_type);
+ tls_connection_set_success_data(data->ssl.conn, buf);
}
@@ -60,7 +77,7 @@ static void * eap_tls_init(struct eap_sm *sm)
return NULL;
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 1, EAP_TYPE_TLS)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_reset(sm, data);
return NULL;
@@ -82,7 +99,7 @@ static void * eap_unauth_tls_init(struct eap_sm *sm)
return NULL;
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_UNAUTH_TLS_TYPE)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_reset(sm, data);
return NULL;
@@ -104,7 +121,8 @@ static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
return NULL;
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0,
+ EAP_WFA_UNAUTH_TLS_TYPE)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_reset(sm, data);
return NULL;
@@ -183,6 +201,7 @@ check_established:
* fragments waiting to be sent out. */
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
eap_tls_state(data, SUCCESS);
+ eap_tls_valid_session(sm, data);
}
return res;
@@ -234,10 +253,41 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
struct eap_tls_data *data = priv;
+ const struct wpabuf *buf;
+ const u8 *pos;
+
if (eap_server_tls_process(sm, &data->ssl, respData, data,
data->eap_type, NULL, eap_tls_process_msg) <
- 0)
+ 0) {
eap_tls_state(data, FAILURE);
+ return;
+ }
+
+ if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ return;
+
+ buf = tls_connection_get_success_data(data->ssl.conn);
+ if (!buf || wpabuf_len(buf) < 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: No success data in resumed session - reject attempt");
+ eap_tls_state(data, FAILURE);
+ return;
+ }
+
+ pos = wpabuf_head(buf);
+ if (*pos != data->eap_type) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Resumed session for another EAP type (%u) - reject attempt",
+ *pos);
+ eap_tls_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Resuming previous session");
+ eap_tls_state(data, SUCCESS);
+ tls_connection_set_success_data_resumed(data->ssl.conn);
}
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 56916c4..05677b7 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -44,8 +44,11 @@ static void eap_server_tls_log_cb(void *ctx, const char *msg)
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- int verify_peer)
+ int verify_peer, int eap_type)
{
+ u8 session_ctx[8];
+ unsigned int flags = 0;
+
if (sm->ssl_ctx == NULL) {
wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
return -1;
@@ -68,7 +71,13 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_TLS_INTERNAL */
- if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
+ if (eap_type != EAP_TYPE_FAST)
+ flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+ os_memcpy(session_ctx, "hostapd", 7);
+ session_ctx[7] = (u8) eap_type;
+ if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
+ flags, session_ctx,
+ sizeof(session_ctx))) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
tls_connection_deinit(sm->ssl_ctx, data->conn);
@@ -100,43 +109,19 @@ void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
- struct tls_keys keys;
- u8 *rnd = NULL, *out;
+ u8 *out;
out = os_malloc(len);
if (out == NULL)
return NULL;
- if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
- 0)
- return out;
-
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
- goto fail;
-
- if (keys.client_random == NULL || keys.server_random == NULL ||
- keys.master_key == NULL)
- goto fail;
-
- rnd = os_malloc(keys.client_random_len + keys.server_random_len);
- if (rnd == NULL)
- goto fail;
- os_memcpy(rnd, keys.client_random, keys.client_random_len);
- os_memcpy(rnd + keys.client_random_len, keys.server_random,
- keys.server_random_len);
-
- if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
- label, rnd, keys.client_random_len +
- keys.server_random_len, out, len))
- goto fail;
+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0,
+ out, len)) {
+ os_free(out);
+ return NULL;
+ }
- os_free(rnd);
return out;
-
-fail:
- os_free(out);
- os_free(rnd);
- return NULL;
}
@@ -157,10 +142,10 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len)
{
- struct tls_keys keys;
+ struct tls_random keys;
u8 *out;
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
return NULL;
if (keys.client_random == NULL || keys.server_random == NULL)
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 12a31b0..53ffa1e 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -71,6 +71,36 @@ static void eap_ttls_state(struct eap_ttls_data *data, int state)
eap_ttls_state_txt(data->state),
eap_ttls_state_txt(state));
data->state = state;
+ if (state == FAILURE)
+ tls_connection_remove_session(data->ssl.conn);
+}
+
+
+static void eap_ttls_valid_session(struct eap_sm *sm,
+ struct eap_ttls_data *data)
+{
+ struct wpabuf *buf;
+
+ if (!sm->tls_session_lifetime)
+ return;
+
+ buf = wpabuf_alloc(1 + 1 + sm->identity_len);
+ if (!buf)
+ return;
+ wpabuf_put_u8(buf, EAP_TYPE_TTLS);
+ if (sm->identity) {
+ u8 id_len;
+
+ if (sm->identity_len <= 255)
+ id_len = sm->identity_len;
+ else
+ id_len = 255;
+ wpabuf_put_u8(buf, id_len);
+ wpabuf_put_data(buf, sm->identity, id_len);
+ } else {
+ wpabuf_put_u8(buf, 0);
+ }
+ tls_connection_set_success_data(data->ssl.conn, buf);
}
@@ -317,7 +347,7 @@ static void * eap_ttls_init(struct eap_sm *sm)
data->ttls_version = EAP_TTLS_VERSION;
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_TTLS)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
eap_ttls_reset(sm, data);
return NULL;
@@ -518,6 +548,7 @@ static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
eap_ttls_state(data, SUCCESS);
+ eap_ttls_valid_session(sm, data);
}
@@ -576,6 +607,7 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
eap_ttls_state(data, SUCCESS);
+ eap_ttls_valid_session(sm, data);
} else {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
eap_ttls_state(data, FAILURE);
@@ -618,6 +650,12 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ eap_server_mschap_rx_callback(sm, "TTLS-MSCHAP",
+ sm->identity, sm->identity_len,
+ challenge, response + 2 + 24);
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN)
!= 0 ||
response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) {
@@ -637,6 +675,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
if (os_memcmp_const(nt_response, response + 2 + 24, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
eap_ttls_state(data, SUCCESS);
+ eap_ttls_valid_session(sm, data);
} else {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
@@ -740,6 +779,18 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
}
rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
+#ifdef CONFIG_TESTING_OPTIONS
+ {
+ u8 challenge2[8];
+
+ if (challenge_hash(peer_challenge, auth_challenge,
+ username, username_len, challenge2) == 0) {
+ eap_server_mschap_rx_callback(sm, "TTLS-MSCHAPV2",
+ username, username_len,
+ challenge2, rx_resp);
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (os_memcmp_const(nt_response, rx_resp, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
"NT-Response");
@@ -888,6 +939,7 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
break;
case PHASE2_METHOD:
eap_ttls_state(data, SUCCESS);
+ eap_ttls_valid_session(sm, data);
break;
case FAILURE:
break;
@@ -1111,6 +1163,7 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
"acknowledged response");
eap_ttls_state(data, SUCCESS);
+ eap_ttls_valid_session(sm, data);
} else if (!data->mschapv2_resp_ok) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
"acknowledged error");
@@ -1137,10 +1190,64 @@ static void eap_ttls_process(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
struct eap_ttls_data *data = priv;
+ const struct wpabuf *buf;
+ const u8 *pos;
+ u8 id_len;
+
if (eap_server_tls_process(sm, &data->ssl, respData, data,
EAP_TYPE_TTLS, eap_ttls_process_version,
- eap_ttls_process_msg) < 0)
+ eap_ttls_process_msg) < 0) {
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ return;
+
+ buf = tls_connection_get_success_data(data->ssl.conn);
+ if (!buf || wpabuf_len(buf) < 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: No success data in resumed session - reject attempt");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ pos = wpabuf_head(buf);
+ if (*pos != EAP_TYPE_TTLS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Resumed session for another EAP type (%u) - reject attempt",
+ *pos);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ pos++;
+ id_len = *pos++;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: Identity from cached session",
+ pos, id_len);
+ os_free(sm->identity);
+ sm->identity = os_malloc(id_len ? id_len : 1);
+ if (!sm->identity) {
+ sm->identity_len = 0;
eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ os_memcpy(sm->identity, pos, id_len);
+ sm->identity_len = id_len;
+
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not found in the user database",
+ sm->identity, sm->identity_len);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Resuming previous session - skip Phase2");
+ eap_ttls_state(data, SUCCESS);
+ tls_connection_set_success_data_resumed(data->ssl.conn);
}
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index ddf90b8..dc943eb 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -70,7 +70,7 @@ struct eap_ssl_data {
struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
u8 code, u8 identifier);
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- int verify_peer);
+ int verify_peer, int eap_type);
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len);