diff options
author | grehan <grehan@FreeBSD.org> | 2013-07-05 05:47:10 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2013-07-05 05:47:10 +0000 |
commit | 6a7baaf83640e0eaa135d2f7a3c1d4401f1683bf (patch) | |
tree | 83ae82cf8f72af4b819f49aa52acdd97f74c6328 /contrib/wpa/src/eap_server | |
parent | 2cb5a953f0a60811764ccaca7c37b51ff007c711 (diff) | |
parent | 8e6b84b998690dcfc1a4957dc7a483ac5b600db8 (diff) | |
download | FreeBSD-src-6a7baaf83640e0eaa135d2f7a3c1d4401f1683bf.zip FreeBSD-src-6a7baaf83640e0eaa135d2f7a3c1d4401f1683bf.tar.gz |
IFC @ r252763
Diffstat (limited to 'contrib/wpa/src/eap_server')
33 files changed, 2379 insertions, 1265 deletions
diff --git a/contrib/wpa/src/eap_server/Makefile b/contrib/wpa/src/eap_server/Makefile deleted file mode 100644 index 9c41962..0000000 --- a/contrib/wpa/src/eap_server/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: - @echo Nothing to be made. - -clean: - rm -f *~ *.o *.d - -install: - @echo Nothing to be made. diff --git a/contrib/wpa/src/eap_server/eap.h b/contrib/wpa/src/eap_server/eap.h index 92400a5..f2a7cd7 100644 --- a/contrib/wpa/src/eap_server/eap.h +++ b/contrib/wpa/src/eap_server/eap.h @@ -2,14 +2,8 @@ * hostapd / EAP Full Authenticator state machine (RFC 4137) * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef EAP_H @@ -22,8 +16,6 @@ struct eap_sm; -#define EAP_MAX_METHODS 8 - #define EAP_TTLS_AUTH_PAP 1 #define EAP_TTLS_AUTH_CHAP 2 #define EAP_TTLS_AUTH_MSCHAP 4 @@ -95,6 +87,7 @@ struct eap_config { void *eap_sim_db_priv; Boolean backend_auth; int eap_server; + u16 pwd_group; u8 *pac_opaque_encr_key; u8 *eap_fast_a_id; size_t eap_fast_a_id_len; @@ -106,7 +99,11 @@ struct eap_config { int tnc; struct wps_context *wps; const struct wpabuf *assoc_wps_ie; + const struct wpabuf *assoc_p2p_ie; const u8 *peer_addr; + int fragment_size; + + int pbc_in_m1; }; @@ -120,5 +117,6 @@ void eap_sm_pending_cb(struct eap_sm *sm); 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); #endif /* EAP_H */ diff --git a/contrib/wpa/src/eap_server/eap_i.h b/contrib/wpa/src/eap_server/eap_i.h index 4269a8c..f92704a 100644 --- a/contrib/wpa/src/eap_server/eap_i.h +++ b/contrib/wpa/src/eap_server/eap_i.h @@ -2,14 +2,8 @@ * hostapd / EAP Authenticator state machine internal structures (RFC 4137) * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef EAP_I_H @@ -119,7 +113,7 @@ struct eap_sm { /* Full authenticator state machine local variables */ - /* Long-term (maintained betwen packets) */ + /* Long-term (maintained between packets) */ EapType currentMethod; int currentId; enum { @@ -157,7 +151,7 @@ struct eap_sm { int user_eap_method_index; int init_phase2; void *ssl_ctx; - void *eap_sim_db_priv; + struct eap_sim_db_data *eap_sim_db_priv; Boolean backend_auth; Boolean update_user; int eap_server; @@ -181,12 +175,19 @@ struct eap_sm { int pac_key_refresh_time; int eap_sim_aka_result_ind; int tnc; + u16 pwd_group; struct wps_context *wps; struct wpabuf *assoc_wps_ie; + struct wpabuf *assoc_p2p_ie; Boolean start_reauth; u8 peer_addr[ETH_ALEN]; + + /* Fragmentation size for EAP method init() handler */ + int fragment_size; + + int pbc_in_m1; }; int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, diff --git a/contrib/wpa/src/eap_server/eap_methods.h b/contrib/wpa/src/eap_server/eap_methods.h index 5d4d92c..bc810a9 100644 --- a/contrib/wpa/src/eap_server/eap_methods.h +++ b/contrib/wpa/src/eap_server/eap_methods.h @@ -2,14 +2,8 @@ * EAP server method registration * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef EAP_SERVER_METHODS_H @@ -32,6 +26,7 @@ const char * eap_server_get_name(int vendor, EapType type); int eap_server_identity_register(void); int eap_server_md5_register(void); int eap_server_tls_register(void); +int eap_server_unauth_tls_register(void); int eap_server_mschapv2_register(void); int eap_server_peap_register(void); int eap_server_tlv_register(void); @@ -49,5 +44,6 @@ int eap_server_fast_register(void); int eap_server_wsc_register(void); int eap_server_ikev2_register(void); int eap_server_tnc_register(void); +int eap_server_pwd_register(void); #endif /* EAP_SERVER_METHODS_H */ diff --git a/contrib/wpa/src/eap_server/eap_server.c b/contrib/wpa/src/eap_server/eap_server.c index fdc26f9..15f7e22 100644 --- a/contrib/wpa/src/eap_server/eap_server.c +++ b/contrib/wpa/src/eap_server/eap_server.c @@ -2,14 +2,8 @@ * hostapd / EAP Full Authenticator state machine (RFC 4137) * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. * * This state machine is based on the full authenticator state machine defined * in RFC 4137. However, to support backend authentication in RADIUS @@ -136,6 +130,14 @@ SM_STATE(EAP, INITIALIZE) { SM_ENTRY(EAP, INITIALIZE); + if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) { + /* + * Need to allow internal Identity method to be used instead + * of passthrough at the beginning of reauthentication. + */ + eap_server_clear_identity(sm); + } + sm->currentId = -1; sm->eap_if.eapSuccess = FALSE; sm->eap_if.eapFail = FALSE; @@ -273,6 +275,11 @@ SM_STATE(EAP, INTEGRITY_CHECK) { SM_ENTRY(EAP, INTEGRITY_CHECK); + if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) { + sm->ignore = TRUE; + return; + } + if (sm->m->check) { sm->ignore = sm->m->check(sm, sm->eap_method_priv, sm->eap_if.eapRespData); @@ -307,6 +314,9 @@ SM_STATE(EAP, METHOD_RESPONSE) { SM_ENTRY(EAP, METHOD_RESPONSE); + if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) + return; + sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); if (sm->m->isDone(sm, sm->eap_method_priv)) { eap_sm_Policy_update(sm, NULL, 0); @@ -378,6 +388,9 @@ SM_STATE(EAP, NAK) } sm->m = NULL; + if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) + return; + nak = wpabuf_head(sm->eap_if.eapRespData); if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { len = be_to_host16(nak->length); @@ -1028,9 +1041,12 @@ void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) not_found: /* not found - remove from the list */ - os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1], - (EAP_MAX_METHODS - i - 1) * - sizeof(sm->user->methods[0])); + if (i + 1 < EAP_MAX_METHODS) { + os_memmove(&sm->user->methods[i], + &sm->user->methods[i + 1], + (EAP_MAX_METHODS - i - 1) * + sizeof(sm->user->methods[0])); + } sm->user->methods[EAP_MAX_METHODS - 1].vendor = EAP_VENDOR_IETF; sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; @@ -1255,8 +1271,13 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx, sm->wps = conf->wps; if (conf->assoc_wps_ie) sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); + if (conf->assoc_p2p_ie) + sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie); if (conf->peer_addr) os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); + sm->fragment_size = conf->fragment_size; + sm->pwd_group = conf->pwd_group; + sm->pbc_in_m1 = conf->pbc_in_m1; wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); @@ -1291,6 +1312,7 @@ void eap_server_sm_deinit(struct eap_sm *sm) os_free(sm->eap_if.aaaEapKeyData); eap_user_free(sm->user); wpabuf_free(sm->assoc_wps_ie); + wpabuf_free(sm->assoc_p2p_ie); os_free(sm); } @@ -1362,3 +1384,18 @@ struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm) { return &sm->eap_if; } + + +/** + * eap_server_clear_identity - Clear EAP identity information + * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() + * + * This function can be used to clear the EAP identity information in the EAP + * server context. This allows the EAP/Identity method to be used again after + * EAPOL-Start or EAPOL-Logoff. + */ +void eap_server_clear_identity(struct eap_sm *sm) +{ + os_free(sm->identity); + sm->identity = NULL; +} diff --git a/contrib/wpa/src/eap_server/eap_server_aka.c b/contrib/wpa/src/eap_server/eap_server_aka.c index 4e7db48..469b9a0 100644 --- a/contrib/wpa/src/eap_server/eap_server_aka.c +++ b/contrib/wpa/src/eap_server/eap_server_aka.c @@ -1,15 +1,9 @@ /* - * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf) - * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi> + * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448) + * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -17,6 +11,7 @@ #include "common.h" #include "crypto/sha256.h" #include "crypto/crypto.h" +#include "crypto/random.h" #include "eap_common/eap_sim_common.h" #include "eap_server/eap_i.h" #include "eap_server/eap_sim_db.h" @@ -54,12 +49,12 @@ struct eap_aka_data { u8 *network_name; size_t network_name_len; u16 kdf; + int identity_round; + char permanent[20]; /* Permanent username */ }; -static void eap_aka_determine_identity(struct eap_sm *sm, - struct eap_aka_data *data, - int before_identity, int after_reauth); +static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data); static const char * eap_aka_state_txt(int state) @@ -92,6 +87,96 @@ static void eap_aka_state(struct eap_aka_data *data, int state) } +static int eap_aka_check_identity_reauth(struct eap_sm *sm, + struct eap_aka_data *data, + const char *username) +{ + if (data->eap_method == EAP_TYPE_AKA_PRIME && + username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX) + return 0; + if (data->eap_method == EAP_TYPE_AKA && + username[0] != EAP_AKA_REAUTH_ID_PREFIX) + return 0; + + wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username); + data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv, + username); + if (data->reauth == NULL) { + wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - " + "request full auth identity"); + /* Remain in IDENTITY state for another round */ + return 0; + } + + wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication"); + os_strlcpy(data->permanent, data->reauth->permanent, + sizeof(data->permanent)); + data->counter = data->reauth->counter; + if (data->eap_method == EAP_TYPE_AKA_PRIME) { + os_memcpy(data->k_encr, data->reauth->k_encr, + EAP_SIM_K_ENCR_LEN); + os_memcpy(data->k_aut, data->reauth->k_aut, + EAP_AKA_PRIME_K_AUT_LEN); + os_memcpy(data->k_re, data->reauth->k_re, + EAP_AKA_PRIME_K_RE_LEN); + } else { + os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); + } + + eap_aka_state(data, REAUTH); + return 1; +} + + +static void eap_aka_check_identity(struct eap_sm *sm, + struct eap_aka_data *data) +{ + char *username; + + /* Check if we already know the identity from EAP-Response/Identity */ + + username = sim_get_username(sm->identity, sm->identity_len); + if (username == NULL) + return; + + if (eap_aka_check_identity_reauth(sm, data, username) > 0) { + os_free(username); + /* + * Since re-auth username was recognized, skip AKA/Identity + * exchange. + */ + return; + } + + if ((data->eap_method == EAP_TYPE_AKA_PRIME && + username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || + (data->eap_method == EAP_TYPE_AKA && + username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { + const char *permanent; + wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", + username); + permanent = eap_sim_db_get_permanent( + sm->eap_sim_db_priv, username); + if (permanent == NULL) { + os_free(username); + wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " + "identity - request permanent identity"); + /* Remain in IDENTITY state for another round */ + return; + } + os_strlcpy(data->permanent, permanent, + sizeof(data->permanent)); + /* + * Since pseudonym username was recognized, skip AKA/Identity + * exchange. + */ + eap_aka_fullauth(sm, data); + } + + os_free(username); +} + + static void * eap_aka_init(struct eap_sm *sm) { struct eap_aka_data *data; @@ -108,8 +193,8 @@ static void * eap_aka_init(struct eap_sm *sm) data->eap_method = EAP_TYPE_AKA; data->state = IDENTITY; - eap_aka_determine_identity(sm, data, 1, 0); data->pending_id = -1; + eap_aka_check_identity(sm, data); return data; } @@ -132,18 +217,17 @@ static void * eap_aka_prime_init(struct eap_sm *sm) return NULL; data->eap_method = EAP_TYPE_AKA_PRIME; - data->network_name = os_malloc(os_strlen(network_name)); + data->network_name = (u8 *) os_strdup(network_name); if (data->network_name == NULL) { os_free(data); return NULL; } data->network_name_len = os_strlen(network_name); - os_memcpy(data->network_name, network_name, data->network_name_len); data->state = IDENTITY; - eap_aka_determine_identity(sm, data, 1, 0); data->pending_id = -1; + eap_aka_check_identity(sm, data); return data; } @@ -270,11 +354,8 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity"); msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, EAP_AKA_SUBTYPE_IDENTITY); - if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, - sm->identity_len)) { - wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); - } else { + data->identity_round++; + if (data->identity_round == 1) { /* * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is * ignored and the AKA/Identity is used to request the @@ -282,6 +363,19 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, */ wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); + } else if (data->identity_round > 3) { + /* Cannot use more than three rounds of Identity messages */ + eap_sim_msg_free(msg); + return NULL; + } else if (sm->identity && sm->identity_len > 0 && + (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX || + sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) { + /* Reauth id may have expired - try fullauth */ + wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ"); + eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0); + } else { + wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); + eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); } buf = eap_sim_msg_finish(msg, NULL, NULL, 0); if (eap_aka_add_id_msg(data, buf) < 0) { @@ -298,12 +392,23 @@ static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, const u8 *nonce_s) { os_free(data->next_pseudonym); - data->next_pseudonym = - eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1); + if (nonce_s == NULL) { + data->next_pseudonym = + eap_sim_db_get_next_pseudonym( + sm->eap_sim_db_priv, + data->eap_method == EAP_TYPE_AKA_PRIME ? + EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); + } else { + /* Do not update pseudonym during re-authentication */ + data->next_pseudonym = NULL; + } os_free(data->next_reauth_id); if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { data->next_reauth_id = - eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1); + eap_sim_db_get_next_reauth_id( + sm->eap_sim_db_priv, + data->eap_method == EAP_TYPE_AKA_PRIME ? + EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); } else { wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " "count exceeded - force full authentication"); @@ -440,7 +545,7 @@ static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication"); - if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN)) + if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) return NULL; wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S", data->nonce_s, EAP_SIM_NONCE_S_LEN); @@ -607,92 +712,83 @@ static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype) static void eap_aka_determine_identity(struct eap_sm *sm, - struct eap_aka_data *data, - int before_identity, int after_reauth) + struct eap_aka_data *data) { - const u8 *identity; - size_t identity_len; - int res; + char *username; - identity = NULL; - identity_len = 0; + wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", + sm->identity, sm->identity_len); - if (after_reauth && data->reauth) { - identity = data->reauth->identity; - identity_len = data->reauth->identity_len; - } else if (sm->identity && sm->identity_len > 0 && - sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) { - identity = sm->identity; - identity_len = sm->identity_len; - } else { - identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, - sm->identity, - sm->identity_len, - &identity_len); - if (identity == NULL) { - data->reauth = eap_sim_db_get_reauth_entry( - sm->eap_sim_db_priv, sm->identity, - sm->identity_len); - if (data->reauth && - data->reauth->aka_prime != - (data->eap_method == EAP_TYPE_AKA_PRIME)) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data " - "was for different AKA version"); - data->reauth = NULL; - } - if (data->reauth) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast " - "re-authentication"); - identity = data->reauth->identity; - identity_len = data->reauth->identity_len; - data->counter = data->reauth->counter; - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - os_memcpy(data->k_encr, - data->reauth->k_encr, - EAP_SIM_K_ENCR_LEN); - os_memcpy(data->k_aut, - data->reauth->k_aut, - EAP_AKA_PRIME_K_AUT_LEN); - os_memcpy(data->k_re, - data->reauth->k_re, - EAP_AKA_PRIME_K_RE_LEN); - } else { - os_memcpy(data->mk, data->reauth->mk, - EAP_SIM_MK_LEN); - } - } - } + username = sim_get_username(sm->identity, sm->identity_len); + if (username == NULL) { + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_aka_state(data, NOTIFICATION); + return; } - if (identity == NULL || - eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, - sm->identity_len) < 0) { - if (before_identity) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name " - "not known - send AKA-Identity request"); - eap_aka_state(data, IDENTITY); - return; - } else { - wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the " - "permanent user name is known; try to use " - "it"); - /* eap_sim_db_get_aka_auth() will report failure, if - * this identity is not known. */ - } + if (eap_aka_check_identity_reauth(sm, data, username) > 0) { + os_free(username); + return; } - wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", - identity, identity_len); + if (((data->eap_method == EAP_TYPE_AKA_PRIME && + username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) || + (data->eap_method == EAP_TYPE_AKA && + username[0] == EAP_AKA_REAUTH_ID_PREFIX)) && + data->identity_round == 1) { + /* Remain in IDENTITY state for another round to request full + * auth identity since we did not recognize reauth id */ + os_free(username); + return; + } - if (!after_reauth && data->reauth) { - eap_aka_state(data, REAUTH); + if ((data->eap_method == EAP_TYPE_AKA_PRIME && + username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || + (data->eap_method == EAP_TYPE_AKA && + username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { + const char *permanent; + wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", + username); + permanent = eap_sim_db_get_permanent( + sm->eap_sim_db_priv, username); + os_free(username); + if (permanent == NULL) { + wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " + "identity - request permanent identity"); + /* Remain in IDENTITY state for another round */ + return; + } + os_strlcpy(data->permanent, permanent, + sizeof(data->permanent)); + } else if ((data->eap_method == EAP_TYPE_AKA_PRIME && + username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) || + (data->eap_method == EAP_TYPE_AKA && + username[0] == EAP_AKA_PERMANENT_PREFIX)) { + wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'", + username); + os_strlcpy(data->permanent, username, sizeof(data->permanent)); + os_free(username); + } else { + wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'", + username); + os_free(username); + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_aka_state(data, NOTIFICATION); return; } - res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity, - identity_len, data->rand, data->autn, - data->ik, data->ck, data->res, - &data->res_len, sm); + eap_aka_fullauth(sm, data); +} + + +static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data) +{ + size_t identity_len; + int res; + + res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent, + data->rand, data->autn, data->ik, + data->ck, data->res, &data->res_len, sm); if (res == EAP_SIM_DB_PENDING) { wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " "not yet available - pending request"); @@ -737,7 +833,7 @@ static void eap_aka_determine_identity(struct eap_sm *sm, sm->identity, identity_len); if (data->eap_method == EAP_TYPE_AKA_PRIME) { - eap_aka_prime_derive_keys(identity, identity_len, data->ik, + eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik, data->ck, data->k_encr, data->k_aut, data->k_re, data->msk, data->emsk); } else { @@ -756,6 +852,8 @@ static void eap_aka_process_identity(struct eap_sm *sm, struct wpabuf *respData, struct eap_sim_attrs *attr) { + u8 *new_identity; + wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity"); if (attr->mac || attr->iv || attr->encr_data) { @@ -766,17 +864,30 @@ static void eap_aka_process_identity(struct eap_sm *sm, return; } - if (attr->identity) { - os_free(sm->identity); - sm->identity = os_malloc(attr->identity_len); - if (sm->identity) { - os_memcpy(sm->identity, attr->identity, - attr->identity_len); - sm->identity_len = attr->identity_len; - } + /* + * We always request identity with AKA/Identity, so the peer is + * required to have replied with one. + */ + if (!attr->identity || attr->identity_len == 0) { + wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any " + "identity"); + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_aka_state(data, NOTIFICATION); + return; + } + + new_identity = os_malloc(attr->identity_len); + if (new_identity == NULL) { + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_aka_state(data, NOTIFICATION); + return; } + os_free(sm->identity); + sm->identity = new_identity; + os_memcpy(sm->identity, attr->identity, attr->identity_len); + sm->identity_len = attr->identity_len; - eap_aka_determine_identity(sm, data, 0, 0); + eap_aka_determine_identity(sm, data); if (eap_get_id(respData) == data->pending_id) { data->pending_id = -1; eap_aka_add_id_msg(data, respData); @@ -801,9 +912,6 @@ static void eap_aka_process_challenge(struct eap_sm *sm, struct wpabuf *respData, struct eap_sim_attrs *attr) { - const u8 *identity; - size_t identity_len; - wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); #ifdef EAP_SERVER_AKA_PRIME @@ -876,16 +984,8 @@ static void eap_aka_process_challenge(struct eap_sm *sm, } else eap_aka_state(data, SUCCESS); - identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, - sm->identity_len, &identity_len); - if (identity == NULL) { - identity = sm->identity; - identity_len = sm->identity_len; - } - if (data->next_pseudonym) { - eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, - identity_len, + eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent, data->next_pseudonym); data->next_pseudonym = NULL; } @@ -893,16 +993,15 @@ static void eap_aka_process_challenge(struct eap_sm *sm, if (data->eap_method == EAP_TYPE_AKA_PRIME) { #ifdef EAP_SERVER_AKA_PRIME eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, - identity, - identity_len, + data->permanent, data->next_reauth_id, data->counter + 1, data->k_encr, data->k_aut, data->k_re); #endif /* EAP_SERVER_AKA_PRIME */ } else { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, - identity_len, + eap_sim_db_add_reauth(sm->eap_sim_db_priv, + data->permanent, data->next_reauth_id, data->counter + 1, data->mk); @@ -931,9 +1030,8 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm, * maintaining a local flag stating whether this AUTS has already been * reported. */ if (!data->auts_reported && - eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity, - sm->identity_len, attr->auts, - data->rand)) { + eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent, + attr->auts, data->rand)) { wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed"); data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); @@ -941,8 +1039,7 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm, } data->auts_reported = 1; - /* Try again after resynchronization */ - eap_aka_determine_identity(sm, data, 0, 0); + /* Remain in CHALLENGE state to re-try after resynchronization */ } @@ -953,8 +1050,6 @@ static void eap_aka_process_reauth(struct eap_sm *sm, { struct eap_sim_attrs eattr; u8 *decrypted = NULL; - const u8 *identity, *id2; - size_t identity_len, id2_len; wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); @@ -997,7 +1092,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " "included AT_COUNTER_TOO_SMALL - starting full " "authentication"); - eap_aka_determine_identity(sm, data, 0, 1); + eap_aka_fullauth(sm, data); return; } @@ -1008,40 +1103,19 @@ static void eap_aka_process_reauth(struct eap_sm *sm, } else eap_aka_state(data, SUCCESS); - if (data->reauth) { - identity = data->reauth->identity; - identity_len = data->reauth->identity_len; - } else { - identity = sm->identity; - identity_len = sm->identity_len; - } - - id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, - identity_len, &id2_len); - if (id2) { - identity = id2; - identity_len = id2_len; - } - - if (data->next_pseudonym) { - eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, - identity_len, data->next_pseudonym); - data->next_pseudonym = NULL; - } if (data->next_reauth_id) { if (data->eap_method == EAP_TYPE_AKA_PRIME) { #ifdef EAP_SERVER_AKA_PRIME eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, - identity, - identity_len, + data->permanent, data->next_reauth_id, data->counter + 1, data->k_encr, data->k_aut, data->k_re); #endif /* EAP_SERVER_AKA_PRIME */ } else { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, - identity_len, + eap_sim_db_add_reauth(sm->eap_sim_db_priv, + data->permanent, data->next_reauth_id, data->counter + 1, data->mk); diff --git a/contrib/wpa/src/eap_server/eap_server_fast.c b/contrib/wpa/src/eap_server/eap_server_fast.c index 39beb33..fcb80dc 100644 --- a/contrib/wpa/src/eap_server/eap_server_fast.c +++ b/contrib/wpa/src/eap_server/eap_server_fast.c @@ -2,14 +2,8 @@ * EAP-FAST server (RFC 4851) * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -18,6 +12,7 @@ #include "crypto/aes_wrap.h" #include "crypto/sha1.h" #include "crypto/tls.h" +#include "crypto/random.h" #include "eap_common/eap_tlv_common.h" #include "eap_common/eap_fast_common.h" #include "eap_i.h" @@ -642,7 +637,7 @@ static struct wpabuf * eap_fast_build_crypto_binding( binding->version = EAP_FAST_VERSION; binding->received_version = data->peer_version; binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST; - if (os_get_random(binding->nonce, sizeof(binding->nonce)) < 0) { + if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) { wpabuf_free(buf); return NULL; } @@ -692,7 +687,7 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, struct eap_tlv_result_tlv *result; struct os_time now; - if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 || + if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 || os_get_time(&now) < 0) return NULL; wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key", diff --git a/contrib/wpa/src/eap_server/eap_server_gpsk.c b/contrib/wpa/src/eap_server/eap_server_gpsk.c index d0c7559..2853c48 100644 --- a/contrib/wpa/src/eap_server/eap_server_gpsk.c +++ b/contrib/wpa/src/eap_server/eap_server_gpsk.c @@ -2,19 +2,14 @@ * hostapd / EAP-GPSK (RFC 5433) server * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" +#include "crypto/random.h" #include "eap_server/eap_i.h" #include "eap_common/eap_gpsk_common.h" @@ -120,7 +115,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1"); - if (os_get_random(data->rand_server, EAP_GPSK_RAND_LEN)) { + if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) { wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data"); eap_gpsk_state(data, FAILURE); return NULL; diff --git a/contrib/wpa/src/eap_server/eap_server_gtc.c b/contrib/wpa/src/eap_server/eap_server_gtc.c index 79b9696..f423106 100644 --- a/contrib/wpa/src/eap_server/eap_server_gtc.c +++ b/contrib/wpa/src/eap_server/eap_server_gtc.c @@ -2,14 +2,8 @@ * hostapd / EAP-GTC (RFC 3748) * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" diff --git a/contrib/wpa/src/eap_server/eap_server_identity.c b/contrib/wpa/src/eap_server/eap_server_identity.c index cd8da2a..51dc4e8 100644 --- a/contrib/wpa/src/eap_server/eap_server_identity.c +++ b/contrib/wpa/src/eap_server/eap_server_identity.c @@ -2,14 +2,8 @@ * hostapd / EAP-Identity * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" diff --git a/contrib/wpa/src/eap_server/eap_server_ikev2.c b/contrib/wpa/src/eap_server/eap_server_ikev2.c index 06074ee..42aaca2 100644 --- a/contrib/wpa/src/eap_server/eap_server_ikev2.c +++ b/contrib/wpa/src/eap_server/eap_server_ikev2.c @@ -2,14 +2,8 @@ * EAP-IKEv2 server (RFC 5106) * Copyright (c) 2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -93,7 +87,8 @@ static void * eap_ikev2_init(struct eap_sm *sm) if (data == NULL) return NULL; data->state = MSG; - data->fragment_size = IKEV2_FRAGMENT_SIZE; + data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : + IKEV2_FRAGMENT_SIZE; data->ikev2.state = SA_INIT; data->ikev2.peer_auth = PEER_AUTH_SECRET; data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); diff --git a/contrib/wpa/src/eap_server/eap_server_md5.c b/contrib/wpa/src/eap_server/eap_server_md5.c index dee2dc5..5a5e290 100644 --- a/contrib/wpa/src/eap_server/eap_server_md5.c +++ b/contrib/wpa/src/eap_server/eap_server_md5.c @@ -1,20 +1,15 @@ /* * hostapd / EAP-MD5 server - * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" +#include "crypto/random.h" #include "eap_i.h" #include "eap_common/chap.h" @@ -52,7 +47,7 @@ static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id) struct eap_md5_data *data = priv; struct wpabuf *req; - if (os_get_random(data->challenge, CHALLENGE_LEN)) { + if (random_get_bytes(data->challenge, CHALLENGE_LEN)) { wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data"); data->state = FAILURE; return NULL; @@ -124,8 +119,12 @@ static void eap_md5_process(struct eap_sm *sm, void *priv, wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN); id = eap_get_id(respData); - chap_md5(id, sm->user->password, sm->user->password_len, - data->challenge, CHALLENGE_LEN, hash); + if (chap_md5(id, sm->user->password, sm->user->password_len, + data->challenge, CHALLENGE_LEN, hash)) { + wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed"); + data->state = FAILURE; + return; + } if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); diff --git a/contrib/wpa/src/eap_server/eap_server_methods.c b/contrib/wpa/src/eap_server/eap_server_methods.c index 900a5dd..0209fad 100644 --- a/contrib/wpa/src/eap_server/eap_server_methods.c +++ b/contrib/wpa/src/eap_server/eap_server_methods.c @@ -2,14 +2,8 @@ * EAP server method registration * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -167,6 +161,8 @@ void eap_server_unregister_methods(void) const char * eap_server_get_name(int vendor, EapType type) { struct eap_method *m; + if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED) + return "expanded"; for (m = eap_methods; m; m = m->next) { if (m->vendor == vendor && m->method == type) return m->name; diff --git a/contrib/wpa/src/eap_server/eap_server_mschapv2.c b/contrib/wpa/src/eap_server/eap_server_mschapv2.c index 39d1c6e..8d3dd52 100644 --- a/contrib/wpa/src/eap_server/eap_server_mschapv2.c +++ b/contrib/wpa/src/eap_server/eap_server_mschapv2.c @@ -2,20 +2,15 @@ * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" #include "crypto/ms_funcs.h" +#include "crypto/random.h" #include "eap_i.h" @@ -109,7 +104,7 @@ static struct wpabuf * eap_mschapv2_build_challenge( size_t ms_len; if (!data->auth_challenge_from_tls && - os_get_random(data->auth_challenge, CHALLENGE_LEN)) { + random_get_bytes(data->auth_challenge, CHALLENGE_LEN)) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random " "data"); data->state = FAILURE; @@ -404,9 +399,12 @@ static void eap_mschapv2_process_response(struct eap_sm *sm, if (sm->user->password_hash) { pw_hash = sm->user->password; } else { - nt_password_hash(sm->user->password, - sm->user->password_len, - pw_hash_buf); + if (nt_password_hash(sm->user->password, + sm->user->password_len, + pw_hash_buf) < 0) { + data->state = FAILURE; + return; + } pw_hash = pw_hash_buf; } generate_authenticator_response_pwhash( diff --git a/contrib/wpa/src/eap_server/eap_server_pax.c b/contrib/wpa/src/eap_server/eap_server_pax.c index 1dc023b..35a42ad 100644 --- a/contrib/wpa/src/eap_server/eap_server_pax.c +++ b/contrib/wpa/src/eap_server/eap_server_pax.c @@ -2,19 +2,14 @@ * hostapd / EAP-PAX (RFC 4746) server * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" +#include "crypto/random.h" #include "eap_server/eap_i.h" #include "eap_common/eap_pax_common.h" @@ -82,7 +77,7 @@ static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)"); - if (os_get_random(data->rand.r.x, EAP_PAX_RAND_LEN)) { + if (random_get_bytes(data->rand.r.x, EAP_PAX_RAND_LEN)) { wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data"); data->state = FAILURE; return NULL; diff --git a/contrib/wpa/src/eap_server/eap_server_peap.c b/contrib/wpa/src/eap_server/eap_server_peap.c index 674ecd2..68253c4 100644 --- a/contrib/wpa/src/eap_server/eap_server_peap.c +++ b/contrib/wpa/src/eap_server/eap_server_peap.c @@ -2,14 +2,8 @@ * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -17,6 +11,7 @@ #include "common.h" #include "crypto/sha1.h" #include "crypto/tls.h" +#include "crypto/random.h" #include "eap_i.h" #include "eap_tls_common.h" #include "eap_common/eap_tlv_common.h" @@ -350,8 +345,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) * in the end of the label just before ISK; is that just a typo?) */ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); - peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys", - isk, sizeof(isk), imck, sizeof(imck)); + if (peap_prfplus(data->peap_version, tk, 40, + "Inner Methods Compound Keys", + isk, sizeof(isk), imck, sizeof(imck)) < 0) { + os_free(tk); + return -1; + } wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", imck, sizeof(imck)); @@ -414,7 +413,7 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, #endif /* EAP_SERVER_TNC */ if (eap_peap_derive_cmk(sm, data) < 0 || - os_get_random(data->binding_nonce, 32)) { + random_get_bytes(data->binding_nonce, 32)) { wpabuf_free(buf); return NULL; } @@ -1059,8 +1058,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm, wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted); - hdr = wpabuf_head(in_decrypted); - if (data->peap_version == 0 && data->state != PHASE2_TLV) { const struct eap_hdr *resp; struct eap_hdr *nhdr; @@ -1319,9 +1316,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) * termination for this label while the one used for deriving * IPMK|CMK did not use null termination. */ - peap_prfplus(data->peap_version, data->ipmk, 40, - "Session Key Generating Function", - (u8 *) "\00", 1, csk, sizeof(csk)); + if (peap_prfplus(data->peap_version, data->ipmk, 40, + "Session Key Generating Function", + (u8 *) "\00", 1, csk, sizeof(csk)) < 0) + return NULL; wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); eapKeyData = os_malloc(EAP_TLS_KEY_LEN); if (eapKeyData) { diff --git a/contrib/wpa/src/eap_server/eap_server_psk.c b/contrib/wpa/src/eap_server/eap_server_psk.c index 4c30346..0cd9799 100644 --- a/contrib/wpa/src/eap_server/eap_server_psk.c +++ b/contrib/wpa/src/eap_server/eap_server_psk.c @@ -2,14 +2,8 @@ * hostapd / EAP-PSK (RFC 4764) server * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. * * Note: EAP-PSK is an EAP authentication method and as such, completely * different from WPA-PSK. This file is not needed for WPA-PSK functionality. @@ -19,6 +13,7 @@ #include "common.h" #include "crypto/aes_wrap.h" +#include "crypto/random.h" #include "eap_common/eap_psk_common.h" #include "eap_server/eap_i.h" @@ -66,7 +61,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)"); - if (os_get_random(data->rand_s, EAP_PSK_RAND_LEN)) { + if (random_get_bytes(data->rand_s, EAP_PSK_RAND_LEN)) { wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); data->state = FAILURE; return NULL; @@ -124,8 +119,10 @@ static struct wpabuf * eap_psk_build_3(struct eap_sm *sm, os_memcpy(buf, data->id_s, data->id_s_len); os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); - if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) + if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) { + os_free(buf); goto fail; + } os_free(buf); if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk, diff --git a/contrib/wpa/src/eap_server/eap_server_pwd.c b/contrib/wpa/src/eap_server/eap_server_pwd.c new file mode 100644 index 0000000..b61061b --- /dev/null +++ b/contrib/wpa/src/eap_server/eap_server_pwd.c @@ -0,0 +1,1045 @@ +/* + * hostapd / EAP-pwd (RFC 5931) server + * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto/sha256.h" +#include "eap_server/eap_i.h" +#include "eap_common/eap_pwd_common.h" + + +struct eap_pwd_data { + enum { + PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE + } state; + u8 *id_peer; + size_t id_peer_len; + u8 *id_server; + size_t id_server_len; + u8 *password; + size_t password_len; + u32 token; + u16 group_num; + EAP_PWD_group *grp; + + struct wpabuf *inbuf; + size_t in_frag_pos; + struct wpabuf *outbuf; + size_t out_frag_pos; + size_t mtu; + + BIGNUM *k; + BIGNUM *private_value; + BIGNUM *peer_scalar; + BIGNUM *my_scalar; + EC_POINT *my_element; + EC_POINT *peer_element; + + u8 my_confirm[SHA256_MAC_LEN]; + + u8 msk[EAP_MSK_LEN]; + u8 emsk[EAP_EMSK_LEN]; + + BN_CTX *bnctx; +}; + + +static const char * eap_pwd_state_txt(int state) +{ + switch (state) { + case PWD_ID_Req: + return "PWD-ID-Req"; + case PWD_Commit_Req: + return "PWD-Commit-Req"; + case PWD_Confirm_Req: + return "PWD-Confirm-Req"; + case SUCCESS: + return "SUCCESS"; + case FAILURE: + return "FAILURE"; + default: + return "PWD-Unk"; + } +} + + +static void eap_pwd_state(struct eap_pwd_data *data, int state) +{ + wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s", + eap_pwd_state_txt(data->state), eap_pwd_state_txt(state)); + data->state = state; +} + + +static void * eap_pwd_init(struct eap_sm *sm) +{ + struct eap_pwd_data *data; + + if (sm->user == NULL || sm->user->password == NULL || + sm->user->password_len == 0) { + wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not " + "configured"); + return NULL; + } + + data = os_zalloc(sizeof(*data)); + if (data == NULL) + return NULL; + + data->group_num = sm->pwd_group; + wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d", + data->group_num); + data->state = PWD_ID_Req; + + data->id_server = (u8 *) os_strdup("server"); + if (data->id_server) + data->id_server_len = os_strlen((char *) data->id_server); + + data->password = os_malloc(sm->user->password_len); + if (data->password == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password " + "fail"); + os_free(data->id_server); + os_free(data); + return NULL; + } + data->password_len = sm->user->password_len; + os_memcpy(data->password, sm->user->password, data->password_len); + + data->bnctx = BN_CTX_new(); + if (data->bnctx == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); + os_free(data->password); + os_free(data->id_server); + os_free(data); + return NULL; + } + + data->in_frag_pos = data->out_frag_pos = 0; + data->inbuf = data->outbuf = NULL; + data->mtu = 1020; /* default from RFC 5931, make it configurable! */ + + return data; +} + + +static void eap_pwd_reset(struct eap_sm *sm, void *priv) +{ + struct eap_pwd_data *data = priv; + + BN_free(data->private_value); + BN_free(data->peer_scalar); + BN_free(data->my_scalar); + BN_free(data->k); + BN_CTX_free(data->bnctx); + EC_POINT_free(data->my_element); + EC_POINT_free(data->peer_element); + os_free(data->id_peer); + os_free(data->id_server); + os_free(data->password); + if (data->grp) { + EC_GROUP_free(data->grp->group); + EC_POINT_free(data->grp->pwe); + BN_free(data->grp->order); + BN_free(data->grp->prime); + os_free(data->grp); + } + os_free(data); +} + + +static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, + u8 id) +{ + wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request"); + /* + * if we're fragmenting then we already have an id request, just return + */ + if (data->out_frag_pos) + return; + + data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) + + data->id_server_len); + if (data->outbuf == NULL) { + eap_pwd_state(data, FAILURE); + return; + } + + /* an lfsr is good enough to generate unpredictable tokens */ + data->token = os_random(); + wpabuf_put_be16(data->outbuf, data->group_num); + 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_data(data->outbuf, data->id_server, data->id_server_len); +} + + +static void eap_pwd_build_commit_req(struct eap_sm *sm, + struct eap_pwd_data *data, u8 id) +{ + BIGNUM *mask = NULL, *x = NULL, *y = NULL; + u8 *scalar = NULL, *element = NULL; + u16 offset; + + wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request"); + /* + * if we're fragmenting then we already have an commit request, just + * return + */ + if (data->out_frag_pos) + return; + + if (((data->private_value = BN_new()) == NULL) || + ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || + ((data->my_scalar = BN_new()) == NULL) || + ((mask = BN_new()) == NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation " + "fail"); + goto fin; + } + + BN_rand_range(data->private_value, data->grp->order); + BN_rand_range(mask, data->grp->order); + BN_add(data->my_scalar, data->private_value, mask); + BN_mod(data->my_scalar, data->my_scalar, data->grp->order, + data->bnctx); + + if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, + data->grp->pwe, mask, data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation " + "fail"); + eap_pwd_state(data, FAILURE); + goto fin; + } + + if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) + { + wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion " + "fail"); + goto fin; + } + BN_free(mask); + + if (((x = BN_new()) == NULL) || + ((y = BN_new()) == NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation " + "fail"); + goto fin; + } + if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, + data->my_element, x, y, + data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment " + "fail"); + goto fin; + } + + if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || + ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == + NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail"); + goto fin; + } + + /* + * bignums occupy as little memory as possible so one that is + * sufficiently smaller than the prime or order might need pre-pending + * with zeros. + */ + os_memset(scalar, 0, BN_num_bytes(data->grp->order)); + os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->my_scalar); + BN_bn2bin(data->my_scalar, scalar + offset); + + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, element + offset); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); + + data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) + + BN_num_bytes(data->grp->order)); + if (data->outbuf == NULL) + goto fin; + + /* We send the element as (x,y) followed by the scalar */ + wpabuf_put_data(data->outbuf, element, + 2 * BN_num_bytes(data->grp->prime)); + wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order)); + +fin: + os_free(scalar); + os_free(element); + BN_free(x); + BN_free(y); + if (data->outbuf == NULL) + eap_pwd_state(data, FAILURE); +} + + +static void eap_pwd_build_confirm_req(struct eap_sm *sm, + struct eap_pwd_data *data, u8 id) +{ + BIGNUM *x = NULL, *y = NULL; + struct crypto_hash *hash; + u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; + u16 grp; + int offset; + + wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request"); + /* + * if we're fragmenting then we already have an confirm request, just + * return + */ + if (data->out_frag_pos) + return; + + /* Each component of the cruft will be at most as big as the prime */ + if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || + ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation " + "fail"); + goto fin; + } + + /* + * commit is H(k | server_element | server_scalar | peer_element | + * peer_scalar | ciphersuite) + */ + hash = eap_pwd_h_init(); + if (hash == NULL) + goto fin; + + /* + * Zero the memory each time because this is mod prime math and some + * value may start with a few zeros and the previous one did not. + * + * First is k + */ + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); + BN_bn2bin(data->k, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + + /* server element: x, y */ + if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, + data->my_element, x, y, + data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } + + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + + /* server scalar */ + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->my_scalar); + BN_bn2bin(data->my_scalar, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); + + /* peer element: x, y */ + if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, + data->peer_element, x, y, + data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } + + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + + /* peer scalar */ + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->peer_scalar); + BN_bn2bin(data->peer_scalar, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); + + /* ciphersuite */ + grp = htons(data->group_num); + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + ptr = cruft; + os_memcpy(ptr, &grp, sizeof(u16)); + ptr += sizeof(u16); + *ptr = EAP_PWD_DEFAULT_RAND_FUNC; + ptr += sizeof(u8); + *ptr = EAP_PWD_DEFAULT_PRF; + ptr += sizeof(u8); + eap_pwd_h_update(hash, cruft, ptr - cruft); + + /* all done with the random function */ + eap_pwd_h_final(hash, conf); + os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN); + + data->outbuf = wpabuf_alloc(SHA256_MAC_LEN); + if (data->outbuf == NULL) + goto fin; + + wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); + +fin: + os_free(cruft); + BN_free(x); + BN_free(y); + if (data->outbuf == NULL) + eap_pwd_state(data, FAILURE); +} + + +static struct wpabuf * +eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id) +{ + struct eap_pwd_data *data = priv; + struct wpabuf *req; + u8 lm_exch; + const u8 *buf; + u16 totlen = 0; + size_t len; + + /* + * if we're buffering response fragments then just ACK + */ + if (data->in_frag_pos) { + wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!"); + req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, + EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id); + if (req == NULL) { + eap_pwd_state(data, FAILURE); + return NULL; + } + switch (data->state) { + case PWD_ID_Req: + wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH); + break; + case PWD_Commit_Req: + wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH); + break; + case PWD_Confirm_Req: + wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH); + break; + default: + eap_pwd_state(data, FAILURE); /* just to be sure */ + wpabuf_free(req); + return NULL; + } + return req; + } + + /* + * build the data portion of a request + */ + switch (data->state) { + case PWD_ID_Req: + eap_pwd_build_id_req(sm, data, id); + lm_exch = EAP_PWD_OPCODE_ID_EXCH; + break; + case PWD_Commit_Req: + eap_pwd_build_commit_req(sm, data, id); + lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH; + break; + case PWD_Confirm_Req: + eap_pwd_build_confirm_req(sm, data, id); + lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH; + break; + default: + wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req", + data->state); + eap_pwd_state(data, FAILURE); + lm_exch = 0; /* hush now, sweet compiler */ + break; + } + + if (data->state == FAILURE) + return NULL; + + /* + * determine whether that data needs to be fragmented + */ + len = wpabuf_len(data->outbuf) - data->out_frag_pos; + if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { + len = data->mtu - EAP_PWD_HDR_SIZE; + EAP_PWD_SET_MORE_BIT(lm_exch); + /* + * if this is the first fragment, need to set the M bit + * and add the total length to the eap_pwd_hdr + */ + if (data->out_frag_pos == 0) { + EAP_PWD_SET_LENGTH_BIT(lm_exch); + totlen = wpabuf_len(data->outbuf) + + EAP_PWD_HDR_SIZE + sizeof(u16); + len -= sizeof(u16); + wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, " + "total length = %d", totlen); + } + wpa_printf(MSG_DEBUG, "EAP-pwd: Send a %d byte fragment", + (int) len); + } + + /* + * alloc an eap request and populate it with the data + */ + req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, + EAP_PWD_HDR_SIZE + len + + (totlen ? sizeof(u16) : 0), + EAP_CODE_REQUEST, id); + if (req == NULL) { + eap_pwd_state(data, FAILURE); + return NULL; + } + + wpabuf_put_u8(req, lm_exch); + if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) + wpabuf_put_be16(req, totlen); + + buf = wpabuf_head_u8(data->outbuf); + wpabuf_put_data(req, buf + data->out_frag_pos, len); + data->out_frag_pos += len; + /* + * either not fragged or last fragment, either way free up the data + */ + if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { + wpabuf_free(data->outbuf); + data->out_frag_pos = 0; + } + + return req; +} + + +static Boolean eap_pwd_check(struct eap_sm *sm, void *priv, + struct wpabuf *respData) +{ + struct eap_pwd_data *data = priv; + const u8 *pos; + size_t len; + + pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len); + if (pos == NULL || len < 1) { + wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame"); + return TRUE; + } + + wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d", + EAP_PWD_GET_EXCHANGE(*pos), (int) len); + + if (data->state == PWD_ID_Req && + ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH)) + return FALSE; + + if (data->state == PWD_Commit_Req && + ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH)) + return FALSE; + + if (data->state == PWD_Confirm_Req && + ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH)) + return FALSE; + + wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d", + *pos, data->state); + + return TRUE; +} + + +static void eap_pwd_process_id_resp(struct eap_sm *sm, + struct eap_pwd_data *data, + const u8 *payload, size_t payload_len) +{ + struct eap_pwd_id *id; + + if (payload_len < sizeof(struct eap_pwd_id)) { + wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response"); + return; + } + + id = (struct eap_pwd_id *) payload; + if ((data->group_num != be_to_host16(id->group_num)) || + (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || + (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) || + (id->prf != EAP_PWD_DEFAULT_PRF)) { + wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters"); + eap_pwd_state(data, FAILURE); + return; + } + data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id)); + if (data->id_peer == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); + return; + } + data->id_peer_len = payload_len - sizeof(struct eap_pwd_id); + os_memcpy(data->id_peer, id->identity, data->id_peer_len); + wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of", + data->id_peer, data->id_peer_len); + + if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) { + wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " + "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)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute " + "PWE"); + return; + } + wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...", + BN_num_bits(data->grp->prime)); + + eap_pwd_state(data, PWD_Commit_Req); +} + + +static void +eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, + const u8 *payload, size_t payload_len) +{ + u8 *ptr; + BIGNUM *x = NULL, *y = NULL, *cofactor = NULL; + EC_POINT *K = NULL, *point = NULL; + int res = 0; + + wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response"); + + if (((data->peer_scalar = BN_new()) == NULL) || + ((data->k = BN_new()) == NULL) || + ((cofactor = BN_new()) == NULL) || + ((x = BN_new()) == NULL) || + ((y = BN_new()) == NULL) || + ((point = EC_POINT_new(data->grp->group)) == NULL) || + ((K = EC_POINT_new(data->grp->group)) == NULL) || + ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " + "fail"); + goto fin; + } + + if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get " + "cofactor for curve"); + goto fin; + } + + /* element, x then y, followed by scalar */ + ptr = (u8 *) payload; + BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); + ptr += BN_num_bytes(data->grp->prime); + BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); + ptr += BN_num_bytes(data->grp->prime); + BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar); + if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, + data->peer_element, x, y, + data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element " + "fail"); + goto fin; + } + + /* check to ensure peer's element is not in a small sub-group */ + if (BN_cmp(cofactor, BN_value_one())) { + if (!EC_POINT_mul(data->grp->group, point, NULL, + data->peer_element, cofactor, NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " + "multiply peer element by order"); + goto fin; + } + if (EC_POINT_is_at_infinity(data->grp->group, point)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): peer element " + "is at infinity!\n"); + goto fin; + } + } + + /* compute the shared key, k */ + if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, + data->peer_scalar, data->bnctx)) || + (!EC_POINT_add(data->grp->group, K, K, data->peer_element, + data->bnctx)) || + (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, + data->bnctx))) { + wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key " + "fail"); + goto fin; + } + + /* ensure that the shared key isn't in a small sub-group */ + if (BN_cmp(cofactor, BN_value_one())) { + if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, + NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " + "multiply shared key point by order!\n"); + goto fin; + } + } + + /* + * This check is strictly speaking just for the case above where + * co-factor > 1 but it was suggested that even though this is probably + * never going to happen it is a simple and safe check "just to be + * sure" so let's be safe. + */ + if (EC_POINT_is_at_infinity(data->grp->group, K)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is " + "at infinity"); + goto fin; + } + if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, + NULL, data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract " + "shared secret from secret point"); + goto fin; + } + res = 1; + +fin: + EC_POINT_free(K); + EC_POINT_free(point); + BN_free(cofactor); + BN_free(x); + BN_free(y); + + if (res) + eap_pwd_state(data, PWD_Confirm_Req); + else + eap_pwd_state(data, FAILURE); +} + + +static void +eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, + const u8 *payload, size_t payload_len) +{ + BIGNUM *x = NULL, *y = NULL; + struct crypto_hash *hash; + u32 cs; + u16 grp; + u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; + int offset; + + /* build up the ciphersuite: group | random_function | prf */ + grp = htons(data->group_num); + ptr = (u8 *) &cs; + os_memcpy(ptr, &grp, sizeof(u16)); + ptr += sizeof(u16); + *ptr = EAP_PWD_DEFAULT_RAND_FUNC; + ptr += sizeof(u8); + *ptr = EAP_PWD_DEFAULT_PRF; + + /* each component of the cruft will be at most as big as the prime */ + if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || + ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { + wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail"); + goto fin; + } + + /* + * commit is H(k | peer_element | peer_scalar | server_element | + * server_scalar | ciphersuite) + */ + hash = eap_pwd_h_init(); + if (hash == NULL) + goto fin; + + /* k */ + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); + BN_bn2bin(data->k, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + + /* peer element: x, y */ + if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, + data->peer_element, x, y, + data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + + /* peer scalar */ + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->peer_scalar); + BN_bn2bin(data->peer_scalar, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); + + /* server element: x, y */ + if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, + data->my_element, x, y, + data->bnctx)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " + "assignment fail"); + goto fin; + } + + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); + + /* server scalar */ + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + offset = BN_num_bytes(data->grp->order) - + BN_num_bytes(data->my_scalar); + BN_bn2bin(data->my_scalar, cruft + offset); + eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); + + /* ciphersuite */ + os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); + eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); + + /* all done */ + eap_pwd_h_final(hash, conf); + + ptr = (u8 *) payload; + if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) { + wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not " + "verify"); + goto fin; + } + + wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified"); + if (compute_keys(data->grp, data->bnctx, data->k, + data->peer_scalar, data->my_scalar, conf, + data->my_confirm, &cs, data->msk, data->emsk) < 0) + eap_pwd_state(data, FAILURE); + else + eap_pwd_state(data, SUCCESS); + +fin: + os_free(cruft); + BN_free(x); + BN_free(y); +} + + +static void eap_pwd_process(struct eap_sm *sm, void *priv, + struct wpabuf *respData) +{ + struct eap_pwd_data *data = priv; + const u8 *pos; + size_t len; + u8 lm_exch; + u16 tot_len; + + pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len); + if ((pos == NULL) || (len < 1)) { + wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d", + (pos == NULL) ? "is NULL" : "is not NULL", + (int) len); + return; + } + + lm_exch = *pos; + pos++; /* skip over the bits and the exch */ + len--; + + /* + * if we're fragmenting then this should be an ACK with no data, + * just return and continue fragmenting in the "build" section above + */ + if (data->out_frag_pos) { + if (len > 1) + wpa_printf(MSG_INFO, "EAP-pwd: Bad response! " + "Fragmenting but not an ACK"); + else + wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from " + "peer"); + return; + } + /* + * if we're receiving fragmented packets then we need to buffer... + * + * the first fragment has a total length + */ + if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { + tot_len = WPA_GET_BE16(pos); + wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total " + "length = %d", tot_len); + data->inbuf = wpabuf_alloc(tot_len); + if (data->inbuf == NULL) { + wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to " + "buffer fragments!"); + return; + } + pos += sizeof(u16); + len -= sizeof(u16); + } + /* + * the first and all intermediate fragments have the M bit set + */ + if (EAP_PWD_GET_MORE_BIT(lm_exch)) { + if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) { + wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow " + "attack detected! (%d+%d > %d)", + (int) data->in_frag_pos, (int) len, + (int) wpabuf_size(data->inbuf)); + eap_pwd_state(data, FAILURE); + return; + } + wpabuf_put_data(data->inbuf, pos, len); + data->in_frag_pos += len; + wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment", + (int) len); + return; + } + /* + * last fragment won't have the M bit set (but we're obviously + * buffering fragments so that's how we know it's the last) + */ + if (data->in_frag_pos) { + wpabuf_put_data(data->inbuf, pos, len); + data->in_frag_pos += len; + pos = wpabuf_head_u8(data->inbuf); + len = data->in_frag_pos; + wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", + (int) len); + } + switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { + case EAP_PWD_OPCODE_ID_EXCH: + eap_pwd_process_id_resp(sm, data, pos, len); + break; + case EAP_PWD_OPCODE_COMMIT_EXCH: + eap_pwd_process_commit_resp(sm, data, pos, len); + break; + case EAP_PWD_OPCODE_CONFIRM_EXCH: + eap_pwd_process_confirm_resp(sm, data, pos, len); + break; + } + /* + * if we had been buffering fragments, here's a great place + * to clean up + */ + if (data->in_frag_pos) { + wpabuf_free(data->inbuf); + data->in_frag_pos = 0; + } +} + + +static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_pwd_data *data = priv; + u8 *key; + + if (data->state != SUCCESS) + return NULL; + + key = os_malloc(EAP_MSK_LEN); + if (key == NULL) + return NULL; + + os_memcpy(key, data->msk, EAP_MSK_LEN); + *len = EAP_MSK_LEN; + + return key; +} + + +static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_pwd_data *data = priv; + u8 *key; + + if (data->state != SUCCESS) + return NULL; + + key = os_malloc(EAP_EMSK_LEN); + if (key == NULL) + return NULL; + + os_memcpy(key, data->emsk, EAP_EMSK_LEN); + *len = EAP_EMSK_LEN; + + return key; +} + + +static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv) +{ + struct eap_pwd_data *data = priv; + return data->state == SUCCESS; +} + + +static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv) +{ + struct eap_pwd_data *data = priv; + return (data->state == SUCCESS) || (data->state == FAILURE); +} + + +int eap_server_pwd_register(void) +{ + struct eap_method *eap; + int ret; + struct timeval tp; + struct timezone tz; + u32 sr; + + EVP_add_digest(EVP_sha256()); + + sr = 0xdeaddada; + (void) gettimeofday(&tp, &tz); + sr ^= (tp.tv_sec ^ tp.tv_usec); + srandom(sr); + + eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, + EAP_VENDOR_IETF, EAP_TYPE_PWD, + "PWD"); + if (eap == NULL) + return -1; + + eap->init = eap_pwd_init; + eap->reset = eap_pwd_reset; + eap->buildReq = eap_pwd_build_req; + eap->check = eap_pwd_check; + eap->process = eap_pwd_process; + eap->isDone = eap_pwd_is_done; + eap->getKey = eap_pwd_getkey; + eap->get_emsk = eap_pwd_get_emsk; + eap->isSuccess = eap_pwd_is_success; + + ret = eap_server_method_register(eap); + if (ret) + eap_server_method_free(eap); + return ret; +} + diff --git a/contrib/wpa/src/eap_server/eap_server_sake.c b/contrib/wpa/src/eap_server/eap_server_sake.c index ce4848f..f72e1bf 100644 --- a/contrib/wpa/src/eap_server/eap_server_sake.c +++ b/contrib/wpa/src/eap_server/eap_server_sake.c @@ -2,19 +2,14 @@ * hostapd / EAP-SAKE (RFC 4763) server * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" +#include "crypto/random.h" #include "eap_server/eap_i.h" #include "eap_common/eap_sake_common.h" @@ -166,7 +161,7 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge"); - if (os_get_random(data->rand_s, EAP_SAKE_RAND_LEN)) { + if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) { wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); data->state = FAILURE; return NULL; diff --git a/contrib/wpa/src/eap_server/eap_server_sim.c b/contrib/wpa/src/eap_server/eap_server_sim.c index 436c655..b531241 100644 --- a/contrib/wpa/src/eap_server/eap_server_sim.c +++ b/contrib/wpa/src/eap_server/eap_server_sim.c @@ -1,20 +1,15 @@ /* * hostapd / EAP-SIM (RFC 4186) - * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" +#include "crypto/random.h" #include "eap_server/eap_i.h" #include "eap_common/eap_sim_common.h" #include "eap_server/eap_sim_db.h" @@ -41,6 +36,8 @@ struct eap_sim_data { struct eap_sim_reauth *reauth; u16 notification; int use_result_ind; + int start_round; + char permanent[20]; /* Permanent username */ }; @@ -110,17 +107,33 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start"); msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START); - if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, - sm->identity_len)) { - wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); - } else { + data->start_round++; + if (data->start_round == 1) { /* * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is * ignored and the SIM/Start is used to request the identity. */ wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); + } else if (data->start_round > 3) { + /* Cannot use more than three rounds of Start messages */ + eap_sim_msg_free(msg); + return NULL; + } else if (data->start_round == 0) { + /* + * This is a special case that is used to recover from + * AT_COUNTER_TOO_SMALL during re-authentication. Since we + * already know the identity of the peer, there is no need to + * request any identity in this case. + */ + } else if (sm->identity && sm->identity_len > 0 && + sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) { + /* Reauth id may have expired - try fullauth */ + wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ"); + eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0); + } else { + wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); + eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); } wpa_printf(MSG_DEBUG, " AT_VERSION_LIST"); ver[0] = 0; @@ -136,12 +149,19 @@ static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data, const u8 *nonce_s) { os_free(data->next_pseudonym); - data->next_pseudonym = - eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0); + if (nonce_s == NULL) { + data->next_pseudonym = + eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, + EAP_SIM_DB_SIM); + } else { + /* Do not update pseudonym during re-authentication */ + data->next_pseudonym = NULL; + } os_free(data->next_reauth_id); if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) { data->next_reauth_id = - eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0); + eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, + EAP_SIM_DB_SIM); } else { wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication " "count exceeded - force full authentication"); @@ -232,7 +252,7 @@ static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication"); - if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN)) + if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) return NULL; wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S", data->nonce_s, EAP_SIM_NONCE_S_LEN); @@ -326,18 +346,22 @@ static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id) static Boolean eap_sim_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { - struct eap_sim_data *data = priv; const u8 *pos; size_t len; - u8 subtype; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); if (pos == NULL || len < 3) { wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame"); return TRUE; } - subtype = *pos; + return FALSE; +} + + +static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data, + u8 subtype) +{ if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) return FALSE; @@ -391,85 +415,113 @@ static void eap_sim_process_start(struct eap_sm *sm, struct wpabuf *respData, struct eap_sim_attrs *attr) { - const u8 *identity; size_t identity_len; u8 ver_list[2]; + u8 *new_identity; + char *username; wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); - if (attr->identity) { - os_free(sm->identity); - sm->identity = os_malloc(attr->identity_len); - if (sm->identity) { - os_memcpy(sm->identity, attr->identity, - attr->identity_len); - sm->identity_len = attr->identity_len; - } + if (data->start_round == 0) { + /* + * Special case for AT_COUNTER_TOO_SMALL recovery - no identity + * was requested since we already know it. + */ + goto skip_id_update; } - identity = NULL; - identity_len = 0; - - if (sm->identity && sm->identity_len > 0 && - sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) { - identity = sm->identity; - identity_len = sm->identity_len; - } else { - identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, - sm->identity, - sm->identity_len, - &identity_len); - if (identity == NULL) { - data->reauth = eap_sim_db_get_reauth_entry( - sm->eap_sim_db_priv, sm->identity, - sm->identity_len); - if (data->reauth) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast " - "re-authentication"); - identity = data->reauth->identity; - identity_len = data->reauth->identity_len; - data->counter = data->reauth->counter; - os_memcpy(data->mk, data->reauth->mk, - EAP_SIM_MK_LEN); - } - } + /* + * We always request identity in SIM/Start, so the peer is required to + * have replied with one. + */ + if (!attr->identity || attr->identity_len == 0) { + wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any " + "identity"); + goto failed; } - if (identity == NULL) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent" - " user name"); - eap_sim_state(data, FAILURE); - return; - } + new_identity = os_malloc(attr->identity_len); + if (new_identity == NULL) + goto failed; + os_free(sm->identity); + sm->identity = new_identity; + os_memcpy(sm->identity, attr->identity, attr->identity_len); + sm->identity_len = attr->identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", - identity, identity_len); - - if (data->reauth) { + sm->identity, sm->identity_len); + username = sim_get_username(sm->identity, sm->identity_len); + if (username == NULL) + goto failed; + + if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) { + wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'", + username); + data->reauth = eap_sim_db_get_reauth_entry( + sm->eap_sim_db_priv, username); + os_free(username); + if (data->reauth == NULL) { + wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth " + "identity - request full auth identity"); + /* Remain in START state for another round */ + return; + } + wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication"); + os_strlcpy(data->permanent, data->reauth->permanent, + sizeof(data->permanent)); + data->counter = data->reauth->counter; + os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); eap_sim_state(data, REAUTH); return; } + if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) { + const char *permanent; + wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'", + username); + permanent = eap_sim_db_get_permanent( + sm->eap_sim_db_priv, username); + os_free(username); + if (permanent == NULL) { + wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym " + "identity - request permanent identity"); + /* Remain in START state for another round */ + return; + } + os_strlcpy(data->permanent, permanent, + sizeof(data->permanent)); + } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) { + wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'", + username); + os_strlcpy(data->permanent, username, sizeof(data->permanent)); + os_free(username); + } else { + wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'", + username); + os_free(username); + goto failed; + } + +skip_id_update: + /* Full authentication */ + if (attr->nonce_mt == NULL || attr->selected_version < 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " "required attributes"); - eap_sim_state(data, FAILURE); - return; + goto failed; } if (!eap_sim_supported_ver(data, attr->selected_version)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " "version %d", attr->selected_version); - eap_sim_state(data, FAILURE); - return; + goto failed; } data->counter = 0; /* reset re-auth counter since this is full auth */ data->reauth = NULL; data->num_chal = eap_sim_db_get_gsm_triplets( - sm->eap_sim_db_priv, identity, identity_len, - EAP_SIM_MAX_CHAL, + sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL, (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); if (data->num_chal == EAP_SIM_DB_PENDING) { wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " @@ -480,8 +532,7 @@ static void eap_sim_process_start(struct eap_sm *sm, if (data->num_chal < 2) { wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " "authentication triplets for the peer"); - eap_sim_state(data, FAILURE); - return; + goto failed; } identity_len = sm->identity_len; @@ -502,6 +553,11 @@ static void eap_sim_process_start(struct eap_sm *sm, data->emsk); eap_sim_state(data, CHALLENGE); + return; + +failed: + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_sim_state(data, NOTIFICATION); } @@ -510,16 +566,14 @@ static void eap_sim_process_challenge(struct eap_sm *sm, struct wpabuf *respData, struct eap_sim_attrs *attr) { - const u8 *identity; - size_t identity_len; - if (attr->mac == NULL || eap_sim_verify_mac(data->k_aut, respData, attr->mac, (u8 *) data->sres, data->num_chal * EAP_SIM_SRES_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " "did not include valid AT_MAC"); - eap_sim_state(data, FAILURE); + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_sim_state(data, NOTIFICATION); return; } @@ -532,22 +586,13 @@ static void eap_sim_process_challenge(struct eap_sm *sm, } else eap_sim_state(data, SUCCESS); - identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, - sm->identity_len, &identity_len); - if (identity == NULL) { - identity = sm->identity; - identity_len = sm->identity_len; - } - if (data->next_pseudonym) { - eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, - identity_len, + eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent, data->next_pseudonym); data->next_pseudonym = NULL; } if (data->next_reauth_id) { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, - identity_len, + eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, data->next_reauth_id, data->counter + 1, data->mk); data->next_reauth_id = NULL; @@ -562,8 +607,6 @@ static void eap_sim_process_reauth(struct eap_sm *sm, { struct eap_sim_attrs eattr; u8 *decrypted = NULL; - const u8 *identity, *id2; - size_t identity_len, id2_len; if (attr->mac == NULL || eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, @@ -599,6 +642,16 @@ static void eap_sim_process_reauth(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " "the correct AT_MAC"); + + if (eattr.counter_too_small) { + wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " + "included AT_COUNTER_TOO_SMALL - starting full " + "authentication"); + data->start_round = -1; + eap_sim_state(data, START); + return; + } + if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; @@ -606,29 +659,9 @@ static void eap_sim_process_reauth(struct eap_sm *sm, } else eap_sim_state(data, SUCCESS); - if (data->reauth) { - identity = data->reauth->identity; - identity_len = data->reauth->identity_len; - } else { - identity = sm->identity; - identity_len = sm->identity_len; - } - - id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, - identity_len, &id2_len); - if (id2) { - identity = id2; - identity_len = id2_len; - } - - if (data->next_pseudonym) { - eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, - identity_len, data->next_pseudonym); - data->next_pseudonym = NULL; - } if (data->next_reauth_id) { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, - identity_len, data->next_reauth_id, + eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, + data->next_reauth_id, data->counter + 1, data->mk); data->next_reauth_id = NULL; } else { @@ -639,7 +672,8 @@ static void eap_sim_process_reauth(struct eap_sm *sm, return; fail: - eap_sim_state(data, FAILURE); + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_sim_state(data, NOTIFICATION); eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; os_free(decrypted); @@ -690,8 +724,24 @@ static void eap_sim_process(struct eap_sm *sm, void *priv, subtype = *pos; pos += 3; + if (eap_sim_unexpected_subtype(data, subtype)) { + wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected " + "EAP-SIM Subtype in EAP Response"); + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_sim_state(data, NOTIFICATION); + return; + } + if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); + if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR && + (data->state == START || data->state == CHALLENGE || + data->state == REAUTH)) { + data->notification = + EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_sim_state(data, NOTIFICATION); + return; + } eap_sim_state(data, FAILURE); return; } diff --git a/contrib/wpa/src/eap_server/eap_server_tls.c b/contrib/wpa/src/eap_server/eap_server_tls.c index c98fa18..447f47c 100644 --- a/contrib/wpa/src/eap_server/eap_server_tls.c +++ b/contrib/wpa/src/eap_server/eap_server_tls.c @@ -2,14 +2,8 @@ * hostapd / EAP-TLS (RFC 2716) * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -27,6 +21,7 @@ struct eap_tls_data { struct eap_ssl_data ssl; enum { START, CONTINUE, SUCCESS, FAILURE } state; int established; + u8 eap_type; }; @@ -71,10 +66,34 @@ static void * eap_tls_init(struct eap_sm *sm) return NULL; } + data->eap_type = EAP_TYPE_TLS; + return data; } +#ifdef EAP_SERVER_UNAUTH_TLS +static void * eap_unauth_tls_init(struct eap_sm *sm) +{ + struct eap_tls_data *data; + + data = os_zalloc(sizeof(*data)); + if (data == NULL) + return NULL; + data->state = START; + + if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { + wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); + eap_tls_reset(sm, data); + return NULL; + } + + data->eap_type = EAP_UNAUTH_TLS_TYPE; + return data; +} +#endif /* EAP_SERVER_UNAUTH_TLS */ + + static void eap_tls_reset(struct eap_sm *sm, void *priv) { struct eap_tls_data *data = priv; @@ -90,8 +109,7 @@ static struct wpabuf * eap_tls_build_start(struct eap_sm *sm, { struct wpabuf *req; - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST, - id); + req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " "request"); @@ -113,11 +131,11 @@ static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) struct wpabuf *res; if (data->ssl.state == FRAG_ACK) { - return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0); + return eap_server_tls_build_ack(id, data->eap_type, 0); } if (data->ssl.state == WAIT_FRAG_ACK) { - res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, + res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id); goto check_established; } @@ -135,7 +153,7 @@ static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) return NULL; } - res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id); + res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id); check_established: if (data->established && data->ssl.state != WAIT_FRAG_ACK) { @@ -152,10 +170,17 @@ check_established: static Boolean eap_tls_check(struct eap_sm *sm, void *priv, struct wpabuf *respData) { + struct eap_tls_data *data = priv; const u8 *pos; size_t len; - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len); + if (data->eap_type == EAP_UNAUTH_TLS_TYPE) + pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, + EAP_VENDOR_TYPE_UNAUTH_TLS, respData, + &len); + else + pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type, + respData, &len); if (pos == NULL || len < 1) { wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); return TRUE; @@ -184,7 +209,7 @@ static void eap_tls_process(struct eap_sm *sm, void *priv, { struct eap_tls_data *data = priv; if (eap_server_tls_process(sm, &data->ssl, respData, data, - EAP_TYPE_TLS, NULL, eap_tls_process_msg) < + data->eap_type, NULL, eap_tls_process_msg) < 0) eap_tls_state(data, FAILURE); } @@ -284,3 +309,34 @@ int eap_server_tls_register(void) eap_server_method_free(eap); return ret; } + + +#ifdef EAP_SERVER_UNAUTH_TLS +int eap_server_unauth_tls_register(void) +{ + struct eap_method *eap; + int ret; + + eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, + EAP_VENDOR_UNAUTH_TLS, + EAP_VENDOR_TYPE_UNAUTH_TLS, + "UNAUTH-TLS"); + if (eap == NULL) + return -1; + + eap->init = eap_unauth_tls_init; + eap->reset = eap_tls_reset; + eap->buildReq = eap_tls_buildReq; + eap->check = eap_tls_check; + eap->process = eap_tls_process; + eap->isDone = eap_tls_isDone; + eap->getKey = eap_tls_getKey; + eap->isSuccess = eap_tls_isSuccess; + eap->get_emsk = eap_tls_get_emsk; + + ret = eap_server_method_register(eap); + if (ret) + eap_server_method_free(eap); + return ret; +} +#endif /* EAP_SERVER_UNAUTH_TLS */ diff --git a/contrib/wpa/src/eap_server/eap_server_tls_common.c b/contrib/wpa/src/eap_server/eap_server_tls_common.c index 625ff52..9efb5b2 100644 --- a/contrib/wpa/src/eap_server/eap_server_tls_common.c +++ b/contrib/wpa/src/eap_server/eap_server_tls_common.c @@ -2,14 +2,8 @@ * EAP-TLS/PEAP/TTLS/FAST server common functions * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -24,6 +18,18 @@ static void eap_server_tls_free_in_buf(struct eap_ssl_data *data); +struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, + u8 code, u8 identifier) +{ + if (type == EAP_UNAUTH_TLS_TYPE) + return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, + EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, + code, identifier); + return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, + identifier); +} + + int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, int verify_peer) { @@ -45,8 +51,7 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, return -1; } - /* TODO: make this configurable */ - data->tls_out_limit = 1398; + data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398; if (data->phase2) { /* Limit the fragment size in the inner TLS authentication * since the outer authentication with EAP-PEAP does not yet @@ -95,9 +100,9 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, os_memcpy(rnd + keys.client_random_len, keys.server_random, keys.server_random_len); - if (tls_prf(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, 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; os_free(rnd); @@ -138,8 +143,7 @@ struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) plen += 4; - req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen, - EAP_CODE_REQUEST, id); + req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id); if (req == NULL) return NULL; @@ -175,8 +179,7 @@ struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version) { struct wpabuf *req; - req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST, - id); + req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id); if (req == NULL) return NULL; wpa_printf(MSG_DEBUG, "SSL: Building ACK"); @@ -294,6 +297,13 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, tls_msg_len); *pos += 4; *left -= 4; + + if (*left > tls_msg_len) { + wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " + "bytes) smaller than this fragment (%d " + "bytes)", (int) tls_msg_len, (int) *left); + return -1; + } } wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x " @@ -374,7 +384,13 @@ int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, size_t left; int ret, res = 0; - pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left); + if (eap_type == EAP_UNAUTH_TLS_TYPE) + pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, + EAP_VENDOR_TYPE_UNAUTH_TLS, respData, + &left); + else + pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, + &left); if (pos == NULL || left < 1) return 0; /* Should not happen - frame already validated */ flags = *pos++; diff --git a/contrib/wpa/src/eap_server/eap_server_tnc.c b/contrib/wpa/src/eap_server/eap_server_tnc.c index f3b70ed..67a3dfa 100644 --- a/contrib/wpa/src/eap_server/eap_server_tnc.c +++ b/contrib/wpa/src/eap_server/eap_server_tnc.c @@ -2,20 +2,13 @@ * EAP server method: EAP-TNC (Trusted Network Connect) * Copyright (c) 2007-2010, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" -#include "base64.h" #include "eap_i.h" #include "tncs.h" @@ -91,7 +84,8 @@ static void * eap_tnc_init(struct eap_sm *sm) return NULL; } - data->fragment_size = 1300; + data->fragment_size = sm->fragment_size > 100 ? + sm->fragment_size - 98 : 1300; return data; } diff --git a/contrib/wpa/src/eap_server/eap_server_ttls.c b/contrib/wpa/src/eap_server/eap_server_ttls.c index 702c50c..647bd2f 100644 --- a/contrib/wpa/src/eap_server/eap_server_ttls.c +++ b/contrib/wpa/src/eap_server/eap_server_ttls.c @@ -1,15 +1,9 @@ /* * hostapd / EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -24,16 +18,7 @@ #include "eap_common/eap_ttls.h" -/* Maximum supported TTLS version - * 0 = RFC 5281 - * 1 = draft-funk-eap-ttls-v1-00.txt - */ -#ifndef EAP_TTLS_VERSION -#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ -#endif /* EAP_TTLS_VERSION */ - - -#define MSCHAPV2_KEY_LEN 16 +#define EAP_TTLS_VERSION 0 static void eap_ttls_reset(struct eap_sm *sm, void *priv); @@ -43,17 +28,15 @@ struct eap_ttls_data { struct eap_ssl_data ssl; enum { START, PHASE1, PHASE2_START, PHASE2_METHOD, - PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE + PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE } state; int ttls_version; - int force_version; const struct eap_method *phase2_method; void *phase2_priv; int mschapv2_resp_ok; u8 mschapv2_auth_response[20]; u8 mschapv2_ident; - int tls_ia_configured; struct wpabuf *pending_phase2_eap_resp; int tnc_started; }; @@ -72,8 +55,6 @@ static const char * eap_ttls_state_txt(int state) return "PHASE2_METHOD"; case PHASE2_MSCHAPV2_RESP: return "PHASE2_MSCHAPV2_RESP"; - case PHASE_FINISHED: - return "PHASE_FINISHED"; case SUCCESS: return "SUCCESS"; case FAILURE: @@ -111,7 +92,8 @@ static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, } avp->avp_code = host_to_be32(avp_code); - avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len)); + avp->avp_length = host_to_be32(((u32) flags << 24) | + ((u32) (hdrlen + len))); return avphdr + hdrlen; } @@ -320,54 +302,8 @@ fail: static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, struct eap_ttls_data *data, size_t len) { - struct tls_keys keys; - u8 *challenge, *rnd; - - if (data->ttls_version == 0) { - return eap_server_tls_derive_key(sm, &data->ssl, - "ttls challenge", len); - } - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive " - "implicit challenge"); - return NULL; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - challenge = os_malloc(len); - if (rnd == NULL || challenge == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " - "challenge derivation"); - os_free(rnd); - os_free(challenge); - return NULL; - } - os_memcpy(rnd, keys.server_random, keys.server_random_len); - os_memcpy(rnd + keys.server_random_len, keys.client_random, - keys.client_random_len); - - if (tls_prf(keys.inner_secret, keys.inner_secret_len, - "inner application challenge", rnd, - keys.client_random_len + keys.server_random_len, - challenge, len)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " - "challenge"); - os_free(rnd); - os_free(challenge); - return NULL; - } - - os_free(rnd); - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", - challenge, len); - - return challenge; + return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge", + len); } @@ -379,27 +315,8 @@ static void * eap_ttls_init(struct eap_sm *sm) if (data == NULL) return NULL; data->ttls_version = EAP_TTLS_VERSION; - data->force_version = -1; - if (sm->user && sm->user->force_version >= 0) { - data->force_version = sm->user->force_version; - wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d", - data->force_version); - data->ttls_version = data->force_version; - } data->state = START; - if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && - data->ttls_version > 0) { - if (data->force_version > 0) { - wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " - "TLS library does not support TLS/IA.", - data->force_version); - eap_ttls_reset(sm, data); - return NULL; - } - data->ttls_version = 0; - } - if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); eap_ttls_reset(sm, data); @@ -516,14 +433,6 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2( } -static struct wpabuf * eap_ttls_build_phase_finished( - struct eap_sm *sm, struct eap_ttls_data *data, int final) -{ - return tls_connection_ia_send_phase_finished(sm->ssl_ctx, - data->ssl.conn, final); -} - - static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) { struct eap_ttls_data *data = priv; @@ -559,11 +468,6 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) data->ssl.tls_out_pos = 0; data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data); break; - case PHASE_FINISHED: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1); - break; default: wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", __func__, data->state); @@ -591,37 +495,6 @@ static Boolean eap_ttls_check(struct eap_sm *sm, void *priv, } -static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *key, size_t key_len) -{ - u8 *buf; - size_t buf_len; - int ret; - - if (key) { - buf_len = 2 + key_len; - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - WPA_PUT_BE16(buf, key_len); - os_memcpy(buf + 2, key, key_len); - } else { - buf = NULL; - buf_len = 0; - } - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " - "secret permutation", buf, buf_len); - ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, - data->ssl.conn, - buf, buf_len); - os_free(buf); - - return ret; -} - - static void eap_ttls_process_phase2_pap(struct eap_sm *sm, struct eap_ttls_data *data, const u8 *user_password, @@ -644,8 +517,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, data->ttls_version > 0 ? PHASE_FINISHED : - SUCCESS); + eap_ttls_state(data, SUCCESS); } @@ -701,8 +573,7 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm, if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password"); - eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : - SUCCESS); + eap_ttls_state(data, SUCCESS); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password"); eap_ttls_state(data, FAILURE); @@ -762,8 +633,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response"); - eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : - SUCCESS); + eap_ttls_state(data, SUCCESS); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response"); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received", @@ -804,6 +674,13 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, return; } + if (sm->identity == NULL) { + wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user identity " + "known"); + eap_ttls_state(data, FAILURE); + return; + } + /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ @@ -863,30 +740,6 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct " "NT-Response"); data->mschapv2_resp_ok = 1; - if (data->ttls_version > 0) { - const u8 *pw_hash; - u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16]; - u8 session_key[2 * MSCHAPV2_KEY_LEN]; - - if (sm->user->password_hash) - pw_hash = sm->user->password; - else { - nt_password_hash(sm->user->password, - sm->user->password_len, - pw_hash_buf); - pw_hash = pw_hash_buf; - } - hash_nt_password_hash(pw_hash, pw_hash_hash); - get_master_key(pw_hash_hash, nt_response, master_key); - get_asymetric_start_key(master_key, session_key, - MSCHAPV2_KEY_LEN, 0, 0); - get_asymetric_start_key(master_key, - session_key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 1, 0); - eap_ttls_ia_permute_inner_secret(sm, data, - session_key, - sizeof(session_key)); - } if (sm->user->password_hash) { generate_authenticator_response_pwhash( @@ -1030,17 +883,7 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm, } break; case PHASE2_METHOD: - if (data->ttls_version > 0) { - if (m->getKey) { - u8 *key; - size_t key_len; - key = m->getKey(sm, priv, &key_len); - eap_ttls_ia_permute_inner_secret(sm, data, - key, key_len); - } - eap_ttls_state(data, PHASE_FINISHED); - } else - eap_ttls_state(data, SUCCESS); + eap_ttls_state(data, SUCCESS); break; case FAILURE: break; @@ -1130,23 +973,6 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, return; } - if (data->state == PHASE_FINISHED) { - if (wpabuf_len(in_decrypted) == 0 && - tls_connection_ia_final_phase_finished(sm->ssl_ctx, - data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished " - "received"); - eap_ttls_state(data, SUCCESS); - } else { - wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid " - "FinalPhaseFinished"); - eap_ttls_state(data, FAILURE); - } - - wpabuf_free(in_decrypted); - return; - } - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", in_decrypted); @@ -1160,11 +986,12 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, if (parse.user_name) { os_free(sm->identity); sm->identity = os_malloc(parse.user_name_len); - if (sm->identity) { - os_memcpy(sm->identity, parse.user_name, - parse.user_name_len); - sm->identity_len = parse.user_name_len; + if (sm->identity == NULL) { + eap_ttls_state(data, FAILURE); + goto done; } + os_memcpy(sm->identity, parse.user_name, parse.user_name_len); + sm->identity_len = parse.user_name_len; if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1) != 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not " @@ -1245,15 +1072,6 @@ static int eap_ttls_process_version(struct eap_sm *sm, void *priv, data->ttls_version = peer_version; } - if (data->ttls_version > 0 && !data->tls_ia_configured) { - if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable " - "TLS/IA"); - return -1; - } - data->tls_ia_configured = 1; - } - return 0; } @@ -1270,7 +1088,6 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, break; case PHASE2_START: case PHASE2_METHOD: - case PHASE_FINISHED: eap_ttls_process_phase2(sm, data, data->ssl.tls_in); eap_ttls_start_tnc(sm, data); break; @@ -1279,8 +1096,7 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " "acknowledged response"); - eap_ttls_state(data, data->ttls_version > 0 ? - PHASE_FINISHED : SUCCESS); + eap_ttls_state(data, SUCCESS); } else if (!data->mschapv2_resp_ok) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " "acknowledged error"); @@ -1321,54 +1137,6 @@ static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv) } -static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - struct tls_keys keys; - u8 *rnd, *key; - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive keying " - "material"); - return NULL; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - key = os_malloc(EAP_TLS_KEY_LEN); - if (rnd == NULL || key == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); - os_free(rnd); - os_free(key); - return NULL; - } - 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(keys.inner_secret, keys.inner_secret_len, - "ttls v1 keying material", rnd, keys.client_random_len + - keys.server_random_len, key, EAP_TLS_KEY_LEN)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); - os_free(rnd); - os_free(key); - return NULL; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", - rnd, keys.client_random_len + keys.server_random_len); - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", - keys.inner_secret, keys.inner_secret_len); - - os_free(rnd); - - return key; -} - - static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_ttls_data *data = priv; @@ -1377,14 +1145,9 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) if (data->state != SUCCESS) return NULL; - if (data->ttls_version == 0) { - eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "ttls keying material", - EAP_TLS_KEY_LEN); - } else { - eapKeyData = eap_ttls_v1_derive_key(sm, data); - } - + eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, + "ttls keying material", + EAP_TLS_KEY_LEN); if (eapKeyData) { *len = EAP_TLS_KEY_LEN; wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", diff --git a/contrib/wpa/src/eap_server/eap_server_vendor_test.c b/contrib/wpa/src/eap_server/eap_server_vendor_test.c index 0dd0aca..30f600d 100644 --- a/contrib/wpa/src/eap_server/eap_server_vendor_test.c +++ b/contrib/wpa/src/eap_server/eap_server_vendor_test.c @@ -2,14 +2,8 @@ * hostapd / Test method for vendor specific (expanded) EAP type * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -18,7 +12,7 @@ #include "eap_i.h" -#define EAP_VENDOR_ID 0xfffefd +#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP #define EAP_VENDOR_TYPE 0xfcfbfaf9 diff --git a/contrib/wpa/src/eap_server/eap_server_wsc.c b/contrib/wpa/src/eap_server/eap_server_wsc.c index 77cf9e2..97ec0c0 100644 --- a/contrib/wpa/src/eap_server/eap_server_wsc.c +++ b/contrib/wpa/src/eap_server/eap_server_wsc.c @@ -2,14 +2,8 @@ * EAP-WSC server for Wi-Fi Protected Setup * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -18,6 +12,7 @@ #include "eloop.h" #include "eap_i.h" #include "eap_common/eap_wsc_common.h" +#include "p2p/p2p.h" #include "wps/wps.h" @@ -135,14 +130,22 @@ static void * eap_wsc_init(struct eap_sm *sm) } cfg.assoc_wps_ie = sm->assoc_wps_ie; cfg.peer_addr = sm->peer_addr; - if (0 /* TODO: could provide option for forcing PSK format */) - cfg.use_psk_key = 1; +#ifdef CONFIG_P2P + if (sm->assoc_p2p_ie) { + wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P " + "client"); + cfg.use_psk_key = 1; + cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); + } +#endif /* CONFIG_P2P */ + cfg.pbc_in_m1 = sm->pbc_in_m1; data->wps = wps_init(&cfg); if (data->wps == NULL) { os_free(data); return NULL; } - data->fragment_size = WSC_FRAGMENT_SIZE; + data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : + WSC_FRAGMENT_SIZE; return data; } diff --git a/contrib/wpa/src/eap_server/eap_sim_db.c b/contrib/wpa/src/eap_server/eap_sim_db.c index aba919a..257013e 100644 --- a/contrib/wpa/src/eap_server/eap_sim_db.c +++ b/contrib/wpa/src/eap_server/eap_sim_db.c @@ -1,15 +1,9 @@ /* * hostapd / EAP-SIM database/authenticator gateway - * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. * * This is an example implementation of the EAP-SIM/AKA database/authentication * gateway interface that is using an external program as an SS7 gateway to @@ -23,23 +17,25 @@ #include "includes.h" #include <sys/un.h> +#ifdef CONFIG_SQLITE +#include <sqlite3.h> +#endif /* CONFIG_SQLITE */ #include "common.h" +#include "crypto/random.h" #include "eap_common/eap_sim_common.h" #include "eap_server/eap_sim_db.h" #include "eloop.h" struct eap_sim_pseudonym { struct eap_sim_pseudonym *next; - u8 *identity; - size_t identity_len; - char *pseudonym; + char *permanent; /* permanent username */ + char *pseudonym; /* pseudonym username */ }; struct eap_sim_db_pending { struct eap_sim_db_pending *next; - u8 imsi[20]; - size_t imsi_len; + char imsi[20]; enum { PENDING, SUCCESS, FAILURE } state; void *cb_session_ctx; struct os_time timestamp; @@ -71,19 +67,316 @@ struct eap_sim_db_data { struct eap_sim_pseudonym *pseudonyms; struct eap_sim_reauth *reauths; struct eap_sim_db_pending *pending; +#ifdef CONFIG_SQLITE + sqlite3 *sqlite_db; + char db_tmp_identity[100]; + char db_tmp_pseudonym_str[100]; + struct eap_sim_pseudonym db_tmp_pseudonym; + struct eap_sim_reauth db_tmp_reauth; +#endif /* CONFIG_SQLITE */ }; +#ifdef CONFIG_SQLITE + +static int db_table_exists(sqlite3 *db, const char *name) +{ + char cmd[128]; + os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name); + return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK; +} + + +static int db_table_create_pseudonym(sqlite3 *db) +{ + char *err = NULL; + const char *sql = + "CREATE TABLE pseudonyms(" + " permanent CHAR(21) PRIMARY KEY," + " pseudonym CHAR(21) NOT NULL" + ");"; + + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for " + "pseudonym information"); + if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) { + wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); + sqlite3_free(err); + return -1; + } + + return 0; +} + + +static int db_table_create_reauth(sqlite3 *db) +{ + char *err = NULL; + const char *sql = + "CREATE TABLE reauth(" + " permanent CHAR(21) PRIMARY KEY," + " reauth_id CHAR(21) NOT NULL," + " counter INTEGER," + " mk CHAR(40)," + " k_encr CHAR(32)," + " k_aut CHAR(64)," + " k_re CHAR(64)" + ");"; + + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for " + "reauth information"); + if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) { + wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); + sqlite3_free(err); + return -1; + } + + return 0; +} + + +static sqlite3 * db_open(const char *db_file) +{ + sqlite3 *db; + + if (sqlite3_open(db_file, &db)) { + wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database " + "%s: %s", db_file, sqlite3_errmsg(db)); + sqlite3_close(db); + return NULL; + } + + if (!db_table_exists(db, "pseudonyms") && + db_table_create_pseudonym(db) < 0) { + sqlite3_close(db); + return NULL; + } + + if (!db_table_exists(db, "reauth") && + db_table_create_reauth(db) < 0) { + sqlite3_close(db); + return NULL; + } + + return db; +} + + +static int valid_db_string(const char *str) +{ + const char *pos = str; + while (*pos) { + if ((*pos < '0' || *pos > '9') && + (*pos < 'a' || *pos > 'f')) + return 0; + pos++; + } + return 1; +} + + +static int db_add_pseudonym(struct eap_sim_db_data *data, + const char *permanent, char *pseudonym) +{ + char cmd[128]; + char *err = NULL; + + if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) { + os_free(pseudonym); + return -1; + } + + os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms " + "(permanent, pseudonym) VALUES ('%s', '%s');", + permanent, pseudonym); + os_free(pseudonym); + if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK) + { + wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); + sqlite3_free(err); + return -1; + } + + return 0; +} + + +static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[]) +{ + struct eap_sim_db_data *data = ctx; + int i; + + for (i = 0; i < argc; i++) { + if (os_strcmp(col[i], "permanent") == 0 && argv[i]) { + os_strlcpy(data->db_tmp_identity, argv[i], + sizeof(data->db_tmp_identity)); + } + } + + return 0; +} + + +static char * +db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym) +{ + char cmd[128]; + + if (!valid_db_string(pseudonym)) + return NULL; + os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity)); + os_snprintf(cmd, sizeof(cmd), + "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';", + pseudonym); + if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) != + SQLITE_OK) + return NULL; + if (data->db_tmp_identity[0] == '\0') + return NULL; + return data->db_tmp_identity; +} + + +static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent, + char *reauth_id, u16 counter, const u8 *mk, + const u8 *k_encr, const u8 *k_aut, const u8 *k_re) +{ + char cmd[2000], *pos, *end; + char *err = NULL; + + if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) { + os_free(reauth_id); + return -1; + } + + pos = cmd; + end = pos + sizeof(cmd); + pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth " + "(permanent, reauth_id, counter%s%s%s%s) " + "VALUES ('%s', '%s', %u", + mk ? ", mk" : "", + k_encr ? ", k_encr" : "", + k_aut ? ", k_aut" : "", + k_re ? ", k_re" : "", + permanent, reauth_id, counter); + os_free(reauth_id); + + if (mk) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + if (k_encr) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, k_encr, + EAP_SIM_K_ENCR_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + if (k_aut) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, k_aut, + EAP_AKA_PRIME_K_AUT_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + if (k_re) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, k_re, + EAP_AKA_PRIME_K_RE_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + os_snprintf(pos, end - pos, ");"); + + if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK) + { + wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); + sqlite3_free(err); + return -1; + } + + return 0; +} + + +static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[]) +{ + struct eap_sim_db_data *data = ctx; + int i; + struct eap_sim_reauth *reauth = &data->db_tmp_reauth; + + for (i = 0; i < argc; i++) { + if (os_strcmp(col[i], "permanent") == 0 && argv[i]) { + os_strlcpy(data->db_tmp_identity, argv[i], + sizeof(data->db_tmp_identity)); + reauth->permanent = data->db_tmp_identity; + } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) { + reauth->counter = atoi(argv[i]); + } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk)); + } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->k_encr, + sizeof(reauth->k_encr)); + } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->k_aut, + sizeof(reauth->k_aut)); + } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->k_re, + sizeof(reauth->k_re)); + } + } + + return 0; +} + + +static struct eap_sim_reauth * +db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id) +{ + char cmd[256]; + + if (!valid_db_string(reauth_id)) + return NULL; + os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth)); + os_strlcpy(data->db_tmp_pseudonym_str, reauth_id, + sizeof(data->db_tmp_pseudonym_str)); + data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str; + os_snprintf(cmd, sizeof(cmd), + "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id); + if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) != + SQLITE_OK) + return NULL; + if (data->db_tmp_reauth.permanent == NULL) + return NULL; + return &data->db_tmp_reauth; +} + + +static void db_remove_reauth(struct eap_sim_db_data *data, + struct eap_sim_reauth *reauth) +{ + char cmd[256]; + + if (!valid_db_string(reauth->permanent)) + return; + os_snprintf(cmd, sizeof(cmd), + "DELETE FROM reauth WHERE permanent='%s';", + reauth->permanent); + sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL); +} + +#endif /* CONFIG_SQLITE */ + + static struct eap_sim_db_pending * -eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi, - size_t imsi_len, int aka) +eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka) { struct eap_sim_db_pending *entry, *prev = NULL; entry = data->pending; while (entry) { - if (entry->aka == aka && entry->imsi_len == imsi_len && - os_memcmp(entry->imsi, imsi, imsi_len) == 0) { + if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) { if (prev) prev->next = entry->next; else @@ -118,7 +411,7 @@ static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data, * (IMSI = ASCII string, Kc/SRES/RAND = hex string) */ - entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0); + entry = eap_sim_db_get_pending(data, imsi, 0); if (entry == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " "received message found"); @@ -196,7 +489,7 @@ static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data, * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string) */ - entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1); + entry = eap_sim_db_get_pending(data, imsi, 1); if (entry == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " "received message found"); @@ -345,6 +638,7 @@ static int eap_sim_db_open_socket(struct eap_sim_db_data *data) addr.sun_family = AF_UNIX; os_snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/eap_sim_db_%d-%d", getpid(), counter++); + os_free(data->local_sock); data->local_sock = os_strdup(addr.sun_path); if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind(eap_sim_db)"); @@ -394,11 +688,13 @@ static void eap_sim_db_close_socket(struct eap_sim_db_data *data) * @ctx: Context pointer for get_complete_cb * Returns: Pointer to a private data structure or %NULL on failure */ -void * eap_sim_db_init(const char *config, - void (*get_complete_cb)(void *ctx, void *session_ctx), - void *ctx) +struct eap_sim_db_data * +eap_sim_db_init(const char *config, + void (*get_complete_cb)(void *ctx, void *session_ctx), + void *ctx) { struct eap_sim_db_data *data; + char *pos; data = os_zalloc(sizeof(*data)); if (data == NULL) @@ -410,10 +706,23 @@ void * eap_sim_db_init(const char *config, data->fname = os_strdup(config); if (data->fname == NULL) goto fail; + pos = os_strstr(data->fname, " db="); + if (pos) { + *pos = '\0'; +#ifdef CONFIG_SQLITE + pos += 4; + data->sqlite_db = db_open(pos); + if (data->sqlite_db == NULL) + goto fail; +#endif /* CONFIG_SQLITE */ + } if (os_strncmp(data->fname, "unix:", 5) == 0) { - if (eap_sim_db_open_socket(data)) - goto fail; + if (eap_sim_db_open_socket(data)) { + wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database " + "connection not available - will retry " + "later"); + } } return data; @@ -428,7 +737,7 @@ fail: static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p) { - os_free(p->identity); + os_free(p->permanent); os_free(p->pseudonym); os_free(p); } @@ -436,7 +745,7 @@ static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p) static void eap_sim_db_free_reauth(struct eap_sim_reauth *r) { - os_free(r->identity); + os_free(r->permanent); os_free(r->reauth_id); os_free(r); } @@ -453,6 +762,13 @@ void eap_sim_db_deinit(void *priv) struct eap_sim_reauth *r, *prevr; struct eap_sim_db_pending *pending, *prev_pending; +#ifdef CONFIG_SQLITE + if (data->sqlite_db) { + sqlite3_close(data->sqlite_db); + data->sqlite_db = NULL; + } +#endif /* CONFIG_SQLITE */ + eap_sim_db_close_socket(data); os_free(data->fname); @@ -519,9 +835,8 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data) /** * eap_sim_db_get_gsm_triplets - Get GSM triplets - * @priv: Private data pointer from eap_sim_db_init() - * @identity: User name identity - * @identity_len: Length of identity in bytes + * @data: Private data pointer from eap_sim_db_init() + * @username: Permanent username (prefix | IMSI) * @max_chal: Maximum number of triplets * @_rand: Buffer for RAND values * @kc: Buffer for Kc values @@ -533,9 +848,6 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data) * callback function registered with eap_sim_db_init() will be called once the * results become available. * - * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in - * ASCII format. - * * When using an external server for GSM triplets, this function can always * start a request and return EAP_SIM_DB_PENDING immediately if authentication * triplets are not available. Once the triplets are received, callback @@ -544,39 +856,28 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data) * function will then be called again and the newly received triplets will then * be given to the caller. */ -int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, - size_t identity_len, int max_chal, +int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data, + const char *username, int max_chal, u8 *_rand, u8 *kc, u8 *sres, void *cb_session_ctx) { - struct eap_sim_db_data *data = priv; struct eap_sim_db_pending *entry; int len, ret; - size_t i; char msg[40]; + const char *imsi; + size_t imsi_len; - if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", - identity, identity_len); + if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX || + username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) { + wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", + username); return EAP_SIM_DB_FAILURE; } - identity++; - identity_len--; - for (i = 0; i < identity_len; i++) { - if (identity[i] == '@') { - identity_len = i; - break; - } - } - if (identity_len + 1 > sizeof(entry->imsi)) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", - identity, identity_len); - return EAP_SIM_DB_FAILURE; - } - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI", - identity, identity_len); + imsi = username + 1; + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'", + imsi); - entry = eap_sim_db_get_pending(data, identity, identity_len, 0); + entry = eap_sim_db_get_pending(data, imsi, 0); if (entry) { int num_chal; if (entry->state == FAILURE) { @@ -611,18 +912,19 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, return EAP_SIM_DB_FAILURE; } + imsi_len = os_strlen(imsi); len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH "); - if (len < 0 || len + identity_len >= sizeof(msg)) + if (len < 0 || len + imsi_len >= sizeof(msg)) return EAP_SIM_DB_FAILURE; - os_memcpy(msg + len, identity, identity_len); - len += identity_len; + os_memcpy(msg + len, imsi, imsi_len); + len += imsi_len; ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal); if (ret < 0 || (size_t) ret >= sizeof(msg) - len) return EAP_SIM_DB_FAILURE; len += ret; - wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication " - "data for IMSI", identity, identity_len); + wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication " + "data for IMSI '%s'", imsi); if (eap_sim_db_send(data, msg, len) < 0) return EAP_SIM_DB_FAILURE; @@ -631,8 +933,7 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, return EAP_SIM_DB_FAILURE; os_get_time(&entry->timestamp); - os_memcpy(entry->imsi, identity, identity_len); - entry->imsi_len = identity_len; + os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); entry->cb_session_ctx = cb_session_ctx; entry->state = PENDING; eap_sim_db_add_pending(data, entry); @@ -642,195 +943,12 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, } -static struct eap_sim_pseudonym * -eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity, - size_t identity_len) -{ - char *pseudonym; - size_t len; - struct eap_sim_pseudonym *p; - - if (identity_len == 0 || - (identity[0] != EAP_SIM_PSEUDONYM_PREFIX && - identity[0] != EAP_AKA_PSEUDONYM_PREFIX)) - return NULL; - - /* Remove possible realm from identity */ - len = 0; - while (len < identity_len) { - if (identity[len] == '@') - break; - len++; - } - - pseudonym = os_malloc(len + 1); - if (pseudonym == NULL) - return NULL; - os_memcpy(pseudonym, identity, len); - pseudonym[len] = '\0'; - - p = data->pseudonyms; - while (p) { - if (os_strcmp(p->pseudonym, pseudonym) == 0) - break; - p = p->next; - } - - os_free(pseudonym); - - return p; -} - - -static struct eap_sim_pseudonym * -eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity, - size_t identity_len) -{ - struct eap_sim_pseudonym *p; - - if (identity_len == 0 || - (identity[0] != EAP_SIM_PERMANENT_PREFIX && - identity[0] != EAP_AKA_PERMANENT_PREFIX)) - return NULL; - - p = data->pseudonyms; - while (p) { - if (identity_len == p->identity_len && - os_memcmp(p->identity, identity, identity_len) == 0) - break; - p = p->next; - } - - return p; -} - - -static struct eap_sim_reauth * -eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity, - size_t identity_len) -{ - char *reauth_id; - size_t len; - struct eap_sim_reauth *r; - - if (identity_len == 0 || - (identity[0] != EAP_SIM_REAUTH_ID_PREFIX && - identity[0] != EAP_AKA_REAUTH_ID_PREFIX)) - return NULL; - - /* Remove possible realm from identity */ - len = 0; - while (len < identity_len) { - if (identity[len] == '@') - break; - len++; - } - - reauth_id = os_malloc(len + 1); - if (reauth_id == NULL) - return NULL; - os_memcpy(reauth_id, identity, len); - reauth_id[len] = '\0'; - - r = data->reauths; - while (r) { - if (os_strcmp(r->reauth_id, reauth_id) == 0) - break; - r = r->next; - } - - os_free(reauth_id); - - return r; -} - - -static struct eap_sim_reauth * -eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity, - size_t identity_len) -{ - struct eap_sim_pseudonym *p; - struct eap_sim_reauth *r; - - if (identity_len == 0) - return NULL; - - p = eap_sim_db_get_pseudonym(data, identity, identity_len); - if (p == NULL) - p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); - if (p) { - identity = p->identity; - identity_len = p->identity_len; - } - - r = data->reauths; - while (r) { - if (identity_len == r->identity_len && - os_memcmp(r->identity, identity, identity_len) == 0) - break; - r = r->next; - } - - return r; -} - - -/** - * eap_sim_db_identity_known - Verify whether the given identity is known - * @priv: Private data pointer from eap_sim_db_init() - * @identity: User name identity - * @identity_len: Length of identity in bytes - * Returns: 0 if the user is found or -1 on failure - * - * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the - * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id. - */ -int eap_sim_db_identity_known(void *priv, const u8 *identity, - size_t identity_len) -{ - struct eap_sim_db_data *data = priv; - - if (identity == NULL || identity_len < 2) - return -1; - - if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX || - identity[0] == EAP_AKA_PSEUDONYM_PREFIX) { - struct eap_sim_pseudonym *p = - eap_sim_db_get_pseudonym(data, identity, identity_len); - return p ? 0 : -1; - } - - if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX || - identity[0] == EAP_AKA_REAUTH_ID_PREFIX) { - struct eap_sim_reauth *r = - eap_sim_db_get_reauth(data, identity, identity_len); - return r ? 0 : -1; - } - - if (identity[0] != EAP_SIM_PERMANENT_PREFIX && - identity[0] != EAP_AKA_PERMANENT_PREFIX) { - /* Unknown identity prefix */ - return -1; - } - - /* TODO: Should consider asking HLR/AuC gateway whether this permanent - * identity is known. If it is, EAP-SIM/AKA can skip identity request. - * In case of EAP-AKA, this would reduce number of needed round-trips. - * Ideally, this would be done with one wait, i.e., just request - * authentication data and store it for the next use. This would then - * need to use similar pending-request functionality as the normal - * request for authentication data at later phase. - */ - return -1; -} - - static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) { char *id, *pos, *end; u8 buf[10]; - if (os_get_random(buf, sizeof(buf))) + if (random_get_bytes(buf, sizeof(buf))) return NULL; id = os_malloc(sizeof(buf) * 2 + 2); if (id == NULL) @@ -847,8 +965,8 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) /** * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym - * @priv: Private data pointer from eap_sim_db_init() - * @aka: Using EAP-AKA instead of EAP-SIM + * @data: Private data pointer from eap_sim_db_init() + * @method: EAP method (SIM/AKA/AKA') * Returns: Next pseudonym (allocated string) or %NULL on failure * * This function is used to generate a pseudonym for EAP-SIM. The returned @@ -856,18 +974,31 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) * with eap_sim_db_add_pseudonym() once the authentication has been completed * successfully. Caller is responsible for freeing the returned buffer. */ -char * eap_sim_db_get_next_pseudonym(void *priv, int aka) +char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data, + enum eap_sim_db_method method) { - struct eap_sim_db_data *data = priv; - return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX : - EAP_SIM_PSEUDONYM_PREFIX); + char prefix = EAP_SIM_REAUTH_ID_PREFIX; + + switch (method) { + case EAP_SIM_DB_SIM: + prefix = EAP_SIM_PSEUDONYM_PREFIX; + break; + case EAP_SIM_DB_AKA: + prefix = EAP_AKA_PSEUDONYM_PREFIX; + break; + case EAP_SIM_DB_AKA_PRIME: + prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX; + break; + } + + return eap_sim_db_get_next(data, prefix); } /** * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id - * @priv: Private data pointer from eap_sim_db_init() - * @aka: Using EAP-AKA instead of EAP-SIM + * @data: Private data pointer from eap_sim_db_init() + * @method: EAP method (SIM/AKA/AKA') * Returns: Next reauth_id (allocated string) or %NULL on failure * * This function is used to generate a fast re-authentication identity for @@ -876,19 +1007,31 @@ char * eap_sim_db_get_next_pseudonym(void *priv, int aka) * has been completed successfully. Caller is responsible for freeing the * returned buffer. */ -char * eap_sim_db_get_next_reauth_id(void *priv, int aka) +char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data, + enum eap_sim_db_method method) { - struct eap_sim_db_data *data = priv; - return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX : - EAP_SIM_REAUTH_ID_PREFIX); + char prefix = EAP_SIM_REAUTH_ID_PREFIX; + + switch (method) { + case EAP_SIM_DB_SIM: + prefix = EAP_SIM_REAUTH_ID_PREFIX; + break; + case EAP_SIM_DB_AKA: + prefix = EAP_AKA_REAUTH_ID_PREFIX; + break; + case EAP_SIM_DB_AKA_PRIME: + prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX; + break; + } + + return eap_sim_db_get_next(data, prefix); } /** * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym - * @priv: Private data pointer from eap_sim_db_init() - * @identity: Identity of the user (may be permanent identity or pseudonym) - * @identity_len: Length of identity + * @data: Private data pointer from eap_sim_db_init() + * @permanent: Permanent username * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer, * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not * free it. @@ -897,20 +1040,22 @@ char * eap_sim_db_get_next_reauth_id(void *priv, int aka) * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is * responsible of freeing pseudonym buffer once it is not needed anymore. */ -int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, - size_t identity_len, char *pseudonym) +int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data, + const char *permanent, char *pseudonym) { - struct eap_sim_db_data *data = priv; struct eap_sim_pseudonym *p; - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity", - identity, identity_len); - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym); + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent " + "username '%s'", pseudonym, permanent); /* TODO: could store last two pseudonyms */ - p = eap_sim_db_get_pseudonym(data, identity, identity_len); - if (p == NULL) - p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); - +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_add_pseudonym(data, permanent, pseudonym); +#endif /* CONFIG_SQLITE */ + for (p = data->pseudonyms; p; p = p->next) { + if (os_strcmp(permanent, p->permanent) == 0) + break; + } if (p) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " "pseudonym: %s", p->pseudonym); @@ -926,14 +1071,12 @@ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, } p->next = data->pseudonyms; - p->identity = os_malloc(identity_len); - if (p->identity == NULL) { + p->permanent = os_strdup(permanent); + if (p->permanent == NULL) { os_free(p); os_free(pseudonym); return -1; } - os_memcpy(p->identity, identity, identity_len); - p->identity_len = identity_len; p->pseudonym = pseudonym; data->pseudonyms = p; @@ -943,18 +1086,16 @@ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, static struct eap_sim_reauth * -eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity, - size_t identity_len, char *reauth_id, u16 counter) +eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, + const char *permanent, + char *reauth_id, u16 counter) { struct eap_sim_reauth *r; - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity", - identity, identity_len); - wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id); - - r = eap_sim_db_get_reauth(data, identity, identity_len); - if (r == NULL) - r = eap_sim_db_get_reauth_id(data, identity, identity_len); + for (r = data->reauths; r; r = r->next) { + if (os_strcmp(r->permanent, permanent) == 0) + break; + } if (r) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " @@ -969,14 +1110,12 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity, } r->next = data->reauths; - r->identity = os_malloc(identity_len); - if (r->identity == NULL) { + r->permanent = os_strdup(permanent); + if (r->permanent == NULL) { os_free(r); os_free(reauth_id); return NULL; } - os_memcpy(r->identity, identity, identity_len); - r->identity_len = identity_len; r->reauth_id = reauth_id; data->reauths = r; wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry"); @@ -991,7 +1130,7 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity, /** * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry * @priv: Private data pointer from eap_sim_db_init() - * @identity: Identity of the user (may be permanent identity or pseudonym) + * @permanent: Permanent username * @identity_len: Length of identity * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not @@ -1004,20 +1143,24 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity, * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed * anymore. */ -int eap_sim_db_add_reauth(void *priv, const u8 *identity, - size_t identity_len, char *reauth_id, u16 counter, - const u8 *mk) +int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent, + char *reauth_id, u16 counter, const u8 *mk) { - struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r; - r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, - counter); + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent " + "identity '%s'", reauth_id, permanent); + +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_add_reauth(data, permanent, reauth_id, counter, mk, + NULL, NULL, NULL); +#endif /* CONFIG_SQLITE */ + r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter); if (r == NULL) return -1; os_memcpy(r->mk, mk, EAP_SIM_MK_LEN); - r->aka_prime = 0; return 0; } @@ -1026,9 +1169,8 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity, #ifdef EAP_SERVER_AKA_PRIME /** * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry - * @priv: Private data pointer from eap_sim_db_init() - * @identity: Identity of the user (may be permanent identity or pseudonym) - * @identity_len: Length of identity + * @data: Private data pointer from eap_sim_db_init() + * @permanent: Permanent username * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not * free it. @@ -1042,20 +1184,25 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity, * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed * anymore. */ -int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, - size_t identity_len, char *reauth_id, - u16 counter, const u8 *k_encr, const u8 *k_aut, - const u8 *k_re) +int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data, + const char *permanent, char *reauth_id, + u16 counter, const u8 *k_encr, + const u8 *k_aut, const u8 *k_re) { - struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r; - r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, - counter); + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent " + "identity '%s'", reauth_id, permanent); + +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_add_reauth(data, permanent, reauth_id, counter, NULL, + k_encr, k_aut, k_re); +#endif /* CONFIG_SQLITE */ + r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter); if (r == NULL) return -1; - r->aka_prime = 1; os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN); os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN); os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN); @@ -1067,66 +1214,75 @@ int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, /** * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity - * @priv: Private data pointer from eap_sim_db_init() - * @identity: Identity of the user (may be permanent identity or pseudonym) - * @identity_len: Length of identity - * @len: Buffer for length of the returned permanent identity - * Returns: Pointer to the permanent identity, or %NULL if not found + * @data: Private data pointer from eap_sim_db_init() + * @pseudonym: Pseudonym username + * Returns: Pointer to permanent username or %NULL if not found */ -const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity, - size_t identity_len, size_t *len) +const char * +eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym) { - struct eap_sim_db_data *data = priv; struct eap_sim_pseudonym *p; - if (identity == NULL) - return NULL; +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_get_pseudonym(data, pseudonym); +#endif /* CONFIG_SQLITE */ - p = eap_sim_db_get_pseudonym(data, identity, identity_len); - if (p == NULL) - p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); - if (p == NULL) - return NULL; + p = data->pseudonyms; + while (p) { + if (os_strcmp(p->pseudonym, pseudonym) == 0) + return p->permanent; + p = p->next; + } - *len = p->identity_len; - return p->identity; + return NULL; } /** * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry - * @priv: Private data pointer from eap_sim_db_init() - * @identity: Identity of the user (may be permanent identity, pseudonym, or - * reauth_id) - * @identity_len: Length of identity + * @data: Private data pointer from eap_sim_db_init() + * @reauth_id: Fast re-authentication username * Returns: Pointer to the re-auth entry, or %NULL if not found */ struct eap_sim_reauth * -eap_sim_db_get_reauth_entry(void *priv, const u8 *identity, - size_t identity_len) +eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data, + const char *reauth_id) { - struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r; - if (identity == NULL) - return NULL; - r = eap_sim_db_get_reauth(data, identity, identity_len); - if (r == NULL) - r = eap_sim_db_get_reauth_id(data, identity, identity_len); +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_get_reauth(data, reauth_id); +#endif /* CONFIG_SQLITE */ + + r = data->reauths; + while (r) { + if (os_strcmp(r->reauth_id, reauth_id) == 0) + break; + r = r->next; + } + return r; } /** * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry - * @priv: Private data pointer from eap_sim_db_init() + * @data: Private data pointer from eap_sim_db_init() * @reauth: Pointer to re-authentication entry from * eap_sim_db_get_reauth_entry() */ -void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) +void eap_sim_db_remove_reauth(struct eap_sim_db_data *data, + struct eap_sim_reauth *reauth) { - struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r, *prev = NULL; +#ifdef CONFIG_SQLITE + if (data->sqlite_db) { + db_remove_reauth(data, reauth); + return; + } +#endif /* CONFIG_SQLITE */ r = data->reauths; while (r) { if (r == reauth) { @@ -1145,9 +1301,8 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) /** * eap_sim_db_get_aka_auth - Get AKA authentication values - * @priv: Private data pointer from eap_sim_db_init() - * @identity: User name identity - * @identity_len: Length of identity in bytes + * @data: Private data pointer from eap_sim_db_init() + * @username: Permanent username (prefix | IMSI) * @_rand: Buffer for RAND value * @autn: Buffer for AUTN value * @ik: Buffer for IK value @@ -1160,9 +1315,6 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) * case, the callback function registered with eap_sim_db_init() will be * called once the results become available. * - * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in - * ASCII format. - * * When using an external server for AKA authentication, this function can * always start a request and return EAP_SIM_DB_PENDING immediately if * authentication triplets are not available. Once the authentication data are @@ -1171,40 +1323,29 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) * eap_sim_db_get_aka_auth() function will then be called again and the newly * received triplets will then be given to the caller. */ -int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, - size_t identity_len, u8 *_rand, u8 *autn, u8 *ik, - u8 *ck, u8 *res, size_t *res_len, - void *cb_session_ctx) +int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username, + u8 *_rand, u8 *autn, u8 *ik, u8 *ck, + u8 *res, size_t *res_len, void *cb_session_ctx) { - struct eap_sim_db_data *data = priv; struct eap_sim_db_pending *entry; int len; - size_t i; char msg[40]; + const char *imsi; + size_t imsi_len; - if (identity_len < 2 || identity == NULL || - identity[0] != EAP_AKA_PERMANENT_PREFIX) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", - identity, identity_len); - return EAP_SIM_DB_FAILURE; - } - identity++; - identity_len--; - for (i = 0; i < identity_len; i++) { - if (identity[i] == '@') { - identity_len = i; - break; - } - } - if (identity_len + 1 > sizeof(entry->imsi)) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", - identity, identity_len); + if (username == NULL || + (username[0] != EAP_AKA_PERMANENT_PREFIX && + username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) || + username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) { + wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", + username); return EAP_SIM_DB_FAILURE; } - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI", - identity, identity_len); + imsi = username + 1; + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'", + imsi); - entry = eap_sim_db_get_pending(data, identity, identity_len, 1); + entry = eap_sim_db_get_pending(data, imsi, 1); if (entry) { if (entry->state == FAILURE) { os_free(entry); @@ -1235,14 +1376,15 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, return EAP_SIM_DB_FAILURE; } + imsi_len = os_strlen(imsi); len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH "); - if (len < 0 || len + identity_len >= sizeof(msg)) + if (len < 0 || len + imsi_len >= sizeof(msg)) return EAP_SIM_DB_FAILURE; - os_memcpy(msg + len, identity, identity_len); - len += identity_len; + os_memcpy(msg + len, imsi, imsi_len); + len += imsi_len; - wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication " - "data for IMSI", identity, identity_len); + wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication " + "data for IMSI '%s'", imsi); if (eap_sim_db_send(data, msg, len) < 0) return EAP_SIM_DB_FAILURE; @@ -1252,8 +1394,7 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, os_get_time(&entry->timestamp); entry->aka = 1; - os_memcpy(entry->imsi, identity, identity_len); - entry->imsi_len = identity_len; + os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); entry->cb_session_ctx = cb_session_ctx; entry->state = PENDING; eap_sim_db_add_pending(data, entry); @@ -1265,9 +1406,8 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, /** * eap_sim_db_resynchronize - Resynchronize AKA AUTN - * @priv: Private data pointer from eap_sim_db_init() - * @identity: User name identity - * @identity_len: Length of identity in bytes + * @data: Private data pointer from eap_sim_db_init() + * @username: Permanent username * @auts: AUTS value from the peer * @_rand: RAND value used in the rejected message * Returns: 0 on success, -1 on failure @@ -1278,42 +1418,35 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, * eap_sim_db_get_aka_auth() will be called again to to fetch updated * RAND/AUTN values for the next challenge. */ -int eap_sim_db_resynchronize(void *priv, const u8 *identity, - size_t identity_len, const u8 *auts, - const u8 *_rand) +int eap_sim_db_resynchronize(struct eap_sim_db_data *data, + const char *username, + const u8 *auts, const u8 *_rand) { - struct eap_sim_db_data *data = priv; - size_t i; + const char *imsi; + size_t imsi_len; - if (identity_len < 2 || identity == NULL || - identity[0] != EAP_AKA_PERMANENT_PREFIX) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", - identity, identity_len); - return -1; - } - identity++; - identity_len--; - for (i = 0; i < identity_len; i++) { - if (identity[i] == '@') { - identity_len = i; - break; - } - } - if (identity_len > 20) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", - identity, identity_len); + if (username == NULL || + (username[0] != EAP_AKA_PERMANENT_PREFIX && + username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) || + username[1] == '\0' || os_strlen(username) > 20) { + wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", + username); return -1; } + imsi = username + 1; + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'", + imsi); if (data->sock >= 0) { char msg[100]; int len, ret; + imsi_len = os_strlen(imsi); len = os_snprintf(msg, sizeof(msg), "AKA-AUTS "); - if (len < 0 || len + identity_len >= sizeof(msg)) + if (len < 0 || len + imsi_len >= sizeof(msg)) return -1; - os_memcpy(msg + len, identity, identity_len); - len += identity_len; + os_memcpy(msg + len, imsi, imsi_len); + len += imsi_len; ret = os_snprintf(msg + len, sizeof(msg) - len, " "); if (ret < 0 || (size_t) ret >= sizeof(msg) - len) @@ -1327,11 +1460,42 @@ int eap_sim_db_resynchronize(void *priv, const u8 *identity, len += ret; len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, _rand, EAP_AKA_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for " - "IMSI", identity, identity_len); + wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for " + "IMSI '%s'", imsi); if (eap_sim_db_send(data, msg, len) < 0) return -1; } return 0; } + + +/** + * sim_get_username - Extract username from SIM identity + * @identity: Identity + * @identity_len: Identity length + * Returns: Allocated buffer with the username part of the identity + * + * Caller is responsible for freeing the returned buffer with os_free(). + */ +char * sim_get_username(const u8 *identity, size_t identity_len) +{ + char *username; + size_t pos; + + if (identity == NULL) + return NULL; + + for (pos = 0; pos < identity_len; pos++) { + if (identity[pos] == '@' || identity[pos] == '\0') + break; + } + + username = os_malloc(pos + 1); + if (username == NULL) + return NULL; + os_memcpy(username, identity, pos); + username[pos] = '\0'; + + return username; +} diff --git a/contrib/wpa/src/eap_server/eap_sim_db.h b/contrib/wpa/src/eap_server/eap_sim_db.h index ab89ae9..53a1a7c 100644 --- a/contrib/wpa/src/eap_server/eap_sim_db.h +++ b/contrib/wpa/src/eap_server/eap_sim_db.h @@ -1,15 +1,9 @@ /* * hostapd / EAP-SIM database/authenticator gateway - * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2008, 2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef EAP_SIM_DB_H @@ -24,49 +18,57 @@ #define EAP_AKA_PERMANENT_PREFIX '0' #define EAP_AKA_PSEUDONYM_PREFIX '2' #define EAP_AKA_REAUTH_ID_PREFIX '4' +#define EAP_AKA_PRIME_PERMANENT_PREFIX '6' +#define EAP_AKA_PRIME_PSEUDONYM_PREFIX '7' +#define EAP_AKA_PRIME_REAUTH_ID_PREFIX '8' + +enum eap_sim_db_method { + EAP_SIM_DB_SIM, + EAP_SIM_DB_AKA, + EAP_SIM_DB_AKA_PRIME +}; -void * eap_sim_db_init(const char *config, - void (*get_complete_cb)(void *ctx, void *session_ctx), - void *ctx); +struct eap_sim_db_data; + +struct eap_sim_db_data * +eap_sim_db_init(const char *config, + void (*get_complete_cb)(void *ctx, void *session_ctx), + void *ctx); void eap_sim_db_deinit(void *priv); -int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, - size_t identity_len, int max_chal, +int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data, + const char *username, int max_chal, u8 *_rand, u8 *kc, u8 *sres, void *cb_session_ctx); #define EAP_SIM_DB_FAILURE -1 #define EAP_SIM_DB_PENDING -2 -int eap_sim_db_identity_known(void *priv, const u8 *identity, - size_t identity_len); - -char * eap_sim_db_get_next_pseudonym(void *priv, int aka); +char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data, + enum eap_sim_db_method method); -char * eap_sim_db_get_next_reauth_id(void *priv, int aka); +char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data, + enum eap_sim_db_method method); -int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, - size_t identity_len, char *pseudonym); +int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data, + const char *permanent, char *pseudonym); -int eap_sim_db_add_reauth(void *priv, const u8 *identity, - size_t identity_len, char *reauth_id, u16 counter, - const u8 *mk); -int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, - size_t identity_len, char *reauth_id, - u16 counter, const u8 *k_encr, const u8 *k_aut, - const u8 *k_re); +int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent, + char *reauth_id, u16 counter, const u8 *mk); +int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data, + const char *permanent, + char *reauth_id, u16 counter, const u8 *k_encr, + const u8 *k_aut, const u8 *k_re); -const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity, - size_t identity_len, size_t *len); +const char * eap_sim_db_get_permanent(struct eap_sim_db_data *data, + const char *pseudonym); struct eap_sim_reauth { struct eap_sim_reauth *next; - u8 *identity; - size_t identity_len; - char *reauth_id; + char *permanent; /* Permanent username */ + char *reauth_id; /* Fast re-authentication username */ u16 counter; - int aka_prime; u8 mk[EAP_SIM_MK_LEN]; u8 k_encr[EAP_SIM_K_ENCR_LEN]; u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; @@ -74,18 +76,20 @@ struct eap_sim_reauth { }; struct eap_sim_reauth * -eap_sim_db_get_reauth_entry(void *priv, const u8 *identity, - size_t identity_len); +eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data, + const char *reauth_id); -void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth); +void eap_sim_db_remove_reauth(struct eap_sim_db_data *data, + struct eap_sim_reauth *reauth); -int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, - size_t identity_len, u8 *_rand, u8 *autn, u8 *ik, - u8 *ck, u8 *res, size_t *res_len, - void *cb_session_ctx); +int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username, + u8 *_rand, u8 *autn, u8 *ik, u8 *ck, + u8 *res, size_t *res_len, void *cb_session_ctx); -int eap_sim_db_resynchronize(void *priv, const u8 *identity, - size_t identity_len, const u8 *auts, +int eap_sim_db_resynchronize(struct eap_sim_db_data *data, + const char *username, const u8 *auts, const u8 *_rand); +char * sim_get_username(const u8 *identity, size_t identity_len); + #endif /* EAP_SIM_DB_H */ diff --git a/contrib/wpa/src/eap_server/eap_tls_common.h b/contrib/wpa/src/eap_server/eap_tls_common.h index c34c401..11f5827 100644 --- a/contrib/wpa/src/eap_server/eap_tls_common.h +++ b/contrib/wpa/src/eap_server/eap_tls_common.h @@ -2,14 +2,8 @@ * EAP-TLS/PEAP/TTLS/FAST server common functions * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef EAP_TLS_COMMON_H @@ -68,7 +62,12 @@ struct eap_ssl_data { /* could be up to 128 bytes, but only the first 64 bytes are used */ #define EAP_TLS_KEY_LEN 64 +/* dummy type used as a flag for UNAUTH-TLS */ +#define EAP_UNAUTH_TLS_TYPE 255 + +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); void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); diff --git a/contrib/wpa/src/eap_server/ikev2.c b/contrib/wpa/src/eap_server/ikev2.c index 435ba26..0e77efb 100644 --- a/contrib/wpa/src/eap_server/ikev2.c +++ b/contrib/wpa/src/eap_server/ikev2.c @@ -2,20 +2,15 @@ * IKEv2 initiator (RFC 4306) for EAP-IKEV2 * Copyright (c) 2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" #include "common.h" #include "crypto/dh_groups.h" +#include "crypto/random.h" #include "ikev2.h" @@ -403,7 +398,7 @@ static int ikev2_process_ker(struct ikev2_initiator_data *data, } /* RFC 4306, Section 3.4: - * The length of DH public value MUST be equal to the lenght of the + * The length of DH public value MUST be equal to the length of the * prime modulus. */ if (ker_len - 4 != data->dh->prime_len) { @@ -1100,7 +1095,7 @@ static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data) data->i_spi, IKEV2_SPI_LEN); data->i_nonce_len = IKEV2_NONCE_MIN_LEN; - if (os_get_random(data->i_nonce, data->i_nonce_len)) + if (random_get_bytes(data->i_nonce, data->i_nonce_len)) return NULL; wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len); @@ -1148,7 +1143,7 @@ static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data) if (data->shared_secret == NULL) return NULL; data->shared_secret_len = 16; - if (os_get_random(data->shared_secret, 16)) + if (random_get_bytes(data->shared_secret, 16)) return NULL; } else { os_free(data->shared_secret); diff --git a/contrib/wpa/src/eap_server/ikev2.h b/contrib/wpa/src/eap_server/ikev2.h index 8349fbe..051a938 100644 --- a/contrib/wpa/src/eap_server/ikev2.h +++ b/contrib/wpa/src/eap_server/ikev2.h @@ -2,14 +2,8 @@ * IKEv2 initiator (RFC 4306) for EAP-IKEV2 * Copyright (c) 2007, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef IKEV2_H diff --git a/contrib/wpa/src/eap_server/tncs.c b/contrib/wpa/src/eap_server/tncs.c index 497b51a..5e332ae 100644 --- a/contrib/wpa/src/eap_server/tncs.c +++ b/contrib/wpa/src/eap_server/tncs.c @@ -2,14 +2,8 @@ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -234,11 +228,11 @@ TNC_Result TNC_TNCS_ReportMessageTypes( return TNC_RESULT_INVALID_PARAMETER; os_free(imv->supported_types); imv->supported_types = - os_malloc(typeCount * sizeof(TNC_MessageTypeList)); + os_malloc(typeCount * sizeof(TNC_MessageType)); if (imv->supported_types == NULL) return TNC_RESULT_FATAL; os_memcpy(imv->supported_types, supportedTypes, - typeCount * sizeof(TNC_MessageTypeList)); + typeCount * sizeof(TNC_MessageType)); imv->num_supported_types = typeCount; return TNC_RESULT_SUCCESS; diff --git a/contrib/wpa/src/eap_server/tncs.h b/contrib/wpa/src/eap_server/tncs.h index 18a3a1f..ac7251b 100644 --- a/contrib/wpa/src/eap_server/tncs.h +++ b/contrib/wpa/src/eap_server/tncs.h @@ -2,14 +2,8 @@ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef TNCS_H |