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