diff options
author | John Levon <john.levon@joyent.com> | 2020-05-26 13:57:13 +0000 |
---|---|---|
committer | John Levon <john.levon@joyent.com> | 2020-05-26 13:57:13 +0000 |
commit | 5b2acc0949194447bba6e45a0fa44d0b5f42f208 (patch) | |
tree | 7ea9eb87bc68fee386dd39035ce715e87a0e673c /usr/src/test/crypto-tests/tests/digest/parser_runner.c | |
parent | 8ca018083101bf1cb175869679bc123187fb1bab (diff) | |
parent | 2a1277d3064386cd5c4e372301007aa330bf1d5e (diff) | |
download | illumos-joyent-gcc9.tar.gz |
mergegcc9
Diffstat (limited to 'usr/src/test/crypto-tests/tests/digest/parser_runner.c')
-rw-r--r-- | usr/src/test/crypto-tests/tests/digest/parser_runner.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/usr/src/test/crypto-tests/tests/digest/parser_runner.c b/usr/src/test/crypto-tests/tests/digest/parser_runner.c new file mode 100644 index 0000000000..56844f0448 --- /dev/null +++ b/usr/src/test/crypto-tests/tests/digest/parser_runner.c @@ -0,0 +1,352 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License (), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019 Joyent, Inc. + * Copyright 2020 Oxide Computer Company + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <errno.h> +#include <err.h> + +#include <sys/debug.h> + +#include "cryptotest.h" +#include "parser_runner.h" + +#define DATA_PATH "/opt/crypto-tests/share" + +/* + * Parse NIST test vector data into a format that is simple to run the digest + * tests against. The parsing logic is not meant to be especially robust given + * that we control the data fed into it. + */ + +struct parser_ctx { + FILE *pc_file; + size_t pc_hash_sz; + char *pc_line_buf; + size_t pc_line_sz; +}; + +parser_ctx_t * +parser_init(const char *path, size_t hash_len, int *errp) +{ + FILE *fp; + parser_ctx_t *ctx; + + /* sanity check for SHA1 -> SHA512 */ + ASSERT(hash_len >= 20 && hash_len <= 64); + + fp = fopen(path, "r"); + if (fp == NULL) { + *errp = errno; + return (NULL); + } + ctx = malloc(sizeof (*ctx)); + if (ctx == NULL) { + *errp = ENOMEM; + (void) fclose(fp); + return (NULL); + } + ctx->pc_file = fp; + ctx->pc_hash_sz = hash_len; + ctx->pc_line_buf = NULL; + ctx->pc_line_sz = 0; + + return (ctx); +} + +void +parser_fini(parser_ctx_t *ctx) +{ + free(ctx->pc_line_buf); + (void) fclose(ctx->pc_file); + free(ctx); +} + +static size_t +hex2bytes(const char *hexbuf, size_t hexlen, uchar_t *outbuf, size_t outlen) +{ + size_t count = 0; + /* naive and lazy conversion */ + errno = 0; + while (hexlen > 1) { + long res; + char buf[3] = {hexbuf[0], hexbuf[1], '\0'}; + + res = strtol(buf, NULL, 16); + if (errno != 0) { + break; + } + *outbuf = res & 0xff; + + hexbuf += 2; + hexlen -= 2; + outbuf += 1; + outlen += 1; + count++; + + if (outbuf == 0) { + break; + } + } + + return (count); +} + +static int +read_len(parser_ctx_t *ctx, size_t *lenp, size_t *szp) +{ + ssize_t sz; + long parsed; + const char *search = "Len = "; + const size_t search_len = strlen(search); + + errno = 0; + sz = getline(&ctx->pc_line_buf, &ctx->pc_line_sz, ctx->pc_file); + if (sz < 1) { + int err = errno; + + if (err == 0 || err == ENOENT) { + /* EOF reached, bail */ + return (-1); + } else { + return (err); + } + } + *szp = sz; + if (strncmp(ctx->pc_line_buf, search, search_len) != 0) { + return (-1); + } + + errno = 0; + parsed = strtol(ctx->pc_line_buf + search_len, NULL, 10); + if (parsed == 0 && errno != 0) { + return (errno); + } + if (parsed < 0) { + return (EINVAL); + } + + /* length in file is in bits, while we want bytes */ + *lenp = (size_t)parsed / 8; + return (0); +} + +static int +read_msg(parser_ctx_t *ctx, uchar_t *msgbuf, size_t msglen) +{ + ssize_t sz; + const char *search = "Msg = "; + const size_t search_len = strlen(search); + + sz = getline(&ctx->pc_line_buf, &ctx->pc_line_sz, ctx->pc_file); + if (sz < 0) { + return (errno); + } + if (strncmp(ctx->pc_line_buf, search, search_len) != 0) { + return (-1); + } + + if (msgbuf == NULL) { + ASSERT(msglen == 0); + return (0); + } + + size_t parsed; + parsed = hex2bytes(ctx->pc_line_buf + search_len, sz - search_len, + msgbuf, msglen); + if (parsed != msglen) { + ASSERT3U(parsed, <, msglen); + return (-1); + } + + return (0); +} + +static int +read_md(parser_ctx_t *ctx, uchar_t *mdbuf, size_t mdlen) +{ + ssize_t sz; + const char *search = "MD = "; + const size_t search_len = strlen(search); + + sz = getline(&ctx->pc_line_buf, &ctx->pc_line_sz, ctx->pc_file); + if (sz < 0) { + return (errno); + } + if (strncmp(ctx->pc_line_buf, search, search_len) != 0) { + return (-1); + } + + size_t parsed; + parsed = hex2bytes(ctx->pc_line_buf + search_len, sz - search_len, + mdbuf, mdlen); + if (parsed != mdlen) { + ASSERT3U(parsed, <, mdlen); + return (-1); + } + + return (0); +} + +parser_entry_t * +parser_read(parser_ctx_t *ctx, int *errp) +{ + int err = 0; + parser_entry_t *res = NULL; + uchar_t *msgbuf = NULL; + uchar_t *mdbuf = NULL; + + while (feof(ctx->pc_file) == 0) { + int ret; + size_t msglen, sz; + + ret = read_len(ctx, &msglen, &sz); + if (ret == -1) { + /* + * Did not find a properly formatted "Len = <num>", but + * no hard errors were incurred while looking for one, + * so continue searching. + */ + continue; + } else if (ret != 0) { + err = ret; + break; + } + + if (msglen != 0) { + msgbuf = calloc(msglen, 1); + if (msgbuf == NULL) { + err = ENOMEM; + break; + } + } + + ret = read_msg(ctx, msgbuf, msglen); + if (ret == -1) { + /* + * Did not find properly formatted "Msg = <hex data>". + * Restart the search for a new record. + */ + free(msgbuf); + msgbuf = NULL; + continue; + } else if (ret != 0) { + err = ret; + break; + } + + mdbuf = calloc(1, ctx->pc_hash_sz); + if (mdbuf == NULL) { + err = ENOMEM; + break; + } + ret = read_md(ctx, mdbuf, ctx->pc_hash_sz); + if (ret == -1) { + /* + * Did not find properly formatted "MD = <hash>". + * Restart search for new record. + */ + free(msgbuf); + free(mdbuf); + msgbuf = mdbuf = NULL; + continue; + } else if (ret != 0) { + err = ret; + break; + } + + res = malloc(sizeof (*res)); + if (res == NULL) { + err = ENOMEM; + break; + } + res->pe_msg = msgbuf; + res->pe_msglen = msglen; + res->pe_hash = mdbuf; + break; + } + + if (err != 0) { + ASSERT(res == NULL); + free(msgbuf); + free(mdbuf); + } + + /* EOF status indicated by err == 0 and res == NULL */ + *errp = err; + return (res); +} + +void +parser_free(parser_entry_t *ent) +{ + free(ent->pe_msg); + free(ent->pe_hash); + free(ent); +} + +/* + * With the above parser, run a the vectors through a given crypto test. + */ +int +digest_runner(char *mech_name, const char *input_file, size_t digest_len) +{ + int fails = 0, error; + uint8_t N[1024]; + size_t updatelens[] = { + 1, 8, 33, 67, CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END + }; + cryptotest_t args = { + .out = N, + .outlen = sizeof (N), + .mechname = mech_name, + .updatelens = updatelens + }; + parser_ctx_t *ctx; + parser_entry_t *ent; + + /* + * XXX: This could be changed to generate a path relative to that of + * the executable to find the data files + */ + char *path = NULL; + if (asprintf(&path, "%s/%s", DATA_PATH, input_file) < 0) { + err(EXIT_FAILURE, NULL); + } + + ctx = parser_init(path, digest_len, &error); + if (ctx == NULL) { + err(EXIT_FAILURE, "%s", path); + } + free(path); + + error = 0; + while ((ent = parser_read(ctx, &error)) != NULL) { + args.in = ent->pe_msg; + args.inlen = ent->pe_msglen; + + fails += run_test(&args, ent->pe_hash, digest_len, DIGEST_FG); + parser_free(ent); + } + if (error != 0) { + err(EXIT_FAILURE, NULL); + } + parser_fini(ctx); + + return (fails); +} |