pdcp_security.c 8.47 KB
Newer Older
1 2 3 4 5
/*
 * 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
Cedric Roux's avatar
Cedric Roux committed
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 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
 */

22
/*! \file pdcp_security.c
23
 * \brief PDCP Security Methods
24 25 26
 * \author ROUX Sebastie and Navid Nikaein
 * \email openair_tech@eurecom.fr, navid.nikaein@eurecom.fr
 * \date 2014
27 28 29 30 31 32 33 34
 */
#include <stdint.h>

#include "assertions.h"

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

Cedric Roux's avatar
Cedric Roux committed
35 36
#include "UTIL/LOG/vcd_signal_dumper.h"

37 38 39
#include "LAYER2/MAC/extern.h"

#include "pdcp.h"
gauthier's avatar
gauthier committed
40
#include "msc.h"
41 42 43 44 45
#include "pdcp_primitives.h"

#if defined(ENABLE_SECURITY)

static
gauthier's avatar
gauthier committed
46
uint32_t pdcp_get_next_count_tx(pdcp_t *const pdcp_pP, const srb_flag_t srb_flagP, const uint16_t pdcp_sn);
47
static
gauthier's avatar
gauthier committed
48
uint32_t pdcp_get_next_count_rx(pdcp_t *const pdcp_pP, const srb_flag_t srb_flagP, const uint16_t pdcp_sn);
49

50
//-----------------------------------------------------------------------------
51
static
52
uint32_t pdcp_get_next_count_tx(
gauthier's avatar
gauthier committed
53
  pdcp_t * const pdcp_pP,
54 55 56
  const srb_flag_t srb_flagP,
  const uint16_t pdcp_sn
)
57
{
58
  uint32_t count;
59

60 61
  /* For TX COUNT = TX_HFN << length of SN | pdcp SN */
  if (srb_flagP) {
62
    /* 5 bits length SN */
gauthier's avatar
gauthier committed
63
    count = ((pdcp_pP->tx_hfn << 5)  | (pdcp_sn & 0x001F));
64
  } else {
gauthier's avatar
gauthier committed
65 66
    if (pdcp_pP->seq_num_size == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) {
      count = ((pdcp_pP->tx_hfn << 7) | (pdcp_sn & 0x07F));
67
    } else { /*Default is the 12 bits length SN */
gauthier's avatar
gauthier committed
68
      count = ((pdcp_pP->tx_hfn << 12) | (pdcp_sn & 0x0FFF));
69
    }
70
  }
71

72
  LOG_D(PDCP, "[OSA] TX COUNT = 0x%08x\n", count);
73

74
  return count;
75 76
}

77
//-----------------------------------------------------------------------------
78
static
79
uint32_t pdcp_get_next_count_rx(
gauthier's avatar
gauthier committed
80
  pdcp_t * const pdcp_pP,
81 82
  const srb_flag_t srb_flagP,
  const uint16_t pdcp_sn)
83
{
84
  uint32_t count;
85

86 87
  /* For RX COUNT = RX_HFN << length of SN | pdcp SN of received PDU */
  if (srb_flagP) {
88
    /* 5 bits length SN */
gauthier's avatar
gauthier committed
89
    count = (((pdcp_pP->rx_hfn + pdcp_pP->rx_hfn_offset) << 5)  | (pdcp_sn & 0x001F));
90
  } else {
gauthier's avatar
gauthier committed
91
    if (pdcp_pP->seq_num_size == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) {
92
      /* 7 bits length SN */
gauthier's avatar
gauthier committed
93
      count = (((pdcp_pP->rx_hfn + pdcp_pP->rx_hfn_offset) << 7) | (pdcp_sn & 0x007F));
94 95
    } else { // default
      /* 12 bits length SN */
gauthier's avatar
gauthier committed
96
      count = (((pdcp_pP->rx_hfn + pdcp_pP->rx_hfn_offset) << 12) | (pdcp_sn & 0x0FFF));
97
    }
98
  }
99

100
  // reset the hfn offset
gauthier's avatar
gauthier committed
101
  pdcp_pP->rx_hfn_offset =0;
102
  LOG_D(PDCP, "[OSA] RX COUNT = 0x%08x\n", count);
103

104
  return count;
105 106
}

107 108 109 110

//-----------------------------------------------------------------------------
int
pdcp_apply_security(
gauthier's avatar
gauthier committed
111 112
  const protocol_ctxt_t* const ctxt_pP,
  pdcp_t        *const pdcp_pP,
113 114 115 116 117 118 119
  const srb_flag_t     srb_flagP,
  const rb_id_t        rb_id,
  const uint8_t        pdcp_header_len,
  const uint16_t       current_sn,
  uint8_t       * const pdcp_pdu_buffer,
  const uint16_t      sdu_buffer_size
)
120
{
121 122
  uint8_t *buffer_encrypted = NULL;
  stream_cipher_t encrypt_params;
123

gauthier's avatar
gauthier committed
124
  DevAssert(pdcp_pP != NULL);
125 126
  DevAssert(pdcp_pdu_buffer != NULL);
  DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);
127

gauthier's avatar
gauthier committed
128
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_IN);
Cedric Roux's avatar
Cedric Roux committed
129

gauthier's avatar
gauthier committed
130
  encrypt_params.direction  = (pdcp_pP->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK;
131
  encrypt_params.bearer     = rb_id - 1;
gauthier's avatar
gauthier committed
132
  encrypt_params.count      = pdcp_get_next_count_tx(pdcp_pP, srb_flagP, current_sn);
133
  encrypt_params.key_length = 16;
134

135 136 137
  if (srb_flagP) {
    /* SRBs */
    uint8_t *mac_i;
138

139
    LOG_D(PDCP, "[OSA][RB %d] %s Applying control-plane security %d \n",
gauthier's avatar
gauthier committed
140
          rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE", pdcp_pP->integrityProtAlgorithm);
141

142 143
    encrypt_params.message    = pdcp_pdu_buffer;
    encrypt_params.blength    = (pdcp_header_len + sdu_buffer_size) << 3;
gauthier's avatar
gauthier committed
144
    encrypt_params.key        = pdcp_pP->kRRCint + 16; // + 128;
145

146
    mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size];
147

148 149
    /* Both header and data parts are integrity protected for
     * control-plane PDUs */
gauthier's avatar
gauthier committed
150
    stream_compute_integrity(pdcp_pP->integrityProtAlgorithm,
151 152
                             &encrypt_params,
                             mac_i);
153

gauthier's avatar
gauthier committed
154
    encrypt_params.key = pdcp_pP->kRRCenc;  // + 128  // bit key
155 156
  } else {
    LOG_D(PDCP, "[OSA][RB %d] %s Applying user-plane security\n",
gauthier's avatar
gauthier committed
157
          rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");
158

gauthier's avatar
gauthier committed
159
    encrypt_params.key = pdcp_pP->kUPenc;//  + 128;
160
  }
161

162 163
  encrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
  encrypt_params.blength    = sdu_buffer_size << 3;
164

165
  buffer_encrypted = &pdcp_pdu_buffer[pdcp_header_len];
166

167
  /* Apply ciphering if any requested */
gauthier's avatar
gauthier committed
168
  stream_encrypt(pdcp_pP->cipheringAlgorithm,
169 170
                 &encrypt_params,
                 &buffer_encrypted);
171

gauthier's avatar
gauthier committed
172
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_OUT);
Cedric Roux's avatar
Cedric Roux committed
173

174
  return 0;
175 176
}

177 178 179
//-----------------------------------------------------------------------------
int
pdcp_validate_security(
gauthier's avatar
gauthier committed
180 181
  const protocol_ctxt_t* const ctxt_pP,
  pdcp_t         * const pdcp_pP,
182 183 184 185 186 187 188
  const srb_flag_t     srb_flagP,
  const rb_id_t        rb_id,
  const uint8_t        pdcp_header_len,
  const uint16_t       current_sn,
  uint8_t       *const pdcp_pdu_buffer,
  const uint16_t       sdu_buffer_size
)
189
{
190 191
  uint8_t *buffer_decrypted = NULL;
  stream_cipher_t decrypt_params;
192

gauthier's avatar
gauthier committed
193
  DevAssert(pdcp_pP != NULL);
194

195 196
  DevAssert(pdcp_pdu_buffer != NULL);
  DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);
197

gauthier's avatar
gauthier committed
198
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_IN);
Cedric Roux's avatar
Cedric Roux committed
199

200
  buffer_decrypted = (uint8_t*)&pdcp_pdu_buffer[pdcp_header_len];
201

gauthier's avatar
gauthier committed
202
  decrypt_params.direction  = (pdcp_pP->is_ue == 1) ? SECU_DIRECTION_DOWNLINK : SECU_DIRECTION_UPLINK ;
203
  decrypt_params.bearer     = rb_id - 1;
gauthier's avatar
gauthier committed
204
  decrypt_params.count      = pdcp_get_next_count_rx(pdcp_pP, srb_flagP, current_sn);
205 206 207
  decrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
  decrypt_params.blength    = (sdu_buffer_size - pdcp_header_len) << 3;
  decrypt_params.key_length = 16;
208

209 210
  if (srb_flagP) {
    LOG_D(PDCP, "[OSA][RB %d] %s Validating control-plane security\n",
gauthier's avatar
gauthier committed
211 212
          rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
    decrypt_params.key = pdcp_pP->kRRCenc;// + 128;
213 214
  } else {
    LOG_D(PDCP, "[OSA][RB %d] %s Validating user-plane security\n",
gauthier's avatar
gauthier committed
215 216
          rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
    decrypt_params.key = pdcp_pP->kUPenc;// + 128;
217
  }
218

219
  /* Uncipher the block */
gauthier's avatar
gauthier committed
220
  stream_decrypt(pdcp_pP->cipheringAlgorithm,
221 222
                 &decrypt_params,
                 &buffer_decrypted);
223
#if !defined(USRP_REC_PLAY)
224 225 226 227
  if (srb_flagP) {
    /* Now check the integrity of the complete PDU */
    decrypt_params.message    = pdcp_pdu_buffer;
    decrypt_params.blength    = sdu_buffer_size << 3;
gauthier's avatar
gauthier committed
228
    decrypt_params.key        = pdcp_pP->kRRCint + 16;// 128;
229

gauthier's avatar
gauthier committed
230
    if (stream_check_integrity(pdcp_pP->integrityProtAlgorithm,
231 232
                               &decrypt_params,
                               &pdcp_pdu_buffer[sdu_buffer_size]) != 0) {
gauthier's avatar
gauthier committed
233 234 235 236 237
      MSC_LOG_EVENT(
    	  (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE,
    	  " Security: failed MAC-I Algo %X UE %"PRIx16" ",
    	  pdcp_pP->integrityProtAlgorithm,
    	  ctxt_pP->rnti);
238
      LOG_E(PDCP, "[OSA][RB %d] %s failed to validate MAC-I of incoming PDU\n",
gauthier's avatar
gauthier committed
239
            rb_id, (pdcp_pP->is_ue != 0) ? "UE" : "eNB");
gauthier's avatar
gauthier committed
240
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
241
      return -1;
242
    }
243
  }
244
#endif
gauthier's avatar
gauthier committed
245
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
246 247

  return 0;
248 249 250
}

#endif /* ENABLE_SECURITY */