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 2015 Nexenta Systems, Inc.  All rights reserved.
14  * Copyright 2018, Joyent, Inc.
15  */
16 
17 #include <fcntl.h>
18 #include <strings.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "cryptotest.h"
25 
26 struct crypto_op {
27 	char *in;
28 	char *out;
29 	char *key;
30 	char *param;
31 
32 	size_t inlen;
33 	size_t outlen;
34 	size_t keylen;
35 	size_t paramlen;
36 	size_t updatelen;
37 
38 	char *mechname;
39 
40 	/* internal */
41 	crypto_mech_type_t mech;
42 	crypto_session_id_t hsession;
43 	crypto_func_group_t fg;
44 };
45 
46 static int fd;
47 static const char CRYPTO_DEVICE[] = "/dev/crypto";
48 
49 int
50 kcf_do_ioctl(int opcode, uint_t *arg, char *opstr)
51 {
52 	int ret;
53 
54 	while ((ret = ioctl(fd, opcode, arg)) < 0) {
55 		if (errno != EINTR)
56 			break;
57 	}
58 
59 	if (ret < 0 || *arg != CRYPTO_SUCCESS)
60 		(void) fprintf(stderr, "%s: Error = %d %d 0x%02x\n",
61 		    (opstr == NULL) ? "ioctl" : opstr,
62 		    ret, errno, *arg);
63 
64 	if (ret < 0)
65 		return (errno);
66 
67 	return (*arg);
68 }
69 
70 crypto_op_t *
71 cryptotest_init(cryptotest_t *arg, crypto_func_group_t fg)
72 {
73 	crypto_op_t *op = malloc(sizeof (*op));
74 
75 	if (op == NULL)
76 		return (NULL);
77 
78 	while ((fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) {
79 		if (errno != EINTR)
80 			return (NULL);
81 	}
82 
83 	op->in = (char *)arg->in;
84 	op->out = (char *)arg->out;
85 	op->key = (char *)arg->key;
86 	op->param = (char *)arg->param;
87 
88 	op->inlen = arg->inlen;
89 	op->outlen = arg->outlen;
90 	op->keylen = arg->keylen * 8; /* kcf uses keylen in bits */
91 	op->paramlen = arg->plen;
92 	op->updatelen = arg->updatelen;
93 
94 	op->mechname = arg->mechname;
95 
96 	op->hsession = CRYPTO_INVALID_SESSION;
97 	op->fg = fg;
98 
99 	if (op->out == NULL)
100 		op->outlen = op->inlen;
101 	return (op);
102 }
103 
104 int
105 cryptotest_close_session(crypto_session_id_t session)
106 {
107 	crypto_close_session_t cs;
108 
109 	cs.cs_session = session;
110 	return (kcf_do_ioctl(CRYPTO_CLOSE_SESSION, (uint_t *)&cs, "session"));
111 }
112 
113 int
114 cryptotest_close(crypto_op_t *op)
115 {
116 	if (op->hsession != CRYPTO_INVALID_SESSION)
117 		(void) cryptotest_close_session(op->hsession);
118 	free(op);
119 	if (fd >= 0)
120 		return (close(fd));
121 	return (0);
122 }
123 
124 int
125 get_mech_info(crypto_op_t *op)
126 {
127 	crypto_get_mechanism_number_t get_number;
128 
129 	bzero(&get_number, sizeof (get_number));
130 
131 	get_number.pn_mechanism_string = op->mechname;
132 	get_number.pn_mechanism_len = strlen(op->mechname) + 1;
133 
134 	if (kcf_do_ioctl(CRYPTO_GET_MECHANISM_NUMBER,
135 	    (uint_t *)&get_number, "get_mech_info") != CRYPTO_SUCCESS) {
136 		(void) fprintf(stderr, "failed to resolve mechanism name %s\n",
137 		    op->mechname);
138 		return (CTEST_NAME_RESOLVE_FAILED);
139 	}
140 	op->mech = get_number.pn_internal_number;
141 	return (CRYPTO_SUCCESS);
142 }
143 
144 int
145 get_hsession_by_mech(crypto_op_t *op)
146 {
147 	crypto_by_mech_t mech;
148 	int rv;
149 
150 	mech.mech_keylen = op->keylen;
151 	mech.mech_type = op->mech;
152 	mech.mech_fg = op->fg;
153 
154 	rv = kcf_do_ioctl(CRYPTO_GET_PROVIDER_BY_MECH, (uint_t *)&mech,
155 	    "get_hsession_by_mech");
156 
157 	if (rv != 0 || mech.rv != CRYPTO_SUCCESS) {
158 		(void) fprintf(stderr,
159 		    "could not find provider for mechanism %llu\n",
160 		    mech.mech_type);
161 		return (CTEST_MECH_NO_PROVIDER);
162 	}
163 
164 	op->hsession = mech.session_id;
165 
166 	return (CRYPTO_SUCCESS);
167 }
168 
169 /*
170  * CRYPTO_MAC_* functions
171  */
172 int
173 mac_init(crypto_op_t *op)
174 {
175 	crypto_mac_init_t init;
176 
177 	bzero((void *)&init, sizeof (init));
178 
179 	init.mi_session = op->hsession;
180 
181 	init.mi_key.ck_data = op->key;
182 	init.mi_key.ck_format = CRYPTO_KEY_RAW; /* must be this */
183 	init.mi_key.ck_length = op->keylen;
184 
185 	init.mi_mech.cm_type = op->mech;
186 	init.mi_mech.cm_param = NULL;
187 	init.mi_mech.cm_param_len = 0;
188 
189 	return (kcf_do_ioctl(CRYPTO_MAC_INIT, (uint_t *)&init, "init"));
190 }
191 
192 int
193 mac_single(crypto_op_t *op)
194 {
195 	crypto_mac_t mac;
196 
197 	bzero(&mac, sizeof (mac));
198 	mac.cm_session = op->hsession;
199 	mac.cm_datalen = op->inlen;
200 	mac.cm_databuf = op->in;
201 	mac.cm_maclen = op->outlen;
202 	mac.cm_macbuf = op->out;
203 
204 	return (kcf_do_ioctl(CRYPTO_MAC, (uint_t *)&mac, "single"));
205 }
206 
207 int
208 mac_update(crypto_op_t *op, int offset)
209 {
210 	crypto_mac_update_t update;
211 
212 	bzero((void *)&update, sizeof (update));
213 
214 	update.mu_session = op->hsession;
215 	update.mu_databuf = op->in + offset;
216 	update.mu_datalen = op->updatelen;
217 
218 	return (kcf_do_ioctl(CRYPTO_MAC_UPDATE, (uint_t *)&update, "update"));
219 }
220 
221 int
222 mac_final(crypto_op_t *op)
223 {
224 	crypto_mac_final_t final;
225 
226 	bzero((void *)&final, sizeof (final));
227 
228 	final.mf_session = op->hsession;
229 	final.mf_maclen = op->outlen;
230 	final.mf_macbuf = op->out;
231 
232 	return (kcf_do_ioctl(CRYPTO_MAC_FINAL, (uint_t *)&final, "final"));
233 }
234 
235 
236 /*
237  * CRYPTO_ENCRYPT_* functions
238  */
239 
240 int
241 encrypt_init(crypto_op_t *op)
242 {
243 	crypto_encrypt_init_t init;
244 
245 	bzero((void *)&init, sizeof (init));
246 
247 	init.ei_session = op->hsession;
248 
249 	init.ei_key.ck_data = op->key;
250 	init.ei_key.ck_format = CRYPTO_KEY_RAW; /* must be this */
251 	init.ei_key.ck_length = op->keylen;
252 
253 	init.ei_mech.cm_type = op->mech;
254 	init.ei_mech.cm_param = op->param;
255 	init.ei_mech.cm_param_len = op->paramlen;
256 
257 	return (kcf_do_ioctl(CRYPTO_ENCRYPT_INIT, (uint_t *)&init, "init"));
258 }
259 
260 int
261 encrypt_single(crypto_op_t *op)
262 {
263 	crypto_encrypt_t encrypt;
264 
265 	bzero(&encrypt, sizeof (encrypt));
266 	encrypt.ce_session = op->hsession;
267 	encrypt.ce_datalen = op->inlen;
268 	encrypt.ce_databuf = op->in;
269 	encrypt.ce_encrlen = op->outlen;
270 	encrypt.ce_encrbuf = op->out;
271 
272 	return (kcf_do_ioctl(CRYPTO_ENCRYPT, (uint_t *)&encrypt, "single"));
273 }
274 
275 int
276 encrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
277 {
278 	crypto_encrypt_update_t update;
279 	int ret;
280 	bzero((void *)&update, sizeof (update));
281 
282 	update.eu_session = op->hsession;
283 	update.eu_databuf = op->in + offset;
284 	update.eu_datalen = op->updatelen;
285 	update.eu_encrlen = op->outlen - *encrlen;
286 	update.eu_encrbuf = op->out + *encrlen;
287 
288 	ret = kcf_do_ioctl(CRYPTO_ENCRYPT_UPDATE, (uint_t *)&update, "update");
289 	*encrlen += update.eu_encrlen;
290 	return (ret);
291 }
292 
293 int
294 encrypt_final(crypto_op_t *op, size_t encrlen)
295 {
296 	crypto_encrypt_final_t final;
297 
298 	bzero((void *)&final, sizeof (final));
299 
300 	final.ef_session = op->hsession;
301 	final.ef_encrlen = op->outlen - encrlen;
302 	final.ef_encrbuf = op->out + encrlen;
303 
304 	return (kcf_do_ioctl(CRYPTO_ENCRYPT_FINAL, (uint_t *)&final, "final"));
305 }
306 
307 /*
308  * CRYPTO_DECRYPT_* functions
309  */
310 
311 int
312 decrypt_init(crypto_op_t *op)
313 {
314 	crypto_decrypt_init_t init;
315 
316 	bzero((void *)&init, sizeof (init));
317 
318 	init.di_session = op->hsession;
319 
320 	init.di_key.ck_data = op->key;
321 	init.di_key.ck_format = CRYPTO_KEY_RAW; /* must be this */
322 	init.di_key.ck_length = op->keylen;
323 
324 	init.di_mech.cm_type = op->mech;
325 	init.di_mech.cm_param = op->param;
326 	init.di_mech.cm_param_len = op->paramlen;
327 
328 	return (kcf_do_ioctl(CRYPTO_DECRYPT_INIT, (uint_t *)&init, "init"));
329 }
330 
331 int
332 decrypt_single(crypto_op_t *op)
333 {
334 	crypto_decrypt_t decrypt;
335 
336 	bzero(&decrypt, sizeof (decrypt));
337 	decrypt.cd_session = op->hsession;
338 	decrypt.cd_datalen = op->outlen;
339 	decrypt.cd_databuf = op->out;
340 	decrypt.cd_encrlen = op->inlen;
341 	decrypt.cd_encrbuf = op->in;
342 
343 	return (kcf_do_ioctl(CRYPTO_DECRYPT, (uint_t *)&decrypt, "single"));
344 }
345 
346 int
347 decrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
348 {
349 	crypto_decrypt_update_t update;
350 	int ret;
351 
352 	bzero((void *)&update, sizeof (update));
353 
354 	update.du_session = op->hsession;
355 	update.du_databuf = op->out + *encrlen;
356 	update.du_datalen = op->outlen - *encrlen;
357 	update.du_encrlen = op->updatelen;
358 	update.du_encrbuf = op->in + offset;
359 
360 	ret = kcf_do_ioctl(CRYPTO_DECRYPT_UPDATE, (uint_t *)&update, "update");
361 	*encrlen += update.du_datalen;
362 	return (ret);
363 }
364 
365 int
366 decrypt_final(crypto_op_t *op, size_t encrlen)
367 {
368 	crypto_decrypt_final_t final;
369 
370 	bzero((void *)&final, sizeof (final));
371 
372 	final.df_session = op->hsession;
373 	final.df_datalen = op->outlen - encrlen;
374 	final.df_databuf = op->out + encrlen;
375 
376 	return (kcf_do_ioctl(CRYPTO_DECRYPT_FINAL, (uint_t *)&final, "final"));
377 }
378 
379 int
380 digest_init(crypto_op_t *op)
381 {
382 	crypto_digest_init_t init;
383 
384 	bzero(&init, sizeof (init));
385 
386 	init.di_session = op->hsession;
387 
388 	init.di_mech.cm_type = op->mech;
389 	init.di_mech.cm_param = NULL;
390 	init.di_mech.cm_param_len = 0;
391 
392 	return (kcf_do_ioctl(CRYPTO_DIGEST_INIT, (uint_t *)&init, "init"));
393 }
394 
395 int
396 digest_single(crypto_op_t *op)
397 {
398 	crypto_digest_t digest;
399 
400 	bzero(&digest, sizeof (digest));
401 
402 	digest.cd_session = op->hsession;
403 
404 	digest.cd_datalen = op->inlen;
405 	digest.cd_databuf = op->in;
406 	digest.cd_digestlen = op->outlen;
407 	digest.cd_digestbuf = op->out;
408 
409 	return (kcf_do_ioctl(CRYPTO_DIGEST, (uint_t *)&digest, "digest"));
410 }
411 
412 int
413 digest_update(crypto_op_t *op, int offset)
414 {
415 	crypto_digest_update_t update;
416 
417 	bzero(&update, sizeof (update));
418 
419 	update.du_session = op->hsession;
420 
421 	update.du_datalen = op->updatelen;
422 	update.du_databuf = op->in + offset;
423 
424 	return (kcf_do_ioctl(CRYPTO_DIGEST_UPDATE, (uint_t *)&update,
425 	    "update"));
426 }
427 
428 int
429 digest_final(crypto_op_t *op)
430 {
431 	crypto_digest_final_t final;
432 
433 	bzero(&final, sizeof (final));
434 
435 	final.df_session = op->hsession;
436 
437 	final.df_digestlen = op->outlen;
438 	final.df_digestbuf = op->out;
439 
440 	return (kcf_do_ioctl(CRYPTO_DIGEST_FINAL, (uint_t *)&final, "final"));
441 }
442