xref: /openbsd/sys/crypto/crypto.c (revision 3d8817e4)
1 /*	$OpenBSD: crypto.c,v 1.59 2011/01/11 15:42:05 deraadt Exp $	*/
2 /*
3  * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
4  *
5  * This code was written by Angelos D. Keromytis in Athens, Greece, in
6  * February 2000. Network Security Technologies Inc. (NSTI) kindly
7  * supported the development of this code.
8  *
9  * Copyright (c) 2000, 2001 Angelos D. Keromytis
10  *
11  * Permission to use, copy, and modify this software with or without fee
12  * is hereby granted, provided that this entire notice is included in
13  * all source code copies of any software which is or includes a copy or
14  * modification of this software.
15  *
16  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
18  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
19  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
20  * PURPOSE.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/malloc.h>
26 #include <sys/proc.h>
27 #include <sys/pool.h>
28 
29 #include <crypto/cryptodev.h>
30 
31 void crypto_init(void);
32 
33 struct cryptocap *crypto_drivers = NULL;
34 int crypto_drivers_num = 0;
35 
36 struct pool cryptop_pool;
37 struct pool cryptodesc_pool;
38 
39 struct workq *crypto_workq;
40 
41 /*
42  * Create a new session.
43  */
44 int
45 crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard)
46 {
47 	u_int32_t hid, lid, hid2 = -1;
48 	struct cryptocap *cpc;
49 	struct cryptoini *cr;
50 	int err, s, turn = 0;
51 
52 	if (crypto_drivers == NULL)
53 		return EINVAL;
54 
55 	s = splvm();
56 
57 	/*
58 	 * The algorithm we use here is pretty stupid; just use the
59 	 * first driver that supports all the algorithms we need. Do
60 	 * a double-pass over all the drivers, ignoring software ones
61 	 * at first, to deal with cases of drivers that register after
62 	 * the software one(s) --- e.g., PCMCIA crypto cards.
63 	 *
64 	 * XXX We need more smarts here (in real life too, but that's
65 	 * XXX another story altogether).
66 	 */
67 	do {
68 		for (hid = 0; hid < crypto_drivers_num; hid++) {
69 			cpc = &crypto_drivers[hid];
70 
71 			/*
72 			 * If it's not initialized or has remaining sessions
73 			 * referencing it, skip.
74 			 */
75 			if (cpc->cc_newsession == NULL ||
76 			    (cpc->cc_flags & CRYPTOCAP_F_CLEANUP))
77 				continue;
78 
79 			if (cpc->cc_flags & CRYPTOCAP_F_SOFTWARE) {
80 				/*
81 				 * First round of search, ignore
82 				 * software drivers.
83 				 */
84 				if (turn == 0)
85 					continue;
86 			} else { /* !CRYPTOCAP_F_SOFTWARE */
87 				/* Second round of search, only software. */
88 				if (turn == 1)
89 					continue;
90 			}
91 
92 			/* See if all the algorithms are supported. */
93 			for (cr = cri; cr; cr = cr->cri_next) {
94 				if (cpc->cc_alg[cr->cri_alg] == 0)
95 					break;
96 			}
97 
98 			/*
99 			 * If even one algorithm is not supported,
100 			 * keep searching.
101 			 */
102 			if (cr != NULL)
103 				continue;
104 
105 			/*
106 			 * If we had a previous match, see how it compares
107 			 * to this one. Keep "remembering" whichever is
108 			 * the best of the two.
109 			 */
110 			if (hid2 != -1) {
111 				/*
112 				 * Compare session numbers, pick the one
113 				 * with the lowest.
114 				 * XXX Need better metrics, this will
115 				 * XXX just do un-weighted round-robin.
116 				 */
117 				if (crypto_drivers[hid].cc_sessions <=
118 				    crypto_drivers[hid2].cc_sessions)
119 					hid2 = hid;
120 			} else {
121 				/*
122 				 * Remember this one, for future
123                                  * comparisons.
124 				 */
125 				hid2 = hid;
126 			}
127 		}
128 
129 		/*
130 		 * If we found something worth remembering, leave. The
131 		 * side-effect is that we will always prefer a hardware
132 		 * driver over the software one.
133 		 */
134 		if (hid2 != -1)
135 			break;
136 
137 		turn++;
138 
139 		/* If we only want hardware drivers, don't do second pass. */
140 	} while (turn <= 2 && hard == 0);
141 
142 	hid = hid2;
143 
144 	/*
145 	 * Can't do everything in one session.
146 	 *
147 	 * XXX Fix this. We need to inject a "virtual" session
148 	 * XXX layer right about here.
149 	 */
150 
151 	if (hid == -1) {
152 		splx(s);
153 		return EINVAL;
154 	}
155 
156 	/* Call the driver initialization routine. */
157 	lid = hid; /* Pass the driver ID. */
158 	err = crypto_drivers[hid].cc_newsession(&lid, cri);
159 	if (err == 0) {
160 		(*sid) = hid;
161 		(*sid) <<= 32;
162 		(*sid) |= (lid & 0xffffffff);
163 		crypto_drivers[hid].cc_sessions++;
164 	}
165 
166 	splx(s);
167 	return err;
168 }
169 
170 /*
171  * Delete an existing session (or a reserved session on an unregistered
172  * driver).
173  */
174 int
175 crypto_freesession(u_int64_t sid)
176 {
177 	int err = 0, s;
178 	u_int32_t hid;
179 
180 	if (crypto_drivers == NULL)
181 		return EINVAL;
182 
183 	/* Determine two IDs. */
184 	hid = (sid >> 32) & 0xffffffff;
185 
186 	if (hid >= crypto_drivers_num)
187 		return ENOENT;
188 
189 	s = splvm();
190 
191 	if (crypto_drivers[hid].cc_sessions)
192 		crypto_drivers[hid].cc_sessions--;
193 
194 	/* Call the driver cleanup routine, if available. */
195 	if (crypto_drivers[hid].cc_freesession)
196 		err = crypto_drivers[hid].cc_freesession(sid);
197 
198 	/*
199 	 * If this was the last session of a driver marked as invalid,
200 	 * make the entry available for reuse.
201 	 */
202 	if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) &&
203 	    crypto_drivers[hid].cc_sessions == 0)
204 		explicit_bzero(&crypto_drivers[hid], sizeof(struct cryptocap));
205 
206 	splx(s);
207 	return err;
208 }
209 
210 /*
211  * Find an empty slot.
212  */
213 int32_t
214 crypto_get_driverid(u_int8_t flags)
215 {
216 	struct cryptocap *newdrv;
217 	int i, s;
218 
219 	s = splvm();
220 
221 	if (crypto_drivers_num == 0) {
222 		crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
223 		crypto_drivers = malloc(crypto_drivers_num *
224 		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT);
225 		if (crypto_drivers == NULL) {
226 			crypto_drivers_num = 0;
227 			splx(s);
228 			return -1;
229 		}
230 
231 		bzero(crypto_drivers, crypto_drivers_num *
232 		    sizeof(struct cryptocap));
233 	}
234 
235 	for (i = 0; i < crypto_drivers_num; i++) {
236 		if (crypto_drivers[i].cc_process == NULL &&
237 		    !(crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) &&
238 		    crypto_drivers[i].cc_sessions == 0) {
239 			crypto_drivers[i].cc_sessions = 1; /* Mark */
240 			crypto_drivers[i].cc_flags = flags;
241 			splx(s);
242 			return i;
243 		}
244 	}
245 
246 	/* Out of entries, allocate some more. */
247 	if (i == crypto_drivers_num) {
248 		/* Be careful about wrap-around. */
249 		if (2 * crypto_drivers_num <= crypto_drivers_num) {
250 			splx(s);
251 			return -1;
252 		}
253 
254 		newdrv = malloc(2 * crypto_drivers_num *
255 		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT);
256 		if (newdrv == NULL) {
257 			splx(s);
258 			return -1;
259 		}
260 
261 		bcopy(crypto_drivers, newdrv,
262 		    crypto_drivers_num * sizeof(struct cryptocap));
263 		bzero(&newdrv[crypto_drivers_num],
264 		    crypto_drivers_num * sizeof(struct cryptocap));
265 
266 		newdrv[i].cc_sessions = 1; /* Mark */
267 		newdrv[i].cc_flags = flags;
268 		crypto_drivers_num *= 2;
269 
270 		free(crypto_drivers, M_CRYPTO_DATA);
271 		crypto_drivers = newdrv;
272 		splx(s);
273 		return i;
274 	}
275 
276 	/* Shouldn't really get here... */
277 	splx(s);
278 	return -1;
279 }
280 
281 /*
282  * Register a crypto driver. It should be called once for each algorithm
283  * supported by the driver.
284  */
285 int
286 crypto_kregister(u_int32_t driverid, int *kalg,
287     int (*kprocess)(struct cryptkop *))
288 {
289 	int s, i;
290 
291 	if (driverid >= crypto_drivers_num || kalg  == NULL ||
292 	    crypto_drivers == NULL)
293 		return EINVAL;
294 
295 	s = splvm();
296 
297 	for (i = 0; i <= CRK_ALGORITHM_MAX; i++) {
298 		/*
299 		 * XXX Do some performance testing to determine
300 		 * placing.  We probably need an auxiliary data
301 		 * structure that describes relative performances.
302 		 */
303 
304 		crypto_drivers[driverid].cc_kalg[i] = kalg[i];
305 	}
306 
307 	crypto_drivers[driverid].cc_kprocess = kprocess;
308 
309 	splx(s);
310 	return 0;
311 }
312 
313 /* Register a crypto driver. */
314 int
315 crypto_register(u_int32_t driverid, int *alg,
316     int (*newses)(u_int32_t *, struct cryptoini *),
317     int (*freeses)(u_int64_t), int (*process)(struct cryptop *))
318 {
319 	int s, i;
320 
321 
322 	if (driverid >= crypto_drivers_num || alg == NULL ||
323 	    crypto_drivers == NULL)
324 		return EINVAL;
325 
326 	s = splvm();
327 
328 	for (i = 0; i <= CRYPTO_ALGORITHM_MAX; i++) {
329 		/*
330 		 * XXX Do some performance testing to determine
331 		 * placing.  We probably need an auxiliary data
332 		 * structure that describes relative performances.
333 		 */
334 
335 		crypto_drivers[driverid].cc_alg[i] = alg[i];
336 	}
337 
338 
339 	crypto_drivers[driverid].cc_newsession = newses;
340 	crypto_drivers[driverid].cc_process = process;
341 	crypto_drivers[driverid].cc_freesession = freeses;
342 	crypto_drivers[driverid].cc_sessions = 0; /* Unmark */
343 
344 	splx(s);
345 
346 	return 0;
347 }
348 
349 /*
350  * Unregister a crypto driver. If there are pending sessions using it,
351  * leave enough information around so that subsequent calls using those
352  * sessions will correctly detect the driver being unregistered and reroute
353  * the request.
354  */
355 int
356 crypto_unregister(u_int32_t driverid, int alg)
357 {
358 	int i = CRYPTO_ALGORITHM_MAX + 1, s;
359 	u_int32_t ses;
360 
361 	s = splvm();
362 
363 	/* Sanity checks. */
364 	if (driverid >= crypto_drivers_num || crypto_drivers == NULL ||
365 	    ((alg <= 0 || alg > CRYPTO_ALGORITHM_MAX) &&
366 		alg != CRYPTO_ALGORITHM_MAX + 1) ||
367 	    crypto_drivers[driverid].cc_alg[alg] == 0) {
368 		splx(s);
369 		return EINVAL;
370 	}
371 
372 	if (alg != CRYPTO_ALGORITHM_MAX + 1) {
373 		crypto_drivers[driverid].cc_alg[alg] = 0;
374 
375 		/* Was this the last algorithm ? */
376 		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
377 			if (crypto_drivers[driverid].cc_alg[i] != 0)
378 				break;
379 	}
380 
381 	/*
382 	 * If a driver unregistered its last algorithm or all of them
383 	 * (alg == CRYPTO_ALGORITHM_MAX + 1), cleanup its entry.
384 	 */
385 	if (i == CRYPTO_ALGORITHM_MAX + 1 || alg == CRYPTO_ALGORITHM_MAX + 1) {
386 		ses = crypto_drivers[driverid].cc_sessions;
387 		bzero(&crypto_drivers[driverid], sizeof(struct cryptocap));
388 		if (ses != 0) {
389 			/*
390 			 * If there are pending sessions, just mark as invalid.
391 			 */
392 			crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP;
393 			crypto_drivers[driverid].cc_sessions = ses;
394 		}
395 	}
396 	splx(s);
397 	return 0;
398 }
399 
400 /*
401  * Add crypto request to a queue, to be processed by a kernel thread.
402  */
403 int
404 crypto_dispatch(struct cryptop *crp)
405 {
406 	int s;
407 	u_int32_t hid;
408 
409 	s = splvm();
410 	/*
411 	 * Keep track of ops per driver, for coallescing purposes. If
412 	 * we have been given an invalid hid, we'll deal with in the
413 	 * crypto_invoke(), through session migration.
414 	 */
415 	hid = (crp->crp_sid >> 32) & 0xffffffff;
416 	if (hid < crypto_drivers_num)
417 		crypto_drivers[hid].cc_queued++;
418 	splx(s);
419 
420 	if (crypto_workq) {
421 		workq_queue_task(crypto_workq, &crp->crp_wqt, 0,
422 		    (workq_fn)crypto_invoke, crp, NULL);
423 	} else {
424 		crypto_invoke(crp);
425 	}
426 
427 	return 0;
428 }
429 
430 int
431 crypto_kdispatch(struct cryptkop *krp)
432 {
433 	if (crypto_workq) {
434 		workq_queue_task(crypto_workq, &krp->krp_wqt, 0,
435 		    (workq_fn)crypto_kinvoke, krp, NULL);
436 	} else {
437 		crypto_kinvoke(krp);
438 	}
439 
440 	return 0;
441 }
442 
443 /*
444  * Dispatch an asymmetric crypto request to the appropriate crypto devices.
445  */
446 int
447 crypto_kinvoke(struct cryptkop *krp)
448 {
449 	extern int cryptodevallowsoft;
450 	u_int32_t hid;
451 	int error;
452 	int s;
453 
454 	/* Sanity checks. */
455 	if (krp == NULL || krp->krp_callback == NULL)
456 		return (EINVAL);
457 
458 	s = splvm();
459 	for (hid = 0; hid < crypto_drivers_num; hid++) {
460 		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
461 		    cryptodevallowsoft == 0)
462 			continue;
463 		if (crypto_drivers[hid].cc_kprocess == NULL)
464 			continue;
465 		if ((crypto_drivers[hid].cc_kalg[krp->krp_op] &
466 		    CRYPTO_ALG_FLAG_SUPPORTED) == 0)
467 			continue;
468 		break;
469 	}
470 
471 	if (hid == crypto_drivers_num) {
472 		krp->krp_status = ENODEV;
473 		crypto_kdone(krp);
474 		splx(s);
475 		return (0);
476 	}
477 
478 	krp->krp_hid = hid;
479 
480 	crypto_drivers[hid].cc_koperations++;
481 
482 	error = crypto_drivers[hid].cc_kprocess(krp);
483 	if (error) {
484 		krp->krp_status = error;
485 		crypto_kdone(krp);
486 	}
487 	splx(s);
488 	return (0);
489 }
490 
491 /*
492  * Dispatch a crypto request to the appropriate crypto devices.
493  */
494 int
495 crypto_invoke(struct cryptop *crp)
496 {
497 	struct cryptodesc *crd;
498 	u_int64_t nid;
499 	u_int32_t hid;
500 	int error;
501 	int s;
502 
503 	/* Sanity checks. */
504 	if (crp == NULL || crp->crp_callback == NULL)
505 		return EINVAL;
506 
507 	s = splvm();
508 	if (crp->crp_desc == NULL || crypto_drivers == NULL) {
509 		crp->crp_etype = EINVAL;
510 		crypto_done(crp);
511 		splx(s);
512 		return 0;
513 	}
514 
515 	hid = (crp->crp_sid >> 32) & 0xffffffff;
516 	if (hid >= crypto_drivers_num)
517 		goto migrate;
518 
519 	crypto_drivers[hid].cc_queued--;
520 
521 	if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) {
522 		crypto_freesession(crp->crp_sid);
523 		goto migrate;
524 	}
525 
526 	if (crypto_drivers[hid].cc_process == NULL)
527 		goto migrate;
528 
529 	crypto_drivers[hid].cc_operations++;
530 	crypto_drivers[hid].cc_bytes += crp->crp_ilen;
531 
532 	error = crypto_drivers[hid].cc_process(crp);
533 	if (error) {
534 		if (error == ERESTART) {
535 			/* Unregister driver and migrate session. */
536 			crypto_unregister(hid, CRYPTO_ALGORITHM_MAX + 1);
537 			goto migrate;
538 		} else {
539 			crp->crp_etype = error;
540 		}
541 	}
542 
543 	splx(s);
544 	return 0;
545 
546  migrate:
547 	/* Migrate session. */
548 	for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
549 		crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
550 
551 	if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
552 		crp->crp_sid = nid;
553 
554 	crp->crp_etype = EAGAIN;
555 	crypto_done(crp);
556 	splx(s);
557 	return 0;
558 }
559 
560 /*
561  * Release a set of crypto descriptors.
562  */
563 void
564 crypto_freereq(struct cryptop *crp)
565 {
566 	struct cryptodesc *crd;
567 	int s;
568 
569 	if (crp == NULL)
570 		return;
571 
572 	s = splvm();
573 
574 	while ((crd = crp->crp_desc) != NULL) {
575 		crp->crp_desc = crd->crd_next;
576 		pool_put(&cryptodesc_pool, crd);
577 	}
578 
579 	pool_put(&cryptop_pool, crp);
580 	splx(s);
581 }
582 
583 /*
584  * Acquire a set of crypto descriptors.
585  */
586 struct cryptop *
587 crypto_getreq(int num)
588 {
589 	struct cryptodesc *crd;
590 	struct cryptop *crp;
591 	int s;
592 
593 	s = splvm();
594 
595 	crp = pool_get(&cryptop_pool, PR_NOWAIT);
596 	if (crp == NULL) {
597 		splx(s);
598 		return NULL;
599 	}
600 	bzero(crp, sizeof(struct cryptop));
601 
602 	while (num--) {
603 		crd = pool_get(&cryptodesc_pool, PR_NOWAIT);
604 		if (crd == NULL) {
605 			splx(s);
606 			crypto_freereq(crp);
607 			return NULL;
608 		}
609 
610 		bzero(crd, sizeof(struct cryptodesc));
611 		crd->crd_next = crp->crp_desc;
612 		crp->crp_desc = crd;
613 	}
614 
615 	splx(s);
616 	return crp;
617 }
618 
619 void
620 crypto_init(void)
621 {
622 	crypto_workq = workq_create("crypto", 1, IPL_HIGH);
623 
624 	pool_init(&cryptop_pool, sizeof(struct cryptop), 0, 0,
625 	    0, "cryptop", NULL);
626 	pool_init(&cryptodesc_pool, sizeof(struct cryptodesc), 0, 0,
627 	    0, "cryptodesc", NULL);
628 }
629 
630 /*
631  * Invoke the callback on behalf of the driver.
632  */
633 void
634 crypto_done(struct cryptop *crp)
635 {
636 	crp->crp_flags |= CRYPTO_F_DONE;
637 	if (crp->crp_flags & CRYPTO_F_NOQUEUE) {
638 		/* not from the crypto queue, wakeup the userland process */
639 		crp->crp_callback(crp);
640 	} else {
641 		workq_queue_task(crypto_workq, &crp->crp_wqt, 0,
642 		    (workq_fn)crp->crp_callback, crp, NULL);
643 	}
644 }
645 
646 /*
647  * Invoke the callback on behalf of the driver.
648  */
649 void
650 crypto_kdone(struct cryptkop *krp)
651 {
652 	workq_queue_task(crypto_workq, &krp->krp_wqt, 0,
653 	    (workq_fn)krp->krp_callback, krp, NULL);
654 }
655 
656 int
657 crypto_getfeat(int *featp)
658 {
659 	extern int cryptodevallowsoft, userasymcrypto;
660 	int hid, kalg, feat = 0;
661 
662 	if (userasymcrypto == 0)
663 		goto out;
664 	for (hid = 0; hid < crypto_drivers_num; hid++) {
665 		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
666 		    cryptodevallowsoft == 0) {
667 			continue;
668 		}
669 		if (crypto_drivers[hid].cc_kprocess == NULL)
670 			continue;
671 		for (kalg = 0; kalg <= CRK_ALGORITHM_MAX; kalg++)
672 			if ((crypto_drivers[hid].cc_kalg[kalg] &
673 			    CRYPTO_ALG_FLAG_SUPPORTED) != 0)
674 				feat |=  1 << kalg;
675 	}
676 out:
677 	*featp = feat;
678 	return (0);
679 }
680