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