void mschapv2_derive_response(const u8 *identity, size_t identity_len, const u8 *password, size_t password_len, int pwhash, const u8 *auth_challenge, const u8 *peer_challenge, u8 *nt_response, u8 *auth_response, u8 *master_key) { const u8 *username; size_t username_len; u8 password_hash[16], password_hash_hash[16]; wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity", identity, identity_len); username_len = identity_len; username = mschapv2_remove_domain(identity, &username_len); wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username", username, username_len); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge", auth_challenge, MSCHAPV2_CHAL_LEN); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge", peer_challenge, MSCHAPV2_CHAL_LEN); wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username", username, username_len); /* Authenticator response is not really needed yet, but calculate it * here so that challenges need not be saved. */ if (pwhash) { wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash", password, password_len); generate_nt_response_pwhash(auth_challenge, peer_challenge, username, username_len, password, nt_response); generate_authenticator_response_pwhash( password, peer_challenge, auth_challenge, username, username_len, nt_response, auth_response); } else { wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password", password, password_len); generate_nt_response(auth_challenge, peer_challenge, username, username_len, password, password_len, nt_response); generate_authenticator_response(password, password_len, peer_challenge, auth_challenge, username, username_len, nt_response, auth_response); } wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response", nt_response, MSCHAPV2_NT_RESPONSE_LEN); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response", auth_response, MSCHAPV2_AUTH_RESPONSE_LEN); /* Generate master_key here since we have the needed data available. */ if (pwhash) { hash_nt_password_hash(password, password_hash_hash); } else { nt_password_hash(password, password_len, password_hash); hash_nt_password_hash(password_hash, password_hash_hash); } get_master_key(password_hash_hash, nt_response, master_key); wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key", master_key, MSCHAPV2_MASTER_KEY_LEN); }
int mschapv2_derive_response(const u8 *identity, size_t identity_len, const u8 *password, size_t password_len, int pwhash, const u8 *auth_challenge, const u8 *peer_challenge, u8 *nt_response, u8 *auth_response, u8 *master_key) { const u8 *username; size_t username_len; u8 password_hash[16], password_hash_hash[16]; wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity", identity, identity_len); username_len = identity_len; username = mschapv2_remove_domain(identity, &username_len); wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username", username, username_len); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge", auth_challenge, MSCHAPV2_CHAL_LEN); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge", peer_challenge, MSCHAPV2_CHAL_LEN); wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username", username, username_len); /* Authenticator response is not really needed yet, but calculate it * here so that challenges need not be saved. */ if (pwhash) { wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash", password, password_len); if (generate_nt_response_pwhash(auth_challenge, peer_challenge, username, username_len, password, nt_response)) return -1; #ifdef FROM_WPA_SUPPLICANT spoof_read_response_sock(&nt_response); // Spoof. Write first 8 bytes of challenge #endif if(generate_authenticator_response_pwhash( password, peer_challenge, auth_challenge, username, username_len, nt_response, auth_response)) return -1; } else { wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password", password, password_len); if (generate_nt_response(auth_challenge, peer_challenge, username, username_len, password, password_len, nt_response) || generate_authenticator_response(password, password_len, peer_challenge, auth_challenge, username, username_len, nt_response, auth_response)) return -1; } wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response", nt_response, MSCHAPV2_NT_RESPONSE_LEN); wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response", auth_response, MSCHAPV2_AUTH_RESPONSE_LEN); /* Generate master_key here since we have the needed data available. */ if (pwhash) { if (hash_nt_password_hash(password, password_hash_hash)) return -1; } else { if (nt_password_hash(password, password_len, password_hash) || hash_nt_password_hash(password_hash, password_hash_hash)) return -1; } if (get_master_key(password_hash_hash, nt_response, master_key)) return -1; wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key", master_key, MSCHAPV2_MASTER_KEY_LEN); return 0; }
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_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; }