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