ipsec: IPSec protection for multi-point tunnel interfaces
[vpp.git] / src / vnet / ipsec / ipsec.c
1 /*
2  * ipsec.c : IPSEC module functions
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 #include <vnet/interface.h>
22 #include <vnet/udp/udp.h>
23
24 #include <vnet/ipsec/ipsec.h>
25 #include <vnet/ipsec/esp.h>
26 #include <vnet/ipsec/ah.h>
27
28 ipsec_main_t ipsec_main;
29
30 static clib_error_t *
31 ipsec_check_ah_support (ipsec_sa_t * sa)
32 {
33   ipsec_main_t *im = &ipsec_main;
34
35   if (sa->integ_alg == IPSEC_INTEG_ALG_NONE)
36     return clib_error_return (0, "unsupported none integ-alg");
37
38   if (!vnet_crypto_is_set_handler (im->integ_algs[sa->integ_alg].alg))
39     return clib_error_return (0, "No crypto engine support for %U",
40                               format_ipsec_integ_alg, sa->integ_alg);
41
42   return 0;
43 }
44
45 static clib_error_t *
46 ipsec_check_esp_support (ipsec_sa_t * sa)
47 {
48   ipsec_main_t *im = &ipsec_main;
49
50   if (IPSEC_INTEG_ALG_NONE != sa->integ_alg)
51     {
52       if (!vnet_crypto_is_set_handler (im->integ_algs[sa->integ_alg].alg))
53         return clib_error_return (0, "No crypto engine support for %U",
54                                   format_ipsec_integ_alg, sa->integ_alg);
55     }
56   if (IPSEC_CRYPTO_ALG_NONE != sa->crypto_alg)
57     {
58       if (!vnet_crypto_is_set_handler (im->crypto_algs[sa->crypto_alg].alg))
59         return clib_error_return (0, "No crypto engine support for %U",
60                                   format_ipsec_crypto_alg, sa->crypto_alg);
61     }
62
63   return (0);
64 }
65
66 clib_error_t *
67 ipsec_add_del_sa_sess_cb (ipsec_main_t * im, u32 sa_index, u8 is_add)
68 {
69   ipsec_ah_backend_t *ah =
70     pool_elt_at_index (im->ah_backends, im->ah_current_backend);
71   if (ah->add_del_sa_sess_cb)
72     {
73       clib_error_t *err = ah->add_del_sa_sess_cb (sa_index, is_add);
74       if (err)
75         return err;
76     }
77   ipsec_esp_backend_t *esp =
78     pool_elt_at_index (im->esp_backends, im->esp_current_backend);
79   if (esp->add_del_sa_sess_cb)
80     {
81       clib_error_t *err = esp->add_del_sa_sess_cb (sa_index, is_add);
82       if (err)
83         return err;
84     }
85   return 0;
86 }
87
88 clib_error_t *
89 ipsec_check_support_cb (ipsec_main_t * im, ipsec_sa_t * sa)
90 {
91   clib_error_t *error = 0;
92
93   if (PREDICT_FALSE (sa->protocol == IPSEC_PROTOCOL_AH))
94     {
95       ipsec_ah_backend_t *ah =
96         pool_elt_at_index (im->ah_backends, im->ah_current_backend);
97       ASSERT (ah->check_support_cb);
98       error = ah->check_support_cb (sa);
99     }
100   else
101     {
102       ipsec_esp_backend_t *esp =
103         pool_elt_at_index (im->esp_backends, im->esp_current_backend);
104       ASSERT (esp->check_support_cb);
105       error = esp->check_support_cb (sa);
106     }
107   return error;
108 }
109
110
111 static void
112 ipsec_add_node (vlib_main_t * vm, const char *node_name,
113                 const char *prev_node_name, u32 * out_node_index,
114                 u32 * out_next_index)
115 {
116   vlib_node_t *prev_node, *node;
117   prev_node = vlib_get_node_by_name (vm, (u8 *) prev_node_name);
118   ASSERT (prev_node);
119   node = vlib_get_node_by_name (vm, (u8 *) node_name);
120   ASSERT (node);
121   *out_node_index = node->index;
122   *out_next_index = vlib_node_add_next (vm, prev_node->index, node->index);
123 }
124
125 void
126 ipsec_add_feature (const char *arc_name,
127                    const char *node_name, u32 * out_feature_index)
128 {
129   u8 arc;
130
131   arc = vnet_get_feature_arc_index (arc_name);
132   ASSERT (arc != (u8) ~ 0);
133   *out_feature_index = vnet_get_feature_index (arc, node_name);
134 }
135
136 u32
137 ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im,
138                            const char *name,
139                            const char *ah4_encrypt_node_name,
140                            const char *ah4_decrypt_node_name,
141                            const char *ah6_encrypt_node_name,
142                            const char *ah6_decrypt_node_name,
143                            check_support_cb_t ah_check_support_cb,
144                            add_del_sa_sess_cb_t ah_add_del_sa_sess_cb)
145 {
146   ipsec_ah_backend_t *b;
147   pool_get (im->ah_backends, b);
148   b->name = format (0, "%s%c", name, 0);
149
150   ipsec_add_node (vm, ah4_encrypt_node_name, "ipsec4-output-feature",
151                   &b->ah4_encrypt_node_index, &b->ah4_encrypt_next_index);
152   ipsec_add_node (vm, ah4_decrypt_node_name, "ipsec4-input-feature",
153                   &b->ah4_decrypt_node_index, &b->ah4_decrypt_next_index);
154   ipsec_add_node (vm, ah6_encrypt_node_name, "ipsec6-output-feature",
155                   &b->ah6_encrypt_node_index, &b->ah6_encrypt_next_index);
156   ipsec_add_node (vm, ah6_decrypt_node_name, "ipsec6-input-feature",
157                   &b->ah6_decrypt_node_index, &b->ah6_decrypt_next_index);
158
159   b->check_support_cb = ah_check_support_cb;
160   b->add_del_sa_sess_cb = ah_add_del_sa_sess_cb;
161   return b - im->ah_backends;
162 }
163
164 u32
165 ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
166                             const char *name,
167                             const char *esp4_encrypt_node_name,
168                             const char *esp4_encrypt_node_tun_name,
169                             const char *esp4_decrypt_node_name,
170                             const char *esp4_decrypt_tun_node_name,
171                             const char *esp6_encrypt_node_name,
172                             const char *esp6_encrypt_node_tun_name,
173                             const char *esp6_decrypt_node_name,
174                             const char *esp6_decrypt_tun_node_name,
175                             check_support_cb_t esp_check_support_cb,
176                             add_del_sa_sess_cb_t esp_add_del_sa_sess_cb)
177 {
178   ipsec_esp_backend_t *b;
179
180   pool_get (im->esp_backends, b);
181   b->name = format (0, "%s%c", name, 0);
182
183   ipsec_add_node (vm, esp4_encrypt_node_name, "ipsec4-output-feature",
184                   &b->esp4_encrypt_node_index, &b->esp4_encrypt_next_index);
185   ipsec_add_node (vm, esp4_decrypt_node_name, "ipsec4-input-feature",
186                   &b->esp4_decrypt_node_index, &b->esp4_decrypt_next_index);
187   ipsec_add_node (vm, esp6_encrypt_node_name, "ipsec6-output-feature",
188                   &b->esp6_encrypt_node_index, &b->esp6_encrypt_next_index);
189   ipsec_add_node (vm, esp6_decrypt_node_name, "ipsec6-input-feature",
190                   &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index);
191   ipsec_add_node (vm, esp4_decrypt_tun_node_name, "ipsec4-tun-input",
192                   &b->esp4_decrypt_tun_node_index,
193                   &b->esp4_decrypt_tun_next_index);
194   ipsec_add_node (vm, esp6_decrypt_tun_node_name, "ipsec6-tun-input",
195                   &b->esp6_decrypt_tun_node_index,
196                   &b->esp6_decrypt_tun_next_index);
197
198   ipsec_add_feature ("ip4-output", esp4_encrypt_node_tun_name,
199                      &b->esp44_encrypt_tun_feature_index);
200   ipsec_add_feature ("ip4-output", esp6_encrypt_node_tun_name,
201                      &b->esp46_encrypt_tun_feature_index);
202   ipsec_add_feature ("ip6-output", esp6_encrypt_node_tun_name,
203                      &b->esp66_encrypt_tun_feature_index);
204   ipsec_add_feature ("ip6-output", esp4_encrypt_node_tun_name,
205                      &b->esp64_encrypt_tun_feature_index);
206
207   b->check_support_cb = esp_check_support_cb;
208   b->add_del_sa_sess_cb = esp_add_del_sa_sess_cb;
209   return b - im->esp_backends;
210 }
211
212 clib_error_t *
213 ipsec_rsc_in_use (ipsec_main_t * im)
214 {
215   /* return an error is crypto resource are in use */
216   if (pool_elts (im->sad) > 0)
217     return clib_error_return (0,
218                               "%d SA entries configured",
219                               pool_elts (im->sad));
220
221   return (NULL);
222 }
223
224 int
225 ipsec_select_ah_backend (ipsec_main_t * im, u32 backend_idx)
226 {
227   if (ipsec_rsc_in_use (im))
228     return VNET_API_ERROR_RSRC_IN_USE;
229
230   if (pool_is_free_index (im->ah_backends, backend_idx))
231     return VNET_API_ERROR_INVALID_VALUE;
232
233   ipsec_ah_backend_t *b = pool_elt_at_index (im->ah_backends, backend_idx);
234   im->ah_current_backend = backend_idx;
235   im->ah4_encrypt_node_index = b->ah4_encrypt_node_index;
236   im->ah4_decrypt_node_index = b->ah4_decrypt_node_index;
237   im->ah4_encrypt_next_index = b->ah4_encrypt_next_index;
238   im->ah4_decrypt_next_index = b->ah4_decrypt_next_index;
239   im->ah6_encrypt_node_index = b->ah6_encrypt_node_index;
240   im->ah6_decrypt_node_index = b->ah6_decrypt_node_index;
241   im->ah6_encrypt_next_index = b->ah6_encrypt_next_index;
242   im->ah6_decrypt_next_index = b->ah6_decrypt_next_index;
243
244   return 0;
245 }
246
247 int
248 ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
249 {
250   if (ipsec_rsc_in_use (im))
251     return VNET_API_ERROR_RSRC_IN_USE;
252
253   if (pool_is_free_index (im->esp_backends, backend_idx))
254     return VNET_API_ERROR_INVALID_VALUE;
255
256   ipsec_esp_backend_t *b = pool_elt_at_index (im->esp_backends, backend_idx);
257   im->esp_current_backend = backend_idx;
258   im->esp4_encrypt_node_index = b->esp4_encrypt_node_index;
259   im->esp4_decrypt_node_index = b->esp4_decrypt_node_index;
260   im->esp4_encrypt_next_index = b->esp4_encrypt_next_index;
261   im->esp4_decrypt_next_index = b->esp4_decrypt_next_index;
262   im->esp6_encrypt_node_index = b->esp6_encrypt_node_index;
263   im->esp6_decrypt_node_index = b->esp6_decrypt_node_index;
264   im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
265   im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
266   im->esp4_decrypt_tun_node_index = b->esp4_decrypt_tun_node_index;
267   im->esp4_decrypt_tun_next_index = b->esp4_decrypt_tun_next_index;
268   im->esp6_decrypt_tun_node_index = b->esp6_decrypt_tun_node_index;
269   im->esp6_decrypt_tun_next_index = b->esp6_decrypt_tun_next_index;
270
271   im->esp44_encrypt_tun_feature_index = b->esp44_encrypt_tun_feature_index;
272   im->esp64_encrypt_tun_feature_index = b->esp64_encrypt_tun_feature_index;
273   im->esp46_encrypt_tun_feature_index = b->esp46_encrypt_tun_feature_index;
274   im->esp66_encrypt_tun_feature_index = b->esp66_encrypt_tun_feature_index;
275
276   return 0;
277 }
278
279 static clib_error_t *
280 ipsec_init (vlib_main_t * vm)
281 {
282   clib_error_t *error;
283   ipsec_main_t *im = &ipsec_main;
284   ipsec_main_crypto_alg_t *a;
285
286   /* Backend registration requires the feature arcs to be set up */
287   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
288     return (error);
289
290   im->vnet_main = vnet_get_main ();
291   im->vlib_main = vm;
292
293   im->spd_index_by_spd_id = hash_create (0, sizeof (uword));
294   im->sa_index_by_sa_id = hash_create (0, sizeof (uword));
295   im->spd_index_by_sw_if_index = hash_create (0, sizeof (uword));
296
297   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
298   ASSERT (node);
299   im->error_drop_node_index = node->index;
300
301   u32 idx = ipsec_register_ah_backend (vm, im, "crypto engine backend",
302                                        "ah4-encrypt",
303                                        "ah4-decrypt",
304                                        "ah6-encrypt",
305                                        "ah6-decrypt",
306                                        ipsec_check_ah_support,
307                                        NULL);
308
309   im->ah_default_backend = idx;
310   int rv = ipsec_select_ah_backend (im, idx);
311   ASSERT (0 == rv);
312   (void) (rv);                  // avoid warning
313
314   idx = ipsec_register_esp_backend (vm, im, "crypto engine backend",
315                                     "esp4-encrypt",
316                                     "esp4-encrypt-tun",
317                                     "esp4-decrypt",
318                                     "esp4-decrypt-tun",
319                                     "esp6-encrypt",
320                                     "esp6-encrypt-tun",
321                                     "esp6-decrypt",
322                                     "esp6-decrypt-tun",
323                                     ipsec_check_esp_support, NULL);
324   im->esp_default_backend = idx;
325
326   rv = ipsec_select_esp_backend (im, idx);
327   ASSERT (0 == rv);
328   (void) (rv);                  // avoid warning
329
330   if ((error = vlib_call_init_function (vm, ipsec_cli_init)))
331     return error;
332
333   vec_validate (im->crypto_algs, IPSEC_CRYPTO_N_ALG - 1);
334
335   a = im->crypto_algs + IPSEC_CRYPTO_ALG_NONE;
336   a->enc_op_id = VNET_CRYPTO_OP_NONE;
337   a->dec_op_id = VNET_CRYPTO_OP_NONE;
338   a->alg = VNET_CRYPTO_ALG_NONE;
339   a->iv_size = 0;
340   a->block_size = 1;
341
342   a = im->crypto_algs + IPSEC_CRYPTO_ALG_DES_CBC;
343   a->enc_op_id = VNET_CRYPTO_OP_DES_CBC_ENC;
344   a->dec_op_id = VNET_CRYPTO_OP_DES_CBC_DEC;
345   a->alg = VNET_CRYPTO_ALG_DES_CBC;
346   a->iv_size = a->block_size = 8;
347
348   a = im->crypto_algs + IPSEC_CRYPTO_ALG_3DES_CBC;
349   a->enc_op_id = VNET_CRYPTO_OP_3DES_CBC_ENC;
350   a->dec_op_id = VNET_CRYPTO_OP_3DES_CBC_DEC;
351   a->alg = VNET_CRYPTO_ALG_3DES_CBC;
352   a->iv_size = a->block_size = 8;
353
354   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_128;
355   a->enc_op_id = VNET_CRYPTO_OP_AES_128_CBC_ENC;
356   a->dec_op_id = VNET_CRYPTO_OP_AES_128_CBC_DEC;
357   a->alg = VNET_CRYPTO_ALG_AES_128_CBC;
358   a->iv_size = a->block_size = 16;
359
360   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_192;
361   a->enc_op_id = VNET_CRYPTO_OP_AES_192_CBC_ENC;
362   a->dec_op_id = VNET_CRYPTO_OP_AES_192_CBC_DEC;
363   a->alg = VNET_CRYPTO_ALG_AES_192_CBC;
364   a->iv_size = a->block_size = 16;
365
366   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_256;
367   a->enc_op_id = VNET_CRYPTO_OP_AES_256_CBC_ENC;
368   a->dec_op_id = VNET_CRYPTO_OP_AES_256_CBC_DEC;
369   a->alg = VNET_CRYPTO_ALG_AES_256_CBC;
370   a->iv_size = a->block_size = 16;
371
372   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_128;
373   a->enc_op_id = VNET_CRYPTO_OP_AES_128_GCM_ENC;
374   a->dec_op_id = VNET_CRYPTO_OP_AES_128_GCM_DEC;
375   a->alg = VNET_CRYPTO_ALG_AES_128_GCM;
376   a->iv_size = 8;
377   a->block_size = 16;
378   a->icv_size = 16;
379
380   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_192;
381   a->enc_op_id = VNET_CRYPTO_OP_AES_192_GCM_ENC;
382   a->dec_op_id = VNET_CRYPTO_OP_AES_192_GCM_DEC;
383   a->alg = VNET_CRYPTO_ALG_AES_192_GCM;
384   a->iv_size = 8;
385   a->block_size = 16;
386   a->icv_size = 16;
387
388   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_256;
389   a->enc_op_id = VNET_CRYPTO_OP_AES_256_GCM_ENC;
390   a->dec_op_id = VNET_CRYPTO_OP_AES_256_GCM_DEC;
391   a->alg = VNET_CRYPTO_ALG_AES_256_GCM;
392   a->iv_size = 8;
393   a->block_size = 16;
394   a->icv_size = 16;
395
396   vec_validate (im->integ_algs, IPSEC_INTEG_N_ALG - 1);
397   ipsec_main_integ_alg_t *i;
398
399   i = &im->integ_algs[IPSEC_INTEG_ALG_MD5_96];
400   i->op_id = VNET_CRYPTO_OP_MD5_HMAC;
401   i->alg = VNET_CRYPTO_ALG_HMAC_MD5;
402   i->icv_size = 12;
403
404   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA1_96];
405   i->op_id = VNET_CRYPTO_OP_SHA1_HMAC;
406   i->alg = VNET_CRYPTO_ALG_HMAC_SHA1;
407   i->icv_size = 12;
408
409   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_256_96];
410   i->op_id = VNET_CRYPTO_OP_SHA1_HMAC;
411   i->alg = VNET_CRYPTO_ALG_HMAC_SHA256;
412   i->icv_size = 12;
413
414   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_256_128];
415   i->op_id = VNET_CRYPTO_OP_SHA256_HMAC;
416   i->alg = VNET_CRYPTO_ALG_HMAC_SHA256;
417   i->icv_size = 16;
418
419   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_384_192];
420   i->op_id = VNET_CRYPTO_OP_SHA384_HMAC;
421   i->alg = VNET_CRYPTO_ALG_HMAC_SHA384;
422   i->icv_size = 24;
423
424   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_512_256];
425   i->op_id = VNET_CRYPTO_OP_SHA512_HMAC;
426   i->alg = VNET_CRYPTO_ALG_HMAC_SHA512;
427   i->icv_size = 32;
428
429   vec_validate_aligned (im->ptd, vlib_num_workers (), CLIB_CACHE_LINE_BYTES);
430
431   im->ah4_enc_fq_index =
432     vlib_frame_queue_main_init (ah4_encrypt_node.index, 0);
433   im->ah4_dec_fq_index =
434     vlib_frame_queue_main_init (ah4_decrypt_node.index, 0);
435   im->ah6_enc_fq_index =
436     vlib_frame_queue_main_init (ah6_encrypt_node.index, 0);
437   im->ah6_dec_fq_index =
438     vlib_frame_queue_main_init (ah6_decrypt_node.index, 0);
439
440   im->esp4_enc_fq_index =
441     vlib_frame_queue_main_init (esp4_encrypt_node.index, 0);
442   im->esp4_dec_fq_index =
443     vlib_frame_queue_main_init (esp4_decrypt_node.index, 0);
444   im->esp6_enc_fq_index =
445     vlib_frame_queue_main_init (esp6_encrypt_node.index, 0);
446   im->esp6_dec_fq_index =
447     vlib_frame_queue_main_init (esp6_decrypt_node.index, 0);
448   im->esp4_enc_tun_fq_index =
449     vlib_frame_queue_main_init (esp4_encrypt_tun_node.index, 0);
450   im->esp6_enc_tun_fq_index =
451     vlib_frame_queue_main_init (esp6_encrypt_tun_node.index, 0);
452   im->esp4_dec_tun_fq_index =
453     vlib_frame_queue_main_init (esp4_decrypt_tun_node.index, 0);
454   im->esp6_dec_tun_fq_index =
455     vlib_frame_queue_main_init (esp6_decrypt_tun_node.index, 0);
456
457   return 0;
458 }
459
460 VLIB_INIT_FUNCTION (ipsec_init);
461
462 /*
463  * fd.io coding-style-patch-verification: ON
464  *
465  * Local Variables:
466  * eval: (c-set-style "gnu")
467  * End:
468  */