mirror of https://github.com/PentHertz/srsLTE.git
Added NR security context manager to RRC NR
This commit is contained in:
parent
37f8dba4ac
commit
e294311034
|
@ -53,6 +53,9 @@ struct rrc_nr_cfg_t {
|
||||||
rrc_cell_list_nr_t cell_list;
|
rrc_cell_list_nr_t cell_list;
|
||||||
bool is_standalone;
|
bool is_standalone;
|
||||||
|
|
||||||
|
std::array<srsran::CIPHERING_ALGORITHM_ID_ENUM, srsran::CIPHERING_ALGORITHM_ID_N_ITEMS> eea_preference_list;
|
||||||
|
std::array<srsran::INTEGRITY_ALGORITHM_ID_ENUM, srsran::INTEGRITY_ALGORITHM_ID_N_ITEMS> eia_preference_list;
|
||||||
|
|
||||||
std::string log_name = "RRC-NR";
|
std::string log_name = "RRC-NR";
|
||||||
std::string log_level;
|
std::string log_level;
|
||||||
uint32_t log_hex_limit;
|
uint32_t log_hex_limit;
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* By using this file, you agree to the terms and conditions set
|
||||||
|
* forth in the LICENSE file which can be found at the top level of
|
||||||
|
* the distribution.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRSRAN_RRC_NR_SECURITY_CONTEXT_H
|
||||||
|
#define SRSRAN_RRC_NR_SECURITY_CONTEXT_H
|
||||||
|
|
||||||
|
#include "srsgnb/hdr/stack/rrc/rrc_nr_config.h"
|
||||||
|
#include "srsran/asn1/ngap.h"
|
||||||
|
#include "srsran/interfaces/gnb_interfaces.h"
|
||||||
|
#include "srsran/srslog/srslog.h"
|
||||||
|
|
||||||
|
namespace srsgnb {
|
||||||
|
|
||||||
|
class nr_security_context
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit nr_security_context(const srsenb::rrc_nr_cfg_t& cfg_) :
|
||||||
|
cfg(&cfg_), logger(srslog::fetch_basic_logger("RRC_NR"))
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit nr_security_context(const nr_security_context& other) : logger(srslog::fetch_basic_logger("RRC_NR"))
|
||||||
|
{
|
||||||
|
cfg = other.cfg;
|
||||||
|
k_gnb_present = other.k_gnb_present;
|
||||||
|
security_capabilities = other.security_capabilities;
|
||||||
|
std::copy(other.k_gnb, other.k_gnb + 32, k_gnb);
|
||||||
|
sec_cfg = other.sec_cfg;
|
||||||
|
ncc = other.ncc;
|
||||||
|
}
|
||||||
|
|
||||||
|
nr_security_context& operator=(const nr_security_context& other)
|
||||||
|
{
|
||||||
|
cfg = other.cfg;
|
||||||
|
k_gnb_present = other.k_gnb_present;
|
||||||
|
security_capabilities = other.security_capabilities;
|
||||||
|
std::copy(other.k_gnb, other.k_gnb + 32, k_gnb);
|
||||||
|
sec_cfg = other.sec_cfg;
|
||||||
|
ncc = other.ncc;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_security_capabilities(const asn1::ngap_nr::ue_security_cap_s& caps);
|
||||||
|
void set_security_key(const asn1::fixed_bitstring<256, false, true>& key);
|
||||||
|
void set_ncc(uint8_t ncc_) { ncc = ncc_; }
|
||||||
|
|
||||||
|
asn1::rrc_nr::security_algorithm_cfg_s get_security_algorithm_cfg() const;
|
||||||
|
const srsran::as_security_config_t& get_as_sec_cfg() const { return sec_cfg; }
|
||||||
|
uint8_t get_ncc() const { return ncc; }
|
||||||
|
bool is_as_sec_cfg_valid() const { return k_gnb_present; }
|
||||||
|
|
||||||
|
void regenerate_keys_handover(uint32_t new_pci, uint32_t new_dl_earfcn);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void generate_as_keys();
|
||||||
|
|
||||||
|
srslog::basic_logger& logger;
|
||||||
|
const srsenb::rrc_nr_cfg_t* cfg = nullptr;
|
||||||
|
bool k_gnb_present = false;
|
||||||
|
asn1::ngap_nr::ue_security_cap_s security_capabilities = {};
|
||||||
|
uint8_t k_gnb[32] = {}; // Provided by MME
|
||||||
|
srsran::as_security_config_t sec_cfg = {};
|
||||||
|
uint8_t ncc = 0;
|
||||||
|
};
|
||||||
|
} // namespace srsgnb
|
||||||
|
#endif
|
|
@ -14,6 +14,7 @@
|
||||||
#define SRSRAN_RRC_NR_UE_H
|
#define SRSRAN_RRC_NR_UE_H
|
||||||
|
|
||||||
#include "rrc_nr.h"
|
#include "rrc_nr.h"
|
||||||
|
#include "rrc_nr_security_context.h"
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
|
|
||||||
|
@ -43,6 +44,11 @@ public:
|
||||||
void get_metrics(rrc_ue_metrics_t& ue_metrics) { ue_metrics = {}; /*TODO fill RRC metrics*/ };
|
void get_metrics(rrc_ue_metrics_t& ue_metrics) { ue_metrics = {}; /*TODO fill RRC metrics*/ };
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
|
void set_security_key(const asn1::fixed_bitstring<256, false, true>& key) { sec_ctx.set_security_key(key); }
|
||||||
|
void set_security_capabilities(const asn1::ngap_nr::ue_security_cap_s& caps)
|
||||||
|
{
|
||||||
|
sec_ctx.set_security_capabilities(caps);
|
||||||
|
}
|
||||||
|
|
||||||
void deactivate_bearers();
|
void deactivate_bearers();
|
||||||
|
|
||||||
|
@ -170,6 +176,9 @@ private:
|
||||||
|
|
||||||
const uint32_t drb1_lcid = 4;
|
const uint32_t drb1_lcid = 4;
|
||||||
|
|
||||||
|
// Security helper
|
||||||
|
srsgnb::nr_security_context sec_ctx;
|
||||||
|
|
||||||
// SA specific variables
|
// SA specific variables
|
||||||
struct ctxt_t {
|
struct ctxt_t {
|
||||||
uint64_t setup_ue_id = -1;
|
uint64_t setup_ue_id = -1;
|
||||||
|
|
|
@ -10,7 +10,7 @@ set(SOURCES rrc_nr_config_utils.cc)
|
||||||
add_library(srsgnb_rrc_config_utils STATIC ${SOURCES})
|
add_library(srsgnb_rrc_config_utils STATIC ${SOURCES})
|
||||||
target_link_libraries(srsgnb_rrc_config_utils srsran_phy)
|
target_link_libraries(srsgnb_rrc_config_utils srsran_phy)
|
||||||
|
|
||||||
set(SOURCES rrc_nr.cc rrc_nr_ue.cc cell_asn1_config.cc)
|
set(SOURCES rrc_nr.cc rrc_nr_ue.cc rrc_nr_security_context.cc cell_asn1_config.cc)
|
||||||
add_library(srsgnb_rrc STATIC ${SOURCES})
|
add_library(srsgnb_rrc STATIC ${SOURCES})
|
||||||
target_link_libraries(srsgnb_rrc srsgnb_rrc_config_utils)
|
target_link_libraries(srsgnb_rrc srsgnb_rrc_config_utils)
|
||||||
|
|
||||||
|
|
|
@ -538,6 +538,15 @@ void rrc_nr::notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) {}
|
||||||
|
|
||||||
int rrc_nr::ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key)
|
int rrc_nr::ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key)
|
||||||
{
|
{
|
||||||
|
logger.debug("Setting securtiy key for rnti=0x%x", rnti);
|
||||||
|
auto ue_it = users.find(rnti);
|
||||||
|
|
||||||
|
if (ue_it == users.end()) {
|
||||||
|
logger.error("Trying to set key for non-existing rnti=0x%x", rnti);
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
ue& u = *ue_it->second;
|
||||||
|
u.set_security_key(key);
|
||||||
return SRSRAN_SUCCESS;
|
return SRSRAN_SUCCESS;
|
||||||
}
|
}
|
||||||
int rrc_nr::ue_set_bitrates(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates)
|
int rrc_nr::ue_set_bitrates(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates)
|
||||||
|
@ -550,6 +559,15 @@ int rrc_nr::set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap_nr::ue_agg
|
||||||
}
|
}
|
||||||
int rrc_nr::ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps)
|
int rrc_nr::ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps)
|
||||||
{
|
{
|
||||||
|
logger.debug("Setting securtiy capabilites for rnti=0x%x", rnti);
|
||||||
|
auto ue_it = users.find(rnti);
|
||||||
|
|
||||||
|
if (ue_it == users.end()) {
|
||||||
|
logger.error("Trying to set security capabilities for non-existing rnti=0x%x", rnti);
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
ue& u = *ue_it->second;
|
||||||
|
u.set_security_capabilities(caps);
|
||||||
return SRSRAN_SUCCESS;
|
return SRSRAN_SUCCESS;
|
||||||
}
|
}
|
||||||
int rrc_nr::start_security_mode_procedure(uint16_t rnti)
|
int rrc_nr::start_security_mode_procedure(uint16_t rnti)
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* By using this file, you agree to the terms and conditions set
|
||||||
|
* forth in the LICENSE file which can be found at the top level of
|
||||||
|
* the distribution.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srsgnb/hdr/stack/rrc/rrc_nr_security_context.h"
|
||||||
|
#include "srsran/asn1/obj_id_cmp_utils.h"
|
||||||
|
#include "srsran/asn1/rrc_utils.h"
|
||||||
|
|
||||||
|
namespace srsgnb {
|
||||||
|
|
||||||
|
asn1::rrc_nr::security_algorithm_cfg_s nr_security_context::get_security_algorithm_cfg() const
|
||||||
|
{
|
||||||
|
asn1::rrc_nr::security_algorithm_cfg_s ret;
|
||||||
|
// TODO: select these based on UE capabilities and preference order
|
||||||
|
ret.integrity_prot_algorithm = (asn1::rrc_nr::integrity_prot_algorithm_e::options)sec_cfg.integ_algo;
|
||||||
|
ret.ciphering_algorithm = (asn1::rrc_nr::ciphering_algorithm_e::options)sec_cfg.cipher_algo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nr_security_context::set_security_capabilities(const asn1::ngap_nr::ue_security_cap_s& caps)
|
||||||
|
{
|
||||||
|
security_capabilities = caps;
|
||||||
|
|
||||||
|
// Selects security algorithms (cipher_algo and integ_algo) based on capabilities and config preferences
|
||||||
|
// Each position in the bitmap represents an encryption algorithm:
|
||||||
|
// “all bits equal to 0” – UE supports no other algorithm than EEA0,
|
||||||
|
// “first bit” – 128-EEA1,
|
||||||
|
// “second bit” – 128-EEA2,
|
||||||
|
// “third bit” – 128-EEA3,
|
||||||
|
// other bits reserved for future use. Value ‘1’ indicates support and value
|
||||||
|
// ‘0’ indicates no support of the algorithm.
|
||||||
|
// Algorithms are defined in TS 33.401 [15].
|
||||||
|
// Note: information missing
|
||||||
|
|
||||||
|
bool enc_algo_found = false;
|
||||||
|
bool integ_algo_found = false;
|
||||||
|
|
||||||
|
for (auto& cipher_item : cfg->eea_preference_list) {
|
||||||
|
auto& v = security_capabilities.nrencryption_algorithms;
|
||||||
|
switch (cipher_item) {
|
||||||
|
case srsran::CIPHERING_ALGORITHM_ID_EEA0:
|
||||||
|
// “all bits equal to 0” – UE supports no other algorithm than EEA0,
|
||||||
|
// specification does not cover the case in which EEA0 is supported with other algorithms
|
||||||
|
// just assume that EEA0 is always supported even this can not be explicity signaled by S1AP
|
||||||
|
sec_cfg.cipher_algo = srsran::CIPHERING_ALGORITHM_ID_EEA0;
|
||||||
|
enc_algo_found = true;
|
||||||
|
logger.info("Selected EEA0 as RRC encryption algorithm");
|
||||||
|
break;
|
||||||
|
case srsran::CIPHERING_ALGORITHM_ID_128_EEA1:
|
||||||
|
// “first bit” – 128-EEA1,
|
||||||
|
if (v.get(v.length() - srsran::CIPHERING_ALGORITHM_ID_128_EEA1)) {
|
||||||
|
sec_cfg.cipher_algo = srsran::CIPHERING_ALGORITHM_ID_128_EEA1;
|
||||||
|
enc_algo_found = true;
|
||||||
|
logger.info("Selected EEA1 as RRC encryption algorithm");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
logger.info("Failed to selected EEA1 as RRC encryption algorithm, due to unsupported algorithm");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case srsran::CIPHERING_ALGORITHM_ID_128_EEA2:
|
||||||
|
// “second bit” – 128-EEA2,
|
||||||
|
if (v.get(v.length() - srsran::CIPHERING_ALGORITHM_ID_128_EEA2)) {
|
||||||
|
sec_cfg.cipher_algo = srsran::CIPHERING_ALGORITHM_ID_128_EEA2;
|
||||||
|
enc_algo_found = true;
|
||||||
|
logger.info("Selected EEA2 as RRC encryption algorithm");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
logger.info("Failed to selected EEA2 as RRC encryption algorithm, due to unsupported algorithm");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case srsran::CIPHERING_ALGORITHM_ID_128_EEA3:
|
||||||
|
// “third bit” – 128-EEA3,
|
||||||
|
if (v.get(v.length() - srsran::CIPHERING_ALGORITHM_ID_128_EEA3)) {
|
||||||
|
sec_cfg.cipher_algo = srsran::CIPHERING_ALGORITHM_ID_128_EEA3;
|
||||||
|
enc_algo_found = true;
|
||||||
|
logger.info("Selected EEA3 as RRC encryption algorithm");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
logger.info("Failed to selected EEA2 as RRC encryption algorithm, due to unsupported algorithm");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
enc_algo_found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (enc_algo_found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& eia_enum : cfg->eia_preference_list) {
|
||||||
|
auto& v = security_capabilities.nrintegrity_protection_algorithms;
|
||||||
|
switch (eia_enum) {
|
||||||
|
case srsran::INTEGRITY_ALGORITHM_ID_EIA0:
|
||||||
|
// Null integrity is not supported
|
||||||
|
logger.info("Skipping EIA0 as RRC integrity algorithm. Null integrity is not supported.");
|
||||||
|
sec_cfg.integ_algo = srsran::INTEGRITY_ALGORITHM_ID_EIA0;
|
||||||
|
integ_algo_found = true;
|
||||||
|
break;
|
||||||
|
case srsran::INTEGRITY_ALGORITHM_ID_128_EIA1:
|
||||||
|
// “first bit” – 128-EIA1,
|
||||||
|
if (v.get(v.length() - srsran::INTEGRITY_ALGORITHM_ID_128_EIA1)) {
|
||||||
|
sec_cfg.integ_algo = srsran::INTEGRITY_ALGORITHM_ID_128_EIA1;
|
||||||
|
integ_algo_found = true;
|
||||||
|
logger.info("Selected EIA1 as RRC integrity algorithm.");
|
||||||
|
} else {
|
||||||
|
logger.info("Failed to selected EIA1 as RRC encryption algorithm, due to unsupported algorithm");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case srsran::INTEGRITY_ALGORITHM_ID_128_EIA2:
|
||||||
|
// “second bit” – 128-EIA2,
|
||||||
|
if (v.get(v.length() - srsran::INTEGRITY_ALGORITHM_ID_128_EIA2)) {
|
||||||
|
sec_cfg.integ_algo = srsran::INTEGRITY_ALGORITHM_ID_128_EIA2;
|
||||||
|
integ_algo_found = true;
|
||||||
|
logger.info("Selected EIA2 as RRC integrity algorithm.");
|
||||||
|
} else {
|
||||||
|
logger.info("Failed to selected EIA2 as RRC encryption algorithm, due to unsupported algorithm");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case srsran::INTEGRITY_ALGORITHM_ID_128_EIA3:
|
||||||
|
// “third bit” – 128-EIA3,
|
||||||
|
if (v.get(v.length() - srsran::INTEGRITY_ALGORITHM_ID_128_EIA3)) {
|
||||||
|
sec_cfg.integ_algo = srsran::INTEGRITY_ALGORITHM_ID_128_EIA3;
|
||||||
|
integ_algo_found = true;
|
||||||
|
logger.info("Selected EIA3 as RRC integrity algorithm.");
|
||||||
|
} else {
|
||||||
|
logger.info("Failed to selected EIA3 as RRC encryption algorithm, due to unsupported algorithm");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
integ_algo_found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (integ_algo_found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not integ_algo_found || not enc_algo_found) {
|
||||||
|
logger.error("Did not find a matching integrity or encryption algorithm with the UE");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nr_security_context::set_security_key(const asn1::fixed_bitstring<256, false, true>& key)
|
||||||
|
{
|
||||||
|
k_gnb_present = true;
|
||||||
|
for (uint32_t i = 0; i < key.nof_octets(); ++i) {
|
||||||
|
k_gnb[i] = key.data()[key.nof_octets() - 1 - i];
|
||||||
|
}
|
||||||
|
logger.info(k_gnb, 32, "Key gNodeB (k_gnb)");
|
||||||
|
|
||||||
|
generate_as_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nr_security_context::generate_as_keys()
|
||||||
|
{
|
||||||
|
// Generate K_rrc_enc and K_rrc_int
|
||||||
|
srsran::security_generate_k_nr_rrc(
|
||||||
|
k_gnb, 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_nr_up(
|
||||||
|
k_gnb, sec_cfg.cipher_algo, sec_cfg.integ_algo, sec_cfg.k_up_enc.data(), sec_cfg.k_up_int.data());
|
||||||
|
|
||||||
|
logger.info(k_gnb, 32, "K_gNB (k_gnb)");
|
||||||
|
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)");
|
||||||
|
logger.info(sec_cfg.k_up_int.data(), 32, "UP Encryption Key (k_up_enc)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void nr_security_context::regenerate_keys_handover(uint32_t new_pci, uint32_t new_dl_earfcn)
|
||||||
|
{
|
||||||
|
logger.info("Regenerating KeNB with PCI=0x%02x, DL-EARFCN=%d", new_pci, new_dl_earfcn);
|
||||||
|
logger.info(k_gnb, 32, "Old K_eNB (k_enb)");
|
||||||
|
// Generate K_enb*
|
||||||
|
uint8_t k_gnb_star[32];
|
||||||
|
srsran::security_generate_k_enb_star(k_gnb, new_pci, new_dl_earfcn, k_gnb_star);
|
||||||
|
|
||||||
|
// K_enb becomes K_enb*
|
||||||
|
memcpy(k_gnb, k_gnb_star, 32);
|
||||||
|
|
||||||
|
generate_as_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace srsgnb
|
|
@ -27,7 +27,7 @@ Every function in UE class is called from a mutex environment thus does not
|
||||||
need extra protection.
|
need extra protection.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg_, bool start_msg3_timer) :
|
rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg_, bool start_msg3_timer) :
|
||||||
parent(parent_), logger(parent_->logger), rnti(rnti_), uecfg(uecfg_)
|
parent(parent_), logger(parent_->logger), rnti(rnti_), uecfg(uecfg_), sec_ctx(parent->cfg)
|
||||||
{
|
{
|
||||||
if (not parent->cfg.is_standalone) {
|
if (not parent->cfg.is_standalone) {
|
||||||
// Add the final PDCCH config in case of NSA
|
// Add the final PDCCH config in case of NSA
|
||||||
|
|
Loading…
Reference in New Issue