diff options
author | Andrew Shadura <andrewsh@debian.org> | 2016-07-23 12:51:30 +0200 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2016-07-23 12:51:30 +0200 |
commit | aa5e2237f3bbd73853b3ffbb4bf693298c409792 (patch) | |
tree | 26bd471557f364e950d823e12e7d9d83a73778c0 /src/eap_server | |
parent | 2b2675a5c8455e6a7224b153a28a6c2b5f1acd70 (diff) |
Imported Upstream version 2.5
Diffstat (limited to 'src/eap_server')
-rw-r--r-- | src/eap_server/Makefile | 19 | ||||
-rw-r--r-- | src/eap_server/eap.h | 6 | ||||
-rw-r--r-- | src/eap_server/eap_i.h | 3 | ||||
-rw-r--r-- | src/eap_server/eap_server.c | 47 | ||||
-rw-r--r-- | src/eap_server/eap_server_eke.c | 24 | ||||
-rw-r--r-- | src/eap_server/eap_server_fast.c | 2 | ||||
-rw-r--r-- | src/eap_server/eap_server_mschapv2.c | 13 | ||||
-rw-r--r-- | src/eap_server/eap_server_peap.c | 147 | ||||
-rw-r--r-- | src/eap_server/eap_server_pwd.c | 64 | ||||
-rw-r--r-- | src/eap_server/eap_server_tls.c | 58 | ||||
-rw-r--r-- | src/eap_server/eap_server_tls_common.c | 53 | ||||
-rw-r--r-- | src/eap_server/eap_server_ttls.c | 111 | ||||
-rw-r--r-- | src/eap_server/eap_tls_common.h | 2 |
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); |