examples/fips_validation: ignore \r in input files
[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 == '\r')
37                         continue;
38                 if (c == '\n')
39                         break;
40                 line[loc++] = c;
41         }
42
43         if (ret == EOF)
44                 return -EOF;
45
46         return 0;
47 }
48
49 int
50 fips_test_fetch_one_block(void)
51 {
52         size_t size;
53         int ret = 0;
54         uint32_t i;
55
56         for (i = 0; i < info.nb_vec_lines; i++) {
57                 free(info.vec[i]);
58                 info.vec[i] = NULL;
59         }
60
61         i = 0;
62         do {
63                 if (i >= MAX_LINE_PER_VECTOR) {
64                         ret = -ENOMEM;
65                         goto error_exit;
66                 }
67
68                 ret = get_file_line();
69                 size = strlen(info.one_line_text);
70                 if (size == 0)
71                         break;
72
73                 info.vec[i] = calloc(1, size + 5);
74                 if (info.vec[i] == NULL)
75                         goto error_exit;
76
77                 strlcpy(info.vec[i], info.one_line_text, size + 1);
78                 i++;
79         } while (ret == 0);
80
81         info.nb_vec_lines = i;
82
83         return ret;
84
85 error_exit:
86         for (i = 0; i < MAX_LINE_PER_VECTOR; i++)
87                 if (info.vec[i] != NULL) {
88                         free(info.vec[i]);
89                         info.vec[i] = NULL;
90                 }
91
92         info.nb_vec_lines = 0;
93
94         return -ENOMEM;
95 }
96
97 static int
98 fips_test_parse_header(void)
99 {
100         uint32_t i;
101         char *tmp;
102         int ret;
103         int algo_parsed = 0;
104         time_t t = time(NULL);
105         struct tm *tm_now = localtime(&t);
106
107         ret = fips_test_fetch_one_block();
108         if (ret < 0)
109                 return ret;
110
111         for (i = 0; i < info.nb_vec_lines; i++) {
112                 if (!algo_parsed) {
113                         if (strstr(info.vec[i], "AESVS")) {
114                                 algo_parsed = 1;
115                                 info.algo = FIPS_TEST_ALGO_AES;
116                                 ret = parse_test_aes_init();
117                                 if (ret < 0)
118                                         return ret;
119                         } else if (strstr(info.vec[i], "GCM")) {
120                                 algo_parsed = 1;
121                                 info.algo = FIPS_TEST_ALGO_AES_GCM;
122                                 ret = parse_test_gcm_init();
123                                 if (ret < 0)
124                                         return ret;
125                         } else if (strstr(info.vec[i], "CMAC")) {
126                                 algo_parsed = 1;
127                                 info.algo = FIPS_TEST_ALGO_AES_CMAC;
128                                 ret = parse_test_cmac_init();
129                                 if (ret < 0)
130                                         return 0;
131                         } else if (strstr(info.vec[i], "CCM")) {
132                                 algo_parsed = 1;
133                                 info.algo = FIPS_TEST_ALGO_AES_CCM;
134                                 ret = parse_test_ccm_init();
135                                 if (ret < 0)
136                                         return 0;
137                         } else if (strstr(info.vec[i], "HMAC")) {
138                                 algo_parsed = 1;
139                                 info.algo = FIPS_TEST_ALGO_HMAC;
140                                 ret = parse_test_hmac_init();
141                                 if (ret < 0)
142                                         return ret;
143                         } else if (strstr(info.vec[i], "TDES")) {
144                                 algo_parsed = 1;
145                                 info.algo = FIPS_TEST_ALGO_TDES;
146                                 ret = parse_test_tdes_init();
147                                 if (ret < 0)
148                                         return 0;
149                         } else if (strstr(info.vec[i], "PERMUTATION")) {
150                                 algo_parsed = 1;
151                                 info.algo = FIPS_TEST_ALGO_TDES;
152                                 ret = parse_test_tdes_init();
153                                 if (ret < 0)
154                                         return 0;
155                         } else if (strstr(info.vec[i], "VARIABLE")) {
156                                 algo_parsed = 1;
157                                 info.algo = FIPS_TEST_ALGO_TDES;
158                                 ret = parse_test_tdes_init();
159                                 if (ret < 0)
160                                         return 0;
161                         } else if (strstr(info.vec[i], "SUBSTITUTION")) {
162                                 algo_parsed = 1;
163                                 info.algo = FIPS_TEST_ALGO_TDES;
164                                 ret = parse_test_tdes_init();
165                                 if (ret < 0)
166                                         return 0;
167                         } else if (strstr(info.vec[i], "SHA-")) {
168                                 algo_parsed = 1;
169                                 info.algo = FIPS_TEST_ALGO_SHA;
170                                 ret = parse_test_sha_init();
171                                 if (ret < 0)
172                                         return ret;
173                         } else if (strstr(info.vec[i], "XTS")) {
174                                 algo_parsed = 1;
175                                 info.algo = FIPS_TEST_ALGO_AES_XTS;
176                                 ret = parse_test_xts_init();
177                                 if (ret < 0)
178                                         return ret;
179                         }
180                 }
181
182                 tmp = strstr(info.vec[i], "# Config info for ");
183                 if (tmp != NULL) {
184                         fprintf(info.fp_wr, "%s%s\n", "# Config info for DPDK Cryptodev ",
185                                         info.device_name);
186                         continue;
187                 }
188
189                 tmp = strstr(info.vec[i], "#  HMAC information for ");
190                 if (tmp != NULL) {
191                         fprintf(info.fp_wr, "%s%s\n", "#  HMAC information for "
192                                 "DPDK Cryptodev ",
193                                 info.device_name);
194                         continue;
195                 }
196
197                 tmp = strstr(info.vec[i], "# Config Info for : ");
198                 if (tmp != NULL) {
199
200                         fprintf(info.fp_wr, "%s%s\n", "# Config Info for DPDK Cryptodev : ",
201                                         info.device_name);
202                         continue;
203                 }
204
205                 tmp = strstr(info.vec[i], "# information for ");
206                 if (tmp != NULL) {
207
208                         char tmp_output[128] = {0};
209
210                         strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
211
212                         fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
213                                         "information for DPDK Cryptodev ",
214                                         info.device_name);
215                         continue;
216                 }
217
218                 tmp = strstr(info.vec[i], " test information for ");
219                 if (tmp != NULL) {
220                         char tmp_output[128] = {0};
221
222                         strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
223
224                         fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
225                                         "test information for DPDK Cryptodev ",
226                                         info.device_name);
227                         continue;
228                 }
229
230                 tmp = strstr(info.vec[i], "\" information for \"");
231                 if (tmp != NULL) {
232                         char tmp_output[128] = {0};
233
234                         strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
235
236                         fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
237                                         "\" information for DPDK Cryptodev ",
238                                         info.device_name);
239                         continue;
240                 }
241
242                 if (i == info.nb_vec_lines - 1) {
243                         /** update the time as current time, write to file */
244                         fprintf(info.fp_wr, "%s%s\n", "# Generated on ",
245                                         asctime(tm_now));
246                         continue;
247                 }
248
249                 /* to this point, no field need to update,
250                  *  only copy to rsp file
251                  */
252                 fprintf(info.fp_wr, "%s\n", info.vec[i]);
253         }
254
255         return 0;
256 }
257
258 static int
259 parse_file_type(const char *path)
260 {
261         const char *tmp = path + strlen(path) - 3;
262
263         if (strstr(tmp, REQ_FILE_PERFIX))
264                 info.file_type = FIPS_TYPE_REQ;
265         else if (strstr(tmp, RSP_FILE_PERFIX))
266                 info.file_type = FIPS_TYPE_RSP;
267         else if (strstr(path, FAX_FILE_PERFIX))
268                 info.file_type = FIPS_TYPE_FAX;
269         else
270                 return -EINVAL;
271
272         return 0;
273 }
274
275 int
276 fips_test_init(const char *req_file_path, const char *rsp_file_path,
277                 const char *device_name)
278 {
279         if (strcmp(req_file_path, rsp_file_path) == 0) {
280                 RTE_LOG(ERR, USER1, "File paths cannot be the same\n");
281                 return -EINVAL;
282         }
283
284         fips_test_clear();
285
286         if (rte_strscpy(info.file_name, req_file_path,
287                                 sizeof(info.file_name)) < 0) {
288                 RTE_LOG(ERR, USER1, "Path %s too long\n", req_file_path);
289                 return -EINVAL;
290         }
291         info.algo = FIPS_TEST_ALGO_MAX;
292         if (parse_file_type(req_file_path) < 0) {
293                 RTE_LOG(ERR, USER1, "File %s type not supported\n",
294                                 req_file_path);
295                 return -EINVAL;
296         }
297
298         info.fp_rd = fopen(req_file_path, "r");
299         if (!info.fp_rd) {
300                 RTE_LOG(ERR, USER1, "Cannot open file %s\n", req_file_path);
301                 return -EINVAL;
302         }
303
304         info.fp_wr = fopen(rsp_file_path, "w");
305         if (!info.fp_wr) {
306                 RTE_LOG(ERR, USER1, "Cannot open file %s\n", rsp_file_path);
307                 return -EINVAL;
308         }
309
310         info.one_line_text = calloc(1, MAX_LINE_CHAR);
311         if (!info.one_line_text) {
312                 RTE_LOG(ERR, USER1, "Insufficient memory\n");
313                 return -ENOMEM;
314         }
315
316         if (rte_strscpy(info.device_name, device_name,
317                                 sizeof(info.device_name)) < 0) {
318                 RTE_LOG(ERR, USER1, "Device name %s too long\n", device_name);
319                 return -EINVAL;
320         }
321
322         if (fips_test_parse_header() < 0) {
323                 RTE_LOG(ERR, USER1, "Failed parsing header\n");
324                 return -1;
325         }
326
327         return 0;
328 }
329
330 void
331 fips_test_clear(void)
332 {
333         if (info.fp_rd)
334                 fclose(info.fp_rd);
335         if (info.fp_wr)
336                 fclose(info.fp_wr);
337         if (info.one_line_text)
338                 free(info.one_line_text);
339         if (info.nb_vec_lines) {
340                 uint32_t i;
341
342                 for (i = 0; i < info.nb_vec_lines; i++)
343                         free(info.vec[i]);
344         }
345
346         memset(&info, 0, sizeof(info));
347 }
348
349 int
350 fips_test_parse_one_case(void)
351 {
352         uint32_t i, j = 0;
353         uint32_t is_interim;
354         uint32_t interim_cnt = 0;
355         int ret;
356
357         if (info.interim_callbacks) {
358                 for (i = 0; i < info.nb_vec_lines; i++) {
359                         is_interim = 0;
360                         for (j = 0; info.interim_callbacks[j].key != NULL; j++)
361                                 if (strstr(info.vec[i],
362                                         info.interim_callbacks[j].key)) {
363                                         is_interim = 1;
364
365                                         ret = info.interim_callbacks[j].cb(
366                                                 info.interim_callbacks[j].key,
367                                                 info.vec[i],
368                                                 info.interim_callbacks[j].val);
369                                         if (ret < 0)
370                                                 return ret;
371                                 }
372
373                         if (is_interim)
374                                 interim_cnt += 1;
375                 }
376         }
377
378         info.vec_start_off = interim_cnt;
379
380         if (interim_cnt) {
381                 for (i = 0; i < interim_cnt; i++)
382                         fprintf(info.fp_wr, "%s\n", info.vec[i]);
383                 fprintf(info.fp_wr, "\n");
384
385                 if (info.nb_vec_lines == interim_cnt)
386                         return 1;
387         }
388
389         for (i = info.vec_start_off; i < info.nb_vec_lines; i++) {
390                 for (j = 0; info.callbacks[j].key != NULL; j++)
391                         if (strstr(info.vec[i], info.callbacks[j].key)) {
392                                 ret = info.callbacks[j].cb(
393                                         info.callbacks[j].key,
394                                         info.vec[i], info.callbacks[j].val);
395                                 if (ret < 0)
396                                         return ret;
397                                 break;
398                         }
399         }
400
401         return 0;
402 }
403
404 void
405 fips_test_write_one_case(void)
406 {
407         uint32_t i;
408
409         for (i = info.vec_start_off; i < info.nb_vec_lines; i++)
410                 fprintf(info.fp_wr, "%s\n", info.vec[i]);
411 }
412
413 static int
414 parser_read_uint64_hex(uint64_t *value, const char *p)
415 {
416         char *next;
417         uint64_t val;
418
419         p = skip_white_spaces(p);
420
421         val = strtoul(p, &next, 16);
422         if (p == next)
423                 return -EINVAL;
424
425         p = skip_white_spaces(next);
426         if (*p != '\0')
427                 return -EINVAL;
428
429         *value = val;
430         return 0;
431 }
432
433 int
434 parser_read_uint8_hex(uint8_t *value, const char *p)
435 {
436         uint64_t val = 0;
437         int ret = parser_read_uint64_hex(&val, p);
438
439         if (ret < 0)
440                 return ret;
441
442         if (val > UINT8_MAX)
443                 return -ERANGE;
444
445         *value = val;
446         return 0;
447 }
448
449 int
450 parse_uint8_known_len_hex_str(const char *key, char *src, struct fips_val *val)
451 {
452         struct fips_val tmp_val = {0};
453         uint32_t len = val->len;
454         int ret;
455
456         if (len == 0) {
457                 if (val->val != NULL) {
458                         rte_free(val->val);
459                         val->val = NULL;
460                 }
461
462                 return 0;
463         }
464
465         ret = parse_uint8_hex_str(key, src, &tmp_val);
466         if (ret < 0)
467                 return ret;
468
469         if (tmp_val.len == val->len) {
470                 val->val = tmp_val.val;
471                 return 0;
472         }
473
474         if (tmp_val.len < val->len) {
475                 rte_free(tmp_val.val);
476                 return -EINVAL;
477         }
478
479         val->val = rte_zmalloc(NULL, val->len, 0);
480         if (!val->val) {
481                 rte_free(tmp_val.val);
482                 memset(val, 0, sizeof(*val));
483                 return -ENOMEM;
484         }
485
486         memcpy(val->val, tmp_val.val, val->len);
487         rte_free(tmp_val.val);
488
489         return 0;
490 }
491
492 int
493 parse_uint8_hex_str(const char *key, char *src, struct fips_val *val)
494 {
495         uint32_t len, j;
496
497         src += strlen(key);
498
499         len = strlen(src) / 2;
500
501         if (val->val) {
502                 rte_free(val->val);
503                 val->val = NULL;
504         }
505
506         val->val = rte_zmalloc(NULL, len, 0);
507         if (!val->val)
508                 return -ENOMEM;
509
510         for (j = 0; j < len; j++) {
511                 char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
512
513                 if (parser_read_uint8_hex(&val->val[j], byte) < 0) {
514                         rte_free(val->val);
515                         memset(val, 0, sizeof(*val));
516                         return -EINVAL;
517                 }
518         }
519
520         val->len = len;
521
522         return 0;
523 }
524
525 int
526 parser_read_uint32_val(const char *key, char *src, struct fips_val *val)
527 {
528         char *data = src + strlen(key);
529         size_t data_len = strlen(data);
530         int ret;
531
532         if (data[data_len - 1] == ']') {
533                 char *tmp_data = calloc(1, data_len + 1);
534
535                 if (tmp_data == NULL)
536                         return -ENOMEM;
537
538                 strlcpy(tmp_data, data, data_len);
539
540                 ret = parser_read_uint32(&val->len, tmp_data);
541
542                 free(tmp_data);
543         } else
544                 ret = parser_read_uint32(&val->len, data);
545
546         return ret;
547 }
548
549 int
550 parser_read_uint32_bit_val(const char *key, char *src, struct fips_val *val)
551 {
552         int ret;
553
554         ret = parser_read_uint32_val(key, src, val);
555
556         if (ret < 0)
557                 return ret;
558
559         val->len /= 8;
560
561         return 0;
562 }
563
564 int
565 writeback_hex_str(const char *key, char *dst, struct fips_val *val)
566 {
567         char *str = dst;
568         uint32_t len;
569
570         str += strlen(key);
571
572         for (len = 0; len < val->len; len++)
573                 snprintf(str + len * 2, 255, "%02x", val->val[len]);
574
575         return 0;
576 }
577
578 static int
579 parser_read_uint64(uint64_t *value, const char *p)
580 {
581         char *next;
582         uint64_t val;
583
584         p = skip_white_spaces(p);
585         if (!isdigit(*p))
586                 return -EINVAL;
587
588         val = strtoul(p, &next, 10);
589         if (p == next)
590                 return -EINVAL;
591
592         p = next;
593         switch (*p) {
594         case 'T':
595                 val *= 1024ULL;
596                 /* fall through */
597         case 'G':
598                 val *= 1024ULL;
599                 /* fall through */
600         case 'M':
601                 val *= 1024ULL;
602                 /* fall through */
603         case 'k':
604         case 'K':
605                 val *= 1024ULL;
606                 p++;
607                 break;
608         }
609
610         p = skip_white_spaces(p);
611         if (*p != '\0')
612                 return -EINVAL;
613
614         *value = val;
615         return 0;
616 }
617
618 int
619 parser_read_uint32(uint32_t *value, char *p)
620 {
621         uint64_t val = 0;
622         int ret = parser_read_uint64(&val, p);
623
624         if (ret < 0)
625                 return ret;
626
627         if (val > UINT32_MAX)
628                 return -EINVAL;
629
630         *value = val;
631         return 0;
632 }
633
634 void
635 parse_write_hex_str(struct fips_val *src)
636 {
637         writeback_hex_str("", info.one_line_text, src);
638
639         fprintf(info.fp_wr, "%s\n", info.one_line_text);
640 }
641
642 int
643 update_info_vec(uint32_t count)
644 {
645         const struct fips_test_callback *cb;
646         uint32_t i, j;
647
648         if (!info.writeback_callbacks)
649                 return -1;
650
651         cb = &info.writeback_callbacks[0];
652
653         if (!(strstr(info.vec[0], cb->key))) {
654                 fprintf(info.fp_wr, "%s%u\n", cb->key, count);
655                 i = 0;
656         } else {
657                 snprintf(info.vec[0], strlen(info.vec[0]) + 4, "%s%u", cb->key,
658                                 count);
659                 i = 1;
660         }
661         snprintf(info.vec[0], strlen(info.vec[0]) + 4, "%s%u", cb->key, count);
662
663         for (i = 1; i < info.nb_vec_lines; i++) {
664                 for (j = 1; info.writeback_callbacks[j].key != NULL; j++) {
665                         cb = &info.writeback_callbacks[j];
666                         if (strstr(info.vec[i], cb->key)) {
667                                 cb->cb(cb->key, info.vec[i], cb->val);
668                                 break;
669                         }
670                 }
671         }
672
673         return 0;
674 }