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