Files
openairinterface5g/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c
T
Navid Nikaein 286c092cfc * add reordering window management to PDCP
* update PDCP security and count calculation



git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5307 818b1a75-f10b-46b9-bf7c-635c3b92a50f
2014-05-06 20:05:07 +00:00

229 lines
8.1 KiB
C

/*******************************************************************************
Eurecom OpenAirInterface
Copyright(c) 1999 - 2013 Eurecom
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information
Openair Admin: openair_admin@eurecom.fr
Openair Tech : openair_tech@eurecom.fr
Forums : http://forums.eurecom.fsr/openairinterface
Address : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France
*******************************************************************************/
/*! \file pdcp_security.c
* \brief PDCP Security Methods
* \author ROUX Sebastie and Navid Nikaein
* \email openair_tech@eurecom.fr, navid.nikaein@eurecom.fr
* \date 2014
*/
#include <stdint.h>
#include "assertions.h"
#include "UTIL/LOG/log.h"
#include "UTIL/OSA/osa_defs.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "LAYER2/MAC/extern.h"
#include "pdcp.h"
#include "pdcp_primitives.h"
#if defined(ENABLE_SECURITY)
static
uint32_t pdcp_get_next_count_tx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn);
static
uint32_t pdcp_get_next_count_rx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn);
static
uint32_t pdcp_get_next_count_tx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn)
{
uint32_t count;
/* For TX COUNT = TX_HFN << length of SN | pdcp SN */
if (srb_flagP) {
/* 5 bits length SN */
count = ((pdcp_entity->tx_hfn << 5) | (pdcp_sn & 0x001F));
} else {
if (pdcp_entity->seq_num_size == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) {
count = ((pdcp_entity->tx_hfn << 7) | (pdcp_sn & 0x07F));
} else { /*Default is the 12 bits length SN */
count = ((pdcp_entity->tx_hfn << 12) | (pdcp_sn & 0x0FFF));
}
}
LOG_D(PDCP, "[OSA] TX COUNT = 0x%08x\n", count);
return count;
}
static
uint32_t pdcp_get_next_count_rx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn)
{
uint32_t count;
/* For RX COUNT = RX_HFN << length of SN | pdcp SN of received PDU */
if (srb_flagP) {
/* 5 bits length SN */
count = (((pdcp_entity->rx_hfn + pdcp_entity->rx_hfn_offset) << 5) | (pdcp_sn & 0x001F));
} else {
if (pdcp_entity->seq_num_size == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) {
/* 7 bits length SN */
count = (((pdcp_entity->rx_hfn + pdcp_entity->rx_hfn_offset) << 7) | (pdcp_sn & 0x007F));
} else { // default
/* 12 bits length SN */
count = (((pdcp_entity->rx_hfn + pdcp_entity->rx_hfn_offset) << 12) | (pdcp_sn & 0x0FFF));
}
}
// reset the hfn offset
pdcp_entity->rx_hfn_offset =0;
LOG_D(PDCP, "[OSA] RX COUNT = 0x%08x\n", count);
return count;
}
int pdcp_apply_security(pdcp_t *pdcp_entity,
srb_flag_t srb_flagP,
rb_id_t rb_id,
uint8_t pdcp_header_len,
uint16_t current_sn,
uint8_t *pdcp_pdu_buffer,
uint16_t sdu_buffer_size)
{
uint8_t *buffer_encrypted = NULL;
stream_cipher_t encrypt_params;
DevAssert(pdcp_entity != NULL);
DevAssert(pdcp_pdu_buffer != NULL);
DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_IN);
encrypt_params.direction = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK;
encrypt_params.bearer = rb_id - 1;
encrypt_params.count = pdcp_get_next_count_tx(pdcp_entity, srb_flagP, current_sn);
encrypt_params.key_length = 16;
if (srb_flagP) {
/* SRBs */
uint8_t *mac_i;
LOG_D(PDCP, "[OSA][RB %d] %s Applying control-plane security %d \n",
rb_id, (pdcp_entity->is_ue != 0) ? "UE -> eNB" : "eNB -> UE", pdcp_entity->integrityProtAlgorithm);
encrypt_params.message = pdcp_pdu_buffer;
encrypt_params.blength = (pdcp_header_len + sdu_buffer_size) << 3;
encrypt_params.key = pdcp_entity->kRRCint + 16; // + 128;
mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size];
/* Both header and data parts are integrity protected for
* control-plane PDUs */
stream_compute_integrity(pdcp_entity->integrityProtAlgorithm,
&encrypt_params,
mac_i);
encrypt_params.key = pdcp_entity->kRRCenc; // + 128 // bit key
} else {
LOG_D(PDCP, "[OSA][RB %d] %s Applying user-plane security\n",
rb_id, (pdcp_entity->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");
encrypt_params.key = pdcp_entity->kUPenc;// + 128;
}
encrypt_params.message = &pdcp_pdu_buffer[pdcp_header_len];
encrypt_params.blength = sdu_buffer_size << 3;
buffer_encrypted = &pdcp_pdu_buffer[pdcp_header_len];
/* Apply ciphering if any requested */
stream_encrypt(pdcp_entity->cipheringAlgorithm,
&encrypt_params,
&buffer_encrypted);
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_OUT);
return 0;
}
int pdcp_validate_security(pdcp_t *pdcp_entity,
srb_flag_t srb_flagP,
rb_id_t rb_id,
uint8_t pdcp_header_len,
uint16_t current_sn,
uint8_t *pdcp_pdu_buffer,
uint16_t sdu_buffer_size)
{
uint8_t *buffer_decrypted = NULL;
stream_cipher_t decrypt_params;
DevAssert(pdcp_entity != NULL);
DevAssert(pdcp_pdu_buffer != NULL);
DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_IN);
buffer_decrypted = (uint8_t*)&pdcp_pdu_buffer[pdcp_header_len];
decrypt_params.direction = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_DOWNLINK : SECU_DIRECTION_UPLINK ;
decrypt_params.bearer = rb_id - 1;
decrypt_params.count = pdcp_get_next_count_rx(pdcp_entity, srb_flagP, current_sn);
decrypt_params.message = &pdcp_pdu_buffer[pdcp_header_len];
decrypt_params.blength = (sdu_buffer_size - pdcp_header_len) << 3;
decrypt_params.key_length = 16;
if (srb_flagP) {
LOG_D(PDCP, "[OSA][RB %d] %s Validating control-plane security\n",
rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
decrypt_params.key = pdcp_entity->kRRCenc;// + 128;
} else {
LOG_D(PDCP, "[OSA][RB %d] %s Validating user-plane security\n",
rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
decrypt_params.key = pdcp_entity->kUPenc;// + 128;
}
/* Uncipher the block */
stream_decrypt(pdcp_entity->cipheringAlgorithm,
&decrypt_params,
&buffer_decrypted);
if (srb_flagP) {
/* Now check the integrity of the complete PDU */
decrypt_params.message = pdcp_pdu_buffer;
decrypt_params.blength = sdu_buffer_size << 3;
decrypt_params.key = pdcp_entity->kRRCint + 16;// 128;
if (stream_check_integrity(pdcp_entity->integrityProtAlgorithm,
&decrypt_params,
&pdcp_pdu_buffer[sdu_buffer_size]) != 0)
{
LOG_E(PDCP, "[OSA] failed to validate MAC-I of incoming PDU\n");
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
return -1;
}
}
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
return 0;
}
#endif /* ENABLE_SECURITY */