diff --git a/openair2/LAYER2/Makefile.inc b/openair2/LAYER2/Makefile.inc index 85100ca6f7ce909a3d9fb3bcc266a851f950e2c7..41cac88a1e83d43abc0c153930229bb6c6f1c995 100644 --- a/openair2/LAYER2/Makefile.inc +++ b/openair2/LAYER2/Makefile.inc @@ -26,6 +26,7 @@ SOURCES_L2 += $(PDCP_DIR)/pdcp_fifo.c SOURCES_L2 += $(PDCP_DIR)/pdcp_sequence_manager.c SOURCES_L2 += $(PDCP_DIR)/pdcp_primitives.c SOURCES_L2 += $(PDCP_DIR)/pdcp_util.c +SOURCES_L2 += $(PDCP_DIR)/pdcp_security.c SOURCES_L2 += $(RLC_AM_DIR)/rlc_am.c SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_init.c diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 29f5d9f773bb97e0b85cd699a5de7751c1440f73..635418ed8d018da3a67752fdd9d883e462491980 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -52,6 +52,10 @@ #include "platform_constants.h" #include "UTIL/LOG/vcd_signal_dumper.h" +#if defined(ENABLE_SECURITY) +# include "UTIL/OSA/osa_defs.h" +#endif + #define PDCP_DATA_REQ_DEBUG 0 #define PDCP_DATA_IND_DEBUG 0 @@ -94,7 +98,7 @@ BOOL pdcp_data_req(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb mem_block_t* pdcp_pdu = NULL; rlc_op_status_t rlc_status; - if ((pdcp->instanciated_instance == 0) && (mode != PDCP_TM)) { + if ((pdcp->instanciated_instance == 0) && (mode != PDCP_TM)) { LOG_W(PDCP, "Instance is not configured, Ignoring SDU...\n"); return FALSE; } @@ -178,16 +182,28 @@ BOOL pdcp_data_req(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb free_mem_block(pdcp_pdu); return FALSE; } - + LOG_D(PDCP, "Sequence number %d is assigned to current PDU\n", current_sn); - + /* Then append data... */ memcpy(&pdcp_pdu->data[pdcp_header_len], sdu_buffer, sdu_buffer_size); + //For control plane data that are not integrity protected, // the MAC-I field is still present and should be padded with padding bits set to 0. + // NOTE: user-plane data are never integrity protected for (i=0;i<pdcp_tailer_len;i++) - pdcp_pdu->data[pdcp_header_len + sdu_buffer_size + i] = 0x00;// pdu_header.mac_i[i]; - + pdcp_pdu->data[pdcp_header_len + sdu_buffer_size + i] = 0x00;// pdu_header.mac_i[i]; + +#if defined(ENABLE_SECURITY) + if ((pdcp->security_activated != 0) && + ((pdcp->cipheringAlgorithm) != 0) && + ((pdcp->integrityProtAlgorithm) != 0)) { + pdcp_apply_security(pdcp, rb_id % NB_RB_MAX, + pdcp_header_len, current_sn, pdcp_pdu->data, + sdu_buffer_size); + } +#endif + /* Print octets of outgoing data in hexadecimal form */ LOG_D(PDCP, "Following content with size %d will be sent over RLC (PDCP PDU header is the first two bytes)\n", pdcp_pdu_size); @@ -275,7 +291,8 @@ BOOL pdcp_data_ind(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb u16 sequence_number; u8 payload_offset=0; - LOG_I(PDCP,"Data indication notification for PDCP entity with module ID %d and radio bearer ID %d rlc sdu size %d\n", module_id, rb_id, sdu_buffer_size); + LOG_I(PDCP,"Data indication notification for PDCP entity with module " + "ID %d and radio bearer ID %d rlc sdu size %d eNB_flag %d\n", module_id, rb_id, sdu_buffer_size, eNB_flag); if (sdu_buffer_size == 0) { LOG_W(PDCP, "SDU buffer size is zero! Ignoring this chunk!"); @@ -335,18 +352,13 @@ BOOL pdcp_data_ind(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb } // SRB1/2: control-plane data if ( (rb_id % NB_RB_MAX) < DTCH ){ - /*new_sdu = get_free_mem_block(sdu_buffer_size - pdcp_header_len - pdcp_tailer_len); - if (new_sdu) { - memcpy(new_sdu->data, - &sdu_buffer->data[pdcp_header_len], - sdu_buffer_size - pdcp_header_len - pdcp_tailer_len); - rrc_lite_data_ind(module_id, - frame, - eNB_flag, - rb_id, - sdu_buffer_size - pdcp_header_len - pdcp_tailer_len, - new_sdu->data); - }*/ +#if defined(ENABLE_SECURITY) + if (pdcp->security_activated == 1) { + pdcp_validate_security(pdcp, rb_id % NB_RB_MAX, pdcp_header_len, + sequence_number, sdu_buffer->data, + sdu_buffer_size - pdcp_tailer_len); + } +#endif //rrc_lite_data_ind(module_id, //Modified MW - L2 Interface pdcp_rrc_data_ind(module_id, frame, @@ -359,6 +371,13 @@ BOOL pdcp_data_ind(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb return TRUE; } payload_offset=PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; +#if defined(ENABLE_SECURITY) + if (pdcp->security_activated == 1) { + pdcp_validate_security(pdcp, rb_id % NB_RB_MAX, pdcp_header_len, + sequence_number, sdu_buffer->data, + sdu_buffer_size - pdcp_tailer_len); + } +#endif } else { payload_offset=0; } @@ -493,9 +512,6 @@ void // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer pdcp_fifo_read_input_sdus(frame,eNB_flag); - // NAS -> PDCP traffic - pdcp_fifo_read_input_sdus(frame,eNB_flag); - // PDCP -> NAS/IP traffic: RX pdcp_fifo_flush_sdus(frame,eNB_flag); @@ -505,9 +521,13 @@ void BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index, SRB_ToAddModList_t* srb2add_list, DRB_ToAddModList_t* drb2add_list, - DRB_ToReleaseList_t* drb2release_list + DRB_ToReleaseList_t* drb2release_list, + u8 security_mode, + u8 *kRRCenc, + u8 *kRRCint, + u8 *kUPenc #ifdef Rel10 - ,PMCH_InfoList_r9_t* pmch_InfoList_r9 + ,PMCH_InfoList_r9_t* pmch_InfoList_r9 #endif ){ @@ -537,7 +557,6 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag (eNB_flag == 1)? "eNB": "UE", index); // srb2add_list does not define pdcp config, we use rlc info to setup the pdcp dcch0 and dcch1 channels - if (srb2add_list != NULL) { for (cnt=0;cnt<srb2add_list->list.count;cnt++) { srb_id = srb2add_list->list.array[cnt]->srb_Identity; @@ -570,7 +589,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag srb_sn, 0, // drb_report 0, // header compression - 0xff); //UNDEF_SECURITY_MODE + security_mode, + kRRCenc, + kRRCint, + kUPenc); break; } break; @@ -659,7 +681,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag drb_sn, drb_report, header_compression_profile, - 0xff); + security_mode, + kRRCenc, + kRRCint, + kUPenc); } } } @@ -681,7 +706,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag 0, 0, 0, - 0xff); + security_mode, + kRRCenc, + kRRCint, + kUPenc); } } @@ -717,7 +745,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag 0, // set to deafult 0, 0, - 0xff); + security_mode, + kRRCenc, + kRRCint, + kUPenc); } } } @@ -727,18 +758,19 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag } - BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 index, rlc_mode_t rlc_mode, u32 action, u16 lc_id,u16 mch_id, rb_id_t rb_id, u8 rb_sn, u8 rb_report, u16 header_compression_profile, - u8 security_mode){ + u8 security_mode, + u8 *kRRCenc, + u8 *kRRCint, + u8 *kUPenc){ switch (action) { case ACTION_ADD: pdcp_array[module_id][lc_id].instanciated_instance = module_id + 1; + pdcp_array[module_id][lc_id].is_ue = (eNB_flag == 0) ? 1 : 0; pdcp_array[module_id][lc_id].lcid = lc_id; pdcp_array[module_id][lc_id].header_compression_profile=header_compression_profile; - pdcp_array[module_id][lc_id].cipheringAlgorithm=security_mode & 0x0f; - pdcp_array[module_id][lc_id].integrityProtAlgorithm=(security_mode>>4) & 0xf; pdcp_array[module_id][lc_id].status_report = rb_report; if (rb_sn == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) pdcp_array[module_id][lc_id].seq_num_size = 7; @@ -761,16 +793,24 @@ BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 frame, lc_id, rb_id, pdcp_array[module_id][lc_id].seq_num_size, (rlc_mode == 1) ? "AM" : (rlc_mode == 2) ? "TM" : "UM"); + /* Setup security */ + if (security_mode != 0xff) { + pdcp_config_set_security(module_id, frame, eNB_flag, rb_id, lc_id, security_mode, kRRCenc, kRRCint, kUPenc); + } + LOG_D(PDCP, "[MSC_NEW][FRAME %05d][PDCP][MOD %02d][RB %02d]\n", frame, module_id,rb_id); break; case ACTION_MODIFY: pdcp_array[module_id][lc_id].header_compression_profile=header_compression_profile; - pdcp_array[module_id][lc_id].cipheringAlgorithm=security_mode & 0x0f; - pdcp_array[module_id][lc_id].integrityProtAlgorithm=(security_mode>>4) & 0xf; pdcp_array[module_id][lc_id].status_report = rb_report; pdcp_array[module_id][lc_id].rlc_mode = rlc_mode; + /* Setup security */ + if (security_mode != 0xff) { + pdcp_config_set_security(module_id, frame, eNB_flag, rb_id, lc_id, security_mode, kRRCenc, kRRCint, kUPenc); + } + if (rb_sn == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) pdcp_array[module_id][lc_id].seq_num_size = 7; else if (rb_sn == PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits) @@ -800,8 +840,21 @@ BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 pdcp_array[module_id][lc_id].last_submitted_pdcp_rx_sn = 4095; pdcp_array[module_id][lc_id].seq_num_size = 0; pdcp_array[module_id][lc_id].first_missing_pdu = -1; + pdcp_array[module_id][lc_id].security_activated = 0; + LOG_I(PDCP,"[%s %d] Config request : ACTION_REMOVE: Frame %d LCID %d RBID %d configured\n", - (eNB_flag) ? "eNB" : "UE", module_id, frame, lc_id,rb_id); + (eNB_flag) ? "eNB" : "UE", module_id, frame, lc_id, rb_id); + /* Security keys */ + if (pdcp_array[module_id][lc_id].kUPenc != NULL) { + free(pdcp_array[module_id][lc_id].kUPenc); + } + if (pdcp_array[module_id][lc_id].kRRCint != NULL) { + free(pdcp_array[module_id][lc_id].kRRCint); + } + if (pdcp_array[module_id][lc_id].kRRCenc != NULL) { + free(pdcp_array[module_id][lc_id].kRRCenc); + } + break; case ACTION_MBMS_ADD: @@ -814,23 +867,37 @@ BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 (eNB_flag == 1) ? "eNB" : "UE", module_id, frame, mch_id, lc_id, rb_id); break; case ACTION_SET_SECURITY_MODE: - if ((security_mode >= 0 ) && (security_mode <=0x77)) { - pdcp_array[module_id][lc_id].cipheringAlgorithm= security_mode & 0x0f; - pdcp_array[module_id][lc_id].integrityProtAlgorithm = (security_mode>>4) & 0xf; - LOG_D(PDCP,"[%s %d] Set security mode : ACTION_SET_SECURITY_MODE: Frame %d cipheringAlgorithm %d integrityProtAlgorithm %d\n", - (eNB_flag) ? "eNB" : "UE", module_id, frame, - pdcp_array[module_id][lc_id].cipheringAlgorithm, - pdcp_array[module_id][lc_id].integrityProtAlgorithm ); - }else - LOG_D(PDCP,"[%s %d] bad security mode %d", security_mode); - break; + pdcp_config_set_security(module_id, frame, eNB_flag, rb_id, lc_id, security_mode, kRRCenc, kRRCint, kUPenc); + break; default: - LOG_W(PDCP,"unknown action %d for the config request\n",action); - break; + LOG_W(PDCP,"unknown action %d for the config request\n",action); + break; } return 0; } - + +void pdcp_config_set_security(module_id_t module_id, u32 frame, u8 eNB_flag, rb_id_t rb_id, + u16 lc_id, u8 security_mode, u8 *kRRCenc, u8 *kRRCint, u8 *kUPenc) +{ + if ((security_mode >= 0) && (security_mode <= 0x77)) { + pdcp_array[module_id][lc_id].cipheringAlgorithm = security_mode & 0x0f; + pdcp_array[module_id][lc_id].integrityProtAlgorithm = (security_mode>>4) & 0xf; + LOG_D(PDCP,"[%s %d][RB %02d] Set security mode : ACTION_SET_SECURITY_MODE: " + "Frame %d cipheringAlgorithm %d integrityProtAlgorithm %d\n", + (eNB_flag) ? "eNB" : "UE", module_id, rb_id, frame, + pdcp_array[module_id][lc_id].cipheringAlgorithm, + pdcp_array[module_id][lc_id].integrityProtAlgorithm); + pdcp_array[module_id][lc_id].kRRCenc = kRRCenc; + pdcp_array[module_id][lc_id].kRRCint = kRRCint; + pdcp_array[module_id][lc_id].kUPenc = kUPenc; + + /* Activate security */ + pdcp_array[module_id][lc_id].security_activated = 1; + } else { + LOG_D(PDCP,"[%s %d] bad security mode %d", security_mode); + } +} + void rrc_pdcp_config_req (module_id_t module_id, u32 frame, u8_t eNB_flag, u32 action, rb_id_t rb_id, u8 security_mode){ /* @@ -867,6 +934,7 @@ void rrc_pdcp_config_req (module_id_t module_id, u32 frame, u8_t eNB_flag, u32 pdcp_array[module_id][rb_id%NB_RB_MAX].last_submitted_pdcp_rx_sn = 4095; pdcp_array[module_id][rb_id%NB_RB_MAX].seq_num_size = 0; pdcp_array[module_id][rb_id%NB_RB_MAX].first_missing_pdu = -1; + pdcp_array[module_id][rb_id].security_activated = 0; LOG_D(PDCP,"[%s %d] Config request : ACTION_REMOVE: Frame %d radio bearer id %d configured\n", (eNB_flag) ? "eNB" : "UE", module_id, frame, rb_id); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index d24ed4f4f3ae8d23dd96238d2408b4ddefb6b55b..06e4420db3f40ebecbf92f811e40c22bb3b61564 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -110,9 +110,26 @@ typedef struct pdcp_t { BOOL instanciated_instance; u16 header_compression_profile; + /* SR: added this flag to distinguish UE/eNB instance as pdcp_run for virtual + * mode can receive data on NETLINK for eNB while eNB_flag = 0 and for UE when eNB_flag = 1 + */ + u8 is_ue; + + /* Configured security algorithms */ u8 cipheringAlgorithm; u8 integrityProtAlgorithm; + /* User-Plane encryption key + * Control-Plane RRC encryption key + * Control-Plane RRC integrity key + * These keys are configured by RRC layer + */ + u8 *kUPenc; + u8 *kRRCint; + u8 *kRRCenc; + + u8 security_activated; + u8 rlc_mode; u8 status_report; u8 seq_num_size; @@ -260,14 +277,25 @@ public_pdcp(void rrc_pdcp_config_req (module_id_t module_id, u32 frame, u8_t eNB * \param[in] srb2add_list SRB configuration list to be created. * \param[in] drb2add_list DRB configuration list to be created. * \param[in] drb2release_list DRB configuration list to be released. +* \param[in] security_mode Security algorithm to apply for integrity/ciphering +* \param[in] kRRCenc RRC encryption key +* \param[in] kRRCint RRC integrity key +* \param[in] kUPenc User-Plane encryption key * \return A status about the processing, OK or error code. */ +public_pdcp( +BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index, + SRB_ToAddModList_t* srb2add_list, + DRB_ToAddModList_t* drb2add_list, + DRB_ToReleaseList_t* drb2release_list, + u8 security_mode, + u8 *kRRCenc, + u8 *kRRCint, + u8 *kUPenc #ifdef Rel10 -public_pdcp(BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index, SRB_ToAddModList_t* srb2add_list, DRB_ToAddModList_t* drb2add_list, DRB_ToReleaseList_t* drb2release_list,PMCH_InfoList_r9_t* pmch_InfoList_r9);) -#else -public_pdcp(BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index, SRB_ToAddModList_t* srb2add_list, DRB_ToAddModList_t* drb2add_list, DRB_ToReleaseList_t* drb2release_list);) + ,PMCH_InfoList_r9_t* pmch_InfoList_r9 #endif - + )); /*! \fn BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u32 action, rb_id_t rb_id, u8 rb_sn, u8 rb_report, u16 header_compression_profile, u8 security_mode) * \brief Function for RRC to configure a Radio Bearer. @@ -280,10 +308,18 @@ public_pdcp(BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u * \param[in] drb_report set a pdcp report for this drb * \param[in] header_compression set the rohc profile * \param[in] security_mode set the integrity and ciphering algs +* \param[in] kRRCenc RRC encryption key +* \param[in] kRRCint RRC integrity key +* \param[in] kUPenc User-Plane encryption key * \return A status about the processing, OK or error code. */ -public_pdcp(BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 index, rlc_mode_t rlc_mode, u32 action, u16 lc_id, u16 mch_id, rb_id_t rb_id, u8 rb_sn, u8 rb_report, u16 header_compression_profile, u8 security_mode);) - +public_pdcp(BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 index, + rlc_mode_t rlc_mode, u32 action, u16 lc_id,u16 mch_id, rb_id_t rb_id, + u8 rb_sn, u8 rb_report, u16 header_compression_profile, + u8 security_mode, + u8 *kRRCenc, + u8 *kRRCint, + u8 *kUPenc)); /*! \fn void rrc_pdcp_config_release(module_id_t, rb_id_t) * \brief This functions is unused * \param[in] module_id Module ID of relevant PDCP entity diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h index 587c1ee977093204cf5ab676237c5d0228f4f153..10b868bc08e5b8b58ccda82684d8a1d6dbc2b8db 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h @@ -153,4 +153,17 @@ BOOL pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* pdu_b BOOL pdcp_serialize_control_pdu_for_pdcp_status_report(unsigned char* pdu_buffer, \ u8 bitmap[512], pdcp_control_pdu_for_pdcp_status_report* pdu); +void pdcp_config_set_security(module_id_t module_id, u32 frame, u8 eNB_flag, rb_id_t rb_id, + u16 lc_id, u8 security_mode, u8 *kRRCenc, u8 *kRRCint, u8 *kUPenc); + +#if defined(ENABLE_SECURITY) +int pdcp_apply_security(pdcp_t *pdcp_entity, rb_id_t rb_id, + u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer, + u16 sdu_buffer_size); + +int pdcp_validate_security(pdcp_t *pdcp_entity, rb_id_t rb_id, + u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer, + u16 sdu_buffer_size); +#endif /* defined(ENABLE_SECURITY) */ + #endif diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c new file mode 100644 index 0000000000000000000000000000000000000000..88cc5c72e98691594e044cc375f481070b3093c6 --- /dev/null +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c @@ -0,0 +1,190 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fsr/openairinterface + Address : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France + +*******************************************************************************/ +/*! \file pdcp_security.c + * \brief PDCP Security Methods + * \author ROUX Sebastien + * \date 2013 + */ +#include <stdint.h> + +#include "assertions.h" + +#include "UTIL/LOG/log.h" +#include "UTIL/OSA/osa_defs.h" + +#include "LAYER2/MAC/extern.h" + +#include "pdcp.h" +#include "pdcp_primitives.h" + +#if defined(ENABLE_SECURITY) + +static +u32 pdcp_get_next_count_tx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn); +static +u32 pdcp_get_next_count_rx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn); + +static +u32 pdcp_get_next_count_tx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn) +{ + u32 count; + /* For TX COUNT = TX_HFN << length of SN | pdcp SN */ + if (pdcp_header_len == PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE) { + /* 5 bits length SN */ + count = (pdcp_entity->tx_hfn << 5) | (pdcp_sn & 0x001F); + } else { + /* 12 bits length SN */ + count = (pdcp_entity->tx_hfn << 12) | (pdcp_sn & 0x0FFF); + } +// LOG_D(PDCP, "[OSA] TX COUNT = 0x%08x\n", count); + + return count; +} + +static +u32 pdcp_get_next_count_rx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn) +{ + u32 count; + /* For RX COUNT = RX_HFN << length of SN | pdcp SN of received PDU */ + if (pdcp_header_len == PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE) { + /* 5 bits length SN */ + count = (pdcp_entity->rx_hfn << 5) | (pdcp_sn & 0x001F); + } else { + /* 12 bits length SN */ + count = (pdcp_entity->rx_hfn << 12) | (pdcp_sn & 0x0FFF); + } +// LOG_D(PDCP, "[OSA] RX COUNT = 0x%08x\n", count); + + return count; +} + +int pdcp_apply_security(pdcp_t *pdcp_entity, rb_id_t rb_id, + u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer, + u16 sdu_buffer_size) +{ + u8 *buffer_encrypted = NULL; + stream_cipher_t encrypt_params; + + DevAssert(pdcp_entity != NULL); + DevAssert(pdcp_pdu_buffer != NULL); + DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0); + + encrypt_params.direction = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK; + encrypt_params.bearer = rb_id; + encrypt_params.count = pdcp_get_next_count_tx(pdcp_entity, pdcp_header_len, current_sn); + encrypt_params.key_length = 16; + + if (rb_id < DTCH) { + /* SRBs */ + u8 *mac_i; + + LOG_D(PDCP, "[OSA][RB %d] %s Applying control-plane security\n", + rb_id, (pdcp_entity->is_ue != 0) ? "UE -> eNB" : "eNB -> UE"); + + encrypt_params.message = pdcp_pdu_buffer; + encrypt_params.blength = (pdcp_header_len + sdu_buffer_size) << 3; + encrypt_params.key = pdcp_entity->kRRCint; + + mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size]; + + /* Both header and data parts are integrity protected for + * control-plane PDUs */ + stream_compute_integrity(pdcp_entity->integrityProtAlgorithm, &encrypt_params, + mac_i); + + encrypt_params.key = pdcp_entity->kRRCenc; + } else { + LOG_D(PDCP, "[OSA][RB %d] %s Applying user-plane security\n", + rb_id, (pdcp_entity->is_ue != 0) ? "UE -> eNB" : "eNB -> UE"); + + encrypt_params.key = pdcp_entity->kUPenc; + } + + encrypt_params.message = &pdcp_pdu_buffer[pdcp_header_len]; + encrypt_params.blength = sdu_buffer_size << 3; + + buffer_encrypted = &pdcp_pdu_buffer[pdcp_header_len]; + + /* Apply ciphering if any requested */ + stream_encrypt(pdcp_entity->cipheringAlgorithm, &encrypt_params, + &buffer_encrypted); + + return 0; +} + +int pdcp_validate_security(pdcp_t *pdcp_entity, rb_id_t rb_id, + u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer, + u16 sdu_buffer_size) +{ + u8 *buffer_decrypted = NULL; + stream_cipher_t decrypt_params; + + DevAssert(pdcp_entity != NULL); + + DevAssert(pdcp_pdu_buffer != NULL); + DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0); + + buffer_decrypted = (u8*)&pdcp_pdu_buffer[pdcp_header_len]; + + decrypt_params.direction = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_DOWNLINK : SECU_DIRECTION_UPLINK ; + decrypt_params.bearer = rb_id; + decrypt_params.count = pdcp_get_next_count_rx(pdcp_entity, pdcp_header_len, current_sn); + decrypt_params.message = &pdcp_pdu_buffer[pdcp_header_len]; + decrypt_params.blength = (sdu_buffer_size - pdcp_header_len) << 3; + decrypt_params.key_length = 16; + + if (rb_id < DTCH) { + LOG_D(PDCP, "[OSA][RB %d] %s Validating control-plane security\n", + rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB"); + decrypt_params.key = pdcp_entity->kRRCenc; + } else { + LOG_D(PDCP, "[OSA][RB %d] %s Validating user-plane security\n", + rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB"); + decrypt_params.key = pdcp_entity->kUPenc; + } + + /* Uncipher the block */ + stream_decrypt(pdcp_entity->cipheringAlgorithm, &decrypt_params, &buffer_decrypted); + + if (rb_id < DTCH) { + /* Now check the integrity of the complete PDU */ + decrypt_params.message = pdcp_pdu_buffer; + decrypt_params.blength = sdu_buffer_size << 3; + decrypt_params.key = pdcp_entity->kRRCint; + + if (stream_check_integrity(pdcp_entity->integrityProtAlgorithm, + &decrypt_params, &pdcp_pdu_buffer[sdu_buffer_size]) != 0) { + LOG_E(PDCP, "[OSA] failed to validate MAC-I of incoming PDU\n"); + return -1; + } + } + return 0; +} + +#endif /* ENABLE_SECURITY */ diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index a87afa1a5abe038074e69ecd0b8e16610cc6a2b1..6aeeef602bd2c9ca6a4545d6f914299daa0b7177 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -36,12 +36,22 @@ # @ingroup _mac */ -#ifndef USER_MODE +#ifdef USER_MODE +# include <inttypes.h> +#else #include <linux/kernel.h> #include <linux/module.h> #include <linux/proc_fs.h> +# ifndef PRIu64 +# if __WORDSIZE == 64 +# define PRIu64 "lu" +# else +# define PRIu64 "llu" +# endif +# endif #endif + #include "LAYER2/RLC/rlc.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/extern.h" @@ -114,7 +124,10 @@ int dump_eNB_l2_stats(char *buffer, int length){ eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].ncce_used_retx ); - len += sprintf(&buffer[len],"[MAC] DLSCH bitrate (TTI %d, avg %d), Transmitted bytes (TTI %d, total %d), Total Transmitted PDU %d, Overhead (TTI %d, total %d, avg %d)", + len += sprintf(&buffer[len], + "[MAC] DLSCH bitrate (TTI %d, avg %d), Transmitted bytes " + "(TTI %d, total %"PRIu64"), Total Transmitted PDU %d, Overhead " + "(TTI %"PRIu64", total %"PRIu64", avg %"PRIu64, eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].dlsch_bitrate, eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].total_dlsch_bitrate, eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].TBS, diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index e21df15a88a5077cb9cd5476f2e5ebcdba8e39e5..35f32b4104c14df1199d7180e07821bcf64f4fe8 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -772,7 +772,7 @@ uint8_t do_SIB23(uint8_t Mod_id, *(*sib3)->intraFreqCellReselectionInfo.s_IntraSearch = 31; (*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth=CALLOC(1,sizeof(*(*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth)); - (*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth=AllowedMeasBandwidth_mbw6; + *(*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth = AllowedMeasBandwidth_mbw6; (*sib3)->intraFreqCellReselectionInfo.presenceAntennaPort1 = 0; (*sib3)->intraFreqCellReselectionInfo.neighCellConfig.buf = CALLOC(8,1); @@ -1299,25 +1299,28 @@ uint8_t do_RRCConnectionSetup(uint8_t *buffer, return((enc_rval.encoded+7)/8); } uint8_t do_SecurityModeCommand(uint8_t Mod_id, - uint8_t *buffer, - uint8_t UE_id, - uint8_t Transaction_id) { + uint8_t *buffer, + uint8_t UE_id, + uint8_t Transaction_id, + uint8_t cipheringAlgorithm, + uint8_t integrityProtAlgorithm) { DL_DCCH_Message_t dl_dcch_msg; asn_enc_rval_t enc_rval; memset(&dl_dcch_msg,0,sizeof(DL_DCCH_Message_t)); - dl_dcch_msg.message.present = DL_DCCH_MessageType_PR_c1; - dl_dcch_msg.message.choice.c1.present = DL_DCCH_MessageType__c1_PR_securityModeCommand; - - dl_dcch_msg.message.choice.c1.choice.securityModeCommand.rrc_TransactionIdentifier = Transaction_id; - dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.present = SecurityModeCommand__criticalExtensions_PR_c1; - - dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.present = SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8; - // the two following information could be based on the mod_id - dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm=SecurityAlgorithmConfig__cipheringAlgorithm_spare1; - dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm=SecurityAlgorithmConfig__integrityProtAlgorithm_spare1; + dl_dcch_msg.message.present = DL_DCCH_MessageType_PR_c1; + dl_dcch_msg.message.choice.c1.present = DL_DCCH_MessageType__c1_PR_securityModeCommand; + + dl_dcch_msg.message.choice.c1.choice.securityModeCommand.rrc_TransactionIdentifier = Transaction_id; + dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.present = SecurityModeCommand__criticalExtensions_PR_c1; + dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.present = SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8; + // the two following information could be based on the mod_id + dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm + = (e_SecurityAlgorithmConfig__cipheringAlgorithm)cipheringAlgorithm; + dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm + = (e_SecurityAlgorithmConfig__integrityProtAlgorithm)integrityProtAlgorithm; #ifdef XER_PRINT xer_fprint(stdout, &asn_DEF_DL_DCCH_Message, (void*)&dl_dcch_msg); @@ -1680,7 +1683,7 @@ uint8_t do_MeasurementReport(uint8_t *buffer,int measid,int phy_id,int rsrp_s,in 100); #ifdef USER_MODE - printf("Measurement Report Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + printf("Measurement Report Encoded %zu bits (%zu bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #endif return((enc_rval.encoded+7)/8); diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.h b/openair2/RRC/LITE/MESSAGES/asn1_msg.h index 3a53b1253a0c630b1852cd252ce728ac47b7f0bc..9741077b2e5556c2fd25de3e5f41ba7195d2d593 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.h +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.h @@ -141,6 +141,8 @@ uint8_t do_UECapabilityEnquiry(uint8_t Mod_id, uint8_t Transaction_id); uint8_t do_SecurityModeCommand(uint8_t Mod_id, - uint8_t *buffer, - uint8_t UE_id, - uint8_t Transaction_id); + uint8_t *buffer, + uint8_t UE_id, + uint8_t Transaction_id, + uint8_t cipheringAlgorithm, + uint8_t integrityProtAlgorithm); diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index d2dcd5409c233e0db52622c01c7f0586c2adadb2..a609f414ec6ee97c3e341dc7930f866b0533e8a2 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -240,6 +240,15 @@ typedef struct{ SRB_INFO Srb0; SRB_INFO_TABLE_ENTRY Srb1[NUMBER_OF_UE_MAX+1]; SRB_INFO_TABLE_ENTRY Srb2[NUMBER_OF_UE_MAX+1]; + +#if defined(ENABLE_SECURITY) + /* KeNB as derived from KASME received from EPC */ + uint8_t kenb[NUMBER_OF_UE_MAX][32]; +#endif + + /* Used integrity/ciphering algorithms */ + e_SecurityAlgorithmConfig__cipheringAlgorithm ciphering_algorithm[NUMBER_OF_UE_MAX]; + e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm[NUMBER_OF_UE_MAX]; } eNB_RRC_INST; #define MAX_UE_CAPABILITY_SIZE 255 @@ -300,6 +309,15 @@ typedef struct{ struct SPS_Config *sps_Config[NB_CNX_UE]; MAC_MainConfig_t *mac_MainConfig[NB_CNX_UE]; MeasGapConfig_t *measGapConfig[NB_CNX_UE]; + +#if defined(ENABLE_SECURITY) + /* KeNB as computed from parameters within USIM card */ + uint8_t kenb[32]; +#endif + + /* Used integrity/ciphering algorithms */ + e_SecurityAlgorithmConfig__cipheringAlgorithm ciphering_algorithm; + e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; }UE_RRC_INST; //main.c diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 9488196283f3065370ef81bb7be9992729609507..2b66aef667375462620ea6f307a0125cdee257f9 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -68,6 +68,11 @@ #include "RRC/NAS/nas_config.h" #include "RRC/NAS/rb_config.h" #endif + +#if defined(ENABLE_SECURITY) +# include "UTIL/OSA/osa_defs.h" +#endif + #ifdef PHY_EMUL extern EMULATION_VARS *Emul_vars; #endif @@ -110,9 +115,29 @@ void init_MCCH_UE(u8 Mod_id, u8 eNB_index) { UE_rrc_inst[Mod_id].MCCH_MESSAGE[eNB_index] = (u8 *)malloc16(32); UE_rrc_inst[Mod_id].mcch_message[eNB_index] = (MBSFNAreaConfiguration_r9_t *)malloc16(sizeof(MBSFNAreaConfiguration_r9_t)); UE_rrc_inst[Mod_id].Info[eNB_index].MCCH_MESSAGEStatus = 0; - - } + +} +#endif + +static +void openair_rrc_lite_ue_init_security(u8 Mod_id) +{ +#if defined(ENABLE_SECURITY) + uint8_t *kRRCenc; + uint8_t *kRRCint; + char ascii_buffer[65]; + uint8_t i; + + memset(UE_rrc_inst[Mod_id].kenb, Mod_id, 32); + + for (i = 0; i < 32; i++) { + sprintf(&ascii_buffer[2 * i], "%02X", UE_rrc_inst[Mod_id].kenb[i]); + } + + LOG_T(RRC, "[OSA][UE %02d] kenb = %s\n", + Mod_id, ascii_buffer); #endif +} /*------------------------------------------------------------------------------*/ char openair_rrc_lite_ue_init(u8 Mod_id, unsigned char eNB_index){ @@ -130,6 +155,15 @@ char openair_rrc_lite_ue_init(u8 Mod_id, unsigned char eNB_index){ UE_rrc_inst[Mod_id].Srb1[eNB_index].Active=0; UE_rrc_inst[Mod_id].Srb2[eNB_index].Active=0; + UE_rrc_inst[Mod_id].ciphering_algorithm = SecurityAlgorithmConfig__cipheringAlgorithm_eea0; +#ifdef Rel10 + UE_rrc_inst[Mod_id].integrity_algorithm = SecurityAlgorithmConfig__integrityProtAlgorithm_eia0_v920; +#else + UE_rrc_inst[Mod_id].integrity_algorithm = SecurityAlgorithmConfig__integrityProtAlgorithm_reserved; +#endif + + openair_rrc_lite_ue_init_security(Mod_id); + init_SI_UE(Mod_id,eNB_index); LOG_D(RRC,"[UE %d] INIT: phy_sync_2_ch_ind\n", Mod_id); @@ -652,12 +686,26 @@ void rrc_ue_process_radioResourceConfigDedicated(u8 Mod_id,u32 frame, u8 eNB_ind // Establish SRBs if present // loop through SRBToAddModList if (radioResourceConfigDedicated->srb_ToAddModList) { + uint8_t *kRRCenc = NULL; + uint8_t *kRRCint = NULL; + +#if defined(ENABLE_SECURITY) + derive_key_rrc_enc(UE_rrc_inst[Mod_id].ciphering_algorithm, + UE_rrc_inst[Mod_id].kenb, &kRRCenc); + derive_key_rrc_int(UE_rrc_inst[Mod_id].integrity_algorithm, + UE_rrc_inst[Mod_id].kenb, &kRRCint); +#endif // Refresh SRBs rrc_pdcp_config_asn1_req(NB_eNB_INST+Mod_id,frame,0,eNB_index, - radioResourceConfigDedicated->srb_ToAddModList, - (DRB_ToAddModList_t*)NULL, - (DRB_ToReleaseList_t*)NULL + radioResourceConfigDedicated->srb_ToAddModList, + (DRB_ToAddModList_t*)NULL, + (DRB_ToReleaseList_t*)NULL, + UE_rrc_inst[Mod_id].ciphering_algorithm | + (UE_rrc_inst[Mod_id].integrity_algorithm << 4), + kRRCenc, + kRRCint, + NULL #ifdef Rel10 ,(MBMS_SessionInfoList_r9_t *)NULL #endif @@ -790,12 +838,23 @@ void rrc_ue_process_radioResourceConfigDedicated(u8 Mod_id,u32 frame, u8 eNB_ind // Establish DRBs if present if (radioResourceConfigDedicated->drb_ToAddModList) { + uint8_t *kUPenc; + +#if defined(ENABLE_SECURITY) + derive_key_up_enc(UE_rrc_inst[Mod_id].integrity_algorithm, + UE_rrc_inst[Mod_id].kenb, &kUPenc); +#endif // Refresh DRBs rrc_pdcp_config_asn1_req(NB_eNB_INST+Mod_id,frame,0,eNB_index, - (SRB_ToAddModList_t*)NULL, - radioResourceConfigDedicated->drb_ToAddModList, - (DRB_ToReleaseList_t*)NULL + (SRB_ToAddModList_t*)NULL, + radioResourceConfigDedicated->drb_ToAddModList, + (DRB_ToReleaseList_t*)NULL, + UE_rrc_inst[Mod_id].ciphering_algorithm | + (UE_rrc_inst[Mod_id].integrity_algorithm << 4), + NULL, + NULL, + kUPenc #ifdef Rel10 ,(MBMS_SessionInfoList_r9_t *)NULL #endif @@ -907,7 +966,11 @@ void rrc_ue_process_securityModeCommand(uint8_t Mod_id,uint32_t frame,SecurityMo break; } LOG_D(RRC,"[UE %d] security mode is %x \n",Mod_id, securityMode); - + + /* Store the parameters received */ + UE_rrc_inst[Mod_id].ciphering_algorithm = securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm; + UE_rrc_inst[Mod_id].integrity_algorithm = securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm; + memset((void *)&ul_dcch_msg,0,sizeof(UL_DCCH_Message_t)); //memset((void *)&SecurityModeCommand,0,sizeof(SecurityModeCommand_t)); @@ -1035,8 +1098,7 @@ void rrc_ue_process_rrcConnectionReconfiguration(u8 Mod_id, u32 frame, if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated) { LOG_I(RRC,"Radio Resource Configuration is present\n"); rrc_ue_process_radioResourceConfigDedicated(Mod_id,frame,eNB_index, - rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated); - + rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated); } } // c1 present } // critical extensions present @@ -1219,6 +1281,7 @@ int decode_BCCH_DLSCH_Message(u8 Mod_id,u32 frame,u8 eNB_index,u8 *Sdu,u8 Sdu_le } break; case BCCH_DL_SCH_MessageType__c1_PR_NOTHING: + default: break; } } @@ -1227,6 +1290,8 @@ int decode_BCCH_DLSCH_Message(u8 Mod_id,u32 frame,u8 eNB_index,u8 *Sdu,u8 Sdu_le (UE_rrc_inst[Mod_id].Info[eNB_index].SIStatus == 1) && (frame >= Mod_id * 20 + 10)) SEQUENCE_free(&asn_DEF_BCCH_DL_SCH_Message, (void*)bcch_message, 0);*/ vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT); + + return 0; } @@ -1385,10 +1450,10 @@ void dump_sib2(SystemInformationBlockType2_t *sib2) { LOG_D(RRC,"ue_TimersAndConstants.n311 : %ld\n", sib2->ue_TimersAndConstants.n311); LOG_D(RRC,"freqInfo.additionalSpectrumEmission : %ld\n",sib2->freqInfo.additionalSpectrumEmission); - LOG_D(RRC,"freqInfo.ul_CarrierFreq : %d\n",(int)sib2->freqInfo.ul_CarrierFreq); - LOG_D(RRC,"freqInfo.ul_Bandwidth : %d\n",(int)sib2->freqInfo.ul_Bandwidth); - LOG_D(RRC,"mbsfn_SubframeConfigList : %d\n",(int)sib2->mbsfn_SubframeConfigList); - LOG_D(RRC,"timeAlignmentTimerCommon : %ld\n",sib2->timeAlignmentTimerCommon); + LOG_D(RRC,"freqInfo.ul_CarrierFreq : %ld\n", sib2->freqInfo.ul_CarrierFreq); + LOG_D(RRC,"freqInfo.ul_Bandwidth : %ld\n", sib2->freqInfo.ul_Bandwidth); + LOG_D(RRC,"mbsfn_SubframeConfigList : %ld\n", sib2->mbsfn_SubframeConfigList); + LOG_D(RRC,"timeAlignmentTimerCommon : %ld\n", sib2->timeAlignmentTimerCommon); diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 8a83409c862f796c15c02d95bf2f8a0f4f306556..969acf6a5174a55a6f7cd78634393f65440e5833 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -64,6 +64,10 @@ #include "OCG_extern.h" #endif +#if defined(ENABLE_SECURITY) +# include "UTIL/OSA/osa_defs.h" +#endif + #if defined(ENABLE_USE_MME) #include "../../S1AP/s1ap_eNB.h" #endif @@ -412,6 +416,23 @@ init_MBMS (u8 Mod_id, u32 frame) #endif +static +void rrc_lite_eNB_init_security(u8 Mod_id, u8 UE_index) +{ +#if defined(ENABLE_SECURITY) + char ascii_buffer[65]; + uint8_t i; + + memset(eNB_rrc_inst[Mod_id].kenb[UE_index], UE_index, 32); + + for (i = 0; i < 32; i++) { + sprintf(&ascii_buffer[2 * i], "%02X", eNB_rrc_inst[Mod_id].kenb[UE_index][i]); + } + + LOG_T(RRC, "[OSA][MOD %02d][UE %02d] kenb = %s\n", Mod_id, UE_index, ascii_buffer); +#endif +} + /*------------------------------------------------------------------------------*/ char openair_rrc_lite_eNB_init (u8 Mod_id) @@ -426,6 +447,13 @@ openair_rrc_lite_eNB_init (u8 Mod_id) for (j = 0; j < NUMBER_OF_UE_MAX; j++) eNB_rrc_inst[Mod_id].Info.Status[j] = RRC_IDLE; //CH_READY; + /* Init security parameters */ + for (j = 0; j < NUMBER_OF_UE_MAX; j++) { + eNB_rrc_inst[Mod_id].ciphering_algorithm[j] = SecurityAlgorithmConfig__cipheringAlgorithm_eea2; + eNB_rrc_inst[Mod_id].integrity_algorithm[j] = SecurityAlgorithmConfig__integrityProtAlgorithm_eia2; + rrc_lite_eNB_init_security(Mod_id, j); + } + #if defined(ENABLE_USE_MME) /* Connect eNB to MME */ if (oai_emulation.info.mme_enabled > 0) @@ -931,7 +959,11 @@ rrc_eNB_decode_ccch (u8 Mod_id, u32 frame, SRB_INFO * Srb_info) eNB_rrc_inst[Mod_id]. SRB_configList[UE_index], (DRB_ToAddModList_t *) NULL, - (DRB_ToReleaseList_t *) NULL + (DRB_ToReleaseList_t *) NULL, + 0xff, + NULL, + NULL, + NULL #ifdef Rel10 , (PMCH_InfoList_r9_t *) NULL #endif @@ -1017,7 +1049,9 @@ rrc_eNB_generate_SecurityModeCommand (u8 Mod_id, u32 frame, u16 UE_index) uint8_t buffer[100]; uint8_t size; - size = do_SecurityModeCommand (Mod_id, buffer, UE_index, 0); + size = do_SecurityModeCommand (Mod_id, buffer, UE_index, 0, + eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index], + eNB_rrc_inst[Mod_id].integrity_algorithm[UE_index]); LOG_I (RRC, "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d, UE id %d)\n", @@ -1611,15 +1645,38 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete (u8 Mod_id, u32 frame, int oip_ifup = 0; int dest_ip_offset = 0; #endif + + uint8_t *kRRCenc = NULL; + uint8_t *kRRCint = NULL; + uint8_t *kUPenc = NULL; + DRB_ToAddModList_t *DRB_configList = eNB_rrc_inst[Mod_id].DRB_configList[UE_index]; SRB_ToAddModList_t *SRB_configList = eNB_rrc_inst[Mod_id].SRB_configList[UE_index]; +#if defined(ENABLE_SECURITY) + /* Derive the keys from kenb */ + if (DRB_configList != NULL) { + derive_key_up_enc(eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index], + eNB_rrc_inst[Mod_id].kenb[UE_index], &kUPenc); + } + + derive_key_rrc_enc(eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index], + eNB_rrc_inst[Mod_id].kenb[UE_index], &kRRCenc); + derive_key_rrc_int(eNB_rrc_inst[Mod_id].integrity_algorithm[UE_index], + eNB_rrc_inst[Mod_id].kenb[UE_index], &kRRCint); +#endif + // Refresh SRBs/DRBs rrc_pdcp_config_asn1_req (Mod_id, frame, 1, UE_index, SRB_configList, - DRB_configList, (DRB_ToReleaseList_t *) NULL + DRB_configList, (DRB_ToReleaseList_t *) NULL, + eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index] | + (eNB_rrc_inst[Mod_id].integrity_algorithm[UE_index] << 4), + kRRCenc, + kRRCint, + kUPenc #ifdef Rel10 , (PMCH_InfoList_r9_t *) NULL #endif diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index 3203544eea30554b72c4830f6147c69df8fcbc59..72a789727179ac5b4634380cb1ddc6a173278c7d 100755 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -281,6 +281,14 @@ int logInit (void) { g_log->log_component[HW].filelog = 0; g_log->log_component[HW].filelog_name = ""; + g_log->log_component[OSA].name = "OSA"; + g_log->log_component[OSA].level = LOG_EMERG; + g_log->log_component[OSA].flag = LOG_MED; + g_log->log_component[OSA].interval = 1; + g_log->log_component[OSA].fd = 0; + g_log->log_component[OSA].filelog = 0; + g_log->log_component[OSA].filelog_name = ""; + g_log->level2string[LOG_EMERG] = "G"; //EMERG g_log->level2string[LOG_ALERT] = "A"; // ALERT g_log->level2string[LOG_CRIT] = "C"; // CRITIC diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index 67de407929a16e7285ea83a5aee51ac81d58c89a..9fbb7878402cbfbc336099c0f88d2c35c66b4af3 100755 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -231,7 +231,34 @@ extern "C" { //static char *log_level_highlight_end[] = {LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, "", "", "", LOG_RESET}; /*!< \brief Optional end-format strings for highlighting */ - typedef enum {MIN_LOG_COMPONENTS=0, PHY, MAC, EMU, OCG, OMG,OPT,OTG,OTG_LATENCY,OTG_LATENCY_BG, OTG_GP, OTG_GP_BG,OTG_JITTER, RLC, PDCP, RRC, PERF,OIP, CLI, MSC, OCM, S1AP, SCTP, HW, MAX_LOG_COMPONENTS} comp_name_t; +typedef enum { + MIN_LOG_COMPONENTS = 0, + PHY, + MAC, + EMU, + OCG, + OMG, + OPT, + OTG, + OTG_LATENCY, + OTG_LATENCY_BG, + OTG_GP, + OTG_GP_BG, + OTG_JITTER, + RLC, + PDCP, + RRC, + PERF, + OIP, + CLI, + MSC, + OCM, + S1AP, + SCTP, + HW, + OSA, + MAX_LOG_COMPONENTS +} comp_name_t; //#define msg printf diff --git a/openair2/UTIL/Makefile.inc b/openair2/UTIL/Makefile.inc index ba96b53303347325c5cfa775dfefd4eb0a515ca4..75ec78cf434db19e79f67359a470103162cac152 100644 --- a/openair2/UTIL/Makefile.inc +++ b/openair2/UTIL/Makefile.inc @@ -12,6 +12,7 @@ CLI_DIR=$(OPENAIR2_TOP)/UTIL/CLI OMV_DIR=$(OPENAIR2_TOP)/UTIL/OMV SCTP_DIR=$(OPENAIR2_TOP)/UTIL/SCTP LFDS_DIR=$(OPENAIR2_TOP)/UTIL/LFDS/liblfds6.1.1/liblfds611 +OSA_DIR=$(OPENAIR2_TOP)/UTIL/OSA LIST_OBJ = $(LIST_DIR)/list.o @@ -34,6 +35,12 @@ OCG_OBJS += $(OCG_DIR)/OCG_parse_filename.o OCG_OBJS += $(OCG_DIR)/OCG_parse_XML.o OCG_OBJS += $(OCG_DIR)/OCG_save_XML.o +ifdef SECU +OSA_OBJS = $(OSA_DIR)/osa_key_deriver.o +OSA_OBJS += $(OSA_DIR)/osa_stream_eia.o +OSA_OBJS += $(OSA_DIR)/osa_stream_eea.o +endif + OPT_OBJS = $(OPT_DIR)/probe.o OMG_OBJS = $(OMG_DIR)/omg.o @@ -69,6 +76,22 @@ SCTP_OBJS = $(SCTP_DIR)/sctp_primitives_client.o else SCTP_OBJS = endif -UTIL_OBJ = $(FIFO_OBJ) $(LIST_OBJ) $(TIMER_OBJ) $(MEM_OBJ) $(LOG_OBJS) $(OCG_OBJS) $(MATH_OBJS) $(OTG_OBJS) $(CLI_OBJ) $(OMG_OBJS) $(OPT_OBJS) $(SCTP_OBJS) +UTIL_OBJ = $(OSA_OBJS) $(FIFO_OBJ) $(LIST_OBJ) $(TIMER_OBJ) $(MEM_OBJ) $(LOG_OBJS) $(OCG_OBJS) $(MATH_OBJS) $(OTG_OBJS) $(CLI_OBJ) $(OMG_OBJS) $(OPT_OBJS) $(SCTP_OBJS) -UTIL_incl = -I$(LFDS_DIR)/inc -I$(MEM_DIR) -I$(LIST_DIR) -I$(FIFO_DIR) -I$(OCG_DIR) -I$(LOG_DIR) -I$(MATH_DIR) -I$(TIMER_DIR) -I$(OMG_DIR) -I$(OTG_DIR) -I$(CLI_DIR) -I$(OPT_DIR) -I$(OMV_DIR) -I$(SCTP_DIR) +UTIL_incl = \ + -I$(OPENAIR2_TOP)/UTIL \ + -I$(OSA_DIR) \ + -I$(LFDS_DIR)/inc \ + -I$(MEM_DIR) \ + -I$(LIST_DIR) \ + -I$(FIFO_DIR) \ + -I$(OCG_DIR) \ + -I$(LOG_DIR) \ + -I$(MATH_DIR) \ + -I$(TIMER_DIR) \ + -I$(OMG_DIR) \ + -I$(OTG_DIR) \ + -I$(CLI_DIR) \ + -I$(OPT_DIR) \ + -I$(OMV_DIR) \ + -I$(SCTP_DIR) diff --git a/openair2/UTIL/OSA/README b/openair2/UTIL/OSA/README new file mode 100644 index 0000000000000000000000000000000000000000..1e54944308426b9000a73d8d3393f48877b859e2 --- /dev/null +++ b/openair2/UTIL/OSA/README @@ -0,0 +1,19 @@ +OAISIM Security Algorithms v0.1 + +Dependencies: +- nettle >= 2.5 +- openssl >= 1.0.1 + +Compilation: + +When compiling oaisim, add SECU=1 to enable security features. The makefile will +check for required dependencies and disable this feature if not all dependencies +are met. + +OSA is based on 3GPP TS 33.401. +Note that only EEA2 and EIA2 algorithms are supported, SNOW-3G is not implemented. + +Currently the kenb used to derive kRRCint, kRRCenc and kUPenc is composed of the +UE_id. In the future this parameter can be either obtained by deriving KASME received +from core epc (in the S1AP initial context setup request) +or configurable via command line or XML file. diff --git a/openair2/UTIL/OSA/osa_defs.h b/openair2/UTIL/OSA/osa_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..682e29363c3d47fe99b5f49a75c94d2953e9130b --- /dev/null +++ b/openair2/UTIL/OSA/osa_defs.h @@ -0,0 +1,129 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! + * \file secu_defs.h + * \brief Openair security algorithms functions implementing 3GPP TS 33.401 + * \note HMAC computations are done by nettle/openssl library + * \author Sebastien ROUX + * \date 2013 + * \version 0.1 + * @ingroup security +*/ + +#ifndef SECU_DEFS_H_ +#define SECU_DEFS_H_ + +#define EIA0_ALG_ID 0x00 +#define EIA1_128_ALG_ID 0x01 +#define EIA2_128_ALG_ID 0x02 + +#define EEA0_ALG_ID EIA0_ALG_ID +#define EEA1_128_ALG_ID EIA1_128_ALG_ID +#define EEA2_128_ALG_ID EIA2_128_ALG_ID + +#define SECU_DIRECTION_UPLINK 0 +#define SECU_DIRECTION_DOWNLINK 1 + +typedef enum { + NAS_ENC_ALG = 0x01, + NAS_INT_ALG = 0x02, + RRC_ENC_ALG = 0x03, + RRC_INT_ALG = 0x04, + UP_ENC_ALG = 0x05 +} algorithm_type_dist_t; + +int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB); + +int derive_key(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_alg_id, + const uint8_t key[32], uint8_t **out); + +#define derive_key_nas_enc(aLGiD, kEY, kNAS) \ + derive_key(NAS_ENC_ALG, aLGiD, kEY, kNAS) + +#define derive_key_nas_int(aLGiD, kEY, kNAS) \ + derive_key(NAS_INT_ALG, aLGiD, kEY, kNAS) + +#define derive_key_rrc_enc(aLGiD, kEY, kNAS) \ + derive_key(RRC_ENC_ALG, aLGiD, kEY, kNAS) + +#define derive_key_rrc_int(aLGiD, kEY, kNAS) \ + derive_key(RRC_INT_ALG, aLGiD, kEY, kNAS) + +#define derive_key_up_enc(aLGiD, kEY, kNAS) \ + derive_key(UP_ENC_ALG, aLGiD, kEY, kNAS) + +#define derive_key_up_int(aLGiD, kEY, kNAS) \ + derive_key(UP_INT_ALG, aLGiD, kEY, kNAS) + +typedef struct { + uint8_t *key; + uint32_t key_length; + uint32_t count; + uint8_t bearer; + uint8_t direction; + uint8_t *message; + /* length in bits */ + uint32_t blength; +} stream_cipher_t; + +/*! + * @brief Encrypt/Decrypt a block of data based on the provided algorithm + * @param[in] algorithm Algorithm used to encrypt the data + * Possible values are: + * - EIA0_ALG_ID for NULL encryption + * - EIA1_128_ALG_ID for SNOW-3G encryption (not avalaible right now) + * - EIA2_128_ALG_ID for 128 bits AES LTE encryption + * @param[in] stream_cipher All parameters used to compute the encrypted block of data + * @param[out] out The encrypted block of data dynamically allocated + * @return 0 if everything OK, -1 if something failed + */ +int stream_encrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out); +#define stream_decrypt stream_encrypt + +int stream_compute_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t out[4]); + +/*! + * @brief Decrypt a block of data based on the provided algorithm + * @param[in] algorithm Algorithm used to encrypt the data + * Possible values are: + * - EIA0_ALG_ID for NULL encryption + * - EIA1_128_ALG_ID for SNOW-3G encryption (not avalaible right now) + * - EIA2_128_ALG_ID for 128 bits AES LTE encryption + * @param[in] stream_cipher All parameters used to compute the decrypted block of data + * @param[out] out The decrypted block of data dynamically allocated + * @return 0 if everything OK, -1 if something failed + */ +int stream_decrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out); + +int stream_check_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t *expected); +#undef SECU_DEBUG + +#endif /* SECU_DEFS_H_ */ diff --git a/openair2/UTIL/OSA/osa_internal.h b/openair2/UTIL/OSA/osa_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..318549b2f75b9c7c95e7f49c30c13f78eb1ef1ff --- /dev/null +++ b/openair2/UTIL/OSA/osa_internal.h @@ -0,0 +1,26 @@ +#ifndef OSA_INTERNAL_H_ +#define OSA_INTERNAL_H_ + +#define FC_KENB (0x11) +#define FC_NH (0x12) +#define FC_KENB_STAR (0x13) +/* 33401 #A.7 Algorithm for key derivation function. + * This FC should be used for: + * - NAS Encryption algorithm + * - NAS Integrity algorithm + * - RRC Encryption algorithm + * - RRC Integrity algorithm + * - User Plane Encryption algorithm + */ +#define FC_ALG_KEY_DER (0x15) +#define FC_KASME_TO_CK (0x16) + +#ifndef hton_int32 +# define hton_int32(x) \ +(((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | \ +((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24)) +#endif + +#define SECU_DEBUG + +#endif /* OSA_INTERNAL_H_ */ diff --git a/openair2/UTIL/OSA/osa_key_deriver.c b/openair2/UTIL/OSA/osa_key_deriver.c new file mode 100644 index 0000000000000000000000000000000000000000..625fe0e4036d7c371f064a704bf5599a4ebd902a --- /dev/null +++ b/openair2/UTIL/OSA/osa_key_deriver.c @@ -0,0 +1,113 @@ +#include <stdint.h> + +#include <nettle/hmac.h> + +#include "osa_defs.h" +#include "osa_internal.h" +#include "UTIL/LOG/log.h" + +static inline +void kdf(const uint8_t *s, const uint32_t s_length, const uint8_t *key, + const uint32_t key_length, uint8_t **out, uint32_t out_length) +{ + struct hmac_sha256_ctx ctx; + + uint8_t *buffer; + + buffer = malloc(sizeof(uint8_t) * out_length); + + hmac_sha256_set_key(&ctx, key_length, key); + hmac_sha256_update(&ctx, s_length, s); + hmac_sha256_digest(&ctx, out_length, buffer); + + *out = buffer; +} + +/*! + * @brief Derive the keys from kasme and perform truncate on the generated key to + * reduce his size to 128 bits. Definition of the derivation function can + * be found in 3GPP TS.33401 #A.7 + * @param[in] alg_type Algorithm distinguisher + * @param[in] alg_id Algorithm identifier. + * Possible values are: + * - 0 for EIA0 algorithm (Null Integrity Protection algorithm) + * - 1 for 128-EIA1 SNOW 3G + * - 2 for 128-EIA2 AES + * @param[in] key The top key used to derive other subkeys + * @param[out] out Pointer to reference where output of KDF will be stored. + * NOTE: knas is dynamically allocated by the KDF function + */ +int derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, + const uint8_t key[32], uint8_t **out) +{ + uint8_t string[7]; +#if defined(SECU_DEBUG) + int i; +#endif + + /* FC */ + string[0] = FC_ALG_KEY_DER; + + /* P0 = algorithm type distinguisher */ + string[1] = (uint8_t)(alg_type & 0xFF); + + /* L0 = length(P0) = 1 */ + string[2] = 0x00; + string[3] = 0x01; + + /* P1 */ + string[4] = alg_id; + + /* L1 = length(P1) = 1 */ + string[5] = 0x00; + string[6] = 0x01; + +#if defined(SECU_DEBUG) + { + int i; + char payload[6 * sizeof(string) + 1]; + int index = 0; + + for (i = 0; i < sizeof(string); i++) + index += sprintf(&payload[index], "0x%02x ", string[i]); + LOG_D(OSA, "Key deriver input string: %s\n", payload); + } +#endif + + kdf(string, 7, key, 32, out, 32); + + return 0; +} + +int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB) +{ + uint8_t string[7]; + + /* FC */ + string[0] = FC_KENB; + /* P0 = Uplink NAS count */ + string[1] = (nas_count & 0xff000000) >> 24; + string[2] = (nas_count & 0x00ff0000) >> 16; + string[3] = (nas_count & 0x0000ff00) >> 8; + string[4] = (nas_count & 0x000000ff); + + /* Length of NAS count */ + string[5] = 0x00; + string[6] = 0x04; + +#if defined(SECU_DEBUG) + { + int i; + char payload[6 * sizeof(string) + 1]; + int index = 0; + + for (i = 0; i < sizeof(string); i++) + index += sprintf(&payload[index], "0x%02x ", string[i]); + LOG_D(OSA, "KeNB deriver input string: %s\n", payload); + } +#endif + + kdf(string, 7, kasme, 32, keNB, 32); + + return 0; +} diff --git a/openair2/UTIL/OSA/osa_stream_eea.c b/openair2/UTIL/OSA/osa_stream_eea.c new file mode 100644 index 0000000000000000000000000000000000000000..7412669bc462205b4311d6846eb385cd8c653508 --- /dev/null +++ b/openair2/UTIL/OSA/osa_stream_eea.c @@ -0,0 +1,110 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include <nettle/nettle-meta.h> +#include <nettle/aes.h> +#include <nettle/ctr.h> + +#include "UTIL/LOG/log.h" + +#include "assertions.h" +#include "osa_defs.h" +#include "osa_internal.h" + +int stream_encrypt_eea2(stream_cipher_t *stream_cipher, uint8_t **out) +{ + uint8_t m[16]; + uint32_t local_count; + + void *ctx; + uint8_t *data = NULL; + + uint32_t zero_bit = 0; + uint32_t byte_length; + + DevAssert(stream_cipher != NULL); + DevAssert(out != NULL); + + LOG_D(OSA, "Entering stream_encrypt_eea2, bits length %u, bearer %u, " + "count %u, direction %s\n", stream_cipher->blength, + stream_cipher->bearer, stream_cipher->count, stream_cipher->direction == SECU_DIRECTION_DOWNLINK ? + "Downlink" : "Uplink"); + + zero_bit = stream_cipher->blength & 0x7; + + byte_length = stream_cipher->blength >> 3; + if (zero_bit > 0) + byte_length += 1; + + ctx = malloc(nettle_aes128.context_size); + + if (*out == NULL) { + /* User provided output buffer */ + data = malloc(byte_length); + *out = data; + } else { + data = *out; + } + + local_count = hton_int32(stream_cipher->count); + + memset(m, 0, sizeof(m)); + memcpy(&m[0], &local_count, 4); + m[4] = ((stream_cipher->bearer & 0x1F) << 3) | + ((stream_cipher->direction & 0x01) << 2); + /* Other bits are 0 */ + +#if defined(SECU_DEBUG) + { + int i; + char payload[6 * byte_length + 1]; + int index = 0; + + for (i = 0; i < byte_length; i++) + index += sprintf(&payload[index], "0x%02x ", stream_cipher->message[i]); + LOG_D(OSA, "Original message: %s\n", payload); + } +#endif + + nettle_aes128.set_encrypt_key(ctx, stream_cipher->key_length, + stream_cipher->key); + + nettle_ctr_crypt(ctx, nettle_aes128.encrypt, + nettle_aes128.block_size, m, + byte_length, data, stream_cipher->message); + + if (zero_bit > 0) + data[byte_length - 1] = data[byte_length - 1] & (uint8_t)(0xFF << (8 - zero_bit)); + + free(ctx); + +#if defined(SECU_DEBUG) + { + int i; + char payload[6 * byte_length + 1]; + int index = 0; + + for (i = 0; i < byte_length; i++) + index += sprintf(&payload[index], "0x%02x ", data[i]); + LOG_D(OSA, "Encrypted message: %s\n", payload); + } +#endif + + return 0; +} + +int stream_encrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out) +{ + if (algorithm == EEA0_ALG_ID) { +// return stream_encrypt_eea0(stream_cipher, out); + } else if (algorithm == EEA1_128_ALG_ID) { + LOG_E(OSA, "SNOW-3G algorithms are currently not implemented\n"); + return -1; + } else if (algorithm == EEA2_128_ALG_ID) { + return stream_encrypt_eea2(stream_cipher, out); + } + LOG_E(OSA, "Provided algorithm is currently not supported = %u\n", algorithm); + return -1; +} diff --git a/openair2/UTIL/OSA/osa_stream_eia.c b/openair2/UTIL/OSA/osa_stream_eia.c new file mode 100644 index 0000000000000000000000000000000000000000..1a2a1cb5ec577a2679bde743722fb86657390394 --- /dev/null +++ b/openair2/UTIL/OSA/osa_stream_eia.c @@ -0,0 +1,115 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include "assertions.h" + +#include <openssl/aes.h> +#include <openssl/cmac.h> +#include <openssl/evp.h> + +#include "UTIL/LOG/log.h" + +#include "osa_defs.h" +#include "osa_internal.h" + +/*! + * @brief Create integrity cmac t for a given message. + * @param[in] stream_cipher Structure containing various variables to setup encoding + * @param[out] out For EIA2 the output string is 32 bits long + */ +int stream_compute_integrity_eia2(stream_cipher_t *stream_cipher, uint8_t out[4]) +{ + uint8_t *m; + uint32_t local_count; + size_t size = 4; + + uint8_t data[16]; + + CMAC_CTX *cmac_ctx; + + uint32_t zero_bit = 0; + uint32_t m_length; + + DevAssert(stream_cipher != NULL); + DevAssert(stream_cipher->key != NULL); + + memset(data, 0, 16); + + zero_bit = stream_cipher->blength & 0x7; + + m_length = stream_cipher->blength >> 3; + if (zero_bit > 0) + m_length += 1; + + local_count = hton_int32(stream_cipher->count); + + m = calloc(m_length + 8, sizeof(uint8_t)); + + memcpy(&m[0], &local_count, 4); + m[4] = ((stream_cipher->bearer & 0x1F) << 3) | ((stream_cipher->direction & 0x01) << 2); + + memcpy(&m[8], stream_cipher->message, m_length); + + #if defined(SECU_DEBUG) + { + int i; + char payload[6 * sizeof(m) + 1]; + int index = 0; + LOG_T(OSA, "Blength: %u, Zero bits: %u\n", + stream_cipher->blength, zero_bit); + for (i = 0; i < sizeof(m); i++) + index += sprintf(&payload[index], "0x%02x ", m[i]); + LOG_T(OSA, "Payload: %s\n", payload); + } + #endif + + cmac_ctx = CMAC_CTX_new(); + + CMAC_Init(cmac_ctx, stream_cipher->key, stream_cipher->key_length, EVP_aes_128_cbc(), NULL); + CMAC_Update(cmac_ctx, m, m_length + 8); + + CMAC_Final(cmac_ctx, data, &size); + + CMAC_CTX_free(cmac_ctx); + + memcpy(out, data, 4); + free(m); + + return 0; +} + +int stream_compute_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t out[4]) +{ + if (algorithm == EIA0_ALG_ID) { + // return stream_encrypt_eea0(stream_cipher, out); + } else if (algorithm == EIA1_128_ALG_ID) { + LOG_E(OSA, "SNOW-3G algorithms are currently not implemented\n"); + return -1; + } else if (algorithm == EIA2_128_ALG_ID) { + return stream_compute_integrity_eia2(stream_cipher, out); + } + LOG_E(OSA, "Provided algorithm is currently not supported = %u\n", algorithm); + return -1; +} + +int stream_check_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t *expected) +{ + uint8_t result[4]; + + if (stream_compute_integrity(algorithm, stream_cipher, result) != 0) { + return -1; + } + + if (memcmp(result, expected, 4) != 0) { + LOG_E(OSA, "Mismatch found in integrity for algorithm %u,\n" + "\tgot %02x.%02x.%02x.%02x, expecting %02x.%02x.%02x.%02x\n", + algorithm, result[0], result[1], result[2], result[3], expected[0], + expected[1], expected[2], expected[3]); + return -1; + } + + /* Integrity verification succeeded */ + return 0; +} diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 80532dbc61bf256171d8f93f7616c3917a3c03e3..4227e7fa93b6cf623cebf19ff0bcbe10abf38d78 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -72,7 +72,7 @@ ifeq ($(ENABLE_DB), 1) CFLAGS +=-I/usr/include/mysql -L/usr/lib/mysql -DENABLE_DB_STATS DB_LDFLAGS = -lmysqlclient endif -endif +endif ifdef PRINT_STATS CFLAGS += -DPRINT_STATS @@ -162,6 +162,25 @@ ifneq ($(USE_MME), R8) UPDATE_RELEASE_9=1 endif +ifdef SECU +NETTLE_FOUND = $(shell if pkg-config --exists nettle; then echo "1" ; else echo "0"; fi) +OPENSSL_FOUND = $(shell if pkg-config --exists openssl; then echo "1" ; else echo "0"; fi) + +ifeq ($(NETTLE_FOUND), 0) +@echo "Nettle library >= 2.5 is not installed on your system, continuing with security disabled" +SECU=0 +else +ifeq ($(OPENSSL_FOUND), 0) +@echo "openssl library is not installed on your system, continuing with security disabled" +SECU=0 +else +CFLAGS += -DENABLE_SECURITY +OSA_LDFLAGS += `pkg-config --libs nettle` +OSA_LDFLAGS += `pkg-config --libs openssl` +endif +endif +endif + include $(OPENAIR1_DIR)/PHY/Makefile.inc include $(OPENAIR1_DIR)/SCHED/Makefile.inc include $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc @@ -318,7 +337,8 @@ oaisim : $(ASN1_MSG_OBJS1) $(OBJ) oaisim.c $(LFDS_DIR)/bin/liblfds611.a endif @echo "Compiling oaisim.c ..." @$(CC) -I$(TOP_DIR) $(L2_incl) $(UTIL_incl) -I$(ASN1_MSG_INC) $(S1AP_Incl) -o oaisim $(CFLAGS) $(EXTRA_CFLAGS) $^ \ - -lm -lblas -lpthread -llapack_atlas -lforms -lxml2 -lX11 -lXpm -lrt $(LFDS_DIR)/bin/liblfds611.a $(PGM_LDFLAGS) $(DB_LDFLAGS) + -lm -lblas -lpthread -llapack_atlas -lforms -lxml2 -lX11 -lXpm -lrt \ + $(LFDS_DIR)/bin/liblfds611.a $(PGM_LDFLAGS) $(DB_LDFLAGS) $(OSA_LDFLAGS) ifeq ($(rrc_cellular_eNB),1) mv oaisim oaisim_eNB diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 2f8d9fecddb81137ef72c81a1e6e24f92197fad6..aaa1f3c6f66fb4b49cb35bdcbf7e3452cee2af08 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -939,6 +939,7 @@ int init_slot_isr(void) oai_emulation.info.slot_sfd = sfd; } + return 0; } void wait_for_slot_isr(void)