FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
ipsecmb.c
Go to the documentation of this file.
1 /*
2  * ipsecmb.c - Intel IPSec Multi-buffer library Crypto Engine
3  *
4  * Copyright (c) 2019 Cisco Systemss
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 <fcntl.h>
19 
20 #include <intel-ipsec-mb.h>
21 
22 #include <vnet/vnet.h>
23 #include <vnet/plugin/plugin.h>
24 #include <vpp/app/version.h>
25 #include <vnet/crypto/crypto.h>
26 #include <vppinfra/cpu.h>
27 
28 #define HMAC_MAX_BLOCK_SIZE SHA_512_BLOCK_SIZE
29 #define EXPANDED_KEY_N_BYTES (16 * 15)
30 
31 typedef struct
32 {
33  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
34  MB_MGR *mgr;
35  __m128i cbc_iv;
37 
38 typedef struct
39 {
42  aes_gcm_pre_t aes_gcm_pre;
43  keyexp_t keyexp;
44  hash_one_block_t hash_one_block;
45  hash_fn_t hash_fn;
47 
48 typedef struct ipsecmb_main_t_
49 {
52  void **key_data;
54 
55 typedef struct
56 {
57  u8 enc_key_exp[EXPANDED_KEY_N_BYTES];
58  u8 dec_key_exp[EXPANDED_KEY_N_BYTES];
60 
62 
63 /*
64  * (Alg, JOB_HASH_ALG, fn, block-size-bytes, hash-size-bytes, digest-size-bytes)
65  */
66 #define foreach_ipsecmb_hmac_op \
67  _(SHA1, SHA1, sha1, 64, 20, 20) \
68  _(SHA224, SHA_224, sha224, 64, 32, 28) \
69  _(SHA256, SHA_256, sha256, 64, 32, 32) \
70  _(SHA384, SHA_384, sha384, 128, 64, 48) \
71  _(SHA512, SHA_512, sha512, 128, 64, 64)
72 
73 /*
74  * (Alg, key-len-bits, JOB_CIPHER_MODE)
75  */
76 #define foreach_ipsecmb_cipher_op \
77  _ (AES_128_CBC, 128, CBC) \
78  _ (AES_192_CBC, 192, CBC) \
79  _ (AES_256_CBC, 256, CBC) \
80  _ (AES_128_CTR, 128, CNTR) \
81  _ (AES_192_CTR, 192, CNTR) \
82  _ (AES_256_CTR, 256, CNTR)
83 
84 /*
85  * (Alg, key-len-bytes, iv-len-bytes)
86  */
87 #define foreach_ipsecmb_gcm_cipher_op \
88  _(AES_128_GCM, 128) \
89  _(AES_192_GCM, 192) \
90  _(AES_256_GCM, 256)
91 
93 ipsecmb_status_job (JOB_STS status)
94 {
95  switch (status)
96  {
97  case STS_COMPLETED:
98  return VNET_CRYPTO_OP_STATUS_COMPLETED;
99  case STS_BEING_PROCESSED:
100  case STS_COMPLETED_AES:
101  case STS_COMPLETED_HMAC:
102  return VNET_CRYPTO_OP_STATUS_WORK_IN_PROGRESS;
103  case STS_INVALID_ARGS:
104  case STS_INTERNAL_ERROR:
105  case STS_ERROR:
106  return VNET_CRYPTO_OP_STATUS_FAIL_ENGINE_ERR;
107  }
108  ASSERT (0);
109  return VNET_CRYPTO_OP_STATUS_FAIL_ENGINE_ERR;
110 }
111 
112 always_inline void
113 ipsecmb_retire_hmac_job (JOB_AES_HMAC * job, u32 * n_fail, u32 digest_size)
114 {
115  vnet_crypto_op_t *op = job->user_data;
116  u32 len = op->digest_len ? op->digest_len : digest_size;
117 
118  if (PREDICT_FALSE (STS_COMPLETED != job->status))
119  {
120  op->status = ipsecmb_status_job (job->status);
121  *n_fail = *n_fail + 1;
122  return;
123  }
124 
126  {
127  if ((memcmp (op->digest, job->auth_tag_output, len)))
128  {
129  *n_fail = *n_fail + 1;
130  op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC;
131  return;
132  }
133  }
134  else if (len == digest_size)
135  clib_memcpy_fast (op->digest, job->auth_tag_output, digest_size);
136  else
137  clib_memcpy_fast (op->digest, job->auth_tag_output, len);
138 
139  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
140 }
141 
144  u32 n_ops, u32 block_size, u32 hash_size,
145  u32 digest_size, JOB_HASH_ALG alg)
146 {
147  ipsecmb_main_t *imbm = &ipsecmb_main;
149  vm->thread_index);
150  JOB_AES_HMAC *job;
151  u32 i, n_fail = 0;
152  u8 scratch[n_ops][digest_size];
153 
154  /*
155  * queue all the jobs first ...
156  */
157  for (i = 0; i < n_ops; i++)
158  {
159  vnet_crypto_op_t *op = ops[i];
160  u8 *kd = (u8 *) imbm->key_data[op->key_index];
161 
162  job = IMB_GET_NEXT_JOB (ptd->mgr);
163 
164  job->src = op->src;
165  job->hash_start_src_offset_in_bytes = 0;
166  job->msg_len_to_hash_in_bytes = op->len;
167  job->hash_alg = alg;
168  job->auth_tag_output_len_in_bytes = digest_size;
169  job->auth_tag_output = scratch[i];
170 
171  job->cipher_mode = NULL_CIPHER;
172  job->cipher_direction = DECRYPT;
173  job->chain_order = HASH_CIPHER;
174 
175  job->u.HMAC._hashed_auth_key_xor_ipad = kd;
176  job->u.HMAC._hashed_auth_key_xor_opad = kd + hash_size;
177  job->user_data = op;
178 
179  job = IMB_SUBMIT_JOB (ptd->mgr);
180 
181  if (job)
182  ipsecmb_retire_hmac_job (job, &n_fail, digest_size);
183  }
184 
185  while ((job = IMB_FLUSH_JOB (ptd->mgr)))
186  ipsecmb_retire_hmac_job (job, &n_fail, digest_size);
187 
188  return n_ops - n_fail;
189 }
190 
191 #define _(a, b, c, d, e, f) \
192 static_always_inline u32 \
193 ipsecmb_ops_hmac_##a (vlib_main_t * vm, \
194  vnet_crypto_op_t * ops[], \
195  u32 n_ops) \
196 { return ipsecmb_ops_hmac_inline (vm, ops, n_ops, d, e, f, b); } \
197 
199 #undef _
200 
201 always_inline void
202 ipsecmb_retire_cipher_job (JOB_AES_HMAC * job, u32 * n_fail)
203 {
204  vnet_crypto_op_t *op = job->user_data;
205 
206  if (PREDICT_FALSE (STS_COMPLETED != job->status))
207  {
208  op->status = ipsecmb_status_job (job->status);
209  *n_fail = *n_fail + 1;
210  }
211  else
212  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
213 }
214 
217  u32 n_ops, u32 key_len,
218  JOB_CIPHER_DIRECTION direction,
219  JOB_CIPHER_MODE cipher_mode)
220 {
221  ipsecmb_main_t *imbm = &ipsecmb_main;
223  vm->thread_index);
224  JOB_AES_HMAC *job;
225  u32 i, n_fail = 0;
226 
227  for (i = 0; i < n_ops; i++)
228  {
230  vnet_crypto_op_t *op = ops[i];
231  kd = (ipsecmb_aes_key_data_t *) imbm->key_data[op->key_index];
232  __m128i iv;
233 
234  job = IMB_GET_NEXT_JOB (ptd->mgr);
235 
236  job->src = op->src;
237  job->dst = op->dst;
238  job->msg_len_to_cipher_in_bytes = op->len;
239  job->cipher_start_src_offset_in_bytes = 0;
240 
241  job->hash_alg = NULL_HASH;
242  job->cipher_mode = cipher_mode;
243  job->cipher_direction = direction;
244  job->chain_order = (direction == ENCRYPT ? CIPHER_HASH : HASH_CIPHER);
245 
246  if ((direction == ENCRYPT) && (op->flags & VNET_CRYPTO_OP_FLAG_INIT_IV))
247  {
248  iv = ptd->cbc_iv;
249  _mm_storeu_si128 ((__m128i *) op->iv, iv);
250  ptd->cbc_iv = _mm_aesenc_si128 (iv, iv);
251  }
252 
253  job->aes_key_len_in_bytes = key_len / 8;
254  job->aes_enc_key_expanded = kd->enc_key_exp;
255  job->aes_dec_key_expanded = kd->dec_key_exp;
256  job->iv = op->iv;
257  job->iv_len_in_bytes = AES_BLOCK_SIZE;
258 
259  job->user_data = op;
260 
261  job = IMB_SUBMIT_JOB (ptd->mgr);
262 
263  if (job)
264  ipsecmb_retire_cipher_job (job, &n_fail);
265  }
266 
267  while ((job = IMB_FLUSH_JOB (ptd->mgr)))
268  ipsecmb_retire_cipher_job (job, &n_fail);
269 
270  return n_ops - n_fail;
271 }
272 
273 #define _(a, b, c) \
274  static_always_inline u32 ipsecmb_ops_cipher_enc_##a ( \
275  vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops) \
276  { \
277  return ipsecmb_ops_aes_cipher_inline (vm, ops, n_ops, b, ENCRYPT, c); \
278  } \
279  \
280  static_always_inline u32 ipsecmb_ops_cipher_dec_##a ( \
281  vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops) \
282  { \
283  return ipsecmb_ops_aes_cipher_inline (vm, ops, n_ops, b, DECRYPT, c); \
284  }
285 
287 #undef _
288 
289 #define _(a, b) \
290 static_always_inline u32 \
291 ipsecmb_ops_gcm_cipher_enc_##a##_chained (vlib_main_t * vm, \
292  vnet_crypto_op_t * ops[], vnet_crypto_op_chunk_t *chunks, u32 n_ops) \
293 { \
294  ipsecmb_main_t *imbm = &ipsecmb_main; \
295  ipsecmb_per_thread_data_t *ptd = vec_elt_at_index (imbm->per_thread_data, \
296  vm->thread_index); \
297  MB_MGR *m = ptd->mgr; \
298  vnet_crypto_op_chunk_t *chp; \
299  u32 i, j; \
300  \
301  for (i = 0; i < n_ops; i++) \
302  { \
303  struct gcm_key_data *kd; \
304  struct gcm_context_data ctx; \
305  vnet_crypto_op_t *op = ops[i]; \
306  \
307  kd = (struct gcm_key_data *) imbm->key_data[op->key_index]; \
308  ASSERT (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS); \
309  IMB_AES##b##_GCM_INIT(m, kd, &ctx, op->iv, op->aad, op->aad_len); \
310  chp = chunks + op->chunk_index; \
311  for (j = 0; j < op->n_chunks; j++) \
312  { \
313  IMB_AES##b##_GCM_ENC_UPDATE (m, kd, &ctx, chp->dst, chp->src, \
314  chp->len); \
315  chp += 1; \
316  } \
317  IMB_AES##b##_GCM_ENC_FINALIZE(m, kd, &ctx, op->tag, op->tag_len); \
318  \
319  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; \
320  } \
321  \
322  return n_ops; \
323 } \
324  \
325 static_always_inline u32 \
326 ipsecmb_ops_gcm_cipher_enc_##a (vlib_main_t * vm, vnet_crypto_op_t * ops[], \
327  u32 n_ops) \
328 { \
329  ipsecmb_main_t *imbm = &ipsecmb_main; \
330  ipsecmb_per_thread_data_t *ptd = vec_elt_at_index (imbm->per_thread_data, \
331  vm->thread_index); \
332  MB_MGR *m = ptd->mgr; \
333  u32 i; \
334  \
335  for (i = 0; i < n_ops; i++) \
336  { \
337  struct gcm_key_data *kd; \
338  struct gcm_context_data ctx; \
339  vnet_crypto_op_t *op = ops[i]; \
340  \
341  kd = (struct gcm_key_data *) imbm->key_data[op->key_index]; \
342  IMB_AES##b##_GCM_ENC (m, kd, &ctx, op->dst, op->src, op->len, op->iv, \
343  op->aad, op->aad_len, op->tag, op->tag_len); \
344  \
345  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; \
346  } \
347  \
348  return n_ops; \
349 } \
350  \
351 static_always_inline u32 \
352 ipsecmb_ops_gcm_cipher_dec_##a##_chained (vlib_main_t * vm, \
353  vnet_crypto_op_t * ops[], vnet_crypto_op_chunk_t *chunks, u32 n_ops) \
354 { \
355  ipsecmb_main_t *imbm = &ipsecmb_main; \
356  ipsecmb_per_thread_data_t *ptd = vec_elt_at_index (imbm->per_thread_data, \
357  vm->thread_index); \
358  MB_MGR *m = ptd->mgr; \
359  vnet_crypto_op_chunk_t *chp; \
360  u32 i, j, n_failed = 0; \
361  \
362  for (i = 0; i < n_ops; i++) \
363  { \
364  struct gcm_key_data *kd; \
365  struct gcm_context_data ctx; \
366  vnet_crypto_op_t *op = ops[i]; \
367  u8 scratch[64]; \
368  \
369  kd = (struct gcm_key_data *) imbm->key_data[op->key_index]; \
370  ASSERT (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS); \
371  IMB_AES##b##_GCM_INIT(m, kd, &ctx, op->iv, op->aad, op->aad_len); \
372  chp = chunks + op->chunk_index; \
373  for (j = 0; j < op->n_chunks; j++) \
374  { \
375  IMB_AES##b##_GCM_DEC_UPDATE (m, kd, &ctx, chp->dst, chp->src, \
376  chp->len); \
377  chp += 1; \
378  } \
379  IMB_AES##b##_GCM_DEC_FINALIZE(m, kd, &ctx, scratch, op->tag_len); \
380  \
381  if ((memcmp (op->tag, scratch, op->tag_len))) \
382  { \
383  op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC; \
384  n_failed++; \
385  } \
386  else \
387  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; \
388  } \
389  \
390  return n_ops - n_failed; \
391 } \
392  \
393 static_always_inline u32 \
394 ipsecmb_ops_gcm_cipher_dec_##a (vlib_main_t * vm, vnet_crypto_op_t * ops[], \
395  u32 n_ops) \
396 { \
397  ipsecmb_main_t *imbm = &ipsecmb_main; \
398  ipsecmb_per_thread_data_t *ptd = vec_elt_at_index (imbm->per_thread_data, \
399  vm->thread_index); \
400  MB_MGR *m = ptd->mgr; \
401  u32 i, n_failed = 0; \
402  \
403  for (i = 0; i < n_ops; i++) \
404  { \
405  struct gcm_key_data *kd; \
406  struct gcm_context_data ctx; \
407  vnet_crypto_op_t *op = ops[i]; \
408  u8 scratch[64]; \
409  \
410  kd = (struct gcm_key_data *) imbm->key_data[op->key_index]; \
411  IMB_AES##b##_GCM_DEC (m, kd, &ctx, op->dst, op->src, op->len, op->iv, \
412  op->aad, op->aad_len, scratch, op->tag_len); \
413  \
414  if ((memcmp (op->tag, scratch, op->tag_len))) \
415  { \
416  op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC; \
417  n_failed++; \
418  } \
419  else \
420  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; \
421  } \
422  \
423  return n_ops - n_failed; \
424 }
425 
427 #undef _
428 
429 always_inline void
430 ipsecmb_retire_aead_job (JOB_AES_HMAC *job, u32 *n_fail)
431 {
432  vnet_crypto_op_t *op = job->user_data;
433  u32 len = op->tag_len;
434 
435  if (PREDICT_FALSE (STS_COMPLETED != job->status))
436  {
437  op->status = ipsecmb_status_job (job->status);
438  *n_fail = *n_fail + 1;
439  return;
440  }
441 
443  {
444  if (memcmp (op->tag, job->auth_tag_output, len))
445  {
446  *n_fail = *n_fail + 1;
447  op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC;
448  return;
449  }
450  }
451 
452  clib_memcpy_fast (op->tag, job->auth_tag_output, len);
453 
454  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
455 }
456 
459  IMB_CIPHER_DIRECTION dir)
460 {
461  ipsecmb_main_t *imbm = &ipsecmb_main;
464  struct IMB_JOB *job;
465  MB_MGR *m = ptd->mgr;
466  u32 i, n_fail = 0, last_key_index = ~0;
467  u8 scratch[VLIB_FRAME_SIZE][16];
468  u8 iv_data[16];
469  u8 *key = 0;
470 
471  for (i = 0; i < n_ops; i++)
472  {
473  vnet_crypto_op_t *op = ops[i];
474  __m128i iv;
475 
476  job = IMB_GET_NEXT_JOB (m);
477  if (last_key_index != op->key_index)
478  {
480 
481  key = kd->data;
482  last_key_index = op->key_index;
483  }
484 
485  job->cipher_direction = dir;
486  job->chain_order = IMB_ORDER_HASH_CIPHER;
487  job->cipher_mode = IMB_CIPHER_CHACHA20_POLY1305;
488  job->hash_alg = IMB_AUTH_CHACHA20_POLY1305;
489  job->enc_keys = job->dec_keys = key;
490  job->key_len_in_bytes = 32;
491 
492  job->u.CHACHA20_POLY1305.aad = op->aad;
493  job->u.CHACHA20_POLY1305.aad_len_in_bytes = op->aad_len;
494  job->src = op->src;
495  job->dst = op->dst;
496 
497  if ((dir == IMB_DIR_ENCRYPT) &&
499  {
500  iv = ptd->cbc_iv;
501  _mm_storeu_si128 ((__m128i *) iv_data, iv);
502  clib_memcpy_fast (op->iv, iv_data, 12);
503  ptd->cbc_iv = _mm_aesenc_si128 (iv, iv);
504  }
505 
506  job->iv = op->iv;
507  job->iv_len_in_bytes = 12;
508  job->msg_len_to_cipher_in_bytes = job->msg_len_to_hash_in_bytes =
509  op->len;
510  job->cipher_start_src_offset_in_bytes =
511  job->hash_start_src_offset_in_bytes = 0;
512 
513  job->auth_tag_output = scratch[i];
514  job->auth_tag_output_len_in_bytes = 16;
515 
516  job->user_data = op;
517 
518  job = IMB_SUBMIT_JOB_NOCHECK (ptd->mgr);
519  if (job)
520  ipsecmb_retire_aead_job (job, &n_fail);
521 
522  op++;
523  }
524 
525  while ((job = IMB_FLUSH_JOB (ptd->mgr)))
526  ipsecmb_retire_aead_job (job, &n_fail);
527 
528  return n_ops - n_fail;
529 }
530 
533  u32 n_ops)
534 {
535  return ipsecmb_ops_chacha_poly (vm, ops, n_ops, IMB_DIR_ENCRYPT);
536 }
537 
540  u32 n_ops)
541 {
542  return ipsecmb_ops_chacha_poly (vm, ops, n_ops, IMB_DIR_DECRYPT);
543 }
544 
547  vnet_crypto_op_chunk_t *chunks, u32 n_ops,
548  IMB_CIPHER_DIRECTION dir)
549 {
550  ipsecmb_main_t *imbm = &ipsecmb_main;
553  MB_MGR *m = ptd->mgr;
554  u32 i, n_fail = 0, last_key_index = ~0;
555  u8 iv_data[16];
556  u8 *key = 0;
557 
558  if (dir == IMB_DIR_ENCRYPT)
559  {
560  for (i = 0; i < n_ops; i++)
561  {
562  vnet_crypto_op_t *op = ops[i];
563  struct chacha20_poly1305_context_data ctx;
565  __m128i iv;
566  u32 j;
567 
569 
570  if (last_key_index != op->key_index)
571  {
573 
574  key = kd->data;
575  last_key_index = op->key_index;
576  }
577 
579  {
580  iv = ptd->cbc_iv;
581  _mm_storeu_si128 ((__m128i *) iv_data, iv);
582  clib_memcpy_fast (op->iv, iv_data, 12);
583  ptd->cbc_iv = _mm_aesenc_si128 (iv, iv);
584  }
585 
586  IMB_CHACHA20_POLY1305_INIT (m, key, &ctx, op->iv, op->aad,
587  op->aad_len);
588 
589  chp = chunks + op->chunk_index;
590  for (j = 0; j < op->n_chunks; j++)
591  {
592  IMB_CHACHA20_POLY1305_ENC_UPDATE (m, key, &ctx, chp->dst,
593  chp->src, chp->len);
594  chp += 1;
595  }
596 
597  IMB_CHACHA20_POLY1305_ENC_FINALIZE (m, &ctx, op->tag, op->tag_len);
598 
599  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
600  }
601  }
602  else /* dir == IMB_DIR_DECRYPT */
603  {
604  for (i = 0; i < n_ops; i++)
605  {
606  vnet_crypto_op_t *op = ops[i];
607  struct chacha20_poly1305_context_data ctx;
609  u8 scratch[16];
610  u32 j;
611 
613 
614  if (last_key_index != op->key_index)
615  {
617 
618  key = kd->data;
619  last_key_index = op->key_index;
620  }
621 
622  IMB_CHACHA20_POLY1305_INIT (m, key, &ctx, op->iv, op->aad,
623  op->aad_len);
624 
625  chp = chunks + op->chunk_index;
626  for (j = 0; j < op->n_chunks; j++)
627  {
628  IMB_CHACHA20_POLY1305_DEC_UPDATE (m, key, &ctx, chp->dst,
629  chp->src, chp->len);
630  chp += 1;
631  }
632 
633  IMB_CHACHA20_POLY1305_DEC_FINALIZE (m, &ctx, scratch, op->tag_len);
634 
635  if (memcmp (op->tag, scratch, op->tag_len))
636  {
637  n_fail = n_fail + 1;
638  op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC;
639  }
640  else
641  op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
642  }
643  }
644 
645  return n_ops - n_fail;
646 }
647 
650  vnet_crypto_op_chunk_t *chunks,
651  u32 n_ops)
652 {
653  return ipsecmb_ops_chacha_poly_chained (vm, ops, chunks, n_ops,
654  IMB_DIR_ENCRYPT);
655 }
656 
659  vnet_crypto_op_chunk_t *chunks,
660  u32 n_ops)
661 {
662  return ipsecmb_ops_chacha_poly_chained (vm, ops, chunks, n_ops,
663  IMB_DIR_DECRYPT);
664 }
665 
666 clib_error_t *
668 {
670  clib_error_t *err = 0;
671  int fd;
672 
673  if ((fd = open ("/dev/urandom", O_RDONLY)) < 0)
674  return clib_error_return_unix (0, "failed to open '/dev/urandom'");
675 
676  vec_foreach (ptd, imbm->per_thread_data)
677  {
678  if (read (fd, &ptd->cbc_iv, sizeof (ptd->cbc_iv)) != sizeof (ptd->cbc_iv))
679  {
680  err = clib_error_return_unix (0, "'/dev/urandom' read failure");
681  close (fd);
682  return (err);
683  }
684  }
685 
686  close (fd);
687  return (NULL);
688 }
689 
690 static void
693 {
694  ipsecmb_main_t *imbm = &ipsecmb_main;
696  ipsecmb_alg_data_t *ad = imbm->alg_data + key->alg;
697  u32 i;
698  void *kd;
699 
700  /** TODO: add linked alg support **/
701  if (key->type == VNET_CRYPTO_KEY_TYPE_LINK)
702  return;
703 
704  if (kop == VNET_CRYPTO_KEY_OP_DEL)
705  {
706  if (idx >= vec_len (imbm->key_data))
707  return;
708 
709  if (imbm->key_data[idx] == 0)
710  return;
711 
712  clib_mem_free_s (imbm->key_data[idx]);
713  imbm->key_data[idx] = 0;
714  return;
715  }
716 
717  if (ad->data_size == 0)
718  return;
719 
721 
722  if (kop == VNET_CRYPTO_KEY_OP_MODIFY && imbm->key_data[idx])
723  {
724  clib_mem_free_s (imbm->key_data[idx]);
725  }
726 
727  kd = imbm->key_data[idx] = clib_mem_alloc_aligned (ad->data_size,
729 
730  /* AES CBC key expansion */
731  if (ad->keyexp)
732  {
733  ad->keyexp (key->data, ((ipsecmb_aes_key_data_t *) kd)->enc_key_exp,
734  ((ipsecmb_aes_key_data_t *) kd)->dec_key_exp);
735  return;
736  }
737 
738  /* AES GCM */
739  if (ad->aes_gcm_pre)
740  {
741  ad->aes_gcm_pre (key->data, (struct gcm_key_data *) kd);
742  return;
743  }
744 
745  /* HMAC */
746  if (ad->hash_one_block)
747  {
748  const int block_qw = HMAC_MAX_BLOCK_SIZE / sizeof (u64);
749  u64 pad[block_qw], key_hash[block_qw];
750 
751  clib_memset_u8 (key_hash, 0, HMAC_MAX_BLOCK_SIZE);
752  if (vec_len (key->data) <= ad->block_size)
753  clib_memcpy_fast (key_hash, key->data, vec_len (key->data));
754  else
755  ad->hash_fn (key->data, vec_len (key->data), key_hash);
756 
757  for (i = 0; i < block_qw; i++)
758  pad[i] = key_hash[i] ^ 0x3636363636363636;
759  ad->hash_one_block (pad, kd);
760 
761  for (i = 0; i < block_qw; i++)
762  pad[i] = key_hash[i] ^ 0x5c5c5c5c5c5c5c5c;
763  ad->hash_one_block (pad, ((u8 *) kd) + (ad->data_size / 2));
764 
765  return;
766  }
767 }
768 
769 static clib_error_t *
771 {
772  ipsecmb_main_t *imbm = &ipsecmb_main;
773  ipsecmb_alg_data_t *ad;
777  MB_MGR *m = 0;
778  u32 eidx;
779  u8 *name;
780 
781  if (!clib_cpu_supports_aes ())
782  return 0;
783 
784  /*
785  * A priority that is better than OpenSSL but worse than VPP natvie
786  */
787  name = format (0, "Intel(R) Multi-Buffer Crypto for IPsec Library %s%c",
788  IMB_VERSION_STR, 0);
789  eidx = vnet_crypto_register_engine (vm, "ipsecmb", 80, (char *) name);
790 
793 
794  /* *INDENT-OFF* */
795  vec_foreach (ptd, imbm->per_thread_data)
796  {
797  ptd->mgr = alloc_mb_mgr (0);
798  if (clib_cpu_supports_avx512f ())
799  init_mb_mgr_avx512 (ptd->mgr);
800  else if (clib_cpu_supports_avx2 ())
801  init_mb_mgr_avx2 (ptd->mgr);
802  else
803  init_mb_mgr_sse (ptd->mgr);
804 
805  if (ptd == imbm->per_thread_data)
806  m = ptd->mgr;
807  }
808  /* *INDENT-ON* */
809 
810  if (clib_cpu_supports_x86_aes () && (error = crypto_ipsecmb_iv_init (imbm)))
811  return (error);
812 
813 #define _(a, b, c, d, e, f) \
814  vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_HMAC, \
815  ipsecmb_ops_hmac_##a); \
816  ad = imbm->alg_data + VNET_CRYPTO_ALG_HMAC_##a; \
817  ad->block_size = d; \
818  ad->data_size = e * 2; \
819  ad->hash_one_block = m-> c##_one_block; \
820  ad->hash_fn = m-> c; \
821 
823 #undef _
824 #define _(a, b, c) \
825  vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_ENC, \
826  ipsecmb_ops_cipher_enc_##a); \
827  vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_DEC, \
828  ipsecmb_ops_cipher_dec_##a); \
829  ad = imbm->alg_data + VNET_CRYPTO_ALG_##a; \
830  ad->data_size = sizeof (ipsecmb_aes_key_data_t); \
831  ad->keyexp = m->keyexp_##b;
832 
834 #undef _
835 #define _(a, b) \
836  vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_ENC, \
837  ipsecmb_ops_gcm_cipher_enc_##a); \
838  vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_DEC, \
839  ipsecmb_ops_gcm_cipher_dec_##a); \
840  vnet_crypto_register_chained_ops_handler \
841  (vm, eidx, VNET_CRYPTO_OP_##a##_ENC, \
842  ipsecmb_ops_gcm_cipher_enc_##a##_chained); \
843  vnet_crypto_register_chained_ops_handler \
844  (vm, eidx, VNET_CRYPTO_OP_##a##_DEC, \
845  ipsecmb_ops_gcm_cipher_dec_##a##_chained); \
846  ad = imbm->alg_data + VNET_CRYPTO_ALG_##a; \
847  ad->data_size = sizeof (struct gcm_key_data); \
848  ad->aes_gcm_pre = m->gcm##b##_pre; \
849 
851 #undef _
852 
854  VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC,
857  VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC,
860  vm, eidx, VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC,
863  vm, eidx, VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC,
865  ad = imbm->alg_data + VNET_CRYPTO_ALG_CHACHA20_POLY1305;
866  ad->data_size = 0;
867 
869  return (NULL);
870 }
871 
872 /* *INDENT-OFF* */
874 {
875  .runs_after = VLIB_INITS ("vnet_crypto_init"),
876 };
877 /* *INDENT-ON* */
878 
879 /* *INDENT-OFF* */
881 {
882  .version = VPP_BUILD_VER,
883  .description = "Intel IPSEC Multi-buffer Crypto Engine",
884 };
885 /* *INDENT-ON* */
886 
887 /*
888  * fd.io coding-style-patch-verification: ON
889  *
890  * Local Variables:
891  * eval: (c-set-style "gnu")
892  * End:
893  */
ipsecmb_main
static ipsecmb_main_t ipsecmb_main
Definition: ipsecmb.c:61
VNET_CRYPTO_KEY_OP_DEL
@ VNET_CRYPTO_KEY_OP_DEL
Definition: crypto.h:132
vnet_crypto_op_t::digest
u8 * digest
Definition: crypto.h:299
vnet_crypto_op_t::digest_len
u8 digest_len
Definition: crypto.h:268
vnet_crypto_op_t::tag
u8 * tag
Definition: crypto.h:298
crypto.h
VNET_CRYPTO_KEY_OP_MODIFY
@ VNET_CRYPTO_KEY_OP_MODIFY
Definition: crypto.h:133
ipsecmb_alg_data_t::aes_gcm_pre
aes_gcm_pre_t aes_gcm_pre
Definition: ipsecmb.c:42
ipsecmb_ops_hmac_inline
static_always_inline u32 ipsecmb_ops_hmac_inline(vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops, u32 block_size, u32 hash_size, u32 digest_size, JOB_HASH_ALG alg)
Definition: ipsecmb.c:143
ipsecmb_retire_cipher_job
static void ipsecmb_retire_cipher_job(JOB_AES_HMAC *job, u32 *n_fail)
Definition: ipsecmb.c:202
vnet_crypto_register_ops_handler
void vnet_crypto_register_ops_handler(vlib_main_t *vm, u32 engine_index, vnet_crypto_op_id_t opt, vnet_crypto_ops_handler_t *fn)
Definition: crypto.c:252
CLIB_CACHE_LINE_ALIGN_MARK
#define CLIB_CACHE_LINE_ALIGN_MARK(mark)
Definition: cache.h:60
name
string name[64]
Definition: fib.api:25
ipsecmb_ops_chacha_poly_chained
static_always_inline u32 ipsecmb_ops_chacha_poly_chained(vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, u32 n_ops, IMB_CIPHER_DIRECTION dir)
Definition: ipsecmb.c:546
vnet_crypto_op_t::status
vnet_crypto_op_status_t status
Definition: crypto.h:260
HMAC_MAX_BLOCK_SIZE
#define HMAC_MAX_BLOCK_SIZE
Definition: ipsecmb.c:28
VLIB_FRAME_SIZE
#define VLIB_FRAME_SIZE
Definition: node.h:368
ipsecmb_retire_aead_job
static void ipsecmb_retire_aead_job(JOB_AES_HMAC *job, u32 *n_fail)
Definition: ipsecmb.c:430
ipsecmb_status_job
static_always_inline vnet_crypto_op_status_t ipsecmb_status_job(JOB_STS status)
Definition: ipsecmb.c:93
crypto_ipsecmb_init
static clib_error_t * crypto_ipsecmb_init(vlib_main_t *vm)
Definition: ipsecmb.c:770
vnet_crypto_op_t::src
u8 * src
Definition: crypto.h:277
ipsecmb_aes_key_data_t::enc_key_exp
u8 enc_key_exp[EXPANDED_KEY_N_BYTES]
Definition: ipsecmb.c:57
u16
unsigned short u16
Definition: types.h:57
vnet_crypto_op_t::dst
u8 * dst
Definition: crypto.h:278
vnet_crypto_key_index_t
u32 vnet_crypto_key_index_t
Definition: crypto.h:378
block_size
u16 block_size
Definition: ikev2_types.api:97
vnet_crypto_register_chained_ops_handler
void vnet_crypto_register_chained_ops_handler(vlib_main_t *vm, u32 engine_index, vnet_crypto_op_id_t opt, vnet_crypto_chained_ops_handler_t *fn)
Definition: crypto.c:260
ipsecmb_aes_key_data_t
Definition: ipsecmb.c:55
vnet_crypto_op_t::user_data
uword user_data
Definition: crypto.h:258
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
ipsecmb_ops_chacha_poly
static_always_inline u32 ipsecmb_ops_chacha_poly(vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops, IMB_CIPHER_DIRECTION dir)
Definition: ipsecmb.c:458
vnet_crypto_op_t::iv
u8 * iv
Definition: crypto.h:293
VNET_CRYPTO_OP_FLAG_INIT_IV
#define VNET_CRYPTO_OP_FLAG_INIT_IV
Definition: crypto.h:262
vnet_crypto_key_t::data
u8 * data
Definition: crypto.h:204
crypto_ipsecmb_key_handler
static void crypto_ipsecmb_key_handler(vlib_main_t *vm, vnet_crypto_key_op_t kop, vnet_crypto_key_index_t idx)
Definition: ipsecmb.c:691
vnet_crypto_op_t::len
u32 len
Definition: crypto.h:287
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
error
Definition: cJSON.c:88
vnet_crypto_register_engine
u32 vnet_crypto_register_engine(vlib_main_t *vm, char *name, int prio, char *desc)
Definition: crypto.c:112
vnet_crypto_op_t::aad_len
u16 aad_len
Definition: crypto.h:271
key
typedef key
Definition: ipsec_types.api:91
ipsecmb_main_t_::alg_data
ipsecmb_alg_data_t alg_data[VNET_CRYPTO_N_ALGS]
Definition: ipsecmb.c:51
vnet_crypto_op_t
Definition: crypto.h:255
vnet_crypto_op_t::flags
u8 flags
Definition: crypto.h:261
ipsecmb_main_t_::per_thread_data
ipsecmb_per_thread_data_t * per_thread_data
Definition: ipsecmb.c:50
vnet_crypto_op_t::key_index
u32 key_index
Definition: crypto.h:292
ipsecmb_main_t_::key_data
void ** key_data
Definition: ipsecmb.c:52
ipsecmb_alg_data_t
Definition: ipsecmb.c:38
vnet_crypto_op_t::chunk_index
u32 chunk_index
Definition: crypto.h:289
VNET_CRYPTO_OP_FLAG_HMAC_CHECK
#define VNET_CRYPTO_OP_FLAG_HMAC_CHECK
Definition: crypto.h:263
vlib_thread_main_t::n_vlib_mains
u32 n_vlib_mains
Definition: threads.h:262
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
ipsecmb_alg_data_t::keyexp
keyexp_t keyexp
Definition: ipsecmb.c:43
ipsecmb_ops_chacha_poly_enc
static_always_inline u32 ipsecmb_ops_chacha_poly_enc(vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops)
Definition: ipsecmb.c:532
len
u8 len
Definition: ip_types.api:103
ipsecmb_per_thread_data_t::mgr
MB_MGR * mgr
Definition: ipsecmb.c:34
VLIB_PLUGIN_REGISTER
VLIB_PLUGIN_REGISTER()
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
foreach_ipsecmb_cipher_op
#define foreach_ipsecmb_cipher_op
Definition: ipsecmb.c:76
vec_validate_aligned
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:534
VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS
#define VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS
Definition: crypto.h:264
static_always_inline
#define static_always_inline
Definition: clib.h:112
clib_mem_free_s
static void clib_mem_free_s(void *p)
Definition: mem.h:353
VNET_CRYPTO_N_ALGS
@ VNET_CRYPTO_N_ALGS
Definition: crypto.h:157
vlib_main_t::thread_index
u32 thread_index
Definition: main.h:215
ipsecmb_alg_data_t::hash_one_block
hash_one_block_t hash_one_block
Definition: ipsecmb.c:44
ipsecmb_main_t_
Definition: ipsecmb.c:48
vnet_crypto_get_key
static_always_inline vnet_crypto_key_t * vnet_crypto_get_key(vnet_crypto_key_index_t index)
Definition: crypto.h:548
ipsecmb_ops_chacha_poly_dec
static_always_inline u32 ipsecmb_ops_chacha_poly_dec(vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops)
Definition: ipsecmb.c:539
vnet_crypto_op_chunk_t
Definition: crypto.h:248
EXPANDED_KEY_N_BYTES
#define EXPANDED_KEY_N_BYTES
Definition: ipsecmb.c:29
CLIB_CACHE_LINE_BYTES
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:58
cpu.h
clib_memset_u8
static_always_inline void clib_memset_u8(void *p, u8 val, uword count)
Definition: string.h:441
ipsecmb_aes_key_data_t::dec_key_exp
u8 dec_key_exp[EXPANDED_KEY_N_BYTES]
Definition: ipsecmb.c:58
ipsec_mb_ops_chacha_poly_enc_chained
static_always_inline u32 ipsec_mb_ops_chacha_poly_enc_chained(vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, u32 n_ops)
Definition: ipsecmb.c:649
plugin.h
vnet_crypto_op_t::n_chunks
u16 n_chunks
Definition: crypto.h:282
always_inline
#define always_inline
Definition: rdma_mlx5dv.h:23
vnet_crypto_op_t::tag_len
u8 tag_len
Definition: crypto.h:269
vnet_crypto_register_key_handler
void vnet_crypto_register_key_handler(vlib_main_t *vm, u32 engine_index, vnet_crypto_key_handler_t *key_handler)
Definition: crypto.c:316
ipsecmb_main_t
struct ipsecmb_main_t_ ipsecmb_main_t
u64
unsigned long u64
Definition: types.h:89
ipsecmb_per_thread_data_t
Definition: ipsecmb.c:31
vnet_crypto_op_t::aad
u8 * aad
Definition: crypto.h:294
format
description fragment has unexpected format
Definition: map.api:433
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
ipsec_mb_ops_chacha_poly_dec_chained
static_always_inline u32 ipsec_mb_ops_chacha_poly_dec_chained(vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, u32 n_ops)
Definition: ipsecmb.c:658
vnet_crypto_key_t
Definition: crypto.h:198
u32
unsigned int u32
Definition: types.h:88
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
clib_cpu_supports_aes
static foreach_aarch64_flags int clib_cpu_supports_aes()
Definition: cpu.h:225
ipsecmb_alg_data_t::hash_fn
hash_fn_t hash_fn
Definition: ipsecmb.c:45
vlib_thread_main_t
Definition: threads.h:243
ipsecmb_retire_hmac_job
static void ipsecmb_retire_hmac_job(JOB_AES_HMAC *job, u32 *n_fail, u32 digest_size)
Definition: ipsecmb.c:113
ctx
long ctx[MAX_CONNS]
Definition: main.c:144
ipsecmb_per_thread_data_t::cbc_iv
__m128i cbc_iv
Definition: ipsecmb.c:35
crypto_ipsecmb_iv_init
clib_error_t * crypto_ipsecmb_iv_init(ipsecmb_main_t *imbm)
Definition: ipsecmb.c:667
vec_foreach
#define vec_foreach(var, vec)
Vector iterator.
Definition: vec_bootstrap.h:213
clib_error_return_unix
#define clib_error_return_unix(e, args...)
Definition: error.h:102
iv
static u8 iv[]
Definition: aes_cbc.c:24
vnet_crypto_key_op_t
vnet_crypto_key_op_t
Definition: crypto.h:129
ipsecmb_alg_data_t::block_size
u8 block_size
Definition: ipsecmb.c:41
vlib_main_t
Definition: main.h:102
VLIB_INITS
#define VLIB_INITS(...)
Definition: init.h:352
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
ipsecmb_ops_aes_cipher_inline
static_always_inline u32 ipsecmb_ops_aes_cipher_inline(vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops, u32 key_len, JOB_CIPHER_DIRECTION direction, JOB_CIPHER_MODE cipher_mode)
Definition: ipsecmb.c:216
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
i
int i
Definition: flowhash_template.h:376
clib_mem_alloc_aligned
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:264
key_len
u16 key_len
Definition: ikev2_types.api:95
foreach_ipsecmb_gcm_cipher_op
#define foreach_ipsecmb_gcm_cipher_op
Definition: ipsecmb.c:87
pad
u8 pad[3]
log2 (size of the packing page block)
Definition: bihash_doc.h:61
vnet.h
foreach_ipsecmb_hmac_op
#define foreach_ipsecmb_hmac_op
Definition: ipsecmb.c:66
vlib_get_thread_main
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:56
direction
direction
Definition: interface_types.api:76
VNET_CRYPTO_KEY_TYPE_LINK
#define VNET_CRYPTO_KEY_TYPE_LINK
Definition: crypto.h:215
ipsecmb_alg_data_t::data_size
u16 data_size
Definition: ipsecmb.c:40
vnet_crypto_op_status_t
vnet_crypto_op_status_t
Definition: crypto.h:136