diff --git a/srsue/hdr/stack/upper/pcsc_usim.h b/srsue/hdr/stack/upper/pcsc_usim.h index 97bee2a6e..d0dd9f1e8 100644 --- a/srsue/hdr/stack/upper/pcsc_usim.h +++ b/srsue/hdr/stack/upper/pcsc_usim.h @@ -32,18 +32,6 @@ namespace srsue { -#define AKA_RAND_LEN 16 -#define AKA_AUTN_LEN 16 -#define AKA_AUTS_LEN 14 -#define RES_MAX_LEN 16 -#define MAC_LEN 8 -#define IK_LEN 16 -#define CK_LEN 16 -#define AK_LEN 6 -#define SQN_LEN 6 - -#define KEY_LEN 32 - typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types_t; static inline uint16_t to_uint16(const uint8_t* a) @@ -60,13 +48,6 @@ public: void stop(); // NAS interface - std::string get_imsi_str(); - std::string get_imei_str(); - - bool get_imsi_vec(uint8_t* imsi_, uint32_t n); - bool get_imei_vec(uint8_t* imei_, uint32_t n); - bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id); - auth_result_t generate_authentication_response(uint8_t* rand, uint8_t* autn_enb, uint16_t mcc, @@ -75,50 +56,7 @@ public: int* res_len, uint8_t* k_asme); - void generate_nas_keys(uint8_t* k_asme, - uint8_t* k_nas_enc, - uint8_t* k_nas_int, - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); - - // RRC interface - void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg); - void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg); - void store_keys_before_ho(const srslte::as_security_config_t& as_ctx); - void restore_keys_from_failed_ho(srslte::as_security_config_t* as_ctx); - private: - srslte::log* log = nullptr; - - // User data - // 3GPP 33.102 v10.0.0 Annex H - uint64_t imsi = 0; - uint64_t imei = 0; - - std::string imsi_str; - std::string imei_str; - - uint32_t mnc_length = 0; - - // Security variables - uint8_t ck[CK_LEN] = {}; - uint8_t ik[IK_LEN] = {}; - uint8_t ak[AK_LEN] = {}; - uint8_t k_asme[KEY_LEN] = {}; - uint8_t nh[KEY_LEN] = {}; - uint8_t k_enb[KEY_LEN] = {}; - uint8_t k_enb_star[KEY_LEN] = {}; - uint8_t auts[AKA_AUTS_LEN] = {}; - - // Helpers to restore security context if HO fails - uint8_t old_k_enb[32] = {}; - uint8_t old_ncc = {}; - srslte::as_security_config_t old_as_ctx = {}; - - uint32_t current_ncc = 0; - - bool initiated = false; - // Smartcard sub-class which is a port of the PC/SC smartcard implementation // of WPA Supplicant written by Jouni Malinen and licensed under BSD // Source: https://w1.fi/cvs.html diff --git a/srsue/hdr/stack/upper/usim.h b/srsue/hdr/stack/upper/usim.h index f8a4b9442..72a6d81be 100644 --- a/srsue/hdr/stack/upper/usim.h +++ b/srsue/hdr/stack/upper/usim.h @@ -39,13 +39,6 @@ public: void stop(); // NAS interface - std::string get_imsi_str(); - std::string get_imei_str(); - - bool get_imsi_vec(uint8_t* imsi_, uint32_t n); - bool get_imei_vec(uint8_t* imei_, uint32_t n); - bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id); - auth_result_t generate_authentication_response(uint8_t* rand, uint8_t* autn_enb, uint16_t mcc, @@ -54,18 +47,6 @@ public: int* res_len, uint8_t* k_asme); - void generate_nas_keys(uint8_t* k_asme, - uint8_t* k_nas_enc, - uint8_t* k_nas_int, - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); - - // RRC interface - void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg); - void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg); - void store_keys_before_ho(const srslte::as_security_config_t& as_ctx); - void restore_keys_from_failed_ho(srslte::as_security_config_t* as_ctx); - private: auth_result_t gen_auth_res_milenage(uint8_t* rand, uint8_t* autn_enb, @@ -83,42 +64,16 @@ private: uint8_t* k_asme); void str_to_hex(std::string str, uint8_t* hex); - srslte::log* usim_log = nullptr; - // User data auth_algo_t auth_algo = auth_algo_milenage; uint8_t amf[2] = {}; // 3GPP 33.102 v10.0.0 Annex H uint8_t op[16] = {}; uint8_t opc[16] = {}; - uint64_t imsi = 0; - uint64_t imei = 0; uint8_t k[16] = {}; - std::string imsi_str; - std::string imei_str; - // Security variables - uint8_t ck[16] = {}; - uint8_t ik[16] = {}; - uint8_t ak[6] = {}; - uint8_t mac[8] = {}; - uint8_t autn[16] = {}; - uint8_t k_asme[32] = {}; - uint8_t nh[32] = {}; - uint8_t k_enb_initial[32] = {}; - uint8_t k_enb[32] = {}; - uint8_t k_enb_star[32] = {}; - - // Helpers to restore security context if HO fails - bool old_is_first_ncc = {}; - uint8_t old_k_enb[32] = {}; - uint8_t old_ncc = {}; - srslte::as_security_config_t old_as_ctx = {}; - - uint32_t current_ncc = 0; - bool is_first_ncc = false; - - bool initiated = false; + uint8_t mac[8] = {}; + uint8_t autn[16] = {}; }; } // namespace srsue diff --git a/srsue/hdr/stack/upper/usim_base.h b/srsue/hdr/stack/upper/usim_base.h index 26e0481ed..9a2360ba1 100644 --- a/srsue/hdr/stack/upper/usim_base.h +++ b/srsue/hdr/stack/upper/usim_base.h @@ -30,6 +30,18 @@ namespace srsue { +#define AKA_RAND_LEN 16 +#define AKA_AUTN_LEN 16 +#define AKA_AUTS_LEN 14 +#define RES_MAX_LEN 16 +#define MAC_LEN 8 +#define IK_LEN 16 +#define CK_LEN 16 +#define AK_LEN 6 +#define SQN_LEN 6 + +#define KEY_LEN 32 + typedef enum { auth_algo_milenage = 0, auth_algo_xor, @@ -54,7 +66,7 @@ public: class usim_base : public usim_interface_nas, public usim_interface_rrc { public: - usim_base(); + usim_base(srslte::log* log_); virtual ~usim_base(); static std::unique_ptr get_instance(usim_args_t* args, srslte::log* log_); @@ -62,12 +74,12 @@ public: virtual void stop() = 0; // NAS interface - virtual std::string get_imsi_str() = 0; - virtual std::string get_imei_str() = 0; + std::string get_imsi_str() final; + std::string get_imei_str() final; - virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; - virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0; - virtual bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) = 0; + bool get_imsi_vec(uint8_t* imsi_, uint32_t n) final; + bool get_imei_vec(uint8_t* imei_, uint32_t n) final; + bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) final; virtual auth_result_t generate_authentication_response(uint8_t* rand, uint8_t* autn_enb, @@ -77,15 +89,51 @@ public: int* res_len, uint8_t* k_asme) = 0; - virtual void generate_nas_keys(uint8_t* k_asme, - uint8_t* k_nas_enc, - uint8_t* k_nas_int, - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; + void generate_nas_keys(uint8_t* k_asme, + uint8_t* k_nas_enc, + uint8_t* k_nas_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) final; // RRC interface - virtual void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) = 0; - virtual void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) = 0; + void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) final; + void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) final; + void store_keys_before_ho(const srslte::as_security_config_t& as_ctx) final; + void restore_keys_from_failed_ho(srslte::as_security_config_t* as_ctx) final; + +protected: + bool initiated = false; + + // Logging + srslte::log* log = nullptr; + + // User data + // 3GPP 33.102 v10.0.0 Annex H + uint64_t imsi = 0; + uint64_t imei = 0; + std::string imsi_str; + std::string imei_str; + uint32_t mnc_length = 0; + + // Security variables + uint8_t ck[CK_LEN] = {}; + uint8_t ik[IK_LEN] = {}; + uint8_t ak[AK_LEN] = {}; + uint8_t k_asme[KEY_LEN] = {}; + uint8_t nh[KEY_LEN] = {}; + uint8_t k_enb[KEY_LEN] = {}; + uint8_t k_enb_star[KEY_LEN] = {}; + uint8_t k_enb_initial[KEY_LEN] = {}; + uint8_t auts[AKA_AUTS_LEN] = {}; + + // Helpers to restore security context if HO fails + bool old_is_first_ncc = false; + uint8_t old_k_enb[32] = {}; + uint8_t old_ncc = {}; + srslte::as_security_config_t old_as_ctx = {}; + + uint32_t current_ncc = 0; + bool is_first_ncc = false; }; } // namespace srsue diff --git a/srsue/src/stack/upper/pcsc_usim.cc b/srsue/src/stack/upper/pcsc_usim.cc index 2df9fb959..b5eb2af81 100644 --- a/srsue/src/stack/upper/pcsc_usim.cc +++ b/srsue/src/stack/upper/pcsc_usim.cc @@ -31,7 +31,7 @@ using namespace srslte; namespace srsue { -pcsc_usim::pcsc_usim(srslte::log* log_) : log(log_) +pcsc_usim::pcsc_usim(srslte::log* log_) : usim_base(log_) { bzero(ck, CK_LEN); bzero(ik, IK_LEN); @@ -107,87 +107,6 @@ void pcsc_usim::stop() {} NAS interface *******************************************************************************/ -std::string pcsc_usim::get_imsi_str() -{ - return imsi_str; -} -std::string pcsc_usim::get_imei_str() -{ - return imei_str; -} - -bool pcsc_usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return false; - } - - if (NULL == imsi_ || n < 15) { - log->error("Invalid parameters to get_imsi_vec"); - return false; - } - - uint64_t temp = imsi; - for (int i = 14; i >= 0; i--) { - imsi_[i] = temp % 10; - temp /= 10; - } - return true; -} - -bool pcsc_usim::get_imei_vec(uint8_t* imei_, uint32_t n) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return false; - } - - if (NULL == imei_ || n < 15) { - log->error("Invalid parameters to get_imei_vec"); - return false; - } - - uint64 temp = imei; - for (int i = 14; i >= 0; i--) { - imei_[i] = temp % 10; - temp /= 10; - } - return true; -} - -bool pcsc_usim::get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return false; - } - - uint8_t imsi_vec[15]; - get_imsi_vec(imsi_vec, 15); - - std::ostringstream plmn_str; - - int mcc_len = 3; - for (int i = 0; i < mcc_len; i++) { - plmn_str << (int)imsi_vec[i]; - } - - int mnc_len = sc.get_mnc_len(); - for (int i = mcc_len; i < mcc_len + mnc_len; i++) { - plmn_str << (int)imsi_vec[i]; - } - - if (home_plmn_id->from_string(plmn_str.str())) { - log->error("Error reading home PLMN from SIM.\n"); - return false; - } - - log->info("Read Home PLMN Id=%s\n", home_plmn_id->to_string().c_str()); - - return true; -} - auth_result_t pcsc_usim::generate_authentication_response(uint8_t* rand, uint8_t* autn_enb, uint16_t mcc, @@ -244,116 +163,6 @@ auth_result_t pcsc_usim::generate_authentication_response(uint8_t* rand, return ret; } -void pcsc_usim::generate_nas_keys(uint8_t* k_asme, - uint8_t* k_nas_enc, - uint8_t* k_nas_int, - CIPHERING_ALGORITHM_ID_ENUM cipher_algo, - INTEGRITY_ALGORITHM_ID_ENUM integ_algo) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return; - } - - // Generate K_nas_enc and K_nas_int - security_generate_k_nas(k_asme, cipher_algo, integ_algo, k_nas_enc, k_nas_int); -} - -/******************************************************************************* - RRC interface -*******************************************************************************/ - -void pcsc_usim::generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return; - } - - // Generate K_enb - security_generate_k_enb(k_asme, count_ul, k_enb); - - memcpy(this->k_asme, k_asme, 32); - - // Generate K_rrc_enc and K_rrc_int - security_generate_k_rrc( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_int.data()); - - // Generate K_up_enc and K_up_int - security_generate_k_up( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_up_enc.data(), sec_cfg->k_up_int.data()); - - current_ncc = 0; -} - -void pcsc_usim::generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return; - } - - uint8_t* enb_star_key = k_enb; - - if (ncc < 0) { - ncc = current_ncc; - } - - // Generate successive NH - while (current_ncc != (uint32_t)ncc) { - uint8_t* sync = NULL; - if (current_ncc) { - sync = nh; - } else { - sync = k_enb; - } - // Generate NH - security_generate_nh(k_asme, sync, nh); - - current_ncc++; - if (current_ncc == 7) { - current_ncc = 0; - } - enb_star_key = nh; - } - - // Generate K_enb - security_generate_k_enb_star(enb_star_key, pci, earfcn, k_enb_star); - - // K_enb becomes K_enb* - memcpy(k_enb, k_enb_star, 32); - - // Generate K_rrc_enc and K_rrc_int - security_generate_k_rrc( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_int.data()); - - // Generate K_up_enc and K_up_int - security_generate_k_up( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_up_enc.data(), sec_cfg->k_up_int.data()); -} - -void pcsc_usim::store_keys_before_ho(const srslte::as_security_config_t& as_ctx) -{ - INFO("Storing AS Keys pre-handover. NCC=%d\n", current_ncc); - old_as_ctx = as_ctx; - old_ncc = current_ncc; - memcpy(old_k_enb, k_enb, 32); - return; -} - -void pcsc_usim::restore_keys_from_failed_ho(srslte::as_security_config_t* as_ctx) -{ - INFO("Restoring Keys from failed handover. NCC=%d\n", old_ncc); - *as_ctx = old_as_ctx; - current_ncc = old_ncc; - memcpy(k_enb, old_k_enb, 32); - return; -} - -/******************************************************************************* - Helpers -*******************************************************************************/ - /********************************* * PC/SC class ********************************/ @@ -1240,7 +1049,9 @@ int pcsc_usim::scard::umts_auth(const unsigned char* _rand, // Authentication error, application specific log->warning("SCARD: UMTS auth failed - MAC != XMAC\n"); return -1; - } else if (len != 2 || resp[0] != 0x61) { + } + + if (len != 2 || resp[0] != 0x61) { log->warning( "SCARD: unexpected response for UMTS auth request (len=%ld resp=%02x %02x)\n", (long)len, resp[0], resp[1]); return -1; @@ -1259,7 +1070,9 @@ int pcsc_usim::scard::umts_auth(const unsigned char* _rand, log->debug_hex(auts, AKA_AUTS_LEN, "SCARD: AUTS\n"); *res_len = AKA_AUTS_LEN; return -2; - } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { + } + + if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { pos = buf + 1; end = buf + len; diff --git a/srsue/src/stack/upper/usim.cc b/srsue/src/stack/upper/usim.cc index e0a463bf5..496b744f7 100644 --- a/srsue/src/stack/upper/usim.cc +++ b/srsue/src/stack/upper/usim.cc @@ -27,7 +27,7 @@ using namespace srslte; namespace srsue { -usim::usim(srslte::log* log_) : usim_log(log_) {} +usim::usim(srslte::log* log_) : usim_base(log_) {} int usim::init(usim_args_t* args) { @@ -45,7 +45,7 @@ int usim::init(usim_args_t* args) 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); + log->error("Invalid length for K: %zu should be %d\n", args->k.length(), 32); srslte::console("Invalid length for K: %zu should be %d\n", args->k.length(), 32); } @@ -55,14 +55,14 @@ int usim::init(usim_args_t* args) 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); + log->error("Invalid length for OP: %zu should be %d\n", args->op.length(), 32); srslte::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); + log->error("Invalid length for OPc: %zu should be %d\n", args->opc.length(), 32); srslte::console("Invalid length for OPc: %zu should be %d\n", args->opc.length(), 32); } } @@ -75,7 +75,7 @@ int usim::init(usim_args_t* args) imsi += imsi_c[i] - '0'; } } else { - usim_log->error("Invalid length for IMSI: %zu should be %d\n", args->imsi.length(), 15); + log->error("Invalid length for IMSI: %zu should be %d\n", args->imsi.length(), 15); srslte::console("Invalid length for IMSI: %zu should be %d\n", args->imsi.length(), 15); } @@ -86,7 +86,7 @@ int usim::init(usim_args_t* args) imei += imei_c[i] - '0'; } } else { - usim_log->error("Invalid length for IMEI: %zu should be %d\n", args->imei.length(), 15); + log->error("Invalid length for IMEI: %zu should be %d\n", args->imei.length(), 15); srslte::console("Invalid length for IMEI: %zu should be %d\n", args->imei.length(), 15); } @@ -101,90 +101,6 @@ void usim::stop() {} NAS interface *******************************************************************************/ -std::string usim::get_imsi_str() -{ - return imsi_str; -} -std::string usim::get_imei_str() -{ - return imei_str; -} - -bool usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return false; - } - - if (NULL == imsi_ || n < 15) { - usim_log->error("Invalid parameters to get_imsi_vec\n"); - return false; - } - - uint64_t temp = imsi; - for (int i = 14; i >= 0; i--) { - imsi_[i] = temp % 10; - temp /= 10; - } - return true; -} - -bool usim::get_imei_vec(uint8_t* imei_, uint32_t n) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return false; - } - - if (NULL == imei_ || n < 15) { - usim_log->error("Invalid parameters to get_imei_vec\n"); - return false; - } - - uint64 temp = imei; - for (int i = 14; i >= 0; i--) { - imei_[i] = temp % 10; - temp /= 10; - } - return true; -} - -bool usim::get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) -{ - if (!initiated) { - ERROR("USIM not initiated!\n"); - return false; - } - - int mcc_len = 3; - int mnc_len = 2; - - uint8_t imsi_vec[15]; - get_imsi_vec(imsi_vec, 15); - - std::ostringstream mcc_str, mnc_str; - - for (int i = 0; i < mcc_len; i++) { - mcc_str << (int)imsi_vec[i]; - } - - // US MCC uses 3 MNC digits - if (!mcc_str.str().compare("310") || !mcc_str.str().compare("311") || !mcc_str.str().compare("312") || - !mcc_str.str().compare("313") || !mcc_str.str().compare("316")) { - mnc_len = 3; - } - for (int i = mcc_len; i < mcc_len + mnc_len; i++) { - mnc_str << (int)imsi_vec[i]; - } - - home_plmn_id->from_string(mcc_str.str() + mnc_str.str()); - - usim_log->info("Read Home PLMN Id=%s\n", home_plmn_id->to_string().c_str()); - - return true; -} - auth_result_t usim::generate_authentication_response(uint8_t* rand, uint8_t* autn_enb, uint16_t mcc, @@ -200,118 +116,6 @@ auth_result_t usim::generate_authentication_response(uint8_t* rand, } } -void usim::generate_nas_keys(uint8_t* k_asme_, - uint8_t* k_nas_enc, - uint8_t* k_nas_int, - CIPHERING_ALGORITHM_ID_ENUM cipher_algo, - INTEGRITY_ALGORITHM_ID_ENUM integ_algo) -{ - // Generate K_nas_enc and K_nas_int - security_generate_k_nas(k_asme_, cipher_algo, integ_algo, k_nas_enc, k_nas_int); -} - -/******************************************************************************* - RRC interface -*******************************************************************************/ - -void usim::generate_as_keys(uint8_t* k_asme_, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) -{ - // Generate K_enb - security_generate_k_enb(k_asme_, count_ul, k_enb); - - memcpy(k_asme, k_asme_, 32); - - // Save initial k_enb - memcpy(k_enb_initial, k_enb, 32); - - // Generate K_rrc_enc and K_rrc_int - security_generate_k_rrc( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_int.data()); - - // Generate K_up_enc and K_up_int - security_generate_k_up( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_up_enc.data(), sec_cfg->k_up_int.data()); - - current_ncc = 0; - is_first_ncc = true; -} - -void usim::generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) -{ - usim_log->info("Generating AS Keys HO. PCI 0x%02x, DL-EARFCN %d, NCC %d\n", pci, earfcn, ncc); - usim_log->info_hex(k_enb, 32, "Old K_eNB"); - - uint8_t* enb_star_key = k_enb; - - if (ncc < 0) { - ncc = current_ncc; - } - - // Generate successive NH - while (current_ncc != (uint32_t)ncc) { - uint8_t* sync = NULL; - if (is_first_ncc) { - usim_log->debug("Using K_enb_initial for sync. 0x%02x, DL-EARFCN %d, NCC %d\n", pci, earfcn, current_ncc); - sync = k_enb_initial; - is_first_ncc = false; - } else { - usim_log->debug("Using NH for sync. 0x%02x, DL-EARFCN %d, NCC %d\n", pci, earfcn, current_ncc); - sync = nh; - } - // Generate NH - security_generate_nh(k_asme, sync, nh); - - current_ncc++; - if (current_ncc == 8) { - current_ncc = 0; - } - enb_star_key = nh; - } - - // Generate K_enb - security_generate_k_enb_star(enb_star_key, pci, earfcn, k_enb_star); - - // K_enb becomes K_enb* - memcpy(k_enb, k_enb_star, 32); - - // Generate K_rrc_enc and K_rrc_int - security_generate_k_rrc( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_int.data()); - - // Generate K_up_enc and K_up_int - security_generate_k_up( - k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_up_enc.data(), sec_cfg->k_up_int.data()); - - usim_log->info_hex(k_enb, 32, "HO K_eNB"); - usim_log->info_hex(sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_enc.size(), "HO K_RRC_enc"); - usim_log->info_hex(sec_cfg->k_rrc_int.data(), sec_cfg->k_rrc_int.size(), "HO K_RRC_int"); -} - -void usim::store_keys_before_ho(const srslte::as_security_config_t& as_ctx) -{ - usim_log->info("Storing AS Keys pre-handover. NCC=%d\n", current_ncc); - usim_log->info_hex(k_enb, 32, "Old K_eNB"); - usim_log->info_hex(as_ctx.k_rrc_enc.data(), as_ctx.k_rrc_enc.size(), "Old K_RRC_enc"); - usim_log->info_hex(as_ctx.k_rrc_enc.data(), as_ctx.k_rrc_enc.size(), "Old K_RRC_enc"); - usim_log->info_hex(as_ctx.k_rrc_int.data(), as_ctx.k_rrc_int.size(), "Old K_RRC_int"); - usim_log->info_hex(as_ctx.k_rrc_int.data(), as_ctx.k_rrc_int.size(), "Old K_RRC_int"); - old_is_first_ncc = is_first_ncc; - old_as_ctx = as_ctx; - old_ncc = current_ncc; - memcpy(old_k_enb, k_enb, 32); - return; -} - -void usim::restore_keys_from_failed_ho(srslte::as_security_config_t* as_ctx) -{ - usim_log->info("Restoring Keys from failed handover. NCC=%d\n", old_ncc); - is_first_ncc = old_is_first_ncc; - *as_ctx = old_as_ctx; - current_ncc = old_ncc; - memcpy(k_enb, old_k_enb, 32); - return; -} - /******************************************************************************* Helpers *******************************************************************************/ diff --git a/srsue/src/stack/upper/usim_base.cc b/srsue/src/stack/upper/usim_base.cc index bfec6088a..a2ab22c30 100644 --- a/srsue/src/stack/upper/usim_base.cc +++ b/srsue/src/stack/upper/usim_base.cc @@ -40,8 +40,217 @@ std::unique_ptr usim_base::get_instance(usim_args_t* args, srslte::lo return std::unique_ptr(new usim(log_)); } -usim_base::usim_base() {} +usim_base::usim_base(srslte::log* _log) : log(_log) {} usim_base::~usim_base() {} +/* + * NAS Interface + */ +std::string usim_base::get_imsi_str() +{ + return imsi_str; +} +std::string usim_base::get_imei_str() +{ + return imei_str; +} + +bool usim_base::get_imsi_vec(uint8_t* imsi_, uint32_t n) +{ + if (!initiated) { + ERROR("USIM not initiated!\n"); + return false; + } + + if (NULL == imsi_ || n < 15) { + log->error("Invalid parameters to get_imsi_vec\n"); + return false; + } + + uint64_t temp = imsi; + for (int i = 14; i >= 0; i--) { + imsi_[i] = temp % 10; + temp /= 10; + } + return true; +} + +bool usim_base::get_imei_vec(uint8_t* imei_, uint32_t n) +{ + if (!initiated) { + ERROR("USIM not initiated!\n"); + return false; + } + + if (NULL == imei_ || n < 15) { + ERROR("Invalid parameters to get_imei_vec\n"); + return false; + } + + uint64 temp = imei; + for (int i = 14; i >= 0; i--) { + imei_[i] = temp % 10; + temp /= 10; + } + return true; +} + +bool usim_base::get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) +{ + if (!initiated) { + ERROR("USIM not initiated!\n"); + return false; + } + + uint8_t imsi_vec[15]; + get_imsi_vec(imsi_vec, 15); + + std::ostringstream plmn_str; + + uint mcc_len = 3; + for (uint i = 0; i < mcc_len; i++) { + plmn_str << (int)imsi_vec[i]; + } + + for (uint i = mcc_len; i < mcc_len + mnc_length; i++) { + plmn_str << (int)imsi_vec[i]; + } + + if (home_plmn_id->from_string(plmn_str.str())) { + log->error("Error reading home PLMN from SIM.\n"); + return false; + } + + log->info("Read Home PLMN Id=%s\n", home_plmn_id->to_string().c_str()); + + return true; +} + +void usim_base::generate_nas_keys(uint8_t* k_asme, + uint8_t* k_nas_enc, + uint8_t* k_nas_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + if (!initiated) { + ERROR("USIM not initiated!\n"); + return; + } + + // Generate K_nas_enc and K_nas_int + security_generate_k_nas(k_asme, cipher_algo, integ_algo, k_nas_enc, k_nas_int); +} + +/* + * RRC Interface + */ +void usim_base::generate_as_keys(uint8_t* k_asme_, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) +{ + if (!initiated) { + ERROR("USIM not initiated!\n"); + return; + } + + // Generate K_enb + srslte::security_generate_k_enb(k_asme_, count_ul, k_enb); + + memcpy(k_asme, k_asme_, 32); + + // Save initial k_enb + memcpy(k_enb_initial, k_enb, 32); + + // Generate K_rrc_enc and K_rrc_int + security_generate_k_rrc( + k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_int.data()); + + // Generate K_up_enc and K_up_int + security_generate_k_up( + k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_up_enc.data(), sec_cfg->k_up_int.data()); + + current_ncc = 0; + is_first_ncc = true; +} + +void usim_base::generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) +{ + if (!initiated) { + ERROR("USIM not initiated!\n"); + return; + } + + INFO("Generating AS Keys HO. PCI 0x%02x, DL-EARFCN %d, NCC %d\n", pci, earfcn, ncc); + log->info_hex(k_enb, 32, "Old K_eNB"); + + uint8_t* enb_star_key = k_enb; + + if (ncc < 0) { + ncc = current_ncc; + } + + // Generate successive NH + while (current_ncc != (uint32_t)ncc) { + uint8_t* sync = NULL; + if (is_first_ncc) { + DEBUG("Using K_enb_initial for sync. 0x%02x, DL-EARFCN %d, NCC %d\n", pci, earfcn, current_ncc); + sync = k_enb_initial; + is_first_ncc = false; + } else { + DEBUG("Using NH for sync. 0x%02x, DL-EARFCN %d, NCC %d\n", pci, earfcn, current_ncc); + sync = nh; + } + // Generate NH + srslte::security_generate_nh(k_asme, sync, nh); + + current_ncc++; + if (current_ncc == 8) { + current_ncc = 0; + } + enb_star_key = nh; + } + + // Generate K_enb + srslte::security_generate_k_enb_star(enb_star_key, pci, earfcn, k_enb_star); + + // K_enb becomes K_enb* + memcpy(k_enb, k_enb_star, 32); + + // Generate K_rrc_enc and K_rrc_int + security_generate_k_rrc( + k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_int.data()); + + // Generate K_up_enc and K_up_int + security_generate_k_up( + k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_up_enc.data(), sec_cfg->k_up_int.data()); + + log->info_hex(k_enb, 32, "HO K_eNB"); + log->info_hex(sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_enc.size(), "HO K_RRC_enc"); + log->info_hex(sec_cfg->k_rrc_int.data(), sec_cfg->k_rrc_int.size(), "HO K_RRC_int"); +} + +void usim_base::store_keys_before_ho(const srslte::as_security_config_t& as_ctx) +{ + INFO("Storing AS Keys pre-handover. NCC=%d\n", current_ncc); + log->info_hex(k_enb, 32, "Old K_eNB"); + log->info_hex(as_ctx.k_rrc_enc.data(), as_ctx.k_rrc_enc.size(), "Old K_RRC_enc"); + log->info_hex(as_ctx.k_rrc_enc.data(), as_ctx.k_rrc_enc.size(), "Old K_RRC_enc"); + log->info_hex(as_ctx.k_rrc_int.data(), as_ctx.k_rrc_int.size(), "Old K_RRC_int"); + log->info_hex(as_ctx.k_rrc_int.data(), as_ctx.k_rrc_int.size(), "Old K_RRC_int"); + old_is_first_ncc = is_first_ncc; + old_as_ctx = as_ctx; + old_ncc = current_ncc; + memcpy(old_k_enb, k_enb, 32); + return; +} + +void usim_base::restore_keys_from_failed_ho(srslte::as_security_config_t* as_ctx) +{ + INFO("Restoring Keys from failed handover. NCC=%d\n", old_ncc); + *as_ctx = old_as_ctx; + current_ncc = old_ncc; + is_first_ncc = old_is_first_ncc; + memcpy(k_enb, old_k_enb, 32); + return; +} + } // namespace srsue