1 /* $OpenBSD: crypto.c,v 1.80 2017/11/30 16:31:12 visa 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 struct taskq *crypto_taskq_mpsafe; 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 = mallocarray(crypto_drivers_num, 224 sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT | M_ZERO); 225 if (crypto_drivers == NULL) { 226 crypto_drivers_num = 0; 227 splx(s); 228 return -1; 229 } 230 } 231 232 for (i = 0; i < crypto_drivers_num; i++) { 233 if (crypto_drivers[i].cc_process == NULL && 234 !(crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) && 235 crypto_drivers[i].cc_sessions == 0) { 236 crypto_drivers[i].cc_sessions = 1; /* Mark */ 237 crypto_drivers[i].cc_flags = flags; 238 splx(s); 239 return i; 240 } 241 } 242 243 /* Out of entries, allocate some more. */ 244 if (i == crypto_drivers_num) { 245 if (crypto_drivers_num >= CRYPTO_DRIVERS_MAX) { 246 splx(s); 247 return -1; 248 } 249 250 newdrv = mallocarray(crypto_drivers_num, 251 2 * sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT); 252 if (newdrv == NULL) { 253 splx(s); 254 return -1; 255 } 256 257 memcpy(newdrv, crypto_drivers, 258 crypto_drivers_num * sizeof(struct cryptocap)); 259 bzero(&newdrv[crypto_drivers_num], 260 crypto_drivers_num * sizeof(struct cryptocap)); 261 262 newdrv[i].cc_sessions = 1; /* Mark */ 263 newdrv[i].cc_flags = flags; 264 265 free(crypto_drivers, M_CRYPTO_DATA, 266 crypto_drivers_num * sizeof(struct cryptocap)); 267 268 crypto_drivers_num *= 2; 269 crypto_drivers = newdrv; 270 splx(s); 271 return i; 272 } 273 274 /* Shouldn't really get here... */ 275 splx(s); 276 return -1; 277 } 278 279 /* 280 * Register a crypto driver. It should be called once for each algorithm 281 * supported by the driver. 282 */ 283 int 284 crypto_register(u_int32_t driverid, int *alg, 285 int (*newses)(u_int32_t *, struct cryptoini *), 286 int (*freeses)(u_int64_t), int (*process)(struct cryptop *)) 287 { 288 int s, i; 289 290 291 if (driverid >= crypto_drivers_num || alg == NULL || 292 crypto_drivers == NULL) 293 return EINVAL; 294 295 s = splvm(); 296 297 for (i = 0; i <= CRYPTO_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_alg[i] = alg[i]; 305 } 306 307 308 crypto_drivers[driverid].cc_newsession = newses; 309 crypto_drivers[driverid].cc_process = process; 310 crypto_drivers[driverid].cc_freesession = freeses; 311 crypto_drivers[driverid].cc_sessions = 0; /* Unmark */ 312 313 splx(s); 314 315 return 0; 316 } 317 318 /* 319 * Unregister a crypto driver. If there are pending sessions using it, 320 * leave enough information around so that subsequent calls using those 321 * sessions will correctly detect the driver being unregistered and reroute 322 * the request. 323 */ 324 int 325 crypto_unregister(u_int32_t driverid, int alg) 326 { 327 int i = CRYPTO_ALGORITHM_MAX + 1, s; 328 u_int32_t ses; 329 330 s = splvm(); 331 332 /* Sanity checks. */ 333 if (driverid >= crypto_drivers_num || crypto_drivers == NULL || 334 ((alg <= 0 || alg > CRYPTO_ALGORITHM_MAX) && 335 alg != CRYPTO_ALGORITHM_MAX + 1) || 336 crypto_drivers[driverid].cc_alg[alg] == 0) { 337 splx(s); 338 return EINVAL; 339 } 340 341 if (alg != CRYPTO_ALGORITHM_MAX + 1) { 342 crypto_drivers[driverid].cc_alg[alg] = 0; 343 344 /* Was this the last algorithm ? */ 345 for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) 346 if (crypto_drivers[driverid].cc_alg[i] != 0) 347 break; 348 } 349 350 /* 351 * If a driver unregistered its last algorithm or all of them 352 * (alg == CRYPTO_ALGORITHM_MAX + 1), cleanup its entry. 353 */ 354 if (i == CRYPTO_ALGORITHM_MAX + 1 || alg == CRYPTO_ALGORITHM_MAX + 1) { 355 ses = crypto_drivers[driverid].cc_sessions; 356 bzero(&crypto_drivers[driverid], sizeof(struct cryptocap)); 357 if (ses != 0) { 358 /* 359 * If there are pending sessions, just mark as invalid. 360 */ 361 crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP; 362 crypto_drivers[driverid].cc_sessions = ses; 363 } 364 } 365 splx(s); 366 return 0; 367 } 368 369 /* 370 * Add crypto request to a queue, to be processed by a kernel thread. 371 */ 372 int 373 crypto_dispatch(struct cryptop *crp) 374 { 375 struct taskq *tq = crypto_taskq; 376 int s; 377 u_int32_t hid; 378 379 s = splvm(); 380 hid = (crp->crp_sid >> 32) & 0xffffffff; 381 if (hid < crypto_drivers_num) { 382 if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_MPSAFE) 383 tq = crypto_taskq_mpsafe; 384 } 385 splx(s); 386 387 if (tq && !(crp->crp_flags & CRYPTO_F_NOQUEUE)) { 388 task_set(&crp->crp_task, (void (*))crypto_invoke, crp); 389 task_add(tq, &crp->crp_task); 390 } else { 391 crypto_invoke(crp); 392 } 393 394 return 0; 395 } 396 397 /* 398 * Dispatch a crypto request to the appropriate crypto devices. 399 */ 400 int 401 crypto_invoke(struct cryptop *crp) 402 { 403 u_int64_t nid; 404 u_int32_t hid; 405 int error; 406 int s, i; 407 408 /* Sanity checks. */ 409 if (crp == NULL || crp->crp_callback == NULL) 410 return EINVAL; 411 412 s = splvm(); 413 if (crp->crp_ndesc < 1 || crypto_drivers == NULL) { 414 crp->crp_etype = EINVAL; 415 crypto_done(crp); 416 splx(s); 417 return 0; 418 } 419 420 hid = (crp->crp_sid >> 32) & 0xffffffff; 421 if (hid >= crypto_drivers_num) 422 goto migrate; 423 424 if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) { 425 crypto_freesession(crp->crp_sid); 426 goto migrate; 427 } 428 429 if (crypto_drivers[hid].cc_process == NULL) 430 goto migrate; 431 432 crypto_drivers[hid].cc_operations++; 433 crypto_drivers[hid].cc_bytes += crp->crp_ilen; 434 435 error = crypto_drivers[hid].cc_process(crp); 436 if (error) { 437 if (error == ERESTART) { 438 /* Unregister driver and migrate session. */ 439 crypto_unregister(hid, CRYPTO_ALGORITHM_MAX + 1); 440 goto migrate; 441 } else { 442 crp->crp_etype = error; 443 } 444 } 445 446 splx(s); 447 return 0; 448 449 migrate: 450 /* Migrate session. */ 451 for (i = 0; i < crp->crp_ndesc - 1; i++) 452 crp->crp_desc[i].CRD_INI.cri_next = &crp->crp_desc[i+1].CRD_INI; 453 crp->crp_desc[crp->crp_ndesc].CRD_INI.cri_next = NULL; 454 455 if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0) 456 crp->crp_sid = nid; 457 458 crp->crp_etype = EAGAIN; 459 crypto_done(crp); 460 splx(s); 461 return 0; 462 } 463 464 /* 465 * Release a set of crypto descriptors. 466 */ 467 void 468 crypto_freereq(struct cryptop *crp) 469 { 470 if (crp == NULL) 471 return; 472 473 if (crp->crp_ndescalloc > 2) 474 free(crp->crp_desc, M_CRYPTO_DATA, 475 crp->crp_ndescalloc * sizeof(struct cryptodesc)); 476 pool_put(&cryptop_pool, crp); 477 } 478 479 /* 480 * Acquire a set of crypto descriptors. 481 */ 482 struct cryptop * 483 crypto_getreq(int num) 484 { 485 struct cryptop *crp; 486 487 crp = pool_get(&cryptop_pool, PR_NOWAIT | PR_ZERO); 488 if (crp == NULL) 489 return NULL; 490 491 crp->crp_desc = crp->crp_sdesc; 492 crp->crp_ndescalloc = crp->crp_ndesc = num; 493 494 if (num > 2) { 495 crp->crp_desc = mallocarray(num, sizeof(struct cryptodesc), 496 M_CRYPTO_DATA, M_NOWAIT | M_ZERO); 497 if (crp->crp_desc == NULL) { 498 pool_put(&cryptop_pool, crp); 499 return NULL; 500 } 501 } 502 503 return crp; 504 } 505 506 void 507 crypto_init(void) 508 { 509 crypto_taskq = taskq_create("crypto", 1, IPL_VM, 0); 510 crypto_taskq_mpsafe = taskq_create("crynlk", 1, IPL_VM, TASKQ_MPSAFE); 511 512 pool_init(&cryptop_pool, sizeof(struct cryptop), 0, IPL_VM, 0, 513 "cryptop", NULL); 514 } 515 516 /* 517 * Invoke the callback on behalf of the driver. 518 */ 519 void 520 crypto_done(struct cryptop *crp) 521 { 522 crp->crp_flags |= CRYPTO_F_DONE; 523 if (crp->crp_flags & CRYPTO_F_NOQUEUE) { 524 /* not from the crypto queue, wakeup the userland process */ 525 crp->crp_callback(crp); 526 } else { 527 task_set(&crp->crp_task, (void (*))crp->crp_callback, crp); 528 task_add(crypto_taskq, &crp->crp_task); 529 } 530 } 531