📄 eap_ttls.c
字号:
/* * EAP peer method: EAP-TTLS (RFC 5281) * 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. */#include "includes.h"#include "common.h"#include "eap_peer/eap_i.h"#include "eap_peer/eap_tls_common.h"#include "eap_peer/eap_config.h"#include "ms_funcs.h"#include "sha1.h"#include "eap_common/chap.h"#include "tls.h"#include "mschapv2.h"#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 MSCHAPV2_NT_RESPONSE_LEN 24static 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; const struct eap_method *phase2_method; void *phase2_priv; int phase2_success; int phase2_start; enum phase2_types { EAP_TTLS_PHASE2_EAP, EAP_TTLS_PHASE2_MSCHAPV2, EAP_TTLS_PHASE2_MSCHAP, EAP_TTLS_PHASE2_PAP, EAP_TTLS_PHASE2_CHAP } phase2_type; struct eap_method_type phase2_eap_type; struct eap_method_type *phase2_eap_types; size_t num_phase2_eap_types; u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; int auth_response_valid; u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ u8 ident; int resuming; /* starting a resumed session */ int reauth; /* reauthentication */ u8 *key_data; struct wpabuf *pending_phase2_req;#ifdef EAP_TNC int ready_for_tnc; int tnc_started;#endif /* EAP_TNC */};static void * eap_ttls_init(struct eap_sm *sm){ struct eap_ttls_data *data; struct eap_peer_config *config = eap_get_config(sm); 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"; 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); } }#endif /* EAP_TTLS_VERSION */ if (config && config->phase2) { if (os_strstr(config->phase2, "autheap=")) { 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) { if (eap_peer_select_phase2_methods(config, "autheap=", &data->phase2_eap_types, &data->num_phase2_eap_types) < 0) { eap_ttls_deinit(sm, data); return NULL; } data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 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; }#endif /* EAP_TTLS_VERSION */ return data;}static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, struct eap_ttls_data *data){ if (data->phase2_priv && data->phase2_method) { data->phase2_method->deinit(sm, data->phase2_priv); data->phase2_method = NULL; data->phase2_priv = NULL; }}static void eap_ttls_deinit(struct eap_sm *sm, void *priv){ struct eap_ttls_data *data = priv; if (data == NULL) 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); wpabuf_free(data->pending_phase2_req); os_free(data);}static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, int mandatory, size_t len){ struct ttls_avp_vendor *avp; u8 flags; size_t hdrlen; avp = (struct ttls_avp_vendor *) avphdr; flags = mandatory ? AVP_FLAGS_MANDATORY : 0; if (vendor_id) { flags |= AVP_FLAGS_VENDOR; hdrlen = sizeof(*avp); avp->vendor_id = host_to_be32(vendor_id); } else { hdrlen = sizeof(struct ttls_avp); } avp->avp_code = host_to_be32(avp_code); avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len)); return avphdr + hdrlen;}static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, u32 vendor_id, int mandatory, const u8 *data, size_t len){ u8 *pos; pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); os_memcpy(pos, data, len); pos += len; AVP_PAD(start, pos); return pos;}static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, int mandatory){ struct wpabuf *msg; u8 *avp, *pos; msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); if (msg == NULL) { wpabuf_free(*resp); *resp = NULL; return -1; } avp = wpabuf_mhead(msg); pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); pos += wpabuf_len(*resp); AVP_PAD(avp, pos); wpabuf_free(*resp); wpabuf_put(msg, pos - avp); *resp = msg; return 0;}#if EAP_TTLS_VERSION > 0static 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;}#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); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, "ttls keying material", EAP_TLS_KEY_LEN); if (!data->key_data) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); return -1; } wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", data->key_data, EAP_TLS_KEY_LEN); return 0;}#if EAP_TTLS_VERSION > 0static 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(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 */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 */}static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, u8 method){ size_t i; for (i = 0; i < data->num_phase2_eap_types; i++) { if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || data->phase2_eap_types[i].method != method) continue; data->phase2_eap_type.vendor = data->phase2_eap_types[i].vendor; data->phase2_eap_type.method = data->phase2_eap_types[i].method; wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " "Phase 2 EAP vendor %d method %d", data->phase2_eap_type.vendor, data->phase2_eap_type.method); break; }}static int eap_ttls_phase2_eap_process(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, struct eap_hdr *hdr, size_t len, struct wpabuf **resp){ struct wpabuf msg; struct eap_method_ret iret; os_memset(&iret, 0, sizeof(iret)); wpabuf_set(&msg, hdr, len); *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, &msg); if ((iret.methodState == METHOD_DONE || iret.methodState == METHOD_MAY_CONT) && (iret.decision == DECISION_UNCOND_SUCC || iret.decision == DECISION_COND_SUCC || iret.decision == DECISION_FAIL)) { ret->methodState = iret.methodState; ret->decision = iret.decision; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -