eapol/eapol_framework/eapol_symbian/am/type/aka/symbian/eap_am_type_aka_symbian.cpp
/*
* 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.
*
*/
/*
* %version: 49 %
*/
// This is enumeration of EAPOL source code.
#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
#undef EAP_FILE_NUMBER_ENUM
#define EAP_FILE_NUMBER_ENUM 604
#undef EAP_FILE_NUMBER_DATE
#define EAP_FILE_NUMBER_DATE 1127594498
#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
// INCLUDE FILES
#include "eap_tools.h"
#include "eap_am_type_aka_symbian.h"
#include "eap_am_tools_symbian.h"
#include "eap_state_notification.h"
#include "EapAkaDbDefaults.h"
#include "EapAkaDbParameterNames.h"
#include "EapAkaDbUtils.h"
#include "eap_am_trace_symbian.h"
#include <d32dbms.h> // For DBMS
#include <s32strm.h> // For RReadStream
#if defined (USE_EAP_TYPE_SERVER_AKA)
// These are needed only for the server and test environment (Plugin tester)
// Enable USE_EAP_TYPE_SERVER_AKA in eapol.mmh to build for test environment.
#include "eap_crypto_api.h"
#include "eap_am_aka_milenage_algorithm.h"
#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
#include "EapAkaInterface.h"
#endif // End of #if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
// This is needed for cf_str_EAP_AKA_2_digit_mnc_map_of_mcc_of_imsi_array.
#include "eap_type_aka_types.h"
const TUint AKA_IMSI_LENGTH = 15u;
const TUint KMaxSqlQueryLength = 512;
const TUint KMaxDBFieldNameLength = 255;
const TInt KDefaultColumnInView_One = 1; // For DB view.
const TInt KMicroSecsInASecond = 1000000; // 1000000 micro seconds is 1 second.
const u8_t EAP_AKA_DEFAULT_REAUTHENTICATION_REALM[] = "dymmy.reauth.org";
const u32_t EAP_AKA_DEFAULT_REAUTHENTICATION_REALM_LENGTH = sizeof(EAP_AKA_DEFAULT_REAUTHENTICATION_REALM)-1ul;
#if defined (USE_EAP_TYPE_SERVER_AKA) || defined(__WINS__)
const char TEST_IMSI[] = "244070100000001";
#endif
#if defined (USE_EAP_TYPE_SERVER_AKA)
// For the server side.
struct eap_aka_encryption_imsi_block_s
{
u8_t id_type:1;
u8_t imsi_length:7;
u8_t imsi_and_padding[AKA_IMSI_LENGTH];
};
struct eap_aka_pseudonym_s
{
u32_t encryption_key_index;
union _IV
{
u8_t IV_8[EAP_AES_BLOCK_SIZE];
u32_t IV_32[EAP_AES_BLOCK_SIZE/sizeof(u32_t)];
} encryption_IV;
eap_aka_encryption_imsi_block_s imsi_block;
u8_t MAC[HMAC_SHA1_128_SIZE];
};
const u32_t ENCRYPTION_KEY_INDEX_SCRAMBLE_CONST = 0xa7b3c922;
#endif //#if defined (USE_EAP_TYPE_SERVER_AKA)
// ================= MEMBER FUNCTIONS =======================
eap_am_type_aka_symbian_c::eap_am_type_aka_symbian_c(
abs_eap_am_tools_c * const tools,
abs_eap_base_type_c * const partner,
const TIndexType aIndexType,
const TInt aIndex,
const eap_type_value_e aTunnelingType,
const bool aIsClient,
const eap_am_network_id_c * const receive_network_id)
: eap_am_type_aka_c(tools)
, m_am_tools(static_cast<eap_am_tools_symbian_c*>(tools)) // Tools class must be of type eap_am_tools_symbian because
// this is Symbian specific code.
, m_partner(partner)
, m_nai_realm(tools)
, m_index_type(aIndexType)
, m_index(aIndex)
, m_tunneling_type(aTunnelingType)
, m_is_valid(false)
, m_is_client(aIsClient)
, m_stored_reauth_id(tools)
, m_stored_pseudonym(tools)
, m_previous_imsi(tools)
, m_stored_required_completion(eap_type_aka_complete_none)
, m_stored_received_eap_identifier(0)
, m_shutdown_was_called(false)
, m_aka_algorithm(0)
, m_aka_if(0)
, m_simulator_aka_K(tools)
, m_simulator_aka_OP(tools)
, m_simulator_aka_AMF(tools)
, m_authentication_vector(0)
, m_pseudonym_identity(tools)
, m_reauthentication_identity(tools)
, m_username(tools)
, m_receive_network_id(tools)
, m_IMSI(tools)
, m_required_identity(aka_payload_NONE)
, m_required_completion(eap_type_aka_complete_none)
, m_identity_type(AKA_IDENTITY_TYPE_NONE)
, m_completion_action(eap_type_aka_complete_none)
, m_next_eap_identifier(0)
, m_aka_authentication_vector_status(eap_aka_authentication_vector_status_ok)
, m_pseudonym_key_index(0u)
, m_pseudonym_key(tools)
, m_pseudonym_MAC_key(tools)
, m_prev_pseudonym_key(tools)
, m_prev_pseudonym_MAC_key(tools)
, m_pseudonym_key_use_count(0u)
, m_RAND(tools)
, m_AUTN(tools)
, m_max_session_time(0)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
#ifdef USE_EAP_EXPANDED_TYPES
m_tunneling_vendor_type = m_tunneling_type.get_vendor_type();
#else
m_tunneling_vendor_type = static_cast<TUint>(m_tunneling_type);
#endif //#ifdef USE_EAP_EXPANDED_TYPES
if (receive_network_id != 0
&& receive_network_id->get_is_valid_data() == true)
{
eap_status_e status = m_receive_network_id.set_copy_of_network_id(
receive_network_id);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
(void)EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
return;
}
}
set_is_valid();
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::ConstructL()
{
#if defined (USE_EAP_TYPE_SERVER_AKA)
// For the server.
m_aka_algorithm = new eap_am_aka_milenage_algorithm_c(m_am_tools, m_is_client);
if (m_aka_algorithm == 0
|| m_aka_algorithm->get_is_valid() == false)
{
if (m_aka_algorithm != 0)
{
m_aka_algorithm->shutdown();
}
delete m_aka_algorithm;
m_aka_algorithm = 0;
return;
}
#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
// Open/create database
EapAkaDbUtils::OpenDatabaseL(m_database, m_session, m_index_type, m_index, m_tunneling_type);
// SIM IMSI, RES, CK, IK and AUTS are queried from SIM using AKA interface.
// If this is not used then Nokia test algorithms and test values are used.
#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
if (m_is_client == true)
{
m_aka_if = CEapAkaInterface::NewL(m_am_tools, this);
}
else
{
EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: EAP-AKA server does not work at the moment in plugintester.\n")));
User::Leave(KErrNotSupported);
}
#endif //#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
}
//--------------------------------------------------
eap_am_type_aka_symbian_c* eap_am_type_aka_symbian_c::NewL(
abs_eap_am_tools_c * const aTools,
abs_eap_base_type_c * const aPartner,
const TIndexType aIndexType,
const TInt aIndex,
const eap_type_value_e aTunnelingType,
const bool aIsClient,
const eap_am_network_id_c * const receive_network_id)
{
eap_am_type_aka_symbian_c* self = new(ELeave) eap_am_type_aka_symbian_c(
aTools,
aPartner,
aIndexType,
aIndex,
aTunnelingType,
aIsClient,
receive_network_id);
CleanupStack::PushL(self);
self->ConstructL();
if (self->get_is_valid() != true)
{
User::Leave(KErrGeneral);
}
CleanupStack::Pop();
return self;
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_am_type_aka_symbian_c::~eap_am_type_aka_symbian_c()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::~eap_am_type_aka_symbian_c(): this = 0x%08x\n"),
this));
m_database.Close();
m_session.Close();
#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
if (m_is_client == true)
{
delete m_aka_if;
}
#endif
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::configure()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
{
eap_status_e status = type_configure_read(
cf_str_EAP_AKA_manual_realm.get_field(),
&m_nai_realm);
if (status == eap_status_ok
&& m_nai_realm.get_is_valid_data() == true)
{
// OK NAI realm configured.
}
else
{
// No NAI realm configured.
// Lets use dummy.
status = m_nai_realm.set_copy_of_buffer(EAP_AKA_DEFAULT_REAUTHENTICATION_REALM,
EAP_AKA_DEFAULT_REAUTHENTICATION_REALM_LENGTH);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
}
}
{
// Read Maximum Session Validity Time from the config file
eap_variable_data_c sessionTimeFromFile(m_am_tools);
eap_status_e status = m_partner->read_configure(
cf_str_EAP_AKA_max_session_validity_time.get_field(),
&sessionTimeFromFile);
if (status == eap_status_ok
&& sessionTimeFromFile.get_is_valid_data() == true
&& sessionTimeFromFile.get_data_length() == sizeof(u32_t))
{
u32_t *session = reinterpret_cast<u32_t *>(sessionTimeFromFile.get_data());
if (session != 0)
{
// Update the max session time (in micro seconds).
// configuration file saves the time in seconds. We have to convert it to micro seconds.
m_max_session_time = static_cast<TInt64>(*session) * static_cast<TInt64>(KMicroSecsInASecond);
}
}
}
#if defined (USE_EAP_TYPE_SERVER_AKA)
// We have to set the values for K, OP and AMF in simulator.
{
eap_status_e status = m_partner->read_configure(
cf_str_EAP_AKA_simulator_aka_k.get_field(),
&m_simulator_aka_K);
if (status == eap_status_ok
&& m_simulator_aka_K.get_is_valid_data() == true
&& m_simulator_aka_K.get_data_length() > 0ul
&& m_simulator_aka_K.get_data(
m_simulator_aka_K.get_data_length()) != 0)
{
// OK.
eap_status_e status = m_aka_algorithm->set_simulator_aka_k(&m_simulator_aka_K);
if (status != eap_status_ok)
{
return EAP_STATUS_RETURN(m_am_tools, status);
}
}
else
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("ERROR: illegal configuration value %s\n"),
cf_str_EAP_AKA_simulator_aka_k.get_field()->get_field()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_configure_field);
}
}
{
eap_status_e status = m_partner->read_configure(
cf_str_EAP_AKA_simulator_aka_op.get_field(),
&m_simulator_aka_OP);
if (status == eap_status_ok
&& m_simulator_aka_OP.get_is_valid_data() == true
&& m_simulator_aka_OP.get_data_length() > 0ul
&& m_simulator_aka_OP.get_data(
m_simulator_aka_OP.get_data_length()) != 0)
{
// OK.
eap_status_e status = m_aka_algorithm->set_simulator_aka_op(&m_simulator_aka_OP);
if (status != eap_status_ok)
{
return EAP_STATUS_RETURN(m_am_tools, status);
}
}
else
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("ERROR: illegal configuration value %s\n"),
cf_str_EAP_AKA_simulator_aka_op.get_field()->get_field()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_configure_field);
}
}
{
eap_status_e status = m_partner->read_configure(
cf_str_EAP_AKA_simulator_aka_amf.get_field(),
&m_simulator_aka_AMF);
if (status == eap_status_ok
&& m_simulator_aka_AMF.get_is_valid_data() == true
&& m_simulator_aka_AMF.get_data_length() == sizeof(u16_t)
&& m_simulator_aka_AMF.get_data(
m_simulator_aka_AMF.get_data_length()) != 0)
{
// OK.
eap_status_e status = m_aka_algorithm->set_simulator_aka_amf(&m_simulator_aka_AMF);
if (status != eap_status_ok)
{
return EAP_STATUS_RETURN(m_am_tools, status);
}
}
else
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("ERROR: illegal configuration value %s\n"),
cf_str_EAP_AKA_simulator_aka_amf.get_field()->get_field()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_configure_field);
}
}
if (m_pseudonym_key.get_is_valid_data() == false)
{
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);
}
// Note this function generates cryptographically strong random bytes.
// Here we use those bytes as a secret encryption key.
eap_status_e status = generate_encryption_IV(
&m_pseudonym_key,
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 = generate_encryption_IV(
&m_pseudonym_MAC_key,
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);
}
++m_pseudonym_key_index;
}
#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_ok;
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::reset()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_ok;
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::shutdown()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("%s: eap_am_type_aka_symbian_c::shutdown(), m_shutdown_was_called=%d\n"),
(m_is_client == true) ? "client": "server",
m_shutdown_was_called));
if (m_shutdown_was_called == true)
{
// Shutdown function was called already.
return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
}
m_shutdown_was_called = true;
if (m_aka_algorithm != 0)
{
m_aka_algorithm->shutdown();
delete m_aka_algorithm;
m_aka_algorithm = 0;
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_ok;
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::send_error_notification(const eap_status_e error)
{
// Here we swap the addresses.
eap_am_network_id_c send_network_id(m_am_tools,
m_receive_network_id.get_destination_id(),
m_receive_network_id.get_source_id(),
m_receive_network_id.get_type());
// Notifies the lower level of an authentication error.
eap_state_notification_c notification(
m_am_tools,
&send_network_id,
m_is_client,
eap_state_notification_eap,
eap_protocol_layer_general,
eap_type_aka,
eap_state_none,
eap_general_state_authentication_error,
0,
false);
notification.set_authentication_error(error);
m_partner->state_notification(¬ification);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::store_pseudonym_id(
const eap_am_network_id_c * const send_network_id,
const eap_variable_data_c * const pseudonym)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Send error if the pseudonym is too long.
if(pseudonym != NULL && pseudonym->get_data_length() > KMaxPseudonymIdLengthInDB)
{
// Pseudonym too long. Can't store this in DB.
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::store_pseudonym_id: ")
EAPL("Too long Pseudonym. Length=%d\n"),
pseudonym->get_data_length()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
eap_status_e status(eap_status_ok);
TRAPD(err, store_pseudonym_idL(send_network_id, pseudonym));
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
send_error_notification(status);
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::store_pseudonym_idL(
const eap_am_network_id_c * const /*network_id*/,
const eap_variable_data_c * const pseudonym)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Form the insertion command
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLInsert, &KPseudonymId, &KAkaTableName,
&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
// Evaluate view
RDbView view;
User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
// Update the columns in the database
view.FirstL();
view.UpdateL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
// Create pointer to the data
if ((pseudonym != NULL)
&& (pseudonym->get_is_valid_data() == true))
{
TPtrC8 pseudonymId(
pseudonym->get_data(pseudonym->get_data_length()),
pseudonym->get_data_length());
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("pseudonymId to DB"),
pseudonymId.Ptr(),
pseudonymId.Length()));
view.SetColL(colSet->ColNo(KPseudonymId), pseudonymId);
}
else
{
// If passed pseudonym was 0 that means the field must be cleared.
view.SetColNullL(colSet->ColNo(KPseudonymId));
}
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
view.PutL();
// Close database
CleanupStack::PopAndDestroy(2); // view, buf
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::store_reauthentication_id(
const eap_am_network_id_c * const send_network_id,
const eap_variable_data_c * const reauthentication_identity)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Send error if the reauthentication id is too long.
if(reauthentication_identity != NULL
&& reauthentication_identity->get_data_length() > KMaxReauthIdLengthInDB)
{
// Reauth id too long. Can't store this in DB.
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::store_reauthentication_id: ")
EAPL("Too long reauth id. Length=%d\n"),
reauthentication_identity->get_data_length()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
eap_status_e status(eap_status_ok);
TRAPD(err, store_reauthentication_idL(send_network_id, reauthentication_identity));
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
send_error_notification(status);
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::store_reauthentication_idL(
const eap_am_network_id_c * const /*network_id*/,
const eap_variable_data_c * const reauthentication_id)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Form the insertion command
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLInsert, &KReauthId, &KAkaTableName,
&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
// Evaluate view
RDbView view;
User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
view.FirstL();
view.UpdateL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
// Create pointer to the data
if ((reauthentication_id != NULL)
&& (reauthentication_id->get_is_valid_data() == true))
{
TPtrC8 reauthId(
reauthentication_id->get_data(reauthentication_id->get_data_length()),
reauthentication_id->get_data_length());
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("reauthId to DB"),
reauthId.Ptr(),
reauthId.Length()));
view.SetColL(colSet->ColNo(KReauthId), reauthId);
}
else
{
// If passed reauthentication_id was 0 that means the field must be cleared.
view.SetColNullL(colSet->ColNo(KReauthId));
}
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
view.PutL();
// Close database
CleanupStack::PopAndDestroy(2); // view, buf
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::store_reauth_parameters(
const eap_variable_data_c * const XKEY,
const eap_variable_data_c * const K_aut,
const eap_variable_data_c * const K_encr,
const u32_t reauth_counter)
{
// These kind of wrapper functions are needed because the Symbian L-functions must be executed in
// trap harness.
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Send error if any of the parameters are invalid.
if(XKEY == NULL
|| K_aut == NULL
|| K_encr == NULL)
{
// Some of the parameters are invalid.
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::store_reauth_parameters: ")
EAPL("ERROR: Invalid parameters\n")));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
// Send error if any of the parameters are too long.
if(XKEY->get_data_length() > KMaxXKeyLengthInDB
|| K_aut->get_data_length() > KMaxK_autLengthInDB
|| K_encr->get_data_length() > KMaxK_encrLengthInDB )
{
// Some of the parameters are too long. Can't store them in DB.
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::store_reauth_parameters: ")
EAPL("Too long parameters. Length: XKEY=%d, K_aut=%d, K_encr=%d\n"),
XKEY->get_data_length(), K_aut->get_data_length(), K_encr->get_data_length()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
eap_status_e status(eap_status_ok);
TRAPD(err, store_reauth_parametersL(XKEY, K_aut, K_encr, reauth_counter));
if (err != KErrNone)
{
// Convert the leave error code to EAPOL stack error code.
status = m_am_tools->convert_am_error_to_eapol_error(err);
send_error_notification(status);
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::store_reauth_parametersL(
const eap_variable_data_c * const XKEY,
const eap_variable_data_c * const K_aut,
const eap_variable_data_c * const K_encr,
const u32_t reauth_counter)
{
// The _L functions do the actual thing.
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Form the insertion command
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
_LIT(KSQLInsert, "SELECT %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLInsert, &KXKey, &KK_aut, &KK_encr, &KReauthCounter, &KAkaTableName,
&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
// Evaluate view
RDbView view;
User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
// Create pointers to the data
TPtrC8 key(XKEY->get_data(XKEY->get_data_length()), XKEY->get_data_length());
TPtrC8 aut(K_aut->get_data(K_aut->get_data_length()), K_aut->get_data_length());
TPtrC8 enc(K_encr->get_data(K_encr->get_data_length()), K_encr->get_data_length());
// Update the columns in the database
view.FirstL();
view.UpdateL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("XKEY to DB"), key.Ptr(), key.Length()));
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("K_aut to DB"), aut.Ptr(), aut.Length()));
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("K_encr to DB"), enc.Ptr(), enc.Length()));
view.SetColL(colSet->ColNo(KXKey), key); // XKEY
view.SetColL(colSet->ColNo(KK_aut), aut); // K_aut
view.SetColL(colSet->ColNo(KK_encr), enc); // K_encr
view.SetColL(colSet->ColNo(KReauthCounter), reauth_counter); // ReauthCounter
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
view.PutL();
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::store_reauth_keys_L(): %s, m_saved_reauth_counter %d.\n"),
(m_is_client == true ? "client": "server"),
reauth_counter));
// Close database
CleanupStack::PopAndDestroy(2); // view, buf
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::authentication_finished(
const bool true_when_successfull,
const eap_aka_authentication_type_e authentication_type,
const eap_type_aka_identity_type identity_type)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status(eap_status_ok);
TInt err(KErrNone);
// Store the authentication time if the full authentication is successful
if (true_when_successfull == true
&& authentication_type == AKA_AUTHENTICATION_TYPE_FULL_AUTH)
{
TRAP(err,store_authentication_timeL());
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
send_error_notification(status);
}
}
if (true_when_successfull == false)
{
if( identity_type == AKA_IDENTITY_TYPE_IMSI_ID
|| identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID )
{
(void) store_pseudonym_id(0,0);
}
if( identity_type == AKA_IDENTITY_TYPE_IMSI_ID
|| identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID )
{
(void) store_reauthentication_id(0,0);
}
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_reauth_parameters(
eap_variable_data_c * const XKEY,
eap_variable_data_c * const K_aut,
eap_variable_data_c * const K_encr,
u32_t * const reauth_counter)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status(eap_status_ok);
TRAPD(err, query_reauth_parametersL(XKEY, K_aut, K_encr, reauth_counter));
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
send_error_notification(status);
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::query_reauth_parametersL(
eap_variable_data_c * const XKEY,
eap_variable_data_c * const reauth_K_aut,
eap_variable_data_c * const reauth_K_encr,
u32_t * const reauth_counter)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
// Form the query
_LIT(KSQLQuery, "SELECT %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLQuery, &KXKey, &KK_aut, &KK_encr, &KReauthCounter, &KAkaTableName,
&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
RDbView view;
// Evaluate view
User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement)));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
// Get the first (and only) row
view.FirstL();
view.GetL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
// Get the values from DB
TPtrC8 key = view.ColDes8(colSet->ColNo(KXKey));
TPtrC8 aut = view.ColDes8(colSet->ColNo(KK_aut));
TPtrC8 enc = view.ColDes8(colSet->ColNo(KK_encr));
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("XKEY from DB"), key.Ptr(), key.Length()));
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("K_aut from DB"), aut.Ptr(), aut.Length()));
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("K_encr from DB"), enc.Ptr(), enc.Length()));
eap_status_e status(eap_status_process_general_error);
// Store the values to the supplied buffers
status = XKEY->set_copy_of_buffer(key.Ptr(),key.Length());
if (status != eap_status_ok)
{
User::Leave(
m_am_tools->convert_eapol_error_to_am_error(
EAP_STATUS_RETURN(m_am_tools, status)));
}
status = reauth_K_aut->set_copy_of_buffer(aut.Ptr(),aut.Length());
if (status != eap_status_ok)
{
User::Leave(
m_am_tools->convert_eapol_error_to_am_error(
EAP_STATUS_RETURN(m_am_tools, status)));
}
status = reauth_K_encr->set_copy_of_buffer(enc.Ptr(),enc.Length());
if (status != eap_status_ok)
{
User::Leave(
m_am_tools->convert_eapol_error_to_am_error(
EAP_STATUS_RETURN(m_am_tools, status)));
}
*reauth_counter = view.ColUint(colSet->ColNo(KReauthCounter));
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::query_reauth_parametersL(): %s, m_saved_reauth_counter %d.\n"),
(m_is_client == true ? "client": "server"),
*reauth_counter));
// Close database
CleanupStack::PopAndDestroy(2); // view, buf
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::increase_reauth_counter()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status(eap_status_ok);
TRAPD(err, increase_reauth_counterL());
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
send_error_notification(status);
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::increase_reauth_counterL()
{
// Form the insertion command
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLInsert, &KReauthCounter, &KAkaTableName,
&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
// Evaluate view
RDbView view;
User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
view.FirstL();
view.GetL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
// Get the previous value
TUint counter = view.ColUint(colSet->ColNo(KReauthCounter));
view.UpdateL();
// Increment the value
view.SetColL(colSet->ColNo(KReauthCounter), counter + 1);
counter = view.ColUint(colSet->ColNo(KReauthCounter));
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::increase_reauth_counterL(): %s, m_saved_reauth_counter %d.\n"),
(m_is_client == true ? "client": "server"),
counter));
view.PutL();
// Close database
CleanupStack::PopAndDestroy(2); // view, buf
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_AKA_IMSI_or_pseudonym_or_reauthentication_id(
eap_variable_data_c * const IMSI,
eap_variable_data_c * const pseudonym_identity,
eap_variable_data_c * const reauthentication_identity,
eap_variable_data_c * const automatic_realm, ///< If this is not used, do not add any data to this parameter.
u32_t * const /*length_of_mnc*/,
const aka_payload_AT_type_e required_identity, ///< This parameter indicated the type of identity required.
const eap_type_aka_complete_e required_completion, ///< This parameter tells the required completion after this call is completed, if this is asyncronous. Use this value with abs_eap_am_type_aka_c::complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query() function call.
const u8_t received_eap_identifier ///< This is the EAP-identifier of the received EAP-request message. Use this value with abs_eap_am_type_aka_c::complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query() function call.
)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status(eap_status_ok);
EAP_ASSERT((IMSI != 0) && (pseudonym_identity != 0) && (reauthentication_identity != 0));
m_stored_required_completion = required_completion;
m_stored_received_eap_identifier = received_eap_identifier;
TRAPD(err, query_AKA_IMSI_or_pseudonym_or_reauthentication_idL(IMSI,
pseudonym_identity,
reauthentication_identity,
automatic_realm,
required_identity,
required_completion,
received_eap_identifier));
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
if (status != eap_status_pending_request)
{
send_error_notification(status);
}
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::query_AKA_IMSI_or_pseudonym_or_reauthentication_idL(
eap_variable_data_c * const IMSI,
eap_variable_data_c * const pseudonym_identity,
eap_variable_data_c * const reauthentication_identity,
eap_variable_data_c * const automatic_realm, ///< If this is not used, do not add any data to this parameter.
const aka_payload_AT_type_e required_identity,
const eap_type_aka_complete_e /*required_completion*/,
const u8_t /*received_eap_identifier*/)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status(eap_status_process_general_error);
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
// Reset everything
IMSI->reset();
pseudonym_identity->reset();
reauthentication_identity->reset();
automatic_realm->reset();
m_stored_pseudonym.reset();
m_stored_reauth_id.reset();
m_previous_imsi.reset();
_LIT(KSQLQuery, "SELECT %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLQuery, &KReauthId, &KReauthCounter, &KPseudonymId,
&KPreviousIMSI, &KAkaTableName,
&KServiceType, m_index_type,
&KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
RDbView view;
// Evaluate view
User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement)));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
// Get the first (and only) row
view.FirstL();
view.GetL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
// Get the values
TUint reauthCount = view.ColUint32(colSet->ColNo(KReauthCounter));
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("query_AKA_IMSI_or_pseudonym_or_reauthentication_idL: ")
EAPL("required_identity=%d, reauthCount from DB %d\n"),
required_identity, reauthCount));
// A stream is needed for LONG columns in DB.
RDbColReadStream readStream;
// Get pseudonym ID from DB.
HBufC8* pseudonymIdBuf = HBufC8::NewLC(KMaxPseudonymIdLengthInDB); // Buffer for pseudonym id.
TPtr8 pseudonymId = pseudonymIdBuf->Des();
readStream.OpenLC(view, colSet->ColNo(KPseudonymId));
readStream.ReadL(pseudonymId, view.ColLength(colSet->ColNo(KPseudonymId)));
readStream.Close();
CleanupStack::Pop(&readStream); // Pop readStream.
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("pseudonymId from DB"), pseudonymId.Ptr(), pseudonymId.Length()));
// Get reauthentication ID from DB.
HBufC8* reauthIdBuf = HBufC8::NewLC(KMaxReauthIdLengthInDB); // Buffer for reauthentication id.
TPtr8 reauthId = reauthIdBuf->Des();
readStream.OpenLC(view, colSet->ColNo(KReauthId));
readStream.ReadL(reauthId, view.ColLength(colSet->ColNo(KReauthId)));
readStream.Close();
CleanupStack::Pop(&readStream); // Pop readStream.
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("reauthId from DB"), reauthId.Ptr(), reauthId.Length()));
#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
// Get the previous IMSI. Used for checking if SIM has been changed.
// The checking is done in complete_AKA_imsi_L
TPtrC8 tmp_imsi = view.ColDes8(colSet->ColNo(KPreviousIMSI));
status = m_previous_imsi.set_copy_of_buffer(tmp_imsi.Ptr(), tmp_imsi.Length());
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
User::Leave(KErrNoMemory);
}
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("imsi from DB"), tmp_imsi.Ptr(), tmp_imsi.Size()));
#endif
if (required_identity == aka_payload_AT_ANY_ID_REQ)
{
if (is_session_valid() )
{
if(reauthId.Length() > 0)
{
#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
// Store the reauth id in case we are using asynchronous processing (= ISA interface)
status = m_stored_reauth_id.set_copy_of_buffer(reauthId.Ptr(), reauthId.Length());
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
User::Leave(KErrNoMemory);
}
#endif
status = reauthentication_identity->set_copy_of_buffer(reauthId.Ptr(), reauthId.Length());
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
User::Leave(KErrNoMemory);
}
}
}
}
CleanupStack::PopAndDestroy(reauthIdBuf); // Delete reauthIdBuf
if (required_identity == aka_payload_AT_ANY_ID_REQ
|| required_identity == aka_payload_AT_FULLAUTH_ID_REQ)
{
if (pseudonymId.Length() > 0)
{
#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
// Store the pseudonym in case we are using
// asynchronous processing (= ISA interface)
status = m_stored_pseudonym.set_copy_of_buffer(
pseudonymId.Ptr(),
pseudonymId.Length());
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
User::Leave(KErrNoMemory);
}
#endif
status = pseudonym_identity->set_copy_of_buffer(
pseudonymId.Ptr(),
pseudonymId.Length());
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
User::Leave(KErrNoMemory);
}
}
}
CleanupStack::PopAndDestroy(pseudonymIdBuf); // Delete pseudonymIdBuf
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
CleanupStack::PopAndDestroy( &view ); // Close view.
CleanupStack::PopAndDestroy(buf); // Delete buf
if (IMSI->get_is_valid_data() == false
|| IMSI->get_buffer_length() < AKA_IMSI_LENGTH)
{
status = IMSI->init(AKA_IMSI_LENGTH);
if (status != eap_status_ok)
{
User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
}
IMSI->set_is_valid();
}
{
#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
// For real AKA USIM interface.
// Use real AKA interface active object.
// This gets the IMSI from the real USIM, using Custom API.
m_aka_if->QueryIMSIL();
// KErrCompletion means that the operation is pending.
User::Leave(KErrCompletion);
#elif defined(__WINS__) // For plugin tester.
// Here we get the Nokia test SIM IMSI since the USIM interface is disabled.
u32_t imsi_length = 0u;
status = query_SIM_imsi(
IMSI->get_buffer(AKA_IMSI_LENGTH),
AKA_IMSI_LENGTH,
&imsi_length);
if (status != eap_status_ok
|| imsi_length != AKA_IMSI_LENGTH)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
User::Leave(KErrGeneral);
}
status = IMSI->set_data_length(imsi_length);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
User::Leave(KErrGeneral);
}
#endif // End of #if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
eap_status_e eap_am_type_aka_symbian_c::complete_AKA_imsi_L(
const eap_variable_data_c * const IMSI,
const eap_status_e completion_status )
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status(eap_status_process_general_error);
if (completion_status != eap_status_ok)
{
// IMSI query failed
status = get_am_partner()->complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query(
IMSI,
&m_stored_pseudonym,
&m_stored_reauth_id,
0,
EAP_TYPE_AKA_DEFAULT_MNC_LENGTH_3_BYTES,
m_stored_required_completion,
m_stored_received_eap_identifier,
completion_status);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return status;
}
if (IMSI == 0
|| IMSI->get_is_valid_data() == false)
{
// IMSI query failed
status = get_am_partner()->complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query(
IMSI,
&m_stored_pseudonym,
&m_stored_reauth_id,
0,
EAP_TYPE_AKA_DEFAULT_MNC_LENGTH_3_BYTES,
m_stored_required_completion,
m_stored_received_eap_identifier,
eap_status_hardware_not_ready);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return status;
}
if (m_previous_imsi.get_data_length() == 0)
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("Previous IMSI not valid. Storing new IMSI.\n")));
// Store new IMSI
status = store_imsi(IMSI);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
}
else if (IMSI->compare(&m_previous_imsi) != 0)
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("SIM has been changed since last authentication. ")
EAPL("Clear pseudonym & reauth IDs.\n")));
// Different IMSI -> SIM has been changed.
// Reset pseudonym and reauthentication ID.
status = store_reauthentication_id(0, 0);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
status = store_pseudonym_id(0, 0);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
// Store new IMSI
status = store_imsi(IMSI);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
// Reset stored pseudonym & reauthentication ID
m_stored_pseudonym.reset();
m_stored_reauth_id.reset();
}
else
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("SIM has not been changed.\n")));
}
status = get_am_partner()->complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query(
IMSI,
&m_stored_pseudonym,
&m_stored_reauth_id,
0,
0ul,
m_stored_required_completion,
m_stored_received_eap_identifier,
eap_status_ok);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return status;
}
//--------------------------------------------------
eap_status_e eap_am_type_aka_symbian_c::store_imsi(
const eap_variable_data_c * const imsi)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Send error if the IMSI is too long.
if(imsi != NULL && imsi->get_data_length() > KMaxIMSILengthInDB)
{
// IMSI too long. Can't store this in DB.
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::store_imsi: ")
EAPL("Too long IMSI. Length=%d\n"),
imsi->get_data_length()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
eap_status_e status(eap_status_ok);
TRAPD(err, store_imsiL(imsi));
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
send_error_notification(status);
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::store_imsiL(
const eap_variable_data_c * const imsi)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Form the insertion command
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLInsert, &KPreviousIMSI, &KAkaTableName,
&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
// Evaluate view
RDbView view;
User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
view.FirstL();
view.UpdateL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
// Create pointer to the data
if ((imsi != 0)
&& (imsi->get_is_valid_data() == true))
{
TPtrC8 tmp_imsi(
imsi->get_data(imsi->get_data_length()),
imsi->get_data_length());
EAP_TRACE_DATA_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("IMSI to DB"), tmp_imsi.Ptr(), tmp_imsi.Length()));
view.SetColL(colSet->ColNo(KPreviousIMSI), tmp_imsi);
}
else
{
// If passed IMSI was 0 that means the field must be cleared.
view.SetColNullL(colSet->ColNo(KPreviousIMSI));
}
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
view.PutL();
// Close database
CleanupStack::PopAndDestroy(2); // view, buf
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_AKA_IMSI_or_pseudonym_or_reauthentication_id_query()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
if (m_is_client == true)
{
m_aka_if->Cancel();
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_ok;
#else
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_not_supported;
#endif
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_AKA_RES(
eap_type_aka_authentication_vector_c * const authentication_vector)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// NOTE if user needs to use state_selector or n_rands after return from query_AKA_RES()
// function those parameters MUST be copied using copy() member function of each parameter.
// For example: saved_n_rands = n_rands->copy()
EAP_ASSERT(m_am_tools->get_global_mutex()->get_is_reserved() == true);
if (authentication_vector == 0
|| authentication_vector->get_is_valid() == false)
{
// Something is really wrong.
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
}
eap_status_e status = eap_status_process_general_error;
if (authentication_vector->get_RAND()->get_is_valid_data() == false)
{
// No RAND. cannot continue.
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
}
if (authentication_vector->get_AUTN()->get_is_valid_data() == false)
{
// No AUTN. cannot continue.
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
}
// Update the member variables with current values for RAND and AUTN.
// These are needed for synchronization failure.
status = m_RAND.set_copy_of_buffer( 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_AUTN.set_copy_of_buffer( authentication_vector->get_AUTN() );
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
#if !defined (USE_EAP_AKA_INTERFACE)
if (authentication_vector == 0)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
status = m_aka_algorithm->generate_RES( authentication_vector );
#elif !defined(__WINS__)
TRAPD(err, m_aka_if->QueryRESL( &m_RAND , &m_AUTN ); );
if (err != KErrNone)
{
status = m_am_tools->convert_am_error_to_eapol_error(err);
if (status == eap_status_process_general_error)
{
status = eap_status_credential_query_failed;
}
send_error_notification(status);
}
else
{
status = eap_status_pending_request;
}
#endif //#if !defined (USE_EAP_AKA_INTERFACE)
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
eap_status_e eap_am_type_aka_symbian_c::complete_AKA_RES_L(
eap_variable_data_c * const aRES,
eap_variable_data_c * const aCK,
eap_variable_data_c * const aIK,
eap_variable_data_c * const aAUTS,
eap_status_e authenticationStatus,
const eap_status_e completion_status )
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status(eap_status_ok);
#if !defined(USE_EAP_AKA_INTERFACE) || defined(__WINS__)
EAP_UNREFERENCED_PARAMETER(aRES);
EAP_UNREFERENCED_PARAMETER(aCK);
EAP_UNREFERENCED_PARAMETER(aIK);
EAP_UNREFERENCED_PARAMETER(aAUTS);
EAP_UNREFERENCED_PARAMETER(authenticationStatus);
EAP_UNREFERENCED_PARAMETER(completion_status);
#else
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("complete_AKA_RES_L\n")));
eap_type_aka_authentication_vector_c authentication_vector( m_am_tools );
if (completion_status != eap_status_ok)
{
// Signal upper layer about the failure.
status = get_am_partner()->complete_AKA_RES_query( &authentication_vector, completion_status);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
if (aRES == 0 || aRES->get_is_valid() == false ||
aCK == 0 || aCK->get_is_valid() == false ||
aIK == 0 || aIK->get_is_valid() == false ||
aAUTS == 0 || aAUTS->get_is_valid() == false )
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
status = authentication_vector.get_RES()->set_copy_of_buffer( aRES );
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_CK()->set_copy_of_buffer( aCK );
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_IK()->set_copy_of_buffer( aIK );
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_AUTS()->set_copy_of_buffer( aAUTS );
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
// Copy RAND and AUTN also. They are needed in case of synchronization failure.
status = authentication_vector.get_RAND()->set_copy_of_buffer( &m_RAND );
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_AUTN()->set_copy_of_buffer( &m_AUTN );
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
authentication_vector.set_vector_status(authenticationStatus);
// Complete request.
status = get_am_partner()->complete_AKA_RES_query( &authentication_vector, eap_status_ok);
if (status == eap_status_ok)
{
status = eap_status_completed_request;
}
#endif
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_AKA_RES_query()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
if (m_is_client == true)
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::cancel_AKA_RES_query() - cancelling IF query\n")));
m_aka_if->Cancel();
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_ok;
#else
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
#endif
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::handle_aka_notification(
eap_aka_notification_codes_e aka_notification_code)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
switch ((aka_notification_code & aka_notification_code_value))
{
case eap_aka_notification_no_F_no_P_user_has_not_subscribed_to_the_requested_service:
send_error_notification(eap_status_user_has_not_subscribed_to_the_requested_service);
break;
case eap_aka_notification_no_F_no_P_users_calls_are_barred:
send_error_notification(eap_status_users_calls_are_barred);
break;
default:
// Do nothing
break;
}
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_am_type_aka_symbian_c::query_AKA_authentication_vector(
const eap_variable_data_c * const username, ///< // This is payload AT_IDENTITY. If this is uninitialized then imsi must be initialized.
const u8_t next_eap_identifier,
eap_variable_data_c * const imsi, ///< This is the real IMSI. If this is uninitialized then username must be initialized and imsi will be initialized after this call.
eap_type_aka_authentication_vector_c * const authentication_vector,
eap_type_aka_identity_type * const type)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// NOTE if user needs to use state_selector or imsi after return from query_AKA_authentication_vector()
// function those parameters MUST be copied using copy() member function of each parameter.
// For example: saved_imsi = p_imsi_or_pseudonym->copy()
// saved_state_selector = state_selector->copy()
eap_status_e status = eap_status_process_general_error;
#if defined (USE_EAP_TYPE_SERVER_AKA)
if (username == 0
|| imsi == 0
|| authentication_vector == 0
|| type == 0)
{
// Something is really wrong.
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
if (username->get_is_valid_data() == false
&& imsi->get_is_valid_data() == false)
{
// Something is really wrong.
// Only one of these must be set.
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
if (username->get_is_valid_data() == true
&& imsi->get_is_valid_data() == false)
{
// We must query IMSI.
// This is akaple test.
query_imsi_from_username_syncronous(
0u,
0,
username,
imsi,
type);
if (imsi->get_is_valid_data() == false
|| imsi->get_data_length() != m_am_tools->strlen(TEST_IMSI)
|| m_am_tools->memcmp(imsi->get_data(imsi->get_data_length()), TEST_IMSI, imsi->get_data_length()) != 0)
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: MAC of identity differs.\n")));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
}
}
else if (imsi->get_is_valid_data() == true)
{
*type = AKA_IDENTITY_TYPE_IMSI_ID;
}
{
status = m_aka_algorithm->generate_authentication_vector(
authentication_vector);
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("query_AKA_authentication_vector(): Used EAP-Identity type %d.\n"),
*type));
m_next_eap_identifier = next_eap_identifier;
m_aka_authentication_vector_status = eap_aka_authentication_vector_status_ok;
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("AKA: %s: direct_complete_function: complete_AKA_authentication_vector_query()\n"),
(m_is_client == true ? "client": "server")));
status = get_am_partner()->complete_AKA_authentication_vector_query(
authentication_vector,
imsi,
m_aka_authentication_vector_status,
*type,
eap_status_ok,
next_eap_identifier);
if (status == eap_status_ok)
{
status = eap_status_completed_request;
}
}
#else
EAP_UNREFERENCED_PARAMETER(username);
EAP_UNREFERENCED_PARAMETER(next_eap_identifier);
EAP_UNREFERENCED_PARAMETER(imsi);
EAP_UNREFERENCED_PARAMETER(authentication_vector);
EAP_UNREFERENCED_PARAMETER(type);
#endif // #if !defined (USE_EAP_TYPE_SERVER_AKA)
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_AKA_authentication_vector_query()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
#if !defined (USE_EAP_TYPE_SERVER_AKA)
EAP_TRACE_ERROR(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("cancel_AKA_authentication_vector_query()\n")));
delete m_authentication_vector;
m_authentication_vector = 0;
#endif // #if !defined (USE_EAP_TYPE_SERVER_AKA)
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_am_type_aka_symbian_c::generate_encryption_IV(
eap_variable_data_c * const encryption_IV,
const u32_t IV_length)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
eap_status_e status = eap_status_process_general_error;
status = encryption_IV->init(IV_length);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
encryption_IV->set_is_valid();
encryption_IV->set_data_length(IV_length);
m_am_tools->get_crypto()->add_rand_seed_hw_ticks();
status = m_am_tools->get_crypto()->get_rand_bytes(
encryption_IV->get_data(encryption_IV->get_data_length()),
encryption_IV->get_data_length());
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::generate_pseudonym_id(
const eap_am_network_id_c * const send_network_id,
const eap_variable_data_c * const imsi,
eap_variable_data_c * const pseudonym_identity,
const u32_t maximum_pseudonym_length)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
#if defined (USE_EAP_TYPE_SERVER_AKA)
// From AKA simulator code.
// This is an example.
return generate_identity(
AKA_IDENTITY_TYPE_PSEUDONYM_ID,
imsi,
pseudonym_identity,
maximum_pseudonym_length);
#else
EAP_UNREFERENCED_PARAMETER(send_network_id);
EAP_UNREFERENCED_PARAMETER(imsi);
EAP_UNREFERENCED_PARAMETER(pseudonym_identity);
EAP_UNREFERENCED_PARAMETER(maximum_pseudonym_length);
// This function shouldn't be called for other than server.
return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
}
//--------------------------------------------------
#if defined (USE_EAP_TYPE_SERVER_AKA)
// These functions are used only for server side.
eap_status_e eap_am_type_aka_symbian_c::generate_identity(
const eap_type_aka_identity_type identity_type,
const eap_variable_data_c * const imsi,
eap_variable_data_c * const pseudonym,
const u32_t maximum_pseudonym_length)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// From AKA simulator code.
// This is an example.
eap_status_e status = eap_status_process_general_error;
//return eap_status_not_supported; // This will disable pseudonym and re-authentication idetities.
// Here pseydonym indentity includes encrypted IMSI.
// This causes the client to be database of it's own pseudonym identity.
// Server stores only one or more global encryption key.
// Encryption key is indexed by encryption_key_index attribute of pseudonym.
// Server could store old keys some time after a new key is changed.
//
// --------time------------>
//
// +---Key-1-------+
// +---Key-2------+
// +---Key-3------+
// +---Key-4------+
//
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);
}
eap_variable_data_c encryption_IV(m_am_tools);
{
status = generate_encryption_IV(
&encryption_IV,
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);
}
eap_variable_data_c tmp_pseudonym(m_am_tools);
status = tmp_pseudonym.set_buffer_length(sizeof(eap_aka_pseudonym_s));
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
tmp_pseudonym.set_data_length(sizeof(eap_aka_pseudonym_s));
eap_aka_pseudonym_s * const str_pseudonym
= reinterpret_cast<eap_aka_pseudonym_s * const>(tmp_pseudonym.get_data(
sizeof(eap_aka_pseudonym_s)));
m_am_tools->memset(str_pseudonym, 0, sizeof(*str_pseudonym));
str_pseudonym->imsi_block.imsi_length = static_cast<u8_t>(imsi->get_data_length());
if (identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID)
{
str_pseudonym->imsi_block.id_type = 0;
}
else if (identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID)
{
str_pseudonym->imsi_block.id_type = 1;
}
else
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
}
str_pseudonym->encryption_key_index = m_pseudonym_key_index;
m_am_tools->memmove(
str_pseudonym->encryption_IV.IV_8,
encryption_IV.get_data(aes.get_block_size()),
sizeof(str_pseudonym->encryption_IV.IV_8));
m_am_tools->memmove(
str_pseudonym->imsi_block.imsi_and_padding,
imsi->get_data(imsi->get_data_length()),
imsi->get_data_length());
u32_t imsi_data_length = sizeof(u8_t)+imsi->get_data_length();
u32_t cbc_aes_data_length = 0u;
if ((imsi_data_length % aes.get_block_size()) != 0u)
{
cbc_aes_data_length = imsi_data_length + (aes.get_block_size() - (aes.get_block_size() % imsi_data_length));
}
else
{
cbc_aes_data_length = imsi_data_length;
}
u32_t padding_bytes_length = cbc_aes_data_length - imsi_data_length;
if (padding_bytes_length > 0u)
{
cbc_aes.add_padding_bytes(
&(str_pseudonym->imsi_block.imsi_and_padding[str_pseudonym->imsi_block.imsi_length]),
padding_bytes_length,
0ul);
}
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym struct"),
reinterpret_cast<u8_t *>(str_pseudonym),
sizeof(*str_pseudonym)));
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym IV"),
encryption_IV.get_data(encryption_IV.get_data_length()),
encryption_IV.get_data_length()));
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym encryption key"),
m_pseudonym_key.get_data(m_pseudonym_key.get_data_length()),
m_pseudonym_key.get_data_length()));
status = cbc_aes.set_encryption_key(
encryption_IV.get_data(encryption_IV.get_data_length()),
encryption_IV.get_data_length(),
m_pseudonym_key.get_data(m_pseudonym_key.get_data_length()),
m_pseudonym_key.get_data_length());
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
status = cbc_aes.encrypt_data(
&(str_pseudonym->imsi_block),
sizeof(str_pseudonym->imsi_block));
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
{
crypto_sha1_c sha1(m_am_tools);
crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false);
if (hmac_sha1.get_is_valid() == false)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
}
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym MAC key"),
m_pseudonym_MAC_key.get_data(m_pseudonym_MAC_key.get_data_length()),
m_pseudonym_MAC_key.get_data_length()));
if (hmac_sha1.hmac_set_key(
&m_pseudonym_MAC_key
) != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
}
hmac_sha1.hmac_update(
reinterpret_cast<u8_t *>(str_pseudonym),
sizeof(*str_pseudonym)-sizeof(str_pseudonym->MAC));
u32_t length = EAP_TYPE_AKA_MAC_SIZE;
hmac_sha1.hmac_128_final(
str_pseudonym->MAC,
&length);
EAP_ASSERT(length == EAP_TYPE_AKA_MAC_SIZE);
}
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
tmp_pseudonym.get_data(tmp_pseudonym.get_data_length()),
tmp_pseudonym.get_data_length()));
// NOTE this does not add any security.
// This will only scramble encryption key index.
str_pseudonym->encryption_key_index ^=
(str_pseudonym->encryption_IV.IV_32[0]
+ str_pseudonym->encryption_IV.IV_32[1]
+ str_pseudonym->encryption_IV.IV_32[2]
+ str_pseudonym->encryption_IV.IV_32[3]
+ ENCRYPTION_KEY_INDEX_SCRAMBLE_CONST);
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
tmp_pseudonym.get_data(tmp_pseudonym.get_data_length()),
tmp_pseudonym.get_data_length()));
pseudonym->init(3ul+(sizeof(*str_pseudonym)+1u)*4u/3u);
pseudonym->set_is_valid();
pseudonym->set_data_length(pseudonym->get_buffer_length());
u32_t pseudonym_length = pseudonym->get_data_length();
status = m_am_tools->convert_bytes_to_ascii_armor(
tmp_pseudonym.get_data_offset(0u, tmp_pseudonym.get_data_length()),
tmp_pseudonym.get_data_length(),
pseudonym->get_data_offset(0u, pseudonym->get_data_length()),
&pseudonym_length);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
if (pseudonym_length > maximum_pseudonym_length)
{
pseudonym_length = maximum_pseudonym_length;
}
pseudonym->set_data_length(pseudonym_length);
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym"),
pseudonym->get_data(pseudonym->get_data_length()),
pseudonym->get_data_length()));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
eap_status_e eap_am_type_aka_symbian_c::query_imsi_from_username_syncronous(
const u8_t next_eap_identifier,
const eap_am_network_id_c * const network_id,
const eap_variable_data_c * const username,
eap_variable_data_c * const imsi,
eap_type_aka_identity_type * const identity_type)
{
// Note this is syncronous call.
if (network_id == 0
|| username == 0
|| imsi == 0
|| identity_type == 0)
{
// Something is really wrong.
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
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);
}
eap_status_e status = eap_status_process_general_error;
const u8_t * const username_prefix = username->get_data_offset(0u, 1u);
if (username->get_data_length() <= AKA_IMSI_LENGTH+1u
&& username->get_data_length() > 1u
&& username_prefix != 0
&& *username_prefix == *AKA_IMSI_PREFIX_CHARACTER
&& check_is_valid_imsi(username) == eap_status_ok)
{
// We have IMSI.
status = imsi->set_copy_of_buffer(
username->get_data_offset(1u, username->get_data_length()-1u),
username->get_data_length()-1u);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
*identity_type = AKA_IDENTITY_TYPE_IMSI_ID;
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("IMSI"),
imsi->get_data(imsi->get_data_length()),
imsi->get_data_length()));
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("query_imsi_from_username(): Used EAP-Identity type %d.\n"),
*identity_type));
status = eap_status_ok;
}
else if (username->get_data_length() > aes.get_block_size()
&& username->get_data_length() > sizeof(eap_aka_pseudonym_s))
{
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("username"),
username->get_data(username->get_data_length()),
username->get_data_length()));
// We have pseudonym_identity.
eap_variable_data_c tmp_imsi(m_am_tools);
tmp_imsi.set_buffer_length(sizeof(eap_aka_pseudonym_s)+1u);
tmp_imsi.set_data_length(sizeof(eap_aka_pseudonym_s)+1u);
u32_t tmp_imsi_length = tmp_imsi.get_data_length();
eap_aka_pseudonym_s * const str_pseudonym = reinterpret_cast<eap_aka_pseudonym_s * const>(tmp_imsi.get_data_offset(0u, tmp_imsi.get_data_length()));
if (str_pseudonym == 0)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
status = m_am_tools->restore_bytes_from_ascii_armor(
username->get_data_offset(0u, username->get_data_length()),
username->get_data_length(),
tmp_imsi.get_data_offset(0u, tmp_imsi.get_data_length()),
&tmp_imsi_length);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
tmp_imsi.set_data_length(tmp_imsi_length);
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
tmp_imsi.get_data(tmp_imsi.get_data_length()),
tmp_imsi.get_data_length()));
// NOTE this does not add any security.
// This will only scramble encryption key index.
str_pseudonym->encryption_key_index ^=
(str_pseudonym->encryption_IV.IV_32[0]
+ str_pseudonym->encryption_IV.IV_32[1]
+ str_pseudonym->encryption_IV.IV_32[2]
+ str_pseudonym->encryption_IV.IV_32[3]
+ ENCRYPTION_KEY_INDEX_SCRAMBLE_CONST);
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
tmp_imsi.get_data(tmp_imsi.get_data_length()),
tmp_imsi.get_data_length()));
status = eap_status_illegal_eap_identity;
if ((m_pseudonym_key_index == str_pseudonym->encryption_key_index
|| m_pseudonym_key_index-1u == str_pseudonym->encryption_key_index)
&& tmp_imsi.get_data_length() == sizeof(eap_aka_pseudonym_s))
{
const eap_variable_data_c *test_pseudonym_key = &m_pseudonym_key;
const eap_variable_data_c *test_pseudonym_MAC_key = &m_pseudonym_MAC_key;
if (m_pseudonym_key_index-1u == str_pseudonym->encryption_key_index)
{
test_pseudonym_key = &m_prev_pseudonym_key;
test_pseudonym_MAC_key = &m_prev_pseudonym_MAC_key;
}
{
crypto_sha1_c sha1(m_am_tools);
crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false);
if (hmac_sha1.get_is_valid() == false)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
}
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym MAC key"),
test_pseudonym_MAC_key->get_data(test_pseudonym_MAC_key->get_data_length()),
test_pseudonym_MAC_key->get_data_length()));
if (hmac_sha1.hmac_set_key(
test_pseudonym_MAC_key
) != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
}
hmac_sha1.hmac_update(
reinterpret_cast<u8_t *>(str_pseudonym),
sizeof(*str_pseudonym)-sizeof(str_pseudonym->MAC));
u32_t length = EAP_TYPE_AKA_MAC_SIZE;
u8_t tmp_MAC[EAP_TYPE_AKA_MAC_SIZE];
hmac_sha1.hmac_128_final(
tmp_MAC,
&length);
EAP_ASSERT(length == EAP_TYPE_AKA_MAC_SIZE);
if (m_am_tools->memcmp(tmp_MAC, str_pseudonym->MAC, EAP_TYPE_AKA_MAC_SIZE) != 0)
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: MAC of identity differs.\n")));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
}
}
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym decryption key"),
test_pseudonym_key->get_data(test_pseudonym_key->get_data_length()),
test_pseudonym_key->get_data_length()));
status = cbc_aes.set_decryption_key(
str_pseudonym->encryption_IV.IV_8,
sizeof(str_pseudonym->encryption_IV.IV_8),
test_pseudonym_key->get_data(test_pseudonym_key->get_data_length()),
test_pseudonym_key->get_data_length());
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
status = cbc_aes.decrypt_data(
&(str_pseudonym->imsi_block),
sizeof(str_pseudonym->imsi_block));
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("pseudonym struct"),
reinterpret_cast<u8_t *>(str_pseudonym),
sizeof(*str_pseudonym)));
u32_t imsi_length = static_cast<u32_t>(str_pseudonym->imsi_block.imsi_length);
if (imsi_length < 0u
|| imsi_length > AKA_IMSI_LENGTH)
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: IMSI length illegal.\n")));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
}
if (str_pseudonym->imsi_block.id_type == 0)
{
*identity_type = AKA_IDENTITY_TYPE_PSEUDONYM_ID;
}
else if (str_pseudonym->imsi_block.id_type == 1)
{
*identity_type = AKA_IDENTITY_TYPE_RE_AUTH_ID;
}
else
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
}
status = imsi->set_copy_of_buffer(
str_pseudonym->imsi_block.imsi_and_padding,
imsi_length);
EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("IMSI"),
imsi->get_data(imsi->get_data_length()),
imsi->get_data_length()));
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("query_imsi_from_username(): Used EAP-Identity type %d.\n"),
*identity_type));
if (m_pseudonym_key_use_count < MAX_PSEUDONYM_USE_COUNT+MAX_REAUTH_USE_COUNT)
{
++m_pseudonym_key_use_count;
}
else
{
{
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);
}
// Note this function generates cryptographically strong random bytes.
// Here we use those bytes as a secret encryption key.
eap_status_e status = m_prev_pseudonym_key.set_copy_of_buffer(&m_pseudonym_key);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
status = generate_encryption_IV(
&m_pseudonym_key,
aes.get_block_size());
if (status == eap_status_ok)
{
status = m_prev_pseudonym_MAC_key.set_copy_of_buffer(&m_pseudonym_MAC_key);
if (status != eap_status_ok)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
status = generate_encryption_IV(
&m_pseudonym_MAC_key,
aes.get_block_size());
if (status == eap_status_ok)
{
}
}
++m_pseudonym_key_index;
m_pseudonym_key_use_count = 0u;
}
}
}
else
{
if (m_pseudonym_key_index != str_pseudonym->encryption_key_index)
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: MAC key index differs, %lu != %lu.\n"),
m_pseudonym_key_index,
str_pseudonym->encryption_key_index));
}
else if (tmp_imsi.get_data_length() == sizeof(eap_aka_pseudonym_s))
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: pseudonym length differs, %lu != %lu.\n"),
tmp_imsi.get_data_length(),
sizeof(eap_aka_pseudonym_s)));
}
status = eap_status_illegal_eap_identity;
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
}
else
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("WARNING: illegal username.\n")));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_illegal_eap_identity;
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
//--------------------------------------------------
eap_status_e eap_am_type_aka_symbian_c::generate_reauthentication_id(
const eap_am_network_id_c * const send_network_id,
const eap_variable_data_c * const imsi,
eap_variable_data_c * const reauthentication_identity,
const u32_t maximum_reauthentication_identity_length)
{
// From AKA simulator code.
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// This is an example.
eap_status_e status = eap_status_process_general_error;
#if defined (USE_EAP_TYPE_SERVER_AKA)
status = generate_identity(
AKA_IDENTITY_TYPE_RE_AUTH_ID,
imsi,
reauthentication_identity,
maximum_reauthentication_identity_length);
if (status != eap_status_ok)
{
reauthentication_identity->reset();
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
if (m_nai_realm.get_is_valid_data() == true
&& m_nai_realm.get_data_length() > 0ul)
{
status = reauthentication_identity->add_data(reinterpret_cast<const u8_t * const>(AKA_AT_CHARACTER), 1u);
if (status != eap_status_ok)
{
reauthentication_identity->reset();
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
status = reauthentication_identity->add_data(&m_nai_realm);
if (status != eap_status_ok)
{
reauthentication_identity->reset();
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
}
#else
EAP_UNREFERENCED_PARAMETER(send_network_id);
EAP_UNREFERENCED_PARAMETER(imsi);
EAP_UNREFERENCED_PARAMETER(reauthentication_identity);
EAP_UNREFERENCED_PARAMETER(maximum_reauthentication_identity_length);
#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_imsi_from_username(
const u8_t next_eap_identifier,
const eap_am_network_id_c * const send_network_id,
const eap_variable_data_c * const username,
eap_variable_data_c * const imsi,
eap_type_aka_identity_type * const type,
const eap_type_aka_complete_e completion_action)
{
// From AKA simulator code.
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
// Note this is asyncronous call.
eap_status_e status = eap_status_process_general_error;
#if defined (USE_EAP_TYPE_SERVER_AKA)
m_identity_type = AKA_IDENTITY_TYPE_NONE;
m_next_eap_identifier = 0;
m_completion_action = eap_type_aka_complete_none;
m_username.reset();
m_IMSI.reset();
status = query_imsi_from_username_syncronous(
next_eap_identifier,
send_network_id,
username,
imsi,
type);
if (status != eap_status_ok)
{
// Do not return immediately.
// Here we test the asyncronous completion.
}
{
status = get_am_partner()->complete_imsi_from_username(
next_eap_identifier,
send_network_id,
username,
imsi,
*type,
eap_status_ok,
completion_action);
if (status == eap_status_ok)
{
status = eap_status_completed_request;
}
}
#else
EAP_UNREFERENCED_PARAMETER(next_eap_identifier);
EAP_UNREFERENCED_PARAMETER(send_network_id);
EAP_UNREFERENCED_PARAMETER(username);
EAP_UNREFERENCED_PARAMETER(imsi);
EAP_UNREFERENCED_PARAMETER(type);
EAP_UNREFERENCED_PARAMETER(completion_action);
#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_re_syncronization(
const u8_t /*next_eap_identifier*/,
eap_type_aka_authentication_vector_c * const /*authentication_vector*/
)
{
/********** For server.**********/
return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_imsi_from_username_query()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::type_configure_read(
const eap_configuration_field_c * const field,
eap_variable_data_c * const data)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_ASSERT(data != 0);
eap_status_e status(eap_status_ok);
// Trap must be set here because the OS independent portion of EAP AKA
// that calls this function does not know anything about Symbian.
TRAPD(err, type_configure_readL(
field->get_field(),
field->get_field_length(),
data));
if (err != KErrNone)
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::type_configure_read(): LEAVE from type_configure_readL, error=%d, Reads configuration from partner.\n"),
err));
status = m_partner->read_configure(
field,
data);
}
m_am_tools->trace_configuration(
status,
field,
data);
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, status);
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::type_configure_readL(
eap_config_string field,
const u32_t field_length,
eap_variable_data_c * const data)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_UNREFERENCED_PARAMETER(field_length);
// Create a buffer for the ascii strings - initialised with the argument
HBufC8* asciibuf = HBufC8::NewLC(KMaxDBFieldNameLength);
TPtr8 asciiString = asciibuf->Des();
asciiString.Copy(reinterpret_cast<const unsigned char *>(field));
// Buffer for unicode parameter
HBufC* unicodebuf = HBufC::NewLC(KMaxDBFieldNameLength);
TPtr unicodeString = unicodebuf->Des();
// Convert to unicode
unicodeString.Copy(asciiString);
// Now do the database query
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
_LIT(KSQLQueryRow, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLQueryRow, &unicodeString, &KAkaTableName,
&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
RDbView view;
User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement), TDbWindow::EUnlimited));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
if (view.FirstL())
{
eap_status_e status;
view.GetL();
switch (view.ColType(KDefaultColumnInView_One))
{
case EDbColText:
{
unicodeString = view.ColDes(KDefaultColumnInView_One);
// Convert to 8-bit
asciiString.Copy(unicodeString);
if (asciiString.Size() > 0)
{
status = data->set_copy_of_buffer(asciiString.Ptr(), asciiString.Size());
if (status != eap_status_ok)
{
User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
}
}
else
{
status = data->init(0);
if (status != eap_status_ok)
{
User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
}
data->set_is_valid();
break;
}
}
break;
case EDbColUint32:
{
TUint value;
value = view.ColUint32(KDefaultColumnInView_One);
status = data->set_copy_of_buffer(&value, sizeof(value));
if (status != eap_status_ok)
{
User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
}
}
break;
default:
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("type_configure_readL: Unexpected column type.\n")));
User::Leave(KErrGeneral);
break;
}
}
else
{
// Could not find parameter
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("type_configure_readL: Could not find configuration parameter.\n")));
User::Leave(KErrArgument);
}
CleanupStack::PopAndDestroy(4); // Close view, & 3 strings
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::type_configure_write(
const eap_configuration_field_c * const field,
eap_variable_data_c * const data)
{
// NOTE: At the moment this is not called anywhere.
// NOTE: This is really just for simulation.
// Write is routed to partner object.
eap_status_e status = m_partner->write_configure(
field,
data);
return status;
}
//--------------------------------------------------
EAP_FUNC_EXPORT void eap_am_type_aka_symbian_c::set_is_valid()
{
m_is_valid = true;
}
//--------------------------------------------------
EAP_FUNC_EXPORT bool eap_am_type_aka_symbian_c::get_is_valid()
{
return m_is_valid;
}
//--------------------------------------------------
#if defined(__WINS__)
EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_SIM_imsi(
u8_t * const imsi, const u32_t max_length, u32_t * const imsi_length)
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
if (imsi == 0 || imsi_length == 0)
{
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
// This function returns Nokia test SIM IMSI.
// It is used only when real AKA interface is not used.
*imsi_length = m_am_tools->strlen(TEST_IMSI);
if (*imsi_length > max_length)
{
// ERROR, too short buffer.
*imsi_length = 0u;
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
}
m_am_tools->memmove(imsi, TEST_IMSI, m_am_tools->strlen(TEST_IMSI));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return eap_status_ok;
}
#endif //#if defined(__WINS__)
//--------------------------------------------------
eap_status_e eap_am_type_aka_symbian_c::check_is_valid_imsi(
const eap_variable_data_c * const username)
{
if (username == 0
|| username->get_is_valid_data() == false)
{
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
}
for (u32_t ind = 0ul; ind < username->get_data_length(); ind++)
{
const u8_t * const digit = username->get_data_offset(
ind,
sizeof(u8_t));
if (digit == 0
|| *digit < '0'
|| *digit > '9')
{
return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
}
}
return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
}
//--------------------------------------------------
bool eap_am_type_aka_symbian_c::is_session_valid()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
bool sessionValidity(false);
TRAPD(err, sessionValidity = is_session_validL());
if (err != KErrNone)
{
EAP_TRACE_ERROR(m_am_tools,
TRACE_FLAGS_DEFAULT, (
EAPL("eap_am_type_aka_symbian_c::is_session_valid - LEAVE - error=%d, Assuming session is invalid \n"),
err));
sessionValidity = false;
}
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return sessionValidity;
}
//--------------------------------------------------
bool eap_am_type_aka_symbian_c::is_session_validL()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::is_session_valid - start \n")));
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
// Query all the relevant parameters
_LIT(KSQLQuery, "SELECT %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLQuery, &cf_str_EAP_AKA_max_session_validity_time_literal,
&KAKALastFullAuthTime, &KAkaTableName,
&KServiceType, m_index_type,
&KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
RDbView view;
// Evaluate view
User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement)));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
// Get the first (and only) row
view.FirstL();
view.GetL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
TInt64 maxSessionTime = view.ColInt64(colSet->ColNo(cf_str_EAP_AKA_max_session_validity_time_literal));
TInt64 fullAuthTime = view.ColInt64(colSet->ColNo(KAKALastFullAuthTime));
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
CleanupStack::PopAndDestroy(&view); // Close view.
CleanupStack::PopAndDestroy(buf); // Delete buf.
// If the max session time from DB is zero then we use the
// one read from configuration file.
if( maxSessionTime == 0)
{
EAP_TRACE_DEBUG(m_am_tools,
TRACE_FLAGS_DEFAULT, (
EAPL("Session Validity - Using max session validity time from config file\n")));
maxSessionTime = m_max_session_time; // value from configuration file.
}
// Get the current time.
TTime currentTime;
currentTime.UniversalTime();
TTime lastFullAuthTime(fullAuthTime);
#if defined(_DEBUG) || defined(DEBUG)
TDateTime currentDateTime = currentTime.DateTime();
TDateTime fullAuthDateTime = lastFullAuthTime.DateTime();
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT,
(EAPL("Session Validity - Current Time, %2d-%2d-%4d : %2d-%2d-%2d-%d\n"),
currentDateTime.Day()+1, currentDateTime.Month()+1, currentDateTime.Year(), currentDateTime.Hour(),
currentDateTime.Minute(), currentDateTime.Second(), currentDateTime.MicroSecond()));
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT,
(EAPL("Session Validity - Last Full Auth Time, %2d-%2d-%4d : %2d-%2d-%2d-%d\n"),
fullAuthDateTime.Day()+1, fullAuthDateTime.Month()+1, fullAuthDateTime.Year(), fullAuthDateTime.Hour(),
fullAuthDateTime.Minute(), fullAuthDateTime.Second(), fullAuthDateTime.MicroSecond()));
#endif
TTimeIntervalMicroSeconds interval = currentTime.MicroSecondsFrom(lastFullAuthTime);
EAP_TRACE_DATA_DEBUG( m_am_tools, TRACE_FLAGS_DEFAULT,(EAPL("eap_am_type_aka_symbian_c::is_session_valid:interval in microseconds:"),
&(interval.Int64()),
sizeof(interval.Int64()) ) );
EAP_TRACE_DATA_DEBUG( m_am_tools, TRACE_FLAGS_DEFAULT,(EAPL("eap_am_type_aka_symbian_c::is_session_valid:max session time in microseconds:"),
&(maxSessionTime),
sizeof(maxSessionTime) ) );
#if defined(_DEBUG) || defined(DEBUG)
TTimeIntervalMinutes intervalMins;
TInt error = currentTime.MinutesFrom(lastFullAuthTime, intervalMins);
if(error == KErrNone)
{
EAP_TRACE_DEBUG(
m_am_tools,
TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::is_session_validL()")
EAPL("interval in Minutes =%d\n"),
intervalMins.Int()));
}
#endif
if( maxSessionTime >= interval.Int64() )
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::is_session_valid - Session Valid \n")));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return true;
}
else
{
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::is_session_valid - Session NOT Valid \n")));
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
return false;
}
}
//--------------------------------------------------
void eap_am_type_aka_symbian_c::store_authentication_timeL()
{
EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::store_authentication_timeL - start \n")));
HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
TPtr sqlStatement = buf->Des();
// Query all the relevant parameters
_LIT(KSQLQuery, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
sqlStatement.Format(KSQLQuery, &KAKALastFullAuthTime, &KAkaTableName,
&KServiceType, m_index_type,
&KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
RDbView view;
// Evaluate view
User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement), TDbWindow::EUnlimited));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
// Get the first (and only) row for updation.
view.FirstL();
view.UpdateL();
// Get column set so we get the correct column numbers
CDbColSet* colSet = view.ColSetL();
CleanupStack::PushL(colSet);
// Get the current universal time.
TTime currentTime;
currentTime.UniversalTime();
#if defined(_DEBUG) || defined(DEBUG)
TDateTime currentDateTime = currentTime.DateTime();
EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT,
(EAPL("eap_am_type_aka_symbian_c::store_authentication_time, %2d-%2d-%4d : %2d-%2d-%2d-%d\n"),
currentDateTime.Day()+1, currentDateTime.Month()+1,currentDateTime.Year(), currentDateTime.Hour(),
currentDateTime.Minute(), currentDateTime.Second(), currentDateTime.MicroSecond()));
#endif
TInt64 fullAuthTime = currentTime.Int64();
view.SetColL(colSet->ColNo(KAKALastFullAuthTime), fullAuthTime);
view.PutL();
CleanupStack::PopAndDestroy(colSet); // Delete colSet.
CleanupStack::PopAndDestroy(&view); // Close view.
CleanupStack::PopAndDestroy(buf); // Delete buf.
EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
}
//--------------------------------------------------
// End of File