/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /***************************************************************************** Source usim_api.h Version 0.1 Date 2012/10/09 Product NAS stack Subsystem Application Programming Interface Author Frederic Maurel Description Implements the API used by the NAS layer to read/write data to/from the USIM application *****************************************************************************/ #include "usim_api.h" #include "nas_log.h" #include "utils.h" #include "memory.h" #include <stdio.h> #include "aka_functions.h" #include <string.h> // memcpy, memset #include <stdlib.h> // malloc, free #include <stdio.h> /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ /****************************************************************************/ /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ /****************************************************************************/ static int _usim_api_check_sqn(uint32_t seq, uint8_t ind); /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: usim_api_read() ** ** ** ** Description: Reads data from the USIM application ** ** ** ** Inputs: None ** ** Others: File where are stored USIM data ** ** ** ** Outputs: data: Pointer to the USIM application data ** ** Return: RETURNerror, RETURNok ** ** Others: None ** ** ** ***************************************************************************/ int usim_api_read(const char *filename, usim_data_t* data) { LOG_FUNC_IN; /* Read USIM application data */ if (memory_read(filename, data, sizeof(usim_data_t)) != RETURNok) { LOG_TRACE(ERROR, "USIM-API - %s file is either not valid " "or not present", filename); LOG_FUNC_RETURN (RETURNerror); } LOG_FUNC_RETURN (RETURNok); } /**************************************************************************** ** ** ** Name: usim_api_write() ** ** ** ** Description: Writes data to the USIM application ** ** ** ** Inputs: data: Pointer to the USIM application data ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNerror, RETURNok ** ** Others: None ** ** ** ***************************************************************************/ int usim_api_write(const char *filename, const usim_data_t* data) { LOG_FUNC_IN; /* Write USIM application data */ if (memory_write(filename, data, sizeof(usim_data_t)) != RETURNok) { LOG_TRACE(ERROR, "USIM-API - Unable to write USIM file %s", filename); LOG_FUNC_RETURN (RETURNerror); } LOG_FUNC_RETURN (RETURNok); } /**************************************************************************** ** ** ** Name: usim_api_authenticate_test() ** ** ** ** Description: Performs mutual authentication of the USIM to the network,** ** checking whether authentication token AUTN can be accep- ** ** ted. If so, returns an authentication response RES and ** ** the ciphering and integrity keys. ** ** In case of synch failure, returns a re-synchronization ** ** token AUTS. ** ** ** ** Key Generation for Test USIM based on 34.108 ** ** ** ** Authentication and key generating function algorithms are ** ** specified in 3GPP TS 35.206. ** ** ** ** Inputs: rand_pP: Random challenge number ** ** autn_pP: Authentication token ** ** AUTN = (SQN xor AK) || AMF || MAC ** ** 48 16 64 bits ** ** Others: Security key ** ** ** ** Outputs: auts_pP: Re-synchronization token ** ** res_pP: Authentication response ** ** ck_pP: Ciphering key ** ** ik_pP Integrity key ** ** ** ** Return: RETURNerror, RETURNok ** ** Others: None ** ** ** ***************************************************************************/ int usim_api_authenticate_test(usim_data_t *usim_data, const OctetString* rand_pP, const OctetString* autn_pP, OctetString* auts_pP, OctetString* res_pP, OctetString* ck_pP, OctetString* ik_pP) { LOG_FUNC_IN; int rc; int i; LOG_TRACE(INFO, "USIM-API - rand :%s",dump_octet_string(rand_pP)); LOG_TRACE(INFO, "USIM-API - autn :%s",dump_octet_string(autn_pP)); //step1: XDOUT = RAND xor K // RES = XDOUT for (i=0; i<USIM_API_K_SIZE; i++) { res_pP->value[i] = rand_pP->value[i] ^ usim_data->keys.usim_api_k[i]; } //step2: res = f2(xdout,n) // ck = f3(xdout) // ik = f4(xdout) // ak = f5(xdout) u8 ak[USIM_API_AK_SIZE]; for (i=0; i<15; i++) { ck_pP->value[i] = res_pP->value[i+1]; } ck_pP->value[15] = res_pP->value[0]; for (i=0; i<14; i++) { ik_pP->value[i] = res_pP->value[i+2]; } ik_pP->value[14] = res_pP->value[0]; ik_pP->value[15] = res_pP->value[1]; for (i=0; i<USIM_API_AK_SIZE; i++) { ak[i] = res_pP->value[i+3]; } LOG_TRACE(INFO, "USIM-API - res(f2) :%s",dump_octet_string(res_pP)); LOG_TRACE(INFO, "USIM-API - ck(f3) :%s",dump_octet_string(ck_pP)); LOG_TRACE(INFO, "USIM-API - ik(f4) :%s",dump_octet_string(ik_pP)); LOG_TRACE(INFO, "USIM-API - ak(f5) : %02X%02X%02X%02X%02X%02X", ak[0],ak[1],ak[2],ak[3],ak[4],ak[5]); //step3: concatenate SQN with AMP SQN||AMF // SQN = AUTN xor ak u8 sqn[USIM_API_SQN_SIZE]; for (i = 0; i < USIM_API_SQN_SIZE; i++) { sqn[i] = autn_pP->value[i] ^ ak[i]; } LOG_TRACE(INFO, "USIM-API - Retrieved SQN %02X%02X%02X%02X%02X%02X", sqn[0],sqn[1],sqn[2],sqn[3],sqn[4],sqn[5]); LOG_TRACE(INFO, "USIM-API - Retrieved AMF %02X%02X", autn_pP->value[USIM_API_SQN_SIZE],autn_pP->value[USIM_API_SQN_SIZE+1]); #define USIM_API_XMAC_SIZE 8 u8 cdout[USIM_API_XMAC_SIZE]; for (i = 0; i < USIM_API_XMAC_SIZE; i++) { if(i < USIM_API_SQN_SIZE) { cdout[i] = sqn[i]; } else { cdout[i] = autn_pP->value[i]; } } LOG_TRACE(INFO, "USIM-API - Retrieved CDOUT %02X%02X%02X%02X%02X%02X%02X%02X", cdout[0],cdout[1],cdout[2],cdout[3],cdout[4],cdout[5],cdout[6],cdout[7]); //step4:calculate XMAC from cdout and xdout u8 xmac[USIM_API_XMAC_SIZE]; for(i = 0; i < USIM_API_XMAC_SIZE; i++) { xmac[i] = res_pP->value[i] ^ cdout[i]; } LOG_TRACE(INFO, "USIM-API - Computed XMAC %02X%02X%02X%02X%02X%02X%02X%02X", xmac[0],xmac[1],xmac[2],xmac[3], xmac[4],xmac[5],xmac[6],xmac[7]); /* Compare the XMAC with the MAC included in AUTN */ #define USIM_API_AMF_SIZE 2 if ( memcmp(xmac, &autn_pP->value[USIM_API_SQN_SIZE + USIM_API_AMF_SIZE], USIM_API_XMAC_SIZE) != 0 ) { LOG_TRACE(INFO, "USIM-API - Comparing the XMAC with the MAC included in AUTN Failed"); rc = RETURNerror; //LOG_FUNC_RETURN (RETURNerror); } else { LOG_TRACE(INFO, "USIM-API - Comparing the XMAC with the MAC included in AUTN Succeeded"); /* Verify that the received sequence number SQN is in the correct range */ rc = _usim_api_check_sqn(*(uint32_t*)(sqn), sqn[USIM_API_SQN_SIZE - 1]); } if (rc != RETURNok) { /* Synchronisation failure; compute the AUTS parameter */ /* Concealed value of the counter SQNms in the USIM: * Conc(SQNMS) = SQNMS ⊕ f5*K(RAND) */ f5star(usim_data->keys.usim_api_k, rand_pP->value, ak, usim_data->keys.opc); u8 sqn_ms[USIM_API_SQNMS_SIZE]; memset(sqn_ms, 0, USIM_API_SQNMS_SIZE); //#define USIM_API_SQN_MS_SIZE 3 printf("usim_data->usim_sqn_data.sqn_ms %p\n", usim_data->usim_sqn_data.sqn_ms); for (i = 0; i < USIM_API_SQNMS_SIZE; i++) { //#warning "LG:BUG HERE TODO" printf("i %d: ((uint8_t*)(usim_data->usim_sqn_data.sqn_ms))[USIM_API_SQNMS_SIZE - i] %d\n",i, ((uint8_t*)(usim_data->usim_sqn_data.sqn_ms))[USIM_API_SQNMS_SIZE - i]); sqn_ms[USIM_API_SQNMS_SIZE - i] = ((uint8_t*)(usim_data->usim_sqn_data.sqn_ms))[USIM_API_SQNMS_SIZE - i]; } u8 sqnms[USIM_API_SQNMS_SIZE]; for (i = 0; i < USIM_API_SQNMS_SIZE; i++) { sqnms[i] = sqn_ms[i] ^ ak[i]; } LOG_TRACE(DEBUG, "USIM-API - SQNms %02X%02X%02X%02X%02X%02X", sqnms[0],sqnms[1],sqnms[2],sqnms[3],sqnms[4],sqnms[5]); /* Synchronisation message authentication code: * MACS = f1*K(SQNMS || RAND || AMF) */ #define USIM_API_MACS_SIZE USIM_API_XMAC_SIZE u8 macs[USIM_API_MACS_SIZE]; f1star(usim_data->keys.usim_api_k, rand_pP->value, sqn_ms, &rand_pP->value[USIM_API_SQN_SIZE], macs, usim_data->keys.opc); LOG_TRACE(DEBUG, "USIM-API - MACS %02X%02X%02X%02X%02X%02X%02X%02X", macs[0],macs[1],macs[2],macs[3], macs[4],macs[5],macs[6],macs[7]); /* Synchronisation authentication token: * AUTS = Conc(SQNMS) || MACS */ memcpy(&auts_pP->value[0], sqnms, USIM_API_SQNMS_SIZE); memcpy(&auts_pP->value[USIM_API_SQNMS_SIZE], macs, USIM_API_MACS_SIZE); auts_pP->length = USIM_API_SQNMS_SIZE + USIM_API_MACS_SIZE; LOG_FUNC_RETURN (RETURNerror); } LOG_FUNC_RETURN (RETURNok); } /**************************************************************************** ** ** ** Name: usim_api_authenticate() ** ** ** ** Description: Performs mutual authentication of the USIM to the network,** ** checking whether authentication token AUTN can be accep- ** ** ted. If so, returns an authentication response RES and ** ** the ciphering and integrity keys. ** ** In case of synch failure, returns a re-synchronization ** ** token AUTS. ** ** ** ** 3GPP TS 31.102, section 7.1.1.1 ** ** ** ** Authentication and key generating function algorithms are ** ** specified in 3GPP TS 35.206. ** ** ** ** Inputs: rand_pP: Random challenge number ** ** autn_pP: Authentication token ** ** AUTN = (SQN xor AK) || AMF || MAC ** ** 48 16 64 bits ** ** ** ** Outputs: auts_pP: Re-synchronization token ** ** res_pP: Authentication response ** ** ck_pP: Ciphering key ** ** ik_pP Integrity key ** ** ** ** Return: RETURNerror, RETURNok ** ** Others: None ** ** ** ***************************************************************************/ int usim_api_authenticate(usim_data_t *usim_data, const OctetString* rand_pP, const OctetString* autn_pP, OctetString* auts_pP, OctetString* res_pP, OctetString* ck_pP, OctetString* ik_pP) { LOG_FUNC_IN; int rc; int i; LOG_TRACE(DEBUG, "USIM-API - rand :%s",dump_octet_string(rand_pP)); LOG_TRACE(DEBUG, "USIM-API - autn :%s",dump_octet_string(autn_pP)); /* Compute the authentication response RES = f2K (RAND) */ /* Compute the cipher key CK = f3K (RAND) */ /* Compute the integrity key IK = f4K (RAND) */ /* Compute the anonymity key AK = f5K (RAND) */ u8 ak[USIM_API_AK_SIZE]; f2345(usim_data->keys.usim_api_k, rand_pP->value, res_pP->value, ck_pP->value, ik_pP->value, ak, usim_data->keys.opc); LOG_TRACE(INFO, "USIM-API - res(f2) :%s",dump_octet_string(res_pP)); LOG_TRACE(INFO, "USIM-API - ck(f3) :%s",dump_octet_string(ck_pP)); LOG_TRACE(INFO, "USIM-API - ik(f4) :%s",dump_octet_string(ik_pP)); LOG_TRACE(INFO, "USIM-API - ak(f5) : %02X%02X%02X%02X%02X%02X", ak[0],ak[1],ak[2],ak[3],ak[4],ak[5]); /* Retrieve the sequence number SQN = (SQN ⊕ AK) ⊕ AK */ u8 sqn[USIM_API_SQN_SIZE]; for (i = 0; i < USIM_API_SQN_SIZE; i++) { sqn[i] = autn_pP->value[i] ^ ak[i]; } LOG_TRACE(INFO, "USIM-API - Retrieved SQN %02X%02X%02X%02X%02X%02X", sqn[0],sqn[1],sqn[2],sqn[3],sqn[4],sqn[5]); /* Compute XMAC = f1K (SQN || RAND || AMF) */ #define USIM_API_XMAC_SIZE 8 u8 xmac[USIM_API_XMAC_SIZE]; f1(usim_data->keys.usim_api_k, rand_pP->value, sqn, &autn_pP->value[USIM_API_SQN_SIZE], xmac, usim_data->keys.opc); LOG_TRACE(DEBUG, "USIM-API - Computed XMAC %02X%02X%02X%02X%02X%02X%02X%02X", xmac[0],xmac[1],xmac[2],xmac[3], xmac[4],xmac[5],xmac[6],xmac[7]); /* Compare the XMAC with the MAC included in AUTN */ #define USIM_API_AMF_SIZE 2 if ( memcmp(xmac, &autn_pP->value[USIM_API_SQN_SIZE + USIM_API_AMF_SIZE], USIM_API_XMAC_SIZE) != 0 ) { LOG_TRACE(INFO, "USIM-API - Comparing the XMAC with the MAC included in AUTN Failed"); rc = RETURNerror; //LOG_FUNC_RETURN (RETURNerror); } else { LOG_TRACE(INFO, "USIM-API - Comparing the XMAC with the MAC included in AUTN Succeeded"); /* Verify that the received sequence number SQN is in the correct range */ rc = _usim_api_check_sqn(*(uint32_t*)(sqn), sqn[USIM_API_SQN_SIZE - 1]); } if (rc != RETURNok) { /* Synchronisation failure; compute the AUTS parameter */ /* Concealed value of the counter SQNms in the USIM: * Conc(SQNMS) = SQNMS ⊕ f5*K(RAND) */ f5star(usim_data->keys.usim_api_k, rand_pP->value, ak, usim_data->keys.opc); u8 sqn_ms[USIM_API_SQNMS_SIZE]; memset(sqn_ms, 0, USIM_API_SQNMS_SIZE); //#define USIM_API_SQN_MS_SIZE 3 printf("usim_data->usim_sqn.sqn_ms %p\n",usim_data->usim_sqn_data.sqn_ms); for (i = 0; i < USIM_API_SQNMS_SIZE; i++) { //#warning "LG:BUG HERE TODO" printf("i %d: ((uint8_t*)(usim_data->usim_sqn_data.sqn_ms))[USIM_API_SQNMS_SIZE - i] %d\n",i, ((uint8_t*)(usim_data->usim_sqn_data.sqn_ms))[USIM_API_SQNMS_SIZE - i]); sqn_ms[USIM_API_SQNMS_SIZE - i] = ((uint8_t*)(usim_data->usim_sqn_data.sqn_ms))[USIM_API_SQNMS_SIZE - i]; } u8 sqnms[USIM_API_SQNMS_SIZE]; for (i = 0; i < USIM_API_SQNMS_SIZE; i++) { sqnms[i] = sqn_ms[i] ^ ak[i]; } LOG_TRACE(DEBUG, "USIM-API - SQNms %02X%02X%02X%02X%02X%02X", sqnms[0],sqnms[1],sqnms[2],sqnms[3],sqnms[4],sqnms[5]); /* Synchronisation message authentication code: * MACS = f1*K(SQNMS || RAND || AMF) */ #define USIM_API_MACS_SIZE USIM_API_XMAC_SIZE u8 macs[USIM_API_MACS_SIZE]; f1star(usim_data->keys.usim_api_k, rand_pP->value, sqn_ms, &rand_pP->value[USIM_API_SQN_SIZE], macs, usim_data->keys.opc); LOG_TRACE(DEBUG, "USIM-API - MACS %02X%02X%02X%02X%02X%02X%02X%02X", macs[0],macs[1],macs[2],macs[3], macs[4],macs[5],macs[6],macs[7]); /* Synchronisation authentication token: * AUTS = Conc(SQNMS) || MACS */ memcpy(&auts_pP->value[0], sqnms, USIM_API_SQNMS_SIZE); memcpy(&auts_pP->value[USIM_API_SQNMS_SIZE], macs, USIM_API_MACS_SIZE); auts_pP->length = USIM_API_SQNMS_SIZE + USIM_API_MACS_SIZE; LOG_FUNC_RETURN (RETURNerror); } LOG_FUNC_RETURN (RETURNok); } /****************************************************************************/ /********************* L O C A L F U N C T I O N S *********************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: _usim_api_check_sqn() ** ** ** ** Description: Verifies the freshness of sequence numbers to determine ** ** whether the specified sequence number is in the correct ** ** range and acceptabled by the USIM. ** ** ** ** 3GPP TS 33.102, Annex C.2 ** ** ** ** Inputs: seq: Sequence number value ** ** ind: Index value ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNerror, RETURNok ** ** Others: None ** ** ** ***************************************************************************/ static int _usim_api_check_sqn(uint32_t seq, uint8_t ind) { /* TODO */ return (RETURNok); }