xref: /openbsd-src/sys/crypto/crypto.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: crypto.c,v 1.52 2008/10/30 23:55:22 dlg 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 <sys/workq.h>
29 
30 #include <crypto/cryptodev.h>
31 
32 void init_crypto(void);
33 
34 struct cryptocap *crypto_drivers = NULL;
35 int crypto_drivers_num = 0;
36 
37 struct pool cryptop_pool;
38 struct pool cryptodesc_pool;
39 int crypto_pool_initialized = 0;
40 
41 struct workq *crypto_workq;
42 
43 /*
44  * Create a new session.
45  */
46 int
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 = splvm();
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
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 = splvm();
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
216 crypto_get_driverid(u_int8_t flags)
217 {
218 	struct cryptocap *newdrv;
219 	int i, s;
220 
221 	s = splvm();
222 
223 	if (crypto_drivers_num == 0) {
224 		crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
225 		crypto_drivers = malloc(crypto_drivers_num *
226 		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT);
227 		if (crypto_drivers == NULL) {
228 			crypto_drivers_num = 0;
229 			splx(s);
230 			return -1;
231 		}
232 
233 		bzero(crypto_drivers, crypto_drivers_num *
234 		    sizeof(struct cryptocap));
235 	}
236 
237 	for (i = 0; i < crypto_drivers_num; i++) {
238 		if (crypto_drivers[i].cc_process == NULL &&
239 		    !(crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) &&
240 		    crypto_drivers[i].cc_sessions == 0) {
241 			crypto_drivers[i].cc_sessions = 1; /* Mark */
242 			crypto_drivers[i].cc_flags = flags;
243 			splx(s);
244 			return i;
245 		}
246 	}
247 
248 	/* Out of entries, allocate some more. */
249 	if (i == crypto_drivers_num) {
250 		/* Be careful about wrap-around. */
251 		if (2 * crypto_drivers_num <= crypto_drivers_num) {
252 			splx(s);
253 			return -1;
254 		}
255 
256 		newdrv = malloc(2 * crypto_drivers_num *
257 		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT);
258 		if (newdrv == NULL) {
259 			splx(s);
260 			return -1;
261 		}
262 
263 		bcopy(crypto_drivers, newdrv,
264 		    crypto_drivers_num * sizeof(struct cryptocap));
265 		bzero(&newdrv[crypto_drivers_num],
266 		    crypto_drivers_num * sizeof(struct cryptocap));
267 
268 		newdrv[i].cc_sessions = 1; /* Mark */
269 		newdrv[i].cc_flags = flags;
270 		crypto_drivers_num *= 2;
271 
272 		free(crypto_drivers, M_CRYPTO_DATA);
273 		crypto_drivers = newdrv;
274 		splx(s);
275 		return i;
276 	}
277 
278 	/* Shouldn't really get here... */
279 	splx(s);
280 	return -1;
281 }
282 
283 /*
284  * Register a crypto driver. It should be called once for each algorithm
285  * supported by the driver.
286  */
287 int
288 crypto_kregister(u_int32_t driverid, int *kalg,
289     int (*kprocess)(struct cryptkop *))
290 {
291 	int s, i;
292 
293 	if (driverid >= crypto_drivers_num || kalg  == NULL ||
294 	    crypto_drivers == NULL)
295 		return EINVAL;
296 
297 	s = splvm();
298 
299 	for (i = 0; i < CRK_ALGORITHM_MAX; i++) {
300 		/*
301 		 * XXX Do some performance testing to determine
302 		 * placing.  We probably need an auxiliary data
303 		 * structure that describes relative performances.
304 		 */
305 
306 		crypto_drivers[driverid].cc_kalg[i] = kalg[i];
307 	}
308 
309 	crypto_drivers[driverid].cc_kprocess = kprocess;
310 
311 	splx(s);
312 	return 0;
313 }
314 
315 /* Register a crypto driver. */
316 int
317 crypto_register(u_int32_t driverid, int *alg,
318     int (*newses)(u_int32_t *, struct cryptoini *),
319     int (*freeses)(u_int64_t), int (*process)(struct cryptop *))
320 {
321 	int s, i;
322 
323 
324 	if (driverid >= crypto_drivers_num || alg == NULL ||
325 	    crypto_drivers == NULL)
326 		return EINVAL;
327 
328 	s = splvm();
329 
330 	for (i = 0; i < CRYPTO_ALGORITHM_ALL; i++) {
331 		/*
332 		 * XXX Do some performance testing to determine
333 		 * placing.  We probably need an auxiliary data
334 		 * structure that describes relative performances.
335 		 */
336 
337 		crypto_drivers[driverid].cc_alg[i] = alg[i];
338 	}
339 
340 
341 	crypto_drivers[driverid].cc_newsession = newses;
342 	crypto_drivers[driverid].cc_process = process;
343 	crypto_drivers[driverid].cc_freesession = freeses;
344 	crypto_drivers[driverid].cc_sessions = 0; /* Unmark */
345 
346 	splx(s);
347 
348 	return 0;
349 }
350 
351 /*
352  * Unregister a crypto driver. If there are pending sessions using it,
353  * leave enough information around so that subsequent calls using those
354  * sessions will correctly detect the driver being unregistered and reroute
355  * the request.
356  */
357 int
358 crypto_unregister(u_int32_t driverid, int alg)
359 {
360 	int i = CRYPTO_ALGORITHM_MAX + 1, s;
361 	u_int32_t ses;
362 
363 	s = splvm();
364 
365 	/* Sanity checks. */
366 	if (driverid >= crypto_drivers_num || crypto_drivers == NULL ||
367 	    ((alg <= 0 || alg > CRYPTO_ALGORITHM_MAX) &&
368 		alg != CRYPTO_ALGORITHM_ALL) ||
369 	    crypto_drivers[driverid].cc_alg[alg] == 0) {
370 		splx(s);
371 		return EINVAL;
372 	}
373 
374 	if (alg != CRYPTO_ALGORITHM_ALL) {
375 		crypto_drivers[driverid].cc_alg[alg] = 0;
376 
377 		/* Was this the last algorithm ? */
378 		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
379 			if (crypto_drivers[driverid].cc_alg[i] != 0)
380 				break;
381 	}
382 
383 	/*
384 	 * If a driver unregistered its last algorithm or all of them
385 	 * (alg == CRYPTO_ALGORITHM_ALL), cleanup its entry.
386 	 */
387 	if (i == CRYPTO_ALGORITHM_MAX + 1 || alg == CRYPTO_ALGORITHM_ALL) {
388 		ses = crypto_drivers[driverid].cc_sessions;
389 		bzero(&crypto_drivers[driverid], sizeof(struct cryptocap));
390 		if (ses != 0) {
391 			/*
392 			 * If there are pending sessions, just mark as invalid.
393 			 */
394 			crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP;
395 			crypto_drivers[driverid].cc_sessions = ses;
396 		}
397 	}
398 	splx(s);
399 	return 0;
400 }
401 
402 /*
403  * Add crypto request to a queue, to be processed by a kernel thread.
404  */
405 int
406 crypto_dispatch(struct cryptop *crp)
407 {
408 	int s;
409 	u_int32_t hid;
410 
411 	s = splvm();
412 	/*
413 	 * Keep track of ops per driver, for coallescing purposes. If
414 	 * we have been given an invalid hid, we'll deal with in the
415 	 * crypto_invoke(), through session migration.
416 	 */
417 	hid = (crp->crp_sid >> 32) & 0xffffffff;
418 	if (hid < crypto_drivers_num)
419 		crypto_drivers[hid].cc_queued++;
420 	splx(s);
421 
422 	if (crypto_workq) {
423 		workq_add_task(crypto_workq, 0,
424 		    (workq_fn)crypto_invoke, crp, NULL);
425 	} else {
426 		crypto_invoke(crp);
427 	}
428 
429 	return 0;
430 }
431 
432 int
433 crypto_kdispatch(struct cryptkop *krp)
434 {
435 
436 	if (crypto_workq) {
437 		workq_add_task(crypto_workq, 0,
438 		    (workq_fn)crypto_kinvoke, krp, NULL);
439 	} else {
440 		crypto_kinvoke(krp);
441 	}
442 
443 	return 0;
444 }
445 
446 /*
447  * Dispatch an asymmetric crypto request to the appropriate crypto devices.
448  */
449 int
450 crypto_kinvoke(struct cryptkop *krp)
451 {
452 	extern int cryptodevallowsoft;
453 	u_int32_t hid;
454 	int error;
455 	int s;
456 
457 	/* Sanity checks. */
458 	if (krp == NULL || krp->krp_callback == NULL)
459 		return (EINVAL);
460 
461 	s = splvm();
462 	for (hid = 0; hid < crypto_drivers_num; hid++) {
463 		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
464 		    cryptodevallowsoft == 0)
465 			continue;
466 		if (crypto_drivers[hid].cc_kprocess == NULL)
467 			continue;
468 		if ((crypto_drivers[hid].cc_kalg[krp->krp_op] &
469 		    CRYPTO_ALG_FLAG_SUPPORTED) == 0)
470 			continue;
471 		break;
472 	}
473 
474 	if (hid == crypto_drivers_num) {
475 		krp->krp_status = ENODEV;
476 		crypto_kdone(krp);
477 		splx(s);
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 	splx(s);
491 	return (0);
492 }
493 
494 /*
495  * Dispatch a crypto request to the appropriate crypto devices.
496  */
497 int
498 crypto_invoke(struct cryptop *crp)
499 {
500 	struct cryptodesc *crd;
501 	u_int64_t nid;
502 	u_int32_t hid;
503 	int error;
504 	int s;
505 
506 	/* Sanity checks. */
507 	if (crp == NULL || crp->crp_callback == NULL)
508 		return EINVAL;
509 
510 	s = splvm();
511 	if (crp->crp_desc == NULL || crypto_drivers == NULL) {
512 		crp->crp_etype = EINVAL;
513 		crypto_done(crp);
514 		splx(s);
515 		return 0;
516 	}
517 
518 	hid = (crp->crp_sid >> 32) & 0xffffffff;
519 	if (hid >= crypto_drivers_num)
520 		goto migrate;
521 
522 	crypto_drivers[hid].cc_queued--;
523 
524 	if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) {
525 		crypto_freesession(crp->crp_sid);
526 		goto migrate;
527 	}
528 
529 	if (crypto_drivers[hid].cc_process == NULL)
530 		goto migrate;
531 
532 	crypto_drivers[hid].cc_operations++;
533 	crypto_drivers[hid].cc_bytes += crp->crp_ilen;
534 
535 	error = crypto_drivers[hid].cc_process(crp);
536 	if (error) {
537 		if (error == ERESTART) {
538 			/* Unregister driver and migrate session. */
539 			crypto_unregister(hid, CRYPTO_ALGORITHM_ALL);
540 			goto migrate;
541 		} else {
542 			crp->crp_etype = error;
543 		}
544 	}
545 
546 	splx(s);
547 	return 0;
548 
549  migrate:
550 	/* Migrate session. */
551 	for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
552 		crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
553 
554 	if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
555 		crp->crp_sid = nid;
556 
557 	crp->crp_etype = EAGAIN;
558 	crypto_done(crp);
559 	splx(s);
560 	return 0;
561 }
562 
563 /*
564  * Release a set of crypto descriptors.
565  */
566 void
567 crypto_freereq(struct cryptop *crp)
568 {
569 	struct cryptodesc *crd;
570 	int s;
571 
572 	if (crp == NULL)
573 		return;
574 
575 	s = splvm();
576 
577 	while ((crd = crp->crp_desc) != NULL) {
578 		crp->crp_desc = crd->crd_next;
579 		pool_put(&cryptodesc_pool, crd);
580 	}
581 
582 	pool_put(&cryptop_pool, crp);
583 	splx(s);
584 }
585 
586 /*
587  * Acquire a set of crypto descriptors.
588  */
589 struct cryptop *
590 crypto_getreq(int num)
591 {
592 	struct cryptodesc *crd;
593 	struct cryptop *crp;
594 	int s;
595 
596 	s = splvm();
597 
598 	if (crypto_pool_initialized == 0) {
599 		pool_init(&cryptop_pool, sizeof(struct cryptop), 0, 0,
600 		    0, "cryptop", NULL);
601 		pool_init(&cryptodesc_pool, sizeof(struct cryptodesc), 0, 0,
602 		    0, "cryptodesc", NULL);
603 		crypto_pool_initialized = 1;
604 	}
605 
606 	crp = pool_get(&cryptop_pool, PR_NOWAIT);
607 	if (crp == NULL) {
608 		splx(s);
609 		return NULL;
610 	}
611 	bzero(crp, sizeof(struct cryptop));
612 
613 	while (num--) {
614 		crd = pool_get(&cryptodesc_pool, PR_NOWAIT);
615 		if (crd == NULL) {
616 			splx(s);
617 			crypto_freereq(crp);
618 			return NULL;
619 		}
620 
621 		bzero(crd, sizeof(struct cryptodesc));
622 		crd->crd_next = crp->crp_desc;
623 		crp->crp_desc = crd;
624 	}
625 
626 	splx(s);
627 	return crp;
628 }
629 
630 void
631 init_crypto()
632 {
633 	crypto_workq = workq_create("crypto", 1, IPL_HIGH);
634 }
635 
636 /*
637  * Invoke the callback on behalf of the driver.
638  */
639 void
640 crypto_done(struct cryptop *crp)
641 {
642 	crp->crp_flags |= CRYPTO_F_DONE;
643 	crp->crp_callback(crp);
644 }
645 
646 /*
647  * Invoke the callback on behalf of the driver.
648  */
649 void
650 crypto_kdone(struct cryptkop *krp)
651 {
652 	krp->krp_callback(krp);
653 }
654 
655 int
656 crypto_getfeat(int *featp)
657 {
658 	extern int cryptodevallowsoft, userasymcrypto;
659 	int hid, kalg, feat = 0;
660 
661 	if (userasymcrypto == 0)
662 		goto out;
663 	for (hid = 0; hid < crypto_drivers_num; hid++) {
664 		if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
665 		    cryptodevallowsoft == 0) {
666 			continue;
667 		}
668 		if (crypto_drivers[hid].cc_kprocess == NULL)
669 			continue;
670 		for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
671 			if ((crypto_drivers[hid].cc_kalg[kalg] &
672 			    CRYPTO_ALG_FLAG_SUPPORTED) != 0)
673 				feat |=  1 << kalg;
674 	}
675 out:
676 	*featp = feat;
677 	return (0);
678 }
679