1 /*	$OpenBSD: crypto.c,v 1.46 2004/12/21 10:07:34 mpf 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 #include <crypto/cryptodev.h>
29 
30 struct cryptocap *crypto_drivers = NULL;
31 int crypto_drivers_num = 0;
32 
33 struct pool cryptop_pool;
34 struct pool cryptodesc_pool;
35 int crypto_pool_initialized = 0;
36 
37 struct cryptop *crp_req_queue = NULL;
38 struct cryptop **crp_req_queue_tail = NULL;
39 
40 struct cryptkop *krp_req_queue = NULL;
41 struct cryptkop **krp_req_queue_tail = NULL;
42 
43 /*
44  * Create a new session.
45  */
46 int
crypto_newsession(u_int64_t * sid,struct cryptoini * cri,int hard)47 crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard)
48 {
49 	u_int32_t hid, lid, hid2 = -1;
50 	struct cryptocap *cpc;
51 	struct cryptoini *cr;
52 	int err, s, turn = 0;
53 
54 	if (crypto_drivers == NULL)
55 		return EINVAL;
56 
57 	s = splimp();
58 
59 	/*
60 	 * The algorithm we use here is pretty stupid; just use the
61 	 * first driver that supports all the algorithms we need. Do
62 	 * a double-pass over all the drivers, ignoring software ones
63 	 * at first, to deal with cases of drivers that register after
64 	 * the software one(s) --- e.g., PCMCIA crypto cards.
65 	 *
66 	 * XXX We need more smarts here (in real life too, but that's
67 	 * XXX another story altogether).
68 	 */
69 	do {
70 		for (hid = 0; hid < crypto_drivers_num; hid++) {
71 			cpc = &crypto_drivers[hid];
72 
73 			/*
74 			 * If it's not initialized or has remaining sessions
75 			 * referencing it, skip.
76 			 */
77 			if (cpc->cc_newsession == NULL ||
78 			    (cpc->cc_flags & CRYPTOCAP_F_CLEANUP))
79 				continue;
80 
81 			if (cpc->cc_flags & CRYPTOCAP_F_SOFTWARE) {
82 				/*
83 				 * First round of search, ignore
84 				 * software drivers.
85 				 */
86 				if (turn == 0)
87 					continue;
88 			} else { /* !CRYPTOCAP_F_SOFTWARE */
89 				/* Second round of search, only software. */
90 				if (turn == 1)
91 					continue;
92 			}
93 
94 			/* See if all the algorithms are supported. */
95 			for (cr = cri; cr; cr = cr->cri_next) {
96 				if (cpc->cc_alg[cr->cri_alg] == 0)
97 					break;
98 			}
99 
100 			/*
101 			 * If even one algorithm is not supported,
102 			 * keep searching.
103 			 */
104 			if (cr != NULL)
105 				continue;
106 
107 			/*
108 			 * If we had a previous match, see how it compares
109 			 * to this one. Keep "remembering" whichever is
110 			 * the best of the two.
111 			 */
112 			if (hid2 != -1) {
113 				/*
114 				 * Compare session numbers, pick the one
115 				 * with the lowest.
116 				 * XXX Need better metrics, this will
117 				 * XXX just do un-weighted round-robin.
118 				 */
119 				if (crypto_drivers[hid].cc_sessions <=
120 				    crypto_drivers[hid2].cc_sessions)
121 					hid2 = hid;
122 			} else {
123 				/*
124 				 * Remember this one, for future
125                                  * comparisons.
126 				 */
127 				hid2 = hid;
128 			}
129 		}
130 
131 		/*
132 		 * If we found something worth remembering, leave. The
133 		 * side-effect is that we will always prefer a hardware
134 		 * driver over the software one.
135 		 */
136 		if (hid2 != -1)
137 			break;
138 
139 		turn++;
140 
141 		/* If we only want hardware drivers, don't do second pass. */
142 	} while (turn <= 2 && hard == 0);
143 
144 	hid = hid2;
145 
146 	/*
147 	 * Can't do everything in one session.
148 	 *
149 	 * XXX Fix this. We need to inject a "virtual" session
150 	 * XXX layer right about here.
151 	 */
152 
153 	if (hid == -1) {
154 		splx(s);
155 		return EINVAL;
156 	}
157 
158 	/* Call the driver initialization routine. */
159 	lid = hid; /* Pass the driver ID. */
160 	err = crypto_drivers[hid].cc_newsession(&lid, cri);
161 	if (err == 0) {
162 		(*sid) = hid;
163 		(*sid) <<= 32;
164 		(*sid) |= (lid & 0xffffffff);
165 		crypto_drivers[hid].cc_sessions++;
166 	}
167 
168 	splx(s);
169 	return err;
170 }
171 
172 /*
173  * Delete an existing session (or a reserved session on an unregistered
174  * driver).
175  */
176 int
crypto_freesession(u_int64_t sid)177 crypto_freesession(u_int64_t sid)
178 {
179 	int err = 0, s;
180 	u_int32_t hid;
181 
182 	if (crypto_drivers == NULL)
183 		return EINVAL;
184 
185 	/* Determine two IDs. */
186 	hid = (sid >> 32) & 0xffffffff;
187 
188 	if (hid >= crypto_drivers_num)
189 		return ENOENT;
190 
191 	s = splimp();
192 
193 	if (crypto_drivers[hid].cc_sessions)
194 		crypto_drivers[hid].cc_sessions--;
195 
196 	/* Call the driver cleanup routine, if available. */
197 	if (crypto_drivers[hid].cc_freesession)
198 		err = crypto_drivers[hid].cc_freesession(sid);
199 
200 	/*
201 	 * If this was the last session of a driver marked as invalid,
202 	 * make the entry available for reuse.
203 	 */
204 	if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) &&
205 	    crypto_drivers[hid].cc_sessions == 0)
206 		bzero(&crypto_drivers[hid], sizeof(struct cryptocap));
207 
208 	splx(s);
209 	return err;
210 }
211 
212 /*
213  * Find an empty slot.
214  */
215 int32_t
crypto_get_driverid(u_int8_t flags)216 crypto_get_driverid(u_int8_t flags)
217 {
218 	struct cryptocap *newdrv;
219 	int i, s = splimp();
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 			splx(s);
227 			crypto_drivers_num = 0;
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
crypto_kregister(u_int32_t driverid,int * kalg,int (* kprocess)(struct cryptkop *))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 = splimp();
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
crypto_register(u_int32_t driverid,int * alg,int (* newses)(u_int32_t *,struct cryptoini *),int (* freeses)(u_int64_t),int (* process)(struct cryptop *))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 = splimp();
327 
328 	for (i = 0; i < CRYPTO_ALGORITHM_ALL; 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
crypto_unregister(u_int32_t driverid,int alg)356 crypto_unregister(u_int32_t driverid, int alg)
357 {
358 	int i = CRYPTO_ALGORITHM_MAX + 1, s = splimp();
359 	u_int32_t ses;
360 
361 	/* Sanity checks. */
362 	if (driverid >= crypto_drivers_num || crypto_drivers == NULL ||
363 	    ((alg <= 0 || alg > CRYPTO_ALGORITHM_MAX) &&
364 		alg != CRYPTO_ALGORITHM_ALL) ||
365 	    crypto_drivers[driverid].cc_alg[alg] == 0) {
366 		splx(s);
367 		return EINVAL;
368 	}
369 
370 	if (alg != CRYPTO_ALGORITHM_ALL) {
371 		crypto_drivers[driverid].cc_alg[alg] = 0;
372 
373 		/* Was this the last algorithm ? */
374 		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
375 			if (crypto_drivers[driverid].cc_alg[i] != 0)
376 				break;
377 	}
378 
379 	/*
380 	 * If a driver unregistered its last algorithm or all of them
381 	 * (alg == CRYPTO_ALGORITHM_ALL), cleanup its entry.
382 	 */
383 	if (i == CRYPTO_ALGORITHM_MAX + 1 || alg == CRYPTO_ALGORITHM_ALL) {
384 		ses = crypto_drivers[driverid].cc_sessions;
385 		bzero(&crypto_drivers[driverid], sizeof(struct cryptocap));
386 		if (ses != 0) {
387 			/*
388 			 * If there are pending sessions, just mark as invalid.
389 			 */
390 			crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP;
391 			crypto_drivers[driverid].cc_sessions = ses;
392 		}
393 	}
394 	splx(s);
395 	return 0;
396 }
397 
398 /*
399  * Add crypto request to a queue, to be processed by a kernel thread.
400  */
401 int
crypto_dispatch(struct cryptop * crp)402 crypto_dispatch(struct cryptop *crp)
403 {
404 	int s = splimp();
405 	u_int32_t hid;
406 
407 	/*
408 	 * Keep track of ops per driver, for coallescing purposes. If
409 	 * we have been given an invalid hid, we'll deal with in the
410 	 * crypto_invoke(), through session migration.
411 	 */
412 	hid = (crp->crp_sid >> 32) & 0xffffffff;
413 	if (hid < crypto_drivers_num)
414 		crypto_drivers[hid].cc_queued++;
415 
416 	crp->crp_next = NULL;
417 	if (crp_req_queue == NULL) {
418 		crp_req_queue = crp;
419 		crp_req_queue_tail = &(crp->crp_next);
420 		splx(s);
421 		wakeup((caddr_t) &crp_req_queue); /* Shared wait channel. */
422 	} else {
423 		*crp_req_queue_tail = crp;
424 		crp_req_queue_tail = &(crp->crp_next);
425 		splx(s);
426 	}
427 	return 0;
428 }
429 
430 int
crypto_kdispatch(struct cryptkop * krp)431 crypto_kdispatch(struct cryptkop *krp)
432 {
433 	int s = splimp();
434 
435 	krp->krp_next = NULL;
436 	if (krp_req_queue == NULL) {
437 		krp_req_queue = krp;
438 		krp_req_queue_tail = &(krp->krp_next);
439 		splx(s);
440 		wakeup((caddr_t) &crp_req_queue); /* Shared wait channel. */
441 	} else {
442 		*krp_req_queue_tail = krp;
443 		krp_req_queue_tail = &(krp->krp_next);
444 		splx(s);
445 	}
446 	return 0;
447 }
448 
449 /*
450  * Dispatch an asymmetric crypto request to the appropriate crypto devices.
451  */
452 int
crypto_kinvoke(struct cryptkop * krp)453 crypto_kinvoke(struct cryptkop *krp)
454 {
455 	extern int cryptodevallowsoft;
456 	u_int32_t hid;
457 	int error;
458 
459 	/* Sanity checks. */
460 	if (krp == NULL || krp->krp_callback == NULL)
461 		return (EINVAL);
462 
463 	for (hid = 0; hid < crypto_drivers_num; hid++) {
464 		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
465 		    cryptodevallowsoft == 0)
466 			continue;
467 		if (crypto_drivers[hid].cc_kprocess == NULL)
468 			continue;
469 		if ((crypto_drivers[hid].cc_kalg[krp->krp_op] &
470 		    CRYPTO_ALG_FLAG_SUPPORTED) == 0)
471 			continue;
472 		break;
473 	}
474 
475 	if (hid == crypto_drivers_num) {
476 		krp->krp_status = ENODEV;
477 		crypto_kdone(krp);
478 		return (0);
479 	}
480 
481 	krp->krp_hid = hid;
482 
483 	crypto_drivers[hid].cc_koperations++;
484 
485 	error = crypto_drivers[hid].cc_kprocess(krp);
486 	if (error) {
487 		krp->krp_status = error;
488 		crypto_kdone(krp);
489 	}
490 	return (0);
491 }
492 
493 /*
494  * Dispatch a crypto request to the appropriate crypto devices.
495  */
496 int
crypto_invoke(struct cryptop * crp)497 crypto_invoke(struct cryptop *crp)
498 {
499 	struct cryptodesc *crd;
500 	u_int64_t nid;
501 	u_int32_t hid;
502 	int error;
503 
504 	/* Sanity checks. */
505 	if (crp == NULL || crp->crp_callback == NULL)
506 		return EINVAL;
507 
508 	if (crp->crp_desc == NULL || crypto_drivers == NULL) {
509 		crp->crp_etype = EINVAL;
510 		crypto_done(crp);
511 		return 0;
512 	}
513 
514 	hid = (crp->crp_sid >> 32) & 0xffffffff;
515 	if (hid >= crypto_drivers_num)
516 		goto migrate;
517 
518 	crypto_drivers[hid].cc_queued--;
519 
520 	if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) {
521 		crypto_freesession(crp->crp_sid);
522 		goto migrate;
523 	}
524 
525 	if (crypto_drivers[hid].cc_process == NULL)
526 		goto migrate;
527 
528 	crypto_drivers[hid].cc_operations++;
529 	crypto_drivers[hid].cc_bytes += crp->crp_ilen;
530 
531 	error = crypto_drivers[hid].cc_process(crp);
532 	if (error) {
533 		if (error == ERESTART) {
534 			/* Unregister driver and migrate session. */
535 			crypto_unregister(hid, CRYPTO_ALGORITHM_ALL);
536 			goto migrate;
537 		} else {
538 			crp->crp_etype = error;
539 			crypto_done(crp);
540 		}
541 	}
542 
543 	return 0;
544 
545  migrate:
546 	/* Migrate session. */
547 	for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
548 		crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
549 
550 	if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
551 		crp->crp_sid = nid;
552 
553 	crp->crp_etype = EAGAIN;
554 	crypto_done(crp);
555 	return 0;
556 }
557 
558 /*
559  * Release a set of crypto descriptors.
560  */
561 void
crypto_freereq(struct cryptop * crp)562 crypto_freereq(struct cryptop *crp)
563 {
564 	struct cryptodesc *crd;
565 	int s;
566 
567 	if (crp == NULL)
568 		return;
569 
570 	s = splimp();
571 
572 	while ((crd = crp->crp_desc) != NULL) {
573 		crp->crp_desc = crd->crd_next;
574 		pool_put(&cryptodesc_pool, crd);
575 	}
576 
577 	pool_put(&cryptop_pool, crp);
578 	splx(s);
579 }
580 
581 /*
582  * Acquire a set of crypto descriptors.
583  */
584 struct cryptop *
crypto_getreq(int num)585 crypto_getreq(int num)
586 {
587 	struct cryptodesc *crd;
588 	struct cryptop *crp;
589 	int s = splimp();
590 
591 	if (crypto_pool_initialized == 0) {
592 		pool_init(&cryptop_pool, sizeof(struct cryptop), 0, 0,
593 		    0, "cryptop", NULL);
594 		pool_init(&cryptodesc_pool, sizeof(struct cryptodesc), 0, 0,
595 		    0, "cryptodesc", NULL);
596 		crypto_pool_initialized = 1;
597 	}
598 
599 	crp = pool_get(&cryptop_pool, 0);
600 	if (crp == NULL) {
601 		splx(s);
602 		return NULL;
603 	}
604 	bzero(crp, sizeof(struct cryptop));
605 
606 	while (num--) {
607 		crd = pool_get(&cryptodesc_pool, 0);
608 		if (crd == NULL) {
609 			splx(s);
610 			crypto_freereq(crp);
611 			return NULL;
612 		}
613 
614 		bzero(crd, sizeof(struct cryptodesc));
615 		crd->crd_next = crp->crp_desc;
616 		crp->crp_desc = crd;
617 	}
618 
619 	splx(s);
620 	return crp;
621 }
622 
623 /*
624  * Crypto thread, runs as a kernel thread to process crypto requests.
625  */
626 void
crypto_thread(void)627 crypto_thread(void)
628 {
629 	struct cryptop *crp;
630 	struct cryptkop *krp;
631 	int s;
632 
633 	s = splimp();
634 
635 	for (;;) {
636 		crp = crp_req_queue;
637 		krp = krp_req_queue;
638 		if (crp == NULL && krp == NULL) {
639 			(void) tsleep(&crp_req_queue, PLOCK, "crypto_wait", 0);
640 			continue;
641 		}
642 
643 		if (crp) {
644 			/* Remove from the queue. */
645 			crp_req_queue = crp->crp_next;
646 			crypto_invoke(crp);
647 		}
648 		if (krp) {
649 			/* Remove from the queue. */
650 			krp_req_queue = krp->krp_next;
651 			crypto_kinvoke(krp);
652 		}
653 	}
654 }
655 
656 /*
657  * Invoke the callback on behalf of the driver.
658  */
659 void
crypto_done(struct cryptop * crp)660 crypto_done(struct cryptop *crp)
661 {
662 	crp->crp_flags |= CRYPTO_F_DONE;
663 	crp->crp_callback(crp);
664 }
665 
666 /*
667  * Invoke the callback on behalf of the driver.
668  */
669 void
crypto_kdone(struct cryptkop * krp)670 crypto_kdone(struct cryptkop *krp)
671 {
672 	krp->krp_callback(krp);
673 }
674 
675 int
crypto_getfeat(int * featp)676 crypto_getfeat(int *featp)
677 {
678 	extern int cryptodevallowsoft, userasymcrypto;
679 	int hid, kalg, feat = 0;
680 
681 	if (userasymcrypto == 0)
682 		goto out;
683 	for (hid = 0; hid < crypto_drivers_num; hid++) {
684 		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
685 		    cryptodevallowsoft == 0) {
686 			continue;
687 		}
688 		if (crypto_drivers[hid].cc_kprocess == NULL)
689 			continue;
690 		for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
691 			if ((crypto_drivers[hid].cc_kalg[kalg] &
692 			    CRYPTO_ALG_FLAG_SUPPORTED) != 0)
693 				feat |=  1 << kalg;
694 	}
695 out:
696 	*featp = feat;
697 	return (0);
698 }
699