/* * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include "internal/cryptlib.h" #include "internal/thread_once.h" struct openssl_ctx_st { CRYPTO_RWLOCK *lock; CRYPTO_EX_DATA data; }; static OPENSSL_CTX default_context; static int context_init(OPENSSL_CTX *ctx) { return (ctx->lock = CRYPTO_THREAD_lock_new()) != NULL && CRYPTO_new_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL, &ctx->data); } static int context_deinit(OPENSSL_CTX *ctx) { CRYPTO_free_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL, &ctx->data); CRYPTO_THREAD_lock_free(ctx->lock); return 1; } static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT; static void do_default_context_deinit(void) { context_deinit(&default_context); } DEFINE_RUN_ONCE_STATIC(do_default_context_init) { return OPENSSL_init_crypto(0, NULL) && context_init(&default_context) && OPENSSL_atexit(do_default_context_deinit); } OPENSSL_CTX *OPENSSL_CTX_new(void) { OPENSSL_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx != NULL && !context_init(ctx)) { OPENSSL_CTX_free(ctx); ctx = NULL; } return ctx; } void OPENSSL_CTX_free(OPENSSL_CTX *ctx) { if (ctx != NULL) context_deinit(ctx); OPENSSL_free(ctx); } static void openssl_ctx_generic_new(void *parent_ign, void *ptr_ign, CRYPTO_EX_DATA *ad, int index, long argl_ign, void *argp) { const OPENSSL_CTX_METHOD *meth = argp; void *ptr = meth->new_func(); if (ptr != NULL) CRYPTO_set_ex_data(ad, index, ptr); } static void openssl_ctx_generic_free(void *parent_ign, void *ptr, CRYPTO_EX_DATA *ad, int index, long argl_ign, void *argp) { const OPENSSL_CTX_METHOD *meth = argp; meth->free_func(ptr); } int openssl_ctx_new_index(const OPENSSL_CTX_METHOD *meth) { return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_OPENSSL_CTX, 0, (void *)meth, openssl_ctx_generic_new, NULL, openssl_ctx_generic_free); } void *openssl_ctx_get_data(OPENSSL_CTX *ctx, int index) { void *data = NULL; if (ctx == NULL) { if (!RUN_ONCE(&default_context_init, do_default_context_init)) return 0; ctx = &default_context; } CRYPTO_THREAD_read_lock(ctx->lock); /* The alloc call ensures there's a value there */ if (CRYPTO_alloc_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL, &ctx->data, index)) data = CRYPTO_get_ex_data(&ctx->data, index); CRYPTO_THREAD_unlock(ctx->lock); return data; }