Merging HSS resynch functionality from David Rupprecht. Resolving conflict in user_db.csv.

master
Pedro Alvarez 7 years ago
commit cc9845ef07

@ -0,0 +1,18 @@
#ifndef EPC_INTERFACE_H
#define EPC_INTERFACE_H
#include "srslte/srslte.h"
#include "srslte/common/common.h"
namespace srsepc {
class hss_interface_s1ap
{
public:
virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres) = 0;
virtual bool resync_sqn(uint64_t imsi, uint8_t *auts) = 0;
};
}
#endif // ENB_METRICS_INTERFACE_H

@ -24,6 +24,7 @@ mme_bind_addr = 127.0.1.100
##################################################################### #####################################################################
# HSS configuration # HSS configuration
# #
# algo: Authentication algorithm (xor/milenage)
# db_file: Location of .csv file that stores UEs information. # db_file: Location of .csv file that stores UEs information.
# #
##################################################################### #####################################################################

@ -38,6 +38,7 @@
#include "srslte/common/logger_file.h" #include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/interfaces/epc_interfaces.h"
#include <fstream> #include <fstream>
#include <map> #include <map>
@ -56,6 +57,8 @@ typedef struct{
uint8_t key[16]; uint8_t key[16];
uint8_t op[16]; uint8_t op[16];
uint8_t amf[2]; uint8_t amf[2];
uint8_t sqn[6];
uint8_t last_rand[16];
}hss_ue_ctx_t; }hss_ue_ctx_t;
enum hss_auth_algo { enum hss_auth_algo {
@ -63,7 +66,7 @@ enum hss_auth_algo {
HSS_ALGO_MILENAGE HSS_ALGO_MILENAGE
}; };
class hss class hss : public hss_interface_s1ap
{ {
public: public:
static hss* get_instance(void); static hss* get_instance(void);
@ -71,18 +74,8 @@ public:
int init(hss_args_t *hss_args, srslte::log_filter* hss_log); int init(hss_args_t *hss_args, srslte::log_filter* hss_log);
void stop(void); void stop(void);
bool set_auth_algo(std::string auth_algo);
bool read_db_file(std::string db_file);
void get_sqn(uint8_t sqn[6]);
void gen_rand(uint8_t rand_[16]);
bool get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op);
bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres); bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
bool gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres); bool resync_sqn(uint64_t imsi, uint8_t *auts);
bool gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
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);
private: private:
@ -90,14 +83,38 @@ private:
virtual ~hss(); virtual ~hss();
static hss *m_instance; static hss *m_instance;
uint64_t m_sqn; //48 bits
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool *m_pool;
std::ifstream m_db_file;
std::map<uint64_t,hss_ue_ctx_t*> m_imsi_to_ue_ctx; std::map<uint64_t,hss_ue_ctx_t*> m_imsi_to_ue_ctx;
enum hss_auth_algo m_auth_algo;
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 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);
bool resync_sqn_milenage(uint64_t imsi, uint8_t *auts);
bool resync_sqn_xor(uint64_t imsi, uint8_t *auts);
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 set_sqn(uint64_t imsi, uint8_t *sqn);
void set_last_rand(uint64_t imsi, uint8_t *rand);
void get_last_rand(uint64_t imsi, uint8_t *rand);
bool set_auth_algo(std::string auth_algo);
bool read_db_file(std::string db_file);
bool write_db_file(std::string db_file);
bool get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx);
std::string hex_string(uint8_t *hex, int size);
enum hss_auth_algo m_auth_algo;
std::string db_file;
/*Logs*/ /*Logs*/
srslte::log_filter *m_hss_log; srslte::log_filter *m_hss_log;

@ -66,7 +66,7 @@ class mme:
public: public:
static mme* get_instance(void); static mme* get_instance(void);
static void cleanup(void); static void cleanup(void);
int init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log); int init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_s1ap * hss_);
void stop(); void stop();
int get_s1_mme(); int get_s1_mme();
void run_thread(); void run_thread();

@ -59,7 +59,7 @@ public:
static void cleanup(); static void cleanup();
int enb_listen(); int enb_listen();
int init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log); int init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1ap * hss_);
void stop(); void stop();
int get_s1_mme(); int get_s1_mme();
@ -103,7 +103,7 @@ private:
uint32_t m_plmn; uint32_t m_plmn;
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool *m_pool;
hss *m_hss; hss_interface_s1ap *m_hss;
int m_s1mme; int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs; std::map<uint16_t, enb_ctx_t*> m_active_enbs;
std::map<int32_t, uint16_t> m_sctp_to_enb_id; std::map<int32_t, uint16_t> m_sctp_to_enb_id;

@ -42,7 +42,7 @@ public:
static s1ap_nas_transport* m_instance; static s1ap_nas_transport* m_instance;
static s1ap_nas_transport* get_instance(void); static s1ap_nas_transport* get_instance(void);
static void cleanup(void); static void cleanup(void);
void init(void); void init(hss_interface_s1ap * hss_);
bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
@ -71,6 +71,7 @@ public:
bool handle_esm_information_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag); bool handle_esm_information_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag); bool handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_tracking_area_update_request(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag); bool handle_tracking_area_update_request(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_authentication_failure(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
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 *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 pack_authentication_reject(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
@ -97,7 +98,7 @@ private:
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool *m_pool;
s1ap* m_s1ap; s1ap* m_s1ap;
hss* m_hss; hss_interface_s1ap* m_hss;
mme_gtpc* m_mme_gtpc; mme_gtpc* m_mme_gtpc;
}; };

@ -27,6 +27,7 @@
#include <time.h> /* time */ #include <time.h> /* time */
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <iomanip>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include "hss/hss.h" #include "hss/hss.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
@ -39,8 +40,6 @@ hss* hss::m_instance = NULL;
boost::mutex hss_instance_mutex; boost::mutex hss_instance_mutex;
hss::hss() hss::hss()
// :m_sqn(0x112233445566)
:m_sqn(0)
{ {
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
return; return;
@ -93,26 +92,25 @@ hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
mcc = hss_args->mcc; mcc = hss_args->mcc;
mnc = hss_args->mnc; mnc = hss_args->mnc;
db_file = hss_args->db_file;
m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n", hss_args->db_file.c_str(),hss_args->auth_algo.c_str(), mcc, mnc); m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n", hss_args->db_file.c_str(),hss_args->auth_algo.c_str(), mcc, mnc);
m_hss_log->console("HSS Initialized\n"); m_hss_log->console("HSS Initialized.\n");
return 0; return 0;
} }
void void
hss::stop(void) hss::stop(void)
{ {
write_db_file(db_file);
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin(); std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end()) while(it!=m_imsi_to_ue_ctx.end())
{ {
m_hss_log->info("Deleting UE context in HSS. IMSI: %lu\n", it->second->imsi); m_hss_log->info("Deleting UE context in HSS. IMSI: %015lu\n", it->second->imsi);
m_hss_log->console("Deleting UE context in HSS. IMSI: %lu\n", it->second->imsi); m_hss_log->console("Deleting UE context in HSS. IMSI: %015lu\n", it->second->imsi);
delete it->second; delete it->second;
m_imsi_to_ue_ctx.erase(it++); m_imsi_to_ue_ctx.erase(it++);
} }
if(m_db_file.is_open())
{
m_db_file.close();
}
return; return;
} }
@ -139,6 +137,8 @@ hss::set_auth_algo(std::string auth_algo)
bool bool
hss::read_db_file(std::string db_filename) hss::read_db_file(std::string db_filename)
{ {
std::ifstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ifstream::in); m_db_file.open(db_filename.c_str(), std::ifstream::in);
if(!m_db_file.is_open()) if(!m_db_file.is_open())
{ {
@ -152,7 +152,7 @@ hss::read_db_file(std::string db_filename)
if(line[0] != '#') if(line[0] != '#')
{ {
std::vector<std::string> split = split_string(line,','); std::vector<std::string> split = split_string(line,',');
if(split.size()!=5) if(split.size()!=6)
{ {
m_hss_log->error("Error parsing UE database\n"); m_hss_log->error("Error parsing UE database\n");
return false; return false;
@ -163,16 +163,65 @@ hss::read_db_file(std::string db_filename)
get_uint_vec_from_hex_str(split[2],ue_ctx->key,16); 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[3],ue_ctx->op,16);
get_uint_vec_from_hex_str(split[4],ue_ctx->amf,2); get_uint_vec_from_hex_str(split[4],ue_ctx->amf,2);
get_uint_vec_from_hex_str(split[5],ue_ctx->sqn,6);
m_hss_log->debug("Added user from DB, IMSI: %015lu\n", ue_ctx->imsi); 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->key, 16, "User Key : ");
m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : "); m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : ");
m_hss_log->debug_hex(ue_ctx->amf, 2, "AMF : "); m_hss_log->debug_hex(ue_ctx->amf, 2, "AMF : ");
m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN : ");
m_imsi_to_ue_ctx.insert(std::pair<uint64_t,hss_ue_ctx_t*>(ue_ctx->imsi,ue_ctx)); m_imsi_to_ue_ctx.insert(std::pair<uint64_t,hss_ue_ctx_t*>(ue_ctx->imsi,ue_ctx));
} }
} }
if(m_db_file.is_open())
{
m_db_file.close();
}
return true;
}
bool hss::write_db_file(std::string db_filename)
{
std::string line;
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
std::ofstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ofstream::out);
if(!m_db_file.is_open())
{
return false;
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str() );
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
m_db_file << it->second->name;
m_db_file << ",";
m_db_file << std::setfill('0') << std::setw(15) << it->second->imsi;
m_db_file << ",";
m_db_file << hex_string(it->second->key, 16);
m_db_file << ",";
m_db_file << hex_string(it->second->op, 16);
m_db_file << ",";
m_db_file << hex_string(it->second->amf, 2);
m_db_file << ",";
m_db_file << hex_string(it->second->sqn, 6);
m_db_file << std::endl;
it++;
}
if(m_db_file.is_open())
{
m_db_file.close();
}
return true; return true;
} }
@ -189,8 +238,99 @@ 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); ret = gen_auth_info_answer_milenage(imsi, k_asme, autn, rand, xres);
break; break;
} }
increment_sqn(imsi);
return ret;
}
bool
hss::resync_sqn(uint64_t imsi, uint8_t *auts)
{
bool ret = false;
switch (m_auth_algo)
{
case HSS_ALGO_XOR:
ret = resync_sqn_xor(imsi, auts);
break;
case HSS_ALGO_MILENAGE:
ret = resync_sqn_milenage(imsi, auts);
break;
}
increment_sqn(imsi);
return ret; return ret;
}
bool
hss::resync_sqn_xor(uint64_t imsi, uint8_t *auts)
{
m_hss_log->error("XOR SQN synchronization not supported yet\n");
m_hss_log->console("XOR SQNs synchronization not supported yet\n");
return false;
}
bool
hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
{
uint8_t last_rand[16];
uint8_t ak[6];
uint8_t mac_s[8];
uint8_t sqn_ms_xor_ak[6];
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
{
return false;
}
get_last_rand(imsi, last_rand);
for(int i=0; i<6; i++){
sqn_ms_xor_ak[i] = auts[i];
}
for(int i=0; i<8; i++){
mac_s[i] = auts[i+6];
}
m_hss_log->debug_hex(k, 16, "User Key : ");
m_hss_log->debug_hex(op, 16, "User OP : ");
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);
m_hss_log->debug_hex(ak, 6, "Resynch AK : ");
uint8_t sqn_ms[6];
for(int i=0; i<6; i++){
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(amf, 2, "AMF : ");
uint8_t mac_s_tmp[8];
security_milenage_f1_star(k, op, 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;
} }
bool bool
@ -207,12 +347,11 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
uint8_t mac[8]; uint8_t mac[8];
if(!get_k_amf_op(imsi,k,amf,op)) if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
{ {
return false; return false;
} }
gen_rand(rand); gen_rand(rand);
get_sqn(sqn);
security_milenage_f2345( k, security_milenage_f2345( k,
op, op,
@ -268,6 +407,8 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
m_hss_log->debug_hex(autn, 16, "User AUTN: "); m_hss_log->debug_hex(autn, 16, "User AUTN: ");
set_last_rand(imsi, rand);
return true; return true;
} }
@ -289,12 +430,11 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
int i = 0; int i = 0;
if(!get_k_amf_op(imsi,k,amf,op)) if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
{ {
return false; return false;
} }
gen_rand(rand); gen_rand(rand);
get_sqn(sqn);
// Use RAND and K to compute RES, CK, IK and AK // Use RAND and K to compute RES, CK, IK and AK
for(i=0; i<16; i++) { for(i=0; i<16; i++) {
@ -376,19 +516,16 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
m_hss_log->debug_hex(autn, 8, "User AUTN: "); m_hss_log->debug_hex(autn, 8, "User AUTN: ");
set_last_rand(imsi, rand);
return true; return true;
} }
bool bool
hss::get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op ) hss::get_k_amf_op_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op, uint8_t *sqn)
{ {
/*
uint8_t k_tmp[16] ={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
uint8_t amf_tmp[2]={0x80,0x00};
uint8_t op_tmp[16]={0x63,0xbf,0xA5,0x0E,0xE6,0x52,0x33,0x65,0xFF,0x14,0xC1,0xF4,0x5F,0x88,0x73,0x7D};
*/
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi); std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end()) if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{ {
@ -398,22 +535,76 @@ hss::get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op )
} }
hss_ue_ctx_t *ue_ctx = ue_ctx_it->second; hss_ue_ctx_t *ue_ctx = ue_ctx_it->second;
m_hss_log->info("Found User %015lu\n",imsi); m_hss_log->info("Found User %015lu\n",imsi);
memcpy(k,ue_ctx->key,16); memcpy(k, ue_ctx->key, 16);
memcpy(amf,ue_ctx->amf,2); memcpy(amf, ue_ctx->amf, 2);
memcpy(op,ue_ctx->op,16); memcpy(op, ue_ctx->op, 16);
memcpy(sqn, ue_ctx->sqn, 6);
return true; return true;
} }
void void
hss::get_sqn(uint8_t sqn[6]) hss::increment_sqn(uint64_t imsi)
{ {
for (int i=0; i<6; i++) hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{ {
sqn[i] = ((uint8_t *)&m_sqn)[i]; return;
}
// Awkward 48 bit sqn and doing arithmetic
uint64_t sqn = 0;
uint8_t *p = (uint8_t *)&sqn;
for(int i = 0; i < 6; i++) {
p[5-i] = (uint8_t) ((ue_ctx->sqn[i]));
}
sqn++;
m_hss_log->debug("Incremented SQN (IMSI: %015lu) SQN: %d\n", imsi, sqn);
for(int i = 0; i < 6; i++){
ue_ctx->sqn[i] = p[5-i];
} }
m_sqn++; }
return; //TODO See TS 33.102, Annex C
void
hss::set_sqn(uint64_t imsi, uint8_t *sqn)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
return;
}
memcpy(ue_ctx->sqn, sqn, 6);
}
void
hss::set_last_rand(uint64_t imsi, uint8_t *rand)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
return;
}
memcpy(ue_ctx->last_rand, rand, 16);
}
void
hss::get_last_rand(uint64_t imsi, uint8_t *rand)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
return;
}
memcpy(rand, ue_ctx->last_rand, 16);
} }
void void
@ -426,6 +617,19 @@ hss::gen_rand(uint8_t rand_[16])
return; return;
} }
bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx)
{
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
m_hss_log->info("User not found. IMSI: %015lu\n",imsi);
return false;
}
*ue_ctx = ue_ctx_it->second;
return true;
}
/* Helper functions*/ /* Helper functions*/
std::vector<std::string> std::vector<std::string>
hss::split_string(const std::string &str, char delimiter) hss::split_string(const std::string &str, char delimiter)
@ -454,6 +658,18 @@ hss::get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint le
return; return;
} }
std::string
hss::hex_string(uint8_t *hex, int size)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
for(int i=0;i<size;i++) {
ss << std::setw(2) << static_cast<unsigned>(hex[i]);
}
return ss.str();
}
/* /*
uint64_t uint64_t
string_to_imsi() string_to_imsi()

@ -307,11 +307,6 @@ main (int argc,char * argv[] )
spgw_log.set_level(level(args.log_args.spgw_level)); spgw_log.set_level(level(args.log_args.spgw_level));
spgw_log.set_hex_limit(args.log_args.spgw_hex_limit); spgw_log.set_hex_limit(args.log_args.spgw_hex_limit);
mme *mme = mme::get_instance();
if (mme->init(&args.mme_args, &s1ap_log, &mme_gtpc_log)) {
cout << "Error initializing MME" << endl;
exit(1);
}
hss *hss = hss::get_instance(); hss *hss = hss::get_instance();
if (hss->init(&args.hss_args,&hss_log)) { if (hss->init(&args.hss_args,&hss_log)) {
@ -319,6 +314,12 @@ main (int argc,char * argv[] )
exit(1); exit(1);
} }
mme *mme = mme::get_instance();
if (mme->init(&args.mme_args, &s1ap_log, &mme_gtpc_log, hss)) {
cout << "Error initializing MME" << endl;
exit(1);
}
spgw *spgw = spgw::get_instance(); spgw *spgw = spgw::get_instance();
if (spgw->init(&args.spgw_args,&spgw_log)) { if (spgw->init(&args.spgw_args,&spgw_log)) {
cout << "Error initializing SP-GW" << endl; cout << "Error initializing SP-GW" << endl;

@ -70,7 +70,7 @@ mme::cleanup(void)
} }
int int
mme::init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log) mme::init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_s1ap * hss_)
{ {
/*Init logger*/ /*Init logger*/
@ -78,7 +78,7 @@ mme::init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mm
m_mme_gtpc_log = mme_gtpc_log; m_mme_gtpc_log = mme_gtpc_log;
/*Init S1AP*/ /*Init S1AP*/
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
if(m_s1ap->init(args->s1ap_args, s1ap_log)){ if(m_s1ap->init(args->s1ap_args, s1ap_log, hss_)){
m_s1ap_log->error("Error initializing MME S1APP\n"); m_s1ap_log->error("Error initializing MME S1APP\n");
exit(-1); exit(-1);
} }

@ -67,7 +67,7 @@ s1ap::cleanup(void)
} }
int int
s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log) s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1ap * hss_)
{ {
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
@ -77,18 +77,18 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log)
//Init log //Init log
m_s1ap_log = s1ap_log; m_s1ap_log = s1ap_log;
//Get pointer to the HSS
m_hss = hss_;
//Init message handlers //Init message handlers
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
m_s1ap_mngmt_proc->init(); m_s1ap_mngmt_proc->init();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures
m_s1ap_nas_transport->init(); m_s1ap_nas_transport->init(m_hss);
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures
m_s1ap_ctx_mngmt_proc->init(); m_s1ap_ctx_mngmt_proc->init();
//Get pointer to the HSS
m_hss = hss::get_instance();
//Get pointer to GTP-C class //Get pointer to GTP-C class
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();

@ -64,13 +64,13 @@ s1ap_nas_transport::cleanup(void)
} }
void void
s1ap_nas_transport::init(void) s1ap_nas_transport::init(hss_interface_s1ap * hss_)
{ {
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log; m_s1ap_log = m_s1ap->m_s1ap_log;
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
m_hss = hss::get_instance(); m_hss = hss_;
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
} }
@ -183,9 +183,14 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
//ue_ctx->security_ctxt.ul_nas_count++; //ue_ctx->security_ctxt.ul_nas_count++;
break; break;
case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST: case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST:
m_s1ap_log->info("UL NAS: Tracking Area Update Request\n"); m_s1ap_log->info("Uplink NAS: Tracking Area Update Request\n");
handle_tracking_area_update_request(nas_msg, ue_ctx, reply_buffer, reply_flag); handle_tracking_area_update_request(nas_msg, ue_ctx, reply_buffer, reply_flag);
break; break;
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
m_s1ap_log->info("Uplink NAS: Authentication Failure\n");
handle_authentication_failure(nas_msg, ue_ctx, reply_buffer, reply_flag);
ue_ctx->security_ctxt.ul_nas_count++;
break;
default: default:
m_s1ap_log->warning("Unhandled NAS message 0x%x\n", msg_type ); m_s1ap_log->warning("Unhandled NAS message 0x%x\n", msg_type );
m_s1ap_log->console("Unhandled NAS message 0x%x\n", msg_type ); m_s1ap_log->console("Unhandled NAS message 0x%x\n", msg_type );
@ -587,7 +592,7 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp; LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp;
LIBLTE_ERROR_ENUM err = liblte_mme_unpack_identity_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &id_resp); LIBLTE_ERROR_ENUM err = liblte_mme_unpack_identity_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &id_resp);
if(err != LIBLTE_SUCCESS){ if(err != LIBLTE_SUCCESS){
m_s1ap_log->error("Error unpacking NAS authentication response. Error: %s\n", liblte_error_text[err]); m_s1ap_log->error("Error unpacking NAS identity response. Error: %s\n", liblte_error_text[err]);
return false; return false;
} }
@ -612,8 +617,8 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_
//Send reply to eNB //Send reply to eNB
*reply_flag = true; *reply_flag = true;
m_s1ap_log->info("Downlink NAS: Sent Athentication Request\n"); m_s1ap_log->info("Downlink NAS: Sent Authentication Request\n");
m_s1ap_log->console("Downlink NAS: Sent Athentication Request\n"); m_s1ap_log->console("Downlink NAS: Sent Authentication Request\n");
//TODO Start T3460 Timer! //TODO Start T3460 Timer!
return true; return true;
@ -693,6 +698,66 @@ s1ap_nas_transport::handle_tracking_area_update_request(srslte::byte_buffer_t *n
} }
bool
s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag)
{
uint8_t autn[16];
uint8_t rand[16];
uint8_t xres[8];
LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT auth_fail;
LIBLTE_ERROR_ENUM err = liblte_mme_unpack_authentication_failure_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &auth_fail);
if(err != LIBLTE_SUCCESS){
m_s1ap_log->error("Error unpacking NAS authentication failure. Error: %s\n", liblte_error_text[err]);
return false;
}
switch(auth_fail.emm_cause){
case 20:
m_s1ap_log->console("MAC code failure\n");
m_s1ap_log->info("MAC code failure\n");
break;
case 26:
m_s1ap_log->console("Non-EPS authentication unacceptable\n");
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");
if(auth_fail.auth_fail_param_present == false){
m_s1ap_log->error("Missing fail parameter\n");
return false;
}
if(!m_hss->resync_sqn(ue_ctx->imsi, auth_fail.auth_fail_param))
{
m_s1ap_log->console("Resynchronization failed. IMSI %015lu\n", ue_ctx->imsi);
m_s1ap_log->info("Resynchronization failed. IMSI %015lu\n", ue_ctx->imsi);
return false;
}
//Get Authentication Vectors from HSS
if(!m_hss->gen_auth_info_answer(ue_ctx->imsi, ue_ctx->security_ctxt.k_asme, autn, rand, ue_ctx->security_ctxt.xres))
{
m_s1ap_log->console("User not found. IMSI %015lu\n", ue_ctx->imsi);
m_s1ap_log->info("User not found. IMSI %015lu\n", ue_ctx->imsi);
return false;
}
//Pack NAS Authentication Request in Downlink NAS Transport msg
pack_authentication_request(reply_msg, ue_ctx->enb_ue_s1ap_id, ue_ctx->mme_ue_s1ap_id, autn, rand);
//Send reply to eNB
*reply_flag = true;
m_s1ap_log->info("Downlink NAS: Sent Authentication Request\n");
m_s1ap_log->console("Downlink NAS: Sent Authentication Request\n");
//TODO Start T3460 Timer!
break;
}
return true;
}
/*Packing/Unpacking helper functions*/ /*Packing/Unpacking helper functions*/
bool 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 *autn, uint8_t *rand)

@ -6,8 +6,9 @@
# IMSI: UE's IMSI value # IMSI: UE's IMSI value
# Key: UE's key, where other keys are derived from. Stored in hexadecimal # Key: UE's key, where other keys are derived from. Stored in hexadecimal
# OP: Operator's code, sotred in hexadecimal # OP: Operator's code, sotred in hexadecimal
# AMF: Authentication management feild, 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 # Note: Lines starting by '#' are ignored
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001 ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001,000000001234
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000 ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000,000000001235

Loading…
Cancel
Save