📄 eap_ttls.c
字号:
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=%d) - dropped", (int) avp_length, left); 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 = malloc(dlen); if (eapdata == NULL) { retval = -1; wpa_printf(MSG_WARNING, "EAP-TTLS: " "failed to allocate memory " "for Phase 2 EAP data"); goto done; } memcpy(eapdata, dpos, dlen); eap_len = dlen; } else { u8 *neweap = 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; } 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 { wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported " "AVP code %d vendor_id %d", (int) avp_code, (int) vendor_id); } pad = (4 - (avp_length & 3)) & 3; pos += avp_length + pad; left -= avp_length + pad; } switch (data->phase2_type) { case EAP_TTLS_PHASE2_EAP: if (eapdata == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in " "the packet - dropped"); retval = -1; goto done; } wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", eapdata, eap_len); hdr = (struct eap_hdr *) eapdata; if (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) eap_len, (unsigned long) sizeof(*hdr)); retval = -1; goto done; } len = be_to_host16(hdr->length); if (len > eap_len) { wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in " "Phase 2 EAP frame (EAP hdr len=%d, EAP " "data len in AVP=%lu)", len, (unsigned long) eap_len); retval = -1; goto done; } wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " "identifier=%d length=%d", hdr->code, hdr->identifier, len); process_eap: switch (hdr->code) { case EAP_CODE_REQUEST: if (eap_ttls_phase2_request(sm, data, ret, req, hdr, &resp, &resp_len)) { wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 " "Request processing failed"); retval = -1; goto done; } break; default: wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " "Phase 2 EAP header", hdr->code); retval = -1; break; } break; case EAP_TTLS_PHASE2_MSCHAPV2: if (mschapv2_error) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " "MS-CHAP-Error - failed"); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; *out_data = eap_tls_build_ack(&data->ssl, out_len, req->identifier, EAP_TYPE_TTLS, 0); break; } if (mschapv2 == NULL) { wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success" " AVP received for Phase2 MSCHAPV2"); retval = -1; break; } if (mschapv2[0] != data->ident) { wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch " "for Phase 2 MSCHAPV2 (received Ident " "0x%02x, expected 0x%02x)", mschapv2[0], data->ident); retval = -1; break; } if (!data->auth_response_valid || mschapv2[1] != 'S' || mschapv2[2] != '=' || hexstr2bin((char *) (mschapv2 + 3), recv_response, 20) || memcmp(data->auth_response, recv_response, 20) != 0) { wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid " "authenticator response in Phase 2 " "MSCHAPV2 success request"); retval = -1; break; } wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " "authentication succeeded"); 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. */ retval = 1; goto done; case EAP_TTLS_PHASE2_MSCHAP: case EAP_TTLS_PHASE2_PAP: case EAP_TTLS_PHASE2_CHAP: /* 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"); retval = -1; break; } if (resp) { wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", resp, resp_len); if (eap_ttls_encrypt(sm, data, req->identifier, resp, resp_len, out_data, out_len)) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt " "a Phase 2 frame"); } free(resp); } else if (config->pending_req_identity || config->pending_req_password || config->pending_req_otp || config->pending_req_new_password) { free(data->pending_phase2_req); data->pending_phase2_req = malloc(len_decrypted); if (data->pending_phase2_req) { memcpy(data->pending_phase2_req, in_decrypted, len_decrypted); data->pending_phase2_req_len = len_decrypted; } }done: free(in_decrypted); free(eapdata); if (retval < 0) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; } return retval;}static u8 * eap_ttls_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen){ const struct eap_hdr *req; size_t left; int res; u8 flags, *resp, id; const u8 *pos; struct eap_ttls_data *data = priv; pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, reqData, reqDataLen, &left, &flags); if (pos == NULL) return NULL; req = (const struct eap_hdr *) reqData; id = req->identifier; if (flags & EAP_TLS_FLAGS_START) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Start"); /* draft-ietf-pppext-eap-ttls-03.txt, Ch. 8.1: * EAP-TTLS Start packet may, in a future specification, be * allowed to contain data. Client based on this draft version * must ignore such data but must not reject the Start packet. */ left = 0; } resp = NULL; if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && !data->resuming) { res = eap_ttls_decrypt(sm, data, ret, req, pos, left, &resp, respDataLen); } else { res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, 0, id, pos, left, &resp, respDataLen); if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to Phase 2"); if (data->resuming) { wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth -" " may skip Phase 2"); ret->decision = DECISION_COND_SUCC; ret->methodState = METHOD_MAY_CONT; } data->phase2_start = 1; free(data->key_data); data->key_data = eap_tls_derive_key(sm, &data->ssl, "ttls keying material", EAP_TLS_KEY_LEN); if (data->key_data) { wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", data->key_data, EAP_TLS_KEY_LEN); } else { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to " "derive key"); } if (*respDataLen == 0) { if (eap_ttls_decrypt(sm, data, ret, req, NULL, 0, &resp, respDataLen)) { wpa_printf(MSG_WARNING, "EAP-TTLS: " "failed to process early " "start for Phase 2"); } res = 0; } data->resuming = 0; } } if (ret->methodState == METHOD_DONE) { ret->allowNotifications = FALSE; if (ret->decision == DECISION_UNCOND_SUCC || ret->decision == DECISION_COND_SUCC) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " "completed successfully"); data->phase2_success = 1; } } else if (sm->workaround && ret->methodState == METHOD_MAY_CONT && (ret->decision == DECISION_UNCOND_SUCC || ret->decision == DECISION_COND_SUCC)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " "completed successfully (EAP workaround)"); data->phase2_success = 1; } if (res == 1) { return eap_tls_build_ack(&data->ssl, respDataLen, id, EAP_TYPE_TTLS, 0); } return resp;}static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv){ struct eap_ttls_data *data = priv; return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && data->phase2_success;}static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv){ struct eap_ttls_data *data = priv; free(data->pending_phase2_req); data->pending_phase2_req = NULL;}static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv){ struct eap_ttls_data *data = priv; free(data->key_data); data->key_data = NULL; if (eap_tls_reauth_init(sm, &data->ssl)) { free(data); return NULL; } data->phase2_start = 0; data->phase2_success = 0; data->resuming = 1; data->reauth = 1; return priv;}static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, size_t buflen, int verbose){ struct eap_ttls_data *data = priv; int len; len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose); switch (data->phase2_type) { case EAP_TTLS_PHASE2_EAP: len += snprintf(buf + len, buflen - len, "EAP-TTLS Phase2 method=EAP-%s\n", data->phase2_method ? data->phase2_method->name : "?"); break; case EAP_TTLS_PHASE2_MSCHAPV2: len += snprintf(buf + len, buflen - len, "EAP-TTLS Phase2 method=MSCHAPV2\n"); break; case EAP_TTLS_PHASE2_MSCHAP: len += snprintf(buf + len, buflen - len, "EAP-TTLS Phase2 method=MSCHAP\n"); break; case EAP_TTLS_PHASE2_PAP: len += snprintf(buf + len, buflen - len, "EAP-TTLS Phase2 method=PAP\n"); break; case EAP_TTLS_PHASE2_CHAP: len += snprintf(buf + len, buflen - len, "EAP-TTLS Phase2 method=CHAP\n"); break; } return len;}static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv){ struct eap_ttls_data *data = priv; return data->key_data != NULL && data->phase2_success;}static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len){ struct eap_ttls_data *data = priv; u8 *key; if (data->key_data == NULL || !data->phase2_success) return NULL; key = malloc(EAP_TLS_KEY_LEN); if (key == NULL) return NULL; *len = EAP_TLS_KEY_LEN; memcpy(key, data->key_data, EAP_TLS_KEY_LEN); return key;}const struct eap_method eap_method_ttls ={ .method = EAP_TYPE_TTLS, .name = "TTLS", .init = eap_ttls_init, .deinit = eap_ttls_deinit, .process = eap_ttls_process, .isKeyAvailable = eap_ttls_isKeyAvailable, .getKey = eap_ttls_getKey, .get_status = eap_ttls_get_status, .has_reauth_data = eap_ttls_has_reauth_data, .deinit_for_reauth = eap_ttls_deinit_for_reauth, .init_for_reauth = eap_ttls_init_for_reauth,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -