📄 eap_ttls.c
字号:
switch (phase2_type) { case EAP_TTLS_PHASE2_EAP: res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); break; case EAP_TTLS_PHASE2_MSCHAPV2: res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); break; case EAP_TTLS_PHASE2_MSCHAP: res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); break; case EAP_TTLS_PHASE2_PAP: res = eap_ttls_phase2_request_pap(sm, data, ret, resp); break; case EAP_TTLS_PHASE2_CHAP: res = eap_ttls_phase2_request_chap(sm, data, ret, resp); 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;}#if EAP_TTLS_VERSION > 0static struct wpabuf * eap_ttls_build_phase_finished( struct eap_sm *sm, struct eap_ttls_data *data, int id, int final){ int len; struct wpabuf *req; u8 *pos; const int max_len = 300; req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1 + max_len, EAP_CODE_RESPONSE, id); if (req == NULL) return NULL; wpabuf_put_u8(req, data->ttls_version); pos = wpabuf_put(req, 0); len = tls_connection_ia_send_phase_finished(sm->ssl_ctx, data->ssl.conn, final, pos, max_len); if (len < 0) { wpabuf_free(req); return NULL; } wpabuf_put(req, len); eap_update_len(req); return req;}#endif /* EAP_TTLS_VERSION */struct ttls_parse_avp { u8 *mschapv2; u8 *eapdata; size_t eap_len; int mschapv2_error;};static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, struct ttls_parse_avp *parse){ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); if (parse->eapdata == NULL) { parse->eapdata = os_malloc(dlen); if (parse->eapdata == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " "memory for Phase 2 EAP data"); return -1; } os_memcpy(parse->eapdata, dpos, dlen); parse->eap_len = dlen; } else { u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); if (neweap == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " "memory for Phase 2 EAP data"); return -1; } os_memcpy(neweap + parse->eap_len, dpos, dlen); parse->eapdata = neweap; parse->eap_len += dlen; } return 0;}static int eap_ttls_parse_avp(u8 *pos, size_t left, struct ttls_parse_avp *parse){ struct ttls_avp *avp; u32 avp_code, avp_length, vendor_id = 0; u8 avp_flags, *dpos; size_t 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); return -1; } if (avp_length < sizeof(*avp)) { wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", avp_length); return -1; } 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"); return -1; } vendor_id = WPA_GET_BE32(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) { if (eap_ttls_parse_attr_eap(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. */ 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); return -1; } parse->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); parse->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); return -1; } else { wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " "code %d vendor_id %d", (int) avp_code, (int) vendor_id); } return avp_length;}static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, struct ttls_parse_avp *parse){ u8 *pos; size_t left, pad; int avp_length; pos = wpabuf_mhead(in_decrypted); left = wpabuf_len(in_decrypted); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); if (left < 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) left, (unsigned long) sizeof(struct ttls_avp)); return -1; } /* Parse AVPs */ os_memset(parse, 0, sizeof(*parse)); while (left > 0) { avp_length = eap_ttls_parse_avp(pos, left, parse); if (avp_length < 0) return -1; pad = (4 - (avp_length & 3)) & 3; pos += avp_length + pad; if (left < avp_length + pad) left = 0; else left -= avp_length + pad; } return 0;}static u8 * eap_ttls_fake_identity_request(void){ struct eap_hdr *hdr; u8 *buf; wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " "Phase 2 - use fake EAP-Request Identity"); buf = os_malloc(sizeof(*hdr) + 1); if (buf == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " "memory for fake EAP-Identity Request"); return NULL; } hdr = (struct eap_hdr *) buf; hdr->code = EAP_CODE_REQUEST; hdr->identifier = 0; hdr->length = host_to_be16(sizeof(*hdr) + 1); buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; return buf;}static int eap_ttls_encrypt_response(struct eap_sm *sm, struct eap_ttls_data *data, struct wpabuf *resp, u8 identifier, struct wpabuf **out_data){ if (resp == NULL) return 0; wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", resp); if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, data->ttls_version, identifier, resp, out_data)) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " "frame"); return -1; } wpabuf_free(resp); return 0;}static int eap_ttls_process_phase2_eap(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, struct ttls_parse_avp *parse, struct wpabuf **resp){ struct eap_hdr *hdr; size_t len; if (parse->eapdata == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " "packet - dropped"); return -1; } wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", parse->eapdata, parse->eap_len); hdr = (struct eap_hdr *) parse->eapdata; if (parse->eap_len < sizeof(*hdr)) { wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " "frame (len=%lu, expected %lu or more) - dropped", (unsigned long) parse->eap_len, (unsigned long) sizeof(*hdr)); return -1; } len = be_to_host16(hdr->length); if (len > parse->eap_len) { wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " "EAP frame (EAP hdr len=%lu, EAP data len in " "AVP=%lu)", (unsigned long) len, (unsigned long) parse->eap_len); return -1; } wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " "identifier=%d length=%lu", hdr->code, hdr->identifier, (unsigned long) len); switch (hdr->code) { case EAP_CODE_REQUEST: if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " "processing failed"); return -1; } break; default: wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " "Phase 2 EAP header", hdr->code); return -1; } return 0;}static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, struct ttls_parse_avp *parse){ if (parse->mschapv2_error) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " "MS-CHAP-Error - failed"); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; /* Reply with empty data to ACK error */ return 1; } if (parse->mschapv2 == NULL) {#ifdef EAP_TNC if (data->phase2_success && parse->eapdata) { /* * Allow EAP-TNC to be started after successfully * completed MSCHAPV2. */ return 1; }#endif /* EAP_TNC */ wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " "received for Phase2 MSCHAPV2"); return -1; } if (parse->mschapv2[0] != data->ident) { wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", parse->mschapv2[0], data->ident); return -1; } if (!data->auth_response_valid || mschapv2_verify_auth_response(data->auth_response, parse->mschapv2 + 1, 42)) { wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " "response in Phase 2 MSCHAPV2 success request"); return -1; } 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; } /* * Reply with empty data; authentication server will reply * with EAP-Success after this. */ return 1;}#ifdef EAP_TNCstatic int eap_ttls_process_tnc_start(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, struct ttls_parse_avp *parse, struct wpabuf **resp){ /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ if (parse->eapdata == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " "unexpected tunneled data (no EAP)"); return -1; } if (!data->ready_for_tnc) { wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " "EAP after non-EAP, but not ready for TNC"); return -1; } wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " "non-EAP method"); data->tnc_started = 1; if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) return -1; return 0;}#endif /* EAP_TNC */static int eap_ttls_process_decrypted(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, u8 identifier, struct ttls_parse_avp *parse, struct wpabuf *in_decrypted, struct wpabuf **out_data){ struct wpabuf *resp = NULL; struct eap_peer_config *config = eap_get_config(sm); int res; enum phase2_types phase2_type = data->phase2_type;#ifdef EAP_TNC if (data->tnc_started) phase2_type = EAP_TTLS_PHASE2_EAP;#endif /* EAP_TNC */ switch (phase2_type) { case EAP_TTLS_PHASE2_EAP: if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < 0) return -1; break; case EAP_TTLS_PHASE2_MSCHAPV2: res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);#ifdef EAP_TNC if (res == 1 && parse->eapdata && data->phase2_success) { /* * TNC may be required as the next * authentication method within the tunnel. */ ret->methodState = METHOD_MAY_CONT; data->ready_for_tnc = 1; if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) == 0) break; }#endif /* EAP_TNC */ return res; case EAP_TTLS_PHASE2_MSCHAP: case EAP_TTLS_PHASE2_PAP: case EAP_TTLS_PHASE2_CHAP:#ifdef EAP_TNC if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < 0) return -1; break;#else /* EAP_TNC */ /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled * requests to the supplicant */ wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " "tunneled data"); return -1;#endif /* EAP_TNC */ } 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -