diff -r 000000000000 -r c8830336c852 eapol/eapol_framework/eapol_common/type/mschapv2/core/eap_type_mschapv2_client.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eapol/eapol_framework/eapol_common/type/mschapv2/core/eap_type_mschapv2_client.cpp Thu Dec 17 08:47:43 2009 +0200 @@ -0,0 +1,1753 @@ +/* +* Copyright (c) 2001-2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: EAP and WLAN authentication protocols. +* +*/ + + +// This is enumeration of EAPOL source code. +#if defined(USE_EAP_MINIMUM_RELEASE_TRACES) + #undef EAP_FILE_NUMBER_ENUM + #define EAP_FILE_NUMBER_ENUM 94 + #undef EAP_FILE_NUMBER_DATE + #define EAP_FILE_NUMBER_DATE 1127594498 +#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES) + + + +#include "eap_am_memory.h" +#include "eap_base_type.h" +#include "eap_state_notification.h" +#include "eap_type_mschapv2.h" +#include "eap_am_type_mschapv2.h" +#include "eap_buffer.h" +#include "eap_master_session_key.h" +#include "eap_network_id_selector.h" +#include "eap_tlv_message_data.h" +#include "eap_config.h" + + +eap_status_e eap_type_mschapv2_c::client_packet_process( + eap_header_wr_c * const received_eap, + const u32_t eap_packet_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::client_packet_process(): this = 0x%08x, m_session.get_state()=%d\n"), + this, + m_session.get_state())); + + eap_status_e status = eap_status_drop_packet_quietly; + + m_identifier = received_eap->get_identifier(); + + if (received_eap->get_type() == eap_type_identity) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + if (received_eap->get_code() == eap_code_failure) + { + if (m_session.is_valid_state(eap_type_mschapv2_state_failure) == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + status = finish_unsuccessful_authentication(false); + + m_session.set_state(eap_type_mschapv2_state_failure); + } + else if (received_eap->get_code() == eap_code_success) + { + if (m_session.is_valid_state(eap_type_mschapv2_state_success) == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + eap_master_session_key_c key( + m_am_tools, + eap_type_mschapv2); + if (key.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = generate_session_key(&key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = get_type_partner()->packet_data_crypto_keys(&m_send_network_id, &key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Check wait for eap success + + status = finish_successful_authentication(); + + m_session.set_state(eap_type_mschapv2_state_success); + } + else if (received_eap->get_code() == eap_code_request) // Request + { + // MsChapV2 + if (received_eap->get_type() == eap_type_mschapv2) + { + status = client_mschapv2_packet_process( + received_eap, + eap_packet_length); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +eap_status_e eap_type_mschapv2_c::client_mschapv2_packet_process( + eap_header_wr_c * const received_eap, + const u32_t eap_packet_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::client_mschapv2_packet_process(): this = 0x%08x\n"), + this)); + + eap_status_e status = eap_status_drop_packet_quietly; + + if (eap_packet_length <= eap_header_base_c::get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + else if (eap_packet_length == received_eap->get_data_length()) + { + // MsChapV2 packet without any data, unspecified packet? + // lets finish unsuccesfully? + if (m_session.is_valid_state(eap_type_mschapv2_state_failure) == true) + { + status = finish_unsuccessful_authentication(false); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + const u32_t type_data_length = received_eap->get_type_data_length(); + + if (received_eap->get_type_data_offset(0, type_data_length) == 0) + { + // Not enough data. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + mschapv2_header_c mschapv2_header( + m_am_tools, + received_eap->get_type_data_offset(0, type_data_length), + type_data_length); + + if (mschapv2_header.check_header() != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + switch (mschapv2_header.get_opcode()) + { + case mschapv2_opcode_challenge: + if (m_session.is_valid_state(eap_type_mschapv2_state_challenge_request) == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + status = client_handle_challenge_request(mschapv2_header); + break; + + case mschapv2_opcode_success: + if (m_session.is_valid_state(eap_type_mschapv2_state_success_request) == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + status = client_handle_success_request(mschapv2_header); + break; + + case mschapv2_opcode_failure: + if (m_session.is_valid_state(eap_type_mschapv2_state_failure_request) == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + status = client_handle_failure_request(mschapv2_header); + break; + + default: + break; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +eap_status_e eap_type_mschapv2_c::client_handle_challenge_request(mschapv2_header_c &challenge_request) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::client_handle_challenge_request(): this = 0x%08x\n"), + this)); + + eap_status_e status = eap_status_drop_packet_quietly; + + if (challenge_request.get_data_length() < mschapv2_challenge_c::get_header_minimum_size()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + m_mschapv2id = challenge_request.get_mschapv2_id(); + + mschapv2_challenge_c challenge_payload( + m_am_tools, + challenge_request.get_data(), + challenge_request.get_data_length()); + + if (challenge_payload.check_header() != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("client_handle_challenge_request(): mschapv2id"), + &m_mschapv2id, + sizeof(m_mschapv2id))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("client_handle_challenge_request(): m_authenticator_challenge"), + challenge_payload.get_challenge(), + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + m_am_tools->memmove( + m_authenticator_challenge, + challenge_payload.get_challenge(), + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE); + +#if defined(USE_FAST_EAP_TYPE) + if (m_use_EAP_FAST_challenge == true) + { + // Note the received authenticator challenge is zero bytes in EAP-FAST. + if (m_server_EAP_FAST_challenge.get_is_valid_data() == false + || m_server_EAP_FAST_challenge.get_data_length() != EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + + m_am_tools->memmove( + m_authenticator_challenge, + m_server_EAP_FAST_challenge.get_data(), + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("client_handle_challenge_request(): EAP-FAST m_authenticator_challenge"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + // If no identity, ask it + if (!m_identity_asked + && (m_password_prompt_enabled + || m_username_utf8.get_is_valid_data() == false)) + { + // Prefill username with identity if it is possible + if (m_username_utf8.get_is_valid_data() == false) + { + status = get_type_partner()->get_saved_eap_identity(&m_username_utf8); + } + + // Open username/password dialog + status = m_am_type_mschapv2->show_username_password_dialog( + m_username_utf8, + m_password_utf8, + m_password_prompt_enabled, + false); + } + else + { + status = client_send_challenge_response(); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +eap_status_e eap_type_mschapv2_c::client_send_challenge_response() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::client_send_challenge_response(): this = 0x%08x\n"), + this)); + + eap_status_e status = m_rand.add_rand_seed_hw_ticks(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_use_EAP_FAST_challenge == true + && m_client_EAP_FAST_challenge.get_is_valid_data() == true + && m_client_EAP_FAST_challenge.get_data_length() == EAP_MSCHAPV2_PEER_CHALLENGE_SIZE) + { + m_am_tools->memmove( + m_peer_challenge, + m_client_EAP_FAST_challenge.get_data(), + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE); + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + status = m_rand.get_rand_bytes(m_peer_challenge, EAP_MSCHAPV2_PEER_CHALLENGE_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + crypto_nt_hash_c nt_hash(m_am_tools); + if (nt_hash.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (m_do_wrong_password_tests == true) + { + u8_t crap_from_stack; + status = m_password_utf8.add_data(&crap_from_stack, sizeof(crap_from_stack)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + status = nt_hash.nt_password_hash( + &m_password_utf8, + &m_password_hash, + EAP_MSCHAPV2_MD4_DIGEST_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = nt_hash.hash_nt_password_hash( + &m_password_hash, + &m_password_hash_hash, + EAP_MSCHAPV2_MD4_DIGEST_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_send_challenge_response(), m_password_utf8"), + m_password_utf8.get_data(), + m_password_utf8.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_send_challenge_response(), m_authenticator_challenge"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_send_challenge_response(), m_peer_challenge"), + m_peer_challenge, + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_send_challenge_response(), m_password_hash"), + m_password_hash.get_data(), + m_password_hash.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_send_challenge_response(), m_username_utf8"), + m_username_utf8.get_data(), + m_username_utf8.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_send_challenge_response(): m_authenticator_challenge"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + status = generate_nt_response( + m_authenticator_challenge, + m_peer_challenge, + m_username_utf8.get_data(), + m_username_utf8.get_data_length(), + &m_password_hash, + m_nt_response); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_send_challenge_response(), m_nt_response:"), + m_nt_response, + EAP_MSCHAPV2_NT_RESPONSE_SIZE)); + + // Send response + + const u32_t type_data_length = EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length + + mschapv2_response_c::get_header_minimum_size() + + m_username_utf8.get_data_length(); + + const u32_t packet_length + = eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type) + + type_data_length; + + eap_buf_chain_wr_c * packet = create_send_packet(packet_length); + if (!packet) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_header_base_c eap_header( + m_am_tools, + packet->get_data_offset(m_offset, packet_length), + packet_length); + if (eap_header.get_is_valid() == false) + { + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + eap_header.set_code(eap_code_response); + eap_header.set_identifier(m_identifier); + eap_header.set_length( + static_cast(packet_length), + m_use_eap_expanded_type); + eap_header.set_type( + eap_type_mschapv2, + m_use_eap_expanded_type); + + mschapv2_header_c mschapv2_header( + m_am_tools, + eap_header.get_type_data_offset(0, eap_header.get_type_data_length()), + eap_header.get_type_data_length()); + + mschapv2_header.set_opcode(mschapv2_opcode_response); + mschapv2_header.set_mschapv2_id(m_mschapv2id); + mschapv2_header.set_ms_length(static_cast(type_data_length)); + + mschapv2_response_c response( + m_am_tools, + mschapv2_header.get_data(), + mschapv2_header.get_data_length()); + if (response.get_is_valid() == false) + { + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = response.set_constants(); + if (status != eap_status_ok) + { + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + +#if defined(USE_FAST_EAP_TYPE) + if (m_use_EAP_FAST_challenge == true) + { + // EAP-FAST sends peer challenge containing only zeroes. + response.set_peer_challenge(EAP_MSCHAPV2_ZERO_CHALLENGE); + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + response.set_peer_challenge(m_peer_challenge); + } + + response.set_nt_response(m_nt_response); + + // Copy username to end of response packet + u32_t username_ascii_size = m_username_utf8.get_data_length(); + response.set_name(m_username_utf8.get_data(username_ascii_size)); + + // Send + status = packet_send(packet, packet_length); + + delete packet; + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + m_session.set_state(eap_type_mschapv2_state_challenge_request); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +eap_status_e eap_type_mschapv2_c::client_handle_success_request(mschapv2_header_c & success_request) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::client_handle_success_request(): this = 0x%08x\n"), + this)); + + eap_status_e status = eap_status_drop_packet_quietly; + + if (success_request.get_data_length() < EAP_MSCHAPV2_SUCCESS_REQUEST_MESSAGE_MIN_LENGTH) // Check this out + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + m_mschapv2id = success_request.get_mschapv2_id(); + + u8_t * success_payload = success_request.get_data(); + bool response_check; + + eap_variable_data_c new_password_hash(m_am_tools); + eap_variable_data_c new_password_hash_hash(m_am_tools); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("client_handle_success_request(): m_authenticator_challenge"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("client_handle_success_request(): m_peer_challenge"), + m_peer_challenge, + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("client_handle_success_request(): m_nt_response"), + m_nt_response, + EAP_MSCHAPV2_NT_RESPONSE_SIZE)); + + if (m_session.get_state() == eap_type_mschapv2_state_change_password_request) + { + // Here we need to generate password hashes from new_password + + crypto_nt_hash_c nt_hash(m_am_tools); + if (nt_hash.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = nt_hash.nt_password_hash( + &m_password_utf8, + &new_password_hash, + EAP_MSCHAPV2_MD4_DIGEST_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = nt_hash.hash_nt_password_hash( + &new_password_hash, + &new_password_hash_hash, + EAP_MSCHAPV2_MD4_DIGEST_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = check_authenticator_response( + &new_password_hash_hash, + m_nt_response, + m_peer_challenge, + m_authenticator_challenge, + m_username_utf8.get_data(), + m_username_utf8.get_data_length(), + success_payload, + response_check); + } + else + { + status = check_authenticator_response( + &m_password_hash_hash, + m_nt_response, + m_peer_challenge, + m_authenticator_challenge, + m_username_utf8.get_data(), + m_username_utf8.get_data_length(), + success_payload, + response_check); + } + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (response_check) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_success_request(): mschapv2_opcode_success, authenticator_response correct\n"))); + + // Check if earlier state was password change + if (m_session.get_state() == eap_type_mschapv2_state_change_password_request) + { + if (m_password_prompt_enabled == false) + { + // Save new password + status = m_am_type_mschapv2->update_username_password(); + } + + // Save new hashes + status = m_password_hash.set_copy_of_buffer(&new_password_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_password_hash_hash.set_copy_of_buffer(&new_password_hash_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // Send success response + + // Return value will be not checked. If fails we still try to finish authentication + status = send_success_failure_response(true); + + if (m_wait_eap_success == false) + { + status = finish_successful_authentication(); + m_session.set_state(eap_type_mschapv2_state_success); + } + else + { + m_session.set_state(eap_type_mschapv2_state_success_request); + } + } + else // drop + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_success_request(): mschapv2_opcode_success, authenticator_response incorrect\n"))); + + status = eap_status_drop_packet_quietly; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +eap_status_e eap_type_mschapv2_c::client_handle_failure_request(mschapv2_header_c & failure_request) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::client_handle_failure_request(): this = 0x%08x\n"), + this)); + + eap_status_e status = eap_status_drop_packet_quietly; + + u32_t buffer_left = failure_request.get_data_length(); + if (buffer_left < EAP_MSCHAPV2_FAILURE_MIN_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + m_mschapv2id = failure_request.get_mschapv2_id(); + + const u8_t * buffer_ptr = failure_request.get_data(); + + // "E=" + if (*buffer_ptr != 'E' || *(buffer_ptr + 1) != '=') + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + buffer_ptr += 2; + buffer_left -= 2; + + while (buffer_left && *buffer_ptr == '0') + { + buffer_ptr++; + buffer_left--; + } + + if (buffer_left == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + const u8_t * error_code_str = buffer_ptr; + + while (buffer_left && *buffer_ptr != ' ') + { + if (*buffer_ptr < '0' || *buffer_ptr > '9') + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + buffer_ptr++; + buffer_left--; + } + + u32_t error_code_str_len = buffer_ptr - error_code_str; + if (buffer_left < 43 || error_code_str_len != 3 || *buffer_ptr != ' ') // " R=x C=<32 bytes> V=x", min 43 bytes + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + buffer_ptr++; + buffer_left--; + + // "R=" + if (*buffer_ptr != 'R' || *(buffer_ptr + 1) != '=') + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + bool retry_allowed = true; // value = 1 + if (*(buffer_ptr + 2) == '0') + { + retry_allowed = false; + } + else if (*(buffer_ptr + 2) != '1') + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + buffer_ptr += 4; + buffer_left -= 4; + + // "C=" + if (*buffer_ptr != 'C' || *(buffer_ptr + 1) != '=') + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + buffer_ptr += 2; + buffer_left -= 2; + + const u8_t * challenge_str = buffer_ptr; + u32_t i; + for (i = 0; i < EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE * 2; i++) + { + if ((*(buffer_ptr + i) >= '0' && *(buffer_ptr + i) <= '9') + || + (*(buffer_ptr + i) >= 'A' && *(buffer_ptr + i) <= 'F')) + { + continue; + } + break; + } + if (i != EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE * 2) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + buffer_ptr += EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE * 2; + buffer_left -= EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE * 2; + + if (*buffer_ptr != ' ' + || *(buffer_ptr + 1) != 'V' // " V=" + || *(buffer_ptr + 2) != '=') + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + buffer_ptr += 3; + buffer_left -= 3; + + while (buffer_left && *buffer_ptr == '0') + { + buffer_ptr++; + buffer_left--; + } + + if (buffer_left == 0 + || *buffer_ptr != '3') // Version must be 3 + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + u32_t error_code = + (*error_code_str - '0') * 100 + + (*(error_code_str + 1) - '0') * 10 + + (*(error_code_str + 2) - '0'); + m_error_code = error_code; + + { + u32_t length = EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE; + + status = m_am_tools->convert_hex_ascii_to_bytes( + challenge_str, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE * 2, + m_authenticator_challenge, + &length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (length != EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_failure_request(): client got auth_challenge:"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_failure_request(): client has peer_challenge:"), + m_peer_challenge, + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE)); + } + +#if defined(USE_USER_NOTIFICATIONS) + // Notification to user + eap_variable_data_c string(m_am_tools); + status = m_am_type_mschapv2->read_auth_failure_string(static_cast (m_error_code), string); + if (status == eap_status_ok) + { + eap_state_notification_c notification( + m_am_tools, + &m_send_network_id, + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_general, // This must be used with eap_general_state_show_notification_string. + eap_type_mschapv2, + eap_state_none, + eap_general_state_show_notification_string, + m_identifier, + false); + notification.set_notification_string(&string, true); + get_type_partner()->state_notification(¬ification); + } +#endif //#if defined(USE_USER_NOTIFICATIONS) + + switch (m_error_code) + { + + case EAP_MSCHAPV2_ERROR_RESTRICTED_LOGON_HOURS: + case EAP_MSCHAPV2_ERROR_ACCT_DISABLED: + case EAP_MSCHAPV2_ERROR_NO_DIALIN_PERMISSION: + + // Notification to user + if (m_error_code == EAP_MSCHAPV2_ERROR_RESTRICTED_LOGON_HOURS) + { + send_error_notification(eap_status_restricted_logon_hours); + } + else if (m_error_code == EAP_MSCHAPV2_ERROR_ACCT_DISABLED) + { + send_error_notification(eap_status_account_disabled); + } + else if (m_error_code == EAP_MSCHAPV2_ERROR_NO_DIALIN_PERMISSION) + { + send_error_notification(eap_status_no_dialin_permission); + } + + // Send failure response + status = send_success_failure_response(false); // failure + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + break; + + case EAP_MSCHAPV2_ERROR_AUTHENTICATION_FAILURE: + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_failure_request(): EAP_MSCHAPV2_ERROR_AUTHENTICATION_FAILURE\n"))); + +#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_failure_request(): m_use_implicit_challenge = %d\n"), + m_use_implicit_challenge)); +#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + + if (retry_allowed == true +#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + // Note, retry is supported only inside EAP-MsChapv2. + // Note, inside TTLS/plain-MsChapv2 the retry is not supported. Authentication will fail immediately. + && m_use_implicit_challenge == false +#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + ) + { + m_is_pending = true; + + // Prompt for username/password + status = m_am_type_mschapv2->show_username_password_dialog( + m_username_utf8, + m_password_utf8, + m_password_prompt_enabled, + false); + } + else + { + // Notification to user + send_error_notification(eap_status_authentication_failure); + + // Send failure response + status = send_success_failure_response(false); + } + break; + + case EAP_MSCHAPV2_ERROR_PASSWD_EXPIRED: + case EAP_MSCHAPV2_ERROR_CHANGING_PASSWORD: + + if (m_error_code == EAP_MSCHAPV2_ERROR_PASSWD_EXPIRED) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_failure_request(): EAP_MSCHAPV2_ERROR_PASSWD_EXPIRED\n"))); + } + else if (m_error_code == EAP_MSCHAPV2_ERROR_CHANGING_PASSWORD) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_failure_request(): EAP_MSCHAPV2_ERROR_CHANGING_PASSWORD\n"))); + } + +#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: client_handle_failure_request(): m_use_implicit_challenge = %d\n"), + m_use_implicit_challenge)); +#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + + if ( +#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + m_use_implicit_challenge == false + && +#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + (m_error_code == EAP_MSCHAPV2_ERROR_PASSWD_EXPIRED + || (m_error_code == EAP_MSCHAPV2_ERROR_CHANGING_PASSWORD && retry_allowed))) + { + m_old_password_utf8.set_copy_of_buffer(&m_password_utf8); + + m_is_pending = true; + + m_session.set_state(eap_type_mschapv2_state_failure_request); + + // Prompt for password change + status = m_am_type_mschapv2->show_change_password_dialog( + m_username_utf8, + m_old_password_utf8, + m_password_utf8, + m_password_prompt_enabled); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // Retry not allowed + { + send_error_notification(eap_status_password_expired); + + status = send_success_failure_response(false); + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + // Show message without retry + } + break; + + default: + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + }; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +EAP_FUNC_EXPORT eap_status_e eap_type_mschapv2_c::eap_acknowledge( + const eap_am_network_id_c * const /* receive_network_id */) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::eap_acknowledge(): this = 0x%08x\n"), + this)); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); +} + +EAP_FUNC_EXPORT eap_status_e eap_type_mschapv2_c::set_initial_eap_identifier( + const eap_am_network_id_c * const /*receive_network_id*/, + const u8_t /*initial_identifier*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::set_initial_eap_identifier(): this = 0x%08x\n"), + this)); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +EAP_FUNC_EXPORT eap_status_e eap_type_mschapv2_c::query_eap_identity( + const bool /*must_be_synchronous*/, + eap_variable_data_c * const identity, + const eap_am_network_id_c * const receive_network_id, + const u8_t eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::query_eap_identity(): this = 0x%08x\n"), + this)); + + if (m_session.is_valid_state(eap_type_mschapv2_state_identity_request) == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + // Here we swap the addresses. + eap_am_network_id_c send_network_id(m_am_tools, + receive_network_id->get_destination_id(), + receive_network_id->get_source_id(), + receive_network_id->get_type()); + + m_identifier = eap_identifier; + + eap_status_e status; + + EAP_TRACE_DEBUG(m_am_tools, + TRACE_FLAGS_DEFAULT, ( + EAPL("eap_type_mschapv2_c::query_eap_identity: m_identity_asked=%d, m_password_prompt_enabled=%d\n"), + m_identity_asked, m_password_prompt_enabled)); + + EAP_TRACE_DEBUG(m_am_tools, + TRACE_FLAGS_DEFAULT, ( + EAPL("eap_type_mschapv2_c::query_eap_identity: user name length=%d, PW length=%d, m_is_pending=%d\n"), + m_username_utf8.get_data_length(), m_password_utf8.get_data_length(), m_is_pending)); + + if (m_identity_asked == false && // Only at first time username/password dialog is shown if needed + (m_username_utf8.get_is_valid_data() == false + || m_username_utf8.get_data_length() == 0 + || m_password_prompt_enabled == true)) + { + // Ask username and password + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: query_eap_identity(): m_username_utf8:"), + m_username_utf8.get_data(), + m_username_utf8.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: query_eap_identity(): m_password_utf8:"), + m_password_utf8.get_data(), + m_password_utf8.get_data_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: query_eap_identity(): password length %d\n"), + m_password_utf8.get_buffer_length())); + + if (m_is_pending == false) + { + m_is_pending = true; + status = m_am_type_mschapv2->show_username_password_dialog( + m_username_utf8, + m_password_utf8, + m_password_prompt_enabled, + true); + if (status == eap_status_pending_request + || status == eap_status_completed_request) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: query_eap_identity(): identity query is already pending!.\n"))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_pending_request); + } + } + + m_identity_asked = true; + + // If this is not the first query, use already stored identity information for reply + status = identity->set_copy_of_buffer(&m_username_utf8); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: query_eap_identity(): identity:"), + identity->get_data(), + identity->get_data_length())); + + m_session.set_state(eap_type_mschapv2_state_identity_request); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +EAP_FUNC_EXPORT eap_status_e eap_type_mschapv2_c::complete_eap_identity_query() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_eap_identity_query() m_username_utf8:"), + m_username_utf8.get_data(), + m_username_utf8.get_data_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_eap_identity_query(), password length %d\n"), + m_password_utf8.get_buffer_length())); + + m_identity_asked = true; + + m_session.set_state(eap_type_mschapv2_state_identity_request); + + eap_status_e status = get_type_partner()->complete_eap_identity_query( + &m_send_network_id, + &m_username_utf8, + m_identifier); + if (status != eap_status_ok) + { + m_session.set_state(eap_type_mschapv2_state_failure); + } + + m_is_pending = false; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +eap_status_e eap_type_mschapv2_c::send_success_failure_response(bool is_success_response) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::send_success_failure_response(): this = 0x%08x\n"), + this)); + + eap_status_e status = eap_status_allocation_error; + + u32_t packet_length + = EAP_MSCHAPV2_OPCODE_SIZE // OpCode is the only payload + + eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type); + + eap_buf_chain_wr_c * packet = create_send_packet(packet_length); + if (!packet) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_header_base_c eap_header( + m_am_tools, + packet->get_data_offset(m_offset, packet_length), + packet_length); + if (eap_header.get_is_valid() == false) + { + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + eap_header.set_code(eap_code_response); + eap_header.set_identifier(m_identifier); + eap_header.set_length( + static_cast(packet_length), + m_use_eap_expanded_type); + eap_header.set_type( + eap_type_mschapv2, + m_use_eap_expanded_type); + + mschapv2_header_c mschapv2_header( + m_am_tools, + eap_header.get_type_data_offset(0, eap_header.get_type_data_length()), + eap_header.get_type_data_length()); + + if (is_success_response) + { + mschapv2_header.set_opcode(mschapv2_opcode_success); + m_session.set_state(eap_type_mschapv2_state_success_request); + } + else + { + mschapv2_header.set_opcode(mschapv2_opcode_failure); + m_session.set_state(eap_type_mschapv2_state_failure_request); + } + + status = packet_send(packet, packet_length); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: send_success_failure_response():\n"))); + + delete packet; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +EAP_FUNC_EXPORT eap_status_e eap_type_mschapv2_c::complete_failure_retry_response() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::complete_failure_retry_response(): this = 0x%08x\n"), + this)); + + m_is_pending = false; + + eap_status_e status = m_rand.add_rand_seed_hw_ticks(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_rand.add_rand_seed( + m_password_utf8.get_data(), + m_password_utf8.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_use_EAP_FAST_challenge == true + && m_client_EAP_FAST_challenge.get_is_valid_data() == true + && m_client_EAP_FAST_challenge.get_data_length() == EAP_MSCHAPV2_PEER_CHALLENGE_SIZE) + { + m_am_tools->memmove( + m_peer_challenge, + m_client_EAP_FAST_challenge.get_data(), + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE); + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + status = m_rand.get_rand_bytes( + m_peer_challenge, + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + crypto_nt_hash_c nt_hash(m_am_tools); + if (nt_hash.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = nt_hash.nt_password_hash( + &m_password_utf8, + &m_password_hash, + EAP_MSCHAPV2_MD4_DIGEST_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = nt_hash.hash_nt_password_hash( + &m_password_hash, + &m_password_hash_hash, + EAP_MSCHAPV2_MD4_DIGEST_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_failure_retry_response(), m_password_utf8"), + m_password_utf8.get_data(), + m_password_utf8.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_failure_retry_response(), m_authenticator_challenge"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_failure_retry_response(), m_peer_challenge"), + m_peer_challenge, + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_failure_retry_response(), m_password_hash"), + m_password_hash.get_data(), + m_password_hash.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_failure_retry_response(), m_username_utf8"), + m_username_utf8.get_data(), + m_username_utf8.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_failure_retry_response(): m_authenticator_challenge"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + + status = generate_nt_response( + m_authenticator_challenge, + m_peer_challenge, + m_username_utf8.get_data(), + m_username_utf8.get_data_length(), + &m_password_hash, + m_nt_response); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_MSCHAPV2: complete_failure_retry_response(), m_nt_response:"), + m_nt_response, + EAP_MSCHAPV2_NT_RESPONSE_SIZE)); + + // Send response + + const u32_t type_data_length = EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length + + mschapv2_response_c::get_header_minimum_size() + + m_username_utf8.get_data_length(); + + const u32_t packet_length = eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type) + + type_data_length; + + eap_buf_chain_wr_c * packet = create_send_packet(packet_length); + + if (!packet) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + + eap_header_base_c eap_header( + m_am_tools, + packet->get_data_offset(m_offset, packet_length), + packet_length); + if (eap_header.get_is_valid() == false) + { + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + eap_header.set_code(eap_code_response); + eap_header.set_identifier(m_identifier); + eap_header.set_length( + static_cast(packet_length), + m_use_eap_expanded_type); + eap_header.set_type( + eap_type_mschapv2, + m_use_eap_expanded_type); + + mschapv2_header_c mschapv2_header( + m_am_tools, + eap_header.get_type_data_offset(0, eap_header.get_type_data_length()), + eap_header.get_type_data_length()); + + mschapv2_header.set_opcode(mschapv2_opcode_response); + mschapv2_header.set_mschapv2_id(++m_mschapv2id); + mschapv2_header.set_ms_length(static_cast(type_data_length)); + + mschapv2_response_c response( + m_am_tools, + mschapv2_header.get_data(), + mschapv2_header.get_data_length()); + if (response.get_is_valid() == false) + { + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = response.set_constants(); + if (status != eap_status_ok) + { + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + response.set_nt_response(m_nt_response); + response.set_peer_challenge(m_peer_challenge); + response.set_name(m_username_utf8.get_data()); + + // Send + status = packet_send(packet, packet_length); + delete packet; + + m_session.set_state(eap_type_mschapv2_state_challenge_request); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +EAP_FUNC_EXPORT eap_status_e eap_type_mschapv2_c::complete_change_password_query() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_mschapv2_c::complete_change_password_query(): this = 0x%08x\n"), + this)); + + eap_status_e status = eap_status_process_general_error; + + m_is_pending = false; + + status = m_rand.add_rand_seed_hw_ticks(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_rand.add_rand_seed( + m_password_utf8.get_data(), + m_password_utf8.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_use_EAP_FAST_challenge == true + && m_client_EAP_FAST_challenge.get_is_valid_data() == true + && m_client_EAP_FAST_challenge.get_data_length() == EAP_MSCHAPV2_PEER_CHALLENGE_SIZE) + { + m_am_tools->memmove( + m_peer_challenge, + m_client_EAP_FAST_challenge.get_data(), + EAP_MSCHAPV2_PEER_CHALLENGE_SIZE); + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + status = m_rand.get_rand_bytes(m_peer_challenge, EAP_MSCHAPV2_PEER_CHALLENGE_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + u8_t * encrypted_pw_block = new u8_t[sizeof(pw_block_s)]; + if (!encrypted_pw_block) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_variable_data_c new_password_hash(m_am_tools); + + crypto_nt_hash_c nt_hash(m_am_tools); + if (nt_hash.get_is_valid() == false) + { + delete [] encrypted_pw_block; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = nt_hash.nt_password_hash( + &m_password_utf8, + &new_password_hash, + EAP_MSCHAPV2_MD4_DIGEST_SIZE); + if (status != eap_status_ok) + { + delete [] encrypted_pw_block; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = new_password_encrypted_with_old_nt_password_hash( + &m_password_utf8, + &m_password_hash, + encrypted_pw_block); + if (status != eap_status_ok) + { + delete [] encrypted_pw_block; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c encrypted_pw_hash(m_am_tools); + + status = old_nt_password_hash_encrypted_with_new_nt_password_hash( + &new_password_hash, + &m_password_hash, + &encrypted_pw_hash); + if (status != eap_status_ok) + { + delete [] encrypted_pw_block; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("complete_change_password_query(): m_authenticator_challenge"), + m_authenticator_challenge, + EAP_MSCHAPV2_AUTHENTICATOR_CHALLENGE_SIZE)); + + status = generate_nt_response( + m_authenticator_challenge, + m_peer_challenge, + m_username_utf8.get_data(), + m_username_utf8.get_data_length(), + &new_password_hash, + m_nt_response); + if (status != eap_status_ok) + { + delete [] encrypted_pw_block; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + const u32_t type_data_length = EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length + + mschapv2_change_password_c::get_header_minimum_size(); + + const u32_t packet_length + = eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type) + + type_data_length; + + + eap_buf_chain_wr_c * packet = create_send_packet(packet_length); + if (!packet) + { + delete [] encrypted_pw_block; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_header_base_c eap_header( + m_am_tools, + packet->get_data_offset(m_offset, packet_length), + packet_length); + if (eap_header.get_is_valid() == false) + { + delete [] encrypted_pw_block; + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + eap_header.set_code(eap_code_response); + eap_header.set_identifier(m_identifier); + eap_header.set_length( + static_cast(packet_length), + m_use_eap_expanded_type); + eap_header.set_type( + eap_type_mschapv2, + m_use_eap_expanded_type); + + mschapv2_header_c mschapv2_header( + m_am_tools, + eap_header.get_type_data_offset(0, eap_header.get_type_data_length()), + eap_header.get_type_data_length()); + + mschapv2_header.set_opcode(mschapv2_opcode_change_password); + mschapv2_header.set_mschapv2_id(static_cast((++m_mschapv2id))); + mschapv2_header.set_ms_length(static_cast(type_data_length)); + + mschapv2_change_password_c response( + m_am_tools, + mschapv2_header.get_data(), + mschapv2_header.get_data_length()); + if (response.get_is_valid() == false) + { + delete [] encrypted_pw_block; + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = response.set_constants(); + if (status != eap_status_ok) + { + delete [] encrypted_pw_block; + delete packet; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + response.set_encrypted_pw_block(encrypted_pw_block); + delete [] encrypted_pw_block; + response.set_encrypted_hash(encrypted_pw_hash.get_data()); + response.set_peer_challenge(m_peer_challenge); + response.set_nt_response(m_nt_response); + + // Send change password response + status = packet_send(packet, packet_length); + delete packet; + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + m_session.set_state(eap_type_mschapv2_state_change_password_request); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +// End of file.