Print this page
6414175 kcf.conf's supportedlist not providing much usefulness
@@ -21,12 +21,10 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Core KCF (Kernel Cryptographic Framework). This file implements
* the cryptoadm entry points.
*/
@@ -46,13 +44,17 @@
/* protects the the soft_config_list. */
kmutex_t soft_config_mutex;
/*
- * This linked list contains software configuration entries that
- * are loaded into the kernel by the CRYPTO_LOAD_SOFT_CONFIG ioctl.
- * It is protected by the soft_config_mutex.
+ * This linked list contains software configuration entries.
+ * The initial list is just software providers loaded by kcf_soft_config_init().
+ * Additional entries may appear for both hardware and software providers
+ * from kcf.conf. These come from "cryptoadm start", which reads file kcf.conf
+ * and updates this table using the CRYPTO_LOAD_SOFT_CONFIG ioctl.
+ * Further cryptoadm commands modify this file and update this table with ioctl.
+ * This list is protected by the soft_config_mutex.
*/
kcf_soft_conf_entry_t *soft_config_list;
static int add_soft_config(char *, uint_t, crypto_mech_name_t *);
static int dup_mech_names(kcf_provider_desc_t *, crypto_mech_name_t **,
@@ -59,21 +61,194 @@
uint_t *, int);
static void free_soft_config_entry(kcf_soft_conf_entry_t *);
#define KCF_MAX_CONFIG_ENTRIES 512 /* maximum entries in soft_config_list */
+#if DEBUG
+extern int kcf_frmwrk_debug;
+static void kcf_soft_config_dump(char *message);
+#endif /* DEBUG */
+
+/*
+ * Count and return the number of mechanisms in an array of crypto_mech_name_t
+ * (excluding final NUL-character string element).
+ */
+static int
+count_mechanisms(crypto_mech_name_t mechs[]) {
+ int count;
+ for (count = 0; mechs[count][0] != '\0'; ++count);
+ return (count);
+}
+
+/*
+ * Initialize a mutex and populate soft_config_list with default entries
+ * of kernel software providers.
+ * Called from kcf module _init().
+ */
void
kcf_soft_config_init(void)
{
+ typedef struct {
+ char *name;
+ crypto_mech_name_t *mechs;
+ } initial_soft_config_entry_t;
+
+ /*
+ * This provides initial default values to soft_config_list.
+ * It is equivalent to these lines in /etc/crypto/kcf.conf
+ * (without line breaks and indenting):
+ *
+ * # /etc/crypto/kcf.conf
+ * des:supportedlist=CKM_DES_CBC,CKM_DES_ECB,CKM_DES3_CBC,CKM_DES3_ECB
+ * aes:supportedlist=CKM_AES_ECB,CKM_AES_CBC,CKM_AES_CTR,CKM_AES_CCM
+ * arcfour:supportedlist=CKM_RC4
+ * blowfish:supportedlist=CKM_BLOWFISH_ECB,CKM_BLOWFISH_CBC
+ * ecc:supportedlist=CKM_EC_KEY_PAIR_GEN,CKM_ECDH1_DERIVE,CKM_ECDSA,\
+ * CKM_ECDSA_SHA1
+ * sha1:supportedlist=CKM_SHA_1,CKM_SHA_1_HMAC_GENERAL,CKM_SHA_1_HMAC
+ * sha2:supportedlist=CKM_SHA256,CKM_SHA256_HMAC,
+ * CKM_SHA256_HMAC_GENERAL,CKM_SHA384,CKM_SHA384_HMAC,\
+ * CKM_SHA384_HMAC_GENERAL,CKM_SHA512,CKM_SHA512_HMAC,\
+ * CKM_SHA512_HMAC_GENERAL
+ * md4:supportedlist=CKM_MD4
+ * md5:supportedlist=CKM_MD5,CKM_MD5_HMAC_GENERAL,CKM_MD5_HMAC
+ * rsa:supportedlist=CKM_RSA_PKCS,CKM_RSA_X_509,CKM_MD5_RSA_PKCS,\
+ * CKM_SHA1_RSA_PKCS,CKM_SHA256_RSA_PKCS,CKM_SHA384_RSA_PKCS,\
+ * CKM_SHA512_RSA_PKCS
+ * swrand:supportedlist=random
+ *
+ * WARNING: If you add a new kernel crypto provider or mechanism,
+ * you must update these constants.
+ *
+ * 1. To add a new mechanism to a provider add the string to the
+ * appropriate array below.
+ *
+ * 2. To add a new provider, create a new *_mechs array listing the
+ * provider's mechanism(s). For example:
+ * sha3_mechs[SHA3_MECH_COUNT] = {"CKM_SHA_3"};
+ * Add the new *_mechs array to initial_soft_config_entry[].
+ */
+ static crypto_mech_name_t des_mechs[] = {
+ "CKM_DES_CBC", "CKM_DES_ECB", "CKM_DES3_CBC", "CKM_DES3_ECB", ""};
+ static crypto_mech_name_t aes_mechs[] = {
+ "CKM_AES_ECB", "CKM_AES_CBC", "CKM_AES_CTR", "CKM_AES_CCM", ""};
+ static crypto_mech_name_t arcfour_mechs[] = {
+ "CKM_RC4", ""};
+ static crypto_mech_name_t blowfish_mechs[] = {
+ "CKM_BLOWFISH_ECB", "CKM_BLOWFISH_CBC", ""};
+ static crypto_mech_name_t ecc_mechs[] = {
+ "CKM_EC_KEY_PAIR_GEN", "CKM_ECDH1_DERIVE", "CKM_ECDSA",
+ "CKM_ECDSA_SHA1", ""};
+ static crypto_mech_name_t sha1_mechs[] = {
+ "CKM_SHA_1", "CKM_SHA_1_HMAC_GENERAL", "CKM_SHA_1_HMAC", ""};
+ static crypto_mech_name_t sha2_mechs[] = {
+ "CKM_SHA256", "CKM_SHA256_HMAC", "CKM_SHA256_HMAC_GENERAL",
+ "CKM_SHA384", "CKM_SHA384_HMAC", "CKM_SHA384_HMAC_GENERAL",
+ "CKM_SHA512", "CKM_SHA512_HMAC", "CKM_SHA512_HMAC_GENERAL", ""};
+ static crypto_mech_name_t md4_mechs[] = {
+ "CKM_MD4", ""};
+ static crypto_mech_name_t md5_mechs[] = {
+ "CKM_MD5", "CKM_MD5_HMAC_GENERAL", "CKM_MD5_HMAC", ""};
+ static crypto_mech_name_t rsa_mechs[] = {
+ "CKM_RSA_PKCS", "CKM_RSA_X_509", "CKM_MD5_RSA_PKCS",
+ "CKM_SHA1_RSA_PKCS", "CKM_SHA256_RSA_PKCS", "CKM_SHA384_RSA_PKCS",
+ "CKM_SHA512_RSA_PKCS", ""};
+ static crypto_mech_name_t swrand_mechs[] = {
+ "random", NULL};
+ static initial_soft_config_entry_t
+ initial_soft_config_entry[] = {
+ "des", des_mechs,
+ "aes", aes_mechs,
+ "arcfour", arcfour_mechs,
+ "blowfish", blowfish_mechs,
+ "ecc", ecc_mechs,
+ "sha1", sha1_mechs,
+ "sha2", sha2_mechs,
+ "md4", md4_mechs,
+ "md5", md5_mechs,
+ "rsa", rsa_mechs,
+ "swrand", swrand_mechs
+ };
+ const int initial_soft_config_entries =
+ sizeof (initial_soft_config_entry)
+ / sizeof (initial_soft_config_entry_t);
+ int i;
+
mutex_init(&soft_config_mutex, NULL, MUTEX_DRIVER, NULL);
+
+ /*
+ * Initialize soft_config_list with default providers.
+ * Populate the linked list backwards so the first entry appears first.
+ */
+ for (i = initial_soft_config_entries - 1; i >= 0; --i) {
+ initial_soft_config_entry_t *p = &initial_soft_config_entry[i];
+ crypto_mech_name_t *mechsp;
+ char *namep;
+ uint_t namelen, alloc_size;
+ int mech_count, r;
+
+ /* allocate/initialize memory for name and mechanism list */
+ namelen = strlen(p->name) + 1;
+ namep = kmem_alloc(namelen, KM_SLEEP);
+ (void) strlcpy(namep, p->name, namelen);
+ mech_count = count_mechanisms(p->mechs);
+ alloc_size = mech_count * CRYPTO_MAX_MECH_NAME;
+ mechsp = kmem_alloc(alloc_size, KM_SLEEP);
+ bcopy(p->mechs, mechsp, alloc_size);
+
+ r = add_soft_config(namep, mech_count, mechsp);
+ if (r != 0)
+ cmn_err(CE_WARN,
+ "add_soft_config(%s) failed; returned %d\n",
+ namep, r);
+ }
+#if DEBUG
+ if (kcf_frmwrk_debug >= 1)
+ kcf_soft_config_dump("kcf_soft_config_init");
+#endif /* DEBUG */
}
+#if DEBUG
/*
+ * Dump soft_config_list, containing a list of kernel software providers
+ * and (optionally) hardware providers, with updates from kcf.conf.
+ * Dump mechanism lists too if kcf_frmwrk_debug is >= 2.
+ */
+static void
+kcf_soft_config_dump(char *message)
+{
+ kcf_soft_conf_entry_t *p;
+ uint_t i;
+
+ mutex_enter(&soft_config_mutex);
+ printf("Soft provider config list soft_config_list: %s\n",
+ message != NULL ? message : "");
+
+ for (p = soft_config_list; p != NULL; p = p->ce_next) {
+ printf("ce_name: %s, %d ce_mechs\n", p->ce_name, p->ce_count);
+ if (kcf_frmwrk_debug >= 2) {
+ printf("\tce_mechs: ");
+ for (i = 0; i < p->ce_count; i++) {
+ printf("%s ", p->ce_mechs[i]);
+ }
+ printf("\n");
+ }
+ }
+ printf("(end of soft_config_list)\n");
+
+ mutex_exit(&soft_config_mutex);
+}
+#endif /* DEBUG */
+
+
+/*
* Utility routine to identify the providers to filter out and
* present only one provider. This happens when a hardware provider
* registers multiple units of the same device instance.
+ *
+ * Called from crypto_get_dev_list().
*/
static void
filter_providers(uint_t count, kcf_provider_desc_t **provider_array,
char *skip_providers, int *mech_counts, int *new_count)
{
@@ -101,11 +276,15 @@
*new_count = n;
}
-/* called from the CRYPTO_GET_DEV_LIST ioctl */
+/*
+ * Return a list of kernel hardware providers and a count of each
+ * provider's supported mechanisms.
+ * 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;
@@ -159,13 +338,13 @@
*count = new_count;
return (CRYPTO_SUCCESS);
}
/*
- * Called from the CRYPTO_GET_SOFT_LIST ioctl, this routine returns
- * a buffer containing the null terminated names of software providers
+ * Return a buffer containing the null terminated names of software providers
* loaded by CRYPTO_LOAD_SOFT_CONFIG.
+ * Called from the CRYPTO_GET_SOFT_LIST ioctl.
*/
int
crypto_get_soft_list(uint_t *count, char **array, size_t *len)
{
char *names = NULL, *namep, *end;
@@ -223,10 +402,14 @@
*count = final_count;
*len = final_size;
return (CRYPTO_SUCCESS);
}
+/*
+ * Check if a mechanism name is already in a mechanism name array
+ * Called by crypto_get_dev_info().
+ */
static boolean_t
duplicate(char *name, crypto_mech_name_t *array, int count)
{
int i;
@@ -236,11 +419,15 @@
return (B_TRUE);
}
return (B_FALSE);
}
-/* called from the CRYPTO_GET_DEV_INFO ioctl */
+/*
+ * Return a list of kernel hardware providers for a given name and instance.
+ * For each entry, also return a list of their supported mechanisms.
+ * 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;
@@ -309,21 +496,24 @@
*array = mech_names;
return (CRYPTO_SUCCESS);
}
-/* called from the CRYPTO_GET_SOFT_INFO ioctl */
+/*
+ * Given a kernel software provider name, return a list of mechanisms
+ * it supports.
+ * Called from the CRYPTO_GET_SOFT_INFO ioctl.
+ */
int
crypto_get_soft_info(caddr_t name, uint_t *count, crypto_mech_name_t **array)
{
ddi_modhandle_t modh = NULL;
kcf_provider_desc_t *provider;
int rv;
provider = kcf_prov_tab_lookup_by_name(name);
if (provider == NULL) {
- if (in_soft_config_list(name)) {
char *tmp;
int name_len;
/* strlen("crypto/") + NULL terminator == 8 */
name_len = strlen(name);
@@ -341,22 +531,26 @@
provider = kcf_prov_tab_lookup_by_name(name);
if (provider == NULL) {
return (CRYPTO_ARGUMENTS_BAD);
}
- } else {
- return (CRYPTO_ARGUMENTS_BAD);
}
- }
rv = dup_mech_names(provider, array, count, KM_SLEEP);
KCF_PROV_REFRELE(provider);
if (modh != NULL)
(void) ddi_modclose(modh);
return (rv);
}
+
+/*
+ * Change the mechanism list for a provider.
+ * If "direction" is CRYPTO_MECH_ADDED, add new mechanisms.
+ * If "direction" is CRYPTO_MECH_REMOVED, remove the mechanism list.
+ * Called from crypto_load_dev_disabled().
+ */
static void
kcf_change_mechs(kcf_provider_desc_t *provider, uint_t count,
crypto_mech_name_t *array, crypto_event_change_t direction)
{
crypto_notify_event_change_t ec;
@@ -559,11 +753,11 @@
* The check, new_count < prev_count, ensures that we do this
* only in the case where a mechanism(s) is now enabled.
* This check assumes that enable and disable are separate
* administrative actions and are not done in a single action.
*/
- if (new_count < prev_count && (in_soft_config_list(name)) &&
+ if ((new_count < prev_count) &&
(modload("crypto", name) != -1)) {
struct modctl *mcp;
boolean_t load_again = B_FALSE;
if ((mcp = mod_hold_by_name(name)) != NULL) {
@@ -588,11 +782,14 @@
crypto_load_soft_config(caddr_t name, uint_t count, crypto_mech_name_t *array)
{
return (add_soft_config(name, count, array));
}
-/* called from the CRYPTO_UNLOAD_SOFT_MODULE ioctl */
+/*
+ * Unload a kernel software crypto module.
+ * Called from the CRYPTO_UNLOAD_SOFT_MODULE ioctl.
+ */
int
crypto_unload_soft_module(caddr_t name)
{
int error;
modid_t id;
@@ -621,11 +818,14 @@
}
return (CRYPTO_SUCCESS);
}
-/* called from CRYPTO_GET_DEV_LIST ioctl */
+/*
+ * Free the list of kernel hardware crypto providers.
+ * Called by get_dev_list() for the CRYPTO_GET_DEV_LIST ioctl.
+ */
void
crypto_free_dev_list(crypto_dev_list_entry_t *array, uint_t count)
{
if (count == 0 || array == NULL)
return;
@@ -811,27 +1011,35 @@
*count = scnt - dcnt;
*array = mech_names;
return (CRYPTO_SUCCESS);
}
+/*
+ * Free memory for elements in a kcf_soft_config_entry_t. This entry must
+ * have been previously removed from the soft_config_list linked list.
+ */
static void
free_soft_config_entry(kcf_soft_conf_entry_t *p)
{
kmem_free(p->ce_name, strlen(p->ce_name) + 1);
crypto_free_mech_list(p->ce_mechs, p->ce_count);
kmem_free(p, sizeof (kcf_soft_conf_entry_t));
}
/*
- * Called from the CRYPTO_LOAD_SOFT_CONFIG ioctl, this routine stores
- * configuration information for software providers in a linked list.
+ * Store configuration information for software providers in a linked list.
* If the list already contains an entry for the specified provider
* and the specified mechanism list has at least one mechanism, then
* the mechanism list for the provider is updated. If the mechanism list
* is empty, the entry for the provider is removed.
*
- * Important note: the array argument is consumed.
+ * Called from kcf_soft_config_init() (to initially populate the list
+ * with default kernel providers) and from crypto_load_soft_config() for
+ * the CRYPTO_LOAD_SOFT_CONFIG ioctl (for third-party kernel modules).
+ *
+ * Important note: the name and array arguments must be allocated memory
+ * and are consumed in soft_config_list.
*/
static int
add_soft_config(char *name, uint_t count, crypto_mech_name_t *array)
{
static uint_t soft_config_count = 0;
@@ -879,11 +1087,11 @@
/* add to head of list */
new_entry->ce_next = soft_config_list;
soft_config_list = new_entry;
soft_config_count++;
entry = new_entry;
- } else {
+ } else { /* mechanism already in list */
kmem_free(new_entry->ce_name, name_len);
kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t));
}
/* mechanism count == 0 means remove entry from list */
@@ -948,27 +1156,6 @@
return (CRYPTO_FAILED);
*name = kmem_alloc(name_len, KM_SLEEP);
bcopy(tmp_name, *name, name_len);
return (CRYPTO_SUCCESS);
-}
-
-/*
- * This routine searches the soft_config_list for the specified
- * software provider, returning B_TRUE if it is in the list.
- */
-boolean_t
-in_soft_config_list(char *provider_name)
-{
- kcf_soft_conf_entry_t *p;
- boolean_t rv = B_FALSE;
-
- mutex_enter(&soft_config_mutex);
- for (p = soft_config_list; p != NULL; p = p->ce_next) {
- if (strcmp(provider_name, p->ce_name) == 0) {
- rv = B_TRUE;
- break;
- }
- }
- mutex_exit(&soft_config_mutex);
- return (rv);
}