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