--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/eapol/eapol_framework/eapol_common/type/aka/core/eap_type_aka_server.cpp Thu Dec 17 08:47:43 2009 +0200
@@ -0,0 +1,5209 @@
+/*
+* 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 70
+ #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 "eap_automatic_variable.h"
+#include "eap_buffer.h"
+
+
+//--------------------------------------------------
+
+/** @file */
+
+//--------------------------------------------------
+
+
+//
+EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::add_mac_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,
+ u8_t ** const MAC_data,
+ u32_t * const MAC_data_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ aka_payload_AT_header_c gp_MAC(
+ m_am_tools,
+ aka->get_data_offset(
+ *aka_data_offset, *aka_data_free),
+ *aka_data_free);
+
+ if (gp_MAC.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+
+ u32_t eap_type_aka_mac_size = EAP_TYPE_AKA_MAC_SIZE;
+
+ gp_MAC.reset_header(static_cast<u16_t>(eap_type_aka_mac_size));
+ gp_MAC.set_data_length(static_cast<u16_t>(eap_type_aka_mac_size));
+ gp_MAC.set_current_payload(aka_payload_AT_MAC);
+
+ *MAC_data = gp_MAC.get_data(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_process_general_error);
+ }
+ *MAC_data_length = eap_type_aka_mac_size;
+
+ m_am_tools->memset(*MAC_data, 0, eap_type_aka_mac_size);
+
+ // MAC is calculated later using call create_message_authentication_code().
+
+ update_payload_indexes(
+ aka_buffer_length,
+ eap_header_size,
+ gp_MAC.get_header_length()+gp_MAC.get_data_length(),
+ aka_data_offset,
+ aka_data_free,
+ packet_buffer_offset,
+ packet_buffer_free);
+
+ EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_MAC);
+
+ 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_padding_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 u32_t plaintext_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ aka_payload_AT_header_c gp_padding(
+ m_am_tools,
+ aka->get_data_offset(
+ *aka_data_offset, *aka_data_free),
+ *aka_data_free);
+
+ if (gp_padding.get_is_valid() == false)
+ {
+ 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);
+ 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);
+ }
+
+ if ((plaintext_length % cbc_aes.get_block_size()) == 0ul)
+ {
+ // We do not need padding, because plaintext length is multiple of
+ // block size.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+
+ u32_t cbc_aes_data_length = cbc_aes.aligned_data_length(plaintext_length);
+ u32_t padding_bytes_length = 0u;
+
+ if (cbc_aes_data_length
+ > plaintext_length+aka_payload_AT_header_c::get_header_length())
+ {
+ // Fill with zero (0x00) bytes.
+ padding_bytes_length
+ = cbc_aes_data_length
+ - (plaintext_length
+ +aka_payload_AT_header_c::get_header_length());
+ }
+
+ u32_t padding_payload_length
+ = aka_payload_AT_header_c::get_header_length()
+ +padding_bytes_length;
+
+ if ((padding_payload_length % EAP_TYPE_AKA_PADDING_MODULUS) != 0)
+ {
+ // ERROR
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_padding);
+ }
+
+ if (padding_payload_length > EAP_TYPE_AKA_PADDING_MAX_VALUE)
+ {
+ padding_payload_length = 0ul;
+ padding_bytes_length = 0ul;
+ }
+
+ // Note the reserved field is the begin of padding.
+ // The reserved field is set zero in reset_header() function.
+ gp_padding.reset_header(static_cast<u16_t>(padding_payload_length));
+ gp_padding.set_data_length(static_cast<u16_t>(padding_bytes_length));
+ gp_padding.set_current_payload(aka_payload_AT_PADDING);
+
+ if (padding_bytes_length > 0ul)
+ {
+ u8_t *padding = gp_padding.get_data(padding_bytes_length);
+ if (padding == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ cbc_aes.add_padding_bytes(
+ padding,
+ padding_bytes_length,
+ 0ul);
+ }
+
+ update_payload_indexes(
+ aka_buffer_length,
+ eap_header_size,
+ gp_padding.get_header_length()+gp_padding.get_data_length(),
+ aka_data_offset,
+ aka_data_free,
+ packet_buffer_offset,
+ packet_buffer_free);
+
+ EAP_AKA_TRACE_PAYLOAD("Padding payload added", &gp_padding);
+
+ 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::encrypt_DATA_payload(
+ u8_t * const data,
+ const u32_t cbc_aes_data_length,
+ const eap_variable_data_c * const IV,
+ const eap_variable_data_c * const encryption_key
+ )
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = eap_status_process_general_error;
+
+ if (data == 0
+ || cbc_aes_data_length == 0
+ || IV == 0
+ || IV->get_is_valid_data() == false
+ || encryption_key == 0
+ || encryption_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);
+ }
+
+ 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);
+ }
+
+ u32_t aes_key_length = aes.get_key_length();
+ if (encryption_key->get_data_length() < aes_key_length)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error);
+ }
+
+ status = cbc_aes.set_encryption_key(
+ IV->get_data(IV->get_data_length()),
+ IV->get_data_length(),
+ encryption_key->get_data(encryption_key->get_data_length()),
+ 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);
+ }
+
+ status = cbc_aes.encrypt_data(
+ data,
+ cbc_aes_data_length);
+
+ store_last_encryption_iv(cbc_aes.get_tmp_IV());
+
+ 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::send_reauthentication_request_message(
+ const eap_variable_data_c * const username,
+ const bool pseudonym_decode_failed,
+ const u8_t eap_identifier)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_UNREFERENCED_PARAMETER(pseudonym_decode_failed);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL(" send: handler 0x%08x, AKA-subtype %10s, %s, state %2d=%s\n"),
+ this,
+ EAPL("aka_subtype_Re_authentication"),
+ EAPL("server"),
+ get_state(),
+ get_state_string()
+ ));
+
+
+ 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 = eap_status_process_general_error;
+
+ 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);
+ }
+
+
+ eap_buf_chain_wr_c request_packet(
+ eap_write_buffer,
+ m_am_tools,
+ EAP_MAX_LOCAL_PACKET_BUFFER_LENGTH);
+
+ if (request_packet.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("packet buffer corrupted.\n")));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ if (m_is_client == true
+ && m_client_responds_retransmitted_packets == true)
+ {
+ // We do not wan't lower layers do re-transmissions behalf of us.
+ // This means AKA does process every re-transmitted EAP-Request.
+ request_packet.set_do_packet_retransmission(false);
+ }
+
+ EAP_ASSERT_ALWAYS(EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH >= (m_aka_header_offset+m_trailer_length));
+ u32_t packet_buffer_free = EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH-m_trailer_length;
+ u32_t packet_buffer_offset = 0u;
+
+ if (m_aka_header_offset+m_MTU < packet_buffer_free)
+ {
+ packet_buffer_free = m_aka_header_offset+m_MTU;
+ }
+
+ aka_header_c aka_response(
+ m_am_tools,
+ request_packet.get_data_offset(
+ m_aka_header_offset,
+ (packet_buffer_free-m_aka_header_offset)),
+ (packet_buffer_free-m_aka_header_offset));
+
+ if (aka_response.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("send_reauthentication_request_message: packet buffer corrupted.\n")));
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ aka_response.reset_header(
+ packet_buffer_free-m_aka_header_offset,
+ m_use_eap_expanded_type);
+ aka_response.set_length(
+ static_cast<u16_t>(packet_buffer_free-m_aka_header_offset),
+ m_use_eap_expanded_type);
+ aka_response.set_code(eap_code_request);
+ aka_response.set_identifier(eap_identifier);
+ aka_response.set_type(
+ eap_type_aka,
+ m_use_eap_expanded_type);
+ aka_response.set_subtype(aka_subtype_Re_authentication);
+
+ update_buffer_indexes(
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ m_aka_header_offset+aka_response.get_header_length(),
+ &packet_buffer_offset,
+ &packet_buffer_free);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::send_reauthentication_request_message(0x%08x).\n"),
+ this));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ u32_t aka_data_free = packet_buffer_free;
+ u32_t aka_data_offset = 0u;
+
+ eap_variable_data_c orig_XKEY(m_am_tools);
+ eap_variable_data_c orig_K_aut(m_am_tools);
+ eap_variable_data_c orig_K_encr(m_am_tools);
+
+ if (orig_XKEY.get_is_valid() == false
+ || orig_K_aut.get_is_valid() == false
+ || orig_K_encr.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ u32_t reauth_counter = 0u;
+
+ eap_variable_data_c reauth_nonce_s(m_am_tools);
+
+ if (reauth_nonce_s.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+
+ // In order to use re-authentication, the client and the server need to
+ // store the following values: original XKEY, K_aut, K_encr, latest
+ // counter value and the next re-authentication identity.
+ status = m_am_type_aka->query_reauth_parameters(
+ &orig_XKEY,
+ &orig_K_aut,
+ &orig_K_encr,
+ &reauth_counter);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = generate_nonce(EAP_TYPE_AKA_NONCE_MT_SIZE, &reauth_nonce_s);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = get_NONCE_S()->set_copy_of_buffer(&reauth_nonce_s);
+ 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 master_session_key(m_am_tools);
+
+ if (master_session_key.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = generate_reauth_shared_secred_keys(
+ EAP_TYPE_AKA_KEYMAT_SIZE,
+ &orig_XKEY,
+ reauth_counter,
+ username,
+ &reauth_nonce_s,
+ &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);
+ }
+
+ // - - - - - - - - - - - -
+
+ m_use_result_indication = m_allow_use_result_indication;
+
+ if (m_use_result_indication == true)
+ {
+ // We support use of protected success indications.
+ status = add_simple_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ aka_payload_AT_RESULT_IND);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ &checkcode_digest,
+ aka_payload_AT_CHECKCODE);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ 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);
+ }
+
+ status = m_am_type_aka->generate_encryption_IV(
+ get_IV()->get_payload_buffer(),
+ aes.get_block_size());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_IV()->get_payload_buffer(),
+ aka_payload_AT_IV);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ u8_t *MAC_data = 0;
+ u32_t MAC_data_length = 0u;
+ eap_type_aka_MAC_attributes_c MAC_attributes;
+
+ // Encrypted data.
+ {
+ aka_payload_AT_header_c gp_encrypted_data(
+ m_am_tools,
+ aka_response.get_data_offset(
+ aka_data_offset,
+ aka_data_free),
+ aka_data_free);
+ if (aka_response.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // Initialize the length of encrypted data to maximum length.
+ // Later this will be set to correct length.
+ gp_encrypted_data.reset_header(aka_payload_AT_header_c::get_max_payload_data_length());
+ gp_encrypted_data.set_current_payload(aka_payload_AT_ENCR_DATA);
+
+ update_payload_indexes(
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ gp_encrypted_data.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_offset,
+ &packet_buffer_free);
+
+ u32_t encrypted_data_offset_begin = packet_buffer_offset;
+
+ // - - - - - - - - - - - -
+
+ status = add_counter_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ static_cast<u16_t>(reauth_counter));
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ &reauth_nonce_s,
+ aka_payload_AT_NONCE_S);
+ 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->generate_reauthentication_id(
+ get_send_network_id(),
+ get_IMSI(),
+ get_reauthentication_identity(),
+ EAP_TYPE_AKA_MAX_NAI_LENGTH);
+ if (status == eap_status_ok)
+ {
+ status = add_pseudonym_or_imsi_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_reauthentication_identity(),
+ aka_payload_AT_NEXT_REAUTH_ID);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_padding_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ (packet_buffer_offset - encrypted_data_offset_begin) // Length of the plain text.
+ );
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ gp_encrypted_data.set_data_length(
+ static_cast<u16_t>(packet_buffer_offset - encrypted_data_offset_begin));
+
+ // - - - - - - - - - - - -
+
+ status = encrypt_DATA_payload(
+ gp_encrypted_data.get_data(gp_encrypted_data.get_data_length()),
+ gp_encrypted_data.get_data_length(),
+ get_IV()->get_payload_buffer(),
+ &orig_K_encr);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_encrypted_data);
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_mac_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ &MAC_data,
+ &MAC_data_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ aka_response.set_data_length(
+ aka_data_offset,
+ m_use_eap_expanded_type);
+ request_packet.set_data_length(packet_buffer_offset);
+
+ EAP_ASSERT_ALWAYS(
+ m_aka_header_offset+aka_response.get_header_length()+aka_response.get_data_length()
+ == packet_buffer_offset);
+
+ // - - - - - - - - - - - -
+
+ MAC_attributes.init(
+ MAC_data,
+ MAC_data_length,
+ aka_response.get_header_buffer(aka_response.get_length()),
+ aka_response.get_length());
+
+ status = create_message_authentication_code(
+ &MAC_attributes,
+ aka_response.get_subtype(),
+ aka_response.get_code(),
+ &orig_K_aut);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ aka_response.set_data_length(
+ aka_data_offset,
+ m_use_eap_expanded_type);
+ request_packet.set_data_length(packet_buffer_offset);
+
+ EAP_ASSERT_ALWAYS(
+ m_aka_header_offset+aka_response.get_header_length()+aka_response.get_data_length()
+ == packet_buffer_offset);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::send_reauthentication_request_message()\n")));
+
+ status = packet_send(
+ get_send_network_id(),
+ &request_packet,
+ m_aka_header_offset,
+ aka_response.get_header_length()+aka_response.get_data_length(),
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH
+ );
+
+ if (status == eap_status_ok)
+ {
+ status = get_master_session_key()->set_copy_of_buffer(&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);
+ }
+ set_state(eap_type_aka_state_waiting_for_reauth_response);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ 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::send_aka_identity_request_message(
+ const bool pseudonym_decode_failed,
+ const u8_t eap_identifier)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL(" send: handler 0x%08x, %s, AKA-subtype %10s, %s, state %2d=%s\n"),
+ this,
+ EAPL("initiator"),
+ EAPL("aka_subtype_Identity"),
+ EAPL("server"),
+ get_state(),
+ get_state_string()
+ ));
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::send_aka_identity_request_message(): ")
+ EAPL("requested identity payload is %d=%s, state %d=%s, pseudonym decode %d.\n"),
+ get_aka_identity_response_includes_identity(),
+ aka_payload_AT_header_c::get_payload_AT_string(get_aka_identity_response_includes_identity()),
+ get_state(),
+ get_state_string(),
+ pseudonym_decode_failed));
+
+ eap_status_e status = eap_status_process_general_error;
+
+ eap_buf_chain_wr_c request_packet(
+ eap_write_buffer,
+ m_am_tools,
+ EAP_MAX_LOCAL_PACKET_BUFFER_LENGTH);
+
+ if (request_packet.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("packet buffer corrupted.\n")));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ if (m_is_client == true
+ && m_client_responds_retransmitted_packets == true)
+ {
+ // We do not wan't lower layers do re-transmissions behalf of us.
+ // This means AKA does process every re-transmitted EAP-Request.
+ request_packet.set_do_packet_retransmission(false);
+ }
+
+ EAP_ASSERT_ALWAYS(EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH >= (m_aka_header_offset+m_trailer_length));
+ u32_t packet_buffer_free = EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH-m_trailer_length;
+ u32_t packet_buffer_offset = 0u;
+
+ if (m_aka_header_offset+m_MTU < packet_buffer_free)
+ {
+ packet_buffer_free = m_aka_header_offset+m_MTU;
+ }
+
+ aka_header_c aka_response(
+ m_am_tools,
+ request_packet.get_data_offset(
+ m_aka_header_offset,
+ (packet_buffer_free-m_aka_header_offset)),
+ (packet_buffer_free-m_aka_header_offset));
+
+ if (aka_response.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("send_aka_identity_request_message: packet buffer corrupted.\n")));
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+
+ aka_response.reset_header(
+ packet_buffer_free-m_aka_header_offset,
+ m_use_eap_expanded_type);
+ aka_response.set_length(
+ static_cast<u16_t>(packet_buffer_free-m_aka_header_offset),
+ m_use_eap_expanded_type);
+ aka_response.set_code(eap_code_request);
+ aka_response.set_identifier(eap_identifier);
+ aka_response.set_type(
+ eap_type_aka,
+ m_use_eap_expanded_type);
+ aka_response.set_subtype(aka_subtype_Identity);
+
+ update_buffer_indexes(
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ m_aka_header_offset+aka_response.get_header_length(),
+ &packet_buffer_offset,
+ &packet_buffer_free);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::send_aka_identity_request_message(0x%08x).\n"),
+ this));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ u32_t aka_data_free = packet_buffer_free;
+ u32_t aka_data_offset = 0u;
+
+ if (pseudonym_decode_failed == true)
+ {
+ aka_payload_AT_type_e next_identity_request = aka_payload_NONE;
+ eap_type_aka_state_variable_e next_state = eap_type_aka_state_failure;
+
+ if (get_identity()->get_is_valid_data() == true)
+ {
+ if (get_aka_identity_response_includes_identity() == aka_payload_AT_FULLAUTH_ID_REQ)
+ {
+ next_identity_request = aka_payload_AT_FULLAUTH_ID_REQ;
+ next_state = eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity;
+ }
+ else if (get_aka_identity_response_includes_identity() == aka_payload_AT_PERMANENT_ID_REQ)
+ {
+ next_identity_request = aka_payload_AT_PERMANENT_ID_REQ;
+ next_state = eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity;
+ }
+ else if (get_aka_identity_response_includes_identity() == aka_payload_AT_ANY_ID_REQ)
+ {
+ next_identity_request = aka_payload_AT_ANY_ID_REQ;
+ next_state = eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity;
+ }
+ else
+ {
+ // We drop this message because no real identity is received from client.
+ EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_AKA_ERROR, (EAPL("ERROR: send_aka_identity_request_message: no real identity received.\n")));
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+ }
+ else
+ {
+ next_identity_request = aka_payload_AT_ANY_ID_REQ;
+ next_state = eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity;
+ }
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ 0,
+ next_identity_request);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ set_state(next_state);
+ }
+ else
+ {
+ set_state(eap_type_aka_state_waiting_for_aka_identity_response);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ aka_response.set_data_length(
+ aka_data_offset,
+ m_use_eap_expanded_type);
+ request_packet.set_data_length(packet_buffer_offset);
+
+ EAP_ASSERT_ALWAYS(
+ m_aka_header_offset+aka_response.get_header_length()+aka_response.get_data_length()
+ == packet_buffer_offset);
+
+ status = checkcode_save_message_server(
+ aka_response.get_header_buffer(
+ aka_response.get_header_length()
+ +aka_response.get_data_length()),
+ aka_response.get_header_length()
+ +aka_response.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);
+ }
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::send_aka_identity_request_message()\n")));
+
+ status = packet_send(
+ get_send_network_id(),
+ &request_packet,
+ m_aka_header_offset,
+ aka_response.get_header_length()+aka_response.get_data_length(),
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH
+ );
+
+ if (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::send_challenge_request_message(
+ const u8_t eap_identifier)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL(" send: handler 0x%08x, AKA-type %10s, %s, state %2d=%s\n"),
+ this,
+ EAPL("aka_subtype_Challenge"),
+ (get_is_client()) ? EAPL("client") : EAPL("server"),
+ get_state(),
+ get_state_string()
+ ));
+
+ 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 = eap_status_process_general_error;
+
+ 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);
+ }
+
+
+ eap_buf_chain_wr_c aka_initial_reply(
+ eap_write_buffer,
+ m_am_tools,
+ EAP_MAX_LOCAL_PACKET_BUFFER_LENGTH);
+
+ if (aka_initial_reply.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("packet buffer corrupted.\n")));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ if (m_is_client == true
+ && m_client_responds_retransmitted_packets == true)
+ {
+ // We do not wan't lower layers do re-transmissions behalf of us.
+ // This means AKA does process every re-transmitted EAP-Request.
+ aka_initial_reply.set_do_packet_retransmission(false);
+ }
+
+ EAP_ASSERT_ALWAYS(EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH >= (m_aka_header_offset+m_trailer_length));
+ u32_t packet_buffer_free = EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH-m_trailer_length;
+ u32_t packet_buffer_offset = 0u;
+
+ if (m_aka_header_offset+m_MTU < packet_buffer_free)
+ {
+ packet_buffer_free = m_aka_header_offset+m_MTU;
+ }
+
+ aka_header_c aka_response(
+ m_am_tools,
+ aka_initial_reply.get_data_offset(
+ m_aka_header_offset,
+ (packet_buffer_free-m_aka_header_offset)),
+ (packet_buffer_free-m_aka_header_offset));
+
+ if (aka_response.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("packet_send: packet buffer corrupted.\n")));
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+
+ aka_response.reset_header(
+ packet_buffer_free-m_aka_header_offset,
+ m_use_eap_expanded_type);
+ aka_response.set_length(
+ static_cast<u16_t>(packet_buffer_free-m_aka_header_offset),
+ m_use_eap_expanded_type);
+ aka_response.set_code(eap_code_request);
+ aka_response.set_identifier(eap_identifier);
+ aka_response.set_type(
+ eap_type_aka,
+ m_use_eap_expanded_type);
+
+ aka_response.set_subtype(aka_subtype_Challenge);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::send_challenge_request_message(0x%08x).\n"),
+ this));
+
+ update_buffer_indexes(
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ m_aka_header_offset+aka_response.get_header_length(),
+ &packet_buffer_offset,
+ &packet_buffer_free);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ u32_t aka_data_free = packet_buffer_free;
+ u32_t aka_data_offset = 0u;
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ if (get_authentication_vector()->get_RAND()->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 (get_authentication_vector()->get_AUTN()->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 (get_authentication_vector()->get_RES()->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 (get_authentication_vector()->get_CK()->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 (get_authentication_vector()->get_IK()->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 (get_identity()->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 (get_IMSI()->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);
+ }
+
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, (EAPL("RAND"),
+ get_authentication_vector()->get_RAND()->get_data(
+ get_authentication_vector()->get_RAND()->get_data_length()),
+ get_authentication_vector()->get_RAND()->get_data_length()));
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("AUTN"),
+ get_authentication_vector()->get_AUTN()->get_data(
+ get_authentication_vector()->get_AUTN()->get_data_length()),
+ get_authentication_vector()->get_AUTN()->get_data_length()));
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("RES"),
+ get_authentication_vector()->get_RES()->get_data(
+ get_authentication_vector()->get_RES()->get_data_length()),
+ get_authentication_vector()->get_RES()->get_data_length()));
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("CK"),
+ get_authentication_vector()->get_CK()->get_data(
+ get_authentication_vector()->get_CK()->get_data_length()),
+ get_authentication_vector()->get_CK()->get_data_length()));
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("IK"),
+ get_authentication_vector()->get_IK()->get_data(
+ get_authentication_vector()->get_IK()->get_data_length()),
+ get_authentication_vector()->get_IK()->get_data_length()));
+
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("identity"),
+ get_identity()->get_data(get_identity()->get_data_length()),
+ get_identity()->get_data_length()));
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("IMSI"),
+ get_IMSI()->get_data(get_IMSI()->get_data_length()),
+ get_IMSI()->get_data_length()));
+
+ eap_variable_data_c XKEY(m_am_tools);
+ eap_variable_data_c K_encr(m_am_tools);
+ eap_variable_data_c K_aut(m_am_tools);
+ eap_variable_data_c master_session_key(m_am_tools);
+
+ if (XKEY.get_is_valid() == false
+ || K_encr.get_is_valid() == false
+ || K_aut.get_is_valid() == false
+ || master_session_key.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = generate_shared_secred_keys(
+ EAP_TYPE_AKA_KEYMAT_SIZE,
+ get_authentication_vector()->get_CK(),
+ get_authentication_vector()->get_IK(),
+ &XKEY,
+ &K_encr,
+ &K_aut,
+ &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);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ m_use_result_indication = m_allow_use_result_indication;
+
+ if (m_use_result_indication == true)
+ {
+ // We support use of protected success indications.
+ status = add_simple_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ aka_payload_AT_RESULT_IND);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ &checkcode_digest,
+ aka_payload_AT_CHECKCODE);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_authentication_vector()->get_RAND(),
+ aka_payload_AT_RAND);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_authentication_vector()->get_AUTN(),
+ aka_payload_AT_AUTN);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ u8_t *MAC_data = 0;
+ u32_t MAC_data_length = 0u;
+ eap_type_aka_MAC_attributes_c MAC_attributes;
+
+ if (m_use_pseudonym_identity == true
+ || m_use_reauthentication_identity == true)
+ {
+ u32_t saved_aka_data_offset = aka_data_offset;
+ u32_t saved_aka_data_free = aka_data_free;
+ u32_t saved_packet_buffer_offset = packet_buffer_offset;
+ u32_t saved_packet_buffer_free = packet_buffer_free;
+
+ 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);
+ }
+
+ status = m_am_type_aka->generate_encryption_IV(
+ get_IV()->get_payload_buffer(),
+ aes.get_block_size());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_IV()->get_payload_buffer(),
+ aka_payload_AT_IV);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ // Encrypted data.
+ {
+ aka_payload_AT_header_c gp_encrypted_data(
+ m_am_tools,
+ aka_response.get_data_offset(
+ aka_data_offset,
+ aka_data_free),
+ aka_data_free);
+ if (gp_encrypted_data.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // Initialize the length of encrypted data to maximum length.
+ // Later this will be set to correct length.
+ gp_encrypted_data.reset_header(aka_payload_AT_header_c::get_max_payload_data_length());
+ gp_encrypted_data.set_current_payload(aka_payload_AT_ENCR_DATA);
+
+ update_payload_indexes(
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ gp_encrypted_data.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_offset,
+ &packet_buffer_free);
+
+ u32_t encrypted_data_offset_begin = packet_buffer_offset;
+
+ // - - - - - - - - - - - -
+
+ if (m_use_pseudonym_identity == true)
+ {
+ status = m_am_type_aka->generate_pseudonym_id(
+ get_send_network_id(),
+ get_IMSI(),
+ get_pseudonym(),
+ EAP_TYPE_AKA_MAX_NAI_LENGTH);
+ if (status == eap_status_ok)
+ {
+ status = add_pseudonym_or_imsi_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_pseudonym(),
+ aka_payload_AT_NEXT_PSEUDONYM);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+ }
+
+ // - - - - - - - - - - - -
+
+ if (m_use_reauthentication_identity == true)
+ {
+ status = m_am_type_aka->generate_reauthentication_id(
+ get_send_network_id(),
+ get_IMSI(),
+ get_reauthentication_identity(),
+ EAP_TYPE_AKA_MAX_NAI_LENGTH);
+ if (status == eap_status_ok)
+ {
+ status = add_pseudonym_or_imsi_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_reauthentication_identity(),
+ aka_payload_AT_NEXT_REAUTH_ID);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+ }
+
+ // - - - - - - - - - - - -
+
+ u32_t plain_text_length = packet_buffer_offset - encrypted_data_offset_begin;
+
+ if (plain_text_length > 0ul)
+ {
+ status = add_padding_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ plain_text_length // Length of the plain text.
+ );
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // Re calculate after adding the padding.
+ plain_text_length = packet_buffer_offset - encrypted_data_offset_begin;
+
+ gp_encrypted_data.set_data_length(
+ static_cast<u16_t>(plain_text_length));
+
+ // - - - - - - - - - - - -
+
+ status = encrypt_DATA_payload(
+ gp_encrypted_data.get_data(gp_encrypted_data.get_data_length()),
+ gp_encrypted_data.get_data_length(),
+ get_IV()->get_payload_buffer(),
+ &K_encr);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_encrypted_data);
+ }
+ else
+ {
+ // No encrypted data, remove AT_ENCR_DATA header.
+ aka_data_offset = saved_aka_data_offset;
+ aka_data_free = saved_aka_data_free;
+ packet_buffer_offset = saved_packet_buffer_offset;
+ packet_buffer_free = saved_packet_buffer_free;
+ }
+ }
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_mac_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ &MAC_data,
+ &MAC_data_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ aka_response.set_data_length(
+ aka_data_offset,
+ m_use_eap_expanded_type);
+ aka_initial_reply.set_data_length(packet_buffer_offset);
+
+ EAP_ASSERT_ALWAYS(
+ m_aka_header_offset+aka_response.get_header_length()+aka_response.get_data_length()
+ == packet_buffer_offset);
+
+ // - - - - - - - - - - - -
+
+ MAC_attributes.init(
+ MAC_data,
+ MAC_data_length,
+ aka_response.get_header_buffer(aka_response.get_length()),
+ aka_response.get_length());
+
+ status = create_message_authentication_code(
+ &MAC_attributes,
+ aka_response.get_subtype(),
+ aka_response.get_code(),
+ &K_aut);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ aka_response.set_data_length(
+ aka_data_offset,
+ m_use_eap_expanded_type);
+ aka_initial_reply.set_data_length(packet_buffer_offset);
+
+ EAP_ASSERT_ALWAYS(
+ m_aka_header_offset+aka_response.get_header_length()+aka_response.get_data_length()
+ == packet_buffer_offset);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = packet_send(
+ get_send_network_id(),
+ &aka_initial_reply,
+ m_aka_header_offset,
+ aka_response.get_header_length()+aka_response.get_data_length(),
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH
+ );
+
+ if (status == eap_status_ok)
+ {
+ // Store keys.
+ status = get_XKEY()->set_copy_of_buffer(&XKEY);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ status = get_K_encr()->set_copy_of_buffer(&K_encr);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ status = get_K_aut()->set_copy_of_buffer(&K_aut);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ status = get_master_session_key()->set_copy_of_buffer(&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);
+ }
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ 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::send_aka_notification_request(
+ const eap_aka_notification_codes_e notification_code,
+ const bool add_at_counter_attribute)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("send: handler 0x%08x, AKA-type %10s, %s, state %2d=%s, notification_code = %d\n"),
+ this,
+ EAPL("send_aka_notification_request"),
+ (get_is_client()) ? EAPL("client") : EAPL("server"),
+ get_state(),
+ get_state_string(),
+ notification_code
+ ));
+
+ eap_buf_chain_wr_c eap_notification_packet(
+ eap_write_buffer,
+ m_am_tools,
+ EAP_MAX_LOCAL_PACKET_BUFFER_LENGTH);
+
+ if (eap_notification_packet.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("packet buffer corrupted.\n")));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ if (m_is_client == true
+ && m_client_responds_retransmitted_packets == true)
+ {
+ // We do not wan't lower layers do re-transmissions behalf of us.
+ // This means AKA does process every re-transmitted EAP-Request.
+ eap_notification_packet.set_do_packet_retransmission(false);
+ }
+
+ EAP_ASSERT_ALWAYS(EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH >= (m_aka_header_offset+m_trailer_length));
+ u32_t packet_buffer_free = EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH-m_trailer_length;
+ u32_t packet_buffer_offset = 0u;
+
+ if (m_aka_header_offset+m_MTU < packet_buffer_free)
+ {
+ packet_buffer_free = m_aka_header_offset+m_MTU;
+ }
+
+ aka_header_c aka_response(
+ m_am_tools,
+ eap_notification_packet.get_data_offset(
+ m_aka_header_offset,
+ (packet_buffer_free-m_aka_header_offset)),
+ (packet_buffer_free-m_aka_header_offset));
+
+ if (aka_response.get_is_valid() == false)
+ {
+ EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("packet_send: packet buffer corrupted.\n")));
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+
+ set_last_eap_identifier(static_cast<u8_t>(get_last_eap_identifier()+1u));
+
+ aka_response.reset_header(
+ static_cast<u16_t>(packet_buffer_free-m_aka_header_offset),
+ m_use_eap_expanded_type);
+ aka_response.set_length(
+ static_cast<u16_t>(packet_buffer_free-m_aka_header_offset),
+ m_use_eap_expanded_type);
+ aka_response.set_code(eap_code_request);
+ aka_response.set_identifier(get_last_eap_identifier());
+ aka_response.set_type(
+ eap_type_aka,
+ m_use_eap_expanded_type);
+ aka_response.set_subtype(aka_subtype_Notification);
+
+
+ update_buffer_indexes(
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ m_aka_header_offset+aka_response.get_header_length(),
+ &packet_buffer_offset,
+ &packet_buffer_free);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ u32_t aka_data_free = packet_buffer_free;
+ u32_t aka_data_offset = 0u;
+
+ eap_status_e status = add_notification_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ notification_code);
+ 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 * K_aut = 0;
+
+ eap_variable_data_c orig_K_aut(m_am_tools);
+
+ if (orig_K_aut.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 (get_aka_notification_code_P_bit(notification_code) == false)
+ {
+ u8_t *MAC_data = 0;
+ u32_t MAC_data_length = 0u;
+ eap_type_aka_MAC_attributes_c MAC_attributes;
+
+ if (add_at_counter_attribute == true)
+ {
+ // If EAP-Request/AKA/Notification is used on fast a re-authentication
+ // exchange, and if the P bit in AT_NOTIFICATION is set to zero, then
+ // AT_COUNTER is used for replay protection. In this case, the
+ // AT_ENCR_DATA and AT_IV attributes MUST be included, and the
+ // encapsulated plaintext attributes MUST include the AT_COUNTER
+ // attribute. The counter value included in AT_COUNTER MUST be the same
+ // as in the EAP-Request/AKA/Re-authentication packet on the same fast
+ // re-authentication exchange.
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c orig_XKEY(m_am_tools);
+ eap_variable_data_c orig_K_encr(m_am_tools);
+
+ if (orig_XKEY.get_is_valid() == false
+ || orig_K_encr.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ u32_t reauth_counter = 0u;
+
+ // In order to use re-authentication, the client and the server need to
+ // store the following values: original XKEY, K_aut, K_encr, latest
+ // counter value and the next re-authentication identity.
+ status = m_am_type_aka->query_reauth_parameters(
+ &orig_XKEY,
+ &orig_K_aut,
+ &orig_K_encr,
+ &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);
+ }
+
+ K_aut = &orig_K_aut;
+
+ // - - - - - - - - - - - -
+
+ 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);
+ }
+
+ status = m_am_type_aka->generate_encryption_IV(
+ get_IV()->get_payload_buffer(),
+ aes.get_block_size());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ status = add_variable_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ get_IV()->get_payload_buffer(),
+ aka_payload_AT_IV);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ // Encrypted data.
+ {
+ aka_payload_AT_header_c gp_encrypted_data(
+ m_am_tools,
+ aka_response.get_data_offset(
+ aka_data_offset,
+ aka_data_free),
+ aka_data_free);
+ if (aka_response.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // Initialize the length of encrypted data to maximum length.
+ // Later this will be set to correct length.
+ gp_encrypted_data.reset_header(aka_payload_AT_header_c::get_max_payload_data_length());
+ gp_encrypted_data.set_current_payload(aka_payload_AT_ENCR_DATA);
+
+ update_payload_indexes(
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ gp_encrypted_data.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_offset,
+ &packet_buffer_free);
+
+ u32_t encrypted_data_offset_begin = packet_buffer_offset;
+
+ // - - - - - - - - - - - -
+
+ status = add_counter_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ static_cast<u16_t>(reauth_counter));
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ status = add_padding_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ (packet_buffer_offset - encrypted_data_offset_begin) // Length of the plain text.
+ );
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ gp_encrypted_data.set_data_length(
+ static_cast<u16_t>(packet_buffer_offset - encrypted_data_offset_begin));
+
+ // - - - - - - - - - - - -
+
+ status = encrypt_DATA_payload(
+ gp_encrypted_data.get_data(gp_encrypted_data.get_data_length()),
+ gp_encrypted_data.get_data_length(),
+ get_IV()->get_payload_buffer(),
+ &orig_K_encr);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_AKA_TRACE_PAYLOAD("Payload added", &gp_encrypted_data);
+ }
+
+ }
+ else
+ {
+ K_aut = get_K_aut();
+ } // if (add_counter_payload == true)
+
+ // - - - - - - - - - - - -
+
+ // Add AT_MAC attribute.
+ status = add_mac_payload(
+ &aka_response,
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH,
+ aka_response.get_header_length(),
+ &aka_data_offset,
+ &aka_data_free,
+ &packet_buffer_free,
+ &packet_buffer_offset,
+ &MAC_data,
+ &MAC_data_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - -
+
+ aka_response.set_data_length(
+ aka_data_offset,
+ m_use_eap_expanded_type);
+ eap_notification_packet.set_data_length(packet_buffer_offset);
+
+ EAP_ASSERT_ALWAYS(
+ m_aka_header_offset+aka_response.get_header_length()+aka_response.get_data_length()
+ == packet_buffer_offset);
+
+ // - - - - - - - - - - - -
+
+ MAC_attributes.init(
+ MAC_data,
+ MAC_data_length,
+ aka_response.get_header_buffer(aka_response.get_length()),
+ aka_response.get_length());
+
+ status = create_message_authentication_code(
+ &MAC_attributes,
+ aka_response.get_subtype(),
+ aka_response.get_code(),
+ K_aut);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ }
+ else
+ {
+ aka_response.set_data_length(
+ aka_data_offset,
+ m_use_eap_expanded_type);
+ eap_notification_packet.set_data_length(packet_buffer_offset);
+
+ EAP_ASSERT_ALWAYS(
+ m_aka_header_offset+aka_response.get_header_length()+aka_response.get_data_length()
+ == packet_buffer_offset);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_notification_packet.set_data_length(packet_buffer_offset);
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("send_aka_notification_request: aka_subtype_Notification packet"),
+ aka_response.get_header_buffer(aka_response.get_length()),
+ aka_response.get_length()));
+
+ status = packet_send(
+ get_send_network_id(),
+ &eap_notification_packet,
+ m_aka_header_offset,
+ aka_response.get_length(),
+ EAP_TYPE_AKA_LOCAL_PACKET_BUFFER_LENGTH
+ );
+
+ if (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::query_AKA_authentication_vector(
+ const u8_t next_eap_identifier,
+ eap_type_aka_identity_type * const identity_type)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_type_aka_authentication_vector_c authentication_vector(m_am_tools);
+
+ set_state(eap_type_aka_state_pending_authentication_vector_query);
+
+ eap_status_e status = m_am_type_aka->query_AKA_authentication_vector(
+ get_identity(), // This is username part from payload AT_IDENTITY.
+ next_eap_identifier,
+ get_IMSI(), // This is the real IMSI. If this is uninitialized get_identity() must be initialized, imsi will be initialized after this call is complete.
+ &authentication_vector,
+ identity_type);
+
+ if (status == eap_status_pending_request)
+ {
+ // This is pending query, that will be completed by complete_AKA_authentication_vector_query() call.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else if (status == eap_status_completed_request)
+ {
+ // This query was already completed by complete_AKA_authentication_vector_query() call.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else if (status != eap_status_ok)
+ {
+ // Some error occurred.
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ set_authentication_vector(authentication_vector.copy());
+ if (get_authentication_vector() == 0
+ || get_authentication_vector()->get_is_valid() == false)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ 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::complete_AKA_authentication_vector_query(
+ eap_type_aka_authentication_vector_c * const authentication_vector,
+ const eap_variable_data_c * const IMSI,
+ const eap_aka_authentication_vector_status_e authentication_vector_status,
+ const eap_type_aka_identity_type identity_type,
+ const eap_status_e completion_status,
+ const u8_t next_eap_identifier)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::complete_AKA_authentication_vector_query(): ")
+ EAPL("EAP-identity is %d=%s, identity payload was %d=%s, state %d=%s.\n"),
+ identity_type,
+ get_identity_string(identity_type),
+ get_aka_identity_response_includes_identity(),
+ aka_payload_AT_header_c::get_payload_AT_string(get_aka_identity_response_includes_identity()),
+ get_state(),
+ get_state_string()));
+
+ if (completion_status != eap_status_ok
+ || authentication_vector == 0)
+ {
+ set_state(eap_type_aka_state_failure);
+
+ // The eap_status_process_general_error error value is more important
+ // than return value of set_session_timeout().
+ (void) get_type_partner()->set_session_timeout(0ul);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+
+ if (get_state() != eap_type_aka_state_pending_authentication_vector_query)
+ {
+ // Authentication is terminated or state is wrong. Cannot continue.
+ set_state(eap_type_aka_state_failure);
+
+ // The eap_status_handler_does_not_exists_error error value is more important
+ // than return value of set_session_timeout().
+ (void) get_type_partner()->set_session_timeout(0ul);
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_handler_does_not_exists_error);
+ }
+
+ eap_status_e status = eap_status_process_general_error;
+
+ if (m_identity_type != AKA_IDENTITY_TYPE_RE_AUTH_ID)
+ {
+ set_identity_type(identity_type);
+ }
+
+ if (m_identity_type == AKA_IDENTITY_TYPE_IMSI_ID
+ && IMSI->get_is_valid_data() == true)
+ {
+ status = m_IMSI.set_copy_of_buffer(IMSI);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ if (authentication_vector_status == eap_aka_authentication_vector_status_ok)
+ {
+ // First check the identity type is correct.
+ if ((m_identity_type == AKA_IDENTITY_TYPE_IMSI_ID
+ && (get_aka_identity_response_includes_identity() == aka_payload_AT_PERMANENT_ID_REQ
+ || get_aka_identity_response_includes_identity() == aka_payload_AT_FULLAUTH_ID_REQ
+ || get_aka_identity_response_includes_identity() == aka_payload_AT_ANY_ID_REQ))
+ || (m_identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID
+ && (get_aka_identity_response_includes_identity() == aka_payload_AT_FULLAUTH_ID_REQ
+ || get_aka_identity_response_includes_identity() == aka_payload_AT_ANY_ID_REQ))
+ || (m_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID
+ && get_aka_identity_response_includes_identity() == aka_payload_AT_ANY_ID_REQ)
+ || get_aka_identity_response_includes_identity() == aka_payload_NONE)
+ {
+ // OK, correct identity received.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::complete_AKA_authentication_vector_query(): OK\n")));
+ }
+ else
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::complete_AKA_authentication_vector_query(): ")
+ EAPL("EAP-identity is wrong, state %d=%s.\n"),
+ get_state(), get_state_string()));
+
+ if (get_aka_identity_response_includes_identity() == aka_payload_AT_PERMANENT_ID_REQ)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::complete_AKA_authentication_vector_query(): ")
+ EAPL("permanent identity was required, %d=%s was get.\n"),
+ m_identity_type,
+ get_identity_string(m_identity_type)));
+ }
+ else if (get_aka_identity_response_includes_identity() == aka_payload_AT_FULLAUTH_ID_REQ)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::complete_AKA_authentication_vector_query(): ")
+ EAPL("full authentication identity was required, %d=%s was get.\n"),
+ m_identity_type,
+ get_identity_string(m_identity_type)));
+ }
+ else if (get_aka_identity_response_includes_identity() == aka_payload_AT_ANY_ID_REQ)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::complete_AKA_authentication_vector_query(): ")
+ EAPL("any identity was required, %d=%s was get.\n"),
+ m_identity_type,
+ get_identity_string(m_identity_type)));
+ }
+ else
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::complete_AKA_authentication_vector_query(): ")
+ EAPL("no special identity was required, %d=%s was get.\n"),
+ m_identity_type,
+ get_identity_string(m_identity_type)));
+ }
+
+ EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR, wrong identity"),
+ get_NAI()->get_data(get_NAI()->get_data_length()),
+ get_NAI()->get_data_length()));
+
+ restore_saved_previous_state();
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+ if (get_IMSI()->get_is_valid_data() == false
+ && IMSI != get_IMSI())
+ {
+ // We must copy queried IMSI.
+ status = get_IMSI()->set_copy_of_buffer(IMSI);
+ 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_vector(authentication_vector->copy());
+ if (get_authentication_vector() == 0
+ || get_authentication_vector()->get_is_valid() == false)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = send_challenge_request_message(
+ next_eap_identifier);
+ 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_last_eap_identifier(next_eap_identifier);
+ set_state(eap_type_aka_state_waiting_for_challenge_response);
+ }
+ else
+ {
+ // Error occurred in tripler query.
+ // We must send EAP-Notification message.
+ //
+
+ // eap_aka_notification_no_F_no_P_users_calls_are_barred and eap_aka_notification_no_F_no_P_user_has_not_subscribed_to_the_requested_service cannot be used because P bit is not set.
+
+ m_aka_notification_code = eap_aka_notification_no_F_P_set_general_failure;
+
+ status = initialize_notification_message();
+
+ set_last_eap_identifier(static_cast<u8_t>(get_last_eap_identifier()+1u));
+
+ set_state(eap_type_aka_state_waiting_for_notification_response_failure);
+ }
+
+
+ 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::randomly_refuse_eap_identity()
+{
+ bool skip_query_imsi_from_username = false;
+
+ if (m_aka_test_version == true
+ && m_aka_randomly_refuse_eap_identity == true)
+ {
+ crypto_random_c rand(m_am_tools);
+
+ if (rand.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return false;
+ }
+
+ u32_t random_guard;
+
+ eap_status_e status = rand.get_rand_bytes(
+ reinterpret_cast<u8_t *>(&random_guard),
+ sizeof(random_guard));
+ if (status != eap_status_ok)
+ {
+ return false;
+ }
+
+ if ((random_guard % 2) == 0)
+ {
+ // Note, this is just for testing.
+ skip_query_imsi_from_username = true;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("TEST: eap_type_aka_c::randomly_refuse_eap_identity(): ")
+ EAPL("randomly fails EAP-Identity.\n")));
+ }
+ }
+
+ return skip_query_imsi_from_username;
+}
+
+//--------------------------------------------------
+
+//
+EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::handle_identity_response_message(
+ eap_header_rd_c * const eap_header,
+ const u32_t aka_packet_length)
+{
+ eap_status_e status = eap_status_process_general_error;
+
+ if (get_state() == eap_type_aka_state_waiting_for_identity_response
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity
+ // In test version new authentication could start from this state.
+ || (m_aka_test_version == true
+ && get_state() == eap_type_aka_state_success) // This one is for testing purposes.
+ )
+ {
+ // OK correct state.
+ }
+ else
+ {
+ // Wrong state, dischard packet.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_identity_response_message(): ")
+ EAPL("EAP-Response/Identity received in wrong state %d=%s. This EAP-packet is dropped.\n"),
+ get_state(), get_state_string()));
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: erroneous EAP packet: code=0x%02x, ")
+ EAPL("identifier=0x%02x, length=0x%04x, type=0x%08x, client %d\n"),
+ eap_header->get_code(),
+ eap_header->get_identifier(),
+ eap_header->get_length(),
+ convert_eap_type_to_u32_t(eap_header->get_type()),
+ get_is_client()));
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_illegal_packet_error);
+ }
+
+ if (m_check_identifier_of_eap_identity_response == true)
+ {
+ if (get_state() == eap_type_aka_state_waiting_for_identity_response
+ && eap_header->get_identifier() != get_last_eap_identifier())
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_identity_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ eap_header->get_identifier(),
+ get_last_eap_identifier(),
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+ else if ((get_state() == eap_type_aka_state_waiting_for_aka_identity_response
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity
+ )
+ && eap_header->get_identifier() != get_last_eap_identifier()-1u)
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_identity_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ eap_header->get_identifier(),
+ get_last_eap_identifier()-1u,
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+ // In test version new authentication could start from this state.
+ else if (m_aka_test_version == true
+ && get_state() == eap_type_aka_state_success) // This one is for testing purposes.
+ {
+ // NOTE here we can not check the EAP-identifier.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("WARNING: eap_type_aka_c::handle_identity_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is not checked in eap_type_aka_state_variable_e %d=%s.\n"),
+ eap_header->get_identifier(),
+ get_state(),
+ get_state_string()));
+ }
+ }
+
+ {
+ // This could be first or retransmission request.
+
+ if (eap_header->get_type_data_length() > aka_packet_length)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+ status = parse_identity(
+ eap_header->get_type_data(
+ eap_header->get_type_data_length()),
+ eap_header->get_type_data_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_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("AKA received EAP-identity NAI"),
+ get_NAI()->get_data(get_NAI()->get_data_length()),
+ get_NAI()->get_data_length()));
+
+ u8_t next_eap_identifier = static_cast<u8_t>(eap_header->get_identifier()+1u);
+
+ if (get_state() == eap_type_aka_state_waiting_for_aka_identity_response
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity
+ )
+ {
+ // This is retransmission, so the EAP-identifier is not increased.
+ next_eap_identifier = get_last_eap_identifier();
+ }
+ // In test version new authentication could start from this state.
+ else if (m_aka_test_version == true
+ && get_state() == eap_type_aka_state_success) // This one is for testing purposes.
+ {
+ // NOTE here we can not check the EAP-identifier.
+ next_eap_identifier = static_cast<u8_t>(eap_header->get_identifier()+1u);
+ set_state(eap_type_aka_state_waiting_for_identity_response);
+ get_IMSI()->reset();
+ }
+
+ save_current_state();
+ set_state(eap_type_aka_state_pending_pseudonym_decode_query);
+
+ eap_type_aka_identity_type identity_type = AKA_IDENTITY_TYPE_NONE;
+
+ if (m_accept_eap_identity_response == true)
+ {
+ if (randomly_refuse_eap_identity() == false)
+ {
+ status = m_am_type_aka->query_imsi_from_username(
+ next_eap_identifier,
+ get_send_network_id(),
+ get_identity(),
+ get_IMSI(),
+ &identity_type,
+ eap_type_aka_complete_handle_imsi_from_username);
+ }
+ else
+ {
+ status = eap_status_illegal_eap_identity;
+ }
+
+ if (status == eap_status_pending_request)
+ {
+ // This is pending query, that will be completed by complete_imsi_from_username() call.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (status == eap_status_completed_request)
+ {
+ // This is already completed by complete_imsi_from_username() call.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (status != eap_status_ok)
+ {
+ // Identity decoding failed.
+ // We must query IMSI of client.
+
+ if (m_use_manual_username == true)
+ {
+ // We reset the illegal identity.
+ // EAP-AKA/request/start will query identity.
+ get_identity()->reset();
+ }
+ }
+ else // status == eap_status_ok
+ {
+ // The query_imsi_from_username() function call was synchronous.
+ // We must call send_aka_identity_request_message().
+ }
+ }
+
+
+ {
+ status = handle_imsi_from_username(
+ next_eap_identifier,
+ get_send_network_id(),
+ get_identity(),
+ get_IMSI(),
+ identity_type);
+ if (status != eap_status_ok)
+ {
+ // ERROR in handle_imsi_from_username().
+ // This will return error status of handle_imsi_from_username() call.
+ }
+ else
+ {
+ // OK handle_imsi_from_username().
+ }
+ }
+ }
+
+ 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_imsi_from_username(
+ const u8_t next_eap_identifier,
+ const eap_am_network_id_c * const network_id,
+ const eap_variable_data_c * const username,
+ const eap_variable_data_c * const imsi, ///< The result is stored to imsi parameter.
+ const eap_type_aka_identity_type received_identity_type)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_UNREFERENCED_PARAMETER(username);
+ EAP_UNREFERENCED_PARAMETER(network_id);
+
+ EAP_ASSERT(received_identity_type == AKA_IDENTITY_TYPE_IMSI_ID
+ || received_identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID
+ || received_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID
+ || received_identity_type == AKA_IDENTITY_TYPE_NONE);
+
+ if (get_state() != eap_type_aka_state_pending_pseudonym_decode_query)
+ {
+ // State is wrong. Cannot continue.
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_gsmsim_state);
+ }
+
+ eap_status_e status = eap_status_process_general_error;
+ bool pseudonym_decode_failed = true;
+
+ //eap_type_aka_identity_type local_identity_type = identity_type;
+ set_identity_type(received_identity_type);
+
+ if (imsi != 0
+ && imsi->get_is_valid_data() == true)
+ {
+ pseudonym_decode_failed = false;
+ status = get_IMSI()->set_copy_of_buffer(imsi);
+ 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);
+ }
+
+ if (received_identity_type == AKA_IDENTITY_TYPE_NONE)
+ {
+ set_identity_type(AKA_IDENTITY_TYPE_IMSI_ID);
+ }
+ }
+ else
+ {
+ get_IMSI()->reset();
+ }
+
+ if (received_identity_type == AKA_IDENTITY_TYPE_IMSI_ID)
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_FULL_AUTH;
+ set_identity_type(received_identity_type);
+ set_aka_identity_response_includes_identity(aka_payload_AT_ANY_ID_REQ);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: IMSI\n")));
+ }
+ else if (received_identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID)
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_FULL_AUTH;
+ set_identity_type(received_identity_type);
+ set_aka_identity_response_includes_identity(aka_payload_AT_ANY_ID_REQ);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: pseudonym\n")));
+ }
+ else if (received_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID)
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_REAUTHENTICATION;
+ set_identity_type(received_identity_type);
+ set_aka_identity_response_includes_identity(aka_payload_AT_ANY_ID_REQ);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: re-authentication\n")));
+ }
+ else
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_NONE;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: other\n")));
+ }
+
+
+ if (m_authentication_type == AKA_AUTHENTICATION_TYPE_FULL_AUTH
+ && (m_identity_type == AKA_IDENTITY_TYPE_IMSI_ID
+ && (get_saved_previous_state() == eap_type_aka_state_waiting_for_identity_response
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response))
+ || (m_identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID
+ && (get_saved_previous_state() == eap_type_aka_state_waiting_for_identity_response
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response))
+ )
+ {
+ eap_type_aka_identity_type local_identity_type = m_identity_type;
+
+ eap_status_e local_status = query_AKA_authentication_vector(next_eap_identifier, &local_identity_type);
+ if (local_status == eap_status_pending_request)
+ {
+ // Request will be completed later with complete_AKA_authentication_vector_query() function.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (local_status == eap_status_completed_request)
+ {
+ // Request was already completed with complete_AKA_authentication_vector_query() function.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (local_status != eap_status_ok)
+ {
+ // This is an error case.
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+ else //if (local_status == eap_status_ok)
+ {
+ // The query_AKA_authentication_vector() function call is synchronous.
+ // We must call send_challenge_request_message().
+ }
+
+ const u8_t local_eap_identifier = static_cast<u8_t>(get_last_eap_identifier()+1u);
+
+ local_status = send_challenge_request_message(
+ local_eap_identifier);
+ if (local_status != eap_status_ok)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+
+ set_last_eap_identifier(local_eap_identifier);
+ set_state(eap_type_aka_state_waiting_for_challenge_response);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+ else if (m_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID
+ && (get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_identity_response
+ || get_saved_previous_state() == eap_type_aka_state_waiting_for_aka_identity_response))
+ {
+ // Here we need to send EAP-Request/Re-authentication
+ status = send_reauthentication_request_message(
+ get_NAI(),
+ pseudonym_decode_failed,
+ next_eap_identifier);
+ }
+ else if (m_identity_type == AKA_IDENTITY_TYPE_NONE
+ && get_saved_previous_state() == eap_type_aka_state_waiting_for_identity_response)
+ {
+ set_aka_identity_response_includes_identity(aka_payload_AT_ANY_ID_REQ);
+
+ status = send_aka_identity_request_message(
+ pseudonym_decode_failed,
+ next_eap_identifier);
+ }
+ else
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_imsi_from_username(): ")
+ EAPL("EAP-Identity type 0x%02x is wrong in eap_type_aka_state_variable_e %d=%s.\n"),
+ m_identity_type,
+ get_saved_previous_state(),
+ get_saved_previous_state_string()));
+
+ status = eap_status_illegal_eap_identity;
+ }
+
+ if (status != eap_status_ok)
+ {
+ restore_saved_previous_state();
+ }
+ else
+ {
+ set_last_eap_identifier(next_eap_identifier);
+ }
+
+ 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::complete_imsi_from_username(
+ const u8_t next_eap_identifier,
+ const eap_am_network_id_c * const network_id,
+ const eap_variable_data_c * const username,
+ const eap_variable_data_c * const imsi, ///< The result is stored to imsi parameter.
+ const eap_type_aka_identity_type identity_type,
+ const eap_status_e completion_status,
+ const eap_type_aka_complete_e completion_action)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::complete_imsi_from_username(): ")
+ EAPL("EAP-identity is %d=%s, identity payload was %d=%s, state %d=%s.\n"),
+ identity_type,
+ get_identity_string(identity_type),
+ get_aka_identity_response_includes_identity(),
+ aka_payload_AT_header_c::get_payload_AT_string(get_aka_identity_response_includes_identity()),
+ get_state(),
+ get_state_string()));
+
+ EAP_UNREFERENCED_PARAMETER(username);
+ EAP_UNREFERENCED_PARAMETER(network_id);
+
+ if (get_state() == eap_type_aka_state_none)
+ {
+ // The eap_status_handler_does_not_exists_error error value is more important
+ // than return value of set_session_timeout().
+ (void) get_type_partner()->set_session_timeout(0ul);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_handler_does_not_exists_error);
+ }
+
+ if (completion_status != eap_status_ok)
+ {
+ set_state(eap_type_aka_state_failure);
+
+ // The completion_status error value is more important
+ // than return value of set_session_timeout().
+ (void) get_type_partner()->set_session_timeout(0ul);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, completion_status);
+ }
+
+ eap_status_e status = eap_status_not_supported;
+
+ if (completion_action == eap_type_aka_complete_handle_imsi_from_username)
+ {
+ status = handle_imsi_from_username(
+ next_eap_identifier,
+ network_id,
+ username,
+ imsi, ///< The result is stored to imsi parameter.
+ identity_type);
+
+ status = eap_status_completed_request;
+ }
+ else if (completion_action == eap_type_aka_complete_handle_aka_identity_response_message_completion)
+ {
+ // NOTE the identity_payload_was_included parameter is
+ // true in this completion.
+ status = handle_aka_identity_response_message_completion(
+ next_eap_identifier,
+ completion_status,
+ identity_type,
+ true);
+
+ status = eap_status_completed_request;
+ }
+ else
+ {
+ // Unknown completion.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::complete_imsi_from_username(): ")
+ EAPL("Unknown eap_type_aka_complete_e %d in eap_type_aka_state_variable_e %d=%s.\n"),
+ completion_action,
+ get_saved_previous_state(),
+ get_saved_previous_state_string()));
+ }
+
+ 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::check_synchronization_failure_response_message(
+ 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_status_e status = eap_status_process_general_error;
+
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_must_not_be // CHECKCODE
+ ) == true
+ )
+ {
+ const u8_t next_eap_identifier = static_cast<u8_t>(get_last_eap_identifier()+1u);
+
+ save_current_state();
+ set_state(eap_type_aka_state_pending_re_syncronization_query);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_type_aka_authentication_vector_c authentication_vector(m_am_tools);
+
+ status = authentication_vector.get_AUTS()->set_copy_of_buffer(
+ p_aka_payloads->get_AUTS()->get_payload_buffer());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = authentication_vector.get_RAND()->set_copy_of_buffer(get_authentication_vector()->get_RAND());
+ 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->query_re_syncronization(
+ next_eap_identifier,
+ &authentication_vector);
+ if (status == eap_status_pending_request)
+ {
+ // Request will be completed later using complete_re_syncronization_query() function.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (status == eap_status_completed_request)
+ {
+ // Request was already completed by AM using complete_re_syncronization_query() function.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (status == eap_status_success)
+ {
+ // eap_status_success means the authentication was successful.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else if (status == eap_status_ok)
+ {
+ // The query_re_syncronization() function call is synchronous.
+ // We must call process_re_syncronization().
+ }
+ else
+ {
+ // This is an error case.
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // eap_status_ok status value means n_kc and n_sres were read but not processed.
+ // Next we must call process_re_syncronization().
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = process_re_syncronization(
+ next_eap_identifier,
+ &authentication_vector);
+
+ if (status != eap_status_ok
+ && status != eap_status_success)
+ {
+ restore_saved_previous_state();
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_challenge_request_message(6): ")
+ EAPL("Not correct AKA-payloads are included in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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_FUNC_EXPORT eap_status_e eap_type_aka_c::complete_re_syncronization_query(
+ const u8_t next_eap_identifier,
+ const eap_type_aka_authentication_vector_c * const authentication_vector)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = eap_status_process_general_error;
+
+ if (get_state() != eap_type_aka_state_pending_re_syncronization_query
+ || authentication_vector == 0
+ || authentication_vector->get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ status = process_re_syncronization(
+ next_eap_identifier,
+ authentication_vector);
+
+ 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::process_re_syncronization(
+ const u8_t next_eap_identifier,
+ const eap_type_aka_authentication_vector_c * const authentication_vector)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = eap_status_process_general_error;
+
+ if (get_state() != eap_type_aka_state_pending_re_syncronization_query
+ || authentication_vector == 0
+ || authentication_vector->get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ set_authentication_vector(authentication_vector->copy());
+ if (get_authentication_vector() == 0
+ || get_authentication_vector()->get_is_valid() == false)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = send_challenge_request_message(
+ next_eap_identifier);
+ 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_last_eap_identifier(next_eap_identifier);
+ set_state(eap_type_aka_state_waiting_for_challenge_response);
+
+ 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_synchronization_failure_response_message(
+ 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_status_e status = eap_status_process_general_error;
+
+ if (get_state() == eap_type_aka_state_waiting_for_challenge_response)
+ {
+ // This could be first or retransmission request.
+ if (received_aka->get_identifier() != get_last_eap_identifier())
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_synchronization_failure_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ received_aka->get_identifier(),
+ get_last_eap_identifier(),
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+ status = check_synchronization_failure_response_message(
+ receive_network_id,
+ received_aka,
+ aka_packet_length,
+ p_aka_payloads);
+ }
+ else if (get_state() == eap_type_aka_state_success)
+ {
+ if (received_aka->get_identifier() != get_last_eap_identifier()-1u)
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_synchronization_failure_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ received_aka->get_identifier(),
+ get_last_eap_identifier()-1u,
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+ status = check_synchronization_failure_response_message(
+ receive_network_id,
+ received_aka,
+ aka_packet_length,
+ p_aka_payloads);
+ }
+ else if (get_state() == eap_type_aka_state_pending_re_syncronization_query)
+ {
+ // This is re-transmitted EAP-Response/AKA/Challenge.
+ // We dischard it quietly.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("WARNING: eap_type_aka_c::handle_challenge_response_message(): ")
+ EAPL("Re-transmitted message %d=%s dropped 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_drop_packet_quietly);
+ }
+ else
+ {
+ // Wrong message in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_challenge_request_message(): ")
+ EAPL("Wrong 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::handle_aka_identity_response_message_completion(
+ const u8_t next_eap_identifier,
+ const eap_status_e identity_status,
+ eap_type_aka_identity_type received_identity_type,
+ const bool identity_payload_was_included)
+{
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::handle_aka_identity_response_message_completion(): ")
+ EAPL("received_identity_type %d=%s, identity payload was %d=%s, state %d=%s.\n"),
+ received_identity_type,
+ get_identity_string(received_identity_type),
+ get_aka_identity_response_includes_identity(),
+ aka_payload_AT_header_c::get_payload_AT_string(get_aka_identity_response_includes_identity()),
+ get_state(),
+ get_state_string()));
+
+ if (get_state() == eap_type_aka_state_none)
+ {
+ // Authentication is terminated or state is wrong. Cannot continue.
+
+ // The eap_status_handler_does_not_exists_error error value is more important
+ // than return value of set_session_timeout().
+ (void) get_type_partner()->set_session_timeout(0ul);
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_handler_does_not_exists_error);
+ }
+
+ if (identity_payload_was_included == true)
+ {
+ if (identity_status != eap_status_ok
+ || received_identity_type == AKA_IDENTITY_TYPE_NONE)
+ {
+ // We did not get valid identity.
+ set_identity_type(AKA_IDENTITY_TYPE_NONE);
+ if (get_aka_identity_response_includes_identity() == aka_payload_AT_ANY_ID_REQ)
+ {
+ set_aka_identity_response_includes_identity(aka_payload_AT_FULLAUTH_ID_REQ);
+ }
+ else // if (get_aka_identity_response_includes_identity() == aka_payload_AT_FULLAUTH_ID_REQ)
+ {
+ set_aka_identity_response_includes_identity(aka_payload_AT_PERMANENT_ID_REQ);
+ }
+ }
+ else
+ {
+ // We receive an identity.
+ set_identity_type(received_identity_type);
+ }
+
+ if (m_identity_type == AKA_IDENTITY_TYPE_IMSI_ID)
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_FULL_AUTH;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: IMSI\n")));
+ }
+ else if (m_identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID)
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_FULL_AUTH;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: pseudonym\n")));
+ }
+ else if (m_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID)
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_REAUTHENTICATION;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: re-authentication\n")));
+ }
+ else
+ {
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_NONE;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("Identity: other\n")));
+ }
+ }
+ else
+ {
+ // No AT_IDENTITY payload.
+ // We may have identity already.
+ if (get_identity()->get_is_valid_data() == true
+ && m_authentication_type != AKA_AUTHENTICATION_TYPE_NONE
+ && m_identity_type != AKA_IDENTITY_TYPE_NONE)
+ {
+ // OK identity is known.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::handle_aka_identity_response_message_completion(): ")
+ EAPL("Known m_identity_type %d=%s, identity payload was %d=%s, state %d=%s.\n"),
+ m_identity_type,
+ get_identity_string(m_identity_type),
+ get_aka_identity_response_includes_identity(),
+ aka_payload_AT_header_c::get_payload_AT_string(get_aka_identity_response_includes_identity()),
+ get_state(),
+ get_state_string()));
+ }
+ else
+ {
+ // ERROR no accepted identity.
+ EAP_TRACE_ERROR(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message_completion(5): ")
+ EAPL("No correct AKA-identity were received in eap_type_gsmsim_state_variable_e %d=%s.\n"),
+ 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);
+ }
+ }
+
+ save_current_state();
+
+ u8_t local_eap_identifier = 0u;
+
+ if (get_saved_previous_state() == eap_type_aka_state_waiting_for_challenge_response)
+ {
+ // Do not increase EAP-Identifier, this was re-transmission.
+ local_eap_identifier = get_last_eap_identifier();
+ }
+ else
+ {
+ local_eap_identifier = static_cast<u8_t>(get_last_eap_identifier()+1u);
+ }
+
+ if (m_identity_type == AKA_IDENTITY_TYPE_NONE)
+ {
+ eap_status_e local_status = send_aka_identity_request_message(
+ true,
+ local_eap_identifier);
+ if (local_status != eap_status_ok)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+ set_last_eap_identifier(local_eap_identifier);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+ else if (m_identity_type == AKA_IDENTITY_TYPE_IMSI_ID
+ || m_identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID
+ || (m_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID
+ && m_authentication_type == AKA_AUTHENTICATION_TYPE_FULL_AUTH))
+ {
+ eap_type_aka_identity_type local_identity_type = m_identity_type;
+
+ eap_status_e local_status = query_AKA_authentication_vector(
+ next_eap_identifier,
+ &local_identity_type);
+ if (local_status == eap_status_pending_request)
+ {
+ // Request will be completed later with complete_AKA_authentication_vector_query() function.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (local_status == eap_status_completed_request)
+ {
+ // Request was already completed with complete_AKA_authentication_vector_query() function.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (local_status != eap_status_ok)
+ {
+ // This is an error case.
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+ else //if (local_status == eap_status_ok)
+ {
+ // The query_AKA_authentication_vector() function call is synchronous.
+ // We must call send_challenge_request_message().
+ }
+
+ local_status = send_challenge_request_message(
+ local_eap_identifier);
+ if (local_status != eap_status_ok)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+
+ set_last_eap_identifier(local_eap_identifier);
+ set_state(eap_type_aka_state_waiting_for_challenge_response);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+ else if (m_identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID
+ && m_authentication_type == AKA_AUTHENTICATION_TYPE_REAUTHENTICATION)
+ {
+ // Here we need to send EAP-Request/Re-authentication
+ eap_status_e local_status = send_reauthentication_request_message(
+ get_NAI(),
+ false,
+ local_eap_identifier);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, local_status);
+ }
+ else
+ {
+ // Unnown identity type, do nothing.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+}
+
+//--------------------------------------------------
+
+//
+EAP_FUNC_EXPORT eap_status_e eap_type_aka_c::handle_aka_identity_response_message(
+ aka_header_c * const received_aka,
+ const u32_t aka_packet_length,
+ aka_payloads_c * const p_aka_payloads)
+{
+ eap_status_e status = eap_status_process_general_error;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::handle_aka_identity_response_message(): ")
+ EAPL("m_identity_type %d=%s, identity payload was %d=%s, state %d=%s.\n"),
+ m_identity_type,
+ get_identity_string(m_identity_type),
+ get_aka_identity_response_includes_identity(),
+ aka_payload_AT_header_c::get_payload_AT_string(get_aka_identity_response_includes_identity()),
+ get_state(),
+ get_state_string()));
+
+ if (aka_packet_length < received_aka->get_length())
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(): ")
+ 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 (get_state() == eap_type_aka_state_waiting_for_aka_identity_response
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity
+ || get_state() == eap_type_aka_state_waiting_for_challenge_response
+ )
+ {
+ if (get_state() == eap_type_aka_state_waiting_for_aka_identity_response
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity
+ || get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity
+ )
+ {
+ if (received_aka->get_identifier() != get_last_eap_identifier())
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ received_aka->get_identifier(),
+ get_last_eap_identifier(),
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+ }
+ else // if (get_state() == eap_type_aka_state_waiting_for_challenge_response)
+ {
+ // This might be retransmission response.
+ if (received_aka->get_identifier() != get_last_eap_identifier()-1u)
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ received_aka->get_identifier(),
+ get_last_eap_identifier()-1u,
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+ }
+
+
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_optional, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_must_not_be // CHECKCODE
+ ) == true
+ )
+ {
+ if (get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_permanent_identity)
+ {
+ if (p_aka_payloads->get_IDENTITY_payload()->get_payload_included() == true)
+ {
+ // OK, NAI identity is included.
+ // Identity must be IMSI. query_AKA_authentication_vector() must decode identity.
+
+ set_aka_identity_response_includes_identity(aka_payload_AT_PERMANENT_ID_REQ);
+ }
+ else
+ {
+ // AT_IDENTITY is missing.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(0x%08x), ")
+ EAPL("AT_IDENTITY is missing in state %s.\n"),
+ this,
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+ }
+ else if (get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_full_auth_identity)
+ {
+ if (p_aka_payloads->get_IDENTITY_payload()->get_payload_included() == true)
+ {
+ // OK, NAI identity is included.
+ // Identity must be IMSI or pseudonym identity. query_AKA_authentication_vector() must decode identity.
+
+ set_aka_identity_response_includes_identity(aka_payload_AT_FULLAUTH_ID_REQ);
+ }
+ else
+ {
+ // AT_IDENTITY is missing.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(0x%08x), ")
+ EAPL("AT_IDENTITY is missing in state %s.\n"),
+ this,
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+ }
+ else if (get_state() == eap_type_aka_state_waiting_for_aka_identity_response_with_at_any_identity)
+ {
+ if (p_aka_payloads->get_IDENTITY_payload()->get_payload_included() == true)
+ {
+ // OK, NAI identity is included.
+ // Identity must be IMSI, pseudonym or re-authentication identity. query_AKA_authentication_vector() must decode identity.
+
+ set_aka_identity_response_includes_identity(aka_payload_AT_ANY_ID_REQ);
+ }
+ else
+ {
+ // AT_IDENTITY is missing.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(0x%08x), ")
+ EAPL("AT_IDENTITY is missing in state %s.\n"),
+ this,
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+ }
+ else if (get_state() == eap_type_aka_state_waiting_for_challenge_response)
+ {
+ // This is re-transmission.
+ if (p_aka_payloads->get_IDENTITY_payload()->get_payload_included() == true)
+ {
+ if (get_aka_identity_response_includes_identity() == aka_payload_AT_PERMANENT_ID_REQ
+ || get_aka_identity_response_includes_identity() == aka_payload_AT_FULLAUTH_ID_REQ
+ || get_aka_identity_response_includes_identity() == aka_payload_AT_ANY_ID_REQ)
+ {
+ // OK, NAI identity is included.
+ }
+ else
+ {
+ // Illegal IDENTITY is included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(0x%08x), ")
+ EAPL("illegal AT_IDENTITY included in state %s.\n"),
+ this,
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+ }
+ }
+ else
+ {
+ if (p_aka_payloads->get_IDENTITY_payload()->get_payload_included() == true)
+ {
+ // Illegal IDENTITY is included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(0x%08x), ")
+ EAPL("illegal AT_IDENTITY included in state %s.\n"),
+ this,
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+ }
+ }
+
+
+ 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);
+ }
+
+ status = checkcode_update(
+ received_aka->get_header_buffer(
+ received_aka->get_header_length()
+ +received_aka->get_data_length()),
+ received_aka->get_header_length()
+ +received_aka->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);
+ }
+
+
+ eap_type_aka_identity_type identity_type = AKA_IDENTITY_TYPE_NONE;
+ bool identity_payload_was_included = false;
+ const u8_t next_eap_identifier = static_cast<u8_t>(received_aka->get_identifier()+1u);
+
+ if (p_aka_payloads->get_IDENTITY_payload()->get_payload_included() == true)
+ {
+ status = parse_identity(
+ p_aka_payloads->get_IDENTITY_payload()->get_data(p_aka_payloads->get_IDENTITY_payload()->get_data_length()),
+ p_aka_payloads->get_IDENTITY_payload()->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);
+ }
+
+ identity_payload_was_included = true;
+
+ // We must ask AM module whether the identity is IMSI, pseudonym or re-authentication identity.
+ // If we have re-authentication identity we must send re-authentication query.
+
+ if (randomly_refuse_eap_identity() == false)
+ {
+ status = m_am_type_aka->query_imsi_from_username(
+ next_eap_identifier,
+ get_send_network_id(),
+ get_identity(),
+ get_IMSI(),
+ &identity_type,
+ eap_type_aka_complete_handle_aka_identity_response_message_completion);
+ if (status == eap_status_pending_request)
+ {
+ // This is pending query, that will be completed by complete_imsi_from_username() call.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_pending_request);
+ }
+ else if (status == eap_status_completed_request)
+ {
+ // This is already completed by complete_imsi_from_username() call.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else if (status != eap_status_ok)
+ {
+ // ERROR in query_imsi_from_username().
+ // This will return error status of query_imsi_from_username() call.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else // status == eap_status_ok
+ {
+ // The query_imsi_from_username() function call was synchronous.
+ // We must call send_aka_identity_request_message().
+ }
+ }
+ else
+ {
+ status = eap_status_illegal_eap_identity;
+ }
+ }
+
+
+ status = handle_aka_identity_response_message_completion(
+ next_eap_identifier,
+ status,
+ identity_type,
+ identity_payload_was_included);
+
+
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(4): ")
+ EAPL("Not correct AKA-payloads are included in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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 if (get_state() == eap_type_aka_state_pending_authentication_vector_query)
+ {
+ // This is retransmission of EAP-Response/AKA/Start.
+ // Triplet query is already initialized.
+ // We will drop this message quietly.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("WARNING: eap_type_aka_c::handle_aka_identity_response_message(5): ")
+ EAPL("Retransmission of EAP-Response/AKA/Start in eap_type_aka_state_variable_e %d=%s.\n"),
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly);
+ }
+ else
+ {
+ // Wrong message in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_aka_identity_response_message(): ")
+ EAPL("Wrong 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::handle_notification_response_message_reauthentication(
+ 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_status_e status = eap_status_process_general_error;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("send: handler 0x%08x, AKA-type %10s, %s, state %2d=%s\n"),
+ this,
+ EAPL("handle_notification_response_message_reauthentication"),
+ (get_is_client()) ? EAPL("client") : EAPL("server"),
+ get_state(),
+ get_state_string()
+ ));
+
+ // The second most significant bit of the notification code is called
+ // the Phase bit (P bit). It specifies at which phase of the EAP-AKA
+ // exchange the notification can be used.
+ if (get_aka_notification_code_P_bit(m_aka_notification_code) == false)
+ {
+ // If the P bit is set to zero,
+ // the notification can only be used after a successful EAP/AKA/
+ // Challenge round in full authentication or a successful EAP/AKA/
+ // Re-authentication round in reautentication. A re-authentication round
+ // is considered successful only if the peer has successfully verified
+ // AT_MAC and AT_COUNTER attributes, and does not include the
+ // AT_COUNTER_TOO_SMALL attribute in EAP-Response/AKA/Re-authentication.
+
+ // The AT_MAC attribute MUST beincluded if the P bit of the notification
+ // code in AT_NOTIFICATION is set to zero, and MUST NOT be included in
+ // cases when the P bit is set to one. The P bit is discussed in Section
+ // 4.4.
+
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_must_not_be // CHECKCODE
+ ) == true
+ )
+ {
+ eap_variable_data_c orig_XKEY(m_am_tools);
+ eap_variable_data_c orig_K_aut(m_am_tools);
+ eap_variable_data_c orig_K_encr(m_am_tools);
+
+ if (orig_XKEY.get_is_valid() == false
+ || orig_K_aut.get_is_valid() == false
+ || orig_K_encr.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ u32_t reauth_counter = 0u;
+
+ // In order to use re-authentication, the client and the server need to
+ // store the following values: original XKEY, K_aut, K_encr, latest
+ // counter value and the next re-authentication identity.
+ status = m_am_type_aka->query_reauth_parameters(
+ &orig_XKEY,
+ &orig_K_aut,
+ &orig_K_encr,
+ &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);
+ }
+
+ status = check_message_authentication_code(
+ &orig_K_aut,
+ p_aka_payloads,
+ received_aka,
+ received_aka->get_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ bool authentication_ok = true;
+
+ // Decrypt and parse encrypted payload.
+ {
+ aka_payloads_c * const l_aka_payloads = new aka_payloads_c(m_am_tools);
+ eap_automatic_variable_c<aka_payloads_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 = decrypt_DATA_payload(
+ p_aka_payloads,
+ &orig_K_encr);
+ 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);
+ }
+
+ u32_t state_payload_buffer_length = p_aka_payloads->get_ENCR_DATA()->get_data_length();
+ const aka_payload_AT_header_c gp_data_payload(
+ m_am_tools,
+ p_aka_payloads->get_ENCR_DATA()->get_data(state_payload_buffer_length),
+ state_payload_buffer_length);
+
+ status = parse_aka_payload(
+ &gp_data_payload,
+ &state_payload_buffer_length,
+ l_aka_payloads,
+ received_aka->get_subtype());
+ 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);
+ }
+
+
+ if (l_aka_payloads->get_COUNTER()->get_payload_included() == false)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+ }
+
+ u32_t counter = l_aka_payloads->get_COUNTER()->get_original_header()->get_reserved();
+
+ if (counter == reauth_counter)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::handle_notification_response_message_reauthentication(): ")
+ EAPL("reauth counter %d OK, %d=%s.\n"),
+ reauth_counter,
+ get_state(),
+ get_state_string()));
+ }
+ else
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message_reauthentication(): ")
+ EAPL("reauth counter %d wrong, should be %d, %d=%s.\n"),
+ counter,
+ reauth_counter,
+ get_state(),
+ get_state_string()));
+
+ authentication_ok = false;
+ }
+ }
+
+ // The most significant bit is called the Failure bit (F bit).
+ // The F bit specifies whether the notification implies failure.
+ if (authentication_ok == false
+ || 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_last_eap_identifier(static_cast<u8_t>(get_last_eap_identifier()+1u));
+ set_state(eap_type_aka_state_failure);
+
+ // This will terminate session immediately.
+ (void) get_type_partner()->set_session_timeout(0UL);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else //if (get_aka_notification_code_F_bit(m_aka_notification_code) == true)
+ {
+ // The receipt of a notification code with the F bit set to one (values
+ // 32768...65536) does not imply failure. Notification code 32768 has
+ // been reserved as a general notification code to indicate successful
+ // authentication.
+ if (m_aka_notification_code == eap_aka_notification_F_set_no_P_user_authenticated)
+ {
+ status = finish_successful_authentication(
+ receive_network_id);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+ }
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message_reauthentication(): ")
+ EAPL("Not correct AKA-payloads are included ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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 //if (get_aka_notification_code_P_bit(m_aka_notification_code) == true)
+ {
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_must_not_be // CHECKCODE
+ ) == true
+ )
+ {
+ // If the P bit is set to one, the notification can only by used before
+ // the EAP/AKA/Challenge round in full authentication, or before the
+ // EAP/AKA/Re-authentication round in reauthentication.
+
+ // The most significant bit is called the Failure bit (F bit).
+ // The F bit specifies whether the notification implies failure.
+ 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.
+ }
+ else //if (get_aka_notification_code_F_bit(m_aka_notification_code) == true)
+ {
+ // The receipt of a notification code with the F bit set to one (values
+ // 32768...65536) does not imply failure. Notification code 32768 has
+ // been reserved as a general notification code to indicate successful
+ // authentication.
+ }
+
+ status = initialize_error_message(
+ eap_status_process_general_error);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message_reauthentication(): ")
+ EAPL("Not correct AKA-payloads are included ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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_FUNC_EXPORT eap_status_e eap_type_aka_c::handle_notification_response_message_full_authentication(
+ 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_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("send: handler 0x%08x, AKA-type %10s, %s, state %2d=%s\n"),
+ this,
+ EAPL("handle_notification_response_message_full_authentication"),
+ (get_is_client()) ? EAPL("client") : EAPL("server"),
+ get_state(),
+ get_state_string()
+ ));
+
+ // The second most significant bit of the notification code is called
+ // the Phase bit (P bit). It specifies at which phase of the EAP-AKA
+ // exchange the notification can be used.
+ if (get_aka_notification_code_P_bit(m_aka_notification_code) == false)
+ {
+ // If the P bit is set to zero,
+ // the notification can only be used after a successful EAP/AKA/
+ // Challenge round in full authentication or a successful EAP/AKA/
+ // Re-authentication round in reautentication. A re-authentication round
+ // is considered successful only if the peer has successfully verified
+ // AT_MAC and AT_COUNTER attributes, and does not include the
+ // AT_COUNTER_TOO_SMALL attribute in EAP-Response/AKA/Re-authentication.
+
+ // The AT_MAC attribute MUST beincluded if the P bit of the notification
+ // code in AT_NOTIFICATION is set to zero, and MUST NOT be included in
+ // cases when the P bit is set to one. The P bit is discussed in Section
+ // 4.4.
+
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_must_not_be // CHECKCODE
+ ) == true
+ )
+ {
+ eap_status_e status = check_message_authentication_code(
+ get_K_aut(),
+ p_aka_payloads,
+ received_aka,
+ received_aka->get_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // The most significant bit is called the Failure bit (F bit).
+ // The F bit specifies whether the notification implies failure.
+ 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_last_eap_identifier(static_cast<u8_t>(get_last_eap_identifier()+1u));
+ set_state(eap_type_aka_state_failure);
+
+ // This will terminate session immediately.
+ (void) get_type_partner()->set_session_timeout(0UL);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else //if (get_aka_notification_code_F_bit(m_aka_notification_code) == true)
+ {
+ // The receipt of a notification code with the F bit set to one (values
+ // 32768...65536) does not imply failure. Notification code 32768 has
+ // been reserved as a general notification code to indicate successful
+ // authentication.
+ if (m_aka_notification_code == eap_aka_notification_F_set_no_P_user_authenticated)
+ {
+ status = finish_successful_authentication(
+ receive_network_id);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+ }
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message_full_authentication(): ")
+ EAPL("Not correct AKA-payloads are included ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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 //if (get_aka_notification_code_P_bit(m_aka_notification_code) == true)
+ {
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_must_not_be // CHECKCODE
+ ) == true
+ )
+ {
+ // If the P bit is set to one, the notification can only by used before
+ // the EAP/AKA/Challenge round in full authentication, or before the
+ // EAP/AKA/Re-authentication round in reauthentication.
+
+ // The most significant bit is called the Failure bit (F bit).
+ // The F bit specifies whether the notification implies failure.
+ 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.
+ }
+ else //if (get_aka_notification_code_F_bit(m_aka_notification_code) == true)
+ {
+ // The receipt of a notification code with the F bit set to one (values
+ // 32768...65536) does not imply failure. Notification code 32768 has
+ // been reserved as a general notification code to indicate successful
+ // authentication.
+ }
+
+ eap_status_e status = initialize_error_message(
+ eap_status_process_general_error);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message_full_authentication(): ")
+ EAPL("Not correct AKA-payloads are included ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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_FUNC_EXPORT eap_status_e eap_type_aka_c::handle_notification_response_message(
+ 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)
+{
+ if (aka_packet_length < received_aka->get_length())
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message(): ")
+ 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);
+ }
+
+ eap_status_e status = eap_status_process_general_error;
+
+ if (get_state() == eap_type_aka_state_waiting_for_notification_response_success
+ || get_state() == eap_type_aka_state_waiting_for_notification_response_failure)
+ {
+ // NOTE, this message is unauthenticated. Anybody could sent this message.
+
+ if (received_aka->get_identifier() != get_last_eap_identifier())
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ received_aka->get_identifier(), get_last_eap_identifier(),
+ get_state(), get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+
+ if (m_authentication_type == AKA_AUTHENTICATION_TYPE_REAUTHENTICATION)
+ {
+ status = handle_notification_response_message_reauthentication(
+ receive_network_id,
+ received_aka,
+ aka_packet_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);
+ }
+ }
+ else
+ {
+ status = handle_notification_response_message_full_authentication(
+ receive_network_id,
+ received_aka,
+ aka_packet_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);
+ }
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ // Wrong message in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_notification_response_message(): ")
+ EAPL("Wrong 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_FUNC_EXPORT eap_status_e eap_type_aka_c::check_challenge_response_message(
+ 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_status_e status = eap_status_process_general_error;
+
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_optional, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_optional // CHECKCODE
+ ) == true
+ )
+ {
+ save_current_state();
+ set_state(eap_type_aka_state_analyses_challenge_response);
+
+ status = get_saved_EAP_packet()->set_buffer(
+ received_aka->get_header_buffer(aka_packet_length),
+ aka_packet_length,
+ false,
+ true);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = check_message_authentication_code(
+ get_K_aut(),
+ p_aka_payloads,
+ received_aka,
+ 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);
+ }
+
+ if (p_aka_payloads->get_CHECKCODE()->get_payload_included() == true)
+ {
+ // Verify AT_CHECKCODE.
+ status = checkcode_verify(
+ p_aka_payloads->get_CHECKCODE()->get_payload_buffer());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ if (status == eap_status_ok)
+ {
+ // Ok, client successfully authenticated.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("Authentication OK.\n")));
+
+ if (m_use_result_indication == false
+ && p_aka_payloads->get_RESULT_IND()->get_payload_included() == true)
+ {
+ // ERROR: We did not send AT_RESULT_IND and client responds with it.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+ }
+ else if (m_use_result_indication == true
+ && p_aka_payloads->get_RESULT_IND()->get_payload_included() == false)
+ {
+ // Client does not expect result indication.
+ m_use_result_indication = false;
+ }
+
+ // 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)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error);
+ }
+
+ // In order to use re-authentication, the client and the server need to
+ // store the following values: original XKEY, K_aut, K_encr, latest
+ // counter value and the next re-authentication identity.
+ status = m_am_type_aka->store_reauth_parameters(
+ get_XKEY(),
+ get_K_aut(),
+ get_K_encr(),
+ EAP_TYPE_AKA_INITIAL_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);
+ }
+
+ if (m_use_result_indication == true)
+ {
+ // Send EAP-Request/AKA/Notification.
+ m_aka_notification_code = eap_aka_notification_F_set_no_P_user_authenticated;
+
+ status = send_aka_notification_request(
+ m_aka_notification_code,
+ false);
+ if (status != eap_status_ok)
+ {
+ 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_notification_response_success);
+ }
+ else
+ {
+ if (m_randomly_fail_successfull_authentication == true
+ && random_selection() == true)
+ {
+ // This is for testing.
+ m_aka_notification_code = eap_aka_notification_no_F_no_P_general_failure;
+
+ status = initialize_notification_message();
+ }
+ else
+ {
+ // Note the EAP-Identifier of EAP-Success must be the same as
+ // EAP-Identifier in the last EAP-Request - EAP-Response roundtrip.
+ status = finish_successful_authentication(
+ receive_network_id);
+ }
+ }
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_challenge_response_message(6): ")
+ EAPL("Not correct AKA-payloads are included in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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_FUNC_EXPORT eap_status_e eap_type_aka_c::handle_challenge_response_message(
+ 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_status_e status = eap_status_process_general_error;
+
+ if (get_state() == eap_type_aka_state_waiting_for_challenge_response)
+ {
+ if (received_aka->get_identifier() != get_last_eap_identifier())
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_challenge_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ received_aka->get_identifier(), get_last_eap_identifier(),
+ get_state(), get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+ status = check_challenge_response_message(
+ receive_network_id,
+ received_aka,
+ aka_packet_length,
+ p_aka_payloads);
+ }
+ else if (get_state() == eap_type_aka_state_success)
+ {
+ if (received_aka->get_identifier() != get_last_eap_identifier()-1u)
+ {
+ // Wrong EAP-Identifier in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_challenge_response_message(): ")
+ EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) ")
+ EAPL("in eap_type_aka_state_variable_e %d=%s.\n"),
+ received_aka->get_identifier(),
+ get_last_eap_identifier()-1u,
+ get_state(),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+ }
+
+ status = check_challenge_response_message(
+ receive_network_id,
+ received_aka,
+ aka_packet_length,
+ p_aka_payloads);
+ }
+ else if (get_state() == eap_type_aka_state_pending_authentication_vector_query)
+ {
+ // This is re-transmitted EAP-Response/AKA/Challenge.
+ // We dischard it quietly.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("WARNING: eap_type_aka_c::handle_challenge_response_message(): ")
+ EAPL("Re-transmitted message %d=%s dropped 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_drop_packet_quietly);
+ }
+ else
+ {
+ // Wrong message in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_challenge_response_message(): ")
+ EAPL("Wrong 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::handle_reauthentication_response_message(
+ 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_status_e status = eap_status_process_general_error;
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_aka_c::handle_reauthentication_response_message(): %s, m_identity_type %d=%s, identity payload was %d=%s.\n"),
+ (m_is_client == true ? "client": "server"),
+ m_identity_type,
+ get_identity_string(m_identity_type),
+ get_aka_identity_response_includes_identity(),
+ aka_payload_AT_header_c::get_payload_AT_string(get_aka_identity_response_includes_identity())));
+
+ if (get_state() == eap_type_aka_state_waiting_for_reauth_response)
+ {
+ // This could be first or retransmission request.
+
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_optional, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_optional // CHECKCODE
+ ) == true
+ )
+ {
+
+ set_last_eap_identifier(received_aka->get_identifier());
+
+ save_current_state();
+ set_state(eap_type_aka_state_analyses_reauthentication_response);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c orig_XKEY(m_am_tools);
+ eap_variable_data_c orig_K_aut(m_am_tools);
+ eap_variable_data_c orig_K_encr(m_am_tools);
+
+ if (orig_XKEY.get_is_valid() == false
+ || orig_K_aut.get_is_valid() == false
+ || orig_K_encr.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ u32_t reauth_counter = 0u;
+ // In order to use re-authentication, the client and the server need to
+ // store the following values: original XKEY, K_aut, K_encr, latest
+ // counter value and the next re-authentication identity.
+ status = m_am_type_aka->query_reauth_parameters(
+ &orig_XKEY,
+ &orig_K_aut,
+ &orig_K_encr,
+ &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);
+ }
+
+ status = check_message_authentication_code(
+ &orig_K_aut,
+ p_aka_payloads,
+ received_aka,
+ aka_packet_length);
+ if (status != eap_status_ok)
+ {
+ restore_saved_previous_state();
+
+ eap_status_string_c status_string;
+ EAP_UNREFERENCED_PARAMETER(status_string);
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: Re-authentication failed: %s, state %s\n"),
+ status_string.get_status_string(status),
+ get_state_string()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ if (p_aka_payloads->get_CHECKCODE()->get_payload_included() == true)
+ {
+ // Verify AT_CHECKCODE.
+ status = checkcode_verify(
+ p_aka_payloads->get_CHECKCODE()->get_payload_buffer());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ // Decrypt and parse encrypted payload.
+ if (p_aka_payloads->get_IV()->get_payload_included() == true
+ || p_aka_payloads->get_ENCR_DATA()->get_payload_included() == true)
+ {
+ if (p_aka_payloads->get_IV()->get_payload_included() == true
+ && p_aka_payloads->get_ENCR_DATA()->get_payload_included() == true
+ && p_aka_payloads->get_MAC()->get_payload_included() == true)
+ {
+ if (m_use_result_indication == false
+ && p_aka_payloads->get_RESULT_IND()->get_payload_included() == true)
+ {
+ // ERROR: We did not send AT_RESULT_IND and client responds with it.
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+ }
+ else if (m_use_result_indication == true
+ && p_aka_payloads->get_RESULT_IND()->get_payload_included() == false)
+ {
+ // Client does not expect result indication.
+ m_use_result_indication = false;
+ }
+
+ aka_payloads_c * const l_aka_payloads = new aka_payloads_c(m_am_tools);
+ eap_automatic_variable_c<aka_payloads_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 = decrypt_DATA_payload(
+ p_aka_payloads,
+ &orig_K_encr);
+ 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);
+ }
+
+ u32_t state_payload_buffer_length = p_aka_payloads->get_ENCR_DATA()->get_data_length();
+
+ const aka_payload_AT_header_c gp_data_payload(
+ m_am_tools,
+ p_aka_payloads->get_ENCR_DATA()->get_data(state_payload_buffer_length),
+ state_payload_buffer_length);
+
+ if (gp_data_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);
+ }
+
+ status = parse_aka_payload(
+ &gp_data_payload,
+ &state_payload_buffer_length,
+ l_aka_payloads,
+ received_aka->get_subtype());
+ 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);
+ }
+
+ if (l_aka_payloads->get_COUNTER_TOO_SMALL()->get_payload_included() == true)
+ {
+ // When the client detects that the
+ // counter value is not fresh, it includes the AT_COUNTER_TOO_SMALL
+ // attribute in EAP-Response/AKA/Re-authentication. This attribute
+ // doesn't contain any data but it is a request for the server to
+ // initiate full authentication.
+
+ // The full authentication must follow.
+ m_authentication_type = AKA_AUTHENTICATION_TYPE_FULL_AUTH;
+ set_aka_identity_response_includes_identity(aka_payload_NONE);
+
+ bool pseudonym_decode_failed = false;
+
+ if (get_identity()->get_is_valid_data() == false
+ || (m_identity_type != AKA_IDENTITY_TYPE_IMSI_ID
+ && m_identity_type != AKA_IDENTITY_TYPE_PSEUDONYM_ID
+ && m_identity_type != AKA_IDENTITY_TYPE_RE_AUTH_ID))
+ {
+ // We do not have any identity of the client.
+ set_aka_identity_response_includes_identity(aka_payload_AT_FULLAUTH_ID_REQ);
+ set_identity_type(AKA_IDENTITY_TYPE_NONE);
+ (void) get_identity()->reset();
+ pseudonym_decode_failed = true;
+ }
+
+ status = send_aka_identity_request_message(
+ pseudonym_decode_failed,
+ static_cast<u8_t>(received_aka->get_identifier()+1u));
+ if (status == eap_status_ok)
+ {
+ set_last_eap_identifier(static_cast<u8_t>(received_aka->get_identifier()+1u));
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ if (l_aka_payloads->get_COUNTER()->get_payload_included() == false)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+ }
+
+ u32_t counter = l_aka_payloads->get_COUNTER()->get_original_header()->get_reserved();
+
+ if (counter != reauth_counter)
+ {
+ restore_saved_previous_state();
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+ }
+
+ // OK, client re-authenticates corretly.
+
+ if (m_use_result_indication == true)
+ {
+ // Send EAP-Request/AKA/Notification.
+ m_aka_notification_code = eap_aka_notification_F_set_no_P_user_authenticated;
+
+ status = send_aka_notification_request(
+ m_aka_notification_code,
+ true);
+ if (status != eap_status_ok)
+ {
+ 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_notification_response_success);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS,
+ (EAPL("EAP_type_AKA: %s, re-authentication OK, waits result indication\n"),
+ (m_is_client == true) ? "client": "server"));
+ }
+ else
+ {
+ if (m_randomly_fail_successfull_authentication == true
+ && random_selection() == true)
+ {
+ // This is for testing.
+ m_aka_notification_code = eap_aka_notification_no_F_no_P_general_failure;
+
+ status = initialize_notification_message();
+ }
+ else
+ {
+ // Note the EAP-Identifier of EAP-Success must be the same as
+ // EAP-Identifier in the last EAP-Request - EAP-Response roundtrip.
+ status = finish_successful_authentication(
+ receive_network_id);
+ }
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ // All of these must be included
+ // or none of these must be included.
+ restore_saved_previous_state();
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+ }
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ restore_saved_previous_state();
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_reauthentication_response_message(6): ")
+ EAPL("Not correct AKA-payloads are included in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_reauthentication_response_message(6): ")
+ EAPL("Not correct AKA-payloads are included in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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
+ {
+ // Wrong message in this state.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_reauthentication_response_message(): ")
+ EAPL("Wrong 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_FUNC_EXPORT eap_status_e eap_type_aka_c::handle_client_error_response_message(
+ 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_UNREFERENCED_PARAMETER(aka_packet_length);
+ EAP_UNREFERENCED_PARAMETER(received_aka);
+
+ eap_status_e status = eap_status_process_general_error;
+
+ // This could be first, retransmission request
+ // or some nasty attacker to make denial of service.
+
+ // Checks the payloads existence.
+ if (p_aka_payloads->check_payloads(
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // nonce_s
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // MAC
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ENCR_DATA
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IDENTITY
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // padding
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // n_RANDs
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTN
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // AUTS
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RES
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // PERMANENT_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // FULLAUTH_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // ANY_ID_REQ
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // IV
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_PSEUDONYM
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NEXT_REAUTH_ID
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // NOTIFICATION
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // COUNTER_TOO_SMALL
+ aka_payloads_c::eap_aka_payload_status_must_be, // CLIENT_ERROR_CODE
+ aka_payloads_c::eap_aka_payload_status_must_not_be, // RESULT_IND
+ aka_payloads_c::eap_aka_payload_status_must_not_be // CHECKCODE
+ ) == true
+ )
+ {
+ eap_status_e client_status = eap_status_process_general_error;
+
+ /** @{ Add some use for the Client Error Code. } */
+ eap_aka_client_error_code_e client_error_code
+ = static_cast<eap_aka_client_error_code_e>(p_aka_payloads->get_CLIENT_ERROR_CODE()
+ ->get_original_header()->get_reserved());
+
+ EAP_UNREFERENCED_PARAMETER(client_error_code);
+
+ status = initialize_error_message(
+ client_status);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ // Not correct AKA-payloads are included.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: eap_type_aka_c::handle_client_error_response_message(): ")
+ EAPL("Not correct AKA-payloads are included in eap_type_aka_state_variable_e %d=%s.\n"),
+ 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_FUNC_EXPORT eap_status_e eap_type_aka_c::check_NAI(
+ const u8_t * const identity,
+ const u32_t identity_length,
+ const u8_t * const at_character)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ bool includes_at = false;
+ bool includes_dot = false;
+ u32_t username_length = 0u;
+ u32_t realm_length = 0u;
+
+ for (u32_t ind = 0; ind < identity_length; ind++)
+ {
+ const u8_t character = identity[ind];
+
+ if (includes_at == false)
+ {
+ if (character != AKA_NAI_AT_BYTE)
+ {
+ ++username_length;
+ }
+ }
+ else
+ {
+ ++realm_length;
+ }
+
+
+ if ('0' <= character && character <= '9')
+ {
+ // OK.
+ }
+ else if ('a' <= character && character <= 'z')
+ {
+ // OK.
+ }
+ else if ('A' <= character && character <= 'Z')
+ {
+ // OK.
+ }
+ else if (character == AKA_NAI_AT_BYTE)
+ {
+ if (includes_at == false)
+ {
+ includes_at = true;
+ }
+ else
+ {
+ // Second at ('@').
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("Illegal NAI, includes second at \'@\' character."),
+ identity,
+ identity_length));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai);
+ }
+ }
+ else if (character == '.')
+ {
+ if (includes_at == true)
+ {
+ // OK.
+ includes_dot = true;
+ }
+ else
+ {
+ // dot ('.') within username
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("Illegal NAI, dot \'.\' within username."),
+ identity,
+ identity_length));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai);
+ }
+ }
+ else if (character == '<'
+ || character == '>'
+ || character == '('
+ || character == ')'
+ || character == '['
+ || character == ']'
+ || character == '\\'
+ || character == '.'
+ || character == ','
+ || character == ';'
+ || character == ':'
+ || character == AKA_NAI_AT_BYTE
+ || character == ' ' // space
+ || character <= 0x1f // Ctrl
+ || character >= 0x7f) // extented characters
+ {
+ // Illegal character.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_AKA_ERROR,
+ (EAPL("ERROR: Illegal NAI, includes illegal character 0x%02x=%c.\n"),
+ character,
+ character));
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("Illegal NAI, includes illegal character."),
+ identity,
+ identity_length));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai);
+ }
+ else
+ {
+ // All other ascii values are OK.
+ }
+ }
+
+ // Note the username could be zero length.
+ if ((realm_length == 1u && includes_at == true) // one at ('@') is illegal.
+ || (realm_length == 2u && includes_at == true && includes_dot == true)) // one at ('@') and one dot is illegal.
+ {
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT, (EAPL("Illegal NAI."),
+ identity,
+ identity_length));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai);
+ }
+
+ if (m_check_nai_realm == true)
+ {
+ if (at_character == 0
+ && realm_length == 0
+ && get_nai_realm()->get_data_length() == 0)
+ {
+ // OK, no realm.
+ }
+ else if (at_character == 0
+ || realm_length != get_nai_realm()->get_data_length()
+ || m_am_tools->memcmp(
+ at_character+1u,
+ get_nai_realm()->get_data(get_nai_realm()->get_data_length()),
+ get_nai_realm()->get_data_length()) != 0)
+ {
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("Illegal NAI, realm unknown."),
+ identity,
+ identity_length));
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("NAI should be"),
+ get_nai_realm()->get_data(get_nai_realm()->get_data_length()),
+ get_nai_realm()->get_data_length()));
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai);
+ }
+ }
+
+
+ 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_identity(
+ const u8_t * const identity,
+ const u32_t identity_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status(eap_status_process_general_error);
+
+ if (identity_length < 1u)
+ {
+ status = get_identity()->init(0ul);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = get_NAI()->init(0ul);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+
+ const u8_t *at_character = reinterpret_cast<const u8_t *>(m_am_tools->memchr(
+ identity,
+ AKA_AT_CHARACTER[0],
+ identity_length));
+
+ // NOTE, at_character could be NULL. Realm is optional.
+
+ status = check_NAI(identity, identity_length, at_character);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = eap_status_process_general_error;
+
+ u32_t username_length = identity_length;
+ if (at_character != 0)
+ {
+ username_length = static_cast<u32_t>(at_character-identity);
+ }
+
+ status = get_identity()->set_copy_of_buffer(
+ identity, // Note we do store whole IMSI or pseudonym including possible prefix.
+ username_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = get_NAI()->set_copy_of_buffer(identity, identity_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);
+}
+
+//--------------------------------------------------
+
+
+
+// End.