pdcp_security.c 8.12 KB
Newer Older
1
/*******************************************************************************
gauthier's avatar
gauthier committed
2 3
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom
4

gauthier's avatar
gauthier committed
5 6 7 8
    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
9 10


gauthier's avatar
gauthier committed
11 12 13 14
    OpenAirInterface is distributed in the hope that 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.
15

gauthier's avatar
gauthier committed
16 17 18 19
    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
   included in this distribution in the file called "COPYING". If not,
   see <http://www.gnu.org/licenses/>.
20 21

  Contact Information
gauthier's avatar
gauthier committed
22 23 24 25 26
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@eurecom.fr

  Address      : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
27

gauthier's avatar
gauthier committed
28
 *******************************************************************************/
29
/*! \file pdcp_security.c
30 31 32 33
 * \brief PDCP Security Methods 
 * \author ROUX Sebastie and Navid Nikaein
 * \email openair_tech@eurecom.fr, navid.nikaein@eurecom.fr
 * \date 2014
34 35 36 37 38 39 40 41
 */
#include <stdint.h>

#include "assertions.h"

#include "UTIL/LOG/log.h"
#include "UTIL/OSA/osa_defs.h"

Cedric Roux's avatar
Cedric Roux committed
42 43
#include "UTIL/LOG/vcd_signal_dumper.h"

44 45 46 47 48 49 50 51
#include "LAYER2/MAC/extern.h"

#include "pdcp.h"
#include "pdcp_primitives.h"

#if defined(ENABLE_SECURITY)

static
52
uint32_t pdcp_get_next_count_tx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn);
53
static
54
uint32_t pdcp_get_next_count_rx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn);
55 56

static
57
uint32_t pdcp_get_next_count_tx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn)
58
{
59 60 61 62 63 64 65 66 67 68
  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));
69
    }
70 71 72 73
  }
  LOG_D(PDCP, "[OSA] TX COUNT = 0x%08x\n", count);
  
  return count;
74 75 76
}

static
77
uint32_t pdcp_get_next_count_rx(pdcp_t *pdcp_entity, srb_flag_t srb_flagP, uint16_t pdcp_sn) 
78
{
79 80 81 82 83 84 85 86 87 88 89 90
  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));
91
    }
92 93 94 95 96 97 98
  
  }
  // reset the hfn offset
  pdcp_entity->rx_hfn_offset =0;
  LOG_D(PDCP, "[OSA] RX COUNT = 0x%08x\n", count);
  
  return count;
99 100
}

101 102 103 104 105 106 107
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)
108
{
gauthier's avatar
gauthier committed
109
    uint8_t *buffer_encrypted = NULL;
110 111 112 113 114 115
    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);

Cedric Roux's avatar
Cedric Roux committed
116 117
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_IN);

118
    encrypt_params.direction  = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK; 
xuhl's avatar
xuhl committed
119
    encrypt_params.bearer     = rb_id - 1;
120
    encrypt_params.count      = pdcp_get_next_count_tx(pdcp_entity, srb_flagP, current_sn);
121 122
    encrypt_params.key_length = 16;

123
    if (srb_flagP) {
124
        /* SRBs */
gauthier's avatar
gauthier committed
125
        uint8_t *mac_i;
126

127 128
        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);
129 130 131

        encrypt_params.message    = pdcp_pdu_buffer;
        encrypt_params.blength    = (pdcp_header_len + sdu_buffer_size) << 3;
132
        encrypt_params.key        = pdcp_entity->kRRCint + 16; // + 128;
133 134 135 136 137

        mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size];

        /* Both header and data parts are integrity protected for
         * control-plane PDUs */
138 139
        stream_compute_integrity(pdcp_entity->integrityProtAlgorithm, 
				 &encrypt_params,
140 141
                                 mac_i);

142
        encrypt_params.key = pdcp_entity->kRRCenc;  // + 128  // bit key 
143 144 145 146
    } else {
        LOG_D(PDCP, "[OSA][RB %d] %s Applying user-plane security\n",
              rb_id, (pdcp_entity->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");

147
        encrypt_params.key = pdcp_entity->kUPenc;//  + 128;
148 149 150 151 152 153 154 155
    }

    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 */
156 157
    stream_encrypt(pdcp_entity->cipheringAlgorithm, 
		   &encrypt_params,
158 159
                   &buffer_encrypted);

Cedric Roux's avatar
Cedric Roux committed
160 161
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_OUT);

162 163 164
    return 0;
}

165 166 167 168 169 170 171
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)
172
{
gauthier's avatar
gauthier committed
173
    uint8_t *buffer_decrypted = NULL;
174 175 176 177 178 179 180
    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);

Cedric Roux's avatar
Cedric Roux committed
181 182
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_IN);

gauthier's avatar
gauthier committed
183
    buffer_decrypted = (uint8_t*)&pdcp_pdu_buffer[pdcp_header_len];
184 185

    decrypt_params.direction  = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_DOWNLINK : SECU_DIRECTION_UPLINK ;
xuhl's avatar
xuhl committed
186
    decrypt_params.bearer     = rb_id - 1;
187
    decrypt_params.count      = pdcp_get_next_count_rx(pdcp_entity, srb_flagP, current_sn);
188 189 190 191
    decrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
    decrypt_params.blength    = (sdu_buffer_size - pdcp_header_len) << 3;
    decrypt_params.key_length = 16;

192
    if (srb_flagP) {
193 194
        LOG_D(PDCP, "[OSA][RB %d] %s Validating control-plane security\n",
              rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
195
        decrypt_params.key = pdcp_entity->kRRCenc;// + 128;
196 197 198
    } else {
        LOG_D(PDCP, "[OSA][RB %d] %s Validating user-plane security\n",
              rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
199
        decrypt_params.key = pdcp_entity->kUPenc;// + 128;
200 201 202
    }

    /* Uncipher the block */
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    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;
	}
221
    }
222
    
Cedric Roux's avatar
Cedric Roux committed
223
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
224
    
225 226 227 228
    return 0;
}

#endif /* ENABLE_SECURITY */