Commit c4540f7b authored by Cedric Roux's avatar Cedric Roux

gnb sa: improve security

Note: some modifications have been done to the UE too, but for syntactic
reasons. The UE may fail to work, not tested.

For the UE, we have the problem of handling properly SecurityModeCommand.
We don't verify its integrity. This is a bit complicated to handle properly
and may require some API changes in the PDCP layer. So, as of today, the
integrity of this message is not verified.

Also, NSA mode has been touched, but it should not be a problem. But not
tested, so not sure.
parent 4d9321d8
......@@ -707,83 +707,86 @@ void RCconfig_nr_macrlc() {
void config_security(gNB_RRC_INST *rrc)
{
paramdef_t logparams_defaults[] = SECURITY_GLOBALPARAMS_DESC;
int ret = config_get(logparams_defaults,
sizeof(logparams_defaults) / sizeof(paramdef_t),
paramdef_t sec_params[] = SECURITY_GLOBALPARAMS_DESC;
int ret = config_get(sec_params,
sizeof(sec_params) / sizeof(paramdef_t),
CONFIG_STRING_SECURITY);
int i;
if (ret < 0) {
LOG_W(RRC, "configuration file does not contain a \"security\" section, applying default parameters (no security)\n");
LOG_W(RRC, "configuration file does not contain a \"security\" section, applying default parameters (nia2 nea0, integrity disabled for DRBs)\n");
rrc->security.ciphering_algorithms[0] = 0; /* nea0 = no ciphering */
rrc->security.ciphering_algorithms_count = 1;
rrc->security.integrity_algorithms[0] = 0; /* nia0 = no integrity */
rrc->security.integrity_algorithms_count = 1;
rrc->security.integrity_algorithms[0] = 2; /* nia2 */
rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity, as a fallback (but nia2 should be supported by all UEs) */
rrc->security.integrity_algorithms_count = 2;
rrc->security.do_drb_ciphering = 1; /* even if nea0 let's activate so that we don't generate cipheringDisabled in pdcp_Config */
rrc->security.do_drb_integrity = 0;
return;
}
if (logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].numelt > 4) {
if (sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt > 4) {
LOG_E(RRC, "too much ciphering algorithms in section \"security\" of the configuration file, maximum is 4\n");
exit(1);
}
if (logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].numelt > 4) {
if (sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt > 4) {
LOG_E(RRC, "too much integrity algorithms in section \"security\" of the configuration file, maximum is 4\n");
exit(1);
}
/* get ciphering algorithms */
rrc->security.ciphering_algorithms_count = 0;
for (i = 0; i < logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].numelt; i++) {
if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea0")) {
for (i = 0; i < sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt; i++) {
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea0")) {
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 0;
rrc->security.ciphering_algorithms_count++;
continue;
}
if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea1")) {
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea1")) {
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 1;
rrc->security.ciphering_algorithms_count++;
continue;
}
if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea2")) {
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea2")) {
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 2;
rrc->security.ciphering_algorithms_count++;
continue;
}
if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea3")) {
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea3")) {
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 3;
rrc->security.ciphering_algorithms_count++;
continue;
}
LOG_E(RRC, "unknown ciphering algorithm \"%s\" in section \"security\" of the configuration file\n",
logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i]);
sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i]);
exit(1);
}
/* get integrity algorithms */
rrc->security.integrity_algorithms_count = 0;
for (i = 0; i < logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].numelt; i++) {
if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia0")) {
for (i = 0; i < sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt; i++) {
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia0")) {
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 0;
rrc->security.integrity_algorithms_count++;
continue;
}
if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia1")) {
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia1")) {
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 1;
rrc->security.integrity_algorithms_count++;
continue;
}
if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia2")) {
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia2")) {
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 2;
rrc->security.integrity_algorithms_count++;
continue;
}
if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia3")) {
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia3")) {
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 3;
rrc->security.integrity_algorithms_count++;
continue;
}
LOG_E(RRC, "unknown integrity algorithm \"%s\" in section \"security\" of the configuration file\n",
logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i]);
sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i]);
exit(1);
}
......@@ -794,9 +797,30 @@ void config_security(gNB_RRC_INST *rrc)
}
if (rrc->security.integrity_algorithms_count == 0) {
LOG_W(RRC, "no preferred integrity algorithm set in configuration file, applying default parameters (no security)\n");
rrc->security.integrity_algorithms[0] = 0; /* nia0 = no integrity */
rrc->security.integrity_algorithms_count = 1;
LOG_W(RRC, "no preferred integrity algorithm set in configuration file, applying default parameters (nia2)\n");
rrc->security.integrity_algorithms[0] = 2; /* nia2 */
rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity */
rrc->security.integrity_algorithms_count = 2;
}
if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "yes")) {
rrc->security.do_drb_ciphering = 1;
} else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "no")) {
rrc->security.do_drb_ciphering = 0;
} else {
LOG_E(RRC, "in configuration file, bad drb_ciphering value '%s', only 'yes' and 'no' allowed\n",
*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr);
exit(1);
}
if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "yes")) {
rrc->security.do_drb_integrity = 1;
} else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "no")) {
rrc->security.do_drb_integrity = 0;
} else {
LOG_E(RRC, "in configuration file, bad drb_integrity value '%s', only 'yes' and 'no' allowed\n",
*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr);
exit(1);
}
}
......
......@@ -467,6 +467,8 @@ typedef enum {
#define SECURITY_CONFIG_CIPHERING "ciphering_algorithms"
#define SECURITY_CONFIG_INTEGRITY "integrity_algorithms"
#define SECURITY_CONFIG_DO_DRB_CIPHERING "drb_ciphering"
#define SECURITY_CONFIG_DO_DRB_INTEGRITY "drb_integrity"
/*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* security configuration */
......@@ -475,10 +477,15 @@ typedef enum {
#define SECURITY_GLOBALPARAMS_DESC { \
{SECURITY_CONFIG_CIPHERING, "preferred ciphering algorithms\n", 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST, 0}, \
{SECURITY_CONFIG_INTEGRITY, "preferred integrity algorithms\n", 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST, 0}, \
{SECURITY_CONFIG_DO_DRB_CIPHERING, "use ciphering for DRBs", 0, strptr:NULL, defstrval:"yes", TYPE_STRING, 0}, \
{SECURITY_CONFIG_DO_DRB_INTEGRITY, "use integrity for DRBs", 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \
}
#define SECURITY_CONFIG_CIPHERING_IDX 0
#define SECURITY_CONFIG_INTEGRITY_IDX 1
#define SECURITY_CONFIG_DO_DRB_CIPHERING_IDX 2
#define SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX 3
/*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#endif
......@@ -102,6 +102,7 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1);
if (memcmp(integrity, buffer + size - integrity_size, 4) != 0) {
LOG_E(PDCP, "discard NR PDU, integrity failed\n");
return;
}
}
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "nr_pdcp_entity_srb.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void nr_pdcp_entity_srb_recv_pdu(nr_pdcp_entity_t *_entity, char *buffer, int size)
{
nr_pdcp_entity_srb_t *entity = (nr_pdcp_entity_srb_t *)_entity;
if (size < 2) abort();
entity->common.deliver_sdu(entity->common.deliver_sdu_data,
(nr_pdcp_entity_t *)entity, buffer+2, size-6);
}
void nr_pdcp_entity_srb_recv_sdu(nr_pdcp_entity_t *_entity, char *buffer, int size,
int sdu_id)
{
nr_pdcp_entity_srb_t *entity = (nr_pdcp_entity_srb_t *)_entity;
int sn;
char buf[size+6];
sn = entity->common.next_nr_pdcp_tx_sn;
entity->common.next_nr_pdcp_tx_sn++;
if (entity->common.next_nr_pdcp_tx_sn > entity->common.maximum_nr_pdcp_sn) {
entity->common.next_nr_pdcp_tx_sn = 0;
entity->common.tx_hfn++;
}
buf[0] = (sn >> 8) & 0x0f;
buf[1] = sn & 0xff;
memcpy(buf+2, buffer, size);
/* For now use padding for the MAC-I bytes (normally carrying message authentication code)
* which come after the data payload bytes (38.323, section 6.2.2.1) */
for (int i=size+2; i<size+6; i++)
buf[i] = 0x11*(i-size-1);
entity->common.deliver_pdu(entity->common.deliver_pdu_data,
(nr_pdcp_entity_t *)entity, buf, size+6, sdu_id);
}
void nr_pdcp_entity_srb_set_integrity_key(nr_pdcp_entity_t *_entity, char *key)
{
/* nothing to do */
}
void nr_pdcp_entity_srb_delete(nr_pdcp_entity_t *_entity)
{
nr_pdcp_entity_srb_t *entity = (nr_pdcp_entity_srb_t *)_entity;
free(entity);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _NR_PDCP_ENTITY_SRB_H_
#define _NR_PDCP_ENTITY_SRB_H_
#include "nr_pdcp_entity.h"
typedef struct {
nr_pdcp_entity_t common;
int srb_id;
} nr_pdcp_entity_srb_t;
void nr_pdcp_entity_srb_recv_pdu(nr_pdcp_entity_t *_entity, char *buffer, int size);
void nr_pdcp_entity_srb_recv_sdu(nr_pdcp_entity_t *_entity, char *buffer, int size, int sdu_id);
void nr_pdcp_entity_srb_set_integrity_key(nr_pdcp_entity_t *_entity, char *key);
void nr_pdcp_entity_srb_delete(nr_pdcp_entity_t *_entity);
#endif /* _NR_PDCP_ENTITY_SRB_H_ */
......@@ -737,7 +737,11 @@ void pdcp_run(const protocol_ctxt_t *const ctxt_pP)
}
}
static void add_srb(int is_gnb, int rnti, struct NR_SRB_ToAddMod *s)
static void add_srb(int is_gnb, int rnti, struct NR_SRB_ToAddMod *s,
int ciphering_algorithm,
int integrity_algorithm,
unsigned char *ciphering_key,
unsigned char *integrity_key)
{
nr_pdcp_entity_t *pdcp_srb;
nr_pdcp_ue_t *ue;
......@@ -758,8 +762,10 @@ static void add_srb(int is_gnb, int rnti, struct NR_SRB_ToAddMod *s)
0, 0, 0, 0, // sdap parameters
deliver_sdu_srb, ue, deliver_pdu_srb, ue,
12, t_Reordering, -1,
0, 0,
NULL, NULL);
ciphering_algorithm,
integrity_algorithm,
ciphering_key,
integrity_key);
nr_pdcp_ue_add_srb_pdcp_entity(ue, srb_id, pdcp_srb);
LOG_D(PDCP, "%s:%d:%s: added srb %d to ue rnti %x\n", __FILE__, __LINE__, __FUNCTION__, srb_id, rnti);
......@@ -781,12 +787,27 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s,
int sn_size_dl = decode_sn_size_dl(*s->pdcp_Config->drb->pdcp_SN_SizeDL);
int discard_timer = decode_discard_timer(*s->pdcp_Config->drb->discardTimer);
int has_integrity;
int has_ciphering;
/* if pdcp_Config->t_Reordering is not present, it means infinity (-1) */
int t_reordering = -1;
if (s->pdcp_Config->t_Reordering != NULL) {
t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering);
}
if (s->pdcp_Config->drb != NULL
&& s->pdcp_Config->drb->integrityProtection != NULL)
has_integrity = 1;
else
has_integrity = 0;
if (s->pdcp_Config->ext1 != NULL
&& s->pdcp_Config->ext1->cipheringDisabled != NULL)
has_ciphering = 0;
else
has_ciphering = 1;
if ((!s->cnAssociation) || s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_NOTHING) {
LOG_E(PDCP,"%s:%d:%s: fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n",__FILE__,__LINE__,__FUNCTION__);
exit(-1);
......@@ -828,15 +849,17 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s,
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, rnti);
if (ue->drb[drb_id-1] != NULL) {
LOG_D(PDCP, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
LOG_W(PDCP, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
__FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
} else {
pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, drb_id,pdusession_id,has_sdap,
has_sdapULheader,has_sdapDLheader,
deliver_sdu_drb, ue, deliver_pdu_drb, ue,
sn_size_dl, t_reordering, discard_timer,
ciphering_algorithm, integrity_algorithm,
ciphering_key, integrity_key);
has_ciphering ? ciphering_algorithm : 0,
has_integrity ? integrity_algorithm : 0,
has_ciphering ? ciphering_key : NULL,
has_integrity ? integrity_key : NULL);
nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb);
LOG_D(PDCP, "%s:%d:%s: added drb %d to ue rnti %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
......@@ -910,7 +933,9 @@ boolean_t nr_rrc_pdcp_config_asn1_req(
if (srb2add_list != NULL) {
for (i = 0; i < srb2add_list->list.count; i++) {
add_srb(ctxt_pP->enb_flag,rnti, srb2add_list->list.array[i]);
add_srb(ctxt_pP->enb_flag,rnti, srb2add_list->list.array[i],
security_modeP & 0x0f, (security_modeP >> 4) & 0x0f,
kRRCenc, kRRCint);
}
}
......
......@@ -471,6 +471,10 @@ typedef struct {
/* nia0 = 0, nia1 = 1, ... */
int integrity_algorithms[4];
int integrity_algorithms_count;
/* flags to enable/disable ciphering and integrity for DRBs */
int do_drb_ciphering;
int do_drb_integrity;
} nr_security_configuration_t;
//---NR---(completely change)---------------------
......
......@@ -411,7 +411,7 @@ void apply_pdcp_config(rrc_gNB_ue_context_t *const ue_context_pP,
ue_context_pP->ue_context.SRB_configList,
NULL,
NULL,
0xff,
0,
NULL,
NULL,
NULL,
......@@ -461,7 +461,7 @@ rrc_gNB_generate_RRCSetup(
ue_context_pP->ue_context.SRB_configList,
NULL,
NULL,
0xff,
0,
NULL,
NULL,
NULL,
......@@ -940,6 +940,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration(
)
//-----------------------------------------------------------------------------
{
gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
NR_DRB_ToAddMod_t *DRB_config = NULL;
NR_SRB_ToAddMod_t *SRB2_config = NULL;
NR_SDAP_Config_t *sdap_config = NULL;
......@@ -1040,6 +1041,17 @@ rrc_gNB_generate_dedicatedRRCReconfiguration(
*DRB_config->pdcp_Config->t_Reordering = NR_PDCP_Config__t_Reordering_ms750;
DRB_config->pdcp_Config->ext1 = NULL;
if (rrc->security.do_drb_integrity) {
DRB_config->pdcp_Config->drb->integrityProtection = calloc(1, sizeof(*DRB_config->pdcp_Config->drb->integrityProtection));
*DRB_config->pdcp_Config->drb->integrityProtection = NR_PDCP_Config__drb__integrityProtection_enabled;
}
if (!rrc->security.do_drb_ciphering) {
DRB_config->pdcp_Config->ext1 = calloc(1, sizeof(*DRB_config->pdcp_Config->ext1));
DRB_config->pdcp_Config->ext1->cipheringDisabled = calloc(1, sizeof(*DRB_config->pdcp_Config->ext1->cipheringDisabled));
*DRB_config->pdcp_Config->ext1->cipheringDisabled = NR_PDCP_Config__ext1__cipheringDisabled_true;
}
// Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping
for (qos_flow_index = 0; qos_flow_index < ue_context_pP->ue_context.pduSession[i].param.nb_qos; qos_flow_index++) {
switch (ue_context_pP->ue_context.pduSession[i].param.qos[qos_flow_index].fiveQI) {
......@@ -1278,6 +1290,7 @@ rrc_gNB_process_RRCReconfigurationComplete(
uint8_t *kRRCenc = NULL;
uint8_t *kRRCint = NULL;
uint8_t *kUPenc = NULL;
uint8_t *kUPint = NULL;
NR_DRB_ToAddModList_t *DRB_configList = ue_context_pP->ue_context.DRB_configList2[xid];
NR_SRB_ToAddModList_t *SRB_configList = ue_context_pP->ue_context.SRB_configList2[xid];
NR_DRB_ToReleaseList_t *DRB_Release_configList2 = ue_context_pP->ue_context.DRB_Release_configList2[xid];
......@@ -1288,19 +1301,49 @@ rrc_gNB_process_RRCReconfigurationComplete(
ue_context_pP->ue_context.ue_reestablishment_timer = 0;
#ifndef PHYSIM
uint8_t *k_kdf = NULL;
/* Derive the keys from kgnb */
if (DRB_configList != NULL) {
derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm,
k_kdf = NULL;
nr_derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm,
ue_context_pP->ue_context.kgnb,
&k_kdf);
/* kUPenc: last 128 bits of key derivation function which returns 256 bits */
kUPenc = malloc(16);
if (kUPenc == NULL) exit(1);
memcpy(kUPenc, k_kdf+16, 16);
free(k_kdf);
k_kdf = NULL;
nr_derive_key_up_int(ue_context_pP->ue_context.integrity_algorithm,
ue_context_pP->ue_context.kgnb,
&kUPenc);
&k_kdf);
/* kUPint: last 128 bits of key derivation function which returns 256 bits */
kUPint = malloc(16);
if (kUPint == NULL) exit(1);
memcpy(kUPint, k_kdf+16, 16);
free(k_kdf);
}
derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm,
k_kdf = NULL;
nr_derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm,
ue_context_pP->ue_context.kgnb,
&kRRCenc);
derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm,
&k_kdf);
/* kRRCenc: last 128 bits of key derivation function which returns 256 bits */
kRRCenc = malloc(16);
if (kRRCenc == NULL) exit(1);
memcpy(kRRCenc, k_kdf+16, 16);
free(k_kdf);
k_kdf = NULL;
nr_derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm,
ue_context_pP->ue_context.kgnb,
&kRRCint);
&k_kdf);
/* kRRCint: last 128 bits of key derivation function which returns 256 bits */
kRRCint = malloc(16);
if (kRRCint == NULL) exit(1);
memcpy(kRRCint, k_kdf+16, 16);
free(k_kdf);
#endif
/* Refresh SRBs/DRBs */
MSC_LOG_TX_MESSAGE(MSC_RRC_GNB, MSC_PDCP_ENB, NULL, 0, MSC_AS_TIME_FMT" CONFIG_REQ UE %x DRB (security unchanged)",
......@@ -1314,11 +1357,12 @@ rrc_gNB_process_RRCReconfigurationComplete(
SRB_configList, // NULL,
DRB_configList,
DRB_Release_configList2,
0, // already configured during the securitymodecommand
(ue_context_pP->ue_context.integrity_algorithm << 4)
| ue_context_pP->ue_context.ciphering_algorithm,
kRRCenc,
kRRCint,
kUPenc,
NULL,
kUPint,
NULL,
NULL,
get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL);
......@@ -1707,7 +1751,7 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete(
nr_rrc_pdcp_config_security(
ctxt_pP,
ue_context_pP,
send_security_mode_command);
send_security_mode_command ? 0 : 1);
LOG_D(NR_RRC, "set security successfully \n");
}
......@@ -2483,6 +2527,9 @@ rrc_gNB_decode_dcch(
xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)ul_dcch_msg);
}
/* configure ciphering */
nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1);
rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p);
//rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p);
break;
......
......@@ -297,7 +297,7 @@ void
nr_rrc_pdcp_config_security(
const protocol_ctxt_t *const ctxt_pP,
rrc_gNB_ue_context_t *const ue_context_pP,
const uint8_t send_security_mode_command
const uint8_t enable_ciphering
)
//------------------------------------------------------------------------------
{
......@@ -364,10 +364,11 @@ nr_rrc_pdcp_config_security(
NULL, /* pdcp_pP not used anymore in NR */
DCCH,
DCCH+2,
(send_security_mode_command == TRUE) ?
0 | (ue_context_pP->ue_context.integrity_algorithm << 4) :
(ue_context_pP->ue_context.ciphering_algorithm ) |
(ue_context_pP->ue_context.integrity_algorithm << 4),
enable_ciphering ?
ue_context_pP->ue_context.ciphering_algorithm
| (ue_context_pP->ue_context.integrity_algorithm << 4)
: 0
| (ue_context_pP->ue_context.integrity_algorithm << 4),
kRRCenc,
kRRCint,
kUPenc);
......@@ -601,21 +602,17 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(
ue_context_p,
NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_key);
uint8_t send_security_mode_command = TRUE;
/* configure only integrity, ciphering comes after receiving SecurityModeComplete */
nr_rrc_pdcp_config_security(
&ctxt,
ue_context_p,
send_security_mode_command);
0);
uint8_t send_security_mode_command = TRUE;
if (send_security_mode_command) {
rrc_gNB_generate_SecurityModeCommand (&ctxt, ue_context_p);
send_security_mode_command = FALSE;
nr_rrc_pdcp_config_security(
&ctxt,
ue_context_p,
send_security_mode_command);
} else {
/* rrc_gNB_generate_UECapabilityEnquiry */
rrc_gNB_generate_UECapabilityEnquiry(&ctxt, ue_context_p);
......@@ -687,43 +684,76 @@ rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(
itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p);
}
static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering(uint16_t algorithms) {
return NR_CipheringAlgorithm_nea0;
static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering(
const protocol_ctxt_t *const ctxt_pP,
uint16_t algorithms)
{
gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
int i;
/* preset nea0 as fallback */
int ret = 0;
if (algorithms & NGAP_ENCRYPTION_NEA3_MASK) {
return NR_CipheringAlgorithm_nea3;
/* Select ciphering algorithm based on gNB configuration file and
* UE's supported algorithms.
* We take the first from the list that is supported by the UE.
* The ordering of the list comes from the configuration file.
*/
for (i = 0; i < rrc->security.ciphering_algorithms_count; i++) {
int nea_mask[4] = {
0,
NGAP_ENCRYPTION_NEA1_MASK,
NGAP_ENCRYPTION_NEA2_MASK,
NGAP_ENCRYPTION_NEA3_MASK
};
if (rrc->security.ciphering_algorithms[i] == 0) {
/* nea0 */
break;
}
if (algorithms & NGAP_ENCRYPTION_NEA2_MASK) {
return NR_CipheringAlgorithm_nea2;
if (algorithms & nea_mask[rrc->security.ciphering_algorithms[i]]) {
ret = rrc->security.ciphering_algorithms[i];
break;
}
if (algorithms & NGAP_ENCRYPTION_NEA1_MASK) {
return NR_CipheringAlgorithm_nea1;
}
}
LOG_I(RRC, "selecting ciphering algorithm %d\n", ret);
static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity(uint16_t algorithms) {
return ret;
}
//only NIA2 supported for now
return NR_IntegrityProtAlgorithm_nia2;
static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity(
const protocol_ctxt_t *const ctxt_pP,
uint16_t algorithms)
{
gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
int i;
/* preset nia0 as fallback */
int ret = 0;
if (algorithms & NGAP_INTEGRITY_NIA3_MASK) {
return NR_IntegrityProtAlgorithm_nia3;
/* Select integrity algorithm based on gNB configuration file and
* UE's supported algorithms.
* We take the first from the list that is supported by the UE.
* The ordering of the list comes from the configuration file.
*/
for (i = 0; i < rrc->security.integrity_algorithms_count; i++) {
int nia_mask[4] = {
0,
NGAP_INTEGRITY_NIA1_MASK,
NGAP_INTEGRITY_NIA2_MASK,
NGAP_INTEGRITY_NIA3_MASK
};
if (rrc->security.integrity_algorithms[i] == 0) {
/* nia0 */
break;
}
if (algorithms & NGAP_INTEGRITY_NIA2_MASK) {
return NR_IntegrityProtAlgorithm_nia2;
if (algorithms & nia_mask[rrc->security.integrity_algorithms[i]]) {
ret = rrc->security.integrity_algorithms[i];
break;
}
if (algorithms & NGAP_INTEGRITY_NIA1_MASK) {
return NR_IntegrityProtAlgorithm_nia1;
}
return NR_IntegrityProtAlgorithm_nia0;
LOG_I(RRC, "selecting integrity algorithm %d\n", ret);
return ret;
}
int
......@@ -746,14 +776,14 @@ rrc_gNB_process_security(
ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms,
ue_context_pP->ue_context.integrity_algorithm);
/* Select relevant algorithms */
cipheringAlgorithm = rrc_gNB_select_ciphering (ue_context_pP->ue_context.security_capabilities.nRencryption_algorithms);
cipheringAlgorithm = rrc_gNB_select_ciphering(ctxt_pP, ue_context_pP->ue_context.security_capabilities.nRencryption_algorithms);
if (ue_context_pP->ue_context.ciphering_algorithm != cipheringAlgorithm) {
ue_context_pP->ue_context.ciphering_algorithm = cipheringAlgorithm;
changed = TRUE;
}
integrityProtAlgorithm = rrc_gNB_select_integrity (ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms);
integrityProtAlgorithm = rrc_gNB_select_integrity(ctxt_pP, ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms);
if (ue_context_pP->ue_context.integrity_algorithm != integrityProtAlgorithm) {
ue_context_pP->ue_context.integrity_algorithm = integrityProtAlgorithm;
......
......@@ -142,6 +142,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp;
protocol_ctxt_t ctxt={0};
unsigned char *kUPenc = NULL;
unsigned char *kUPint = NULL;
int i;
// NR RRCReconfiguration
AssertFatal(rrc->Nb_ue < MAX_NR_RRC_UE_CONTEXTS,"cannot add another UE\n");
......@@ -224,6 +225,16 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
memcpy(kUPenc, kUPenc_kdf+16, 16);
free(kUPenc_kdf);
unsigned char *kUPint_kdf;
nr_derive_key_up_int(ue_context_p->ue_context.integrity_algorithm,
ue_context_p->ue_context.kgnb,
&kUPint_kdf);
/* kUPint: last 128 bits of key derivation function which returns 256 bits */
kUPint = malloc(16);
if (kUPint == NULL) exit(1);
memcpy(kUPint, kUPint_kdf+16, 16);
free(kUPint_kdf);
e_NR_CipheringAlgorithm cipher_algo;
switch (ue_context_p->ue_context.ciphering_algorithm) {
case 0: cipher_algo = NR_CipheringAlgorithm_nea0; break;
......@@ -387,7 +398,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
NULL, /* kRRCenc - unused */
NULL, /* kRRCint - unused */
kUPenc, /* kUPenc */
NULL, /* kUPint - unused */
kUPint, /* kUPint */
NULL,
NULL,
ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList);
......
......@@ -2038,12 +2038,22 @@ nr_rrc_ue_establish_srb2(
}
}
uint8_t *k_kdf = NULL;
uint8_t *kRRCenc = NULL;
uint8_t *kRRCint = NULL;
derive_key_rrc_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm,
NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCenc);
derive_key_rrc_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm,
NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCint);
nr_derive_key_rrc_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm,
NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &k_kdf);
kRRCenc = malloc(16);
if (kRRCenc == NULL) exit(1);
memcpy(kRRCenc, k_kdf + 16, 16);
free(k_kdf);
nr_derive_key_rrc_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm,
NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &k_kdf);
kRRCint = malloc(16);
if (kRRCint == NULL) exit(1);
memcpy(kRRCint, k_kdf + 16, 16);
free(k_kdf);
// Refresh SRBs
nr_rrc_pdcp_config_asn1_req(ctxt_pP,
radioBearerConfig->srb_ToAddModList,
......@@ -2124,9 +2134,24 @@ nr_rrc_ue_establish_srb2(
}
}
uint8_t *k_kdf = NULL;
uint8_t *kUPenc = NULL;
derive_key_up_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm,
NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kUPenc);
uint8_t *kUPint = NULL;
nr_derive_key_up_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm,
NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &k_kdf);
kUPenc = malloc(16);
if (kUPenc == NULL) exit(1);
memcpy(kUPenc, k_kdf + 16, 16);
free(k_kdf);
nr_derive_key_up_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm,
NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &k_kdf);
kUPint = malloc(16);
if (kUPint == NULL) exit(1);
memcpy(kUPint, k_kdf + 16, 16);
free(k_kdf);
MSC_LOG_TX_MESSAGE(
MSC_RRC_UE,
MSC_PDCP_UE,
......@@ -2147,7 +2172,7 @@ nr_rrc_ue_establish_srb2(
NULL,
NULL,
kUPenc,
NULL,
kUPint,
NULL,
NR_UE_rrc_inst[ctxt_pP->module_id].defaultDRB,
NR_UE_rrc_inst[ctxt_pP->module_id].cell_group_config->rlc_BearerToAddModList);
......
......@@ -1127,12 +1127,11 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id,
BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAencryptionAlgorithms);
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).security_capabilities.eUTRAintegrity_algorithms =
BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAintegrityProtectionAlgorithms);
/* id-SecurityKey : Copy the security key */
} else {/* ie != NULL */
return -1;
}
/* id-MobilityRestrictionList */
/* id-SecurityKey : Copy the security key */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_SecurityKey, true);
......@@ -1144,7 +1143,7 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id,
return -1;
}
/* id-NAS-PDU */
/* id-MobilityRestrictionList */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false);
......@@ -1160,6 +1159,7 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id,
}
/* id-NAS-PDU */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_NAS_PDU, false);
......@@ -1171,7 +1171,6 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id,
memcpy(NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).nas_pdu.buffer,
ie->value.choice.NAS_PDU.buf, ie->value.choice.NAS_PDU.size);
}
}
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment