xref: /openbsd-src/sys/crypto/crypto.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /*	$OpenBSD: crypto.c,v 1.72 2014/10/23 00:15:09 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/pool.h>
27 
28 #include <crypto/cryptodev.h>
29 
30 void crypto_init(void);
31 
32 struct cryptocap *crypto_drivers = NULL;
33 int crypto_drivers_num = 0;
34 
35 struct pool cryptop_pool;
36 struct pool cryptodesc_pool;
37 
38 struct taskq *crypto_taskq;
39 
40 /*
41  * Create a new session.
42  */
43 int
44 crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard)
45 {
46 	u_int32_t hid, lid, hid2 = -1;
47 	struct cryptocap *cpc;
48 	struct cryptoini *cr;
49 	int err, s, turn = 0;
50 
51 	if (crypto_drivers == NULL)
52 		return EINVAL;
53 
54 	s = splvm();
55 
56 	/*
57 	 * The algorithm we use here is pretty stupid; just use the
58 	 * first driver that supports all the algorithms we need. Do
59 	 * a double-pass over all the drivers, ignoring software ones
60 	 * at first, to deal with cases of drivers that register after
61 	 * the software one(s) --- e.g., PCMCIA crypto cards.
62 	 *
63 	 * XXX We need more smarts here (in real life too, but that's
64 	 * XXX another story altogether).
65 	 */
66 	do {
67 		for (hid = 0; hid < crypto_drivers_num; hid++) {
68 			cpc = &crypto_drivers[hid];
69 
70 			/*
71 			 * If it's not initialized or has remaining sessions
72 			 * referencing it, skip.
73 			 */
74 			if (cpc->cc_newsession == NULL ||
75 			    (cpc->cc_flags & CRYPTOCAP_F_CLEANUP))
76 				continue;
77 
78 			if (cpc->cc_flags & CRYPTOCAP_F_SOFTWARE) {
79 				/*
80 				 * First round of search, ignore
81 				 * software drivers.
82 				 */
83 				if (turn == 0)
84 					continue;
85 			} else { /* !CRYPTOCAP_F_SOFTWARE */
86 				/* Second round of search, only software. */
87 				if (turn == 1)
88 					continue;
89 			}
90 
91 			/* See if all the algorithms are supported. */
92 			for (cr = cri; cr; cr = cr->cri_next) {
93 				if (cpc->cc_alg[cr->cri_alg] == 0)
94 					break;
95 			}
96 
97 			/*
98 			 * If even one algorithm is not supported,
99 			 * keep searching.
100 			 */
101 			if (cr != NULL)
102 				continue;
103 
104 			/*
105 			 * If we had a previous match, see how it compares
106 			 * to this one. Keep "remembering" whichever is
107 			 * the best of the two.
108 			 */
109 			if (hid2 != -1) {
110 				/*
111 				 * Compare session numbers, pick the one
112 				 * with the lowest.
113 				 * XXX Need better metrics, this will
114 				 * XXX just do un-weighted round-robin.
115 				 */
116 				if (crypto_drivers[hid].cc_sessions <=
117 				    crypto_drivers[hid2].cc_sessions)
118 					hid2 = hid;
119 			} else {
120 				/*
121 				 * Remember this one, for future
122                                  * comparisons.
123 				 */
124 				hid2 = hid;
125 			}
126 		}
127 
128 		/*
129 		 * If we found something worth remembering, leave. The
130 		 * side-effect is that we will always prefer a hardware
131 		 * driver over the software one.
132 		 */
133 		if (hid2 != -1)
134 			break;
135 
136 		turn++;
137 
138 		/* If we only want hardware drivers, don't do second pass. */
139 	} while (turn <= 2 && hard == 0);
140 
141 	hid = hid2;
142 
143 	/*
144 	 * Can't do everything in one session.
145 	 *
146 	 * XXX Fix this. We need to inject a "virtual" session
147 	 * XXX layer right about here.
148 	 */
149 
150 	if (hid == -1) {
151 		splx(s);
152 		return EINVAL;
153 	}
154 
155 	/* Call the driver initialization routine. */
156 	lid = hid; /* Pass the driver ID. */
157 	err = crypto_drivers[hid].cc_newsession(&lid, cri);
158 	if (err == 0) {
159 		(*sid) = hid;
160 		(*sid) <<= 32;
161 		(*sid) |= (lid & 0xffffffff);
162 		crypto_drivers[hid].cc_sessions++;
163 	}
164 
165 	splx(s);
166 	return err;
167 }
168 
169 /*
170  * Delete an existing session (or a reserved session on an unregistered
171  * driver).
172  */
173 int
174 crypto_freesession(u_int64_t sid)
175 {
176 	int err = 0, s;
177 	u_int32_t hid;
178 
179 	if (crypto_drivers == NULL)
180 		return EINVAL;
181 
182 	/* Determine two IDs. */
183 	hid = (sid >> 32) & 0xffffffff;
184 
185 	if (hid >= crypto_drivers_num)
186 		return ENOENT;
187 
188 	s = splvm();
189 
190 	if (crypto_drivers[hid].cc_sessions)
191 		crypto_drivers[hid].cc_sessions--;
192 
193 	/* Call the driver cleanup routine, if available. */
194 	if (crypto_drivers[hid].cc_freesession)
195 		err = crypto_drivers[hid].cc_freesession(sid);
196 
197 	/*
198 	 * If this was the last session of a driver marked as invalid,
199 	 * make the entry available for reuse.
200 	 */
201 	if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) &&
202 	    crypto_drivers[hid].cc_sessions == 0)
203 		explicit_bzero(&crypto_drivers[hid], sizeof(struct cryptocap));
204 
205 	splx(s);
206 	return err;
207 }
208 
209 /*
210  * Find an empty slot.
211  */
212 int32_t
213 crypto_get_driverid(u_int8_t flags)
214 {
215 	struct cryptocap *newdrv;
216 	int i, s;
217 
218 	s = splvm();
219 
220 	if (crypto_drivers_num == 0) {
221 		crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
222 		crypto_drivers = mallocarray(crypto_drivers_num,
223 		    sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
224 		if (crypto_drivers == NULL) {
225 			crypto_drivers_num = 0;
226 			splx(s);
227 			return -1;
228 		}
229 	}
230 
231 	for (i = 0; i < crypto_drivers_num; i++) {
232 		if (crypto_drivers[i].cc_process == NULL &&
233 		    !(crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) &&
234 		    crypto_drivers[i].cc_sessions == 0) {
235 			crypto_drivers[i].cc_sessions = 1; /* Mark */
236 			crypto_drivers[i].cc_flags = flags;
237 			splx(s);
238 			return i;
239 		}
240 	}
241 
242 	/* Out of entries, allocate some more. */
243 	if (i == crypto_drivers_num) {
244 		if (crypto_drivers_num >= CRYPTO_DRIVERS_MAX) {
245 			splx(s);
246 			return -1;
247 		}
248 
249 		newdrv = mallocarray(crypto_drivers_num,
250 		    2 * sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT);
251 		if (newdrv == NULL) {
252 			splx(s);
253 			return -1;
254 		}
255 
256 		bcopy(crypto_drivers, newdrv,
257 		    crypto_drivers_num * sizeof(struct cryptocap));
258 		bzero(&newdrv[crypto_drivers_num],
259 		    crypto_drivers_num * sizeof(struct cryptocap));
260 
261 		newdrv[i].cc_sessions = 1; /* Mark */
262 		newdrv[i].cc_flags = flags;
263 		crypto_drivers_num *= 2;
264 
265 		free(crypto_drivers, M_CRYPTO_DATA, 0);
266 		crypto_drivers = newdrv;
267 		splx(s);
268 		return i;
269 	}
270 
271 	/* Shouldn't really get here... */
272 	splx(s);
273 	return -1;
274 }
275 
276 /*
277  * Register a crypto driver. It should be called once for each algorithm
278  * supported by the driver.
279  */
280 int
281 crypto_register(u_int32_t driverid, int *alg,
282     int (*newses)(u_int32_t *, struct cryptoini *),
283     int (*freeses)(u_int64_t), int (*process)(struct cryptop *))
284 {
285 	int s, i;
286 
287 
288 	if (driverid >= crypto_drivers_num || alg == NULL ||
289 	    crypto_drivers == NULL)
290 		return EINVAL;
291 
292 	s = splvm();
293 
294 	for (i = 0; i <= CRYPTO_ALGORITHM_MAX; i++) {
295 		/*
296 		 * XXX Do some performance testing to determine
297 		 * placing.  We probably need an auxiliary data
298 		 * structure that describes relative performances.
299 		 */
300 
301 		crypto_drivers[driverid].cc_alg[i] = alg[i];
302 	}
303 
304 
305 	crypto_drivers[driverid].cc_newsession = newses;
306 	crypto_drivers[driverid].cc_process = process;
307 	crypto_drivers[driverid].cc_freesession = freeses;
308 	crypto_drivers[driverid].cc_sessions = 0; /* Unmark */
309 
310 	splx(s);
311 
312 	return 0;
313 }
314 
315 /*
316  * Unregister a crypto driver. If there are pending sessions using it,
317  * leave enough information around so that subsequent calls using those
318  * sessions will correctly detect the driver being unregistered and reroute
319  * the request.
320  */
321 int
322 crypto_unregister(u_int32_t driverid, int alg)
323 {
324 	int i = CRYPTO_ALGORITHM_MAX + 1, s;
325 	u_int32_t ses;
326 
327 	s = splvm();
328 
329 	/* Sanity checks. */
330 	if (driverid >= crypto_drivers_num || crypto_drivers == NULL ||
331 	    ((alg <= 0 || alg > CRYPTO_ALGORITHM_MAX) &&
332 		alg != CRYPTO_ALGORITHM_MAX + 1) ||
333 	    crypto_drivers[driverid].cc_alg[alg] == 0) {
334 		splx(s);
335 		return EINVAL;
336 	}
337 
338 	if (alg != CRYPTO_ALGORITHM_MAX + 1) {
339 		crypto_drivers[driverid].cc_alg[alg] = 0;
340 
341 		/* Was this the last algorithm ? */
342 		for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
343 			if (crypto_drivers[driverid].cc_alg[i] != 0)
344 				break;
345 	}
346 
347 	/*
348 	 * If a driver unregistered its last algorithm or all of them
349 	 * (alg == CRYPTO_ALGORITHM_MAX + 1), cleanup its entry.
350 	 */
351 	if (i == CRYPTO_ALGORITHM_MAX + 1 || alg == CRYPTO_ALGORITHM_MAX + 1) {
352 		ses = crypto_drivers[driverid].cc_sessions;
353 		bzero(&crypto_drivers[driverid], sizeof(struct cryptocap));
354 		if (ses != 0) {
355 			/*
356 			 * If there are pending sessions, just mark as invalid.
357 			 */
358 			crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP;
359 			crypto_drivers[driverid].cc_sessions = ses;
360 		}
361 	}
362 	splx(s);
363 	return 0;
364 }
365 
366 /*
367  * Add crypto request to a queue, to be processed by a kernel thread.
368  */
369 int
370 crypto_dispatch(struct cryptop *crp)
371 {
372 	if (crypto_taskq && !(crp->crp_flags & CRYPTO_F_NOQUEUE)) {
373 		task_set(&crp->crp_task, (void (*))crypto_invoke, crp, NULL);
374 		task_add(crypto_taskq, &crp->crp_task);
375 	} else {
376 		crypto_invoke(crp);
377 	}
378 
379 	return 0;
380 }
381 
382 /*
383  * Dispatch a crypto request to the appropriate crypto devices.
384  */
385 int
386 crypto_invoke(struct cryptop *crp)
387 {
388 	struct cryptodesc *crd;
389 	u_int64_t nid;
390 	u_int32_t hid;
391 	int error;
392 	int s;
393 
394 	/* Sanity checks. */
395 	if (crp == NULL || crp->crp_callback == NULL)
396 		return EINVAL;
397 
398 	s = splvm();
399 	if (crp->crp_desc == NULL || crypto_drivers == NULL) {
400 		crp->crp_etype = EINVAL;
401 		crypto_done(crp);
402 		splx(s);
403 		return 0;
404 	}
405 
406 	hid = (crp->crp_sid >> 32) & 0xffffffff;
407 	if (hid >= crypto_drivers_num)
408 		goto migrate;
409 
410 	if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) {
411 		crypto_freesession(crp->crp_sid);
412 		goto migrate;
413 	}
414 
415 	if (crypto_drivers[hid].cc_process == NULL)
416 		goto migrate;
417 
418 	crypto_drivers[hid].cc_operations++;
419 	crypto_drivers[hid].cc_bytes += crp->crp_ilen;
420 
421 	error = crypto_drivers[hid].cc_process(crp);
422 	if (error) {
423 		if (error == ERESTART) {
424 			/* Unregister driver and migrate session. */
425 			crypto_unregister(hid, CRYPTO_ALGORITHM_MAX + 1);
426 			goto migrate;
427 		} else {
428 			crp->crp_etype = error;
429 		}
430 	}
431 
432 	splx(s);
433 	return 0;
434 
435  migrate:
436 	/* Migrate session. */
437 	for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
438 		crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
439 
440 	if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0)
441 		crp->crp_sid = nid;
442 
443 	crp->crp_etype = EAGAIN;
444 	crypto_done(crp);
445 	splx(s);
446 	return 0;
447 }
448 
449 /*
450  * Release a set of crypto descriptors.
451  */
452 void
453 crypto_freereq(struct cryptop *crp)
454 {
455 	struct cryptodesc *crd;
456 
457 	if (crp == NULL)
458 		return;
459 
460 	while ((crd = crp->crp_desc) != NULL) {
461 		crp->crp_desc = crd->crd_next;
462 		pool_put(&cryptodesc_pool, crd);
463 	}
464 
465 	pool_put(&cryptop_pool, crp);
466 }
467 
468 /*
469  * Acquire a set of crypto descriptors.
470  */
471 struct cryptop *
472 crypto_getreq(int num)
473 {
474 	struct cryptodesc *crd;
475 	struct cryptop *crp;
476 
477 	crp = pool_get(&cryptop_pool, PR_NOWAIT | PR_ZERO);
478 	if (crp == NULL)
479 		return NULL;
480 
481 	while (num--) {
482 		crd = pool_get(&cryptodesc_pool, PR_NOWAIT | PR_ZERO);
483 		if (crd == NULL) {
484 			crypto_freereq(crp);
485 			return NULL;
486 		}
487 
488 		crd->crd_next = crp->crp_desc;
489 		crp->crp_desc = crd;
490 	}
491 
492 	return crp;
493 }
494 
495 void
496 crypto_init(void)
497 {
498 	crypto_taskq = taskq_create("crypto", 1, IPL_VM);
499 
500 	pool_init(&cryptop_pool, sizeof(struct cryptop), 0, 0,
501 	    0, "cryptop", NULL);
502 	pool_setipl(&cryptop_pool, IPL_VM);
503 	pool_init(&cryptodesc_pool, sizeof(struct cryptodesc), 0, 0,
504 	    0, "cryptodesc", NULL);
505 	pool_setipl(&cryptodesc_pool, IPL_VM);
506 }
507 
508 /*
509  * Invoke the callback on behalf of the driver.
510  */
511 void
512 crypto_done(struct cryptop *crp)
513 {
514 	crp->crp_flags |= CRYPTO_F_DONE;
515 	if (crp->crp_flags & CRYPTO_F_NOQUEUE) {
516 		/* not from the crypto queue, wakeup the userland process */
517 		crp->crp_callback(crp);
518 	} else {
519 		task_set(&crp->crp_task, (void (*))crp->crp_callback,
520 		    crp, NULL);
521 		task_add(crypto_taskq, &crp->crp_task);
522 	}
523 }
524