1 /* 2 * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <assert.h> 11 #include <openssl/crypto.h> 12 #include <openssl/core_dispatch.h> 13 #include <openssl/core_names.h> 14 #include <openssl/provider.h> 15 #include <openssl/evp.h> 16 #include "internal/provider.h" 17 #include "internal/cryptlib.h" 18 #include "crypto/evp.h" 19 20 DEFINE_STACK_OF(OSSL_PROVIDER) 21 22 struct child_prov_globals { 23 const OSSL_CORE_HANDLE *handle; 24 const OSSL_CORE_HANDLE *curr_prov; 25 CRYPTO_RWLOCK *lock; 26 OSSL_FUNC_core_get_libctx_fn *c_get_libctx; 27 OSSL_FUNC_provider_register_child_cb_fn *c_provider_register_child_cb; 28 OSSL_FUNC_provider_deregister_child_cb_fn *c_provider_deregister_child_cb; 29 OSSL_FUNC_provider_name_fn *c_prov_name; 30 OSSL_FUNC_provider_get0_provider_ctx_fn *c_prov_get0_provider_ctx; 31 OSSL_FUNC_provider_get0_dispatch_fn *c_prov_get0_dispatch; 32 OSSL_FUNC_provider_up_ref_fn *c_prov_up_ref; 33 OSSL_FUNC_provider_free_fn *c_prov_free; 34 }; 35 36 static void *child_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx) 37 { 38 return OPENSSL_zalloc(sizeof(struct child_prov_globals)); 39 } 40 41 static void child_prov_ossl_ctx_free(void *vgbl) 42 { 43 struct child_prov_globals *gbl = vgbl; 44 45 CRYPTO_THREAD_lock_free(gbl->lock); 46 OPENSSL_free(gbl); 47 } 48 49 static const OSSL_LIB_CTX_METHOD child_prov_ossl_ctx_method = { 50 OSSL_LIB_CTX_METHOD_LOW_PRIORITY, 51 child_prov_ossl_ctx_new, 52 child_prov_ossl_ctx_free, 53 }; 54 55 static OSSL_provider_init_fn ossl_child_provider_init; 56 57 static int ossl_child_provider_init(const OSSL_CORE_HANDLE *handle, 58 const OSSL_DISPATCH *in, 59 const OSSL_DISPATCH **out, 60 void **provctx) 61 { 62 OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; 63 OSSL_LIB_CTX *ctx; 64 struct child_prov_globals *gbl; 65 66 for (; in->function_id != 0; in++) { 67 switch (in->function_id) { 68 case OSSL_FUNC_CORE_GET_LIBCTX: 69 c_get_libctx = OSSL_FUNC_core_get_libctx(in); 70 break; 71 default: 72 /* Just ignore anything we don't understand */ 73 break; 74 } 75 } 76 77 if (c_get_libctx == NULL) 78 return 0; 79 80 /* 81 * We need an OSSL_LIB_CTX but c_get_libctx returns OPENSSL_CORE_CTX. We are 82 * a built-in provider and so we can get away with this cast. Normal 83 * providers can't do this. 84 */ 85 ctx = (OSSL_LIB_CTX *)c_get_libctx(handle); 86 87 gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX, 88 &child_prov_ossl_ctx_method); 89 if (gbl == NULL) 90 return 0; 91 92 *provctx = gbl->c_prov_get0_provider_ctx(gbl->curr_prov); 93 *out = gbl->c_prov_get0_dispatch(gbl->curr_prov); 94 95 return 1; 96 } 97 98 static int provider_create_child_cb(const OSSL_CORE_HANDLE *prov, void *cbdata) 99 { 100 OSSL_LIB_CTX *ctx = cbdata; 101 struct child_prov_globals *gbl; 102 const char *provname; 103 OSSL_PROVIDER *cprov; 104 int ret = 0; 105 106 gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX, 107 &child_prov_ossl_ctx_method); 108 if (gbl == NULL) 109 return 0; 110 111 if (!CRYPTO_THREAD_write_lock(gbl->lock)) 112 return 0; 113 114 provname = gbl->c_prov_name(prov); 115 116 /* 117 * We're operating under a lock so we can store the "current" provider in 118 * the global data. 119 */ 120 gbl->curr_prov = prov; 121 122 if ((cprov = ossl_provider_find(ctx, provname, 1)) != NULL) { 123 /* 124 * We free the newly created ref. We rely on the provider sticking around 125 * in the provider store. 126 */ 127 ossl_provider_free(cprov); 128 129 /* 130 * The provider already exists. It could be a previously created child, 131 * or it could have been explicitly loaded. If explicitly loaded we 132 * ignore it - i.e. we don't start treating it like a child. 133 */ 134 if (!ossl_provider_activate(cprov, 0, 1)) 135 goto err; 136 } else { 137 /* 138 * Create it - passing 1 as final param so we don't try and recursively 139 * init children 140 */ 141 if ((cprov = ossl_provider_new(ctx, provname, ossl_child_provider_init, 142 1)) == NULL) 143 goto err; 144 145 if (!ossl_provider_activate(cprov, 0, 0)) { 146 ossl_provider_free(cprov); 147 goto err; 148 } 149 150 if (!ossl_provider_set_child(cprov, prov) 151 || !ossl_provider_add_to_store(cprov, NULL, 0)) { 152 ossl_provider_deactivate(cprov, 0); 153 ossl_provider_free(cprov); 154 goto err; 155 } 156 } 157 158 ret = 1; 159 err: 160 CRYPTO_THREAD_unlock(gbl->lock); 161 return ret; 162 } 163 164 static int provider_remove_child_cb(const OSSL_CORE_HANDLE *prov, void *cbdata) 165 { 166 OSSL_LIB_CTX *ctx = cbdata; 167 struct child_prov_globals *gbl; 168 const char *provname; 169 OSSL_PROVIDER *cprov; 170 171 gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX, 172 &child_prov_ossl_ctx_method); 173 if (gbl == NULL) 174 return 0; 175 176 provname = gbl->c_prov_name(prov); 177 cprov = ossl_provider_find(ctx, provname, 1); 178 if (cprov == NULL) 179 return 0; 180 /* 181 * ossl_provider_find ups the ref count, so we free it again here. We can 182 * rely on the provider store reference count. 183 */ 184 ossl_provider_free(cprov); 185 if (ossl_provider_is_child(cprov) 186 && !ossl_provider_deactivate(cprov, 1)) 187 return 0; 188 189 return 1; 190 } 191 192 static int provider_global_props_cb(const char *props, void *cbdata) 193 { 194 OSSL_LIB_CTX *ctx = cbdata; 195 196 return evp_set_default_properties_int(ctx, props, 0, 1); 197 } 198 199 int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx, 200 const OSSL_CORE_HANDLE *handle, 201 const OSSL_DISPATCH *in) 202 { 203 struct child_prov_globals *gbl; 204 205 if (ctx == NULL) 206 return 0; 207 208 gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX, 209 &child_prov_ossl_ctx_method); 210 if (gbl == NULL) 211 return 0; 212 213 gbl->handle = handle; 214 for (; in->function_id != 0; in++) { 215 switch (in->function_id) { 216 case OSSL_FUNC_CORE_GET_LIBCTX: 217 gbl->c_get_libctx = OSSL_FUNC_core_get_libctx(in); 218 break; 219 case OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB: 220 gbl->c_provider_register_child_cb 221 = OSSL_FUNC_provider_register_child_cb(in); 222 break; 223 case OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB: 224 gbl->c_provider_deregister_child_cb 225 = OSSL_FUNC_provider_deregister_child_cb(in); 226 break; 227 case OSSL_FUNC_PROVIDER_NAME: 228 gbl->c_prov_name = OSSL_FUNC_provider_name(in); 229 break; 230 case OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX: 231 gbl->c_prov_get0_provider_ctx 232 = OSSL_FUNC_provider_get0_provider_ctx(in); 233 break; 234 case OSSL_FUNC_PROVIDER_GET0_DISPATCH: 235 gbl->c_prov_get0_dispatch = OSSL_FUNC_provider_get0_dispatch(in); 236 break; 237 case OSSL_FUNC_PROVIDER_UP_REF: 238 gbl->c_prov_up_ref 239 = OSSL_FUNC_provider_up_ref(in); 240 break; 241 case OSSL_FUNC_PROVIDER_FREE: 242 gbl->c_prov_free = OSSL_FUNC_provider_free(in); 243 break; 244 default: 245 /* Just ignore anything we don't understand */ 246 break; 247 } 248 } 249 250 if (gbl->c_get_libctx == NULL 251 || gbl->c_provider_register_child_cb == NULL 252 || gbl->c_prov_name == NULL 253 || gbl->c_prov_get0_provider_ctx == NULL 254 || gbl->c_prov_get0_dispatch == NULL 255 || gbl->c_prov_up_ref == NULL 256 || gbl->c_prov_free == NULL) 257 return 0; 258 259 gbl->lock = CRYPTO_THREAD_lock_new(); 260 if (gbl->lock == NULL) 261 return 0; 262 263 if (!gbl->c_provider_register_child_cb(gbl->handle, 264 provider_create_child_cb, 265 provider_remove_child_cb, 266 provider_global_props_cb, 267 ctx)) 268 return 0; 269 270 return 1; 271 } 272 273 void ossl_provider_deinit_child(OSSL_LIB_CTX *ctx) 274 { 275 struct child_prov_globals *gbl 276 = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX, 277 &child_prov_ossl_ctx_method); 278 if (gbl == NULL) 279 return; 280 281 gbl->c_provider_deregister_child_cb(gbl->handle); 282 } 283 284 /* 285 * ossl_provider_up_ref_parent() and ossl_provider_free_parent() do 286 * nothing in "self-referencing" child providers, i.e. when the parent 287 * of the child provider is the same as the provider where this child 288 * provider was created. 289 * This allows the teardown function in the parent provider to be called 290 * at the correct moment. 291 * For child providers in other providers, the reference count is done to 292 * ensure that cross referencing is recorded. These should be cleared up 293 * through that providers teardown, as part of freeing its child libctx. 294 */ 295 296 int ossl_provider_up_ref_parent(OSSL_PROVIDER *prov, int activate) 297 { 298 struct child_prov_globals *gbl; 299 const OSSL_CORE_HANDLE *parent_handle; 300 301 gbl = ossl_lib_ctx_get_data(ossl_provider_libctx(prov), 302 OSSL_LIB_CTX_CHILD_PROVIDER_INDEX, 303 &child_prov_ossl_ctx_method); 304 if (gbl == NULL) 305 return 0; 306 307 parent_handle = ossl_provider_get_parent(prov); 308 if (parent_handle == gbl->handle) 309 return 1; 310 return gbl->c_prov_up_ref(parent_handle, activate); 311 } 312 313 int ossl_provider_free_parent(OSSL_PROVIDER *prov, int deactivate) 314 { 315 struct child_prov_globals *gbl; 316 const OSSL_CORE_HANDLE *parent_handle; 317 318 gbl = ossl_lib_ctx_get_data(ossl_provider_libctx(prov), 319 OSSL_LIB_CTX_CHILD_PROVIDER_INDEX, 320 &child_prov_ossl_ctx_method); 321 if (gbl == NULL) 322 return 0; 323 324 parent_handle = ossl_provider_get_parent(prov); 325 if (parent_handle == gbl->handle) 326 return 1; 327 return gbl->c_prov_free(ossl_provider_get_parent(prov), deactivate); 328 } 329