static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_leap_data *data = priv; u8 *key, pw_hash_hash[16], pw_hash[16]; const u8 *addr[5], *password; size_t elen[5], password_len; int pwhash; if (data->state != LEAP_DONE) return NULL; password = eap_get_config_password2(sm, &password_len, &pwhash); if (password == NULL) return NULL; key = os_malloc(LEAP_KEY_LEN); if (key == NULL) return NULL; if (pwhash) { if (hash_nt_password_hash(password, pw_hash_hash)) { os_free(key); return NULL; } } else { if (nt_password_hash(password, password_len, pw_hash) || hash_nt_password_hash(pw_hash, pw_hash_hash)) { os_free(key); return NULL; } } wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", pw_hash_hash, 16); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", data->peer_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", data->peer_response, LEAP_RESPONSE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", data->ap_challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", data->ap_response, LEAP_RESPONSE_LEN); addr[0] = pw_hash_hash; elen[0] = 16; addr[1] = data->ap_challenge; elen[1] = LEAP_CHALLENGE_LEN; addr[2] = data->ap_response; elen[2] = LEAP_RESPONSE_LEN; addr[3] = data->peer_challenge; elen[3] = LEAP_CHALLENGE_LEN; addr[4] = data->peer_response; elen[4] = LEAP_RESPONSE_LEN; md5_vector(5, addr, elen, key); wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); *len = LEAP_KEY_LEN; return key; }
static void * eap_pwd_init(struct eap_sm *sm) { struct eap_pwd_data *data; const u8 *identity, *password; size_t identity_len, password_len; int fragment_size; int pwhash; password = eap_get_config_password2(sm, &password_len, &pwhash); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: No password configured!"); return NULL; } identity = eap_get_config_identity(sm, &identity_len); if (identity == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!"); return NULL; } if ((data = os_zalloc(sizeof(*data))) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail"); return NULL; } if ((data->bnctx = BN_CTX_new()) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); os_free(data); return NULL; } if ((data->id_peer = os_malloc(identity_len)) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); BN_CTX_free(data->bnctx); os_free(data); return NULL; } os_memcpy(data->id_peer, identity, identity_len); data->id_peer_len = identity_len; if ((data->password = os_malloc(password_len)) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); BN_CTX_free(data->bnctx); bin_clear_free(data->id_peer, data->id_peer_len); os_free(data); return NULL; } os_memcpy(data->password, password, password_len); data->password_len = password_len; data->password_hash = pwhash; data->out_frag_pos = data->in_frag_pos = 0; data->inbuf = data->outbuf = NULL; fragment_size = eap_get_config_fragment_size(sm); if (fragment_size <= 0) data->mtu = 1020; /* default from RFC 5931 */ else data->mtu = fragment_size; data->state = PWD_ID_Req; return data; }
static struct wpabuf * eap_mschapv2_change_password( struct eap_sm *sm, struct eap_mschapv2_data *data, struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id) { struct wpabuf *resp; int ms_len; const u8 *username, *password, *new_password; size_t username_len, password_len, new_password_len; struct eap_mschapv2_hdr *ms; struct ms_change_password *cp; u8 password_hash[16], password_hash_hash[16]; int pwhash; username = eap_get_config_identity(sm, &username_len); password = eap_get_config_password2(sm, &password_len, &pwhash); new_password = eap_get_config_new_password(sm, &new_password_len); if (username == NULL || password == NULL || new_password == NULL) return NULL; username = mschapv2_remove_domain(username, &username_len); ret->ignore = false; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_COND_SUCC; ret->allowNotifications = TRUE; ms_len = sizeof(*ms) + sizeof(*cp); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, EAP_CODE_RESPONSE, id); if (resp == NULL) return NULL; ms = wpabuf_put(resp, sizeof(*ms)); ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD; ms->mschapv2_id = req->mschapv2_id + 1; WPA_PUT_BE16(ms->ms_length, ms_len); cp = wpabuf_put(resp, sizeof(*cp)); if (pwhash) { if (encrypt_pw_block_with_password_hash( new_password, new_password_len, password, cp->encr_password)) goto fail; } else { if (new_password_encrypted_with_old_nt_password_hash( new_password, new_password_len, password, password_len, cp->encr_password)) goto fail; } if (pwhash) { u8 new_password_hash[16]; nt_password_hash(new_password, new_password_len, new_password_hash); nt_password_hash_encrypted_with_block(password, new_password_hash, cp->encr_hash); } else { old_nt_password_hash_encrypted_with_new_nt_password_hash( new_password, new_password_len, password, password_len, cp->encr_hash); } if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN)) goto fail; os_memset(cp->reserved, 0, 8); generate_nt_response(data->passwd_change_challenge, cp->peer_challenge, username, username_len, new_password, new_password_len, cp->nt_response); generate_authenticator_response(new_password, new_password_len, cp->peer_challenge, data->passwd_change_challenge, username, username_len, cp->nt_response, data->auth_response); data->auth_response_valid = 1; nt_password_hash(new_password, new_password_len, password_hash); hash_nt_password_hash(password_hash, password_hash_hash); get_master_key(password_hash_hash, cp->nt_response, data->master_key); data->master_key_valid = 1; os_memset(cp->flags, 0, 2); return resp; fail: wpabuf_free(resp); return NULL; }
static struct wpabuf * eap_mschapv2_challenge_reply( struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id, u8 mschapv2_id, const u8 *auth_challenge) { struct wpabuf *resp; struct eap_mschapv2_hdr *ms; u8 *peer_challenge; int ms_len; struct ms_response *r; size_t identity_len, password_len; const u8 *identity, *password; int pwhash; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generate Challenge Response\n"); identity = eap_get_config_identity(sm, &identity_len); password = eap_get_config_password2(sm, &password_len, &pwhash); if (identity == NULL || password == NULL) return NULL; ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, EAP_CODE_RESPONSE, id); if (resp == NULL) return NULL; ms = wpabuf_put(resp, sizeof(*ms)); ms->op_code = MSCHAPV2_OP_RESPONSE; ms->mschapv2_id = mschapv2_id; if (data->prev_error) ms->mschapv2_id++; WPA_PUT_BE16(ms->ms_length, ms_len); wpabuf_put_u8(resp, sizeof(*r)); /* Response */ r = wpabuf_put(resp, sizeof(*r)); peer_challenge = r->peer_challenge; if (data->peer_challenge) { peer_challenge = data->peer_challenge; os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN); } else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) { wpabuf_free(resp); return NULL; } os_memset(r->reserved, 0, 8); if (data->auth_challenge) auth_challenge = data->auth_challenge; if (mschapv2_derive_response(identity, identity_len, password, password_len, pwhash, auth_challenge, peer_challenge, r->nt_response, data->auth_response, data->master_key)) { wpabuf_free(resp); return NULL; } data->auth_response_valid = 1; data->master_key_valid = 1; r->flags = 0; wpabuf_put_data(resp, identity, identity_len); return resp; }
static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_leap_data *data = priv; struct wpabuf *resp; const u8 *pos, *challenge, *identity, *password; u8 challenge_len, *rpos; size_t identity_len, password_len, len; int pwhash; wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request"); identity = eap_get_config_identity(sm, &identity_len); password = eap_get_config_password2(sm, &password_len, &pwhash); if (identity == NULL || password == NULL) return NULL; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); if (pos == NULL || len < 3) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame"); ret->ignore = TRUE; return NULL; } if (*pos != LEAP_VERSION) { wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " "%d", *pos); ret->ignore = TRUE; return NULL; } pos++; pos++; /* skip unused byte */ challenge_len = *pos++; if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge " "(challenge_len=%d reqDataLen=%lu)", challenge_len, (unsigned long) wpabuf_len(reqData)); ret->ignore = TRUE; return NULL; } challenge = pos; os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP", challenge, LEAP_CHALLENGE_LEN); wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response"); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, 3 + LEAP_RESPONSE_LEN + identity_len, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) return NULL; wpabuf_put_u8(resp, LEAP_VERSION); wpabuf_put_u8(resp, 0); /* unused */ wpabuf_put_u8(resp, LEAP_RESPONSE_LEN); rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN); if (pwhash) challenge_response(challenge, password, rpos); else nt_challenge_response(challenge, password, password_len, rpos); os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", rpos, LEAP_RESPONSE_LEN); wpabuf_put_data(resp, identity, identity_len); data->state = LEAP_WAIT_SUCCESS; return resp; }
static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const struct wpabuf *reqData) { struct eap_leap_data *data = priv; const u8 *pos, *password; u8 response_len, pw_hash[16], pw_hash_hash[16], expected[LEAP_RESPONSE_LEN]; size_t password_len, len; int pwhash; wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); password = eap_get_config_password2(sm, &password_len, &pwhash); if (password == NULL) return NULL; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); if (pos == NULL || len < 3) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); ret->ignore = TRUE; return NULL; } if (*pos != LEAP_VERSION) { wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " "%d", *pos); ret->ignore = TRUE; return NULL; } pos++; pos++; /* skip unused byte */ response_len = *pos++; if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " "(response_len=%d reqDataLen=%lu)", response_len, (unsigned long) wpabuf_len(reqData)); ret->ignore = TRUE; return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", pos, LEAP_RESPONSE_LEN); os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); if (pwhash) { if (hash_nt_password_hash(password, pw_hash_hash)) { ret->ignore = TRUE; return NULL; } } else { if (nt_password_hash(password, password_len, pw_hash) || hash_nt_password_hash(pw_hash, pw_hash_hash)) { ret->ignore = TRUE; return NULL; } } challenge_response(data->ap_challenge, pw_hash_hash, expected); ret->methodState = METHOD_DONE; ret->allowNotifications = FALSE; if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) { wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " "response - authentication failed"); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", expected, LEAP_RESPONSE_LEN); ret->decision = DECISION_FAIL; return NULL; } ret->decision = DECISION_UNCOND_SUCC; /* LEAP is somewhat odd method since it sends EAP-Success in the middle * of the authentication. Use special variable to transit EAP state * machine to SUCCESS state. */ sm->leap_done = TRUE; data->state = LEAP_DONE; /* No more authentication messages expected; AP will send EAPOL-Key * frames if encryption is enabled. */ return NULL; }
static struct wpabuf * eap_mschapv2_change_password( struct eap_sm *sm, struct eap_mschapv2_data *data, struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id) { struct wpabuf *resp; int ms_len; const u8 *username, *password, *new_password; size_t username_len, password_len, new_password_len; struct eap_mschapv2_hdr *ms; struct ms_change_password *cp; u8 password_hash[16], password_hash_hash[16]; int pwhash; username = eap_get_config_identity(sm, &username_len); password = eap_get_config_password2(sm, &password_len, &pwhash); new_password = eap_get_config_new_password(sm, &new_password_len); if (username == NULL || password == NULL || new_password == NULL) return NULL; username = mschapv2_remove_domain(username, &username_len); ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_COND_SUCC; ret->allowNotifications = TRUE; ms_len = sizeof(*ms) + sizeof(*cp); resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, EAP_CODE_RESPONSE, id); if (resp == NULL) return NULL; ms = wpabuf_put(resp, sizeof(*ms)); ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD; ms->mschapv2_id = req->mschapv2_id + 1; WPA_PUT_BE16(ms->ms_length, ms_len); cp = wpabuf_put(resp, sizeof(*cp)); /* Encrypted-Password */ if (pwhash) { if (encrypt_pw_block_with_password_hash( new_password, new_password_len, password, cp->encr_password)) goto fail; } else { if (new_password_encrypted_with_old_nt_password_hash( new_password, new_password_len, password, password_len, cp->encr_password)) goto fail; } /* Encrypted-Hash */ if (pwhash) { u8 new_password_hash[16]; nt_password_hash(new_password, new_password_len, new_password_hash); nt_password_hash_encrypted_with_block(password, new_password_hash, cp->encr_hash); } else { old_nt_password_hash_encrypted_with_new_nt_password_hash( new_password, new_password_len, password, password_len, cp->encr_hash); } /* Peer-Challenge */ if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN)) goto fail; /* Reserved, must be zero */ os_memset(cp->reserved, 0, 8); /* NT-Response */ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge", cp->peer_challenge, MSCHAPV2_CHAL_LEN); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username", username, username_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password", new_password, new_password_len); generate_nt_response(data->passwd_change_challenge, cp->peer_challenge, username, username_len, new_password, new_password_len, cp->nt_response); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response", cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN); /* Authenticator response is not really needed yet, but calculate it * here so that challenges need not be saved. */ generate_authenticator_response(new_password, new_password_len, cp->peer_challenge, data->passwd_change_challenge, username, username_len, cp->nt_response, data->auth_response); data->auth_response_valid = 1; /* Likewise, generate master_key here since we have the needed data * available. */ nt_password_hash(new_password, new_password_len, password_hash); hash_nt_password_hash(password_hash, password_hash_hash); get_master_key(password_hash_hash, cp->nt_response, data->master_key); data->master_key_valid = 1; /* Flags */ os_memset(cp->flags, 0, 2); wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " "(change pw)", id, ms->mschapv2_id); return resp; fail: wpabuf_free(resp); return NULL; }
static struct wpabuf * eap_mschapv2_challenge_reply( struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id, u8 mschapv2_id, const u8 *auth_challenge) { struct wpabuf *resp; struct eap_mschapv2_hdr *ms; u8 *peer_challenge; int ms_len; struct ms_response *r; size_t identity_len, password_len; const u8 *identity, *password; int pwhash; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response"); identity = eap_get_config_identity(sm, &identity_len); password = eap_get_config_password2(sm, &password_len, &pwhash); if (identity == NULL || password == NULL) return NULL; ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, EAP_CODE_RESPONSE, id); if (resp == NULL) return NULL; ms = wpabuf_put(resp, sizeof(*ms)); ms->op_code = MSCHAPV2_OP_RESPONSE; ms->mschapv2_id = mschapv2_id; if (data->prev_error) { /* * TODO: this does not seem to be enough when processing two * or more failure messages. IAS did not increment mschapv2_id * in its own packets, but it seemed to expect the peer to * increment this for all packets(?). */ ms->mschapv2_id++; } WPA_PUT_BE16(ms->ms_length, ms_len); wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */ /* Response */ r = wpabuf_put(resp, sizeof(*r)); peer_challenge = r->peer_challenge; if (data->peer_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated " "in Phase 1"); peer_challenge = data->peer_challenge; os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN); } else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) { wpabuf_free(resp); return NULL; } os_memset(r->reserved, 0, 8); if (data->auth_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated " "in Phase 1"); auth_challenge = data->auth_challenge; } if (mschapv2_derive_response(identity, identity_len, password, password_len, pwhash, auth_challenge, peer_challenge, r->nt_response, data->auth_response, data->master_key)) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive " "response"); wpabuf_free(resp); return NULL; } data->auth_response_valid = 1; data->master_key_valid = 1; r->flags = 0; /* reserved, must be zero */ wpabuf_put_data(resp, identity, identity_len); wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " "(response)", id, ms->mschapv2_id); return resp; }