/* ****************************************************************************** * 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 ****************************************************************************** */ /* 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 #include #include #include #include #include #include #include #include #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|[@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; iversion_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 **************************************************************************** */