mirror of https://github.com/PentHertz/srsLTE.git
ue,rrc_nr,nas_5g: Introduce NR AS Key derivation and update context handling in 5G NAS
This commit is contained in:
parent
cabdd05cb8
commit
efa13290a9
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "srsran/common/s3g.h"
|
||||
#include "srsran/common/ssl.h"
|
||||
#include "srsran/config.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#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<uint8_t> 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<uint8_t> 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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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
|
||||
******************************************************************************/
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue