Commit 13ac4105 authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Merge remote-tracking branch 'origin/improve-nrue-security' into integration_2024_w14

parents 2ace33d2 fbe2b65e
......@@ -88,14 +88,18 @@ typedef struct NRRrcDcchDataReq_s {
uint8_t gNB_index;
} NRRrcDcchDataReq;
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_data.h"
typedef struct NRRrcDcchDataInd_s {
uint32_t frame;
uint8_t dcch_index;
uint32_t sdu_size;
uint8_t *sdu_p;
uint16_t rnti;
uint8_t module_id;
uint8_t gNB_index; // LG: needed in UE
uint16_t rnti;
uint8_t module_id;
uint8_t gNB_index; // LG: needed in UE
/* 'msg_integrity' is needed for RRC to check integrity of the PDCP SDU */
nr_pdcp_integrity_data_t msg_integrity;
} NRRrcDcchDataInd;
typedef struct RrcPcchDataReq_s {
......
......@@ -121,6 +121,16 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
rcvd_count = (rcvd_hfn << entity->sn_size) | rcvd_sn;
nr_pdcp_integrity_data_t msg_integrity = { 0 };
/* the MAC-I/header/rcvd_count is needed by some RRC procedures, store it */
if (entity->has_integrity || entity->type == NR_PDCP_SRB) {
msg_integrity.count = rcvd_count;
memcpy(msg_integrity.mac, &buffer[size-4], 4);
msg_integrity.header_size = header_size;
memcpy(msg_integrity.header, buffer, header_size);
}
if (entity->has_ciphering)
entity->cipher(entity->security_context,
buffer + header_size + sdap_header_size,
......@@ -152,7 +162,8 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
sdu = nr_pdcp_new_sdu(rcvd_count,
(char *)buffer + header_size,
size - header_size - integrity_size);
size - header_size - integrity_size,
&msg_integrity);
entity->rx_list = nr_pdcp_sdu_list_add(entity->rx_list, sdu);
entity->rx_size += size-header_size;
......@@ -168,7 +179,8 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
while (entity->rx_list != NULL && count == entity->rx_list->count) {
nr_pdcp_sdu_t *cur = entity->rx_list;
entity->deliver_sdu(entity->deliver_sdu_data, entity,
cur->buffer, cur->size);
cur->buffer, cur->size,
&cur->msg_integrity);
entity->rx_list = cur->next;
entity->rx_size -= cur->size;
entity->stats.txsdu_pkts++;
......@@ -261,13 +273,11 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity,
memset(buf + header_size + size, 0, PDCP_INTEGRITY_SIZE);
}
if (entity->has_ciphering && (entity->is_gnb || entity->security_mode_completed)) {
if (entity->has_ciphering) {
entity->cipher(entity->security_context,
(unsigned char *)buf + header_size + sdap_header_size,
size + integrity_size - sdap_header_size,
entity->rb_id, count, entity->is_gnb ? 1 : 0);
} else {
entity->security_mode_completed = true;
}
entity->tx_next++;
......@@ -279,6 +289,31 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity,
return header_size + size + integrity_size;
}
static bool nr_pdcp_entity_check_integrity(struct nr_pdcp_entity_t *entity,
const uint8_t *buffer,
int buffer_size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
if (!entity->has_integrity)
return false;
int header_size = msg_integrity->header_size;
uint8_t b[buffer_size + header_size];
for (int i = 0; i < header_size; i++)
b[i] = msg_integrity->header[i];
memcpy(b + header_size, buffer, buffer_size);
unsigned char mac[4];
entity->integrity(entity->integrity_context, mac,
b, buffer_size + header_size,
entity->rb_id, msg_integrity->count, entity->is_gnb ? 0 : 1);
return memcmp(mac, msg_integrity->mac, 4) == 0;
}
/* may be called several times, take care to clean previous settings */
static void nr_pdcp_entity_set_security(nr_pdcp_entity_t *entity,
int integrity_algorithm,
......@@ -360,7 +395,8 @@ static void check_t_reordering(nr_pdcp_entity_t *entity)
while (entity->rx_list != NULL && entity->rx_list->count < entity->rx_reord) {
nr_pdcp_sdu_t *cur = entity->rx_list;
entity->deliver_sdu(entity->deliver_sdu_data, entity,
cur->buffer, cur->size);
cur->buffer, cur->size,
&cur->msg_integrity);
entity->rx_list = cur->next;
entity->rx_size -= cur->size;
entity->stats.txsdu_pkts++;
......@@ -373,7 +409,8 @@ static void check_t_reordering(nr_pdcp_entity_t *entity)
while (entity->rx_list != NULL && count == entity->rx_list->count) {
nr_pdcp_sdu_t *cur = entity->rx_list;
entity->deliver_sdu(entity->deliver_sdu_data, entity,
cur->buffer, cur->size);
cur->buffer, cur->size,
&cur->msg_integrity);
entity->rx_list = cur->next;
entity->rx_size -= cur->size;
entity->stats.txsdu_pkts++;
......@@ -403,7 +440,8 @@ static void deliver_all_sdus(nr_pdcp_entity_t *entity)
while (entity->rx_list != NULL) {
nr_pdcp_sdu_t *cur = entity->rx_list;
entity->deliver_sdu(entity->deliver_sdu_data, entity,
cur->buffer, cur->size);
cur->buffer, cur->size,
&cur->msg_integrity);
entity->rx_list = cur->next;
entity->rx_size -= cur->size;
entity->stats.txsdu_pkts++;
......@@ -524,7 +562,8 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
bool has_sdap_rx,
bool has_sdap_tx,
void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
char *buf, int size),
char *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity),
void *deliver_sdu_data,
void (*deliver_pdu)(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id),
......@@ -547,10 +586,11 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
ret->type = type;
ret->recv_pdu = nr_pdcp_entity_recv_pdu;
ret->process_sdu = nr_pdcp_entity_process_sdu;
ret->set_security = nr_pdcp_entity_set_security;
ret->set_time = nr_pdcp_entity_set_time;
ret->recv_pdu = nr_pdcp_entity_recv_pdu;
ret->process_sdu = nr_pdcp_entity_process_sdu;
ret->set_security = nr_pdcp_entity_set_security;
ret->check_integrity = nr_pdcp_entity_check_integrity;
ret->set_time = nr_pdcp_entity_set_time;
ret->delete_entity = nr_pdcp_entity_delete;
ret->release_entity = nr_pdcp_entity_release;
......
......@@ -104,11 +104,17 @@ typedef struct nr_pdcp_entity_t {
int ciphering_algorithm,
char *ciphering_key);
/* check_integrity is used by RRC */
bool (*check_integrity)(struct nr_pdcp_entity_t *entity,
const uint8_t *buffer, int buffer_length,
const nr_pdcp_integrity_data_t *msg_integrity);
void (*set_time)(struct nr_pdcp_entity_t *entity, uint64_t now);
/* callbacks provided to the PDCP module */
void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
char *buf, int size);
char *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity);
void *deliver_sdu_data;
void (*deliver_pdu)(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id);
......@@ -167,19 +173,6 @@ typedef struct nr_pdcp_entity_t {
int rx_maxsize;
nr_pdcp_statistics_t stats;
// WARNING: This is a hack!
// 3GPP TS 38.331 (RRC) version 15.3
// Section 5.3.4.3 Reception of the SecurityModeCommand by the UE
// The UE needs to send the Security Mode Complete message. However, the message
// needs to be sent without being ciphered.
// However:
// 1- The Security Mode Command arrives to the UE with the cipher algo (e.g., nea2).
// 2- The UE is configured with the cipher algo.
// 3- The Security Mode Complete message is sent to the itti task queue.
// 4- The ITTI task, forwards the message ciphering (e.g., nea2) it.
// 5- The gNB cannot understand the ciphered Security Mode Complete message.
bool security_mode_completed;
/* Keep tracks of whether the PDCP entity was suspended or not */
bool entity_suspended;
} nr_pdcp_entity_t;
......@@ -192,7 +185,8 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
bool has_sdap_rx,
bool has_sdap_tx,
void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
char *buf, int size),
char *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity),
void *deliver_sdu_data,
void (*deliver_pdu)(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id),
......
/*
* 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_INTEGRITY_DATA_H_
#define _NR_PDCP_INTEGRITY_DATA_H_
#include <stdint.h>
typedef struct {
uint32_t count;
uint8_t mac[4];
uint8_t header_size;
uint8_t header[3];
} nr_pdcp_integrity_data_t;
#endif /* _NR_PDCP_INTEGRITY_DATA_H_ */
......@@ -658,7 +658,8 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id)
}
static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
char *buf, int size)
char *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
nr_pdcp_ue_t *ue = _ue;
int rb_id;
......@@ -741,7 +742,8 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id
}
static void deliver_sdu_srb(void *_ue, nr_pdcp_entity_t *entity,
char *buf, int size)
char *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
nr_pdcp_ue_t *ue = _ue;
int srb_id;
......@@ -782,6 +784,7 @@ srb_found:
NR_RRC_DCCH_DATA_IND(message_p).dcch_index = srb_id;
NR_RRC_DCCH_DATA_IND(message_p).sdu_p = rrc_buffer_p;
NR_RRC_DCCH_DATA_IND(message_p).sdu_size = size;
memcpy(&NR_RRC_DCCH_DATA_IND(message_p).msg_integrity, msg_integrity, sizeof(*msg_integrity));
ue_id_t ue_id = ue->ue_id;
itti_send_msg_to_task(TASK_RRC_NRUE, ue_id, message_p);
}
......@@ -1047,8 +1050,8 @@ void nr_pdcp_config_set_security(ue_id_t ue_id,
rb = nr_pdcp_get_rb(ue, rb_id, true);
if (rb == NULL) {
LOG_E(PDCP, "no SRB found (ue_id %ld, rb_id %ld)\n", ue_id, rb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "no SRB found (ue_id %ld, rb_id %ld)\n", ue_id, rb_id);
return;
}
......@@ -1056,11 +1059,38 @@ void nr_pdcp_config_set_security(ue_id_t ue_id,
ciphering_algorithm = security_modeP & 0x0f;
rb->set_security(rb, integrity_algorithm, (char *)kRRCint_pP,
ciphering_algorithm, (char *)kRRCenc_pP);
rb->security_mode_completed = false;
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
}
bool nr_pdcp_check_integrity_srb(ue_id_t ue_id,
int srb_id,
const uint8_t *msg,
int msg_size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
nr_pdcp_ue_t *ue;
nr_pdcp_entity_t *rb;
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
rb = nr_pdcp_get_rb(ue, srb_id, true);
if (rb == NULL) {
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "no SRB found (ue_id %ld, rb_id %d)\n", ue_id, srb_id);
return false;
}
bool ret = rb->check_integrity(rb, msg, msg_size, msg_integrity);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return ret;
}
bool nr_pdcp_data_req_srb(ue_id_t ue_id,
const rb_id_t rb_id,
const mui_t muiP,
......@@ -1079,8 +1109,8 @@ bool nr_pdcp_data_req_srb(ue_id_t ue_id,
rb = nr_pdcp_get_rb(ue, rb_id, true);
if (rb == NULL) {
LOG_E(PDCP, "no SRB found (ue_id %ld, rb_id %ld)\n", ue_id, rb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "no SRB found (ue_id %ld, rb_id %ld)\n", ue_id, rb_id);
return 0;
}
......@@ -1106,8 +1136,8 @@ void nr_pdcp_suspend_srb(ue_id_t ue_id, int srb_id)
nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
nr_pdcp_entity_t *srb = nr_pdcp_get_rb(ue, srb_id, true);
if (srb == NULL) {
LOG_E(PDCP, "Trying to suspend SRB with ID %d but it is not established\n", srb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "Trying to suspend SRB with ID %d but it is not established\n", srb_id);
return;
}
srb->suspend_entity(srb);
......@@ -1121,8 +1151,8 @@ void nr_pdcp_suspend_drb(ue_id_t ue_id, int drb_id)
nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
nr_pdcp_entity_t *drb = nr_pdcp_get_rb(ue, drb_id, false);
if (drb == NULL) {
LOG_E(PDCP, "Trying to suspend DRB with ID %d but it is not established\n", drb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "Trying to suspend DRB with ID %d but it is not established\n", drb_id);
return;
}
drb->suspend_entity(drb);
......@@ -1136,8 +1166,8 @@ void nr_pdcp_reconfigure_srb(ue_id_t ue_id, int srb_id, long t_Reordering)
nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
nr_pdcp_entity_t *srb = nr_pdcp_get_rb(ue, srb_id, true);
if (srb == NULL) {
LOG_E(PDCP, "Trying to reconfigure SRB with ID %d but it is not established\n", srb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "Trying to reconfigure SRB with ID %d but it is not established\n", srb_id);
return;
}
int decoded_t_reordering = decode_t_reordering(t_Reordering);
......@@ -1154,8 +1184,8 @@ void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, NR_PDCP_Config_t *pdcp_c
nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
nr_pdcp_entity_t *drb = nr_pdcp_get_rb(ue, drb_id, false);
if (drb == NULL) {
LOG_E(PDCP, "Trying to reconfigure DRB with ID %d but it is not established\n", drb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "Trying to reconfigure DRB with ID %d but it is not established\n", drb_id);
return;
}
if (pdcp_config) {
......@@ -1268,8 +1298,8 @@ bool nr_pdcp_data_req_drb(protocol_ctxt_t *ctxt_pP,
rb = nr_pdcp_get_rb(ue, rb_id, false);
if (rb == NULL) {
LOG_E(PDCP, "[UE %lx] DRB %ld not found\n", rb_id, ue_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
LOG_E(PDCP, "[UE %lx] DRB %ld not found\n", ue_id, rb_id);
return 0;
}
......
......@@ -87,6 +87,12 @@ void nr_pdcp_config_set_security(ue_id_t ue_id,
uint8_t *const kRRCint_pP,
uint8_t *const kUPenc_pP);
bool nr_pdcp_check_integrity_srb(ue_id_t ue_id,
int srb_id,
const uint8_t *msg,
int msg_size,
const nr_pdcp_integrity_data_t *msg_integrity);
bool cu_f1u_data_req(protocol_ctxt_t *ctxt_pP,
const srb_flag_t srb_flagP,
const rb_id_t rb_id,
......
......@@ -24,7 +24,8 @@
#include <stdlib.h>
#include <string.h>
nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size)
nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
nr_pdcp_sdu_t *ret = calloc(1, sizeof(nr_pdcp_sdu_t));
if (ret == NULL)
......@@ -35,6 +36,7 @@ nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size)
exit(1);
memcpy(ret->buffer, buffer, size);
ret->size = size;
memcpy(&ret->msg_integrity, msg_integrity, sizeof(*msg_integrity));
return ret;
}
......
......@@ -24,14 +24,18 @@
#include <stdint.h>
#include "nr_pdcp_integrity_data.h"
typedef struct nr_pdcp_sdu_t {
uint32_t count;
char *buffer;
int size;
struct nr_pdcp_sdu_t *next;
uint32_t count;
char *buffer;
int size;
nr_pdcp_integrity_data_t msg_integrity;
struct nr_pdcp_sdu_t *next;
} nr_pdcp_sdu_t;
nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size);
nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size,
const nr_pdcp_integrity_data_t *msg_integrity);
nr_pdcp_sdu_t *nr_pdcp_sdu_list_add(nr_pdcp_sdu_t *l, nr_pdcp_sdu_t *sdu);
int nr_pdcp_sdu_in_list(nr_pdcp_sdu_t *l, uint32_t count);
void nr_pdcp_free_sdu(nr_pdcp_sdu_t *sdu);
......
......@@ -1004,11 +1004,19 @@ static int8_t nr_rrc_ue_decode_ccch(NR_UE_RRC_INST_t *rrc,
}
static void nr_rrc_ue_process_securityModeCommand(NR_UE_RRC_INST_t *ue_rrc,
NR_SecurityModeCommand_t *const securityModeCommand)
NR_SecurityModeCommand_t *const securityModeCommand,
int srb_id,
const uint8_t *msg,
int msg_size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
int securityMode = 0;
LOG_I(NR_RRC, "Receiving from SRB1 (DL-DCCH), Processing securityModeCommand\n");
AssertFatal(securityModeCommand->criticalExtensions.present == NR_SecurityModeCommand__criticalExtensions_PR_securityModeCommand,
"securityModeCommand->criticalExtensions.present (%d) != "
"NR_SecurityModeCommand__criticalExtensions_PR_securityModeCommand\n",
securityModeCommand->criticalExtensions.present);
NR_SecurityConfigSMC_t *securityConfigSMC =
&securityModeCommand->criticalExtensions.choice.securityModeCommand->securityConfigSMC;
......@@ -1016,53 +1024,28 @@ static void nr_rrc_ue_process_securityModeCommand(NR_UE_RRC_INST_t *ue_rrc,
case NR_CipheringAlgorithm_nea0:
case NR_CipheringAlgorithm_nea1:
case NR_CipheringAlgorithm_nea2:
LOG_I(NR_RRC, "Security algorithm is set to nea%d\n", securityMode);
securityMode = securityConfigSMC->securityAlgorithmConfig.cipheringAlgorithm;
LOG_I(NR_RRC, "Security algorithm is set to nea%ld\n",
securityConfigSMC->securityAlgorithmConfig.cipheringAlgorithm);
break;
default:
LOG_W(NR_RRC, "Security algorithm is set to none\n");
securityMode = NR_CipheringAlgorithm_spare1;
break;
AssertFatal(0, "Security algorithm not known/supported\n");
}
ue_rrc->cipheringAlgorithm = securityConfigSMC->securityAlgorithmConfig.cipheringAlgorithm;
ue_rrc->integrityProtAlgorithm = 0;
if (securityConfigSMC->securityAlgorithmConfig.integrityProtAlgorithm != NULL) {
switch (*securityConfigSMC->securityAlgorithmConfig.integrityProtAlgorithm) {
case NR_IntegrityProtAlgorithm_nia0:
case NR_IntegrityProtAlgorithm_nia1:
LOG_I(NR_RRC, "Integrity protection algorithm is set to nia1\n");
securityMode |= 1 << 5;
break;
case NR_IntegrityProtAlgorithm_nia2:
LOG_I(NR_RRC, "Integrity protection algorithm is set to nia2\n");
securityMode |= 1 << 6;
LOG_I(NR_RRC, "Integrity protection algorithm is set to nia%ld\n", *securityConfigSMC->securityAlgorithmConfig.integrityProtAlgorithm);
break;
default:
LOG_I(NR_RRC, "Integrity protection algorithm is set to none\n");
securityMode |= 0x70;
break;
AssertFatal(0, "Integrity algorithm not known/supported\n");
}
ue_rrc->integrityProtAlgorithm = *securityConfigSMC->securityAlgorithmConfig.integrityProtAlgorithm;
}
LOG_D(NR_RRC, "security mode is %x \n", securityMode);
NR_UL_DCCH_Message_t ul_dcch_msg = {0};
// memset((void *)&SecurityModeCommand,0,sizeof(SecurityModeCommand_t));
ul_dcch_msg.message.present = NR_UL_DCCH_MessageType_PR_c1;
asn1cCalloc(ul_dcch_msg.message.choice.c1, c1);
if (securityMode >= NO_SECURITY_MODE) {
LOG_I(NR_RRC, "rrc_ue_process_securityModeCommand, security mode complete case \n");
c1->present = NR_UL_DCCH_MessageType__c1_PR_securityModeComplete;
} else {
LOG_I(NR_RRC, "rrc_ue_process_securityModeCommand, security mode failure case \n");
c1->present = NR_UL_DCCH_MessageType__c1_PR_securityModeFailure;
c1->present = NR_UL_DCCH_MessageType__c1_PR_securityModeComplete;
}
uint8_t kRRCenc[NR_K_KEY_SIZE] = {0};
uint8_t kUPenc[NR_K_KEY_SIZE] = {0};
uint8_t kRRCint[NR_K_KEY_SIZE] = {0};
......@@ -1070,55 +1053,98 @@ static void nr_rrc_ue_process_securityModeCommand(NR_UE_RRC_INST_t *ue_rrc,
nr_derive_key(RRC_ENC_ALG, ue_rrc->cipheringAlgorithm, ue_rrc->kgnb, kRRCenc);
nr_derive_key(RRC_INT_ALG, ue_rrc->integrityProtAlgorithm, ue_rrc->kgnb, kRRCint);
log_dump(NR_RRC, ue_rrc->kgnb, 32, LOG_DUMP_CHAR, "driving kRRCenc, kRRCint and kUPenc from KgNB=");
log_dump(NR_RRC, ue_rrc->kgnb, 32, LOG_DUMP_CHAR, "deriving kRRCenc, kRRCint and kUPenc from KgNB=");
if (securityMode != 0xff) {
uint8_t security_mode = ue_rrc->cipheringAlgorithm | (ue_rrc->integrityProtAlgorithm << 4);
// configure lower layers to apply SRB integrity protection and ciphering
for (int i = 1; i < NR_NUM_SRB; i++) {
if (ue_rrc->Srb[i] == RB_ESTABLISHED)
nr_pdcp_config_set_security(ue_rrc->ue_id, i, security_mode, kRRCenc, kRRCint, kUPenc);
}
} else {
LOG_I(NR_RRC, "skipped pdcp_config_set_security() as securityMode == 0x%02x", securityMode);
/* for SecurityModeComplete, ciphering is not activated yet, only integrity */
uint8_t security_mode = ue_rrc->integrityProtAlgorithm << 4;
// configure lower layers to apply SRB integrity protection and ciphering
for (int i = 1; i < NR_NUM_SRB; i++) {
if (ue_rrc->Srb[i] == RB_ESTABLISHED)
nr_pdcp_config_set_security(ue_rrc->ue_id, i, security_mode, kRRCenc, kRRCint, kUPenc);
}
if (securityModeCommand->criticalExtensions.present == NR_SecurityModeCommand__criticalExtensions_PR_securityModeCommand) {
asn1cCalloc(c1->choice.securityModeComplete, modeComplete);
modeComplete->rrc_TransactionIdentifier = securityModeCommand->rrc_TransactionIdentifier;
modeComplete->criticalExtensions.present = NR_SecurityModeComplete__criticalExtensions_PR_securityModeComplete;
asn1cCalloc(modeComplete->criticalExtensions.choice.securityModeComplete, ext);
NR_UL_DCCH_Message_t ul_dcch_msg = {0};
ul_dcch_msg.message.present = NR_UL_DCCH_MessageType_PR_c1;
asn1cCalloc(ul_dcch_msg.message.choice.c1, c1);
// the SecurityModeCommand message needs to pass the integrity protection check
// for the UE to declare AS security to be activated
bool integrity_pass = nr_pdcp_check_integrity_srb(ue_rrc->ue_id, srb_id, msg, msg_size, msg_integrity);
if (!integrity_pass) {
/* - continue using the configuration used prior to the reception of the SecurityModeCommand message, i.e.
* neither apply integrity protection nor ciphering.
* - submit the SecurityModeFailure message to lower layers for transmission, upon which the procedure ends.
*/
LOG_E(NR_RRC, "integrity of SecurityModeCommand failed, reply with SecurityModeFailure\n");
c1->present = NR_UL_DCCH_MessageType__c1_PR_securityModeFailure;
asn1cCalloc(c1->choice.securityModeFailure, modeFailure);
modeFailure->rrc_TransactionIdentifier = securityModeCommand->rrc_TransactionIdentifier;
modeFailure->criticalExtensions.present = NR_SecurityModeFailure__criticalExtensions_PR_securityModeFailure;
asn1cCalloc(modeFailure->criticalExtensions.choice.securityModeFailure, ext);
ext->nonCriticalExtension = NULL;
LOG_I(NR_RRC,
"Receiving from SRB1 (DL-DCCH), encoding securityModeComplete, rrc_TransactionIdentifier: %ld\n",
securityModeCommand->rrc_TransactionIdentifier);
uint8_t buffer[200];
asn_enc_rval_t enc_rval =
uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, sizeof(buffer));
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded);
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
if (LOG_DEBUGFLAG(DEBUG_ASN1))
xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg);
}
log_dump(NR_RRC, buffer, 16, LOG_DUMP_CHAR, "securityModeComplete payload: ");
LOG_D(NR_RRC, "securityModeComplete Encoded %zd bits (%zd bytes)\n", enc_rval.encoded, (enc_rval.encoded + 7) / 8);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_UL_DCCH_Message, &ul_dcch_msg);
for (int i = 0; i < (enc_rval.encoded + 7) / 8; i++) {
LOG_T(NR_RRC, "%02x.", buffer[i]);
/* disable both ciphering and integrity */
security_mode = 0;
for (int i = 1; i < NR_NUM_SRB; i++) {
if (ue_rrc->Srb[i] == RB_ESTABLISHED)
nr_pdcp_config_set_security(ue_rrc->ue_id, i, security_mode, NULL, NULL, NULL);
}
LOG_T(NR_RRC, "\n");
// TODO the SecurityModeCommand message needs to pass the integrity protection check
// for the UE to declare AS security to be activated
ue_rrc->as_security_activated = true;
int srb_id = 1; // SecurityModeComplete in SRB1
srb_id = 1; // SecurityModeFailure in SRB1
nr_pdcp_data_req_srb(ue_rrc->ue_id, srb_id, 0, (enc_rval.encoded + 7) / 8, buffer, deliver_pdu_srb_rlc, NULL);
} else
LOG_W(NR_RRC,
"securityModeCommand->criticalExtensions.present (%d) != "
"NR_SecurityModeCommand__criticalExtensions_PR_securityModeCommand\n",
securityModeCommand->criticalExtensions.present);
return;
}
/* integrity passed, send SecurityModeComplete */
c1->present = NR_UL_DCCH_MessageType__c1_PR_securityModeComplete;
asn1cCalloc(c1->choice.securityModeComplete, modeComplete);
modeComplete->rrc_TransactionIdentifier = securityModeCommand->rrc_TransactionIdentifier;
modeComplete->criticalExtensions.present = NR_SecurityModeComplete__criticalExtensions_PR_securityModeComplete;
asn1cCalloc(modeComplete->criticalExtensions.choice.securityModeComplete, ext);
ext->nonCriticalExtension = NULL;
LOG_I(NR_RRC,
"Receiving from SRB1 (DL-DCCH), encoding securityModeComplete, rrc_TransactionIdentifier: %ld\n",
securityModeCommand->rrc_TransactionIdentifier);
uint8_t buffer[200];
asn_enc_rval_t enc_rval =
uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, sizeof(buffer));
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded);
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg);
}
log_dump(NR_RRC, buffer, 16, LOG_DUMP_CHAR, "securityModeComplete payload: ");
LOG_D(NR_RRC, "securityModeComplete Encoded %zd bits (%zd bytes)\n", enc_rval.encoded, (enc_rval.encoded + 7) / 8);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_UL_DCCH_Message, &ul_dcch_msg);
for (int i = 0; i < (enc_rval.encoded + 7) / 8; i++) {
LOG_T(NR_RRC, "%02x.", buffer[i]);
}
LOG_T(NR_RRC, "\n");
ue_rrc->as_security_activated = true;
srb_id = 1; // SecurityModeComplete in SRB1
nr_pdcp_data_req_srb(ue_rrc->ue_id, srb_id, 0, (enc_rval.encoded + 7) / 8, buffer, deliver_pdu_srb_rlc, NULL);
/* after encoding SecurityModeComplete we activate both ciphering and integrity */
security_mode = ue_rrc->cipheringAlgorithm | (ue_rrc->integrityProtAlgorithm << 4);
// configure lower layers to apply SRB integrity protection and ciphering
for (int i = 1; i < NR_NUM_SRB; i++) {
if (ue_rrc->Srb[i] == RB_ESTABLISHED)
/* pass NULL to keep current keys */
nr_pdcp_config_set_security(ue_rrc->ue_id, i, security_mode, NULL, NULL, NULL);
}
}
static void handle_meas_reporting_remove(rrcPerNB_t *rrc, int id, NR_UE_Timers_Constants_t *timers)
......@@ -1391,6 +1417,9 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc,
uint8_t kRRCenc[NR_K_KEY_SIZE] = {0};
uint8_t kRRCint[NR_K_KEY_SIZE] = {0};
uint8_t kUPenc[NR_K_KEY_SIZE] = {0};
uint8_t kUPint[NR_K_KEY_SIZE] = {0};
if (ue_rrc->as_security_activated) {
if (radioBearerConfig->securityConfig != NULL) {
// When the field is not included, continue to use the currently configured keyToUse
......@@ -1407,6 +1436,8 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc,
}
nr_derive_key(RRC_ENC_ALG, ue_rrc->cipheringAlgorithm, ue_rrc->kgnb, kRRCenc);
nr_derive_key(RRC_INT_ALG, ue_rrc->integrityProtAlgorithm, ue_rrc->kgnb, kRRCint);
nr_derive_key(UP_ENC_ALG, ue_rrc->cipheringAlgorithm, ue_rrc->kgnb, kUPenc);
nr_derive_key(UP_INT_ALG, ue_rrc->integrityProtAlgorithm, ue_rrc->kgnb, kUPint);
}
if (radioBearerConfig->srb_ToAddModList != NULL) {
......@@ -1477,8 +1508,8 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc,
radioBearerConfig->drb_ToAddModList->list.array[cnt],
ue_rrc->cipheringAlgorithm,
ue_rrc->integrityProtAlgorithm,
kRRCenc,
kRRCint);
kUPenc,
kUPint);
}
}
} // drb_ToAddModList //
......@@ -1555,8 +1586,8 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc,
const srb_id_t Srb_id,
const uint8_t *const Buffer,
size_t Buffer_size,
const uint8_t gNB_indexP)
const uint8_t gNB_indexP,
const nr_pdcp_integrity_data_t *msg_integrity)
{
NR_DL_DCCH_Message_t *dl_dcch_msg = NULL;
if (Srb_id != 1 && Srb_id != 2) {
......@@ -1639,7 +1670,8 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc,
break;
case NR_DL_DCCH_MessageType__c1_PR_securityModeCommand:
LOG_I(NR_RRC, "Received securityModeCommand (gNB %d)\n", gNB_indexP);
nr_rrc_ue_process_securityModeCommand(rrc, c1->choice.securityModeCommand);
nr_rrc_ue_process_securityModeCommand(rrc, c1->choice.securityModeCommand,
Srb_id, Buffer, Buffer_size, msg_integrity);
break;
}
} break;
......@@ -1744,7 +1776,8 @@ void *rrc_nrue(void *notUsed)
NR_RRC_DCCH_DATA_IND(msg_p).dcch_index,
NR_RRC_DCCH_DATA_IND(msg_p).sdu_p,
NR_RRC_DCCH_DATA_IND(msg_p).sdu_size,
NR_RRC_DCCH_DATA_IND(msg_p).gNB_index);
NR_RRC_DCCH_DATA_IND(msg_p).gNB_index,
&NR_RRC_DCCH_DATA_IND(msg_p).msg_integrity);
break;
case NAS_KENB_REFRESH_REQ:
......
......@@ -466,7 +466,7 @@ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT;
mm_msg->registration_request.nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI;
mm_msg->registration_request.nruesecuritycapability.length = 8;
mm_msg->registration_request.nruesecuritycapability.fg_EA = 0x80;
mm_msg->registration_request.nruesecuritycapability.fg_EA = 0xa0;
mm_msg->registration_request.nruesecuritycapability.fg_IA = 0x20;
mm_msg->registration_request.nruesecuritycapability.EEA = 0;
mm_msg->registration_request.nruesecuritycapability.EIA = 0;
......
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