Moved common variables and functions from the usim and pcsc_usim classes into usim_base class.

This commit is contained in:
Pedro Alvarez 2020-09-23 18:54:48 +01:00
parent 8a917bdd06
commit 22a6dc305f
6 changed files with 286 additions and 519 deletions

View File

@ -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 <j@w1.fi> and licensed under BSD
// Source: https://w1.fi/cvs.html

View File

@ -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

View File

@ -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<usim_base> 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

View File

@ -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;

View File

@ -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
*******************************************************************************/

View File

@ -40,8 +40,217 @@ std::unique_ptr<usim_base> usim_base::get_instance(usim_args_t* args, srslte::lo
return std::unique_ptr<usim_base>(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