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,6 +88,8 @@ 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;
......@@ -96,6 +98,8 @@ typedef struct NRRrcDcchDataInd_s {
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),
......@@ -550,6 +589,7 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
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;
......
......@@ -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;
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);
......
This diff is collapsed.
......@@ -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