diff --git a/lib/include/srsran/common/security.h b/lib/include/srsran/common/security.h index 035501770..f346725c4 100644 --- a/lib/include/srsran/common/security.h +++ b/lib/include/srsran/common/security.h @@ -97,6 +97,7 @@ struct k_enb_context_t { }; struct k_gnb_context_t { + as_key_t k_gnb; as_key_t sk_gnb; }; @@ -180,6 +181,8 @@ uint8_t security_generate_k_amf(const uint8_t* k_seaf, uint8_t security_generate_k_seaf(const uint8_t* k_ausf, const char* serving_network_name, uint8_t* k_seaf); +uint8_t security_generate_k_gnb(const as_key_t& k_amf, const uint32_t nas_count, as_key_t& k_gnb); + uint8_t security_generate_k_enb(const uint8_t* k_asme, const uint32_t nas_count, uint8_t* k_enb); uint8_t security_generate_k_nb_star_common(uint8_t fc, diff --git a/lib/include/srsran/interfaces/ue_nas_interfaces.h b/lib/include/srsran/interfaces/ue_nas_interfaces.h index 7cb81b666..a96f1372a 100644 --- a/lib/include/srsran/interfaces/ue_nas_interfaces.h +++ b/lib/include/srsran/interfaces/ue_nas_interfaces.h @@ -58,8 +58,9 @@ public: class nas_5g_interface_rrc_nr { public: - virtual int write_pdu(srsran::unique_byte_buffer_t pdu) = 0; - virtual int get_k_amf(srsran::as_key_t& k_amf) = 0; + virtual int write_pdu(srsran::unique_byte_buffer_t pdu) = 0; + virtual int get_k_amf(srsran::as_key_t& k_amf) = 0; + virtual uint32_t get_ul_nas_count() = 0; }; class nas_5g_interface_procedures diff --git a/lib/include/srsran/interfaces/ue_usim_interfaces.h b/lib/include/srsran/interfaces/ue_usim_interfaces.h index 5a7fd84bc..7869ab90a 100644 --- a/lib/include/srsran/interfaces/ue_usim_interfaces.h +++ b/lib/include/srsran/interfaces/ue_usim_interfaces.h @@ -24,24 +24,24 @@ enum auth_result_t { AUTH_OK, AUTH_FAILED, AUTH_SYNCH_FAILURE }; class usim_interface_nas { public: - virtual std::string get_imsi_str() = 0; - virtual std::string get_imei_str() = 0; - 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(srsran::plmn_id_t* home_plmn_id) = 0; + virtual std::string get_imsi_str() = 0; + virtual std::string get_imei_str() = 0; + 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(srsran::plmn_id_t* home_plmn_id) = 0; // Get the home mcc as bytes array - virtual bool get_home_mcc_bytes(uint8_t* mcc_, uint32_t n) = 0; + virtual bool get_home_mcc_bytes(uint8_t* mcc_, uint32_t n) = 0; // Get the home mnc as byte array - virtual bool get_home_mnc_bytes(uint8_t* mnc_, uint32_t n) = 0; + virtual bool get_home_mnc_bytes(uint8_t* mnc_, uint32_t n) = 0; // Get the home msin in bytes array encoded as bcd - virtual bool get_home_msin_bcd(uint8_t* msin_, uint32_t n) = 0; + virtual bool get_home_msin_bcd(uint8_t* msin_, uint32_t n) = 0; virtual auth_result_t generate_authentication_response(uint8_t* rand, uint8_t* autn_enb, uint16_t mcc, uint16_t mnc, uint8_t* res, int* res_len, - uint8_t* k_asme) = 0; + uint8_t* k_asme) = 0; virtual auth_result_t generate_authentication_response_5g(uint8_t* rand, uint8_t* autn_enb, @@ -77,8 +77,10 @@ public: class usim_interface_rrc_nr { public: - virtual bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) = 0; - virtual bool update_nr_context(srsran::as_security_config_t* sec_cfg) = 0; + virtual void + generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg) = 0; + virtual bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) = 0; + virtual bool update_nr_context(srsran::as_security_config_t* sec_cfg) = 0; }; } // namespace srsue diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc index 8affa0848..82d7f0088 100644 --- a/lib/src/common/security.cc +++ b/lib/src/common/security.cc @@ -15,7 +15,6 @@ #include "srsran/common/s3g.h" #include "srsran/common/ssl.h" #include "srsran/config.h" - #include #ifdef HAVE_MBEDTLS @@ -195,6 +194,32 @@ uint8_t security_generate_k_amf(const uint8_t* k_seaf, return SRSRAN_SUCCESS; } +uint8_t security_generate_k_gnb(const as_key_t& k_amf, const uint32_t nas_count_, as_key_t& k_gnb) +{ + if (k_amf.empty()) { + log_error("Invalid inputs"); + return SRSRAN_ERROR; + } + + // NAS Count + std::vector nas_count; + nas_count.resize(4); + nas_count[0] = (nas_count_ >> 24) & 0xFF; + nas_count[1] = (nas_count_ >> 16) & 0xFF; + nas_count[2] = (nas_count_ >> 8) & 0xFF; + nas_count[3] = nas_count_ & 0xFF; + + // Access Type Distinguisher 3GPP access = 0x01 (TS 33501 Annex A.9) + std::vector access_type_distinguisher = {1}; + + if (kdf_common(FC_5G_KGNB_KN3IWF_DERIVATION, k_amf, nas_count, access_type_distinguisher, k_gnb.data()) != + SRSRAN_SUCCESS) { + log_error("Failed to run kdf_common"); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; +} + uint8_t security_generate_k_enb(const uint8_t* k_asme, const uint32_t nas_count_, uint8_t* k_enb) { if (k_asme == NULL || k_enb == NULL) { diff --git a/srsue/hdr/stack/upper/nas_5g.h b/srsue/hdr/stack/upper/nas_5g.h index f317ca9ae..0c57a64b9 100644 --- a/srsue/hdr/stack/upper/nas_5g.h +++ b/srsue/hdr/stack/upper/nas_5g.h @@ -57,8 +57,9 @@ public: void run_tti(); // Stack+RRC interface - bool is_registered(); - int get_k_amf(srsran::as_key_t& k_amf); + bool is_registered(); + int get_k_amf(srsran::as_key_t& k_amf); + uint32_t get_ul_nas_count(); int write_pdu(srsran::unique_byte_buffer_t pdu); @@ -94,6 +95,8 @@ private: bool ia5g_caps[8] = {}; bool ea5g_caps[8] = {}; + void set_k_gnb_count(uint32_t count); + // TS 23.003 Sec. 6.2.2 IMEISV's last two octets are Software Version Number (SVN) // which identifies the software version number of the mobile equipment const uint8_t ue_svn_oct1 = 0x5; diff --git a/srsue/hdr/stack/upper/nas_base.h b/srsue/hdr/stack/upper/nas_base.h index 5bcc61c03..602be07c4 100644 --- a/srsue/hdr/stack/upper/nas_base.h +++ b/srsue/hdr/stack/upper/nas_base.h @@ -60,6 +60,7 @@ protected: struct nas_5g_sec_ctxt { uint8_t ksi; uint8_t k_amf[32]; + uint32_t k_gnb_count; }; nas_sec_base_ctxt ctxt_base = {}; @@ -70,7 +71,7 @@ protected: // Security void - integrity_generate(uint8_t* key_128, uint32_t count, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac); + integrity_generate(uint8_t* key_128, uint32_t count, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac); bool integrity_check(srsran::byte_buffer_t* pdu); void cipher_encrypt(srsran::byte_buffer_t* pdu); void cipher_decrypt(srsran::byte_buffer_t* pdu); diff --git a/srsue/hdr/stack/upper/usim_base.h b/srsue/hdr/stack/upper/usim_base.h index f9516073f..b2bc23e81 100644 --- a/srsue/hdr/stack/upper/usim_base.h +++ b/srsue/hdr/stack/upper/usim_base.h @@ -97,6 +97,7 @@ public: void restore_keys_from_failed_ho(srsran::as_security_config_t* as_ctx) final; // NR RRC interface + void generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg) final; bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) final; bool update_nr_context(srsran::as_security_config_t* sec_cfg) final; @@ -140,6 +141,8 @@ protected: uint8_t k_enb_initial[KEY_LEN] = {}; uint8_t auts[AKA_AUTS_LEN] = {}; + srsran::as_key_t k_gnb_initial = {}; + // Current K_eNB context (K_eNB, NH and NCC) srsran::k_enb_context_t k_enb_ctx = {}; srsran::k_gnb_context_t k_gnb_ctx = {}; diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index ad720f727..9b101cbd5 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -2114,12 +2114,11 @@ void rrc_nr::handle_security_mode_command(const asn1::rrc_nr::security_mode_cmd_ // Security helper used by Security Mode Command and Mobility handling routines void rrc_nr::generate_as_keys() { - uint8_t k_asme[32] = {}; - // FIXME: need to add - // nas->get_k_asme(k_asme, 32); - logger.debug(k_asme, 32, "UE K_asme"); - // logger.debug("Generating K_enb with UL NAS COUNT: %d", nas->get_k_enb_count()); - // usim->generate_as_keys(k_asme, nas->get_k_enb_count(), &sec_cfg); + as_key_t k_amf = {}; + nas->get_k_amf(k_amf); + logger.debug(k_amf.data(), 32, "UE K_amf"); + logger.debug("Generating K_gnb with UL NAS COUNT: %d", nas->get_ul_nas_count()); + usim->generate_nr_as_keys(k_amf, nas->get_ul_nas_count(), &sec_cfg); logger.info(sec_cfg.k_rrc_enc.data(), 32, "RRC encryption key - k_rrc_enc"); logger.info(sec_cfg.k_rrc_int.data(), 32, "RRC integrity key - k_rrc_int"); logger.info(sec_cfg.k_up_enc.data(), 32, "UP encryption key - k_up_enc"); diff --git a/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc index e4fa5e7a8..da85d7c05 100644 --- a/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc +++ b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc @@ -109,12 +109,14 @@ class dummy_eutra : public rrc_eutra_interface_rrc_nr class dummy_nas : public nas_5g_interface_rrc_nr { - int write_pdu(srsran::unique_byte_buffer_t pdu) { return SRSRAN_SUCCESS; }; - int get_k_amf(srsran::as_key_t& k_amf) { return SRSRAN_SUCCESS; }; + int write_pdu(srsran::unique_byte_buffer_t pdu) { return SRSRAN_SUCCESS; }; + int get_k_amf(srsran::as_key_t& k_amf) { return SRSRAN_SUCCESS; }; + uint32_t get_ul_nas_count() { return SRSRAN_SUCCESS; }; }; class dummy_sim : public usim_interface_rrc_nr { + void generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg){}; bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) { return true; } bool update_nr_context(srsran::as_security_config_t* sec_cfg) { return true; } }; diff --git a/srsue/src/stack/upper/nas_5g.cc b/srsue/src/stack/upper/nas_5g.cc index 4dc468bd9..9478bfac5 100644 --- a/srsue/src/stack/upper/nas_5g.cc +++ b/srsue/src/stack/upper/nas_5g.cc @@ -293,6 +293,11 @@ int nas_5g::send_registration_request() } } + if (has_sec_ctxt) { + set_k_gnb_count(ctxt_base.tx_count); + ctxt_base.tx_count++; + } + state.set_registered_initiated(); return SRSRAN_SUCCESS; @@ -847,6 +852,7 @@ int nas_5g::handle_authentication_request(authentication_request_t& authenticati return SRSRAN_ERROR; } + initial_sec_command = true; uint8_t res_star[16]; logger.info(authentication_request.authentication_parameter_rand.rand.data(), @@ -936,10 +942,8 @@ int nas_5g::handle_security_mode_command(security_mode_command_t& security_m return SRSRAN_ERROR; } - initial_sec_command = false; // TODO - if (initial_sec_command) { - ctxt_base.rx_count = 0; + set_k_gnb_count(0); ctxt_base.tx_count = 0; initial_sec_command = false; } @@ -1121,6 +1125,16 @@ int nas_5g::get_k_amf(as_key_t& k_amf) return SRSRAN_SUCCESS; } +uint32_t nas_5g::get_ul_nas_count() +{ + return ctxt_5g.k_gnb_count; +} + +void nas_5g::set_k_gnb_count(uint32_t count) +{ + ctxt_5g.k_gnb_count = count; +} + /******************************************************************************* * Helpers ******************************************************************************/ diff --git a/srsue/src/stack/upper/usim_base.cc b/srsue/src/stack/upper/usim_base.cc index 479ed6b3d..6d1260a4a 100644 --- a/srsue/src/stack/upper/usim_base.cc +++ b/srsue/src/stack/upper/usim_base.cc @@ -222,6 +222,7 @@ void usim_base::generate_nas_keys(uint8_t* k_asme, /* * RRC Interface */ + void usim_base::generate_as_keys(uint8_t* k_asme_, uint32_t count_ul, srsran::as_security_config_t* sec_cfg) { if (!initiated) { @@ -367,6 +368,42 @@ bool usim_base::generate_nas_keys_5g(uint8_t* k_amf, * NR RRC Interface */ +void usim_base::generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg) +{ + if (!initiated) { + logger.error("USIM not initiated!"); + return; + } + + logger.info("Generating NR AS Keys. NAS UL COUNT %d", count_ul); + logger.debug(k_amf.data(), 32, "K_amf"); + + // Generate K_gnb + srsran::security_generate_k_gnb(k_amf, count_ul, k_gnb_ctx.k_gnb); + logger.info(k_gnb_ctx.k_gnb.data(), 32, "K_gnb"); + + // Save initial k_gnb + k_gnb_initial = k_gnb_ctx.k_gnb; + + security_generate_k_nr_rrc(k_gnb_ctx.k_gnb.data(), + sec_cfg->cipher_algo, + sec_cfg->integ_algo, + sec_cfg->k_rrc_enc.data(), + sec_cfg->k_rrc_int.data()); + + security_generate_k_nr_up(k_gnb_ctx.k_gnb.data(), + sec_cfg->cipher_algo, + sec_cfg->integ_algo, + sec_cfg->k_up_enc.data(), + sec_cfg->k_up_int.data()); + + logger.info(k_gnb_ctx.k_gnb.data(), 32, "Initial K_gnb"); + logger.info(sec_cfg->k_rrc_int.data(), sec_cfg->k_rrc_int.size(), "NR K_RRC_int"); + logger.info(sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_enc.size(), "NR K_RRC_enc"); + logger.info(sec_cfg->k_up_int.data(), sec_cfg->k_up_int.size(), "NR K_UP_int"); + logger.info(sec_cfg->k_up_enc.data(), sec_cfg->k_up_enc.size(), "NR K_UP_enc"); +} + bool usim_base::generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) { if (!initiated) {