📄 eap_ttls.c
字号:
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && sm->user->methods[sm->user_eap_method_index].method != EAP_TYPE_NONE) { next_type = sm->user->methods[ sm->user_eap_method_index++].method; wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type); if (eap_ttls_phase2_eap_init(sm, data, next_type)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to " "initialize EAP type %d", next_type); eap_ttls_state(data, FAILURE); return; } } else { eap_ttls_state(data, FAILURE); } return; } wpabuf_set(&buf, in_data, in_len); if (m->check(sm, priv, &buf)) { wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to " "ignore the packet"); return; } m->process(sm, priv, &buf); if (sm->method_pending == METHOD_PENDING_WAIT) { wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method is in " "pending wait state - save decrypted response"); wpabuf_free(data->pending_phase2_eap_resp); data->pending_phase2_eap_resp = wpabuf_dup(&buf); } if (!m->isDone(sm, priv)) return; if (!m->isSuccess(sm, priv)) { wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed"); eap_ttls_state(data, FAILURE); return; } switch (data->state) { case PHASE2_START: if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { wpa_hexdump_ascii(MSG_DEBUG, "EAP_TTLS: Phase2 " "Identity not found in the user " "database", sm->identity, sm->identity_len); eap_ttls_state(data, FAILURE); break; } eap_ttls_state(data, PHASE2_METHOD); next_type = sm->user->methods[0].method; sm->user_eap_method_index = 1; wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type); if (eap_ttls_phase2_eap_init(sm, data, next_type)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize " "EAP type %d", next_type); eap_ttls_state(data, FAILURE); } 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); break; case FAILURE: break; default: wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", __func__, data->state); break; }}static void eap_ttls_process_phase2_eap(struct eap_sm *sm, struct eap_ttls_data *data, const u8 *eap, size_t eap_len){ struct eap_hdr *hdr; size_t len; if (data->state == PHASE2_START) { wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2"); if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to " "initialize EAP-Identity"); return; } } if (eap_len < sizeof(*hdr)) { wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: too short Phase 2 EAP " "packet (len=%lu)", (unsigned long) eap_len); return; } hdr = (struct eap_hdr *) eap; len = be_to_host16(hdr->length); wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: received Phase 2 EAP: code=%d " "identifier=%d length=%lu", hdr->code, hdr->identifier, (unsigned long) len); if (len > eap_len) { wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Length mismatch in Phase 2" " EAP frame (hdr len=%lu, data len in AVP=%lu)", (unsigned long) len, (unsigned long) eap_len); return; } switch (hdr->code) { case EAP_CODE_RESPONSE: eap_ttls_process_phase2_eap_response(sm, data, (u8 *) hdr, len); break; default: wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Unexpected code=%d in " "Phase 2 EAP header", hdr->code); break; }}static void eap_ttls_process_phase2(struct eap_sm *sm, struct eap_ttls_data *data, struct wpabuf *in_buf){ u8 *in_decrypted; int len_decrypted; struct eap_ttls_avp parse; size_t buf_len; u8 *in_data; size_t in_len; in_data = wpabuf_mhead(in_buf); in_len = wpabuf_len(in_buf); wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" " Phase 2", (unsigned long) in_len); if (data->pending_phase2_eap_resp) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response " "- skip decryption and use old data"); eap_ttls_process_phase2_eap( sm, data, wpabuf_head(data->pending_phase2_eap_resp), wpabuf_len(data->pending_phase2_eap_resp)); wpabuf_free(data->pending_phase2_eap_resp); data->pending_phase2_eap_resp = NULL; return; } buf_len = in_len; /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ buf_len += 500; buf_len *= 3; in_decrypted = os_malloc(buf_len); if (in_decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory " "for decryption"); return; } len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, in_data, in_len, in_decrypted, buf_len); if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " "data"); os_free(in_decrypted); eap_ttls_state(data, FAILURE); return; } if (data->state == PHASE_FINISHED) { if (len_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); } os_free(in_decrypted); return; } wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", in_decrypted, len_decrypted); if (eap_ttls_avp_parse(in_decrypted, len_decrypted, &parse) < 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs"); os_free(in_decrypted); eap_ttls_state(data, FAILURE); return; } 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 (eap_user_get(sm, parse.user_name, parse.user_name_len, 1) != 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not " "found in the user database"); eap_ttls_state(data, FAILURE); goto done; } }#ifdef EAP_TNC if (data->tnc_started && parse.eap == NULL) { wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP " "response from peer"); eap_ttls_state(data, FAILURE); goto done; }#endif /* EAP_TNC */ if (parse.eap) { eap_ttls_process_phase2_eap(sm, data, parse.eap, parse.eap_len); } else if (parse.user_password) { eap_ttls_process_phase2_pap(sm, data, parse.user_password, parse.user_password_len); } else if (parse.chap_password) { eap_ttls_process_phase2_chap(sm, data, parse.chap_challenge, parse.chap_challenge_len, parse.chap_password, parse.chap_password_len); } else if (parse.mschap_response) { eap_ttls_process_phase2_mschap(sm, data, parse.mschap_challenge, parse.mschap_challenge_len, parse.mschap_response, parse.mschap_response_len); } else if (parse.mschap2_response) { eap_ttls_process_phase2_mschapv2(sm, data, parse.mschap_challenge, parse.mschap_challenge_len, parse.mschap2_response, parse.mschap2_response_len); }done: os_free(in_decrypted); os_free(parse.eap);}static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data){#ifdef EAP_TNC if (!sm->tnc || data->state != SUCCESS || data->tnc_started) return; wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC"); if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC"); eap_ttls_state(data, FAILURE); return; } data->tnc_started = 1; eap_ttls_state(data, PHASE2_METHOD);#endif /* EAP_TNC */}static int eap_ttls_process_version(struct eap_sm *sm, void *priv, int peer_version){ struct eap_ttls_data *data = priv; if (peer_version < data->ttls_version) { wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; " "use version %d", peer_version, data->ttls_version, peer_version); 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;}static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, const struct wpabuf *respData){ struct eap_ttls_data *data = priv; switch (data->state) { case PHASE1: if (eap_server_tls_phase1(sm, &data->ssl) < 0) eap_ttls_state(data, FAILURE); break; case PHASE2_START: case PHASE2_METHOD: case PHASE_FINISHED: eap_ttls_process_phase2(sm, data, data->ssl.in_buf); eap_ttls_start_tnc(sm, data); break; case PHASE2_MSCHAPV2_RESP: if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.in_buf) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " "acknowledged response"); eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : SUCCESS); } else if (!data->mschapv2_resp_ok) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " "acknowledged error"); eap_ttls_state(data, FAILURE); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected " "frame from peer (payload len %lu, " "expected empty frame)", (unsigned long) wpabuf_len(data->ssl.in_buf)); eap_ttls_state(data, FAILURE); } eap_ttls_start_tnc(sm, data); break; default: wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s", data->state, __func__); break; }}static void eap_ttls_process(struct eap_sm *sm, void *priv, struct wpabuf *respData){ struct eap_ttls_data *data = priv; if (eap_server_tls_process(sm, &data->ssl, respData, data, EAP_TYPE_TTLS, eap_ttls_process_version, eap_ttls_process_msg) < 0) eap_ttls_state(data, FAILURE);}static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv){ struct eap_ttls_data *data = priv; return data->state == SUCCESS || data->state == FAILURE;}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; u8 *eapKeyData; 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); } if (eapKeyData) { *len = EAP_TLS_KEY_LEN; wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", eapKeyData, EAP_TLS_KEY_LEN); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); } return eapKeyData;}static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv){ struct eap_ttls_data *data = priv; return data->state == SUCCESS;}int eap_server_ttls_register(void){ struct eap_method *eap; int ret; eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); if (eap == NULL) return -1; eap->init = eap_ttls_init; eap->reset = eap_ttls_reset; eap->buildReq = eap_ttls_buildReq; eap->check = eap_ttls_check; eap->process = eap_ttls_process; eap->isDone = eap_ttls_isDone; eap->getKey = eap_ttls_getKey; eap->isSuccess = eap_ttls_isSuccess; ret = eap_server_method_register(eap); if (ret) eap_server_method_free(eap); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -