summaryrefslogtreecommitdiff
path: root/usr/src/test/crypto-tests/tests/digest/parser_runner.c
diff options
context:
space:
mode:
authorJohn Levon <john.levon@joyent.com>2020-05-26 13:57:13 +0000
committerJohn Levon <john.levon@joyent.com>2020-05-26 13:57:13 +0000
commit5b2acc0949194447bba6e45a0fa44d0b5f42f208 (patch)
tree7ea9eb87bc68fee386dd39035ce715e87a0e673c /usr/src/test/crypto-tests/tests/digest/parser_runner.c
parent8ca018083101bf1cb175869679bc123187fb1bab (diff)
parent2a1277d3064386cd5c4e372301007aa330bf1d5e (diff)
downloadillumos-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.c352
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);
+}