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