Merge remote-tracking branch 'origin/improve-nrue-security' into integration_2024_w14
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
+108
-75
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user