Files
m241Neelima/components/ip_net2-6.9/ipeap/src/ipeap_sim.c
T
2026-07-30 11:19:44 +05:30

2462 lines
77 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipeap_sim.c,v $ $Revision: 1.10 $
* $Source: /home/interpeak/CVSRoot/ipeap/src/ipeap_sim.c,v $
* $Author: hchowdhu $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Roger Boden <roger@interpeak.se>
******************************************************************************
*/
/*
modification history
--------------------
01a,21may10,hfc update eap as per requirement WIND00198105
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipeap_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_clib.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
#include <ipcom_sysvar.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include "ipeap.h"
#include "ipeap_h.h"
#include "ipeap_sim.h"
#include "ipeap_sim_card.h"
#include "ipeap_sim_util.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipeap_sim_string_map_st
{
const char* string;
unsigned long value;
} Ipeap_sim_string_map;
typedef struct Ipeap_sim_attr_st
{
Ip_value rand;
Ip_value padding;
Ip_value nonce_mt;
Ip_value mac;
Ip_value identity;
Ip_value version_list;
Ip_value nonce_s;
Ip_value iv;
Ip_value encr_data;
Ip_value next_pseudonym;
Ip_value next_reauth_id;
Ip_u8 id_req;
Ip_u16 counter;
Ip_u16 notification;
Ip_u16 selected_version;
Ip_u16 client_error_code;
} Ipeap_sim_attr;
typedef struct Ipeap_sim_config_st
{
Ip_value pin;
Ip_value realm;
} Ipeap_sim_config;
typedef struct Ipeap_sim_ctx_st
{
Ip_bool is_test;/* running test vector */
Ipeap_sim_config config;
Ipeap_sim_card* card;
Ipeap_sim_attr attr; /* attributes */
Ip_value sres;
Ip_value kc;
Ip_u32 kc_num;
Ip_value mk; /* master key */
Ip_value k_auth; /* authentication key */
Ip_value k_encr; /* encryption key */
Ip_value msk; /* master session key */
Ip_value emsk; /* extended master session key */
Ip_u32 mac_offset;
Ip_u32 notification_num;
} Ipeap_sim_ctx;
typedef struct Ipeap_sim_msg_st
{
Ip_u8 code;
Ip_u8 id;
Ip_u16 length;
Ip_u8 type;
Ip_u8 subtype;
Ip_u8 reserved[2];
Ip_u8 data[1];
} Ipeap_sim_msg;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipeap_sim_init
*===========================================================================
* Description: Initialize an EAP SIM EAP exchange.
* Parameters: ctx - The eap context structure.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_init(
Ipeap_ctx* ctx);
/*
*===========================================================================
* ipeap_sim_free
*===========================================================================
* Description: Free an EAP SIM EAP exchange.
* Parameters:
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_free(
Ipeap_ctx* ctx);
/*
*===========================================================================
* ipeap_sim_process_msg
*===========================================================================
* Description: Process EAP SIM messages
* Parameters: in_pkt - The incoming message
* out_pkt - Will receive the eventual outgoing message
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
* IPEAP_SUCCESS
* IPEAP_FAILURE
*/
IP_STATIC Ip_err
ipeap_sim_process_msg(
Ipeap_ctx* ctx,
Ipeap_pkt* in_pkt,
Ipeap_pkt* out_pkt);
/*
*===========================================================================
* ipeap_sim_get_key
*===========================================================================
* Description: Receive the key generated from the EAP SIM exchange.
* Parameters: ctx - The EAP context.
* key - Buffer that will receive the key value.
* key_len - Length of key buffer.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_INVALID_ARG
*/
IP_STATIC Ip_err
ipeap_sim_get_key(
Ipeap_ctx* ctx,
Ip_u8* key,
int key_len);
/*
*===========================================================================
* ipeap_sim_append_attribute
*===========================================================================
* Description: Append an attribute to the message.
* Parameters: msg - The message.
* type - Type of attribute.
* value - Attribute value.
* max_len - The maximum length of the message.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_INVALID_ARG
*/
IP_STATIC Ip_err
ipeap_sim_append_attribute(
Ipeap_sim_msg* msg,
Ip_u8 type,
Ip_value* value,
Ip_u32 max_len);
/*
*===========================================================================
* ipeap_sim_get_sim_session_id
*===========================================================================
* Description: Get the SIM Session-Id from the successful EAP SIM
* authentication.
* Parameters: ctx - The EAP context.
* session_id - Buffer that will receive the Session-Id.
* session_id_len - Length of session_id buffer.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_INVALID_ARG
*/
IP_STATIC Ip_err
ipeap_sim_get_sim_session_id(
Ipeap_ctx *ctx,
Ip_u8 *session_id,
Ip_u32 *session_id_len
);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
IP_STATIC Ipeap_methods ipeap_sim_methods =
{
ipeap_sim_process_msg,
ipeap_sim_init,
ipeap_sim_free,
ipeap_sim_get_key,
IP_NULL,
IP_NULL,
ipeap_sim_get_sim_session_id
};
/* Values used for testing */
#ifdef IPEAP_SIM_ENABLE_TEST
IP_STATIC Ip_u8 TEST_NONCE_MT[] =
{
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10
};
IP_STATIC Ip_u8 TEST_SRES[3][4] =
{
{0xd1,0xd2,0xd3,0xd4},
{0xe1,0xe2,0xe3,0xe4},
{0xf1,0xf2,0xf3,0xf4}
};
IP_STATIC Ip_u8 TEST_KC[3][8] =
{
{0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7},
{0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7},
{0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7}
};
IP_STATIC Ip_u8 TEST_IV[16] =
{
0xcd,0xf7,0xff,0xa6,0x5d,0xe0,0x4c,0x02,
0x6b,0x56,0xc8,0x6b,0x76,0xb1,0x02,0xea
};
#endif /* IPEAP_SIM_ENABLE_TEST */
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipeap_sim_attribute_type_to_string
*===========================================================================
* Description: Convert an attribute value to a string.
* Parameters: type - attribute type value.
* Returns: A string representing the attribute type.
*/
IP_STATIC const char*
ipeap_sim_attribute_type_to_string(
Ip_u8 type)
{
static const Ipeap_sim_string_map type_map[] =
{
{ "AT_RAND", IPEAP_SIM_AT_RAND },
{ "AT_PADDING", IPEAP_SIM_AT_PADDING },
{ "AT_NONCE_MT", IPEAP_SIM_AT_NONCE_MT },
{ "AT_PERMANENT_ID_REQ", IPEAP_SIM_AT_PERMANENT_ID_REQ },
{ "AT_MAC", IPEAP_SIM_AT_MAC },
{ "AT_NOTIFICATION", IPEAP_SIM_AT_NOTIFICATION },
{ "AT_NY_ID_REQ", IPEAP_SIM_AT_ANY_ID_REQ },
{ "AT_IDENTITY", IPEAP_SIM_AT_IDENTITY },
{ "AT_VERSION_LIST", IPEAP_SIM_AT_VERSION_LIST },
{ "AT_SELECTED_VERSION", IPEAP_SIM_AT_SELECTED_VERSION },
{ "AT_FULLAUTH_ID_REQ", IPEAP_SIM_AT_FULLAUTH_ID_REQ },
{ "AT_COUNTER", IPEAP_SIM_AT_COUNTER },
{ "AT_COUNTER_TOO_SMALL", IPEAP_SIM_AT_COUNTER_TOO_SMALL },
{ "AT_NONCE_S", IPEAP_SIM_AT_NONCE_S },
{ "AT_CLIENT_ERROR_CODE", IPEAP_SIM_AT_CLIENT_ERROR_CODE },
{ "AT_IV", IPEAP_SIM_AT_IV },
{ "AT_ENCR_DATA", IPEAP_SIM_AT_ENCR_DATA },
{ "AT_NEXT_PSEUDONYM", IPEAP_SIM_AT_NEXT_PSEUDONYM },
{ "AT_NEXT_REAUTH_ID", IPEAP_SIM_AT_NEXT_REAUTH_ID },
{ "AT_RESULT_IND", IPEAP_SIM_AT_RESULT_IND },
{ IP_NULL, 0 }
};
Ip_u16 i = 0;
while (IP_NULL != type_map[i].string)
if (type_map[i].value == type)
return type_map[i].string;
else
i++;
return "UNKNOWN";
}
/*
*===========================================================================
* ipeap_sim_check_attributes
*===========================================================================
* Description: Error checking on the attributes received in the last message
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context
* attr - The EAP SIM attributes
* encr - The attributes was received in encrypted form.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_check_attributes(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ip_bool encr)
{
Ip_err err = IPCOM_ERR_FAILED;
(void)sim_ctx;
(void)encr;
(void)ctx;
if ((attr->nonce_mt.n > 0) && ((attr->nonce_mt.n % IPEAP_SIM_NONCE_MT_LEN) != 0))
{
IPCOM_LOG0(ERR, "ipeap_sim_check_attributes - Bad nonce_mt attribute");
}
else if ((attr->nonce_s.n > 0) && ((attr->nonce_s.n % IPEAP_SIM_NONCE_S_LEN) != 0))
{
IPCOM_LOG0(ERR, "ipeap_sim_check_attributes - Bad nonce_s attribute");
}
else if ((attr->rand.n > 0) && ((attr->rand.n % IPEAP_SIM_RAND_LEN) != 0))
{
IPCOM_LOG0(ERR, "ipeap_sim_check_attributes - Bad rand attribute");
}
else if ((attr->mac.n > 0) && ((attr->mac.n % IPEAP_SIM_MAC_LEN) != 0))
{
IPCOM_LOG0(ERR, "ipeap_sim_check_attributes - Bad mac attribute");
}
else if ((attr->iv.n > 0) && ((attr->iv.n % IPEAP_SIM_MAC_LEN) != 0))
{
IPCOM_LOG0(ERR, "ipeap_sim_check_attributes - Bad iv attribute");
}
else
{
err = IPCOM_SUCCESS;
}
return err;
}
/*
*===========================================================================
* ipeap_sim_parse_attributes_data
*===========================================================================
* Description: Parse and validate the attribute data and add the values to
* attribute context.
* Parameters: ctx - The EAP context.
* data - The attribute data buffer.
* data_len - Length of attribute data buffer.
* encr - TRUE if attribute data was received encrypted.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_parse_attributes_data(
Ipeap_ctx* ctx,
Ip_u8* data,
Ip_u32 data_len,
Ip_bool encr)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_ctx* sim_ctx = IP_NULL;
Ipeap_sim_attr* attr = IP_NULL;
Ip_u8* end = IP_NULL;
Ip_u8* pos = IP_NULL;
Ip_u8* att = IP_NULL;
Ip_u32 att_len = 0;
Ip_u32 len = 0;
/* lint */
(void)err;
(void)ipeap_sim_attribute_type_to_string;
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
attr = &sim_ctx->attr;
pos = data;
end = data + data_len;
while (pos < end)
{
if (pos + 2 > end)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad attribute data");
return IPCOM_ERR_FAILED;
}
IPCOM_LOG2(DEBUG2, "ipeap_sim_parse_attributes - Attribute %s (%d bytes)",
ipeap_sim_attribute_type_to_string(pos[0]), pos[1]*4);
if ((pos + (pos[1] * 4)) > end)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad attribute data value");
return IPCOM_ERR_FAILED;
}
att = pos + 2;
att_len = (Ip_u32)(pos[1] * 4) - 2;
IPCOM_LOG0(DEBUG2, "ipeap_sim_parse_attributes - Attribute value:");
if (att_len > 32)
ipeap_print_memory("\n", att, att_len);
else
ipeap_print_memory(" ", att, att_len);
if (att_len < 2)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad data");
return IPCOM_ERR_FAILED;
}
switch (pos[0])
{
case IPEAP_SIM_AT_RAND:
err = ip_set_value(&attr->rand, att+2, att_len-2);
break;
case IPEAP_SIM_AT_PADDING:
err = ip_set_value(&attr->padding, att+2, att_len-2);
break;
case IPEAP_SIM_AT_NONCE_MT:
err = ip_set_value(&attr->nonce_mt, att+2, att_len-2);
break;
case IPEAP_SIM_AT_PERMANENT_ID_REQ:
attr->id_req = IPEAP_SIM_AT_PERMANENT_ID_REQ;
break;
case IPEAP_SIM_AT_MAC:
err = ip_set_value(&attr->mac, att+2, att_len-2);
/* Set message mac to zero, so we can verify later */
ipcom_memset(att+2, 0, att_len-2);
break;
case IPEAP_SIM_AT_NOTIFICATION:
if (att_len != 2)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad notification data");
return IPCOM_ERR_FAILED;
}
attr->notification = (Ip_u16)((256 * att[0]) + att[1]);
break;
case IPEAP_SIM_AT_ANY_ID_REQ:
attr->id_req = IPEAP_SIM_AT_ANY_ID_REQ;
break;
case IPEAP_SIM_AT_IDENTITY:
err = ip_set_value(&attr->identity, att+2, att_len-2);
break;
case IPEAP_SIM_AT_VERSION_LIST:
len = (Ip_u32)(att[0] * 256 + att[1]);
if ((len < 2) ||
(len > (att_len - 2)))
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad version list");
return IPCOM_ERR_FAILED;
}
err = ip_set_value(&attr->version_list, att+2, len);
break;
case IPEAP_SIM_AT_SELECTED_VERSION:
if (att_len != 2)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad selected version data");
return IPCOM_ERR_FAILED;
}
attr->selected_version = (Ip_u16)(att[0] * 256 + att[1]);
break;
case IPEAP_SIM_AT_FULLAUTH_ID_REQ:
attr->id_req = IPEAP_SIM_AT_FULLAUTH_ID_REQ;
break;
case IPEAP_SIM_AT_COUNTER:
if (att_len != 2)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad counter data");
return IPCOM_ERR_FAILED;
}
attr->counter = (Ip_u16)(att[0] * 256 + att[1]);
break;
case IPEAP_SIM_AT_NONCE_S:
err = ip_set_value(&attr->nonce_s, att+2, att_len-2);
break;
case IPEAP_SIM_AT_CLIENT_ERROR_CODE:
if (att_len != 2)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad client error code data");
return IPCOM_ERR_FAILED;
}
attr->client_error_code = (Ip_u16)(att[0] * 256 + att[1]);
break;
case IPEAP_SIM_AT_IV:
err = ip_set_value(&attr->iv, att+2, att_len-2);
break;
case IPEAP_SIM_AT_ENCR_DATA:
if ((att_len - 2) % 16)
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad encr data");
return IPCOM_ERR_FAILED;
}
err = ip_set_value(&attr->encr_data, att+2, att_len-2);
break;
case IPEAP_SIM_AT_NEXT_PSEUDONYM:
len = ((att[0] * 256) + att[1]);
if (len > (att_len - 2))
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad next pseudonym data");
return IPCOM_ERR_FAILED;
}
err = ip_set_value(&attr->next_pseudonym, att+2, len);
break;
case IPEAP_SIM_AT_NEXT_REAUTH_ID:
len = (att[0] * 256) + att[1];
if (len > (att_len - 2))
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_attributes - bad next reauth_id data");
return IPCOM_ERR_FAILED;
}
err = ip_set_value(&attr->next_reauth_id, att+2, len);
break;
default:
if (pos[0] < 128)
{
IPCOM_LOG1(ERR, "ipeap_sim_parse_attributes - unrecognized non-skippable attribute (%d)", pos[0]);
return IPCOM_ERR_FAILED;
}
IPCOM_LOG1(INFO, "ipeap_sim_parse_attributes - unrecognized skippable attribute (%d)", pos[0]);
break;
}
pos += pos[1] * 4;
}
return ipeap_sim_check_attributes(ctx, sim_ctx, attr, encr);
}
/*
*===========================================================================
* ipeap_sim_parse_attributes
*===========================================================================
* Description: Parse and validate the attribute data in the received message
* and add the values to attribute context.
* Parameters: ctx - The EAP context.
* msg - The received message.
* encr - TRUE if attribute data was received encrypted.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_parse_attributes(
Ipeap_ctx* ctx,
Ipeap_sim_msg* msg,
Ip_bool encr)
{
Ip_u8* data = IP_NULL;
Ip_u32 data_len = 0;
data = msg->data;
data_len = (Ip_u32)ip_htons(msg->length) - IPEAP_SIM_HEADER_LEN;
return ipeap_sim_parse_attributes_data(ctx, data, data_len, encr);
}
/*
*===========================================================================
* ipeap_sim_parse_encrypted_attributes
*===========================================================================
* Description: Decrypt/parse and validate the encrypted attribute from the
* received message and add the values to attribute context.
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute context.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_parse_encrypted_attributes(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr)
{
/* Decrypt the data */
if (IPCOM_SUCCESS != ipeap_sim_aes_cbc_decrypt(
sim_ctx->k_encr.p,
sim_ctx->k_encr.n,
attr->iv.p,
attr->iv.n,
attr->encr_data.p,
attr->encr_data.n))
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_encrypted_attributes - failed to decrypt");
return IPCOM_ERR_FAILED;
}
if (IPCOM_SUCCESS != ipeap_sim_parse_attributes_data(
ctx,
attr->encr_data.p,
attr->encr_data.n,
IP_TRUE))
{
IPCOM_LOG0(ERR, "ipeap_sim_parse_encrypted_attributes - failed to parse");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_encrypt_attributes
*===========================================================================
* Description: Encrypt the attributes and add as encrypted data attribute.
* Parameters: sim_ctx - The EAP SIM context.
* attr - The attribute context.
* msg - The output message
* data_len - Tells how many bytes from the end of msg buffer
* that should be encrypted.
* max_len - The maximum length of message buffer.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_encrypt_attributes(
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ipeap_sim_msg* msg,
Ip_u32 data_len,
Ip_u32 max_len)
{
Ip_err err = IPCOM_SUCCESS;
Ip_u32 pad_len = 0;
Ip_value tmp = {0};
Ip_value iv = {0};
(void)attr;
/* We must have multiple of 16 bytes, so add padding attribute (zeros as
* value) if needed. */
pad_len = 16 - (data_len % 16);
if ((IPCOM_SUCCESS != (err = ip_alloc_value(&tmp, data_len+pad_len))) ||
(IPCOM_SUCCESS != (err = ip_alloc_value(&iv, 16))))
goto cleanup;
/* data_len tells how many bytes from the end of msg buffer that should
* be encrypted */
ipcom_memcpy(tmp.p, msg->data + msg->length - data_len, data_len);
tmp.n = data_len + pad_len;
if (pad_len > 0)
{
tmp.p[data_len] = IPEAP_SIM_AT_PADDING;
tmp.p[data_len+1] = (Ip_u8)(pad_len/4);
}
/* Remove unencrypted attibutes from msg */
msg->length -= (Ip_u16)data_len;
/* Generate iv */
(void)RAND_bytes(iv.p, (int)iv.n);
#ifdef IPEAP_SIM_ENABLE_TEST
if (sim_ctx->is_test)
ipcom_memcpy(iv.p, TEST_IV, iv.n);
#endif
/* Append iv attribute to msg */
err = ipeap_sim_append_attribute(msg, IPEAP_SIM_AT_IV, &iv, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Encrypt the data */
if (IPCOM_SUCCESS != (err = ipeap_sim_aes_cbc_encrypt(
sim_ctx->k_encr.p,
sim_ctx->k_encr.n,
iv.p,
iv.n,
tmp.p,
tmp.n)))
{
IPCOM_LOG0(ERR, "ipeap_sim_encrypt_attributes - failed to encrypt");
goto cleanup;
}
/* Append encrypted data attribute to msg */
err = ipeap_sim_append_attribute(msg, IPEAP_SIM_AT_ENCR_DATA, &tmp, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
cleanup:
ip_free_value(&tmp);
ip_free_value(&iv);
return err;
}
/*
*===========================================================================
* ipeap_sim_generate_auth
*===========================================================================
* Description: Generate authentication data with the smart card.
* Parameters: sim_ctx - The EAP SIM context.
* attr - The attribute context.
* kc - The kc authentication data buffer (8 bytes * X)
* kc_num - The number of generated authentication data.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_generate_auth(
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ip_value* kc,
Ip_u32* kc_num)
{
Ip_u32 i = 0;
Ip_u8* p = IP_NULL;
Ip_u32 n = 0;
/* We already have the values if running as test */
if (!sim_ctx->is_test)
{
/* We need as many challenges as rand blocks */
*kc_num = attr->rand.n / IPEAP_SIM_RAND_LEN;
if (ip_alloc_value(&sim_ctx->sres, 4*(*kc_num)) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
if (ip_alloc_value(&sim_ctx->kc, 8*(*kc_num)) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
for (i=0; i<(*kc_num); i++)
if (ipeap_sim_card_gsm_auth(sim_ctx->card,
attr->rand.p + 16*i,
sim_ctx->sres.p + 4*i,
sim_ctx->kc.p + 8*i) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
}
/* Trace auth value */
n = kc->n/(*kc_num);
for (i=0; i<(*kc_num); i++)
{
p = kc->p + i*n;
IPCOM_LOG1(DEBUG2, "ipeap_sim_generate_auth - Value %d:", i+1);
ipeap_print_memory(" ", p, n);
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_generate_mk
*===========================================================================
* Description: Generate the mk (Master Key).
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute context.
* mk - Will receive the mk value.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_generate_mk(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ip_value* mk)
{
SHA_CTX md_ctx = {0};
Ip_u8 ver[2] = {0};
if (ip_alloc_value(mk, 20) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
ver[0] = (Ip_u8)(attr->selected_version >> 8);
ver[1] = (Ip_u8)(attr->selected_version);
(void)SHA1_Init(&md_ctx);
(void)SHA1_Update(&md_ctx, (Ip_u8*)ctx->identity, ipcom_strlen(ctx->identity));
(void)SHA1_Update(&md_ctx, sim_ctx->kc.p, sim_ctx->kc.n);
(void)SHA1_Update(&md_ctx, attr->nonce_mt.p, attr->nonce_mt.n);
(void)SHA1_Update(&md_ctx, attr->version_list.p, attr->version_list.n);
(void)SHA1_Update(&md_ctx, ver, 2);
(void)SHA1_Final(mk->p, &md_ctx);
IPCOM_LOG0(DEBUG2, "ipeap_sim_generate_mk - Master key (mk):");
ipeap_print_memory(" ", mk->p, mk->n);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_generate_keys
*===========================================================================
* Description: Generate the encryption/authentication keys, msk (Master
* Secret Key) and emsk (Extended Master Secret Key) from the
* mk (Matser Key).
* Parameters: mk - The master key.
* k_encr - Will receive the encryption key value.
* k_auth - Will receive the authentication key value.
* msk - Will receive the master secret key value.
* emsk - Will receive the extended master secret key value.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_generate_keys(
Ip_value* mk,
Ip_value* k_encr,
Ip_value* k_auth,
Ip_value* msk,
Ip_value* emsk)
{
Ip_u8* p = IP_NULL;
Ip_u32 n = 0;
if ((IPCOM_SUCCESS != ip_alloc_value(k_encr, IPEAP_SIM_K_ENCR_LEN)) ||
(IPCOM_SUCCESS != ip_alloc_value(k_auth, IPEAP_SIM_K_AUTH_LEN)) ||
(IPCOM_SUCCESS != ip_alloc_value(msk, IPEAP_SIM_MSK_LEN)) ||
(IPCOM_SUCCESS != ip_alloc_value(emsk, IPEAP_SIM_MSK_LEN)))
return IPCOM_ERR_FAILED;
n = k_auth->n;
n += k_encr->n;
n += msk->n;
n += emsk->n;
p = ipcom_calloc(1, n);
if (IP_NULL == p)
return IPCOM_ERR_FAILED;
if (IPCOM_SUCCESS != ipeap_sim_prf(mk->p, mk->n, p, n))
{
ipcom_free(p);
return IPCOM_ERR_FAILED;
}
n = 0;
ipcom_memcpy(k_encr->p, p+n, k_encr->n);
n += k_encr->n;
ipcom_memcpy(k_auth->p, p+n, k_auth->n);
n += k_auth->n;
ipcom_memcpy(msk->p, p+n, msk->n);
n += msk->n;
ipcom_memcpy(emsk->p, p+n, emsk->n);
n += emsk->n;
IPCOM_LOG0(DEBUG2, "ipeap_sim_generate_keys - k_encr:");
ipeap_print_memory(" ", k_encr->p, k_encr->n);
IPCOM_LOG0(DEBUG2, "ipeap_sim_generate_keys - k_auth:");
ipeap_print_memory(" ", k_auth->p, k_auth->n);
ipeap_print_memory("ipeap_sim_generate_keys - msk:\n", msk->p, msk->n);
ipeap_print_memory("ipeap_sim_generate_keys - emsk:\n", emsk->p, emsk->n);
ipcom_free(p);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_generate_new_keys
*===========================================================================
* Description: Generate new msk and emsk key values after reauthentication.
* Parameters: identity - The identity value.
* counter - The reauthentication counter.
* nonce_s - The nonce_s value.
* mk - The master key value.
* msk - Will receive the new master secret key value.
* emsk - Will receive the new extended master secret key value.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_generate_new_keys(
char* identity,
Ip_u16 counter,
Ip_value* nonce_s,
Ip_value* mk,
Ip_value* msk,
Ip_value* emsk)
{
Ip_err err = IPCOM_SUCCESS;
SHA_CTX md_ctx = {0};
Ip_u8 count[2] = {0};
Ip_u32 xkey_len = 0;
Ip_u8* xkey = IP_NULL;
Ip_u32 tmp_len = 0;
Ip_u8* tmp = IP_NULL;
xkey_len = 20;
xkey = ipcom_malloc(xkey_len);
tmp_len = msk->n + emsk->n;
/* in 40 byte blocks */
tmp_len = ((tmp_len + 2*xkey_len-1)/(2*xkey_len))*(2*xkey_len);
tmp = ipcom_malloc(tmp_len);
if ((IP_NULL == xkey) || (IP_NULL == tmp))
{
err = IPCOM_ERR_NO_MEMORY;
goto cleanup;
}
count[0] = (Ip_u8)(counter >> 8);
count[1] = (Ip_u8)(counter);
(void)SHA1_Init(&md_ctx);
(void)SHA1_Update(&md_ctx, identity, ipcom_strlen(identity));
(void)SHA1_Update(&md_ctx, count, 2);
(void)SHA1_Update(&md_ctx, nonce_s->p, nonce_s->n);
(void)SHA1_Update(&md_ctx, mk->p, mk->n);
(void)SHA1_Final(xkey, &md_ctx);
IPCOM_LOG0(DEBUG2, "ipeap_sim_generate_new_keys - xkey':");
ipeap_print_memory(" ", xkey, xkey_len);
if (IPCOM_SUCCESS != (err = ipeap_sim_prf(xkey, xkey_len, tmp, tmp_len)))
goto cleanup;
ipcom_memcpy(msk->p, tmp, msk->n);
ipcom_memcpy(emsk->p, tmp+msk->n, emsk->n);
cleanup:
ipcom_free(xkey);
ipcom_free(tmp);
return err;
}
#ifdef IPEAP_SIM_ENABLE_TEST
/*
*===========================================================================
* ipeap_sim_enable_test
*===========================================================================
* Description: Enable test vector values. Will set static values instead of
* random, so test vectors may be verified.
* Parameters:
* Returns:
*/
IP_STATIC void
ipeap_sim_enable_test(
Ipeap_sim_ctx* sim_ctx)
{
Ip_u32 i = 0;
IPCOM_LOG0(INFO, "IPEAP-SIM :: Test mode enabled");
sim_ctx->is_test = IP_TRUE;
/* Set static nonce_mt attribute */
(void)ip_set_value(&sim_ctx->attr.nonce_mt, TEST_NONCE_MT, sizeof(TEST_NONCE_MT));
/* Set static kc and sres values */
sim_ctx->kc_num = 3;
if ((ip_alloc_value(&sim_ctx->kc, 3*8) == IPCOM_SUCCESS) &&
(ip_alloc_value(&sim_ctx->sres, 3*4) == IPCOM_SUCCESS))
{
for (i = 0; i < 3; i++)
{
ipcom_memcpy(sim_ctx->kc.p+i*8, TEST_KC[i], 8);
ipcom_memcpy(sim_ctx->sres.p+i*4, TEST_SRES[i], 4);
}
}
return;
}
#endif /* IPEAP_SIM_ENABLE_TEST */
/*
*===========================================================================
* ipeap_sim_load_config
*===========================================================================
* Description: Load configuration from system variables.
* Parameters:
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_load_config(
Ipeap_sim_ctx* sim_ctx)
{
char buf[100] = {0};
char* p = IP_NULL;
Ip_size_t n = 0;
#ifdef IPEAP_SIM_ENABLE_TEST
n = sizeof(buf);
p = ipcom_sysvar_get("ipeap.sim.test", buf, &n);
if (IP_NULL != p)
if ('1' == *p)
sim_ctx->is_test = IP_TRUE;
#endif
n = sizeof(buf);
p = ipcom_sysvar_get("ipeap.sim.pin", buf, &n);
if (IP_NULL != p)
if (ip_set_value(&sim_ctx->config.pin, (Ip_u8*)p, (Ip_u32)n) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
n = sizeof(buf);
p = ipcom_sysvar_get("ipeap.sim.realm", buf, &n);
if (IP_NULL != p)
if (ip_set_value(&sim_ctx->config.realm, (Ip_u8*)p, (Ip_u32)n) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_generate_permanent_id
*===========================================================================
* Description: Generate permanent id value. Will read imsi number from smart
* card and also add an eventual realm.
* Parameters: sim_ctx - The EAP SIM context.
* id - The id buffer that will receive the 0 terminated value.
* id_len - Length of id buffer.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_generate_permanent_id(
Ipeap_sim_ctx* sim_ctx,
char* id,
Ip_u32 id_len)
{
Ip_err err = IPCOM_SUCCESS;
if (sim_ctx->is_test)
{
/* This is handled outside for test */
if (id[0] == 0)
(void)ipcom_sysvar_get("ipeap.identity", id, (Ip_size_t*)&id_len);
}
else
{
/* Id format: "1|<imsi>[@realm]" */
ipcom_strcpy(id, "1");
err = ipeap_sim_card_get_imsi(sim_ctx->card,
id+1,
id_len - sim_ctx->config.realm.n - 2);
if (IPCOM_SUCCESS != err)
return err;
if (sim_ctx->config.realm.n > 0)
{
if (sim_ctx->config.realm.p[0] != '@')
ipcom_strcat(id, "@");
id_len = (Ip_u32)ipcom_strlen(id);
ipcom_memcpy(id+id_len, sim_ctx->config.realm.p, sim_ctx->config.realm.n);
id[id_len+sim_ctx->config.realm.n] = 0;
}
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_init
*===========================================================================
* Description: Initialize EAP SIM context.
* Parameters: ctx - The EAP SIM context.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_init(
Ipeap_ctx* ctx)
{
Ip_err err = IPCOM_ERR_FAILED;
Ipeap_sim_ctx* sim_ctx = IP_NULL;
sim_ctx = ipcom_calloc(1, sizeof(*sim_ctx));
if (IP_NULL == sim_ctx)
goto cleanup;
ctx->mech_data = sim_ctx;
ctx->state = IPEAP_STATE_INIT;
err = ipeap_sim_load_config(sim_ctx);
if (IPCOM_SUCCESS != err)
goto cleanup;
err = ip_alloc_value(&sim_ctx->attr.nonce_mt, IPEAP_SIM_NONCE_MT_LEN);
if (IPCOM_SUCCESS != err)
goto cleanup;
(void)RAND_bytes(sim_ctx->attr.nonce_mt.p, (int)sim_ctx->attr.nonce_mt.n);
#ifdef IPEAP_SIM_ENABLE_TEST
if (sim_ctx->is_test)
{
/* Will set static values instead of random, and we will not need
* any smart card. */
ipeap_sim_enable_test(sim_ctx);
}
else
#endif
{
sim_ctx->card = ipeap_sim_card_initialize(IPEAP_SIM_CARD_GSM,
sim_ctx->config.pin.p,
sim_ctx->config.pin.n);
if (IP_NULL == sim_ctx->card)
{
err = IPCOM_ERR_FAILED;
goto cleanup;
}
}
err = ipeap_sim_generate_permanent_id(sim_ctx,
ctx->identity,
sizeof(ctx->identity));
if (IPCOM_SUCCESS != err)
goto cleanup;
cleanup:
if (IPCOM_SUCCESS != err)
{
(void)ipeap_sim_free(ctx);
err = IPCOM_ERR_FAILED;
}
else
{
err = IPCOM_SUCCESS;
}
return err;
}
/*
*===========================================================================
* ipeap_sim_free_config
*===========================================================================
* Description: Free config values.
* Parameters: config - The config structure.
* Returns:
*/
IP_STATIC void
ipeap_sim_free_config(
Ipeap_sim_config* config)
{
ip_free_value(&config->pin);
ip_free_value(&config->realm);
return;
}
/*
*===========================================================================
* ipeap_sim_free_attributes
*===========================================================================
* Description: Free attribute values.
* Parameters: attr - The attribute structure.
* Returns:
*/
IP_STATIC void
ipeap_sim_free_attributes(
Ipeap_sim_attr* attr)
{
if (IP_NULL != attr)
{
ip_free_value(&attr->rand);
ip_free_value(&attr->padding);
ip_free_value(&attr->nonce_mt);
ip_free_value(&attr->mac);
ip_free_value(&attr->identity);
ip_free_value(&attr->version_list);
ip_free_value(&attr->nonce_s);
ip_free_value(&attr->iv);
ip_free_value(&attr->encr_data);
ip_free_value(&attr->next_pseudonym);
ip_free_value(&attr->next_reauth_id);
}
return;
}
/*
*===========================================================================
* ipeap_sim_free
*===========================================================================
* Description: Free EAP SIM context.
* Parameters: ctx - The EAP context.
* Returns: IPCOM_SUCCESS
*/
IP_STATIC Ip_err
ipeap_sim_free(
Ipeap_ctx* ctx)
{
Ipeap_sim_ctx* sim_ctx = IP_NULL;
if (IP_NULL != ctx)
{
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
if (IP_NULL != sim_ctx)
{
ipeap_sim_free_config(&sim_ctx->config);
ipeap_sim_free_attributes(&sim_ctx->attr);
ipeap_sim_card_finalize(sim_ctx->card);
ip_free_value(&sim_ctx->sres);
ip_free_value(&sim_ctx->kc);
ip_free_value(&sim_ctx->mk);
ip_free_value(&sim_ctx->k_auth);
ip_free_value(&sim_ctx->k_encr);
ip_free_value(&sim_ctx->msk);
ip_free_value(&sim_ctx->emsk);
ipcom_free(sim_ctx);
ctx->mech_data = IP_NULL;
}
ctx->cb = IP_NULL;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_append_attribute
*===========================================================================
* Description: Append an attribute to the message.
* Parameters: msg - The message structure.
* type - Type of attribute.
* value - The attribute value.
* max_len - The maximum message length.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_append_attribute(
Ipeap_sim_msg* msg,
Ip_u8 type,
Ip_value* value,
Ip_u32 max_len)
{
Ip_err err = IPCOM_SUCCESS;
Ip_u16 len = 0;
/* Length in 4 byte blocks, first block for header. */
len = (Ip_u16)(((value->n + 3) / 4) + 1);
if (max_len < (Ip_u32)(msg->length + (len * 4)))
{
IPCOM_LOG0(ERR, "ipeap_sim_append_attribute - Packet buffer too small");
err = IPCOM_ERR_FAILED;
}
else
{
msg->data[msg->length] = type;
msg->data[msg->length+1] = (Ip_u8)len;
if ((type == IPEAP_SIM_AT_IDENTITY) ||
(type == IPEAP_SIM_AT_NEXT_PSEUDONYM) ||
(type == IPEAP_SIM_AT_NEXT_REAUTH_ID))
{
msg->data[msg->length+2] = (Ip_u8)(value->n >> 8);
msg->data[msg->length+3] = (Ip_u8)(value->n & 0xff);
}
else
{
msg->data[msg->length+2] = 0;
msg->data[msg->length+3] = 0;
}
ipcom_memcpy(&msg->data[msg->length+4], value->p, value->n);
ipcom_memset(&msg->data[msg->length+4 + (int)value->n], 0, len*4 - 4 - value->n );
msg->length += len*4; /*lint !e734*/
}
return err;
}
/*
*===========================================================================
* ipeap_sim_append_attribute2
*===========================================================================
* Description: Append an attribute to the message.
* Parameters: msg - The message structure.
* type - Type of attribute.
* value - The attribute value.
* max_len - The maximum message length.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_append_attribute2(
Ipeap_sim_msg* msg,
Ip_u8 type,
Ip_u16 value,
Ip_u32 max_len)
{
Ip_err err = IPCOM_SUCCESS;
/* Will be one single block of 4 bytes. */
if (max_len < (Ip_u32)(msg->length + 4))
{
IPCOM_LOG0(ERR, "ipeap_sim_append_attribute - Packet buffer too small");
err = IPCOM_ERR_FAILED;
}
else
{
msg->data[msg->length] = type;
msg->data[msg->length+1] = 1;
msg->data[msg->length+2] = (Ip_u8)(value >> 8);
msg->data[msg->length+3] = (Ip_u8)(value);
msg->length += 4;
}
return err;
}
/*
*===========================================================================
* ipeap_sim_append_attribute_identity
*===========================================================================
* Description: Append an identity attribute to the message.
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute structure.
* msg - The message structure.
* max_len - The maximum message length.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_append_attribute_identity(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ipeap_sim_msg* msg,
Ip_u32 max_len)
{
Ip_err err = IPCOM_SUCCESS;
Ip_value id = {0};
if ((attr->id_req == IPEAP_SIM_AT_ANY_ID_REQ) &&
(attr->next_reauth_id.n > 0) &&
(attr->next_reauth_id.n < sizeof(ctx->identity)))
{
id.p = attr->next_reauth_id.p;
id.n = attr->next_reauth_id.n;
}
else if ((attr->id_req == IPEAP_SIM_AT_ANY_ID_REQ) &&
(attr->next_pseudonym.n > 0) &&
(attr->next_pseudonym.n < sizeof(ctx->identity)))
{
id.p = attr->next_pseudonym.p;
id.n = attr->next_pseudonym.n;
}
else if ((attr->id_req == IPEAP_SIM_AT_PERMANENT_ID_REQ) ||
(attr->id_req == IPEAP_SIM_AT_ANY_ID_REQ))
{
id.p = (Ip_u8*)ctx->identity;
id.n = sizeof(ctx->identity);
err = ipeap_sim_generate_permanent_id(sim_ctx, (char*)id.p, id.n);
if (IPCOM_SUCCESS != err)
return err;
id.n = (Ip_u32)ipcom_strlen((char*)id.p);
}
if (id.n > 0)
err = ipeap_sim_append_attribute(msg, IPEAP_SIM_AT_IDENTITY, &id, max_len);
return err;
}
/*
*===========================================================================
* ipeap_sim_append_attribute_mac
*===========================================================================
* Description: Append an mac attribute to the message.
* Parameters: sim_ctx - The EAP SIM context.
* msg - The message structure.
* max_len - The maximum message length.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_FAILED
*/
IP_STATIC Ip_err
ipeap_sim_append_attribute_mac(
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_msg* msg,
Ip_u32 max_len)
{
Ip_err err = IPCOM_SUCCESS;
Ip_value mac = {0};
/* Append mac with correct size and zeros as value. The mac value will
* be calculated later (ipeap_sim_finish_response) over the complete
* message. */
err = ip_alloc_value(&mac, IPEAP_SIM_MAC_LEN);
if (IPCOM_SUCCESS != err)
goto cleanup;
ipcom_memset(mac.p, 0, mac.n);
err = ipeap_sim_append_attribute(msg, IPEAP_SIM_AT_MAC, &mac, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
sim_ctx->mac_offset = (Ip_u32) (msg->length + IPEAP_SIM_HEADER_LEN - IPEAP_SIM_MAC_LEN) ;
cleanup:
ip_free_value(&mac);
return err;
}
/*
*===========================================================================
* ipeap_sim_report_notification
*===========================================================================
* Description: Report a notification received in a message.
* Parameters: notification - The notification code.
* Returns:
*/
IP_STATIC void
ipeap_sim_report_notification(Ip_u16 notification)
{
switch (notification)
{
case IPEAP_SIM_FAILURE_AFTER_AUTH:
IPCOM_LOG0(INFO, "IPEAP-SIM :: Failure notification after authentication");
break;
case IPEAP_SIM_TEMPORARILY_DENIED:
IPCOM_LOG0(INFO, "IPEAP-SIM :: Failure notification: User has been temporarily denied");
break;
case IPEAP_SIM_NOT_SUBSCRIBED:
IPCOM_LOG0(INFO, "IPEAP-SIM :: Failure notification: User has no subscribed");
break;
case IPEAP_SIM_FAILURE_BEFORE_AUTH:
IPCOM_LOG0(INFO, "IPEAP-SIM :: Failure notification before authentication");
break;
case IPEAP_SIM_SUCCESS:
IPCOM_LOG0(INFO, "IPEAP-SIM :: Successful authentication notification");
break;
default:
if (notification >= IPEAP_SIM_SUCCESS)
IPCOM_LOG1(INFO, "IPEAP-SIM :: Unrecognized non-failure notification (%0x%.4X)", notification);
else
IPCOM_LOG1(INFO, "IPEAP-SIM :: Unrecognized failure notification (%0x%.4X)", notification);
}
return;
}
/*
*===========================================================================
* ipeap_sim_finish_response
*===========================================================================
* Description: Finalize the response message.
* Parameters: sim_ctx - The EAP SIM context.
* mac_data - Data value used to calculate the authentication
* mac.
* msg - The response message.
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_finish_response(
Ipeap_sim_ctx* sim_ctx,
Ip_value* mac_data,
Ipeap_sim_msg* msg)
{
Ip_err err = IPCOM_SUCCESS;
/* Change message length to network order */
msg->length = ip_htons(msg->length);
/* Add mac if possible */
if ((IP_NULL != mac_data) &&
(sim_ctx->mac_offset > 0) &&
(sim_ctx->k_auth.n > 0))
{
err = ipeap_sim_generate_mac(sim_ctx->k_auth.p,
sim_ctx->k_auth.n,
(Ip_u8*)msg,
ip_htons(msg->length),
mac_data->p,
mac_data->n,
(Ip_u8*)msg + sim_ctx->mac_offset,
IPEAP_SIM_MAC_LEN);
}
/* Remove attributes not needed anymore */
ip_free_value(&sim_ctx->attr.encr_data);
ip_free_value(&sim_ctx->attr.iv);
ip_free_value(&sim_ctx->attr.mac);
ip_free_value(&sim_ctx->attr.padding);
/* tell that we have an out packet */
if (IPCOM_SUCCESS == err)
err = IPEAP_PENDING_SEND_OUT_PKT;
else
err = IPEAP_DROPPED_PKT;
return err;
}
/*
*===========================================================================
* ipeap_sim_create_response_start
*===========================================================================
* Description: Start creation of a response message.
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute structure.
* pkt - The response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_create_response_start(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ipeap_pkt* pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_msg* msg = IP_NULL;
Ip_u32 max_len = 0;
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(pkt);
msg->code = IPEAP_MSG_RESPONSE;
msg->type = IPEAP_TYPE_SIM;
msg->subtype = IPEAP_SIM_SUBTYPE_START;
msg->length = 0; /* Used as offset to data buffer during attribute append */
max_len = ipeap_get_pkt_data_size(pkt) - IPEAP_SIM_HEADER_LEN;
ipcom_memset(msg->reserved, 0, sizeof(msg->reserved));
ipcom_memset(msg->data, 0, max_len);
/* Append identity attribute */
err = ipeap_sim_append_attribute_identity(ctx, sim_ctx, attr, msg, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Append nonce_mt attribute */
err = ipeap_sim_append_attribute(msg, IPEAP_SIM_AT_NONCE_MT, &attr->nonce_mt, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Append selected_version attribute */
err = ipeap_sim_append_attribute2(msg, IPEAP_SIM_AT_SELECTED_VERSION, attr->selected_version, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Append header length */
msg->length += IPEAP_SIM_HEADER_LEN;
pkt->end = pkt->start + msg->length;
cleanup:
if (IPCOM_SUCCESS != err)
err = IPEAP_DROPPED_PKT;
else
err = ipeap_sim_finish_response(sim_ctx, IP_NULL, msg);
return err;
}
/*
*===========================================================================
* ipeap_sim_create_response_challenge
*===========================================================================
* Description: Create a challenge response message.
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute structure.
* pkt - The response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_create_response_challenge(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ipeap_pkt* pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_msg* msg = IP_NULL;
Ip_u32 max_len = 0;
(void)attr;
(void)ctx;
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(pkt);
msg->code = IPEAP_MSG_RESPONSE;
msg->type = IPEAP_TYPE_SIM;
msg->subtype = IPEAP_SIM_SUBTYPE_CHALLENGE;
msg->length = 0; /* Used as offset to data buffer during attribute append */
max_len = ipeap_get_pkt_data_size(pkt) - IPEAP_SIM_HEADER_LEN;
ipcom_memset(msg->reserved, 0, sizeof(msg->reserved));
ipcom_memset(msg->data, 0, max_len);
/* Append mac attribute */
err = ipeap_sim_append_attribute_mac(sim_ctx, msg, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Append header length */
msg->length += IPEAP_SIM_HEADER_LEN;
pkt->end = pkt->start + msg->length;
cleanup:
if (IPCOM_SUCCESS != err)
err = IPEAP_DROPPED_PKT;
else
err = ipeap_sim_finish_response(sim_ctx, &sim_ctx->sres, msg);
return err;
}
/*
*===========================================================================
* ipeap_sim_create_response_reauthentication
*===========================================================================
* Description: Create a reauthentication response message.
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute structure.
* pkt - The response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_create_response_reauthentication(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ipeap_pkt* pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_msg* msg = IP_NULL;
Ip_u32 max_len = 0;
Ip_u32 tmp_len = 0;
(void)ctx;
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(pkt);
msg->code = IPEAP_MSG_RESPONSE;
msg->type = IPEAP_TYPE_SIM;
msg->subtype = IPEAP_SIM_SUBTYPE_REAUTHENTICATION;
msg->length = 0; /* Used as offset to data buffer during attribute append */
max_len = ipeap_get_pkt_data_size(pkt) - IPEAP_SIM_HEADER_LEN;
ipcom_memset(msg->reserved, 0, sizeof(msg->reserved));
ipcom_memset(msg->data, 0, max_len);
/* Append encrypted attributes: counter */
tmp_len = msg->length;
err = ipeap_sim_append_attribute2(msg, IPEAP_SIM_AT_COUNTER, attr->counter, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
tmp_len = msg->length - tmp_len;
err = ipeap_sim_encrypt_attributes(sim_ctx, attr, msg, tmp_len, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Append mac attribute */
err = ipeap_sim_append_attribute_mac(sim_ctx, msg, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Append header length */
msg->length += IPEAP_SIM_HEADER_LEN;
pkt->end = pkt->start + msg->length;
cleanup:
if (IPCOM_SUCCESS != err)
err = IPEAP_DROPPED_PKT;
else
err = ipeap_sim_finish_response(sim_ctx, &attr->nonce_s, msg);
return err;
}
/*
*===========================================================================
* ipeap_sim_create_response_notification
*===========================================================================
* Description: Create a notification response message.
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute structure.
* pkt - The response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_create_response_notification(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_sim_attr* attr,
Ipeap_pkt* pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_msg* msg = IP_NULL;
Ip_u32 max_len = 0;
Ip_u32 tmp_len = 0;
(void)ctx;
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(pkt);
msg->code = IPEAP_MSG_RESPONSE;
msg->type = IPEAP_TYPE_SIM;
msg->subtype = IPEAP_SIM_SUBTYPE_NOTIFICATION;
msg->length = 0; /* Used as offset to data buffer during attribute append */
max_len = ipeap_get_pkt_data_size(pkt) - IPEAP_SIM_HEADER_LEN;
ipcom_memset(msg->reserved, 0, sizeof(msg->reserved));
ipcom_memset(msg->data, 0, max_len);
/* Add counter attribute if re-authentication */
if ((sim_ctx->k_encr.n > 0) && (attr->encr_data.n > 0))
{
/* Append encrypted attributes: counter */
tmp_len = msg->length;
err = ipeap_sim_append_attribute2(msg, IPEAP_SIM_AT_COUNTER, attr->counter, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
tmp_len = msg->length - tmp_len;
err = ipeap_sim_encrypt_attributes(sim_ctx, attr, msg, tmp_len, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
}
/* Append mac attribute if possible */
if (sim_ctx->k_auth.n > 0)
{
err = ipeap_sim_append_attribute_mac(sim_ctx, msg, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
}
/* Append header length */
msg->length += IPEAP_SIM_HEADER_LEN;
pkt->end = pkt->start + msg->length;
cleanup:
if (IPCOM_SUCCESS != err)
err = IPEAP_DROPPED_PKT;
else
err = ipeap_sim_finish_response(sim_ctx, &attr->nonce_s, msg);
return err;
}
/*
*===========================================================================
* ipeap_sim_create_response_client_error
*===========================================================================
* Description: Create a client error response message.
* Parameters: ctx - The EAP context.
* sim_ctx - The EAP SIM context.
* attr - The attribute structure.
* pkt - The response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_create_response_client_error(
Ipeap_ctx* ctx,
Ipeap_sim_ctx* sim_ctx,
Ipeap_pkt* pkt,
Ip_u16 client_error)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_msg* msg = IP_NULL;
Ip_u32 max_len = 0;
(void)ctx;
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(pkt);
msg->code = IPEAP_MSG_RESPONSE;
msg->type = IPEAP_TYPE_SIM;
msg->subtype = IPEAP_SIM_SUBTYPE_CLIENT_ERROR;
msg->length = 0; /* Used as offset to data buffer during attribute append */
max_len = ipeap_get_pkt_data_size(pkt) - IPEAP_SIM_HEADER_LEN;
ipcom_memset(msg->reserved, 0, sizeof(msg->reserved));
/* Append client error attribute */
err = ipeap_sim_append_attribute2(msg, IPEAP_SIM_AT_CLIENT_ERROR_CODE, client_error, max_len);
if (IPCOM_SUCCESS != err)
goto cleanup;
/* Append header length */
msg->length += IPEAP_SIM_HEADER_LEN;
pkt->end = pkt->start + msg->length;
cleanup:
if (IPCOM_SUCCESS != err)
err = IPEAP_DROPPED_PKT;
else
err = ipeap_sim_finish_response(sim_ctx, IP_NULL, msg);
return err;
}
/*
*===========================================================================
* ipeap_sim_process_request_start
*===========================================================================
* Description: Process a start request message.
* Parameters: ctx - The EAP context.
* pkt - The created response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_process_request_start(
Ipeap_ctx* ctx,
Ipeap_pkt* pkt)
{
Ipeap_sim_ctx* sim_ctx = IP_NULL;
Ipeap_sim_attr* attr = IP_NULL;
Ip_s32 i = 0;
Ip_u16 version = 0;
ctx->state = IPEAP_STATE_HANDSHAKE;
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
attr = &sim_ctx->attr;
/* Select version */
if (IP_NULL == attr->version_list.p)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_start - No AT_VERSION_LIST in packet");
return ipeap_sim_create_response_client_error(ctx, sim_ctx, pkt, IPEAP_SIM_UNSUPPORTED_VERSION);
}
attr->selected_version = 0;
for (i=0; i<attr->version_list.n; i += 2)
{
version = (Ip_u16)( 256*attr->version_list.p[i*2] );
version = (Ip_u16)( version + attr->version_list.p[i*2+1]) ;
if (IPEAP_SIM_VERSION == version)
{
attr->selected_version = version;
break;
}
}
if (0 == attr->selected_version)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_start - Unsupported version");
return ipeap_sim_create_response_client_error(ctx, sim_ctx, pkt, IPEAP_SIM_UNSUPPORTED_VERSION);
}
return ipeap_sim_create_response_start(ctx, sim_ctx, attr, pkt);
}
/*
*===========================================================================
* ipeap_sim_process_request_challenge
*===========================================================================
* Description: Process a challenge request message.
* Parameters: ctx - The EAP context.
* in_pkt - The request packet (message).
* out_pkt - The created response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_process_request_challenge(
Ipeap_ctx* ctx,
Ipeap_pkt* in_pkt,
Ipeap_pkt* out_pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_ctx* sim_ctx = IP_NULL;
Ipeap_sim_attr* attr = IP_NULL;
Ipeap_sim_msg* msg = IP_NULL;
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
attr = &sim_ctx->attr;
/* Generate authentication values */
err = ipeap_sim_generate_auth(sim_ctx, attr, &sim_ctx->kc, &sim_ctx->kc_num);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_challenge - failed to generate authentication values");
goto cleanup;
}
/* Generate master key (mk) */
err = ipeap_sim_generate_mk(ctx, sim_ctx, attr, &sim_ctx->mk);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_challenge - failed to generate master key");
goto cleanup;
}
/* Generate keys (k_auth, k_encr, msk, emsk) */
err = ipeap_sim_generate_keys(&sim_ctx->mk,
&sim_ctx->k_encr,
&sim_ctx->k_auth,
&sim_ctx->msk,
&sim_ctx->emsk);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_challenge - failed to generate keys");
goto cleanup;
}
/* Verify mac */
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(in_pkt);
err = ipeap_sim_verify_mac(sim_ctx->k_auth.p,
sim_ctx->k_auth.n,
(Ip_u8*)msg,
ip_htons(msg->length),
attr->nonce_mt.p,
attr->nonce_mt.n,
attr->mac.p,
attr->mac.n);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_challenge - failed to verify mac");
goto cleanup;
}
/* Decrypt and parse encrypted attributes */
err = ipeap_sim_parse_encrypted_attributes(ctx, sim_ctx, attr);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_challenge - failed to parse encrypted attributes");
goto cleanup;
}
cleanup:
if (IPCOM_SUCCESS != err)
err = ipeap_sim_create_response_client_error(ctx, sim_ctx, out_pkt, IPEAP_SIM_UNABLE_TO_PROCESS_PACKET);
else
err = ipeap_sim_create_response_challenge(ctx, sim_ctx, attr, out_pkt);
return err;
}
/*
*===========================================================================
* ipeap_sim_process_request_notification
*===========================================================================
* Description: Process a notification request message.
* Parameters: ctx - The EAP context.
* pkt - The created response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_process_request_notification(
Ipeap_ctx* ctx,
Ipeap_pkt* pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_ctx* sim_ctx = IP_NULL;
Ipeap_sim_attr* attr = IP_NULL;
Ipeap_sim_msg* msg = IP_NULL;
Ip_u16 counter = 0;
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
attr = &sim_ctx->attr;
/* Only one notification round is allowed */
if (sim_ctx->notification_num > 0)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_notification - only one notifcation round is allowed");
err = IPCOM_ERR_FAILED;
goto cleanup;
}
sim_ctx->notification_num++;
/* Is authentication required for this notification? */
if ((attr->notification & 0x4000) == 0)
{
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(pkt);
err = ipeap_sim_verify_mac(sim_ctx->k_auth.p,
sim_ctx->k_auth.n,
(Ip_u8*)msg,
ip_htons(msg->length),
IP_NULL,
0,
attr->mac.p,
attr->mac.n);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_notification - failed to authenticate msg");
goto cleanup;
}
/* Do we have an encrypted counter? */
counter = attr->counter;
if (attr->encr_data.n > 0)
{
/* Decrypt and parse encrypted attributes */
err = ipeap_sim_parse_encrypted_attributes(ctx, sim_ctx, attr);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_notification - failed to parse encrypted attributes");
goto cleanup;
}
if (counter != attr->counter)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_notification - bad counter value");
goto cleanup;
}
}
}
/* Report notification */
ipeap_sim_report_notification(attr->notification);
cleanup:
if (IPCOM_SUCCESS != err)
err = ipeap_sim_create_response_client_error(ctx, sim_ctx, pkt, IPEAP_SIM_UNABLE_TO_PROCESS_PACKET);
else
err = ipeap_sim_create_response_notification(ctx, sim_ctx, attr, pkt);
return err;
}
/*
*===========================================================================
* ipeap_sim_process_request_reauthentication
*===========================================================================
* Description: Process a reauthentication request message.
* Parameters: ctx - The EAP context.
* in_pkt - The request packet (message).
* out_pkt - The created response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_process_request_reauthentication(
Ipeap_ctx* ctx,
Ipeap_pkt* in_pkt,
Ipeap_pkt* out_pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_ctx* sim_ctx = IP_NULL;
Ipeap_sim_attr* attr = IP_NULL;
Ipeap_sim_msg* msg = IP_NULL;
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
attr = &sim_ctx->attr;
/* Decrypt and parse encrypted attributes */
err = ipeap_sim_parse_encrypted_attributes(ctx, sim_ctx, attr);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_challenge - failed to parse encrypted attributes");
goto cleanup;
}
/* Verify mac */
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(in_pkt);
err = ipeap_sim_verify_mac(sim_ctx->k_auth.p,
sim_ctx->k_auth.n,
(Ip_u8*)msg,
ip_htons(msg->length),
IP_NULL,
0,
attr->mac.p,
attr->mac.n);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_reauthentication - failed to verify mac");
goto cleanup;
}
/* Generate new keys */
err = ipeap_sim_generate_new_keys(ctx->identity,
attr->counter,
&attr->nonce_s,
&sim_ctx->mk,
&sim_ctx->msk,
&sim_ctx->emsk);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_reauthentication - failed to generate new keys");
goto cleanup;
}
cleanup:
if (IPCOM_SUCCESS != err)
err = ipeap_sim_create_response_client_error(ctx, sim_ctx, out_pkt, IPEAP_SIM_UNABLE_TO_PROCESS_PACKET);
else
err = ipeap_sim_create_response_reauthentication(ctx, sim_ctx, attr, out_pkt);
return err;
}
/*
*===========================================================================
* ipeap_sim_process_request
*===========================================================================
* Description: Process a request message.
* Parameters: ctx - The EAP context.
* in_pkt - The request packet (message).
* out_pkt - The created response packet (message).
* Returns:
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_process_request(
Ipeap_ctx* ctx,
Ipeap_pkt* in_pkt,
Ipeap_pkt* out_pkt)
{
Ip_err err = IPCOM_SUCCESS;
Ipeap_sim_msg* in_msg = IP_NULL;
Ipeap_sim_msg* out_msg = IP_NULL;
in_msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(in_pkt);
out_msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(out_pkt);
/* Response id always same as request id */
out_msg->id = in_msg->id;
/* Parse and validate all attributes */
err = ipeap_sim_parse_attributes(ctx, in_msg, IP_FALSE);
if (IPCOM_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_request_request - bad attributes");
return IPEAP_DROPPED_PKT;
}
/* Do something based on the subtype */
switch (in_msg->subtype)
{
case IPEAP_SIM_SUBTYPE_START:
err = ipeap_sim_process_request_start(ctx, out_pkt);
break;
case IPEAP_SIM_SUBTYPE_CHALLENGE:
err = ipeap_sim_process_request_challenge(ctx, in_pkt, out_pkt);
break;
case IPEAP_SIM_SUBTYPE_NOTIFICATION:
err = ipeap_sim_process_request_notification(ctx, out_pkt);
break;
case IPEAP_SIM_SUBTYPE_REAUTHENTICATION:
err = ipeap_sim_process_request_reauthentication(ctx, in_pkt, out_pkt);
break;
default:
IPCOM_LOG1(ERR, "ipeap_sim_process_request - bad subtype (%d)", in_msg->subtype);
err = IPEAP_DROPPED_PKT;
break;
}
return err;
}
/*
*===========================================================================
* ipeap_sim_process_success
*===========================================================================
* Description: Process a success message.
* Parameters: ctx - The EAP context.
* Returns:
* IPEAP_SUCCESS
*/
IP_STATIC Ip_err
ipeap_sim_process_success(
Ipeap_ctx* ctx)
{
Ipeap_sim_ctx* sim_ctx = IP_NULL;
Ipeap_sim_attr* attr = IP_NULL;
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
attr = &sim_ctx->attr;
if (attr->next_reauth_id.n > 0)
{
/* We can't handle re_auth id larger than buffer, so copy only if
* buffer is big enough. */
if (attr->next_reauth_id.n < sizeof(ctx->identity))
{
ipcom_memcpy(ctx->identity,
attr->next_reauth_id.p,
attr->next_reauth_id.n);
ctx->identity[attr->next_reauth_id.n] = 0;
}
}
ctx->state = IPEAP_STATE_AUTHENTICATED;
return IPEAP_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_process_msg
*===========================================================================
* Description: Process a message.
* Parameters: ctx - The EAP context.
* in_pkt - The request packet (message).
* out_pkt - The created response packet (message).
* Returns:
* IPEAP_SUCCESS
* IPEAP_PENDING_SEND_OUT_PKT
* IPEAP_FAILURE
* IPEAP_DROPPED_PKT
*/
IP_STATIC Ip_err
ipeap_sim_process_msg(
Ipeap_ctx* ctx,
Ipeap_pkt* in_pkt,
Ipeap_pkt* out_pkt)
{
Ip_err err = IPEAP_FAILURE;
Ipeap_sim_msg* msg = IP_NULL;
/* Alwyas need our context */
if (ctx->mech_data == IP_NULL)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_msg - bad context");
return IPEAP_DROPPED_PKT;
}
msg = (Ipeap_sim_msg*)ipeap_get_pkt_data_buffer(in_pkt);
ipeap_print_memory("IPEAP-SIM :: Process:\n", (Ip_u8*)msg, ip_htons(msg->length));
/* Always at least 4 bytes of data */
if ((in_pkt->end - in_pkt->start) < 4)
{
IPCOM_LOG0(ERR, "ipeap_sim_process_msg - bad packet");
return IPEAP_DROPPED_PKT;
}
switch (msg->code)
{
case IPEAP_MSG_REQUEST:
IPCOM_LOG0(DEBUG, "IPEAP-SIM :: Received request msg");
err = ipeap_sim_process_request(ctx, in_pkt, out_pkt);
break;
case IPEAP_MSG_RESPONSE:
IPCOM_LOG0(ERR, "IPEAP-SIM :: Received response msg, dropping msg");
err = IPEAP_DROPPED_PKT;
break;
case IPEAP_MSG_FAILURE:
IPCOM_LOG0(ERR, "IPEAP-SIM :: Received failure msg, resetting state");
(void)ipeap_sim_free(ctx);
err = IPEAP_FAILURE;
break;
case IPEAP_MSG_SUCCESS:
IPCOM_LOG0(INFO, "IPEAP-SIM :: Received EAP success");
err = ipeap_sim_process_success(ctx);
break;
default:
IPCOM_LOG1(ERR, "ipeap_sim_process_msg :: received unknown msg type: %d, dropping msg", msg->code);
err = IPEAP_DROPPED_PKT;
break;
}
return err;
}
/*
*===========================================================================
* ipeap_sim_get_key
*===========================================================================
* Description: Get the key generated from the successful EAP SIM
* authentication.
* Parameters: ctx - The EAP context.
* key - Buffer that will receive the key value.
* key_len - Length of key buffer.
* Returns:
* IPCOM_SUCCESS
* IPCOM_ERR_INVALID_ARG
*/
IP_STATIC Ip_err
ipeap_sim_get_key(
Ipeap_ctx* ctx,
Ip_u8* key,
int key_len)
{
Ipeap_sim_ctx* sim_ctx = IP_NULL;
int n = 0;
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
if (key_len > (int)(sim_ctx->msk.n + sim_ctx->emsk.n))
{
IPCOM_LOG1(ERR, "ipeap_sim_get_key - not enough key material (%d wanted)", key_len);
return IPCOM_ERR_INVALID_ARG;
}
if (key_len > (int)sim_ctx->msk.n)
n = (int)sim_ctx->msk.n;
else
n = key_len;
ipcom_memcpy(key, sim_ctx->msk.p, (Ip_size_t)n);
if (n < key_len)
ipcom_memcpy(key+n, sim_ctx->emsk.p,(Ip_size_t)( key_len - n));
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_sim_get_sim_session_id
*===========================================================================
*
*/
IP_STATIC Ip_err
ipeap_sim_get_sim_session_id(
Ipeap_ctx *ctx,
Ip_u8 *session_id,
Ip_u32 *session_id_len
)
{
Ip_err rc = IPCOM_SUCCESS;
Ipeap_sim_ctx *sim_ctx = IP_NULL;
Ipeap_sim_attr *attr = IP_NULL;
IPCOM_LOG0(DEBUG2, "IPEAP-SIM :: Get Session-Id ...");
if(!ctx)
{
IPCOM_LOG0(ERR, "ipeap_sim_get_sim_session_id - NULL EAP ctx");
rc = IPCOM_ERR_INVALID_ARG;
goto out;
}
sim_ctx = (Ipeap_sim_ctx*)ctx->mech_data;
if(!sim_ctx)
{
IPCOM_LOG0(ERR, "ipeap_sim_get_sim_session_id - NULL EAP-SIM ctx");
rc = IPCOM_ERR_FAILED;
goto out;
}
attr = &sim_ctx->attr;
if (attr->rand.n <= 0)
{
IPCOM_LOG0(ERR, "ipeap_sim_get_sim_session_id - RAND is not available");
rc = IPCOM_ERR_FAILED;
goto out;
}
if (attr->nonce_mt.n <= 0)
{
IPCOM_LOG0(ERR, "ipeap_sim_get_sim_session_id - NONCE_MT is not available");
rc = IPCOM_ERR_FAILED;
goto out;
}
/* The number of RAND challenges (n) MUST be two or three ,each 16 bytes long rfc4186, page 57 */
if (*session_id_len < (1 + attr->rand.n + attr->nonce_mt.n ) )
{
IPCOM_LOG2(ERR, "ipeap_sim_get_sim_session_id - not enough buffer is available to hold "
"the SIM-Session-ID (%d wanted), (%d given )",(1 + attr->rand.n + attr->nonce_mt.n ) , *session_id_len );
rc = IPCOM_ERR_INVALID_ARG;
goto out;
}
ipcom_memset(session_id, 0,*session_id_len);
session_id[0] = IPEAP_TYPE_SIM;
session_id+= 1;
ipcom_memcpy(session_id,attr->rand.p,attr->rand.n);
session_id+= attr->rand.n;
ipcom_memcpy(session_id,attr->nonce_mt.p,attr->nonce_mt.n);
*session_id_len = 1 + attr->rand.n + attr->nonce_mt.n ;
out:
return rc;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipeap_sim_methods_get
*===========================================================================
*/
IP_PUBLIC Ipeap_methods*
ipeap_sim_methods_get(void)
{
/* Check algorithms */
if (ipeap_sim_algorithm_test() != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "IPEAP-SIM :: Algorithms test failed, check cryptographic support");
}
return &ipeap_sim_methods;
}
/*
*===========================================================================
* ipeap_sim_get_identity
*===========================================================================
*/
IP_PUBLIC Ip_err
ipeap_sim_get_identity(char* identity, Ip_u32 identityLen)
{
Ip_err err = IPCOM_ERR_FAILED;
Ipeap_ctx ctx = {0};
IPCOM_LOG0(DEBUG, "IPEAP-SIM :: Get identity ...");
if (ipeap_sim_init(&ctx) == IPCOM_SUCCESS)
{
if (identityLen > ipcom_strlen(ctx.identity))
{
ipcom_strcpy(identity, ctx.identity);
err = IPCOM_SUCCESS;
}
(void)ipeap_sim_free(&ctx);
}
if (err == IPCOM_SUCCESS)
IPCOM_LOG1(DEBUG, "IPEAP-SIM :: Got identity '%s'", identity);
else
IPCOM_LOG0(DEBUG, "IPEAP-SIM :: Get identity ... FAILED");
return err;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/