Add support for multiple microarchitectures in single binary
[vpp.git] / vnet / vnet / ipsec / esp_decrypt.c
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 {
34   foreach_esp_decrypt_next
35 #undef _
36   ESP_DECRYPT_N_NEXT,
37 } esp_decrypt_next_t;
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,
50   foreach_esp_decrypt_error
51 #undef _
52   ESP_DECRYPT_N_ERROR,
53 } esp_decrypt_error_t;
54
55 static char * esp_decrypt_error_strings[] = {
56 #define _(sym,string) string,
57   foreach_esp_decrypt_error
58 #undef _
59 };
60
61 typedef struct {
62   ipsec_crypto_alg_t crypto_alg;
63   ipsec_integ_alg_t integ_alg;
64 } esp_decrypt_trace_t;
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",
74               format_ipsec_crypto_alg, t->crypto_alg,
75               format_ipsec_integ_alg, t->integ_alg);
76   return s;
77 }
78
79 always_inline void
80 esp_decrypt_aes_cbc(ipsec_crypto_alg_t alg,
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
93   ASSERT(alg < IPSEC_CRYPTO_N_ALG);
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
110 esp_replay_check (ipsec_sa_t * sa, u32 seq)
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
128 esp_replay_check_esn (ipsec_sa_t * sa, u32 seq)
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
171 esp_replay_advance (ipsec_sa_t * sa, u32 seq)
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
192 esp_replay_advance_esn (ipsec_sa_t * sa, u32 seq)
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
229 esp_decrypt_node_fn (vlib_main_t * vm,
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
242   ipsec_alloc_empty_buffers(vm, im);
243
244   if (PREDICT_FALSE(vec_len (empty_buffers) < n_left_from)){
245     vlib_node_increment_counter (vm, esp_decrypt_node.index,
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);
296                   vlib_node_increment_counter (vm, esp_decrypt_node.index,
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                 {
317                   vlib_node_increment_counter (vm, esp_decrypt_node.index,
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
352             esp_decrypt_aes_cbc(sa0->crypto_alg,
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;
360             o_b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
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);
370                 vlib_node_increment_counter (vm, esp_decrypt_node.index,
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:
384           if (PREDICT_FALSE(i_b0->flags & VLIB_BUFFER_IS_TRACED)) {
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     }
399   vlib_node_increment_counter (vm, esp_decrypt_node.index,
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
410 VLIB_REGISTER_NODE (esp_decrypt_node) = {
411   .function = esp_decrypt_node_fn,
412   .name = "esp-decrypt",
413   .vector_size = sizeof (u32),
414   .format_trace = format_esp_decrypt_trace,
415   .type = VLIB_NODE_TYPE_INTERNAL,
416
417   .n_errors = ARRAY_LEN(esp_decrypt_error_strings),
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,
423     foreach_esp_decrypt_next
424 #undef _
425   },
426 };
427
428 VLIB_NODE_FUNCTION_MULTIARCH (esp_decrypt_node, esp_decrypt_node_fn)
429