numam-dpdk/examples/fips_validation/fips_validation.c
Ibtisam Tariq fc6e6515c7 examples/fips_validation: enhance getopt_long usage
Instead of using getopt_long return value, strcmp was used to
compare the input parameters with the struct option array. This
patch get rid of all those strcmp by directly binding each longopt
with an int enum. This is to improve readability and consistency in
all examples.

Bugzilla ID: 238

Reported-by: David Marchand <david.marchand@redhat.com>
Signed-off-by: Ibtisam Tariq <ibtisam.tariq@emumba.com>
Reviewed-by: David Marchand <david.marchand@redhat.com>
2021-03-23 12:48:11 +01:00

709 lines
13 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2018 Intel Corporation
*/
#include <stdio.h>
#include <string.h>
#include <rte_string_fns.h>
#include <rte_cryptodev.h>
#include <rte_malloc.h>
#include "fips_validation.h"
#define skip_white_spaces(pos) \
({ \
__typeof__(pos) _p = (pos); \
for ( ; isspace(*_p); _p++) \
; \
_p; \
})
static int
get_file_line(void)
{
FILE *fp = info.fp_rd;
char *line = info.one_line_text;
int ret;
uint32_t loc = 0;
memset(line, 0, MAX_LINE_CHAR);
while ((ret = fgetc(fp)) != EOF) {
char c = (char)ret;
if (loc >= MAX_LINE_CHAR - 1)
return -ENOMEM;
if (c == '\n')
break;
line[loc++] = c;
}
if (ret == EOF)
return -EOF;
return 0;
}
int
fips_test_fetch_one_block(void)
{
size_t size;
int ret = 0;
uint32_t i;
for (i = 0; i < info.nb_vec_lines; i++) {
free(info.vec[i]);
info.vec[i] = NULL;
}
i = 0;
do {
if (i >= MAX_LINE_PER_VECTOR) {
ret = -ENOMEM;
goto error_exit;
}
ret = get_file_line();
size = strlen(info.one_line_text);
if (size == 0)
break;
info.vec[i] = calloc(1, size + 5);
if (info.vec[i] == NULL)
goto error_exit;
strlcpy(info.vec[i], info.one_line_text, size + 1);
i++;
} while (ret == 0);
info.nb_vec_lines = i;
return ret;
error_exit:
for (i = 0; i < MAX_LINE_PER_VECTOR; i++)
if (info.vec[i] != NULL) {
free(info.vec[i]);
info.vec[i] = NULL;
}
info.nb_vec_lines = 0;
return -ENOMEM;
}
static void
fips_test_parse_version(void)
{
int len = strlen(info.vec[0]);
char *ptr = info.vec[0];
info.version = strtof(ptr + len - 4, NULL);
}
static int
fips_test_parse_header(void)
{
uint32_t i;
char *tmp;
int ret;
int algo_parsed = 0;
time_t t = time(NULL);
struct tm *tm_now = localtime(&t);
ret = fips_test_fetch_one_block();
if (ret < 0)
return ret;
if (info.nb_vec_lines)
fips_test_parse_version();
for (i = 0; i < info.nb_vec_lines; i++) {
if (!algo_parsed) {
if (strstr(info.vec[i], "AESVS")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_AES;
ret = parse_test_aes_init();
if (ret < 0)
return ret;
} else if (strstr(info.vec[i], "GCM")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_AES_GCM;
ret = parse_test_gcm_init();
if (ret < 0)
return ret;
} else if (strstr(info.vec[i], "CMAC")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_AES_CMAC;
ret = parse_test_cmac_init();
if (ret < 0)
return 0;
} else if (strstr(info.vec[i], "CCM")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_AES_CCM;
ret = parse_test_ccm_init();
if (ret < 0)
return 0;
} else if (strstr(info.vec[i], "HMAC")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_HMAC;
ret = parse_test_hmac_init();
if (ret < 0)
return ret;
} else if (strstr(info.vec[i], "TDES")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_TDES;
ret = parse_test_tdes_init();
if (ret < 0)
return 0;
} else if (strstr(info.vec[i], "PERMUTATION")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_TDES;
ret = parse_test_tdes_init();
if (ret < 0)
return 0;
} else if (strstr(info.vec[i], "VARIABLE")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_TDES;
ret = parse_test_tdes_init();
if (ret < 0)
return 0;
} else if (strstr(info.vec[i], "SUBSTITUTION")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_TDES;
ret = parse_test_tdes_init();
if (ret < 0)
return 0;
} else if (strstr(info.vec[i], "SHA-")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_SHA;
ret = parse_test_sha_init();
if (ret < 0)
return ret;
} else if (strstr(info.vec[i], "XTS")) {
algo_parsed = 1;
info.algo = FIPS_TEST_ALGO_AES_XTS;
ret = parse_test_xts_init();
if (ret < 0)
return ret;
}
}
tmp = strstr(info.vec[i], "# Config info for ");
if (tmp != NULL) {
fprintf(info.fp_wr, "%s%s\n", "# Config info for DPDK Cryptodev ",
info.device_name);
continue;
}
tmp = strstr(info.vec[i], "# HMAC information for ");
if (tmp != NULL) {
fprintf(info.fp_wr, "%s%s\n", "# HMAC information for "
"DPDK Cryptodev ",
info.device_name);
continue;
}
tmp = strstr(info.vec[i], "# Config Info for : ");
if (tmp != NULL) {
fprintf(info.fp_wr, "%s%s\n", "# Config Info for DPDK Cryptodev : ",
info.device_name);
continue;
}
tmp = strstr(info.vec[i], "# information for ");
if (tmp != NULL) {
char tmp_output[128] = {0};
strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
"information for DPDK Cryptodev ",
info.device_name);
continue;
}
tmp = strstr(info.vec[i], " test information for ");
if (tmp != NULL) {
char tmp_output[128] = {0};
strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
"test information for DPDK Cryptodev ",
info.device_name);
continue;
}
tmp = strstr(info.vec[i], "\" information for \"");
if (tmp != NULL) {
char tmp_output[128] = {0};
strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
"\" information for DPDK Cryptodev ",
info.device_name);
continue;
}
if (i == info.nb_vec_lines - 1) {
/** update the time as current time, write to file */
fprintf(info.fp_wr, "%s%s\n", "# Generated on ",
asctime(tm_now));
continue;
}
/* to this point, no field need to update,
* only copy to rsp file
*/
fprintf(info.fp_wr, "%s\n", info.vec[i]);
}
return 0;
}
static int
parse_file_type(const char *path)
{
const char *tmp = path + strlen(path) - 3;
if (strstr(tmp, REQ_FILE_PERFIX))
info.file_type = FIPS_TYPE_REQ;
else if (strstr(tmp, RSP_FILE_PERFIX))
info.file_type = FIPS_TYPE_RSP;
else if (strstr(path, FAX_FILE_PERFIX))
info.file_type = FIPS_TYPE_FAX;
else
return -EINVAL;
return 0;
}
int
fips_test_init(const char *req_file_path, const char *rsp_file_path,
const char *device_name)
{
if (strcmp(req_file_path, rsp_file_path) == 0) {
RTE_LOG(ERR, USER1, "File paths cannot be the same\n");
return -EINVAL;
}
fips_test_clear();
if (rte_strscpy(info.file_name, req_file_path,
sizeof(info.file_name)) < 0) {
RTE_LOG(ERR, USER1, "Path %s too long\n", req_file_path);
return -EINVAL;
}
info.algo = FIPS_TEST_ALGO_MAX;
if (parse_file_type(req_file_path) < 0) {
RTE_LOG(ERR, USER1, "File %s type not supported\n",
req_file_path);
return -EINVAL;
}
info.fp_rd = fopen(req_file_path, "r");
if (!info.fp_rd) {
RTE_LOG(ERR, USER1, "Cannot open file %s\n", req_file_path);
return -EINVAL;
}
info.fp_wr = fopen(rsp_file_path, "w");
if (!info.fp_wr) {
RTE_LOG(ERR, USER1, "Cannot open file %s\n", rsp_file_path);
return -EINVAL;
}
info.one_line_text = calloc(1, MAX_LINE_CHAR);
if (!info.one_line_text) {
RTE_LOG(ERR, USER1, "Insufficient memory\n");
return -ENOMEM;
}
if (rte_strscpy(info.device_name, device_name,
sizeof(info.device_name)) < 0) {
RTE_LOG(ERR, USER1, "Device name %s too long\n", device_name);
return -EINVAL;
}
if (fips_test_parse_header() < 0) {
RTE_LOG(ERR, USER1, "Failed parsing header\n");
return -1;
}
return 0;
}
void
fips_test_clear(void)
{
if (info.fp_rd)
fclose(info.fp_rd);
if (info.fp_wr)
fclose(info.fp_wr);
if (info.one_line_text)
free(info.one_line_text);
if (info.nb_vec_lines) {
uint32_t i;
for (i = 0; i < info.nb_vec_lines; i++)
free(info.vec[i]);
}
memset(&info, 0, sizeof(info));
}
int
fips_test_parse_one_case(void)
{
uint32_t i, j = 0;
uint32_t is_interim;
uint32_t interim_cnt = 0;
int ret;
info.vec_start_off = 0;
if (info.interim_callbacks) {
for (i = 0; i < info.nb_vec_lines; i++) {
is_interim = 0;
for (j = 0; info.interim_callbacks[j].key != NULL; j++)
if (strstr(info.vec[i],
info.interim_callbacks[j].key)) {
is_interim = 1;
ret = info.interim_callbacks[j].cb(
info.interim_callbacks[j].key,
info.vec[i],
info.interim_callbacks[j].val);
if (ret < 0)
return ret;
}
if (is_interim)
interim_cnt += 1;
}
}
if (interim_cnt) {
if (info.version == 21.4f) {
for (i = 0; i < interim_cnt; i++)
fprintf(info.fp_wr, "%s\n", info.vec[i]);
fprintf(info.fp_wr, "\n");
if (info.nb_vec_lines == interim_cnt)
return 1;
} else {
for (i = 0; i < info.nb_vec_lines; i++)
fprintf(info.fp_wr, "%s\n", info.vec[i]);
fprintf(info.fp_wr, "\n");
return 1;
}
}
info.vec_start_off = interim_cnt;
for (i = info.vec_start_off; i < info.nb_vec_lines; i++) {
for (j = 0; info.callbacks[j].key != NULL; j++)
if (strstr(info.vec[i], info.callbacks[j].key)) {
ret = info.callbacks[j].cb(
info.callbacks[j].key,
info.vec[i], info.callbacks[j].val);
if (ret < 0)
return ret;
break;
}
}
return 0;
}
void
fips_test_write_one_case(void)
{
uint32_t i;
for (i = info.vec_start_off; i < info.nb_vec_lines; i++)
fprintf(info.fp_wr, "%s\n", info.vec[i]);
}
static int
parser_read_uint64_hex(uint64_t *value, const char *p)
{
char *next;
uint64_t val;
p = skip_white_spaces(p);
val = strtoul(p, &next, 16);
if (p == next)
return -EINVAL;
p = skip_white_spaces(next);
if (*p != '\0')
return -EINVAL;
*value = val;
return 0;
}
int
parser_read_uint8_hex(uint8_t *value, const char *p)
{
uint64_t val = 0;
int ret = parser_read_uint64_hex(&val, p);
if (ret < 0)
return ret;
if (val > UINT8_MAX)
return -ERANGE;
*value = val;
return 0;
}
int
parse_uint8_known_len_hex_str(const char *key, char *src, struct fips_val *val)
{
struct fips_val tmp_val = {0};
uint32_t len = val->len;
int ret;
if (len == 0) {
if (val->val != NULL) {
rte_free(val->val);
val->val = NULL;
}
return 0;
}
ret = parse_uint8_hex_str(key, src, &tmp_val);
if (ret < 0)
return ret;
if (tmp_val.len == val->len) {
val->val = tmp_val.val;
return 0;
}
if (tmp_val.len < val->len) {
rte_free(tmp_val.val);
return -EINVAL;
}
val->val = rte_zmalloc(NULL, val->len, 0);
if (!val->val) {
rte_free(tmp_val.val);
memset(val, 0, sizeof(*val));
return -ENOMEM;
}
memcpy(val->val, tmp_val.val, val->len);
rte_free(tmp_val.val);
return 0;
}
int
parse_uint8_hex_str(const char *key, char *src, struct fips_val *val)
{
uint32_t len, j;
src += strlen(key);
len = strlen(src) / 2;
if (val->val) {
rte_free(val->val);
val->val = NULL;
}
val->val = rte_zmalloc(NULL, len, 0);
if (!val->val)
return -ENOMEM;
for (j = 0; j < len; j++) {
char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
if (parser_read_uint8_hex(&val->val[j], byte) < 0) {
rte_free(val->val);
memset(val, 0, sizeof(*val));
return -EINVAL;
}
}
val->len = len;
return 0;
}
int
parser_read_uint32_val(const char *key, char *src, struct fips_val *val)
{
char *data = src + strlen(key);
size_t data_len = strlen(data);
int ret;
if (data[data_len - 1] == ']') {
char *tmp_data = calloc(1, data_len + 1);
if (tmp_data == NULL)
return -ENOMEM;
strlcpy(tmp_data, data, data_len);
ret = parser_read_uint32(&val->len, tmp_data);
free(tmp_data);
} else
ret = parser_read_uint32(&val->len, data);
return ret;
}
int
parser_read_uint32_bit_val(const char *key, char *src, struct fips_val *val)
{
int ret;
ret = parser_read_uint32_val(key, src, val);
if (ret < 0)
return ret;
val->len /= 8;
return 0;
}
int
writeback_hex_str(const char *key, char *dst, struct fips_val *val)
{
char *str = dst;
uint32_t len;
str += strlen(key);
for (len = 0; len < val->len; len++)
snprintf(str + len * 2, 255, "%02x", val->val[len]);
return 0;
}
static int
parser_read_uint64(uint64_t *value, const char *p)
{
char *next;
uint64_t val;
p = skip_white_spaces(p);
if (!isdigit(*p))
return -EINVAL;
val = strtoul(p, &next, 10);
if (p == next)
return -EINVAL;
p = next;
switch (*p) {
case 'T':
val *= 1024ULL;
/* fall through */
case 'G':
val *= 1024ULL;
/* fall through */
case 'M':
val *= 1024ULL;
/* fall through */
case 'k':
case 'K':
val *= 1024ULL;
p++;
break;
}
p = skip_white_spaces(p);
if (*p != '\0')
return -EINVAL;
*value = val;
return 0;
}
int
parser_read_uint32(uint32_t *value, char *p)
{
uint64_t val = 0;
int ret = parser_read_uint64(&val, p);
if (ret < 0)
return ret;
if (val > UINT32_MAX)
return -EINVAL;
*value = val;
return 0;
}
int
parser_read_uint16(uint16_t *value, const char *p)
{
uint64_t val = 0;
int ret = parser_read_uint64(&val, p);
if (ret < 0)
return ret;
if (val > UINT16_MAX)
return -ERANGE;
*value = val;
return 0;
}
void
parse_write_hex_str(struct fips_val *src)
{
writeback_hex_str("", info.one_line_text, src);
fprintf(info.fp_wr, "%s\n", info.one_line_text);
}
int
update_info_vec(uint32_t count)
{
const struct fips_test_callback *cb;
uint32_t i, j;
if (!info.writeback_callbacks)
return -1;
cb = &info.writeback_callbacks[0];
if ((info.version == 21.4f) && (!(strstr(info.vec[0], cb->key)))) {
fprintf(info.fp_wr, "%s%u\n", cb->key, count);
i = 0;
} else {
snprintf(info.vec[0], strlen(info.vec[0]) + 4, "%s%u", cb->key,
count);
i = 1;
}
for (; i < info.nb_vec_lines; i++) {
for (j = 1; info.writeback_callbacks[j].key != NULL; j++) {
cb = &info.writeback_callbacks[j];
if (strstr(info.vec[i], cb->key)) {
cb->cb(cb->key, info.vec[i], cb->val);
break;
}
}
}
return 0;
}