mirror of https://github.com/PentHertz/srsLTE.git
Merging HSS resynch functionality from David Rupprecht. Resolving conflict in user_db.csv.
This commit is contained in:
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
|
||||
#
|
||||
# algo: Authentication algorithm (xor/milenage)
|
||||
# db_file: Location of .csv file that stores UEs information.
|
||||
#
|
||||
#####################################################################
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "srslte/common/logger_file.h"
|
||||
#include "srslte/common/log_filter.h"
|
||||
#include "srslte/common/buffer_pool.h"
|
||||
#include "srslte/interfaces/epc_interfaces.h"
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
|
@ -56,6 +57,8 @@ typedef struct{
|
|||
uint8_t key[16];
|
||||
uint8_t op[16];
|
||||
uint8_t amf[2];
|
||||
uint8_t sqn[6];
|
||||
uint8_t last_rand[16];
|
||||
}hss_ue_ctx_t;
|
||||
|
||||
enum hss_auth_algo {
|
||||
|
@ -63,7 +66,7 @@ enum hss_auth_algo {
|
|||
HSS_ALGO_MILENAGE
|
||||
};
|
||||
|
||||
class hss
|
||||
class hss : public hss_interface_s1ap
|
||||
{
|
||||
public:
|
||||
static hss* get_instance(void);
|
||||
|
@ -71,18 +74,8 @@ public:
|
|||
int init(hss_args_t *hss_args, srslte::log_filter* hss_log);
|
||||
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_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);
|
||||
|
||||
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);
|
||||
bool resync_sqn(uint64_t imsi, uint8_t *auts);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -90,14 +83,38 @@ private:
|
|||
virtual ~hss();
|
||||
static hss *m_instance;
|
||||
|
||||
uint64_t m_sqn; //48 bits
|
||||
srslte::byte_buffer_pool *m_pool;
|
||||
std::ifstream m_db_file;
|
||||
|
||||
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*/
|
||||
srslte::log_filter *m_hss_log;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ class mme:
|
|||
public:
|
||||
static mme* get_instance(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();
|
||||
int get_s1_mme();
|
||||
void run_thread();
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
static void cleanup();
|
||||
|
||||
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();
|
||||
|
||||
int get_s1_mme();
|
||||
|
@ -103,7 +103,7 @@ private:
|
|||
uint32_t m_plmn;
|
||||
srslte::byte_buffer_pool *m_pool;
|
||||
|
||||
hss *m_hss;
|
||||
hss_interface_s1ap *m_hss;
|
||||
int m_s1mme;
|
||||
std::map<uint16_t, enb_ctx_t*> m_active_enbs;
|
||||
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* get_instance(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_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_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_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_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;
|
||||
|
||||
s1ap* m_s1ap;
|
||||
hss* m_hss;
|
||||
hss_interface_s1ap* m_hss;
|
||||
mme_gtpc* m_mme_gtpc;
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <time.h> /* time */
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "hss/hss.h"
|
||||
#include "srslte/common/security.h"
|
||||
|
@ -39,8 +40,6 @@ hss* hss::m_instance = NULL;
|
|||
boost::mutex hss_instance_mutex;
|
||||
|
||||
hss::hss()
|
||||
// :m_sqn(0x112233445566)
|
||||
:m_sqn(0)
|
||||
{
|
||||
m_pool = srslte::byte_buffer_pool::get_instance();
|
||||
return;
|
||||
|
@ -93,26 +92,25 @@ hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
|
|||
mcc = hss_args->mcc;
|
||||
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->console("HSS Initialized\n");
|
||||
m_hss_log->console("HSS Initialized.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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();
|
||||
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->console("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: %015lu\n", it->second->imsi);
|
||||
delete it->second;
|
||||
m_imsi_to_ue_ctx.erase(it++);
|
||||
}
|
||||
if(m_db_file.is_open())
|
||||
{
|
||||
m_db_file.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -139,6 +137,8 @@ hss::set_auth_algo(std::string auth_algo)
|
|||
bool
|
||||
hss::read_db_file(std::string db_filename)
|
||||
{
|
||||
std::ifstream m_db_file;
|
||||
|
||||
m_db_file.open(db_filename.c_str(), std::ifstream::in);
|
||||
if(!m_db_file.is_open())
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ hss::read_db_file(std::string db_filename)
|
|||
if(line[0] != '#')
|
||||
{
|
||||
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");
|
||||
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[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);
|
||||
|
||||
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 : ");
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -189,10 +238,101 @@ 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);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
|
||||
{
|
||||
|
@ -207,12 +347,11 @@ 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(imsi,k,amf,op))
|
||||
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
gen_rand(rand);
|
||||
get_sqn(sqn);
|
||||
|
||||
security_milenage_f2345( k,
|
||||
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: ");
|
||||
|
||||
set_last_rand(imsi, rand);
|
||||
|
||||
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;
|
||||
|
||||
if(!get_k_amf_op(imsi,k,amf,op))
|
||||
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
gen_rand(rand);
|
||||
get_sqn(sqn);
|
||||
|
||||
// Use RAND and K to compute RES, CK, IK and AK
|
||||
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: ");
|
||||
|
||||
set_last_rand(imsi, rand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
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;
|
||||
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(k, ue_ctx->key, 16);
|
||||
memcpy(amf, ue_ctx->amf, 2);
|
||||
memcpy(op, ue_ctx->op, 16);
|
||||
memcpy(sqn, ue_ctx->sqn, 6);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
m_sqn++;
|
||||
return; //TODO See TS 33.102, Annex C
|
||||
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -426,6 +617,19 @@ hss::gen_rand(uint8_t rand_[16])
|
|||
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*/
|
||||
std::vector<std::string>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
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_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();
|
||||
if (hss->init(&args.hss_args,&hss_log)) {
|
||||
|
@ -319,6 +314,12 @@ main (int argc,char * argv[] )
|
|||
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();
|
||||
if (spgw->init(&args.spgw_args,&spgw_log)) {
|
||||
cout << "Error initializing SP-GW" << endl;
|
||||
|
|
|
@ -70,7 +70,7 @@ mme::cleanup(void)
|
|||
}
|
||||
|
||||
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*/
|
||||
|
@ -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;
|
||||
/*Init S1AP*/
|
||||
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");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ s1ap::cleanup(void)
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
|
@ -77,18 +77,18 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log)
|
|||
//Init log
|
||||
m_s1ap_log = s1ap_log;
|
||||
|
||||
//Get pointer to the HSS
|
||||
m_hss = hss_;
|
||||
|
||||
//Init message handlers
|
||||
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
|
||||
m_s1ap_mngmt_proc->init();
|
||||
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->init();
|
||||
|
||||
|
||||
//Get pointer to the HSS
|
||||
m_hss = hss::get_instance();
|
||||
|
||||
//Get pointer to GTP-C class
|
||||
m_mme_gtpc = mme_gtpc::get_instance();
|
||||
|
||||
|
|
|
@ -64,13 +64,13 @@ s1ap_nas_transport::cleanup(void)
|
|||
}
|
||||
|
||||
void
|
||||
s1ap_nas_transport::init(void)
|
||||
s1ap_nas_transport::init(hss_interface_s1ap * hss_)
|
||||
{
|
||||
m_s1ap = s1ap::get_instance();
|
||||
m_s1ap_log = m_s1ap->m_s1ap_log;
|
||||
m_pool = srslte::byte_buffer_pool::get_instance();
|
||||
|
||||
m_hss = hss::get_instance();
|
||||
m_hss = hss_;
|
||||
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++;
|
||||
break;
|
||||
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);
|
||||
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:
|
||||
m_s1ap_log->warning("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_ERROR_ENUM err = liblte_mme_unpack_identity_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &id_resp);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -612,8 +617,8 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_
|
|||
|
||||
//Send reply to eNB
|
||||
*reply_flag = true;
|
||||
m_s1ap_log->info("Downlink NAS: Sent Athentication Request\n");
|
||||
m_s1ap_log->console("Downlink NAS: Sent Athentication Request\n");
|
||||
m_s1ap_log->info("Downlink NAS: Sent Authentication Request\n");
|
||||
m_s1ap_log->console("Downlink NAS: Sent Authentication Request\n");
|
||||
//TODO Start T3460 Timer!
|
||||
|
||||
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*/
|
||||
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)
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
# 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 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
|
||||
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001
|
||||
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000
|
||||
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001,000000001234
|
||||
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000,000000001235
|
||||
|
|
Loading…
Reference in New Issue