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