/* called from the CRYPTO_GET_DEV_LIST ioctl */ int crypto_get_dev_list(uint_t *count, crypto_dev_list_entry_t **array) { kcf_provider_desc_t **provider_array; kcf_provider_desc_t *pd; crypto_dev_list_entry_t *p; size_t skip_providers_size, mech_counts_size; char *skip_providers; uint_t provider_count; int rval, i, j, new_count, *mech_counts; /* * Take snapshot of provider table returning only hardware providers * that are in a usable state. Logical providers not included. */ rval = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP, NULL, 0, B_FALSE); if (rval != CRYPTO_SUCCESS) return (rval); if (provider_count == 0) { *array = NULL; *count = 0; return (CRYPTO_SUCCESS); } skip_providers_size = provider_count * sizeof (char); mech_counts_size = provider_count * sizeof (int); skip_providers = kmem_zalloc(skip_providers_size, KM_SLEEP); mech_counts = kmem_zalloc(mech_counts_size, KM_SLEEP); filter_providers(provider_count, provider_array, skip_providers, mech_counts, &new_count); p = kmem_alloc(new_count * sizeof (crypto_dev_list_entry_t), KM_SLEEP); for (i = 0, j = 0; i < provider_count; i++) { if (skip_providers[i] == 1) { ASSERT(mech_counts[i] == 0); continue; } pd = provider_array[i]; p[j].le_mechanism_count = mech_counts[i]; p[j].le_dev_instance = pd->pd_instance; (void) strncpy(p[j].le_dev_name, pd->pd_name, MAXNAMELEN); j++; } kcf_free_provider_tab(provider_count, provider_array); kmem_free(skip_providers, skip_providers_size); kmem_free(mech_counts, mech_counts_size); *array = p; *count = new_count; return (CRYPTO_SUCCESS); }
/* called from the CRYPTO_GET_DEV_INFO ioctl */ int crypto_get_dev_info(char *name, uint_t instance, uint_t *count, crypto_mech_name_t **array) { int rv; crypto_mech_name_t *mech_names; int i, j, k, all_count; uint_t provider_count; kcf_provider_desc_t **provider_array; kcf_provider_desc_t *pd; /* * Get provider table entries matching name and instance * for hardware providers that are in a usable state. * Logical providers not included. NULL name matches * all hardware providers. */ rv = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP, name, instance, B_FALSE); if (rv != CRYPTO_SUCCESS) return (rv); if (provider_count == 0) return (CRYPTO_ARGUMENTS_BAD); /* Get count */ all_count = 0; for (i = 0; i < provider_count; i++) all_count += provider_array[i]->pd_mech_list_count; if (all_count == 0) { mech_names = NULL; goto out; } /* Allocate space and copy mech names */ mech_names = kmem_alloc(all_count * sizeof (crypto_mech_name_t), KM_SLEEP); k = 0; for (i = 0; i < provider_count; i++) { pd = provider_array[i]; for (j = 0; j < pd->pd_mech_list_count; j++, k++) bcopy(&pd->pd_mechanisms[j].cm_mech_name[0], &mech_names[k][0], sizeof (crypto_mech_name_t)); } out: kcf_free_provider_tab(provider_count, provider_array); *count = all_count; *array = mech_names; return (CRYPTO_SUCCESS); }
/* * Called from CRYPTO_LOAD_DEV_DISABLED ioctl. * If new_count is 0, then completely remove the entry. */ int crypto_load_dev_disabled(char *name, uint_t instance, uint_t new_count, crypto_mech_name_t *new_array) { kcf_provider_desc_t *provider = NULL; kcf_provider_desc_t **provider_array; crypto_mech_name_t *prev_array; uint_t provider_count, prev_count; int i, rv = CRYPTO_SUCCESS; /* * Remove the policy entry if new_count is 0, otherwise put disabled * mechanisms into policy table. */ if (new_count == 0) { kcf_policy_remove_by_dev(name, instance, &prev_count, &prev_array); } else if ((rv = kcf_policy_load_dev_disabled(name, instance, new_count, new_array, &prev_count, &prev_array)) != CRYPTO_SUCCESS) { return (rv); } /* * Get provider table entries matching name and instance * for providers that are are in a usable or unverified state. */ rv = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP, name, instance, B_TRUE); if (rv != CRYPTO_SUCCESS) return (rv); for (i = 0; i < provider_count; i++) { provider = provider_array[i]; /* previously disabled mechanisms may become enabled */ if (prev_array != NULL) { kcf_compare_mechs(new_count, new_array, prev_count, prev_array); kcf_change_mechs(provider, prev_count, prev_array, CRYPTO_EVENT_CHANGE_ADDED); } kcf_change_mechs(provider, new_count, new_array, CRYPTO_EVENT_CHANGE_REMOVED); } kcf_free_provider_tab(provider_count, provider_array); crypto_free_mech_list(prev_array, prev_count); return (rv); }
/* * Returns an array of hardware provider descriptors. This routine * used by cryptoadm(1M). A REFHOLD is done on each descriptor before * the array is returned. The entire table can be freed by calling * kcf_free_provider_tab(). * * A NULL name argument puts all hardware providers in the array. * A non-NULL name argument puts only those providers in the array * which match the name and instance arguments. */ int kcf_get_hw_prov_tab(uint_t *count, kcf_provider_desc_t ***array, int kmflag, char *name, uint_t instance, boolean_t unverified) { kcf_provider_desc_t *prov_desc; kcf_provider_desc_t **p = NULL; char *last; uint_t cnt = 0; uint_t i, j; int rval = CRYPTO_SUCCESS; size_t n, final_size; /* count the providers */ mutex_enter(&prov_tab_mutex); for (i = 0; i < KCF_MAX_PROVIDERS; i++) { if ((prov_desc = prov_tab[i]) != NULL && prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) { if (KCF_IS_PROV_USABLE(prov_desc) || (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) { if (name == NULL || (strncmp(prov_desc->pd_name, name, MAXNAMELEN) == 0 && prov_desc->pd_instance == instance)) { cnt++; } } } } mutex_exit(&prov_tab_mutex); if (cnt == 0) goto out; n = cnt * sizeof (kcf_provider_desc_t *); again: p = kmem_zalloc(n, kmflag); if (p == NULL) { rval = CRYPTO_HOST_MEMORY; goto out; } /* pointer to last entry in the array */ last = (char *)&p[cnt-1]; mutex_enter(&prov_tab_mutex); for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) { if ((prov_desc = prov_tab[i]) != NULL && prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) { if (KCF_IS_PROV_USABLE(prov_desc) || (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) { if (name == NULL || (strncmp(prov_desc->pd_name, name, MAXNAMELEN) == 0 && prov_desc->pd_instance == instance)) { if ((char *)&p[j] > last) { mutex_exit(&prov_tab_mutex); kcf_free_provider_tab(cnt, p); n = n << 1; cnt = cnt << 1; goto again; } p[j++] = prov_desc; KCF_PROV_REFHOLD(prov_desc); } } } } mutex_exit(&prov_tab_mutex); final_size = j * sizeof (kcf_provider_desc_t *); ASSERT(final_size <= n); /* check if buffer we allocated is too large */ if (final_size < n) { char *final_buffer = NULL; if (final_size > 0) { final_buffer = kmem_alloc(final_size, kmflag); if (final_buffer == NULL) { kcf_free_provider_tab(cnt, p); cnt = 0; p = NULL; rval = CRYPTO_HOST_MEMORY; goto out; } bcopy(p, final_buffer, final_size); } kmem_free(p, n); p = (kcf_provider_desc_t **)final_buffer; } cnt = j; out: *count = cnt; *array = p; return (rval); }
/* * Returns an array of hardware and logical provider descriptors, * a.k.a the PKCS#11 slot list. A REFHOLD is done on each descriptor * before the array is returned. The entire table can be freed by * calling kcf_free_provider_tab(). */ int kcf_get_slot_list(uint_t *count, kcf_provider_desc_t ***array, boolean_t unverified) { kcf_provider_desc_t *prov_desc; kcf_provider_desc_t **p = NULL; char *last; uint_t cnt = 0; uint_t i, j; int rval = CRYPTO_SUCCESS; size_t n, final_size; /* count the providers */ mutex_enter(&prov_tab_mutex); for (i = 0; i < KCF_MAX_PROVIDERS; i++) { if ((prov_desc = prov_tab[i]) != NULL && ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER && (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) || prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) { if (KCF_IS_PROV_USABLE(prov_desc) || (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) { cnt++; } } } mutex_exit(&prov_tab_mutex); if (cnt == 0) goto out; n = cnt * sizeof (kcf_provider_desc_t *); again: p = kmem_zalloc(n, KM_SLEEP); /* pointer to last entry in the array */ last = (char *)&p[cnt-1]; mutex_enter(&prov_tab_mutex); /* fill the slot list */ for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) { if ((prov_desc = prov_tab[i]) != NULL && ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER && (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) || prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) { if (KCF_IS_PROV_USABLE(prov_desc) || (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) { if ((char *)&p[j] > last) { mutex_exit(&prov_tab_mutex); kcf_free_provider_tab(cnt, p); n = n << 1; cnt = cnt << 1; goto again; } p[j++] = prov_desc; KCF_PROV_REFHOLD(prov_desc); } } } mutex_exit(&prov_tab_mutex); final_size = j * sizeof (kcf_provider_desc_t *); cnt = j; ASSERT(final_size <= n); /* check if buffer we allocated is too large */ if (final_size < n) { char *final_buffer = NULL; if (final_size > 0) { final_buffer = kmem_alloc(final_size, KM_SLEEP); bcopy(p, final_buffer, final_size); } kmem_free(p, n); p = (kcf_provider_desc_t **)final_buffer; } out: *count = cnt; *array = p; return (rval); }