📄 eap_ttls.c
字号:
if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || keys.client_random == NULL || keys.server_random == NULL || keys.inner_secret == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " "client random, or server random to derive " "implicit challenge"); return NULL; } rnd = os_malloc(keys.client_random_len + keys.server_random_len); challenge = os_malloc(len); if (rnd == NULL || challenge == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " "challenge derivation"); os_free(rnd); os_free(challenge); return NULL; } os_memcpy(rnd, keys.server_random, keys.server_random_len); os_memcpy(rnd + keys.server_random_len, keys.client_random, keys.client_random_len); if (tls_prf(keys.inner_secret, keys.inner_secret_len, "inner application challenge", rnd, keys.client_random_len + keys.server_random_len, challenge, len)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " "challenge"); os_free(rnd); os_free(challenge); return NULL; } os_free(rnd); wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", challenge, len); return challenge;}static int eap_ttls_phase2_nak(struct eap_ttls_data *data, struct eap_hdr *hdr, u8 **resp, size_t *resp_len){ struct eap_hdr *resp_hdr; u8 *pos = (u8 *) (hdr + 1); size_t i; /* TODO: add support for expanded Nak */ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 Request: Nak type=%d", *pos); wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Allowed Phase2 EAP types", (u8 *) data->phase2_eap_types, data->num_phase2_eap_types * sizeof(struct eap_method_type)); *resp_len = sizeof(struct eap_hdr) + 1; *resp = os_malloc(*resp_len + data->num_phase2_eap_types); if (*resp == NULL) return -1; resp_hdr = (struct eap_hdr *) (*resp); resp_hdr->code = EAP_CODE_RESPONSE; resp_hdr->identifier = hdr->identifier; pos = (u8 *) (resp_hdr + 1); *pos++ = EAP_TYPE_NAK; for (i = 0; i < data->num_phase2_eap_types; i++) { if (data->phase2_eap_types[i].vendor == EAP_VENDOR_IETF && data->phase2_eap_types[i].method < 256) { (*resp_len)++; *pos++ = data->phase2_eap_types[i].method; } } resp_hdr->length = host_to_be16(*resp_len); return 0;}static int eap_ttls_phase2_request_eap(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, struct eap_hdr *hdr, u8 **resp, size_t *resp_len){ size_t len = be_to_host16(hdr->length); u8 *pos; struct eap_method_ret iret; struct wpa_ssid *config = eap_get_config(sm); if (len <= sizeof(struct eap_hdr)) { wpa_printf(MSG_INFO, "EAP-TTLS: too short " "Phase 2 request (len=%lu)", (unsigned long) len); return -1; } pos = (u8 *) (hdr + 1); wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); switch (*pos) { case EAP_TYPE_IDENTITY: *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1); break; default: if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && data->phase2_eap_type.method == EAP_TYPE_NONE) { size_t i; for (i = 0; i < data->num_phase2_eap_types; i++) { if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || data->phase2_eap_types[i].method != *pos) continue; data->phase2_eap_type.vendor = data->phase2_eap_types[i].vendor; data->phase2_eap_type.method = data->phase2_eap_types[i].method; wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " "Phase 2 EAP vendor %d method %d", data->phase2_eap_type.vendor, data->phase2_eap_type.method); break; } } if (*pos != data->phase2_eap_type.method || *pos == EAP_TYPE_NONE) { if (eap_ttls_phase2_nak(data, hdr, resp, resp_len)) return -1; break; } if (data->phase2_priv == NULL) { data->phase2_method = eap_sm_get_eap_methods( EAP_VENDOR_IETF, *pos); if (data->phase2_method) { sm->init_phase2 = 1; sm->mschapv2_full_key = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; sm->mschapv2_full_key = 0; } } if (data->phase2_priv == NULL || data->phase2_method == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " "Phase 2 EAP method %d", *pos); return -1; } os_memset(&iret, 0, sizeof(iret)); *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, (u8 *) hdr, len, resp_len); if ((iret.methodState == METHOD_DONE || iret.methodState == METHOD_MAY_CONT) && (iret.decision == DECISION_UNCOND_SUCC || iret.decision == DECISION_COND_SUCC || iret.decision == DECISION_FAIL)) { ret->methodState = iret.methodState; ret->decision = iret.decision; } if (data->ttls_version > 0) { const struct eap_method *m = data->phase2_method; void *priv = data->phase2_priv; /* TTLSv1 requires TLS/IA FinalPhaseFinished */ if (ret->decision == DECISION_UNCOND_SUCC) ret->decision = DECISION_COND_SUCC; ret->methodState = METHOD_CONT; if (ret->decision == DECISION_COND_SUCC && m->isKeyAvailable && m->getKey && m->isKeyAvailable(sm, priv)) { u8 *key; size_t key_len; key = m->getKey(sm, priv, &key_len); if (key) { eap_ttls_ia_permute_inner_secret( sm, data, key, key_len); os_free(key); } } } break; } if (*resp == NULL && (config->pending_req_identity || config->pending_req_password || config->pending_req_otp)) { return 0; } if (*resp == NULL) return -1; wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", *resp, *resp_len); return eap_ttls_avp_encapsulate(resp, resp_len, RADIUS_ATTR_EAP_MESSAGE, 1);}static int eap_ttls_phase2_request_mschapv2(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, *username, *peer_challenge; size_t username_len, i; wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ username = config->identity; username_len = config->identity_len; pos = username; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } pos = buf = os_malloc(config->identity_len + 1000); if (buf == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: 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_ttls_implicit_challenge( sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN * 2 + 1); if (challenge == NULL) { os_free(buf); wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " "implicit challenge"); return -1; } peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, RADIUS_VENDOR_ID_MICROSOFT, 1, challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); /* 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 */ os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; os_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; if (data->ttls_version > 0) { u8 pw_hash[16], pw_hash_hash[16], master_key[16]; u8 session_key[2 * MSCHAPV2_KEY_LEN]; nt_password_hash(config->password, config->password_len, pw_hash); hash_nt_password_hash(pw_hash, pw_hash_hash); get_master_key(pw_hash_hash, pos /* 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)); } pos += 24; os_free(challenge); AVP_PAD(buf, pos); *resp = buf; *resp_len = pos - buf; if (sm->workaround && data->ttls_version == 0) { /* 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, 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 = os_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_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN); if (challenge == NULL) { os_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 */ os_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; 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/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, 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 = os_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); os_memcpy(pos, config->password, config->password_len); pos += config->password_len; os_memset(pos, 0, pad); pos += pad; 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/PAP does not provide tunneled success notification, * so assume that Phase2 succeeds. */ ret->methodState = METHOD_DONE; ret->decision = DECISION_COND_SUCC; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -