1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file is part of the core Kernel Cryptographic Framework. 28 * It implements the SPI functions exported to cryptographic 29 * providers. 30 */ 31 32 33 #include <sys/zfs_context.h> 34 #include <sys/crypto/common.h> 35 #include <sys/crypto/impl.h> 36 #include <sys/crypto/sched_impl.h> 37 #include <sys/crypto/spi.h> 38 39 static int init_prov_mechs(const crypto_provider_info_t *, 40 kcf_provider_desc_t *); 41 42 /* 43 * This routine is used to add cryptographic providers to the KEF framework. 44 * Providers pass a crypto_provider_info structure to crypto_register_provider() 45 * and get back a handle. The crypto_provider_info structure contains a 46 * list of mechanisms supported by the provider and an ops vector containing 47 * provider entry points. Providers call this routine in their _init() routine. 48 */ 49 int 50 crypto_register_provider(const crypto_provider_info_t *info, 51 crypto_kcf_provider_handle_t *handle) 52 { 53 kcf_provider_desc_t *prov_desc = NULL; 54 int ret = CRYPTO_ARGUMENTS_BAD; 55 56 /* 57 * Allocate and initialize a new provider descriptor. We also 58 * hold it and release it when done. 59 */ 60 prov_desc = kcf_alloc_provider_desc(); 61 KCF_PROV_REFHOLD(prov_desc); 62 63 /* copy provider description string */ 64 prov_desc->pd_description = info->pi_provider_description; 65 66 /* Change from Illumos: the ops vector is persistent. */ 67 prov_desc->pd_ops_vector = info->pi_ops_vector; 68 69 /* process the mechanisms supported by the provider */ 70 if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS) 71 goto bail; 72 73 /* 74 * Add provider to providers tables, also sets the descriptor 75 * pd_prov_id field. 76 */ 77 if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) { 78 undo_register_provider(prov_desc, B_FALSE); 79 goto bail; 80 } 81 82 /* 83 * The global queue is used for providers. We handle ordering 84 * of multi-part requests in the taskq routine. So, it is safe to 85 * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag 86 * to keep some entries cached to improve performance. 87 */ 88 89 mutex_enter(&prov_desc->pd_lock); 90 prov_desc->pd_state = KCF_PROV_READY; 91 mutex_exit(&prov_desc->pd_lock); 92 93 *handle = prov_desc->pd_kcf_prov_handle; 94 ret = CRYPTO_SUCCESS; 95 96 bail: 97 KCF_PROV_REFRELE(prov_desc); 98 return (ret); 99 } 100 101 /* 102 * This routine is used to notify the framework when a provider is being 103 * removed. Providers call this routine in their _fini() routine. 104 */ 105 int 106 crypto_unregister_provider(crypto_kcf_provider_handle_t handle) 107 { 108 uint_t mech_idx; 109 kcf_provider_desc_t *desc; 110 kcf_prov_state_t saved_state; 111 112 /* lookup provider descriptor */ 113 if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL) 114 return (CRYPTO_UNKNOWN_PROVIDER); 115 116 mutex_enter(&desc->pd_lock); 117 /* 118 * Check if any other thread is disabling or removing 119 * this provider. We return if this is the case. 120 */ 121 if (desc->pd_state >= KCF_PROV_DISABLED) { 122 mutex_exit(&desc->pd_lock); 123 /* Release reference held by kcf_prov_tab_lookup(). */ 124 KCF_PROV_REFRELE(desc); 125 return (CRYPTO_BUSY); 126 } 127 128 saved_state = desc->pd_state; 129 desc->pd_state = KCF_PROV_REMOVED; 130 131 /* 132 * Check if this provider is currently being used. 133 * pd_irefcnt is the number of holds from the internal 134 * structures. We add one to account for the above lookup. 135 */ 136 if (desc->pd_refcnt > desc->pd_irefcnt + 1) { 137 desc->pd_state = saved_state; 138 mutex_exit(&desc->pd_lock); 139 /* Release reference held by kcf_prov_tab_lookup(). */ 140 KCF_PROV_REFRELE(desc); 141 /* 142 * The administrator will presumably stop the clients, 143 * thus removing the holds, when they get the busy 144 * return value. Any retry will succeed then. 145 */ 146 return (CRYPTO_BUSY); 147 } 148 mutex_exit(&desc->pd_lock); 149 150 /* remove the provider from the mechanisms tables */ 151 for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; 152 mech_idx++) { 153 kcf_remove_mech_provider( 154 desc->pd_mechanisms[mech_idx].cm_mech_name, desc); 155 } 156 157 /* remove provider from providers table */ 158 if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) != 159 CRYPTO_SUCCESS) { 160 /* Release reference held by kcf_prov_tab_lookup(). */ 161 KCF_PROV_REFRELE(desc); 162 return (CRYPTO_UNKNOWN_PROVIDER); 163 } 164 165 /* Release reference held by kcf_prov_tab_lookup(). */ 166 KCF_PROV_REFRELE(desc); 167 168 /* 169 * Wait till the existing requests complete. 170 */ 171 mutex_enter(&desc->pd_lock); 172 while (desc->pd_state != KCF_PROV_FREED) 173 cv_wait(&desc->pd_remove_cv, &desc->pd_lock); 174 mutex_exit(&desc->pd_lock); 175 176 /* 177 * This is the only place where kcf_free_provider_desc() 178 * is called directly. KCF_PROV_REFRELE() should free the 179 * structure in all other places. 180 */ 181 ASSERT(desc->pd_state == KCF_PROV_FREED && 182 desc->pd_refcnt == 0); 183 kcf_free_provider_desc(desc); 184 185 return (CRYPTO_SUCCESS); 186 } 187 188 /* 189 * Process the mechanism info structures specified by the provider 190 * during registration. A NULL crypto_provider_info_t indicates 191 * an already initialized provider descriptor. 192 * 193 * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one 194 * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY 195 * if the table of mechanisms is full. 196 */ 197 static int 198 init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc) 199 { 200 uint_t mech_idx; 201 uint_t cleanup_idx; 202 int err = CRYPTO_SUCCESS; 203 kcf_prov_mech_desc_t *pmd; 204 int desc_use_count = 0; 205 206 /* 207 * Copy the mechanism list from the provider info to the provider 208 * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t 209 * element if the provider has random_ops since we keep an internal 210 * mechanism, SUN_RANDOM, in this case. 211 */ 212 if (info != NULL) { 213 ASSERT(info->pi_mechanisms != NULL); 214 desc->pd_mech_list_count = info->pi_mech_list_count; 215 desc->pd_mechanisms = info->pi_mechanisms; 216 } 217 218 /* 219 * For each mechanism support by the provider, add the provider 220 * to the corresponding KCF mechanism mech_entry chain. 221 */ 222 for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) { 223 if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) != 224 KCF_SUCCESS) 225 break; 226 227 if (pmd == NULL) 228 continue; 229 230 /* The provider will be used for this mechanism */ 231 desc_use_count++; 232 } 233 234 /* 235 * Don't allow multiple providers with disabled mechanisms 236 * to register. Subsequent enabling of mechanisms will result in 237 * an unsupported configuration, i.e. multiple providers 238 * per mechanism. 239 */ 240 if (desc_use_count == 0) 241 return (CRYPTO_ARGUMENTS_BAD); 242 243 if (err == KCF_SUCCESS) 244 return (CRYPTO_SUCCESS); 245 246 /* 247 * An error occurred while adding the mechanism, cleanup 248 * and bail. 249 */ 250 for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) { 251 kcf_remove_mech_provider( 252 desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc); 253 } 254 255 if (err == KCF_MECH_TAB_FULL) 256 return (CRYPTO_HOST_MEMORY); 257 258 return (CRYPTO_ARGUMENTS_BAD); 259 } 260 261 /* 262 * Utility routine called from failure paths in crypto_register_provider() 263 * and from crypto_load_soft_disabled(). 264 */ 265 void 266 undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov) 267 { 268 uint_t mech_idx; 269 270 /* remove the provider from the mechanisms tables */ 271 for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; 272 mech_idx++) { 273 kcf_remove_mech_provider( 274 desc->pd_mechanisms[mech_idx].cm_mech_name, desc); 275 } 276 277 /* remove provider from providers table */ 278 if (remove_prov) 279 (void) kcf_prov_tab_rem_provider(desc->pd_prov_id); 280 } 281