1 /* $OpenBSD: crypto.c,v 1.30 2001/11/13 18:54:32 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(u_int8_t flags) 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 crypto_drivers[i].cc_flags = flags; 182 splx(s); 183 return i; 184 } 185 } 186 187 /* Out of entries, allocate some more. */ 188 if (i == crypto_drivers_num) { 189 /* Be careful about wrap-around. */ 190 if (2 * crypto_drivers_num <= crypto_drivers_num) { 191 splx(s); 192 return -1; 193 } 194 195 newdrv = malloc(2 * crypto_drivers_num * 196 sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT); 197 if (newdrv == NULL) { 198 splx(s); 199 return -1; 200 } 201 202 bcopy(crypto_drivers, newdrv, 203 crypto_drivers_num * sizeof(struct cryptocap)); 204 bzero(&newdrv[crypto_drivers_num], 205 crypto_drivers_num * sizeof(struct cryptocap)); 206 207 newdrv[i].cc_sessions = 1; /* Mark */ 208 newdrv[i].cc_flags = flags; 209 crypto_drivers_num *= 2; 210 211 free(crypto_drivers, M_CRYPTO_DATA); 212 crypto_drivers = newdrv; 213 splx(s); 214 return i; 215 } 216 217 /* Shouldn't really get here... */ 218 splx(s); 219 return -1; 220 } 221 222 /* 223 * Register a crypto driver. It should be called once for each algorithm 224 * supported by the driver. 225 */ 226 int 227 crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, 228 u_int32_t flags, 229 int (*newses)(u_int32_t *, struct cryptoini *), 230 int (*freeses)(u_int64_t), int (*process)(struct cryptop *)) 231 { 232 int s; 233 234 if (driverid >= crypto_drivers_num || alg <= 0 || 235 alg > CRYPTO_ALGORITHM_MAX || crypto_drivers == NULL) 236 return EINVAL; 237 238 s = splimp(); 239 240 /* 241 * XXX Do some performance testing to determine placing. 242 * XXX We probably need an auxiliary data structure that describes 243 * XXX relative performances. 244 */ 245 246 crypto_drivers[driverid].cc_alg[alg] = 247 flags | CRYPTO_ALG_FLAG_SUPPORTED; 248 249 crypto_drivers[driverid].cc_max_op_len[alg] = maxoplen; 250 251 if (crypto_drivers[driverid].cc_process == NULL) { 252 crypto_drivers[driverid].cc_newsession = newses; 253 crypto_drivers[driverid].cc_process = process; 254 crypto_drivers[driverid].cc_freesession = freeses; 255 crypto_drivers[driverid].cc_sessions = 0; /* Unmark */ 256 } 257 258 splx(s); 259 return 0; 260 } 261 262 /* 263 * Unregister a crypto driver. If there are pending sessions using it, 264 * leave enough information around so that subsequent calls using those 265 * sessions will correctly detect the driver being unregistered and reroute 266 * the request. 267 */ 268 int 269 crypto_unregister(u_int32_t driverid, int alg) 270 { 271 int i, s = splimp(); 272 u_int32_t ses; 273 274 /* Sanity checks */ 275 if (driverid >= crypto_drivers_num || alg <= 0 || 276 alg > CRYPTO_ALGORITHM_MAX || crypto_drivers == NULL || 277 crypto_drivers[driverid].cc_alg[alg] == 0) { 278 splx(s); 279 return EINVAL; 280 } 281 282 crypto_drivers[driverid].cc_alg[alg] = 0; 283 crypto_drivers[driverid].cc_max_op_len[alg] = 0; 284 285 /* Was this the last algorithm ? */ 286 for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) 287 if (crypto_drivers[driverid].cc_alg[i] != 0) 288 break; 289 290 if (i == CRYPTO_ALGORITHM_MAX + 1) { 291 ses = crypto_drivers[driverid].cc_sessions; 292 bzero(&crypto_drivers[driverid], sizeof(struct cryptocap)); 293 if (ses != 0) { 294 /* 295 * If there are pending sessions, just mark as invalid. 296 */ 297 crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP; 298 crypto_drivers[driverid].cc_sessions = ses; 299 } 300 } 301 splx(s); 302 return 0; 303 } 304 305 /* 306 * Add crypto request to a queue, to be processed by a kernel thread. 307 */ 308 int 309 crypto_dispatch(struct cryptop *crp) 310 { 311 int s = splimp(); 312 313 if (crp_req_queue == NULL) { 314 crp_req_queue = crp; 315 crp_req_queue_tail = &(crp->crp_next); 316 splx(s); 317 wakeup((caddr_t) &crp_req_queue); 318 } else { 319 *crp_req_queue_tail = crp; 320 crp_req_queue_tail = &(crp->crp_next); 321 splx(s); 322 } 323 return 0; 324 } 325 326 /* 327 * Dispatch a crypto request to the appropriate crypto devices. 328 */ 329 int 330 crypto_invoke(struct cryptop *crp) 331 { 332 struct cryptodesc *crd; 333 u_int64_t nid; 334 u_int32_t hid; 335 336 /* Sanity checks. */ 337 if (crp == NULL || crp->crp_callback == NULL) 338 return EINVAL; 339 340 if (crp->crp_desc == NULL || crypto_drivers == NULL) { 341 crp->crp_etype = EINVAL; 342 crypto_done(crp); 343 return 0; 344 } 345 346 hid = (crp->crp_sid >> 32) & 0xffffffff; 347 if (hid >= crypto_drivers_num) { 348 /* Migrate session. */ 349 for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) 350 crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); 351 352 if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0) 353 crp->crp_sid = nid; 354 355 crp->crp_etype = EAGAIN; 356 crypto_done(crp); 357 return 0; 358 } 359 360 if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) 361 crypto_freesession(crp->crp_sid); 362 363 if (crypto_drivers[hid].cc_process == NULL) { 364 /* Migrate session. */ 365 for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) 366 crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); 367 368 if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0) 369 crp->crp_sid = nid; 370 371 crp->crp_etype = EAGAIN; 372 crypto_done(crp); 373 return 0; 374 } 375 376 crypto_drivers[hid].cc_process(crp); 377 return 0; 378 } 379 380 /* 381 * Release a set of crypto descriptors. 382 */ 383 void 384 crypto_freereq(struct cryptop *crp) 385 { 386 struct cryptodesc *crd; 387 int s; 388 389 if (crp == NULL) 390 return; 391 392 s = splimp(); 393 394 while ((crd = crp->crp_desc) != NULL) { 395 crp->crp_desc = crd->crd_next; 396 pool_put(&cryptodesc_pool, crd); 397 } 398 399 pool_put(&cryptop_pool, crp); 400 splx(s); 401 } 402 403 /* 404 * Acquire a set of crypto descriptors. 405 */ 406 struct cryptop * 407 crypto_getreq(int num) 408 { 409 struct cryptodesc *crd; 410 struct cryptop *crp; 411 int s = splimp(); 412 413 if (crypto_pool_initialized == 0) { 414 pool_init(&cryptop_pool, sizeof(struct cryptop), 0, 0, 415 PR_FREEHEADER, "cryptop", 0, NULL, NULL, M_CRYPTO_OPS); 416 pool_init(&cryptodesc_pool, sizeof(struct cryptodesc), 0, 0, 417 PR_FREEHEADER, "cryptodesc", 0, NULL, NULL, M_CRYPTO_OPS); 418 crypto_pool_initialized = 1; 419 } 420 421 crp = pool_get(&cryptop_pool, 0); 422 if (crp == NULL) { 423 splx(s); 424 return NULL; 425 } 426 bzero(crp, sizeof(struct cryptop)); 427 428 while (num--) { 429 crd = pool_get(&cryptodesc_pool, 0); 430 if (crd == NULL) { 431 splx(s); 432 crypto_freereq(crp); 433 return NULL; 434 } 435 436 bzero(crd, sizeof(struct cryptodesc)); 437 crd->crd_next = crp->crp_desc; 438 crp->crp_desc = crd; 439 } 440 441 splx(s); 442 return crp; 443 } 444 445 /* 446 * Crypto thread, runs as a kernel thread to process crypto requests. 447 */ 448 void 449 crypto_thread(void) 450 { 451 struct cryptop *crp; 452 int s; 453 454 s = splimp(); 455 456 for (;;) { 457 crp = crp_req_queue; 458 if (crp == NULL) { 459 (void) tsleep(&crp_req_queue, PLOCK, "crypto_wait", 0); 460 continue; 461 } 462 463 /* Remove from the queue. */ 464 crp_req_queue = crp->crp_next; 465 crypto_invoke(crp); 466 } 467 } 468 469 /* 470 * Invoke the callback on behalf of the driver. 471 */ 472 void 473 crypto_done(struct cryptop *crp) 474 { 475 crp->crp_callback(crp); 476 } 477 478 /* 479 * Return SYMMETRIC or PUBLIC_KEY, depending on the algorithm type. 480 */ 481 int 482 crypto_check_alg(struct cryptoini *cri) 483 { 484 switch (cri->cri_alg) 485 { 486 case CRYPTO_DES_CBC: 487 case CRYPTO_3DES_CBC: 488 case CRYPTO_BLF_CBC: 489 case CRYPTO_CAST_CBC: 490 case CRYPTO_SKIPJACK_CBC: 491 case CRYPTO_RIJNDAEL128_CBC: 492 case CRYPTO_ARC4: 493 return SYMMETRIC; 494 case CRYPTO_DH_SEND: 495 case CRYPTO_DH_RECEIVE: 496 case CRYPTO_RSA_ENCRYPT: 497 case CRYPTO_RSA_DECRYPT: 498 case CRYPTO_DSA_SIGN: 499 case CRYPTO_DSA_VERIFY: 500 return PUBLIC_KEY; 501 } 502 503 #ifdef DIAGNOSTIC 504 panic("crypto_check_alg: unknown algorithm %d", cri->cri_alg); 505 #endif 506 return -1; 507 } 508