Print this page
6414175 kcf.conf's supportedlist not providing much usefulness

*** 21,32 **** /* * 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. */ --- 21,30 ----
*** 46,58 **** /* 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. */ 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 **, --- 44,60 ---- /* protects the the soft_config_list. */ kmutex_t 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,79 **** --- 61,254 ---- 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,111 **** *new_count = n; } ! /* 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; --- 276,290 ---- *new_count = n; } ! /* ! * 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,171 **** *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 * loaded by CRYPTO_LOAD_SOFT_CONFIG. */ int crypto_get_soft_list(uint_t *count, char **array, size_t *len) { char *names = NULL, *namep, *end; --- 338,350 ---- *count = new_count; return (CRYPTO_SUCCESS); } /* ! * 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,232 **** --- 402,415 ---- *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,246 **** return (B_TRUE); } return (B_FALSE); } ! /* 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; --- 419,433 ---- return (B_TRUE); } return (B_FALSE); } ! /* ! * 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,329 **** *array = mech_names; return (CRYPTO_SUCCESS); } ! /* 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); --- 496,519 ---- *array = mech_names; return (CRYPTO_SUCCESS); } ! /* ! * 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) { char *tmp; int name_len; /* strlen("crypto/") + NULL terminator == 8 */ name_len = strlen(name);
*** 341,362 **** 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); } 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; --- 531,556 ---- provider = kcf_prov_tab_lookup_by_name(name); if (provider == NULL) { 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,569 **** * 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)) && (modload("crypto", name) != -1)) { struct modctl *mcp; boolean_t load_again = B_FALSE; if ((mcp = mod_hold_by_name(name)) != NULL) { --- 753,763 ---- * 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) && (modload("crypto", name) != -1)) { struct modctl *mcp; boolean_t load_again = B_FALSE; if ((mcp = mod_hold_by_name(name)) != NULL) {
*** 588,598 **** 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 */ int crypto_unload_soft_module(caddr_t name) { int error; modid_t id; --- 782,795 ---- crypto_load_soft_config(caddr_t name, uint_t count, crypto_mech_name_t *array) { return (add_soft_config(name, count, array)); } ! /* ! * 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,631 **** } return (CRYPTO_SUCCESS); } ! /* called from 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; --- 818,831 ---- } return (CRYPTO_SUCCESS); } ! /* ! * 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,837 **** *count = scnt - dcnt; *array = mech_names; return (CRYPTO_SUCCESS); } 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. * 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. */ static int add_soft_config(char *name, uint_t count, crypto_mech_name_t *array) { static uint_t soft_config_count = 0; --- 1011,1045 ---- *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)); } /* ! * 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. * ! * 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,889 **** /* add to head of list */ new_entry->ce_next = soft_config_list; soft_config_list = new_entry; soft_config_count++; entry = new_entry; ! } else { 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 */ --- 1087,1097 ---- /* add to head of list */ new_entry->ce_next = soft_config_list; soft_config_list = new_entry; soft_config_count++; entry = new_entry; ! } 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,974 **** 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); } --- 1156,1161 ----