cryptodev.c revision 168355
1/*	$OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $	*/
2
3/*-
4 * Copyright (c) 2001 Theo de Raadt
5 * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *   notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *   notice, this list of conditions and the following disclaimer in the
15 *   documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *   derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Effort sponsored in part by the Defense Advanced Research Projects
31 * Agency (DARPA) and Air Force Research Laboratory, Air Force
32 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/sys/opencrypto/cryptodev.c 168355 2007-04-04 09:11:34Z rwatson $");
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/lock.h>
43#include <sys/mutex.h>
44#include <sys/sysctl.h>
45#include <sys/file.h>
46#include <sys/filedesc.h>
47#include <sys/errno.h>
48#include <sys/uio.h>
49#include <sys/random.h>
50#include <sys/conf.h>
51#include <sys/kernel.h>
52#include <sys/module.h>
53#include <sys/fcntl.h>
54#include <sys/bus.h>
55
56#include <opencrypto/cryptodev.h>
57#include <opencrypto/xform.h>
58
59struct csession {
60	TAILQ_ENTRY(csession) next;
61	u_int64_t	sid;
62	u_int32_t	ses;
63	struct mtx	lock;		/* for op submission */
64
65	u_int32_t	cipher;
66	struct enc_xform *txform;
67	u_int32_t	mac;
68	struct auth_hash *thash;
69
70	caddr_t		key;
71	int		keylen;
72	u_char		tmp_iv[EALG_MAX_BLOCK_LEN];
73
74	caddr_t		mackey;
75	int		mackeylen;
76
77	struct iovec	iovec;
78	struct uio	uio;
79	int		error;
80};
81
82struct fcrypt {
83	TAILQ_HEAD(csessionlist, csession) csessions;
84	int		sesn;
85};
86
87static	int cryptof_rw(struct file *fp, struct uio *uio,
88		    struct ucred *cred, int flags, struct thread *);
89static	int cryptof_ioctl(struct file *, u_long, void *,
90		    struct ucred *, struct thread *);
91static	int cryptof_poll(struct file *, int, struct ucred *, struct thread *);
92static	int cryptof_kqfilter(struct file *, struct knote *);
93static	int cryptof_stat(struct file *, struct stat *,
94		    struct ucred *, struct thread *);
95static	int cryptof_close(struct file *, struct thread *);
96
97static struct fileops cryptofops = {
98    .fo_read = cryptof_rw,
99    .fo_write = cryptof_rw,
100    .fo_ioctl = cryptof_ioctl,
101    .fo_poll = cryptof_poll,
102    .fo_kqfilter = cryptof_kqfilter,
103    .fo_stat = cryptof_stat,
104    .fo_close = cryptof_close
105};
106
107static struct csession *csefind(struct fcrypt *, u_int);
108static int csedelete(struct fcrypt *, struct csession *);
109static struct csession *cseadd(struct fcrypt *, struct csession *);
110static struct csession *csecreate(struct fcrypt *, u_int64_t, caddr_t,
111    u_int64_t, caddr_t, u_int64_t, u_int32_t, u_int32_t, struct enc_xform *,
112    struct auth_hash *);
113static int csefree(struct csession *);
114
115static	int cryptodev_op(struct csession *, struct crypt_op *,
116			struct ucred *, struct thread *td);
117static	int cryptodev_key(struct crypt_kop *);
118static	int cryptodev_find(struct crypt_find_op *);
119
120static int
121cryptof_rw(
122	struct file *fp,
123	struct uio *uio,
124	struct ucred *active_cred,
125	int flags,
126	struct thread *td)
127{
128
129	return (EIO);
130}
131
132/*
133 * Check a crypto identifier to see if it requested
134 * a software device/driver.  This can be done either
135 * by device name/class or through search constraints.
136 */
137static int
138checkforsoftware(int crid)
139{
140	if (crid & CRYPTOCAP_F_SOFTWARE)
141		return EINVAL;		/* XXX */
142	if ((crid & CRYPTOCAP_F_HARDWARE) == 0 &&
143	    (crypto_getcaps(crid) & CRYPTOCAP_F_HARDWARE) == 0)
144		return EINVAL;		/* XXX */
145	return 0;
146}
147
148/* ARGSUSED */
149static int
150cryptof_ioctl(
151	struct file *fp,
152	u_long cmd,
153	void *data,
154	struct ucred *active_cred,
155	struct thread *td)
156{
157#define	SES2(p)	((struct session2_op *)p)
158	struct cryptoini cria, crie;
159	struct fcrypt *fcr = fp->f_data;
160	struct csession *cse;
161	struct session_op *sop;
162	struct crypt_op *cop;
163	struct enc_xform *txform = NULL;
164	struct auth_hash *thash = NULL;
165	struct crypt_kop *kop;
166	u_int64_t sid;
167	u_int32_t ses;
168	int error = 0, crid;
169
170	switch (cmd) {
171	case CIOCGSESSION:
172	case CIOCGSESSION2:
173		sop = (struct session_op *)data;
174		switch (sop->cipher) {
175		case 0:
176			break;
177		case CRYPTO_DES_CBC:
178			txform = &enc_xform_des;
179			break;
180		case CRYPTO_3DES_CBC:
181			txform = &enc_xform_3des;
182			break;
183		case CRYPTO_BLF_CBC:
184			txform = &enc_xform_blf;
185			break;
186		case CRYPTO_CAST_CBC:
187			txform = &enc_xform_cast5;
188			break;
189		case CRYPTO_SKIPJACK_CBC:
190			txform = &enc_xform_skipjack;
191			break;
192		case CRYPTO_AES_CBC:
193			txform = &enc_xform_rijndael128;
194			break;
195		case CRYPTO_NULL_CBC:
196			txform = &enc_xform_null;
197			break;
198		case CRYPTO_ARC4:
199			txform = &enc_xform_arc4;
200			break;
201		default:
202			return (EINVAL);
203		}
204
205		switch (sop->mac) {
206		case 0:
207			break;
208		case CRYPTO_MD5_HMAC:
209			thash = &auth_hash_hmac_md5;
210			break;
211		case CRYPTO_SHA1_HMAC:
212			thash = &auth_hash_hmac_sha1;
213			break;
214		case CRYPTO_SHA2_256_HMAC:
215			thash = &auth_hash_hmac_sha2_256;
216			break;
217		case CRYPTO_SHA2_384_HMAC:
218			thash = &auth_hash_hmac_sha2_384;
219			break;
220		case CRYPTO_SHA2_512_HMAC:
221			thash = &auth_hash_hmac_sha2_512;
222			break;
223		case CRYPTO_RIPEMD160_HMAC:
224			thash = &auth_hash_hmac_ripemd_160;
225			break;
226#ifdef notdef
227		case CRYPTO_MD5:
228			thash = &auth_hash_md5;
229			break;
230		case CRYPTO_SHA1:
231			thash = &auth_hash_sha1;
232			break;
233#endif
234		case CRYPTO_NULL_HMAC:
235			thash = &auth_hash_null;
236			break;
237		default:
238			return (EINVAL);
239		}
240
241		bzero(&crie, sizeof(crie));
242		bzero(&cria, sizeof(cria));
243
244		if (txform) {
245			crie.cri_alg = txform->type;
246			crie.cri_klen = sop->keylen * 8;
247			if (sop->keylen > txform->maxkey ||
248			    sop->keylen < txform->minkey) {
249				error = EINVAL;
250				goto bail;
251			}
252
253			MALLOC(crie.cri_key, u_int8_t *,
254			    crie.cri_klen / 8, M_XDATA, M_WAITOK);
255			if ((error = copyin(sop->key, crie.cri_key,
256			    crie.cri_klen / 8)))
257				goto bail;
258			if (thash)
259				crie.cri_next = &cria;
260		}
261
262		if (thash) {
263			cria.cri_alg = thash->type;
264			cria.cri_klen = sop->mackeylen * 8;
265			if (sop->mackeylen != thash->keysize) {
266				error = EINVAL;
267				goto bail;
268			}
269
270			if (cria.cri_klen) {
271				MALLOC(cria.cri_key, u_int8_t *,
272				    cria.cri_klen / 8, M_XDATA, M_WAITOK);
273				if ((error = copyin(sop->mackey, cria.cri_key,
274				    cria.cri_klen / 8)))
275					goto bail;
276			}
277		}
278
279		/* NB: CIOGSESSION2 has the crid */
280		if (cmd == CIOCGSESSION2) {
281			crid = SES2(sop)->crid;
282			error = checkforsoftware(crid);
283			if (error)
284				goto bail;
285		} else
286			crid = CRYPTOCAP_F_HARDWARE;
287		error = crypto_newsession(&sid, (txform ? &crie : &cria), crid);
288		if (error)
289			goto bail;
290
291		cse = csecreate(fcr, sid, crie.cri_key, crie.cri_klen,
292		    cria.cri_key, cria.cri_klen, sop->cipher, sop->mac, txform,
293		    thash);
294
295		if (cse == NULL) {
296			crypto_freesession(sid);
297			error = EINVAL;
298			goto bail;
299		}
300		sop->ses = cse->ses;
301		if (cmd == CIOCGSESSION2) {
302			/* return hardware/driver id */
303			SES2(sop)->crid = CRYPTO_SESID2HID(cse->sid);
304		}
305bail:
306		if (error) {
307			if (crie.cri_key)
308				FREE(crie.cri_key, M_XDATA);
309			if (cria.cri_key)
310				FREE(cria.cri_key, M_XDATA);
311		}
312		break;
313	case CIOCFSESSION:
314		ses = *(u_int32_t *)data;
315		cse = csefind(fcr, ses);
316		if (cse == NULL)
317			return (EINVAL);
318		csedelete(fcr, cse);
319		error = csefree(cse);
320		break;
321	case CIOCCRYPT:
322		cop = (struct crypt_op *)data;
323		cse = csefind(fcr, cop->ses);
324		if (cse == NULL)
325			return (EINVAL);
326		error = cryptodev_op(cse, cop, active_cred, td);
327		break;
328	case CIOCKEY:
329	case CIOCKEY2:
330		if (!crypto_userasymcrypto)
331			return (EPERM);		/* XXX compat? */
332		mtx_lock(&Giant);
333		kop = (struct crypt_kop *)data;
334		if (cmd == CIOCKEY) {
335			/* NB: crypto core enforces s/w driver use */
336			kop->crk_crid =
337			    CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
338		}
339		error = cryptodev_key(kop);
340		mtx_unlock(&Giant);
341		break;
342	case CIOCASYMFEAT:
343		if (!crypto_userasymcrypto) {
344			/*
345			 * NB: if user asym crypto operations are
346			 * not permitted return "no algorithms"
347			 * so well-behaved applications will just
348			 * fallback to doing them in software.
349			 */
350			*(int *)data = 0;
351		} else
352			error = crypto_getfeat((int *)data);
353		break;
354	case CIOCFINDDEV:
355		error = cryptodev_find((struct crypt_find_op *)data);
356		break;
357	default:
358		error = EINVAL;
359		break;
360	}
361	return (error);
362#undef SES2
363}
364
365static int cryptodev_cb(void *);
366
367
368static int
369cryptodev_op(
370	struct csession *cse,
371	struct crypt_op *cop,
372	struct ucred *active_cred,
373	struct thread *td)
374{
375	struct cryptop *crp = NULL;
376	struct cryptodesc *crde = NULL, *crda = NULL;
377	int error;
378
379	if (cop->len > 256*1024-4)
380		return (E2BIG);
381
382	if (cse->txform) {
383		if (cop->len == 0 || (cop->len % cse->txform->blocksize) != 0)
384			return (EINVAL);
385	}
386
387	cse->uio.uio_iov = &cse->iovec;
388	cse->uio.uio_iovcnt = 1;
389	cse->uio.uio_offset = 0;
390	cse->uio.uio_resid = cop->len;
391	cse->uio.uio_segflg = UIO_SYSSPACE;
392	cse->uio.uio_rw = UIO_WRITE;
393	cse->uio.uio_td = td;
394	cse->uio.uio_iov[0].iov_len = cop->len;
395	if (cse->thash)
396		cse->uio.uio_iov[0].iov_len += cse->thash->hashsize;
397	cse->uio.uio_iov[0].iov_base = malloc(cse->uio.uio_iov[0].iov_len,
398	    M_XDATA, M_WAITOK);
399
400	crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL));
401	if (crp == NULL) {
402		error = ENOMEM;
403		goto bail;
404	}
405
406	if (cse->thash) {
407		crda = crp->crp_desc;
408		if (cse->txform)
409			crde = crda->crd_next;
410	} else {
411		if (cse->txform)
412			crde = crp->crp_desc;
413		else {
414			error = EINVAL;
415			goto bail;
416		}
417	}
418
419	if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, cop->len)))
420		goto bail;
421
422	if (crda) {
423		crda->crd_skip = 0;
424		crda->crd_len = cop->len;
425		crda->crd_inject = cop->len;
426
427		crda->crd_alg = cse->mac;
428		crda->crd_key = cse->mackey;
429		crda->crd_klen = cse->mackeylen * 8;
430	}
431
432	if (crde) {
433		if (cop->op == COP_ENCRYPT)
434			crde->crd_flags |= CRD_F_ENCRYPT;
435		else
436			crde->crd_flags &= ~CRD_F_ENCRYPT;
437		crde->crd_len = cop->len;
438		crde->crd_inject = 0;
439
440		crde->crd_alg = cse->cipher;
441		crde->crd_key = cse->key;
442		crde->crd_klen = cse->keylen * 8;
443	}
444
445	crp->crp_ilen = cop->len;
446	crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
447		       | (cop->flags & COP_F_BATCH);
448	crp->crp_buf = (caddr_t)&cse->uio;
449	crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
450	crp->crp_sid = cse->sid;
451	crp->crp_opaque = (void *)cse;
452
453	if (cop->iv) {
454		if (crde == NULL) {
455			error = EINVAL;
456			goto bail;
457		}
458		if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
459			error = EINVAL;
460			goto bail;
461		}
462		if ((error = copyin(cop->iv, cse->tmp_iv, cse->txform->blocksize)))
463			goto bail;
464		bcopy(cse->tmp_iv, crde->crd_iv, cse->txform->blocksize);
465		crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
466		crde->crd_skip = 0;
467	} else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
468		crde->crd_skip = 0;
469	} else if (crde) {
470		crde->crd_flags |= CRD_F_IV_PRESENT;
471		crde->crd_skip = cse->txform->blocksize;
472		crde->crd_len -= cse->txform->blocksize;
473	}
474
475	if (cop->mac && crda == NULL) {
476		error = EINVAL;
477		goto bail;
478	}
479
480	/*
481	 * Let the dispatch run unlocked, then, interlock against the
482	 * callback before checking if the operation completed and going
483	 * to sleep.  This insures drivers don't inherit our lock which
484	 * results in a lock order reversal between crypto_dispatch forced
485	 * entry and the crypto_done callback into us.
486	 */
487	error = crypto_dispatch(crp);
488	mtx_lock(&cse->lock);
489	if (error == 0 && (crp->crp_flags & CRYPTO_F_DONE) == 0)
490		error = msleep(crp, &cse->lock, PWAIT, "crydev", 0);
491	mtx_unlock(&cse->lock);
492
493	if (error != 0)
494		goto bail;
495
496	if (crp->crp_etype != 0) {
497		error = crp->crp_etype;
498		goto bail;
499	}
500
501	if (cse->error) {
502		error = cse->error;
503		goto bail;
504	}
505
506	if (cop->dst &&
507	    (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len)))
508		goto bail;
509
510	if (cop->mac &&
511	    (error = copyout((caddr_t)cse->uio.uio_iov[0].iov_base + cop->len,
512	    cop->mac, cse->thash->hashsize)))
513		goto bail;
514
515bail:
516	if (crp)
517		crypto_freereq(crp);
518	if (cse->uio.uio_iov[0].iov_base)
519		free(cse->uio.uio_iov[0].iov_base, M_XDATA);
520
521	return (error);
522}
523
524static int
525cryptodev_cb(void *op)
526{
527	struct cryptop *crp = (struct cryptop *) op;
528	struct csession *cse = (struct csession *)crp->crp_opaque;
529	int error;
530
531	error = crp->crp_etype;
532	if (error == EAGAIN)
533		error = crypto_dispatch(crp);
534	mtx_lock(&cse->lock);
535	if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
536		cse->error = error;
537		wakeup_one(crp);
538	}
539	mtx_unlock(&cse->lock);
540	return (0);
541}
542
543static int
544cryptodevkey_cb(void *op)
545{
546	struct cryptkop *krp = (struct cryptkop *) op;
547
548	wakeup_one(krp);
549	return (0);
550}
551
552static int
553cryptodev_key(struct crypt_kop *kop)
554{
555	struct cryptkop *krp = NULL;
556	int error = EINVAL;
557	int in, out, size, i;
558
559	if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
560		return (EFBIG);
561	}
562
563	in = kop->crk_iparams;
564	out = kop->crk_oparams;
565	switch (kop->crk_op) {
566	case CRK_MOD_EXP:
567		if (in == 3 && out == 1)
568			break;
569		return (EINVAL);
570	case CRK_MOD_EXP_CRT:
571		if (in == 6 && out == 1)
572			break;
573		return (EINVAL);
574	case CRK_DSA_SIGN:
575		if (in == 5 && out == 2)
576			break;
577		return (EINVAL);
578	case CRK_DSA_VERIFY:
579		if (in == 7 && out == 0)
580			break;
581		return (EINVAL);
582	case CRK_DH_COMPUTE_KEY:
583		if (in == 3 && out == 1)
584			break;
585		return (EINVAL);
586	default:
587		return (EINVAL);
588	}
589
590	krp = (struct cryptkop *)malloc(sizeof *krp, M_XDATA, M_WAITOK);
591	if (!krp)
592		return (ENOMEM);
593	bzero(krp, sizeof *krp);
594	krp->krp_op = kop->crk_op;
595	krp->krp_status = kop->crk_status;
596	krp->krp_iparams = kop->crk_iparams;
597	krp->krp_oparams = kop->crk_oparams;
598	krp->krp_crid = kop->crk_crid;
599	krp->krp_status = 0;
600	krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
601
602	for (i = 0; i < CRK_MAXPARAM; i++)
603		krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
604	for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
605		size = (krp->krp_param[i].crp_nbits + 7) / 8;
606		if (size == 0)
607			continue;
608		MALLOC(krp->krp_param[i].crp_p, caddr_t, size, M_XDATA, M_WAITOK);
609		if (i >= krp->krp_iparams)
610			continue;
611		error = copyin(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size);
612		if (error)
613			goto fail;
614	}
615
616	error = crypto_kdispatch(krp);
617	if (error)
618		goto fail;
619	error = tsleep(krp, PSOCK, "crydev", 0);
620	if (error) {
621		/* XXX can this happen?  if so, how do we recover? */
622		goto fail;
623	}
624
625	kop->crk_crid = krp->krp_crid;		/* device that did the work */
626	if (krp->krp_status != 0) {
627		error = krp->krp_status;
628		goto fail;
629	}
630
631	for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
632		size = (krp->krp_param[i].crp_nbits + 7) / 8;
633		if (size == 0)
634			continue;
635		error = copyout(krp->krp_param[i].crp_p, kop->crk_param[i].crp_p, size);
636		if (error)
637			goto fail;
638	}
639
640fail:
641	if (krp) {
642		kop->crk_status = krp->krp_status;
643		for (i = 0; i < CRK_MAXPARAM; i++) {
644			if (krp->krp_param[i].crp_p)
645				FREE(krp->krp_param[i].crp_p, M_XDATA);
646		}
647		free(krp, M_XDATA);
648	}
649	return (error);
650}
651
652static int
653cryptodev_find(struct crypt_find_op *find)
654{
655	device_t dev;
656
657	if (find->crid != -1) {
658		dev = crypto_find_device_byhid(find->crid);
659		if (dev == NULL)
660			return (ENOENT);
661		strlcpy(find->name, device_get_nameunit(dev),
662		    sizeof(find->name));
663	} else {
664		find->crid = crypto_find_driver(find->name);
665		if (find->crid == -1)
666			return (ENOENT);
667	}
668	return (0);
669}
670
671/* ARGSUSED */
672static int
673cryptof_poll(
674	struct file *fp,
675	int events,
676	struct ucred *active_cred,
677	struct thread *td)
678{
679
680	return (0);
681}
682
683/* ARGSUSED */
684static int
685cryptof_kqfilter(struct file *fp, struct knote *kn)
686{
687
688	return (0);
689}
690
691/* ARGSUSED */
692static int
693cryptof_stat(
694	struct file *fp,
695	struct stat *sb,
696	struct ucred *active_cred,
697	struct thread *td)
698{
699
700	return (EOPNOTSUPP);
701}
702
703/* ARGSUSED */
704static int
705cryptof_close(struct file *fp, struct thread *td)
706{
707	struct fcrypt *fcr = fp->f_data;
708	struct csession *cse;
709
710	while ((cse = TAILQ_FIRST(&fcr->csessions))) {
711		TAILQ_REMOVE(&fcr->csessions, cse, next);
712		(void)csefree(cse);
713	}
714	FREE(fcr, M_XDATA);
715	fp->f_data = NULL;
716	return 0;
717}
718
719static struct csession *
720csefind(struct fcrypt *fcr, u_int ses)
721{
722	struct csession *cse;
723
724	TAILQ_FOREACH(cse, &fcr->csessions, next)
725		if (cse->ses == ses)
726			return (cse);
727	return (NULL);
728}
729
730static int
731csedelete(struct fcrypt *fcr, struct csession *cse_del)
732{
733	struct csession *cse;
734
735	TAILQ_FOREACH(cse, &fcr->csessions, next) {
736		if (cse == cse_del) {
737			TAILQ_REMOVE(&fcr->csessions, cse, next);
738			return (1);
739		}
740	}
741	return (0);
742}
743
744static struct csession *
745cseadd(struct fcrypt *fcr, struct csession *cse)
746{
747	TAILQ_INSERT_TAIL(&fcr->csessions, cse, next);
748	cse->ses = fcr->sesn++;
749	return (cse);
750}
751
752struct csession *
753csecreate(struct fcrypt *fcr, u_int64_t sid, caddr_t key, u_int64_t keylen,
754    caddr_t mackey, u_int64_t mackeylen, u_int32_t cipher, u_int32_t mac,
755    struct enc_xform *txform, struct auth_hash *thash)
756{
757	struct csession *cse;
758
759#ifdef INVARIANTS
760	/* NB: required when mtx_init is built with INVARIANTS */
761	MALLOC(cse, struct csession *, sizeof(struct csession),
762	    M_XDATA, M_NOWAIT | M_ZERO);
763#else
764	MALLOC(cse, struct csession *, sizeof(struct csession),
765	    M_XDATA, M_NOWAIT);
766#endif
767	if (cse == NULL)
768		return NULL;
769	mtx_init(&cse->lock, "cryptodev", "crypto session lock", MTX_DEF);
770	cse->key = key;
771	cse->keylen = keylen/8;
772	cse->mackey = mackey;
773	cse->mackeylen = mackeylen/8;
774	cse->sid = sid;
775	cse->cipher = cipher;
776	cse->mac = mac;
777	cse->txform = txform;
778	cse->thash = thash;
779	cseadd(fcr, cse);
780	return (cse);
781}
782
783static int
784csefree(struct csession *cse)
785{
786	int error;
787
788	error = crypto_freesession(cse->sid);
789	mtx_destroy(&cse->lock);
790	if (cse->key)
791		FREE(cse->key, M_XDATA);
792	if (cse->mackey)
793		FREE(cse->mackey, M_XDATA);
794	FREE(cse, M_XDATA);
795	return (error);
796}
797
798static int
799cryptoopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
800{
801	return (0);
802}
803
804static int
805cryptoread(struct cdev *dev, struct uio *uio, int ioflag)
806{
807	return (EIO);
808}
809
810static int
811cryptowrite(struct cdev *dev, struct uio *uio, int ioflag)
812{
813	return (EIO);
814}
815
816static int
817cryptoioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
818{
819	struct file *f;
820	struct fcrypt *fcr;
821	int fd, error;
822
823	switch (cmd) {
824	case CRIOGET:
825		MALLOC(fcr, struct fcrypt *,
826		    sizeof(struct fcrypt), M_XDATA, M_WAITOK);
827		TAILQ_INIT(&fcr->csessions);
828		fcr->sesn = 0;
829
830		error = falloc(td, &f, &fd);
831
832		if (error) {
833			FREE(fcr, M_XDATA);
834			return (error);
835		}
836		/* falloc automatically provides an extra reference to 'f'. */
837		FILE_LOCK(f);
838		f->f_flag = FREAD | FWRITE;
839		f->f_type = DTYPE_CRYPTO;
840		f->f_data = fcr;
841		f->f_ops = &cryptofops;
842		FILE_UNLOCK(f);
843		*(u_int32_t *)data = fd;
844		fdrop(f, td);
845		break;
846	case CRIOFINDDEV:
847		error = cryptodev_find((struct crypt_find_op *)data);
848		break;
849	case CRIOASYMFEAT:
850		error = crypto_getfeat((int *)data);
851		break;
852	default:
853		error = EINVAL;
854		break;
855	}
856	return (error);
857}
858
859static struct cdevsw crypto_cdevsw = {
860	.d_version =	D_VERSION,
861	.d_flags =	D_NEEDGIANT,
862	.d_open =	cryptoopen,
863	.d_read =	cryptoread,
864	.d_write =	cryptowrite,
865	.d_ioctl =	cryptoioctl,
866	.d_name =	"crypto",
867};
868static struct cdev *crypto_dev;
869
870/*
871 * Initialization code, both for static and dynamic loading.
872 */
873static int
874cryptodev_modevent(module_t mod, int type, void *unused)
875{
876	switch (type) {
877	case MOD_LOAD:
878		if (bootverbose)
879			printf("crypto: <crypto device>\n");
880		crypto_dev = make_dev(&crypto_cdevsw, 0,
881				      UID_ROOT, GID_WHEEL, 0666,
882				      "crypto");
883		return 0;
884	case MOD_UNLOAD:
885		/*XXX disallow if active sessions */
886		destroy_dev(crypto_dev);
887		return 0;
888	}
889	return EINVAL;
890}
891
892static moduledata_t cryptodev_mod = {
893	"cryptodev",
894	cryptodev_modevent,
895	0
896};
897MODULE_VERSION(cryptodev, 1);
898DECLARE_MODULE(cryptodev, cryptodev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
899MODULE_DEPEND(cryptodev, crypto, 1, 1, 1);
900MODULE_DEPEND(cryptodev, zlib, 1, 1, 1);
901