diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h index 5759c6bc8..816824461 100644 --- a/lib/include/srslte/common/interfaces_common.h +++ b/lib/include/srslte/common/interfaces_common.h @@ -31,30 +31,8 @@ #include "srslte/common/security.h" #include - namespace srslte { -class srslte_nas_config_t -{ -public: - srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "", std::string apn_protocol_ = "", std::string user_ = "", std::string pass_ = "", bool force_imsi_attach_ = false) - :lcid(lcid_), - apn(apn_), - apn_protocol(apn_protocol_), - user(user_), - pass(pass_), - force_imsi_attach(force_imsi_attach_) - {} - - uint32_t lcid; - std::string apn; - std::string apn_protocol; - std::string user; - std::string pass; - bool force_imsi_attach; -}; - - class srslte_gw_config_t { public: diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 6b09a5e5e..e4ced61c7 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -39,13 +39,19 @@ using srslte::byte_buffer_t; namespace srsue { -typedef struct { +class nas_args_t +{ +public: + nas_args_t() : force_imsi_attach(false) {} + std::string apn_name; std::string apn_protocol; std::string apn_user; std::string apn_pass; bool force_imsi_attach; -} nas_args_t; + std::string eia; + std::string eea; +}; // EMM states (3GPP 24.302 v10.0.0) typedef enum { @@ -62,9 +68,6 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED INITIATED", "TRACKING AREA UPDATE INITIATED"}; -static const bool eia_caps[8] = {false, true, true, false, false, false, false, false}; -static const bool eea_caps[8] = {true, true, true, false, false, false, false, false}; - class nas : public nas_interface_rrc, public nas_interface_ue, @@ -72,11 +75,11 @@ class nas { public: nas(); - void init(usim_interface_nas *usim_, - rrc_interface_nas *rrc_, - gw_interface_nas *gw_, - srslte::log *nas_log_, - srslte::srslte_nas_config_t cfg_); + void init(usim_interface_nas* usim_, + rrc_interface_nas* rrc_, + gw_interface_nas* gw_, + srslte::log* nas_log_, + nas_args_t args_); void stop(); emm_state_t get_state(); @@ -105,7 +108,7 @@ private: usim_interface_nas *usim; gw_interface_nas *gw; - srslte::srslte_nas_config_t cfg; + nas_args_t cfg; emm_state_t state; @@ -145,6 +148,8 @@ private: uint8_t transaction_id; // Security + bool eia_caps[8]; + bool eea_caps[8]; uint8_t k_nas_enc[32]; uint8_t k_nas_int[32]; @@ -234,6 +239,20 @@ private: } return true; } + + std::vector split_string(const std::string input) + { + std::vector list; + std::stringstream ss(input); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + if (not substr.empty()) { + list.push_back(atoi(substr.c_str())); + } + } + return list; + } }; } // namespace srsue diff --git a/srsue/hdr/upper/usim_base.h b/srsue/hdr/upper/usim_base.h index ee54cda7c..ddb718d82 100644 --- a/srsue/hdr/upper/usim_base.h +++ b/srsue/hdr/upper/usim_base.h @@ -40,7 +40,10 @@ typedef enum{ auth_algo_xor, }auth_algo_t; -typedef struct{ +class usim_args_t +{ +public: + usim_args_t() : using_op(false) {} std::string mode; std::string algo; bool using_op; @@ -51,7 +54,7 @@ typedef struct{ std::string k; std::string pin; std::string reader; -}usim_args_t; +}; class usim_base :public usim_interface_nas diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 9d640d9ee..863199bad 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -92,6 +92,8 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("nas.user", bpo::value(&args->nas.apn_user)->default_value(""), "Username for CHAP authentication") ("nas.pass", bpo::value(&args->nas.apn_pass)->default_value(""), "Password for CHAP authentication") ("nas.force_imsi_attach", bpo::value(&args->nas.force_imsi_attach)->default_value(false), "Whether to always perform an IMSI attach") + ("nas.eia", bpo::value(&args->nas.eia)->default_value("1,2"), "List of integrity algorithms included in UE capabilities") + ("nas.eea", bpo::value(&args->nas.eea)->default_value("0,1,2"), "List of ciphering algorithms included in UE capabilities") ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 41efc846a..5858a2ffe 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -116,7 +116,6 @@ bool ue::init(all_args_t *args_) { phy_log.push_back(NULL); } - mac_log.set_level(level(args->log.mac_level)); rlc_log.set_level(level(args->log.rlc_level)); pdcp_log.set_level(level(args->log.pdcp_level)); @@ -242,9 +241,7 @@ bool ue::init(all_args_t *args_) { mac.init(&phy, &rlc, &rrc, &mac_log); rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); - - srslte_nas_config_t nas_cfg(1, args->nas.apn_name, args->nas.apn_protocol, args->nas.apn_user, args->nas.apn_pass, args->nas.force_imsi_attach); /* RB_ID_SRB1 */ - nas.init(usim, &rrc, &gw, &nas_log, nas_cfg); + nas.init(usim, &rrc, &gw, &nas_log, args->nas); gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); gw.set_netmask(args->expert.ip_netmask); gw.set_tundevname(args->expert.ip_devname); diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 10e152da5..10c1563d6 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -55,13 +55,12 @@ nas::nas() plmn_is_selected = false; chap_id = 0; memset(ipv6_if_id, 0, sizeof(ipv6_if_id)); + bzero(eia_caps, sizeof(eia_caps)); + bzero(eea_caps, sizeof(eea_caps)); } -void nas::init(usim_interface_nas *usim_, - rrc_interface_nas *rrc_, - gw_interface_nas *gw_, - srslte::log *nas_log_, - srslte::srslte_nas_config_t cfg_) +void nas::init( + usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_, srslte::log* nas_log_, nas_args_t cfg_) { pool = byte_buffer_pool::get_instance(); usim = usim_; @@ -78,6 +77,33 @@ void nas::init(usim_interface_nas *usim_, srslte::mcc_to_bytes(mcc, &home_plmn.mcc[0]); srslte::mnc_to_bytes(mnc, home_plmn.mnc); } + + // parse and sanity check EIA list + std::vector cap_list = split_string(cfg_.eia); + if (cap_list.empty()) { + nas_log->error("Empty EIA list. Select at least one EIA algorithm.\n"); + } + for (std::vector::const_iterator it = cap_list.begin(); it != cap_list.end(); ++it) { + if (*it != 0 && *it < 3) { + eia_caps[*it] = true; + } else { + nas_log->error("EIA%d is not a valid EIA algorithm.\n", *it); + } + } + + // parse and sanity check EEA list + cap_list = split_string(cfg_.eea); + if (cap_list.empty()) { + nas_log->error("Empty EEA list. Select at least one EEA algorithm.\n"); + } + for (std::vector::const_iterator it = cap_list.begin(); it != cap_list.end(); ++it) { + if (*it < 3) { + eea_caps[*it] = true; + } else { + nas_log->error("EEA%d is not a valid EEA algorithm.\n", *it); + } + } + cfg = cfg_; if((read_ctxt_file(&ctxt))) { @@ -1297,7 +1323,7 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { } // Set the optional flags - if (cfg.apn == "") { + if (cfg.apn_name == "") { pdn_con_req.esm_info_transfer_flag_present = false; } else { // request ESM info transfer is APN is specified @@ -1573,29 +1599,24 @@ void nas::send_esm_information_response(const uint8 proc_transaction_id) { esm_info_resp.proc_transaction_id = proc_transaction_id; esm_info_resp.eps_bearer_id = 0; // respone shall always have no bearer assigned - if (cfg.apn == "") { + if (cfg.apn_name == "") { esm_info_resp.apn_present = false; } else { - nas_log->debug("Including APN %s in ESM info response\n", cfg.apn.c_str()); + nas_log->debug("Including APN %s in ESM info response\n", cfg.apn_name.c_str()); esm_info_resp.apn_present = true; - int len = std::min((int)cfg.apn.length(), LIBLTE_STRING_LEN-1); - strncpy(esm_info_resp.apn.apn, cfg.apn.c_str(), len); + int len = std::min((int)cfg.apn_name.length(), LIBLTE_STRING_LEN - 1); + strncpy(esm_info_resp.apn.apn, cfg.apn_name.c_str(), len); esm_info_resp.apn.apn[len] = '\0'; } + if (cfg.apn_user != "" && cfg.apn_user.length() < LIBLTE_STRING_LEN && cfg.apn_pass != "" && + cfg.apn_pass.length() < LIBLTE_STRING_LEN) { - if (cfg.user != "" && cfg.user.length() < LIBLTE_STRING_LEN && - cfg.pass != "" && cfg.pass.length() < LIBLTE_STRING_LEN) { - - nas_log->debug("Including CHAP authentication for user %s in ESM info response\n", cfg.user.c_str()); + nas_log->debug("Including CHAP authentication for user %s in ESM info response\n", cfg.apn_user.c_str()); // Generate CHAP challenge - uint16_t len = 1 /* CHAP code */ + - 1 /* ID */ + - 2 /* complete length */ + - 1 /* data value size */ + - 16 /* data value */ + - cfg.user.length(); + uint16_t len = 1 /* CHAP code */ + 1 /* ID */ + 2 /* complete length */ + 1 /* data value size */ + + 16 /* data value */ + cfg.apn_user.length(); uint8_t challenge[len]; bzero(challenge, len*sizeof(uint8_t)); @@ -1611,8 +1632,8 @@ void nas::send_esm_information_response(const uint8 proc_transaction_id) { } // add user as name field - for (size_t i = 0; i < cfg.user.length(); i++) { - const char *name = cfg.user.c_str(); + for (size_t i = 0; i < cfg.apn_user.length(); i++) { + const char* name = cfg.apn_user.c_str(); challenge[21 + i] = name[i]; } @@ -1626,32 +1647,30 @@ void nas::send_esm_information_response(const uint8 proc_transaction_id) { response[4] = 16; // Generate response value - uint16_t resp_val_len = 16 /* MD5 len */ + - 1 /* ID */ + - cfg.pass.length(); + uint16_t resp_val_len = 16 /* MD5 len */ + 1 /* ID */ + cfg.apn_pass.length(); uint8_t resp_val[resp_val_len]; resp_val[0] = chap_id; // add secret - for (size_t i = 0; i < cfg.pass.length(); i++) { - const char* pass = cfg.pass.c_str(); + for (size_t i = 0; i < cfg.apn_pass.length(); i++) { + const char* pass = cfg.apn_pass.c_str(); resp_val[1 + i] = pass[i]; } // copy original challenge behind secret uint8_t *chal_val = &challenge[5]; - memcpy(&resp_val[1+cfg.pass.length()], chal_val, 16); + memcpy(&resp_val[1 + cfg.apn_pass.length()], chal_val, 16); // Compute MD5 of resp_val and add to response security_md5(resp_val, resp_val_len, &response[5]); // add user as name field again - for (size_t i = 0; i < cfg.user.length(); i++) { - const char *name = cfg.user.c_str(); + for (size_t i = 0; i < cfg.apn_user.length(); i++) { + const char* name = cfg.apn_user.c_str(); response[21 + i] = name[i]; } - // Add challenge and resposne to ESM info response + // Add challenge and response to ESM info response esm_info_resp.protocol_cnfg_opts_present = true; esm_info_resp.protocol_cnfg_opts.opt[0].id = LIBLTE_MME_CONFIGURATION_PROTOCOL_OPTIONS_CHAP; memcpy(esm_info_resp.protocol_cnfg_opts.opt[0].contents, challenge, sizeof(challenge)); diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index 88342c225..d8f9d5b75 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -170,8 +170,9 @@ int security_command_test() usim.init(&args, &usim_log); srsue::nas nas; - srslte_nas_config_t cfg; - ZERO_OBJECT(cfg); + nas_args_t cfg; + cfg.eia = "1,2"; + cfg.eea = "0,1,2"; nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg); // push auth request PDU to NAS to generate security context @@ -230,10 +231,9 @@ int mme_attach_request_test() args.op = "63BFA50EE6523365FF14C1F45F88737D"; usim.init(&args, &usim_log); - srslte_nas_config_t nas_cfg; - ZERO_OBJECT(nas_cfg); + nas_args_t nas_cfg; nas_cfg.force_imsi_attach = true; - nas_cfg.apn = "test123"; + nas_cfg.apn_name = "test123"; srsue::nas nas; srsue::gw gw; @@ -302,11 +302,10 @@ int esm_info_request_test() pool = byte_buffer_pool::get_instance(); srsue::nas nas; - srslte_nas_config_t cfg; - ZERO_OBJECT(cfg); - cfg.apn = "srslte"; - cfg.user = "srsuser"; - cfg.pass = "srspass"; + nas_args_t cfg; + cfg.apn_name = "srslte"; + cfg.apn_user = "srsuser"; + cfg.apn_pass = "srspass"; cfg.force_imsi_attach = true; nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg); diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 7bcff5110..f4bfe10f2 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -124,6 +124,10 @@ imei = 353490069873319 # user: Username for CHAP authentication # pass: Password for CHAP authentication # force_imsi_attach: Whether to always perform an IMSI attach +# eia: List of integrity algorithms included in UE capabilities +# Supported: 1 - Snow3G, 2 - AES +# eea: List of ciphering algorithms included in UE capabilities +# Supported: 0 - NULL, 1 - Snow3G, 2 - AES ##################################################################### [nas] #apn = internetinternet @@ -131,6 +135,8 @@ imei = 353490069873319 #user = srsuser #pass = srspass #force_imsi_attach = false +#eia = 1,2 +#eea = 0,1,2 [gui] enable = false