1 /* $OpenBSD: crypto.c,v 1.48 2006/05/31 23:01:44 tedu 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
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
421 crp->crp_next = NULL;
422 if (crp_req_queue == NULL) {
423 crp_req_queue = crp;
424 crp_req_queue_tail = &(crp->crp_next);
425 splx(s);
426 wakeup(&crp_req_queue); /* Shared wait channel. */
427 } else {
428 *crp_req_queue_tail = crp;
429 crp_req_queue_tail = &(crp->crp_next);
430 splx(s);
431 }
432 return 0;
433 }
434
435 int
436 crypto_kdispatch(struct cryptkop *krp)
437 {
438 int s;
439
440 s = splvm();
441
442 krp->krp_next = NULL;
443 if (krp_req_queue == NULL) {
444 krp_req_queue = krp;
445 krp_req_queue_tail = &(krp->krp_next);
446 splx(s);
447 wakeup(&crp_req_queue); /* Shared wait channel. */
448 } else {
449 *krp_req_queue_tail = krp;
450 krp_req_queue_tail = &(krp->krp_next);
451 splx(s);
452 }
453 return 0;
454 }
455
456 /*
457 * Dispatch an asymmetric crypto request to the appropriate crypto devices.
458 */
459 int
460 crypto_kinvoke(struct cryptkop *krp)
461 {
462 extern int cryptodevallowsoft;
463 u_int32_t hid;
464 int error;
465
466 /* Sanity checks. */
467 if (krp == NULL || krp->krp_callback == NULL)
468 return (EINVAL);
469
470 for (hid = 0; hid < crypto_drivers_num; hid++) {
471 if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
472 cryptodevallowsoft == 0)
473 continue;
474 if (crypto_drivers[hid].cc_kprocess == NULL)
475 continue;
476 if ((crypto_drivers[hid].cc_kalg[krp->krp_op] &
477 CRYPTO_ALG_FLAG_SUPPORTED) == 0)
478 continue;
479 break;
480 }
481
482 if (hid == crypto_drivers_num) {
483 krp->krp_status = ENODEV;
484 crypto_kdone(krp);
485 return (0);
486 }
487
488 krp->krp_hid = hid;
489
490 crypto_drivers[hid].cc_koperations++;
491
492 error = crypto_drivers[hid].cc_kprocess(krp);
493 if (error) {
494 krp->krp_status = error;
495 crypto_kdone(krp);
496 }
497 return (0);
498 }
499
500 /*
501 * Dispatch a crypto request to the appropriate crypto devices.
502 */
503 int
504 crypto_invoke(struct cryptop *crp)
505 {
506 struct cryptodesc *crd;
507 u_int64_t nid;
508 u_int32_t hid;
509 int error;
510
511 /* Sanity checks. */
512 if (crp == NULL || crp->crp_callback == NULL)
513 return EINVAL;
514
515 if (crp->crp_desc == NULL || crypto_drivers == NULL) {
516 crp->crp_etype = EINVAL;
517 crypto_done(crp);
518 return 0;
519 }
520
521 hid = (crp->crp_sid >> 32) & 0xffffffff;
522 if (hid >= crypto_drivers_num)
523 goto migrate;
524
525 crypto_drivers[hid].cc_queued--;
526
527 if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) {
528 crypto_freesession(crp->crp_sid);
529 goto migrate;
530 }
531
532 if (crypto_drivers[hid].cc_process == NULL)
533 goto migrate;
534
535 crypto_drivers[hid].cc_operations++;
536 crypto_drivers[hid].cc_bytes += crp->crp_ilen;
537
538 error = crypto_drivers[hid].cc_process(crp);
539 if (error) {
540 if (error == ERESTART) {
541 /* Unregister driver and migrate session. */
542 crypto_unregister(hid, CRYPTO_ALGORITHM_ALL);
543 goto migrate;
544 } else {
545 crp->crp_etype = error;
546 crypto_done(crp);
547 }
548 }
549
550 return 0;
551
552 migrate:
553 /* Migrate session. */
554 for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
555 crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
556
557 if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
558 crp->crp_sid = nid;
559
560 crp->crp_etype = EAGAIN;
561 crypto_done(crp);
562 return 0;
563 }
564
565 /*
566 * Release a set of crypto descriptors.
567 */
568 void
569 crypto_freereq(struct cryptop *crp)
570 {
571 struct cryptodesc *crd;
572 int s;
573
574 if (crp == NULL)
575 return;
576
577 s = splvm();
578
579 while ((crd = crp->crp_desc) != NULL) {
580 crp->crp_desc = crd->crd_next;
581 pool_put(&cryptodesc_pool, crd);
582 }
583
584 pool_put(&cryptop_pool, crp);
585 splx(s);
586 }
587
588 /*
589 * Acquire a set of crypto descriptors.
590 */
591 struct cryptop *
592 crypto_getreq(int num)
593 {
594 struct cryptodesc *crd;
595 struct cryptop *crp;
596 int s;
597
598 s = splvm();
599
600 if (crypto_pool_initialized == 0) {
601 pool_init(&cryptop_pool, sizeof(struct cryptop), 0, 0,
602 0, "cryptop", NULL);
603 pool_init(&cryptodesc_pool, sizeof(struct cryptodesc), 0, 0,
604 0, "cryptodesc", NULL);
605 crypto_pool_initialized = 1;
606 }
607
608 crp = pool_get(&cryptop_pool, PR_NOWAIT);
609 if (crp == NULL) {
610 splx(s);
611 return NULL;
612 }
613 bzero(crp, sizeof(struct cryptop));
614
615 while (num--) {
616 crd = pool_get(&cryptodesc_pool, PR_NOWAIT);
617 if (crd == NULL) {
618 splx(s);
619 crypto_freereq(crp);
620 return NULL;
621 }
622
623 bzero(crd, sizeof(struct cryptodesc));
624 crd->crd_next = crp->crp_desc;
625 crp->crp_desc = crd;
626 }
627
628 splx(s);
629 return crp;
630 }
631
632 /*
633 * Crypto thread, runs as a kernel thread to process crypto requests.
634 */
635 void
636 crypto_thread(void)
637 {
638 struct cryptop *crp;
639 struct cryptkop *krp;
640 int s;
641
642 s = splvm();
643
644 for (;;) {
645 crp = crp_req_queue;
646 krp = krp_req_queue;
647 if (crp == NULL && krp == NULL) {
648 (void)tsleep(&crp_req_queue, PLOCK, "crypto_wait", 0);
649 continue;
650 }
651
652 if (crp) {
653 /* Remove from the queue. */
654 crp_req_queue = crp->crp_next;
655 crypto_invoke(crp);
656 }
657 if (krp) {
658 /* Remove from the queue. */
659 krp_req_queue = krp->krp_next;
660 crypto_kinvoke(krp);
661 }
662 }
663 }
664
665 /*
666 * Invoke the callback on behalf of the driver.
667 */
668 void
669 crypto_done(struct cryptop *crp)
670 {
671 crp->crp_flags |= CRYPTO_F_DONE;
672 crp->crp_callback(crp);
673 }
674
675 /*
676 * Invoke the callback on behalf of the driver.
677 */
678 void
679 crypto_kdone(struct cryptkop *krp)
680 {
681 krp->krp_callback(krp);
682 }
683
684 int
685 crypto_getfeat(int *featp)
686 {
687 extern int cryptodevallowsoft, userasymcrypto;
688 int hid, kalg, feat = 0;
689
690 if (userasymcrypto == 0)
691 goto out;
692 for (hid = 0; hid < crypto_drivers_num; hid++) {
693 if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) &&
694 cryptodevallowsoft == 0) {
695 continue;
696 }
697 if (crypto_drivers[hid].cc_kprocess == NULL)
698 continue;
699 for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
700 if ((crypto_drivers[hid].cc_kalg[kalg] &
701 CRYPTO_ALG_FLAG_SUPPORTED) != 0)
702 feat |= 1 << kalg;
703 }
704 out:
705 *featp = feat;
706 return (0);
707 }