1*080adf91SPatrick Mooney /*
2*080adf91SPatrick Mooney  * This file and its contents are supplied under the terms of the
3*080adf91SPatrick Mooney  * Common Development and Distribution License (), version 1.0.
4*080adf91SPatrick Mooney  * You may only use this file in accordance with the terms of version
5*080adf91SPatrick Mooney  * 1.0 of the CDDL.
6*080adf91SPatrick Mooney  *
7*080adf91SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8*080adf91SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9*080adf91SPatrick Mooney  * http://www.illumos.org/license/CDDL.
10*080adf91SPatrick Mooney  */
11*080adf91SPatrick Mooney 
12*080adf91SPatrick Mooney /*
13*080adf91SPatrick Mooney  * Copyright 2019 Joyent, Inc.
14*080adf91SPatrick Mooney  * Copyright 2020 Oxide Computer Company
15*080adf91SPatrick Mooney  */
16*080adf91SPatrick Mooney 
17*080adf91SPatrick Mooney #include <stdio.h>
18*080adf91SPatrick Mooney #include <stdlib.h>
19*080adf91SPatrick Mooney #include <string.h>
20*080adf91SPatrick Mooney #include <strings.h>
21*080adf91SPatrick Mooney #include <errno.h>
22*080adf91SPatrick Mooney #include <err.h>
23*080adf91SPatrick Mooney 
24*080adf91SPatrick Mooney #include <sys/debug.h>
25*080adf91SPatrick Mooney 
26*080adf91SPatrick Mooney #include "cryptotest.h"
27*080adf91SPatrick Mooney #include "parser_runner.h"
28*080adf91SPatrick Mooney 
29*080adf91SPatrick Mooney #define	DATA_PATH	"/opt/crypto-tests/share"
30*080adf91SPatrick Mooney 
31*080adf91SPatrick Mooney /*
32*080adf91SPatrick Mooney  * Parse NIST test vector data into a format that is simple to run the digest
33*080adf91SPatrick Mooney  * tests against.  The parsing logic is not meant to be especially robust given
34*080adf91SPatrick Mooney  * that we control the data fed into it.
35*080adf91SPatrick Mooney  */
36*080adf91SPatrick Mooney 
37*080adf91SPatrick Mooney struct parser_ctx {
38*080adf91SPatrick Mooney 	FILE	*pc_file;
39*080adf91SPatrick Mooney 	size_t	pc_hash_sz;
40*080adf91SPatrick Mooney 	char	*pc_line_buf;
41*080adf91SPatrick Mooney 	size_t	pc_line_sz;
42*080adf91SPatrick Mooney };
43*080adf91SPatrick Mooney 
44*080adf91SPatrick Mooney parser_ctx_t *
parser_init(const char * path,size_t hash_len,int * errp)45*080adf91SPatrick Mooney parser_init(const char *path, size_t hash_len, int *errp)
46*080adf91SPatrick Mooney {
47*080adf91SPatrick Mooney 	FILE *fp;
48*080adf91SPatrick Mooney 	parser_ctx_t *ctx;
49*080adf91SPatrick Mooney 
50*080adf91SPatrick Mooney 	/* sanity check for SHA1 -> SHA512 */
51*080adf91SPatrick Mooney 	ASSERT(hash_len >= 20 && hash_len <= 64);
52*080adf91SPatrick Mooney 
53*080adf91SPatrick Mooney 	fp = fopen(path, "r");
54*080adf91SPatrick Mooney 	if (fp == NULL) {
55*080adf91SPatrick Mooney 		*errp = errno;
56*080adf91SPatrick Mooney 		return (NULL);
57*080adf91SPatrick Mooney 	}
58*080adf91SPatrick Mooney 	ctx = malloc(sizeof (*ctx));
59*080adf91SPatrick Mooney 	if (ctx == NULL) {
60*080adf91SPatrick Mooney 		*errp = ENOMEM;
61*080adf91SPatrick Mooney 		(void) fclose(fp);
62*080adf91SPatrick Mooney 		return (NULL);
63*080adf91SPatrick Mooney 	}
64*080adf91SPatrick Mooney 	ctx->pc_file = fp;
65*080adf91SPatrick Mooney 	ctx->pc_hash_sz = hash_len;
66*080adf91SPatrick Mooney 	ctx->pc_line_buf = NULL;
67*080adf91SPatrick Mooney 	ctx->pc_line_sz = 0;
68*080adf91SPatrick Mooney 
69*080adf91SPatrick Mooney 	return (ctx);
70*080adf91SPatrick Mooney }
71*080adf91SPatrick Mooney 
72*080adf91SPatrick Mooney void
parser_fini(parser_ctx_t * ctx)73*080adf91SPatrick Mooney parser_fini(parser_ctx_t *ctx)
74*080adf91SPatrick Mooney {
75*080adf91SPatrick Mooney 	free(ctx->pc_line_buf);
76*080adf91SPatrick Mooney 	(void) fclose(ctx->pc_file);
77*080adf91SPatrick Mooney 	free(ctx);
78*080adf91SPatrick Mooney }
79*080adf91SPatrick Mooney 
80*080adf91SPatrick Mooney static size_t
hex2bytes(const char * hexbuf,size_t hexlen,uchar_t * outbuf,size_t outlen)81*080adf91SPatrick Mooney hex2bytes(const char *hexbuf, size_t hexlen, uchar_t *outbuf, size_t outlen)
82*080adf91SPatrick Mooney {
83*080adf91SPatrick Mooney 	size_t count = 0;
84*080adf91SPatrick Mooney 	/* naive and lazy conversion */
85*080adf91SPatrick Mooney 	errno = 0;
86*080adf91SPatrick Mooney 	while (hexlen > 1) {
87*080adf91SPatrick Mooney 		long res;
88*080adf91SPatrick Mooney 		char buf[3] = {hexbuf[0], hexbuf[1], '\0'};
89*080adf91SPatrick Mooney 
90*080adf91SPatrick Mooney 		res = strtol(buf, NULL, 16);
91*080adf91SPatrick Mooney 		if (errno != 0) {
92*080adf91SPatrick Mooney 			break;
93*080adf91SPatrick Mooney 		}
94*080adf91SPatrick Mooney 		*outbuf = res & 0xff;
95*080adf91SPatrick Mooney 
96*080adf91SPatrick Mooney 		hexbuf += 2;
97*080adf91SPatrick Mooney 		hexlen -= 2;
98*080adf91SPatrick Mooney 		outbuf += 1;
99*080adf91SPatrick Mooney 		outlen += 1;
100*080adf91SPatrick Mooney 		count++;
101*080adf91SPatrick Mooney 
102*080adf91SPatrick Mooney 		if (outbuf == 0) {
103*080adf91SPatrick Mooney 			break;
104*080adf91SPatrick Mooney 		}
105*080adf91SPatrick Mooney 	}
106*080adf91SPatrick Mooney 
107*080adf91SPatrick Mooney 	return (count);
108*080adf91SPatrick Mooney }
109*080adf91SPatrick Mooney 
110*080adf91SPatrick Mooney static int
read_len(parser_ctx_t * ctx,size_t * lenp,size_t * szp)111*080adf91SPatrick Mooney read_len(parser_ctx_t *ctx, size_t *lenp, size_t *szp)
112*080adf91SPatrick Mooney {
113*080adf91SPatrick Mooney 	ssize_t sz;
114*080adf91SPatrick Mooney 	long parsed;
115*080adf91SPatrick Mooney 	const char *search = "Len = ";
116*080adf91SPatrick Mooney 	const size_t search_len = strlen(search);
117*080adf91SPatrick Mooney 
118*080adf91SPatrick Mooney 	errno = 0;
119*080adf91SPatrick Mooney 	sz = getline(&ctx->pc_line_buf, &ctx->pc_line_sz, ctx->pc_file);
120*080adf91SPatrick Mooney 	if (sz < 1) {
121*080adf91SPatrick Mooney 		int err = errno;
122*080adf91SPatrick Mooney 
123*080adf91SPatrick Mooney 		if (err == 0 || err == ENOENT) {
124*080adf91SPatrick Mooney 			/* EOF reached, bail */
125*080adf91SPatrick Mooney 			return (-1);
126*080adf91SPatrick Mooney 		} else {
127*080adf91SPatrick Mooney 			return (err);
128*080adf91SPatrick Mooney 		}
129*080adf91SPatrick Mooney 	}
130*080adf91SPatrick Mooney 	*szp = sz;
131*080adf91SPatrick Mooney 	if (strncmp(ctx->pc_line_buf, search, search_len) != 0) {
132*080adf91SPatrick Mooney 		return (-1);
133*080adf91SPatrick Mooney 	}
134*080adf91SPatrick Mooney 
135*080adf91SPatrick Mooney 	errno = 0;
136*080adf91SPatrick Mooney 	parsed = strtol(ctx->pc_line_buf + search_len, NULL, 10);
137*080adf91SPatrick Mooney 	if (parsed == 0 && errno != 0) {
138*080adf91SPatrick Mooney 		return (errno);
139*080adf91SPatrick Mooney 	}
140*080adf91SPatrick Mooney 	if (parsed < 0) {
141*080adf91SPatrick Mooney 		return (EINVAL);
142*080adf91SPatrick Mooney 	}
143*080adf91SPatrick Mooney 
144*080adf91SPatrick Mooney 	/* length in file is in bits, while we want bytes */
145*080adf91SPatrick Mooney 	*lenp = (size_t)parsed / 8;
146*080adf91SPatrick Mooney 	return (0);
147*080adf91SPatrick Mooney }
148*080adf91SPatrick Mooney 
149*080adf91SPatrick Mooney static int
read_msg(parser_ctx_t * ctx,uchar_t * msgbuf,size_t msglen)150*080adf91SPatrick Mooney read_msg(parser_ctx_t *ctx, uchar_t *msgbuf, size_t msglen)
151*080adf91SPatrick Mooney {
152*080adf91SPatrick Mooney 	ssize_t sz;
153*080adf91SPatrick Mooney 	const char *search = "Msg = ";
154*080adf91SPatrick Mooney 	const size_t search_len = strlen(search);
155*080adf91SPatrick Mooney 
156*080adf91SPatrick Mooney 	sz = getline(&ctx->pc_line_buf, &ctx->pc_line_sz, ctx->pc_file);
157*080adf91SPatrick Mooney 	if (sz < 0) {
158*080adf91SPatrick Mooney 		return (errno);
159*080adf91SPatrick Mooney 	}
160*080adf91SPatrick Mooney 	if (strncmp(ctx->pc_line_buf, search, search_len) != 0) {
161*080adf91SPatrick Mooney 		return (-1);
162*080adf91SPatrick Mooney 	}
163*080adf91SPatrick Mooney 
164*080adf91SPatrick Mooney 	if (msgbuf == NULL) {
165*080adf91SPatrick Mooney 		ASSERT(msglen == 0);
166*080adf91SPatrick Mooney 		return (0);
167*080adf91SPatrick Mooney 	}
168*080adf91SPatrick Mooney 
169*080adf91SPatrick Mooney 	size_t parsed;
170*080adf91SPatrick Mooney 	parsed = hex2bytes(ctx->pc_line_buf + search_len, sz - search_len,
171*080adf91SPatrick Mooney 	    msgbuf, msglen);
172*080adf91SPatrick Mooney 	if (parsed != msglen) {
173*080adf91SPatrick Mooney 		ASSERT3U(parsed, <, msglen);
174*080adf91SPatrick Mooney 		return (-1);
175*080adf91SPatrick Mooney 	}
176*080adf91SPatrick Mooney 
177*080adf91SPatrick Mooney 	return (0);
178*080adf91SPatrick Mooney }
179*080adf91SPatrick Mooney 
180*080adf91SPatrick Mooney static int
read_md(parser_ctx_t * ctx,uchar_t * mdbuf,size_t mdlen)181*080adf91SPatrick Mooney read_md(parser_ctx_t *ctx, uchar_t *mdbuf, size_t mdlen)
182*080adf91SPatrick Mooney {
183*080adf91SPatrick Mooney 	ssize_t sz;
184*080adf91SPatrick Mooney 	const char *search = "MD = ";
185*080adf91SPatrick Mooney 	const size_t search_len = strlen(search);
186*080adf91SPatrick Mooney 
187*080adf91SPatrick Mooney 	sz = getline(&ctx->pc_line_buf, &ctx->pc_line_sz, ctx->pc_file);
188*080adf91SPatrick Mooney 	if (sz < 0) {
189*080adf91SPatrick Mooney 		return (errno);
190*080adf91SPatrick Mooney 	}
191*080adf91SPatrick Mooney 	if (strncmp(ctx->pc_line_buf, search, search_len) != 0) {
192*080adf91SPatrick Mooney 		return (-1);
193*080adf91SPatrick Mooney 	}
194*080adf91SPatrick Mooney 
195*080adf91SPatrick Mooney 	size_t parsed;
196*080adf91SPatrick Mooney 	parsed = hex2bytes(ctx->pc_line_buf + search_len, sz - search_len,
197*080adf91SPatrick Mooney 	    mdbuf, mdlen);
198*080adf91SPatrick Mooney 	if (parsed != mdlen) {
199*080adf91SPatrick Mooney 		ASSERT3U(parsed, <, mdlen);
200*080adf91SPatrick Mooney 		return (-1);
201*080adf91SPatrick Mooney 	}
202*080adf91SPatrick Mooney 
203*080adf91SPatrick Mooney 	return (0);
204*080adf91SPatrick Mooney }
205*080adf91SPatrick Mooney 
206*080adf91SPatrick Mooney parser_entry_t *
parser_read(parser_ctx_t * ctx,int * errp)207*080adf91SPatrick Mooney parser_read(parser_ctx_t *ctx, int *errp)
208*080adf91SPatrick Mooney {
209*080adf91SPatrick Mooney 	int err = 0;
210*080adf91SPatrick Mooney 	parser_entry_t *res = NULL;
211*080adf91SPatrick Mooney 	uchar_t *msgbuf = NULL;
212*080adf91SPatrick Mooney 	uchar_t *mdbuf = NULL;
213*080adf91SPatrick Mooney 
214*080adf91SPatrick Mooney 	while (feof(ctx->pc_file) == 0) {
215*080adf91SPatrick Mooney 		int ret;
216*080adf91SPatrick Mooney 		size_t msglen, sz;
217*080adf91SPatrick Mooney 
218*080adf91SPatrick Mooney 		ret = read_len(ctx, &msglen, &sz);
219*080adf91SPatrick Mooney 		if (ret == -1) {
220*080adf91SPatrick Mooney 			/*
221*080adf91SPatrick Mooney 			 * Did not find a properly formatted "Len = <num>", but
222*080adf91SPatrick Mooney 			 * no hard errors were incurred while looking for one,
223*080adf91SPatrick Mooney 			 * so continue searching.
224*080adf91SPatrick Mooney 			 */
225*080adf91SPatrick Mooney 			continue;
226*080adf91SPatrick Mooney 		} else if (ret != 0) {
227*080adf91SPatrick Mooney 			err = ret;
228*080adf91SPatrick Mooney 			break;
229*080adf91SPatrick Mooney 		}
230*080adf91SPatrick Mooney 
231*080adf91SPatrick Mooney 		if (msglen != 0) {
232*080adf91SPatrick Mooney 			msgbuf = calloc(msglen, 1);
233*080adf91SPatrick Mooney 			if (msgbuf == NULL) {
234*080adf91SPatrick Mooney 				err = ENOMEM;
235*080adf91SPatrick Mooney 				break;
236*080adf91SPatrick Mooney 			}
237*080adf91SPatrick Mooney 		}
238*080adf91SPatrick Mooney 
239*080adf91SPatrick Mooney 		ret = read_msg(ctx, msgbuf, msglen);
240*080adf91SPatrick Mooney 		if (ret == -1) {
241*080adf91SPatrick Mooney 			/*
242*080adf91SPatrick Mooney 			 * Did not find properly formatted "Msg = <hex data>".
243*080adf91SPatrick Mooney 			 * Restart the search for a new record.
244*080adf91SPatrick Mooney 			 */
245*080adf91SPatrick Mooney 			free(msgbuf);
246*080adf91SPatrick Mooney 			msgbuf = NULL;
247*080adf91SPatrick Mooney 			continue;
248*080adf91SPatrick Mooney 		} else if (ret != 0) {
249*080adf91SPatrick Mooney 			err = ret;
250*080adf91SPatrick Mooney 			break;
251*080adf91SPatrick Mooney 		}
252*080adf91SPatrick Mooney 
253*080adf91SPatrick Mooney 		mdbuf = calloc(1, ctx->pc_hash_sz);
254*080adf91SPatrick Mooney 		if (mdbuf == NULL) {
255*080adf91SPatrick Mooney 			err = ENOMEM;
256*080adf91SPatrick Mooney 			break;
257*080adf91SPatrick Mooney 		}
258*080adf91SPatrick Mooney 		ret = read_md(ctx, mdbuf, ctx->pc_hash_sz);
259*080adf91SPatrick Mooney 		if (ret == -1) {
260*080adf91SPatrick Mooney 			/*
261*080adf91SPatrick Mooney 			 * Did not find properly formatted "MD = <hash>".
262*080adf91SPatrick Mooney 			 * Restart search for new record.
263*080adf91SPatrick Mooney 			 */
264*080adf91SPatrick Mooney 			free(msgbuf);
265*080adf91SPatrick Mooney 			free(mdbuf);
266*080adf91SPatrick Mooney 			msgbuf = mdbuf = NULL;
267*080adf91SPatrick Mooney 			continue;
268*080adf91SPatrick Mooney 		} else if (ret != 0) {
269*080adf91SPatrick Mooney 			err = ret;
270*080adf91SPatrick Mooney 			break;
271*080adf91SPatrick Mooney 		}
272*080adf91SPatrick Mooney 
273*080adf91SPatrick Mooney 		res = malloc(sizeof (*res));
274*080adf91SPatrick Mooney 		if (res == NULL) {
275*080adf91SPatrick Mooney 			err = ENOMEM;
276*080adf91SPatrick Mooney 			break;
277*080adf91SPatrick Mooney 		}
278*080adf91SPatrick Mooney 		res->pe_msg = msgbuf;
279*080adf91SPatrick Mooney 		res->pe_msglen = msglen;
280*080adf91SPatrick Mooney 		res->pe_hash = mdbuf;
281*080adf91SPatrick Mooney 		break;
282*080adf91SPatrick Mooney 	}
283*080adf91SPatrick Mooney 
284*080adf91SPatrick Mooney 	if (err != 0) {
285*080adf91SPatrick Mooney 		ASSERT(res == NULL);
286*080adf91SPatrick Mooney 		free(msgbuf);
287*080adf91SPatrick Mooney 		free(mdbuf);
288*080adf91SPatrick Mooney 	}
289*080adf91SPatrick Mooney 
290*080adf91SPatrick Mooney 	/* EOF status indicated by err == 0 and res == NULL */
291*080adf91SPatrick Mooney 	*errp = err;
292*080adf91SPatrick Mooney 	return (res);
293*080adf91SPatrick Mooney }
294*080adf91SPatrick Mooney 
295*080adf91SPatrick Mooney void
parser_free(parser_entry_t * ent)296*080adf91SPatrick Mooney parser_free(parser_entry_t *ent)
297*080adf91SPatrick Mooney {
298*080adf91SPatrick Mooney 	free(ent->pe_msg);
299*080adf91SPatrick Mooney 	free(ent->pe_hash);
300*080adf91SPatrick Mooney 	free(ent);
301*080adf91SPatrick Mooney }
302*080adf91SPatrick Mooney 
303*080adf91SPatrick Mooney /*
304*080adf91SPatrick Mooney  * With the above parser, run a the vectors through a given crypto test.
305*080adf91SPatrick Mooney  */
306*080adf91SPatrick Mooney int
digest_runner(char * mech_name,const char * input_file,size_t digest_len)307*080adf91SPatrick Mooney digest_runner(char *mech_name, const char *input_file, size_t digest_len)
308*080adf91SPatrick Mooney {
309*080adf91SPatrick Mooney 	int fails = 0, error;
310*080adf91SPatrick Mooney 	uint8_t N[1024];
311*080adf91SPatrick Mooney 	size_t updatelens[] = {
312*080adf91SPatrick Mooney 		1, 8, 33, 67, CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
313*080adf91SPatrick Mooney 	};
314*080adf91SPatrick Mooney 	cryptotest_t args = {
315*080adf91SPatrick Mooney 		.out = N,
316*080adf91SPatrick Mooney 		.outlen = sizeof (N),
317*080adf91SPatrick Mooney 		.mechname = mech_name,
318*080adf91SPatrick Mooney 		.updatelens = updatelens
319*080adf91SPatrick Mooney 	};
320*080adf91SPatrick Mooney 	parser_ctx_t *ctx;
321*080adf91SPatrick Mooney 	parser_entry_t *ent;
322*080adf91SPatrick Mooney 
323*080adf91SPatrick Mooney 	/*
324*080adf91SPatrick Mooney 	 * XXX: This could be changed to generate a path relative to that of
325*080adf91SPatrick Mooney 	 * the executable to find the data files
326*080adf91SPatrick Mooney 	 */
327*080adf91SPatrick Mooney 	char *path = NULL;
328*080adf91SPatrick Mooney 	if (asprintf(&path, "%s/%s", DATA_PATH, input_file) < 0) {
329*080adf91SPatrick Mooney 		err(EXIT_FAILURE, NULL);
330*080adf91SPatrick Mooney 	}
331*080adf91SPatrick Mooney 
332*080adf91SPatrick Mooney 	ctx = parser_init(path, digest_len, &error);
333*080adf91SPatrick Mooney 	if (ctx == NULL) {
334*080adf91SPatrick Mooney 		err(EXIT_FAILURE, "%s", path);
335*080adf91SPatrick Mooney 	}
336*080adf91SPatrick Mooney 	free(path);
337*080adf91SPatrick Mooney 
338*080adf91SPatrick Mooney 	error = 0;
339*080adf91SPatrick Mooney 	while ((ent = parser_read(ctx, &error)) != NULL) {
340*080adf91SPatrick Mooney 		args.in = ent->pe_msg;
341*080adf91SPatrick Mooney 		args.inlen = ent->pe_msglen;
342*080adf91SPatrick Mooney 
343*080adf91SPatrick Mooney 		fails += run_test(&args, ent->pe_hash, digest_len, DIGEST_FG);
344*080adf91SPatrick Mooney 		parser_free(ent);
345*080adf91SPatrick Mooney 	}
346*080adf91SPatrick Mooney 	if (error != 0) {
347*080adf91SPatrick Mooney 		err(EXIT_FAILURE, NULL);
348*080adf91SPatrick Mooney 	}
349*080adf91SPatrick Mooney 	parser_fini(ctx);
350*080adf91SPatrick Mooney 
351*080adf91SPatrick Mooney 	return (fails);
352*080adf91SPatrick Mooney }
353