1010e3708804decb6e3e0a0c5f6b150bd3d7d624
[vpp.git] / src / plugins / tlsmbedtls / tls_mbedtls.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <mbedtls/ssl.h>
17 #include <mbedtls/certs.h>
18 #include <mbedtls/entropy.h>
19 #include <mbedtls/ctr_drbg.h>
20 #include <mbedtls/timing.h>
21 #include <mbedtls/debug.h>
22 #include <vnet/plugin/plugin.h>
23 #include <vpp/app/version.h>
24 #include <vnet/tls/tls.h>
25
26 #define TLS_USE_OUR_MEM_FUNCS   0
27
28 typedef struct tls_ctx_mbedtls_
29 {
30   tls_ctx_t ctx;                        /**< First */
31   u32 mbedtls_ctx_index;
32   mbedtls_ssl_context ssl;
33   mbedtls_ssl_config conf;
34   mbedtls_x509_crt srvcert;
35   mbedtls_pk_context pkey;
36 } mbedtls_ctx_t;
37
38 typedef struct mbedtls_main_
39 {
40   mbedtls_ctx_t ***ctx_pool;
41   mbedtls_ctr_drbg_context *ctr_drbgs;
42   mbedtls_entropy_context *entropy_pools;
43   mbedtls_x509_crt cacert;
44   u8 **rx_bufs;
45   u8 **tx_bufs;
46 } mbedtls_main_t;
47
48 static mbedtls_main_t mbedtls_main;
49
50 #if TLS_USE_OUR_MEM_FUNCS
51 #include <mbedtls/platform.h>
52
53 void *
54 mbedtls_calloc_fn (size_t n, size_t size)
55 {
56   void *ptr;
57   ptr = clib_mem_alloc (n * size);
58   memset (ptr, 0, sizeof (*ptr));
59   return ptr;
60 }
61
62 void
63 mbedtls_free_fn (void *ptr)
64 {
65   if (ptr)
66     clib_mem_free (ptr);
67 }
68 #endif
69
70 static u32
71 mbedtls_ctx_alloc (void)
72 {
73   u8 thread_index = vlib_get_thread_index ();
74   mbedtls_main_t *tm = &mbedtls_main;
75   mbedtls_ctx_t **ctx;
76
77   pool_get (tm->ctx_pool[thread_index], ctx);
78   if (!(*ctx))
79     *ctx = clib_mem_alloc (sizeof (mbedtls_ctx_t));
80
81   memset (*ctx, 0, sizeof (mbedtls_ctx_t));
82   (*ctx)->ctx.c_thread_index = thread_index;
83   (*ctx)->ctx.tls_ctx_engine = TLS_ENGINE_MBEDTLS;
84   (*ctx)->mbedtls_ctx_index = ctx - tm->ctx_pool[thread_index];
85   return ((*ctx)->mbedtls_ctx_index);
86 }
87
88 static void
89 mbedtls_ctx_free (tls_ctx_t * ctx)
90 {
91   mbedtls_ctx_t *mc = (mbedtls_ctx_t *) ctx;
92
93   if (mc->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER && !ctx->is_passive_close)
94     mbedtls_ssl_close_notify (&mc->ssl);
95   if (mc->ssl.conf->endpoint == MBEDTLS_SSL_IS_SERVER)
96     {
97       mbedtls_x509_crt_free (&mc->srvcert);
98       mbedtls_pk_free (&mc->pkey);
99     }
100   mbedtls_ssl_free (&mc->ssl);
101   mbedtls_ssl_config_free (&mc->conf);
102
103   pool_put_index (mbedtls_main.ctx_pool[ctx->c_thread_index],
104                   mc->mbedtls_ctx_index);
105 }
106
107 static tls_ctx_t *
108 mbedtls_ctx_get (u32 ctx_index)
109 {
110   mbedtls_ctx_t **ctx;
111   ctx = pool_elt_at_index (mbedtls_main.ctx_pool[vlib_get_thread_index ()],
112                            ctx_index);
113   return &(*ctx)->ctx;
114 }
115
116 static tls_ctx_t *
117 mbedtls_ctx_get_w_thread (u32 ctx_index, u8 thread_index)
118 {
119   mbedtls_ctx_t **ctx;
120   ctx = pool_elt_at_index (mbedtls_main.ctx_pool[thread_index], ctx_index);
121   return &(*ctx)->ctx;
122 }
123
124 static int
125 tls_init_ctr_seed_drbgs (void)
126 {
127   u32 thread_index = vlib_get_thread_index ();
128   mbedtls_main_t *tm = &mbedtls_main;
129   u8 *pers;
130   int rv;
131   pers = format (0, "vpp thread %u", thread_index);
132
133   mbedtls_entropy_init (&tm->entropy_pools[thread_index]);
134   mbedtls_ctr_drbg_init (&mbedtls_main.ctr_drbgs[thread_index]);
135   if ((rv = mbedtls_ctr_drbg_seed (&tm->ctr_drbgs[thread_index],
136                                    mbedtls_entropy_func,
137                                    &tm->entropy_pools[thread_index],
138                                    (const unsigned char *) pers,
139                                    vec_len (pers))) != 0)
140     {
141       vec_free (pers);
142       TLS_DBG (1, " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", rv);
143       return -1;
144     }
145   vec_free (pers);
146   return 0;
147 }
148
149 mbedtls_ctr_drbg_context *
150 tls_get_ctr_drbg ()
151 {
152   u8 thread_index = vlib_get_thread_index ();
153   if (PREDICT_FALSE (!mbedtls_main.ctr_drbgs[thread_index].f_entropy))
154     tls_init_ctr_seed_drbgs ();
155   return &mbedtls_main.ctr_drbgs[thread_index];
156 }
157
158 static int
159 tls_net_send (void *ctx_indexp, const unsigned char *buf, size_t len)
160 {
161   stream_session_t *tls_session;
162   uword ctx_index;
163   tls_ctx_t *ctx;
164   int rv;
165
166   ctx_index = pointer_to_uword (ctx_indexp);
167   ctx = mbedtls_ctx_get (ctx_index);
168   tls_session = session_get_from_handle (ctx->tls_session_handle);
169   rv = svm_fifo_enqueue_nowait (tls_session->server_tx_fifo, len, buf);
170   if (rv < 0)
171     return MBEDTLS_ERR_SSL_WANT_WRITE;
172   tls_add_vpp_q_tx_evt (tls_session);
173   return rv;
174 }
175
176 static int
177 tls_net_recv (void *ctx_indexp, unsigned char *buf, size_t len)
178 {
179   stream_session_t *tls_session;
180   uword ctx_index;
181   tls_ctx_t *ctx;
182   int rv;
183
184   ctx_index = pointer_to_uword (ctx_indexp);
185   ctx = mbedtls_ctx_get (ctx_index);
186   tls_session = session_get_from_handle (ctx->tls_session_handle);
187   rv = svm_fifo_dequeue_nowait (tls_session->server_rx_fifo, len, buf);
188   return (rv < 0) ? 0 : rv;
189 }
190
191 static void
192 mbedtls_debug (void *ctx, int level, const char *file, int line,
193                const char *str)
194 {
195   ((void) level);
196   fprintf ((FILE *) ctx, "%s:%04d: %s", file, line, str);
197   fflush ((FILE *) ctx);
198 }
199
200 static int
201 mbedtls_ctx_init_client (tls_ctx_t * ctx)
202 {
203   mbedtls_ctx_t *mc = (mbedtls_ctx_t *) ctx;
204   mbedtls_main_t *mm = &mbedtls_main;
205   void *ctx_ptr;
206   int rv;
207
208   /*
209    * 1. Setup SSL
210    */
211   mbedtls_ssl_init (&mc->ssl);
212   mbedtls_ssl_config_init (&mc->conf);
213   if ((rv = mbedtls_ssl_config_defaults (&mc->conf, MBEDTLS_SSL_IS_CLIENT,
214                                          MBEDTLS_SSL_TRANSPORT_STREAM,
215                                          MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
216     {
217       TLS_DBG (1, "failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n",
218                rv);
219       return -1;
220     }
221
222   mbedtls_ssl_conf_authmode (&mc->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
223   mbedtls_ssl_conf_ca_chain (&mc->conf, &mm->cacert, NULL);
224   mbedtls_ssl_conf_rng (&mc->conf, mbedtls_ctr_drbg_random,
225                         tls_get_ctr_drbg ());
226   mbedtls_ssl_conf_dbg (&mc->conf, mbedtls_debug, stdout);
227
228   if ((rv = mbedtls_ssl_setup (&mc->ssl, &mc->conf)) != 0)
229     {
230       TLS_DBG (1, "failed\n  ! mbedtls_ssl_setup returned %d\n", rv);
231       return -1;
232     }
233
234   if ((rv = mbedtls_ssl_set_hostname (&mc->ssl,
235                                       (const char *) ctx->srv_hostname)) != 0)
236     {
237       TLS_DBG (1, "failed\n  ! mbedtls_ssl_set_hostname returned %d\n", rv);
238       return -1;
239     }
240
241   ctx_ptr = uword_to_pointer (mc->mbedtls_ctx_index, void *);
242   mbedtls_ssl_set_bio (&mc->ssl, ctx_ptr, tls_net_send, tls_net_recv, NULL);
243   mbedtls_debug_set_threshold (TLS_DEBUG_LEVEL_CLIENT);
244
245   /*
246    * 2. Do the first 2 steps in the handshake.
247    */
248   TLS_DBG (1, "Initiating handshake for [%u]%u", ctx->c_thread_index,
249            mc->mbedtls_ctx_index);
250   while (mc->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER)
251     {
252       rv = mbedtls_ssl_handshake_step (&mc->ssl);
253       if (rv != 0)
254         break;
255     }
256   TLS_DBG (2, "tls state for [%u]%u is %u", ctx->c_thread_index,
257            mc->mbedtls_ctx_index, mc->ssl.state);
258   return 0;
259 }
260
261 static int
262 mbedtls_start_listen (tls_ctx_t * lctx)
263 {
264   return 0;
265 }
266
267 static int
268 mbedtls_stop_listen (tls_ctx_t * lctx)
269 {
270   return 0;
271 }
272
273 static int
274 mbedtls_ctx_init_server (tls_ctx_t * ctx)
275 {
276   mbedtls_ctx_t *mc = (mbedtls_ctx_t *) ctx;
277   mbedtls_main_t *mm = &mbedtls_main;
278   application_t *app;
279   void *ctx_ptr;
280   int rv;
281
282   mbedtls_ssl_init (&mc->ssl);
283   mbedtls_ssl_config_init (&mc->conf);
284   mbedtls_x509_crt_init (&mc->srvcert);
285   mbedtls_pk_init (&mc->pkey);
286
287   /*
288    * 1. Cert
289    */
290   app = application_get (ctx->parent_app_index);
291   if (!app->tls_cert || !app->tls_key)
292     {
293       TLS_DBG (1, " failed\n  ! tls cert and/or key not configured %d",
294                ctx->parent_app_index);
295       return -1;
296     }
297
298   rv = mbedtls_x509_crt_parse (&mc->srvcert,
299                                (const unsigned char *) app->tls_cert,
300                                vec_len (app->tls_cert));
301   if (rv != 0)
302     {
303       TLS_DBG (1, " failed\n  !  mbedtls_x509_crt_parse returned %d", rv);
304       goto exit;
305     }
306
307   rv = mbedtls_pk_parse_key (&mc->pkey,
308                              (const unsigned char *) app->tls_key,
309                              vec_len (app->tls_key), NULL, 0);
310   if (rv != 0)
311     {
312       TLS_DBG (1, " failed\n  !  mbedtls_pk_parse_key returned %d", rv);
313       goto exit;
314     }
315
316   /*
317    * 2. SSL context config
318    */
319   if ((rv = mbedtls_ssl_config_defaults (&mc->conf, MBEDTLS_SSL_IS_SERVER,
320                                          MBEDTLS_SSL_TRANSPORT_STREAM,
321                                          MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
322     {
323       TLS_DBG (1, " failed\n  ! mbedtls_ssl_config_defaults returned %d", rv);
324       goto exit;
325     }
326
327   mbedtls_ssl_conf_rng (&mc->conf, mbedtls_ctr_drbg_random,
328                         tls_get_ctr_drbg ());
329   mbedtls_ssl_conf_dbg (&mc->conf, mbedtls_debug, stdout);
330
331   /* TODO CACHE
332      mbedtls_ssl_conf_session_cache( &ctx->conf, &cache,
333      mbedtls_ssl_cache_get,
334      mbedtls_ssl_cache_set );
335    */
336
337   mbedtls_ssl_conf_ca_chain (&mc->conf, &mm->cacert, NULL);
338   if ((rv = mbedtls_ssl_conf_own_cert (&mc->conf, &mc->srvcert, &mc->pkey))
339       != 0)
340     {
341       TLS_DBG (1, " failed\n  ! mbedtls_ssl_conf_own_cert returned %d", rv);
342       goto exit;
343     }
344
345   if ((rv = mbedtls_ssl_setup (&mc->ssl, &mc->conf)) != 0)
346     {
347       TLS_DBG (1, " failed\n  ! mbedtls_ssl_setup returned %d", rv);
348       goto exit;
349     }
350
351   mbedtls_ssl_session_reset (&mc->ssl);
352   ctx_ptr = uword_to_pointer (mc->mbedtls_ctx_index, void *);
353   mbedtls_ssl_set_bio (&mc->ssl, ctx_ptr, tls_net_send, tls_net_recv, NULL);
354   mbedtls_debug_set_threshold (TLS_DEBUG_LEVEL_SERVER);
355
356   /*
357    * 3. Start handshake state machine
358    */
359   TLS_DBG (1, "Initiating handshake for [%u]%u", ctx->c_thread_index,
360            mc->mbedtls_ctx_index);
361   while (mc->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER)
362     {
363       rv = mbedtls_ssl_handshake_step (&mc->ssl);
364       if (rv != 0)
365         break;
366     }
367
368   TLS_DBG (2, "tls state for [%u]%u is %u", ctx->c_thread_index,
369            mc->mbedtls_ctx_index, mc->ssl.state);
370   return 0;
371
372 exit:
373   return -1;
374 }
375
376 static int
377 mbedtls_ctx_handshake_rx (tls_ctx_t * ctx)
378 {
379   mbedtls_ctx_t *mc = (mbedtls_ctx_t *) ctx;
380   u32 flags;
381   int rv;
382   while (mc->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER)
383     {
384       rv = mbedtls_ssl_handshake_step (&mc->ssl);
385       if (rv != 0)
386         break;
387     }
388   TLS_DBG (2, "tls state for %u is %u", mc->mbedtls_ctx_index, mc->ssl.state);
389
390   if (mc->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER)
391     return 0;
392
393   /*
394    * Handshake complete
395    */
396   if (mc->ssl.conf->endpoint == MBEDTLS_SSL_IS_CLIENT)
397     {
398       /*
399        * Verify server certificate
400        */
401       if ((flags = mbedtls_ssl_get_verify_result (&mc->ssl)) != 0)
402         {
403           char buf[512];
404           TLS_DBG (1, " failed\n");
405           mbedtls_x509_crt_verify_info (buf, sizeof (buf), "  ! ", flags);
406           TLS_DBG (1, "%s\n", buf);
407
408           /*
409            * Presence of hostname enforces strict certificate verification
410            */
411           if (ctx->srv_hostname)
412             {
413               tls_notify_app_connected (ctx, /* is failed */ 0);
414               return -1;
415             }
416         }
417       tls_notify_app_connected (ctx, /* is failed */ 0);
418     }
419   else
420     {
421       tls_notify_app_accept (ctx);
422     }
423
424   TLS_DBG (1, "Handshake for %u complete. TLS cipher is %x",
425            mc->mbedtls_ctx_index, mc->ssl.session->ciphersuite);
426   return 0;
427 }
428
429 static int
430 mbedtls_ctx_write (tls_ctx_t * ctx, stream_session_t * app_session)
431 {
432   mbedtls_ctx_t *mc = (mbedtls_ctx_t *) ctx;
433   u8 thread_index = ctx->c_thread_index;
434   mbedtls_main_t *mm = &mbedtls_main;
435   u32 enq_max, deq_max, deq_now;
436   stream_session_t *tls_session;
437   int wrote;
438
439   ASSERT (mc->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER);
440
441   deq_max = svm_fifo_max_dequeue (app_session->server_tx_fifo);
442   if (!deq_max)
443     return 0;
444
445   tls_session = session_get_from_handle (ctx->tls_session_handle);
446   enq_max = svm_fifo_max_enqueue (tls_session->server_tx_fifo);
447   deq_now = clib_min (deq_max, TLS_CHUNK_SIZE);
448
449   if (PREDICT_FALSE (enq_max == 0))
450     {
451       tls_add_vpp_q_builtin_tx_evt (app_session);
452       return 0;
453     }
454
455   vec_validate (mm->tx_bufs[thread_index], deq_now);
456   svm_fifo_peek (app_session->server_tx_fifo, 0, deq_now,
457                  mm->tx_bufs[thread_index]);
458
459   wrote = mbedtls_ssl_write (&mc->ssl, mm->tx_bufs[thread_index], deq_now);
460   if (wrote <= 0)
461     {
462       tls_add_vpp_q_builtin_tx_evt (app_session);
463       return 0;
464     }
465
466   svm_fifo_dequeue_drop (app_session->server_tx_fifo, wrote);
467   vec_reset_length (mm->tx_bufs[thread_index]);
468   tls_add_vpp_q_tx_evt (tls_session);
469
470   if (deq_now < deq_max)
471     tls_add_vpp_q_builtin_tx_evt (app_session);
472
473   return 0;
474 }
475
476 static int
477 mbedtls_ctx_read (tls_ctx_t * ctx, stream_session_t * tls_session)
478 {
479   mbedtls_ctx_t *mc = (mbedtls_ctx_t *) ctx;
480   mbedtls_main_t *mm = &mbedtls_main;
481   u8 thread_index = ctx->c_thread_index;
482   u32 deq_max, enq_max, enq_now;
483   stream_session_t *app_session;
484   int read, enq;
485
486   if (PREDICT_FALSE (mc->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER))
487     {
488       mbedtls_ctx_handshake_rx (ctx);
489       return 0;
490     }
491
492   deq_max = svm_fifo_max_dequeue (tls_session->server_rx_fifo);
493   if (!deq_max)
494     return 0;
495
496   app_session = session_get_from_handle (ctx->app_session_handle);
497   enq_max = svm_fifo_max_enqueue (app_session->server_rx_fifo);
498   enq_now = clib_min (enq_max, TLS_CHUNK_SIZE);
499
500   if (PREDICT_FALSE (enq_now == 0))
501     {
502       tls_add_vpp_q_builtin_rx_evt (tls_session);
503       return 0;
504     }
505
506   vec_validate (mm->rx_bufs[thread_index], enq_now);
507   read = mbedtls_ssl_read (&mc->ssl, mm->rx_bufs[thread_index], enq_now);
508   if (read <= 0)
509     {
510       tls_add_vpp_q_builtin_rx_evt (tls_session);
511       return 0;
512     }
513
514   enq = svm_fifo_enqueue_nowait (app_session->server_rx_fifo, read,
515                                  mm->rx_bufs[thread_index]);
516   ASSERT (enq == read);
517   vec_reset_length (mm->rx_bufs[thread_index]);
518
519   if (svm_fifo_max_dequeue (tls_session->server_rx_fifo))
520     tls_add_vpp_q_builtin_rx_evt (tls_session);
521
522   if (enq > 0)
523     tls_notify_app_enqueue (ctx, app_session);
524
525   return enq;
526 }
527
528 static u8
529 mbedtls_handshake_is_over (tls_ctx_t * ctx)
530 {
531   mbedtls_ctx_t *mc = (mbedtls_ctx_t *) ctx;
532   return (mc->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER);
533 }
534
535 const static tls_engine_vft_t mbedtls_engine = {
536   .ctx_alloc = mbedtls_ctx_alloc,
537   .ctx_free = mbedtls_ctx_free,
538   .ctx_get = mbedtls_ctx_get,
539   .ctx_get_w_thread = mbedtls_ctx_get_w_thread,
540   .ctx_init_server = mbedtls_ctx_init_server,
541   .ctx_init_client = mbedtls_ctx_init_client,
542   .ctx_write = mbedtls_ctx_write,
543   .ctx_read = mbedtls_ctx_read,
544   .ctx_handshake_is_over = mbedtls_handshake_is_over,
545   .ctx_start_listen = mbedtls_start_listen,
546   .ctx_stop_listen = mbedtls_stop_listen,
547 };
548
549 int
550 tls_init_mem (void)
551 {
552 #if TLS_USE_OUR_MEM_FUNCS
553   mbedtls_platform_set_calloc_free (mbedtls_calloc_fn, mbedtls_free_fn);
554 #endif
555   return 0;
556 }
557
558 static int
559 tls_init_ctr_drbgs_and_entropy (u32 num_threads)
560 {
561   mbedtls_main_t *mm = &mbedtls_main;
562   int i;
563
564   vec_validate (mm->ctr_drbgs, num_threads - 1);
565   vec_validate (mm->entropy_pools, num_threads - 1);
566   for (i = 0; i < num_threads; i++)
567     mm->ctr_drbgs[i].f_entropy = 0;
568
569   return 0;
570 }
571
572 int
573 tls_init_ca_chain (void)
574 {
575   mbedtls_main_t *mm = &mbedtls_main;
576   tls_main_t *tm = vnet_tls_get_main ();
577   int rv;
578
579   if (access (tm->ca_cert_path, F_OK | R_OK) == -1)
580     {
581       clib_warning ("Could not initialize TLS CA certificates");
582       return -1;
583     }
584
585   mbedtls_x509_crt_init (&mm->cacert);
586   rv = mbedtls_x509_crt_parse_file (&mm->cacert, tm->ca_cert_path);
587   if (rv < 0)
588     {
589       clib_warning ("Couldn't parse system CA certificates: -0x%x", -rv);
590     }
591   if (tm->use_test_cert_in_ca)
592     {
593       rv = mbedtls_x509_crt_parse (&mm->cacert,
594                                    (const unsigned char *) test_srv_crt_rsa,
595                                    test_srv_crt_rsa_len);
596       if (rv < 0)
597         {
598           clib_warning ("Couldn't parse test certificate: -0x%x", -rv);
599           return -1;
600         }
601     }
602   return (rv < 0 ? -1 : 0);
603 }
604
605 static clib_error_t *
606 tls_mbedtls_init (vlib_main_t * vm)
607 {
608   vlib_thread_main_t *vtm = vlib_get_thread_main ();
609   mbedtls_main_t *mm = &mbedtls_main;
610   clib_error_t *error;
611   u32 num_threads;
612
613   num_threads = 1 /* main thread */  + vtm->n_threads;
614
615   if ((error = vlib_call_init_function (vm, tls_init)))
616     return error;
617
618   if (tls_init_ca_chain ())
619     {
620       clib_warning ("failed to initialize TLS CA chain");
621       return 0;
622     }
623   if (tls_init_mem ())
624     {
625       clib_warning ("failed to initialize mem");
626       return 0;
627     }
628   if (tls_init_ctr_drbgs_and_entropy (num_threads))
629     {
630       clib_warning ("failed to initialize entropy and random generators");
631       return 0;
632     }
633
634   vec_validate (mm->ctx_pool, num_threads - 1);
635   vec_validate (mm->rx_bufs, num_threads - 1);
636   vec_validate (mm->tx_bufs, num_threads - 1);
637
638   tls_register_engine (&mbedtls_engine, TLS_ENGINE_MBEDTLS);
639   return 0;
640 }
641
642 VLIB_INIT_FUNCTION (tls_mbedtls_init);
643
644 /* *INDENT-OFF* */
645 VLIB_PLUGIN_REGISTER () = {
646     .version = VPP_BUILD_VER,
647     .description = "mbedtls based TLS Engine",
648 };
649 /* *INDENT-ON* */
650
651 /*
652  * fd.io coding-style-patch-verification: ON
653  *
654  * Local Variables:
655  * eval: (c-set-style "gnu")
656  * End:
657  */