1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
14  * Copyright 2019 Joyent, Inc.
15  */
16 
17 #define	__EXTENSIONS__
18 #include <limits.h>
19 #include <strings.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <sys/debug.h>
23 #include "cryptotest.h"
24 
25 /*
26  * A somewhat arbitrary size that should be large enough to hold the printed
27  * error and size messages.
28  */
29 #define	BUFSZ 128
30 
31 #define	EXIT_FAILURE_MULTIPART	1
32 #define	EXIT_FAILURE_SINGLEPART	2
33 
34 test_fg_t cryptotest_decr_fg = {
35 	.tf_fg = CRYPTO_FG_DECRYPT,
36 	.tf_init = decrypt_init,
37 	.tf_single = decrypt_single,
38 	.tf_update = decrypt_update,
39 	.tf_final = decrypt_final
40 };
41 
42 test_fg_t cryptotest_encr_fg = {
43 	.tf_fg = CRYPTO_FG_ENCRYPT,
44 	.tf_init = encrypt_init,
45 	.tf_single = encrypt_single,
46 	.tf_update = encrypt_update,
47 	.tf_final = encrypt_final
48 };
49 
50 test_fg_t cryptotest_mac_fg = {
51 	.tf_fg = CRYPTO_FG_MAC,
52 	.tf_init = mac_init,
53 	.tf_single = mac_single,
54 	.tf_update = mac_update,
55 	.tf_final = mac_final
56 };
57 
58 test_fg_t cryptotest_digest_fg = {
59 	.tf_fg = CRYPTO_FG_DIGEST,
60 	.tf_init = digest_init,
61 	.tf_single = digest_single,
62 	.tf_update = digest_update,
63 	.tf_final = digest_final
64 };
65 
66 /*
67  * Utils
68  */
69 
70 static const char *
ctest_errstr(int e,char * buf,size_t buflen)71 ctest_errstr(int e, char *buf, size_t buflen)
72 {
73 	const char *name = NULL;
74 	;
75 	switch (e) {
76 	case CTEST_INIT_FAILED:
77 		name = "CTEST_INIT_FAILED";
78 		break;
79 	case CTEST_NAME_RESOLVE_FAILED:
80 		name = "CTEST_MECH_NO_PROVIDER";
81 		break;
82 	case CTEST_MECH_NO_PROVIDER:
83 		name = "CTEST_MECH_NO_PROVIDER";
84 		break;
85 	default:
86 		name = "Unknown fatal error";
87 		break;
88 	}
89 
90 	(void) snprintf(buf, buflen, "%s (%d)", name, e);
91 	return (buf);
92 }
93 
94 void
printbuf(uint8_t * buf,char * name,size_t size)95 printbuf(uint8_t *buf, char *name, size_t size)
96 {
97 	size_t i;
98 
99 	flockfile(stderr);
100 	(void) fprintf(stderr, "%s%s", name, (size > 0) ? " " : "");
101 	for (i = 0; i < size; i++)
102 		(void) fprintf(stderr, "%02x", buf[i]);
103 	(void) fputc('\n', stderr);
104 	funlockfile(stderr);
105 }
106 
107 int
bufcmp(uint8_t * auth,uint8_t * cmp,size_t size)108 bufcmp(uint8_t *auth, uint8_t *cmp, size_t size)
109 {
110 	if (memcmp(cmp, auth, size) != 0) {
111 		(void) fprintf(stderr, "        mismatched result\n\n");
112 		printbuf(cmp, "calc", size);
113 		printbuf(auth, "orig", size);
114 		return (1);
115 	} else {
116 		(void) fprintf(stderr, "        result matches\n\n");
117 		return (0);
118 	}
119 }
120 
121 static int
test_setup(cryptotest_t * args,test_fg_t * funcs,crypto_op_t ** opp)122 test_setup(cryptotest_t *args, test_fg_t *funcs, crypto_op_t **opp)
123 {
124 	crypto_op_t *crypto_op = NULL;
125 	int ret;
126 
127 	switch (funcs->tf_fg) {
128 	case CRYPTO_FG_DECRYPT:
129 	case CRYPTO_FG_ENCRYPT:
130 		if (args->key == NULL)
131 			return (CRYPTO_FAILED);
132 		break;
133 	case CRYPTO_FG_MAC:
134 		if (args->in == NULL || args->key == NULL)
135 			return (CRYPTO_FAILED);
136 		break;
137 	case CRYPTO_FG_DIGEST:
138 		break;
139 	default:
140 		(void) fprintf(stderr,
141 		    "Unexpected function group value %" PRIu32 "\n",
142 		    funcs->tf_fg);
143 		abort();
144 	}
145 
146 	if ((crypto_op = cryptotest_init(args, funcs->tf_fg)) == NULL) {
147 		/* cryptotest_init() will prints out a specific error msg  */
148 		cryptotest_close(NULL);
149 		return (CTEST_INIT_FAILED);
150 	}
151 
152 	if ((ret = get_mech_info(crypto_op)) != CRYPTO_SUCCESS) {
153 		cryptotest_close(crypto_op);
154 		return (ret);
155 	}
156 
157 	if ((ret = get_hsession_by_mech(crypto_op)) != CRYPTO_SUCCESS) {
158 		cryptotest_close(crypto_op);
159 		return (ret);
160 	}
161 
162 	*opp = crypto_op;
163 	return (CRYPTO_SUCCESS);
164 }
165 
166 static int
test_multi(cryptotest_t * args,test_fg_t * funcs,uint8_t * cmp,size_t cmplen)167 test_multi(cryptotest_t *args, test_fg_t *funcs, uint8_t *cmp, size_t cmplen)
168 {
169 	crypto_op_t *crypto_op = NULL;
170 	size_t errs = 0;
171 	size_t n;
172 	int ret;
173 
174 	(void) fprintf(stderr, "multi-part:\n");
175 
176 	if ((ret = test_setup(args, funcs, &crypto_op)) != CRYPTO_SUCCESS) {
177 		(void) fprintf(stderr, "        fatal error %d\n", ret);
178 		exit(EXIT_FAILURE_MULTIPART);
179 	}
180 
181 	for (n = 0; args->updatelens[n] != CTEST_UPDATELEN_END; n++) {
182 		char errbuf[BUFSZ] = { 0 };
183 		char sizebuf[BUFSZ] = { 0 };
184 		size_t updatelen = args->updatelens[n];
185 		size_t offset = 0;
186 		size_t outlen = 0;
187 
188 		bzero(args->out, args->outlen);
189 
190 		if (updatelen == CTEST_UPDATELEN_WHOLE) {
191 			updatelen = args->inlen;
192 			(void) snprintf(sizebuf, sizeof (sizebuf),
193 			    "%zu (whole buffer)", updatelen);
194 		} else if (updatelen > args->inlen) {
195 			/*
196 			 * This can sometimes cause the same update size to
197 			 * be used twice if one is specified larger than the
198 			 * input and one also specifies a test using the
199 			 * entire input as the update size.  It doesn't
200 			 * hurt anything other than adding a little extra
201 			 * time.
202 			 */
203 			updatelen = args->inlen;
204 			(void) snprintf(sizebuf, sizeof (sizebuf),
205 			    "%zu (was %zu but capped at input size)",
206 			    updatelen, args->updatelens[n]);
207 		} else {
208 			(void) snprintf(sizebuf, sizeof (sizebuf), "%zu",
209 			    updatelen);
210 		}
211 		(void) fprintf(stderr, "    update size: %s\n", sizebuf);
212 		(void) fflush(stderr);
213 
214 		if ((ret = funcs->tf_init(crypto_op)) != CRYPTO_SUCCESS) {
215 			(void) fprintf(stderr, "        fatal error %d\n", ret);
216 			exit(EXIT_FAILURE_MULTIPART);
217 		}
218 
219 		while (offset < args->inlen) {
220 			size_t len = updatelen;
221 
222 			if (offset + updatelen > args->inlen) {
223 				len = args->inlen - offset;
224 			}
225 
226 			ret = funcs->tf_update(crypto_op, offset, len, &outlen);
227 			if (ret != CRYPTO_SUCCESS) {
228 				/*
229 				 * The update functions will print out their
230 				 * own error messages, so we don't need to.
231 				 */
232 				errs += 1;
233 				break;
234 			}
235 
236 			offset += len;
237 		}
238 
239 		if (ret != CRYPTO_SUCCESS)
240 			continue;
241 
242 		ret = funcs->tf_final(crypto_op, outlen);
243 
244 		/*
245 		 * Errors from the crypto frameworks (KCF, PKCS#11) are all
246 		 * positive (and 0 == success).  Negative values are used by
247 		 * the test framework to signal fatal errors (CTEST_xxx).
248 		 */
249 		if (ret > 0) {
250 			(void) fprintf(stderr, "        failure %s\n",
251 			    cryptotest_errstr(ret, errbuf, sizeof (errbuf)));
252 			errs += 1;
253 		} else if (ret < 0) {
254 			(void) fprintf(stderr, "        fatal error %s\n",
255 			    ctest_errstr(ret, errbuf, sizeof (errbuf)));
256 			exit(EXIT_FAILURE_MULTIPART);
257 		} else {
258 			errs += bufcmp(cmp, args->out, cmplen);
259 		}
260 	}
261 
262 	VERIFY3U(errs, <=, INT_MAX);
263 	cryptotest_close(crypto_op);
264 	return (errs);
265 }
266 
267 static int
test_single(cryptotest_t * args,test_fg_t * funcs,uint8_t * cmp,size_t cmplen)268 test_single(cryptotest_t *args, test_fg_t *funcs, uint8_t *cmp, size_t cmplen)
269 {
270 	crypto_op_t *crypto_op = NULL;
271 	char errbuf[BUFSZ] = { 0 };
272 	int ret;
273 
274 	(void) fprintf(stderr, "single part:\n");
275 
276 	if ((ret = test_setup(args, funcs, &crypto_op)) != CRYPTO_SUCCESS) {
277 		(void) fprintf(stderr, "        fatal error %d\n", ret);
278 		exit(EXIT_FAILURE_SINGLEPART);
279 	}
280 
281 	if ((ret = funcs->tf_init(crypto_op)) != CRYPTO_SUCCESS) {
282 		(void) fprintf(stderr, "        fatal error %d\n", ret);
283 		exit(EXIT_FAILURE_SINGLEPART);
284 	}
285 
286 	if ((ret = funcs->tf_single(crypto_op)) != CRYPTO_SUCCESS)
287 		goto out;
288 
289 	/*
290 	 * Errors from the crypto frameworks (KCF, PKCS#11) are all
291 	 * positive (and 0 == success).  Negative values are used by
292 	 * the test framework to signal fatal errors (CTEST_xxx).
293 	 */
294 	if (ret > 0) {
295 		(void) fprintf(stderr, "        failure %s\n",
296 		    cryptotest_errstr(ret, errbuf, sizeof (errbuf)));
297 		return (1);
298 	} else if (ret < 0) {
299 		(void) fprintf(stderr, "        fatal error %s\n",
300 		    ctest_errstr(ret, errbuf, sizeof (errbuf)));
301 		exit(EXIT_FAILURE_SINGLEPART);
302 	} else {
303 		ret = bufcmp(cmp, args->out, cmplen);
304 	}
305 
306 out:
307 	(void) cryptotest_close(crypto_op);
308 	return ((ret == CRYPTO_SUCCESS) ? 0 : 1);
309 }
310 
311 /*
312  * Wrapper functions
313  */
314 
315 int
run_test(cryptotest_t * args,uint8_t * cmp,size_t cmplen,test_fg_t * funcs)316 run_test(cryptotest_t *args, uint8_t *cmp, size_t cmplen,
317     test_fg_t *funcs)
318 {
319 	size_t errs = 0;
320 	static int i = 0;
321 
322 	(void) fprintf(stderr, "%s: run %d\n", args->mechname, ++i);
323 
324 	errs += test_multi(args, funcs, cmp, cmplen);
325 
326 	bzero(args->out, args->outlen);
327 
328 	errs += test_single(args, funcs, cmp, cmplen);
329 
330 	VERIFY3U(errs, <=, INT_MAX);
331 	return (errs);
332 }
333