1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Core KCF (Kernel Cryptographic Framework). This file implements 31 * the cryptoadm entry points. 32 */ 33 34 #include <sys/systm.h> 35 #include <sys/errno.h> 36 #include <sys/cmn_err.h> 37 #include <sys/rwlock.h> 38 #include <sys/kmem.h> 39 #include <sys/modctl.h> 40 #include <sys/sunddi.h> 41 #include <sys/door.h> 42 #include <sys/crypto/common.h> 43 #include <sys/crypto/api.h> 44 #include <sys/crypto/spi.h> 45 #include <sys/crypto/impl.h> 46 #include <sys/crypto/sched_impl.h> 47 48 /* protects the the soft_config_list. */ 49 kmutex_t soft_config_mutex; 50 51 /* 52 * This linked list contains software configuration entries that 53 * are loaded into the kernel by the CRYPTO_LOAD_SOFT_CONFIG ioctl. 54 * It is protected by the soft_config_mutex. 55 */ 56 kcf_soft_conf_entry_t *soft_config_list; 57 58 static int add_soft_config(char *, uint_t, crypto_mech_name_t *); 59 static int dup_mech_names(kcf_provider_desc_t *, crypto_mech_name_t **, 60 uint_t *, int); 61 static void free_soft_config_entry(kcf_soft_conf_entry_t *); 62 63 #define KCF_MAX_CONFIG_ENTRIES 512 /* maximum entries in soft_config_list */ 64 65 void 66 kcf_soft_config_init(void) 67 { 68 mutex_init(&soft_config_mutex, NULL, MUTEX_DRIVER, NULL); 69 } 70 71 72 /* 73 * Utility routine to identify the providers to filter out and 74 * present only one provider. This happens when a hardware provider 75 * registers multiple units of the same device instance. 76 */ 77 static void 78 filter_providers(uint_t count, kcf_provider_desc_t **provider_array, 79 char *skip_providers, int *mech_counts, int *new_count) 80 { 81 int i, j; 82 kcf_provider_desc_t *prov1, *prov2; 83 int n = 0; 84 85 for (i = 0; i < count; i++) { 86 if (skip_providers[i] == 1) 87 continue; 88 89 prov1 = provider_array[i]; 90 mech_counts[i] = prov1->pd_mech_list_count; 91 for (j = i + 1; j < count; j++) { 92 prov2 = provider_array[j]; 93 if (strncmp(prov1->pd_name, prov2->pd_name, 94 MAXNAMELEN) == 0 && 95 prov1->pd_instance == prov2->pd_instance) { 96 skip_providers[j] = 1; 97 mech_counts[i] += prov2->pd_mech_list_count; 98 } 99 } 100 n++; 101 } 102 103 *new_count = n; 104 } 105 106 107 /* called from the CRYPTO_GET_DEV_LIST ioctl */ 108 int 109 crypto_get_dev_list(uint_t *count, crypto_dev_list_entry_t **array) 110 { 111 kcf_provider_desc_t **provider_array; 112 kcf_provider_desc_t *pd; 113 crypto_dev_list_entry_t *p; 114 size_t skip_providers_size, mech_counts_size; 115 char *skip_providers; 116 uint_t provider_count; 117 int rval, i, j, new_count, *mech_counts; 118 119 /* 120 * Take snapshot of provider table returning only hardware providers 121 * that are in a usable state. Logical providers not included. 122 */ 123 rval = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP, 124 NULL, 0, B_FALSE); 125 if (rval != CRYPTO_SUCCESS) 126 return (rval); 127 128 if (provider_count == 0) { 129 *array = NULL; 130 *count = 0; 131 return (CRYPTO_SUCCESS); 132 } 133 134 skip_providers_size = provider_count * sizeof (char); 135 mech_counts_size = provider_count * sizeof (int); 136 137 skip_providers = kmem_zalloc(skip_providers_size, KM_SLEEP); 138 mech_counts = kmem_zalloc(mech_counts_size, KM_SLEEP); 139 filter_providers(provider_count, provider_array, skip_providers, 140 mech_counts, &new_count); 141 142 p = kmem_alloc(new_count * sizeof (crypto_dev_list_entry_t), KM_SLEEP); 143 for (i = 0, j = 0; i < provider_count; i++) { 144 if (skip_providers[i] == 1) { 145 ASSERT(mech_counts[i] == 0); 146 continue; 147 } 148 pd = provider_array[i]; 149 p[j].le_mechanism_count = mech_counts[i]; 150 p[j].le_dev_instance = pd->pd_instance; 151 (void) strncpy(p[j].le_dev_name, pd->pd_name, MAXNAMELEN); 152 j++; 153 } 154 155 kcf_free_provider_tab(provider_count, provider_array); 156 kmem_free(skip_providers, skip_providers_size); 157 kmem_free(mech_counts, mech_counts_size); 158 159 *array = p; 160 *count = new_count; 161 return (CRYPTO_SUCCESS); 162 } 163 164 /* 165 * Called from the CRYPTO_GET_SOFT_LIST ioctl, this routine returns 166 * a buffer containing the null terminated names of software providers 167 * loaded by CRYPTO_LOAD_SOFT_CONFIG. 168 */ 169 int 170 crypto_get_soft_list(uint_t *count, char **array, size_t *len) 171 { 172 char *names = NULL, *namep, *end; 173 kcf_soft_conf_entry_t *p; 174 uint_t n = 0, cnt = 0, final_count = 0; 175 size_t name_len, final_size = 0; 176 177 /* first estimate */ 178 mutex_enter(&soft_config_mutex); 179 for (p = soft_config_list; p != NULL; p = p->ce_next) { 180 n += strlen(p->ce_name) + 1; 181 cnt++; 182 } 183 mutex_exit(&soft_config_mutex); 184 185 if (cnt == 0) 186 goto out; 187 188 again: 189 namep = names = kmem_alloc(n, KM_SLEEP); 190 end = names + n; 191 final_size = 0; 192 final_count = 0; 193 194 mutex_enter(&soft_config_mutex); 195 for (p = soft_config_list; p != NULL; p = p->ce_next) { 196 name_len = strlen(p->ce_name) + 1; 197 /* check for enough space */ 198 if ((namep + name_len) > end) { 199 mutex_exit(&soft_config_mutex); 200 kmem_free(names, n); 201 n = n << 1; 202 goto again; 203 } 204 (void) strcpy(namep, p->ce_name); 205 namep += name_len; 206 final_size += name_len; 207 final_count++; 208 } 209 mutex_exit(&soft_config_mutex); 210 211 ASSERT(final_size <= n); 212 213 /* check if buffer we allocated is too large */ 214 if (final_size < n) { 215 char *final_buffer; 216 217 final_buffer = kmem_alloc(final_size, KM_SLEEP); 218 bcopy(names, final_buffer, final_size); 219 kmem_free(names, n); 220 names = final_buffer; 221 } 222 out: 223 *array = names; 224 *count = final_count; 225 *len = final_size; 226 return (CRYPTO_SUCCESS); 227 } 228 229 /* called from the CRYPTO_GET_DEV_INFO ioctl */ 230 int 231 crypto_get_dev_info(char *name, uint_t instance, uint_t *count, 232 crypto_mech_name_t **array) 233 { 234 int rv; 235 crypto_mech_name_t *mech_names; 236 int i, j, k, all_count; 237 uint_t provider_count; 238 kcf_provider_desc_t **provider_array; 239 kcf_provider_desc_t *pd; 240 241 /* 242 * Get provider table entries matching name and instance 243 * for hardware providers that are in a usable state. 244 * Logical providers not included. NULL name matches 245 * all hardware providers. 246 */ 247 rv = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP, 248 name, instance, B_FALSE); 249 if (rv != CRYPTO_SUCCESS) 250 return (rv); 251 252 if (provider_count == 0) 253 return (CRYPTO_ARGUMENTS_BAD); 254 255 /* Get count */ 256 all_count = 0; 257 for (i = 0; i < provider_count; i++) 258 all_count += provider_array[i]->pd_mech_list_count; 259 260 if (all_count == 0) { 261 mech_names = NULL; 262 goto out; 263 } 264 265 /* Allocate space and copy mech names */ 266 mech_names = kmem_alloc(all_count * sizeof (crypto_mech_name_t), 267 KM_SLEEP); 268 269 k = 0; 270 for (i = 0; i < provider_count; i++) { 271 pd = provider_array[i]; 272 for (j = 0; j < pd->pd_mech_list_count; j++, k++) 273 bcopy(&pd->pd_mechanisms[j].cm_mech_name[0], 274 &mech_names[k][0], sizeof (crypto_mech_name_t)); 275 } 276 277 out: 278 kcf_free_provider_tab(provider_count, provider_array); 279 *count = all_count; 280 *array = mech_names; 281 282 return (CRYPTO_SUCCESS); 283 } 284 285 /* called from the CRYPTO_GET_SOFT_INFO ioctl */ 286 int 287 crypto_get_soft_info(caddr_t name, uint_t *count, crypto_mech_name_t **array) 288 { 289 ddi_modhandle_t modh = NULL; 290 kcf_provider_desc_t *provider; 291 int rv; 292 293 provider = kcf_prov_tab_lookup_by_name(name); 294 if (provider == NULL) { 295 if (in_soft_config_list(name)) { 296 char *tmp; 297 int name_len; 298 299 /* strlen("crypto/") + NULL terminator == 8 */ 300 name_len = strlen(name); 301 tmp = kmem_alloc(name_len + 8, KM_SLEEP); 302 bcopy("crypto/", tmp, 7); 303 bcopy(name, &tmp[7], name_len); 304 tmp[name_len + 7] = '\0'; 305 306 modh = ddi_modopen(tmp, KRTLD_MODE_FIRST, NULL); 307 kmem_free(tmp, name_len + 8); 308 309 if (modh == NULL) { 310 return (CRYPTO_ARGUMENTS_BAD); 311 } 312 313 provider = kcf_prov_tab_lookup_by_name(name); 314 if (provider == NULL) { 315 return (CRYPTO_ARGUMENTS_BAD); 316 } 317 } else { 318 return (CRYPTO_ARGUMENTS_BAD); 319 } 320 } 321 322 rv = dup_mech_names(provider, array, count, KM_SLEEP); 323 KCF_PROV_REFRELE(provider); 324 if (modh != NULL) 325 (void) ddi_modclose(modh); 326 return (rv); 327 } 328 329 static void 330 kcf_change_mechs(kcf_provider_desc_t *provider, uint_t count, 331 crypto_mech_name_t *array, crypto_event_change_t direction) 332 { 333 crypto_notify_event_change_t ec; 334 crypto_mech_info_t *mi; 335 kcf_prov_mech_desc_t *pmd; 336 char *mech; 337 int i, j, n; 338 339 ASSERT(direction == CRYPTO_EVENT_CHANGE_ADDED || 340 direction == CRYPTO_EVENT_CHANGE_REMOVED); 341 342 if (provider == NULL) { 343 /* 344 * Nothing to add or remove from the tables since 345 * the provider isn't registered. 346 */ 347 return; 348 } 349 350 for (i = 0; i < count; i++) { 351 if (array[i][0] == '\0') 352 continue; 353 354 mech = &array[i][0]; 355 356 n = provider->pd_mech_list_count; 357 for (j = 0; j < n; j++) { 358 mi = &provider->pd_mechanisms[j]; 359 if (strncmp(mi->cm_mech_name, mech, 360 CRYPTO_MAX_MECH_NAME) == 0) 361 break; 362 } 363 if (j == n) 364 continue; 365 366 switch (direction) { 367 case CRYPTO_EVENT_CHANGE_ADDED: 368 (void) kcf_add_mech_provider(mi, provider, &pmd); 369 break; 370 371 case CRYPTO_EVENT_CHANGE_REMOVED: 372 kcf_remove_mech_provider(mech, provider); 373 break; 374 } 375 376 /* Inform interested clients of the event */ 377 ec.ec_provider_type = provider->pd_prov_type; 378 ec.ec_change = direction; 379 380 (void) strncpy(ec.ec_mech_name, mech, CRYPTO_MAX_MECH_NAME); 381 kcf_walk_ntfylist(CRYPTO_EVENT_PROVIDERS_CHANGE, &ec); 382 } 383 } 384 385 /* 386 * If a mech name in the second array (prev_array) is also in the 387 * first array, then a NULL character is written into the first byte 388 * of the mech name in the second array. This effectively removes 389 * the mech name from the second array. 390 */ 391 static void 392 kcf_compare_mechs(uint_t count, crypto_mech_name_t *array, uint_t prev_count, 393 crypto_mech_name_t *prev_array) 394 { 395 int i, j; 396 397 for (i = 0; i < prev_count; i++) { 398 for (j = 0; j < count; j++) { 399 if (strncmp(&prev_array[i][0], &array[j][0], 400 CRYPTO_MAX_MECH_NAME) == 0) { 401 prev_array[i][0] = '\0'; 402 } 403 } 404 } 405 } 406 407 /* 408 * Called from CRYPTO_LOAD_DEV_DISABLED ioctl. 409 * If new_count is 0, then completely remove the entry. 410 */ 411 int 412 crypto_load_dev_disabled(char *name, uint_t instance, uint_t new_count, 413 crypto_mech_name_t *new_array) 414 { 415 kcf_provider_desc_t *provider = NULL; 416 kcf_provider_desc_t **provider_array; 417 crypto_mech_name_t *prev_array; 418 uint_t provider_count, prev_count; 419 int i, rv = CRYPTO_SUCCESS; 420 421 /* 422 * Remove the policy entry if new_count is 0, otherwise put disabled 423 * mechanisms into policy table. 424 */ 425 if (new_count == 0) { 426 kcf_policy_remove_by_dev(name, instance, &prev_count, 427 &prev_array); 428 } else if ((rv = kcf_policy_load_dev_disabled(name, instance, new_count, 429 new_array, &prev_count, &prev_array)) != CRYPTO_SUCCESS) { 430 return (rv); 431 } 432 433 /* 434 * Get provider table entries matching name and instance 435 * for providers that are are in a usable or unverified state. 436 */ 437 rv = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP, 438 name, instance, B_TRUE); 439 if (rv != CRYPTO_SUCCESS) 440 return (rv); 441 442 for (i = 0; i < provider_count; i++) { 443 provider = provider_array[i]; 444 445 /* previously disabled mechanisms may become enabled */ 446 if (prev_array != NULL) { 447 kcf_compare_mechs(new_count, new_array, 448 prev_count, prev_array); 449 kcf_change_mechs(provider, prev_count, prev_array, 450 CRYPTO_EVENT_CHANGE_ADDED); 451 } 452 453 kcf_change_mechs(provider, new_count, new_array, 454 CRYPTO_EVENT_CHANGE_REMOVED); 455 } 456 457 kcf_free_provider_tab(provider_count, provider_array); 458 crypto_free_mech_list(prev_array, prev_count); 459 return (rv); 460 } 461 462 /* 463 * Called from CRYPTO_LOAD_SOFT_DISABLED ioctl. 464 * If new_count is 0, then completely remove the entry. 465 */ 466 int 467 crypto_load_soft_disabled(char *name, uint_t new_count, 468 crypto_mech_name_t *new_array) 469 { 470 kcf_provider_desc_t *provider = NULL; 471 crypto_mech_name_t *prev_array; 472 uint_t prev_count = 0; 473 int rv; 474 475 provider = kcf_prov_tab_lookup_by_name(name); 476 if (provider != NULL) { 477 mutex_enter(&provider->pd_lock); 478 /* 479 * Check if any other thread is disabling or removing 480 * this provider. We return if this is the case. 481 */ 482 if (provider->pd_state >= KCF_PROV_DISABLED) { 483 mutex_exit(&provider->pd_lock); 484 KCF_PROV_REFRELE(provider); 485 return (CRYPTO_BUSY); 486 } 487 provider->pd_state = KCF_PROV_DISABLED; 488 mutex_exit(&provider->pd_lock); 489 490 undo_register_provider(provider, B_TRUE); 491 KCF_PROV_REFRELE(provider); 492 if (provider->pd_kstat != NULL) 493 KCF_PROV_REFRELE(provider); 494 495 mutex_enter(&provider->pd_lock); 496 /* Wait till the existing requests complete. */ 497 while (provider->pd_state != KCF_PROV_FREED) { 498 cv_wait(&provider->pd_remove_cv, &provider->pd_lock); 499 } 500 mutex_exit(&provider->pd_lock); 501 } 502 503 if (new_count == 0) { 504 kcf_policy_remove_by_name(name, &prev_count, &prev_array); 505 crypto_free_mech_list(prev_array, prev_count); 506 rv = CRYPTO_SUCCESS; 507 goto out; 508 } 509 510 /* put disabled mechanisms into policy table */ 511 if ((rv = kcf_policy_load_soft_disabled(name, new_count, new_array, 512 &prev_count, &prev_array)) == CRYPTO_SUCCESS) { 513 crypto_free_mech_list(prev_array, prev_count); 514 } 515 516 out: 517 if (provider != NULL) { 518 redo_register_provider(provider); 519 if (provider->pd_kstat != NULL) 520 KCF_PROV_REFHOLD(provider); 521 mutex_enter(&provider->pd_lock); 522 provider->pd_state = KCF_PROV_READY; 523 mutex_exit(&provider->pd_lock); 524 } else if (rv == CRYPTO_SUCCESS) { 525 /* 526 * There are some cases where it is useful to kCF clients 527 * to have a provider whose mechanism is enabled now to be 528 * available. So, we attempt to load it here. 529 * 530 * The check, new_count < prev_count, ensures that we do this 531 * only in the case where a mechanism(s) is now enabled. 532 * This check assumes that enable and disable are separate 533 * administrative actions and are not done in a single action. 534 */ 535 if (new_count < prev_count && (in_soft_config_list(name)) && 536 (modload("crypto", name) != -1)) { 537 struct modctl *mcp; 538 boolean_t load_again = B_FALSE; 539 540 if ((mcp = mod_hold_by_name(name)) != NULL) { 541 mcp->mod_loadflags |= MOD_NOAUTOUNLOAD; 542 543 /* memory pressure may have unloaded module */ 544 if (!mcp->mod_installed) 545 load_again = B_TRUE; 546 mod_release_mod(mcp); 547 548 if (load_again) 549 (void) modload("crypto", name); 550 } 551 } 552 } 553 554 return (rv); 555 } 556 557 /* called from the CRYPTO_LOAD_SOFT_CONFIG ioctl */ 558 int 559 crypto_load_soft_config(caddr_t name, uint_t count, crypto_mech_name_t *array) 560 { 561 return (add_soft_config(name, count, array)); 562 } 563 564 /* called from the CRYPTO_UNLOAD_SOFT_MODULE ioctl */ 565 int 566 crypto_unload_soft_module(caddr_t name) 567 { 568 int error; 569 modid_t id; 570 kcf_provider_desc_t *provider; 571 struct modctl *mcp; 572 573 /* verify that 'name' refers to a registered crypto provider */ 574 if ((provider = kcf_prov_tab_lookup_by_name(name)) == NULL) 575 return (CRYPTO_UNKNOWN_PROVIDER); 576 577 /* 578 * We save the module id and release the reference. We need to 579 * do this as modunload() calls unregister which waits for the 580 * refcnt to drop to zero. 581 */ 582 id = provider->pd_module_id; 583 KCF_PROV_REFRELE(provider); 584 585 if ((mcp = mod_hold_by_name(name)) != NULL) { 586 mcp->mod_loadflags &= ~(MOD_NOAUTOUNLOAD); 587 mod_release_mod(mcp); 588 } 589 590 if ((error = modunload(id)) != 0) { 591 return (error == EBUSY ? CRYPTO_BUSY : CRYPTO_FAILED); 592 } 593 594 return (CRYPTO_SUCCESS); 595 } 596 597 /* called from CRYPTO_GET_DEV_LIST ioctl */ 598 void 599 crypto_free_dev_list(crypto_dev_list_entry_t *array, uint_t count) 600 { 601 if (count == 0 || array == NULL) 602 return; 603 604 kmem_free(array, count * sizeof (crypto_dev_list_entry_t)); 605 } 606 607 /* 608 * Returns duplicate array of mechanisms. The array is allocated and 609 * must be freed by the caller. 610 */ 611 static int 612 dup_mech_names(kcf_provider_desc_t *provider, crypto_mech_name_t **array, 613 uint_t *count, int kmflag) 614 { 615 crypto_mech_name_t *mech_names; 616 uint_t n; 617 uint_t i; 618 619 if ((n = provider->pd_mech_list_count) == 0) { 620 *count = 0; 621 *array = NULL; 622 return (CRYPTO_SUCCESS); 623 } 624 625 mech_names = kmem_alloc(n * sizeof (crypto_mech_name_t), kmflag); 626 if (mech_names == NULL) 627 return (CRYPTO_HOST_MEMORY); 628 629 for (i = 0; i < n; i++) { 630 bcopy(&provider->pd_mechanisms[i].cm_mech_name[0], 631 &mech_names[i][0], sizeof (crypto_mech_name_t)); 632 } 633 634 *count = n; 635 *array = mech_names; 636 return (CRYPTO_SUCCESS); 637 } 638 639 /* 640 * Returns B_TRUE if the specified mechanism is disabled, B_FALSE otherwise. 641 */ 642 boolean_t 643 is_mech_disabled_byname(crypto_provider_type_t prov_type, char *pd_name, 644 uint_t pd_instance, crypto_mech_name_t mech_name) 645 { 646 kcf_policy_desc_t *policy; 647 uint_t i; 648 649 ASSERT(prov_type == CRYPTO_SW_PROVIDER || 650 prov_type == CRYPTO_HW_PROVIDER); 651 652 switch (prov_type) { 653 case CRYPTO_SW_PROVIDER: 654 policy = kcf_policy_lookup_by_name(pd_name); 655 /* no policy for provider - so mechanism can't be disabled */ 656 if (policy == NULL) 657 return (B_FALSE); 658 break; 659 660 case CRYPTO_HW_PROVIDER: 661 policy = kcf_policy_lookup_by_dev(pd_name, pd_instance); 662 /* no policy for provider - so mechanism can't be disabled */ 663 if (policy == NULL) 664 return (B_FALSE); 665 break; 666 } 667 668 mutex_enter(&policy->pd_mutex); 669 for (i = 0; i < policy->pd_disabled_count; i ++) { 670 if (strncmp(mech_name, &policy->pd_disabled_mechs[i][0], 671 CRYPTO_MAX_MECH_NAME) == 0) { 672 mutex_exit(&policy->pd_mutex); 673 KCF_POLICY_REFRELE(policy); 674 return (B_TRUE); 675 } 676 } 677 mutex_exit(&policy->pd_mutex); 678 KCF_POLICY_REFRELE(policy); 679 return (B_FALSE); 680 } 681 682 /* 683 * Returns B_TRUE if the specified mechanism is disabled, B_FALSE otherwise. 684 * 685 * This is a wrapper routine around is_mech_disabled_byname() above and 686 * takes a pointer kcf_provider_desc structure as argument. 687 */ 688 boolean_t 689 is_mech_disabled(kcf_provider_desc_t *provider, crypto_mech_name_t name) 690 { 691 kcf_provider_list_t *e; 692 kcf_provider_desc_t *pd; 693 boolean_t found = B_FALSE; 694 uint_t count, i; 695 696 if (provider->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) { 697 return (is_mech_disabled_byname(provider->pd_prov_type, 698 provider->pd_name, provider->pd_instance, name)); 699 } 700 701 /* 702 * Lock the logical provider just in case one of its hardware 703 * provider members unregisters. 704 */ 705 mutex_enter(&provider->pd_lock); 706 for (e = provider->pd_provider_list; e != NULL; e = e->pl_next) { 707 708 pd = e->pl_provider; 709 ASSERT(pd->pd_prov_type == CRYPTO_HW_PROVIDER); 710 711 /* find out if mechanism is offered by hw provider */ 712 count = pd->pd_mech_list_count; 713 for (i = 0; i < count; i++) { 714 if (strncmp(&pd->pd_mechanisms[i].cm_mech_name[0], 715 name, MAXNAMELEN) == 0) { 716 break; 717 } 718 } 719 if (i == count) 720 continue; 721 722 found = !is_mech_disabled_byname(pd->pd_prov_type, 723 pd->pd_name, pd->pd_instance, name); 724 725 if (found) 726 break; 727 } 728 mutex_exit(&provider->pd_lock); 729 /* 730 * If we found the mechanism, then it means it is still enabled for 731 * at least one hardware provider, so the mech can't be disabled 732 * for the logical provider. 733 */ 734 return (!found); 735 } 736 737 /* 738 * Builds array of permitted mechanisms. The array is allocated and 739 * must be freed by the caller. 740 */ 741 int 742 crypto_build_permitted_mech_names(kcf_provider_desc_t *provider, 743 crypto_mech_name_t **array, uint_t *count, int kmflag) 744 { 745 crypto_mech_name_t *mech_names, *p; 746 uint_t i; 747 uint_t scnt = provider->pd_mech_list_count; 748 uint_t dcnt = 0; 749 750 /* 751 * Compute number of 'permitted mechanisms', which is 752 * 'supported mechanisms' - 'disabled mechanisms'. 753 */ 754 for (i = 0; i < scnt; i++) { 755 if (is_mech_disabled(provider, 756 &provider->pd_mechanisms[i].cm_mech_name[0])) { 757 dcnt++; 758 } 759 } 760 761 /* all supported mechanisms have been disabled */ 762 if (scnt == dcnt) { 763 *count = 0; 764 *array = NULL; 765 return (CRYPTO_SUCCESS); 766 } 767 768 mech_names = kmem_alloc((scnt - dcnt) * sizeof (crypto_mech_name_t), 769 kmflag); 770 if (mech_names == NULL) 771 return (CRYPTO_HOST_MEMORY); 772 773 /* build array of permitted mechanisms */ 774 for (i = 0, p = mech_names; i < scnt; i++) { 775 if (!is_mech_disabled(provider, 776 &provider->pd_mechanisms[i].cm_mech_name[0])) { 777 bcopy(&provider->pd_mechanisms[i].cm_mech_name[0], 778 p++, sizeof (crypto_mech_name_t)); 779 } 780 } 781 782 *count = scnt - dcnt; 783 *array = mech_names; 784 return (CRYPTO_SUCCESS); 785 } 786 787 static void 788 free_soft_config_entry(kcf_soft_conf_entry_t *p) 789 { 790 kmem_free(p->ce_name, strlen(p->ce_name) + 1); 791 crypto_free_mech_list(p->ce_mechs, p->ce_count); 792 kmem_free(p, sizeof (kcf_soft_conf_entry_t)); 793 } 794 795 /* 796 * Called from the CRYPTO_LOAD_SOFT_CONFIG ioctl, this routine stores 797 * configuration information for software providers in a linked list. 798 * If the list already contains an entry for the specified provider 799 * and the specified mechanism list has at least one mechanism, then 800 * the mechanism list for the provider is updated. If the mechanism list 801 * is empty, the entry for the provider is removed. 802 * 803 * Important note: the array argument is consumed. 804 */ 805 static int 806 add_soft_config(char *name, uint_t count, crypto_mech_name_t *array) 807 { 808 static uint_t soft_config_count = 0; 809 kcf_soft_conf_entry_t *prev = NULL, *entry = NULL, *new_entry, *p; 810 size_t name_len; 811 812 /* 813 * Allocate storage for a new entry. 814 * Free later if an entry already exists. 815 */ 816 name_len = strlen(name) + 1; 817 new_entry = kmem_zalloc(sizeof (kcf_soft_conf_entry_t), KM_SLEEP); 818 new_entry->ce_name = kmem_alloc(name_len, KM_SLEEP); 819 (void) strcpy(new_entry->ce_name, name); 820 821 mutex_enter(&soft_config_mutex); 822 p = soft_config_list; 823 if (p != NULL) { 824 do { 825 if (strncmp(name, p->ce_name, MAXNAMELEN) == 0) { 826 entry = p; 827 break; 828 } 829 prev = p; 830 831 } while ((p = p->ce_next) != NULL); 832 } 833 834 if (entry == NULL) { 835 if (count == 0) { 836 mutex_exit(&soft_config_mutex); 837 kmem_free(new_entry->ce_name, name_len); 838 kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t)); 839 return (CRYPTO_SUCCESS); 840 } 841 842 if (soft_config_count > KCF_MAX_CONFIG_ENTRIES) { 843 mutex_exit(&soft_config_mutex); 844 kmem_free(new_entry->ce_name, name_len); 845 kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t)); 846 cmn_err(CE_WARN, "out of soft_config_list entries"); 847 return (CRYPTO_FAILED); 848 } 849 850 /* add to head of list */ 851 new_entry->ce_next = soft_config_list; 852 soft_config_list = new_entry; 853 soft_config_count++; 854 entry = new_entry; 855 } else { 856 kmem_free(new_entry->ce_name, name_len); 857 kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t)); 858 } 859 860 /* mechanism count == 0 means remove entry from list */ 861 if (count == 0) { 862 if (prev == NULL) { 863 /* remove first in list */ 864 soft_config_list = entry->ce_next; 865 } else { 866 prev->ce_next = entry->ce_next; 867 } 868 soft_config_count--; 869 mutex_exit(&soft_config_mutex); 870 871 /* free entry */ 872 free_soft_config_entry(entry); 873 874 return (CRYPTO_SUCCESS); 875 } 876 877 878 /* replace mechanisms */ 879 if (entry->ce_mechs != NULL) 880 crypto_free_mech_list(entry->ce_mechs, entry->ce_count); 881 882 entry->ce_mechs = array; 883 entry->ce_count = count; 884 mutex_exit(&soft_config_mutex); 885 886 return (CRYPTO_SUCCESS); 887 } 888 889 /* 890 * This routine searches the soft_config_list for the first entry that 891 * has the specified mechanism in its mechanism list. If found, 892 * a buffer containing the name of the software module that implements 893 * the mechanism is allocated and stored in 'name'. 894 */ 895 int 896 get_sw_provider_for_mech(crypto_mech_name_t mech, char **name) 897 { 898 kcf_soft_conf_entry_t *p, *next; 899 char tmp_name[MAXNAMELEN]; 900 size_t name_len = 0; 901 int i; 902 903 mutex_enter(&soft_config_mutex); 904 p = soft_config_list; 905 while (p != NULL) { 906 next = p->ce_next; 907 for (i = 0; i < p->ce_count; i++) { 908 if (strcmp(mech, &p->ce_mechs[i][0]) == 0) { 909 name_len = strlen(p->ce_name) + 1; 910 bcopy(p->ce_name, tmp_name, name_len); 911 break; 912 } 913 } 914 p = next; 915 } 916 mutex_exit(&soft_config_mutex); 917 918 if (name_len == 0) 919 return (CRYPTO_FAILED); 920 921 *name = kmem_alloc(name_len, KM_SLEEP); 922 bcopy(tmp_name, *name, name_len); 923 return (CRYPTO_SUCCESS); 924 } 925 926 /* 927 * This routine searches the soft_config_list for the specified 928 * software provider, returning B_TRUE if it is in the list. 929 */ 930 boolean_t 931 in_soft_config_list(char *provider_name) 932 { 933 kcf_soft_conf_entry_t *p; 934 boolean_t rv = B_FALSE; 935 936 mutex_enter(&soft_config_mutex); 937 for (p = soft_config_list; p != NULL; p = p->ce_next) { 938 if (strcmp(provider_name, p->ce_name) == 0) { 939 rv = B_TRUE; 940 break; 941 } 942 } 943 mutex_exit(&soft_config_mutex); 944 return (rv); 945 } 946