Merge pull request #221 from softwareradiosystems/op_vs_opc

Op vs opc
master
Andre Puschmann 6 years ago committed by GitHub
commit 1cba6b18ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -52,6 +52,17 @@
DECLARATIONS
*******************************************************************************/
/*********************************************************************
Name: compute_OPc
Description: Computes OPc from OP and K.
Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_compute_opc(uint8 *k,
uint8 *op,
uint8 *op_c);
/*********************************************************************
Name: liblte_security_generate_k_asme

@ -151,6 +151,9 @@ uint8_t security_128_eea2(uint8_t *key,
/******************************************************************************
* Authentication
*****************************************************************************/
uint8_t compute_opc( uint8_t *k,
uint8_t *op,
uint8_t *opc);
uint8_t security_milenage_f1( uint8_t *k,
uint8_t *op,

@ -1099,7 +1099,7 @@ LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key,
Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_milenage_f1(uint8 *k,
uint8 *op,
uint8 *op_c,
uint8 *rand,
uint8 *sqn,
uint8 *amf,
@ -1108,13 +1108,13 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f1(uint8 *k,
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
ROUND_KEY_STRUCT round_keys;
uint32 i;
uint8 op_c[16];
uint8 temp[16];
uint8 in1[16];
uint8 out1[16];
uint8 rijndael_input[16];
if(k != NULL &&
op_c != NULL &&
rand != NULL &&
sqn != NULL &&
amf != NULL &&
@ -1123,9 +1123,6 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f1(uint8 *k,
// Initialize the round keys
rijndael_key_schedule(k, &round_keys);
// Compute OPc
compute_OPc(&round_keys, op, op_c);
// Compute temp
for(i=0; i<16; i++)
{
@ -1183,7 +1180,7 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f1(uint8 *k,
Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_milenage_f1_star(uint8 *k,
uint8 *op,
uint8 *op_c,
uint8 *rand,
uint8 *sqn,
uint8 *amf,
@ -1192,13 +1189,13 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f1_star(uint8 *k,
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
ROUND_KEY_STRUCT round_keys;
uint32 i;
uint8 op_c[16];
uint8 temp[16];
uint8 in1[16];
uint8 out1[16];
uint8 rijndael_input[16];
if(k != NULL &&
op_c != NULL &&
rand != NULL &&
sqn != NULL &&
amf != NULL &&
@ -1207,9 +1204,6 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f1_star(uint8 *k,
// Initialize the round keys
rijndael_key_schedule(k, &round_keys);
// Compute OPc
compute_OPc(&round_keys, op, op_c);
// Compute temp
for(i=0; i<16; i++)
{
@ -1267,7 +1261,7 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f1_star(uint8 *k,
Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_milenage_f2345(uint8 *k,
uint8 *op,
uint8 *op_c,
uint8 *rand,
uint8 *res,
uint8 *ck,
@ -1277,12 +1271,12 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f2345(uint8 *k,
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
ROUND_KEY_STRUCT round_keys;
uint32 i;
uint8 op_c[16];
uint8 temp[16];
uint8 out[16];
uint8 rijndael_input[16];
if(k != NULL &&
op_c != NULL &&
rand != NULL &&
res != NULL &&
ck != NULL &&
@ -1292,9 +1286,6 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f2345(uint8 *k,
// Initialize the round keys
rijndael_key_schedule(k, &round_keys);
// Compute OPc
compute_OPc(&round_keys, op, op_c);
// Compute temp
for(i=0; i<16; i++)
{
@ -1378,28 +1369,25 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f2345(uint8 *k,
Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_milenage_f5_star(uint8 *k,
uint8 *op,
uint8 *op_c,
uint8 *rand,
uint8 *ak)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
ROUND_KEY_STRUCT round_keys;
uint32 i;
uint8 op_c[16];
uint8 temp[16];
uint8 out[16];
uint8 rijndael_input[16];
if(k != NULL &&
op_c != NULL &&
rand != NULL &&
ak != NULL)
{
// Initialize the round keys
rijndael_key_schedule(k, &round_keys);
// Compute OPc
compute_OPc(&round_keys, op, op_c);
// Compute temp
for(i=0; i<16; i++)
{
@ -1424,37 +1412,48 @@ LIBLTE_ERROR_ENUM liblte_security_milenage_f5_star(uint8 *k,
{
ak[i] = out[i];
}
err = LIBLTE_SUCCESS;
}
return(err);
}
/*******************************************************************************
LOCAL FUNCTIONS
*******************************************************************************/
/*********************************************************************
Name: compute_OPc
Name: liblte_compute_opc
Description: Computes OPc from OP and K.
Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
void compute_OPc(ROUND_KEY_STRUCT *rk,
uint8 *op,
uint8 *op_c)
LIBLTE_ERROR_ENUM liblte_compute_opc(uint8 *k,
uint8 *op,
uint8 *op_c)
{
uint32 i;
uint32 i;
ROUND_KEY_STRUCT round_keys;
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(k != NULL &&
op != NULL &&
op_c != NULL)
{
rijndael_encrypt(op, rk, op_c);
rijndael_key_schedule(k, &round_keys);
rijndael_encrypt(op, &round_keys, op_c);
for(i=0; i<16; i++)
{
op_c[i] ^= op[i];
op_c[i] ^= op[i];
}
err = LIBLTE_SUCCESS;
}
return err;
}
/*******************************************************************************
LOCAL FUNCTIONS
*******************************************************************************/
/*********************************************************************
Name: rijndael_key_schedule

@ -229,6 +229,14 @@ uint8_t security_128_eea2(uint8_t *key,
/******************************************************************************
* Authentication
*****************************************************************************/
uint8_t compute_opc( uint8_t *k,
uint8_t *op,
uint8_t *opc)
{
return liblte_compute_opc(k,
op,
opc);
}
uint8_t security_milenage_f1( uint8_t *k,
uint8_t *op,

@ -63,9 +63,19 @@ void test_set_2()
uint8_t op[] = {0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6, 0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18};
// f1
uint8_t mac_o[8];
uint8_t opc_o[16];
err_lte = liblte_compute_opc(k,op,opc_o);
assert(err_lte == LIBLTE_SUCCESS);
arrprint(opc_o, sizeof(opc_o));
uint8_t opc_a[] = {0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e, 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf};
err_cmp = arrcmp(opc_o,opc_a,sizeof(opc_o));
assert(err_cmp == 0);
uint8_t mac_o[8];
err_lte = liblte_security_milenage_f1(k,
op,
opc_o,
rand,
sqn,
amf,
@ -84,7 +94,7 @@ void test_set_2()
uint8_t mac_so[8];
err_lte = liblte_security_milenage_f1_star(k,
op,
opc_o,
rand,
sqn,
amf,
@ -106,7 +116,7 @@ void test_set_2()
uint8_t ak_o[6];
err_lte = liblte_security_milenage_f2345(k,
op,
opc_o,
rand,
res_o,
ck_o,
@ -145,7 +155,7 @@ void test_set_2()
// f star
uint8_t ak_star_o[6];
err_lte = liblte_security_milenage_f5_star(k, op, rand, ak_star_o);
err_lte = liblte_security_milenage_f5_star(k, opc_o, rand, ak_star_o);
assert(err_lte == LIBLTE_SUCCESS);
arrprint(ak_star_o, sizeof(ak_star_o));
@ -160,8 +170,9 @@ void test_set_2()
*/
int main(int argc, char * argv[]) {
/*
test_set_2();
/*
test_set_3();
test_set_4();
test_set_5();

@ -54,11 +54,13 @@ typedef struct{
typedef struct{
std::string name;
uint64_t imsi;
uint8_t key[16];
uint8_t op[16];
uint8_t amf[2];
uint8_t sqn[6];
uint8_t last_rand[16];
uint8_t key[16];
bool op_configured;
uint8_t op[16];
uint8_t opc[16];
uint8_t amf[2];
uint8_t sqn[6];
uint8_t last_rand[16];
}hss_ue_ctx_t;
enum hss_auth_algo {
@ -89,7 +91,7 @@ private:
void gen_rand(uint8_t rand_[16]);
bool get_k_amf_op_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op, uint8_t *sqn);
bool get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, uint8_t *sqn);
bool gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
bool gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
@ -100,7 +102,8 @@ private:
std::vector<std::string> split_string(const std::string &str, char delimiter);
void get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len);
void increment_sqn(uint64_t imsi);
void increment_ue_sqn(uint64_t imsi);
void increment_sqn(uint8_t *sqn, uint8_t *next_sqn);
void set_sqn(uint64_t imsi, uint8_t *sqn);
void set_last_rand(uint64_t imsi, uint8_t *rand);

@ -110,6 +110,7 @@ typedef struct{
} enb_ctx_t;
typedef struct{
uint8_t eksi;
uint8_t k_asme[32];
uint8_t xres[16]; //minimum 6, maximum 16
uint32_t dl_nas_count;

@ -113,7 +113,7 @@ private:
bool integrity_check(ue_emm_ctx_t *emm_ctx, srslte::byte_buffer_t *pdu);
bool short_integrity_check(ue_emm_ctx_t *emm_ctx, srslte::byte_buffer_t *pdu);
bool pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t *autn,uint8_t *rand);
bool pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t eksi, uint8_t *autn, uint8_t *rand);
bool pack_authentication_reject(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
bool unpack_authentication_response(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp);

@ -153,23 +153,43 @@ hss::read_db_file(std::string db_filename)
{
if(line[0] != '#')
{
uint column_size = 7;
std::vector<std::string> split = split_string(line,',');
if(split.size()!=6)
if(split.size() != column_size)
{
m_hss_log->error("Error parsing UE database\n");
m_hss_log->error("Error parsing UE database. Wrong number of columns in .csv\n");
m_hss_log->error("Columns: %lu, Expected %d.\n",split.size(),column_size);
return false;
}
hss_ue_ctx_t *ue_ctx = new hss_ue_ctx_t;
ue_ctx->name = split[0];
ue_ctx->imsi = atoll(split[1].c_str());
get_uint_vec_from_hex_str(split[2],ue_ctx->key,16);
get_uint_vec_from_hex_str(split[3],ue_ctx->op,16);
get_uint_vec_from_hex_str(split[4],ue_ctx->amf,2);
get_uint_vec_from_hex_str(split[5],ue_ctx->sqn,6);
if(split[3] == std::string("op"))
{
ue_ctx->op_configured = true;
get_uint_vec_from_hex_str(split[4],ue_ctx->op,16);
compute_opc(ue_ctx->key,ue_ctx->op,ue_ctx->opc);
}
else if (split[3] == std::string("opc"))
{
ue_ctx->op_configured =false;
get_uint_vec_from_hex_str(split[4],ue_ctx->opc,16);
}
else
{
m_hss_log->error("Neither OP nor OPc configured.\n");
return false;
}
get_uint_vec_from_hex_str(split[5],ue_ctx->amf,2);
get_uint_vec_from_hex_str(split[6],ue_ctx->sqn,6);
m_hss_log->debug("Added user from DB, IMSI: %015lu\n", ue_ctx->imsi);
m_hss_log->debug_hex(ue_ctx->key, 16, "User Key : ");
m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : ");
if(ue_ctx->op_configured){
m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : ");
}
m_hss_log->debug_hex(ue_ctx->opc, 16, "User OPc : ");
m_hss_log->debug_hex(ue_ctx->amf, 2, "AMF : ");
m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN : ");
@ -202,6 +222,21 @@ bool hss::write_db_file(std::string db_filename)
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str() );
//Write comment info
m_db_file << "# " << std::endl
<< "# .csv to store UE's information in HSS " << std::endl
<< "# Kept in the following format: \"Name,IMSI,Key,OP_Type,OP,AMF,SQN\" " << std::endl
<< "# " << std::endl
<< "# Name: Human readable name to help distinguish UE's. Ignored by the HSS " << std::endl
<< "# IMSI: UE's IMSI value " << std::endl
<< "# Key: UE's key, where other keys are derived from. Stored in hexadecimal" << std::endl
<< "# OP_Type: Operator's code type, either OP or OPc " << std::endl
<< "# OP/OPc: Operator Code/Cyphered Operator Code, stored in hexadecimal " << std::endl
<< "# AMF: Authentication management field, stored in hexadecimal " << std::endl
<< "# SQN: UE's Sequence number for freshness of the authentication " << std::endl
<< "# " << std::endl
<< "# Note: Lines starting by '#' are ignored and will be overwritten " << std::endl;
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
@ -211,7 +246,14 @@ bool hss::write_db_file(std::string db_filename)
m_db_file << ",";
m_db_file << hex_string(it->second->key, 16);
m_db_file << ",";
m_db_file << hex_string(it->second->op, 16);
if(it->second->op_configured){
m_db_file << "op,";
m_db_file << hex_string(it->second->op, 16);
}
else{
m_db_file << "opc,";
m_db_file << hex_string(it->second->opc, 16);
}
m_db_file << ",";
m_db_file << hex_string(it->second->amf, 2);
m_db_file << ",";
@ -240,7 +282,7 @@ hss::gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t
ret = gen_auth_info_answer_milenage(imsi, k_asme, autn, rand, xres);
break;
}
increment_sqn(imsi);
increment_ue_sqn(imsi);
return ret;
}
@ -258,7 +300,7 @@ hss::resync_sqn(uint64_t imsi, uint8_t *auts)
ret = resync_sqn_milenage(imsi, auts);
break;
}
increment_sqn(imsi);
increment_ue_sqn(imsi);
return ret;
}
@ -281,10 +323,10 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t opc[16];
uint8_t sqn[6];
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
return false;
}
@ -300,13 +342,13 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
}
m_hss_log->debug_hex(k, 16, "User Key : ");
m_hss_log->debug_hex(op, 16, "User OP : ");
m_hss_log->debug_hex(opc, 16, "User OPc : ");
m_hss_log->debug_hex(last_rand, 16, "User Last Rand : ");
m_hss_log->debug_hex(auts, 16, "AUTS : ");
m_hss_log->debug_hex(sqn_ms_xor_ak, 6, "SQN xor AK : ");
m_hss_log->debug_hex(mac_s, 8, "MAC : ");
security_milenage_f5_star(k, op, last_rand, ak);
security_milenage_f5_star(k, opc, last_rand, ak);
m_hss_log->debug_hex(ak, 6, "Resynch AK : ");
uint8_t sqn_ms[6];
@ -314,22 +356,16 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
sqn_ms[i] = sqn_ms_xor_ak[i] ^ ak[i];
}
m_hss_log->debug_hex(sqn_ms, 6, "SQN MS : ");
m_hss_log->debug_hex(sqn , 6, "SQN HE : ");
m_hss_log->debug_hex(amf, 2, "AMF : ");
uint8_t mac_s_tmp[8];
security_milenage_f1_star(k, op, last_rand, sqn_ms, amf, mac_s_tmp);
security_milenage_f1_star(k, opc, last_rand, sqn_ms, amf, mac_s_tmp);
m_hss_log->debug_hex(mac_s_tmp, 8, "MAC calc : ");
/*
for(int i=0; i<8; i++){
if(!(mac_s_tmp[i] == mac_s[i])){
m_hss_log->error("Calculated MAC does not match sent MAC\n");
return false;
}
}
*/
set_sqn(imsi, sqn_ms);
return true;
@ -340,7 +376,7 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
{
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t opc[16];
uint8_t sqn[6];
uint8_t ck[16];
@ -349,14 +385,14 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
uint8_t mac[8];
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
return false;
}
gen_rand(rand);
security_milenage_f2345( k,
op,
opc,
rand,
xres,
ck,
@ -364,7 +400,7 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
ak);
m_hss_log->debug_hex(k, 16, "User Key : ");
m_hss_log->debug_hex(op, 16, "User OP : ");
m_hss_log->debug_hex(opc, 16, "User OPc : ");
m_hss_log->debug_hex(rand, 16, "User Rand : ");
m_hss_log->debug_hex(xres, 8, "User XRES: ");
m_hss_log->debug_hex(ck, 16, "User CK: ");
@ -372,7 +408,7 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
m_hss_log->debug_hex(ak, 6, "User AK: ");
security_milenage_f1( k,
op,
opc,
rand,
sqn,
amf,
@ -419,7 +455,7 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
{
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t opc[16];
uint8_t sqn[6];
uint8_t xdout[16];
@ -432,7 +468,7 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
int i = 0;
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
return false;
}
@ -453,7 +489,7 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
}
m_hss_log->debug_hex(k, 16, "User Key : ");
m_hss_log->debug_hex(op, 16, "User OP : ");
m_hss_log->debug_hex(opc, 16, "User OPc : ");
m_hss_log->debug_hex(rand, 16, "User Rand : ");
m_hss_log->debug_hex(xres, 8, "User XRES: ");
m_hss_log->debug_hex(ck, 16, "User CK: ");
@ -525,7 +561,7 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
bool
hss::get_k_amf_op_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op, uint8_t *sqn)
hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, uint8_t *sqn)
{
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
@ -539,14 +575,14 @@ hss::get_k_amf_op_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op, uint
m_hss_log->info("Found User %015lu\n",imsi);
memcpy(k, ue_ctx->key, 16);
memcpy(amf, ue_ctx->amf, 2);
memcpy(op, ue_ctx->op, 16);
memcpy(opc, ue_ctx->opc, 16);
memcpy(sqn, ue_ctx->sqn, 6);
return true;
}
void
hss::increment_sqn(uint64_t imsi)
hss::increment_ue_sqn(uint64_t imsi)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
@ -555,23 +591,28 @@ hss::increment_sqn(uint64_t imsi)
return;
}
increment_sqn(ue_ctx->sqn,ue_ctx->sqn);
m_hss_log->debug("Incremented SQN (IMSI: %" PRIu64 ")" PRIu64 "\n", imsi);
m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN: ");
}
void
hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn)
{
// Awkward 48 bit sqn and doing arithmetic
uint64_t sqn = 0;
uint8_t *p = (uint8_t *)&sqn;
uint64_t tmp_sqn = 0;
uint8_t *p = (uint8_t *)&tmp_sqn;
for(int i = 0; i < 6; i++) {
p[5-i] = (uint8_t) ((ue_ctx->sqn[i]));
p[5-i] = sqn[i];
}
sqn++;
m_hss_log->debug("Incremented SQN (IMSI: %" PRIu64 ") SQN: %" PRIu64 "\n", imsi, sqn);
tmp_sqn++;
for(int i = 0; i < 6; i++){
ue_ctx->sqn[i] = p[5-i];
next_sqn[i] = p[5-i];
}
return;
}
void
hss::set_sqn(uint64_t imsi, uint8_t *sqn)
{

@ -223,7 +223,8 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
if( sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS ||
(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) ||
(msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY))
(msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) ||
(msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY))
{
//Only identity response and authentication response are valid as plain NAS.
//Sometimes authentication response and identity are sent as integrity protected,
@ -504,6 +505,9 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
m_s1ap_log->info("User not found. IMSI %015lu\n",emm_ctx->imsi);
return false;
}
//Allocate eKSI for this authentication vector
//Here we assume a new security context thus a new eKSI
emm_ctx->security_ctxt.eksi=0;
//Save the UE context
ue_ctx_t *new_ctx = new ue_ctx_t;
@ -513,7 +517,7 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
m_s1ap->add_ue_to_enb_set(enb_sri->sinfo_assoc_id,ecm_ctx->mme_ue_s1ap_id);
//Pack NAS Authentication Request in Downlink NAS Transport msg
pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand);
pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, emm_ctx->security_ctxt.eksi, autn, rand);
//Send reply to eNB
*reply_flag = true;
@ -593,7 +597,7 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_ue_s1ap_id,
//Save whether ESM information transfer is necessary
ecm_ctx->eit = pdn_con_req.esm_info_transfer_flag_present;
//m_s1ap_log->console("EPS Bearer id: %d\n", eps_bearer_id);
//Add eNB info to UE ctxt
memcpy(&ecm_ctx->enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo));
//Initialize E-RABs
@ -618,7 +622,6 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_ue_s1ap_id,
m_s1ap_log->console("Could not find M-TMSI=0x%x. Sending ID request\n",m_tmsi);
m_s1ap_log->info("Could not find M-TMSI=0x%x. Sending Id Request\n", m_tmsi);
//m_s1ap->add_new_ue_ecm_ctx(ue_ecm_ctx);
//Store temporary ue context
ue_ctx_t *new_ctx = new ue_ctx_t;
@ -776,7 +779,9 @@ s1ap_nas_transport::handle_nas_guti_attach_request( uint32_t enb_ue_s1ap_id,
m_s1ap_log->info("User not found. IMSI %015lu\n",emm_ctx->imsi);
return false;
}
pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand);
//Restarting security context. Reseting eKSI to 0.
emm_ctx->security_ctxt.eksi=0;
pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, emm_ctx->security_ctxt.eksi, autn, rand);
//Send reply to eNB
*reply_flag = true;
@ -1034,6 +1039,7 @@ s1ap_nas_transport::handle_nas_authentication_response(srslte::byte_buffer_t *na
{
m_s1ap_log->console("UE Authentication Accepted.\n");
m_s1ap_log->info("UE Authentication Accepted.\n");
//Send Security Mode Command
emm_ctx->security_ctxt.ul_nas_count = 0; // Reset the NAS uplink counter for the right key k_enb derivation
pack_security_mode_command(reply_buffer, emm_ctx, ecm_ctx);
@ -1199,12 +1205,14 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_
m_s1ap_log->info("User not found. IMSI %015lu\n",imsi);
return false;
}
//Identity reponse from unknown GUTI atach. Assigning new eKSI.
emm_ctx->security_ctxt.eksi=0;
//Store UE context im IMSI map
m_s1ap->add_ue_ctx_to_imsi_map(ue_ctx);
//Pack NAS Authentication Request in Downlink NAS Transport msg
pack_authentication_request(reply_msg, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand);
pack_authentication_request(reply_msg, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, emm_ctx->security_ctxt.eksi, autn, rand);
//Send reply to eNB
*reply_flag = true;
@ -1385,8 +1393,8 @@ s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg
m_s1ap_log->info("Non-EPS authentication unacceptable\n");
break;
case 21:
m_s1ap_log->console("Sequence number synch failure\n");
m_s1ap_log->info("Sequence number synch failure\n");
m_s1ap_log->console("Authentication Failure -- Synchronization Failure\n");
m_s1ap_log->info("Authentication Failure -- Synchronization Failure\n");
if(auth_fail.auth_fail_param_present == false){
m_s1ap_log->error("Missing fail parameter\n");
return false;
@ -1404,8 +1412,11 @@ s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg
m_s1ap_log->info("User not found. IMSI %015lu\n", emm_ctx->imsi);
return false;
}
//Making sure eKSI is different from previous eKSI.
emm_ctx->security_ctxt.eksi = (emm_ctx->security_ctxt.eksi+1)%6;
//Pack NAS Authentication Request in Downlink NAS Transport msg
pack_authentication_request(reply_msg, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand);
pack_authentication_request(reply_msg, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, emm_ctx->security_ctxt.eksi, autn, rand);
//Send reply to eNB
*reply_flag = true;
@ -1417,15 +1428,10 @@ s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg
}
return true;
}
/*
bool
s1ap_nas_transport::handle_detach_request(nas_msg, ue_ctx, reply_buffer, reply_flag)
{
return true;
}*/
/*Packing/Unpacking helper functions*/
bool
s1ap_nas_transport::pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t *autn, uint8_t *rand)
s1ap_nas_transport::pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t eksi, uint8_t *autn, uint8_t *rand)
{
srslte::byte_buffer_t *nas_buffer = m_pool->allocate();
@ -1453,7 +1459,7 @@ s1ap_nas_transport::pack_authentication_request(srslte::byte_buffer_t *reply_msg
memcpy(auth_req.autn , autn, 16);
memcpy(auth_req.rand, rand, 16);
auth_req.nas_ksi.tsc_flag=LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE;
auth_req.nas_ksi.nas_ksi=0;
auth_req.nas_ksi.nas_ksi = eksi;
LIBLTE_ERROR_ENUM err = liblte_mme_pack_authentication_request_msg(&auth_req, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if(err != LIBLTE_SUCCESS)
@ -1590,7 +1596,7 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg,
sm_cmd.selected_nas_sec_algs.type_of_eia = LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_128_EIA1;
sm_cmd.nas_ksi.tsc_flag=LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE;
sm_cmd.nas_ksi.nas_ksi=0;
sm_cmd.nas_ksi.nas_ksi=ue_emm_ctx->security_ctxt.eksi;
//Replay UE security cap
memcpy(sm_cmd.ue_security_cap.eea,ue_emm_ctx->security_ctxt.ue_network_cap.eea,8*sizeof(bool));
@ -1607,8 +1613,6 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg,
sm_cmd.nonce_mme_present=false;
uint8_t sec_hdr_type=3;
// ue_emm_ctx->security_ctxt.dl_nas_count = 0;
LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg(&sm_cmd,sec_hdr_type, ue_emm_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if(err != LIBLTE_SUCCESS)
{
@ -1692,7 +1696,6 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms
uint8_t sec_hdr_type = LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED;
ue_emm_ctx->security_ctxt.dl_nas_count++;
LIBLTE_ERROR_ENUM err = srslte_mme_pack_esm_information_request_msg(&esm_info_req, sec_hdr_type,ue_emm_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if(err != LIBLTE_SUCCESS)
{
@ -1893,7 +1896,7 @@ s1ap_nas_transport::pack_identity_request(srslte::byte_buffer_t *reply_msg, uint
//Setup Dw NAS structure
LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport;
dw_nas->ext=false;
dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_s1ap_id;//FIXME Change name
dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_s1ap_id;
dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_s1ap_id;
dw_nas->HandoverRestrictionList_present=false;
dw_nas->SubscriberProfileIDforRFP_present=false;

@ -1,14 +1,15 @@
#
# .csv to store UE's information in HSS
# Kept in the following format: "Name,IMSI,Key,OP,AMF"
# Kept in the following format: "Name,IMSI,Key,OP_Type,OP,AMF,SQN"
#
# Name: Human readable name to help distinguish UE's. Largely ignored by the HSS
# IMSI: UE's IMSI value
# Key: UE's key, where other keys are derived from. Stored in hexadecimal
# OP: Operator's code, sotred in hexadecimal
# AMF: Authentication management field, stored in hexadecimal
# SQN: UE's Sequence number for freshness of the authentication
# Name: Human readable name to help distinguish UE's. Ignored by the HSS
# IMSI: UE's IMSI value
# Key: UE's key, where other keys are derived from. Stored in hexadecimal
# OP_Type: Operator's code type, either OP or OPc
# OP/OPc: Operator Code/Cyphered Operator Code, stored in hexadecimal
# AMF: Authentication management field, stored in hexadecimal
# SQN: UE's Sequence number for freshness of the authentication
#
# Note: Lines starting by '#' are ignored
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001,000000001234
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000,000000001235
# Note: Lines starting by '#' are ignored and will be overwritten
ue1,001010123456789,00112233445566778899aabbccddeeff,opc,63bfa50ee6523365ff14c1f45f88737d,9001,000000001234
ue2,001010123456780,00112233445566778899aabbccddeeff,opc,63bfa50ee6523365ff14c1f45f88737d,8000,000000001234

@ -110,6 +110,7 @@ private:
auth_algo_t auth_algo;
uint8_t amf[2]; // 3GPP 33.102 v10.0.0 Annex H
uint8_t op[16];
uint8_t opc[16];
uint64_t imsi;
uint64_t imei;
uint8_t k[16];

@ -43,7 +43,9 @@ typedef enum{
typedef struct{
std::string mode;
std::string algo;
bool using_op;
std::string op;
std::string opc;
std::string imsi;
std::string imei;
std::string k;

@ -131,7 +131,8 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
("usim.mode", bpo::value<string>(&args->usim.mode)->default_value("soft"), "USIM mode (soft or pcsc)")
("usim.algo", bpo::value<string>(&args->usim.algo), "USIM authentication algorithm")
("usim.op", bpo::value<string>(&args->usim.op), "USIM operator variant")
("usim.op", bpo::value<string>(&args->usim.op), "USIM operator code")
("usim.opc", bpo::value<string>(&args->usim.opc), "USIM operator code (ciphered variant)")
("usim.imsi", bpo::value<string>(&args->usim.imsi), "USIM IMSI")
("usim.imei", bpo::value<string>(&args->usim.imei), "USIM IMEI")
("usim.k", bpo::value<string>(&args->usim.k), "USIM K")
@ -361,9 +362,27 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
exit(1);
}
bpo::store(bpo::parse_config_file(conf, common), vm);
bpo::notify(vm);
//Check conflicting OP/OPc options and which is being used
if (vm.count("usim.op") && !vm["usim.op"].defaulted() &&
vm.count("usim.opc") && !vm["usim.opc"].defaulted())
{
cout << "Conflicting options OP and OPc. Please configure either one or the other." << endl;
exit(1);
}
else
{
if(vm["usim.op"].defaulted()){
args->usim.using_op = true;
}
else{
args->usim.using_op = false;
}
}
// Apply all_level to any unset layers
if (vm.count("log.all_level")) {
if (!vm.count("log.phy_level")) {

@ -46,11 +46,30 @@ int usim::init(usim_args_t *args, srslte::log *usim_log_)
const char *imei_c = args->imei.c_str();
uint32_t i;
if(32 == args->op.length()) {
str_to_hex(args->op, op);
if(32 == args->k.length()) {
str_to_hex(args->k, k);
} else {
usim_log->error("Invalid length for OP: %zu should be %d\n", args->op.length(), 32);
usim_log->console("Invalid length for OP: %zu should be %d\n", args->op.length(), 32);
usim_log->error("Invalid length for K: %zu should be %d\n", args->k.length(), 32);
usim_log->console("Invalid length for K: %zu should be %d\n", args->k.length(), 32);
}
if(args->using_op)
{
if(32 == args->op.length()) {
str_to_hex(args->op, op);
compute_opc(k,op,opc);
} else {
usim_log->error("Invalid length for OP: %zu should be %d\n", args->op.length(), 32);
usim_log->console("Invalid length for OP: %zu should be %d\n", args->op.length(), 32);
}
}
else{
if(32 == args->opc.length()) {
str_to_hex(args->opc, opc);
} else {
usim_log->error("Invalid length for OPc: %zu should be %d\n", args->opc.length(), 32);
usim_log->console("Invalid length for OPc: %zu should be %d\n", args->opc.length(), 32);
}
}
if(15 == args->imsi.length()) {
@ -77,13 +96,6 @@ int usim::init(usim_args_t *args, srslte::log *usim_log_)
usim_log->console("Invalid length for IMEI: %zu should be %d\n", args->imei.length(), 15);
}
if(32 == args->k.length()) {
str_to_hex(args->k, k);
} else {
usim_log->error("Invalid length for K: %zu should be %d\n", args->k.length(), 32);
usim_log->console("Invalid length for K: %zu should be %d\n", args->k.length(), 32);
}
auth_algo = auth_algo_milenage;
if("xor" == args->algo) {
auth_algo = auth_algo_xor;
@ -341,7 +353,7 @@ auth_result_t usim::gen_auth_res_milenage(uint8_t *rand,
// Use RAND and K to compute RES, CK, IK and AK
security_milenage_f2345( k,
op,
opc,
rand,
res,
ck,
@ -363,7 +375,7 @@ auth_result_t usim::gen_auth_res_milenage(uint8_t *rand,
// Generate MAC
security_milenage_f1( k,
op,
opc,
rand,
sqn,
amf,

@ -78,10 +78,11 @@ int main(int argc, char **argv)
args.imei = "356092040793011";
args.imsi = "208930000000001";
args.k = "8BAF473F2F8FD09487CCCBD7097C6862";
args.using_op = true;
args.op = "11111111111111111111111111111111";
srsue::usim usim;
usim.init(&args, &usim_log);
//assert(usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, res, &res_len, k_asme) == AUTH_OK);
assert(usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, res, &res_len, k_asme) == AUTH_OK);
}

@ -98,7 +98,7 @@ file_max_size = -1
[usim]
mode = soft
algo = xor
op = 63BFA50EE6523365FF14C1F45F88737D
opc = 63BFA50EE6523365FF14C1F45F88737D
k = 00112233445566778899aabbccddeeff
imsi = 001010123456789
imei = 353490069873319

Loading…
Cancel
Save