X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=libeap%2Fsrc%2Feap_peer%2Feap_ttls.c;h=12ea169c0f3f12f4e7b51a4ed8f52187d36d8194;hb=d1dd9aae6741e74f20bfc35e1db598652680279d;hp=25737803beeda10ccda70b2775b53f4ce5409beb;hpb=3d5083e8a273503d6d5233195d2ee7cb2e754e6d;p=mech_eap.git diff --git a/libeap/src/eap_peer/eap_ttls.c b/libeap/src/eap_peer/eap_ttls.c index 2573780..12ea169 100644 --- a/libeap/src/eap_peer/eap_ttls.c +++ b/libeap/src/eap_peer/eap_ttls.c @@ -1,20 +1,15 @@ /* * EAP peer method: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2008, Jouni Malinen + * Copyright (c) 2004-2015, Jouni Malinen * - * 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 "radius/radius.h" #include "crypto/ms_funcs.h" #include "crypto/sha1.h" #include "crypto/tls.h" @@ -26,17 +21,7 @@ #include "eap_config.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 MSCHAPV2_NT_RESPONSE_LEN 24 +#define EAP_TTLS_VERSION 0 static void eap_ttls_deinit(struct eap_sm *sm, void *priv); @@ -44,14 +29,14 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv); struct eap_ttls_data { struct eap_ssl_data ssl; - int ssl_initialized; - int ttls_version, force_ttls_version; + int ttls_version; const struct eap_method *phase2_method; void *phase2_priv; int phase2_success; int phase2_start; + EapDecision decision_succ; enum phase2_types { EAP_TTLS_PHASE2_EAP, @@ -71,9 +56,14 @@ struct eap_ttls_data { int resuming; /* starting a resumed session */ int reauth; /* reauthentication */ u8 *key_data; + u8 *session_id; + size_t id_len; struct wpabuf *pending_phase2_req; - + struct wpabuf *pending_resp; + int chbind_req_sent; /* channel binding request was sent */ + int done_butfor_cb; /*we turned METHOD_DONE into METHOD_MAY_CONT to receive cb*/ + EapDecision cbDecision; #ifdef EAP_TNC int ready_for_tnc; int tnc_started; @@ -81,50 +71,96 @@ struct eap_ttls_data { }; +/* draft-ietf-emu-chbind-13 section 5.3 */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct chbind_hdr { + u16 len; + u8 nsid; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + + static void * eap_ttls_init(struct eap_sm *sm) { struct eap_ttls_data *data; struct eap_peer_config *config = eap_get_config(sm); + int selected_non_eap; char *selected; data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->ttls_version = EAP_TTLS_VERSION; - data->force_ttls_version = -1; selected = "EAP"; + selected_non_eap = 0; data->phase2_type = EAP_TTLS_PHASE2_EAP; -#if EAP_TTLS_VERSION > 0 - if (config && config->phase1) { - const char *pos = os_strstr(config->phase1, "ttlsver="); - if (pos) { - data->force_ttls_version = atoi(pos + 8); - data->ttls_version = data->force_ttls_version; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version " - "%d", data->force_ttls_version); + /* + * Either one auth= type or one or more autheap= methods can be + * specified. + */ + if (config && config->phase2) { + const char *token, *last = NULL; + + while ((token = cstr_token(config->phase2, " \t", &last))) { + if (os_strncmp(token, "auth=", 5) != 0) + continue; + token += 5; + + if (last - token == 8 && + os_strncmp(token, "MSCHAPV2", 8) == 0) { + selected = "MSCHAPV2"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; + } else if (last - token == 6 && + os_strncmp(token, "MSCHAP", 6) == 0) { + selected = "MSCHAP"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; + } else if (last - token == 3 && + os_strncmp(token, "PAP", 3) == 0) { + selected = "PAP"; + data->phase2_type = EAP_TTLS_PHASE2_PAP; + } else if (last - token == 4 && + os_strncmp(token, "CHAP", 4) == 0) { + selected = "CHAP"; + data->phase2_type = EAP_TTLS_PHASE2_CHAP; + } else { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Unsupported Phase2 type '%s'", + token); + eap_ttls_deinit(sm, data); + return NULL; + } + + if (selected_non_eap) { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Only one Phase2 type can be specified"); + eap_ttls_deinit(sm, data); + return NULL; + } + + selected_non_eap = 1; } - } -#endif /* EAP_TTLS_VERSION */ - if (config && config->phase2) { if (os_strstr(config->phase2, "autheap=")) { + if (selected_non_eap) { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Both auth= and autheap= params cannot be specified"); + eap_ttls_deinit(sm, data); + return NULL; + } selected = "EAP"; data->phase2_type = EAP_TTLS_PHASE2_EAP; - } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { - selected = "MSCHAPV2"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; - } else if (os_strstr(config->phase2, "auth=MSCHAP")) { - selected = "MSCHAP"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; - } else if (os_strstr(config->phase2, "auth=PAP")) { - selected = "PAP"; - data->phase2_type = EAP_TTLS_PHASE2_PAP; - } else if (os_strstr(config->phase2, "auth=CHAP")) { - selected = "CHAP"; - data->phase2_type = EAP_TTLS_PHASE2_CHAP; } } + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { @@ -140,19 +176,11 @@ static void * eap_ttls_init(struct eap_sm *sm) data->phase2_eap_type.method = EAP_TYPE_NONE; } -#if EAP_TTLS_VERSION > 0 - if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && - data->ttls_version > 0) { - if (data->force_ttls_version > 0) { - wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " - "TLS library does not support TLS/IA.", - data->force_ttls_version); - eap_ttls_deinit(sm, data); - return NULL; - } - data->ttls_version = 0; + if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { + wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); + eap_ttls_deinit(sm, data); + return NULL; } -#endif /* EAP_TTLS_VERSION */ return data; } @@ -169,6 +197,15 @@ static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, } +static void eap_ttls_free_key(struct eap_ttls_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); + data->key_data = NULL; + } +} + + static void eap_ttls_deinit(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; @@ -176,10 +213,11 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv) return; eap_ttls_phase2_eap_deinit(sm, data); os_free(data->phase2_eap_types); - if (data->ssl_initialized) - eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); + eap_peer_tls_ssl_deinit(sm, &data->ssl); + eap_ttls_free_key(data); + os_free(data->session_id); wpabuf_free(data->pending_phase2_req); + wpabuf_free(data->pending_resp); os_free(data); } @@ -202,7 +240,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; } @@ -245,47 +284,57 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, return 0; } - -#if EAP_TTLS_VERSION > 0 -static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *key, size_t key_len) +/* chop up resp into multiple vsa's as necessary*/ +static int eap_ttls_avp_radius_vsa_encapsulate(struct wpabuf **resp, u32 vendor, + u8 attr, int mandatory) { - u8 *buf; - size_t buf_len; - int ret; + struct wpabuf *msg; + u8 *avp, *pos, *src, *final; + size_t size = wpabuf_len(*resp); + size_t num_msgs = 1 + (size / 248); + size_t msg_wrapper_size = sizeof(struct ttls_avp_vendor) + 6; + size_t allocated_total = num_msgs * (4 + msg_wrapper_size) + size; - 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; + msg = wpabuf_alloc(allocated_total); + if (msg == NULL) { + wpabuf_free(*resp); + *resp = NULL; + return -1; } - - 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; + src = wpabuf_mhead(*resp); + avp = wpabuf_mhead(msg); + while (size > 0) { + int avp_size = size > 248 ? 248 : size; + size -= avp_size; + pos = eap_ttls_avp_hdr(avp, RADIUS_ATTR_VENDOR_SPECIFIC, 0, mandatory, + avp_size+6); + wpabuf_put(msg, pos-avp); + wpabuf_put_be32(msg, vendor); + wpabuf_put_u8(msg, (u8) attr); + wpabuf_put_u8(msg, (u8) avp_size+2); + wpabuf_put_data(msg, src, avp_size); + src += avp_size; + pos = wpabuf_mhead_u8(msg) + wpabuf_len(msg); + final = pos; /*keep pos so we know how much padding is added*/ + AVP_PAD(avp, final); /*final modified*/ + if (final > pos) + wpabuf_put(msg, final-pos); + avp = final; + } + /* check avp-wpabuf_mhead(msg) < allocated_total */ + wpabuf_free(*resp); + *resp = msg; + return 0; } -#endif /* EAP_TTLS_VERSION */ - static int eap_ttls_v0_derive_key(struct eap_sm *sm, struct eap_ttls_data *data) { - os_free(data->key_data); + eap_ttls_free_key(data); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, "ttls keying material", - EAP_TLS_KEY_LEN); + EAP_TLS_KEY_LEN + + EAP_EMSK_LEN); if (!data->key_data) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); return -1; @@ -293,162 +342,32 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm, wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", data->key_data, EAP_TLS_KEY_LEN); - - return 0; -} - - -#if EAP_TTLS_VERSION > 0 -static int eap_ttls_v1_derive_key(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - struct tls_keys keys; - u8 *rnd; - - os_free(data->key_data); - data->key_data = NULL; - - 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 -1; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - data->key_data = os_malloc(EAP_TLS_KEY_LEN); - if (rnd == NULL || data->key_data == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); - os_free(rnd); - os_free(data->key_data); - data->key_data = NULL; - return -1; - } - 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, data->key_data, EAP_TLS_KEY_LEN)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); - os_free(rnd); - os_free(data->key_data); - data->key_data = NULL; - return -1; + wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK", + data->key_data + EAP_TLS_KEY_LEN, + EAP_EMSK_LEN); + + os_free(data->session_id); + data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, + EAP_TYPE_TTLS, + &data->id_len); + if (data->session_id) { + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", + data->session_id, data->id_len); + } else { + wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); } - 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); - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", - data->key_data, EAP_TLS_KEY_LEN); - return 0; } -#endif /* EAP_TTLS_VERSION */ +#ifndef CONFIG_FIPS static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, struct eap_ttls_data *data, size_t len) { -#if EAP_TTLS_VERSION > 0 - struct tls_keys keys; - u8 *challenge, *rnd; -#endif /* EAP_TTLS_VERSION */ - - if (data->ttls_version == 0) { - return eap_peer_tls_derive_key(sm, &data->ssl, - "ttls challenge", len); - } - -#if EAP_TTLS_VERSION > 0 - - 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; - -#else /* EAP_TTLS_VERSION */ - - return NULL; - -#endif /* EAP_TTLS_VERSION */ -} - - -static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret) -{ -#if EAP_TTLS_VERSION > 0 - if (data->ttls_version > 0) { - const struct eap_method *m = data->phase2_method; - void *priv = data->phase2_priv; - - /* TTLSv1 requires TLS/IA FinalPhaseFinished */ - if (ret->decision == DECISION_UNCOND_SUCC) - ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_CONT; - - if (ret->decision == DECISION_COND_SUCC && - m->isKeyAvailable && m->getKey && - m->isKeyAvailable(sm, priv)) { - u8 *key; - size_t key_len; - key = m->getKey(sm, priv, &key_len); - if (key) { - eap_ttls_ia_permute_inner_secret( - sm, data, key, key_len); - os_free(key); - } - } - } -#endif /* EAP_TTLS_VERSION */ + return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); } +#endif /* CONFIG_FIPS */ static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, @@ -494,7 +413,6 @@ static int eap_ttls_phase2_eap_process(struct eap_sm *sm, ret->methodState = iret.methodState; ret->decision = iret.decision; } - eap_ttlsv1_phase2_eap_finish(sm, data, ret); return 0; } @@ -615,31 +533,16 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm, } -static void eap_ttlsv1_permute_inner(struct eap_sm *sm, - struct eap_ttls_data *data) -{ -#if EAP_TTLS_VERSION > 0 - u8 session_key[2 * MSCHAPV2_KEY_LEN]; - - if (data->ttls_version == 0) - return; - - get_asymetric_start_key(data->master_key, session_key, - MSCHAPV2_KEY_LEN, 0, 0); - get_asymetric_start_key(data->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)); -#endif /* EAP_TTLS_VERSION */ -} - - static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, struct wpabuf **resp) { +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build"); + return -1; +#else /* CONFIG_FIPS */ +#ifdef EAP_MSCHAPv2 struct wpabuf *msg; u8 *buf, *pos, *challenge, *peer_challenge; const u8 *identity, *password; @@ -674,7 +577,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, "implicit challenge"); return -1; } - peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, RADIUS_VENDOR_ID_MICROSOFT, 1, @@ -687,7 +589,14 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; *pos++ = data->ident; *pos++ = 0; /* Flags */ - os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); + if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { + os_free(challenge); + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " + "random data for peer challenge"); + return -1; + } + peer_challenge = pos; pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; os_memset(pos, 0, 8); /* Reserved, must be zero */ pos += 8; @@ -695,6 +604,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, password_len, pwhash, challenge, peer_challenge, pos, data->auth_response, data->master_key)) { + os_free(challenge); wpabuf_free(msg); wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " "response"); @@ -702,8 +612,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, } data->auth_response_valid = 1; - eap_ttlsv1_permute_inner(sm, data); - pos += 24; os_free(challenge); AVP_PAD(buf, pos); @@ -711,17 +619,12 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (sm->workaround && data->ttls_version == 0) { - /* At least FreeRADIUS seems to be terminating - * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success - * packet. */ - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " - "allow success without tunneled response"); - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_COND_SUCC; - } - return 0; +#else /* EAP_MSCHAPv2 */ + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); + return -1; +#endif /* EAP_MSCHAPv2 */ +#endif /* CONFIG_FIPS */ } @@ -730,6 +633,10 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, struct eap_method_ret *ret, struct wpabuf **resp) { +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build"); + return -1; +#else /* CONFIG_FIPS */ struct wpabuf *msg; u8 *buf, *pos, *challenge; const u8 *identity, *password; @@ -798,19 +705,13 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/MSCHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } + /* EAP-TTLS/MSCHAP does not provide tunneled success + * notification, so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; return 0; +#endif /* CONFIG_FIPS */ } @@ -859,17 +760,10 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/PAP does not provide tunneled success notification, - * so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } + /* EAP-TTLS/PAP does not provide tunneled success notification, + * so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; return 0; } @@ -880,6 +774,10 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm, struct eap_method_ret *ret, struct wpabuf **resp) { +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build"); + return -1; +#else /* CONFIG_FIPS */ struct wpabuf *msg; u8 *buf, *pos, *challenge; const u8 *identity, *password; @@ -942,19 +840,13 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/CHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } + /* EAP-TTLS/CHAP does not provide tunneled success + * notification, so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; return 0; +#endif /* CONFIG_FIPS */ } @@ -1027,40 +919,12 @@ static int eap_ttls_phase2_request(struct eap_sm *sm, } -#if EAP_TTLS_VERSION > 0 -static struct wpabuf * eap_ttls_build_phase_finished( - struct eap_sm *sm, struct eap_ttls_data *data, int id, int final) -{ - struct wpabuf *req, *buf; - - buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx, - data->ssl.conn, - final); - if (buf == NULL) - return NULL; - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, - 1 + wpabuf_len(buf), - EAP_CODE_RESPONSE, id); - if (req == NULL) { - wpabuf_free(buf); - return NULL; - } - - wpabuf_put_u8(req, data->ttls_version); - wpabuf_put_buf(req, buf); - wpabuf_free(buf); - eap_update_len(req); - - return req; -} -#endif /* EAP_TTLS_VERSION */ - - struct ttls_parse_avp { u8 *mschapv2; u8 *eapdata; size_t eap_len; + u8 *chbind_data; + size_t chbind_len; int mschapv2_error; }; @@ -1094,6 +958,38 @@ static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, } +static int eap_ttls_parse_attr_chbind(const u8 *dpos, size_t dlen, + struct ttls_parse_avp *parse) +{ + wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - Channel Binding Message"); + + if (parse->chbind_data == NULL) { + parse->chbind_data = os_malloc(dlen); + if (parse->chbind_data == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " + "memory for Phase 2 channel binding data"); + return -1; + } + os_memcpy(parse->chbind_data, dpos, dlen); + parse->chbind_len = dlen; + } else { + /* TODO: can this really happen? maybe just make this an error? */ + u8 *newchbind = os_realloc(parse->chbind_data, + parse->chbind_len + dlen); + if (newchbind == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " + "memory for Phase 2 channel binding data"); + return -1; + } + os_memcpy(newchbind + parse->chbind_len, dpos, dlen); + parse->chbind_data = newchbind; + parse->chbind_len += dlen; + } + + return 0; +} + + static int eap_ttls_parse_avp(u8 *pos, size_t left, struct ttls_parse_avp *parse) { @@ -1144,6 +1040,11 @@ static int eap_ttls_parse_avp(u8 *pos, size_t left, if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) return -1; + } else if (vendor_id == RADIUS_VENDOR_ID_UKERNA && + avp_code == RADIUS_ATTR_UKERNA_CHBIND) { + /* message containing channel binding data */ + if (eap_ttls_parse_attr_chbind(dpos, dlen, parse) < 0) + return -1; } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { /* This is an optional message that can be displayed to * the user. */ @@ -1258,6 +1159,7 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm, resp, out_data)) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " "frame"); + wpabuf_free(resp); return -1; } wpabuf_free(resp); @@ -1265,6 +1167,111 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm, return 0; } +static int eap_ttls_add_chbind_request(struct eap_sm *sm, + struct eap_ttls_data *data, + struct wpabuf **resp) +{ + struct wpabuf *chbind_req, *res; + int length = 1, i; + struct eap_peer_config *config = eap_get_config(sm); + + if (!config->chbind_config || config->chbind_config_len <= 0) + return -1; + + for (i=0; ichbind_config_len; i++) { + length += 3 + config->chbind_config[i].req_data_len; + } + + chbind_req = wpabuf_alloc(length); + if (!chbind_req) + return -1; + + wpabuf_put_u8(chbind_req, CHBIND_CODE_REQUEST); + for (i=0; ichbind_config_len; i++) { + struct eap_peer_chbind_config *chbind_config = + &config->chbind_config[i]; + wpabuf_put_be16(chbind_req, chbind_config->req_data_len); + wpabuf_put_u8(chbind_req, chbind_config->nsid); + wpabuf_put_data(chbind_req, chbind_config->req_data, + chbind_config->req_data_len); + } + if (eap_ttls_avp_radius_vsa_encapsulate(&chbind_req, + RADIUS_VENDOR_ID_UKERNA, + RADIUS_ATTR_UKERNA_CHBIND, 0) < 0) + return -1; + + /* bleh. This will free *resp regardless of whether combined buffer + alloc succeeds, which is not consistent with the other error + condition behavior in this function */ + *resp = wpabuf_concat(chbind_req, *resp); + + return (*resp) ? 0 : -1; +} + + +static int eap_ttls_process_chbind(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse, + struct wpabuf **resp) +{ + size_t pos=0; + u8 code; + u16 len; + struct chbind_hdr *hdr; + struct eap_peer_config *config = eap_get_config(sm); + int i, found; + + + if (parse->chbind_data == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: No channel binding message " + "in the packet - dropped"); + return -1; + } + if (parse->chbind_len < 1 ) { + wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response " + "frame (len=%lu, expected %lu or more) - dropped", + (unsigned long) parse->chbind_len, + (unsigned long) 1); + return -1; + } + code = parse->chbind_data[pos++]; + for (i=0; ichbind_config_len; i++) { + struct eap_peer_chbind_config *chbind_config = + &config->chbind_config[i]; + pos = 1; + found = 0; + while (pos+sizeof(*hdr) < parse->chbind_len) { + hdr = (struct chbind_hdr *)(&parse->chbind_data[pos]); + pos += sizeof(*hdr); + len = be_to_host16(hdr->len); + if (pos + len <= parse->chbind_len) { + if (chbind_config->nsid == hdr->nsid) + chbind_config->response_cb( + chbind_config->ctx, + code, hdr->nsid, + &parse->chbind_data[pos], len); + found = 1; + } + pos += len; + } + if (pos != parse->chbind_len) { + wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response " + "frame (parsed len=%lu, expected %lu) - dropped", + (unsigned long) pos, + (unsigned long) parse->chbind_len); + return -1; + } + if (!found) { + chbind_config->response_cb( + chbind_config->ctx, + code, chbind_config->nsid, + NULL, 0); + } + + } + return 0; +} static int eap_ttls_process_phase2_eap(struct eap_sm *sm, struct eap_ttls_data *data, @@ -1327,6 +1334,7 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, struct eap_method_ret *ret, struct ttls_parse_avp *parse) { +#ifdef EAP_MSCHAPv2 if (parse->mschapv2_error) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " "MS-CHAP-Error - failed"); @@ -1366,25 +1374,19 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " "authentication succeeded"); - if (data->ttls_version > 0) { - /* - * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report - * success, so do not allow connection to be terminated - * yet. - */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - } + ret->methodState = METHOD_DONE; + ret->decision = DECISION_UNCOND_SUCC; + data->phase2_success = 1; /* * Reply with empty data; authentication server will reply * with EAP-Success after this. */ return 1; +#else /* EAP_MSCHAPv2 */ + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); + return -1; +#endif /* EAP_MSCHAPv2 */ } @@ -1438,6 +1440,19 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm, phase2_type = EAP_TTLS_PHASE2_EAP; #endif /* EAP_TNC */ + /* handle channel binding response here */ + if (parse->chbind_data) { + /* received channel binding repsonse */ + if (eap_ttls_process_chbind(sm, data, ret, parse, &resp) < 0) + return -1; + if (data->done_butfor_cb) { + ret->methodState = METHOD_DONE; + ret->decision = data->cbDecision; + data->phase2_success = 1; + return 1; /*request ack*/ + } + } + switch (phase2_type) { case EAP_TTLS_PHASE2_EAP: if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < @@ -1477,40 +1492,38 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm, #endif /* EAP_TNC */ } + if (!resp && (config->pending_req_identity || + config->pending_req_password || + config->pending_req_otp || + config->pending_req_new_password)) { + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = wpabuf_dup(in_decrypted); + return 0; + } + + /* issue channel binding request when appropriate */ + if (config->chbind_config && config->chbind_config_len > 0 && + !data->chbind_req_sent) { + if (eap_ttls_add_chbind_request(sm, data, &resp) < 0) + return -1; + data->chbind_req_sent = 1; + if (ret->methodState == METHOD_DONE) { + data->done_butfor_cb = 1; + data->cbDecision = ret->decision; + ret->methodState = METHOD_MAY_CONT; + } + } + if (resp) { if (eap_ttls_encrypt_response(sm, data, resp, identifier, out_data) < 0) return -1; - } else if (config->pending_req_identity || - config->pending_req_password || - config->pending_req_otp || - config->pending_req_new_password) { - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = wpabuf_dup(in_decrypted); } return 0; } -#if EAP_TTLS_VERSION > 0 -static void eap_ttls_final_phase_finished(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - struct wpabuf **out_data) -{ - wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received"); - wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1); - eap_ttls_v1_derive_key(sm, data); -} -#endif /* EAP_TTLS_VERSION */ - - static int eap_ttls_implicit_identity_request(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -1534,6 +1547,21 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm, "processing failed"); retval = -1; } else { + struct eap_peer_config *config = eap_get_config(sm); + if (resp == NULL && + (config->pending_req_identity || + config->pending_req_password || + config->pending_req_otp || + config->pending_req_new_password)) { + /* + * Use empty buffer to force implicit request + * processing when EAP request is re-processed after + * user input. + */ + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = wpabuf_alloc(0); + } + retval = eap_ttls_encrypt_response(sm, data, resp, identifier, out_data); } @@ -1627,17 +1655,6 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, if (retval) goto done; -#if EAP_TTLS_VERSION > 0 - if (data->ttls_version > 0 && - (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) && - tls_connection_ia_final_phase_finished(sm->ssl_ctx, - data->ssl.conn)) { - eap_ttls_final_phase_finished(sm, data, ret, identifier, - out_data); - goto done; - } -#endif /* EAP_TTLS_VERSION */ - continue_req: data->phase2_start = 0; @@ -1662,58 +1679,59 @@ done: } -static int eap_ttls_process_start(struct eap_sm *sm, - struct eap_ttls_data *data, u8 flags, - struct eap_method_ret *ret) -{ - struct eap_peer_config *config = eap_get_config(sm); - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)", - flags & EAP_TLS_VERSION_MASK, data->ttls_version); -#if EAP_TTLS_VERSION > 0 - if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version) - data->ttls_version = flags & EAP_TLS_VERSION_MASK; - if (data->force_ttls_version >= 0 && - data->force_ttls_version != data->ttls_version) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select " - "forced TTLS version %d", - data->force_ttls_version); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d", - data->ttls_version); - - if (data->ttls_version > 0) - data->ssl.tls_ia = 1; -#endif /* EAP_TTLS_VERSION */ - if (!data->ssl_initialized && - eap_peer_tls_ssl_init(sm, &data->ssl, config)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); - return -1; - } - data->ssl_initialized = 1; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start"); - - return 0; -} - - static int eap_ttls_process_handshake(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, u8 identifier, - const u8 *in_data, size_t in_len, + const struct wpabuf *in_data, struct wpabuf **out_data) { int res; + if (sm->waiting_ext_cert_check && data->pending_resp) { + struct eap_peer_config *config = eap_get_config(sm); + + if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) { + wpa_printf(MSG_DEBUG, + "EAP-TTLS: External certificate check succeeded - continue handshake"); + *out_data = data->pending_resp; + data->pending_resp = NULL; + sm->waiting_ext_cert_check = 0; + return 0; + } + + if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) { + wpa_printf(MSG_DEBUG, + "EAP-TTLS: External certificate check failed - force authentication failure"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + sm->waiting_ext_cert_check = 0; + return 0; + } + + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Continuing to wait external server certificate validation"); + return 0; + } + res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, data->ttls_version, identifier, - in_data, in_len, out_data); + in_data, out_data); + if (res < 0) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return -1; + } + + if (sm->waiting_ext_cert_check) { + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Waiting external server certificate validation"); + wpabuf_free(data->pending_resp); + data->pending_resp = *out_data; + *out_data = NULL; + return 0; + } if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " @@ -1725,8 +1743,7 @@ static int eap_ttls_process_handshake(struct eap_sm *sm, ret->methodState = METHOD_MAY_CONT; } data->phase2_start = 1; - if (data->ttls_version == 0) - eap_ttls_v0_derive_key(sm, data); + eap_ttls_v0_derive_key(sm, data); if (*out_data == NULL || wpabuf_len(*out_data) == 0) { if (eap_ttls_decrypt(sm, data, ret, identifier, @@ -1741,15 +1758,13 @@ static int eap_ttls_process_handshake(struct eap_sm *sm, } if (res == 2) { - struct wpabuf msg; /* * Application data included in the handshake message. */ wpabuf_free(data->pending_phase2_req); data->pending_phase2_req = *out_data; *out_data = NULL; - wpabuf_set(&msg, in_data, in_len); - res = eap_ttls_decrypt(sm, data, ret, identifier, &msg, + res = eap_ttls_decrypt(sm, data, ret, identifier, in_data, out_data); } @@ -1761,13 +1776,14 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret) { - if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) { + if (ret->methodState == METHOD_DONE) { ret->allowNotifications = FALSE; if (ret->decision == DECISION_UNCOND_SUCC || ret->decision == DECISION_COND_SUCC) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " "completed successfully"); data->phase2_success = 1; + data->decision_succ = ret->decision; #ifdef EAP_TNC if (!data->ready_for_tnc && !data->tnc_started) { /* @@ -1779,13 +1795,24 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm, } #endif /* EAP_TNC */ } - } else if (data->ttls_version == 0 && - ret->methodState == METHOD_MAY_CONT && + } else if (ret->methodState == METHOD_MAY_CONT && (ret->decision == DECISION_UNCOND_SUCC || ret->decision == DECISION_COND_SUCC)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " "completed successfully (MAY_CONT)"); data->phase2_success = 1; + data->decision_succ = ret->decision; + } else if (data->decision_succ != DECISION_FAIL && + data->phase2_success && + !data->ssl.tls_out) { + /* + * This is needed to cover the case where the final Phase 2 + * message gets fragmented since fragmentation clears + * decision back to FAIL. + */ + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Restore success decision after fragmented frame sent completely"); + ret->decision = data->decision_succ; } } @@ -1800,6 +1827,7 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, struct wpabuf *resp; const u8 *pos; struct eap_ttls_data *data = priv; + struct wpabuf msg; pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, reqData, &left, &flags); @@ -1808,8 +1836,9 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, id = eap_get_id(reqData); if (flags & EAP_TLS_FLAGS_START) { - if (eap_ttls_process_start(sm, data, flags, ret) < 0) - return NULL; + wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " + "ver=%d)", flags & EAP_TLS_VERSION_MASK, + data->ttls_version); /* RFC 5281, Ch. 9.2: * "This packet MAY contain additional information in the form @@ -1817,24 +1846,17 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, * For now, ignore any potential extra data. */ left = 0; - } else if (!data->ssl_initialized) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not " - "include Start flag"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return NULL; } + wpabuf_set(&msg, pos, left); + resp = NULL; if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && !data->resuming) { - struct wpabuf msg; - wpabuf_set(&msg, pos, left); res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); } else { res = eap_ttls_process_handshake(sm, data, ret, id, - pos, left, &resp); + &msg, &resp); } eap_ttls_check_auth_status(sm, data, ret); @@ -1863,6 +1885,9 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) struct eap_ttls_data *data = priv; wpabuf_free(data->pending_phase2_req); data->pending_phase2_req = NULL; + wpabuf_free(data->pending_resp); + data->pending_resp = NULL; + data->decision_succ = DECISION_FAIL; #ifdef EAP_TNC data->ready_for_tnc = 0; data->tnc_started = 0; @@ -1873,8 +1898,9 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; + eap_ttls_free_key(data); + os_free(data->session_id); + data->session_id = NULL; if (eap_peer_tls_reauth_init(sm, &data->ssl)) { os_free(data); return NULL; @@ -1900,7 +1926,7 @@ static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, ret = os_snprintf(buf + len, buflen - len, "EAP-TTLSv%d Phase2 method=", data->ttls_version); - if (ret < 0 || (size_t) ret >= buflen - len) + if (os_snprintf_error(buflen - len, ret)) return len; len += ret; switch (data->phase2_type) { @@ -1925,7 +1951,7 @@ static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, ret = 0; break; } - if (ret < 0 || (size_t) ret >= buflen - len) + if (os_snprintf_error(buflen - len, ret)) return len; len += ret; @@ -1959,10 +1985,47 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) } +static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ttls_data *data = priv; + u8 *id; + + if (data->session_id == NULL || !data->phase2_success) + return NULL; + + id = os_malloc(data->id_len); + if (id == NULL) + return NULL; + + *len = data->id_len; + os_memcpy(id, data->session_id, data->id_len); + + return id; +} + + +static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ttls_data *data = priv; + u8 *key; + + if (data->key_data == NULL) + return NULL; + + key = os_malloc(EAP_EMSK_LEN); + if (key == NULL) + return NULL; + + *len = EAP_EMSK_LEN; + os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); + + return key; +} + + int eap_peer_ttls_register(void) { struct eap_method *eap; - int ret; eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); @@ -1974,13 +2037,12 @@ int eap_peer_ttls_register(void) eap->process = eap_ttls_process; eap->isKeyAvailable = eap_ttls_isKeyAvailable; eap->getKey = eap_ttls_getKey; + eap->getSessionId = eap_ttls_get_session_id; eap->get_status = eap_ttls_get_status; eap->has_reauth_data = eap_ttls_has_reauth_data; eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; eap->init_for_reauth = eap_ttls_init_for_reauth; + eap->get_emsk = eap_ttls_get_emsk; - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; + return eap_peer_method_register(eap); }