xref: /dpdk/examples/fips_validation/fips_validation.c (revision e9fd1ebf981f361844aea9ec94e17f4bda5e1479)
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
479 		return -EINVAL;
480 
481 	return 0;
482 }
483 
484 int
485 fips_test_parse_one_json_group(void)
486 {
487 	int ret, i;
488 	json_t *param;
489 
490 	if (info.interim_callbacks) {
491 		char json_value[FIPS_TEST_JSON_BUF_LEN];
492 		for (i = 0; info.interim_callbacks[i].key != NULL; i++) {
493 			param = json_object_get(json_info.json_test_group,
494 					info.interim_callbacks[i].key);
495 			if (!param)
496 				continue;
497 
498 			switch (json_typeof(param)) {
499 			case JSON_STRING:
500 				snprintf(json_value, sizeof(json_value), "%s",
501 						 json_string_value(param));
502 				break;
503 
504 			case JSON_INTEGER:
505 				snprintf(json_value, sizeof(json_value), "%"JSON_INTEGER_FORMAT,
506 						json_integer_value(param));
507 				break;
508 
509 			default:
510 				return -EINVAL;
511 			}
512 
513 			ret = info.interim_callbacks[i].cb(
514 				info.interim_callbacks[i].key, json_value,
515 				info.interim_callbacks[i].val
516 			);
517 			if (ret < 0)
518 				return ret;
519 		}
520 
521 		if (info.parse_interim_writeback) {
522 			ret = info.parse_interim_writeback(NULL);
523 			if (ret < 0)
524 				return ret;
525 		}
526 	}
527 
528 	return 0;
529 }
530 
531 int
532 fips_test_parse_one_json_case(void)
533 {
534 	uint32_t i;
535 	int ret = 0;
536 	json_t *param;
537 
538 	for (i = 0; info.callbacks[i].key != NULL; i++) {
539 		param = json_object_get(json_info.json_test_case, info.callbacks[i].key);
540 		if (!param)
541 			continue;
542 
543 		switch (json_typeof(param)) {
544 		case JSON_STRING:
545 			snprintf(info.one_line_text, MAX_LINE_CHAR, "%s",
546 					 json_string_value(param));
547 			break;
548 
549 		case JSON_INTEGER:
550 			snprintf(info.one_line_text, MAX_LINE_CHAR, "%"JSON_INTEGER_FORMAT,
551 					 json_integer_value(param));
552 			break;
553 
554 		default:
555 			return -EINVAL;
556 		}
557 
558 		ret = info.callbacks[i].cb(info.callbacks[i].key, info.one_line_text,
559 				info.callbacks[i].val);
560 		if (ret < 0)
561 			return ret;
562 	}
563 
564 	return 0;
565 }
566 #endif /* USE_JANSSON */
567 
568 static int
569 parser_read_uint64_hex(uint64_t *value, const char *p)
570 {
571 	char *next;
572 	uint64_t val;
573 
574 	p = rte_str_skip_leading_spaces(p);
575 
576 	val = strtoul(p, &next, 16);
577 	if (p == next)
578 		return -EINVAL;
579 
580 	p = rte_str_skip_leading_spaces(next);
581 	if (*p != '\0')
582 		return -EINVAL;
583 
584 	*value = val;
585 	return 0;
586 }
587 
588 int
589 parser_read_uint8_hex(uint8_t *value, const char *p)
590 {
591 	uint64_t val = 0;
592 	int ret = parser_read_uint64_hex(&val, p);
593 
594 	if (ret < 0)
595 		return ret;
596 
597 	if (val > UINT8_MAX)
598 		return -ERANGE;
599 
600 	*value = val;
601 	return 0;
602 }
603 
604 int
605 parse_uint8_known_len_hex_str(const char *key, char *src, struct fips_val *val)
606 {
607 	struct fips_val tmp_val = {0};
608 	uint32_t len = val->len;
609 	int ret;
610 
611 	if (len == 0) {
612 		if (val->val != NULL) {
613 			rte_free(val->val);
614 			val->val = NULL;
615 		}
616 
617 		return 0;
618 	}
619 
620 	ret = parse_uint8_hex_str(key, src, &tmp_val);
621 	if (ret < 0)
622 		return ret;
623 
624 	if (tmp_val.len == val->len) {
625 		val->val = tmp_val.val;
626 		return 0;
627 	}
628 
629 	if (tmp_val.len < val->len) {
630 		rte_free(tmp_val.val);
631 		return -EINVAL;
632 	}
633 
634 	val->val = rte_zmalloc(NULL, val->len, 0);
635 	if (!val->val) {
636 		rte_free(tmp_val.val);
637 		memset(val, 0, sizeof(*val));
638 		return -ENOMEM;
639 	}
640 
641 	memcpy(val->val, tmp_val.val, val->len);
642 	rte_free(tmp_val.val);
643 
644 	return 0;
645 }
646 
647 int
648 parse_uint8_hex_str(const char *key, char *src, struct fips_val *val)
649 {
650 	uint32_t len, j;
651 
652 #ifdef USE_JANSSON
653 	/*
654 	 * Offset not applicable in case of JSON test vectors.
655 	 */
656 	if (info.file_type == FIPS_TYPE_JSON) {
657 		RTE_SET_USED(key);
658 	} else
659 #endif
660 		src += strlen(key);
661 
662 	len = strlen(src) / 2;
663 
664 	if (val->val) {
665 		rte_free(val->val);
666 		val->val = NULL;
667 	}
668 
669 	val->val = rte_zmalloc(NULL, len + 1, 0);
670 	if (!val->val)
671 		return -ENOMEM;
672 
673 	for (j = 0; j < len; j++) {
674 		char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
675 
676 		if (parser_read_uint8_hex(&val->val[j], byte) < 0) {
677 			rte_free(val->val);
678 			memset(val, 0, sizeof(*val));
679 			return -EINVAL;
680 		}
681 	}
682 
683 	val->len = len;
684 
685 	return 0;
686 }
687 
688 int
689 parser_read_uint32_val(const char *key, char *src, struct fips_val *val)
690 {
691 #ifdef USE_JANSSON
692 	if (info.file_type == FIPS_TYPE_JSON) {
693 		RTE_SET_USED(key);
694 
695 		return parser_read_uint32(&val->len, src);
696 	}
697 # endif
698 	char *data = src + strlen(key);
699 	size_t data_len = strlen(data);
700 	int ret;
701 
702 	if (data[data_len - 1] == ']') {
703 		char *tmp_data = calloc(1, data_len + 1);
704 
705 		if (tmp_data == NULL)
706 			return -ENOMEM;
707 
708 		strlcpy(tmp_data, data, data_len);
709 
710 		ret = parser_read_uint32(&val->len, tmp_data);
711 
712 		free(tmp_data);
713 	} else
714 		ret = parser_read_uint32(&val->len, data);
715 
716 	return ret;
717 }
718 
719 int
720 parser_read_uint32_bit_val(const char *key, char *src, struct fips_val *val)
721 {
722 	int ret;
723 
724 	ret = parser_read_uint32_val(key, src, val);
725 
726 	if (ret < 0)
727 		return ret;
728 
729 	val->len /= 8;
730 
731 	return 0;
732 }
733 
734 int
735 writeback_hex_str(const char *key, char *dst, struct fips_val *val)
736 {
737 	char *str = dst;
738 	uint32_t len;
739 
740 	str += strlen(key);
741 
742 	for (len = 0; len < val->len; len++)
743 		snprintf(str + len * 2, 255, "%02x", val->val[len]);
744 
745 	return 0;
746 }
747 
748 static int
749 parser_read_uint64(uint64_t *value, const char *p)
750 {
751 	char *next;
752 	uint64_t val;
753 
754 	p = rte_str_skip_leading_spaces(p);
755 	if (!isdigit(*p))
756 		return -EINVAL;
757 
758 	val = strtoul(p, &next, 10);
759 	if (p == next)
760 		return -EINVAL;
761 
762 	p = next;
763 	switch (*p) {
764 	case 'T':
765 		val *= 1024ULL;
766 		/* fall through */
767 	case 'G':
768 		val *= 1024ULL;
769 		/* fall through */
770 	case 'M':
771 		val *= 1024ULL;
772 		/* fall through */
773 	case 'k':
774 	case 'K':
775 		val *= 1024ULL;
776 		p++;
777 		break;
778 	}
779 
780 	p = rte_str_skip_leading_spaces(p);
781 	if (*p != '\0')
782 		return -EINVAL;
783 
784 	*value = val;
785 	return 0;
786 }
787 
788 int
789 parser_read_uint32(uint32_t *value, char *p)
790 {
791 	uint64_t val = 0;
792 	int ret = parser_read_uint64(&val, p);
793 
794 	if (ret < 0)
795 		return ret;
796 
797 	if (val > UINT32_MAX)
798 		return -EINVAL;
799 
800 	*value = val;
801 	return 0;
802 }
803 
804 int
805 parser_read_uint16(uint16_t *value, const char *p)
806 {
807 	uint64_t val = 0;
808 	int ret = parser_read_uint64(&val, p);
809 
810 	if (ret < 0)
811 		return ret;
812 
813 	if (val > UINT16_MAX)
814 		return -ERANGE;
815 
816 	*value = val;
817 	return 0;
818 }
819 
820 void
821 parse_write_hex_str(struct fips_val *src)
822 {
823 	writeback_hex_str("", info.one_line_text, src);
824 
825 	fprintf(info.fp_wr, "%s\n", info.one_line_text);
826 }
827 
828 int
829 update_info_vec(uint32_t count)
830 {
831 	const struct fips_test_callback *cb;
832 	uint32_t i, j;
833 
834 	if (!info.writeback_callbacks)
835 		return -1;
836 
837 	cb = &info.writeback_callbacks[0];
838 
839 	if ((info.version == 21.4f) && (!(strstr(info.vec[0], cb->key)))) {
840 		fprintf(info.fp_wr, "%s%u\n", cb->key, count);
841 		i = 0;
842 	} else {
843 		snprintf(info.vec[0], strlen(info.vec[0]) + 4, "%s%u", cb->key,
844 				count);
845 		i = 1;
846 	}
847 
848 	for (; i < info.nb_vec_lines; i++) {
849 		for (j = 1; info.writeback_callbacks[j].key != NULL; j++) {
850 			cb = &info.writeback_callbacks[j];
851 			if (strstr(info.vec[i], cb->key)) {
852 				cb->cb(cb->key, info.vec[i], cb->val);
853 				break;
854 			}
855 		}
856 	}
857 
858 	return 0;
859 }
860