📄 eap_ttls.c
字号:
/* MS-CHAP2-Response */ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, RADIUS_VENDOR_ID_MICROSOFT, 1, EAP_TTLS_MSCHAPV2_RESPONSE_LEN); data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; *pos++ = data->ident; *pos++ = 0; /* Flags */ memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; memset(pos, 0, 8); /* Reserved, must be zero */ pos += 8; wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2: implicit auth_challenge", challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2: peer_challenge", peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 username", username, username_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password", config->password, config->password_len); generate_nt_response(challenge, peer_challenge, username, username_len, config->password, config->password_len, pos); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24); generate_authenticator_response(config->password, config->password_len, peer_challenge, challenge, username, username_len, pos, data->auth_response); data->auth_response_valid = 1; pos += 24; free(challenge); AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; if (sm->workaround) { /* At least FreeRADIUS seems to be terminating * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success * packet. */ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " "allow success without tunneled response"); ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_COND_SUCC; } return 0;}static int eap_ttls_phase2_request_mschap(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){ struct wpa_ssid *config = eap_get_config(sm); u8 *buf, *pos, *challenge; wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); pos = buf = malloc(config->identity_len + 1000); if (buf == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: 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); /* MS-CHAP-Challenge */ challenge = eap_tls_derive_key(sm, &data->ssl, "ttls challenge", EAP_TLS_KEY_LEN); if (challenge == NULL) { free(buf); wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " "implicit challenge"); return -1; } pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, RADIUS_VENDOR_ID_MICROSOFT, 1, challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); /* MS-CHAP-Response */ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, RADIUS_VENDOR_ID_MICROSOFT, 1, EAP_TTLS_MSCHAP_RESPONSE_LEN); data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; *pos++ = data->ident; *pos++ = 1; /* Flags: Use NT style passwords */ memset(pos, 0, 24); /* LM-Response */ pos += 24; nt_challenge_response(challenge, config->password, config->password_len, pos); /* NT-Response */ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", config->password, config->password_len); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); pos += 24; free(challenge); AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; /* EAP-TTLS/MSCHAP 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_pap(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){ struct wpa_ssid *config = eap_get_config(sm); u8 *buf, *pos; size_t pad; wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); pos = buf = malloc(config->identity_len + config->password_len + 100); if (buf == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS/PAP: 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); /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts * the data, so no separate encryption is used in the AVP itself. * However, the password is padded to obfuscate its length. */ pad = (16 - (config->password_len & 15)) & 15; pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, config->password_len + pad); memcpy(pos, config->password, config->password_len); pos += config->password_len; memset(pos, 0, pad); pos += pad; AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; /* EAP-TTLS/PAP 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_chap(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){ 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 = 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_tls_derive_key(sm, &data->ssl, "ttls challenge", EAP_TLS_KEY_LEN); if (challenge == NULL) { 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; free(challenge); AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; /* 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){ struct wpa_ssid *config = eap_get_config(sm); int res = 0; 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 (config->identity == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Identity not configured"); eap_sm_request_identity(sm, config); if (config->password == NULL) eap_sm_request_password(sm, config); return 0; } if (config->password == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Password not configured"); eap_sm_request_password(sm, config); return 0; } } switch (data->phase2_type) { case EAP_TTLS_PHASE2_EAP: res = eap_ttls_phase2_request_eap(sm, data, ret, req, hdr, resp, resp_len); break; case EAP_TTLS_PHASE2_MSCHAPV2: res = eap_ttls_phase2_request_mschapv2(sm, data, ret, req, hdr, resp, resp_len); break; case EAP_TTLS_PHASE2_MSCHAP: res = eap_ttls_phase2_request_mschap(sm, data, ret, req, hdr, resp, resp_len); break; case EAP_TTLS_PHASE2_PAP: res = eap_ttls_phase2_request_pap(sm, data, ret, req, hdr, resp, resp_len); break; case EAP_TTLS_PHASE2_CHAP: res = eap_ttls_phase2_request_chap(sm, data, ret, req, hdr, 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 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 buf_len, len_decrypted = 0, len, left, retval = 0; struct eap_hdr *hdr = NULL; u8 *resp = NULL, *mschapv2 = NULL, *eapdata = NULL; size_t resp_len, eap_len = 0; 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. */ 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) { 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 = 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 = malloc(buf_len); if (in_decrypted == NULL) { 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; } len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, msg, msg_len, in_decrypted, buf_len); free(data->ssl.tls_in); data->ssl.tls_in = NULL; data->ssl.tls_in_len = 0; if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " "data"); retval = -1; 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=%d expected %lu or more - dropped", 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -