2462 lines
77 KiB
C
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
|
|
****************************************************************************
|
|
*/
|