Line data Source code
1 : /*
2 : * Copyright (c) 2019 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 : #include <vlib/vlib.h>
16 : #include <vppinfra/time.h>
17 : #include <vppinfra/cache.h>
18 : #include <vppinfra/error.h>
19 : #include <vnet/crypto/crypto.h>
20 : #include <unittest/crypto/crypto.h>
21 :
22 : crypto_test_main_t crypto_test_main;
23 :
24 : static int
25 260 : sort_registrations (void *a0, void *a1)
26 : {
27 260 : unittest_crypto_test_registration_t **r0 = a0;
28 260 : unittest_crypto_test_registration_t **r1 = a1;
29 :
30 260 : return (strncmp (r0[0]->name, r1[0]->name, 256));
31 : }
32 :
33 : static void
34 3 : print_results (vlib_main_t * vm, unittest_crypto_test_registration_t ** rv,
35 : vnet_crypto_op_t * ops, vnet_crypto_op_chunk_t * chunks,
36 : u32 n_ops, crypto_test_main_t * tm)
37 : {
38 : int i;
39 : unittest_crypto_test_registration_t *r;
40 : vnet_crypto_op_chunk_t *chp;
41 3 : u8 *s = 0, *err = 0;
42 : vnet_crypto_op_t *op;
43 :
44 101 : vec_foreach (op, ops)
45 : {
46 98 : int fail = 0;
47 98 : r = rv[op->user_data];
48 98 : unittest_crypto_test_data_t *exp_pt = 0, *exp_ct = 0, exp_pt_data;
49 98 : unittest_crypto_test_data_t *exp_digest = 0, *exp_tag = 0;
50 98 : unittest_crypto_test_data_t *exp_pt_chunks = 0, *exp_ct_chunks = 0;
51 :
52 98 : switch (vnet_crypto_get_op_type (op->op))
53 : {
54 12 : case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
55 12 : exp_tag = &r->tag;
56 : /* fall through */
57 19 : case VNET_CRYPTO_OP_TYPE_ENCRYPT:
58 19 : exp_ct = &r->ciphertext;
59 19 : exp_ct_chunks = r->ct_chunks;
60 19 : break;
61 27 : case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
62 : case VNET_CRYPTO_OP_TYPE_DECRYPT:
63 27 : if (r->plaintext_incremental)
64 : {
65 8 : exp_pt_data.length = r->plaintext_incremental;
66 8 : exp_pt_data.data = tm->inc_data;
67 8 : exp_pt = &exp_pt_data;
68 : }
69 : else
70 : {
71 19 : exp_pt = &r->plaintext;
72 19 : exp_pt_chunks = r->pt_chunks;
73 : }
74 27 : break;
75 47 : case VNET_CRYPTO_OP_TYPE_HMAC:
76 47 : exp_digest = &r->digest;
77 47 : break;
78 5 : case VNET_CRYPTO_OP_TYPE_HASH:
79 5 : exp_digest = &r->digest;
80 5 : break;
81 0 : default:
82 0 : ASSERT (0);
83 : }
84 :
85 98 : vec_reset_length (err);
86 :
87 98 : if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
88 0 : err = format (err, "%sengine error: %U", vec_len (err) ? ", " : "",
89 0 : format_vnet_crypto_op_status, op->status);
90 :
91 98 : if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
92 : {
93 7 : if (exp_ct_chunks)
94 : {
95 2 : chp = vec_elt_at_index (chunks, op->chunk_index);
96 7 : for (i = 0; i < op->n_chunks; i++)
97 : {
98 5 : if (memcmp (chp->dst, exp_ct_chunks[i].data, chp->len))
99 0 : err = format (err, "%sciphertext mismatch [chunk %d]",
100 0 : vec_len (err) ? ", " : "", i);
101 5 : chp += 1;
102 : }
103 : }
104 :
105 7 : if (exp_pt_chunks)
106 : {
107 2 : chp = vec_elt_at_index (chunks, op->chunk_index);
108 7 : for (i = 0; i < op->n_chunks; i++)
109 : {
110 5 : if (memcmp (chp->dst, exp_pt_chunks[i].data, chp->len))
111 0 : err = format (err, "%splaintext mismatch [chunk %d]",
112 0 : vec_len (err) ? ", " : "", i);
113 5 : chp += 1;
114 : }
115 : }
116 : }
117 : else
118 : {
119 91 : if (exp_ct && memcmp (op->dst, exp_ct->data, exp_ct->length) != 0)
120 0 : err = format (err, "%sciphertext mismatch",
121 0 : vec_len (err) ? ", " : "");
122 :
123 91 : if (exp_pt && memcmp (op->dst, exp_pt->data, exp_pt->length) != 0)
124 0 : err = format (err, "%splaintext mismatch",
125 0 : vec_len (err) ? ", " : "");
126 : }
127 :
128 98 : if (exp_tag && memcmp (op->tag, exp_tag->data, exp_tag->length) != 0)
129 0 : err = format (err, "%stag mismatch", vec_len (err) ? ", " : "");
130 :
131 98 : if (exp_digest &&
132 52 : memcmp (op->digest, exp_digest->data, exp_digest->length) != 0)
133 0 : err = format (err, "%sdigest mismatch", vec_len (err) ? ", " : "");
134 :
135 98 : vec_reset_length (s);
136 196 : s = format (s, "%s (%U)", r->name, format_vnet_crypto_op, op->op,
137 98 : r->is_chained);
138 :
139 98 : if (vec_len (err))
140 0 : fail = 1;
141 :
142 98 : vlib_cli_output (vm, "%-60v%s%v", s, vec_len (err) ? "FAIL: " : "OK",
143 : err);
144 98 : if (tm->verbose)
145 : {
146 0 : if (tm->verbose == 2)
147 0 : fail = 1;
148 :
149 0 : if (exp_ct && fail)
150 0 : vlib_cli_output (vm, "Expected ciphertext:\n%U"
151 : "\nCalculated ciphertext:\n%U",
152 : format_hexdump, exp_ct->data, exp_ct->length,
153 : format_hexdump, op->dst, exp_ct->length);
154 0 : if (exp_pt && fail)
155 0 : vlib_cli_output (vm, "Expected plaintext:\n%U"
156 : "\nCalculated plaintext:\n%U",
157 : format_hexdump, exp_pt->data, exp_pt->length,
158 : format_hexdump, op->dst, exp_pt->length);
159 0 : if (r->tag.length && fail)
160 0 : vlib_cli_output (vm, "Expected tag:\n%U"
161 : "\nCalculated tag:\n%U",
162 : format_hexdump, r->tag.data, r->tag.length,
163 0 : format_hexdump, op->tag, op->tag_len);
164 0 : if (exp_digest && fail)
165 0 : vlib_cli_output (vm, "Expected digest:\n%U"
166 : "\nCalculated Digest:\n%U",
167 : format_hexdump, exp_digest->data,
168 : exp_digest->length, format_hexdump, op->digest,
169 0 : op->digest_len);
170 : }
171 : }
172 3 : vec_free (err);
173 3 : vec_free (s);
174 3 : }
175 :
176 : static void
177 1 : validate_data (u8 ** data, u32 len)
178 : {
179 : u32 i, diff, old_len;
180 1 : if (vec_len (data[0]) >= len)
181 0 : return;
182 :
183 1 : old_len = vec_len (data[0]);
184 1 : diff = len - vec_len (data[0]);
185 1 : vec_validate (data[0], old_len + diff - 1);
186 2049 : for (i = old_len; i < len; i++)
187 2048 : data[0][i] = (u8) i;
188 : }
189 :
190 : static void
191 1 : generate_digest (vlib_main_t * vm,
192 : unittest_crypto_test_registration_t * r,
193 : vnet_crypto_op_id_t id)
194 : {
195 1 : crypto_test_main_t *cm = &crypto_test_main;
196 : vnet_crypto_op_t op[1];
197 1 : vnet_crypto_op_init (op, id);
198 1 : vec_validate (r->digest.data, r->digest.length - 1);
199 1 : op->src = cm->inc_data;
200 1 : op->len = r->plaintext_incremental;
201 1 : op->digest = r->digest.data;
202 1 : op->digest_len = r->digest.length;
203 2 : op->key_index = vnet_crypto_key_add (vm, r->alg,
204 1 : cm->inc_data, r->key.length);
205 :
206 : /* at this point openssl is set for each algo */
207 1 : vnet_crypto_process_ops (vm, op, 1);
208 1 : }
209 :
210 : static int
211 1 : restore_engines (u32 * engs)
212 : {
213 1 : vnet_crypto_main_t *cm = &crypto_main;
214 : u32 i;
215 : vnet_crypto_engine_t *ce;
216 :
217 36 : for (i = 1; i < VNET_CRYPTO_N_OP_IDS; i++)
218 : {
219 35 : vnet_crypto_op_data_t *od = &cm->opt_data[i];
220 :
221 35 : if (engs[i] != ~0)
222 : {
223 35 : ce = vec_elt_at_index (cm->engines, engs[i]);
224 35 : od->active_engine_index_simple = engs[i];
225 35 : cm->ops_handlers[i] = ce->ops_handlers[i];
226 : }
227 : }
228 :
229 1 : return 0;
230 : }
231 :
232 : static int
233 1 : save_current_engines (u32 * engs)
234 : {
235 1 : vnet_crypto_main_t *cm = &crypto_main;
236 : uword *p;
237 : u32 i;
238 : vnet_crypto_engine_t *ce;
239 :
240 1 : p = hash_get_mem (cm->engine_index_by_name, "openssl");
241 1 : if (!p)
242 0 : return -1;
243 :
244 1 : ce = vec_elt_at_index (cm->engines, p[0]);
245 :
246 : /* set openssl for all crypto algs to generate expected data */
247 36 : for (i = 1; i < VNET_CRYPTO_N_OP_IDS; i++)
248 : {
249 35 : vnet_crypto_op_data_t *od = &cm->opt_data[i];
250 35 : if (od->active_engine_index_simple != ~0)
251 : {
252 : /* save engine index */
253 35 : engs[i] = od->active_engine_index_simple;
254 35 : od->active_engine_index_simple = ce - cm->engines;
255 35 : cm->ops_handlers[i] = ce->ops_handlers[i];
256 : }
257 : }
258 :
259 1 : return 0;
260 : }
261 :
262 : static clib_error_t *
263 1 : test_crypto_incremental (vlib_main_t * vm, crypto_test_main_t * tm,
264 : unittest_crypto_test_registration_t ** rv, u32 n_ops,
265 : u32 computed_data_total_len)
266 : {
267 1 : vnet_crypto_main_t *cm = &crypto_main;
268 : vnet_crypto_alg_data_t *ad;
269 1 : vnet_crypto_key_index_t *key_indices = 0;
270 : u32 i;
271 : unittest_crypto_test_registration_t *r;
272 1 : vnet_crypto_op_t *ops = 0, *op;
273 1 : u8 *encrypted_data = 0, *decrypted_data = 0, *s = 0, *err = 0;
274 :
275 1 : if (n_ops == 0)
276 0 : return 0;
277 :
278 1 : vec_validate_aligned (encrypted_data, computed_data_total_len - 1,
279 : CLIB_CACHE_LINE_BYTES);
280 1 : vec_validate_aligned (decrypted_data, computed_data_total_len - 1,
281 : CLIB_CACHE_LINE_BYTES);
282 1 : vec_validate_aligned (ops, n_ops - 1, CLIB_CACHE_LINE_BYTES);
283 1 : computed_data_total_len = 0;
284 :
285 1 : op = ops;
286 : /* first stage: encrypt only */
287 :
288 10 : vec_foreach_index (i, rv)
289 : {
290 9 : r = rv[i];
291 : int t;
292 9 : ad = vec_elt_at_index (cm->algs, r->alg);
293 63 : for (t = 0; t < VNET_CRYPTO_OP_N_TYPES; t++)
294 : {
295 54 : vnet_crypto_op_id_t id = ad->op_by_type[t];
296 :
297 54 : if (id == 0)
298 37 : continue;
299 :
300 17 : switch (t)
301 : {
302 2 : case VNET_CRYPTO_OP_TYPE_ENCRYPT:
303 2 : vnet_crypto_op_init (op, id);
304 2 : op->iv = tm->inc_data;
305 4 : op->key_index = vnet_crypto_key_add (vm, r->alg,
306 2 : tm->inc_data, r->key.length);
307 2 : vec_add1 (key_indices, op->key_index);
308 2 : op->len = r->plaintext_incremental;
309 2 : op->src = tm->inc_data;
310 2 : op->dst = encrypted_data + computed_data_total_len;
311 2 : computed_data_total_len += r->plaintext_incremental;
312 2 : op->user_data = i;
313 2 : op++;
314 2 : break;
315 6 : case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
316 6 : vnet_crypto_op_init (op, id);
317 6 : op->iv = tm->inc_data;
318 12 : op->key_index = vnet_crypto_key_add (vm, r->alg,
319 6 : tm->inc_data, r->key.length);
320 6 : vec_add1 (key_indices, op->key_index);
321 6 : op->aad = tm->inc_data;
322 6 : op->aad_len = r->aad.length;
323 6 : op->len = r->plaintext_incremental;
324 6 : op->dst = encrypted_data + computed_data_total_len;
325 6 : computed_data_total_len += r->plaintext_incremental;
326 6 : op->src = tm->inc_data;
327 6 : op->tag = encrypted_data + computed_data_total_len;
328 6 : computed_data_total_len += r->tag.length;
329 6 : op->tag_len = r->tag.length;
330 6 : op->user_data = i;
331 6 : op++;
332 6 : break;
333 1 : case VNET_CRYPTO_OP_TYPE_HMAC:
334 : /* compute hmac in the next stage */
335 1 : op->op = VNET_CRYPTO_OP_NONE;
336 1 : computed_data_total_len += r->digest.length;
337 1 : op->user_data = i;
338 1 : op++;
339 1 : break;
340 8 : default:
341 8 : break;
342 : };
343 : }
344 : }
345 :
346 1 : vnet_crypto_process_ops (vm, ops, n_ops);
347 1 : computed_data_total_len = 0;
348 :
349 : /* second stage: hash/decrypt previously encrypted data */
350 1 : op = ops;
351 :
352 10 : vec_foreach_index (i, rv)
353 : {
354 9 : r = rv[i];
355 : int t;
356 9 : ad = vec_elt_at_index (cm->algs, r->alg);
357 63 : for (t = 0; t < VNET_CRYPTO_OP_N_TYPES; t++)
358 : {
359 54 : vnet_crypto_op_id_t id = ad->op_by_type[t];
360 :
361 54 : if (id == 0)
362 37 : continue;
363 :
364 17 : switch (t)
365 : {
366 2 : case VNET_CRYPTO_OP_TYPE_DECRYPT:
367 2 : vnet_crypto_op_init (op, id);
368 2 : op->iv = tm->inc_data;
369 4 : op->key_index = vnet_crypto_key_add (vm, r->alg,
370 2 : tm->inc_data, r->key.length);
371 2 : vec_add1 (key_indices, op->key_index);
372 2 : op->len = r->plaintext_incremental;
373 2 : op->src = encrypted_data + computed_data_total_len;
374 2 : op->dst = decrypted_data + computed_data_total_len;
375 2 : computed_data_total_len += r->plaintext_incremental;
376 2 : op->user_data = i;
377 2 : op++;
378 2 : break;
379 6 : case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
380 6 : vnet_crypto_op_init (op, id);
381 6 : op->iv = tm->inc_data;
382 12 : op->key_index = vnet_crypto_key_add (vm, r->alg,
383 6 : tm->inc_data, r->key.length);
384 6 : vec_add1 (key_indices, op->key_index);
385 6 : op->aad = tm->inc_data;
386 6 : op->aad_len = r->aad.length;
387 6 : op->len = r->plaintext_incremental;
388 6 : op->dst = decrypted_data + computed_data_total_len;
389 6 : op->src = encrypted_data + computed_data_total_len;
390 6 : computed_data_total_len += r->plaintext_incremental;
391 :
392 6 : op->tag = encrypted_data + computed_data_total_len;
393 6 : computed_data_total_len += r->tag.length;
394 6 : op->tag_len = r->tag.length;
395 6 : op->user_data = i;
396 6 : op++;
397 6 : break;
398 1 : case VNET_CRYPTO_OP_TYPE_HMAC:
399 1 : vnet_crypto_op_init (op, id);
400 2 : op->key_index = vnet_crypto_key_add (vm, r->alg,
401 1 : tm->inc_data, r->key.length);
402 1 : vec_add1 (key_indices, op->key_index);
403 1 : op->src = tm->inc_data;
404 1 : op->len = r->plaintext_incremental;
405 1 : op->digest_len = r->digest.length;
406 1 : op->digest = encrypted_data + computed_data_total_len;
407 1 : computed_data_total_len += r->digest.length;
408 1 : op->user_data = i;
409 1 : op++;
410 1 : break;
411 8 : default:
412 8 : break;
413 : };
414 :
415 : }
416 : }
417 :
418 1 : vnet_crypto_process_ops (vm, ops, n_ops);
419 1 : print_results (vm, rv, ops, 0, n_ops, tm);
420 :
421 18 : vec_foreach_index (i, key_indices) vnet_crypto_key_del (vm, key_indices[i]);
422 1 : vec_free (tm->inc_data);
423 1 : vec_free (ops);
424 1 : vec_free (encrypted_data);
425 1 : vec_free (decrypted_data);
426 1 : vec_free (err);
427 1 : vec_free (s);
428 1 : return 0;
429 : }
430 :
431 : static clib_error_t *
432 1 : test_crypto_static (vlib_main_t * vm, crypto_test_main_t * tm,
433 : unittest_crypto_test_registration_t ** rv, u32 n_ops,
434 : u32 n_chained_ops, u32 computed_data_total_len)
435 : {
436 : unittest_crypto_test_data_t *pt, *ct;
437 1 : vnet_crypto_op_chunk_t *chunks = 0, ch;
438 : unittest_crypto_test_registration_t *r;
439 1 : vnet_crypto_op_t *ops = 0, *op, *chained_ops = 0;
440 1 : vnet_crypto_op_t *current_chained_op = 0, *current_op = 0;
441 1 : vnet_crypto_main_t *cm = &crypto_main;
442 : vnet_crypto_alg_data_t *ad;
443 1 : vnet_crypto_key_index_t *key_indices = 0;
444 1 : u8 *computed_data = 0;
445 : u32 i;
446 :
447 1 : vec_sort_with_function (rv, sort_registrations);
448 :
449 1 : vec_validate_aligned (computed_data, computed_data_total_len - 1,
450 : CLIB_CACHE_LINE_BYTES);
451 1 : vec_validate_aligned (ops, n_ops - 1, CLIB_CACHE_LINE_BYTES);
452 1 : vec_validate_aligned (chained_ops, n_chained_ops - 1,
453 : CLIB_CACHE_LINE_BYTES);
454 1 : computed_data_total_len = 0;
455 :
456 1 : current_op = ops;
457 1 : current_chained_op = chained_ops;
458 : /* *INDENT-OFF* */
459 71 : vec_foreach_index (i, rv)
460 : {
461 70 : r = rv[i];
462 : int t;
463 70 : ad = vec_elt_at_index (cm->algs, r->alg);
464 490 : for (t = 0; t < VNET_CRYPTO_OP_N_TYPES; t++)
465 : {
466 420 : vnet_crypto_op_id_t id = ad->op_by_type[t];
467 :
468 420 : if (id == 0)
469 331 : continue;
470 :
471 89 : if (r->is_chained)
472 : {
473 7 : op = current_chained_op;
474 7 : current_chained_op += 1;
475 : }
476 : else
477 : {
478 82 : op = current_op;
479 82 : current_op += 1;
480 : }
481 :
482 89 : vnet_crypto_op_init (op, id);
483 :
484 89 : switch (t)
485 : {
486 14 : case VNET_CRYPTO_OP_TYPE_ENCRYPT:
487 : case VNET_CRYPTO_OP_TYPE_DECRYPT:
488 14 : op->iv = r->iv.data;
489 28 : op->key_index = vnet_crypto_key_add (vm, r->alg,
490 : r->key.data,
491 14 : r->key.length);
492 14 : vec_add1 (key_indices, op->key_index);
493 :
494 14 : if (r->is_chained)
495 : {
496 2 : pt = r->pt_chunks;
497 2 : ct = r->ct_chunks;
498 2 : op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
499 2 : op->chunk_index = vec_len (chunks);
500 6 : while (pt->data)
501 : {
502 4 : ch.src = t == VNET_CRYPTO_OP_TYPE_ENCRYPT ?
503 4 : pt->data : ct->data;
504 4 : ch.len = pt->length;
505 4 : ch.dst = computed_data + computed_data_total_len;
506 4 : computed_data_total_len += pt->length;
507 4 : vec_add1 (chunks, ch);
508 4 : op->n_chunks++;
509 4 : pt++;
510 4 : ct++;
511 : }
512 : }
513 : else
514 : {
515 12 : op->len = r->plaintext.length;
516 12 : op->src = t == VNET_CRYPTO_OP_TYPE_ENCRYPT ?
517 12 : r->plaintext.data : r->ciphertext.data;
518 12 : op->dst = computed_data + computed_data_total_len;
519 12 : computed_data_total_len += r->ciphertext.length;
520 : }
521 14 : break;
522 24 : case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
523 : case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
524 24 : if (r->is_chained)
525 : {
526 2 : op->iv = r->iv.data;
527 4 : op->key_index = vnet_crypto_key_add (vm, r->alg,
528 : r->key.data,
529 2 : r->key.length);
530 2 : vec_add1 (key_indices, op->key_index);
531 2 : op->aad = r->aad.data;
532 2 : op->aad_len = r->aad.length;
533 2 : if (t == VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT)
534 : {
535 1 : pt = r->pt_chunks;
536 1 : op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
537 1 : op->chunk_index = vec_len (chunks);
538 4 : while (pt->data)
539 : {
540 3 : clib_memset (&ch, 0, sizeof (ch));
541 3 : ch.src = pt->data;
542 3 : ch.len = pt->length;
543 3 : ch.dst = computed_data + computed_data_total_len;
544 3 : computed_data_total_len += pt->length;
545 3 : vec_add1 (chunks, ch);
546 3 : op->n_chunks++;
547 3 : pt++;
548 : }
549 1 : op->tag = computed_data + computed_data_total_len;
550 1 : computed_data_total_len += r->tag.length;
551 : }
552 : else
553 : {
554 1 : ct = r->ct_chunks;
555 1 : op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
556 1 : op->chunk_index = vec_len (chunks);
557 4 : while (ct->data)
558 : {
559 3 : clib_memset (&ch, 0, sizeof (ch));
560 3 : ch.src = ct->data;
561 3 : ch.len = ct->length;
562 3 : ch.dst = computed_data + computed_data_total_len;
563 3 : computed_data_total_len += ct->length;
564 3 : vec_add1 (chunks, ch);
565 3 : op->n_chunks++;
566 3 : ct++;
567 : }
568 1 : op->tag = r->tag.data;
569 : }
570 2 : op->tag_len = r->tag.length;
571 : }
572 : else
573 : {
574 22 : op->iv = r->iv.data;
575 44 : op->key_index = vnet_crypto_key_add (vm, r->alg,
576 : r->key.data,
577 22 : r->key.length);
578 22 : vec_add1 (key_indices, op->key_index);
579 22 : op->aad = r->aad.data;
580 22 : op->aad_len = r->aad.length;
581 22 : op->len = r->plaintext.length;
582 22 : op->dst = computed_data + computed_data_total_len;
583 22 : computed_data_total_len += r->ciphertext.length;
584 :
585 22 : if (t == VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT)
586 : {
587 11 : op->src = r->plaintext.data;
588 11 : op->tag = computed_data + computed_data_total_len;
589 11 : computed_data_total_len += r->tag.length;
590 : }
591 : else
592 : {
593 11 : op->tag = r->tag.data;
594 11 : op->src = r->ciphertext.data;
595 : }
596 22 : op->tag_len = r->tag.length;
597 : }
598 24 : break;
599 46 : case VNET_CRYPTO_OP_TYPE_HMAC:
600 46 : if (r->is_chained)
601 : {
602 6 : op->key_index = vnet_crypto_key_add (vm, r->alg,
603 : r->key.data,
604 3 : r->key.length);
605 3 : vec_add1 (key_indices, op->key_index);
606 3 : op->digest_len = r->digest.length;
607 3 : op->digest = computed_data + computed_data_total_len;
608 3 : computed_data_total_len += r->digest.length;
609 3 : pt = r->pt_chunks;
610 3 : op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
611 3 : op->chunk_index = vec_len (chunks);
612 11 : while (pt->data)
613 : {
614 8 : clib_memset (&ch, 0, sizeof (ch));
615 8 : ch.src = pt->data;
616 8 : ch.len = pt->length;
617 8 : vec_add1 (chunks, ch);
618 8 : op->n_chunks++;
619 8 : pt++;
620 : }
621 : }
622 : else
623 : {
624 86 : op->key_index = vnet_crypto_key_add (vm, r->alg,
625 : r->key.data,
626 43 : r->key.length);
627 43 : vec_add1 (key_indices, op->key_index);
628 43 : op->digest_len = r->digest.length;
629 43 : op->digest = computed_data + computed_data_total_len;
630 43 : computed_data_total_len += r->digest.length;
631 43 : op->src = r->plaintext.data;
632 43 : op->len = r->plaintext.length;
633 : }
634 46 : break;
635 5 : case VNET_CRYPTO_OP_TYPE_HASH:
636 5 : op->digest = computed_data + computed_data_total_len;
637 5 : computed_data_total_len += r->digest.length;
638 5 : op->src = r->plaintext.data;
639 5 : op->len = r->plaintext.length;
640 5 : break;
641 0 : default:
642 0 : break;
643 : };
644 :
645 89 : op->user_data = i;
646 : }
647 : }
648 : /* *INDENT-ON* */
649 :
650 1 : vnet_crypto_process_ops (vm, ops, vec_len (ops));
651 1 : vnet_crypto_process_chained_ops (vm, chained_ops, chunks,
652 1 : vec_len (chained_ops));
653 :
654 1 : print_results (vm, rv, ops, chunks, vec_len (ops), tm);
655 1 : print_results (vm, rv, chained_ops, chunks, vec_len (chained_ops), tm);
656 :
657 85 : vec_foreach_index (i, key_indices) vnet_crypto_key_del (vm, key_indices[i]);
658 :
659 1 : vec_free (computed_data);
660 1 : vec_free (ops);
661 1 : vec_free (chained_ops);
662 1 : vec_free (chunks);
663 1 : return 0;
664 : }
665 :
666 : static u32
667 0 : test_crypto_get_key_sz (vnet_crypto_alg_t alg)
668 : {
669 0 : switch (alg)
670 : {
671 : #define _(n, s, l) \
672 : case VNET_CRYPTO_ALG_##n: \
673 : return l;
674 : /* *INDENT-OFF* */
675 0 : foreach_crypto_cipher_alg
676 0 : foreach_crypto_aead_alg
677 : /* *INDENT-ON* */
678 : #undef _
679 0 : case VNET_CRYPTO_ALG_HMAC_MD5:
680 : case VNET_CRYPTO_ALG_HMAC_SHA1:
681 0 : return 20;
682 0 : case VNET_CRYPTO_ALG_HMAC_SHA224:
683 0 : return 28;
684 0 : case VNET_CRYPTO_ALG_HMAC_SHA256:
685 0 : return 32;
686 0 : case VNET_CRYPTO_ALG_HMAC_SHA384:
687 0 : return 48;
688 0 : case VNET_CRYPTO_ALG_HMAC_SHA512:
689 0 : return 64;
690 0 : default:
691 0 : return 0;
692 : }
693 : return 0;
694 : }
695 :
696 : static clib_error_t *
697 1 : test_crypto (vlib_main_t * vm, crypto_test_main_t * tm)
698 : {
699 1 : clib_error_t *err = 0;
700 1 : vnet_crypto_main_t *cm = &crypto_main;
701 1 : unittest_crypto_test_registration_t *r = tm->test_registrations;
702 1 : unittest_crypto_test_registration_t **static_tests = 0, **inc_tests = 0;
703 1 : u32 i, j, n_ops_static = 0, n_ops_incr = 0, n_chained_ops = 0;
704 : vnet_crypto_alg_data_t *ad;
705 1 : u32 computed_data_total_len = 0;
706 1 : u32 computed_data_total_incr_len = 0;
707 1 : u32 saved_engs[VNET_CRYPTO_N_OP_IDS] = { ~0, };
708 : unittest_crypto_test_data_t *ct;
709 :
710 : /* pre-allocate plaintext data with reasonable length */
711 1 : validate_data (&tm->inc_data, 2048);
712 :
713 1 : int rc = save_current_engines (saved_engs);
714 1 : if (rc)
715 0 : return clib_error_return (0, "failed to set default crypto engine!");
716 :
717 : /* construct registration vector */
718 80 : while (r)
719 : {
720 79 : if (r->plaintext_incremental)
721 9 : vec_add1 (inc_tests, r);
722 : else
723 70 : vec_add1 (static_tests, r);
724 :
725 79 : ad = vec_elt_at_index (cm->algs, r->alg);
726 :
727 553 : for (i = 0; i < VNET_CRYPTO_OP_N_TYPES; i++)
728 : {
729 474 : vnet_crypto_op_id_t id = ad->op_by_type[i];
730 :
731 474 : if (id == 0)
732 368 : continue;
733 :
734 106 : switch (i)
735 : {
736 9 : case VNET_CRYPTO_OP_TYPE_ENCRYPT:
737 9 : if (r->plaintext_incremental)
738 : {
739 2 : computed_data_total_incr_len += r->plaintext_incremental;
740 2 : n_ops_incr += 1;
741 : }
742 : /* fall though */
743 : case VNET_CRYPTO_OP_TYPE_DECRYPT:
744 : case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
745 36 : if (r->is_chained)
746 : {
747 3 : ct = r->ct_chunks;
748 3 : j = 0;
749 10 : while (ct->data)
750 : {
751 7 : if (j > CRYPTO_TEST_MAX_OP_CHUNKS)
752 0 : return clib_error_return (0,
753 : "test case '%s' exceeds extra data!",
754 : r->name);
755 7 : computed_data_total_len += ct->length;
756 7 : ct++;
757 7 : j++;
758 : }
759 3 : n_chained_ops += 1;
760 : }
761 33 : else if (!r->plaintext_incremental)
762 : {
763 23 : computed_data_total_len += r->ciphertext.length;
764 23 : n_ops_static += 1;
765 : }
766 36 : break;
767 18 : case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
768 18 : if (r->plaintext_incremental)
769 : {
770 6 : computed_data_total_incr_len += r->plaintext_incremental;
771 6 : computed_data_total_incr_len += r->tag.length;
772 6 : n_ops_incr += 1;
773 : }
774 : else
775 : {
776 12 : computed_data_total_len += r->ciphertext.length;
777 12 : computed_data_total_len += r->tag.length;
778 12 : if (r->is_chained)
779 : {
780 1 : ct = r->ct_chunks;
781 1 : j = 0;
782 4 : while (ct->data)
783 : {
784 3 : if (j > CRYPTO_TEST_MAX_OP_CHUNKS)
785 0 : return clib_error_return (0,
786 : "test case '%s' exceeds extra data!",
787 : r->name);
788 3 : computed_data_total_len += ct->length;
789 3 : ct++;
790 3 : j++;
791 : }
792 1 : n_chained_ops += 1;
793 : }
794 : else
795 11 : n_ops_static += 1;
796 : }
797 18 : break;
798 47 : case VNET_CRYPTO_OP_TYPE_HMAC:
799 47 : if (r->plaintext_incremental)
800 : {
801 1 : computed_data_total_incr_len += r->digest.length;
802 1 : n_ops_incr += 1;
803 1 : generate_digest (vm, r, id);
804 : }
805 : else
806 : {
807 46 : computed_data_total_len += r->digest.length;
808 46 : if (r->is_chained)
809 3 : n_chained_ops += 1;
810 : else
811 43 : n_ops_static += 1;
812 : }
813 47 : break;
814 5 : case VNET_CRYPTO_OP_TYPE_HASH:
815 5 : computed_data_total_len += r->digest.length;
816 5 : n_ops_static += 1;
817 5 : break;
818 0 : default:
819 0 : break;
820 : };
821 : }
822 :
823 : /* next: */
824 79 : r = r->next;
825 : }
826 1 : restore_engines (saved_engs);
827 :
828 1 : err = test_crypto_static (vm, tm, static_tests, n_ops_static, n_chained_ops,
829 : computed_data_total_len);
830 1 : if (err)
831 0 : goto done;
832 :
833 1 : err = test_crypto_incremental (vm, tm, inc_tests, n_ops_incr,
834 : computed_data_total_incr_len);
835 :
836 1 : r = tm->test_registrations;
837 80 : while (r)
838 : {
839 79 : if (r->plaintext_incremental)
840 9 : vec_free (r->digest.data);
841 79 : r = r->next;
842 : }
843 :
844 1 : done:
845 1 : vec_free (inc_tests);
846 1 : vec_free (static_tests);
847 1 : return err;
848 : }
849 :
850 : static clib_error_t *
851 0 : test_crypto_perf (vlib_main_t * vm, crypto_test_main_t * tm)
852 : {
853 0 : vnet_crypto_main_t *cm = &crypto_main;
854 0 : clib_error_t *err = 0;
855 0 : u32 n_buffers, n_alloc = 0, warmup_rounds, rounds;
856 0 : u32 *buffer_indices = 0;
857 0 : vnet_crypto_op_t *ops1 = 0, *ops2 = 0, *op1, *op2;
858 0 : vnet_crypto_alg_data_t *ad = vec_elt_at_index (cm->algs, tm->alg);
859 0 : vnet_crypto_key_index_t key_index = ~0;
860 : u8 key[64];
861 0 : int buffer_size = vlib_buffer_get_default_data_size (vm);
862 0 : u64 seed = clib_cpu_time_now ();
863 0 : u64 t0[5], t1[5], t2[5], n_bytes = 0;
864 : int i, j;
865 :
866 0 : if (tm->buffer_size > buffer_size)
867 0 : return clib_error_return (0, "buffer size must be <= %u", buffer_size);
868 :
869 0 : rounds = tm->rounds ? tm->rounds : 100;
870 0 : n_buffers = tm->n_buffers ? tm->n_buffers : 256;
871 0 : buffer_size = tm->buffer_size ? tm->buffer_size : 2048;
872 0 : warmup_rounds = tm->warmup_rounds ? tm->warmup_rounds : 100;
873 :
874 0 : if (buffer_size > vlib_buffer_get_default_data_size (vm))
875 0 : return clib_error_return (0, "buffer size too big");
876 :
877 0 : vec_validate_aligned (buffer_indices, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
878 0 : vec_validate_aligned (ops1, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
879 0 : vec_validate_aligned (ops2, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
880 :
881 0 : n_alloc = vlib_buffer_alloc (vm, buffer_indices, n_buffers);
882 0 : if (n_alloc != n_buffers)
883 : {
884 0 : if (n_alloc)
885 0 : vlib_buffer_free (vm, buffer_indices, n_alloc);
886 0 : err = clib_error_return (0, "buffer alloc failure");
887 0 : goto done;
888 : }
889 :
890 0 : vlib_cli_output (vm, "%U: n_buffers %u buffer-size %u rounds %u "
891 : "warmup-rounds %u",
892 0 : format_vnet_crypto_alg, tm->alg, n_buffers, buffer_size,
893 : rounds, warmup_rounds);
894 0 : vlib_cli_output (vm, " cpu-freq %.2f GHz",
895 0 : (f64) vm->clib_time.clocks_per_second * 1e-9);
896 :
897 0 : vnet_crypto_op_type_t ot = 0;
898 :
899 0 : for (i = 0; i < sizeof (key); i++)
900 0 : key[i] = i;
901 :
902 0 : key_index = vnet_crypto_key_add (vm, tm->alg, key,
903 0 : test_crypto_get_key_sz (tm->alg));
904 :
905 0 : for (i = 0; i < VNET_CRYPTO_OP_N_TYPES; i++)
906 : {
907 0 : vnet_crypto_op_id_t id = ad->op_by_type[i];
908 0 : if (id == 0)
909 0 : continue;
910 0 : ot = i;
911 0 : break;
912 : }
913 :
914 0 : for (i = 0; i < n_buffers; i++)
915 : {
916 0 : vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
917 0 : op1 = ops1 + i;
918 0 : op2 = ops2 + i;
919 :
920 0 : switch (ot)
921 : {
922 0 : case VNET_CRYPTO_OP_TYPE_ENCRYPT:
923 : case VNET_CRYPTO_OP_TYPE_DECRYPT:
924 0 : vnet_crypto_op_init (op1,
925 : ad->op_by_type[VNET_CRYPTO_OP_TYPE_ENCRYPT]);
926 0 : vnet_crypto_op_init (op2,
927 : ad->op_by_type[VNET_CRYPTO_OP_TYPE_DECRYPT]);
928 0 : op1->src = op2->src = op1->dst = op2->dst = b->data;
929 0 : op1->key_index = op2->key_index = key_index;
930 0 : op1->iv = op2->iv = b->data - 64;
931 0 : n_bytes += op1->len = op2->len = buffer_size;
932 0 : break;
933 0 : case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
934 : case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
935 0 : vnet_crypto_op_init (op1,
936 : ad->op_by_type
937 : [VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT]);
938 0 : vnet_crypto_op_init (op2,
939 : ad->op_by_type
940 : [VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT]);
941 0 : op1->src = op2->src = op1->dst = op2->dst = b->data;
942 0 : op1->key_index = op2->key_index = key_index;
943 0 : op1->tag = op2->tag = b->data - 32;
944 0 : op1->iv = op2->iv = b->data - 64;
945 0 : op1->aad = op2->aad = b->data - VLIB_BUFFER_PRE_DATA_SIZE;
946 0 : op1->aad_len = op2->aad_len = 64;
947 0 : op1->tag_len = op2->tag_len = 16;
948 0 : n_bytes += op1->len = op2->len = buffer_size;
949 0 : break;
950 0 : case VNET_CRYPTO_OP_TYPE_HMAC:
951 0 : vnet_crypto_op_init (op1, ad->op_by_type[VNET_CRYPTO_OP_TYPE_HMAC]);
952 0 : op1->src = b->data;
953 0 : op1->key_index = key_index;
954 0 : op1->iv = 0;
955 0 : op1->digest = b->data - VLIB_BUFFER_PRE_DATA_SIZE;
956 0 : op1->digest_len = 0;
957 0 : n_bytes += op1->len = buffer_size;
958 0 : break;
959 0 : default:
960 0 : return 0;
961 : }
962 :
963 0 : for (j = -VLIB_BUFFER_PRE_DATA_SIZE; j < buffer_size; j += 8)
964 0 : *(u64 *) (b->data + j) = 1 + random_u64 (&seed);
965 : }
966 :
967 0 : for (i = 0; i < 5; i++)
968 : {
969 0 : for (j = 0; j < warmup_rounds; j++)
970 : {
971 0 : vnet_crypto_process_ops (vm, ops1, n_buffers);
972 0 : if (ot != VNET_CRYPTO_OP_TYPE_HMAC)
973 0 : vnet_crypto_process_ops (vm, ops2, n_buffers);
974 : }
975 :
976 0 : t0[i] = clib_cpu_time_now ();
977 0 : for (j = 0; j < rounds; j++)
978 0 : vnet_crypto_process_ops (vm, ops1, n_buffers);
979 0 : t1[i] = clib_cpu_time_now ();
980 :
981 0 : if (ot != VNET_CRYPTO_OP_TYPE_HMAC)
982 : {
983 0 : for (j = 0; j < rounds; j++)
984 0 : vnet_crypto_process_ops (vm, ops2, n_buffers);
985 0 : t2[i] = clib_cpu_time_now ();
986 : }
987 : }
988 :
989 0 : for (i = 0; i < 5; i++)
990 : {
991 0 : f64 tpb1 = (f64) (t1[i] - t0[i]) / (n_bytes * rounds);
992 0 : f64 gbps1 = vm->clib_time.clocks_per_second * 1e-9 * 8 / tpb1;
993 : f64 tpb2, gbps2;
994 :
995 0 : if (ot != VNET_CRYPTO_OP_TYPE_HMAC)
996 : {
997 0 : tpb2 = (f64) (t2[i] - t1[i]) / (n_bytes * rounds);
998 0 : gbps2 = vm->clib_time.clocks_per_second * 1e-9 * 8 / tpb2;
999 0 : vlib_cli_output (vm, "%-2u: encrypt %.03f ticks/byte, %.02f Gbps; "
1000 : "decrypt %.03f ticks/byte, %.02f Gbps",
1001 : i + 1, tpb1, gbps1, tpb2, gbps2);
1002 : }
1003 : else
1004 : {
1005 0 : vlib_cli_output (vm, "%-2u: hash %.03f ticks/byte, %.02f Gbps\n",
1006 : i + 1, tpb1, gbps1);
1007 : }
1008 : }
1009 :
1010 0 : done:
1011 0 : if (n_alloc)
1012 0 : vlib_buffer_free (vm, buffer_indices, n_alloc);
1013 :
1014 0 : if (key_index != ~0)
1015 0 : vnet_crypto_key_del (vm, key_index);
1016 :
1017 0 : vec_free (buffer_indices);
1018 0 : vec_free (ops1);
1019 0 : vec_free (ops2);
1020 0 : return err;
1021 : }
1022 :
1023 : static clib_error_t *
1024 1 : test_crypto_command_fn (vlib_main_t * vm,
1025 : unformat_input_t * input, vlib_cli_command_t * cmd)
1026 : {
1027 1 : crypto_test_main_t *tm = &crypto_test_main;
1028 : unittest_crypto_test_registration_t *tr;
1029 1 : int is_perf = 0;
1030 :
1031 1 : tr = tm->test_registrations;
1032 1 : memset (tm, 0, sizeof (crypto_test_main_t));
1033 1 : tm->test_registrations = tr;
1034 1 : tm->alg = ~0;
1035 :
1036 1 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1037 : {
1038 0 : if (unformat (input, "verbose"))
1039 0 : tm->verbose = 1;
1040 0 : else if (unformat (input, "detail"))
1041 0 : tm->verbose = 2;
1042 : else
1043 0 : if (unformat (input, "perf %U", unformat_vnet_crypto_alg, &tm->alg))
1044 0 : is_perf = 1;
1045 0 : else if (unformat (input, "buffers %u", &tm->n_buffers))
1046 : ;
1047 0 : else if (unformat (input, "rounds %u", &tm->rounds))
1048 : ;
1049 0 : else if (unformat (input, "warmup-rounds %u", &tm->warmup_rounds))
1050 : ;
1051 0 : else if (unformat (input, "buffer-size %u", &tm->buffer_size))
1052 : ;
1053 : else
1054 0 : return clib_error_return (0, "unknown input '%U'",
1055 : format_unformat_error, input);
1056 : }
1057 :
1058 1 : if (is_perf)
1059 0 : return test_crypto_perf (vm, tm);
1060 : else
1061 1 : return test_crypto (vm, tm);
1062 : }
1063 :
1064 : /* *INDENT-OFF* */
1065 16239 : VLIB_CLI_COMMAND (test_crypto_command, static) =
1066 : {
1067 : .path = "test crypto",
1068 : .short_help = "test crypto",
1069 : .function = test_crypto_command_fn,
1070 : };
1071 : /* *INDENT-ON* */
1072 :
1073 : static clib_error_t *
1074 559 : crypto_test_init (vlib_main_t * vm)
1075 : {
1076 559 : return (0);
1077 : }
1078 :
1079 1679 : VLIB_INIT_FUNCTION (crypto_test_init);
1080 :
1081 : /*
1082 : * fd.io coding-style-patch-verification: ON
1083 : *
1084 : * Local Variables:
1085 : * eval: (c-set-style "gnu")
1086 : * End:
1087 : */
|