kcf_mech_tabs.c revision 983a10335731bc55a0b7a37f195575fa109e30d4
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Cryptographic mechanisms tables and their access functions */
/*
* Internal numbers assigned to mechanisms are coded as follows:
*
* +----------------+----------------+
* | mech. class | mech. index |
* <--- 32-bits --->+<--- 32-bits --->
*
* the mech_class identifies the table the mechanism belongs to.
* mech_index is the index for that mechanism in the table.
* A mechanism belongs to exactly 1 table.
* The tables are:
* . digest_mechs_tab[] for the msg digest mechs.
* . mac_mechs_tab[] for MAC mechs.
* . sign_mechs_tab[] for sign & verify mechs.
* . misc_mechs_tab[] for mechs that don't belong to any of the above.
*
* There are no holes in the tables.
*/
/*
* Locking conventions:
* --------------------
* A global mutex, kcf_mech_tabs_lock, serializes writes to the
* mechanism table via kcf_create_mech_entry().
*
* A mutex is associated with every entry of the tables.
* The mutex is acquired whenever the entry is accessed for
* 1) retrieving the mech_id (comparing the mech name)
* 2) finding a provider for an xxx_init() or atomic operation.
* 3) altering the mechs entry to add or remove a provider.
*
* In 2), after a provider is chosen, its prov_desc is held and the
* entry's mutex must be dropped. The provider's working function (SPI) is
* called outside the mech_entry's mutex.
*
* The number of providers for a particular mechanism is not expected to be
* long enough to justify the cost of using rwlocks, so the per-mechanism
* entry mutex won't be very *hot*.
*
* When both kcf_mech_tabs_lock and a mech_entry mutex need to be held,
* kcf_mech_tabs_lock must always be acquired first.
*
*/
/* Mechanisms tables */
/* RFE 4687834 Will deal with the extensibility of these tables later */
{0, NULL}, /* No class zero */
};
/*
* Per-algorithm internal threasholds for the minimum input size of before
* offloading to hardware provider.
* Dispatching a crypto operation to a hardware provider entails paying the
* cost of an additional context switch. Measurments with Sun Accelerator 4000
* shows that 512-byte jobs or smaller are better handled in software.
* There is room for refinement here.
*
*/
int kcf_md5_threshold = 512;
int kcf_sha1_threshold = 512;
int kcf_des_threshold = 512;
int kcf_des3_threshold = 512;
int kcf_aes_threshold = 512;
int kcf_bf_threshold = 512;
int kcf_rc4_threshold = 512;
static uint32_t kcf_gen_swprov = 0;
int kcf_mech_hash_size = 256;
static crypto_mech_type_t
kcf_mech_hash_find(char *mechname)
{
}
return (mt);
}
/*
* kcf_init_mech_tabs()
*
* of mech_entry's.
*/
void
{
int i, max;
/* Initializes the mutex locks. */
/* Then the pre-defined mechanism entries */
/* Two digests */
/* The symmetric ciphers in various modes */
/* 5 HMACs */
/* 1 random number generation pseudo mechanism */
for (i = 0; i < max; i++) {
(void) mod_hash_insert(kcf_mech_hash,
}
}
}
}
/*
* kcf_create_mech_entry()
*
* Arguments:
* . The class of mechanism.
* . the name of the new mechanism.
*
* Description:
* Creates a new mech_entry for a mechanism not yet known to the
* framework.
* This routine is called by kcf_add_mech_provider, which is
* in turn invoked for each mechanism supported by a provider.
* The'class' argument depends on the crypto_func_group_t bitmask
* in the registering provider's mech_info struct for this mechanism.
* When there is ambiguity in the mapping between the crypto_func_group_t
* and a class (dual ops, ...) the KCF_MISC_CLASS should be used.
*
* Context:
* User context only.
*
* Returns:
* KCF_INVALID_MECH_CLASS or KCF_INVALID_MECH_NAME if the class or
* the mechname is bogus.
* KCF_MECH_TAB_FULL when there is no room left in the mech. tabs.
* KCF_SUCCESS otherwise.
*/
static int
{
int i = 0, size;
return (KCF_INVALID_MECH_CLASS);
return (KCF_INVALID_MECH_NAME);
/*
* First check if the mechanism is already in one of the tables.
* The mech_entry could be in another class.
*/
if (mt != CRYPTO_MECH_INVALID) {
/* Nothing to do, regardless the suggested class. */
return (KCF_SUCCESS);
}
/* Now take the next unused mech entry in the class's tab */
while (i < size) {
/* Found an empty spot */
/*
* No a-priori information about the new mechanism, so
* the threshold is set to zero.
*/
me_tab[i].me_threshold = 0;
/* Add the new mechanism to the hash table */
(void) mod_hash_insert(kcf_mech_hash,
break;
}
i++;
}
if (i == size) {
return (KCF_MECH_TAB_FULL);
}
return (KCF_SUCCESS);
}
/*
* kcf_add_mech_provider()
*
* Arguments:
* . An index in to the provider mechanism array
* . A pointer to the provider descriptor
* . A storage for the kcf_prov_mech_desc_t the entry was added at.
*
* Description:
* Adds a new provider of a mechanism to the mechanism's mech_entry
* chain.
*
* Context:
* User context only.
*
* Returns
* KCF_SUCCESS on success
* KCF_MECH_TAB_FULL otherwise.
*/
int
kcf_add_mech_provider(short mech_indx,
{
int error;
int i;
/*
* Do not use the provider for the mechanism if
* policy does not allow it.
*/
return (KCF_SUCCESS);
}
/*
* A mechanism belongs to exactly one mechanism table.
* Find the class corresponding to the function group flag of
* the mechanism.
*/
if (kcf_mech_type == CRYPTO_MECH_INVALID) {
fg & CRYPTO_FG_SIGN_ATOMIC ||
fg & CRYPTO_FG_SIGN_RECOVER ||
else if (fg & CRYPTO_FG_GENERATE ||
else
/*
* Attempt to create a new mech_entry for the specified
* mechanism. kcf_create_mech_entry() can handle the case
* where such an entry already exists.
*/
return (error);
}
/* get the KCF mech type that was assigned to the mechanism */
}
/* allocate and initialize new kcf_prov_mech_desc */
if (dual_fg_mask == ((crypto_func_group_t)0))
goto add_entry;
for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
/* skip self */
continue;
/* skip if policy doesn't allow mechanism */
continue;
/* skip if not a dual operation mechanism */
continue;
if (mt == CRYPTO_MECH_INVALID)
continue;
continue;
/*
* Ignore hard-coded entries in the mech table
* if the provider hasn't registered.
*/
continue;
}
/*
* Add other dual mechanisms that have registered
* with the framework to this mechanism's
* cross-reference list.
*/
/* add to head of list */
else
if (prov_mech2 == NULL) {
continue;
}
/*
* Update all other cross-reference lists by
* adding this new mechanism.
*/
while (prov_mech2 != NULL) {
/* struct assignment */
/* add to head of list */
break;
}
}
if (prov_mech2 == NULL)
}
/*
* Add new kcf_prov_mech_desc at the front of HW providers
* chain.
*/
switch (prov_desc->pd_prov_type) {
case CRYPTO_HW_PROVIDER:
break;
case CRYPTO_SW_PROVIDER:
/*
* There is already a SW provider for this mechanism.
* Since we allow only one SW provider per mechanism,
* report this condition.
*/
"\"%s\" will not be used for %s. The provider "
"\"%s\" will be used for this mechanism "
} else {
/*
* Set the provider as the software provider for
* this mechanism.
*/
/* We'll wrap around after 4 billion registrations! */
}
break;
}
return (KCF_SUCCESS);
}
/*
* kcf_remove_mech_provider()
*
* Arguments:
* . mech_name: the name of the mechanism.
* . prov_desc: The provider descriptor
*
* Description:
* Removes a provider from chain of provider descriptors.
* The provider is made unavailable to kernel consumers for the specified
* mechanism.
*
* Context:
* User context only.
*/
void
{
/* get the KCF mech type that was assigned to the mechanism */
/*
* Provider was not allowed for this mech due to policy or
* configuration.
*/
return;
}
/* get a ptr to the mech_entry that was created */
/*
* Provider was not allowed for this mech due to policy or
* configuration.
*/
return;
}
switch (prov_desc->pd_prov_type) {
case CRYPTO_HW_PROVIDER:
/* find the provider in the mech_entry chain */
}
/* entry not found, simply return */
return;
}
/* remove provider entry from mech_entry chain */
break;
case CRYPTO_SW_PROVIDER:
/* not the software provider for this mechanism */
return;
}
break;
}
/* Free the dual ops cross-reference lists */
&mech_entry) != KCF_SUCCESS) {
continue;
}
else
while (prov_chain != NULL) {
}
}
break;
}
}
}
/* free entry */
}
/*
* kcf_get_mech_entry()
*
* Arguments:
* . The framework mechanism type
* . Storage for the mechanism entry
*
* Description:
* Retrieves the mechanism entry for the mech.
*
* Context:
* User and interrupt contexts.
*
* Returns:
* KCF_MECHANISM_XXX appropriate error code.
* KCF_SUCCESS otherwise.
*/
int
{
int index;
/* the caller won't need to know it's an invalid class */
return (KCF_INVALID_MECH_NUMBER);
}
return (KCF_INVALID_MECH_NUMBER);
}
return (KCF_SUCCESS);
}
/*
* Returns TRUE if the provider is usable and the MOD_NOAUTOUNLOAD flag
* is set in the modctl structure.
*/
static boolean_t
{
if (KCF_IS_PROV_USABLE(pd)) {
}
}
}
return (ret);
}
/*
* Lookup the hash table for an entry that matches the mechname.
* If there are no hardware or software providers for the mechanism,
* but there is an unloaded software provider, this routine will attempt
* to load it.
*
* If the MOD_NOAUTOUNLOAD flag is not set, a software provider is
* in constant danger of being unloaded. For consumers that call
* crypto_mech2id() only once, the provider will not be reloaded
* if it becomes unloaded. If a provider gets loaded elsewhere
* without the MOD_NOAUTOUNLOAD flag being set, we set it now.
*/
{
int i;
return (mt);
if (mt != CRYPTO_MECH_INVALID) {
i = KCF_MECH2INDEX(mt);
}
}
char *module_name;
int module_name_size;
/* try to find a software provider for the mechanism */
!= CRYPTO_SUCCESS) {
/* mt may already be set for a hw provider */
return (mt);
}
/* mt may already be set for a hw provider */
return (mt);
}
/* memory pressure may have unloaded the module */
if (!mcp->mod_installed)
load_again = B_TRUE;
if (load_again)
/* mt may already be set for a hw provider */
if (mt != CRYPTO_MECH_INVALID)
return (mt);
/*
* Try again. Should find a software provider in the
* table this time around.
*/
goto try_again;
}
return (mt);
}