From b616944a137a5f3545735335a5ef3b7e59081334 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 10 Sep 2020 15:55:51 +0200 Subject: [PATCH] ue,rrc: fix security config during HO/reestablishment we fix a number of very related issues for HO/reestablishment in the success/error case: * this patch removes the hard-coded check that intra-cell HO aren't allowed. There are cases where eNBs use this method to update the security context. * the patch also fixes an issue after failed HO where the security context of the source eNB should be used for the reestablishment. * update security keys according to specs when mobilitycontrol indicated change of key --- srsue/hdr/stack/rrc/rrc.h | 1 + srsue/hdr/stack/rrc/rrc_procedures.h | 7 ++- srsue/src/stack/rrc/rrc.cc | 27 ++++++----- srsue/src/stack/rrc/rrc_cell.cc | 5 ++ srsue/src/stack/rrc/rrc_procedures.cc | 67 ++++++++++++--------------- 5 files changed, 57 insertions(+), 50 deletions(-) diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index cef4db3b4..c08f138fc 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -203,6 +203,7 @@ private: srslte::mac_cfg_t current_mac_cfg, previous_mac_cfg = {}; bool current_scell_configured[SRSLTE_MAX_CARRIERS] = {}; + void generate_as_keys(); srslte::as_security_config_t sec_cfg = {}; std::map srbs; diff --git a/srsue/hdr/stack/rrc/rrc_procedures.h b/srsue/hdr/stack/rrc/rrc_procedures.h index 0d3e66664..4f523889a 100644 --- a/srsue/hdr/stack/rrc/rrc_procedures.h +++ b/srsue/hdr/stack/rrc/rrc_procedures.h @@ -306,8 +306,11 @@ private: asn1::rrc::rrc_conn_recfg_r8_ies_s recfg_r8; // state - uint32_t target_earfcn; - bool sec_cfg_failed = false; + phy_interface_rrc_lte::phy_cell_t target_cell; + + // helper to revert security config of source cell + void reset_security_config(); + enum state_t { launch_phy_cell_select, wait_phy_cell_select_complete, wait_ra_completion } state; }; diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 440ea0c17..05f3adc46 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -168,7 +168,7 @@ void rrc::get_metrics(rrc_metrics_t& m) { m.state = state; // Save strongest cells metrics - for (unique_cell_t& c : meas_cells) { + for (auto& c : meas_cells) { rrc_interface_phy_lte::phy_meas_t meas = {}; meas.cfo_hz = c->get_cfo_hz(); meas.earfcn = c->get_earfcn(); @@ -470,7 +470,7 @@ void rrc::cell_reselection(float rsrp, float rsrq) // TODO: Inter-frequency cell reselection } -// Set new serving cell +// Set serving cell void rrc::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving) { meas_cells.set_serving_cell(phy_cell, discard_serving); @@ -1592,15 +1592,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu) integrity_algorithm_id_text[sec_cfg.integ_algo]); // Generate AS security keys - uint8_t k_asme[32]; - nas->get_k_asme(k_asme, 32); - rrc_log->debug_hex(k_asme, 32, "UE K_asme"); - rrc_log->debug("Generating K_enb with UL NAS COUNT: %d\n", nas->get_k_enb_count()); - usim->generate_as_keys(k_asme, nas->get_k_enb_count(), &sec_cfg); - rrc_log->info_hex(sec_cfg.k_rrc_enc.data(), 32, "RRC encryption key - k_rrc_enc"); - rrc_log->info_hex(sec_cfg.k_rrc_int.data(), 32, "RRC integrity key - k_rrc_int"); - rrc_log->info_hex(sec_cfg.k_up_enc.data(), 32, "UP encryption key - k_up_enc"); - + generate_as_keys(); security_is_activated = true; // Configure PDCP for security @@ -1628,6 +1620,19 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu) } } +// Security helper used by Security Mode Command and Mobility handling routines +void rrc::generate_as_keys(void) +{ + uint8_t k_asme[32] = {}; + nas->get_k_asme(k_asme, 32); + rrc_log->debug_hex(k_asme, 32, "UE K_asme"); + rrc_log->debug("Generating K_enb with UL NAS COUNT: %d\n", nas->get_k_enb_count()); + usim->generate_as_keys(k_asme, nas->get_k_enb_count(), &sec_cfg); + rrc_log->info_hex(sec_cfg.k_rrc_enc.data(), 32, "RRC encryption key - k_rrc_enc"); + rrc_log->info_hex(sec_cfg.k_rrc_int.data(), 32, "RRC integrity key - k_rrc_int"); + rrc_log->info_hex(sec_cfg.k_up_enc.data(), 32, "UP encryption key - k_up_enc"); +} + /******************************************************************************* * * diff --git a/srsue/src/stack/rrc/rrc_cell.cc b/srsue/src/stack/rrc/rrc_cell.cc index e8684c681..f100ff631 100644 --- a/srsue/src/stack/rrc/rrc_cell.cc +++ b/srsue/src/stack/rrc/rrc_cell.cc @@ -331,6 +331,11 @@ bool meas_cell_list::has_neighbour_cell(uint32_t earfcn, uint32_t pci) const int meas_cell_list::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving) { + // don't update neighbor cell list unless serving cell changes + if (phy_cell.pci == serving_cell().get_pci() && phy_cell.earfcn == serving_cell().get_earfcn()) { + return SRSLTE_SUCCESS; + } + // Remove future serving cell from neighbours to make space for current serving cell unique_cell_t new_serving_cell = remove_neighbour_cell(phy_cell.earfcn, phy_cell.pci); if (new_serving_cell == nullptr) { diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 2af9c508a..2528288da 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -1346,26 +1346,26 @@ rrc::ho_proc::ho_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_) {} srslte::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc_reconf) { Info("Starting...\n"); - sec_cfg_failed = false; recfg_r8 = rrc_reconf.crit_exts.c1().rrc_conn_recfg_r8(); asn1::rrc::mob_ctrl_info_s* mob_ctrl_info = &recfg_r8.mob_ctrl_info; - if (mob_ctrl_info->target_pci == rrc_ptr->meas_cells.serving_cell().get_pci()) { - rrc_ptr->rrc_log->console("Warning: Received HO command to own cell\n"); - Warning("Received HO command to own cell\n"); - rrc_ptr->con_reconfig_failed(); - return proc_outcome_t::error; - } - Info("Received HO command to target PCell=%d\n", mob_ctrl_info->target_pci); rrc_ptr->rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", mob_ctrl_info->target_pci, recfg_r8.security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count); - target_earfcn = (mob_ctrl_info->carrier_freq_present) ? mob_ctrl_info->carrier_freq.dl_carrier_freq - : rrc_ptr->meas_cells.serving_cell().get_earfcn(); - - if (not rrc_ptr->has_neighbour_cell(target_earfcn, mob_ctrl_info->target_pci)) { + uint32_t target_earfcn = (mob_ctrl_info->carrier_freq_present) ? mob_ctrl_info->carrier_freq.dl_carrier_freq + : rrc_ptr->meas_cells.serving_cell().get_earfcn(); + + // Target cell shall be either serving cell (intra-cell HO) or neighbour cell + if (rrc_ptr->has_neighbour_cell(target_earfcn, mob_ctrl_info->target_pci)) { + // target cell is neighbour cell + target_cell = + rrc_ptr->meas_cells.get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci)->phy_cell; + } else if (recfg_r8.mob_ctrl_info.target_pci == rrc_ptr->meas_cells.serving_cell().get_pci()) { + // intra-cell HO, target cell is current serving cell + target_cell = rrc_ptr->get_serving_cell()->phy_cell; + } else { rrc_ptr->rrc_log->console("Received HO command to unknown PCI=%d\n", mob_ctrl_info->target_pci); Error("Could not find target cell earfcn=%d, pci=%d\n", rrc_ptr->meas_cells.serving_cell().get_earfcn(), @@ -1395,24 +1395,16 @@ srslte::proc_outcome_t rrc::ho_proc::react(const bool& cs_ret) Warning("Received unexpected PHY Cell Selection event\n"); return proc_outcome_t::yield; } - // Check if cell has not been deleted in the meantime - cell_t* target_cell = rrc_ptr->meas_cells.get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci); - if (target_cell == nullptr) { - Error("Cell removed from list of neighbours. Aborting handover preparation\n"); - return proc_outcome_t::error; - } if (not cs_ret) { - Error("Could not synchronize with target cell %s. Removing cell and trying to return to source %s\n", - target_cell->to_string().c_str(), + Error("Could not synchronize with target PCI=%d on EARFCN=%d. Removing cell and trying to return to source %s\n", + target_cell.pci, + target_cell.earfcn, rrc_ptr->meas_cells.serving_cell().to_string().c_str()); - - // Remove cell from list to avoid cell re-selection, picking the same cell - target_cell->set_rsrp(-INFINITY); return proc_outcome_t::error; } - rrc_ptr->set_serving_cell(target_cell->phy_cell, false); + rrc_ptr->set_serving_cell(target_cell, false); // Extract and apply scell config if any rrc_ptr->task_sched.enqueue_background_task([this](uint32_t wid) { @@ -1435,9 +1427,8 @@ srslte::proc_outcome_t rrc::ho_proc::react(const bool& cs_ret) auto& sec_intralte = recfg_r8.security_cfg_ho.handov_type.intra_lte(); ncc = sec_intralte.next_hop_chaining_count; if (sec_intralte.key_change_ind) { - rrc_ptr->rrc_log->console("keyChangeIndicator in securityConfigHO not supported\n"); - sec_cfg_failed = true; - return; + // update Kenb based on fresh Kasme taken from previous successful NAS SMC + rrc_ptr->generate_as_keys(); } if (sec_intralte.security_algorithm_cfg_present) { rrc_ptr->sec_cfg.cipher_algo = @@ -1494,9 +1485,6 @@ srslte::proc_outcome_t rrc::ho_proc::step() rrc_ptr->apply_rr_config_dedicated(&recfg_r8.rr_cfg_ded, true); } - cell_t* target_cell = - rrc_ptr->meas_cells.get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci); - // if the RRCConnectionReconfiguration message includes the measConfig: if (not rrc_ptr->measurements->parse_meas_config(&recfg_r8, true, ho_src_cell.get_earfcn())) { Error("Parsing measurementConfig. TODO: Send ReconfigurationReject\n"); @@ -1506,10 +1494,10 @@ srslte::proc_outcome_t rrc::ho_proc::step() // perform the measurement related actions as specified in 5.5.6.1; rrc_ptr->measurements->ho_reest_actions(ho_src_cell.get_earfcn(), rrc_ptr->get_serving_cell()->get_earfcn()); - Info("Starting cell selection of target cell %s\n", target_cell->to_string().c_str()); + Info("Starting cell selection of target cell PCI=%d on EARFCN=%d\n", target_cell.pci, target_cell.earfcn); - if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell->phy_cell, rrc_ptr->ho_handler)) { - Error("Failed to launch the selection of target cell %s\n", target_cell->to_string().c_str()); + if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell, rrc_ptr->ho_handler)) { + Error("Failed to launch the selection of target cell PCI=%d on EARFCN=%d\n", target_cell.pci, target_cell.earfcn); return proc_outcome_t::error; } state = wait_phy_cell_select_complete; @@ -1519,7 +1507,13 @@ srslte::proc_outcome_t rrc::ho_proc::step() srslte::proc_outcome_t rrc::ho_proc::react(t304_expiry ev) { - Info("HO preparation timed out.\n"); + Info("HO preparation timed out. Reverting RRC security config from source cell.\n"); + + // revert security settings from source cell for reestablishment according to Sec 5.3.7.4 + rrc_ptr->generate_as_keys(); + + rrc_ptr->pdcp->config_security_all(rrc_ptr->sec_cfg); + return proc_outcome_t::error; } @@ -1529,15 +1523,14 @@ srslte::proc_outcome_t rrc::ho_proc::react(ra_completed_ev ev) Warning("Received unexpected RA Complete Event\n"); return proc_outcome_t::yield; } - bool ho_successful = ev.success and not sec_cfg_failed; - if (ho_successful) { + if (ev.success) { // TS 36.331, sec. 5.3.5.4, last "1>" rrc_ptr->t304.stop(); rrc_ptr->apply_rr_config_dedicated_on_ho_complete(recfg_r8.rr_cfg_ded); } - return ho_successful ? proc_outcome_t::success : proc_outcome_t::error; + return ev.success ? proc_outcome_t::success : proc_outcome_t::error; } void rrc::ho_proc::then(const srslte::proc_state_t& result)