[openssl] master update

Richard Levitte levitte at openssl.org
Mon Mar 11 19:40:48 UTC 2019


The branch master has been updated
       via  c453283421299b7f8e0db6d6069c68369294a9f7 (commit)
       via  021a65527735af2ddc063d9300138660e3782a15 (commit)
       via  16c2f1bdb5f051ee2c0ac96182a0fb5bad7daa68 (commit)
       via  3374dc03edda56cbfd2a558fc62b7970eb0b9ad1 (commit)
       via  4c2883a9bf59c5ee31e8e2e101b3894a16c06950 (commit)
       via  3f4e8d6604842db4f416d029e9bbeddf90976c00 (commit)
      from  98f29466dc1ed7f80b9b8750309a41b5a1150d25 (commit)


- Log -----------------------------------------------------------------
commit c453283421299b7f8e0db6d6069c68369294a9f7
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Feb 21 21:20:53 2019 +0100

    Add documentation
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8287)

commit 021a65527735af2ddc063d9300138660e3782a15
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Feb 20 22:55:43 2019 +0100

    Add provider tests
    
    Two tests are added, one that tests the internal API, the other tests
    the public API.  Those two tests both test the same provider, which
    acts both as a built-in provider and as a loadable provider module.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8287)

commit 16c2f1bdb5f051ee2c0ac96182a0fb5bad7daa68
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Feb 20 22:55:29 2019 +0100

    Add provider module infrastructure
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8287)

commit 3374dc03edda56cbfd2a558fc62b7970eb0b9ad1
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Feb 19 23:07:57 2019 +0100

    Replumbing: New public API to load or add providers
    
    Adding a provider means creating an internal provier object and adding
    it to the store.  This allows the addition of built in providers, be it
    in the OpenSSL libraries or in any application.
    
    "Loading" a provider is defined broadly.  A built in provider is already
    "loaded" in essence and only needs activating, while a provider in a
    dynamically loadable module requires actually loading the module itself.
    In this API, "loading" a provider does both.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8287)

commit 4c2883a9bf59c5ee31e8e2e101b3894a16c06950
Author: Richard Levitte <levitte at openssl.org>
Date:   Sun Jan 20 13:14:58 2019 +0100

    Replumbing: Add the Provider Object, type OSSL_PROVIDER
    
    The OSSL_PROVIDER is the core object involved in loading a provider
    module, initialize a provider and do the initial communication of
    provider wide and core wide dispatch tables.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8287)

commit 3f4e8d6604842db4f416d029e9bbeddf90976c00
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Feb 5 23:18:50 2019 +0100

    Replumbing: Add MODULESDIR macro and OPENSSL_MODULES environment variable
    
    These will be used to point out general OpenSSL modules directory.
    ENGINE modules are kept apart for backward compatibility.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8287)

-----------------------------------------------------------------------

Summary of changes:
 Configurations/descrip.mms.tmpl          |   5 +-
 Configurations/unix-Makefile.tmpl        |   4 +-
 Configurations/windows-makefile.tmpl     |  26 +-
 crypto/build.info                        |   6 +-
 crypto/cpt_err.c                         |  12 +-
 crypto/err/openssl.txt                   |   5 +
 crypto/provider.c                        |  70 ++++++
 crypto/provider_core.c                   | 418 +++++++++++++++++++++++++++++++
 doc/internal/man3/ossl_provider_new.pod  | 196 +++++++++++++++
 doc/man3/OSSL_PROVIDER.pod               | 112 +++++++++
 include/internal/provider.h              |  61 +++++
 include/internal/symhacks.h              |  26 ++
 include/openssl/core.h                   |  20 ++
 include/openssl/core_numbers.h           |  76 ++++++
 include/openssl/cryptoerr.h              |   5 +
 include/openssl/ossl_typ.h               |   2 +
 include/openssl/provider.h               |  34 +++
 test/build.info                          |  23 ++
 test/p_test.c                            | 110 ++++++++
 test/provider_internal_test.c            |  79 ++++++
 test/provider_test.c                     |  69 +++++
 test/recipes/02-test_internal_provider.t |  18 ++
 test/recipes/04-test_provider.t          |  18 ++
 util/libcrypto.num                       |   5 +
 util/perl/OpenSSL/ParseC.pm              |   9 +
 util/private.num                         |   1 +
 util/providers.num                       |   1 +
 27 files changed, 1401 insertions(+), 10 deletions(-)
 create mode 100644 crypto/provider.c
 create mode 100644 crypto/provider_core.c
 create mode 100644 doc/internal/man3/ossl_provider_new.pod
 create mode 100644 doc/man3/OSSL_PROVIDER.pod
 create mode 100644 include/internal/provider.h
 create mode 100644 include/internal/symhacks.h
 create mode 100644 include/openssl/core_numbers.h
 create mode 100644 include/openssl/provider.h
 create mode 100644 test/p_test.c
 create mode 100644 test/provider_internal_test.c
 create mode 100644 test/provider_test.c
 create mode 100644 test/recipes/02-test_internal_provider.t
 create mode 100644 test/recipes/04-test_provider.t
 create mode 100644 util/providers.num

diff --git a/Configurations/descrip.mms.tmpl b/Configurations/descrip.mms.tmpl
index 8efdeb7..2f74756 100644
--- a/Configurations/descrip.mms.tmpl
+++ b/Configurations/descrip.mms.tmpl
@@ -167,6 +167,8 @@ OPENSSLDIR={- catdir($config{openssldir}) or
 OPENSSLDIR_C={- platform->osslprefix() -}DATAROOT:[000000]
 # Where installed ENGINE modules reside, for C
 ENGINESDIR_C={- platform->osslprefix() -}ENGINES{- $sover_dirname.$target{pointer_size} -}:
+# Where modules reside, for C
+MODULESDIR_C={- platform->osslprefix() -}MODULES{- $sover_dirname.$target{pointer_size} -}:
 
 ##### User defined commands and flags ################################
 
@@ -226,7 +228,8 @@ LIB_DEFINES={- our $lib_defines =
                                        @{$config{shared_defines}}));
                join('', $lib_defines,
                         (map { ",$_" } 'OPENSSLDIR="""$(OPENSSLDIR_C)"""',
-                                       'ENGINESDIR="""$(ENGINESDIR_C)"""'),
+                                       'ENGINESDIR="""$(ENGINESDIR_C)"""',
+                                       'MODULESDIR="""$(MODULESDIR_C)"""'),
                         '$(CNF_DEFINES)', '$(DEFINES)') -}
 LIB_INCLUDES={- our $lib_includes =
                 join(',', @{$target{lib_includes}},
diff --git a/Configurations/unix-Makefile.tmpl b/Configurations/unix-Makefile.tmpl
index dfae9af..2561c47 100644
--- a/Configurations/unix-Makefile.tmpl
+++ b/Configurations/unix-Makefile.tmpl
@@ -142,6 +142,7 @@ LIBDIR={- our $libdir = $config{libdir};
 libdir={- file_name_is_absolute($libdir)
           ? $libdir : '$(INSTALLTOP)/$(LIBDIR)' -}
 ENGINESDIR=$(libdir)/engines-{- $sover_dirname -}
+MODULESDIR=$(libdir)/ossl-modules
 
 # Convenience variable for those who want to set the rpath in shared
 # libraries and applications
@@ -238,7 +239,8 @@ LIB_CPPFLAGS={- our $lib_cppflags =
                 join(' ', $lib_cppflags,
                           (map { '-D'.$_ }
                                'OPENSSLDIR="\"$(OPENSSLDIR)\""',
-                               'ENGINESDIR="\"$(ENGINESDIR)\""'),
+                               'ENGINESDIR="\"$(ENGINESDIR)\""',
+                               'MODULESDIR="\"$(MODULESDIR)\""'),
                           '$(CNF_CPPFLAGS)', '$(CPPFLAGS)') -}
 LIB_CFLAGS={- join(' ', $target{lib_cflags} || (),
                         $target{shared_cflag} || (),
diff --git a/Configurations/windows-makefile.tmpl b/Configurations/windows-makefile.tmpl
index 6d38cfe..f327169 100644
--- a/Configurations/windows-makefile.tmpl
+++ b/Configurations/windows-makefile.tmpl
@@ -148,20 +148,33 @@ OPENSSLDIR_dev={- #
 OPENSSLDIR_dir={- canonpath($openssldir_dir) -}
 LIBDIR={- our $libdir = $config{libdir} || "lib";
           file_name_is_absolute($libdir) ? "" : $libdir -}
-ENGINESDIR_dev={- use File::Spec::Functions qw(:DEFAULT splitpath);
-                  our $enginesdir = catdir($prefix,$libdir,"engines-$sover_dirname");
-                  our ($enginesdir_dev, $enginesdir_dir, $enginesdir_file) =
-                      splitpath($enginesdir, 1);
-                  $enginesdir_dev -}
+MODULESDIR_dev={- use File::Spec::Functions qw(:DEFAULT splitpath);
+                  our $modulesprefix = catdir($prefix,$libdir);
+                  our ($modulesprefix_dev, $modulesprefix_dir,
+                       $modulesprefix_file) =
+                      splitpath($modulesprefix, 1);
+                  our $modulesdir_dev = $modulesprefix_dev;
+                  our $modulesdir_dir =
+                      catdir($modulesprefix_dir, "ossl-modules");
+                  our $modulesdir = catpath($modulesdir_dev, $modulesdir_dir);
+                  our $enginesdir_dev = $modulesprefix_dev;
+                  out $enginesdir_dir =
+                      catdir($modulesprefix_dir, "engines-$sover_dirname");
+                  our $enginesdir = catpath($enginesdir_dev, $enginesdir_dir);
+                  $modulesdir_dev -}
+MODULESDIR_dir={- canonpath($modulesdir_dir) -}
+ENGINESDIR_dev={- $enginesdir_dev -}
 ENGINESDIR_dir={- canonpath($enginesdir_dir) -}
 !IF "$(DESTDIR)" != ""
 INSTALLTOP=$(DESTDIR)$(INSTALLTOP_dir)
 OPENSSLDIR=$(DESTDIR)$(OPENSSLDIR_dir)
 ENGINESDIR=$(DESTDIR)$(ENGINESDIR_dir)
+MODULESDIR=$(DESTDIR)$(MODULESDIR_dir)
 !ELSE
 INSTALLTOP=$(INSTALLTOP_dev)$(INSTALLTOP_dir)
 OPENSSLDIR=$(OPENSSLDIR_dev)$(OPENSSLDIR_dir)
 ENGINESDIR=$(ENGINESDIR_dev)$(ENGINESDIR_dir)
+MODULESDIR=$(MODULESDIR_dev)$(MODULESDIR_dir)
 !ENDIF
 
 # $(libdir) is chosen to be compatible with the GNU coding standards
@@ -255,7 +268,8 @@ LIB_CPPFLAGS={- our $lib_cppflags =
                 join(' ', $lib_cppflags,
                           (map { '-D'.quotify1($_) }
                                "OPENSSLDIR=\"$openssldir\"",
-                               "ENGINESDIR=\"$enginesdir\""),
+                               "ENGINESDIR=\"$enginesdir\"",
+                               "MODULESDIR=\"$modulesdir\""),
                           '$(CNF_CPPFLAGS)', '$(CPPFLAGS)') -}
 LIB_CFLAGS={- join(' ', $target{lib_cflags} || (),
                         $target{shared_cflag} || (),
diff --git a/crypto/build.info b/crypto/build.info
index e3e9cee..0cca6ab 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -8,12 +8,16 @@ SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 x509v3 conf \
         err comp ocsp cms ts srp cmac ct async kmac ess
 
 LIBS=../libcrypto
+# The Core
+SOURCE[../libcrypto]=provider_core.c
+
+# Central utilities
 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 context.c sparse_array.c \
-        trace.c \
+        trace.c provider.c \
         {- $target{cpuid_asm_src} -} {- $target{uplink_aux_src} -}
 
 DEPEND[cversion.o]=buildinf.h
diff --git a/crypto/cpt_err.c b/crypto/cpt_err.c
index 8c11da8..bf7985c 100644
--- a/crypto/cpt_err.c
+++ b/crypto/cpt_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-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
@@ -32,6 +32,8 @@ static const ERR_STRING_DATA CRYPTO_str_functs[] = {
      "CRYPTO_set_ex_data"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_FIPS_MODE_SET, 0), "FIPS_mode_set"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_GET_AND_LOCK, 0), "get_and_lock"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_GET_PROVIDER_STORE, 0),
+     "get_provider_store"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OPENSSL_ATEXIT, 0), "OPENSSL_atexit"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OPENSSL_BUF2HEXSTR, 0),
      "OPENSSL_buf2hexstr"},
@@ -44,6 +46,12 @@ static const ERR_STRING_DATA CRYPTO_str_functs[] = {
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OPENSSL_SK_DEEP_COPY, 0),
      "OPENSSL_sk_deep_copy"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OPENSSL_SK_DUP, 0), "OPENSSL_sk_dup"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN, 0),
+     "OSSL_PROVIDER_add_builtin"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_ACTIVATE, 0),
+     "ossl_provider_activate"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_NEW, 0),
+     "ossl_provider_new"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PKEY_HMAC_INIT, 0), "pkey_hmac_init"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PKEY_POLY1305_INIT, 0),
      "pkey_poly1305_init"},
@@ -60,6 +68,8 @@ static const ERR_STRING_DATA CRYPTO_str_reasons[] = {
     "illegal hex digit"},
     {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_ODD_NUMBER_OF_DIGITS),
     "odd number of digits"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_PROVIDER_ALREADY_EXISTS),
+    "provider already exists"},
     {0, NULL}
 };
 
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index aec6a8d..3b3f761 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -359,6 +359,7 @@ CRYPTO_F_CRYPTO_OCB128_INIT:122:CRYPTO_ocb128_init
 CRYPTO_F_CRYPTO_SET_EX_DATA:102:CRYPTO_set_ex_data
 CRYPTO_F_FIPS_MODE_SET:109:FIPS_mode_set
 CRYPTO_F_GET_AND_LOCK:113:get_and_lock
+CRYPTO_F_GET_PROVIDER_STORE:133:get_provider_store
 CRYPTO_F_OPENSSL_ATEXIT:114:OPENSSL_atexit
 CRYPTO_F_OPENSSL_BUF2HEXSTR:117:OPENSSL_buf2hexstr
 CRYPTO_F_OPENSSL_FOPEN:119:openssl_fopen
@@ -367,6 +368,9 @@ CRYPTO_F_OPENSSL_INIT_CRYPTO:116:OPENSSL_init_crypto
 CRYPTO_F_OPENSSL_LH_NEW:126:OPENSSL_LH_new
 CRYPTO_F_OPENSSL_SK_DEEP_COPY:127:OPENSSL_sk_deep_copy
 CRYPTO_F_OPENSSL_SK_DUP:128:OPENSSL_sk_dup
+CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN:132:OSSL_PROVIDER_add_builtin
+CRYPTO_F_OSSL_PROVIDER_ACTIVATE:130:ossl_provider_activate
+CRYPTO_F_OSSL_PROVIDER_NEW:131:ossl_provider_new
 CRYPTO_F_PKEY_HMAC_INIT:123:pkey_hmac_init
 CRYPTO_F_PKEY_POLY1305_INIT:124:pkey_poly1305_init
 CRYPTO_F_PKEY_SIPHASH_INIT:125:pkey_siphash_init
@@ -2097,6 +2101,7 @@ CONF_R_VARIABLE_HAS_NO_VALUE:104:variable has no value
 CRYPTO_R_FIPS_MODE_NOT_SUPPORTED:101:fips mode not supported
 CRYPTO_R_ILLEGAL_HEX_DIGIT:102:illegal hex digit
 CRYPTO_R_ODD_NUMBER_OF_DIGITS:103:odd number of digits
+CRYPTO_R_PROVIDER_ALREADY_EXISTS:104:provider already exists
 CT_R_BASE64_DECODE_ERROR:108:base64 decode error
 CT_R_INVALID_LOG_ID_LENGTH:100:invalid log id length
 CT_R_LOG_CONF_INVALID:109:log conf invalid
diff --git a/crypto/provider.c b/crypto/provider.c
new file mode 100644
index 0000000..823d5dd
--- /dev/null
+++ b/crypto/provider.c
@@ -0,0 +1,70 @@
+/*
+ * 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 <openssl/err.h>
+#include <openssl/cryptoerr.h>
+#include <openssl/provider.h>
+#include "internal/provider.h"
+
+OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *libctx, const char *name)
+{
+    OSSL_PROVIDER *prov = NULL;
+
+    /* Find it or create it */
+    if ((prov = ossl_provider_find(libctx, name)) == NULL
+        && (prov = ossl_provider_new(libctx, name, NULL)) == NULL)
+        return NULL;
+
+    if (!ossl_provider_activate(prov)) {
+        ossl_provider_free(prov);
+        return NULL;
+    }
+
+    return prov;
+}
+
+int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov)
+{
+    ossl_provider_free(prov);
+    return 1;
+}
+
+const OSSL_ITEM *OSSL_PROVIDER_get_param_types(OSSL_PROVIDER *prov)
+{
+    return ossl_provider_get_param_types(prov);
+}
+
+int OSSL_PROVIDER_get_params(OSSL_PROVIDER *prov, const OSSL_PARAM params[])
+{
+    return ossl_provider_get_params(prov, params);
+}
+
+int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *libctx, const char *name,
+                              OSSL_provider_init_fn *init_fn)
+{
+    OSSL_PROVIDER *prov = NULL;
+
+    if (name == NULL || init_fn == NULL) {
+        CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN,
+                  ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    /* Create it */
+    if ((prov = ossl_provider_new(libctx, name, init_fn)) == NULL)
+        return 0;
+
+    /*
+     * It's safely stored in the internal store at this point,
+     * free the returned extra reference
+     */
+    ossl_provider_free(prov);
+
+    return 1;
+}
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
new file mode 100644
index 0000000..b3d44f1
--- /dev/null
+++ b/crypto/provider_core.c
@@ -0,0 +1,418 @@
+/*
+ * 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 <openssl/core.h>
+#include <openssl/core_numbers.h>
+#include <openssl/opensslv.h>
+#include "internal/cryptlib.h"
+#include "internal/thread_once.h"
+#include "internal/provider.h"
+#include "internal/refcount.h"
+
+/*-
+ * Provider Object structure
+ * =========================
+ */
+
+struct provider_store_st;        /* Forward declaration */
+
+struct ossl_provider_st {
+    /* Flag bits */
+    unsigned int flag_initialized:1;
+
+    /* OpenSSL library side data */
+    CRYPTO_REF_COUNT refcnt;
+#ifndef HAVE_ATOMICS
+    CRYPTO_RWLOCK refcnt_lock;   /* For the ref counter */
+#endif
+    char *name;
+    DSO *module;
+    OSSL_provider_init_fn *init_function;
+
+    /* Provider side functions */
+    OSSL_provider_teardown_fn *teardown;
+    OSSL_provider_get_param_types_fn *get_param_types;
+    OSSL_provider_get_params_fn *get_params;
+};
+DEFINE_STACK_OF(OSSL_PROVIDER)
+
+static int ossl_provider_cmp(const OSSL_PROVIDER * const *a,
+                             const OSSL_PROVIDER * const *b)
+{
+    return strcmp((*a)->name, (*b)->name);
+}
+
+/*-
+ * Provider Object store
+ * =====================
+ *
+ * The Provider Object store is a library context object, and therefore needs
+ * an index.
+ */
+
+struct provider_store_st {
+    STACK_OF(OSSL_PROVIDER) *providers;
+    CRYPTO_RWLOCK *lock;
+};
+static int provider_store_index = -1;
+
+static void provider_store_free(void *vstore)
+{
+    struct provider_store_st *store = vstore;
+
+    if (store == NULL)
+        return;
+    sk_OSSL_PROVIDER_pop_free(store->providers, ossl_provider_free);
+    CRYPTO_THREAD_lock_free(store->lock);
+    OPENSSL_free(store);
+}
+
+static void *provider_store_new(void)
+{
+    struct provider_store_st *store = OPENSSL_zalloc(sizeof(*store));
+
+    if (store == NULL
+        || (store->providers = sk_OSSL_PROVIDER_new(ossl_provider_cmp)) == NULL
+        || (store->lock = CRYPTO_THREAD_lock_new()) == NULL) {
+        provider_store_free(store);
+        store = NULL;
+    }
+    return store;
+}
+
+static const OPENSSL_CTX_METHOD provider_store_method = {
+    provider_store_new,
+    provider_store_free,
+};
+
+static CRYPTO_ONCE provider_store_init_flag = CRYPTO_ONCE_STATIC_INIT;
+DEFINE_RUN_ONCE_STATIC(do_provider_store_init)
+{
+    return OPENSSL_init_crypto(0, NULL)
+        && (provider_store_index =
+            openssl_ctx_new_index(&provider_store_method)) != -1;
+}
+
+
+static struct provider_store_st *get_provider_store(OPENSSL_CTX *libctx)
+{
+    struct provider_store_st *store = NULL;
+
+    if (!RUN_ONCE(&provider_store_init_flag, do_provider_store_init))
+        return NULL;
+
+    store = openssl_ctx_get_data(libctx, provider_store_index);
+    if (store == NULL)
+        CRYPTOerr(CRYPTO_F_GET_PROVIDER_STORE, ERR_R_INTERNAL_ERROR);
+    return store;
+}
+
+/*-
+ * Provider Object methods
+ * =======================
+ */
+
+int ossl_provider_upref(OSSL_PROVIDER *prov)
+{
+    int ref = 0;
+
+#ifndef HAVE_ATOMICS
+    CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock);
+#else
+    CRYPTO_UP_REF(&prov->refcnt, &ref, NULL);
+#endif
+    return ref;
+}
+
+/* Finder, constructor and destructor */
+OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name)
+{
+    struct provider_store_st *store = NULL;
+    OSSL_PROVIDER *prov = NULL;
+
+    if ((store = get_provider_store(libctx)) != NULL) {
+        OSSL_PROVIDER tmpl = { 0, };
+        int i;
+
+        tmpl.name = (char *)name;
+        CRYPTO_THREAD_write_lock(store->lock);
+        if ((i = sk_OSSL_PROVIDER_find(store->providers, &tmpl)) == -1
+            || (prov = sk_OSSL_PROVIDER_value(store->providers, i)) == NULL
+            || !ossl_provider_upref(prov))
+            prov = NULL;
+        CRYPTO_THREAD_unlock(store->lock);
+    }
+
+    return prov;
+}
+
+OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
+                                 OSSL_provider_init_fn *init_function)
+{
+    struct provider_store_st *store = NULL;
+    OSSL_PROVIDER *prov = NULL;
+
+    if ((store = get_provider_store(libctx)) == NULL)
+        return NULL;
+
+    if ((prov = ossl_provider_find(libctx, name)) != NULL) { /* refcount +1 */
+        ossl_provider_free(prov); /* refcount -1 */
+        CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW,
+                  CRYPTO_R_PROVIDER_ALREADY_EXISTS);
+        ERR_add_error_data(2, "name=", name);
+        return NULL;
+    }
+
+    if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL
+        || !ossl_provider_upref(prov) /* +1 One reference to be returned */
+        || (prov->name = OPENSSL_strdup(name)) == NULL) {
+        ossl_provider_free(prov);
+        CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    prov->init_function = init_function;
+
+    CRYPTO_THREAD_write_lock(store->lock);
+    if (!ossl_provider_upref(prov)) { /* +1 One reference for the store */
+        ossl_provider_free(prov); /* -1 Reference that was to be returned */
+        prov = NULL;
+    } else if (sk_OSSL_PROVIDER_push(store->providers, prov) == 0) {
+        ossl_provider_free(prov); /* -1 Store reference */
+        ossl_provider_free(prov); /* -1 Reference that was to be returned */
+        prov = NULL;
+    }
+    CRYPTO_THREAD_unlock(store->lock);
+
+    if (prov == NULL)
+        CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW, ERR_R_MALLOC_FAILURE);
+
+    /*
+     * At this point, the provider is only partially "loaded".  To be
+     * fully "loaded", ossl_provider_activate() must also be called.
+     */
+
+    return prov;
+}
+
+void ossl_provider_free(OSSL_PROVIDER *prov)
+{
+    if (prov != NULL) {
+        int ref = 0;
+
+#ifndef HAVE_ATOMICS
+        CRYPTO_DOWN_REF(&prov->refcnt, &ref, provider_lock);
+#else
+        CRYPTO_DOWN_REF(&prov->refcnt, &ref, NULL);
+#endif
+
+        /*
+         * When the refcount drops down to one, there is only one reference,
+         * the store.
+         * When that happens, the provider is inactivated.
+         */
+        if (ref == 1 && prov->flag_initialized) {
+            if (prov->teardown != NULL)
+                prov->teardown();
+            prov->flag_initialized = 0;
+        }
+
+        /*
+         * When the refcount drops to zero, it has been taken out of
+         * the store.  All we have to do here is clean it out.
+         */
+        if (ref == 0) {
+            DSO_free(prov->module);
+            OPENSSL_free(prov->name);
+            OPENSSL_free(prov);
+        }
+    }
+}
+
+/*
+ * Provider activation.
+ *
+ * What "activation" means depends on the provider form; for built in
+ * providers (in the library or the application alike), the provider
+ * can already be considered to be loaded, all that's needed is to
+ * initialize it.  However, for dynamically loadable provider modules,
+ * we must first load that module.
+ *
+ * Built in modules are distinguished from dynamically loaded modules
+ * with an already assigned init function.
+ */
+static const OSSL_DISPATCH *core_dispatch; /* Define further down */
+
+int ossl_provider_activate(OSSL_PROVIDER *prov)
+{
+    const OSSL_DISPATCH *provider_dispatch = NULL;
+
+    if (prov->flag_initialized)
+        return 1;
+
+    /*
+     * If the init function isn't set, it indicates that this provider is
+     * a loadable module.
+     */
+    if (prov->init_function == NULL) {
+        if (prov->module == NULL) {
+            char *platform_module_name = NULL;
+            char *module_path = NULL;
+            const char *load_dir = ossl_safe_getenv("OPENSSL_MODULES");
+
+            if ((prov->module = DSO_new()) == NULL) {
+                /* DSO_new() generates an error already */
+                return 0;
+            }
+
+            if (load_dir == NULL)
+                load_dir = MODULESDIR;
+
+            DSO_ctrl(prov->module, DSO_CTRL_SET_FLAGS,
+                     DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL);
+            if ((platform_module_name =
+                 DSO_convert_filename(prov->module, prov->name)) == NULL
+                || (module_path =
+                    DSO_merge(prov->module, platform_module_name,
+                              load_dir)) == NULL
+                || DSO_load(prov->module, module_path, NULL,
+                            DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == NULL) {
+                DSO_free(prov->module);
+                prov->module = NULL;
+            }
+
+            OPENSSL_free(platform_module_name);
+            OPENSSL_free(module_path);
+        }
+
+        if (prov->module != NULL)
+            prov->init_function = (OSSL_provider_init_fn *)
+                DSO_bind_func(prov->module, "OSSL_provider_init");
+    }
+
+    if (prov->init_function == NULL
+        || !prov->init_function(prov, core_dispatch, &provider_dispatch)) {
+        CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_ACTIVATE, ERR_R_INIT_FAIL);
+        ERR_add_error_data(2, "name=", prov->name);
+        DSO_free(prov->module);
+        prov->module = NULL;
+        return 0;
+    }
+
+    for (; provider_dispatch->function_id != 0; provider_dispatch++) {
+        switch (provider_dispatch->function_id) {
+        case OSSL_FUNC_PROVIDER_TEARDOWN:
+            prov->teardown =
+                OSSL_get_provider_teardown(provider_dispatch);
+            break;
+        case OSSL_FUNC_PROVIDER_GET_PARAM_TYPES:
+            prov->get_param_types =
+                OSSL_get_provider_get_param_types(provider_dispatch);
+            break;
+        case OSSL_FUNC_PROVIDER_GET_PARAMS:
+            prov->get_params =
+                OSSL_get_provider_get_params(provider_dispatch);
+            break;
+        }
+    }
+
+    /* With this flag set, this provider has become fully "loaded". */
+    prov->flag_initialized = 1;
+
+    return 1;
+}
+
+/* Getters of Provider Object data */
+const char *ossl_provider_name(OSSL_PROVIDER *prov)
+{
+    return prov->name;
+}
+
+const DSO *ossl_provider_dso(OSSL_PROVIDER *prov)
+{
+    return prov->module;
+}
+
+const char *ossl_provider_module_name(OSSL_PROVIDER *prov)
+{
+    return DSO_get_filename(prov->module);
+}
+
+const char *ossl_provider_module_path(OSSL_PROVIDER *prov)
+{
+    /* FIXME: Ensure it's a full path */
+    return DSO_get_filename(prov->module);
+}
+
+/* Wrappers around calls to the provider */
+void ossl_provider_teardown(const OSSL_PROVIDER *prov)
+{
+    if (prov->teardown != NULL)
+        prov->teardown();
+}
+
+const OSSL_ITEM *ossl_provider_get_param_types(const OSSL_PROVIDER *prov)
+{
+    return prov->get_param_types == NULL ? NULL : prov->get_param_types(prov);
+}
+
+int ossl_provider_get_params(const OSSL_PROVIDER *prov,
+                             const OSSL_PARAM params[])
+{
+    return prov->get_params == NULL ? 0 : prov->get_params(prov, params);
+}
+
+/*-
+ * Core functions for the provider
+ * ===============================
+ *
+ * This is the set of functions that the core makes available to the provider
+ */
+
+/*
+ * This returns a list of Provider Object parameters with their types, for
+ * discovery.  We do not expect that many providers will use this, but one
+ * never knows.
+ */
+static const OSSL_ITEM param_types[] = {
+    { OSSL_PARAM_UTF8_STRING_PTR, "openssl-version" },
+    { OSSL_PARAM_UTF8_STRING_PTR, "provider-name" },
+    { 0, NULL }
+};
+
+static const OSSL_ITEM *core_get_param_types(const OSSL_PROVIDER *prov)
+{
+    return param_types;
+}
+
+static int core_get_params(const OSSL_PROVIDER *prov, const OSSL_PARAM params[])
+{
+    int i;
+
+    for (i = 0; params[i].key != NULL; i++) {
+        if (strcmp(params[i].key, "openssl-version") == 0) {
+            *(void **)params[i].buffer = OPENSSL_VERSION_STR;
+            if (params[i].return_size)
+                *params[i].return_size = sizeof(OPENSSL_VERSION_STR);
+        } else if (strcmp(params[i].key, "provider-name") == 0) {
+            *(void **)params[i].buffer = prov->name;
+            if (params[i].return_size)
+                *params[i].return_size = strlen(prov->name) + 1;
+        }
+    }
+
+    return 1;
+}
+
+static const OSSL_DISPATCH core_dispatch_[] = {
+    { OSSL_FUNC_CORE_GET_PARAM_TYPES, (void (*)(void))core_get_param_types },
+    { OSSL_FUNC_CORE_GET_PARAMS, (void (*)(void))core_get_params },
+    { 0, NULL }
+};
+static const OSSL_DISPATCH *core_dispatch = core_dispatch_;
diff --git a/doc/internal/man3/ossl_provider_new.pod b/doc/internal/man3/ossl_provider_new.pod
new file mode 100644
index 0000000..79964d6
--- /dev/null
+++ b/doc/internal/man3/ossl_provider_new.pod
@@ -0,0 +1,196 @@
+=pod
+
+=head1 NAME
+
+ossl_provider_find, ossl_provider_new, ossl_provider_upref,
+ossl_provider_free, ossl_provider_add_module_location,
+ossl_provider_activate, ossl_provider_name, ossl_provider_dso,
+ossl_provider_module_name, ossl_provider_module_path,
+ossl_provider_teardown, ossl_provider_get_param_types,
+ossl_provider_get_params - internal provider routines
+
+=head1 SYNOPSIS
+
+ #include "internal/provider.h"
+
+ OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name);
+ OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
+                                  ossl_provider_init_fn *init_function);
+ int ossl_provider_upref(OSSL_PROVIDER *prov);
+ void ossl_provider_free(OSSL_PROVIDER *prov);
+
+ /* Setters */
+ int ossl_provider_add_module_location(OSSL_PROVIDER *prov, const char *loc);
+
+ /* Load and initialize the Provider */
+ int ossl_provider_activate(OSSL_PROVIDER *prov);
+
+ /* Getters for other library functions */
+ const char *ossl_provider_name(OSSL_PROVIDER *prov);
+ const DSO *ossl_provider_dso(OSSL_PROVIDER *prov);
+ const char *ossl_provider_module_name(OSSL_PROVIDER *prov);
+ const char *ossl_provider_module_path(OSSL_PROVIDER *prov);
+
+ /* Thin wrappers around calls to the provider */
+ void ossl_provider_teardown(const OSSL_PROVIDER *prov);
+ const OSSL_ITEM *ossl_provider_get_param_types(const OSSL_PROVIDER *prov);
+ int ossl_provider_get_params(const OSSL_PROVIDER *prov,
+                              const OSSL_PARAM params[]);
+
+=head1 DESCRIPTION
+
+C<OSSL_PROVIDER> is a type that holds all the necessary information
+to handle a provider, regardless of if it's built in to the
+application or the OpenSSL libraries, or if it's a loadable provider
+module.
+Instances of this type are commonly refered to as I<provider object>s.
+
+A I<provider object> is always stored in a set of I<provider object>s
+in the library context.
+
+I<provider object>s are reference counted.
+
+I<provider object>s are initially inactive, i.e. they are only
+recorded in the store, but are not used.
+They are activated with the first call to ossl_provider_activate(),
+and are inactivated when ossl_provider_free() has been called as many
+times as ossl_provider_activate() has.
+
+=head2 Functions
+
+ossl_provider_find() finds an existing I<provider object> in the
+I<provider object> store by C<name>.
+The I<provider object> it finds gets it's reference count
+incremented.
+
+ossl_provider_new() creates a new I<provider object> and stores it in
+the I<provider object> store, unless there already is one there with
+the same name.
+The reference counter of a newly created I<provider object> will
+always be 2; one for being added to the store, and one for the
+returned reference.
+To indicate a built-in provider, the C<init_function> argument must
+point at the provider initialization function for that provider.
+
+ossl_provider_free() decrements a I<provider object>'s reference
+counter; if it drops to one, the I<provider object> will be
+inactivated (it's teardown function is called) but kept in the store;
+if it drops down to zero, the associated module will be unloaded if
+one was loaded, and the I<provider object> will be freed.
+
+ossl_provider_add_module_location() adds a location to look for a
+provider module.
+
+ossl_provider_activate() "activates" the provider for the given
+I<provider object>.
+What "activates" means depends on what type of I<provider object> it
+is:
+
+=over 4
+
+=item *
+
+If an initialization function was given with ossl_provider_new(), that
+function will get called.
+
+=item *
+
+If no intialization function was given with ossl_provider_new(), a
+loadable module with the C<name> that was given to ossl_provider_new()
+will be located and loaded, then the symbol C<OSSL_provider_init> will
+be located in that module, and called.
+
+=back
+
+ossl_provider_name() returns the name that was given with
+ossl_provider_new().
+
+ossl_provider_dso() returns a reference to the module, for providers
+that come in the form of loadable modules.
+
+ossl_provider_module_name() returns the file name of the module, for
+providers that come in the form of loadable modules.
+
+ossl_provider_module_path() returns the full path of the module file,
+for providers that come in the form of loadable modules.
+
+ossl_provider_teardown() calls the provider's C<teardown> function, if
+the provider has one.
+
+ossl_provider_get_param_types() calls the provider's C<get_param_types>
+function, if the provider has one.
+It should return an array of C<OSSL_ITEM> to describe all the
+parameters that the provider has for the I<provider object>.
+
+ossl_provider_get_params() calls the provider's parameter request
+responder.
+It should treat the given C<OSSL_PARAM> array as described in
+L<OSSL_PARAM(3)>.
+
+=head1 NOTES
+
+Locating a provider module happens as follows:
+
+=over 4
+
+=item 1.
+
+Look in each directory given by ossl_provider_add_module_location().
+
+=item 2.
+
+Look in the directory given by the environment variable
+B<OPENSSL_MODULES>.
+
+=item 3.
+
+Look in the directory given by the OpenSSL built in macro
+B<MODULESDIR>.
+
+=back
+
+=head1 RETURN VALUES
+
+ossl_provider_find() and ossl_provider_new() return a pointer to a
+I<provider object> (C<OSSL_PROVIDER>) on success, or B<NULL> on error.
+
+ossl_provider_upref() returns the value of the reference counter after
+it has been incremented.
+
+ossl_provider_free() doesn't return any value.
+
+ossl_provider_add_module_location() and ossl_provider_activate()
+return 1 on success, or 0 on error.
+
+ossl_provider_name(), ossl_provider_dso(),
+ossl_provider_module_name(), and ossl_provider_module_path() return a
+pointer to their respective data if it's available, otherwise B<NULL>
+is returned.
+
+ossl_provider_teardown() doesnt't return any value.
+
+ossl_provider_get_param_types() returns a pointer to an C<OSSL_ITEM>
+array if this function is available in the provider, otherwise
+B<NULL>.
+
+ossl_provider_get_params() returns 1 on success, or 0 on error.
+If this function isn't available in the provider, 0 is returned.
+
+=head1 SEE ALSO
+
+L<OSSL_PROVIDER(3)>, L<provider(7)>
+
+=head1 HISTORY
+
+The functions described here were all added in OpenSSL 3.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
diff --git a/doc/man3/OSSL_PROVIDER.pod b/doc/man3/OSSL_PROVIDER.pod
new file mode 100644
index 0000000..e365366
--- /dev/null
+++ b/doc/man3/OSSL_PROVIDER.pod
@@ -0,0 +1,112 @@
+=pod
+
+=head1 NAME
+
+OSSL_PROVIDER, OSSL_PROVIDER_load, OSSL_PROVIDER_unload,
+OSSL_PROVIDER_get_param_types, OSSL_PROVIDER_get_params,
+OSSL_PROVIDER_add_builtin - provider routines
+
+=head1 SYNOPSIS
+
+ #include <openssl/provider.h>
+
+ typedef struct ossl_provider_st OSSL_PROVIDER;
+
+ OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *, const char *name);
+ int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov);
+
+ const OSSL_ITEM *OSSL_PROVIDER_get_param_types(OSSL_PROVIDER *prov);
+ int OSSL_PROVIDER_get_params(OSSL_PROVIDER *prov, const OSSL_PARAM params[]);
+
+ int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *, const char *name,
+                               ossl_provider_init_fn *init_fn);
+
+=head1 DESCRIPTION
+
+B<OSSL_PROVIDER> is a type that holds internal information about
+implementation providers (see L<provider(7)> for information on what a
+provider is).
+A provider can be built in to the application or the OpenSSL
+libraries, or can be a loadable module.
+The functions described here handle both forms.
+
+=head2 Functions
+
+OSSL_PROVIDER_add_builtin() is used to add a built in provider to
+B<OSSL_PROVIDER> store in the given library context, by associating a
+provider name with a provider initialization function.
+This name can then be used with OSSL_PROVIDER_load().
+
+OSSL_PROVIDER_load() loads and initializes a provider.
+This may simply initialize a provider that was previously added with
+OSSL_PROVIDER_add_builtin() and run its given initialization function,
+or load a provider module with the given name and run its provider
+entry point, C<OSSL_provider_init>.
+
+OSSL_PROVIDER_unload() unloads the given provider.
+For a provider added with OSSL_PROVIDER_add_builtin(), this simply
+runs its teardown function.
+
+OSSL_PROVIDER_get_param_types() is used to get a provider parameter
+descriptor set as an B<OSSL_ITEM> array.
+Each element is a tuple of an B<OSSL_PARAM> parameter type and a name
+in form of a C string.
+See L<openssl-core.h(7)> for more information on B<OSSL_ITEM> and
+parameter types.
+
+OSSL_PROVIDER_get_params() is used to get provider parameter values.
+The caller must prepare the B<OSSL_PARAM> array before calling this
+function, and the variables acting as buffers for this parameter array
+should be filled with data when it returns successfully.
+
+=head1 RETURN VALUES
+
+OSSL_PROVIDER_add() returns 1 on success, or 0 on error.
+
+OSSL_PROVIDER_load() returns a pointer to a provider object on
+success, or B<NULL> on error.
+
+OSSL_PROVIDER_unload() returns 1 on success, or 0 on error.
+
+OSSL_PROVIDER_get_param_types() returns a pointer to a constant array
+of B<OSSL_ITEM>, or NULL if none is provided.
+
+OSSL_PROVIDER_get_params() returns 1 on success, or 0 on error.
+
+=head1 EXAMPLES
+
+This demonstrates how to load the provider module "foo" and ask for
+its build number.
+
+ OSSL_PROVIDER *prov = NULL;
+ const char *build = NULL;
+ size_t built_l = 0;
+ const OSSL_PARAM request[] = {
+     { "build", OSSL_PARAM_UTF8_STRING_PTR, &build, 0, &build_l },
+     { NULL, 0, NULL, 0, NULL }
+ };
+
+ if ((prov = OSSL_PROVIDER_load(NULL, "foo")) != NULL
+     && OSSL_PROVIDER_get_params(prov, request))
+     printf("Provider 'foo' build %s\n", build);
+ else
+     ERR_print_errors_fp(stderr);
+
+=head1 SEE ALSO
+
+L<openssl-core.h(7)>, L<provider(7)>
+
+=head1 HISTORY
+
+The type and functions described here were added in OpenSSL 3.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
diff --git a/include/internal/provider.h b/include/internal/provider.h
new file mode 100644
index 0000000..44d1d70
--- /dev/null
+++ b/include/internal/provider.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+ */
+
+#ifndef OSSL_INTERNAL_PROVIDER_H
+# define OSSL_INTERNAL_PROVIDER_H
+
+# include <openssl/core.h>
+# include "internal/dso.h"
+# include "internal/symhacks.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/*
+ * namespaces:
+ *
+ * ossl_provider_       Provider Object internal API
+ * OSSL_PROVIDER        Provider Object
+ */
+
+/* Provider Object finder, constructor and destructor */
+OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name);
+OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
+                                 OSSL_provider_init_fn *init_function);
+int ossl_provider_upref(OSSL_PROVIDER *prov);
+void ossl_provider_free(OSSL_PROVIDER *prov);
+
+/* Setters */
+int ossl_provider_add_module_location(OSSL_PROVIDER *prov, const char *loc);
+
+/*
+ * Activate the Provider
+ * If the Provider is a module, the module will be loaded
+ * Inactivation is done by freeing the Provider
+ */
+int ossl_provider_activate(OSSL_PROVIDER *prov);
+
+/* Getters for other library functions */
+const char *ossl_provider_name(OSSL_PROVIDER *prov);
+const DSO *ossl_provider_dso(OSSL_PROVIDER *prov);
+const char *ossl_provider_module_name(OSSL_PROVIDER *prov);
+const char *ossl_provider_module_path(OSSL_PROVIDER *prov);
+
+/* Thin wrappers around calls to the provider */
+void ossl_provider_teardown(const OSSL_PROVIDER *prov);
+const OSSL_ITEM *ossl_provider_get_param_types(const OSSL_PROVIDER *prov);
+int ossl_provider_get_params(const OSSL_PROVIDER *prov,
+                             const OSSL_PARAM params[]);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/include/internal/symhacks.h b/include/internal/symhacks.h
new file mode 100644
index 0000000..2b09604
--- /dev/null
+++ b/include/internal/symhacks.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+ */
+
+#ifndef OSSL_INTERNAL_SYMHACKS_H
+# define OSSL_INTERNAL_SYMHACKS_H
+
+# include <openssl/e_os2.h>
+
+# if defined(OPENSSL_SYS_VMS)
+
+/* ossl_provider_get_param_types vs OSSL_PROVIDER_get_param_types */
+#  undef ossl_provider_get_param_types
+#  define ossl_provider_get_param_types           ossl_int_prov_get_param_types
+/* ossl_provider_get_params vs OSSL_PROVIDER_get_params */
+#  undef ossl_provider_get_params
+#  define ossl_provider_get_params                ossl_int_prov_get_params
+
+# endif
+
+#endif                          /* ! defined HEADER_VMS_IDHACKS_H */
diff --git a/include/openssl/core.h b/include/openssl/core.h
index 98b58be..15e8843 100644
--- a/include/openssl/core.h
+++ b/include/openssl/core.h
@@ -136,6 +136,26 @@ struct ossl_param_st {
 # define OSSL_PARAM_OCTET_STRING_PTR                    \
     (OSSL_PARAM_OCTET_STRING|OSSL_PARAM_POINTER_FLAG)
 
+/*-
+ * Provider entry point
+ * --------------------
+ *
+ * This function is expected to be present in any dynamically loadable
+ * provider module.  By definition, if this function doesn't exist in a
+ * module, that module is not an OpenSSL provider module.
+ */
+/*-
+ * |provider|   pointer to opaque type OSSL_PROVIDER.  This can be used
+ *              together with some functions passed via |in| to query data.
+ * |in|         is the array of functions that the Core passes to the provider.
+ * |out|        will be the array of base functions that the provider passes
+ *              back to the Core.
+ */
+typedef int (OSSL_provider_init_fn)(const OSSL_PROVIDER *provider,
+                                    const OSSL_DISPATCH *in,
+                                    const OSSL_DISPATCH **out);
+extern OSSL_provider_init_fn OSSL_provider_init;
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h
new file mode 100644
index 0000000..cd10938
--- /dev/null
+++ b/include/openssl/core_numbers.h
@@ -0,0 +1,76 @@
+/*
+ * 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
+ */
+
+#ifndef OSSL_CORE_NUMBERS_H
+# define OSSL_CORE_NUMBERS_H
+
+# include <openssl/core.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/*-
+ * Identities
+ * ----------
+ *
+ * All series start with 1, to allow 0 to be an array terminator.
+ * For any FUNC identity, we also provide a function signature typedef
+ * and a static inline function to extract a function pointer from a
+ * OSSL_DISPATCH element in a type safe manner.
+ *
+ * Names:
+ * for any function base name 'foo' (uppercase form 'FOO'), we will have
+ * the following:
+ * - a macro for the identity with the name OSSL_FUNC_'FOO' or derivates
+ *   thereof (to be specified further down)
+ * - a function signature typedef with the name OSSL_'foo'_fn
+ * - a function pointer extractor function with the name OSSL_'foo'
+ */
+
+/* Helper macro to create the function signature typedef and the extractor */
+#define OSSL_CORE_MAKE_FUNC(type,name,args)                             \
+    typedef type (OSSL_##name##_fn)args;                                \
+    static ossl_inline \
+    OSSL_##name##_fn *OSSL_get_##name(const OSSL_DISPATCH *opf)         \
+    {                                                                   \
+        return (OSSL_##name##_fn *)opf->function;                       \
+    }
+
+/*
+ * Core function identities, for the two OSSL_DISPATCH tables being passed
+ * in the OSSL_provider_init call.
+ *
+ * 0 serves as a marker for the end of the OSSL_DISPATCH array, and must
+ * therefore NEVER be used as a function identity.
+ */
+/* Functions provided by the Core to the provider, reserved numbers 1-1023 */
+# define OSSL_FUNC_CORE_GET_PARAM_TYPES        1
+OSSL_CORE_MAKE_FUNC(const OSSL_ITEM *,
+                    core_get_param_types,(const OSSL_PROVIDER *prov))
+# define OSSL_FUNC_CORE_GET_PARAMS             2
+OSSL_CORE_MAKE_FUNC(int,core_get_params,(const OSSL_PROVIDER *prov,
+                                         const OSSL_PARAM params[]))
+
+/* Functions provided by the provider to the Core, reserved numbers 1024-1535 */
+# define OSSL_FUNC_PROVIDER_TEARDOWN         1024
+OSSL_CORE_MAKE_FUNC(void,provider_teardown,(void))
+# define OSSL_FUNC_PROVIDER_GET_PARAM_TYPES  1025
+OSSL_CORE_MAKE_FUNC(const OSSL_ITEM *,
+                    provider_get_param_types,(const OSSL_PROVIDER *prov))
+# define OSSL_FUNC_PROVIDER_GET_PARAMS       1026
+OSSL_CORE_MAKE_FUNC(int,provider_get_params,(const OSSL_PROVIDER *prov,
+                                             const OSSL_PARAM params[]))
+
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/include/openssl/cryptoerr.h b/include/openssl/cryptoerr.h
index f07d07e..c27f05c 100644
--- a/include/openssl/cryptoerr.h
+++ b/include/openssl/cryptoerr.h
@@ -34,6 +34,7 @@ int ERR_load_CRYPTO_strings(void);
 # define CRYPTO_F_CRYPTO_SET_EX_DATA                      102
 # define CRYPTO_F_FIPS_MODE_SET                           109
 # define CRYPTO_F_GET_AND_LOCK                            113
+# define CRYPTO_F_GET_PROVIDER_STORE                      133
 # define CRYPTO_F_OPENSSL_ATEXIT                          114
 # define CRYPTO_F_OPENSSL_BUF2HEXSTR                      117
 # define CRYPTO_F_OPENSSL_FOPEN                           119
@@ -42,6 +43,9 @@ int ERR_load_CRYPTO_strings(void);
 # define CRYPTO_F_OPENSSL_LH_NEW                          126
 # define CRYPTO_F_OPENSSL_SK_DEEP_COPY                    127
 # define CRYPTO_F_OPENSSL_SK_DUP                          128
+# define CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN               132
+# define CRYPTO_F_OSSL_PROVIDER_ACTIVATE                  130
+# define CRYPTO_F_OSSL_PROVIDER_NEW                       131
 # define CRYPTO_F_PKEY_HMAC_INIT                          123
 # define CRYPTO_F_PKEY_POLY1305_INIT                      124
 # define CRYPTO_F_PKEY_SIPHASH_INIT                       125
@@ -53,5 +57,6 @@ int ERR_load_CRYPTO_strings(void);
 # define CRYPTO_R_FIPS_MODE_NOT_SUPPORTED                 101
 # define CRYPTO_R_ILLEGAL_HEX_DIGIT                       102
 # define CRYPTO_R_ODD_NUMBER_OF_DIGITS                    103
+# define CRYPTO_R_PROVIDER_ALREADY_EXISTS                 104
 
 #endif
diff --git a/include/openssl/ossl_typ.h b/include/openssl/ossl_typ.h
index 9b97e3d..07e5f02 100644
--- a/include/openssl/ossl_typ.h
+++ b/include/openssl/ossl_typ.h
@@ -18,6 +18,8 @@ extern "C" {
 
 # include <openssl/e_os2.h>
 
+typedef struct ossl_provider_st OSSL_PROVIDER; /* Provider Object */
+
 # ifdef NO_ASN1_TYPEDEFS
 #  define ASN1_INTEGER            ASN1_STRING
 #  define ASN1_ENUMERATED         ASN1_STRING
diff --git a/include/openssl/provider.h b/include/openssl/provider.h
new file mode 100644
index 0000000..7dc5b8a
--- /dev/null
+++ b/include/openssl/provider.h
@@ -0,0 +1,34 @@
+/*
+ * 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
+ */
+
+#ifndef OSSL_PROVIDER_H
+# define OSSL_PROVIDER_H
+
+# include <openssl/core.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* Load and unload a provider */
+OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *, const char *name);
+int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov);
+
+const OSSL_ITEM *OSSL_PROVIDER_get_param_types(OSSL_PROVIDER *prov);
+int OSSL_PROVIDER_get_params(OSSL_PROVIDER *prov, const OSSL_PARAM params[]);
+
+/* Add a built in providers */
+int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *, const char *name,
+                              OSSL_provider_init_fn *init_fn);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/test/build.info b/test/build.info
index 4dd400f..f7ec8a2 100644
--- a/test/build.info
+++ b/test/build.info
@@ -578,6 +578,29 @@ IF[{- !$disabled{tests} -}]
   SOURCE[context_internal_test]=context_internal_test.c
   INCLUDE[context_internal_test]=.. ../include ../apps/include
   DEPEND[context_internal_test]=../libcrypto.a libtestutil.a
+
+  PROGRAMS{noinst}=provider_internal_test
+  DEFINE[provider_internal_test]=PROVIDER_INIT_FUNCTION_NAME=p_test_init
+  SOURCE[provider_internal_test]=provider_internal_test.c p_test.c
+  INCLUDE[provider_internal_test]=../include ../apps/include
+  DEPEND[provider_internal_test]=../libcrypto.a libtestutil.a
+  PROGRAMS{noinst}=provider_test
+  DEFINE[provider_test]=PROVIDER_INIT_FUNCTION_NAME=p_test_init
+  SOURCE[provider_test]=provider_test.c p_test.c
+  INCLUDE[provider_test]=../include ../apps/include
+  DEPEND[provider_test]=../libcrypto.a libtestutil.a
+  IF[{- !$disabled{shared} -}]
+    MODULES{noinst}=p_test
+    SOURCE[p_test]=p_test.c
+    INCLUDE[p_test]=../include
+    IF[{- defined $target{shared_defflag} -}]
+      SOURCE[p_test]=p_test.ld
+      GENERATE[p_test.ld]=../util/providers.num
+    ENDIF
+  ELSE
+    DEFINE[provider_test]=OPENSSL_NO_SHARED
+    DEFINE[provider_internal_test]=OPENSSL_NO_SHARED
+  ENDIF
 ENDIF
 
 {-
diff --git a/test/p_test.c b/test/p_test.c
new file mode 100644
index 0000000..6dc0410
--- /dev/null
+++ b/test/p_test.c
@@ -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
+ */
+
+/*
+ * This is a very simple provider that does absolutely nothing except respond
+ * to provider global parameter requests.  It does this by simply echoing back
+ * a parameter request it makes to the loading library.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * When built as an object file to link the application with, we get the
+ * init function name through the macro PROVIDER_INIT_FUNCTION_NAME.  If
+ * not defined, we use the standard init function name for the shared
+ * object form.
+ */
+#ifdef PROVIDER_INIT_FUNCTION_NAME
+# define OSSL_provider_init PROVIDER_INIT_FUNCTION_NAME
+#endif
+
+#include <openssl/core.h>
+#include <openssl/core_numbers.h>
+
+static OSSL_core_get_param_types_fn *c_get_param_types = NULL;
+static OSSL_core_get_params_fn *c_get_params = NULL;
+
+/* Tell the core what params we provide and what type they are */
+static const OSSL_ITEM p_param_types[] = {
+    { OSSL_PARAM_UTF8_STRING, "greeting" },
+    { 0, NULL }
+};
+
+static const OSSL_ITEM *p_get_param_types(const OSSL_PROVIDER *_)
+{
+    return p_param_types;
+}
+
+static int p_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[])
+{
+    const OSSL_PARAM *p = params;
+    int ok = 1;
+
+    for (; ok && p->key != NULL; p++) {
+        if (strcmp(p->key, "greeting") == 0) {
+            static char *opensslv = NULL;
+            static char *provname = NULL;
+            static OSSL_PARAM counter_request[] = {
+                { "openssl-version", OSSL_PARAM_UTF8_STRING_PTR,
+                  &opensslv, sizeof(&opensslv), NULL },
+                { "provider-name", OSSL_PARAM_UTF8_STRING_PTR,
+                  &provname, sizeof(&provname), NULL},
+                { NULL, 0, NULL, 0, NULL }
+            };
+            char buf[256];
+            size_t buf_l;
+
+            if (c_get_params(prov, counter_request)) {
+                const char *versionp = *(void **)counter_request[0].buffer;
+                const char *namep = *(void **)counter_request[1].buffer;
+                sprintf(buf, "Hello OpenSSL %.20s, greetings from %s!",
+                        versionp, namep);
+            } else {
+                sprintf(buf, "Howdy stranger...");
+            }
+
+            *p->return_size = buf_l = strlen(buf) + 1;
+            if (p->buffer_size >= buf_l)
+                strncpy(p->buffer, buf, buf_l);
+            else
+                ok = 0;
+        }
+    }
+    return ok;
+}
+
+static const OSSL_DISPATCH p_test_table[] = {
+    { OSSL_FUNC_PROVIDER_GET_PARAM_TYPES, (void (*)(void))p_get_param_types },
+    { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))p_get_params },
+    { 0, NULL }
+};
+
+int OSSL_provider_init(const OSSL_PROVIDER *provider,
+                       const OSSL_DISPATCH *in,
+                       const OSSL_DISPATCH **out)
+{
+    for (; in->function_id != 0; in++) {
+        switch (in->function_id) {
+        case OSSL_FUNC_CORE_GET_PARAM_TYPES:
+            c_get_param_types = OSSL_get_core_get_param_types(in);
+            break;
+        case OSSL_FUNC_CORE_GET_PARAMS:
+            c_get_params = OSSL_get_core_get_params(in);
+            break;
+        default:
+            /* Just ignore anything we don't understand */
+            break;
+        }
+    }
+
+    *out = p_test_table;
+    return 1;
+}
diff --git a/test/provider_internal_test.c b/test/provider_internal_test.c
new file mode 100644
index 0000000..c423808
--- /dev/null
+++ b/test/provider_internal_test.c
@@ -0,0 +1,79 @@
+/*
+ * 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 <stddef.h>
+#include "internal/provider.h"
+#include "testutil.h"
+
+extern OSSL_provider_init_fn PROVIDER_INIT_FUNCTION_NAME;
+
+static char buf[256];
+static size_t buf_l = 0;
+static OSSL_PARAM greeting_request[] = {
+    { "greeting", OSSL_PARAM_UTF8_STRING, buf, sizeof(buf), &buf_l },
+    { NULL, 0, NULL, 0, NULL }
+};
+
+static int test_provider(OSSL_PROVIDER *prov)
+{
+    const char *name = NULL;
+    const char *greeting = NULL;
+    char expected_greeting[256];
+    int ret = 0;
+
+    if (!TEST_ptr(name = ossl_provider_name(prov)))
+        return 0;
+
+    snprintf(expected_greeting, sizeof(expected_greeting),
+             "Hello OpenSSL %.20s, greetings from %s!",
+             OPENSSL_VERSION_STR, name);
+
+    ret =
+        TEST_true(ossl_provider_activate(prov))
+        && TEST_true(ossl_provider_get_params(prov, greeting_request))
+        && TEST_ptr(greeting = greeting_request[0].buffer)
+        && TEST_size_t_gt(greeting_request[0].buffer_size, 0)
+        && TEST_str_eq(greeting, expected_greeting);
+
+    ossl_provider_free(prov);
+    return ret;
+}
+
+static int test_builtin_provider(void)
+{
+    const char *name = "p_test_builtin";
+    OSSL_PROVIDER *prov = NULL;
+
+    return
+        TEST_ptr(prov =
+                 ossl_provider_new(NULL, name, PROVIDER_INIT_FUNCTION_NAME))
+        && test_provider(prov);
+}
+
+#ifndef OPENSSL_NO_SHARED
+static int test_loaded_provider(void)
+{
+    const char *name = "p_test";
+    OSSL_PROVIDER *prov = NULL;
+
+    return
+        TEST_ptr(prov = ossl_provider_new(NULL, name, NULL))
+        && test_provider(prov);
+}
+#endif
+
+int setup_tests(void)
+{
+    ADD_TEST(test_builtin_provider);
+#ifndef OPENSSL_NO_SHARED
+    ADD_TEST(test_loaded_provider);
+#endif
+    return 1;
+}
+
diff --git a/test/provider_test.c b/test/provider_test.c
new file mode 100644
index 0000000..738cd7b
--- /dev/null
+++ b/test/provider_test.c
@@ -0,0 +1,69 @@
+/*
+ * 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 <stddef.h>
+#include <openssl/provider.h>
+#include "testutil.h"
+
+extern OSSL_provider_init_fn PROVIDER_INIT_FUNCTION_NAME;
+
+static char buf[256];
+static size_t buf_l = 0;
+static OSSL_PARAM greeting_request[] = {
+    { "greeting", OSSL_PARAM_UTF8_STRING, buf, sizeof(buf), &buf_l },
+    { NULL, 0, NULL, 0, NULL }
+};
+
+static int test_provider(const char *name)
+{
+    OSSL_PROVIDER *prov = NULL;
+    const char *greeting = NULL;
+    char expected_greeting[256];
+
+    snprintf(expected_greeting, sizeof(expected_greeting),
+             "Hello OpenSSL %.20s, greetings from %s!",
+             OPENSSL_VERSION_STR, name);
+
+    return
+        TEST_ptr(prov = OSSL_PROVIDER_load(NULL, name))
+        && TEST_true(OSSL_PROVIDER_get_params(prov, greeting_request))
+        && TEST_ptr(greeting = greeting_request[0].buffer)
+        && TEST_size_t_gt(greeting_request[0].buffer_size, 0)
+        && TEST_str_eq(greeting, expected_greeting)
+        && TEST_true(OSSL_PROVIDER_unload(prov));
+}
+
+static int test_builtin_provider(void)
+{
+    const char *name = "p_test_builtin";
+
+    return
+        TEST_true(OSSL_PROVIDER_add_builtin(NULL, name,
+					    PROVIDER_INIT_FUNCTION_NAME))
+        && test_provider(name);
+}
+
+#ifndef OPENSSL_NO_SHARED
+static int test_loaded_provider(void)
+{
+    const char *name = "p_test";
+
+    return test_provider(name);
+}
+#endif
+
+int setup_tests(void)
+{
+    ADD_TEST(test_builtin_provider);
+#ifndef OPENSSL_NO_SHARED
+    ADD_TEST(test_loaded_provider);
+#endif
+    return 1;
+}
+
diff --git a/test/recipes/02-test_internal_provider.t b/test/recipes/02-test_internal_provider.t
new file mode 100644
index 0000000..8275eb2
--- /dev/null
+++ b/test/recipes/02-test_internal_provider.t
@@ -0,0 +1,18 @@
+#! /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 qw(:DEFAULT bldtop_dir);
+use OpenSSL::Test::Simple;
+use OpenSSL::Test::Utils;
+
+setup("test_internal_provider");
+
+$ENV{"OPENSSL_MODULES"} = bldtop_dir("test");
+
+simple_test("test_internal_provider", "provider_internal_test");
diff --git a/test/recipes/04-test_provider.t b/test/recipes/04-test_provider.t
new file mode 100644
index 0000000..9195a42
--- /dev/null
+++ b/test/recipes/04-test_provider.t
@@ -0,0 +1,18 @@
+#! /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 qw(:DEFAULT bldtop_dir);
+use OpenSSL::Test::Simple;
+use OpenSSL::Test::Utils;
+
+setup("test_provider");
+
+$ENV{"OPENSSL_MODULES"} = bldtop_dir("test");
+
+simple_test("test_provider", "provider_test");
diff --git a/util/libcrypto.num b/util/libcrypto.num
index cb0cb22..4243593 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4655,3 +4655,8 @@ OSSL_trace_set_callback                 4610	3_0_0	EXIST::FUNCTION:
 OSSL_trace_enabled                      4611	3_0_0	EXIST::FUNCTION:
 OSSL_trace_begin                        4612	3_0_0	EXIST::FUNCTION:
 OSSL_trace_end                          4613	3_0_0	EXIST::FUNCTION:
+OSSL_PROVIDER_load                      4614	3_0_0	EXIST::FUNCTION:
+OSSL_PROVIDER_unload                    4615	3_0_0	EXIST::FUNCTION:
+OSSL_PROVIDER_add_builtin               4616	3_0_0	EXIST::FUNCTION:
+OSSL_PROVIDER_get_param_types           4617	3_0_0	EXIST::FUNCTION:
+OSSL_PROVIDER_get_params                4618	3_0_0	EXIST::FUNCTION:
diff --git a/util/perl/OpenSSL/ParseC.pm b/util/perl/OpenSSL/ParseC.pm
index 7a13930..59b08e8 100644
--- a/util/perl/OpenSSL/ParseC.pm
+++ b/util/perl/OpenSSL/ParseC.pm
@@ -578,6 +578,15 @@ my @chandlers = (
     { regexp   => qr/extern "C" (.*;)/,
       massager => sub { return ($1); },
     },
+    # any other extern is just ignored
+    { regexp   => qr/^\s*                       # Any spaces before
+                     extern                     # The keyword we look for
+                     \b                         # word to non-word boundary
+                     .*                         # Anything after
+                     ;
+                    /x,
+      massager => sub { return (); },
+    },
     # union, struct and enum definitions
     # Because this one might appear a little everywhere within type
     # definitions, we take it out and replace it with just
diff --git a/util/private.num b/util/private.num
index ad1865f..cb1997a 100644
--- a/util/private.num
+++ b/util/private.num
@@ -33,6 +33,7 @@ OPENSSL_Applink                         external
 OPENSSL_CTX                             datatype
 NAMING_AUTHORITY                        datatype
 OSSL_PARAM                              datatype
+OSSL_PROVIDER                           datatype
 OSSL_STORE_CTX                          datatype
 OSSL_STORE_INFO                         datatype
 OSSL_STORE_LOADER                       datatype
diff --git a/util/providers.num b/util/providers.num
new file mode 100644
index 0000000..4e2fa81
--- /dev/null
+++ b/util/providers.num
@@ -0,0 +1 @@
+OSSL_provider_init                     1	*	EXIST::FUNCTION:


More information about the openssl-commits mailing list