Browse Source

Add an OpenSSL library context

The context builds on CRYPTO_EX_DATA, allowing it to be dynamically
extended with new data from the different parts of libcrypto.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/8225)
master
Richard Levitte 3 years ago
parent
commit
d64b62998b
12 changed files with 406 additions and 3 deletions
  1. +1
    -1
      crypto/build.info
  2. +110
    -0
      crypto/context.c
  3. +117
    -0
      doc/internal/man3/openssl_ctx_get_data.pod
  4. +48
    -0
      doc/man3/OPENSSL_CTX.pod
  5. +9
    -0
      include/internal/cryptlib.h
  6. +4
    -1
      include/openssl/crypto.h
  7. +2
    -0
      include/openssl/ossl_typ.h
  8. +7
    -1
      test/build.info
  9. +89
    -0
      test/context_internal_test.c
  10. +16
    -0
      test/recipes/02-test_internal_context.t
  11. +2
    -0
      util/libcrypto.num
  12. +1
    -0
      util/private.num

+ 1
- 1
crypto/build.info View File

@ -12,7 +12,7 @@ SOURCE[../libcrypto]=\
cryptlib.c mem.c mem_dbg.c cversion.c ex_data.c cpt_err.c \
ebcdic.c uid.c o_time.c o_str.c o_dir.c o_fopen.c ctype.c \
threads_pthread.c threads_win.c threads_none.c getenv.c \
o_init.c o_fips.c mem_sec.c init.c sparse_array.c \
o_init.c o_fips.c mem_sec.c init.c context.c sparse_array.c \
{- $target{cpuid_asm_src} -} {- $target{uplink_aux_src} -}
DEPEND[cversion.o]=buildinf.h


+ 110
- 0
crypto/context.c View File

@ -0,0 +1,110 @@
/*
* 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;
}

+ 117
- 0
doc/internal/man3/openssl_ctx_get_data.pod View File

@ -0,0 +1,117 @@
=pod
=head1 NAME
openssl_ctx_new_index, openssl_ctx_free_index,
openssl_ctx_new_fn, openssl_ctx_free_fn,
openssl_ctx_set_data, openssl_ctx_get_data - internal OPENSSL_CTX routines
=head1 SYNOPSIS
#include <openssl/ossl_typ.h>
#include "internal/cryptlib.h"
typedef CRYPTO_EX_new openssl_ctx_new_fn;
typedef CRYPTO_EX_free openssl_ctx_free_fn;
typedef struct openssl_ctx_method {
void *(*new_func)(void);
void (*free_func)(void *);
} OPENSSL_CTX_METHOD;
int openssl_ctx_new_index(const OPENSSL_CTX_METHOD *meth);
void *openssl_ctx_get_data(OPENSSL_CTX *ctx, int index);
=head1 DESCRIPTION
Internally, the OpenSSL library context C<OPENSSL_CTX> is implemented
as a C<CRYPTO_EX_DATA>, which allows data from diverse parts of the
library to be added and removed dynamically.
Each such data item must have a corresponding CRYPTO_EX_DATA index
associated with it.
See the example further down to see how that's done.
openssl_ctx_new_index() allocates a new library context index, and
associates it with the functions given through C<meth>.
The functions given through that method are used to create or free
items that are stored at that index whenever a library context is
created or freed, meaning that the code that use a data item of that
index doesn't have to worry about that, just use the data available.
Deallocation of an index happens automatically when the library
context is freed.
openssl_ctx_get_data() is used to retrieve a pointer to the data in
the library context C<ctx> associated with the given C<index>.
=head1 EXAMPLES
=head2 Initialization
For a type C<FOO> that should end up in the OpenSSL library context, a
small bit of initialization is needed, i.e. to associate a constructor
and a destructor to a new index.
/* The index will always be entirely global, and dynamically allocated */
static int foo_index = -1;
typedef struct foo_st {
int i;
void *data;
} FOO;
static void *foo_new(void)
{
FOO *ptr = OPENSSL_zalloc(sizeof(*foo));
if (ptr != NULL)
ptr->i = 42;
return ptr;
}
static void foo_free(void *ptr)
{
OPENSSL_free(ptr);
}
static const OPENSSL_CTX_METHOD foo_method = {
foo_new,
foo_free
};
static int foo_init(void)
{
foo_index = openssl_ctx_new_index(foo_method);
return foo_index != -1;
}
=head2 Usage
To get and use the data stored in the library context, simply do this:
/*
* ctx is received from a caller,
* foo_index comes from the example above
*/
FOO *data = openssl_ctx_get_data(ctx, foo_index);
=head1 RETURN VALUES
openssl_ctx_new_index() returns -1 on error, otherwise the allocated
index number.
openssl_ctx_get_data() returns a pointer on success, or C<NULL> on
failure.
=head1 SEE ALSO
L<OPENSSL_CTX(3)>
=head1 COPYRIGHT
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
L<https://www.openssl.org/source/license.html>.
=cut

+ 48
- 0
doc/man3/OPENSSL_CTX.pod View File

@ -0,0 +1,48 @@
=pod
=head1 NAME
OPENSSL_CTX, OPENSSL_CTX_new, OPENSSL_CTX_free - OpenSSL library context
=head1 SYNOPSIS
#include <openssl/crypto.h>
typedef struct openssl_ctx_st OPENSSL_CTX;
OPENSSL_CTX *OPENSSL_CTX_new(void);
void OPENSSL_CTX_free(OPENSSL_CTX *ctx);
=head1 DESCRIPTION
C<OPENSSL_CTX> is an internal OpenSSL library context type.
Applications may allocate their own, but may also use C<NULL> to use
the internal default context with functions that take a C<OPENSSL_CTX>
argument.
OPENSSL_CTX_new() creates a new OpenSSL library context.
OPENSSL_CTX_free() frees the given C<ctx>.
=head1 RETURN VALUES
OPENSSL_CTX_new() return a library context pointer on success, or
C<NULL> on error.
OPENSSL_CTX_free() doesn't return any value.
=head1 HISTORY
OPENSSL_CTX, OPENSSL_CTX_new() and OPENSSL_CTX_free()
were added in OpenSSL 3.0.0.
=head1 COPYRIGHT
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
L<https://www.openssl.org/source/license.html>.
=cut

+ 9
- 0
include/internal/cryptlib.h View File

@ -95,4 +95,13 @@ uint32_t OPENSSL_rdtsc(void);
size_t OPENSSL_instrument_bus(unsigned int *, size_t);
size_t OPENSSL_instrument_bus2(unsigned int *, size_t, size_t);
typedef struct openssl_ctx_method {
void *(*new_func)(void);
void (*free_func)(void *);
} OPENSSL_CTX_METHOD;
/* For each type of data to store in the context, an index must be created */
int openssl_ctx_new_index(const OPENSSL_CTX_METHOD *);
/* Functions to retrieve pointers to data by index */
void *openssl_ctx_get_data(OPENSSL_CTX *, int /* index */);
#endif

+ 4
- 1
include/openssl/crypto.h View File

@ -107,7 +107,8 @@ DEFINE_STACK_OF(void)
# define CRYPTO_EX_INDEX_APP 13
# define CRYPTO_EX_INDEX_UI_METHOD 14
# define CRYPTO_EX_INDEX_DRBG 15
# define CRYPTO_EX_INDEX__COUNT 16
# define CRYPTO_EX_INDEX_OPENSSL_CTX 16
# define CRYPTO_EX_INDEX__COUNT 17
/* No longer needed, so this is a no-op */
#define OPENSSL_malloc_init() while(0) continue
@ -450,6 +451,8 @@ int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key);
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void);
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b);
OPENSSL_CTX *OPENSSL_CTX_new(void);
void OPENSSL_CTX_free(OPENSSL_CTX *);
# ifdef __cplusplus
}


+ 2
- 0
include/openssl/ossl_typ.h View File

@ -179,6 +179,8 @@ typedef struct ct_policy_eval_ctx_st CT_POLICY_EVAL_CTX;
typedef struct ossl_store_info_st OSSL_STORE_INFO;
typedef struct ossl_store_search_st OSSL_STORE_SEARCH;
typedef struct openssl_ctx_st OPENSSL_CTX;
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
defined(INTMAX_MAX) && defined(UINTMAX_MAX)
typedef intmax_t ossl_intmax_t;


+ 7
- 1
test/build.info View File

@ -46,7 +46,8 @@ IF[{- !$disabled{tests} -}]
recordlentest drbgtest drbg_cavs_test sslbuffertest \
time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \
servername_test ocspapitest rsa_mp_test fatalerrtest tls13ccstest \
sysdefaulttest errtest gosttest
sysdefaulttest errtest gosttest \
context_internal_test
SOURCE[versions]=versions.c
INCLUDE[versions]=../include ../apps/include
@ -557,6 +558,11 @@ IF[{- !$disabled{tests} -}]
SOURCE[gosttest]=gosttest.c ssltestlib.c
INCLUDE[gosttest]=../include ../apps/include ..
DEPEND[gosttest]=../libcrypto ../libssl libtestutil.a
PROGRAMS{noinst}=context_internal_test
SOURCE[context_internal_test]=context_internal_test.c
INCLUDE[context_internal_test]=.. ../include ../apps/include
DEPEND[context_internal_test]=../libcrypto.a libtestutil.a
ENDIF
{-


+ 89
- 0
test/context_internal_test.c View File

@ -0,0 +1,89 @@
/*
* 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
*/
/* Internal tests for the OpenSSL library context */
#include "internal/cryptlib.h"
#include "testutil.h"
/*
* Everything between BEGIN EXAMPLE and END EXAMPLE is copied from
* doc/internal/man3/openssl_ctx_get_data.pod
*/
/*
* ======================================================================
* BEGIN EXAMPLE
*/
/* The index will always be entirely global, and dynamically allocated */
static int foo_index = -1;
typedef struct foo_st {
int i;
void *data;
} FOO;
static void *foo_new(void)
{
FOO *ptr = OPENSSL_zalloc(sizeof(*ptr));
if (ptr != NULL)
ptr->i = 42;
return ptr;
}
static void foo_free(void *ptr)
{
OPENSSL_free(ptr);
}
static const OPENSSL_CTX_METHOD foo_method = {
foo_new,
foo_free
};
static int foo_init(void) {
foo_index = openssl_ctx_new_index(&foo_method);
return foo_index != -1;
}
/*
* END EXAMPLE
* ======================================================================
*/
static int test_context(OPENSSL_CTX *ctx)
{
FOO *data = NULL;
return (TEST_ptr(data = openssl_ctx_get_data(ctx, foo_index))
/* OPENSSL_zalloc in foo_new() initialized it to zero */
&& TEST_int_eq(data->i, 42));
}
static int test_app_context(void)
{
OPENSSL_CTX *ctx = NULL;
int result = (TEST_ptr(ctx = OPENSSL_CTX_new()) && test_context(ctx));
OPENSSL_CTX_free(ctx);
return result;
}
static int test_def_context(void)
{
return test_context(NULL);
}
int setup_tests(void)
{
ADD_TEST(foo_init);
ADD_TEST(test_app_context);
ADD_TEST(test_def_context);
return 1;
}

+ 16
- 0
test/recipes/02-test_internal_context.t View File

@ -0,0 +1,16 @@
#! /usr/bin/env perl
# 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
use strict;
use OpenSSL::Test; # get 'plan'
use OpenSSL::Test::Simple;
use OpenSSL::Test::Utils;
setup("test_internal_context");
simple_test("test_internal_context", "context_internal_test");

+ 2
- 0
util/libcrypto.num View File

@ -4641,3 +4641,5 @@ EVP_KDF_size 4596 3_0_0 EXIST::FUNCTION:
EVP_KDF_derive 4597 3_0_0 EXIST::FUNCTION:
EC_GROUP_get0_field 4598 3_0_0 EXIST::FUNCTION:EC
CRYPTO_alloc_ex_data 4599 3_0_0 EXIST::FUNCTION:
OPENSSL_CTX_new 4600 3_0_0 EXIST::FUNCTION:
OPENSSL_CTX_free 4601 3_0_0 EXIST::FUNCTION:

+ 1
- 0
util/private.num View File

@ -30,6 +30,7 @@ EVP_PKEY_METHOD datatype
EVP_PKEY_ASN1_METHOD datatype
GEN_SESSION_CB datatype
OPENSSL_Applink external
OPENSSL_CTX datatype
NAMING_AUTHORITY datatype
OSSL_STORE_CTX datatype
OSSL_STORE_INFO datatype


Loading…
Cancel
Save