xref: /dpdk/examples/fips_validation/fips_validation.c (revision 12ede9ac497fed989a1f4d0357e839cbe7d1e45b)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4 
5 #include <ctype.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include <rte_string_fns.h>
11 #include <rte_cryptodev.h>
12 #include <rte_malloc.h>
13 
14 #include "fips_validation.h"
15 
16 static int
17 get_file_line(void)
18 {
19 	FILE *fp = info.fp_rd;
20 	char *line = info.one_line_text;
21 	int ret;
22 	uint32_t loc = 0;
23 
24 	memset(line, 0, MAX_LINE_CHAR);
25 	while ((ret = fgetc(fp)) != EOF) {
26 		char c = (char)ret;
27 
28 		if (loc >= MAX_LINE_CHAR - 1)
29 			return -ENOMEM;
30 		if (c == '\n')
31 			break;
32 		line[loc++] = c;
33 	}
34 
35 	if (ret == EOF)
36 		return -EOF;
37 
38 	return 0;
39 }
40 
41 int
42 fips_test_fetch_one_block(void)
43 {
44 	size_t size;
45 	int ret = 0;
46 	uint32_t i;
47 
48 	for (i = 0; i < info.nb_vec_lines; i++) {
49 		free(info.vec[i]);
50 		info.vec[i] = NULL;
51 	}
52 
53 	i = 0;
54 	do {
55 		if (i >= MAX_LINE_PER_VECTOR) {
56 			ret = -ENOMEM;
57 			goto error_exit;
58 		}
59 
60 		ret = get_file_line();
61 		size = strlen(info.one_line_text);
62 		if (size == 0)
63 			break;
64 
65 		info.vec[i] = calloc(1, size + 5);
66 		if (info.vec[i] == NULL)
67 			goto error_exit;
68 
69 		strlcpy(info.vec[i], info.one_line_text, size + 1);
70 		i++;
71 	} while (ret == 0);
72 
73 	info.nb_vec_lines = i;
74 
75 	return ret;
76 
77 error_exit:
78 	for (i = 0; i < MAX_LINE_PER_VECTOR; i++)
79 		if (info.vec[i] != NULL) {
80 			free(info.vec[i]);
81 			info.vec[i] = NULL;
82 		}
83 
84 	info.nb_vec_lines = 0;
85 
86 	return -ENOMEM;
87 }
88 
89 static void
90 fips_test_parse_version(void)
91 {
92 	int len = strlen(info.vec[0]);
93 	char *ptr = info.vec[0];
94 
95 	info.version = strtof(ptr + len - 4, NULL);
96 }
97 
98 static int
99 fips_test_parse_header(void)
100 {
101 	uint32_t i;
102 	char *tmp;
103 	int ret;
104 	int algo_parsed = 0;
105 	time_t t = time(NULL);
106 	struct tm *tm_now = localtime(&t);
107 
108 	ret = fips_test_fetch_one_block();
109 	if (ret < 0)
110 		return ret;
111 
112 	if (info.nb_vec_lines)
113 		fips_test_parse_version();
114 
115 	for (i = 0; i < info.nb_vec_lines; i++) {
116 		if (!algo_parsed) {
117 			if (strstr(info.vec[i], "AES")) {
118 				algo_parsed = 1;
119 				info.algo = FIPS_TEST_ALGO_AES;
120 				ret = parse_test_aes_init();
121 				if (ret < 0)
122 					return ret;
123 			} else if (strstr(info.vec[i], "GCM")) {
124 				algo_parsed = 1;
125 				info.algo = FIPS_TEST_ALGO_AES_GCM;
126 				ret = parse_test_gcm_init();
127 				if (ret < 0)
128 					return ret;
129 			} else if (strstr(info.vec[i], "CMAC")) {
130 				algo_parsed = 1;
131 				info.algo = FIPS_TEST_ALGO_AES_CMAC;
132 				ret = parse_test_cmac_init();
133 				if (ret < 0)
134 					return 0;
135 			} else if (strstr(info.vec[i], "CCM")) {
136 				algo_parsed = 1;
137 				info.algo = FIPS_TEST_ALGO_AES_CCM;
138 				ret = parse_test_ccm_init();
139 				if (ret < 0)
140 					return 0;
141 			} else if (strstr(info.vec[i], "HMAC")) {
142 				algo_parsed = 1;
143 				info.algo = FIPS_TEST_ALGO_HMAC;
144 				ret = parse_test_hmac_init();
145 				if (ret < 0)
146 					return ret;
147 			} else if (strstr(info.vec[i], "TDES")) {
148 				algo_parsed = 1;
149 				info.algo = FIPS_TEST_ALGO_TDES;
150 				ret = parse_test_tdes_init();
151 				if (ret < 0)
152 					return 0;
153 			} else if (strstr(info.vec[i], "PERMUTATION")) {
154 				algo_parsed = 1;
155 				info.algo = FIPS_TEST_ALGO_TDES;
156 				ret = parse_test_tdes_init();
157 				if (ret < 0)
158 					return 0;
159 			} else if (strstr(info.vec[i], "VARIABLE")) {
160 				algo_parsed = 1;
161 				info.algo = FIPS_TEST_ALGO_TDES;
162 				ret = parse_test_tdes_init();
163 				if (ret < 0)
164 					return 0;
165 			} else if (strstr(info.vec[i], "SUBSTITUTION")) {
166 				algo_parsed = 1;
167 				info.algo = FIPS_TEST_ALGO_TDES;
168 				ret = parse_test_tdes_init();
169 				if (ret < 0)
170 					return 0;
171 			} else if (strstr(info.vec[i], "SHA-")) {
172 				algo_parsed = 1;
173 				info.algo = FIPS_TEST_ALGO_SHA;
174 				ret = parse_test_sha_init();
175 				if (ret < 0)
176 					return ret;
177 			} else if (strstr(info.vec[i], "XTS")) {
178 				algo_parsed = 1;
179 				info.algo = FIPS_TEST_ALGO_AES_XTS;
180 				ret = parse_test_xts_init();
181 				if (ret < 0)
182 					return ret;
183 			}
184 		}
185 
186 		tmp = strstr(info.vec[i], "# Config info for ");
187 		if (tmp != NULL) {
188 			fprintf(info.fp_wr, "%s%s\n", "# Config info for DPDK Cryptodev ",
189 					info.device_name);
190 			continue;
191 		}
192 
193 		tmp = strstr(info.vec[i], "#  HMAC information for ");
194 		if (tmp != NULL) {
195 			fprintf(info.fp_wr, "%s%s\n", "#  HMAC information for "
196 				"DPDK Cryptodev ",
197 				info.device_name);
198 			continue;
199 		}
200 
201 		tmp = strstr(info.vec[i], "# Config Info for : ");
202 		if (tmp != NULL) {
203 
204 			fprintf(info.fp_wr, "%s%s\n", "# Config Info for DPDK Cryptodev : ",
205 					info.device_name);
206 			continue;
207 		}
208 
209 		tmp = strstr(info.vec[i], "# information for ");
210 		if (tmp != NULL) {
211 
212 			char tmp_output[128] = {0};
213 
214 			strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
215 
216 			fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
217 					"information for DPDK Cryptodev ",
218 					info.device_name);
219 			continue;
220 		}
221 
222 		tmp = strstr(info.vec[i], " test information for ");
223 		if (tmp != NULL) {
224 			char tmp_output[128] = {0};
225 
226 			strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
227 
228 			fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
229 					"test information for DPDK Cryptodev ",
230 					info.device_name);
231 			continue;
232 		}
233 
234 		tmp = strstr(info.vec[i], "\" information for \"");
235 		if (tmp != NULL) {
236 			char tmp_output[128] = {0};
237 
238 			strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
239 
240 			fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
241 					"\" information for DPDK Cryptodev ",
242 					info.device_name);
243 			continue;
244 		}
245 
246 		if (i == info.nb_vec_lines - 1) {
247 			/** update the time as current time, write to file */
248 			fprintf(info.fp_wr, "%s%s\n", "# Generated on ",
249 					asctime(tm_now));
250 			continue;
251 		}
252 
253 		/* to this point, no field need to update,
254 		 *  only copy to rsp file
255 		 */
256 		fprintf(info.fp_wr, "%s\n", info.vec[i]);
257 	}
258 
259 	return 0;
260 }
261 
262 static int
263 parse_file_type(const char *path)
264 {
265 	const char *tmp = path + strlen(path) - 3;
266 
267 	if (strstr(tmp, REQ_FILE_PREFIX))
268 		info.file_type = FIPS_TYPE_REQ;
269 	else if (strstr(tmp, RSP_FILE_PREFIX))
270 		info.file_type = FIPS_TYPE_RSP;
271 	else if (strstr(path, FAX_FILE_PREFIX))
272 		info.file_type = FIPS_TYPE_FAX;
273 	else if (strstr(path, JSON_FILE_PREFIX))
274 		info.file_type = FIPS_TYPE_JSON;
275 	else
276 		return -EINVAL;
277 
278 	return 0;
279 }
280 
281 int
282 fips_test_init(const char *req_file_path, const char *rsp_file_path,
283 		const char *device_name)
284 {
285 	if (strcmp(req_file_path, rsp_file_path) == 0) {
286 		RTE_LOG(ERR, USER1, "File paths cannot be the same\n");
287 		return -EINVAL;
288 	}
289 
290 	fips_test_clear();
291 
292 	if (rte_strscpy(info.file_name, req_file_path,
293 				sizeof(info.file_name)) < 0) {
294 		RTE_LOG(ERR, USER1, "Path %s too long\n", req_file_path);
295 		return -EINVAL;
296 	}
297 	info.algo = FIPS_TEST_ALGO_MAX;
298 	if (parse_file_type(req_file_path) < 0) {
299 		RTE_LOG(ERR, USER1, "File %s type not supported\n",
300 				req_file_path);
301 		return -EINVAL;
302 	}
303 
304 	info.fp_rd = fopen(req_file_path, "r");
305 	if (!info.fp_rd) {
306 		RTE_LOG(ERR, USER1, "Cannot open file %s\n", req_file_path);
307 		return -EINVAL;
308 	}
309 
310 	if (info.file_type == FIPS_TYPE_JSON) {
311 #ifdef USE_JANSSON
312 		json_error_t error;
313 		json_info.json_root = json_loadf(info.fp_rd, 0, &error);
314 		if (!json_info.json_root) {
315 			RTE_LOG(ERR, USER1, "Cannot parse json file %s (line %d, column %d)\n",
316 				req_file_path, error.line, error.column);
317 			return -EINVAL;
318 		}
319 #else /* USE_JANSSON */
320 		RTE_LOG(ERR, USER1, "No json library configured.\n");
321 		return -EINVAL;
322 #endif /* USE_JANSSON */
323 	}
324 
325 	info.fp_wr = fopen(rsp_file_path, "w");
326 	if (!info.fp_wr) {
327 		RTE_LOG(ERR, USER1, "Cannot open file %s\n", rsp_file_path);
328 		return -EINVAL;
329 	}
330 
331 	info.one_line_text = calloc(1, MAX_LINE_CHAR);
332 	if (!info.one_line_text) {
333 		RTE_LOG(ERR, USER1, "Insufficient memory\n");
334 		return -ENOMEM;
335 	}
336 
337 	if (rte_strscpy(info.device_name, device_name,
338 				sizeof(info.device_name)) < 0) {
339 		RTE_LOG(ERR, USER1, "Device name %s too long\n", device_name);
340 		return -EINVAL;
341 	}
342 
343 	if (info.file_type == FIPS_TYPE_JSON)
344 		return 0;
345 
346 	if (fips_test_parse_header() < 0) {
347 		RTE_LOG(ERR, USER1, "Failed parsing header\n");
348 		return -1;
349 	}
350 
351 	return 0;
352 }
353 
354 void
355 fips_test_clear(void)
356 {
357 	if (info.fp_rd)
358 		fclose(info.fp_rd);
359 	if (info.fp_wr)
360 		fclose(info.fp_wr);
361 	free(info.one_line_text);
362 	if (info.nb_vec_lines) {
363 		uint32_t i;
364 
365 		for (i = 0; i < info.nb_vec_lines; i++)
366 			free(info.vec[i]);
367 	}
368 
369 	memset(&info, 0, sizeof(info));
370 }
371 
372 int
373 fips_test_parse_one_case(void)
374 {
375 	uint32_t i, j = 0;
376 	uint32_t is_interim;
377 	uint32_t interim_cnt = 0;
378 	int ret;
379 
380 	info.vec_start_off = 0;
381 
382 	if (info.interim_callbacks) {
383 		for (i = 0; i < info.nb_vec_lines; i++) {
384 			is_interim = 0;
385 			for (j = 0; info.interim_callbacks[j].key != NULL; j++)
386 				if (strstr(info.vec[i],
387 					info.interim_callbacks[j].key)) {
388 					is_interim = 1;
389 
390 					ret = info.interim_callbacks[j].cb(
391 						info.interim_callbacks[j].key,
392 						info.vec[i],
393 						info.interim_callbacks[j].val);
394 					if (ret < 0)
395 						return ret;
396 				}
397 
398 			if (is_interim)
399 				interim_cnt += 1;
400 		}
401 	}
402 
403 	if (interim_cnt) {
404 		if (info.version == 21.4f) {
405 			for (i = 0; i < interim_cnt; i++)
406 				fprintf(info.fp_wr, "%s\n", info.vec[i]);
407 			fprintf(info.fp_wr, "\n");
408 
409 			if (info.nb_vec_lines == interim_cnt)
410 				return 1;
411 		} else {
412 			for (i = 0; i < info.nb_vec_lines; i++)
413 				fprintf(info.fp_wr, "%s\n", info.vec[i]);
414 			fprintf(info.fp_wr, "\n");
415 			return 1;
416 		}
417 	}
418 
419 	info.vec_start_off = interim_cnt;
420 
421 	for (i = info.vec_start_off; i < info.nb_vec_lines; i++) {
422 		for (j = 0; info.callbacks[j].key != NULL; j++)
423 			if (strstr(info.vec[i], info.callbacks[j].key)) {
424 				ret = info.callbacks[j].cb(
425 					info.callbacks[j].key,
426 					info.vec[i], info.callbacks[j].val);
427 				if (ret < 0)
428 					return ret;
429 				break;
430 			}
431 	}
432 
433 	return 0;
434 }
435 
436 void
437 fips_test_write_one_case(void)
438 {
439 	uint32_t i;
440 
441 	for (i = info.vec_start_off; i < info.nb_vec_lines; i++)
442 		fprintf(info.fp_wr, "%s\n", info.vec[i]);
443 }
444 
445 #ifdef USE_JANSSON
446 int
447 fips_test_parse_one_json_vector_set(void)
448 {
449 	json_t *algo_obj = json_object_get(json_info.json_vector_set, "algorithm");
450 	const char *algo_str = json_string_value(algo_obj);
451 
452 	/* Vector sets contain the algorithm type, and nothing else we need. */
453 	if (strstr(algo_str, "AES-GCM"))
454 		info.algo = FIPS_TEST_ALGO_AES_GCM;
455 	else if (strstr(algo_str, "AES-CCM"))
456 		info.algo = FIPS_TEST_ALGO_AES_CCM;
457 	else if (strstr(algo_str, "AES-GMAC"))
458 		info.algo = FIPS_TEST_ALGO_AES_GMAC;
459 	else if (strstr(algo_str, "HMAC"))
460 		info.algo = FIPS_TEST_ALGO_HMAC;
461 	else if (strstr(algo_str, "CMAC"))
462 		info.algo = FIPS_TEST_ALGO_AES_CMAC;
463 	else if (strstr(algo_str, "AES-CBC"))
464 		info.algo = FIPS_TEST_ALGO_AES_CBC;
465 	else if (strstr(algo_str, "AES-XTS"))
466 		info.algo = FIPS_TEST_ALGO_AES_XTS;
467 	else if (strstr(algo_str, "AES-CTR"))
468 		info.algo = FIPS_TEST_ALGO_AES_CTR;
469 	else if (strstr(algo_str, "SHA"))
470 		info.algo = FIPS_TEST_ALGO_SHA;
471 	else if (strstr(algo_str, "TDES-CBC") ||
472 		strstr(algo_str, "TDES-ECB"))
473 		info.algo = FIPS_TEST_ALGO_TDES;
474 	else if (strstr(algo_str, "RSA"))
475 		info.algo = FIPS_TEST_ALGO_RSA;
476 	else if (strstr(algo_str, "ECDSA"))
477 		info.algo = FIPS_TEST_ALGO_ECDSA;
478 	else if (strstr(algo_str, "EDDSA"))
479 		info.algo = FIPS_TEST_ALGO_EDDSA;
480 	else
481 		return -EINVAL;
482 
483 	return 0;
484 }
485 
486 int
487 fips_test_parse_one_json_group(void)
488 {
489 	int ret, i;
490 	json_t *param;
491 
492 	if (info.interim_callbacks) {
493 		char json_value[FIPS_TEST_JSON_BUF_LEN];
494 		for (i = 0; info.interim_callbacks[i].key != NULL; i++) {
495 			param = json_object_get(json_info.json_test_group,
496 					info.interim_callbacks[i].key);
497 			if (!param)
498 				continue;
499 
500 			switch (json_typeof(param)) {
501 			case JSON_STRING:
502 				snprintf(json_value, sizeof(json_value), "%s",
503 						 json_string_value(param));
504 				break;
505 
506 			case JSON_INTEGER:
507 				snprintf(json_value, sizeof(json_value), "%"JSON_INTEGER_FORMAT,
508 						json_integer_value(param));
509 				break;
510 
511 			default:
512 				return -EINVAL;
513 			}
514 
515 			ret = info.interim_callbacks[i].cb(
516 				info.interim_callbacks[i].key, json_value,
517 				info.interim_callbacks[i].val
518 			);
519 			if (ret < 0)
520 				return ret;
521 		}
522 
523 		if (info.parse_interim_writeback) {
524 			ret = info.parse_interim_writeback(NULL);
525 			if (ret < 0)
526 				return ret;
527 		}
528 	}
529 
530 	return 0;
531 }
532 
533 int
534 fips_test_parse_one_json_case(void)
535 {
536 	uint32_t i;
537 	int ret = 0;
538 	json_t *param;
539 
540 	for (i = 0; info.callbacks[i].key != NULL; i++) {
541 		param = json_object_get(json_info.json_test_case, info.callbacks[i].key);
542 		if (!param)
543 			continue;
544 
545 		switch (json_typeof(param)) {
546 		case JSON_STRING:
547 			snprintf(info.one_line_text, MAX_LINE_CHAR, "%s",
548 					 json_string_value(param));
549 			break;
550 
551 		case JSON_INTEGER:
552 			snprintf(info.one_line_text, MAX_LINE_CHAR, "%"JSON_INTEGER_FORMAT,
553 					 json_integer_value(param));
554 			break;
555 
556 		default:
557 			return -EINVAL;
558 		}
559 
560 		ret = info.callbacks[i].cb(info.callbacks[i].key, info.one_line_text,
561 				info.callbacks[i].val);
562 		if (ret < 0)
563 			return ret;
564 	}
565 
566 	return 0;
567 }
568 #endif /* USE_JANSSON */
569 
570 static int
571 parser_read_uint64_hex(uint64_t *value, const char *p)
572 {
573 	char *next;
574 	uint64_t val;
575 
576 	p = rte_str_skip_leading_spaces(p);
577 
578 	val = strtoul(p, &next, 16);
579 	if (p == next)
580 		return -EINVAL;
581 
582 	p = rte_str_skip_leading_spaces(next);
583 	if (*p != '\0')
584 		return -EINVAL;
585 
586 	*value = val;
587 	return 0;
588 }
589 
590 int
591 parser_read_uint8_hex(uint8_t *value, const char *p)
592 {
593 	uint64_t val = 0;
594 	int ret = parser_read_uint64_hex(&val, p);
595 
596 	if (ret < 0)
597 		return ret;
598 
599 	if (val > UINT8_MAX)
600 		return -ERANGE;
601 
602 	*value = val;
603 	return 0;
604 }
605 
606 int
607 parse_uint8_known_len_hex_str(const char *key, char *src, struct fips_val *val)
608 {
609 	struct fips_val tmp_val = {0};
610 	uint32_t len = val->len;
611 	int ret;
612 
613 	if (len == 0) {
614 		if (val->val != NULL) {
615 			rte_free(val->val);
616 			val->val = NULL;
617 		}
618 
619 		return 0;
620 	}
621 
622 	ret = parse_uint8_hex_str(key, src, &tmp_val);
623 	if (ret < 0)
624 		return ret;
625 
626 	if (tmp_val.len == val->len) {
627 		val->val = tmp_val.val;
628 		return 0;
629 	}
630 
631 	if (tmp_val.len < val->len) {
632 		rte_free(tmp_val.val);
633 		return -EINVAL;
634 	}
635 
636 	val->val = rte_zmalloc(NULL, val->len, 0);
637 	if (!val->val) {
638 		rte_free(tmp_val.val);
639 		memset(val, 0, sizeof(*val));
640 		return -ENOMEM;
641 	}
642 
643 	memcpy(val->val, tmp_val.val, val->len);
644 	rte_free(tmp_val.val);
645 
646 	return 0;
647 }
648 
649 int
650 parse_uint8_hex_str(const char *key, char *src, struct fips_val *val)
651 {
652 	uint32_t len, j;
653 
654 #ifdef USE_JANSSON
655 	/*
656 	 * Offset not applicable in case of JSON test vectors.
657 	 */
658 	if (info.file_type == FIPS_TYPE_JSON) {
659 		RTE_SET_USED(key);
660 	} else
661 #endif
662 		src += strlen(key);
663 
664 	len = strlen(src) / 2;
665 
666 	if (val->val) {
667 		rte_free(val->val);
668 		val->val = NULL;
669 	}
670 
671 	val->val = rte_zmalloc(NULL, len + 1, 0);
672 	if (!val->val)
673 		return -ENOMEM;
674 
675 	for (j = 0; j < len; j++) {
676 		char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
677 
678 		if (parser_read_uint8_hex(&val->val[j], byte) < 0) {
679 			rte_free(val->val);
680 			memset(val, 0, sizeof(*val));
681 			return -EINVAL;
682 		}
683 	}
684 
685 	val->len = len;
686 
687 	return 0;
688 }
689 
690 int
691 parser_read_uint32_val(const char *key, char *src, struct fips_val *val)
692 {
693 #ifdef USE_JANSSON
694 	if (info.file_type == FIPS_TYPE_JSON) {
695 		RTE_SET_USED(key);
696 
697 		return parser_read_uint32(&val->len, src);
698 	}
699 # endif
700 	char *data = src + strlen(key);
701 	size_t data_len = strlen(data);
702 	int ret;
703 
704 	if (data[data_len - 1] == ']') {
705 		char *tmp_data = calloc(1, data_len + 1);
706 
707 		if (tmp_data == NULL)
708 			return -ENOMEM;
709 
710 		strlcpy(tmp_data, data, data_len);
711 
712 		ret = parser_read_uint32(&val->len, tmp_data);
713 
714 		free(tmp_data);
715 	} else
716 		ret = parser_read_uint32(&val->len, data);
717 
718 	return ret;
719 }
720 
721 int
722 parser_read_uint32_bit_val(const char *key, char *src, struct fips_val *val)
723 {
724 	int ret;
725 
726 	ret = parser_read_uint32_val(key, src, val);
727 
728 	if (ret < 0)
729 		return ret;
730 
731 	val->len /= 8;
732 
733 	return 0;
734 }
735 
736 int
737 writeback_hex_str(const char *key, char *dst, struct fips_val *val)
738 {
739 	char *str = dst;
740 	uint32_t len;
741 
742 	str += strlen(key);
743 
744 	for (len = 0; len < val->len; len++)
745 		snprintf(str + len * 2, 255, "%02x", val->val[len]);
746 
747 	return 0;
748 }
749 
750 static int
751 parser_read_uint64(uint64_t *value, const char *p)
752 {
753 	char *next;
754 	uint64_t val;
755 
756 	p = rte_str_skip_leading_spaces(p);
757 	if (!isdigit(*p))
758 		return -EINVAL;
759 
760 	val = strtoul(p, &next, 10);
761 	if (p == next)
762 		return -EINVAL;
763 
764 	p = next;
765 	switch (*p) {
766 	case 'T':
767 		val *= 1024ULL;
768 		/* fall through */
769 	case 'G':
770 		val *= 1024ULL;
771 		/* fall through */
772 	case 'M':
773 		val *= 1024ULL;
774 		/* fall through */
775 	case 'k':
776 	case 'K':
777 		val *= 1024ULL;
778 		p++;
779 		break;
780 	}
781 
782 	p = rte_str_skip_leading_spaces(p);
783 	if (*p != '\0')
784 		return -EINVAL;
785 
786 	*value = val;
787 	return 0;
788 }
789 
790 int
791 parser_read_uint32(uint32_t *value, char *p)
792 {
793 	uint64_t val = 0;
794 	int ret = parser_read_uint64(&val, p);
795 
796 	if (ret < 0)
797 		return ret;
798 
799 	if (val > UINT32_MAX)
800 		return -EINVAL;
801 
802 	*value = val;
803 	return 0;
804 }
805 
806 int
807 parser_read_uint16(uint16_t *value, const char *p)
808 {
809 	uint64_t val = 0;
810 	int ret = parser_read_uint64(&val, p);
811 
812 	if (ret < 0)
813 		return ret;
814 
815 	if (val > UINT16_MAX)
816 		return -ERANGE;
817 
818 	*value = val;
819 	return 0;
820 }
821 
822 void
823 parse_write_hex_str(struct fips_val *src)
824 {
825 	writeback_hex_str("", info.one_line_text, src);
826 
827 	fprintf(info.fp_wr, "%s\n", info.one_line_text);
828 }
829 
830 int
831 update_info_vec(uint32_t count)
832 {
833 	const struct fips_test_callback *cb;
834 	uint32_t i, j;
835 
836 	if (!info.writeback_callbacks)
837 		return -1;
838 
839 	cb = &info.writeback_callbacks[0];
840 
841 	if ((info.version == 21.4f) && (!(strstr(info.vec[0], cb->key)))) {
842 		fprintf(info.fp_wr, "%s%u\n", cb->key, count);
843 		i = 0;
844 	} else {
845 		snprintf(info.vec[0], strlen(info.vec[0]) + 4, "%s%u", cb->key,
846 				count);
847 		i = 1;
848 	}
849 
850 	for (; i < info.nb_vec_lines; i++) {
851 		for (j = 1; info.writeback_callbacks[j].key != NULL; j++) {
852 			cb = &info.writeback_callbacks[j];
853 			if (strstr(info.vec[i], cb->key)) {
854 				cb->cb(cb->key, info.vec[i], cb->val);
855 				break;
856 			}
857 		}
858 	}
859 
860 	return 0;
861 }
862