📄 eap_ttls.c
字号:
if (data->mschapv2_resp_ok) { pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS, RADIUS_VENDOR_ID_MICROSOFT, 1, 43); *pos++ = data->mschapv2_ident; ret = os_snprintf((char *) pos, end - pos, "S="); if (ret >= 0 && ret < end - pos) pos += ret; pos += wpa_snprintf_hex_uppercase( (char *) pos, end - pos, data->mschapv2_auth_response, sizeof(data->mschapv2_auth_response)); } else { pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR, RADIUS_VENDOR_ID_MICROSOFT, 1, 6); os_memcpy(pos, "Failed", 6); pos += 6; AVP_PAD(req, pos); } req_len = pos - req; wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " "data", req, req_len); encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); os_free(req); return encr_req;}static struct wpabuf * eap_ttls_build_phase_finished( struct eap_sm *sm, struct eap_ttls_data *data, int final){ int len; struct wpabuf *req; const int max_len = 300; req = wpabuf_alloc(max_len); if (req == NULL) return NULL; len = tls_connection_ia_send_phase_finished(sm->ssl_ctx, data->ssl.conn, final, wpabuf_mhead(req), max_len); if (len < 0) { wpabuf_free(req); return NULL; } wpabuf_put(req, len); return req;}static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id){ struct eap_ttls_data *data = priv; if (data->ssl.state == FRAG_ACK) { return eap_server_tls_build_ack(id, EAP_TYPE_TTLS, data->ttls_version); } if (data->ssl.state == WAIT_FRAG_ACK) { return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, data->ttls_version, id); } switch (data->state) { case START: return eap_ttls_build_start(sm, data, id); case PHASE1: if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, " "starting Phase2"); eap_ttls_state(data, PHASE2_START); } break; case PHASE2_METHOD: wpabuf_free(data->ssl.out_buf); data->ssl.out_used = 0; data->ssl.out_buf = eap_ttls_build_phase2_eap_req(sm, data, id); break; case PHASE2_MSCHAPV2_RESP: wpabuf_free(data->ssl.out_buf); data->ssl.out_used = 0; data->ssl.out_buf = eap_ttls_build_phase2_mschapv2(sm, data); break; case PHASE_FINISHED: wpabuf_free(data->ssl.out_buf); data->ssl.out_used = 0; data->ssl.out_buf = eap_ttls_build_phase_finished(sm, data, 1); break; default: wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", __func__, data->state); return NULL; } return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, data->ttls_version, id);}static Boolean eap_ttls_check(struct eap_sm *sm, void *priv, struct wpabuf *respData){ const u8 *pos; size_t len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len); if (pos == NULL || len < 1) { wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame"); return TRUE; } return FALSE;}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, size_t user_password_len){ if (!sm->user || !sm->user->password || sm->user->password_hash || !(sm->user->ttls_auth & EAP_TTLS_AUTH_PAP)) { wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No plaintext user " "password configured"); eap_ttls_state(data, FAILURE); return; } if (sm->user->password_len != user_password_len || os_memcmp(sm->user->password, user_password, user_password_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password"); eap_ttls_state(data, FAILURE); return; } wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password"); eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : SUCCESS);}static void eap_ttls_process_phase2_chap(struct eap_sm *sm, struct eap_ttls_data *data, const u8 *challenge, size_t challenge_len, const u8 *password, size_t password_len){ u8 *chal, hash[CHAP_MD5_LEN]; if (challenge == NULL || password == NULL || challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN || password_len != 1 + EAP_TTLS_CHAP_PASSWORD_LEN) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid CHAP attributes " "(challenge len %lu password len %lu)", (unsigned long) challenge_len, (unsigned long) password_len); eap_ttls_state(data, FAILURE); return; } if (!sm->user || !sm->user->password || sm->user->password_hash || !(sm->user->ttls_auth & EAP_TTLS_AUTH_CHAP)) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No plaintext user " "password configured"); eap_ttls_state(data, FAILURE); return; } chal = eap_ttls_implicit_challenge(sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); if (chal == NULL) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate " "challenge from TLS data"); eap_ttls_state(data, FAILURE); return; } if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 || password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch"); os_free(chal); eap_ttls_state(data, FAILURE); return; } os_free(chal); /* MD5(Ident + Password + Challenge) */ chap_md5(password[0], sm->user->password, sm->user->password_len, challenge, challenge_len, hash); 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); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password"); eap_ttls_state(data, FAILURE); }}static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, struct eap_ttls_data *data, u8 *challenge, size_t challenge_len, u8 *response, size_t response_len){ u8 *chal, nt_response[24]; if (challenge == NULL || response == NULL || challenge_len != EAP_TTLS_MSCHAP_CHALLENGE_LEN || response_len != EAP_TTLS_MSCHAP_RESPONSE_LEN) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid MS-CHAP " "attributes (challenge len %lu response len %lu)", (unsigned long) challenge_len, (unsigned long) response_len); eap_ttls_state(data, FAILURE); return; } if (!sm->user || !sm->user->password || !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAP)) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: No user password " "configured"); eap_ttls_state(data, FAILURE); return; } chal = eap_ttls_implicit_challenge(sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); if (chal == NULL) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate " "challenge from TLS data"); eap_ttls_state(data, FAILURE); return; } if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 || response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch"); os_free(chal); eap_ttls_state(data, FAILURE); return; } os_free(chal); if (sm->user->password_hash) challenge_response(challenge, sm->user->password, nt_response); else nt_challenge_response(challenge, sm->user->password, sm->user->password_len, nt_response); 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); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response"); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received", response + 2 + 24, 24); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Expected", nt_response, 24); eap_ttls_state(data, FAILURE); }}static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, u8 *challenge, size_t challenge_len, u8 *response, size_t response_len){ u8 *chal, *username, nt_response[24], *rx_resp, *peer_challenge, *auth_challenge; size_t username_len, i; if (challenge == NULL || response == NULL || challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN || response_len != EAP_TTLS_MSCHAPV2_RESPONSE_LEN) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid MS-CHAP2 " "attributes (challenge len %lu response len %lu)", (unsigned long) challenge_len, (unsigned long) response_len); eap_ttls_state(data, FAILURE); return; } if (!sm->user || !sm->user->password || !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAPV2)) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user password " "configured"); eap_ttls_state(data, FAILURE); return; } /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ username = sm->identity; username_len = sm->identity_len; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } chal = eap_ttls_implicit_challenge( sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); if (chal == NULL) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate " "challenge from TLS data"); eap_ttls_state(data, FAILURE); return; } if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 || response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch"); os_free(chal); eap_ttls_state(data, FAILURE); return; } os_free(chal); auth_challenge = challenge; peer_challenge = response + 2; wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: User", username, username_len); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: auth_challenge", auth_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge", peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); if (sm->user->password_hash) { generate_nt_response_pwhash(auth_challenge, peer_challenge, username, username_len, sm->user->password, nt_response); } else { generate_nt_response(auth_challenge, peer_challenge, username, username_len, sm->user->password, sm->user->password_len, nt_response); } rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8; if (os_memcmp(nt_response, rx_resp, 24) == 0) { 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( sm->user->password, peer_challenge, auth_challenge, username, username_len, nt_response, data->mschapv2_auth_response); } else { generate_authenticator_response( sm->user->password, sm->user->password_len, peer_challenge, auth_challenge, username, username_len, nt_response, data->mschapv2_auth_response); } } else { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid " "NT-Response"); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Received", rx_resp, 24); wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Expected", nt_response, 24); data->mschapv2_resp_ok = 0; } eap_ttls_state(data, PHASE2_MSCHAPV2_RESP); data->mschapv2_ident = response[0];}static int eap_ttls_phase2_eap_init(struct eap_sm *sm, struct eap_ttls_data *data, EapType eap_type){ if (data->phase2_priv && data->phase2_method) { data->phase2_method->reset(sm, data->phase2_priv); data->phase2_method = NULL; data->phase2_priv = NULL; } data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, eap_type); if (!data->phase2_method) return -1; sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; return data->phase2_priv == NULL ? -1 : 0;}static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm, struct eap_ttls_data *data, u8 *in_data, size_t in_len){ u8 next_type = EAP_TYPE_NONE; struct eap_hdr *hdr; u8 *pos; size_t left; struct wpabuf buf; const struct eap_method *m = data->phase2_method; void *priv = data->phase2_priv; if (priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not " "initialized?!", __func__); return; } hdr = (struct eap_hdr *) in_data; pos = (u8 *) (hdr + 1); if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { left = in_len - sizeof(*hdr); wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; " "allowed types", pos + 1, left - 1); eap_sm_process_nak(sm, pos + 1, left - 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -