FD.io VPP  v16.06
Vector Packet Processing
esp_decrypt.c
Go to the documentation of this file.
1 /*
2  * esp_decrypt.c : IPSec ESP decrypt node
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 
22 #include <vnet/ipsec/ipsec.h>
23 #include <vnet/ipsec/esp.h>
24 
25 #define ESP_WINDOW_SIZE 64
26 
27 #define foreach_esp_decrypt_next \
28 _(DROP, "error-drop") \
29 _(IP4_INPUT, "ip4-input") \
30 _(IP6_INPUT, "ip6-input")
31 
32 #define _(v, s) ESP_DECRYPT_NEXT_##v,
33 typedef enum {
35 #undef _
38 
39 
40 #define foreach_esp_decrypt_error \
41  _(RX_PKTS, "ESP pkts received") \
42  _(NO_BUFFER, "No buffer (packed dropped)") \
43  _(DECRYPTION_FAILED, "ESP decryption failed") \
44  _(INTEG_ERROR, "Integrity check failed") \
45  _(REPLAY, "SA replayed packet")
46 
47 
48 typedef enum {
49 #define _(sym,str) ESP_DECRYPT_ERROR_##sym,
51 #undef _
54 
55 static char * esp_decrypt_error_strings[] = {
56 #define _(sym,string) string,
58 #undef _
59 };
60 
61 typedef struct {
65 
66 /* packet trace format function */
67 static u8 * format_esp_decrypt_trace (u8 * s, va_list * args)
68 {
69  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
71  esp_decrypt_trace_t * t = va_arg (*args, esp_decrypt_trace_t *);
72 
73  s = format (s, "esp: crypto %U integrity %U",
76  return s;
77 }
78 
79 always_inline void
81  u8 * in,
82  u8 * out,
83  size_t in_len,
84  u8 * key,
85  u8 * iv)
86 {
87  esp_main_t * em = &esp_main;
88  u32 cpu_index = os_get_cpu_number();
89  EVP_CIPHER_CTX * ctx = &(em->per_thread_data[cpu_index].decrypt_ctx);
90  const EVP_CIPHER * cipher = NULL;
91  int out_len;
92 
94 
95  if (PREDICT_FALSE(em->esp_crypto_algs[alg].type == 0))
96  return;
97 
98  if (PREDICT_FALSE(alg != em->per_thread_data[cpu_index].last_decrypt_alg)) {
99  cipher = em->esp_crypto_algs[alg].type;
100  em->per_thread_data[cpu_index].last_decrypt_alg = alg;
101  }
102 
103  EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv);
104 
105  EVP_DecryptUpdate(ctx, out, &out_len, in, in_len);
106  EVP_DecryptFinal_ex(ctx, out + out_len, &out_len);
107 }
108 
109 always_inline int
111 {
112  u32 diff;
113 
114  if (PREDICT_TRUE(seq > sa->last_seq))
115  return 0;
116 
117  diff = sa->last_seq - seq;
118 
119  if (ESP_WINDOW_SIZE > diff)
120  return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
121  else
122  return 1;
123 
124  return 0;
125 }
126 
127 always_inline int
129 {
130  u32 tl = sa->last_seq;
131  u32 th = sa->last_seq_hi;
132  u32 diff = tl - seq;
133 
134  if (PREDICT_TRUE(tl >= (ESP_WINDOW_SIZE - 1)))
135  {
136  if (seq >= (tl - ESP_WINDOW_SIZE + 1))
137  {
138  sa->seq_hi = th;
139  if (seq <= tl)
140  return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
141  else
142  return 0;
143  }
144  else
145  {
146  sa->seq_hi = th + 1;
147  return 0;
148  }
149  }
150  else
151  {
152  if (seq >= (tl - ESP_WINDOW_SIZE + 1))
153  {
154  sa->seq_hi = th - 1;
155  return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
156  }
157  else
158  {
159  sa->seq_hi = th;
160  if (seq <= tl)
161  return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
162  else
163  return 0;
164  }
165  }
166 
167  return 0;
168 }
169 
170 always_inline void
172 {
173  u32 pos;
174 
175  if (seq > sa->last_seq)
176  {
177  pos = seq - sa->last_seq;
178  if (pos < ESP_WINDOW_SIZE)
179  sa->replay_window = ((sa->replay_window) << pos) | 1;
180  else
181  sa->replay_window = 1;
182  sa->last_seq = seq;
183  }
184  else
185  {
186  pos = sa->last_seq - seq;
187  sa->replay_window |= (1ULL << pos);
188  }
189 }
190 
191 always_inline void
193 {
194  int wrap = sa->seq_hi - sa->last_seq_hi;
195  u32 pos;
196 
197  if (wrap == 0 && seq > sa->last_seq)
198  {
199  pos = seq - sa->last_seq;
200  if (pos < ESP_WINDOW_SIZE)
201  sa->replay_window = ((sa->replay_window) << pos) | 1;
202  else
203  sa->replay_window = 1;
204  sa->last_seq = seq;
205  }
206  else if (wrap > 0)
207  {
208  pos = ~seq + sa->last_seq + 1;
209  if (pos < ESP_WINDOW_SIZE)
210  sa->replay_window = ((sa->replay_window) << pos) | 1;
211  else
212  sa->replay_window = 1;
213  sa->last_seq = seq;
214  sa->last_seq_hi = sa->seq_hi;
215  }
216  else if (wrap < 0)
217  {
218  pos = ~seq + sa->last_seq + 1;
219  sa->replay_window |= (1ULL << pos);
220  }
221  else
222  {
223  pos = sa->last_seq - seq;
224  sa->replay_window |= (1ULL << pos);
225  }
226 }
227 
228 static uword
230  vlib_node_runtime_t * node,
231  vlib_frame_t * from_frame)
232 {
233  u32 n_left_from, *from, next_index, *to_next;
234  ipsec_main_t *im = &ipsec_main;
235  esp_main_t *em = &esp_main;
236  u32 * recycle = 0;
237  from = vlib_frame_vector_args (from_frame);
238  n_left_from = from_frame->n_vectors;
239  u32 cpu_index = os_get_cpu_number();
240  u32 * empty_buffers = im->empty_buffers[cpu_index];
241 
243 
244  if (PREDICT_FALSE(vec_len (empty_buffers) < n_left_from)){
246  ESP_DECRYPT_ERROR_NO_BUFFER, n_left_from);
247  goto free_buffers_and_exit;
248  }
249 
250  next_index = node->cached_next_index;
251 
252  while (n_left_from > 0)
253  {
254  u32 n_left_to_next;
255 
256  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
257 
258  while (n_left_from > 0 && n_left_to_next > 0)
259  {
260  u32 i_bi0, o_bi0 = (u32) ~0, next0;
261  vlib_buffer_t * i_b0;
262  vlib_buffer_t * o_b0 = 0;
263  esp_header_t * esp0;
264  ipsec_sa_t * sa0;
265  u32 sa_index0 = ~0;
266  u32 seq;
267 
268  i_bi0 = from[0];
269  from += 1;
270  n_left_from -= 1;
271  n_left_to_next -= 1;
272 
273  next0 = ESP_DECRYPT_NEXT_DROP;
274 
275  i_b0 = vlib_get_buffer (vm, i_bi0);
276  esp0 = vlib_buffer_get_current (i_b0);
277 
278  sa_index0 = vnet_buffer(i_b0)->output_features.ipsec_sad_index;
279  sa0 = pool_elt_at_index (im->sad, sa_index0);
280 
281  seq = clib_host_to_net_u32(esp0->seq);
282 
283  /* anti-replay check */
284  if (sa0->use_anti_replay)
285  {
286  int rv = 0;
287 
288  if (PREDICT_TRUE(sa0->use_esn))
289  rv = esp_replay_check_esn(sa0, seq);
290  else
291  rv = esp_replay_check(sa0, seq);
292 
293  if (PREDICT_FALSE(rv))
294  {
295  clib_warning("anti-replay SPI %u seq %u", sa0->spi, seq);
297  ESP_DECRYPT_ERROR_REPLAY, 1);
298  o_bi0 = i_bi0;
299  goto trace;
300  }
301  }
302 
303  if (PREDICT_TRUE(sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
304  {
305  u8 sig[64];
306  int icv_size = em->esp_integ_algs[sa0->integ_alg].trunc_size;
307  memset(sig, 0, sizeof(sig));
308  u8 * icv = vlib_buffer_get_current (i_b0) + i_b0->current_length - icv_size;
309  i_b0->current_length -= icv_size;
310 
311  hmac_calc(sa0->integ_alg, sa0->integ_key, sa0->integ_key_len,
312  (u8 *) esp0, i_b0->current_length, sig, sa0->use_esn,
313  sa0->seq_hi);
314 
315  if (PREDICT_FALSE(memcmp(icv, sig, icv_size)))
316  {
318  ESP_DECRYPT_ERROR_INTEG_ERROR, 1);
319  o_bi0 = i_bi0;
320  goto trace;
321  }
322  }
323 
324  if (PREDICT_TRUE(sa0->use_anti_replay))
325  {
326  if (PREDICT_TRUE(sa0->use_esn))
327  esp_replay_advance_esn(sa0, seq);
328  else
329  esp_replay_advance(sa0, seq);
330  }
331 
332  /* grab free buffer */
333  uword last_empty_buffer = vec_len (empty_buffers) - 1;
334  o_bi0 = empty_buffers[last_empty_buffer];
335  o_b0 = vlib_get_buffer (vm, o_bi0);
336  vlib_prefetch_buffer_with_index (vm, empty_buffers[last_empty_buffer-1], STORE);
337  _vec_len (empty_buffers) = last_empty_buffer;
338 
339  /* add old buffer to the recycle list */
340  vec_add1(recycle, i_bi0);
341 
342  if (sa0->crypto_alg >= IPSEC_CRYPTO_ALG_AES_CBC_128 &&
343  sa0->crypto_alg <= IPSEC_CRYPTO_ALG_AES_CBC_256) {
344  const int BLOCK_SIZE = 16;
345  const int IV_SIZE = 16;
346  esp_footer_t * f0;
347 
348  int blocks = (i_b0->current_length - sizeof (esp_header_t) - IV_SIZE) / BLOCK_SIZE;
349 
350  o_b0->current_data = sizeof(ethernet_header_t);
351 
353  esp0->data + IV_SIZE,
354  (u8 *) vlib_buffer_get_current (o_b0),
355  BLOCK_SIZE * blocks,
356  sa0->crypto_key,
357  esp0->data);
358 
359  o_b0->current_length = (blocks * 16) - 2;
361  f0 = (esp_footer_t *) ((u8 *) vlib_buffer_get_current (o_b0) + o_b0->current_length);
362  o_b0->current_length -= f0->pad_length;
363  if (PREDICT_TRUE(f0->next_header == IP_PROTOCOL_IP_IN_IP))
364  next0 = ESP_DECRYPT_NEXT_IP4_INPUT;
365  else if (f0->next_header == IP_PROTOCOL_IPV6)
366  next0 = ESP_DECRYPT_NEXT_IP6_INPUT;
367  else
368  {
369  clib_warning("next header: 0x%x", f0->next_header);
371  ESP_DECRYPT_ERROR_DECRYPTION_FAILED,
372  1);
373  o_b0 = 0;
374  goto trace;
375  }
376 
377  to_next[0] = o_bi0;
378  to_next += 1;
379 
380  vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32)~0;
381  }
382 
383 trace:
385  if (o_b0) {
386  o_b0->flags |= VLIB_BUFFER_IS_TRACED;
387  o_b0->trace_index = i_b0->trace_index;
388  }
389  esp_decrypt_trace_t *tr = vlib_add_trace (vm, node, o_b0, sizeof (*tr));
390  tr->crypto_alg = sa0->crypto_alg;
391  tr->integ_alg = sa0->integ_alg;
392  }
393 
394  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
395  n_left_to_next, o_bi0, next0);
396  }
397  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
398  }
400  ESP_DECRYPT_ERROR_RX_PKTS,
401  from_frame->n_vectors);
402 
403 free_buffers_and_exit:
404  vlib_buffer_free (vm, recycle, vec_len(recycle));
405  vec_free(recycle);
406  return from_frame->n_vectors;
407 }
408 
409 
411  .function = esp_decrypt_node_fn,
412  .name = "esp-decrypt",
413  .vector_size = sizeof (u32),
414  .format_trace = format_esp_decrypt_trace,
416 
418  .error_strings = esp_decrypt_error_strings,
419 
420  .n_next_nodes = ESP_DECRYPT_N_NEXT,
421  .next_nodes = {
422 #define _(s,n) [ESP_DECRYPT_NEXT_##s] = n,
424 #undef _
425  },
426 };
427 
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Definition: main.c:459
always_inline void esp_replay_advance_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp_decrypt.c:192
ipsec_crypto_alg_t last_decrypt_alg
Definition: esp.h:61
#define CLIB_UNUSED(x)
Definition: clib.h:79
vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: memory_vlib.c:1046
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
#define PREDICT_TRUE(x)
Definition: clib.h:98
esp_decrypt_error_t
Definition: esp_decrypt.c:48
#define NULL
Definition: clib.h:55
ipsec_integ_alg_t integ_alg
Definition: ipsec.h:75
const EVP_CIPHER * type
Definition: esp.h:45
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
always_inline void esp_replay_advance(ipsec_sa_t *sa, u32 seq)
Definition: esp_decrypt.c:171
ipsec_main_t ipsec_main
Definition: ipsec.h:202
ipsec_crypto_alg_t crypto_alg
Definition: esp_decrypt.c:62
static char * esp_decrypt_error_strings[]
Definition: esp_decrypt.c:55
vlib_node_registration_t esp_decrypt_node
(constructor) VLIB_REGISTER_NODE (esp_decrypt_node)
Definition: esp_decrypt.c:410
esp_crypto_alg_t * esp_crypto_algs
Definition: esp.h:66
esp_integ_alg_t * esp_integ_algs
Definition: esp.h:67
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
esp_main_t esp_main
Definition: esp.h:71
u8 crypto_key[128]
Definition: ipsec.h:73
u32 spi
Definition: ipsec.h:68
u32 seq_hi
Definition: ipsec.h:89
u8 trunc_size
Definition: esp.h:50
u64 replay_window
Definition: ipsec.h:92
always_inline int esp_replay_check(ipsec_sa_t *sa, u32 seq)
Definition: esp_decrypt.c:110
always_inline void ipsec_alloc_empty_buffers(vlib_main_t *vm, ipsec_main_t *im)
Definition: ipsec.h:237
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:77
u8 integ_key[128]
Definition: ipsec.h:77
#define vlib_prefetch_buffer_with_index(vm, bi, type)
Prefetch buffer metadata by buffer index The first 64 bytes of buffer contains most header informatio...
Definition: buffer_funcs.h:181
#define always_inline
Definition: clib.h:84
u8 use_esn
Definition: ipsec.h:79
always_inline void esp_decrypt_aes_cbc(ipsec_crypto_alg_t alg, u8 *in, u8 *out, size_t in_len, u8 *key, u8 *iv)
Definition: esp_decrypt.c:80
static u8 * format_esp_decrypt_trace(u8 *s, va_list *args)
Definition: esp_decrypt.c:67
#define clib_warning(format, args...)
Definition: error.h:59
u8 data[0]
Definition: esp.h:26
u8 * format_ipsec_integ_alg(u8 *s, va_list *args)
Definition: ipsec_format.c:90
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
u32 last_seq
Definition: ipsec.h:90
#define pool_elt_at_index(p, i)
Definition: pool.h:346
void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer.c:1060
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
uword os_get_cpu_number(void)
Definition: unix-misc.c:206
u32 last_seq_hi
Definition: ipsec.h:91
#define PREDICT_FALSE(x)
Definition: clib.h:97
always_inline void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:970
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Definition: buffer_node.h:83
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Definition: node_funcs.h:265
#define ESP_WINDOW_SIZE
Definition: esp_decrypt.c:25
esp_decrypt_next_t
Definition: esp_decrypt.c:33
u16 n_vectors
Definition: node.h:307
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
#define VLIB_BUFFER_TOTAL_LENGTH_VALID
Definition: buffer.h:95
#define ARRAY_LEN(x)
Definition: clib.h:59
static uword esp_decrypt_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: esp_decrypt.c:229
#define foreach_esp_decrypt_next
Definition: esp_decrypt.c:27
u16 cached_next_index
Definition: node.h:422
#define ASSERT(truth)
always_inline int esp_replay_check_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp_decrypt.c:128
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:300
ipsec_sa_t * sad
Definition: ipsec.h:172
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
ipsec_crypto_alg_t
Definition: ipsec.h:38
u8 integ_key_len
Definition: ipsec.h:76
u32 seq
Definition: esp.h:25
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:91
u64 uword
Definition: types.h:112
Definition: defs.h:46
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
always_inline void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
ipsec_crypto_alg_t crypto_alg
Definition: ipsec.h:71
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
always_inline unsigned int hmac_calc(ipsec_integ_alg_t alg, u8 *key, int key_len, u8 *data, int data_len, u8 *signature, u8 use_esn, u32 seq_hi)
Definition: esp.h:121
Definition: esp.h:65
#define foreach_esp_decrypt_error
Definition: esp_decrypt.c:40
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
u32 ** empty_buffers
Definition: ipsec.h:178
u8 * format_ipsec_crypto_alg(u8 *s, va_list *args)
Definition: ipsec_format.c:58
u8 use_anti_replay
Definition: ipsec.h:80
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
esp_main_per_thread_data_t * per_thread_data
Definition: esp.h:68
u32 trace_index
Specifies index into trace buffer if VLIB_PACKET_IS_TRACED flag is set.
Definition: buffer.h:116
EVP_CIPHER_CTX decrypt_ctx
Definition: esp.h:57
ipsec_integ_alg_t integ_alg
Definition: esp_decrypt.c:63
ipsec_integ_alg_t
Definition: ipsec.h:54