diff -r 000000000000 -r c8830336c852 eapol/eapol_framework/eapol_common/type/aka/core/eap_type_aka.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eapol/eapol_framework/eapol_common/type/aka/core/eap_type_aka.cpp Thu Dec 17 08:47:43 2009 +0200 @@ -0,0 +1,7167 @@ +/* +* 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 67 + #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_tools.h" +#include "eap_type_aka.h" +#include "eap_type_aka_header.h" +#include "eap_type_aka_payloads.h" +#include "abs_eap_am_type_aka.h" +#include "eap_crypto_api.h" +#include "eap_state_notification.h" +#include "abs_eap_am_mutex.h" +#include "eap_automatic_variable.h" +#include "eap_sort.h" +#include "eap_buffer.h" +#include "eap_config.h" + + +//-------------------------------------------------- + +/** @file */ + +// +EAP_FUNC_EXPORT eap_type_aka_c::~eap_type_aka_c() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::~eap_type_aka_c(): this = 0x%08x => 0x%08x\n"), + this, + dynamic_cast(this))); + + EAP_ASSERT(m_shutdown_was_called == true); + + if (m_free_am_type_aka == true + && m_am_type_aka != 0) + { + delete m_am_type_aka; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +#if defined(_WIN32) && !defined(__GNUC__) + #pragma warning( disable : 4355 ) // 'this' : used in base member initializer list +#endif + +// +EAP_FUNC_EXPORT eap_type_aka_c::eap_type_aka_c( + abs_eap_am_tools_c * const tools, + abs_eap_base_type_c * const partner, + eap_am_type_aka_c * const am_type_aka, + const bool free_am_type_aka, + const bool is_client_when_true, + const eap_am_network_id_c * const receive_network_id) + : eap_base_type_c(tools, partner) + , m_am_tools(tools) + , m_am_type_aka(am_type_aka) + , m_checkcode(tools) + , m_checkcode_update_count(0UL) + , m_received_checkcode(tools) + , m_checkcode_saved_message(tools) + , m_all_payloads(tools) + , m_nonce_mt_file(tools) + , m_manual_username(tools) + , m_manual_realm(tools) + , m_automatic_realm(tools) + , m_automatic_realm_read(false) + , m_aka_header_offset(0u) + , m_MTU(0u) + , m_trailer_length(0u) + , m_length_of_mnc(EAP_TYPE_AKA_DEFAULT_MNC_LENGTH_3_BYTES) + , m_authentication_type(AKA_AUTHENTICATION_TYPE_NONE) + , m_identity_type(AKA_IDENTITY_TYPE_NONE) + , m_client_error_code(eap_aka_client_error_code_none) + , m_aka_notification_code(eap_aka_notification_none) + , m_failure_message_delay_time(EAP_TYPE_AKA_TIMER_TIMEOUT_VALUE_DELAY_FAILURE_MESSAGE_SENT) + , m_is_valid(false) + , m_is_client(is_client_when_true) + , m_wait_eap_success_packet(true) + , m_check_identifier_of_eap_identity_response(false) + , m_free_am_type_aka(free_am_type_aka) + , m_client_responds_retransmitted_packets(false) + , m_aka_test_version(false) + , m_aka_randomly_refuse_eap_identity(false) + , m_check_nai_realm(false) + , m_fail_reauthentication_counter_check(false) + , m_accept_eap_identity_response(true) + , m_use_random_identity_on_eap_identity_response(false) + , m_shutdown_was_called(false) + , m_reset_was_called(false) + , m_use_pseudonym_identity(true) + , m_use_reauthentication_identity(true) + , m_erroneus_packet_received(false) + , m_aka_notification_packet_received(false) + , m_use_manual_username(false) + , m_use_manual_realm(false) + , m_randomly_fail_successfull_authentication(false) + , m_allow_use_result_indication(true) + , m_use_result_indication(false) + , m_state(eap_type_aka_state_none) + , m_saved_previous_state(eap_type_aka_state_none) + , m_send_network_id(tools) + , m_nonce_s(tools) + , m_IV(tools) + , m_saved_EAP_packet(tools) + , m_XKEY(tools) + , m_K_encr(tools) + , m_K_aut(tools) + , m_master_session_key(tools, eap_type_aka) + , m_IMSI(tools) + , m_pseudonym(tools) + , m_reauthentication_identity(tools) + , m_identity(tools) + , m_NAI(tools) + , m_RAND(tools) + , m_AUTN(tools) + , m_RES(tools) + , m_2_digit_mnc_map_of_mcc_of_imsi_array(tools) + , m_uma_automatic_realm_prefix(tools) + , m_use_uma_profile(false) + , m_authentication_vector(0) + , m_reauthentication_counter(0u) + , m_include_identity_to_aka_identity_response(aka_payload_NONE) + , m_aka_identity_response_includes_identity(aka_payload_NONE) + , m_failure_message_received(false) + , m_authentication_finished_successfully(false) + , m_last_eap_identifier(0) + , m_use_eap_expanded_type(false) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::eap_type_aka_c(): this = 0x%08x => 0x%08x, ") + EAPL("partner 0x%08x, type partner 0x%08x, compiled %s %s\n"), + this, + dynamic_cast(this), + partner, + get_type_partner(), + __DATE__, + __TIME__)); + + if (m_am_type_aka == 0) + { + // Something wrong with AM. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + m_am_type_aka->set_am_partner(this); + + if (m_checkcode.get_is_valid() == false + || m_received_checkcode.get_is_valid() == false + || m_checkcode_saved_message.get_is_valid() == false + || m_nonce_mt_file.get_is_valid() == false + || m_manual_username.get_is_valid() == false + || m_manual_realm.get_is_valid() == false + || m_send_network_id.get_is_valid() == false + || m_nonce_s.get_is_valid() == false + || m_IV.get_is_valid() == false + || m_saved_EAP_packet.get_is_valid() == false + || m_XKEY.get_is_valid() == false + || m_K_encr.get_is_valid() == false + || m_K_aut.get_is_valid() == false + || m_master_session_key.get_is_valid() == false + || m_IMSI.get_is_valid() == false + || m_pseudonym.get_is_valid() == false + || m_reauthentication_identity.get_is_valid() == false + || m_identity.get_is_valid() == false + || m_NAI.get_is_valid() == false + || m_RAND.get_is_valid() == false + || m_AUTN.get_is_valid() == false + || m_RES.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + eap_status_e status = checkcode_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + initialize_state(eap_type_aka_state_pending_kc_sres_query, false, false, + aka_subtype_Notification, + aka_subtype_Challenge, // Re-transmitted EAP-Request/AKA/Challenge is allowed. + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_pending_authentication_vector_query, false, false, + aka_subtype_Notification, + aka_subtype_Identity, // Note EAP-Response/AKA/Identity message is allowed here, eap_type_aka_c::handle_aka_identity_response_message() will drop EAP-Response/AKA/Identity message quietly. + aka_subtype_Client_Error, + aka_subtype_Challenge, // Re-transmitted EAP-Response/AKA/Challenge is allowed. + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_aka_identity_request, false, false, + aka_subtype_Notification, + aka_subtype_Identity, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_pseydonym_waiting_for_aka_identity_request, false, false, + aka_subtype_Notification, + aka_subtype_Identity, + aka_subtype_Re_authentication, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_imsi_waiting_for_aka_identity_request, false, false, + aka_subtype_Notification, + aka_subtype_Identity, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_aka_identity_response, true, false, + aka_subtype_Notification, + aka_subtype_Identity, + aka_subtype_Client_Error, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_notification_request_success, false, true, + aka_subtype_Notification, + aka_subtype_Challenge, + aka_subtype_Re_authentication, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_notification_response_failure, true, false, + aka_subtype_Notification, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_notification_response_success, true, false, + aka_subtype_Notification, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity, true, false, + aka_subtype_Notification, + aka_subtype_Identity, + aka_subtype_Client_Error, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity, true, false, + aka_subtype_Notification, + aka_subtype_Identity, + aka_subtype_Client_Error, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity, true, false, + aka_subtype_Notification, + aka_subtype_Identity, + aka_subtype_Client_Error, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_analyse_aka_identity_request, false, false, + aka_subtype_Notification, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_challenge_request, false, false, + aka_subtype_Notification, + aka_subtype_Challenge, + aka_subtype_Identity, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_challenge_response, false, false, + aka_subtype_Notification, + aka_subtype_Challenge, + aka_subtype_Identity, + aka_subtype_Client_Error, + aka_subtype_Synchronization_Failure); + + initialize_state(eap_type_aka_state_waiting_for_reauth_request, false, false, + aka_subtype_Notification, + aka_subtype_Re_authentication, + aka_subtype_Identity, + aka_subtype_Challenge, // This is allowed because, server could start full authentication. + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_reauth_response, false, false, + aka_subtype_Notification, + aka_subtype_Re_authentication, + aka_subtype_Identity, + aka_subtype_Client_Error, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_success, false, false, + aka_subtype_Notification, + aka_subtype_Challenge, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_waiting_for_success, false, false, + aka_subtype_Notification, + aka_subtype_Challenge, + aka_subtype_Re_authentication, + aka_subtype_NONE, + aka_subtype_NONE); + + initialize_state(eap_type_aka_state_failure, false, false, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE, + aka_subtype_NONE); + + { + // 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()); + + status = m_send_network_id.set_copy_of_network_id(&send_network_id); + + if (status != eap_status_ok + || m_send_network_id.get_is_valid_data() == false) + { + (void) EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + return; + } + } + + set_is_valid(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//----------------------------------------------- + +// +void eap_type_aka_c::initialize_state( + const eap_type_aka_state_variable_e state, + const bool must_be_initiator, + const bool must_be_responder, + const aka_subtype_e type0, + const aka_subtype_e type1, + const aka_subtype_e type2, + const aka_subtype_e type3, + const aka_subtype_e type4) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + m_parameters[(state)].init_state(must_be_initiator, must_be_responder, + type0, type1, type2, type3, type4); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool eap_type_aka_c::random_selection() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + crypto_random_c rand(m_am_tools); + + if (rand.get_is_valid() == false) + { + return false; + } + + return (rand.get_rand_integer(0, 1) != 0); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::checkcode_init() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + m_checkcode_update_count = 0UL; + + m_received_checkcode.reset(); + + m_checkcode_saved_message.reset(); + + m_all_payloads.reset(); + + eap_status_e status = m_checkcode.hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool eap_type_aka_c::compare_payload_first_is_less( + const aka_payload_AT_type_e * const first, + const aka_payload_AT_type_e * const second, + abs_eap_am_tools_c * const /* m_am_tools */) +{ + return *first < *second; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::checkcode_verify_payloads( + aka_payloads_c * const p_aka_payloads) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (p_aka_payloads != 0 + && p_aka_payloads->get_all_payloads()->get_is_valid_data() == true) + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL(" CHECKCODE plain payload array"), + p_aka_payloads->get_all_payloads()->get_data(p_aka_payloads->get_all_payloads()->get_data_length()), + p_aka_payloads->get_all_payloads()->get_data_length())); + + // This will sort the payload array of type aka_payload_AT_type_e in increasing order. + // Comparing this payload array to previous payload arrays is then easy task. + eap_status_e status = eap_sort_array( + reinterpret_cast( + p_aka_payloads->get_all_payloads()->get_data( + p_aka_payloads->get_all_payloads()->get_data_length())), + p_aka_payloads->get_all_payloads()->get_data_length()/sizeof(aka_payload_AT_type_e), + compare_payload_first_is_less, + m_am_tools); + 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("CHECKCODE sorted payload array"), + p_aka_payloads->get_all_payloads()->get_data(p_aka_payloads->get_all_payloads()->get_data_length()), + p_aka_payloads->get_all_payloads()->get_data_length())); + + for (u32_t ind = 0ul; ind < m_all_payloads.get_object_count(); ind++) + { + eap_variable_data_c * const payloads = m_all_payloads.get_object(ind); + if (payloads != 0) + { + if (payloads->compare(p_aka_payloads->get_all_payloads()) == 0) + { + // Message with these payloads have been seen already. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("WARNING: message with these payloads have been seen already.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_already_exists); + } + } + } + + // Save this payload array. + eap_variable_data_c * copy_attributes = p_aka_payloads->get_all_payloads()->copy(); + if (copy_attributes == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = m_all_payloads.add_object(copy_attributes, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + + 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_aka_c::checkcode_save_message_client( + const void * const data, + const u32_t data_length, + aka_payloads_c * const p_aka_payloads) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + if (p_aka_payloads != 0) + { + // Client received a message. + + status = checkcode_verify_payloads(p_aka_payloads); + if (status == eap_status_ok) + { + // This is a new received message with new payloads. + status = checkcode_update_saved_message(); + + } + else + { + // Received message is duplicate. + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("CHECKCODE saved data client"), + data, + data_length)); + + status = m_checkcode_saved_message.set_copy_of_buffer( + data, + data_length); + } + else + { + // Client sends a response message. + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("CHECKCODE saved data client"), + data, + data_length)); + + status = m_checkcode_saved_message.add_data( + data, + data_length); + } + + 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_aka_c::checkcode_save_message_server( + const void * const data, + const u32_t data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("CHECKCODE saved data server"), + data, + data_length)); + + eap_status_e status = m_checkcode_saved_message.set_copy_of_buffer( + data, + data_length); + + 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_aka_c::checkcode_update_saved_message() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_ok; + + if (m_checkcode_saved_message.get_is_valid_data() == true + && m_checkcode_saved_message.get_data_length() > 0UL) + { + status = checkcode_update( + m_checkcode_saved_message.get_data(m_checkcode_saved_message.get_data_length()), + m_checkcode_saved_message.get_data_length()); + + m_checkcode_saved_message.reset(); + } + + 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_aka_c::checkcode_update( + const void * const data, + const u32_t data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("CHECKCODE data"), + data, + data_length)); + + ++m_checkcode_update_count; + + eap_status_e status = m_checkcode.hash_update( + data, + data_length); + + 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_aka_c::checkcode_final( + eap_variable_data_c * const digest) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = checkcode_update_saved_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t digest_length = m_checkcode.get_digest_length(); + + status = digest->init(digest_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + digest->set_is_valid(); + digest->set_data_length(digest_length); + + if (m_checkcode_update_count == 0UL) + { + // No AKA-Identity messages were sent. + digest->set_data_length(0UL); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + + // Create a copy of crypto_sha1_c object. + // This will save the HASH for later use. + abs_crypto_hash_algorithm_c * const copy_checkcode = m_checkcode.copy(); + eap_automatic_variable_c automatic_copy_checkcode(m_am_tools, copy_checkcode); + + if (copy_checkcode == 0 + || copy_checkcode->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 = copy_checkcode->hash_final( + digest->get_data(digest_length), + &digest_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + 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_aka_c::checkcode_verify( + const eap_variable_data_c * const received_digest) +{ + // Verify AT_CHECKCODE. + eap_variable_data_c checkcode_digest(m_am_tools); + + if (checkcode_digest.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = checkcode_final( + &checkcode_digest); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if ((m_checkcode_update_count != 0 && received_digest->get_data_length() == 0) + || (m_checkcode_update_count == 0 && received_digest->get_data_length() != 0) + || checkcode_digest.compare(received_digest) != 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("ERROR: EAP_type_AKA: %s, eap_type_aka_c::checkcode_verify(): CHECKCODE failed, m_checkcode_update_count %d, state %s\n"), + (m_is_client == true) ? "client": "server", + m_checkcode_update_count, + get_state_string())); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL(" local digest"), + checkcode_digest.get_data(checkcode_digest.get_data_length()), + checkcode_digest.get_data_length())); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("received digest"), + received_digest->get_data(received_digest->get_data_length()), + received_digest->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("EAP_type_AKA: %s, eap_type_aka_c::checkcode_verify(): CHECKCODE OK, state %s\n"), + (m_is_client == true) ? "client": "server", + get_state_string())); + } + + 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_aka_c::send_final_notification() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_is_valid == true) + { + if (get_authentication_finished_successfully() == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("ERROR: EAP_type_AKA: %s, authentication FAILED, state %s\n"), + (m_is_client == true) ? "client": "server", + get_state_string())); + + if (m_aka_notification_code != eap_aka_notification_none) + { + // We have received EAP-Request/AKA notification, we pass the received code to the adaptation module. + (void) m_am_type_aka->handle_aka_notification(m_aka_notification_code); + } + + set_state(eap_type_aka_state_failure); + + // Notifies the lower level of unsuccessfull authentication. + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_type_aka, + eap_state_none, + eap_state_authentication_terminated_unsuccessfully, + get_last_eap_identifier(), + false); + + notification.set_authentication_error(eap_status_authentication_failure); + + state_notification(¬ification); + + // Indicate AKA AM authentication finish. + m_am_type_aka->authentication_finished(false, m_authentication_type, m_identity_type); + } + } + + 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_aka_c::add_variable_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + const eap_variable_data_c * const data_payload, + const aka_payload_AT_type_e data_payload_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + u16_t data_length = 0u; + + if (data_payload != 0) + { + if (data_payload->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_data_payload); + } + + if (data_payload->get_data_length() > aka_payload_AT_header_c::get_max_payload_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + data_length = static_cast(data_payload->get_data_length()); + } + else + { + // No data. + data_length = 0u; + } + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset(*aka_data_offset, *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + gp_data.reset_header(data_length); + + if (data_length > 0u) + { + u8_t *payload_buffer = gp_data.get_data(data_length); + + if (payload_buffer == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + m_am_tools->memmove( + payload_buffer, + data_payload->get_data(data_payload->get_data_length()), + data_payload->get_data_length()); + } + + gp_data.set_data_length(data_length); + + status = eap_status_ok; + + + gp_data.set_current_payload(data_payload_type); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + 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_aka_c::add_RES_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + const eap_variable_data_c * const RES, + const aka_payload_AT_type_e data_payload_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + u16_t data_length = 0u; + + if (RES != 0) + { + if (RES->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_data_payload); + } + + if (RES->get_data_length() > aka_payload_AT_header_c::get_max_payload_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + data_length = static_cast(RES->get_data_length()); + } + else + { + // No data. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + u16_t padding_zero_count = 0u; + // Add padding zero octets + if ((data_length % 4u) != 0) + { + padding_zero_count = 4u - (data_length % 4u); + } + + if (RES->get_data_length()+padding_zero_count + > aka_payload_AT_header_c::get_max_payload_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (RES->get_data_length()+padding_zero_count > *packet_buffer_free) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset(*aka_data_offset, *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + gp_data.reset_header(data_length+padding_zero_count); + + { + u8_t *payload_buffer = gp_data.get_data(data_length+padding_zero_count); + + if (payload_buffer == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + m_am_tools->memmove( + payload_buffer, + RES->get_data(data_length), + data_length); + + if (padding_zero_count > 0u) + { + m_am_tools->memset( + payload_buffer+data_length, + 0, + padding_zero_count); + } + } + + // Note the reserved field includes the actual length of RES in bits in network order. + // It is always multiple of 8 bits. + gp_data.set_reserved(static_cast(data_length*8ul)); + + gp_data.set_data_length(data_length+padding_zero_count); + + status = eap_status_ok; + + + gp_data.set_current_payload(data_payload_type); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + 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_aka_c::add_AUTS_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + const eap_variable_data_c * const AUTS, + const aka_payload_AT_type_e data_payload_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + u16_t data_length = 0u; + + if (AUTS != 0) + { + if (AUTS->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_data_payload); + } + + if (AUTS->get_data_length() > aka_payload_AT_header_c::get_max_payload_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (AUTS->get_data_length() >= 2ul) + { + // NOTE first 2 bytes are in reserved field. + data_length = static_cast(AUTS->get_data_length() - 2ul); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_buffer_too_short); + } + } + else + { + // No data. + data_length = 0u; + } + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset(*aka_data_offset, *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + gp_data.reset_header(data_length); + + if (data_length > 0u) + { + u8_t *payload_buffer = gp_data.get_reserved_pointer(AUTS->get_data_length()); + + if (payload_buffer == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + // The first 2 bytes are in reserved field. + m_am_tools->memmove( + payload_buffer, + AUTS->get_data(AUTS->get_data_length()), + AUTS->get_data_length()); + } + + gp_data.set_data_length(data_length); + + status = eap_status_ok; + + + gp_data.set_current_payload(data_payload_type); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// Note the specification of IMSI payload is not same as pseudonym. +// IMSI and pseudonym specifications should be integrated. +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::add_pseudonym_or_imsi_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + const eap_variable_data_c * const pseudonym_or_imsi, + const aka_payload_AT_type_e data_payload_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + if (pseudonym_or_imsi->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_data_payload); + } + + u32_t padding_zero_count = 0u; + // Add padding zero octets + if ((pseudonym_or_imsi->get_data_length() % 4u) != 0) + { + padding_zero_count = 4u - (pseudonym_or_imsi->get_data_length() % 4u); + } + + if (pseudonym_or_imsi->get_data_length()+padding_zero_count + > aka_payload_AT_header_c::get_max_payload_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (pseudonym_or_imsi->get_data_length()+padding_zero_count > *packet_buffer_free) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset( + *aka_data_offset, + *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + gp_data.reset_header(static_cast(pseudonym_or_imsi->get_data_length()+padding_zero_count)); + + u8_t *payload_buffer = gp_data.get_data(pseudonym_or_imsi->get_data_length()+padding_zero_count); + + if (payload_buffer == 0 + || pseudonym_or_imsi->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + m_am_tools->memmove( + payload_buffer, + pseudonym_or_imsi->get_data(pseudonym_or_imsi->get_data_length()), + pseudonym_or_imsi->get_data_length()); + + if (padding_zero_count > 0u) + { + m_am_tools->memset( + payload_buffer+(pseudonym_or_imsi->get_data_length()), + 0, + padding_zero_count); + } + + // Note the reserved field includes the actual length of pseudonym in network order. + // This must be less or equal to the length field. + gp_data.set_reserved(static_cast(pseudonym_or_imsi->get_data_length())); + + gp_data.set_data_length(static_cast(pseudonym_or_imsi->get_data_length()+padding_zero_count)); + + status = eap_status_ok; + + gp_data.set_current_payload(data_payload_type); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + 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_aka_c::add_notification_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + const eap_aka_notification_codes_e notification_code) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset( + *aka_data_offset, + *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + gp_data.reset_header(0u); + + // Note the reserved field includes the notificatio code in network order. + gp_data.set_reserved(static_cast(notification_code)); + + gp_data.set_data_length(0u); + + status = eap_status_ok; + + gp_data.set_current_payload(aka_payload_AT_NOTIFICATION); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + 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_aka_c::add_client_error_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + const eap_aka_client_error_code_e client_error_code) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset( + *aka_data_offset, + *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + gp_data.reset_header(0u); + + // Note the reserved field includes the client error code in network order. + // This must be less or equal to the length field. + gp_data.set_reserved(static_cast(client_error_code)); + + gp_data.set_data_length(0u); + + status = eap_status_ok; + + gp_data.set_current_payload(aka_payload_AT_CLIENT_ERROR_CODE); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + 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_aka_c::add_counter_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + u16_t counter) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset( + *aka_data_offset, + *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + gp_data.reset_header(0u); + + // Note the reserved field includes the counter value in network order. + gp_data.set_reserved(counter); + + gp_data.set_data_length(0u); + + status = eap_status_ok; + + gp_data.set_current_payload(aka_payload_AT_COUNTER); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + 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_aka_c::add_simple_payload( + aka_header_c * const aka, + const u32_t aka_buffer_length, + const u32_t eap_header_size, + u32_t * const aka_data_offset, + u32_t * const aka_data_free, + u32_t * const packet_buffer_free, + u32_t * const packet_buffer_offset, + const aka_payload_AT_type_e data_payload_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + aka_payload_AT_header_c gp_data( + m_am_tools, + aka->get_data_offset( + *aka_data_offset, + *aka_data_free), + *aka_data_free); + + if (gp_data.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + gp_data.reset_header(0u); + + gp_data.set_reserved(0u); + + gp_data.set_data_length(0u); + + status = eap_status_ok; + + gp_data.set_current_payload(data_payload_type); + + update_payload_indexes( + aka_buffer_length, + eap_header_size, + gp_data.get_header_length()+gp_data.get_data_length(), + aka_data_offset, + aka_data_free, + packet_buffer_offset, + packet_buffer_free); + + EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_data); + + 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_aka_c::parse_generic_payload( + const aka_payload_AT_type_e current_payload, + const aka_payload_AT_header_c * const payload, + aka_payloads_c * const p_aka_payloads, + const aka_subtype_e /*subtype*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_AKA_TRACE_PAYLOAD("Parsing payload", payload); + + if ((payload->get_payload_length() % static_cast(AKA_PAYLOAD_LENGTH_ALIGN)) != 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x not aligned to 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), + payload->get_payload_length(), AKA_PAYLOAD_LENGTH_ALIGN)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + eap_status_e status(eap_status_process_general_error); + + + status = p_aka_payloads->get_all_payloads()->add_data( + ¤t_payload, + sizeof(current_payload)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + if (current_payload == aka_payload_AT_NONCE_S) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_NONCE_S | Length = 5 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // | NONCE_S | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (payload->get_data_length() != EAP_TYPE_AKA_NONCE_MT_SIZE) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_data_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t * buffer + = static_cast(payload->get_data(EAP_TYPE_AKA_NONCE_MT_SIZE)); + + if (buffer == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + // Note here we get a reference to the data bytes of the received packet. + status = p_aka_payloads->get_NONCE_S()->set_buffer( + payload, buffer, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_RAND) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_RAND | Length | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | RAND ... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (payload->get_data_length() < EAP_TYPE_AKA_MINIMUM_RAND_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x. Too few RAND bytes 0x%04x, 0x%04x bytes required.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_data_length(), + EAP_TYPE_AKA_MINIMUM_RAND_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_enough_challenges); + } + + u8_t * n_rands = static_cast(payload->get_data(payload->get_data_length())); + if (n_rands == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_RAND()->set_buffer( + payload, n_rands, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_AUTN) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_AUTN | Length | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AUTN ... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (payload->get_data_length() < EAP_TYPE_AKA_MINIMUM_AUTN_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x. Too few AUTN bytes 0x%04x, 0x%04x bytes required.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_data_length(), + EAP_TYPE_AKA_MINIMUM_AUTN_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_enough_challenges); + } + + u8_t * AUTN = static_cast(payload->get_data(payload->get_data_length())); + if (AUTN == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_AUTN()->set_buffer( + payload, AUTN, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_AUTS) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_AUTS | Length | AUTS ... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ... AUTS ... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // NOTE first 2 bytes are in reserved field. + if (payload->get_data_length()+2ul != EAP_TYPE_AKA_AUTS_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x. Too few AUTN bytes 0x%04x, 0x%04x bytes required.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_data_length(), + EAP_TYPE_AKA_MINIMUM_AUTN_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_enough_challenges); + } + + u8_t * AUTS = static_cast(payload->get_reserved_pointer(payload->get_data_length())); + if (AUTS == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + // NOTE first 2 bytes are in reserved field. + status = p_aka_payloads->get_AUTS()->set_buffer( + payload, AUTS, payload->get_data_length()+2ul, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_RES) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_RES | Length | RES Length in bits | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | RES ... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // Reserved field includes the length of RES in bits. It is always multiple of 8 bits. + u32_t RES_length = payload->get_reserved() / 8ul; + + if (RES_length == 0u + || RES_length > payload->get_data_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (payload->get_data_length() < EAP_TYPE_AKA_MINIMUM_RES_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x. Too few RES bytes 0x%04x, 0x%04x bytes required.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_data_length(), + EAP_TYPE_AKA_MINIMUM_RES_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_enough_challenges); + } + + u8_t * RES = static_cast(payload->get_data(RES_length)); + if (RES == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_RES()->set_buffer( + payload, RES, RES_length, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_PADDING) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_PADDING | Length | Padding... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + u8_t * padding = 0; + + // Note two first octets of padding are the reserved field. It must be zero. + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + // NOTE padding data length could be zero. + if (payload->get_data_length() != 0u) + { + padding = static_cast(payload->get_data(payload->get_data_length())); + } + + status = p_aka_payloads->get_padding_payload()->set_buffer( + payload, padding, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_NEXT_PSEUDONYM) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_NEXT...YM | Length | Actual Pseudonym Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // | Pseudonym | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // Note the reserved field includes the actual length of pseudonym. + // This must be less or equal to the length field. + u16_t pseudonym_length = payload->get_reserved(); + if (pseudonym_length == 0u + || pseudonym_length > payload->get_data_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, pseudonym length field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t * pseudonym = static_cast(payload->get_data(pseudonym_length)); + if (pseudonym == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_NEXT_PSEUDONYM()->set_buffer( + payload, pseudonym, pseudonym_length, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_NEXT_REAUTH_ID) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_NEXT...ID | Length | Actual Identity Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // | Reauthentication identity | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // Note the reserved field includes the actual length of reauthentication identity. + // This must be less or equal to the length field. + u16_t next_reauth_id_length = payload->get_reserved(); + if (next_reauth_id_length == 0u + || next_reauth_id_length > payload->get_data_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reauthentication identity length field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t * next_reauth_id = static_cast(payload->get_data(next_reauth_id_length)); + if (next_reauth_id == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_NEXT_REAUTH_ID()->set_buffer( + payload, next_reauth_id, next_reauth_id_length, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_RESULT_IND) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_RESULT_IND | Length = 1 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved %d.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_reserved())); + + status = p_aka_payloads->get_RESULT_IND()->set_buffer( + payload, 0, 0u, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_NOTIFICATION) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_NOTIFICATION| Length = 1 | Notification Code | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + // Note the reserved field includes the notification code (client error code). + eap_aka_notification_codes_e notification_code = static_cast(payload->get_reserved()); + EAP_UNREFERENCED_PARAMETER(notification_code); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, notification code %d.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_reserved())); + + status = p_aka_payloads->get_NOTIFICATION()->set_buffer( + payload, 0, 0u, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_COUNTER) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_COUNTER | Length = 1 | Counter | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, counter %d.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_reserved())); + + status = p_aka_payloads->get_COUNTER()->set_buffer( + payload, 0, 0u, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_COUNTER_TOO_SMALL) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_COUNTER_TOO.| Length = 1 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved %d.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_reserved())); + + status = p_aka_payloads->get_COUNTER_TOO_SMALL()->set_buffer( + payload, 0, 0u, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_MAC) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_MAC | Length = 5 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // | MAC | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (payload->get_data_length() != EAP_TYPE_AKA_MAC_SIZE) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_data_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t * buffer + = static_cast(payload->get_data(EAP_TYPE_AKA_MAC_SIZE)); + + if (buffer == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_MAC()->set_buffer( + payload, buffer, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_IV) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_IV | Length = 5 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // | Initialization Vector (optional) | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + crypto_aes_c aes(m_am_tools); + + if (aes.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 (payload->get_data_length() != aes.get_block_size()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_data_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t * buffer + = static_cast(payload->get_data(payload->get_data_length())); + + if (buffer == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + // Note here we get a reference to the data bytes of the received packet. + status = p_aka_payloads->get_IV()->set_buffer( + payload, buffer, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_ENCR_DATA) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_ENCR_DATA | Length | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // | Encrypted Data (optional) | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (payload->get_data_length() < 8u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_data_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t * buffer + = static_cast(payload->get_data(payload->get_data_length())); + + if (buffer == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_ENCR_DATA()->set_buffer( + payload, buffer, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_PERMANENT_ID_REQ) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_PERM..._REQ | Length = 1 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_PERMANENT_ID_REQ()->set_buffer( + payload, 0, 0, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_FULLAUTH_ID_REQ) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_FULL..._REQ | Length = 1 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_FULLAUTH_ID_REQ()->set_buffer( + payload, 0, 0, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_ANY_ID_REQ) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_ANY..._REQ | Length = 1 | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = p_aka_payloads->get_ANY_ID_REQ()->set_buffer( + payload, 0, 0, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_IDENTITY) + { + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_IDENTITY | Length | Actual Identity Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // . Current Identity (optional) . + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + u16_t identity_length = payload->get_reserved(); + + if (payload->get_data_length() == 0 + || identity_length > payload->get_data_length() + || identity_length < 1u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, identity_length 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), identity_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t * identity_data + = static_cast(payload->get_data(payload->get_data_length())); + + if (identity_data == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (identity_length < payload->get_data_length()) + { + crypto_aes_c aes(m_am_tools); + crypto_cbc_c cbc_aes(m_am_tools, &aes, false); + + if (cbc_aes.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + // Includes padding bytes. Those must be zero. + eap_status_e status = cbc_aes.check_padding_bytes( + identity_data+identity_length, + payload->get_data_length()-identity_length, + 0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // We assume the prefix byte is included. + status = p_aka_payloads->get_IDENTITY_payload()->set_buffer( + payload, identity_data, identity_length, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_CLIENT_ERROR_CODE) + { + // The format of the AT_CLIENT_ERROR_CODE attribute is shown below. + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |AT_CLIENT_ERR..| Length = 1 | Client Error Code | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // Note the reserved field includes the client error code. + + if (payload->get_data_length() != EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data length incorrect 0x%04x, should be 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), + payload->get_data_length(), EAP_AKA_PAYLOAD_ZERO_DATA_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + eap_aka_client_error_code_e client_error_code = static_cast(payload->get_reserved()); + + if (client_error_code > eap_aka_client_error_code_maximum_value) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, illegal AKA client error code %d.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), client_error_code)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, client_error_code %d.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + client_error_code)); + + status = p_aka_payloads->get_CLIENT_ERROR_CODE()->set_buffer( + payload, 0, 0u, false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (current_payload == aka_payload_AT_CHECKCODE) + { + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | AT_CHECKCODE | Length | Reserved | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // | Checkcode (0 or 20 bytes) | + // | | + // | | + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (payload->get_reserved() != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, reserved field incorrect 0x%04x.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length(), payload->get_reserved())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (payload->get_data_length() != 0UL + && payload->get_data_length() != EAP_TYPE_AKA_MAXIMUM_CHECKCODE_LENGTH) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x. Illegal CHECKCODE bytes 0x%04x, 0 or 0x%04x bytes required.\n"), + payload, + current_payload, + payload->get_payload_AT_string(), + payload->get_payload_length(), + payload->get_data_length(), + EAP_TYPE_AKA_MAXIMUM_CHECKCODE_LENGTH)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_enough_challenges); + } + + + u8_t * CHECKCODE = 0; + + if (payload->get_data_length() != 0) + { + CHECKCODE = static_cast(payload->get_data(payload->get_data_length())); + if (CHECKCODE == 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(0x%08x): ") + EAPL("current payload 0x%04x=%s, length 0x%04x, data buffer incorrect.\n"), + payload, current_payload, payload->get_payload_AT_string(), payload->get_payload_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + } + + status = p_aka_payloads->get_CHECKCODE()->set_buffer( + payload, CHECKCODE, payload->get_data_length(), false, false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (128 <= current_payload && current_payload <= 255) + { + // Unknown skippable attribute. + // Silently ignore this payload. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("IGNORED: eap_type_aka_c::parse_generic_payload(): Ignored skippable attribute %d=0x%04x.\n"), + current_payload, + current_payload)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + else + { + // Unknown non-skippable attribute. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_generic_payload(): Unknown non-skippable attribute %d=0x%04x.\n"), + current_payload, + current_payload)); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unsupported_gsmsim_payload); + } +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::analyse_aka_packet( + const eap_am_network_id_c * const receive_network_id, + aka_header_c * const received_aka, + const u32_t aka_packet_length, + aka_payloads_c * const p_aka_payloads) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + if (m_is_client == true) + { + // Client + + if (received_aka->get_subtype() == aka_subtype_Identity) + { + status = handle_aka_identity_request_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Challenge) + { + status = handle_challenge_request_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Notification) + { + status = handle_aka_notification_request_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Re_authentication) + { + status = handle_reauthentication_request_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else + { + // Unknown message in this state. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::analyse_aka_packet(): ") + EAPL("Unknown message %d=%s in eap_type_aka_state_variable_e %d=%s.\n"), + received_aka->get_subtype(), + received_aka->get_subtype_string(), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + } + else + { + // Server + + if (received_aka->get_subtype() == aka_subtype_Identity) + { + status = handle_aka_identity_response_message( + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Synchronization_Failure) + { + status = handle_synchronization_failure_response_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Challenge) + { + status = handle_challenge_response_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Notification) + { + status = handle_notification_response_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Re_authentication) + { + status = handle_reauthentication_response_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else if (received_aka->get_subtype() == aka_subtype_Client_Error) + { + status = handle_client_error_response_message( + receive_network_id, + received_aka, + aka_packet_length, + p_aka_payloads); + } + else + { + // Unknown message in this state. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::analyse_aka_packet(): ") + EAPL("Unknown message %d=%s in eap_type_aka_state_variable_e %d=%s.\n"), + received_aka->get_subtype(), + received_aka->get_subtype_string(), + get_state(), + get_state_string())); + 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_aka_c::parse_aka_payload( + const aka_payload_AT_header_c * const p_payload, + u32_t * const buffer_length, + aka_payloads_c * const p_aka_payloads, + const aka_subtype_e subtype) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + aka_payload_AT_header_c payload( + m_am_tools, + p_payload->get_header_buffer(*buffer_length), + *buffer_length); // Const correctness is gone. + + aka_payload_AT_type_e current_payload = payload.get_current_payload(); + + eap_status_e status = eap_status_header_corrupted; + + if (payload.get_is_valid() == true + && current_payload != aka_payload_NONE) + { + if (*buffer_length < payload.get_header_length()+payload.get_data_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_payload(0x%08x): current payload 0x%04x=%s, data length 0x%04x, buffer length 0x%04x.\n"), + payload.get_header_buffer(0ul), + current_payload, + payload.get_payload_AT_string(), + payload.get_data_length(), + *buffer_length)); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_payload(): AKA-payload header is corrupted.\n"))); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("payload"), + payload.get_header_buffer(*buffer_length), + *buffer_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = parse_generic_payload(current_payload, &payload, p_aka_payloads, subtype); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_ASSERT_ALWAYS(*buffer_length >= payload.get_header_length()+payload.get_data_length()); + *buffer_length -= payload.get_header_length()+payload.get_data_length(); + + while(*buffer_length >= payload.get_header_length() + && payload.get_is_valid() == true + && payload.get_header_buffer_length() >= (payload.get_header_length()+payload.get_data_length())) + { + payload.set_header_buffer( + payload.get_next_header(), + payload.get_header_buffer_length()-(payload.get_header_length()+payload.get_data_length())); + if (payload.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + current_payload = payload.get_current_payload(); + + if (*buffer_length < payload.get_header_length()+payload.get_data_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_payload(0x%08x): current payload 0x%04x=%s, data length 0x%04x, buffer length 0x%04x.\n"), + payload.get_header_buffer(0ul), + current_payload, + payload.get_payload_AT_string(), + payload.get_data_length(), + *buffer_length)); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_payload(): AKA-payload header is corrupted.\n"))); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("payload"), + payload.get_header_buffer(*buffer_length), + *buffer_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = parse_generic_payload(current_payload, &payload, p_aka_payloads, subtype); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_ASSERT_ALWAYS(*buffer_length >= payload.get_header_length()+payload.get_data_length()); + *buffer_length -= payload.get_header_length()+payload.get_data_length(); + } + } + + if (*buffer_length != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_payload(): ") + EAPL("AKA-header is corrupted. Buffer length and payload length does not match. %lu illegal bytes.\n"), + *buffer_length)); + 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, eap_status_ok); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::parse_aka_packet( + aka_header_c * const aka, + const u32_t aka_packet_length, + aka_payloads_c * const p_aka_payloads) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (aka->get_length() < aka->get_header_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_packet(): ") + EAPL("AKA-header is corrupted. Buffer length and payload ") + EAPL("length does not match. AKA-header length %lu < minimum AKA-header length %lu.\n"), + aka->get_length(), + aka->get_header_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (aka->get_length() > aka_packet_length) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_packet(): ") + EAPL("AKA-header is corrupted. Buffer length and payload ") + EAPL("length does not match. AKA-header length %lu > packet length %lu\n"), + aka->get_length(), + aka_packet_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u32_t buffer_length = aka->get_length() - aka->get_header_length(); + + if (buffer_length == 0u) + { + // No payload in this packet. + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + + + aka_payload_AT_header_c payload( + m_am_tools, + aka->get_data(buffer_length), + buffer_length); + + if (payload.get_is_valid() == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: No aka_payload_AT_header_c.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + + eap_status_e status = parse_aka_payload( + &payload, + &buffer_length, + p_aka_payloads, + aka->get_subtype()); + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (buffer_length != 0u) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::parse_aka_packet(): ") + EAPL("AKA-header is corrupted. Buffer length and payload ") + EAPL("length does not match. Illegal byte count %lu\n"), + buffer_length)); + 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_aka_c::handle_aka_packet( + const eap_am_network_id_c * const receive_network_id, + aka_header_c * const received_aka, + const u32_t aka_length, + aka_payloads_c * const p_aka_payloads) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = check_valid_state(received_aka->get_subtype()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = parse_aka_packet(received_aka, aka_length, p_aka_payloads); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = analyse_aka_packet( + receive_network_id, + received_aka, + aka_length, + p_aka_payloads); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + +#if defined(USE_EAP_TRACE) + +// +EAP_FUNC_EXPORT void eap_type_aka_c::packet_trace( + eap_const_string prefix, + const eap_am_network_id_c * const /* receive_network_id */, + eap_header_wr_c * const eap_packet, + const u32_t /* eap_packet_length */) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_UNREFERENCED_PARAMETER(prefix); + + if (eap_packet->get_length() > eap_header_base_c::get_header_length() + && eap_packet->get_type() == eap_type_aka) + { + aka_header_c aka_eap( + m_am_tools, + eap_packet->get_header_buffer(eap_packet->get_header_buffer_length()), + eap_packet->get_header_buffer_length()); + + EAP_UNREFERENCED_PARAMETER(aka_eap); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("%s EAP_type_AKA: %s, code=0x%02x=%s, identifier=0x%02x, ") + EAPL("length=0x%04x, type=0x%08x=%s, subtype=0x%02x=%s\n"), + prefix, + (m_is_client == true) ? "client": "server", + aka_eap.get_code(), + aka_eap.get_code_string(), + aka_eap.get_identifier(), + aka_eap.get_length(), + convert_eap_type_to_u32_t(aka_eap.get_type()), + aka_eap.get_eap_type_string(), + aka_eap.get_subtype(), + aka_eap.get_subtype_string())); + + EAP_TRACE_DEBUG(m_am_tools, eap_am_tools_c::eap_trace_mask_eap_messages, + (EAPL("\n\t%s\n\tcode = 0x%02x = %s\n\tidentifier = 0x%02x") + EAPL("\n\tlength = 0x%04x = %lu\n\ttype = 0x%08x = %s\n\tsubtype = 0x%02x = %s\n"), + (m_is_client == true) ? "client": "server", + aka_eap.get_code(), + aka_eap.get_code_string(), + aka_eap.get_identifier(), + aka_eap.get_length(), + aka_eap.get_length(), + convert_eap_type_to_u32_t(aka_eap.get_type()), + aka_eap.get_eap_type_string(), + aka_eap.get_subtype(), + aka_eap.get_subtype_string())); + } + else if (eap_packet->get_length() > eap_header_base_c::get_header_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("%s EAP_type_AKA: %s, code=0x%02x=%s, identifier=0x%02x, length=0x%04x, type=0x%08x=%s\n"), + prefix, + (m_is_client == true) ? "client": "server", + eap_packet->get_code(), + eap_packet->get_code_string(), + eap_packet->get_identifier(), + eap_packet->get_length(), + convert_eap_type_to_u32_t(eap_packet->get_type()), + eap_packet->get_type_string())); + + EAP_TRACE_DEBUG( + m_am_tools, + eap_am_tools_c::eap_trace_mask_eap_messages, + (EAPL("\n\t%s\n\tcode = 0x%02x = %s\n\tidentifier = 0x%02x\n\tlength = 0x%04x = %lu\n\ttype = 0x%08x = %s\n"), + (m_is_client == true) ? "client": "server", + eap_packet->get_code(), + eap_packet->get_code_string(), + eap_packet->get_identifier(), + eap_packet->get_length(), + eap_packet->get_length(), + convert_eap_type_to_u32_t(eap_packet->get_type()), + eap_packet->get_type_string())); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("%s EAP_type_AKA: %s, code=0x%02x=%s, identifier=0x%02x, length=0x%04x\n"), + prefix, + (m_is_client == true) ? "client": "server", + eap_packet->get_code(), + eap_packet->get_code_string(), + eap_packet->get_identifier(), + eap_packet->get_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + eap_am_tools_c::eap_trace_mask_eap_messages, + (EAPL("\n\t%s\n\tcode = 0x%02x = %s\n\tidentifier = 0x%02x\n\tlength = 0x%04x = %lu\n"), + (m_is_client == true) ? "client": "server", + eap_packet->get_code(), + eap_packet->get_code_string(), + eap_packet->get_identifier(), + eap_packet->get_length(), + eap_packet->get_length())); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +#endif //#if defined(USE_EAP_TRACE) + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_variable_data_c * eap_type_aka_c::get_nai_realm() +{ + return &m_manual_realm; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_aka_c::update_buffer_indexes( + const u32_t maximum_buffer_size, + const u32_t payload_size, + u32_t * const buffer_offset, + u32_t * const buffer_free) +{ + EAP_UNREFERENCED_PARAMETER(maximum_buffer_size); + + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_ASSERT_ALWAYS(*buffer_offset + *buffer_free <= maximum_buffer_size-m_trailer_length); + EAP_ASSERT_ALWAYS(*buffer_free >= payload_size); + EAP_ASSERT_ALWAYS(m_aka_header_offset+m_MTU == *buffer_offset + *buffer_free); + + *buffer_free -= payload_size; + *buffer_offset += payload_size; + + EAP_ASSERT_ALWAYS(*buffer_offset + *buffer_free <= maximum_buffer_size-m_trailer_length); + EAP_ASSERT_ALWAYS(*buffer_offset <= m_aka_header_offset+m_MTU); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_aka_c::update_payload_indexes( + const u32_t maximum_buffer_size, + const u32_t eap_header_size, + const u32_t payload_size, + u32_t * const data_offset, + u32_t * const data_free, + u32_t * const buffer_offset, + u32_t * const buffer_free) +{ + EAP_UNREFERENCED_PARAMETER(eap_header_size); + + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_ASSERT_ALWAYS(*buffer_offset == m_aka_header_offset + eap_header_size + *data_offset); + EAP_ASSERT_ALWAYS(*buffer_free == *data_free); + EAP_ASSERT_ALWAYS(*data_free >= payload_size); + + *data_free -= payload_size; + *data_offset += payload_size; + + update_buffer_indexes( + maximum_buffer_size, + payload_size, + buffer_offset, + buffer_free); + + EAP_ASSERT_ALWAYS(*buffer_offset == m_aka_header_offset + eap_header_size + *data_offset); + EAP_ASSERT_ALWAYS(*buffer_free == *data_free); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT bool eap_type_aka_c::get_is_client() +{ + return m_is_client; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_aka_c::set_is_valid() +{ + m_is_valid = true; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT bool eap_type_aka_c::get_is_valid() +{ + return m_is_valid; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_aka_c::state_notification( + const abs_eap_state_notification_c * const state + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::state_notification(): get_type_partner() 0x%08x\n"), + get_type_partner())); + + get_type_partner()->state_notification(state); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::finish_successful_authentication( + 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_aka_c::finish_successful_authentication().\n"))); + + + // 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()); + + if (get_master_session_key()->get_is_valid_data() == false + || get_master_session_key()->get_data_length() == 0u) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error); + } + + eap_status_e status = get_type_partner()->packet_data_crypto_keys( + &send_network_id, + get_master_session_key()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (m_authentication_type == AKA_AUTHENTICATION_TYPE_REAUTHENTICATION) + { + // Re-authentication counter is increased only on successfull re-authentication. + // In order to use re-authentication, the client and the server need to + // update re-authentication counter value. + status = m_am_type_aka->increase_reauth_counter(); + if (status != eap_status_ok) + { + restore_saved_previous_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + set_authentication_finished_successfully(); + set_state(eap_type_aka_state_success); + + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_type_aka, + eap_state_none, + eap_state_authentication_finished_successfully, + get_last_eap_identifier(), + true); + state_notification(¬ification); + + // Indicate AKA AM authentication finish. + m_am_type_aka->authentication_finished(true, m_authentication_type, m_identity_type); + + + if (m_authentication_type == AKA_AUTHENTICATION_TYPE_REAUTHENTICATION) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("EAP_type_AKA: %s, re-authentication EAP-SUCCESS, ") + EAPL("re-authentication identity\n"), + (m_is_client == true) ? "client": "server")); + } + else if (m_authentication_type == AKA_AUTHENTICATION_TYPE_FULL_AUTH) + { + if (m_identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID) + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("EAP_type_AKA: %s, full authentication EAP-SUCCESS, ") + EAPL("pseudonym identity\n"), + (m_is_client == true) ? "client": "server")); + } + else if (m_identity_type == AKA_IDENTITY_TYPE_IMSI_ID) + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("EAP_type_AKA: %s, full authentication EAP-SUCCESS, ") + EAPL("IMSI identity\n"), + (m_is_client == true) ? "client": "server")); + } + else if (m_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID) + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("EAP_type_AKA: %s, full authentication EAP-SUCCESS, ") + EAPL("Re-auth identity\n"), + (m_is_client == true) ? "client": "server")); + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS|TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: EAP_type_AKA: %s, unknown authentication EAP-SUCCESS, ") + EAPL("unknown identity\n"), + (m_is_client == true) ? "client": "server")); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity); + } + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS|TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: EAP_type_AKA: %s, unknown authentication EAP-SUCCESS, ") + EAPL("unknown identity\n"), + (m_is_client == true) ? "client": "server")); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity); + } + + + cancel_error_message_delay_timer(); + + cancel_notification_message_delay_timer(); + + status = eap_status_ok; + + 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_aka_c::packet_process( + const eap_am_network_id_c * const receive_network_id, + eap_header_wr_c * const received_eap, + const u32_t eap_packet_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (receive_network_id == 0 + || receive_network_id->get_is_valid_data() == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::packet_process(): receive_network_id=0x%08x is invalid.\n"), + receive_network_id)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + if (received_eap == 0 + || received_eap->get_is_valid() == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::packet_process(): received_eap 0x%08x is invalid.\n"), + received_eap)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + EAP_AKA_PACKET_TRACE( + EAPL("->"), + receive_network_id, + received_eap, + eap_packet_length); + + if (eap_packet_length < received_eap->get_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::packet_process(): ") + EAPL("eap_packet_length=0x%04x < received_eap->get_length()=0x%04x.\n"), + eap_packet_length, received_eap->get_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_illegal_packet_error); + } + + if (received_eap->get_length() < eap_header_base_c::get_header_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::packet_process(): received_eap->get_length() ") + EAPL("< eap_header_base_c::get_header_length().\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_illegal_packet_error); + } + + + // NOTE: by disabling these calls throughput increases about 18%. + // Disabling also decreases random seeds. + m_am_tools->get_crypto()->add_rand_seed( + received_eap->get_header_buffer(eap_packet_length), + eap_packet_length); + m_am_tools->get_crypto()->add_rand_seed_hw_ticks(); + + eap_status_e status = eap_status_process_general_error; + + if ((m_is_client == true + && received_eap->get_code() == eap_code_request) + || (m_is_client == false + && received_eap->get_code() == eap_code_response)) + { + if (received_eap->get_type() == eap_type_identity + || received_eap->get_type() == eap_type_aka) + { + if (received_eap->get_type() == eap_type_identity + && received_eap->get_code() == eap_code_request + && received_eap->get_length() <= eap_header_base_c::get_header_length()) + { + status = eap_status_header_corrupted; + } + else if (received_eap->get_type() == eap_type_identity + && received_eap->get_code() == eap_code_response + && received_eap->get_length() <= eap_header_base_c::get_header_length()) + { + status = eap_status_header_corrupted; + } + else if (received_eap->get_type() == eap_type_aka + && received_eap->get_length() < received_eap->get_header_length()) + { + status = eap_status_header_corrupted; + } + else + { + aka_header_c aka_header( + m_am_tools, + received_eap->get_header_buffer(received_eap->get_header_buffer_length()), + received_eap->get_header_buffer_length()); + + if (aka_header.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = aka_packet_process( + receive_network_id, + &aka_header, + eap_packet_length, + m_is_client); + + if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_drop_packet_quietly + && status != eap_status_pending_request) + { + eap_status_string_c status_string; + EAP_UNREFERENCED_PARAMETER(status_string); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: %s=%d eap_type_aka_c::aka_packet_process() failed\n"), + status_string.get_status_string(status), status)); + + if (m_is_client == true) + { + status = initialize_error_message( + status); + } + else + { + status = initialize_notification_message(); + } + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (status == eap_status_ok) + { + EAP_GENERAL_HEADER_SET_ERROR_DETECTED(received_eap, false); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (received_eap->get_type() == eap_type_notification) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP type notification: code=0x%02x, ") + EAPL("identifier=0x%02x, length=0x%04x, type=0x%08x\n"), + received_eap->get_code(), + received_eap->get_identifier(), + received_eap->get_length(), + convert_eap_type_to_u32_t(received_eap->get_type()))); + + status = eap_status_illegal_eap_type; + + 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("dropped EAP type unknown: code=0x%02x, ") + EAPL("identifier=0x%02x, length=0x%04x, type=0x%08x\n"), + received_eap->get_code(), + received_eap->get_identifier(), + received_eap->get_length(), + convert_eap_type_to_u32_t(received_eap->get_type()))); + + status = eap_status_illegal_eap_type; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (m_is_client == true + && (received_eap->get_code() == eap_code_success + || received_eap->get_code() == eap_code_failure)) + { + // 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()); + + if (received_eap->get_code() == eap_code_success) + { + if (get_state() == eap_type_aka_state_waiting_for_success) + { + EAP_GENERAL_HEADER_SET_ERROR_DETECTED(received_eap, false); + + if (m_wait_eap_success_packet == false) + { + /** + * @{ Check right functionality. + * Here we return eap_status_ok, eap_status_success was returned after successfull + * EAP-Request/AKA/Challenge. This may change after EAP, 802.1X and 802.11i specifications are ready. } + */ + status = eap_status_ok; + } + else + { + status = finish_successful_authentication( + receive_network_id); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP-Success: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, state %d=%s, is client %d\n"), + received_eap->get_code(), + received_eap->get_identifier(), + received_eap->get_length(), + get_state(), + get_state_string(), + (m_is_client == true))); + status = eap_status_drop_packet_quietly; + } + } + else if (received_eap->get_code() == eap_code_failure) + { + // EAP is quite sloppy protocol. + // Somebody just send a EAP-failure message and authentication is terminated. + + // Save received failure. We do not change our state yet. + // The real correct EAP message could be received later if this failure was + // send by nasty attacker. + set_failure_message_received(); + // We handle the EAP-Request/Failure message after a timeout. + + status = eap_status_ok; + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP code unknown: code=0x%02x, ") + EAPL("identifier=0x%02x, length=0x%04x, is client %d\n"), + received_eap->get_code(), received_eap->get_identifier(), + received_eap->get_length(), (m_is_client == true))); + status = eap_status_illegal_eap_code; + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP code unknown: code=0x%02x, ") + EAPL("identifier=0x%02x, length=0x%04x, is client %d\n"), + received_eap->get_code(), received_eap->get_identifier(), + received_eap->get_length(), (m_is_client == true))); + status = eap_status_illegal_eap_code; + } + + 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_aka_c::new_handler( + const eap_am_network_id_c * const /* receive_network_id */, + const bool is_client_when_true) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::new_handler(): Creating new handler 0x%08x.\n"), + this)); + + // We do not have handler yet and the message is identity EAP-message. + // A new handler is needed. + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + m_is_client = is_client_when_true; + + if (is_client_when_true == true) + { + set_state(eap_type_aka_state_waiting_for_identity_request); + } + else if (is_client_when_true == false) + { + set_state(eap_type_aka_state_waiting_for_identity_response); + } + + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::aka_packet_process(0x%08x): New handler created.\n"), + this)); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL(" own address"), + m_send_network_id.get_source_id()->get_data(m_send_network_id.get_source_id()->get_data_length()), + m_send_network_id.get_source_id()->get_data_length())); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("peer address"), + m_send_network_id.get_destination_id()->get_data(m_send_network_id.get_destination_id()->get_data_length()), + m_send_network_id.get_destination_id()->get_data_length())); + + 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_aka_c::aka_packet_process( + const eap_am_network_id_c * const receive_network_id, + aka_header_c * const received_aka, + const u32_t aka_packet_length, + const bool is_client_when_true) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (receive_network_id == 0 + || receive_network_id->get_is_valid_data() == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("receive_network_id=0x%08x is invalid.\n"), + receive_network_id)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + if (received_aka == 0 + || received_aka->get_is_valid() == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("received_aka 0x%08x is invalid.\n"), + received_aka)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + if (aka_packet_length < received_aka->get_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("aka_packet_length < received_aka->get_length().\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_illegal_packet_error); + } + + if (received_aka->get_type() == eap_type_aka) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::aka_packet_process(), AKA subtype %d=%s\n"), + received_aka->get_subtype(), received_aka->get_subtype_string())); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::aka_packet_process(), EAP-type 0x%08x=%s\n"), + convert_eap_type_to_u32_t(received_aka->get_type()), + received_aka->get_eap_type_string())); + } + + eap_status_e status = eap_status_process_general_error; + + // 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()); + + if (get_state() == eap_type_aka_state_none) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::aka_packet_process(): No handler found.\n"))); + + if (is_client_when_true == false + && received_aka->get_type() == eap_type_identity) + { + // The EAP-identity is plain EAP-packet without additional fields.. + eap_header_rd_c eap_header( + m_am_tools, + received_aka->get_header_buffer(received_aka->get_header_buffer_length()), + received_aka->get_header_buffer_length()); + + EAP_UNREFERENCED_PARAMETER(eap_header); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("received: EAP-identity"), + eap_header.get_type_data(eap_header.get_type_data_length()), + eap_header.get_type_data_length())); + + status = new_handler( + receive_network_id, + is_client_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): new_handler() failed, status %d.\n"), + status)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (is_client_when_true == true + && received_aka->get_code() == eap_code_request) + { + if (received_aka->get_length() < received_aka->get_header_length()) + { + status = eap_status_process_illegal_packet_error; + eap_status_string_c status_string; + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: %s=%d eap_type_aka_c::aka_packet_process(): corrupted AKA-header.\n"), + status_string.get_status_string(status), status)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Here we create a handler and set state to eap_type_aka_state_waiting_for_aka_identity_request + // if first EAP-Request is EAP-Request/AKA/Identity. + if (received_aka->get_subtype() == aka_subtype_Identity) + { + eap_header_rd_c eap_header( + m_am_tools, + received_aka->get_header_buffer(received_aka->get_header_buffer_length()), + received_aka->get_header_buffer_length()); + + EAP_UNREFERENCED_PARAMETER(eap_header); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("received: EAP-Request/AKA/Identity"), + eap_header.get_type_data(eap_header.get_type_data_length()), + eap_header.get_type_data_length())); + + status = new_handler( + receive_network_id, + is_client_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): new_handler() failed, status %d.\n"), + status)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + set_state(eap_type_aka_state_waiting_for_aka_identity_request); + } + else if (received_aka->get_subtype() == aka_subtype_Challenge) + { + eap_header_rd_c eap_header( + m_am_tools, + received_aka->get_header_buffer(received_aka->get_header_buffer_length()), + received_aka->get_header_buffer_length()); + + EAP_UNREFERENCED_PARAMETER(eap_header); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("received: EAP-Request/AKA/Challenge"), + eap_header.get_type_data(eap_header.get_type_data_length()), + eap_header.get_type_data_length())); + + // We must query the previous sent EAP-Identity from EAP_Core. + // The EAP_Core saves the sent EAP-Identity when the EAP-Identity is + // sent to the network. + // Previous EAP-type was NOT this instance. EAP-Identity was queried from other instance. + status = get_type_partner()->get_saved_eap_identity(get_identity()); + if (status != eap_status_ok) + { + // We do not have the identity server accepted anymore. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("Cannot create new handler because EAP-Identity is missing. This EAP-packet is dropped.\n"))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + + status = get_NAI()->set_copy_of_buffer(get_identity()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + m_authentication_type = AKA_AUTHENTICATION_TYPE_FULL_AUTH; + set_identity_type(AKA_IDENTITY_TYPE_IMSI_ID); + + status = new_handler( + receive_network_id, + is_client_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): new_handler() failed, status %d.\n"), + status)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + set_state(eap_type_aka_state_waiting_for_challenge_request); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("Only EAP-Request/AKA/Identity message in EAP-AKA client ") + EAPL("causes creation of new handler. This EAP-packet is dropped.\n"))); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: received: source"), + receive_network_id->get_source(), + receive_network_id->get_source_length())); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: received: destination"), + receive_network_id->get_destination(), + receive_network_id->get_destination_length())); + + if (received_aka->get_type() == eap_type_aka) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: erroneous EAP packet: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, type=0x%08x, subtype=0x%02x, client %d\n"), + received_aka->get_code(), + received_aka->get_identifier(), + received_aka->get_length(), + convert_eap_type_to_u32_t(received_aka->get_type()), + received_aka->get_subtype(), + is_client_when_true)); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: erroneous EAP packet: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, type=0x%08x, client %d\n"), + received_aka->get_code(), + received_aka->get_identifier(), + received_aka->get_length(), + convert_eap_type_to_u32_t(received_aka->get_type()), + is_client_when_true)); + } + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("Only EAP-identity message in server causes creation ") + EAPL("of new handler. This EAP-packet is dropped.\n"))); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: received: source"), + receive_network_id->get_source(), + receive_network_id->get_source_length())); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: received: destination"), + receive_network_id->get_destination(), + receive_network_id->get_destination_length())); + + if (received_aka->get_type() == eap_type_aka) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: erroneous EAP packet: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, type=0x%08x, subtype=0x%02x, client %d\n"), + received_aka->get_code(), + received_aka->get_identifier(), + received_aka->get_length(), + convert_eap_type_to_u32_t(received_aka->get_type()), + received_aka->get_subtype(), + is_client_when_true)); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: erroneous EAP packet: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, type=0x%08x, client %d\n"), + received_aka->get_code(), + received_aka->get_identifier(), + received_aka->get_length(), + convert_eap_type_to_u32_t(received_aka->get_type()), + is_client_when_true)); + } + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::aka_packet_process(): state %d=%s\n"), + get_state(), + get_state_string())); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("received: AKA packet"), + received_aka->get_header_buffer( + received_aka->get_header_buffer_length()), + received_aka->get_header_buffer_length())); + + if (received_aka->get_type() == eap_type_identity) + { + if (is_client_when_true == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("EAP-Request/Identity is not handled here anymore.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + status = eap_status_process_general_error; + } + else if (is_client_when_true == false) + { + eap_header_rd_c eap_header( + m_am_tools, + received_aka->get_header_buffer(received_aka->get_header_buffer_length()), + received_aka->get_header_buffer_length()); + + const eap_type_aka_state_variable_e saved_state = get_state(); + + EAP_UNREFERENCED_PARAMETER(saved_state); + + status = handle_identity_response_message( + &eap_header, + aka_packet_length + ); + + if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_drop_packet_quietly) + { + eap_status_string_c status_string; + EAP_UNREFERENCED_PARAMETER(status_string); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: %s=%d eap_type_aka_c::aka_packet_process(): ") + EAPL("handle_identity_response_message().\n"), + status_string.get_status_string(status), status)); + } + + if (status == eap_status_ok) + { + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_type_aka, + eap_state_none, + eap_state_identity_response_received, + get_last_eap_identifier(), + false); + state_notification(¬ification); + } + } + + if (status == eap_status_ok + || status == eap_status_success) + { + // Ok, good EAP message received. + if (m_is_client == true) + { + unset_failure_message_received(); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("handle_identity_response_message() failed, status %d.\n"), + status)); + } + + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (aka_packet_length < received_aka->get_header_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::aka_packet_process(): ") + EAPL("aka_packet_length < aka_header_c::get_header_length().\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + status = received_aka->check_header(); + if (status != eap_status_ok) + { + eap_status_string_c status_string; + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: %s=%d eap_type_aka_c::aka_packet_process(): corrupted AKA-header.\n"), + status_string.get_status_string(status), status)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("received: handler 0x%08x, AKA-type %10s, %s, state %2d=%s\n"), + this, + received_aka->get_subtype_string(), + (get_is_client()) ? EAPL("client") : EAPL("server"), + get_state(), + get_state_string() + )); + + aka_payloads_c * const l_aka_payloads = new aka_payloads_c(m_am_tools); + eap_automatic_variable_c l_aka_payloads_automatic(m_am_tools, l_aka_payloads); + + if (l_aka_payloads == 0 + || l_aka_payloads->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 = handle_aka_packet( + receive_network_id, + received_aka, + aka_packet_length, + l_aka_payloads); + + if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_drop_packet_quietly + && status != eap_status_pending_request) + { + eap_status_string_c status_string; + EAP_UNREFERENCED_PARAMETER(status_string); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: %s=%d eap_type_aka_c::aka_packet_process(): handle_aka_packet().\n"), + status_string.get_status_string(status), status)); + } + + if (status == eap_status_ok + || status == eap_status_success + || status == eap_status_pending_request) + { + // Ok, good EAP message received. + if (m_is_client == true) + { + unset_failure_message_received(); + } + } + + if (status == eap_status_ok) + { + // Do nothing special. + } + else if (status == eap_status_drop_packet_quietly) + { + // We will drop this message quietly. + } + else if (status != eap_status_ok) + { + // EAP-Failure will be sent from shutdown(). + } + + 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_aka_c::cancel_error_message_delay_timer() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = cancel_timer( + this, + EAP_TYPE_AKA_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID); + + m_erroneus_packet_received = false; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID cancelled.\n"), + (m_is_client == true) ? "client": "server")); + + 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_aka_c::set_error_message_delay_timer() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = set_timer( + this, + EAP_TYPE_AKA_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID, + 0, + m_failure_message_delay_time); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID set.\n"), + (m_is_client == true) ? "client": "server")); + + 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_aka_c::cancel_notification_message_delay_timer() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = cancel_timer( + this, + EAP_TYPE_AKA_TIMER_DELAY_NOTIFICATION_MESSAGE_ID); + + m_erroneus_packet_received = false; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_NOTIFICATION_MESSAGE_ID cancelled.\n"), + (m_is_client == true) ? "client": "server")); + + 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_aka_c::set_notification_message_delay_timer() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = set_timer( + this, + EAP_TYPE_AKA_TIMER_DELAY_NOTIFICATION_MESSAGE_ID, + 0, + m_failure_message_delay_time); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_NOTIFICATION_MESSAGE_ID set.\n"), + (m_is_client == true) ? "client": "server")); + + 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_aka_c::handle_error_packet() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::handle_error_packet(): ") + EAPL("erroneus_packet_received %d, m_client_error_code %d\n"), + m_erroneus_packet_received, + m_client_error_code)); + + if (m_erroneus_packet_received == true) + { + set_state(eap_type_aka_state_failure); + + if (m_is_client == true) + { + // Client will send EAP-Response/AKA/Client-Error. + status = send_aka_client_error_response(); + } + else + { + // Server will send EAP-Failure. + // Notifies the lower level of unsuccessfull authentication. + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_type_aka, + eap_state_none, + eap_state_authentication_terminated_unsuccessfully, + get_last_eap_identifier(), + false); + + notification.set_authentication_error(eap_status_authentication_failure); + + state_notification(¬ification); + + status = eap_status_ok; + } + } + else + { + // One erroneous packet is already received. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("WARNING: eap_type_aka_c::handle_error_packet(): one erroneus packet already received. This is ignored.\n"))); + status = eap_status_ok; + } + + 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_aka_c::initialize_error_message( + const eap_status_e error_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + eap_status_string_c status_string; + EAP_UNREFERENCED_PARAMETER(status_string); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::initialize_error_message(): erroneus_packet_received %d, error_status %s\n"), + m_erroneus_packet_received, + status_string.get_status_string(error_status))); + + if (m_erroneus_packet_received == false) + { + // Only the first erroneus packet is recorded. + m_erroneus_packet_received = true; + + if (m_is_client == true) + { + // Client will send EAP-Response/AKA/Client-Error. + switch(error_status) + { + case eap_status_no_matching_protocol_version: + m_client_error_code = eap_aka_client_error_code_unsupported_version; + break; + case eap_status_not_enough_challenges: + m_client_error_code = eap_aka_client_error_code_insufficient_number_of_challenges; + break; + case eap_status_not_fresh_challenges: + m_client_error_code = eap_aka_client_error_code_rands_are_not_fresh; + break; + default: + m_client_error_code = eap_aka_client_error_code_unable_to_process_packet; + break; + }; + } + else + { + // Server will send EAP-Failure. + } + + if (m_failure_message_delay_time > 0ul) + { + // First try set delay timer. + status = set_error_message_delay_timer(); + if (status != eap_status_ok) + { + // ERROR: Process error packet immediately. + status = handle_error_packet(); + } + } + else + { + // Process error packet immediately. + status = handle_error_packet(); + } + } + else + { + // Error packet is already processed. + status = eap_status_ok; + } + + 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_aka_c::handle_notification_packet() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::handle_notification_packet(): aka_notification_packet_received %d\n"), + m_aka_notification_packet_received)); + + if (m_aka_notification_packet_received == true) + { + bool add_at_counter_attribute = false; + if (m_authentication_type == AKA_AUTHENTICATION_TYPE_REAUTHENTICATION) + { + add_at_counter_attribute = true; + } + + if (m_is_client == true) + { + // Client will send EAP-Response/AKA/Notification. + if (get_aka_notification_code_F_bit(m_aka_notification_code) == false) + { + // The code values with the F bit set to zero (code values 0...32767) + // are used on unsuccessful cases. + // The receipt of a notification code from this range implies failed EAP + // exchange, so the peer can use the notification as a failure indication. + set_state(eap_type_aka_state_failure); + } + + status = send_aka_notification_response( + m_aka_notification_code, + add_at_counter_attribute); + } + else + { + set_state(eap_type_aka_state_waiting_for_notification_response_failure); + + // Server will send EAP-Request/AKA/Notification. + status = send_aka_notification_request( + m_aka_notification_code, + add_at_counter_attribute); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::handle_notification_packet(): one AKA/Notification packet already received. This is ignored.\n"))); + + status = eap_status_ok; + } + + 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_aka_c::initialize_notification_message() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + if (m_aka_notification_packet_received == false) + { + // Only the first AKA notification packet is recorded. + m_aka_notification_packet_received = true; + + if (m_is_client == true) + { + // Client will send empty EAP-Response/AKA/Notification. + } + else + { + // Server will send EAP-Request/AKA/Notification. + if (m_aka_notification_code == eap_aka_notification_none) + { + m_aka_notification_code = eap_aka_notification_no_F_P_set_general_failure; + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::initialize_notification_message(0x%08x), notification_code = 0x%04x, F bit %d, P bit %d.\n"), + this, + m_aka_notification_code, + get_aka_notification_code_F_bit(m_aka_notification_code), + get_aka_notification_code_P_bit(m_aka_notification_code))); + } + + if (m_failure_message_delay_time > 0ul) + { + // First try set delay timer. + status = set_notification_message_delay_timer(); + if (status != eap_status_ok) + { + // ERROR: Process AKA notification packet immediately. + status = handle_notification_packet(); + } + } + else + { + // Process AKA notification packet immediately. + status = handle_notification_packet(); + } + } + else + { + // AKA notification packet is already processed. + status = eap_status_ok; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u32_t eap_type_aka_c::get_header_offset( + u32_t * const MTU, + u32_t * const trailer_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + u32_t offset = get_type_partner()->get_header_offset(MTU, trailer_length); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return offset; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::extra_message_authentication_code_bytes( + const aka_subtype_e subtype, + const eap_code_value_e code, + crypto_hmac_c *hmac_sha1) +{ + if (code == eap_code_request) + { + } + else if (code == eap_code_response) + { + if (subtype == aka_subtype_Re_authentication) + { + eap_status_e status = hmac_sha1->hmac_update( + get_NONCE_S()->get_data(get_NONCE_S()->get_data_length()), + get_NONCE_S()->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); + } + } + } + else + { + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: extra_message_authentication_code_bytes(): unsupported EAP-Code %d.\n"), + code)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::create_message_authentication_code( + eap_type_aka_MAC_attributes_c *MAC_attributes, + const aka_subtype_e subtype, + const eap_code_value_e code, + const eap_variable_data_c * const authentication_key +) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (MAC_attributes == 0 + || authentication_key == 0 + || authentication_key->get_is_valid_data() == false + || MAC_attributes->get_data() == 0 + || MAC_attributes->get_data_length() == 0u + || MAC_attributes->get_MAC() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("authentication_key"), + authentication_key->get_data(authentication_key->get_data_length()), + authentication_key->get_data_length())); + + eap_status_e status = eap_status_process_general_error; + +#if defined(USE_EAP_TRACE) + { + eap_variable_data_c buffer(m_am_tools); + + if (buffer.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 = buffer.set_buffer_length(2048); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = buffer.set_buffer_length(buffer.get_buffer_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u8_t * const tmpbuffer = buffer.get_data(buffer.get_data_length()); + if (tmpbuffer == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u32_t offset = 0; + + m_am_tools->memmove(tmpbuffer+offset, + (MAC_attributes->get_data()), + MAC_attributes->get_data_length()); + offset += MAC_attributes->get_data_length(); + + if (code == eap_code_request) + { + } + else if (code == eap_code_response) + { + if (subtype == aka_subtype_Re_authentication) + { + m_am_tools->memmove(tmpbuffer+offset, + get_NONCE_S()->get_data(get_NONCE_S()->get_data_length()), + get_NONCE_S()->get_data_length()); + offset += get_NONCE_S()->get_data_length(); + } + } + else + { + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: extra_message_authentication_code_bytes(): unsupported EAP-Code %d.\n"), + code)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("create_message_authentication_code(): MAC calculated over the following bytes:\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("MAC data"), + tmpbuffer, + offset)); + } +#endif // #if defined(USE_EAP_TRACE) + + + crypto_sha1_c sha1(m_am_tools); + crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false); + + if (hmac_sha1.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 (hmac_sha1.hmac_set_key( + authentication_key + ) != eap_status_ok) + { + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: create_message_authentication_code(): set_key() failed.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = hmac_sha1.hmac_update( + MAC_attributes->get_data(), + MAC_attributes->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); + } + + status = extra_message_authentication_code_bytes(subtype, code, &hmac_sha1); + if (status != eap_status_ok) + { + eap_status_string_c status_string; + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: %s=%d create_message_authentication_code(): extra_message_authentication_code_bytes().\n"), + status_string.get_status_string(status), status)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + u32_t length = 0u; + + status = hmac_sha1.hmac_128_final( + MAC_attributes->get_MAC(), + &length); + if (status != eap_status_ok + || length != EAP_TYPE_AKA_MAC_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_ASSERT(length == EAP_TYPE_AKA_MAC_SIZE); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("MAC:\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("MAC"), + MAC_attributes->get_MAC(), + length)); + + + 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_aka_c::check_message_authentication_code( + const eap_variable_data_c * const authentication_key, + aka_payloads_c * const p_aka_payloads, + const aka_header_c * const aka_packet, + const u32_t aka_packet_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (authentication_key == 0 + || authentication_key->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + if (p_aka_payloads->get_MAC() == 0 + || p_aka_payloads->get_MAC()->get_payload_included() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + if (aka_packet == 0 + || aka_packet_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("authentication_key"), + authentication_key->get_data(authentication_key->get_data_length()), + authentication_key->get_data_length())); + + crypto_sha1_c sha1(m_am_tools); + crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false); + + if (hmac_sha1.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 (hmac_sha1.hmac_set_key( + authentication_key + ) != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u8_t saved_MAC[EAP_TYPE_AKA_MAC_SIZE]; + + m_am_tools->memmove( + saved_MAC, + p_aka_payloads->get_MAC()->get_data(p_aka_payloads->get_MAC()->get_data_length()), + p_aka_payloads->get_MAC()->get_data_length()); + + m_am_tools->memset( + p_aka_payloads->get_MAC()->get_data(p_aka_payloads->get_MAC()->get_data_length()), + 0, + p_aka_payloads->get_MAC()->get_data_length()); + + + eap_status_e status = hmac_sha1.hmac_update( + aka_packet->get_header_buffer(aka_packet_length), + aka_packet_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = extra_message_authentication_code_bytes( + aka_packet->get_subtype(), + aka_packet->get_code(), + &hmac_sha1); + if (status != eap_status_ok) + { + eap_status_string_c status_string; + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: %s=%d check_message_authentication_code(): extra_message_authentication_code_bytes().\n"), + status_string.get_status_string(status), status)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + + eap_variable_data_c *end_of_authentication = 0; + if (p_aka_payloads->get_MAC()->get_payload_included() == true) + { + end_of_authentication = p_aka_payloads->get_MAC()->get_payload_buffer(); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + + + u32_t length = 0u; + + eap_variable_data_c tmp_MAC(m_am_tools); + + if (tmp_MAC.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 = tmp_MAC.init(EAP_TYPE_AKA_MAC_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + tmp_MAC.set_is_valid(); + tmp_MAC.set_data_length(EAP_TYPE_AKA_MAC_SIZE); + + u8_t * const mac_data = tmp_MAC.get_data_offset(0u, EAP_TYPE_AKA_MAC_SIZE); + if (mac_data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = hmac_sha1.hmac_128_final( + mac_data, + &length); + if (status != eap_status_ok + || length != EAP_TYPE_AKA_MAC_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_ASSERT(length == EAP_TYPE_AKA_MAC_SIZE); + + + +#if defined(USE_EAP_TRACE) + { + eap_variable_data_c buffer(m_am_tools); + + if (buffer.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 = buffer.set_buffer_length(2048); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = buffer.set_buffer_length(buffer.get_buffer_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u8_t * const tmpbuffer = buffer.get_data(buffer.get_data_length()); + if (tmpbuffer == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u32_t offset = 0; + + m_am_tools->memmove(tmpbuffer+offset, + aka_packet->get_header_buffer(aka_packet_length), + aka_packet_length); + offset += aka_packet_length; + + if (aka_packet->get_code() == eap_code_request) + { + } + else if (aka_packet->get_code() == eap_code_response) + { + if (aka_packet->get_subtype() == aka_subtype_Re_authentication) + { + m_am_tools->memmove(tmpbuffer+offset, + get_NONCE_S()->get_data(get_NONCE_S()->get_data_length()), + get_NONCE_S()->get_data_length()); + offset += get_NONCE_S()->get_data_length(); + } + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: extra_message_authentication_code_bytes(): unsupported EAP-Code %d.\n"), + aka_packet->get_code())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("check_message_authentication_code(): MAC calculated over the following bytes:\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("MAC data"), + tmpbuffer, + offset)); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("MAC:\n"))); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("MAC"), + tmp_MAC.get_data(tmp_MAC.get_data_length()), + tmp_MAC.get_data_length())); + } +#endif // #if defined(USE_EAP_TRACE) + + + if (length != end_of_authentication->get_data_length() + || tmp_MAC.get_data_length() + != end_of_authentication->get_data_length()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_EAP_AM_CRYPTO|TRACE_FLAGS_AKA_ERROR|TRACE_TEST_VECTORS, + (EAPL("ERROR: MAC differs.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + + if (m_am_tools->memcmp( + tmp_MAC.get_data(tmp_MAC.get_data_length()), + saved_MAC, + tmp_MAC.get_data_length()) != 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_EAP_AM_CRYPTO|TRACE_FLAGS_AKA_ERROR|TRACE_TEST_VECTORS, + (EAPL("ERROR: MAC differs.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("MAC OK.\n"))); + + 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_aka_c::timer_expired( + const u32_t id, void *data) +{ + EAP_UNREFERENCED_PARAMETER(id); + EAP_UNREFERENCED_PARAMETER(data); + + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: [0x%08x]->eap_type_aka_c::timer_expired(id 0x%02x, data 0x%08x).\n"), + this, id, data)); + + eap_status_e status = eap_status_process_general_error; + + if (id == EAP_TYPE_AKA_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID elapsed.\n"), + (m_is_client == true) ? "client": "server")); + + if (get_state() == eap_type_aka_state_failure) + { + // Athentication is already failed. + + // We set the session timeout to zero. + // This will terminate this session immediately. + status = get_type_partner()->set_session_timeout(0ul); + } + else + { + status = handle_error_packet(); + } + } + else if (id == EAP_TYPE_AKA_TIMER_DELAY_NOTIFICATION_MESSAGE_ID) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_NOTIFICATION_MESSAGE_ID elapsed.\n"), + (m_is_client == true) ? "client": "server")); + + status = handle_notification_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_aka_c::timer_delete_data( + const u32_t id, void *data) +{ + EAP_UNREFERENCED_PARAMETER(id); + EAP_UNREFERENCED_PARAMETER(data); + + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: [0x%08x]->eap_type_aka_c::timer_delete_data(id 0x%02x, data 0x%08x).\n"), + this, id, data)); + + if (id == EAP_TYPE_AKA_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_FAILURE_MESSAGE_SENT_ID delete data.\n"), + (m_is_client == true) ? "client": "server")); + } + else if (id == EAP_TYPE_AKA_TIMER_DELAY_NOTIFICATION_MESSAGE_ID) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: %s: EAP_TYPE_TIMER_DELAY_NOTIFICATION_MESSAGE_ID delete data.\n"), + (m_is_client == true) ? "client": "server")); + } + + 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_aka_c::packet_send( + const eap_am_network_id_c * const network_id, + eap_buf_chain_wr_c * const sent_packet, + const u32_t header_offset, + const u32_t data_length, + const u32_t buffer_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::packet_send().\n"))); + + eap_header_wr_c eap( + m_am_tools, + sent_packet->get_data_offset( + header_offset, data_length), + data_length); + if (eap.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_illegal_packet_error); + } + + EAP_AKA_PACKET_TRACE( + EAPL("<-"), + network_id, + &eap, + data_length); + + eap_status_e status = get_type_partner()->packet_send( + network_id, + sent_packet, + header_offset, + data_length, + buffer_length + ); + + 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_aka_c::read_configure( + const eap_configuration_field_c * const field, + eap_variable_data_c * const data) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // NOTE this will be read from AM of AKA EAP-type. + const eap_status_e status = m_am_type_aka->type_configure_read(field, data); + + 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_aka_c::write_configure( + const eap_configuration_field_c * const field, + eap_variable_data_c * const data) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // NOTE this will be written to AM of AKA EAP-type. + const eap_status_e status = m_am_type_aka->type_configure_write(field, data); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in eap_base_type_c::configure(). +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::configure() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::configure(): this = 0x%08x => 0x%08x\n"), + this, + dynamic_cast(this))); + + eap_status_e status(eap_status_process_general_error); + + + // This must be configured first. + status = m_am_type_aka->configure(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + //---------------------------------------------------------- + + { + eap_variable_data_c error_message_delay_time(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_failure_message_delay_time.get_field(), + &error_message_delay_time); + if (status == eap_status_ok + && error_message_delay_time.get_is_valid_data() == true + && error_message_delay_time.get_data_length() == sizeof(u32_t) + && error_message_delay_time.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + m_failure_message_delay_time = *reinterpret_cast( + error_message_delay_time.get_data(sizeof(u32_t))); + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c use_manual_realm(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_use_manual_realm.get_field(), + &use_manual_realm); + if (status == eap_status_ok + && use_manual_realm.get_is_valid_data() == true + && use_manual_realm.get_data_length() == sizeof(u32_t)) + { + u32_t *flag = reinterpret_cast( + use_manual_realm.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_use_manual_realm = false; + } + else + { + m_use_manual_realm = true; + } + } + } + } + + //---------------------------------------------------------- + + { + status = read_configure( + cf_str_EAP_AKA_manual_realm.get_field(), + get_nai_realm()); + if (status == eap_status_ok + && get_nai_realm()->get_is_valid_data() == true) + { + // OK NAI realm is configured. + } + else + { + // No configured NAI realm. + // We will use automatic realm "wlan.mnc456.mcc123.3gppnetwork.org" as a realm. + // Look at eap_type_aka_c::generate_nai(). + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c wait_eap_success_packet(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_wait_eap_success_packet.get_field(), + &wait_eap_success_packet); + + if (status == eap_status_ok + && wait_eap_success_packet.get_is_valid_data() == true) + { + u32_t *flag = reinterpret_cast( + wait_eap_success_packet.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_wait_eap_success_packet = false; + } + else + { + m_wait_eap_success_packet = true; + } + } + } + + if (get_type_partner()->get_is_tunneled_eap() == true) + { + // Inside the PEAP we must wait EAP-Success to fullfill the state machine of PEAP. + m_wait_eap_success_packet = true; + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c check_identifier_of_eap_identity_response(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_check_identifier_of_eap_identity_response.get_field(), + &check_identifier_of_eap_identity_response); + + if (status == eap_status_ok + && check_identifier_of_eap_identity_response.get_is_valid_data() == true) + { + u32_t *flag = reinterpret_cast( + check_identifier_of_eap_identity_response.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_check_identifier_of_eap_identity_response = false; + } + else + { + m_check_identifier_of_eap_identity_response = true; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c EAP_AKA_check_nai_realm(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_check_nai_realm.get_field(), + &EAP_AKA_check_nai_realm); + if (status == eap_status_ok + && EAP_AKA_check_nai_realm.get_is_valid_data() == true) + { + u32_t *check_nai_realm = reinterpret_cast( + EAP_AKA_check_nai_realm.get_data(sizeof(u32_t))); + if (check_nai_realm != 0 + && *check_nai_realm != 0) + { + m_check_nai_realm = true; + } + } + } + + //---------------------------------------------------------- + + { + status = read_configure( + cf_str_EAP_AKA_nonce_mt_file.get_field(), + &m_nonce_mt_file); + if (status == eap_status_ok + && m_nonce_mt_file.get_is_valid_data() == true + && m_nonce_mt_file.get_data_length() != 0 + && m_nonce_mt_file.get_data(m_nonce_mt_file.get_data_length()) != 0) + { + // This is optional value. + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c EAP_AKA_client_responds_retransmitted_packets(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_client_responds_retransmitted_packets.get_field(), + &EAP_AKA_client_responds_retransmitted_packets); + if (status == eap_status_ok + && EAP_AKA_client_responds_retransmitted_packets.get_is_valid_data() == true + && EAP_AKA_client_responds_retransmitted_packets.get_data_length() == sizeof(u32_t) + && EAP_AKA_client_responds_retransmitted_packets.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + EAP_AKA_client_responds_retransmitted_packets.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_client_responds_retransmitted_packets = false; + } + else + { + m_client_responds_retransmitted_packets = true; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c test_version(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_test_version.get_field(), + &test_version); + if (status == eap_status_ok + && test_version.get_is_valid_data() == true + && test_version.get_data_length() == sizeof(u32_t) + && test_version.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast(test_version.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_aka_test_version = false; + } + else + { + m_aka_test_version = true; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c randomly_refuse_eap_identity(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_randomly_refuse_eap_identity.get_field(), + &randomly_refuse_eap_identity); + if (status == eap_status_ok + && randomly_refuse_eap_identity.get_is_valid_data() == true + && randomly_refuse_eap_identity.get_data_length() == sizeof(u32_t) + && randomly_refuse_eap_identity.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + randomly_refuse_eap_identity.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_aka_randomly_refuse_eap_identity = false; + } + else + { + m_aka_randomly_refuse_eap_identity = true; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c use_manual_username(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_use_manual_username.get_field(), + &use_manual_username); + if (status == eap_status_ok + && use_manual_username.get_is_valid_data() == true) + { + u32_t *use_manual_username_flag = reinterpret_cast( + use_manual_username.get_data(sizeof(u32_t))); + if (use_manual_username_flag != 0 + && *use_manual_username_flag != 0) + { + m_use_manual_username = true; + } + } + } + + //---------------------------------------------------------- + + if (m_use_manual_username == true) + { + status = read_configure( + cf_str_EAP_AKA_manual_username.get_field(), + &m_manual_username); + if (status == eap_status_ok + && m_manual_username.get_is_valid_data() == true) + { + // This is optional value. + } + else + { + // No username defined. + m_use_manual_username = false; + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c fail_re_authentication_counter_check(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_fail_re_authentication_counter_check.get_field(), + &fail_re_authentication_counter_check); + if (status == eap_status_ok + && fail_re_authentication_counter_check.get_is_valid_data() == true + && fail_re_authentication_counter_check.get_data_length() == sizeof(u32_t) + && fail_re_authentication_counter_check.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + fail_re_authentication_counter_check.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_fail_reauthentication_counter_check = false; + } + else + { + m_fail_reauthentication_counter_check = true; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c accept_eap_identity_response(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_accept_eap_identity_response.get_field(), + &accept_eap_identity_response); + if (status == eap_status_ok + && accept_eap_identity_response.get_is_valid_data() == true + && accept_eap_identity_response.get_data_length() == sizeof(u32_t) + && accept_eap_identity_response.get_data( + accept_eap_identity_response.get_data_length()) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + accept_eap_identity_response.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag != 0) + { + m_accept_eap_identity_response = true; + } + else if (*flag == 0) + { + m_accept_eap_identity_response = false; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c use_random_identity_on_eap_identity_response(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_use_random_identity_on_eap_identity_response.get_field(), + &use_random_identity_on_eap_identity_response); + if (status == eap_status_ok + && use_random_identity_on_eap_identity_response.get_is_valid_data() == true + && use_random_identity_on_eap_identity_response.get_data_length() == sizeof(u32_t) + && use_random_identity_on_eap_identity_response.get_data( + use_random_identity_on_eap_identity_response.get_data_length()) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + use_random_identity_on_eap_identity_response.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag != 0) + { + m_use_random_identity_on_eap_identity_response = true; + } + else if (*flag == 0) + { + m_use_random_identity_on_eap_identity_response = false; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c use_pseudonym_identity(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_use_pseudonym_identity.get_field(), + &use_pseudonym_identity); + if (status == eap_status_ok + && use_pseudonym_identity.get_is_valid_data() == true + && use_pseudonym_identity.get_data_length() == sizeof(u32_t) + && use_pseudonym_identity.get_data(use_pseudonym_identity.get_data_length()) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast(use_pseudonym_identity.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag != 0) + { + m_use_pseudonym_identity = true; + } + else if (*flag == 0) + { + m_use_pseudonym_identity = false; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c use_reauthentication_identity(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_use_reauthentication_identity.get_field(), + &use_reauthentication_identity); + if (status == eap_status_ok + && use_reauthentication_identity.get_is_valid_data() == true + && use_reauthentication_identity.get_data_length() == sizeof(u32_t) + && use_reauthentication_identity.get_data( + use_reauthentication_identity.get_data_length()) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + use_reauthentication_identity.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag != 0) + { + m_use_reauthentication_identity = true; + } + else if (*flag == 0) + { + m_use_reauthentication_identity = false; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c randomly_fail_successfull_authentication(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_randomly_fail_successfull_authentication.get_field(), + &randomly_fail_successfull_authentication); + if (status == eap_status_ok + && randomly_fail_successfull_authentication.get_is_valid_data() == true + && randomly_fail_successfull_authentication.get_data_length() == sizeof(u32_t) + && randomly_fail_successfull_authentication.get_data( + randomly_fail_successfull_authentication.get_data_length()) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + randomly_fail_successfull_authentication.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag != 0) + { + m_randomly_fail_successfull_authentication = true; + } + else + { + m_randomly_fail_successfull_authentication = false; + } + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c allow_use_result_indication(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_allow_use_result_indication.get_field(), + &allow_use_result_indication); + if (status == eap_status_ok + && allow_use_result_indication.get_is_valid_data() == true + && allow_use_result_indication.get_data_length() == sizeof(u32_t) + && allow_use_result_indication.get_data( + allow_use_result_indication.get_data_length()) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + allow_use_result_indication.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag != 0) + { + m_allow_use_result_indication = true; + } + else + { + m_allow_use_result_indication = false; + } + } + } + } + + if (m_is_client == false) + { + eap_variable_data_c server_allow_use_result_indication(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_server_allow_use_result_indication.get_field(), + &server_allow_use_result_indication); + if (status == eap_status_ok + && server_allow_use_result_indication.get_is_valid_data() == true + && server_allow_use_result_indication.get_data_length() == sizeof(u32_t) + && server_allow_use_result_indication.get_data( + server_allow_use_result_indication.get_data_length()) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + server_allow_use_result_indication.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag != 0) + { + m_allow_use_result_indication = true; + } + else + { + m_allow_use_result_indication = false; + } + } + } + } + + //---------------------------------------------------------- + +#if defined(USE_EAP_EXPANDED_TYPES) + { + eap_variable_data_c use_eap_expanded_type(m_am_tools); + + eap_status_e status = read_configure( + cf_str_EAP_AKA_use_eap_expanded_type.get_field(), + &use_eap_expanded_type); + + if (status != eap_status_ok) + { + status = read_configure( + cf_str_EAP_CORE_use_eap_expanded_type.get_field(), + &use_eap_expanded_type); + } + + if (status == eap_status_ok + && use_eap_expanded_type.get_data_length() == sizeof(u32_t) + && use_eap_expanded_type.get_data() != 0) + { + u32_t *flag = reinterpret_cast(use_eap_expanded_type.get_data(use_eap_expanded_type.get_data_length())); + + if (flag != 0) + { + if ((*flag) != 0ul) + { + m_use_eap_expanded_type = true; + } + else + { + m_use_eap_expanded_type = false; + } + } + } + } +#endif //#if defined(USE_EAP_EXPANDED_TYPES) + + //---------------------------------------------------------- + + { + (void) read_configure( + cf_str_EAP_AKA_2_digit_mnc_map_of_mcc_of_imsi_array.get_field(), + &m_2_digit_mnc_map_of_mcc_of_imsi_array); + // This is optional value. + } + + { + eap_variable_data_c use_uma_profile(m_am_tools); + + eap_status_e status = read_configure( + cf_str_EAP_AKA_UMA_profile.get_field(), + &use_uma_profile); + if (status == eap_status_ok + && use_uma_profile.get_is_valid_data() == true + && use_uma_profile.get_data_length() == sizeof(u32_t)) + { + u32_t *flag = reinterpret_cast(use_uma_profile.get_data()); + if (flag != 0) + { + if (*flag == 0) + { + m_use_uma_profile = false; + } + else + { + m_use_uma_profile = true; + } + } + } + } + + if (m_use_uma_profile == true) + { + (void) read_configure( + cf_str_EAP_AKA_UMA_realm_prefix.get_field(), + &m_uma_automatic_realm_prefix); + // m_uma_automatic_realm_prefix is optional. + + // In the UMA we must wait EAP-Success to fullfill the state machine of mVPN. + m_wait_eap_success_packet = true; + } + else + { + eap_variable_data_c wait_eap_success_packet(m_am_tools); + + status = read_configure( + cf_str_EAP_AKA_wait_eap_success_packet.get_field(), + &wait_eap_success_packet); + + if (status == eap_status_ok + && wait_eap_success_packet.get_is_valid_data() == true) + { + u32_t *flag = reinterpret_cast(wait_eap_success_packet.get_data()); + if (flag != 0) + { + if (*flag == 0) + { + m_wait_eap_success_packet = false; + } + else + { + m_wait_eap_success_packet = true; + } + } + } + + if (get_type_partner()->get_is_tunneled_eap() == true) + { + // Inside the PEAP we must wait EAP-Success to fullfill the state machine of PEAP. + m_wait_eap_success_packet = true; + } + } + + //---------------------------------------------------------- + + m_aka_header_offset = get_type_partner()->get_header_offset( + &m_MTU, &m_trailer_length); + + if (m_aka_header_offset+m_MTU+m_trailer_length > EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH) + { + EAP_ASSERT_ALWAYS(EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH + >= (m_aka_header_offset+m_trailer_length)); + + m_MTU = EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH - (m_aka_header_offset+m_trailer_length); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +// This is commented in eap_base_type_c::shutdown(). +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::shutdown() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::shutdown(): this = 0x%08x => 0x%08x\n"), + this, + dynamic_cast(this))); + + if (m_shutdown_was_called == true) + { + // Shutdown function was called already. + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + m_shutdown_was_called = true; + + cancel_error_message_delay_timer(); + cancel_notification_message_delay_timer(); + + if (m_am_type_aka != 0) + { + // We must cancel the pending query. + if (get_state() == eap_type_aka_state_pending_identity_query) + { + (void) m_am_type_aka->cancel_AKA_IMSI_or_pseudonym_or_reauthentication_id_query(); + } + else if (get_state() == eap_type_aka_state_pending_kc_sres_query) + { + (void) m_am_type_aka->cancel_AKA_RES_query(); + } + else if (get_state() == eap_type_aka_state_pending_pseudonym_decode_query) + { + (void) m_am_type_aka->cancel_imsi_from_username_query(); + } + else if (get_state() == eap_type_aka_state_pending_authentication_vector_query) + { + (void) m_am_type_aka->cancel_AKA_authentication_vector_query(); + } + + send_final_notification(); + } + + reset(); + + eap_status_e status(eap_status_ok); + if (m_am_type_aka != 0) + { + status = m_am_type_aka->shutdown(); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This function is to allow reuse of this object. +// The whole object state must be reset. +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::reset() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("AKA: %s: function: eap_type_aka_c::reset(): this = 0x%08x\n"), + (m_is_client == true ? "client": "server"), + this)); + + eap_status_e status = eap_status_not_supported; + + m_reset_was_called = true; + + m_use_result_indication = false; + m_authentication_type = AKA_AUTHENTICATION_TYPE_NONE; + set_identity_type(AKA_IDENTITY_TYPE_NONE); + + + { + cancel_error_message_delay_timer(); + m_client_error_code = eap_aka_client_error_code_none; + m_erroneus_packet_received = false; + + cancel_notification_message_delay_timer(); + m_aka_notification_code = eap_aka_notification_none; + m_aka_notification_packet_received = false; + + if (m_authentication_vector != 0) + { + delete m_authentication_vector; + m_authentication_vector = 0; + } + + m_state = eap_type_aka_state_none; + + m_nonce_s.reset(); + m_IV.get_payload_buffer()->reset(); + m_saved_EAP_packet.reset(); + m_XKEY.reset(); + m_K_encr.reset(); + m_K_aut.reset(); + m_master_session_key.reset(); + m_automatic_realm.reset(); + m_automatic_realm_read = false; + m_IMSI.reset(); + m_pseudonym.reset(); + m_reauthentication_identity.reset(); + m_identity.reset(); + m_NAI.reset(); + m_RAND.reset(); + m_AUTN.reset(); + m_RES.reset(); + } + + status = checkcode_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_am_type_aka->reset(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + 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_aka_c::set_timer( + abs_eap_base_timer_c * const p_initializer, + const u32_t p_id, + void * const p_data, + const u32_t p_time_ms) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_ASSERT(m_am_tools->get_global_mutex()->get_is_reserved() == true); + + const eap_status_e status = get_type_partner()->set_timer( + p_initializer, + p_id, + p_data, + p_time_ms); + + 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_aka_c::cancel_timer( + abs_eap_base_timer_c * const p_initializer, + const u32_t p_id) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_ASSERT(m_am_tools->get_global_mutex()->get_is_reserved() == true); + + const eap_status_e status = get_type_partner()->cancel_timer( + p_initializer, + p_id); + + 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_aka_c::cancel_all_timers() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_ASSERT(m_am_tools->get_global_mutex()->get_is_reserved() == true); + + const eap_status_e status = get_type_partner()->cancel_all_timers(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- +//-------------------------------------------------- + +EAP_FUNC_EXPORT const eap_type_aka_state_variable_parameters_c * eap_type_aka_c::get_state_variable() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + if (get_state() < eap_type_aka_state_last_value) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &(m_parameters[get_state()]); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::check_valid_state(aka_subtype_e type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + const eap_type_aka_state_variable_parameters_c * const state_variable = get_state_variable(); + + if (state_variable == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_gsmsim_state); + } + + if (state_variable->check_initiator(!get_is_client()) == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::check_valid_state(): Initiator type %d is wrong in eap_type_aka_state_variable_e %d=%s.\n"), + get_is_client(), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_gsmsim_state); + } + + if (state_variable->check_valid_types(type) == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: eap_type_aka_c::check_valid_state(): aka_subtype_e %d is wrong in eap_type_aka_state_variable_e %d=%s.\n"), + type, + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_subtype); + } + + 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_aka_c::store_identity( + const eap_variable_data_c * const IMSI_or_pseudonym, + const bool IMSI_is_used) +{ + eap_status_e status = get_identity()->init(IMSI_or_pseudonym->get_data_length()+1u); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + get_identity()->set_is_valid(); + + if (IMSI_is_used == true) + { + // Note the first octet is reserved for IMSI prefix. + status = get_identity()->set_copy_of_buffer(AKA_IMSI_PREFIX_CHARACTER, 1u); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + status = get_identity()->add_data(IMSI_or_pseudonym); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +/// not used: expansion_0 = prf(key, seed | 0) +/// not used: expansion_i = prf(key, expansion_i-1 | seed | i), where i = 1, 2... + +/// The following is from "DIGITAL SIGNATURE STANDARD (DSS)" FIPS PUB 186-2: +/// Let x be the signer's private key. The following may be used to generate m values of x: +/// Step 1. Choose a new, secret value for the seed-key, XKEY. +/// Step 2. In hexadecimal notation let +/// t = 67452301 EFCDAB89 98BADCFE 10325476 C3D2E1F0. +/// This is the initial value for H0 || H1 || H2 || H3 || H4 in the SHS. +/// Step 3. For j = 0 to m - 1 do +/// a. XSEEDj = optional user input. +/// b. XVAL = (XKEY + XSEEDj) mod 2^b. +/// c. xj = G(t,XVAL) mod q. +/// d. XKEY = (1 + XKEY + xj) mod 2^b. +/// +/// Within AKA the following parameters are used: +/// 160-bit XKEY and XVAL values are used, so b = 160. +/// XKEY = SHA1(n*Kc| NONCE_MT) +/// The optional user input values (XSEED_j) are set to zero. +/// xj = G(t, XVAL) + +/// Random generator become as follows: +/// Step 1. Choose a new, secret value for the seed-key, XKEY. +/// Step 2. In hexadecimal notation let +/// t = 67452301 EFCDAB89 98BADCFE 10325476 C3D2E1F0. +/// This is the initial value for H0 || H1 || H2 || H3 || H4 in the SHS. +/// Step 3. For j = 0 to m - 1 do +/// c. xj = G(t,XKEY). +/// d. XKEY = (1 + XKEY + xj) mod 2^b. + +EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::data_exp( + const u32_t data_length, + eap_variable_data_c * const expansion, + const eap_variable_data_c * const key, + const eap_variable_data_c * const seed) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + eap_status_e status = eap_status_process_general_error; + + EAP_UNREFERENCED_PARAMETER(seed); + + u32_t count = data_length/EAP_TYPE_AKA_KEYMAT_SIZE; + if ((data_length % EAP_TYPE_AKA_KEYMAT_SIZE) != 0) + { + ++count; + } + + status = expansion->init(count*EAP_TYPE_AKA_KEYMAT_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + expansion->set_is_valid(); + + status = expansion->set_data_length(count*EAP_TYPE_AKA_KEYMAT_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_am_tools->get_crypto()->dss_pseudo_random( + expansion->get_data(expansion->get_data_length()), + expansion->get_data_length(), + key->get_data(key->get_data_length()), + key->get_data_length()); + + 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_aka_c::generate_shared_secred_keys( + const u32_t key_length, + const eap_variable_data_c * const CK, + const eap_variable_data_c * const IK, + eap_variable_data_c * const XKEY, + eap_variable_data_c * const K_encr, + eap_variable_data_c * const K_aut, + eap_variable_data_c * const master_session_key) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("generate_shared_secred_keys():\n"))); + + if (get_NAI()->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai); + } + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("full auth NAI"), + get_NAI()->get_data(get_NAI()->get_data_length()), + get_NAI()->get_data_length())); + + if (IK->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("IK"), + IK->get_data(IK->get_data_length()), + IK->get_data_length())); + + if (CK->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("CK"), + CK->get_data(CK->get_data_length()), + CK->get_data_length())); + + eap_status_e status = eap_status_process_general_error; + + // - - - - - - - - - - - - - - - - - - - - - - - - + + // XKEY = SHA1(NAI | IK | CK) + + crypto_sha1_c sha1(m_am_tools); + + if (sha1.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 (sha1.hash_init() != eap_status_ok) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_AKA_ERROR, + (EAPL("ERROR: generate_shared_secred_keys(): init() failed.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = sha1.hash_update( + get_NAI()->get_data(get_NAI()->get_data_length()), + get_NAI()->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); + } + + status = sha1.hash_update( + IK->get_data(IK->get_data_length()), + IK->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); + } + + status = sha1.hash_update( + CK->get_data(CK->get_data_length()), + CK->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); + } + + status = XKEY->init(key_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + XKEY->set_is_valid(); + XKEY->set_data_length(key_length); + + u32_t md_length = key_length; + + status = sha1.hash_final( + XKEY->get_data_offset(0u, key_length), + &md_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_ASSERT_ALWAYS(md_length == key_length); + + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("generate_shared_secred_keys(): XKEY\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL(" XKEY"), + XKEY->get_data(XKEY->get_data_length()), + XKEY->get_data_length())); + + // - - - - - - - - - - - - - - - - - - - - - - - - + + u32_t aes_key_length = m_am_tools->get_crypto()->aes_key_length(); + u32_t data_length = aes_key_length + EAP_TYPE_AKA_MAC_SIZE + EAP_TYPE_AKA_MASTER_SESSION_KEY_SIZE; + + eap_variable_data_c expansion(m_am_tools); + eap_variable_data_c seed(m_am_tools); + + if (expansion.get_is_valid() == false + || seed.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 = seed.add_data(get_NAI()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = data_exp( + data_length, + &expansion, + XKEY, + &seed); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("generate_shared_secred_keys(): expansion\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("expansion"), + expansion.get_data(expansion.get_data_length()), + expansion.get_data_length())); + + u8_t *data = expansion.get_data_offset(0u, data_length); + if (data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + const u8_t * const data_begin = data; + + EAP_UNREFERENCED_PARAMETER(data_begin); + + // K_encr, K_aut and master_session_key + + status = K_encr->set_copy_of_buffer(data, aes_key_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + data += aes_key_length; + EAP_ASSERT_ALWAYS(static_cast(data-data_begin) <= data_length); + + status = K_aut->set_copy_of_buffer(data, EAP_TYPE_AKA_MAC_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + data += EAP_TYPE_AKA_MAC_SIZE; + EAP_ASSERT_ALWAYS(static_cast(data-data_begin) <= data_length); + + status = master_session_key->set_copy_of_buffer(data, EAP_TYPE_AKA_MASTER_SESSION_KEY_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + data += EAP_TYPE_AKA_MASTER_SESSION_KEY_SIZE; + EAP_ASSERT_ALWAYS(static_cast(data-data_begin) <= data_length); + + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("generate_shared_secred_keys(): K_encr\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL(" K_encr"), + K_encr->get_data(K_encr->get_data_length()), + K_encr->get_data_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("generate_shared_secred_keys(): K_aut\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL(" K_aut"), + K_aut->get_data(K_aut->get_data_length()), + K_aut->get_data_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("generate_shared_secred_keys(): master_session_key\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL(" MSK+EMSK"), + master_session_key->get_data(master_session_key->get_data_length()), + master_session_key->get_data_length())); + + // - - - - - - - - - - - - - - - - - - - - - - - - + + + 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_aka_c::generate_reauth_shared_secred_keys( + const u32_t key_length, + const eap_variable_data_c * const orig_XKEY, + const u32_t reauth_counter, + const eap_variable_data_c * const reauth_identity, + const eap_variable_data_c * const reauth_nonce_s, + eap_variable_data_c * const master_session_key) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + u16_t counter = eap_htons(static_cast(reauth_counter)); + + eap_variable_data_c reauth_XKEY(m_am_tools); + + if (reauth_XKEY.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("generate_reauth_shared_secred_keys():\n"))); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("reauth NAI"), + reauth_identity->get_data(reauth_identity->get_data_length()), + reauth_identity->get_data_length())); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("reauth_counter"), + &counter, + sizeof(counter))); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("NONCE_S"), + reauth_nonce_s->get_data(reauth_nonce_s->get_data_length()), + reauth_nonce_s->get_data_length())); + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("orig_XKEY"), + orig_XKEY->get_data(orig_XKEY->get_data_length()), + orig_XKEY->get_data_length())); + + eap_status_e status = eap_status_process_general_error; + + // - - - - - - - - - - - - - - - - - - - - - - - - + + // XKEY = SHA1(Identity|counter|NONCE_S|original XKEY) + + crypto_sha1_c sha1(m_am_tools); + + if (sha1.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 (sha1.hash_init() != eap_status_ok) + { + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: generate_reauth_shared_secred_keys(): init() failed.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = sha1.hash_update( + reauth_identity->get_data(reauth_identity->get_data_length()), + reauth_identity->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); + } + + status = sha1.hash_update( + &counter, + sizeof(counter)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = sha1.hash_update( + reauth_nonce_s->get_data(reauth_nonce_s->get_data_length()), + reauth_nonce_s->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); + } + + status = sha1.hash_update( + orig_XKEY->get_data(orig_XKEY->get_data_length()), + orig_XKEY->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); + } + + status = reauth_XKEY.init(key_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + reauth_XKEY.set_is_valid(); + reauth_XKEY.set_data_length(key_length); + + u32_t md_length = key_length; + + status = sha1.hash_final( + reauth_XKEY.get_data_offset(0u, key_length), + &md_length); + + EAP_ASSERT_ALWAYS(md_length == key_length); + + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("generate_reauth_shared_secred_keys(): reauth_XKEY\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("reauth_XKEY"), + reauth_XKEY.get_data(reauth_XKEY.get_data_length()), + reauth_XKEY.get_data_length())); + + // - - - - - - - - - - - - - - - - - - - - - - - - + + u32_t aes_key_length = m_am_tools->get_crypto()->aes_key_length(); + u32_t data_length = aes_key_length + EAP_TYPE_AKA_MAC_SIZE + EAP_TYPE_AKA_MASTER_SESSION_KEY_SIZE; + + eap_variable_data_c expansion(m_am_tools); + eap_variable_data_c seed(m_am_tools); + + if (expansion.get_is_valid() == false + || seed.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 = seed.add_data(get_NAI()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = data_exp( + data_length, + &expansion, + &reauth_XKEY, + &seed); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("generate_reauth_shared_secred_keys(): expansion\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("expansion"), + expansion.get_data(expansion.get_data_length()), + expansion.get_data_length())); + + u8_t *data = expansion.get_data_offset(0u, data_length); + if (data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + const u8_t * const data_begin = data; + + EAP_UNREFERENCED_PARAMETER(data_begin); + + // Only master_session_key is used in re-authentication. + + status = master_session_key->set_copy_of_buffer(data, EAP_TYPE_AKA_MASTER_SESSION_KEY_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + data += EAP_TYPE_AKA_MASTER_SESSION_KEY_SIZE; + EAP_ASSERT_ALWAYS(static_cast(data-data_begin) <= data_length); + + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("generate_reauth_shared_secred_keys(): master_session_key\n"))); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL(" MSK+EMSK"), + master_session_key->get_data(master_session_key->get_data_length()), + master_session_key->get_data_length())); + + // - - - - - - - - - - - - - - - - - - - - - - - - + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void eap_type_aka_c::delete_unused_keys() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_const_string eap_type_aka_c::get_identity_string(const eap_type_aka_identity_type identity_type) +{ +#if defined(USE_EAP_TRACE_STRINGS) + EAP_IF_RETURN_STRING(identity_type, AKA_IDENTITY_TYPE_NONE) + else EAP_IF_RETURN_STRING(identity_type, AKA_IDENTITY_TYPE_IMSI_ID) + else EAP_IF_RETURN_STRING(identity_type, AKA_IDENTITY_TYPE_PSEUDONYM_ID) + else EAP_IF_RETURN_STRING(identity_type, AKA_IDENTITY_TYPE_RE_AUTH_ID) + else +#endif // #if defined(USE_EAP_TRACE_STRINGS) + { + EAP_UNREFERENCED_PARAMETER(identity_type); + return EAPL("Unknown AKA identity"); + } +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_const_string eap_type_aka_c::get_state_string(eap_type_aka_state_variable_e state) +{ + +#if defined(USE_EAP_TRACE_STRINGS) + EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_identity_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_pending_identity_query) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_aka_identity_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_imsi_waiting_for_aka_identity_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_pseydonym_waiting_for_aka_identity_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_analyse_aka_identity_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_challenge_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_analyses_challenge_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_pending_kc_sres_query) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_success) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_reauth_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_analyses_reauthentication_request) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_pending_pseudonym_decode_query) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_identity_response) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_aka_identity_response) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_challenge_response) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_pending_authentication_vector_query) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_analyses_challenge_response) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_analyses_aka_identity_response) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_notification_request_success) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_notification_response_failure) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_notification_response_success) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_waiting_for_reauth_response) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_analyses_reauthentication_response) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_success) + else EAP_IF_RETURN_STRING(state, eap_type_aka_state_failure) + else +#else +EAP_UNREFERENCED_PARAMETER(state); +#endif // #if defined(USE_EAP_TRACE_STRINGS) + { + return EAPL("Unknown AKA state"); + } +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_const_string eap_type_aka_c::get_state_string() const +{ + return get_state_string(m_state); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_const_string eap_type_aka_c::get_saved_previous_state_string() const +{ + return get_state_string(m_saved_previous_state); +} + +//-------------------------------------------------- + +bool eap_type_aka_c::get_aka_notification_code_F_bit(const eap_aka_notification_codes_e notification_code) +{ + return ((notification_code & aka_notification_code_bit_f) != 0); +} + +//-------------------------------------------------- + +bool eap_type_aka_c::get_aka_notification_code_P_bit(const eap_aka_notification_codes_e notification_code) +{ + return ((notification_code & aka_notification_code_bit_p) != 0); +} + +//-------------------------------------------------- + +void eap_type_aka_c::object_increase_reference_count() +{ +} + +//-------------------------------------------------- + +u32_t eap_type_aka_c::object_decrease_reference_count() +{ + return 0u; +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_authentication_vector(eap_type_aka_authentication_vector_c * const authentication_vector) +{ + if (m_authentication_vector != 0) + { + delete m_authentication_vector; + m_authentication_vector = 0; + } + m_authentication_vector = authentication_vector; +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_reauthentication_counter(const u32_t reauthentication_counter) +{ + m_reauthentication_counter = reauthentication_counter; +} + +//-------------------------------------------------- + +u32_t eap_type_aka_c::get_reauthentication_counter() +{ + return m_reauthentication_counter; +} + +//-------------------------------------------------- + +eap_type_aka_authentication_vector_c * eap_type_aka_c::get_authentication_vector() +{ + return m_authentication_vector; +} + +//-------------------------------------------------- + +const eap_variable_data_c * eap_type_aka_c::get_RAND() const +{ + return &m_RAND; +} + +//-------------------------------------------------- + +eap_status_e eap_type_aka_c::set_RAND(const eap_variable_data_c * const RAND) +{ + return m_RAND.set_copy_of_buffer(RAND); +} + +//-------------------------------------------------- + +const eap_variable_data_c * eap_type_aka_c::get_AUTN() const +{ + return &m_AUTN; +} + +//-------------------------------------------------- + +eap_status_e eap_type_aka_c::set_AUTN(const eap_variable_data_c * const AUTN) +{ + return m_AUTN.set_copy_of_buffer(AUTN); +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_last_eap_identifier(const u8_t last_eap_identifier) +{ + m_last_eap_identifier = last_eap_identifier; +} + +//-------------------------------------------------- + +u8_t eap_type_aka_c::get_last_eap_identifier() +{ + return m_last_eap_identifier; +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_include_identity_to_aka_identity_response(const aka_payload_AT_type_e id_type_required) +{ + m_include_identity_to_aka_identity_response = id_type_required; +} + +//-------------------------------------------------- + +aka_payload_AT_type_e eap_type_aka_c::get_include_identity_to_aka_identity_response() +{ + return m_include_identity_to_aka_identity_response; +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_aka_identity_response_includes_identity(const aka_payload_AT_type_e id_type_required) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_AKA: %s: eap_type_aka_c::set_aka_identity_response_includes_identity(): %d=%s\n"), + (m_is_client == true ? "client": "server"), + id_type_required, + aka_payload_AT_header_c::get_payload_AT_string(id_type_required))); + + m_aka_identity_response_includes_identity = id_type_required; +} + +//-------------------------------------------------- + +aka_payload_AT_type_e eap_type_aka_c::get_aka_identity_response_includes_identity() +{ + return m_aka_identity_response_includes_identity; +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_failure_message_received() +{ + m_failure_message_received = true; +} + +//-------------------------------------------------- + +void eap_type_aka_c::unset_failure_message_received() +{ + m_failure_message_received = false; +} + +//-------------------------------------------------- + +bool eap_type_aka_c::get_failure_message_received() +{ + return m_failure_message_received; +} + +//-------------------------------------------------- + +eap_type_aka_state_variable_e eap_type_aka_c::get_state() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_state; +} + +//-------------------------------------------------- + +eap_type_aka_state_variable_e eap_type_aka_c::get_saved_previous_state() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_saved_previous_state; +} + +//-------------------------------------------------- + +void eap_type_aka_c::save_current_state() +{ + m_saved_previous_state = m_state; +} + +//-------------------------------------------------- + +void eap_type_aka_c::restore_saved_previous_state() +{ + set_state(m_saved_previous_state); +} + +//-------------------------------------------------- + +eap_am_network_id_c * eap_type_aka_c::get_send_network_id() +{ + return &m_send_network_id; +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_authentication_finished_successfully() +{ + m_authentication_finished_successfully = true; +} + +//-------------------------------------------------- + +bool eap_type_aka_c::get_authentication_finished_successfully() +{ + return m_authentication_finished_successfully; +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_state(eap_type_aka_state_variable_e state) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_type_aka_state_variable_e previous_state = m_state; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::set_state(): old state %d=%s\n"), + get_state(), + get_state_string())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_aka_c::set_state(): new state %d=%s\n"), + state, + get_state_string(state))); + + m_state = state; + + eap_type_aka_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap_type, + eap_type_aka, + previous_state, + state, + m_last_eap_identifier, + false); + state_notification(¬ification); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_NONCE_S() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_nonce_s; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_IMSI() +{ + return &m_IMSI; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_identity() +{ + return &m_identity; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_NAI() +{ + return &m_NAI; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_RES() +{ + return &m_RES; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_pseudonym() +{ + return &m_pseudonym; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_reauthentication_identity() +{ + return &m_reauthentication_identity; +} + +//-------------------------------------------------- + +aka_variable_data_c * eap_type_aka_c::get_IV() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_IV; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_saved_EAP_packet() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_saved_EAP_packet; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_XKEY() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_XKEY; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_K_encr() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_K_encr; +} + +//-------------------------------------------------- + +eap_variable_data_c * eap_type_aka_c::get_K_aut() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_K_aut; +} + +//-------------------------------------------------- + +eap_master_session_key_c * eap_type_aka_c::get_master_session_key() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_master_session_key; +} + +//-------------------------------------------------- + +eap_status_e eap_type_aka_c::store_last_encryption_iv(const eap_variable_data_c * const encryption_IV) +{ + return m_IV.get_payload_buffer()->set_copy_of_buffer(encryption_IV); +} + +//-------------------------------------------------- + +void eap_type_aka_c::set_identity_type(eap_type_aka_identity_type type) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("GSMSIM: %s: eap_type_aka_c::set_identity_type(): %d=%s\n"), + (m_is_client == true ? "client": "server"), + type, + get_identity_string(type))); + + m_identity_type = type; +} + +//-------------------------------------------------- +//-------------------------------------------------- +//-------------------------------------------------- + +eap_type_aka_MAC_attributes_c::~eap_type_aka_MAC_attributes_c() +{ +} + +//-------------------------------------------------- + +eap_type_aka_MAC_attributes_c::eap_type_aka_MAC_attributes_c() + : m_MAC(0) + , m_MAC_size(0) + , m_data(0) + , m_data_length(0u) +{ +} + +//-------------------------------------------------- + +eap_type_aka_MAC_attributes_c::eap_type_aka_MAC_attributes_c( + u8_t * MAC, + u32_t MAC_size, + u8_t * const EAP_data, + u32_t EAP_data_length) + : m_MAC(MAC) + , m_MAC_size(MAC_size) + , m_data(EAP_data) + , m_data_length(EAP_data_length) +{ +} + +//-------------------------------------------------- + +void eap_type_aka_MAC_attributes_c::init( + u8_t * MAC, + u32_t MAC_size, + u8_t * const EAP_data, + u32_t EAP_data_length) +{ + m_MAC = (MAC); + m_MAC_size = (MAC_size); + m_data = (EAP_data); + m_data_length = (EAP_data_length); +} + +//-------------------------------------------------- + +u8_t * eap_type_aka_MAC_attributes_c::get_MAC() const +{ + return m_MAC; +} + +//-------------------------------------------------- + +void eap_type_aka_MAC_attributes_c::set_MAC(u8_t * MAC) +{ + m_MAC = MAC; +} + +//-------------------------------------------------- + +u32_t eap_type_aka_MAC_attributes_c::get_MAC_size() const +{ + return m_MAC_size; +} + +//-------------------------------------------------- + +eap_type_aka_MAC_attributes_c * eap_type_aka_MAC_attributes_c::copy() const +{ + return new eap_type_aka_MAC_attributes_c( + m_MAC, + m_MAC_size, + m_data, + m_data_length); +} + +//-------------------------------------------------- + +u8_t * eap_type_aka_MAC_attributes_c::get_data() const +{ + return m_data; +} + +//-------------------------------------------------- + +u32_t eap_type_aka_MAC_attributes_c::get_data_length() +{ + return m_data_length; +} + +//-------------------------------------------------- + +void eap_type_aka_MAC_attributes_c::set_data(u8_t * const data) +{ + m_data = data; +} + + +//-------------------------------------------------- +//-------------------------------------------------- +//-------------------------------------------------- +// End.