Commit 18cb68ec authored by Cedric Roux's avatar Cedric Roux

nr pdcp: first draft of NIA2 integrity

This code has not been tested with a COTS UE. We need SRB1/2 (so we need SA)
to test.

The activation of security and integrity for SRB1 will need more code
(new functions) because it happens after some time, not at creation time
of the PDCP entity and there is no way to do this with current code.
parent 14c82303
...@@ -1973,6 +1973,7 @@ set(NR_PDCP_SRC ...@@ -1973,6 +1973,7 @@ set(NR_PDCP_SRC
${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_sdu.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_sdu.c
${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c
${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c
${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c
${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c
) )
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <string.h> #include <string.h>
#include "nr_pdcp_security_nea2.h" #include "nr_pdcp_security_nea2.h"
#include "nr_pdcp_integrity_nia2.h"
#include "nr_pdcp_sdu.h" #include "nr_pdcp_sdu.h"
#include "LOG/log.h" #include "LOG/log.h"
...@@ -54,17 +55,21 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, ...@@ -54,17 +55,21 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
} }
if (entity->sn_size == 12) { if (entity->sn_size == 12) {
rcvd_sn = (((unsigned char)buffer[0] & 0xf) << 8) | rcvd_sn = ((buffer[0] & 0xf) << 8) |
(unsigned char)buffer[1]; buffer[1];
header_size = 2; header_size = 2;
} else { } else {
rcvd_sn = (((unsigned char)buffer[0] & 0x3) << 16) | rcvd_sn = ((buffer[0] & 0x3) << 16) |
((unsigned char)buffer[1] << 8) | (buffer[1] << 8) |
(unsigned char)buffer[2]; buffer[2];
header_size = 3; header_size = 3;
} }
integrity_size = 0; if (entity->has_integrity) {
integrity_size = 4;
} else {
integrity_size = 0;
}
if (size < header_size + integrity_size + 1) { if (size < header_size + integrity_size + 1) {
LOG_E(PDCP, "bad PDU received (size = %d)\n", size); LOG_E(PDCP, "bad PDU received (size = %d)\n", size);
...@@ -86,9 +91,20 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, ...@@ -86,9 +91,20 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
if (entity->has_ciphering) if (entity->has_ciphering)
entity->cipher(entity->security_context, entity->cipher(entity->security_context,
(unsigned char *)buffer+header_size, size-header_size, buffer+header_size, size-header_size,
entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1);
if (entity->has_integrity) {
unsigned char integrity[4];
entity->integrity(entity->integrity_context, integrity,
buffer, size - integrity_size,
entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1);
if (memcmp(integrity, buffer, 4) != 0) {
LOG_E(PDCP, "discard NR PDU, integrity failed\n");
return;
}
}
if (rcvd_count < entity->rx_deliv if (rcvd_count < entity->rx_deliv
|| nr_pdcp_sdu_in_list(entity->rx_list, rcvd_count)) { || nr_pdcp_sdu_in_list(entity->rx_list, rcvd_count)) {
LOG_D(PDCP, "discard NR PDU rcvd_count=%d\n", rcvd_count); LOG_D(PDCP, "discard NR PDU rcvd_count=%d\n", rcvd_count);
...@@ -139,7 +155,8 @@ static void nr_pdcp_entity_recv_sdu(nr_pdcp_entity_t *entity, ...@@ -139,7 +155,8 @@ static void nr_pdcp_entity_recv_sdu(nr_pdcp_entity_t *entity,
uint32_t count; uint32_t count;
int sn; int sn;
int header_size; int header_size;
char buf[size+3+4]; int integrity_size;
char buf[size + 3 + 4];
int dc_bit; int dc_bit;
count = entity->tx_next; count = entity->tx_next;
...@@ -163,23 +180,37 @@ static void nr_pdcp_entity_recv_sdu(nr_pdcp_entity_t *entity, ...@@ -163,23 +180,37 @@ static void nr_pdcp_entity_recv_sdu(nr_pdcp_entity_t *entity,
header_size = 3; header_size = 3;
} }
memcpy(buf+header_size, buffer, size); if (entity->has_integrity) {
integrity_size = 4;
} else {
integrity_size = 0;
}
memcpy(buf + header_size, buffer, size);
if (entity->has_integrity)
entity->integrity(entity->integrity_context,
(unsigned char *)buf + header_size + size,
(unsigned char *)buf, header_size + size,
entity->rb_id, count, entity->is_gnb ? 1 : 0);
if (entity->has_ciphering) if (entity->has_ciphering)
entity->cipher(entity->security_context, entity->cipher(entity->security_context,
(unsigned char *)buf+header_size, size, (unsigned char *)buf + header_size, size + integrity_size,
entity->rb_id, count, entity->is_gnb ? 1 : 0); entity->rb_id, count, entity->is_gnb ? 1 : 0);
entity->tx_next++; entity->tx_next++;
entity->deliver_pdu(entity->deliver_pdu_data, entity, buf, entity->deliver_pdu(entity->deliver_pdu_data, entity, buf,
size+header_size, sdu_id); header_size + size + integrity_size, sdu_id);
} }
static void nr_pdcp_entity_set_integrity_key(nr_pdcp_entity_t *entity, static void nr_pdcp_entity_set_integrity_key(nr_pdcp_entity_t *entity,
char *key) char *key)
{ {
memcpy(entity->integrity_key, key, 16); LOG_E(PDCP, "%s: %d: %s: TODO? to remove?\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
//memcpy(entity->integrity_key, key, 16);
} }
static void check_t_reordering(nr_pdcp_entity_t *entity) static void check_t_reordering(nr_pdcp_entity_t *entity)
...@@ -240,6 +271,8 @@ void nr_pdcp_entity_delete(nr_pdcp_entity_t *entity) ...@@ -240,6 +271,8 @@ void nr_pdcp_entity_delete(nr_pdcp_entity_t *entity)
} }
if (entity->free_security != NULL) if (entity->free_security != NULL)
entity->free_security(entity->security_context); entity->free_security(entity->security_context);
if (entity->free_integrity != NULL)
entity->free_integrity(entity->integrity_context);
free(entity); free(entity);
} }
...@@ -306,9 +339,18 @@ nr_pdcp_entity_t *new_nr_pdcp_entity( ...@@ -306,9 +339,18 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
} }
ret->is_gnb = is_gnb; ret->is_gnb = is_gnb;
if (integrity_key != NULL) { if (integrity_key != NULL && integrity_algorithm != 0) {
printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); if (integrity_algorithm != 2) {
exit(1); LOG_E(PDCP, "FATAL: only nia2 supported for the moment\n");
exit(1);
}
ret->has_integrity = 1;
ret->integrity_algorithm = integrity_algorithm;
memcpy(ret->integrity_key, integrity_key, 16);
ret->integrity_context = nr_pdcp_integrity_nia2_init(integrity_key);
ret->integrity = nr_pdcp_integrity_nia2_integrity;
ret->free_integrity = nr_pdcp_integrity_nia2_free_integrity;
} }
return ret; return ret;
......
...@@ -85,7 +85,12 @@ typedef struct nr_pdcp_entity_t { ...@@ -85,7 +85,12 @@ typedef struct nr_pdcp_entity_t {
unsigned char *buffer, int length, unsigned char *buffer, int length,
int bearer, int count, int direction); int bearer, int count, int direction);
void (*free_security)(void *security_context); void (*free_security)(void *security_context);
/* security algorithms need to know uplink/downlink information void *integrity_context;
void (*integrity)(void *integrity_context, unsigned char *out,
unsigned char *buffer, int length,
int bearer, int count, int direction);
void (*free_integrity)(void *integrity_context);
/* security/integrity algorithms need to know uplink/downlink information
* which is reverse for gnb and ue, so we need to know if this * which is reverse for gnb and ue, so we need to know if this
* pdcp entity is for a gnb or an ue * pdcp entity is for a gnb or an ue
*/ */
......
/*
* 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_integrity_nia2.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <openssl/cmac.h>
void *nr_pdcp_integrity_nia2_init(unsigned char *integrity_key)
{
CMAC_CTX *ctx;
ctx = CMAC_CTX_new();
if (ctx == NULL) abort();
CMAC_Init(ctx, integrity_key, 16, EVP_aes_128_cbc(), NULL);
return ctx;
}
static void compute_t(unsigned char *t, uint32_t count, int bearer,
int direction)
{
t[0] = (count >> 24) & 255;
t[1] = (count >> 16) & 255;
t[2] = (count >> 8) & 255;
t[3] = (count ) & 255;
t[4] = (bearer << 3) | (direction << 2);
memset(&t[5], 0, 8-5);
}
void nr_pdcp_integrity_nia2_integrity(void *integrity_context,
unsigned char *out,
unsigned char *buffer, int length,
int bearer, int count, int direction)
{
CMAC_CTX *ctx = integrity_context;
unsigned char t[8];
unsigned char mac[16];
size_t maclen;
compute_t(t, count, bearer, direction);
CMAC_Update(ctx, t, 8);
CMAC_Update(ctx, buffer, length);
CMAC_Final(ctx, mac, &maclen);
memcpy(out, mac, 4);
}
void nr_pdcp_integrity_nia2_free_integrity(void *integrity_context)
{
CMAC_CTX *ctx = integrity_context;
CMAC_CTX_free(ctx);
}
/*
* 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_NIA2_H_
#define _NR_PDCP_INTEGRITY_NIA2_H_
void *nr_pdcp_integrity_nia2_init(unsigned char *integrity_key);
void nr_pdcp_integrity_nia2_integrity(void *integrity_context,
unsigned char *out,
unsigned char *buffer, int length,
int bearer, int count, int direction);
void nr_pdcp_integrity_nia2_free_integrity(void *integrity_context);
#endif /* _NR_PDCP_INTEGRITY_NIA2_H_ */
...@@ -48,7 +48,8 @@ typedef enum { ...@@ -48,7 +48,8 @@ typedef enum {
NAS_INT_ALG = 0x02, NAS_INT_ALG = 0x02,
RRC_ENC_ALG = 0x03, RRC_ENC_ALG = 0x03,
RRC_INT_ALG = 0x04, RRC_INT_ALG = 0x04,
UP_ENC_ALG = 0x05 UP_ENC_ALG = 0x05,
UP_INT_ALG = 0x06
} algorithm_type_dist_t; } algorithm_type_dist_t;
//int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB); //int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB);
......
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