static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, u32 vendor_id, int mandatory, u8 *data, size_t len) { u8 *pos; pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); os_memcpy(pos, data, len); pos += len; AVP_PAD(start, pos); return pos; }
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; } return 0; }
static struct wpabuf * eap_ttls_avp_encapsulate(struct wpabuf *resp, u32 avp_code, int mandatory) { struct wpabuf *avp; u8 *pos; avp = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(resp) + 4); if (avp == NULL) { wpabuf_free(resp); return NULL; } pos = eap_ttls_avp_hdr(wpabuf_mhead(avp), avp_code, 0, mandatory, wpabuf_len(resp)); os_memcpy(pos, wpabuf_head(resp), wpabuf_len(resp)); pos += wpabuf_len(resp); AVP_PAD((const u8 *) wpabuf_head(avp), pos); wpabuf_free(resp); wpabuf_put(avp, pos - (u8 *) wpabuf_head(avp)); return avp; }
static int eap_ttls_avp_encapsulate(u8 **resp, size_t *resp_len, u32 avp_code, int mandatory) { u8 *avp, *pos; avp = os_malloc(sizeof(struct ttls_avp) + *resp_len + 4); if (avp == NULL) { os_free(*resp); *resp = NULL; *resp_len = 0; return -1; } pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, *resp_len); os_memcpy(pos, *resp, *resp_len); pos += *resp_len; AVP_PAD(avp, pos); os_free(*resp); *resp = avp; *resp_len = pos - avp; 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_TTLS_CHAP_CHALLENGE_LEN + 1); 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_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_TTLS_MSCHAP_CHALLENGE_LEN + 1); 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_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 + 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; }