void old_nt_password_hash_encrypted_with_new_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_password_hash) { u8 old_password_hash[16], new_password_hash[16]; nt_password_hash(old_password, old_password_len, old_password_hash); nt_password_hash(new_password, new_password_len, new_password_hash); nt_password_hash_encrypted_with_block(old_password_hash, new_password_hash, encrypted_password_hash); }
int main(int argc, char *argv[]) { unsigned char password_hash[16]; size_t i; char *password, buf[64], *pos; if (argc > 1) password = argv[1]; else { if (fgets(buf, sizeof(buf), stdin) == NULL) { printf("Failed to read password\n"); return 1; } buf[sizeof(buf) - 1] = '\0'; pos = buf; while (*pos != '\0') { if (*pos == '\r' || *pos == '\n') { *pos = '\0'; break; } pos++; } password = buf; } if (nt_password_hash((u8 *) password, strlen(password), password_hash)) return -1; for (i = 0; i < sizeof(password_hash); i++) printf("%02x", password_hash[i]); printf("\n"); return 0; }
void nt_challenge_response(const u8 *challenge, const u8 *password, size_t password_len, u8 *response) { u8 password_hash[16]; nt_password_hash(password, password_len, password_hash); challenge_response(challenge, password_hash, response); }
static void eap_mschapv2_password_changed(struct eap_sm *sm, struct eap_mschapv2_data *data) { struct eap_peer_config *config = eap_get_config(sm); if (config && config->new_password) { wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_PASSWORD_CHANGED "EAP-MSCHAPV2: Password changed successfully"); data->prev_error = 0; os_free(config->password); if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { /* TODO: update external storage */ } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { config->password = os_malloc(16); config->password_len = 16; if (config->password) { nt_password_hash(config->new_password, config->new_password_len, config->password); } os_free(config->new_password); } else { config->password = config->new_password; config->password_len = config->new_password_len; } config->new_password = NULL; config->new_password_len = 0; } }
static void eap_mschapv2_password_changed(struct eap_sm *sm, struct eap_mschapv2_data *data) { struct eap_peer_config *config = eap_get_config(sm); if (config && config->new_password) { data->prev_error = 0; os_free(config->password); if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { config->password = os_malloc(16); config->password_len = 16; if (config->password) { nt_password_hash(config->new_password, config->new_password_len, config->password); } os_free(config->new_password); } else { config->password = config->new_password; config->password_len = config->new_password_len; } config->new_password = NULL; config->new_password_len = 0; } }
/** * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) * @new_password_len: Length of new_password * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) * @old_password_len: Length of old_password * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT) * Returns: 0 on success, -1 on failure */ int old_nt_password_hash_encrypted_with_new_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_password_hash) { u8 old_password_hash[16], new_password_hash[16]; if (nt_password_hash(old_password, old_password_len, old_password_hash) || nt_password_hash(new_password, new_password_len, new_password_hash)) return -1; nt_password_hash_encrypted_with_block(old_password_hash, new_password_hash, encrypted_password_hash); return 0; }
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; }
/** * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5 * @challenge: 8-octet Challenge (IN) * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @response: 24-octet Response (OUT) * Returns: 0 on success, -1 on failure */ int nt_challenge_response(const u8 *challenge, const u8 *password, size_t password_len, u8 *response) { u8 password_hash[16]; if (nt_password_hash(password, password_len, password_hash)) return -1; challenge_response(challenge, password_hash, response); return 0; }
void new_password_encrypted_with_old_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_pw_block) { u8 password_hash[16]; nt_password_hash(old_password, old_password_len, password_hash); encrypt_pw_block_with_password_hash(new_password, new_password_len, password_hash, encrypted_pw_block); }
void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, const u8 *username, size_t username_len, const u8 *password, size_t password_len, u8 *response) { u8 challenge[8]; u8 password_hash[16]; challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge); nt_password_hash(password, password_len, password_hash); challenge_response(challenge, password_hash, response); }
/** * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @nt_response: 24-octet NT-Response (IN) * @peer_challenge: 16-octet PeerChallenge (IN) * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually * encoded as a 42-octet ASCII string (S=hexdump_of_response) * Returns: 0 on success, -1 on failure */ int generate_authenticator_response(const u8 *password, size_t password_len, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, const u8 *nt_response, u8 *response) { u8 password_hash[16]; if (nt_password_hash(password, password_len, password_hash)) return -1; return generate_authenticator_response_pwhash( password_hash, peer_challenge, auth_challenge, username, username_len, nt_response, response); }
/** * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @peer_challenge: 16-octet PeerChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @password: 0-to-256-unicode-char Password (IN; UTF-8) * @password_len: Length of password * @response: 24-octet Response (OUT) * Returns: 0 on success, -1 on failure */ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, const u8 *username, size_t username_len, const u8 *password, size_t password_len, u8 *response) { u8 challenge[8]; u8 password_hash[16]; if (challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge) || nt_password_hash(password, password_len, password_hash)) return -1; challenge_response(challenge, password_hash, response); return 0; }
/** * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) * @new_password_len: Length of new_password * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) * @old_password_len: Length of old_password * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT) * Returns: 0 on success, -1 on failure */ int new_password_encrypted_with_old_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_pw_block) { u8 password_hash[16]; if (nt_password_hash(old_password, old_password_len, password_hash)) return -1; if (encrypt_pw_block_with_password_hash(new_password, new_password_len, password_hash, encrypted_pw_block)) return -1; return 0; }
static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_leap_data *data = priv; struct wpa_ssid *config = eap_get_config(sm); u8 *key, pw_hash_hash[16], pw_hash[16]; const u8 *addr[5]; size_t elen[5]; if (data->state != LEAP_DONE) return NULL; key = malloc(LEAP_KEY_LEN); if (key == NULL) return NULL; nt_password_hash(config->password, config->password_len, pw_hash); hash_nt_password_hash(pw_hash, pw_hash_hash); 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; }
/** * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 * @password: 0-to-256-unicode-char Password (IN) * @password_len: Length of password * @nt_response: 24-octet NT-Response (IN) * @peer_challenge: 16-octet PeerChallenge (IN) * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @response: 42-octet AuthenticatorResponse (OUT) */ void generate_authenticator_response(const u8 *password, size_t password_len, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, const u8 *nt_response, u8 *response) { static const u8 magic1[39] = { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; static const u8 magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E }; u8 password_hash[16], password_hash_hash[16], challenge[8]; const unsigned char *addr1[3]; const size_t len1[3] = { 16, 24, sizeof(magic1) }; const unsigned char *addr2[3]; const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) }; addr1[0] = password_hash_hash; addr1[1] = nt_response; addr1[2] = magic1; addr2[0] = response; addr2[1] = challenge; addr2[2] = magic2; nt_password_hash(password, password_len, password_hash); hash_nt_password_hash(password_hash, password_hash_hash); sha1_vector(3, addr1, len1, response); challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge); sha1_vector(3, addr2, len2, response); }
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 u8 * eap_leap_process_response(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, size_t *respDataLen) { struct eap_leap_data *data = priv; struct wpa_ssid *config = eap_get_config(sm); const struct eap_hdr *resp; const u8 *pos; u8 response_len, pw_hash[16], pw_hash_hash[16], expected[LEAP_RESPONSE_LEN]; wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); resp = (const struct eap_hdr *) reqData; pos = (const u8 *) (resp + 1); if (reqDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_LEAP) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); ret->ignore = TRUE; return NULL; } pos++; 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 > reqDataLen - sizeof(*resp) - 4) { wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " "(response_len=%d reqDataLen=%lu", response_len, (unsigned long) reqDataLen); ret->ignore = TRUE; return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", pos, LEAP_RESPONSE_LEN); memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); nt_password_hash(config->password, config->password_len, pw_hash); hash_nt_password_hash(pw_hash, pw_hash_hash); challenge_response(data->ap_challenge, pw_hash_hash, expected); ret->methodState = METHOD_DONE; ret->allowNotifications = FALSE; if (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; }
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); }
static void eap_mschapv2_process_response(struct eap_sm *sm, struct eap_mschapv2_data *data, struct wpabuf *respData) { struct eap_mschapv2_hdr *resp; const u8 *pos, *end, *peer_challenge, *nt_response, *name; u8 flags; size_t len, name_len, i; u8 expected[24]; u8 challenge_hash1[8]; const u8 *username, *user; size_t username_len, user_len; int x; char *buf; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, &len); if (pos == NULL || len < 1) return; /* Should not happen - frame already validated */ end = pos + len; resp = (struct eap_mschapv2_hdr *) pos; pos = (u8 *) (resp + 1); if (len < sizeof(*resp) + 1 + 49 || resp->op_code != MSCHAPV2_OP_RESPONSE || pos[0] != 49) { wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response", respData); data->state = FAILURE; return; } data->resp_mschapv2_id = resp->mschapv2_id; pos++; peer_challenge = pos; pos += 16 + 8; nt_response = pos; pos += 24; flags = *pos++; name = pos; name_len = end - name; if (data->peer_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured " "Peer-Challenge"); peer_challenge = data->peer_challenge; } wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge", peer_challenge, 16); wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24); wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len); challenge_hash(peer_challenge, data->auth_challenge, name, name_len, challenge_hash1); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: Challenge Hash", challenge_hash1, 8); wpa_printf(MSG_INFO, "MANA (EAP-FAST) : Username:%s", name); wpa_printf(MSG_INFO, "MANA (EAP-FAST) : Challenge"); printf("MANA (EAP-FAST) : "); for (x=0;x<7;x++) printf("%02x:",challenge_hash1[x]); printf("%02x\n",challenge_hash1[7]); wpa_printf(MSG_INFO, "MANA (EAP-FAST) : Response"); printf("MANA (EAP-FAST) : "); for (x=0;x<23;x++) printf("%02x:",nt_response[x]); printf("%02x\n",nt_response[23]); char *ennode = getenv("KARMANODE"); FILE *f = fopen(ennode, "a"); if (f != NULL) { const char *hdr = "CHAP"; fprintf(f, "%s|%s|", hdr, name); for (x = 0; x < 7; x++) { fprintf(f, "%02x:", challenge_hash1[x]); } fprintf(f, "%02x|", challenge_hash1[7]); for (x = 0; x < 23; x++) { fprintf(f, "%02x:", nt_response[x]); } fprintf(f, "%02x\n", nt_response[23]); fclose(f); } buf = os_malloc(name_len * 4 + 1); if (buf) { printf_encode(buf, name_len * 4 + 1, name, name_len); eap_log_msg(sm, "EAP-MSCHAPV2 Name '%s'", buf); os_free(buf); } /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ username = sm->identity; username_len = sm->identity_len; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } user = name; user_len = name_len; for (i = 0; i < user_len; i++) { if (user[i] == '\\') { user_len -= i + 1; user += i + 1; break; } } if (username_len != user_len || os_memcmp(username, user, username_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names"); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user " "name", username, username_len); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user " "name", user, user_len); data->state = FAILURE; return; } wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name", username, username_len); if (sm->user->password_hash) { //res = generate_nt_response_pwhash(data->auth_challenge, generate_nt_response_pwhash(data->auth_challenge, peer_challenge, username, username_len, sm->user->password, expected); } else { //res = generate_nt_response(data->auth_challenge, generate_nt_response(data->auth_challenge, peer_challenge, username, username_len, sm->user->password, sm->user->password_len, expected); } //if (res) { //data->state = FAILURE; //return; //} nt_response = expected; //os_memset((void *)nt_response, 0, 24); //os_memset((void *)expected, 0, 24); //if (os_memcmp_const(nt_response, expected, 24) == 0) { const u8 *pw_hash; u8 pw_hash_buf[16], pw_hash_hash[16]; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response"); data->state = SUCCESS_REQ; /* Authenticator response is not really needed yet, but * calculate it here so that peer_challenge and username need * not be saved. */ if (sm->user->password_hash) { pw_hash = sm->user->password; } else { if (nt_password_hash(sm->user->password, sm->user->password_len, pw_hash_buf) < 0) { //data->state = FAILURE; data->state = SUCCESS; //return; } pw_hash = pw_hash_buf; } generate_authenticator_response_pwhash( pw_hash, peer_challenge, data->auth_challenge, username, username_len, nt_response, data->auth_response); hash_nt_password_hash(pw_hash, pw_hash_hash); get_master_key(pw_hash_hash, nt_response, data->master_key); data->master_key_valid = 1; wpa_hexdump_key(MSG_INFO, "EAP-MSCHAPV2: Derived Master Key", data->master_key, MSCHAPV2_KEY_LEN); //} else { //data->state = SUCCESS; //} }
int main(int argc, char *argv[]) { /* Test vector from RFC2759 example */ u8 *username = "******"; u8 *password = "******"; u8 auth_challenge[] = { 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E, 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28 }; u8 peer_challenge[] = { 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E }; u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 }; u8 password_hash[] = { 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6, 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE }; u8 nt_response[] = { 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E, 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54, 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF }; u8 password_hash_hash[] = { 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C, 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F }; u8 authenticator_response[] = { 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6, 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66, 0x93, 0x2C, 0xDA, 0x56 }; u8 master_key[] = { 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C, 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31 }; u8 send_start_key[] = { 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B, 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB }; u8 buf[32]; int errors = 0; printf("Testing ms_funcs.c\n"); challenge_hash(peer_challenge, auth_challenge, username, strlen(username), buf); if (memcmp(challenge, buf, sizeof(challenge)) != 0) { printf("challenge_hash failed\n"); errors++; } nt_password_hash(password, strlen(password), buf); if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) { printf("nt_password_hash failed\n"); errors++; } generate_nt_response(auth_challenge, peer_challenge, username, strlen(username), password, strlen(password), buf); if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) { printf("generate_nt_response failed\n"); errors++; } hash_nt_password_hash(password_hash, buf); if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) { printf("hash_nt_password_hash failed\n"); errors++; } generate_authenticator_response(password, strlen(password), peer_challenge, auth_challenge, username, strlen(username), nt_response, buf); if (memcmp(authenticator_response, buf, sizeof(authenticator_response)) != 0) { printf("generate_authenticator_response failed\n"); errors++; } get_master_key(password_hash_hash, nt_response, buf); if (memcmp(master_key, buf, sizeof(master_key)) != 0) { printf("get_master_key failed\n"); errors++; } get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1); if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) { printf("get_asymetric_start_key failed\n"); errors++; } if (errors) printf("FAILED! %d errors\n", errors); return errors; }
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; }
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 u8 * eap_mschapv2_challenge(struct eap_sm *sm, struct eap_mschapv2_data *data, struct eap_method_ret *ret, struct eap_mschapv2_hdr *req, size_t *respDataLen) { struct wpa_ssid *config = eap_get_config(sm); u8 *challenge, *peer_challenge, *username, *pos; int challenge_len, i, ms_len; size_t len, username_len; struct eap_mschapv2_hdr *resp; u8 password_hash[16], password_hash_hash[16]; /* 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; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge"); len = be_to_host16(req->length); pos = (u8 *) (req + 1); challenge_len = *pos++; if (challenge_len != 16) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length " "%d", challenge_len); ret->ignore = TRUE; return NULL; } if (len - challenge_len - 10 < 0) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge" " packet: len=%lu challenge_len=%d", (unsigned long) len, challenge_len); } challenge = pos; pos += challenge_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername", pos, len - challenge_len - 10); ret->ignore = FALSE; ret->methodState = METHOD_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response"); *respDataLen = sizeof(*resp) + 1 + MSCHAPV2_RESP_LEN + config->identity_len; resp = malloc(*respDataLen); if (resp == NULL) return NULL; memset(resp, 0, *respDataLen); resp->code = EAP_CODE_RESPONSE; resp->identifier = req->identifier; resp->length = host_to_be16(*respDataLen); resp->type = EAP_TYPE_MSCHAPV2; resp->op_code = MSCHAPV2_OP_RESPONSE; resp->mschapv2_id = req->mschapv2_id; ms_len = *respDataLen - 5; resp->ms_length[0] = ms_len >> 8; resp->ms_length[1] = ms_len & 0xff; pos = (u8 *) (resp + 1); *pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */ /* Response */ peer_challenge = pos; if (data->peer_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated " "in Phase 1"); peer_challenge = data->peer_challenge; } else if (hostapd_get_rand(peer_challenge, 16)) { free(resp); return NULL; } pos += 16; pos += 8; /* Reserved, must be zero */ if (data->auth_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated " "in Phase 1"); challenge = data->auth_challenge; } wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", challenge, 16); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge", peer_challenge, 16); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username", username, username_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-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-MSCHAPV2: response", pos, 24); /* Authenticator response is not really needed yet, but calculate it * here so that challenges need not be saved. */ generate_authenticator_response(config->password, config->password_len, peer_challenge, challenge, username, username_len, pos, data->auth_response); data->auth_response_valid = 1; /* Likewise, generate master_key here since we have the needed data * available. */ nt_password_hash(config->password, config->password_len, password_hash); hash_nt_password_hash(password_hash, password_hash_hash); get_master_key(password_hash_hash, pos /* nt_response */, data->master_key); data->master_key_valid = 1; pos += 24; pos++; /* Flag / reserved, must be zero */ memcpy(pos, config->identity, config->identity_len); return (u8 *) 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 void eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, struct eap_method_ret *ret, const struct wpabuf *reqData, const u8 *payload, size_t payload_len) { struct eap_pwd_id *id; const u8 *password; size_t password_len; u8 pwhashhash[16]; int res; if (data->state != PWD_ID_Req) { ret->ignore = TRUE; eap_pwd_state(data, FAILURE); return; } if (payload_len < sizeof(struct eap_pwd_id)) { ret->ignore = TRUE; eap_pwd_state(data, FAILURE); return; } id = (struct eap_pwd_id *) payload; data->group_num = be_to_host16(id->group_num); wpa_printf(MSG_DEBUG, "EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u", data->group_num, id->random_function, id->prf, id->prep); if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || (id->prf != EAP_PWD_DEFAULT_PRF)) { ret->ignore = TRUE; eap_pwd_state(data, FAILURE); return; } if (id->prep != EAP_PWD_PREP_NONE && id->prep != EAP_PWD_PREP_MS) { wpa_printf(MSG_DEBUG, "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)", id->prep); eap_pwd_state(data, FAILURE); return; } if (id->prep == EAP_PWD_PREP_NONE && data->password_hash) { wpa_printf(MSG_DEBUG, "EAP-PWD: Unhashed password not available"); eap_pwd_state(data, FAILURE); return; } wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d", data->group_num); data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id)); if (data->id_server == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); eap_pwd_state(data, FAILURE); return; } data->id_server_len = payload_len - sizeof(struct eap_pwd_id); os_memcpy(data->id_server, id->identity, data->id_server_len); wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of", data->id_server, data->id_server_len); data->grp = os_zalloc(sizeof(EAP_PWD_group)); if (data->grp == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " "group"); eap_pwd_state(data, FAILURE); return; } if (id->prep == EAP_PWD_PREP_MS) { if (data->password_hash) { res = hash_nt_password_hash(data->password, pwhashhash); } else { u8 pwhash[16]; res = nt_password_hash(data->password, data->password_len, pwhash); if (res == 0) res = hash_nt_password_hash(pwhash, pwhashhash); os_memset(pwhash, 0, sizeof(pwhash)); } if (res) { eap_pwd_state(data, FAILURE); return; } password = pwhashhash; password_len = sizeof(pwhashhash); } else { password = data->password; password_len = data->password_len; } /* compute PWE */ res = compute_password_element(data->grp, data->group_num, password, password_len, data->id_server, data->id_server_len, data->id_peer, data->id_peer_len, id->token); os_memset(pwhashhash, 0, sizeof(pwhashhash)); if (res) { wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE"); eap_pwd_state(data, FAILURE); return; } wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...", BN_num_bits(data->grp->prime)); data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) + data->id_peer_len); if (data->outbuf == NULL) { eap_pwd_state(data, FAILURE); return; } wpabuf_put_be16(data->outbuf, data->group_num); wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC); wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF); wpabuf_put_data(data->outbuf, id->token, sizeof(id->token)); wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE); wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len); eap_pwd_state(data, PWD_Commit_Req); }
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; }
static u8 * eap_mschapv2_challenge(struct eap_sm *sm, struct eap_mschapv2_data *data, struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, size_t *respDataLen) { u8 *challenge, *peer_challenge, *pos; int ms_len; size_t i, len, challenge_len, username_len, identity_len, password_len; struct eap_mschapv2_hdr *resp; u8 password_hash[16], password_hash_hash[16]; const u8 *username, *identity, *password; identity = eap_get_config_identity(sm, &identity_len); password = eap_get_config_password(sm, &password_len); if (identity == NULL || password == NULL) return NULL; /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ username = identity; username_len = identity_len; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge"); len = be_to_host16(req->length); pos = (u8 *) (req + 1); challenge_len = *pos++; if (challenge_len != 16) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length " "%lu", (unsigned long) challenge_len); ret->ignore = TRUE; return NULL; } if (len < 10 || len - 10 < challenge_len) { wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge" " packet: len=%lu challenge_len=%lu", (unsigned long) len, (unsigned long) challenge_len); ret->ignore = TRUE; return NULL; } if (data->passwd_change_challenge_valid) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the " "failure message"); challenge = data->passwd_change_challenge; } else challenge = pos; pos += challenge_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername", pos, len - challenge_len - 10); ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response"); *respDataLen = sizeof(*resp) + 1 + MSCHAPV2_RESP_LEN + identity_len; resp = wpa_zalloc(*respDataLen); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = req->identifier; resp->length = host_to_be16(*respDataLen); resp->type = EAP_TYPE_MSCHAPV2; resp->op_code = MSCHAPV2_OP_RESPONSE; resp->mschapv2_id = req->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(?). */ resp->mschapv2_id++; } ms_len = *respDataLen - 5; WPA_PUT_BE16(resp->ms_length, ms_len); pos = (u8 *) (resp + 1); *pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */ /* Response */ peer_challenge = pos; if (data->peer_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated " "in Phase 1"); peer_challenge = data->peer_challenge; } else if (hostapd_get_rand(peer_challenge, 16)) { free(resp); return NULL; } pos += 16; pos += 8; /* Reserved, must be zero */ if (data->auth_challenge) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated " "in Phase 1"); challenge = data->auth_challenge; } wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", challenge, 16); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge", peer_challenge, 16); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username", username, username_len); wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password", password, password_len); generate_nt_response(challenge, peer_challenge, username, username_len, password, password_len, pos); wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", pos, 24); /* Authenticator response is not really needed yet, but calculate it * here so that challenges need not be saved. */ generate_authenticator_response(password, password_len, peer_challenge, challenge, username, username_len, pos, data->auth_response); data->auth_response_valid = 1; /* Likewise, generate master_key here since we have the needed data * available. */ nt_password_hash(password, password_len, password_hash); hash_nt_password_hash(password_hash, password_hash_hash); get_master_key(password_hash_hash, pos /* nt_response */, data->master_key); data->master_key_valid = 1; pos += 24; pos++; /* Flag / reserved, must be zero */ memcpy(pos, identity, identity_len); wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " "(response)", resp->identifier, resp->mschapv2_id); return (u8 *) resp; }
static void eap_mschapv2_process_response(struct eap_sm *sm, struct eap_mschapv2_data *data, u8 *respData, size_t respDataLen) { struct eap_mschapv2_hdr *resp; const u8 *pos, *end, *peer_challenge, *nt_response, *name; u8 flags; size_t len, name_len, i; u8 expected[24]; const u8 *username, *user; size_t username_len, user_len; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, respDataLen, &len); if (pos == NULL || len < 1) return; /* Should not happen - frame already validated */ end = pos + len; resp = (struct eap_mschapv2_hdr *) pos; pos = (u8 *) (resp + 1); if (len < sizeof(*resp) + 1 + 49 || resp->op_code != MSCHAPV2_OP_RESPONSE || pos[0] != 49) { wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response", respData, respDataLen); data->state = FAILURE; return; } data->resp_mschapv2_id = resp->mschapv2_id; pos++; peer_challenge = pos; pos += 16 + 8; nt_response = pos; pos += 24; flags = *pos++; name = pos; name_len = end - name; wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge", peer_challenge, 16); wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24); wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len); /* MSCHAPv2 does not include optional domain name in the * challenge-response calculation, so remove domain prefix * (if present). */ username = sm->identity; username_len = sm->identity_len; for (i = 0; i < username_len; i++) { if (username[i] == '\\') { username_len -= i + 1; username += i + 1; break; } } user = name; user_len = name_len; for (i = 0; i < user_len; i++) { if (user[i] == '\\') { user_len -= i + 1; user += i + 1; break; } } if (username_len != user_len || memcmp(username, user, username_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names"); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user " "name", username, username_len); wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user " "name", user, user_len); data->state = FAILURE; return; } wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name", username, username_len); if (sm->user->password_hash) { generate_nt_response_pwhash(data->auth_challenge, peer_challenge, username, username_len, sm->user->password, expected); } else { generate_nt_response(data->auth_challenge, peer_challenge, username, username_len, sm->user->password, sm->user->password_len, expected); } if (memcmp(nt_response, expected, 24) == 0) { const u8 *pw_hash; u8 pw_hash_buf[16], pw_hash_hash[16]; wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response"); data->state = SUCCESS_REQ; /* Authenticator response is not really needed yet, but * calculate it here so that peer_challenge and username need * not be saved. */ if (sm->user->password_hash) { pw_hash = sm->user->password; generate_authenticator_response_pwhash( sm->user->password, peer_challenge, data->auth_challenge, username, username_len, nt_response, data->auth_response); } else { nt_password_hash(sm->user->password, sm->user->password_len, pw_hash_buf); pw_hash = pw_hash_buf; generate_authenticator_response(sm->user->password, sm->user->password_len, peer_challenge, data->auth_challenge, username, username_len, nt_response, data->auth_response); } hash_nt_password_hash(pw_hash, pw_hash_hash); get_master_key(pw_hash_hash, nt_response, data->master_key); data->master_key_valid = 1; wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key", data->master_key, MSCHAPV2_KEY_LEN); } else { wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response", expected, 24); wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response"); data->state = FAILURE_REQ; } }