crypto: add support for AEAD and AES-GCM
[vpp.git] / src / plugins / unittest / crypto_test.c
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 sort_registrations (void *a0, void *a1)
26 {
27   unittest_crypto_test_registration_t **r0 = a0;
28   unittest_crypto_test_registration_t **r1 = a1;
29
30   return (strncmp (r0[0]->name, r1[0]->name, 256));
31 }
32
33 static clib_error_t *
34 test_crypto (vlib_main_t * vm, crypto_test_main_t * tm)
35 {
36   vnet_crypto_main_t *cm = &crypto_main;
37   unittest_crypto_test_registration_t *r = tm->test_registrations;
38   unittest_crypto_test_registration_t **rv = 0;
39   vnet_crypto_alg_data_t *ad;
40   vnet_crypto_op_t *ops = 0, *op;
41   u8 *computed_data = 0, *s = 0, *err = 0;
42   u32 computed_data_total_len = 0, n_ops = 0;
43   u32 i;
44
45   /* construct registration vector */
46   while (r)
47     {
48       vec_add1 (rv, r);
49       ad = vec_elt_at_index (cm->algs, r->alg);
50
51       for (i = 0; i < VNET_CRYPTO_OP_N_TYPES; i++)
52         {
53           vnet_crypto_op_id_t id = ad->op_by_type[i];
54
55           if (id == 0)
56             continue;
57
58           switch (i)
59             {
60             case VNET_CRYPTO_OP_TYPE_ENCRYPT:
61             case VNET_CRYPTO_OP_TYPE_DECRYPT:
62             case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
63               computed_data_total_len += r->ciphertext.length;
64               n_ops += 1;
65               break;
66             case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
67               computed_data_total_len += r->ciphertext.length;
68               computed_data_total_len += r->tag.length;
69               n_ops += 1;
70               break;
71             case VNET_CRYPTO_OP_TYPE_HMAC:
72               computed_data_total_len += r->digest.length;
73               n_ops += 1;
74               break;
75             default:
76               break;
77             };
78         }
79
80       /* next */
81       r = r->next;
82     }
83
84   vec_sort_with_function (rv, sort_registrations);
85
86   vec_validate_aligned (computed_data, computed_data_total_len - 1,
87                         CLIB_CACHE_LINE_BYTES);
88   vec_validate_aligned (ops, n_ops - 1, CLIB_CACHE_LINE_BYTES);
89   computed_data_total_len = 0;
90
91   op = ops;
92   /* *INDENT-OFF* */
93   vec_foreach_index (i, rv)
94     {
95       r = rv[i];
96       int t;
97       ad = vec_elt_at_index (cm->algs, r->alg);
98       for (t = 0; t < VNET_CRYPTO_OP_N_TYPES; t++)
99         {
100           vnet_crypto_op_id_t id = ad->op_by_type[t];
101
102           if (id == 0)
103             continue;
104
105           vnet_crypto_op_init (op, id);
106
107           switch (t)
108             {
109             case VNET_CRYPTO_OP_TYPE_ENCRYPT:
110             case VNET_CRYPTO_OP_TYPE_DECRYPT:
111               op->iv = r->iv.data;
112               op->iv_len = r->iv.length;
113               op->key = r->key.data;
114               op->key_len = r->key.length;
115               op->len = r->plaintext.length;
116               op->src = t == VNET_CRYPTO_OP_TYPE_ENCRYPT ?
117                 r->plaintext.data : r->ciphertext.data;
118               op->dst = computed_data + computed_data_total_len;
119               computed_data_total_len += r->ciphertext.length;
120               break;
121             case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
122             case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
123               op->iv = r->iv.data;
124               op->iv_len = r->iv.length;
125               op->key = r->key.data;
126               op->key_len = r->key.length;
127               op->aad = r->aad.data;
128               op->aad_len = r->aad.length;
129               op->len = r->plaintext.length;
130               op->dst = computed_data + computed_data_total_len;
131               computed_data_total_len += r->ciphertext.length;
132               if (t == VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT)
133                 {
134                   op->src = r->plaintext.data;
135                   op->tag = computed_data + computed_data_total_len;
136                   computed_data_total_len += r->tag.length;
137                 }
138               else
139                 {
140                   op->src = r->ciphertext.data;
141                   op->tag = r->tag.data;
142                 }
143               op->tag_len = r->tag.length;
144               break;
145             case VNET_CRYPTO_OP_TYPE_HMAC:
146               op->key = r->key.data;
147               op->key_len = r->key.length;
148               op->src = r->plaintext.data;
149               op->len = r->plaintext.length;
150               op->digest_len = r->digest.length;
151               op->digest = computed_data + computed_data_total_len;
152               computed_data_total_len += r->digest.length;
153               break;
154             default:
155               break;
156             };
157
158           op->user_data = i;
159           op++;
160         }
161       /* next */
162       r = r->next;
163     }
164   /* *INDENT-ON* */
165
166   vnet_crypto_process_ops (vm, ops, vec_len (ops));
167
168   /* *INDENT-OFF* */
169   vec_foreach (op, ops)
170     {
171       int fail = 0;
172       r = rv[op->user_data];
173       unittest_crypto_test_data_t *exp_pt = 0, *exp_ct = 0;
174       unittest_crypto_test_data_t *exp_digest = 0, *exp_tag = 0;
175
176       switch (vnet_crypto_get_op_type (op->op))
177         {
178         case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
179           exp_tag = &r->tag;
180         case VNET_CRYPTO_OP_TYPE_ENCRYPT:
181           exp_ct = &r->ciphertext;
182           break;
183         case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
184         case VNET_CRYPTO_OP_TYPE_DECRYPT:
185           exp_pt = &r->plaintext;
186           break;
187         case VNET_CRYPTO_OP_TYPE_HMAC:
188           exp_digest = &r->digest;
189           break;
190         default:
191           break;
192         }
193
194       vec_reset_length (err);
195
196       if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
197         err = format (err, "%sengine error: %U", vec_len (err) ? ", " : "",
198                       format_vnet_crypto_op_status, op->status);
199
200       if (exp_ct && memcmp (op->dst, exp_ct->data, exp_ct->length) != 0)
201         err = format (err, "%sciphertext mismatch",
202                       vec_len (err) ? ", " : "");
203
204       if (exp_pt && memcmp (op->dst, exp_pt->data, exp_pt->length) != 0)
205         err = format (err, "%splaintext mismatch", vec_len (err) ? ", " : "");
206
207       if (exp_tag && memcmp (op->tag, exp_tag->data, exp_tag->length) != 0)
208         err = format (err, "%stag mismatch", vec_len (err) ? ", " : "");
209
210       if (exp_digest &&
211           memcmp (op->digest, exp_digest->data, exp_digest->length) != 0)
212         err = format (err, "%sdigest mismatch", vec_len (err) ? ", " : "");
213
214       vec_reset_length (s);
215       s = format (s, "%s (%U)", r->name, format_vnet_crypto_op, op->op);
216
217       if (vec_len (err))
218         fail = 1;
219
220       vlib_cli_output (vm, "%-60v%s%v", s, vec_len (err) ? "FAIL: " : "OK",
221                        err);
222       if (tm->verbose)
223         {
224           if (tm->verbose == 2)
225             fail = 1;
226
227           if (exp_ct && fail)
228             vlib_cli_output (vm, "Expected ciphertext:\n%U"
229                              "\nCalculated ciphertext:\n%U",
230                              format_hexdump, exp_ct->data, exp_ct->length,
231                              format_hexdump, op->dst, exp_ct->length);
232           if (exp_pt && fail)
233             vlib_cli_output (vm, "Expected plaintext:\n%U"
234                              "\nCalculated plaintext:\n%U",
235                              format_hexdump, exp_pt->data, exp_pt->length,
236                              format_hexdump, op->dst, exp_pt->length);
237           if (r->tag.length && fail)
238             vlib_cli_output (vm, "Expected tag:\n%U"
239                              "\nCalculated tag:\n%U",
240                              format_hexdump, r->tag.data, r->tag.length,
241                              format_hexdump, op->tag, op->tag_len);
242           if (exp_digest && fail)
243             vlib_cli_output (vm, "Expected digest:\n%U"
244                              "\nCalculated Digest:\n%U",
245                              format_hexdump, exp_digest->data,
246                              exp_digest->length, format_hexdump, op->digest,
247                              op->digest_len);
248         }
249     }
250   /* *INDENT-ON* */
251
252   vec_free (computed_data);
253   vec_free (ops);
254   vec_free (err);
255   vec_free (rv);
256   vec_free (s);
257   return 0;
258 }
259
260 static clib_error_t *
261 test_crypto_command_fn (vlib_main_t * vm,
262                         unformat_input_t * input, vlib_cli_command_t * cmd)
263 {
264   crypto_test_main_t *tm = &crypto_test_main;
265
266   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
267     {
268       if (unformat (input, "verbose"))
269         tm->verbose = 1;
270       else if (unformat (input, "detail"))
271         tm->verbose = 2;
272       else
273         return clib_error_return (0, "unknown input '%U'",
274                                   format_unformat_error, input);
275     }
276
277   return test_crypto (vm, tm);
278 }
279
280 /* *INDENT-OFF* */
281 VLIB_CLI_COMMAND (test_crypto_command, static) =
282 {
283   .path = "test crypto",
284   .short_help = "test crypto",
285   .function = test_crypto_command_fn,
286 };
287 /* *INDENT-ON* */
288
289 static clib_error_t *
290 crypto_test_init (vlib_main_t * vm)
291 {
292   return (0);
293 }
294
295 VLIB_INIT_FUNCTION (crypto_test_init);
296
297 /*
298  * fd.io coding-style-patch-verification: ON
299  *
300  * Local Variables:
301  * eval: (c-set-style "gnu")
302  * End:
303  */