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