📄 eap_ttls.c
字号:
return 0;}static int eap_ttls_phase2_request_chap(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, u8 **resp, size_t *resp_len){ struct wpa_ssid *config = eap_get_config(sm); u8 *buf, *pos, *challenge; const u8 *addr[3]; size_t len[3]; wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); pos = buf = os_malloc(config->identity_len + 1000); if (buf == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to allocate memory"); return -1; } /* User-Name */ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, config->identity, config->identity_len); /* CHAP-Challenge */ challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN); if (challenge == NULL) { os_free(buf); wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " "implicit challenge"); return -1; } pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); /* CHAP-Password */ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, 1 + EAP_TTLS_CHAP_PASSWORD_LEN); data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; *pos++ = data->ident; /* MD5(Ident + Password + Challenge) */ addr[0] = &data->ident; len[0] = 1; addr[1] = config->password; len[1] = config->password_len; addr[2] = challenge; len[2] = EAP_TTLS_CHAP_CHALLENGE_LEN; md5_vector(3, addr, len, pos); wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", config->identity, config->identity_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", config->password, config->password_len); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", pos, EAP_TTLS_CHAP_PASSWORD_LEN); pos += EAP_TTLS_CHAP_PASSWORD_LEN; os_free(challenge); AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; 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; } return 0;}static int eap_ttls_phase2_request(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, const struct eap_hdr *req, struct eap_hdr *hdr, u8 **resp, size_t *resp_len){ int res = 0; size_t len; if (data->phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || data->phase2_type == EAP_TTLS_PHASE2_MSCHAP || data->phase2_type == EAP_TTLS_PHASE2_PAP || data->phase2_type == EAP_TTLS_PHASE2_CHAP) { if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Identity not configured"); eap_sm_request_identity(sm); if (eap_get_config_password(sm, &len) == NULL) eap_sm_request_password(sm); return 0; } if (eap_get_config_password(sm, &len) == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Password not configured"); eap_sm_request_password(sm); return 0; } } switch (data->phase2_type) { case EAP_TTLS_PHASE2_EAP: res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp, resp_len); break; case EAP_TTLS_PHASE2_MSCHAPV2: res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp, resp_len); break; case EAP_TTLS_PHASE2_MSCHAP: res = eap_ttls_phase2_request_mschap(sm, data, ret, resp, resp_len); break; case EAP_TTLS_PHASE2_PAP: res = eap_ttls_phase2_request_pap(sm, data, ret, resp, resp_len); break; case EAP_TTLS_PHASE2_CHAP: res = eap_ttls_phase2_request_chap(sm, data, ret, resp, resp_len); break; default: wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); res = -1; break; } if (res < 0) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; } return res;}static u8 * eap_ttls_build_phase_finished(struct eap_sm *sm, struct eap_ttls_data *data, int id, int final, size_t *reqDataLen){ int len; struct eap_hdr *req; u8 *pos; const int max_len = 300; len = sizeof(struct eap_hdr) + 2 + max_len; req = os_malloc(len); if (req == NULL) return NULL; req->code = EAP_CODE_RESPONSE; req->identifier = id; pos = (u8 *) (req + 1); *pos++ = EAP_TYPE_TTLS; *pos++ = data->ttls_version; len = tls_connection_ia_send_phase_finished(sm->ssl_ctx, data->ssl.conn, final, pos, max_len); if (len < 0) { os_free(req); return NULL; } *reqDataLen = sizeof(struct eap_hdr) + 2 + len; req->length = host_to_be16(*reqDataLen); return (u8 *) req;}static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, const struct eap_hdr *req, const u8 *in_data, size_t in_len, u8 **out_data, size_t *out_len){ u8 *in_decrypted = NULL, *pos; int res, retval = 0; struct eap_hdr *hdr = NULL; u8 *resp = NULL, *mschapv2 = NULL, *eapdata = NULL; size_t resp_len, eap_len = 0, len_decrypted = 0, len, buf_len, left; struct ttls_avp *avp; u8 recv_response[20]; int mschapv2_error = 0; struct wpa_ssid *config = eap_get_config(sm); const u8 *msg; size_t msg_len; int need_more_input; wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" " Phase 2", (unsigned long) in_len); if (data->pending_phase2_req) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " "skip decryption and use old data"); /* Clear TLS reassembly state. */ os_free(data->ssl.tls_in); data->ssl.tls_in = NULL; data->ssl.tls_in_len = 0; data->ssl.tls_in_left = 0; data->ssl.tls_in_total = 0; in_decrypted = data->pending_phase2_req; data->pending_phase2_req = NULL; len_decrypted = data->pending_phase2_req_len; if (data->pending_phase2_req_len == 0) { os_free(in_decrypted); in_decrypted = NULL; goto fake_req_identity; } goto continue_req; } if (in_len == 0 && data->phase2_start) { data->phase2_start = 0; /* EAP-TTLS does not use Phase2 on fast re-auth; this must be * done only if TLS part was indeed resuming a previous * session. Most Authentication Servers terminate EAP-TTLS * before reaching this point, but some do not. Make * wpa_supplicant stop phase 2 here, if needed. */ if (data->reauth && tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " "skip phase 2"); *out_data = eap_tls_build_ack(&data->ssl, out_len, req->identifier, EAP_TYPE_TTLS, 0); ret->methodState = METHOD_DONE; ret->decision = DECISION_UNCOND_SUCC; data->phase2_success = 1; return 0; } fake_req_identity: wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " "Phase 2 - use fake EAP-Request Identity"); buf_len = sizeof(*hdr) + 1; in_decrypted = os_malloc(buf_len); if (in_decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " "memory for fake EAP-Identity Request"); retval = -1; goto done; } hdr = (struct eap_hdr *) in_decrypted; hdr->code = EAP_CODE_REQUEST; hdr->identifier = 0; hdr->length = host_to_be16(sizeof(*hdr) + 1); in_decrypted[sizeof(*hdr)] = EAP_TYPE_IDENTITY; goto process_eap; } msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len, &msg_len, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; buf_len = in_len; if (data->ssl.tls_in_total > buf_len) buf_len = data->ssl.tls_in_total; in_decrypted = os_malloc(buf_len); if (in_decrypted == NULL) { os_free(data->ssl.tls_in); data->ssl.tls_in = NULL; data->ssl.tls_in_len = 0; wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory " "for decryption"); retval = -1; goto done; } res = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, msg, msg_len, in_decrypted, buf_len); os_free(data->ssl.tls_in); data->ssl.tls_in = NULL; data->ssl.tls_in_len = 0; if (res < 0) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " "data"); retval = -1; goto done; } len_decrypted = res; if (data->ttls_version > 0 && len_decrypted == 0 && tls_connection_ia_final_phase_finished(sm->ssl_ctx, data->ssl.conn)) { 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, req->identifier, 1, out_len); eap_ttls_v1_derive_key(sm, data); goto done; }continue_req: data->phase2_start = 0; wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", in_decrypted, len_decrypted); if (len_decrypted < sizeof(struct ttls_avp)) { wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" " len=%lu expected %lu or more - dropped", (unsigned long) len_decrypted, (unsigned long) sizeof(struct ttls_avp)); retval = -1; goto done; } /* Parse AVPs */ pos = in_decrypted; left = len_decrypted; mschapv2 = NULL; while (left > 0) { u32 avp_code, avp_length, vendor_id = 0; u8 avp_flags, *dpos; size_t pad, dlen; avp = (struct ttls_avp *) pos; avp_code = be_to_host32(avp->avp_code); avp_length = be_to_host32(avp->avp_length); avp_flags = (avp_length >> 24) & 0xff; avp_length &= 0xffffff; wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " "length=%d", (int) avp_code, avp_flags, (int) avp_length); if (avp_length > left) { wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " "(len=%d, left=%lu) - dropped", (int) avp_length, (unsigned long) left); retval = -1; goto done; } if (avp_length < sizeof(*avp)) { wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length " "%d", avp_length); retval = -1; goto done; } dpos = (u8 *) (avp + 1); dlen = avp_length - sizeof(*avp); if (avp_flags & AVP_FLAGS_VENDOR) { if (dlen < 4) { wpa_printf(MSG_WARNING, "EAP-TTLS: vendor AVP " "underflow"); retval = -1; goto done; } vendor_id = be_to_host32(* (u32 *) dpos); wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", (int) vendor_id); dpos += 4; dlen -= 4; } wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); if (eapdata == NULL) { eapdata = os_malloc(dlen); if (eapdata == NULL) { retval = -1; wpa_printf(MSG_WARNING, "EAP-TTLS: " "failed to allocate memory " "for Phase 2 EAP data"); goto done; } os_memcpy(eapdata, dpos, dlen); eap_len = dlen; } else { u8 *neweap = os_realloc(eapdata, eap_len + dlen); if (neweap == NULL) { retval = -1; wpa_printf(MSG_WARNING, "EAP-TTLS: " "failed to allocate memory " "for Phase 2 EAP data"); goto done; } os_memcpy(neweap + eap_len, dpos, dlen); eapdata = neweap; eap_len += dlen; } } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { /* This is an optional message that can be displayed to * the user. */ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", dpos, dlen); } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: " "MS-CHAP2-Success", dpos, dlen); if (dlen != 43) { wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " "MS-CHAP2-Success length " "(len=%lu, expected 43)", (unsigned long) dlen); retval = -1; break; } mschapv2 = dpos; } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: " "MS-CHAP-Error", dpos, dlen); mschapv2_error = 1; } else if (avp_flags & AVP_FLAGS_MANDATORY) { wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported " "mandatory AVP code %d vendor_id %d - " "dropped", (int) avp_code, (int) vendor_id); retval = -1; goto done; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -