diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 7c43427999188681d3d09d45dbeb3e45a648bbbb..4dd9f859c045edbeecc5eb631588a0dc1f2ff018 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -183,6 +183,9 @@ typedef struct eNB_RRC_UE_INFO_s { /* Information from S1AP initial_context_setup_req */ uint32_t eNB_ue_s1ap_id :24; + + security_capabilities_t security_capabilities; + /* Number of e_rab to be setup in the list */ uint8_t nb_of_e_rabs; /* list of e_rab to be setup by RRC layers */ diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index b2e3c3ddb543f6837a66ffa2f358a1245bbcb543..836aaf14794308d77ee72ca1869d62e0482b34c5 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -457,6 +457,7 @@ static void rrc_lite_eNB_init_security(u8 Mod_id, u8 UE_index) for (i = 0; i < 32; i++) { sprintf(&ascii_buffer[2 * i], "%02X", eNB_rrc_inst[Mod_id].kenb[UE_index][i]); } + ascii_buffer[2 * i] = '\0'; LOG_T(RRC, "[OSA][MOD %02d][UE %02d] kenb = %s\n", Mod_id, UE_index, ascii_buffer); #endif @@ -2408,13 +2409,6 @@ char openair_rrc_lite_eNB_init (u8 Mod_id) for (j = 0; j < NUMBER_OF_UE_MAX; j++) eNB_rrc_inst[Mod_id].Info.UE[j].Status = 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 (EPC_MODE_ENABLED > 0) @@ -2427,7 +2421,16 @@ char openair_rrc_lite_eNB_init (u8 Mod_id) } # endif } + else #endif + { + /* 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); + } + } eNB_rrc_inst[Mod_id].Info.Nb_ue = 0; diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index 4181ecbfc09e9b2550485955ba23f3bc008d5d7b..81904b5be476b64d5c2ea6cdc68e6758c3f72866 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -55,6 +55,20 @@ /* Value to indicate an invalid UE initial id */ static const uint16_t UE_INITIAL_ID_INVALID = 0; +/* Masks for S1AP Encryption algorithms, EEA0 is always supported (not coded) */ +static const uint16_t S1AP_ENCRYPTION_EEA1_MASK = 0x1; +static const uint16_t S1AP_ENCRYPTION_EEA2_MASK = 0x2; + +/* Masks for S1AP Integrity algorithms, EIA0 is always supported (not coded) */ +static const uint16_t S1AP_INTEGRITY_EIA1_MASK = 0x1; +static const uint16_t S1AP_INTEGRITY_EIA2_MASK = 0x2; + +#ifdef Rel10 +# define INTEGRITY_ALGORITHM_NONE SecurityAlgorithmConfig__integrityProtAlgorithm_eia0_v920 +#else +# define INTEGRITY_ALGORITHM_NONE SecurityAlgorithmConfig__integrityProtAlgorithm_reserved +#endif + # if defined(ENABLE_ITTI) /*! \fn uint16_t get_next_ue_initial_id(uint8_t mod_id) *\brief provide an UE initial ID for S1AP initial communication. @@ -84,11 +98,12 @@ static uint8_t get_UE_index_from_initial_id(uint8_t mod_id, uint16_t ue_initial_ uint8_t ue_index; DevCheck(mod_id < NB_eNB_INST, mod_id, NB_eNB_INST, 0); - LOG_I(RRC, "get_UE_index_from_initial_id eNB %d, ue_initial_id %d\n", mod_id, ue_initial_id); + LOG_D(RRC, "[eNB %d] get_UE_index_from_initial_id: ue_initial_id %d\n", ue_initial_id); for (ue_index = 0; ue_index < NUMBER_OF_UE_MAX; ue_index++) { /* Check if this UE is in use */ - LOG_I(RRC, " UE %d: 0x%" PRIx64 " %d\n", ue_index, eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].ue_initial_id); + LOG_D(RRC, "[eNB %d][UE %d] 0x%" PRIx64 " %d\n", mod_id, ue_index, + eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].ue_initial_id); if (eNB_rrc_inst[mod_id].Info.UE_list[ue_index] != 0) { /* Check if the initial id match */ @@ -110,11 +125,12 @@ static uint8_t get_UE_index_from_eNB_ue_s1ap_id(uint8_t mod_id, uint32_t eNB_ue_ uint8_t ue_index; DevCheck(mod_id < NB_eNB_INST, mod_id, NB_eNB_INST, 0); - LOG_I(RRC, "get_UE_index_from_eNB_ue_s1ap_id eNB %d, eNB_ue_s1ap_id %d\n", mod_id, eNB_ue_s1ap_id); + LOG_D(RRC, "[eNB %d] get_UE_index_from_eNB_ue_s1ap_id: eNB_ue_s1ap_id %d\n", mod_id, eNB_ue_s1ap_id); for (ue_index = 0; ue_index < NUMBER_OF_UE_MAX; ue_index++) { /* Check if this UE is in use */ - LOG_I(RRC, " UE %d: 0x%" PRIx64 " %d\n", ue_index, eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].eNB_ue_s1ap_id); + LOG_D(RRC, "[eNB %d][UE %d] 0x%" PRIx64 " %d\n", mod_id, ue_index, + eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].eNB_ue_s1ap_id); if (eNB_rrc_inst[mod_id].Info.UE_list[ue_index] != 0) { /* Check if the initial id match */ @@ -149,6 +165,101 @@ static uint8_t get_UE_index_from_s1ap_ids(uint8_t mod_id, uint16_t ue_initial_id return ue_index; } +/*! \fn e_SecurityAlgorithmConfig__cipheringAlgorithm rrc_eNB_select_ciphering(uint16_t algorithms) + *\brief analyze available encryption algorithms bit mask and return the relevant one. + *\param algorithms The bit mask of available algorithms received from S1AP. + *\return the selected algorithm. + */ +static e_SecurityAlgorithmConfig__cipheringAlgorithm rrc_eNB_select_ciphering(uint16_t algorithms) { + if (algorithms & S1AP_ENCRYPTION_EEA2_MASK) { + return SecurityAlgorithmConfig__cipheringAlgorithm_eea2; + } + +#if defined (ENABLE_SNOW_3G) + if (algorithms & S1AP_ENCRYPTION_EEA1_MASK) { + return SecurityAlgorithmConfig__cipheringAlgorithm_eea1; + } +#endif + + return SecurityAlgorithmConfig__cipheringAlgorithm_eea0; +} + +/*! \fn e_SecurityAlgorithmConfig__integrityProtAlgorithm rrc_eNB_select_integrity(uint16_t algorithms) + *\brief analyze available integrity algorithms bit mask and return the relevant one. + *\param algorithms The bit mask of available algorithms received from S1AP. + *\return the selected algorithm. + */ +static e_SecurityAlgorithmConfig__integrityProtAlgorithm rrc_eNB_select_integrity(uint16_t algorithms) { + if (algorithms & S1AP_INTEGRITY_EIA2_MASK) { + return SecurityAlgorithmConfig__integrityProtAlgorithm_eia2; + } + +#if defined (ENABLE_SNOW_3G) + if (algorithms & S1AP_INTEGRITY_EIA1_MASK) { + return SecurityAlgorithmConfig__integrityProtAlgorithm_eia1; + } +#endif + + return INTEGRITY_ALGORITHM_NONE; +} + +/*! \fn int rrc_eNB_process_security (uint8_t mod_id, uint8_t ue_index, security_capabilities_t *security_capabilities) + *\brief save and analyze available security algorithms bit mask and select relevant ones. + *\param mod_id Instance ID of eNB. + *\param ue_index Instance ID of UE in the eNB. + *\param security_capabilities The security capabilities received from S1AP. + *\return TRUE if at least one algorithm has been changed else FALSE. + */ +static int rrc_eNB_process_security (uint8_t mod_id, uint8_t ue_index, security_capabilities_t *security_capabilities) { + int changed = FALSE; + e_SecurityAlgorithmConfig__cipheringAlgorithm cipheringAlgorithm; + e_SecurityAlgorithmConfig__integrityProtAlgorithm integrityProtAlgorithm; + + /* Save security parameters */ + eNB_rrc_inst[mod_id].Info.UE[ue_index].security_capabilities = *security_capabilities; + + /* Select relevant algorithms */ + cipheringAlgorithm = rrc_eNB_select_ciphering (eNB_rrc_inst[mod_id].Info.UE[ue_index].security_capabilities.encryption_algorithms); + if (eNB_rrc_inst[mod_id].ciphering_algorithm[ue_index] != cipheringAlgorithm) { + eNB_rrc_inst[mod_id].ciphering_algorithm[ue_index] = cipheringAlgorithm; + changed = TRUE; + } + + integrityProtAlgorithm = rrc_eNB_select_integrity (eNB_rrc_inst[mod_id].Info.UE[ue_index].security_capabilities.integrity_algorithms); + if (eNB_rrc_inst[mod_id].integrity_algorithm[ue_index] != integrityProtAlgorithm) { + eNB_rrc_inst[mod_id].integrity_algorithm[ue_index] = integrityProtAlgorithm; + changed = TRUE; + } + + LOG_I (RRC, "[eNB %d][UE %d] Selected security algorithms: %x, %x, %s", + mod_id, ue_index, cipheringAlgorithm, integrityProtAlgorithm, changed ? "changed" : "same"); + + return changed; +} + +/*! \fn void process_eNB_security_key (uint8_t mod_id, uint8_t ue_index, uint8_t *security_key) + *\brief save security key. + *\param mod_id Instance ID of eNB. + *\param ue_index Instance ID of UE in the eNB. + *\param security_key The security key received from S1AP. + */ +static void process_eNB_security_key (uint8_t mod_id, uint8_t ue_index, uint8_t *security_key) { +#if defined(ENABLE_SECURITY) + char ascii_buffer[65]; + uint8_t i; + + /* Saves the security key */ + memcpy (eNB_rrc_inst[mod_id].kenb[ue_index], security_key, SECURITY_KEY_LENGTH); + + for (i = 0; i < 32; i++) { + sprintf(&ascii_buffer[2 * i], "%02X", eNB_rrc_inst[mod_id].kenb[ue_index][i]); + } + ascii_buffer[2 * i] = '\0'; + + LOG_I (RRC, "[eNB %d][UE %d] Saved security key %s", mod_id, ue_index, ascii_buffer); +#endif +} + /*------------------------------------------------------------------------------*/ void rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(uint8_t mod_id, uint8_t ue_index) { eNB_RRC_UE_INFO *UE_info = &eNB_rrc_inst[mod_id].Info.UE[ue_index]; @@ -321,13 +432,13 @@ int rrc_eNB_process_S1AP_DOWNLINK_NAS(MessageDef *msg_p, const char *msg_name, i eNB_ue_s1ap_id = S1AP_DOWNLINK_NAS (msg_p).eNB_ue_s1ap_id; ue_index = get_UE_index_from_s1ap_ids (instance, ue_initial_id, eNB_ue_s1ap_id); - LOG_I(RRC, "Received %s: instance %d, ue_initial_id %d, eNB_ue_s1ap_id %d, ue_index %d\n", msg_name, instance, ue_initial_id, eNB_ue_s1ap_id, ue_index); + LOG_I(RRC, "[eNB %d] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, ue_index %d\n", instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, ue_index); if (ue_index == UE_INDEX_INVALID) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p; - LOG_W(RRC, "In S1AP_DOWNLINK_NAS: unknown UE from S1AP ids (%d, %d) for eNB %d\n", ue_initial_id, eNB_ue_s1ap_id, instance); + LOG_W(RRC, "[eNB %d] In S1AP_DOWNLINK_NAS: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_NAS_NON_DELIVERY_IND); S1AP_NAS_NON_DELIVERY_IND (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; @@ -364,14 +475,14 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char eNB_ue_s1ap_id = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).eNB_ue_s1ap_id; ue_index = get_UE_index_from_s1ap_ids (instance, ue_initial_id, eNB_ue_s1ap_id); - LOG_I(RRC, "Received %s: instance %d, ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d, ue_index %d\n", - msg_name, instance, ue_initial_id, eNB_ue_s1ap_id, S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nb_of_e_rabs, ue_index); + LOG_I(RRC, "[eNB %d] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d, ue_index %d\n", + instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nb_of_e_rabs, ue_index); if (ue_index == UE_INDEX_INVALID) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p; - LOG_W(RRC, "In S1AP_INITIAL_CONTEXT_SETUP_REQ: unknown UE from S1AP ids (%d, %d) for eNB %d\n", ue_initial_id, eNB_ue_s1ap_id, instance); + LOG_W(RRC, "[eNB %d] In S1AP_INITIAL_CONTEXT_SETUP_REQ: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_INITIAL_CONTEXT_SETUP_FAIL); S1AP_INITIAL_CONTEXT_SETUP_FAIL (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; @@ -399,18 +510,19 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char /* TODO parameters yet to process ... */ { S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).ue_ambr; - S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_key; } - /* Save security parameters, assuming S1AP and RRC are using the same coding for all configuration */ - eNB_rrc_inst[instance].ciphering_algorithm[ue_index] = - S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_capabilities.encryption_algorithms; - eNB_rrc_inst[instance].ciphering_algorithm[ue_index] = - S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_capabilities.integrity_algorithms; + + rrc_eNB_process_security (instance, ue_index, &S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_capabilities); + + process_eNB_security_key (instance, ue_index, S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_key); { uint8_t send_security_mode_command = TRUE; - // TODO evaluate if security mode command should be skipped + if ((eNB_rrc_inst[instance].ciphering_algorithm[ue_index] == SecurityAlgorithmConfig__cipheringAlgorithm_eea0) + && (eNB_rrc_inst[instance].integrity_algorithm[ue_index] == INTEGRITY_ALGORITHM_NONE)) { + send_security_mode_command = FALSE; + } if (send_security_mode_command) { rrc_eNB_generate_SecurityModeCommand (instance, 0 /* TODO put frame number ! */, ue_index); @@ -435,7 +547,7 @@ int rrc_eNB_process_S1AP_UE_CTXT_MODIFICATION_REQ(MessageDef *msg_p, const char /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p; - LOG_W(RRC, "In S1AP_UE_CTXT_MODIFICATION_REQ: unknown UE from eNB_ue_s1ap_id (%d) for eNB %d\n", eNB_ue_s1ap_id, instance); + LOG_W(RRC, "[eNB %d] In S1AP_UE_CTXT_MODIFICATION_REQ: unknown UE from eNB_ue_s1ap_id (%d) for eNB %d\n", instance, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_UE_CTXT_MODIFICATION_FAIL); S1AP_UE_CTXT_MODIFICATION_FAIL (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; @@ -450,24 +562,22 @@ int rrc_eNB_process_S1AP_UE_CTXT_MODIFICATION_REQ(MessageDef *msg_p, const char /* TODO parameters yet to process ... */ { - if (S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).present & S1AP_UE_CONTEXT_MODIFICATION_SECURITY_KEY) { - S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).security_key; - } - if (S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).present & S1AP_UE_CONTEXT_MODIFICATION_UE_AMBR) { S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).ue_ambr; } } if (S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).present & S1AP_UE_CONTEXT_MODIFICATION_UE_SECU_CAP) { - /* Save security parameters, assuming S1AP and RRC are using the same coding for all configuration */ - eNB_rrc_inst[instance].ciphering_algorithm[ue_index] = - S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).security_capabilities.encryption_algorithms; - eNB_rrc_inst[instance].ciphering_algorithm[ue_index] = - S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).security_capabilities.integrity_algorithms; - - /* transmit the new security parameters to UE */ - rrc_eNB_generate_SecurityModeCommand (instance, 0 /* TODO put frame number ! */, ue_index); + if (rrc_eNB_process_security (instance, ue_index, &S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).security_capabilities)) { + /* transmit the new security parameters to UE */ + rrc_eNB_generate_SecurityModeCommand (instance, 0 /* TODO put frame number ! */, ue_index); + } + } + + if (S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).present & S1AP_UE_CONTEXT_MODIFICATION_SECURITY_KEY) { + process_eNB_security_key (instance, ue_index, S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).security_key); + + /* TODO reconfigure lower layers... */ } /* Send the response */ @@ -496,8 +606,7 @@ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_REQ (MessageDef *msg_p, const char * /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p; - LOG_W(RRC, - "In S1AP_UE_CONTEXT_RELEASE_REQ: unknown UE from eNB_ue_s1ap_id (%d) for eNB %d\n", eNB_ue_s1ap_id, instance); + LOG_W(RRC, "[eNB %d] In S1AP_UE_CONTEXT_RELEASE_REQ: unknown UE from eNB_ue_s1ap_id (%d) for eNB %d\n", instance, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message(TASK_RRC_ENB, S1AP_UE_CONTEXT_RELEASE_RESP); /* TODO change message ID. */ S1AP_UE_CONTEXT_RELEASE_RESP(msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id;