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