1 /* $OpenBSD: crypto.c,v 1.26 2001/08/05 09:36:38 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 #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 /* 41 * Create a new session. 42 */ 43 int 44 crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard) 45 { 46 struct cryptoini *cr; 47 u_int32_t hid, lid; 48 int err, s; 49 50 if (crypto_drivers == NULL) 51 return EINVAL; 52 53 s = splimp(); 54 55 /* 56 * The algorithm we use here is pretty stupid; just use the 57 * first driver that supports all the algorithms we need. 58 * 59 * XXX We need more smarts here (in real life too, but that's 60 * XXX another story altogether). 61 */ 62 63 for (hid = 0; hid < crypto_drivers_num; hid++) { 64 /* 65 * If it's not initialized or has remaining sessions 66 * referencing it, skip. 67 */ 68 if (crypto_drivers[hid].cc_newsession == NULL || 69 (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP)) 70 continue; 71 72 /* Hardware requested -- ignore software drivers. */ 73 if (hard && 74 (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE)) 75 continue; 76 77 /* See if all the algorithms are supported. */ 78 for (cr = cri; cr; cr = cr->cri_next) 79 if (crypto_drivers[hid].cc_alg[cr->cri_alg] == 0) 80 break; 81 82 /* Ok, all algorithms are supported. */ 83 if (cr == NULL) 84 break; 85 } 86 87 /* 88 * Can't do everything in one session. 89 * 90 * XXX Fix this. We need to inject a "virtual" session layer right 91 * XXX about here. 92 */ 93 94 if (hid == crypto_drivers_num) { 95 splx(s); 96 return EINVAL; 97 } 98 99 /* Call the driver initialization routine. */ 100 lid = hid; /* Pass the driver ID. */ 101 err = crypto_drivers[hid].cc_newsession(&lid, cri); 102 if (err == 0) { 103 (*sid) = hid; 104 (*sid) <<= 32; 105 (*sid) |= (lid & 0xffffffff); 106 crypto_drivers[hid].cc_sessions++; 107 } 108 109 splx(s); 110 return err; 111 } 112 113 /* 114 * Delete an existing session (or a reserved session on an unregistered 115 * driver). 116 */ 117 int 118 crypto_freesession(u_int64_t sid) 119 { 120 int err = 0, s; 121 u_int32_t hid; 122 123 if (crypto_drivers == NULL) 124 return EINVAL; 125 126 /* Determine two IDs. */ 127 hid = (sid >> 32) & 0xffffffff; 128 129 if (hid >= crypto_drivers_num) 130 return ENOENT; 131 132 s = splimp(); 133 134 if (crypto_drivers[hid].cc_sessions) 135 crypto_drivers[hid].cc_sessions--; 136 137 /* Call the driver cleanup routine, if available. */ 138 if (crypto_drivers[hid].cc_freesession) 139 err = crypto_drivers[hid].cc_freesession(sid); 140 141 /* 142 * If this was the last session of a driver marked as invalid, 143 * make the entry available for reuse. 144 */ 145 if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) && 146 crypto_drivers[hid].cc_sessions == 0) 147 bzero(&crypto_drivers[hid], sizeof(struct cryptocap)); 148 149 splx(s); 150 return err; 151 } 152 153 /* 154 * Find an empty slot. 155 */ 156 int32_t 157 crypto_get_driverid(void) 158 { 159 struct cryptocap *newdrv; 160 int i, s = splimp(); 161 162 if (crypto_drivers_num == 0) { 163 crypto_drivers_num = CRYPTO_DRIVERS_INITIAL; 164 crypto_drivers = malloc(crypto_drivers_num * 165 sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT); 166 if (crypto_drivers == NULL) { 167 splx(s); 168 crypto_drivers_num = 0; 169 return -1; 170 } 171 172 bzero(crypto_drivers, crypto_drivers_num * 173 sizeof(struct cryptocap)); 174 } 175 176 for (i = 0; i < crypto_drivers_num; i++) { 177 if (crypto_drivers[i].cc_process == NULL && 178 !(crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) && 179 crypto_drivers[i].cc_sessions == 0) { 180 crypto_drivers[i].cc_sessions = 1; /* Mark */ 181 splx(s); 182 return i; 183 } 184 } 185 186 /* Out of entries, allocate some more. */ 187 if (i == crypto_drivers_num) { 188 /* Be careful about wrap-around. */ 189 if (2 * crypto_drivers_num <= crypto_drivers_num) { 190 splx(s); 191 return -1; 192 } 193 194 newdrv = malloc(2 * crypto_drivers_num * 195 sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT); 196 if (newdrv == NULL) { 197 splx(s); 198 return -1; 199 } 200 201 bcopy(crypto_drivers, newdrv, 202 crypto_drivers_num * sizeof(struct cryptocap)); 203 bzero(&newdrv[crypto_drivers_num], 204 crypto_drivers_num * sizeof(struct cryptocap)); 205 206 newdrv[i].cc_sessions = 1; /* Mark */ 207 crypto_drivers_num *= 2; 208 209 free(crypto_drivers, M_CRYPTO_DATA); 210 crypto_drivers = newdrv; 211 splx(s); 212 return i; 213 } 214 215 /* Shouldn't really get here... */ 216 splx(s); 217 return -1; 218 } 219 220 /* 221 * Register a crypto driver. It should be called once for each algorithm 222 * supported by the driver. 223 */ 224 int 225 crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, 226 u_int32_t flags, 227 int (*newses)(u_int32_t *, struct cryptoini *), 228 int (*freeses)(u_int64_t), int (*process)(struct cryptop *)) 229 { 230 int s; 231 232 if (driverid >= crypto_drivers_num || alg <= 0 || 233 alg > CRYPTO_ALGORITHM_MAX || crypto_drivers == NULL) 234 return EINVAL; 235 236 s = splimp(); 237 238 /* 239 * XXX Do some performance testing to determine placing. 240 * XXX We probably need an auxiliary data structure that describes 241 * XXX relative performances. 242 */ 243 244 crypto_drivers[driverid].cc_alg[alg] = 245 flags | CRYPTO_ALG_FLAG_SUPPORTED; 246 247 crypto_drivers[driverid].cc_max_op_len[alg] = maxoplen; 248 249 if (crypto_drivers[driverid].cc_process == NULL) { 250 crypto_drivers[driverid].cc_newsession = newses; 251 crypto_drivers[driverid].cc_process = process; 252 crypto_drivers[driverid].cc_freesession = freeses; 253 crypto_drivers[driverid].cc_sessions = 0; /* Unmark */ 254 } 255 256 splx(s); 257 return 0; 258 } 259 260 /* 261 * Unregister a crypto driver. If there are pending sessions using it, 262 * leave enough information around so that subsequent calls using those 263 * sessions will correctly detect the driver being unregistered and reroute 264 * the request. 265 */ 266 int 267 crypto_unregister(u_int32_t driverid, int alg) 268 { 269 int i, s = splimp(); 270 u_int32_t ses; 271 272 /* Sanity checks */ 273 if (driverid >= crypto_drivers_num || alg <= 0 || 274 alg > CRYPTO_ALGORITHM_MAX || crypto_drivers == NULL || 275 crypto_drivers[driverid].cc_alg[alg] == 0) { 276 splx(s); 277 return EINVAL; 278 } 279 280 crypto_drivers[driverid].cc_alg[alg] = 0; 281 crypto_drivers[driverid].cc_max_op_len[alg] = 0; 282 283 /* Was this the last algorithm ? */ 284 for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) 285 if (crypto_drivers[driverid].cc_alg[i] != 0) 286 break; 287 288 if (i == CRYPTO_ALGORITHM_MAX + 1) { 289 ses = crypto_drivers[driverid].cc_sessions; 290 bzero(&crypto_drivers[driverid], sizeof(struct cryptocap)); 291 if (ses != 0) { 292 /* 293 * If there are pending sessions, just mark as invalid. 294 */ 295 crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP; 296 crypto_drivers[driverid].cc_sessions = ses; 297 } 298 } 299 splx(s); 300 return 0; 301 } 302 303 /* 304 * Add crypto request to a queue, to be processed by a kernel thread. 305 */ 306 int 307 crypto_dispatch(struct cryptop *crp) 308 { 309 int s = splimp(); 310 311 if (crp_req_queue == NULL) { 312 crp_req_queue = crp; 313 crp_req_queue_tail = &(crp->crp_next); 314 splx(s); 315 wakeup((caddr_t) &crp_req_queue); 316 } else { 317 *crp_req_queue_tail = crp; 318 crp_req_queue_tail = &(crp->crp_next); 319 splx(s); 320 } 321 return 0; 322 } 323 324 /* 325 * Dispatch a crypto request to the appropriate crypto devices. 326 */ 327 int 328 crypto_invoke(struct cryptop *crp) 329 { 330 struct cryptodesc *crd; 331 u_int64_t nid; 332 u_int32_t hid; 333 334 /* Sanity checks. */ 335 if (crp == NULL || crp->crp_callback == NULL) 336 return EINVAL; 337 338 if (crp->crp_desc == NULL || crypto_drivers == NULL) { 339 crp->crp_etype = EINVAL; 340 crypto_done(crp); 341 return 0; 342 } 343 344 hid = (crp->crp_sid >> 32) & 0xffffffff; 345 if (hid >= crypto_drivers_num) { 346 /* Migrate session. */ 347 for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) 348 crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); 349 350 if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0) 351 crp->crp_sid = nid; 352 353 crp->crp_etype = EAGAIN; 354 crypto_done(crp); 355 return 0; 356 } 357 358 if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) 359 crypto_freesession(crp->crp_sid); 360 361 if (crypto_drivers[hid].cc_process == NULL) { 362 /* Migrate session. */ 363 for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) 364 crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); 365 366 if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0) 367 crp->crp_sid = nid; 368 369 crp->crp_etype = EAGAIN; 370 crypto_done(crp); 371 return 0; 372 } 373 374 crypto_drivers[hid].cc_process(crp); 375 return 0; 376 } 377 378 /* 379 * Release a set of crypto descriptors. 380 */ 381 void 382 crypto_freereq(struct cryptop *crp) 383 { 384 struct cryptodesc *crd; 385 int s; 386 387 if (crp == NULL) 388 return; 389 390 s = splimp(); 391 392 while ((crd = crp->crp_desc) != NULL) { 393 crp->crp_desc = crd->crd_next; 394 pool_put(&cryptodesc_pool, crd); 395 } 396 397 pool_put(&cryptop_pool, crp); 398 splx(s); 399 } 400 401 /* 402 * Acquire a set of crypto descriptors. 403 */ 404 struct cryptop * 405 crypto_getreq(int num) 406 { 407 struct cryptodesc *crd; 408 struct cryptop *crp; 409 int s = splimp(); 410 411 if (crypto_pool_initialized == 0) { 412 pool_init(&cryptop_pool, sizeof(struct cryptop), 0, 0, 413 PR_FREEHEADER, "cryptop", 0, NULL, NULL, M_CRYPTO_OPS); 414 pool_init(&cryptodesc_pool, sizeof(struct cryptodesc), 0, 0, 415 PR_FREEHEADER, "cryptodesc", 0, NULL, NULL, M_CRYPTO_OPS); 416 crypto_pool_initialized = 1; 417 } 418 419 crp = pool_get(&cryptop_pool, 0); 420 if (crp == NULL) { 421 splx(s); 422 return NULL; 423 } 424 bzero(crp, sizeof(struct cryptop)); 425 426 while (num--) { 427 crd = pool_get(&cryptodesc_pool, 0); 428 if (crd == NULL) { 429 splx(s); 430 crypto_freereq(crp); 431 return NULL; 432 } 433 434 bzero(crd, sizeof(struct cryptodesc)); 435 crd->crd_next = crp->crp_desc; 436 crp->crp_desc = crd; 437 } 438 439 splx(s); 440 return crp; 441 } 442 443 /* 444 * Crypto thread, runs as a kernel thread to process crypto requests. 445 */ 446 void 447 crypto_thread(void) 448 { 449 struct cryptop *crp; 450 int s; 451 452 s = splimp(); 453 454 for (;;) { 455 crp = crp_req_queue; 456 if (crp == NULL) { 457 (void) tsleep(&crp_req_queue, PLOCK, "crypto_wait", 0); 458 continue; 459 } 460 461 /* Remove from the queue. */ 462 crp_req_queue = crp->crp_next; 463 crypto_invoke(crp); 464 } 465 } 466 467 /* 468 * Invoke the callback on behalf of the driver. 469 */ 470 void 471 crypto_done(struct cryptop *crp) 472 { 473 crp->crp_callback(crp); 474 } 475 476 /* 477 * Return SYMMETRIC or PUBLIC_KEY, depending on the algorithm type. 478 */ 479 int 480 crypto_check_alg(struct cryptoini *cri) 481 { 482 switch (cri->cri_alg) 483 { 484 case CRYPTO_DES_CBC: 485 case CRYPTO_3DES_CBC: 486 case CRYPTO_BLF_CBC: 487 case CRYPTO_CAST_CBC: 488 case CRYPTO_SKIPJACK_CBC: 489 case CRYPTO_RIJNDAEL128_CBC: 490 case CRYPTO_ARC4: 491 return SYMMETRIC; 492 case CRYPTO_DH_SEND: 493 case CRYPTO_DH_RECEIVE: 494 case CRYPTO_RSA_ENCRYPT: 495 case CRYPTO_RSA_DECRYPT: 496 case CRYPTO_DSA_SIGN: 497 case CRYPTO_DSA_VERIFY: 498 return PUBLIC_KEY; 499 } 500 501 #ifdef DIAGNOSTIC 502 panic("crypto_check_alg: unknown algorithm %d", cri->cri_alg); 503 #endif 504 return -1; 505 } 506