From 5b8b7184823fb7f197d8d7cd059e954eb6ce0b77 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 6 Mar 2020 12:52:28 +0100 Subject: [PATCH] simplify NAS security handling and fix missing call in act test mode complete add extra method to apply NAS security config, if configured, that can be used by each NAS message sender --- srsue/hdr/stack/upper/nas.h | 6 +- srsue/src/stack/upper/nas.cc | 147 +++++++++++++++++++---------------- 2 files changed, 83 insertions(+), 70 deletions(-) diff --git a/srsue/hdr/stack/upper/nas.h b/srsue/hdr/stack/upper/nas.h index 5743b3c27..548968dce 100644 --- a/srsue/hdr/stack/upper/nas.h +++ b/srsue/hdr/stack/upper/nas.h @@ -159,6 +159,8 @@ private: bool integrity_check(srslte::byte_buffer_t* pdu); void cipher_encrypt(srslte::byte_buffer_t* pdu); void cipher_decrypt(srslte::byte_buffer_t* pdu); + int apply_security_config(srslte::unique_byte_buffer_t& pdu); + void set_k_enb_count(uint32_t count); bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT* caps); @@ -183,8 +185,8 @@ private: void parse_modify_eps_bearer_context_request(srslte::unique_byte_buffer_t pdu); // Packet generators - void gen_attach_request(srslte::byte_buffer_t* msg); - void gen_service_request(srslte::byte_buffer_t* msg); + void gen_attach_request(srslte::unique_byte_buffer_t& msg); + void gen_service_request(srslte::unique_byte_buffer_t& msg); // Senders void send_attach_complete(const uint8_t& transaction_id, const uint8_t& eps_bearer_id); diff --git a/srsue/src/stack/upper/nas.cc b/srsue/src/stack/upper/nas.cc index a0942ab64..db9e3b6b9 100644 --- a/srsue/src/stack/upper/nas.cc +++ b/srsue/src/stack/upper/nas.cc @@ -149,9 +149,9 @@ proc_outcome_t nas::rrc_connect_proc::init(srslte::establishment_cause_t cause_, } if (nas_ptr->state == EMM_STATE_REGISTERED) { - nas_ptr->gen_service_request(pdu.get()); + nas_ptr->gen_service_request(pdu); } else { - nas_ptr->gen_attach_request(pdu.get()); + nas_ptr->gen_attach_request(pdu); } } @@ -856,6 +856,33 @@ bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT* caps) return true; } +/** + * Applies the current security config on a packed NAS PDU + * + * The PDU is ciphered and integrity protected if NAS security is configured + * and the current security context is valid. The function also performs + * a length check. + * + * @param pdu The NAS PDU already packed inside a byte_buffer + * @return True if successfull, false otherwise + */ +int nas::apply_security_config(srslte::unique_byte_buffer_t& pdu) +{ + if (have_ctxt) { + if (pdu->N_bytes > 5) { + cipher_encrypt(pdu.get()); + 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 SRSLTE_ERROR; + } + } else { + nas_log->debug("Not applying security for PDU. No context configured.\n"); + } + return SRSLTE_SUCCESS; +} + /******************************************************************************* * Parsers ******************************************************************************/ @@ -1311,9 +1338,12 @@ void nas::parse_security_mode_command(uint32_t lcid, unique_byte_buffer_t pdu) if (pcap != nullptr) { pcap->write_nas(pdu->msg, pdu->N_bytes); } - cipher_encrypt(pdu.get()); - integrity_generate( - &k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, &pdu->msg[1]); + + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); + return; + } + nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n", ctxt.tx_count, rrc->get_rb_name(lcid).c_str()); @@ -1346,7 +1376,7 @@ void nas::parse_service_reject(uint32_t lcid, unique_byte_buffer_t pdu) // Send attach request after receiving service reject pdu->clear(); - gen_attach_request(pdu.get()); + gen_attach_request(pdu); rrc->write_sdu(std::move(pdu)); } @@ -1548,7 +1578,7 @@ void nas::parse_emm_status(uint32_t lcid, unique_byte_buffer_t pdu) * Senders ******************************************************************************/ -void nas::gen_attach_request(byte_buffer_t* msg) +void nas::gen_attach_request(srslte::unique_byte_buffer_t& msg) { if (msg == nullptr) { nas_log->error("Fatal Error: Couldn't allocate PDU in gen_attach_request().\n"); @@ -1609,14 +1639,11 @@ void nas::gen_attach_request(byte_buffer_t* msg) ctxt.guti.mme_group_id, ctxt.guti.mme_code); liblte_mme_pack_attach_request_msg( - &attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT*)msg); + &attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT*)msg.get()); - // Add MAC - if (msg->N_bytes > 5) { - integrity_generate( - &k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK, &msg->msg[5], msg->N_bytes - 5, &msg->msg[1]); - } else { - nas_log->error("Invalid PDU size %d\n", msg->N_bytes); + if (apply_security_config(msg)) { + nas_log->error("Error applying NAS security.\n"); + return; } } else { attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; @@ -1624,7 +1651,7 @@ void nas::gen_attach_request(byte_buffer_t* msg) attach_req.nas_ksi.nas_ksi = 0; usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); nas_log->info("Requesting IMSI attach (IMSI=%s)\n", usim->get_imsi_str().c_str()); - liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg); + liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg.get()); } if (pcap != nullptr) { @@ -1643,7 +1670,7 @@ void nas::gen_attach_request(byte_buffer_t* msg) } } -void nas::gen_service_request(byte_buffer_t* msg) +void nas::gen_service_request(srslte::unique_byte_buffer_t& msg) { if (msg == nullptr) { nas_log->error("Fatal Error: Couldn't allocate PDU in gen_service_request().\n"); @@ -1772,16 +1799,9 @@ void nas::send_detach_request(bool switch_off) pcap->write_nas(pdu->msg, pdu->N_bytes); } - // Add MAC - if (pdu->N_bytes > 5) { - if (rrc->is_connected()) { - cipher_encrypt(pdu.get()); - } - integrity_generate( - &k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, &pdu->msg[1]); - ctxt.tx_count++; - } else { - nas_log->error("Invalid PDU size %d\n", pdu->N_bytes); + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); + return; } } else { detach_request.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; @@ -1812,6 +1832,8 @@ void nas::send_detach_request(bool switch_off) } callbacks.add_proc(rrc_connector); } + + ctxt.tx_count++; } void nas::send_attach_complete(const uint8_t& transaction_id, const uint8_t& eps_bearer_id) @@ -1836,9 +1858,10 @@ void nas::send_attach_complete(const uint8_t& transaction_id, const uint8_t& eps pcap->write_nas(pdu->msg, pdu->N_bytes); } - cipher_encrypt(pdu.get()); - integrity_generate( - &k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, &pdu->msg[1]); + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); + return; + } // Instruct RRC to enable capabilities rrc->enable_capabilities(); @@ -1867,13 +1890,9 @@ void nas::send_detach_accept() pcap->write_nas(pdu->msg, pdu->N_bytes); } - // Encrypt and add MAC - if (pdu->N_bytes > 5) { - cipher_encrypt(pdu.get()); - 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); + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); + return; } nas_log->info("Sending detach accept\n"); @@ -1902,14 +1921,16 @@ void nas::send_authentication_response(const uint8_t* res, const size_t res_len, pcap->write_nas(pdu->msg, pdu->N_bytes); } - if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && pdu->N_bytes > 5) { - cipher_encrypt(pdu.get()); - integrity_generate( - &k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, &pdu->msg[1]); + if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED) { + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); + return; + } } nas_log->info("Sending Authentication Response\n"); rrc->write_sdu(std::move(pdu)); + ctxt.tx_count++; } void nas::send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param) @@ -1971,10 +1992,11 @@ void nas::send_identity_response(const uint8 id_type, const uint8_t sec_hdr_type liblte_mme_pack_identity_response_msg(&id_resp, sec_hdr_type, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT*)pdu.get()); // add security if needed - if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && pdu->N_bytes > 5) { - cipher_encrypt(pdu.get()); - integrity_generate( - &k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, &pdu->msg[1]); + if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED) { + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); + return; + } } if (pcap != nullptr) { @@ -2126,12 +2148,8 @@ void nas::send_esm_information_response(const uint8 proc_transaction_id) pcap->write_nas(pdu->msg, pdu->N_bytes); } - cipher_encrypt(pdu.get()); - 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); + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); return; } @@ -2165,12 +2183,8 @@ void nas::send_activate_dedicated_eps_bearer_context_accept(const uint8_t& proc_ pcap->write_nas(pdu->msg, pdu->N_bytes); } - cipher_encrypt(pdu.get()); - 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); + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); return; } @@ -2205,12 +2219,8 @@ void nas::send_deactivate_eps_bearer_context_accept(const uint8_t& proc_transact pcap->write_nas(pdu->msg, pdu->N_bytes); } - cipher_encrypt(pdu.get()); - 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); + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); return; } @@ -2245,12 +2255,8 @@ void nas::send_modify_eps_bearer_context_accept(const uint8_t& proc_transaction_ pcap->write_nas(pdu->msg, pdu->N_bytes); } - cipher_encrypt(pdu.get()); - 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); + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); return; } @@ -2278,6 +2284,11 @@ void nas::send_activate_test_mode_complete(const uint8_t sec_hdr_type) pcap->write_nas(pdu->msg, pdu->N_bytes); } + if (apply_security_config(pdu)) { + nas_log->error("Error applying NAS security.\n"); + return; + } + nas_log->info_hex(pdu->msg, pdu->N_bytes, "Sending Activate test mode complete\n"); rrc->write_sdu(std::move(pdu));