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