kcf_prov_tabs.c revision 034448fe565200cb042559f50fab6cf751f182c5
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file is part of the core Kernel Cryptographic Framework.
* It implements the management of tables of Providers. Entries to
* added and removed when cryptographic providers register with
* and unregister from the framework, respectively. The KCF scheduler
* and ioctl pseudo driver call this function to obtain the list
* of available providers.
*
* The provider table is indexed by crypto_provider_id_t. Each
* element of the table contains a pointer to a provider descriptor,
* or NULL if the entry is free.
*
* This file also implements helper functions to allocate and free
* provider descriptors.
*/
#if DEBUG
extern int kcf_frmwrk_debug;
static void kcf_prov_tab_dump(void);
#endif /* DEBUG */
/*
* Initialize the providers table. The providers table is dynamically
* allocated with prov_tab_max entries.
*/
void
kcf_prov_tab_init(void)
{
KM_SLEEP);
}
/*
* Add a provider to the provider table. If no free entry can be found
* for the new provider, returns CRYPTO_HOST_MEMORY. Otherwise, add
* the provider to the table, initialize the pd_prov_id field
* of the specified provider descriptor to the index in that table,
* and return CRYPTO_SUCCESS. Note that a REFHOLD is done on the
* provider when pointed to by a table entry.
*/
int
{
uint_t i;
/* find free slot in providers table */
if (i == KCF_MAX_PROVIDERS) {
/* ran out of providers entries */
return (CRYPTO_HOST_MEMORY);
}
/* initialize entry */
prov_tab_num++;
/* update provider descriptor */
prov_desc->pd_prov_id = i;
/*
* The KCF-private provider handle is defined as the internal
* provider id.
*/
#if DEBUG
if (kcf_frmwrk_debug >= 1)
#endif /* DEBUG */
return (CRYPTO_SUCCESS);
}
/*
* Remove the provider specified by its id. A REFRELE is done on the
* corresponding provider descriptor before this function returns.
* Returns CRYPTO_UNKNOWN_PROVIDER if the provider id is not valid.
*/
int
{
ASSERT(prov_tab_num >= 0);
/*
* Validate provider id, since it can be specified by a 3rd-party
* provider.
*/
if (prov_id >= KCF_MAX_PROVIDERS ||
return (CRYPTO_INVALID_PROVIDER_ID);
}
/*
* The provider id must remain valid until the associated provider
* descriptor is freed. For this reason, we simply release our
* reference to the descriptor here. When the reference count
* reaches zero, kcf_free_provider_desc() will be invoked and
* the associated entry in the providers table will be released
* at that time.
*/
#if DEBUG
if (kcf_frmwrk_debug >= 1)
#endif /* DEBUG */
return (CRYPTO_SUCCESS);
}
/*
* Returns the provider descriptor corresponding to the specified
* provider id. A REFHOLD is done on the descriptor before it is
* returned to the caller. It is the responsibility of the caller
* to do a REFRELE once it is done with the provider descriptor.
*/
{
return (NULL);
}
return (prov_desc);
}
static void
{
KM_SLEEP);
KM_SLEEP);
KM_SLEEP);
KM_SLEEP);
KM_SLEEP);
KM_SLEEP);
KM_SLEEP);
sizeof (crypto_dual_cipher_mac_ops_t), KM_SLEEP);
sizeof (crypto_random_number_ops_t), KM_SLEEP);
/*
* Allocate storage to store the array of supported mechanisms
* specified by provider. We allocate extra mechanism storage
* if the provider has random_ops since we keep an internal
* mechanism, SUN_RANDOM, in this case.
*/
(*mech_list_count)++;
}
KM_SLEEP);
KM_SLEEP);
KM_SLEEP);
sizeof (crypto_provider_management_ops_t), KM_SLEEP);
KM_SLEEP);
}
static void
{
KM_SLEEP);
}
static void
{
}
/*
* Allocate a provider descriptor. mech_list_count specifies the
* number of mechanisms supported by the providers, and is used
* to allocate storage for the mechanism table.
* This function may sleep while allocating memory, which is OK
* since it is invoked from user context during provider registration.
*/
{
int i, j;
/*
* pd_description serves two purposes
* - Appears as a blank padded PKCS#11 style string, that will be
* returned to applications in CK_SLOT_INFO.slotDescription.
* This means that we should not have a null character in the
* first CRYPTO_PROVIDER_DESCR_MAX_LEN bytes.
* - Appears as a null-terminated string that can be used by
* other kcf routines.
*
* So, we allocate enough room for one extra null terminator
* which keeps every one happy.
*/
KM_SLEEP);
/*
* Since the framework does not require the ops vector specified
* by the providers during registration to be persistent,
* KCF needs to allocate storage where copies of the ops
* vectors are copied.
*/
}
for (i = 0; i < KCF_OPS_CLASSSIZE; i++)
for (j = 0; j < KCF_MAXMECHTAB; j++)
return (desc);
}
/*
* Called by KCF_PROV_REFRELE when a provider's reference count drops
* to zero. We free the descriptor when the last reference is released.
* However, for software providers, we do not free it when there is an
* unregister thread waiting. We signal that thread in this case and
* that thread is responsible for freeing the descriptor.
*/
void
{
switch (desc->pd_prov_type) {
case CRYPTO_SW_PROVIDER:
break;
}
/* FALLTHRU */
case CRYPTO_HW_PROVIDER:
case CRYPTO_LOGICAL_PROVIDER:
}
}
/*
* Free a provider descriptor.
*/
void
{
return;
/* release the associated providers table entry */
prov_tab_num--;
}
/* free the kernel memory associated with the provider descriptor */
sizeof (crypto_control_ops_t));
sizeof (crypto_digest_ops_t));
sizeof (crypto_cipher_ops_t));
sizeof (crypto_mac_ops_t));
sizeof (crypto_sign_ops_t));
sizeof (crypto_verify_ops_t));
sizeof (crypto_dual_ops_t));
sizeof (crypto_dual_cipher_mac_ops_t));
sizeof (crypto_random_number_ops_t));
sizeof (crypto_session_ops_t));
sizeof (crypto_object_ops_t));
sizeof (crypto_key_ops_t));
sizeof (crypto_provider_management_ops_t));
sizeof (crypto_ctx_ops_t));
sizeof (crypto_mech_ops_t));
sizeof (crypto_nostore_key_ops_t));
}
/* free the memory associated with the mechanism info's */
}
}
/*
* Returns the provider descriptor corresponding to the specified
* module name. A REFHOLD is done on the descriptor before it is
* returned to the caller. It is the responsibility of the caller
* to do a REFRELE once it is done with the provider descriptor.
* Only software providers are returned by this function.
*/
{
uint_t i;
for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
(!KCF_IS_PROV_REMOVED(prov_desc)) &&
MAXNAMELEN) == 0) {
return (prov_desc);
}
}
}
return (NULL);
}
/*
* Returns the provider descriptor corresponding to the specified
* device name and instance. A REFHOLD is done on the descriptor
* before it is returned to the caller. It is the responsibility
* of the caller to do a REFRELE once it is done with the provider
* descriptor. Only hardware providers are returned by this function.
*/
{
uint_t i;
for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
(!KCF_IS_PROV_REMOVED(prov_desc)) &&
MAXNAMELEN) == 0 &&
return (prov_desc);
}
}
}
return (NULL);
}
/*
* 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_provider_desc_t **p = NULL;
char *last;
uint_t i, j;
int rval = CRYPTO_SUCCESS;
size_t n, final_size;
/* count the providers */
for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
if (KCF_IS_PROV_USABLE(prov_desc) ||
cnt++;
}
}
}
if (cnt == 0)
goto out;
n = cnt * sizeof (kcf_provider_desc_t *);
p = kmem_zalloc(n, KM_SLEEP);
/* pointer to last entry in the array */
/* fill the slot list */
for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) {
if (KCF_IS_PROV_USABLE(prov_desc) ||
if ((char *)&p[j] > last) {
kcf_free_provider_tab(cnt, p);
n = n << 1;
goto again;
}
p[j++] = prov_desc;
}
}
}
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) {
}
kmem_free(p, n);
p = (kcf_provider_desc_t **)final_buffer;
}
out:
*array = p;
return (rval);
}
/*
* 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_provider_desc_t **p = NULL;
char *last;
uint_t i, j;
int rval = CRYPTO_SUCCESS;
size_t n, final_size;
/* count the providers */
for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
if (KCF_IS_PROV_USABLE(prov_desc) ||
MAXNAMELEN) == 0 &&
cnt++;
}
}
}
}
if (cnt == 0)
goto out;
n = cnt * sizeof (kcf_provider_desc_t *);
p = kmem_zalloc(n, kmflag);
if (p == NULL) {
goto out;
}
/* pointer to last entry in the array */
for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) {
if (KCF_IS_PROV_USABLE(prov_desc) ||
MAXNAMELEN) == 0 &&
if ((char *)&p[j] > last) {
kcf_free_provider_tab(cnt, p);
n = n << 1;
goto again;
}
p[j++] = prov_desc;
}
}
}
}
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) {
if (final_buffer == NULL) {
kcf_free_provider_tab(cnt, p);
cnt = 0;
p = NULL;
goto out;
}
}
kmem_free(p, n);
p = (kcf_provider_desc_t **)final_buffer;
}
cnt = j;
out:
*array = p;
return (rval);
}
/*
* Free an array of hardware provider descriptors. A REFRELE
* is done on each descriptor before the table is freed.
*/
void
{
int i;
for (i = 0; i < count; i++) {
}
}
}
/*
* Returns in the location pointed to by pd a pointer to the descriptor
* for the software provider for the specified mechanism.
* The provider descriptor is returned held and it is the caller's
* responsibility to release it when done. The mechanism entry
* is returned if the optional argument mep is non NULL.
*
* Returns one of the CRYPTO_ * error codes on failure, and
* CRYPTO_SUCCESS on success.
*/
int
{
/* get the mechanism entry for this mechanism */
return (CRYPTO_MECHANISM_INVALID);
/*
* Get the software provider for this mechanism.
* Lock the mech_entry until we grab the 'pd'.
*/
/* no SW provider for this mechanism */
if (log_warn)
return (CRYPTO_MECH_NOT_SUPPORTED);
}
return (CRYPTO_SUCCESS);
}
#if DEBUG
static void
kcf_prov_tab_dump(void)
{
uint_t i;
printf("Providers table:\n");
for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
printf("[%d]: (%s) %s\n",
i, (prov_tab[i]->pd_prov_type ==
prov_tab[i]->pd_description);
}
}
printf("(end of providers table)\n");
}
#endif /* DEBUG */
/*
* This function goes through the provider table and verifies
* any unverified providers.
*
* This is called when kcfd is up and the door handle is ready.
*/
void
{
int i, rv;
for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
continue;
continue;
if (!need_verify)
continue;
/*
* We need to drop this lock, since it is
* acquired by crypto_unregister_provider().
* This is safe, as any providers that are
* added to the table after we dropped the
* lock *will see* a non NULL
* kcf_dh and hence would have been
* verified already.
*/
} else {
/*
* We are in the context of the kcfd thread doing
* the CRYPTO_LOAD_DOOR ioctl. So, we have a valid
* door handle and should not get -1 (unverified).
*/
}
}
}