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