Annotation of sys/crypto/crypto.c, Revision 1.1.1.1
1.1 nbrk 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: }
CVSweb