mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 18:40:43 +03:00
Illumos Crypto Port module added to enable native encryption in zfs
A port of the Illumos Crypto Framework to a Linux kernel module (found in module/icp). This is needed to do the actual encryption work. We cannot use the Linux kernel's built in crypto api because it is only exported to GPL-licensed modules. Having the ICP also means the crypto code can run on any of the other kernels under OpenZFS. I ended up porting over most of the internals of the framework, which means that porting over other API calls (if we need them) should be fairly easy. Specifically, I have ported over the API functions related to encryption, digests, macs, and crypto templates. The ICP is able to use assembly-accelerated encryption on amd64 machines and AES-NI instructions on Intel chips that support it. There are place-holder directories for similar assembly optimizations for other architectures (although they have not been written). Signed-off-by: Tom Caputi <tcaputi@datto.com> Signed-off-by: Tony Hutter <hutter2@llnl.gov> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Issue #4329
This commit is contained in:
committed by
Brian Behlendorf
parent
be88e733a6
commit
0b04990a5d
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* 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
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* 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 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/api.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/modhash.h>
|
||||
|
||||
/* 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.
|
||||
* . cipher_mechs_tab[] for encrypt/decrypt and wrap/unwrap mechs.
|
||||
* . mac_mechs_tab[] for MAC mechs.
|
||||
* . sign_mechs_tab[] for sign & verify mechs.
|
||||
* . keyops_mechs_tab[] for key/key pair generation, and key derivation.
|
||||
* . 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 */
|
||||
|
||||
kcf_mech_entry_t kcf_digest_mechs_tab[KCF_MAXDIGEST];
|
||||
kcf_mech_entry_t kcf_cipher_mechs_tab[KCF_MAXCIPHER];
|
||||
kcf_mech_entry_t kcf_mac_mechs_tab[KCF_MAXMAC];
|
||||
kcf_mech_entry_t kcf_sign_mechs_tab[KCF_MAXSIGN];
|
||||
kcf_mech_entry_t kcf_keyops_mechs_tab[KCF_MAXKEYOPS];
|
||||
kcf_mech_entry_t kcf_misc_mechs_tab[KCF_MAXMISC];
|
||||
|
||||
kcf_mech_entry_tab_t kcf_mech_tabs_tab[KCF_LAST_OPSCLASS + 1] = {
|
||||
{0, NULL}, /* No class zero */
|
||||
{KCF_MAXDIGEST, kcf_digest_mechs_tab},
|
||||
{KCF_MAXCIPHER, kcf_cipher_mechs_tab},
|
||||
{KCF_MAXMAC, kcf_mac_mechs_tab},
|
||||
{KCF_MAXSIGN, kcf_sign_mechs_tab},
|
||||
{KCF_MAXKEYOPS, kcf_keyops_mechs_tab},
|
||||
{KCF_MAXMISC, kcf_misc_mechs_tab}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
kmutex_t kcf_mech_tabs_lock;
|
||||
static uint32_t kcf_gen_swprov = 0;
|
||||
|
||||
int kcf_mech_hash_size = 256;
|
||||
mod_hash_t *kcf_mech_hash; /* mech name to id hash */
|
||||
|
||||
static crypto_mech_type_t
|
||||
kcf_mech_hash_find(char *mechname)
|
||||
{
|
||||
mod_hash_val_t hv;
|
||||
crypto_mech_type_t mt;
|
||||
|
||||
mt = CRYPTO_MECH_INVALID;
|
||||
if (mod_hash_find(kcf_mech_hash, (mod_hash_key_t)mechname, &hv) == 0) {
|
||||
mt = *(crypto_mech_type_t *)hv;
|
||||
ASSERT(mt != CRYPTO_MECH_INVALID);
|
||||
}
|
||||
|
||||
return (mt);
|
||||
}
|
||||
|
||||
void
|
||||
kcf_destroy_mech_tabs(void)
|
||||
{
|
||||
if (kcf_mech_hash) mod_hash_destroy_hash(kcf_mech_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* kcf_init_mech_tabs()
|
||||
*
|
||||
* Called by the misc/kcf's _init() routine to initialize the tables
|
||||
* of mech_entry's.
|
||||
*/
|
||||
void
|
||||
kcf_init_mech_tabs(void)
|
||||
{
|
||||
int i, max;
|
||||
kcf_ops_class_t class;
|
||||
kcf_mech_entry_t *me_tab;
|
||||
|
||||
/* Initializes the mutex locks. */
|
||||
|
||||
mutex_init(&kcf_mech_tabs_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
|
||||
/* Then the pre-defined mechanism entries */
|
||||
|
||||
/* Two digests */
|
||||
(void) strncpy(kcf_digest_mechs_tab[0].me_name, SUN_CKM_MD5,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_digest_mechs_tab[0].me_threshold = kcf_md5_threshold;
|
||||
|
||||
(void) strncpy(kcf_digest_mechs_tab[1].me_name, SUN_CKM_SHA1,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_digest_mechs_tab[1].me_threshold = kcf_sha1_threshold;
|
||||
|
||||
/* The symmetric ciphers in various modes */
|
||||
(void) strncpy(kcf_cipher_mechs_tab[0].me_name, SUN_CKM_DES_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[0].me_threshold = kcf_des_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[1].me_name, SUN_CKM_DES3_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[1].me_threshold = kcf_des3_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[2].me_name, SUN_CKM_DES_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[2].me_threshold = kcf_des_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[3].me_name, SUN_CKM_DES3_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[3].me_threshold = kcf_des3_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[4].me_name, SUN_CKM_BLOWFISH_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[4].me_threshold = kcf_bf_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[5].me_name, SUN_CKM_BLOWFISH_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[5].me_threshold = kcf_bf_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[6].me_name, SUN_CKM_AES_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[6].me_threshold = kcf_aes_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[7].me_name, SUN_CKM_AES_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[7].me_threshold = kcf_aes_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[8].me_name, SUN_CKM_RC4,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[8].me_threshold = kcf_rc4_threshold;
|
||||
|
||||
|
||||
/* 4 HMACs */
|
||||
(void) strncpy(kcf_mac_mechs_tab[0].me_name, SUN_CKM_MD5_HMAC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[0].me_threshold = kcf_md5_threshold;
|
||||
|
||||
(void) strncpy(kcf_mac_mechs_tab[1].me_name, SUN_CKM_MD5_HMAC_GENERAL,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[1].me_threshold = kcf_md5_threshold;
|
||||
|
||||
(void) strncpy(kcf_mac_mechs_tab[2].me_name, SUN_CKM_SHA1_HMAC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[2].me_threshold = kcf_sha1_threshold;
|
||||
|
||||
(void) strncpy(kcf_mac_mechs_tab[3].me_name, SUN_CKM_SHA1_HMAC_GENERAL,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[3].me_threshold = kcf_sha1_threshold;
|
||||
|
||||
|
||||
/* 1 random number generation pseudo mechanism */
|
||||
(void) strncpy(kcf_misc_mechs_tab[0].me_name, SUN_RANDOM,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
|
||||
kcf_mech_hash = mod_hash_create_strhash_nodtr("kcf mech2id hash",
|
||||
kcf_mech_hash_size, mod_hash_null_valdtor);
|
||||
|
||||
for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
|
||||
max = kcf_mech_tabs_tab[class].met_size;
|
||||
me_tab = kcf_mech_tabs_tab[class].met_tab;
|
||||
for (i = 0; i < max; i++) {
|
||||
mutex_init(&(me_tab[i].me_mutex), NULL,
|
||||
MUTEX_DEFAULT, NULL);
|
||||
if (me_tab[i].me_name[0] != 0) {
|
||||
me_tab[i].me_mechid = KCF_MECHID(class, i);
|
||||
(void) mod_hash_insert(kcf_mech_hash,
|
||||
(mod_hash_key_t)me_tab[i].me_name,
|
||||
(mod_hash_val_t)&(me_tab[i].me_mechid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
|
||||
{
|
||||
crypto_mech_type_t mt;
|
||||
kcf_mech_entry_t *me_tab;
|
||||
int i = 0, size;
|
||||
|
||||
if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS))
|
||||
return (KCF_INVALID_MECH_CLASS);
|
||||
|
||||
if ((mechname == NULL) || (mechname[0] == 0))
|
||||
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.
|
||||
*/
|
||||
mutex_enter(&kcf_mech_tabs_lock);
|
||||
mt = kcf_mech_hash_find(mechname);
|
||||
if (mt != CRYPTO_MECH_INVALID) {
|
||||
/* Nothing to do, regardless the suggested class. */
|
||||
mutex_exit(&kcf_mech_tabs_lock);
|
||||
return (KCF_SUCCESS);
|
||||
}
|
||||
/* Now take the next unused mech entry in the class's tab */
|
||||
me_tab = kcf_mech_tabs_tab[class].met_tab;
|
||||
size = kcf_mech_tabs_tab[class].met_size;
|
||||
|
||||
while (i < size) {
|
||||
mutex_enter(&(me_tab[i].me_mutex));
|
||||
if (me_tab[i].me_name[0] == 0) {
|
||||
/* Found an empty spot */
|
||||
(void) strncpy(me_tab[i].me_name, mechname,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
me_tab[i].me_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
|
||||
me_tab[i].me_mechid = KCF_MECHID(class, i);
|
||||
/*
|
||||
* No a-priori information about the new mechanism, so
|
||||
* the threshold is set to zero.
|
||||
*/
|
||||
me_tab[i].me_threshold = 0;
|
||||
|
||||
mutex_exit(&(me_tab[i].me_mutex));
|
||||
/* Add the new mechanism to the hash table */
|
||||
(void) mod_hash_insert(kcf_mech_hash,
|
||||
(mod_hash_key_t)me_tab[i].me_name,
|
||||
(mod_hash_val_t)&(me_tab[i].me_mechid));
|
||||
break;
|
||||
}
|
||||
mutex_exit(&(me_tab[i].me_mutex));
|
||||
i++;
|
||||
}
|
||||
|
||||
mutex_exit(&kcf_mech_tabs_lock);
|
||||
|
||||
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,
|
||||
kcf_provider_desc_t *prov_desc, kcf_prov_mech_desc_t **pmdpp)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *mech_entry = NULL;
|
||||
crypto_mech_info_t *mech_info;
|
||||
crypto_mech_type_t kcf_mech_type, mt;
|
||||
kcf_prov_mech_desc_t *prov_mech, *prov_mech2;
|
||||
crypto_func_group_t simple_fg_mask, dual_fg_mask;
|
||||
crypto_mech_info_t *dmi;
|
||||
crypto_mech_info_list_t *mil, *mil2;
|
||||
kcf_mech_entry_t *me;
|
||||
int i;
|
||||
|
||||
ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
mech_info = &prov_desc->pd_mechanisms[mech_indx];
|
||||
|
||||
/*
|
||||
* A mechanism belongs to exactly one mechanism table.
|
||||
* Find the class corresponding to the function group flag of
|
||||
* the mechanism.
|
||||
*/
|
||||
kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
|
||||
if (kcf_mech_type == CRYPTO_MECH_INVALID) {
|
||||
crypto_func_group_t fg = mech_info->cm_func_group_mask;
|
||||
kcf_ops_class_t class;
|
||||
|
||||
if (fg & CRYPTO_FG_DIGEST || fg & CRYPTO_FG_DIGEST_ATOMIC)
|
||||
class = KCF_DIGEST_CLASS;
|
||||
else if (fg & CRYPTO_FG_ENCRYPT || fg & CRYPTO_FG_DECRYPT ||
|
||||
fg & CRYPTO_FG_ENCRYPT_ATOMIC ||
|
||||
fg & CRYPTO_FG_DECRYPT_ATOMIC)
|
||||
class = KCF_CIPHER_CLASS;
|
||||
else if (fg & CRYPTO_FG_MAC || fg & CRYPTO_FG_MAC_ATOMIC)
|
||||
class = KCF_MAC_CLASS;
|
||||
else if (fg & CRYPTO_FG_SIGN || fg & CRYPTO_FG_VERIFY ||
|
||||
fg & CRYPTO_FG_SIGN_ATOMIC ||
|
||||
fg & CRYPTO_FG_VERIFY_ATOMIC ||
|
||||
fg & CRYPTO_FG_SIGN_RECOVER ||
|
||||
fg & CRYPTO_FG_VERIFY_RECOVER)
|
||||
class = KCF_SIGN_CLASS;
|
||||
else if (fg & CRYPTO_FG_GENERATE ||
|
||||
fg & CRYPTO_FG_GENERATE_KEY_PAIR ||
|
||||
fg & CRYPTO_FG_WRAP || fg & CRYPTO_FG_UNWRAP ||
|
||||
fg & CRYPTO_FG_DERIVE)
|
||||
class = KCF_KEYOPS_CLASS;
|
||||
else
|
||||
class = KCF_MISC_CLASS;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if ((error = kcf_create_mech_entry(class,
|
||||
mech_info->cm_mech_name)) != KCF_SUCCESS) {
|
||||
return (error);
|
||||
}
|
||||
/* get the KCF mech type that was assigned to the mechanism */
|
||||
kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
|
||||
ASSERT(kcf_mech_type != CRYPTO_MECH_INVALID);
|
||||
}
|
||||
|
||||
error = kcf_get_mech_entry(kcf_mech_type, &mech_entry);
|
||||
ASSERT(error == KCF_SUCCESS);
|
||||
|
||||
/* allocate and initialize new kcf_prov_mech_desc */
|
||||
prov_mech = kmem_zalloc(sizeof (kcf_prov_mech_desc_t), KM_SLEEP);
|
||||
bcopy(mech_info, &prov_mech->pm_mech_info, sizeof (crypto_mech_info_t));
|
||||
prov_mech->pm_prov_desc = prov_desc;
|
||||
prov_desc->pd_mech_indx[KCF_MECH2CLASS(kcf_mech_type)]
|
||||
[KCF_MECH2INDEX(kcf_mech_type)] = mech_indx;
|
||||
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
KCF_PROV_IREFHOLD(prov_desc);
|
||||
|
||||
dual_fg_mask = mech_info->cm_func_group_mask & CRYPTO_FG_DUAL_MASK;
|
||||
|
||||
if (dual_fg_mask == ((crypto_func_group_t)0))
|
||||
goto add_entry;
|
||||
|
||||
simple_fg_mask = (mech_info->cm_func_group_mask &
|
||||
CRYPTO_FG_SIMPLEOP_MASK) | CRYPTO_FG_RANDOM;
|
||||
|
||||
for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
|
||||
dmi = &prov_desc->pd_mechanisms[i];
|
||||
|
||||
/* skip self */
|
||||
if (dmi->cm_mech_number == mech_info->cm_mech_number)
|
||||
continue;
|
||||
|
||||
/* skip if not a dual operation mechanism */
|
||||
if (!(dmi->cm_func_group_mask & dual_fg_mask) ||
|
||||
(dmi->cm_func_group_mask & simple_fg_mask))
|
||||
continue;
|
||||
|
||||
mt = kcf_mech_hash_find(dmi->cm_mech_name);
|
||||
if (mt == CRYPTO_MECH_INVALID)
|
||||
continue;
|
||||
|
||||
if (kcf_get_mech_entry(mt, &me) != KCF_SUCCESS)
|
||||
continue;
|
||||
|
||||
mil = kmem_zalloc(sizeof (*mil), KM_SLEEP);
|
||||
mil2 = kmem_zalloc(sizeof (*mil2), KM_SLEEP);
|
||||
|
||||
/*
|
||||
* Ignore hard-coded entries in the mech table
|
||||
* if the provider hasn't registered.
|
||||
*/
|
||||
mutex_enter(&me->me_mutex);
|
||||
if (me->me_hw_prov_chain == NULL && me->me_sw_prov == NULL) {
|
||||
mutex_exit(&me->me_mutex);
|
||||
kmem_free(mil, sizeof (*mil));
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add other dual mechanisms that have registered
|
||||
* with the framework to this mechanism's
|
||||
* cross-reference list.
|
||||
*/
|
||||
mil->ml_mech_info = *dmi; /* struct assignment */
|
||||
mil->ml_kcf_mechid = mt;
|
||||
|
||||
/* add to head of list */
|
||||
mil->ml_next = prov_mech->pm_mi_list;
|
||||
prov_mech->pm_mi_list = mil;
|
||||
|
||||
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
|
||||
prov_mech2 = me->me_hw_prov_chain;
|
||||
else
|
||||
prov_mech2 = me->me_sw_prov;
|
||||
|
||||
if (prov_mech2 == NULL) {
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
mutex_exit(&me->me_mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update all other cross-reference lists by
|
||||
* adding this new mechanism.
|
||||
*/
|
||||
while (prov_mech2 != NULL) {
|
||||
if (prov_mech2->pm_prov_desc == prov_desc) {
|
||||
/* struct assignment */
|
||||
mil2->ml_mech_info = *mech_info;
|
||||
mil2->ml_kcf_mechid = kcf_mech_type;
|
||||
|
||||
/* add to head of list */
|
||||
mil2->ml_next = prov_mech2->pm_mi_list;
|
||||
prov_mech2->pm_mi_list = mil2;
|
||||
break;
|
||||
}
|
||||
prov_mech2 = prov_mech2->pm_next;
|
||||
}
|
||||
if (prov_mech2 == NULL)
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
|
||||
mutex_exit(&me->me_mutex);
|
||||
}
|
||||
|
||||
add_entry:
|
||||
/*
|
||||
* Add new kcf_prov_mech_desc at the front of HW providers
|
||||
* chain.
|
||||
*/
|
||||
switch (prov_desc->pd_prov_type) {
|
||||
|
||||
case CRYPTO_HW_PROVIDER:
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
prov_mech->pm_me = mech_entry;
|
||||
prov_mech->pm_next = mech_entry->me_hw_prov_chain;
|
||||
mech_entry->me_hw_prov_chain = prov_mech;
|
||||
mech_entry->me_num_hwprov++;
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
break;
|
||||
|
||||
case CRYPTO_SW_PROVIDER:
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
if (mech_entry->me_sw_prov != NULL) {
|
||||
/*
|
||||
* There is already a SW provider for this mechanism.
|
||||
* Since we allow only one SW provider per mechanism,
|
||||
* report this condition.
|
||||
*/
|
||||
cmn_err(CE_WARN, "The cryptographic software provider "
|
||||
"\"%s\" will not be used for %s. The provider "
|
||||
"\"%s\" will be used for this mechanism "
|
||||
"instead.", prov_desc->pd_description,
|
||||
mech_info->cm_mech_name,
|
||||
mech_entry->me_sw_prov->pm_prov_desc->
|
||||
pd_description);
|
||||
KCF_PROV_REFRELE(prov_desc);
|
||||
kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
|
||||
prov_mech = NULL;
|
||||
} else {
|
||||
/*
|
||||
* Set the provider as the software provider for
|
||||
* this mechanism.
|
||||
*/
|
||||
mech_entry->me_sw_prov = prov_mech;
|
||||
|
||||
/* We'll wrap around after 4 billion registrations! */
|
||||
mech_entry->me_gen_swprov = kcf_gen_swprov++;
|
||||
}
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*pmdpp = prov_mech;
|
||||
|
||||
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
|
||||
kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
|
||||
{
|
||||
crypto_mech_type_t mech_type;
|
||||
kcf_prov_mech_desc_t *prov_mech = NULL, *prov_chain;
|
||||
kcf_prov_mech_desc_t **prev_entry_next;
|
||||
kcf_mech_entry_t *mech_entry;
|
||||
crypto_mech_info_list_t *mil, *mil2, *next, **prev_next;
|
||||
|
||||
ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* get the KCF mech type that was assigned to the mechanism */
|
||||
if ((mech_type = kcf_mech_hash_find(mech_name)) ==
|
||||
CRYPTO_MECH_INVALID) {
|
||||
/*
|
||||
* Provider was not allowed for this mech due to policy or
|
||||
* configuration.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* get a ptr to the mech_entry that was created */
|
||||
if (kcf_get_mech_entry(mech_type, &mech_entry) != KCF_SUCCESS) {
|
||||
/*
|
||||
* Provider was not allowed for this mech due to policy or
|
||||
* configuration.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
|
||||
switch (prov_desc->pd_prov_type) {
|
||||
|
||||
case CRYPTO_HW_PROVIDER:
|
||||
/* find the provider in the mech_entry chain */
|
||||
prev_entry_next = &mech_entry->me_hw_prov_chain;
|
||||
prov_mech = mech_entry->me_hw_prov_chain;
|
||||
while (prov_mech != NULL &&
|
||||
prov_mech->pm_prov_desc != prov_desc) {
|
||||
prev_entry_next = &prov_mech->pm_next;
|
||||
prov_mech = prov_mech->pm_next;
|
||||
}
|
||||
|
||||
if (prov_mech == NULL) {
|
||||
/* entry not found, simply return */
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove provider entry from mech_entry chain */
|
||||
*prev_entry_next = prov_mech->pm_next;
|
||||
ASSERT(mech_entry->me_num_hwprov > 0);
|
||||
mech_entry->me_num_hwprov--;
|
||||
break;
|
||||
|
||||
case CRYPTO_SW_PROVIDER:
|
||||
if (mech_entry->me_sw_prov == NULL ||
|
||||
mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
|
||||
/* not the software provider for this mechanism */
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
return;
|
||||
}
|
||||
prov_mech = mech_entry->me_sw_prov;
|
||||
mech_entry->me_sw_prov = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
|
||||
/* Free the dual ops cross-reference lists */
|
||||
mil = prov_mech->pm_mi_list;
|
||||
while (mil != NULL) {
|
||||
next = mil->ml_next;
|
||||
if (kcf_get_mech_entry(mil->ml_kcf_mechid,
|
||||
&mech_entry) != KCF_SUCCESS) {
|
||||
mil = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
|
||||
prov_chain = mech_entry->me_hw_prov_chain;
|
||||
else
|
||||
prov_chain = mech_entry->me_sw_prov;
|
||||
|
||||
while (prov_chain != NULL) {
|
||||
if (prov_chain->pm_prov_desc == prov_desc) {
|
||||
prev_next = &prov_chain->pm_mi_list;
|
||||
mil2 = prov_chain->pm_mi_list;
|
||||
while (mil2 != NULL &&
|
||||
mil2->ml_kcf_mechid != mech_type) {
|
||||
prev_next = &mil2->ml_next;
|
||||
mil2 = mil2->ml_next;
|
||||
}
|
||||
if (mil2 != NULL) {
|
||||
*prev_next = mil2->ml_next;
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
prov_chain = prov_chain->pm_next;
|
||||
}
|
||||
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
kmem_free(mil, sizeof (crypto_mech_info_list_t));
|
||||
mil = next;
|
||||
}
|
||||
|
||||
/* free entry */
|
||||
KCF_PROV_REFRELE(prov_mech->pm_prov_desc);
|
||||
KCF_PROV_IREFRELE(prov_mech->pm_prov_desc);
|
||||
kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
kcf_get_mech_entry(crypto_mech_type_t mech_type, kcf_mech_entry_t **mep)
|
||||
{
|
||||
kcf_ops_class_t class;
|
||||
int index;
|
||||
kcf_mech_entry_tab_t *me_tab;
|
||||
|
||||
ASSERT(mep != NULL);
|
||||
|
||||
class = KCF_MECH2CLASS(mech_type);
|
||||
|
||||
if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
|
||||
/* the caller won't need to know it's an invalid class */
|
||||
return (KCF_INVALID_MECH_NUMBER);
|
||||
}
|
||||
|
||||
me_tab = &kcf_mech_tabs_tab[class];
|
||||
index = KCF_MECH2INDEX(mech_type);
|
||||
|
||||
if ((index < 0) || (index >= me_tab->met_size)) {
|
||||
return (KCF_INVALID_MECH_NUMBER);
|
||||
}
|
||||
|
||||
*mep = &((me_tab->met_tab)[index]);
|
||||
|
||||
return (KCF_SUCCESS);
|
||||
}
|
||||
|
||||
/* CURRENTLY UNSUPPORTED: attempting to load the module if it isn't found */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
crypto_mech_type_t
|
||||
crypto_mech2id_common(char *mechname, boolean_t load_module)
|
||||
{
|
||||
crypto_mech_type_t mt = kcf_mech_hash_find(mechname);
|
||||
return (mt);
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <modes/modes.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
|
||||
/*
|
||||
* Utility routine to copy a buffer to a crypto_data structure.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Utility routine to apply the command, 'cmd', to the
|
||||
* data in the uio structure.
|
||||
*/
|
||||
int
|
||||
crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
|
||||
void *digest_ctx, void (*update)(void))
|
||||
{
|
||||
uio_t *uiop = data->cd_uio;
|
||||
off_t offset = data->cd_offset;
|
||||
size_t length = len;
|
||||
uint_t vec_idx;
|
||||
size_t cur_len;
|
||||
uchar_t *datap;
|
||||
|
||||
ASSERT(data->cd_format == CRYPTO_DATA_UIO);
|
||||
if (uiop->uio_segflg != UIO_SYSSPACE) {
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Jump to the first iovec containing data to be
|
||||
* processed.
|
||||
*/
|
||||
for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
|
||||
offset >= uiop->uio_iov[vec_idx].iov_len;
|
||||
offset -= uiop->uio_iov[vec_idx++].iov_len)
|
||||
;
|
||||
|
||||
if (vec_idx == uiop->uio_iovcnt) {
|
||||
/*
|
||||
* The caller specified an offset that is larger than
|
||||
* the total size of the buffers it provided.
|
||||
*/
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
while (vec_idx < uiop->uio_iovcnt && length > 0) {
|
||||
cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
|
||||
offset, length);
|
||||
|
||||
datap = (uchar_t *)(uiop->uio_iov[vec_idx].iov_base +
|
||||
offset);
|
||||
switch (cmd) {
|
||||
case COPY_FROM_DATA:
|
||||
bcopy(datap, buf, cur_len);
|
||||
buf += cur_len;
|
||||
break;
|
||||
case COPY_TO_DATA:
|
||||
bcopy(buf, datap, cur_len);
|
||||
buf += cur_len;
|
||||
break;
|
||||
case COMPARE_TO_DATA:
|
||||
if (bcmp(datap, buf, cur_len))
|
||||
return (CRYPTO_SIGNATURE_INVALID);
|
||||
buf += cur_len;
|
||||
break;
|
||||
case MD5_DIGEST_DATA:
|
||||
case SHA1_DIGEST_DATA:
|
||||
case SHA2_DIGEST_DATA:
|
||||
case GHASH_DATA:
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
}
|
||||
|
||||
length -= cur_len;
|
||||
vec_idx++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (vec_idx == uiop->uio_iovcnt && length > 0) {
|
||||
/*
|
||||
* The end of the specified iovec's was reached but
|
||||
* the length requested could not be processed.
|
||||
*/
|
||||
switch (cmd) {
|
||||
case COPY_TO_DATA:
|
||||
data->cd_length = len;
|
||||
return (CRYPTO_BUFFER_TOO_SMALL);
|
||||
default:
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len)
|
||||
{
|
||||
switch (output->cd_format) {
|
||||
case CRYPTO_DATA_RAW:
|
||||
if (output->cd_raw.iov_len < len) {
|
||||
output->cd_length = len;
|
||||
return (CRYPTO_BUFFER_TOO_SMALL);
|
||||
}
|
||||
bcopy(buf, (uchar_t *)(output->cd_raw.iov_base +
|
||||
output->cd_offset), len);
|
||||
break;
|
||||
|
||||
case CRYPTO_DATA_UIO:
|
||||
return (crypto_uio_data(output, buf, len,
|
||||
COPY_TO_DATA, NULL, NULL));
|
||||
default:
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output,
|
||||
int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
|
||||
void (*copy_block)(uint8_t *, uint64_t *))
|
||||
{
|
||||
common_ctx_t *common_ctx = ctx;
|
||||
int rv;
|
||||
|
||||
if (input->cd_miscdata != NULL) {
|
||||
copy_block((uint8_t *)input->cd_miscdata,
|
||||
&common_ctx->cc_iv[0]);
|
||||
}
|
||||
|
||||
if (input->cd_raw.iov_len < input->cd_length)
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
|
||||
rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
|
||||
input->cd_length, (input == output) ? NULL : output);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
|
||||
int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
|
||||
void (*copy_block)(uint8_t *, uint64_t *))
|
||||
{
|
||||
common_ctx_t *common_ctx = ctx;
|
||||
uio_t *uiop = input->cd_uio;
|
||||
off_t offset = input->cd_offset;
|
||||
size_t length = input->cd_length;
|
||||
uint_t vec_idx;
|
||||
size_t cur_len;
|
||||
|
||||
if (input->cd_miscdata != NULL) {
|
||||
copy_block((uint8_t *)input->cd_miscdata,
|
||||
&common_ctx->cc_iv[0]);
|
||||
}
|
||||
|
||||
if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Jump to the first iovec containing data to be
|
||||
* processed.
|
||||
*/
|
||||
for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
|
||||
offset >= uiop->uio_iov[vec_idx].iov_len;
|
||||
offset -= uiop->uio_iov[vec_idx++].iov_len)
|
||||
;
|
||||
if (vec_idx == uiop->uio_iovcnt) {
|
||||
/*
|
||||
* The caller specified an offset that is larger than the
|
||||
* total size of the buffers it provided.
|
||||
*/
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now process the iovecs.
|
||||
*/
|
||||
while (vec_idx < uiop->uio_iovcnt && length > 0) {
|
||||
cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
|
||||
offset, length);
|
||||
|
||||
(cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset,
|
||||
cur_len, (input == output) ? NULL : output);
|
||||
|
||||
length -= cur_len;
|
||||
vec_idx++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (vec_idx == uiop->uio_iovcnt && length > 0) {
|
||||
/*
|
||||
* The end of the specified iovec's was reached but
|
||||
* the length requested could not be processed, i.e.
|
||||
* The caller requested to digest more data than it provided.
|
||||
*/
|
||||
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
* 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
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* 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 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/crypto/sched_impl.h>
|
||||
#include <sys/crypto/spi.h>
|
||||
|
||||
#define KCF_MAX_PROVIDERS 512 /* max number of providers */
|
||||
|
||||
/*
|
||||
* Prov_tab is an array of providers which is updated when
|
||||
* a crypto provider registers with kcf. The provider calls the
|
||||
* SPI routine, crypto_register_provider(), which in turn calls
|
||||
* kcf_prov_tab_add_provider().
|
||||
*
|
||||
* A provider unregisters by calling crypto_unregister_provider()
|
||||
* which triggers the removal of the prov_tab entry.
|
||||
* It also calls kcf_remove_mech_provider().
|
||||
*
|
||||
* prov_tab entries are not updated from kcf.conf or by cryptoadm(1M).
|
||||
*/
|
||||
static kcf_provider_desc_t **prov_tab = NULL;
|
||||
static kmutex_t prov_tab_mutex; /* ensure exclusive access to the table */
|
||||
static uint_t prov_tab_num = 0; /* number of providers in table */
|
||||
static uint_t prov_tab_max = KCF_MAX_PROVIDERS;
|
||||
|
||||
void
|
||||
kcf_prov_tab_destroy(void)
|
||||
{
|
||||
if (prov_tab) kmem_free(prov_tab, prov_tab_max *
|
||||
sizeof (kcf_provider_desc_t *));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a mutex and the KCF providers table, prov_tab.
|
||||
* The providers table is dynamically allocated with prov_tab_max entries.
|
||||
* Called from kcf module _init().
|
||||
*/
|
||||
void
|
||||
kcf_prov_tab_init(void)
|
||||
{
|
||||
mutex_init(&prov_tab_mutex, NULL, MUTEX_DEFAULT, NULL);
|
||||
|
||||
prov_tab = kmem_zalloc(prov_tab_max * sizeof (kcf_provider_desc_t *),
|
||||
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
|
||||
kcf_prov_tab_add_provider(kcf_provider_desc_t *prov_desc)
|
||||
{
|
||||
uint_t i;
|
||||
|
||||
ASSERT(prov_tab != NULL);
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
|
||||
/* find free slot in providers table */
|
||||
for (i = 1; i < KCF_MAX_PROVIDERS && prov_tab[i] != NULL; i++)
|
||||
;
|
||||
if (i == KCF_MAX_PROVIDERS) {
|
||||
/* ran out of providers entries */
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
cmn_err(CE_WARN, "out of providers entries");
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
}
|
||||
|
||||
/* initialize entry */
|
||||
prov_tab[i] = prov_desc;
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
KCF_PROV_IREFHOLD(prov_desc);
|
||||
prov_tab_num++;
|
||||
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
/* update provider descriptor */
|
||||
prov_desc->pd_prov_id = i;
|
||||
|
||||
/*
|
||||
* The KCF-private provider handle is defined as the internal
|
||||
* provider id.
|
||||
*/
|
||||
prov_desc->pd_kcf_prov_handle =
|
||||
(crypto_kcf_provider_handle_t)prov_desc->pd_prov_id;
|
||||
|
||||
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
|
||||
kcf_prov_tab_rem_provider(crypto_provider_id_t prov_id)
|
||||
{
|
||||
kcf_provider_desc_t *prov_desc;
|
||||
|
||||
ASSERT(prov_tab != NULL);
|
||||
ASSERT(prov_tab_num >= 0);
|
||||
|
||||
/*
|
||||
* Validate provider id, since it can be specified by a 3rd-party
|
||||
* provider.
|
||||
*/
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
if (prov_id >= KCF_MAX_PROVIDERS ||
|
||||
((prov_desc = prov_tab[prov_id]) == NULL)) {
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
return (CRYPTO_INVALID_PROVIDER_ID);
|
||||
}
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
KCF_PROV_REFRELE(prov_desc);
|
||||
KCF_PROV_IREFRELE(prov_desc);
|
||||
|
||||
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.
|
||||
*/
|
||||
kcf_provider_desc_t *
|
||||
kcf_prov_tab_lookup(crypto_provider_id_t prov_id)
|
||||
{
|
||||
kcf_provider_desc_t *prov_desc;
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
|
||||
prov_desc = prov_tab[prov_id];
|
||||
|
||||
if (prov_desc == NULL) {
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
return (prov_desc);
|
||||
}
|
||||
|
||||
static void
|
||||
allocate_ops_v1(crypto_ops_t *src, crypto_ops_t *dst, uint_t *mech_list_count)
|
||||
{
|
||||
if (src->co_control_ops != NULL)
|
||||
dst->co_control_ops = kmem_alloc(sizeof (crypto_control_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_digest_ops != NULL)
|
||||
dst->co_digest_ops = kmem_alloc(sizeof (crypto_digest_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_cipher_ops != NULL)
|
||||
dst->co_cipher_ops = kmem_alloc(sizeof (crypto_cipher_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_mac_ops != NULL)
|
||||
dst->co_mac_ops = kmem_alloc(sizeof (crypto_mac_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_sign_ops != NULL)
|
||||
dst->co_sign_ops = kmem_alloc(sizeof (crypto_sign_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_verify_ops != NULL)
|
||||
dst->co_verify_ops = kmem_alloc(sizeof (crypto_verify_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_dual_ops != NULL)
|
||||
dst->co_dual_ops = kmem_alloc(sizeof (crypto_dual_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_dual_cipher_mac_ops != NULL)
|
||||
dst->co_dual_cipher_mac_ops = kmem_alloc(
|
||||
sizeof (crypto_dual_cipher_mac_ops_t), KM_SLEEP);
|
||||
|
||||
if (src->co_random_ops != NULL) {
|
||||
dst->co_random_ops = kmem_alloc(
|
||||
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)++;
|
||||
}
|
||||
|
||||
if (src->co_session_ops != NULL)
|
||||
dst->co_session_ops = kmem_alloc(sizeof (crypto_session_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_object_ops != NULL)
|
||||
dst->co_object_ops = kmem_alloc(sizeof (crypto_object_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_key_ops != NULL)
|
||||
dst->co_key_ops = kmem_alloc(sizeof (crypto_key_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_provider_ops != NULL)
|
||||
dst->co_provider_ops = kmem_alloc(
|
||||
sizeof (crypto_provider_management_ops_t), KM_SLEEP);
|
||||
|
||||
if (src->co_ctx_ops != NULL)
|
||||
dst->co_ctx_ops = kmem_alloc(sizeof (crypto_ctx_ops_t),
|
||||
KM_SLEEP);
|
||||
}
|
||||
|
||||
static void
|
||||
allocate_ops_v2(crypto_ops_t *src, crypto_ops_t *dst)
|
||||
{
|
||||
if (src->co_mech_ops != NULL)
|
||||
dst->co_mech_ops = kmem_alloc(sizeof (crypto_mech_ops_t),
|
||||
KM_SLEEP);
|
||||
}
|
||||
|
||||
static void
|
||||
allocate_ops_v3(crypto_ops_t *src, crypto_ops_t *dst)
|
||||
{
|
||||
if (src->co_nostore_key_ops != NULL)
|
||||
dst->co_nostore_key_ops =
|
||||
kmem_alloc(sizeof (crypto_nostore_key_ops_t), KM_SLEEP);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
kcf_provider_desc_t *
|
||||
kcf_alloc_provider_desc(crypto_provider_info_t *info)
|
||||
{
|
||||
int i, j;
|
||||
kcf_provider_desc_t *desc;
|
||||
uint_t mech_list_count = info->pi_mech_list_count;
|
||||
crypto_ops_t *src_ops = info->pi_ops_vector;
|
||||
|
||||
desc = kmem_zalloc(sizeof (kcf_provider_desc_t), KM_SLEEP);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
desc->pd_description = kmem_alloc(CRYPTO_PROVIDER_DESCR_MAX_LEN + 1,
|
||||
KM_SLEEP);
|
||||
(void) memset(desc->pd_description, ' ',
|
||||
CRYPTO_PROVIDER_DESCR_MAX_LEN);
|
||||
desc->pd_description[CRYPTO_PROVIDER_DESCR_MAX_LEN] = '\0';
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
desc->pd_ops_vector = kmem_zalloc(sizeof (crypto_ops_t), KM_SLEEP);
|
||||
|
||||
if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
|
||||
allocate_ops_v1(src_ops, desc->pd_ops_vector, &mech_list_count);
|
||||
if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2)
|
||||
allocate_ops_v2(src_ops, desc->pd_ops_vector);
|
||||
if (info->pi_interface_version == CRYPTO_SPI_VERSION_3)
|
||||
allocate_ops_v3(src_ops, desc->pd_ops_vector);
|
||||
}
|
||||
|
||||
desc->pd_mech_list_count = mech_list_count;
|
||||
desc->pd_mechanisms = kmem_zalloc(sizeof (crypto_mech_info_t) *
|
||||
mech_list_count, KM_SLEEP);
|
||||
for (i = 0; i < KCF_OPS_CLASSSIZE; i++)
|
||||
for (j = 0; j < KCF_MAXMECHTAB; j++)
|
||||
desc->pd_mech_indx[i][j] = KCF_INVALID_INDX;
|
||||
|
||||
desc->pd_prov_id = KCF_PROVID_INVALID;
|
||||
desc->pd_state = KCF_PROV_ALLOCATED;
|
||||
|
||||
mutex_init(&desc->pd_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
cv_init(&desc->pd_resume_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&desc->pd_remove_cv, NULL, CV_DEFAULT, NULL);
|
||||
|
||||
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
|
||||
kcf_provider_zero_refcnt(kcf_provider_desc_t *desc)
|
||||
{
|
||||
mutex_enter(&desc->pd_lock);
|
||||
switch (desc->pd_prov_type) {
|
||||
case CRYPTO_SW_PROVIDER:
|
||||
if (desc->pd_state == KCF_PROV_REMOVED ||
|
||||
desc->pd_state == KCF_PROV_DISABLED) {
|
||||
desc->pd_state = KCF_PROV_FREED;
|
||||
cv_broadcast(&desc->pd_remove_cv);
|
||||
mutex_exit(&desc->pd_lock);
|
||||
break;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
||||
case CRYPTO_HW_PROVIDER:
|
||||
case CRYPTO_LOGICAL_PROVIDER:
|
||||
mutex_exit(&desc->pd_lock);
|
||||
kcf_free_provider_desc(desc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a provider descriptor.
|
||||
*/
|
||||
void
|
||||
kcf_free_provider_desc(kcf_provider_desc_t *desc)
|
||||
{
|
||||
if (desc == NULL)
|
||||
return;
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
if (desc->pd_prov_id != KCF_PROVID_INVALID) {
|
||||
/* release the associated providers table entry */
|
||||
ASSERT(prov_tab[desc->pd_prov_id] != NULL);
|
||||
prov_tab[desc->pd_prov_id] = NULL;
|
||||
prov_tab_num--;
|
||||
}
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
/* free the kernel memory associated with the provider descriptor */
|
||||
|
||||
if (desc->pd_description != NULL)
|
||||
kmem_free(desc->pd_description,
|
||||
CRYPTO_PROVIDER_DESCR_MAX_LEN + 1);
|
||||
|
||||
if (desc->pd_ops_vector != NULL) {
|
||||
|
||||
if (desc->pd_ops_vector->co_control_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_control_ops,
|
||||
sizeof (crypto_control_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_digest_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_digest_ops,
|
||||
sizeof (crypto_digest_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_cipher_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_cipher_ops,
|
||||
sizeof (crypto_cipher_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_mac_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_mac_ops,
|
||||
sizeof (crypto_mac_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_sign_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_sign_ops,
|
||||
sizeof (crypto_sign_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_verify_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_verify_ops,
|
||||
sizeof (crypto_verify_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_dual_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_dual_ops,
|
||||
sizeof (crypto_dual_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_dual_cipher_mac_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_dual_cipher_mac_ops,
|
||||
sizeof (crypto_dual_cipher_mac_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_random_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_random_ops,
|
||||
sizeof (crypto_random_number_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_session_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_session_ops,
|
||||
sizeof (crypto_session_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_object_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_object_ops,
|
||||
sizeof (crypto_object_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_key_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_key_ops,
|
||||
sizeof (crypto_key_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_provider_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_provider_ops,
|
||||
sizeof (crypto_provider_management_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_ctx_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_ctx_ops,
|
||||
sizeof (crypto_ctx_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_mech_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_mech_ops,
|
||||
sizeof (crypto_mech_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_nostore_key_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_nostore_key_ops,
|
||||
sizeof (crypto_nostore_key_ops_t));
|
||||
|
||||
kmem_free(desc->pd_ops_vector, sizeof (crypto_ops_t));
|
||||
}
|
||||
|
||||
if (desc->pd_mechanisms != NULL)
|
||||
/* free the memory associated with the mechanism info's */
|
||||
kmem_free(desc->pd_mechanisms, sizeof (crypto_mech_info_t) *
|
||||
desc->pd_mech_list_count);
|
||||
|
||||
if (desc->pd_sched_info.ks_taskq != NULL)
|
||||
taskq_destroy(desc->pd_sched_info.ks_taskq);
|
||||
|
||||
kmem_free(desc, sizeof (kcf_provider_desc_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free an array of hardware provider descriptors. A REFRELE
|
||||
* is done on each descriptor before the table is freed.
|
||||
*/
|
||||
void
|
||||
kcf_free_provider_tab(uint_t count, kcf_provider_desc_t **array)
|
||||
{
|
||||
kcf_provider_desc_t *prov_desc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((prov_desc = array[i]) != NULL) {
|
||||
KCF_PROV_REFRELE(prov_desc);
|
||||
}
|
||||
}
|
||||
kmem_free(array, count * sizeof (kcf_provider_desc_t *));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
kcf_get_sw_prov(crypto_mech_type_t mech_type, kcf_provider_desc_t **pd,
|
||||
kcf_mech_entry_t **mep, boolean_t log_warn)
|
||||
{
|
||||
kcf_mech_entry_t *me;
|
||||
|
||||
/* get the mechanism entry for this mechanism */
|
||||
if (kcf_get_mech_entry(mech_type, &me) != KCF_SUCCESS)
|
||||
return (CRYPTO_MECHANISM_INVALID);
|
||||
|
||||
/*
|
||||
* Get the software provider for this mechanism.
|
||||
* Lock the mech_entry until we grab the 'pd'.
|
||||
*/
|
||||
mutex_enter(&me->me_mutex);
|
||||
|
||||
if (me->me_sw_prov == NULL ||
|
||||
(*pd = me->me_sw_prov->pm_prov_desc) == NULL) {
|
||||
/* no SW provider for this mechanism */
|
||||
if (log_warn)
|
||||
cmn_err(CE_WARN, "no SW provider for \"%s\"\n",
|
||||
me->me_name);
|
||||
mutex_exit(&me->me_mutex);
|
||||
return (CRYPTO_MECH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
KCF_PROV_REFHOLD(*pd);
|
||||
mutex_exit(&me->me_mutex);
|
||||
|
||||
if (mep != NULL)
|
||||
*mep = me;
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user