perform initial attach with ESM info transfer

This commit is contained in:
Andre Puschmann 2018-04-17 15:24:47 +02:00
parent ff42fa0991
commit 4dc2951d59
6 changed files with 212 additions and 21 deletions

View File

@ -3792,6 +3792,8 @@ typedef struct{
}LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp);

View File

@ -10041,10 +10041,19 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint8 sec_hdr_type;
if(msg != NULL &&
esm_info_req != NULL)
{
// Security Header Type
sec_hdr_type = (msg->msg[0] & 0xF0) >> 4;
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) {
msg_ptr++;
} else{
msg_ptr += 6;
}
// EPS Bearer ID
esm_info_req->eps_bearer_id = (*msg_ptr >> 4);
msg_ptr++;
@ -10072,6 +10081,8 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_
Document Reference: 24.301 v10.2.0 Section 8.3.14
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -10080,6 +10091,20 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
if(esm_info_resp != NULL &&
msg != NULL)
{
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type)
{
// Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++;
// MAC will be filled in later
msg_ptr += 4;
// Sequence Number
*msg_ptr = count & 0xFF;
msg_ptr++;
}
// Protocol Discriminator and EPS Bearer ID
*msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++;
@ -10116,6 +10141,8 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
return(err);
}
LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp)
{

View File

@ -171,7 +171,8 @@ private:
// Senders
void send_identity_response();
void send_esm_information_response();
void send_service_request();
void send_esm_information_response(const uint8 proc_transaction_id);
void send_authentication_response(const uint8_t* res, const size_t res_len);
void send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param);
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);

View File

@ -30,6 +30,7 @@
#include <iomanip>
#include <fstream>
#include <sstream>
#include <srslte/asn1/liblte_mme.h>
#include "srslte/asn1/liblte_rrc.h"
#include "srsue/hdr/upper/nas.h"
#include "srslte/common/security.h"
@ -51,7 +52,10 @@ nas::nas()
ctxt.tx_count = 0;
ctxt.cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
ctxt.integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
<<<<<<< HEAD
plmn_is_selected = false;
=======
>>>>>>> perform initial attach with ESM info transfer
}
void nas::init(usim_interface_nas *usim_,
@ -353,7 +357,13 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
}
uint32_t nas::get_ul_count() {
return ctxt.tx_count;
// UL count for RRC key derivation depends on ESM information transfer procedure
if (cfg.apn.empty()) {
// No ESM info transfer has been sent
return ctxt.tx_count - 1;
} else {
return ctxt.tx_count - 2;
}
}
bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
@ -483,7 +493,11 @@ void nas::cipher_encrypt(byte_buffer_t *pdu)
memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6);
break;
default:
<<<<<<< HEAD
nas_log->error("Ciphering algorithm not known\n");
=======
nas_log->error("Ciphering algorithmus not known\n");
>>>>>>> perform initial attach with ESM info transfer
break;
}
}
@ -517,7 +531,7 @@ void nas::cipher_decrypt(byte_buffer_t *pdu)
memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6);
break;
default:
nas_log->error("Ciphering algorithmus not known");
nas_log->error("Ciphering algorithmus not known\n");
break;
}
}
@ -921,8 +935,15 @@ void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
}
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_esm_information_request\n");
LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT esm_info_req;
liblte_mme_unpack_esm_information_request_msg((LIBLTE_BYTE_MSG_STRUCT *)pdu, &esm_info_req);
nas_log->info("ESM information request received for beaser=%d, transaction_id=%d\n", esm_info_req.eps_bearer_id, esm_info_req.proc_transaction_id);
ctxt.rx_count++;
pool->deallocate(pdu);
// send response
send_esm_information_response(esm_info_req.proc_transaction_id);
}
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
@ -1065,24 +1086,18 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
pdn_con_req.proc_transaction_id = 0x01; // First transaction ID
pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4;
pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST;
pdn_con_req.apn_present = false;
// Set the optional flags
pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
if (cfg.apn == "") {
pdn_con_req.apn_present = false;
pdn_con_req.esm_info_transfer_flag_present = false;
} else {
pdn_con_req.apn_present = true;
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn = {0};
strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN);
pdn_con_req.apn = apn;
// request ESM info transfer is APN is specified
pdn_con_req.esm_info_transfer_flag_present = true;
pdn_con_req.esm_info_transfer_flag = LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_REQUIRED;
}
// Request DNS Server
pdn_con_req.protocol_cnfg_opts_present = true;
pdn_con_req.protocol_cnfg_opts.opt[0].id = LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_P_CSCF_IPV4_ADDRESS_REQUEST;
pdn_con_req.protocol_cnfg_opts.opt[1].id = LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_DNS_SERVER_IPV4_ADDRESS_REQUEST;
pdn_con_req.protocol_cnfg_opts.N_opts = 2;
pdn_con_req.protocol_cnfg_opts_present = false;
pdn_con_req.device_properties_present = false;
// Pack the message
@ -1159,7 +1174,91 @@ void nas::send_authentication_failure(const uint8_t cause, const uint8_t* auth_f
void nas::send_identity_response() {}
void nas::send_esm_information_response() {}
void nas::send_service_request() {
byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_service_request().\n");
return;
}
// Pack the service request message directly
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg->N_bytes++;
msg->msg[1] = (ctxt.ksi & 0x07) << 5;
msg->msg[1] |= ctxt.tx_count & 0x1F;
msg->N_bytes++;
uint8_t mac[4];
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&msg->msg[0],
2,
&mac[0]);
// Set the short MAC
msg->msg[2] = mac[2];
msg->N_bytes++;
msg->msg[3] = mac[3];
msg->N_bytes++;
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending service request\n");
rrc->write_sdu(cfg.lcid, msg);
ctxt.tx_count++;
}
void nas::send_esm_information_response(const uint8 proc_transaction_id) {
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT esm_info_resp;
esm_info_resp.proc_transaction_id = proc_transaction_id;
esm_info_resp.eps_bearer_id = 0; // respone shall always have no bearer assigned
if (cfg.apn == "") {
esm_info_resp.apn_present = false;
} else {
esm_info_resp.apn_present = true;
esm_info_resp.apn.apn = cfg.apn;
}
esm_info_resp.protocol_cnfg_opts_present = false;
byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n");
return;
}
if (liblte_mme_pack_esm_information_response_msg(&esm_info_resp,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *)pdu)) {
nas_log->error("Error packing ESM information response.\n");
return;
}
if(pcap != NULL) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
}
cipher_encrypt(pdu);
if (pdu->N_bytes > 5) {
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[5],
pdu->N_bytes - 5,
&pdu->msg[1]);
} else {
nas_log->error("Invalid PDU size %d\n", pdu->N_bytes);
return;
}
nas_log->info_hex(pdu->msg, pdu->N_bytes, "Sending ESM information response\n");
rrc->write_sdu(cfg.lcid, pdu);
ctxt.tx_count++;
}
/*******************************************************************************

View File

@ -1947,7 +1947,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
// Generate AS security keys
uint8_t k_asme[32];
nas->get_k_asme(k_asme, 32);
usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo);
usim->generate_as_keys(k_asme, nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo);
rrc_log->debug_hex(k_rrc_enc, 32, "RRC encryption key - k_rrc_enc");
rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int");
rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc");

View File

@ -28,7 +28,6 @@
#include <assert.h>
#include <srsue/hdr/upper/usim_base.h>
#include "srsue/hdr/upper/usim.h"
#include "srsue/hdr/upper/pcsc_usim.h"
#include "srsue/hdr/upper/nas.h"
#include "srslte/upper/rlc.h"
#include "srsue/hdr/upper/rrc.h"
@ -61,6 +60,8 @@ uint8_t attach_accept_pdu[] = { 0x27, 0x0f, 0x4f, 0xb3, 0xef, 0x01, 0x07, 0x42,
0x80, 0x50, 0x0b, 0xf6, 0x00, 0xf1, 0x10, 0x80, 0x01, 0x01,
0x35, 0x16, 0x6d, 0xbc, 0x64, 0x01, 0x00 };
uint8_t esm_info_req_pdu[] = { 0x27, 0x1d, 0xbf, 0x7e, 0x05, 0x01, 0x02, 0x5a, 0xd9 };
uint16 mcc = 61441;
uint16 mnc = 65281;
@ -204,9 +205,9 @@ int mme_attach_request_test()
rrc_dummy rrc_dummy;
gw_dummy gw;
srsue::pcsc_usim usim;
srsue::usim usim;
usim_args_t args;
args.mode = "pcsc";
args.mode = "soft";
args.algo = "xor";
args.imei = "353490069873319";
args.imsi = "001010123456789";
@ -215,6 +216,7 @@ int mme_attach_request_test()
usim.init(&args, &usim_log);
srslte_nas_config_t nas_cfg;
nas_cfg.apn = "test123";
srsue::nas nas;
nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg);
@ -239,6 +241,61 @@ int mme_attach_request_test()
}
int esm_info_request_test()
{
int ret = SRSLTE_ERROR;
srslte::log_filter nas_log("NAS");
srslte::log_filter rrc_log("RRC");
srslte::log_filter mac_log("MAC");
srslte::log_filter usim_log("USIM");
nas_log.set_level(srslte::LOG_LEVEL_DEBUG);
rrc_log.set_level(srslte::LOG_LEVEL_DEBUG);
nas_log.set_hex_limit(100000);
rrc_log.set_hex_limit(100000);
rrc_dummy rrc_dummy;
gw_dummy gw;
usim_args_t args;
args.algo = "xor";
args.imei = "353490069873319";
args.imsi = "001010123456789";
args.k = "00112233445566778899aabbccddeeff";
args.op = "63BFA50EE6523365FF14C1F45F88737D";
// init USIM
srsue::usim usim;
bool net_valid;
uint8_t res[16];
usim.init(&args, &usim_log);
srslte::byte_buffer_pool *pool;
pool = byte_buffer_pool::get_instance();
srsue::nas nas;
srslte_nas_config_t cfg;
cfg.apn = "srslte";
nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg);
// push ESM info request PDU to NAS to generate response
byte_buffer_t* tmp = pool->allocate();
memcpy(tmp->msg, esm_info_req_pdu, sizeof(esm_info_req_pdu));
tmp->N_bytes = sizeof(esm_info_req_pdu);
nas.write_pdu(LCID, tmp);
// check length of generated NAS SDU
if (rrc_dummy.get_last_sdu_len() > 3) {
ret = SRSLTE_SUCCESS;
}
pool->cleanup();
return ret;
}
int main(int argc, char **argv)
{
if (security_command_test()) {
@ -251,5 +308,10 @@ int main(int argc, char **argv)
return -1;
}
if (esm_info_request_test()) {
printf("ESM info request test failed.\n");
return -1;
}
return 0;
}