examples/fips_validation: add crypto FIPS application
[dpdk.git] / examples / fips_validation / fips_validation.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <string.h>
7
8 #include <rte_string_fns.h>
9 #include <rte_cryptodev.h>
10 #include <rte_malloc.h>
11
12 #include "fips_validation.h"
13
14 #define skip_white_spaces(pos)                  \
15 ({                                              \
16         __typeof__(pos) _p = (pos);             \
17         for ( ; isspace(*_p); _p++)             \
18                 ;                               \
19         _p;                                     \
20 })
21
22 static int
23 get_file_line(void)
24 {
25         FILE *fp = info.fp_rd;
26         char *line = info.one_line_text;
27         int ret;
28         uint32_t loc = 0;
29
30         memset(line, 0, MAX_LINE_CHAR);
31         while ((ret = fgetc(fp)) != EOF) {
32                 char c = (char)ret;
33
34                 if (loc >= MAX_LINE_CHAR - 1)
35                         return -ENOMEM;
36                 if (c == '\n')
37                         break;
38                 line[loc++] = c;
39         }
40
41         if (ret == EOF)
42                 return -EOF;
43
44         return 0;
45 }
46
47 int
48 fips_test_fetch_one_block(void)
49 {
50         size_t size;
51         int ret = 0;
52         uint32_t i;
53
54         for (i = 0; i < info.nb_vec_lines; i++) {
55                 free(info.vec[i]);
56                 info.vec[i] = NULL;
57         }
58
59         i = 0;
60         do {
61                 if (i >= MAX_LINE_PER_VECTOR) {
62                         ret = -ENOMEM;
63                         goto error_exit;
64                 }
65
66                 ret = get_file_line();
67                 size = strlen(info.one_line_text);
68                 if (size == 0)
69                         break;
70
71                 info.vec[i] = calloc(1, size + 5);
72                 if (info.vec[i] == NULL)
73                         goto error_exit;
74
75                 strlcpy(info.vec[i], info.one_line_text, size + 1);
76                 i++;
77         } while (ret == 0);
78
79         info.nb_vec_lines = i;
80
81         return ret;
82
83 error_exit:
84         for (i = 0; i < MAX_LINE_PER_VECTOR; i++)
85                 if (info.vec[i] != NULL) {
86                         free(info.vec[i]);
87                         info.vec[i] = NULL;
88                 }
89
90         info.nb_vec_lines = 0;
91
92         return -ENOMEM;
93 }
94
95 static int
96 fips_test_parse_header(void)
97 {
98         uint32_t i;
99         char *tmp;
100         int ret;
101         time_t t = time(NULL);
102         struct tm *tm_now = localtime(&t);
103
104         ret = fips_test_fetch_one_block();
105         if (ret < 0)
106                 return ret;
107
108         for (i = 0; i < info.nb_vec_lines; i++) {
109
110                 tmp = strstr(info.vec[i], "# Config info for ");
111                 if (tmp != NULL) {
112                         fprintf(info.fp_wr, "%s%s\n", "# Config info for DPDK Cryptodev ",
113                                         info.device_name);
114                         continue;
115                 }
116
117                 tmp = strstr(info.vec[i], "#  HMAC information for ");
118                 if (tmp != NULL) {
119                         fprintf(info.fp_wr, "%s%s\n", "#  HMAC information for "
120                                 "DPDK Cryptodev ",
121                                 info.device_name);
122                         continue;
123                 }
124
125                 tmp = strstr(info.vec[i], "# Config Info for : ");
126                 if (tmp != NULL) {
127
128                         fprintf(info.fp_wr, "%s%s\n", "# Config Info for DPDK Cryptodev : ",
129                                         info.device_name);
130                         continue;
131                 }
132
133                 tmp = strstr(info.vec[i], "# information for ");
134                 if (tmp != NULL) {
135
136                         char tmp_output[128] = {0};
137
138                         strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
139
140                         fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
141                                         "information for DPDK Cryptodev ",
142                                         info.device_name);
143                         continue;
144                 }
145
146                 tmp = strstr(info.vec[i], " test information for ");
147                 if (tmp != NULL) {
148                         char tmp_output[128] = {0};
149
150                         strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
151
152                         fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
153                                         "test information for DPDK Cryptodev ",
154                                         info.device_name);
155                         continue;
156                 }
157
158                 if (i == info.nb_vec_lines - 1) {
159                         /** update the time as current time, write to file */
160                         fprintf(info.fp_wr, "%s%s\n", "# Generated on ",
161                                         asctime(tm_now));
162                         continue;
163                 }
164
165                 /* to this point, no field need to update,
166                  *  only copy to rsp file
167                  */
168                 fprintf(info.fp_wr, "%s\n", info.vec[i]);
169         }
170
171         return 0;
172 }
173
174 static int
175 parse_file_type(const char *path)
176 {
177         const char *tmp = path + strlen(path) - 3;
178
179         if (strstr(tmp, REQ_FILE_PERFIX))
180                 info.file_type = FIPS_TYPE_REQ;
181         else if (strstr(tmp, RSP_FILE_PERFIX))
182                 info.file_type = FIPS_TYPE_RSP;
183         else if (strstr(path, FAX_FILE_PERFIX))
184                 info.file_type = FIPS_TYPE_FAX;
185         else
186                 return -EINVAL;
187
188         return 0;
189 }
190
191 int
192 fips_test_init(const char *req_file_path, const char *rsp_file_path,
193                 const char *device_name)
194 {
195         if (strcmp(req_file_path, rsp_file_path) == 0) {
196                 RTE_LOG(ERR, USER1, "File paths cannot be the same\n");
197                 return -EINVAL;
198         }
199
200         fips_test_clear();
201
202         info.algo = FIPS_TEST_ALGO_MAX;
203         if (parse_file_type(req_file_path) < 0) {
204                 RTE_LOG(ERR, USER1, "File %s type not supported\n",
205                                 req_file_path);
206                 return -EINVAL;
207         }
208
209         info.fp_rd = fopen(req_file_path, "r");
210         if (!info.fp_rd) {
211                 RTE_LOG(ERR, USER1, "Cannot open file %s\n", req_file_path);
212                 return -EINVAL;
213         }
214
215         info.fp_wr = fopen(rsp_file_path, "w");
216         if (!info.fp_wr) {
217                 RTE_LOG(ERR, USER1, "Cannot open file %s\n", rsp_file_path);
218                 return -EINVAL;
219         }
220
221         info.one_line_text = calloc(1, MAX_LINE_CHAR);
222         if (!info.one_line_text) {
223                 RTE_LOG(ERR, USER1, "Insufficient memory\n");
224                 return -ENOMEM;
225         }
226
227         strlcpy(info.device_name, device_name, sizeof(info.device_name));
228
229         if (fips_test_parse_header() < 0) {
230                 RTE_LOG(ERR, USER1, "Failed parsing header\n");
231                 return -1;
232         }
233
234         return 0;
235 }
236
237 void
238 fips_test_clear(void)
239 {
240         if (info.fp_rd)
241                 fclose(info.fp_rd);
242         if (info.fp_wr)
243                 fclose(info.fp_wr);
244         if (info.one_line_text)
245                 free(info.one_line_text);
246         if (info.nb_vec_lines) {
247                 uint32_t i;
248
249                 for (i = 0; i < info.nb_vec_lines; i++)
250                         free(info.vec[i]);
251         }
252
253         memset(&info, 0, sizeof(info));
254 }
255
256 int
257 fips_test_parse_one_case(void)
258 {
259         uint32_t i, j = 0;
260         uint32_t is_interim = 0;
261         int ret;
262
263         if (info.interim_callbacks) {
264                 for (i = 0; i < info.nb_vec_lines; i++) {
265                         for (j = 0; info.interim_callbacks[j].key != NULL; j++)
266                                 if (strstr(info.vec[i],
267                                         info.interim_callbacks[j].key)) {
268                                         is_interim = 1;
269
270                                         ret = info.interim_callbacks[j].cb(
271                                                 info.interim_callbacks[j].key,
272                                                 info.vec[i],
273                                                 info.interim_callbacks[j].val);
274                                         if (ret < 0)
275                                                 return ret;
276                                 }
277                 }
278         }
279
280         if (is_interim) {
281                 for (i = 0; i < info.nb_vec_lines; i++)
282                         fprintf(info.fp_wr, "%s\n", info.vec[i]);
283                 fprintf(info.fp_wr, "\n");
284                 return 1;
285         }
286
287         for (i = 0; i < info.nb_vec_lines; i++) {
288                 for (j = 0; info.callbacks[j].key != NULL; j++)
289                         if (strstr(info.vec[i], info.callbacks[j].key)) {
290                                 ret = info.callbacks[j].cb(
291                                         info.callbacks[j].key,
292                                         info.vec[i], info.callbacks[j].val);
293                                 if (ret < 0)
294                                         return ret;
295                                 break;
296                         }
297         }
298
299         return 0;
300 }
301
302 void
303 fips_test_write_one_case(void)
304 {
305         uint32_t i;
306
307         for (i = 0; i < info.nb_vec_lines; i++)
308                 fprintf(info.fp_wr, "%s\n", info.vec[i]);
309 }
310
311 static int
312 parser_read_uint64_hex(uint64_t *value, const char *p)
313 {
314         char *next;
315         uint64_t val;
316
317         p = skip_white_spaces(p);
318
319         val = strtoul(p, &next, 16);
320         if (p == next)
321                 return -EINVAL;
322
323         p = skip_white_spaces(next);
324         if (*p != '\0')
325                 return -EINVAL;
326
327         *value = val;
328         return 0;
329 }
330
331 int
332 parser_read_uint8_hex(uint8_t *value, const char *p)
333 {
334         uint64_t val = 0;
335         int ret = parser_read_uint64_hex(&val, p);
336
337         if (ret < 0)
338                 return ret;
339
340         if (val > UINT8_MAX)
341                 return -ERANGE;
342
343         *value = val;
344         return 0;
345 }
346
347 int
348 parse_uint8_known_len_hex_str(const char *key, char *src, struct fips_val *val)
349 {
350         struct fips_val tmp_val = {0};
351         uint32_t len = val->len;
352         int ret;
353
354         if (len == 0) {
355                 if (val->val != NULL) {
356                         rte_free(val->val);
357                         val->val = NULL;
358                 }
359
360                 return 0;
361         }
362
363         ret = parse_uint8_hex_str(key, src, &tmp_val);
364         if (ret < 0)
365                 return ret;
366
367         if (tmp_val.len == val->len) {
368                 val->val = tmp_val.val;
369                 return 0;
370         }
371
372         if (tmp_val.len < val->len) {
373                 rte_free(tmp_val.val);
374                 return -EINVAL;
375         }
376
377         val->val = rte_zmalloc(NULL, val->len, 0);
378         if (!val->val) {
379                 rte_free(tmp_val.val);
380                 memset(val, 0, sizeof(*val));
381                 return -ENOMEM;
382         }
383
384         memcpy(val->val, tmp_val.val, val->len);
385         rte_free(tmp_val.val);
386
387         return 0;
388 }
389
390 int
391 parse_uint8_hex_str(const char *key, char *src, struct fips_val *val)
392 {
393         uint32_t len, j;
394
395         src += strlen(key);
396
397         len = strlen(src) / 2;
398
399         if (val->val) {
400                 rte_free(val->val);
401                 val->val = NULL;
402         }
403
404         val->val = rte_zmalloc(NULL, len, 0);
405         if (!val->val)
406                 return -ENOMEM;
407
408         for (j = 0; j < len; j++) {
409                 char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
410
411                 if (parser_read_uint8_hex(&val->val[j], byte) < 0) {
412                         rte_free(val->val);
413                         memset(val, 0, sizeof(*val));
414                         return -EINVAL;
415                 }
416         }
417
418         val->len = len;
419
420         return 0;
421 }
422
423 int
424 parser_read_uint32_val(const char *key, char *src, struct fips_val *val)
425 {
426         char *data = src + strlen(key);
427         size_t data_len = strlen(data);
428         int ret;
429
430         if (data[data_len - 1] == ']') {
431                 char *tmp_data = calloc(1, data_len + 1);
432
433                 if (tmp_data == NULL)
434                         return -ENOMEM;
435
436                 strlcpy(tmp_data, data, data_len);
437
438                 ret = parser_read_uint32(&val->len, tmp_data);
439
440                 free(tmp_data);
441         } else
442                 ret = parser_read_uint32(&val->len, data);
443
444         return ret;
445 }
446
447 int
448 parser_read_uint32_bit_val(const char *key, char *src, struct fips_val *val)
449 {
450         int ret;
451
452         ret = parser_read_uint32_val(key, src, val);
453
454         if (ret < 0)
455                 return ret;
456
457         val->len /= 8;
458
459         return 0;
460 }
461
462 int
463 writeback_hex_str(const char *key, char *dst, struct fips_val *val)
464 {
465         char *str = dst;
466         uint32_t len;
467
468         str += strlen(key);
469
470         for (len = 0; len < val->len; len++)
471                 snprintf(str + len * 2, 255, "%02x", val->val[len]);
472
473         return 0;
474 }
475
476 static int
477 parser_read_uint64(uint64_t *value, const char *p)
478 {
479         char *next;
480         uint64_t val;
481
482         p = skip_white_spaces(p);
483         if (!isdigit(*p))
484                 return -EINVAL;
485
486         val = strtoul(p, &next, 10);
487         if (p == next)
488                 return -EINVAL;
489
490         p = next;
491         switch (*p) {
492         case 'T':
493                 val *= 1024ULL;
494                 /* fall through */
495         case 'G':
496                 val *= 1024ULL;
497                 /* fall through */
498         case 'M':
499                 val *= 1024ULL;
500                 /* fall through */
501         case 'k':
502         case 'K':
503                 val *= 1024ULL;
504                 p++;
505                 break;
506         }
507
508         p = skip_white_spaces(p);
509         if (*p != '\0')
510                 return -EINVAL;
511
512         *value = val;
513         return 0;
514 }
515
516 int
517 parser_read_uint32(uint32_t *value, char *p)
518 {
519         uint64_t val = 0;
520         int ret = parser_read_uint64(&val, p);
521
522         if (ret < 0)
523                 return ret;
524
525         if (val > UINT32_MAX)
526                 return -EINVAL;
527
528         *value = val;
529         return 0;
530 }
531
532 void
533 parse_write_hex_str(struct fips_val *src)
534 {
535         writeback_hex_str("", info.one_line_text, src);
536
537         fprintf(info.fp_wr, "%s\n", info.one_line_text);
538 }
539
540 int
541 update_info_vec(uint32_t count)
542 {
543         const struct fips_test_callback *cb;
544         uint32_t i, j;
545
546         if (!info.writeback_callbacks)
547                 return -1;
548
549         cb = &info.writeback_callbacks[0];
550
551         snprintf(info.vec[0], strlen(info.vec[0]) + 4, "%s%u", cb->key, count);
552
553         for (i = 1; i < info.nb_vec_lines; i++) {
554                 for (j = 1; info.writeback_callbacks[j].key != NULL; j++) {
555                         cb = &info.writeback_callbacks[j];
556                         if (strstr(info.vec[i], cb->key)) {
557                                 cb->cb(cb->key, info.vec[i], cb->val);
558                                 break;
559                         }
560                 }
561         }
562
563         return 0;
564 }