[openssl-commits] [openssl] master update

Richard Levitte levitte at openssl.org
Thu Jun 29 09:56:09 UTC 2017


The branch master has been updated
       via  6fc1d33c90015d3ad5738ec99aaa12fdb9640295 (commit)
       via  f95c439804bc227818b4290939569b515d730a63 (commit)
       via  2fad1dd26ac11dd3b4e2a87a2b19665b132f7edc (commit)
       via  8f507bc5d5fa3b848acb3db8618b55b5f643f6b3 (commit)
       via  e2e603fe7c5b35d8dadb1eec4696307d16665731 (commit)
       via  fa66949c26ad4381cbc90746c71597f2311f90a3 (commit)
       via  f91ded1fc40bbe3950ae3e971d4c84a2edf039f8 (commit)
       via  d32e10d6fadd39bf01282922a8ed3543173de440 (commit)
       via  970f467ac32af4fb5680eb5bc845f35618468bed (commit)
       via  7ad2ef366c3e96747dabee232a10b33d8fd2262a (commit)
       via  1aabc2445b126f951707b287db9a9145b003f2ca (commit)
       via  50ecedda40d0e57c635d673c1e66cb688ed9719e (commit)
       via  6d737ea09ba62b15df00cd99c4728a4dc55086df (commit)
       via  a09003ea22fd99511cc0153314c8751a84d95496 (commit)
       via  e61ec2d9babf30da3a4d94554e576bf10c1fc92c (commit)
       via  e1613d9f253329e033c62d1ed7d0b7826bf82965 (commit)
       via  c403a1ddff475ae5346ba1b9ee431a5b995a1584 (commit)
       via  9c6da42d0c61fafcf860c8a6c03efd3c33826f99 (commit)
       via  dc10560eba147b1b6484153b424d8f715c055e2f (commit)
       via  86f7b042124b3395a9c9b8dacc02dbba579ca0e8 (commit)
       via  71a5516dcc8a91a9c4fbb724ea7e3658e85f2ad2 (commit)
       via  c785fd48e68611c837f4e30027c02b84525501af (commit)
      from  a599574be17579496877bcdcc5e1eeaf5b014cf3 (commit)


- Log -----------------------------------------------------------------
commit 6fc1d33c90015d3ad5738ec99aaa12fdb9640295
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Jun 27 23:08:54 2017 +0200

    STORE 'file' scheme loader: refactor the treatment of matches
    
    Sometimes, 'file_load' couldn't really distinguish if a file handler
    matched the data and produced an error or if it didn't match the data
    at all.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit f95c439804bc227818b4290939569b515d730a63
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri May 26 18:36:26 2017 +0200

    STORE: Add an entry in NEWS and CHANGES
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 2fad1dd26ac11dd3b4e2a87a2b19665b132f7edc
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu May 18 16:07:15 2017 +0200

    STORE test recipe: Remove comment refering to OpenConnect
    
    These tests were inspired by OpenConnect and incorporated
    by permission of David Woodhouse under CLA
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 8f507bc5d5fa3b848acb3db8618b55b5f643f6b3
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Dec 13 13:47:13 2016 +0100

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

commit e2e603fe7c5b35d8dadb1eec4696307d16665731
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Dec 13 13:46:53 2016 +0100

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

commit fa66949c26ad4381cbc90746c71597f2311f90a3
Author: Richard Levitte <levitte at openssl.org>
Date:   Sun Dec 11 07:06:13 2016 +0100

    engine app: print out information on STORE loaders and STORE FILE handlers
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit f91ded1fc40bbe3950ae3e971d4c84a2edf039f8
Author: Richard Levitte <levitte at openssl.org>
Date:   Sun Dec 11 07:02:06 2016 +0100

    STORE: add ENGINE information to loaders
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit d32e10d6fadd39bf01282922a8ed3543173de440
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Feb 7 16:30:31 2017 +0100

    Test that storeutl with a directory path works as expected
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 970f467ac32af4fb5680eb5bc845f35618468bed
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Feb 7 16:19:40 2017 +0100

    STORE 'file' scheme loader: Add directory listing capability
    
    This has it recognised when the given path is a directory.  In that
    case, the file loader will give back a series of names, all as URI
    formatted as possible given the incoming URI.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 7ad2ef366c3e96747dabee232a10b33d8fd2262a
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Feb 11 01:18:29 2017 +0100

    STORE 'file' scheme loader: Add handler for encrypted PKCS#8 data
    
    Add a separate handler for encrypted PKCS#8 data.  This uses the new
    restart functionality.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 1aabc2445b126f951707b287db9a9145b003f2ca
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Feb 11 01:17:50 2017 +0100

    STORE 'file' scheme loader: refactor file_load to support decoding restart
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 50ecedda40d0e57c635d673c1e66cb688ed9719e
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 8 14:28:42 2016 +0100

    STORE: Add a OSSL_STORE_INFO type to help support file handler restarts
    
    Some containers might very simply decode into something new that
    deserves to be considered as new (embedded) data.  With the help of a
    special OSSL_STORE_INFO type, make that new data available to the
    loader functions so they can start over.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 6d737ea09ba62b15df00cd99c4728a4dc55086df
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Dec 5 15:13:01 2016 +0100

    STORE tests: add PKCS#12 tests
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit a09003ea22fd99511cc0153314c8751a84d95496
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Feb 11 01:16:07 2017 +0100

    STORE 'file' scheme loader: add support for the PKCS#12 container
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit e61ec2d9babf30da3a4d94554e576bf10c1fc92c
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Dec 5 23:15:58 2016 +0100

    STORE 'file' scheme loader: add support for containers
    
    Containers are objects that are containers for a bunch of other
    objects with types we recognise but aren't readable in a stream.  Such
    containers are read and parsed, and their content is cached, to be
    served one object at a time.
    
    This extends the FILE_HANDLER type to include a function to destroy
    the cache and a function to simulate the EOF check.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit e1613d9f253329e033c62d1ed7d0b7826bf82965
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Nov 19 20:24:17 2016 +0100

    Add a test that checks the store utility
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit c403a1ddff475ae5346ba1b9ee431a5b995a1584
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Nov 19 19:38:23 2016 +0100

    Add a simple store utility command
    
    This command can be used to view the contents of any supported type of
    information fetched from a URI, and output them in PEM format.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 9c6da42d0c61fafcf860c8a6c03efd3c33826f99
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Nov 28 17:30:21 2016 +0100

    Add a STORE loader for the "file" scheme
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit dc10560eba147b1b6484153b424d8f715c055e2f
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Nov 18 18:18:37 2016 +0100

    Make it possible to peek at BIO data through BIO_f_buffer()
    
    This is needed for the upcoming "file" scheme STORE loader.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 86f7b042124b3395a9c9b8dacc02dbba579ca0e8
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Nov 18 18:17:20 2016 +0100

    Make asn1_d2i_read_bio accessible from STORE
    
    This is needed for the upcoming "file" scheme STORE loader.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit 71a5516dcc8a91a9c4fbb724ea7e3658e85f2ad2
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 8 15:51:31 2016 +0100

    Add the STORE module
    
    This STORE module adds the following functionality:
    
    - A function OSSL_STORE_open(), OSSL_STORE_load() and OSSL_STORE_close()
      that accesses a URI and helps loading the supported objects (PKEYs,
      CERTs and CRLs for the moment) from it.
    - An opaque type OSSL_STORE_INFO that holds information on each loaded
      object.
    - A few functions to retrieve desired data from a OSSL_STORE_INFO
      reference.
    - Functions to register and unregister loaders for different URI
      schemes.  This enables dynamic addition of loaders from applications
      or from engines.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

commit c785fd48e68611c837f4e30027c02b84525501af
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Dec 6 04:29:08 2016 +0100

    Make it possible to refer to ERR_R_UI_LIB
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3542)

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

Summary of changes:
 CHANGES                                  |    9 +
 Configure                                |    2 +-
 NEWS                                     |    2 +
 apps/build.info                          |    2 +-
 apps/engine.c                            |   32 +
 apps/storeutl.c                          |  199 ++++++
 crypto/asn1/a_d2i_fp.c                   |    5 +-
 crypto/bio/bf_buff.c                     |   16 +
 crypto/err/err.c                         |    4 +
 crypto/err/err_all.c                     |    4 +-
 crypto/err/openssl.ec                    |    1 +
 crypto/err/openssl.txt                   |   48 ++
 crypto/include/internal/asn1_int.h       |    1 +
 crypto/include/internal/store.h          |   10 +
 crypto/init.c                            |    2 +
 crypto/store/build.info                  |    4 +
 crypto/store/loader_file.c               | 1140 ++++++++++++++++++++++++++++++
 crypto/store/store_err.c                 |  116 +++
 crypto/store/store_init.c                |   33 +
 crypto/store/store_lib.c                 |  409 +++++++++++
 crypto/store/store_locl.h                |   94 +++
 crypto/store/store_register.c            |  278 ++++++++
 crypto/store/store_strings.c             |   28 +
 doc/man1/storeutl.pod                    |   76 ++
 doc/man3/OSSL_STORE_INFO.pod             |  196 +++++
 doc/man3/OSSL_STORE_LOADER.pod           |  229 ++++++
 doc/man3/OSSL_STORE_open.pod             |  145 ++++
 doc/man7/ossl_store.pod                  |  103 +++
 include/openssl/bio.h                    |    2 +
 include/openssl/err.h                    |    8 +-
 include/openssl/ossl_typ.h               |    2 +
 include/openssl/store.h                  |  214 ++++++
 include/openssl/storeerr.h               |   74 ++
 test/recipes/90-test_store.t             |  349 +++++++++
 test/recipes/90-test_store_data/ca.cnf   |   56 ++
 test/recipes/90-test_store_data/user.cnf |   19 +
 util/libcrypto.num                       |   42 ++
 util/private.num                         |   11 +
 38 files changed, 3957 insertions(+), 8 deletions(-)
 create mode 100644 apps/storeutl.c
 create mode 100644 crypto/include/internal/store.h
 create mode 100644 crypto/store/build.info
 create mode 100644 crypto/store/loader_file.c
 create mode 100644 crypto/store/store_err.c
 create mode 100644 crypto/store/store_init.c
 create mode 100644 crypto/store/store_lib.c
 create mode 100644 crypto/store/store_locl.h
 create mode 100644 crypto/store/store_register.c
 create mode 100644 crypto/store/store_strings.c
 create mode 100644 doc/man1/storeutl.pod
 create mode 100644 doc/man3/OSSL_STORE_INFO.pod
 create mode 100644 doc/man3/OSSL_STORE_LOADER.pod
 create mode 100644 doc/man3/OSSL_STORE_open.pod
 create mode 100644 doc/man7/ossl_store.pod
 create mode 100644 include/openssl/store.h
 create mode 100644 include/openssl/storeerr.h
 create mode 100644 test/recipes/90-test_store.t
 create mode 100644 test/recipes/90-test_store_data/ca.cnf
 create mode 100644 test/recipes/90-test_store_data/user.cnf

diff --git a/CHANGES b/CHANGES
index bda8e22..4500fbd 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,15 @@
 
  Changes between 1.1.0f and 1.1.1 [xx XXX xxxx]
 
+  *) Add a STORE module, which implements a uniform and URI based reader of
+     stores that can contain keys, certificates, CRLs and numerous other
+     objects.  The main API is loosely based on a few stdio functions,
+     and includes OSSL_STORE_open, OSSL_STORE_load, OSSL_STORE_eof,
+     OSSL_STORE_error and OSSL_STORE_close.
+     The implementation uses backends called "loaders" to implement arbitrary
+     URI schemes.  There is one built in "loader" for the 'file' scheme.
+     [Richard Levitte]
+
   *) Add devcrypto engine.  This has been implemented against cryptodev-linux,
      then adjusted to work on FreeBSD 8.4 as well.
      Enable by configuring with 'enable-devcryptoeng'.  This is done by default
diff --git a/Configure b/Configure
index 2eacb23..e302a58 100755
--- a/Configure
+++ b/Configure
@@ -310,7 +310,7 @@ $config{sdirs} = [
     "bn", "ec", "rsa", "dsa", "dh", "dso", "engine",
     "buffer", "bio", "stack", "lhash", "rand", "err",
     "evp", "asn1", "pem", "x509", "x509v3", "conf", "txt_db", "pkcs7", "pkcs12", "comp", "ocsp", "ui",
-    "cms", "ts", "srp", "cmac", "ct", "async", "kdf"
+    "cms", "ts", "srp", "cmac", "ct", "async", "kdf", "store"
     ];
 # test/ subdirectories to build
 $config{tdirs} = [ "ossl_shim" ];
diff --git a/NEWS b/NEWS
index 4c582fc..846ca1d 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@
 
   Major changes between OpenSSL 1.1.0f and OpenSSL 1.1.1 [under development]
 
+      o 
+      o Add a STORE module (OSSL_STORE)
       o Claim the namespaces OSSL and OPENSSL, represented as symbol prefixes
 
   Major changes between OpenSSL 1.1.0e and OpenSSL 1.1.0f [25 May 2017]
diff --git a/apps/build.info b/apps/build.info
index e2ddd2b..996e5a6 100644
--- a/apps/build.info
+++ b/apps/build.info
@@ -6,7 +6,7 @@
             genpkey.c genrsa.c nseq.c ocsp.c passwd.c pkcs12.c pkcs7.c pkcs8.c
             pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c rsa.c rsautl.c
             s_client.c s_server.c s_time.c sess_id.c smime.c speed.c spkac.c
-            srp.c ts.c verify.c version.c x509.c rehash.c
+            srp.c ts.c verify.c version.c x509.c rehash.c storeutl.c
             apps.c opt.c s_cb.c s_socket.c
             app_rand.c),
           split(/\s+/, $target{apps_aux_src}) );
diff --git a/apps/engine.c b/apps/engine.c
index 49f53ee..7724084 100644
--- a/apps/engine.c
+++ b/apps/engine.c
@@ -19,6 +19,7 @@ NON_EMPTY_TRANSLATION_UNIT
 # include <openssl/err.h>
 # include <openssl/engine.h>
 # include <openssl/ssl.h>
+# include <openssl/store.h>
 
 typedef enum OPTION_choice {
     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
@@ -258,6 +259,25 @@ static void util_do_cmds(ENGINE *e, STACK_OF(OPENSSL_STRING) *cmds,
     }
 }
 
+struct util_store_cap_data {
+    ENGINE *engine;
+    char **cap_buf;
+    int *cap_size;
+    int ok;
+};
+static void util_store_cap(const OSSL_STORE_LOADER *loader, void *arg)
+{
+    struct util_store_cap_data *ctx = arg;
+
+    if (OSSL_STORE_LOADER_get0_engine(loader) == ctx->engine) {
+        char buf[256];
+        BIO_snprintf(buf, sizeof(buf), "STORE(%s)",
+                     OSSL_STORE_LOADER_get0_scheme(loader));
+        if (!append_buf(ctx->cap_buf, ctx->cap_size, buf))
+            ctx->ok = 0;
+    }
+}
+
 int engine_main(int argc, char **argv)
 {
     int ret = 1, i;
@@ -405,6 +425,18 @@ int engine_main(int argc, char **argv)
                     if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k])))
                         goto end;
  skip_pmeths:
+                {
+                    struct util_store_cap_data store_ctx;
+
+                    store_ctx.engine = e;
+                    store_ctx.cap_buf = &cap_buf;
+                    store_ctx.cap_size = &cap_size;
+                    store_ctx.ok = 1;
+
+                    OSSL_STORE_do_all_loaders(util_store_cap, &store_ctx);
+                    if (!store_ctx.ok)
+                        goto end;
+                }
                 if (cap_buf != NULL && (*cap_buf != '\0'))
                     BIO_printf(out, " [%s]\n", cap_buf);
 
diff --git a/apps/storeutl.c b/apps/storeutl.c
new file mode 100644
index 0000000..dd2f60b
--- /dev/null
+++ b/apps/storeutl.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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/opensslconf.h>
+
+#include "apps.h"
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/store.h>
+
+typedef enum OPTION_choice {
+    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ENGINE, OPT_OUT, OPT_PASSIN,
+    OPT_NOOUT, OPT_TEXT
+} OPTION_CHOICE;
+
+const OPTIONS storeutl_options[] = {
+    {OPT_HELP_STR, 1, '-', "Usage: %s [options] uri\nValid options are:\n"},
+    {"help", OPT_HELP, '-', "Display this summary"},
+    {"out", OPT_OUT, '>', "Output file - default stdout"},
+    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
+    {"text", OPT_TEXT, '-', "Print a text form of the objects"},
+    {"noout", OPT_NOOUT, '-', "No PEM output, just status"},
+#ifndef OPENSSL_NO_ENGINE
+    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
+#endif
+    {NULL}
+};
+
+int storeutl_main(int argc, char *argv[])
+{
+    OSSL_STORE_CTX *store_ctx = NULL;
+    int ret = 1, noout = 0, text = 0, items = 0;
+    char *outfile = NULL, *passin = NULL, *passinarg = NULL;
+    BIO *out = NULL;
+    ENGINE *e = NULL;
+    OPTION_CHOICE o;
+    char *prog = opt_init(argc, argv, storeutl_options);
+    PW_CB_DATA pw_cb_data;
+
+    while ((o = opt_next()) != OPT_EOF) {
+        switch (o) {
+        case OPT_EOF:
+        case OPT_ERR:
+ opthelp:
+            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
+            goto end;
+        case OPT_HELP:
+            opt_help(storeutl_options);
+            ret = 0;
+            goto end;
+        case OPT_OUT:
+            outfile = opt_arg();
+            break;
+        case OPT_PASSIN:
+            passinarg = opt_arg();
+            break;
+        case OPT_NOOUT:
+            noout = 1;
+            break;
+        case OPT_TEXT:
+            text = 1;
+            break;
+        case OPT_ENGINE:
+            e = setup_engine(opt_arg(), 0);
+            break;
+        }
+    }
+    argc = opt_num_rest();
+    argv = opt_rest();
+
+    if (argc == 0) {
+        BIO_printf(bio_err, "%s: No URI given, nothing to do...\n", prog);
+        goto opthelp;
+    }
+    if (argc > 1) {
+        BIO_printf(bio_err, "%s: Unknown extra parameters after URI\n", prog);
+        goto opthelp;
+    }
+
+    if (!app_passwd(passinarg, NULL, &passin, NULL)) {
+        BIO_printf(bio_err, "Error getting passwords\n");
+        goto end;
+    }
+    pw_cb_data.password = passin;
+    pw_cb_data.prompt_info = argv[0];
+
+    out = bio_open_default(outfile, 'w', FORMAT_TEXT);
+    if (out == NULL)
+        goto end;
+
+    if ((store_ctx = OSSL_STORE_open(argv[0], get_ui_method(), &pw_cb_data,
+                                     NULL, NULL)) == NULL) {
+        BIO_printf(bio_err, "Couldn't open file or uri %s\n", argv[0]);
+        ERR_print_errors(bio_err);
+        goto end;
+    }
+
+    /* From here on, we count errors, and we'll return the count at the end */
+    ret = 0;
+
+    for (;;) {
+        OSSL_STORE_INFO *info = OSSL_STORE_load(store_ctx);
+        int type = info == NULL ? 0 : OSSL_STORE_INFO_get_type(info);
+        const char *infostr =
+            info == NULL ? NULL : OSSL_STORE_INFO_type_string(type);
+
+        if (info == NULL) {
+            if (OSSL_STORE_eof(store_ctx))
+                break;
+
+            if (OSSL_STORE_error(store_ctx)) {
+                ERR_print_errors(bio_err);
+                ret++;
+                continue;
+            }
+
+            BIO_printf(bio_err,
+                       "ERROR: OSSL_STORE_load() returned NULL without "
+                       "eof or error indications\n");
+            BIO_printf(bio_err, "       This is an error in the loader\n");
+            ERR_print_errors(bio_err);
+            ret++;
+            break;
+        }
+
+        if (type == OSSL_STORE_INFO_NAME) {
+            const char *name = OSSL_STORE_INFO_get0_NAME(info);
+            const char *desc = OSSL_STORE_INFO_get0_NAME_description(info);
+            BIO_printf(bio_out, "%d: %s: %s\n", items, infostr, name);
+            if (desc != NULL)
+                BIO_printf(bio_out, "%s\n", desc);
+        } else {
+            BIO_printf(bio_out, "%d: %s\n", items, infostr);
+        }
+
+        /*
+         * Unfortunately, PEM_X509_INFO_write_bio() is sorely lacking in
+         * functionality, so we must figure out how exactly to write things
+         * ourselves...
+         */
+        switch (type) {
+        case OSSL_STORE_INFO_NAME:
+            break;
+        case OSSL_STORE_INFO_PARAMS:
+            if (text)
+                EVP_PKEY_print_params(out, OSSL_STORE_INFO_get0_PARAMS(info),
+                                      0, NULL);
+            if (!noout)
+                PEM_write_bio_Parameters(out,
+                                         OSSL_STORE_INFO_get0_PARAMS(info));
+            break;
+        case OSSL_STORE_INFO_PKEY:
+            if (text)
+                EVP_PKEY_print_private(out, OSSL_STORE_INFO_get0_PKEY(info),
+                                       0, NULL);
+            if (!noout)
+                PEM_write_bio_PrivateKey(out, OSSL_STORE_INFO_get0_PKEY(info),
+                                         NULL, NULL, 0, NULL, NULL);
+            break;
+        case OSSL_STORE_INFO_CERT:
+            if (text)
+                X509_print(out, OSSL_STORE_INFO_get0_CERT(info));
+            if (!noout)
+                PEM_write_bio_X509(out, OSSL_STORE_INFO_get0_CERT(info));
+            break;
+        case OSSL_STORE_INFO_CRL:
+            if (text)
+                X509_CRL_print(out, OSSL_STORE_INFO_get0_CRL(info));
+            if (!noout)
+                PEM_write_bio_X509_CRL(out, OSSL_STORE_INFO_get0_CRL(info));
+            break;
+        default:
+            BIO_printf(bio_err, "!!! Unknown code\n");
+            ret++;
+            break;
+        }
+        items++;
+        OSSL_STORE_INFO_free(info);
+    }
+    BIO_printf(out, "Total found: %d\n", items);
+
+    if (!OSSL_STORE_close(store_ctx)) {
+        ERR_print_errors(bio_err);
+        ret++;
+        goto end;
+    }
+
+ end:
+    BIO_free_all(out);
+    OPENSSL_free(passin);
+    release_engine(e);
+    return ret;
+}
diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c
index e5c1d0e..5fa4d0f 100644
--- a/crypto/asn1/a_d2i_fp.c
+++ b/crypto/asn1/a_d2i_fp.c
@@ -13,8 +13,7 @@
 #include "internal/numbers.h"
 #include <openssl/buffer.h>
 #include <openssl/asn1.h>
-
-static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
+#include "internal/asn1_int.h"
 
 #ifndef NO_OLD_ASN1
 # ifndef OPENSSL_NO_STDIO
@@ -92,7 +91,7 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
 
 #define HEADER_SIZE   8
 #define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
-static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
+int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
 {
     BUF_MEM *b;
     unsigned char *p;
diff --git a/crypto/bio/bf_buff.c b/crypto/bio/bf_buff.c
index 7a73095..255a4d4 100644
--- a/crypto/bio/bf_buff.c
+++ b/crypto/bio/bf_buff.c
@@ -255,6 +255,11 @@ static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
             return (0);
         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
         break;
+    case BIO_CTRL_EOF:
+        if (ctx->ibuf_len > 0)
+            return 0;
+        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+        break;
     case BIO_CTRL_INFO:
         ret = (long)ctx->obuf_len;
         break;
@@ -380,6 +385,17 @@ static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
             !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
             ret = 0;
         break;
+    case BIO_CTRL_PEEK:
+        /* Ensure there's stuff in the input buffer */
+        {
+            char fake_buf[1];
+            (void)buffer_read(b, fake_buf, 0);
+        }
+        if (num > ctx->ibuf_len)
+            num = ctx->ibuf_len;
+        memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num);
+        ret = num;
+        break;
     default:
         if (b->next_bio == NULL)
             return (0);
diff --git a/crypto/err/err.c b/crypto/err/err.c
index 37637a7..adbd41e 100644
--- a/crypto/err/err.c
+++ b/crypto/err/err.c
@@ -60,6 +60,7 @@ static ERR_STRING_DATA ERR_str_libraries[] = {
     {ERR_PACK(ERR_LIB_CT, 0, 0), "CT routines"},
     {ERR_PACK(ERR_LIB_ASYNC, 0, 0), "ASYNC routines"},
     {ERR_PACK(ERR_LIB_KDF, 0, 0), "KDF routines"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, 0), "STORE routines"},
     {0, NULL},
 };
 
@@ -87,6 +88,7 @@ static ERR_STRING_DATA ERR_str_functs[] = {
     {ERR_PACK(0, SYS_F_OPEN, 0), "open"},
     {ERR_PACK(0, SYS_F_CLOSE, 0), "close"},
     {ERR_PACK(0, SYS_F_IOCTL, 0), "ioctl"},
+    {ERR_PACK(0, SYS_F_STAT, 0), "stat"},
     {0, NULL},
 };
 
@@ -107,6 +109,8 @@ static ERR_STRING_DATA ERR_str_reasons[] = {
     {ERR_R_PKCS7_LIB, "PKCS7 lib"},
     {ERR_R_X509V3_LIB, "X509V3 lib"},
     {ERR_R_ENGINE_LIB, "ENGINE lib"},
+    {ERR_R_UI_LIB, "UI lib"},
+    {ERR_R_OSSL_STORE_LIB, "STORE lib"},
     {ERR_R_ECDSA_LIB, "ECDSA lib"},
 
     {ERR_R_NESTED_ASN1_ERROR, "nested asn1 error"},
diff --git a/crypto/err/err_all.c b/crypto/err/err_all.c
index 6cc8c8f..3fff594 100644
--- a/crypto/err/err_all.c
+++ b/crypto/err/err_all.c
@@ -36,6 +36,7 @@
 #include <openssl/ct.h>
 #include <openssl/async.h>
 #include <openssl/kdf.h>
+#include <openssl/store.h>
 
 int err_load_crypto_strings_int(void)
 {
@@ -93,7 +94,8 @@ int err_load_crypto_strings_int(void)
 # endif
         ERR_load_ASYNC_strings() == 0 ||
 #endif
-        ERR_load_KDF_strings() == 0)
+        ERR_load_KDF_strings() == 0 ||
+        ERR_load_OSSL_STORE_strings() == 0)
         return 0;
 
     return 1;
diff --git a/crypto/err/openssl.ec b/crypto/err/openssl.ec
index 20b6b4a..be84c7c 100644
--- a/crypto/err/openssl.ec
+++ b/crypto/err/openssl.ec
@@ -32,6 +32,7 @@ L CMS           include/openssl/cms.h           crypto/cms/cms_err.c
 L CT            include/openssl/ct.h            crypto/ct/ct_err.c
 L ASYNC         include/openssl/async.h         crypto/async/async_err.c
 L KDF           include/openssl/kdf.h           crypto/kdf/kdf_err.c
+L OSSL_STORE    include/openssl/store.h         crypto/store/store_err.c
 
 # additional header files to be scanned for function names
 L NONE          include/openssl/x509_vfy.h      NONE
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index d9fa3d3..e539302 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -724,6 +724,37 @@ OCSP_F_OCSP_REQUEST_SIGN:110:OCSP_request_sign
 OCSP_F_OCSP_REQUEST_VERIFY:116:OCSP_request_verify
 OCSP_F_OCSP_RESPONSE_GET1_BASIC:111:OCSP_response_get1_basic
 OCSP_F_PARSE_HTTP_LINE1:118:parse_http_line1
+OSSL_STORE_F_FILE_GET_PASS:118:file_get_pass
+OSSL_STORE_F_FILE_LOAD:119:file_load
+OSSL_STORE_F_FILE_LOAD_TRY_DECODE:124:file_load_try_decode
+OSSL_STORE_F_FILE_NAME_TO_URI:126:file_name_to_uri
+OSSL_STORE_F_FILE_OPEN:120:file_open
+OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT:100:ossl_store_get0_loader_int
+OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT:101:OSSL_STORE_INFO_get1_CERT
+OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL:102:OSSL_STORE_INFO_get1_CRL
+OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME:103:OSSL_STORE_INFO_get1_NAME
+OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION:135:\
+	OSSL_STORE_INFO_get1_NAME_description
+OSSL_STORE_F_OSSL_STORE_INFO_GET1_PARAMS:104:OSSL_STORE_INFO_get1_PARAMS
+OSSL_STORE_F_OSSL_STORE_INFO_GET1_PKEY:105:OSSL_STORE_INFO_get1_PKEY
+OSSL_STORE_F_OSSL_STORE_INFO_NEW_CERT:106:OSSL_STORE_INFO_new_CERT
+OSSL_STORE_F_OSSL_STORE_INFO_NEW_CRL:107:OSSL_STORE_INFO_new_CRL
+OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED:123:ossl_store_info_new_EMBEDDED
+OSSL_STORE_F_OSSL_STORE_INFO_NEW_NAME:109:OSSL_STORE_INFO_new_NAME
+OSSL_STORE_F_OSSL_STORE_INFO_NEW_PARAMS:110:OSSL_STORE_INFO_new_PARAMS
+OSSL_STORE_F_OSSL_STORE_INFO_NEW_PKEY:111:OSSL_STORE_INFO_new_PKEY
+OSSL_STORE_F_OSSL_STORE_INFO_SET0_NAME_DESCRIPTION:134:\
+	OSSL_STORE_INFO_set0_NAME_description
+OSSL_STORE_F_OSSL_STORE_INIT_ONCE:112:ossl_store_init_once
+OSSL_STORE_F_OSSL_STORE_LOADER_NEW:113:OSSL_STORE_LOADER_new
+OSSL_STORE_F_OSSL_STORE_OPEN:114:OSSL_STORE_open
+OSSL_STORE_F_OSSL_STORE_OPEN_INT:115:*
+OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT:117:ossl_store_register_loader_int
+OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT:116:\
+	ossl_store_unregister_loader_int
+OSSL_STORE_F_TRY_DECODE_PARAMS:121:try_decode_params
+OSSL_STORE_F_TRY_DECODE_PKCS12:122:try_decode_PKCS12
+OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED:125:try_decode_PKCS8Encrypted
 PEM_F_B2I_DSS:127:b2i_dss
 PEM_F_B2I_PVK_BIO:128:b2i_PVK_bio
 PEM_F_B2I_RSA:129:b2i_rsa
@@ -1950,6 +1981,23 @@ OCSP_R_STATUS_TOO_OLD:127:status too old
 OCSP_R_UNKNOWN_MESSAGE_DIGEST:119:unknown message digest
 OCSP_R_UNKNOWN_NID:120:unknown nid
 OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type
+OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type
+OSSL_STORE_R_BAD_PASSWORD_READ:115:bad password read
+OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC:113:error verifying pkcs12 mac
+OSSL_STORE_R_INVALID_SCHEME:106:invalid scheme
+OSSL_STORE_R_IS_NOT_A:112:is not a
+OSSL_STORE_R_NOT_A_CERTIFICATE:100:not a certificate
+OSSL_STORE_R_NOT_A_CRL:101:not a crl
+OSSL_STORE_R_NOT_A_KEY:102:not a key
+OSSL_STORE_R_NOT_A_NAME:103:not a name
+OSSL_STORE_R_NOT_PARAMETERS:104:not parameters
+OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR:114:passphrase callback error
+OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE:108:path must be absolute
+OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED:109:\
+	ui process interrupted or cancelled
+OSSL_STORE_R_UNREGISTERED_SCHEME:105:unregistered scheme
+OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE:110:unsupported content type
+OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED:111:uri authority unsuppored
 PEM_R_BAD_BASE64_DECODE:100:bad base64 decode
 PEM_R_BAD_DECRYPT:101:bad decrypt
 PEM_R_BAD_END_LINE:102:bad end line
diff --git a/crypto/include/internal/asn1_int.h b/crypto/include/internal/asn1_int.h
index a2e2b17..8ff919c 100644
--- a/crypto/include/internal/asn1_int.h
+++ b/crypto/include/internal/asn1_int.h
@@ -99,3 +99,4 @@ struct asn1_pctx_st {
 } /* ASN1_PCTX */ ;
 
 int asn1_valid_host(const ASN1_STRING *host);
+int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
diff --git a/crypto/include/internal/store.h b/crypto/include/internal/store.h
new file mode 100644
index 0000000..f5013dc
--- /dev/null
+++ b/crypto/include/internal/store.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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
+ */
+
+void ossl_store_cleanup_int(void);
diff --git a/crypto/init.c b/crypto/init.c
index 2d2b07d..e159a3d 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -24,6 +24,7 @@
 #include <assert.h>
 #include <internal/thread_once.h>
 #include <internal/dso.h>
+#include <internal/store.h>
 
 static int stopped = 0;
 
@@ -491,6 +492,7 @@ void OPENSSL_cleanup(void)
 #ifndef OPENSSL_NO_ENGINE
     engine_cleanup_int();
 #endif
+    ossl_store_cleanup_int();
     crypto_cleanup_all_ex_data_int();
     bio_cleanup();
     evp_cleanup_int();
diff --git a/crypto/store/build.info b/crypto/store/build.info
new file mode 100644
index 0000000..7d882f3
--- /dev/null
+++ b/crypto/store/build.info
@@ -0,0 +1,4 @@
+LIBS=../../libcrypto
+SOURCE[../../libcrypto]=\
+        store_err.c store_init.c store_lib.c store_register.c store_strings.c \
+        loader_file.c
diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c
new file mode 100644
index 0000000..ea2ec8b
--- /dev/null
+++ b/crypto/store/loader_file.c
@@ -0,0 +1,1140 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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 <string.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include <openssl/bio.h>
+#include <openssl/dsa.h>         /* For d2i_DSAPrivateKey */
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>      /* For the PKCS8 stuff o.O */
+#include <openssl/rsa.h>         /* For d2i_RSAPrivateKey */
+#include <openssl/safestack.h>
+#include <openssl/store.h>
+#include <openssl/ui.h>
+#include <openssl/x509.h>        /* For the PKCS8 stuff o.O */
+#include "internal/asn1_int.h"
+#include "internal/o_dir.h"
+#include "internal/cryptlib.h"
+#include "store_locl.h"
+
+#include "e_os.h"
+
+/*
+ *  Password prompting
+ */
+
+static char *file_get_pass(const UI_METHOD *ui_method, char *pass,
+                           size_t maxsize, const char *prompt_info, void *data)
+{
+    UI *ui = UI_new();
+    char *prompt = NULL;
+
+    if (ui == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    if (ui_method != NULL)
+        UI_set_method(ui, ui_method);
+    UI_add_user_data(ui, data);
+
+    if ((prompt = UI_construct_prompt(ui, "pass phrase",
+                                      prompt_info)) == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_MALLOC_FAILURE);
+        pass = NULL;
+    } else if (!UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD,
+                                    pass, 0, maxsize - 1)) {
+        OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_UI_LIB);
+        pass = NULL;
+    } else {
+        switch (UI_process(ui)) {
+        case -2:
+            OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS,
+                          OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED);
+            pass = NULL;
+            break;
+        case -1:
+            OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_UI_LIB);
+            pass = NULL;
+            break;
+        default:
+            break;
+        }
+    }
+
+    OPENSSL_free(prompt);
+    UI_free(ui);
+    return pass;
+}
+
+struct pem_pass_data {
+    const UI_METHOD *ui_method;
+    void *data;
+    const char *prompt_info;
+};
+static int file_fill_pem_pass_data(struct pem_pass_data *pass_data,
+                                   const char *prompt_info,
+                                   const UI_METHOD *ui_method, void *ui_data)
+{
+    if (pass_data == NULL)
+        return 0;
+    pass_data->ui_method = ui_method;
+    pass_data->data = ui_data;
+    pass_data->prompt_info = prompt_info;
+    return 1;
+}
+static int file_get_pem_pass(char *buf, int num, int w, void *data)
+{
+    struct pem_pass_data *pass_data = data;
+    char *pass = file_get_pass(pass_data->ui_method, buf, num,
+                               pass_data->prompt_info, pass_data->data);
+
+    return pass == NULL ? 0 : strlen(pass);
+}
+
+/*
+ *  The file scheme handlers
+ */
+
+/*-
+ * The try_decode function is called to check if the blob of data can
+ * be used by this handler, and if it can, decodes it into a supported
+ * OpenSSL type and returns a OSSL_STORE_INFO with the decoded data.
+ * Input:
+ *    pem_name:     If this blob comes from a PEM file, this holds
+ *                  the PEM name.  If it comes from another type of
+ *                  file, this is NULL.
+ *    pem_header:   If this blob comes from a PEM file, this holds
+ *                  the PEM headers.  If it comes from another type of
+ *                  file, this is NULL.
+ *    blob:         The blob of data to match with what this handler
+ *                  can use.
+ *    len:          The length of the blob.
+ *    handler_ctx:  For a handler marked repeatable, this pointer can
+ *                  be used to create a context for the handler.  IT IS
+ *                  THE HANDLER'S RESPONSIBILITY TO CREATE AND DESTROY
+ *                  THIS CONTEXT APPROPRIATELY, i.e. create on first call
+ *                  and destroy when about to return NULL.
+ *    matchcount:   A pointer to an int to count matches for this data.
+ *                  Usually becomes 0 (no match) or 1 (match!), but may
+ *                  be higher in the (unlikely) event that the data matches
+ *                  more than one possibility.  The int will always be
+ *                  zero when the function is called.
+ *    ui_method:    Application UI method for getting a password, pin
+ *                  or any other interactive data.
+ *    ui_data:      Application data to be passed to ui_method when
+ *                  it's called.
+ * Output:
+ *    a OSSL_STORE_INFO
+ */
+typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name,
+                                               const char *pem_header,
+                                               const unsigned char *blob,
+                                               size_t len, void **handler_ctx,
+                                               int *matchcount,
+                                               const UI_METHOD *ui_method,
+                                               void *ui_data);
+/*
+ * The eof function should return 1 if there's no more data to be found
+ * with the handler_ctx, otherwise 0.  This is only used when the handler is
+ * marked repeatable.
+ */
+typedef int (*file_eof_fn)(void *handler_ctx);
+/*
+ * The destroy_ctx function is used to destroy the handler_ctx that was
+ * intiated by a repeatable try_decode fuction.  This is only used when
+ * the handler is marked repeatable.
+ */
+typedef void (*file_destroy_ctx_fn)(void **handler_ctx);
+
+typedef struct file_handler_st {
+    const char *name;
+    file_try_decode_fn try_decode;
+    file_eof_fn eof;
+    file_destroy_ctx_fn destroy_ctx;
+
+    /* flags */
+    int repeatable;
+} FILE_HANDLER;
+
+static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,
+                                          const char *pem_header,
+                                          const unsigned char *blob,
+                                          size_t len, void **pctx,
+                                          int *matchcount,
+                                          const UI_METHOD *ui_method,
+                                          void *ui_data)
+{
+    OSSL_STORE_INFO *store_info = NULL;
+    STACK_OF(OSSL_STORE_INFO) *ctx = *pctx;
+
+    if (ctx == NULL) {
+        /* Initial parsing */
+        PKCS12 *p12;
+        int ok = 0;
+
+        if (pem_name != NULL)
+            /* No match, there is no PEM PKCS12 tag */
+            return NULL;
+
+        if ((p12 = d2i_PKCS12(NULL, &blob, len)) != NULL) {
+            char *pass = NULL;
+            char tpass[PEM_BUFSIZE];
+            EVP_PKEY *pkey = NULL;
+            X509 *cert = NULL;
+            STACK_OF(X509) *chain = NULL;
+
+            *matchcount = 1;
+
+            if (PKCS12_verify_mac(p12, "", 0)
+                || PKCS12_verify_mac(p12, NULL, 0)) {
+                pass = "";
+            } else {
+                if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE,
+                                          "PKCS12 import password",
+                                          ui_data)) == NULL) {
+                    OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS12,
+                                  OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR);
+                    goto p12_end;
+                }
+                if (!PKCS12_verify_mac(p12, pass, strlen(pass))) {
+                    OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS12,
+                                  OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC);
+                    goto p12_end;
+                }
+            }
+
+            if (PKCS12_parse(p12, pass, &pkey, &cert, &chain)) {
+                OSSL_STORE_INFO *si_pkey = NULL;
+                OSSL_STORE_INFO *si_cert = NULL;
+                OSSL_STORE_INFO *si_ca = NULL;
+
+                if ((ctx = sk_OSSL_STORE_INFO_new_null()) != NULL
+                    && (si_pkey = OSSL_STORE_INFO_new_PKEY(pkey)) != NULL
+                    && sk_OSSL_STORE_INFO_push(ctx, si_pkey) != 0
+                    && (si_cert = OSSL_STORE_INFO_new_CERT(cert)) != NULL
+                    && sk_OSSL_STORE_INFO_push(ctx, si_cert) != 0) {
+                    ok = 1;
+                    si_pkey = NULL;
+                    si_cert = NULL;
+
+                    while(sk_X509_num(chain) > 0) {
+                        X509 *ca = sk_X509_value(chain, 0);
+
+                        if ((si_ca = OSSL_STORE_INFO_new_CERT(ca)) == NULL
+                            || sk_OSSL_STORE_INFO_push(ctx, si_ca) == 0) {
+                            ok = 0;
+                            break;
+                        }
+                        si_ca = NULL;
+                        (void)sk_X509_shift(chain);
+                    }
+                }
+                if (!ok) {
+                    OSSL_STORE_INFO_free(si_ca);
+                    OSSL_STORE_INFO_free(si_cert);
+                    OSSL_STORE_INFO_free(si_pkey);
+                    sk_OSSL_STORE_INFO_pop_free(ctx, OSSL_STORE_INFO_free);
+                    EVP_PKEY_free(pkey);
+                    X509_free(cert);
+                    sk_X509_pop_free(chain, X509_free);
+                    ctx = NULL;
+                }
+                *pctx = ctx;
+            }
+        }
+     p12_end:
+        PKCS12_free(p12);
+        if (!ok)
+            return NULL;
+    }
+
+    if (ctx != NULL) {
+        *matchcount = 1;
+        store_info = sk_OSSL_STORE_INFO_shift(ctx);
+    }
+
+    return store_info;
+}
+static int eof_PKCS12(void *ctx_)
+{
+    STACK_OF(OSSL_STORE_INFO) *ctx = ctx_;
+
+    return ctx == NULL || sk_OSSL_STORE_INFO_num(ctx) == 0;
+}
+static void destroy_ctx_PKCS12(void **pctx)
+{
+    STACK_OF(OSSL_STORE_INFO) *ctx = *pctx;
+
+    sk_OSSL_STORE_INFO_pop_free(ctx, OSSL_STORE_INFO_free);
+    *pctx = NULL;
+}
+static FILE_HANDLER PKCS12_handler = {
+    "PKCS12",
+    try_decode_PKCS12,
+    eof_PKCS12,
+    destroy_ctx_PKCS12,
+    1                            /* repeatable */
+};
+
+static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name,
+                                                  const char *pem_header,
+                                                  const unsigned char *blob,
+                                                  size_t len, void **pctx,
+                                                  int *matchcount,
+                                                  const UI_METHOD *ui_method,
+                                                  void *ui_data)
+{
+    X509_SIG *p8 = NULL;
+    char kbuf[PEM_BUFSIZE];
+    char *pass = NULL;
+    const X509_ALGOR *dalg = NULL;
+    const ASN1_OCTET_STRING *doct = NULL;
+    OSSL_STORE_INFO *store_info = NULL;
+    BUF_MEM *mem = NULL;
+    unsigned char *new_data = NULL;
+    int new_data_len;
+
+    if (pem_name != NULL) {
+        if (strcmp(pem_name, PEM_STRING_PKCS8) != 0)
+            return NULL;
+        *matchcount = 1;
+    }
+
+    if ((p8 = d2i_X509_SIG(NULL, &blob, len)) == NULL)
+        return NULL;
+
+    *matchcount = 1;
+
+    if ((mem = BUF_MEM_new()) == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED,
+                      ERR_R_MALLOC_FAILURE);
+        goto nop8;
+    }
+
+    if ((pass = file_get_pass(ui_method, kbuf, PEM_BUFSIZE,
+                              "PKCS8 decrypt password", ui_data)) == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED,
+                      OSSL_STORE_R_BAD_PASSWORD_READ);
+        goto nop8;
+    }
+
+    X509_SIG_get0(p8, &dalg, &doct);
+    if (!PKCS12_pbe_crypt(dalg, pass, strlen(pass), doct->data, doct->length,
+                          &new_data, &new_data_len, 0))
+        goto nop8;
+
+    mem->data = (char *)new_data;
+    mem->max = mem->length = (size_t)new_data_len;
+    X509_SIG_free(p8);
+
+    store_info = ossl_store_info_new_EMBEDDED(PEM_STRING_PKCS8INF, mem);
+    if (store_info == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED,
+                      ERR_R_MALLOC_FAILURE);
+        goto nop8;
+    }
+
+    return store_info;
+ nop8:
+    X509_SIG_free(p8);
+    BUF_MEM_free(mem);
+    return NULL;
+}
+static FILE_HANDLER PKCS8Encrypted_handler = {
+    "PKCS8Encrypted",
+    try_decode_PKCS8Encrypted
+};
+
+int pem_check_suffix(const char *pem_str, const char *suffix);
+static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name,
+                                              const char *pem_header,
+                                              const unsigned char *blob,
+                                              size_t len, void **pctx,
+                                              int *matchcount,
+                                              const UI_METHOD *ui_method,
+                                              void *ui_data)
+{
+    OSSL_STORE_INFO *store_info = NULL;
+    EVP_PKEY *pkey = NULL;
+    const EVP_PKEY_ASN1_METHOD *ameth = NULL;
+
+    if (pem_name != NULL) {
+        if (strcmp(pem_name, PEM_STRING_PKCS8INF) == 0) {
+            PKCS8_PRIV_KEY_INFO *p8inf =
+                d2i_PKCS8_PRIV_KEY_INFO(NULL, &blob, len);
+
+            *matchcount = 1;
+            if (p8inf != NULL)
+                pkey = EVP_PKCS82PKEY(p8inf);
+            PKCS8_PRIV_KEY_INFO_free(p8inf);
+        } else {
+            int slen;
+
+            if ((slen = pem_check_suffix(pem_name, "PRIVATE KEY")) > 0
+                && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name,
+                                                   slen)) != NULL) {
+                *matchcount = 1;
+                pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &blob, len);
+            }
+        }
+    } else {
+        int i;
+
+        for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {
+            EVP_PKEY *tmp_pkey = NULL;
+            const unsigned char *tmp_blob = blob;
+
+            ameth = EVP_PKEY_asn1_get0(i);
+            if (ameth->pkey_flags & ASN1_PKEY_ALIAS)
+                continue;
+
+            tmp_pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &tmp_blob, len);
+            if (tmp_pkey != NULL) {
+                if (pkey != NULL)
+                    EVP_PKEY_free(tmp_pkey);
+                else
+                    pkey = tmp_pkey;
+                (*matchcount)++;
+            }
+        }
+
+        if (*matchcount > 1) {
+            EVP_PKEY_free(pkey);
+            pkey = NULL;
+        }
+    }
+    if (pkey == NULL)
+        /* No match */
+        return NULL;
+
+    store_info = OSSL_STORE_INFO_new_PKEY(pkey);
+    if (store_info == NULL)
+        EVP_PKEY_free(pkey);
+
+    return store_info;
+}
+static FILE_HANDLER PrivateKey_handler = {
+    "PrivateKey",
+    try_decode_PrivateKey
+};
+
+static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name,
+                                          const char *pem_header,
+                                          const unsigned char *blob,
+                                          size_t len, void **pctx,
+                                          int *matchcount,
+                                          const UI_METHOD *ui_method,
+                                          void *ui_data)
+{
+    OSSL_STORE_INFO *store_info = NULL;
+    EVP_PKEY *pkey = NULL;
+
+    if (pem_name != NULL) {
+        if (strcmp(pem_name, PEM_STRING_PUBLIC) != 0)
+            /* No match */
+            return NULL;
+        *matchcount = 1;
+    }
+
+    if ((pkey = d2i_PUBKEY(NULL, &blob, len)) != NULL) {
+        *matchcount = 1;
+        store_info = OSSL_STORE_INFO_new_PKEY(pkey);
+    }
+
+    return store_info;
+}
+static FILE_HANDLER PUBKEY_handler = {
+    "PUBKEY",
+    try_decode_PUBKEY
+};
+
+static OSSL_STORE_INFO *try_decode_params(const char *pem_name,
+                                          const char *pem_header,
+                                          const unsigned char *blob,
+                                          size_t len, void **pctx,
+                                          int *matchcount,
+                                          const UI_METHOD *ui_method,
+                                          void *ui_data)
+{
+    OSSL_STORE_INFO *store_info = NULL;
+    int slen = 0;
+    EVP_PKEY *pkey = NULL;
+    const EVP_PKEY_ASN1_METHOD *ameth = NULL;
+    int ok = 0;
+
+    if (pem_name != NULL) {
+        if ((slen = pem_check_suffix(pem_name, "PARAMETERS")) == 0)
+            return NULL;
+        *matchcount = 1;
+    }
+
+    if ((pkey = EVP_PKEY_new()) == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PARAMS, ERR_R_EVP_LIB);
+        return NULL;
+    }
+
+    if (slen > 0) {
+        if (EVP_PKEY_set_type_str(pkey, pem_name, slen)
+            && (ameth = EVP_PKEY_get0_asn1(pkey)) != NULL
+            && ameth->param_decode != NULL
+            && ameth->param_decode(pkey, &blob, len))
+            ok = 1;
+    } else {
+        int i;
+
+        for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {
+            const unsigned char *tmp_blob = blob;
+
+            ameth = EVP_PKEY_asn1_get0(i);
+            if (ameth->pkey_flags & ASN1_PKEY_ALIAS)
+                continue;
+            if (EVP_PKEY_set_type(pkey, ameth->pkey_id)
+                && (ameth = EVP_PKEY_get0_asn1(pkey)) != NULL
+                && ameth->param_decode != NULL
+                && ameth->param_decode(pkey, &tmp_blob, len)) {
+                (*matchcount)++;
+                ok = 1;
+                break;
+            }
+        }
+    }
+
+    if (ok)
+        store_info = OSSL_STORE_INFO_new_PARAMS(pkey);
+    if (store_info == NULL)
+        EVP_PKEY_free(pkey);
+
+    return store_info;
+}
+static FILE_HANDLER params_handler = {
+    "params",
+    try_decode_params
+};
+
+static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name,
+                                                   const char *pem_header,
+                                                   const unsigned char *blob,
+                                                   size_t len, void **pctx,
+                                                   int *matchcount,
+                                                   const UI_METHOD *ui_method,
+                                                   void *ui_data)
+{
+    OSSL_STORE_INFO *store_info = NULL;
+    X509 *cert = NULL;
+
+    /*
+     * In most cases, we can try to interpret the serialized data as a trusted
+     * cert (X509 + X509_AUX) and fall back to reading it as a normal cert
+     * (just X509), but if the PEM name specifically declares it as a trusted
+     * cert, then no fallback should be engaged.  |ignore_trusted| tells if
+     * the fallback can be used (1) or not (0).
+     */
+    int ignore_trusted = 1;
+
+    if (pem_name != NULL) {
+        if (strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0)
+            ignore_trusted = 0;
+        else if (strcmp(pem_name, PEM_STRING_X509_OLD) != 0
+                 && strcmp(pem_name, PEM_STRING_X509) != 0)
+            /* No match */
+            return NULL;
+        *matchcount = 1;
+    }
+
+    if ((cert = d2i_X509_AUX(NULL, &blob, len)) != NULL
+        || (ignore_trusted && (cert = d2i_X509(NULL, &blob, len)) != NULL)) {
+        *matchcount = 1;
+        store_info = OSSL_STORE_INFO_new_CERT(cert);
+    }
+
+    if (store_info == NULL)
+        X509_free(cert);
+
+    return store_info;
+}
+static FILE_HANDLER X509Certificate_handler = {
+    "X509Certificate",
+    try_decode_X509Certificate
+};
+
+static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name,
+                                           const char *pem_header,
+                                           const unsigned char *blob,
+                                           size_t len, void **pctx,
+                                           int *matchcount,
+                                           const UI_METHOD *ui_method,
+                                           void *ui_data)
+{
+    OSSL_STORE_INFO *store_info = NULL;
+    X509_CRL *crl = NULL;
+
+    if (pem_name != NULL) {
+        if (strcmp(pem_name, PEM_STRING_X509_CRL) != 0)
+            /* No match */
+            return NULL;
+        *matchcount = 1;
+    }
+
+    if ((crl = d2i_X509_CRL(NULL, &blob, len)) != NULL) {
+        *matchcount = 1;
+        store_info = OSSL_STORE_INFO_new_CRL(crl);
+    }
+
+    if (store_info == NULL)
+        X509_CRL_free(crl);
+
+    return store_info;
+}
+static FILE_HANDLER X509CRL_handler = {
+    "X509CRL",
+    try_decode_X509CRL
+};
+
+static const FILE_HANDLER *file_handlers[] = {
+    &PKCS12_handler,
+    &PKCS8Encrypted_handler,
+    &X509Certificate_handler,
+    &X509CRL_handler,
+    &params_handler,
+    &PUBKEY_handler,
+    &PrivateKey_handler,
+};
+
+
+/*
+ *  The loader itself
+ */
+
+struct ossl_store_loader_ctx_st {
+    enum {
+        is_raw = 0,
+        is_pem,
+        is_dir
+    } type;
+    int errcnt;
+    union {
+        struct {                 /* Used with is_raw and is_pem */
+            BIO *file;
+
+            /*
+             * The following are used when the handler is marked as
+             * repeatable
+             */
+            const FILE_HANDLER *last_handler;
+            void *last_handler_ctx;
+        } file;
+        struct {                 /* Used with is_dir */
+            OPENSSL_DIR_CTX *ctx;
+            int end_reached;
+            char *uri;
+
+            /*
+             * The directory reading utility we have combines opening with
+             * reading the first name.  To make sure we can detect the end
+             * at the right time, we read early and cache the name.
+             */
+            const char *last_entry;
+            int last_errno;
+        } dir;
+    } _;
+};
+
+static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)
+{
+    if (ctx->type == is_dir) {
+        OPENSSL_free(ctx->_.dir.uri);
+    } else {
+        if (ctx->_.file.last_handler != NULL) {
+            ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);
+            ctx->_.file.last_handler_ctx = NULL;
+            ctx->_.file.last_handler = NULL;
+        }
+    }
+    OPENSSL_free(ctx);
+}
+
+static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
+                                        const char *uri,
+                                        const UI_METHOD *ui_method,
+                                        void *ui_data)
+{
+    OSSL_STORE_LOADER_CTX *ctx = NULL;
+    struct stat st;
+    const char *path = NULL;
+
+    if (strncasecmp(uri, "file:", 5) == 0) {
+        if (strncmp(&uri[5], "//localhost/", 12) == 0) {
+            path = &uri[16];
+        } else if (strncmp(&uri[5], "///", 3) == 0) {
+            path = &uri[7];
+        } else if (strncmp(&uri[5], "//", 2) != 0) {
+            path = &uri[5];
+        } else {
+            OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN,
+                          OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED);
+            return NULL;
+        }
+
+        /*
+         * If the scheme "file" was an explicit part of the URI, the path must
+         * be absolute.  So says RFC 8089
+         */
+        if (path[0] != '/') {
+            OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN,
+                          OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE);
+            return NULL;
+        }
+
+#ifdef _WIN32
+        /* Windows file: URIs with a drive letter start with a / */
+        if (path[0] == '/' && path[2] == ':' && path[3] == '/')
+            path++;
+#endif
+    } else {
+        path = uri;
+    }
+
+
+    if (stat(path, &st) < 0) {
+        SYSerr(SYS_F_STAT, errno);
+        ERR_add_error_data(1, path);
+        return NULL;
+    }
+
+    ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    if ((st.st_mode & S_IFDIR) == S_IFDIR) {
+        /*
+         * Try to copy everything, even if we know that some of them must be
+         * NULL for the moment.  This prevents errors in the future, when more
+         * components may be used.
+         */
+        ctx->_.dir.uri = OPENSSL_strdup(uri);
+        ctx->type = is_dir;
+
+        if (ctx->_.dir.uri == NULL)
+            goto err;
+
+        ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path);
+        ctx->_.dir.last_errno = errno;
+        if (ctx->_.dir.last_entry == NULL) {
+            if (ctx->_.dir.last_errno != 0) {
+                char errbuf[256];
+                errno = ctx->_.dir.last_errno;
+                openssl_strerror_r(errno, errbuf, sizeof(errbuf));
+                OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_SYS_LIB);
+                ERR_add_error_data(1, errbuf);
+                goto err;
+            }
+            ctx->_.dir.end_reached = 1;
+        }
+    } else {
+        BIO *buff = NULL;
+        char peekbuf[4096];
+
+        if ((buff = BIO_new(BIO_f_buffer())) == NULL
+            || (ctx->_.file.file = BIO_new_file(path, "rb")) == NULL) {
+            BIO_free_all(buff);
+            goto err;
+        }
+
+        ctx->_.file.file = BIO_push(buff, ctx->_.file.file);
+        if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf)-1) > 0) {
+            peekbuf[sizeof(peekbuf)-1] = '\0';
+            if (strstr(peekbuf, "-----BEGIN ") != NULL)
+                ctx->type = is_pem;
+        }
+    }
+
+    return ctx;
+ err:
+    OSSL_STORE_LOADER_CTX_free(ctx);
+    return NULL;
+}
+
+static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,
+                                             const char *pem_name,
+                                             const char *pem_header,
+                                             unsigned char *data, size_t len,
+                                             const UI_METHOD *ui_method,
+                                             void *ui_data, int *matchcount)
+{
+    OSSL_STORE_INFO *result = NULL;
+    BUF_MEM *new_mem = NULL;
+    char *new_pem_name = NULL;
+    int t = 0;
+
+ again:
+    {
+        size_t i = 0;
+        void *handler_ctx = NULL;
+        const FILE_HANDLER **matching_handlers =
+            OPENSSL_zalloc(sizeof(*matching_handlers)
+                           * OSSL_NELEM(file_handlers));
+
+        if (matching_handlers == NULL) {
+            OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD_TRY_DECODE,
+                          ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        *matchcount = 0;
+        for (i = 0; i < OSSL_NELEM(file_handlers); i++) {
+            const FILE_HANDLER *handler = file_handlers[i];
+            int try_matchcount = 0;
+            void *tmp_handler_ctx = NULL;
+            OSSL_STORE_INFO *tmp_result =
+                handler->try_decode(pem_name, pem_header, data, len,
+                                    &tmp_handler_ctx, &try_matchcount,
+                                    ui_method, ui_data);
+
+            if (try_matchcount > 0) {
+                if (matching_handlers)
+                    matching_handlers[*matchcount] = handler;
+
+                if (handler_ctx)
+                    handler->destroy_ctx(&handler_ctx);
+                handler_ctx = tmp_handler_ctx;
+
+                if ((*matchcount += try_matchcount) > 1) {
+                    /* more than one match => ambiguous, kill any result */
+                    OSSL_STORE_INFO_free(result);
+                    OSSL_STORE_INFO_free(tmp_result);
+                    if (handler->destroy_ctx != NULL)
+                        handler->destroy_ctx(&handler_ctx);
+                    handler_ctx = NULL;
+                    tmp_result = NULL;
+                    result = NULL;
+                }
+                if (result == NULL)
+                    result = tmp_result;
+            }
+        }
+
+        if (*matchcount == 1 && matching_handlers[0]->repeatable) {
+            ctx->_.file.last_handler = matching_handlers[0];
+            ctx->_.file.last_handler_ctx = handler_ctx;
+        }
+
+        OPENSSL_free(matching_handlers);
+    }
+
+ err:
+    OPENSSL_free(new_pem_name);
+    BUF_MEM_free(new_mem);
+
+    if (result != NULL
+        && (t = OSSL_STORE_INFO_get_type(result)) == OSSL_STORE_INFO_EMBEDDED) {
+        pem_name = new_pem_name =
+            ossl_store_info_get0_EMBEDDED_pem_name(result);
+        new_mem = ossl_store_info_get0_EMBEDDED_buffer(result);
+        data = (unsigned char *)new_mem->data;
+        len = new_mem->length;
+        OPENSSL_free(result);
+        result = NULL;
+        goto again;
+    }
+
+    if (result != NULL)
+        ERR_clear_error();
+
+    return result;
+}
+
+static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx,
+                                             const UI_METHOD *ui_method,
+                                             void *ui_data)
+{
+    OSSL_STORE_INFO *result = NULL;
+    int try_matchcount = 0;
+
+    if (ctx->_.file.last_handler != NULL) {
+        result =
+            ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0,
+                                                 &ctx->_.file.last_handler_ctx,
+                                                 &try_matchcount,
+                                                 ui_method, ui_data);
+
+        if (result == NULL) {
+            ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);
+            ctx->_.file.last_handler_ctx = NULL;
+            ctx->_.file.last_handler = NULL;
+        }
+    }
+    return result;
+}
+
+static int file_read_pem(BIO *bp, char **pem_name, char **pem_header,
+                         unsigned char **data, long *len,
+                         const UI_METHOD *ui_method,
+                         void *ui_data)
+{
+    int i = PEM_read_bio(bp, pem_name, pem_header, data, len);
+
+    if (i <= 0)
+        return 0;
+
+    /*
+     * 10 is the number of characters in "Proc-Type:", which
+     * PEM_get_EVP_CIPHER_INFO() requires to be present.
+     * If the PEM header has less characters than that, it's
+     * not worth spending cycles on it.
+     */
+    if (strlen(*pem_header) > 10) {
+        EVP_CIPHER_INFO cipher;
+        struct pem_pass_data pass_data;
+
+        if (!PEM_get_EVP_CIPHER_INFO(*pem_header, &cipher)
+            || !file_fill_pem_pass_data(&pass_data, "PEM", ui_method, ui_data)
+            || !PEM_do_header(&cipher, *data, len, file_get_pem_pass,
+                              &pass_data)) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static int file_read_asn1(BIO *bp, unsigned char **data, long *len)
+{
+    BUF_MEM *mem = NULL;
+
+    if (asn1_d2i_read_bio(bp, &mem) < 0)
+        return 0;
+
+    *data = (unsigned char *)mem->data;
+    *len = (long)mem->length;
+    OPENSSL_free(mem);
+
+    return 1;
+}
+
+static int ends_with_dirsep(const char *uri)
+{
+    if (*uri != '\0')
+        uri += strlen(uri) - 1;
+#if defined __VMS
+    if (*uri == ']' || *uri == '>' || *uri == ':')
+        return 1;
+#elif defined _WIN32
+    if (*uri == '\\')
+        return 1;
+#endif
+    return *uri == '/';
+}
+
+static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name,
+                            char **data)
+{
+    assert(name != NULL);
+    assert(data != NULL);
+    {
+        const char *pathsep = ends_with_dirsep(ctx->_.dir.uri) ? "" : "/";
+        long calculated_length = strlen(ctx->_.dir.uri) + strlen(pathsep)
+            + strlen(name) + 1 /* \0 */;
+
+        *data = OPENSSL_zalloc(calculated_length);
+        if (*data == NULL) {
+            OSSL_STOREerr(OSSL_STORE_F_FILE_NAME_TO_URI, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+
+        OPENSSL_strlcat(*data, ctx->_.dir.uri, calculated_length);
+        OPENSSL_strlcat(*data, pathsep, calculated_length);
+        OPENSSL_strlcat(*data, name, calculated_length);
+    }
+    return 1;
+}
+
+static int file_eof(OSSL_STORE_LOADER_CTX *ctx);
+static int file_error(OSSL_STORE_LOADER_CTX *ctx);
+static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
+                                  const UI_METHOD *ui_method, void *ui_data)
+{
+    OSSL_STORE_INFO *result = NULL;
+
+    ctx->errcnt = 0;
+    ERR_clear_error();
+
+    if (ctx->type == is_dir) {
+        do {
+            char *newname = NULL;
+
+            if (ctx->_.dir.last_entry == NULL) {
+                if (!ctx->_.dir.end_reached) {
+                    char errbuf[256];
+                    assert(ctx->_.dir.last_errno != 0);
+                    errno = ctx->_.dir.last_errno;
+                    ctx->errcnt++;
+                    openssl_strerror_r(errno, errbuf, sizeof(errbuf));
+                    OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_SYS_LIB);
+                    ERR_add_error_data(1, errbuf);
+                }
+                return NULL;
+            }
+
+            if (ctx->_.dir.last_entry[0] != '.'
+                && !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname))
+                return NULL;
+
+            /*
+             * On the first call (with a NULL context), OPENSSL_DIR_read()
+             * cares about the second argument.  On the following calls, it
+             * only cares that it isn't NULL.  Therefore, we can safely give
+             * it our URI here.
+             */
+            ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx,
+                                                     ctx->_.dir.uri);
+            ctx->_.dir.last_errno = errno;
+            if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0)
+                ctx->_.dir.end_reached = 1;
+
+            if (newname != NULL
+                && (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) {
+                OPENSSL_free(newname);
+                OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_OSSL_STORE_LIB);
+                return NULL;
+            }
+        } while (result == NULL && !file_eof(ctx));
+    } else {
+        int matchcount = -1;
+
+        result = file_load_try_repeat(ctx, ui_method, ui_data);
+        if (result != NULL)
+            return result;
+
+        if (file_eof(ctx))
+            return NULL;
+
+        do {
+            char *pem_name = NULL;      /* PEM record name */
+            char *pem_header = NULL;    /* PEM record header */
+            unsigned char *data = NULL; /* DER encoded data */
+            long len = 0;               /* DER encoded data length */
+
+            matchcount = -1;
+            if (ctx->type == is_pem) {
+                if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header,
+                                   &data, &len, ui_method, ui_data)) {
+                    ctx->errcnt++;
+                    goto endloop;
+                }
+            } else {
+                if (!file_read_asn1(ctx->_.file.file, &data, &len)) {
+                    ctx->errcnt++;
+                    goto endloop;
+                }
+            }
+
+            result = file_load_try_decode(ctx, pem_name, pem_header, data, len,
+                                          ui_method, ui_data, &matchcount);
+
+            if (result != NULL)
+                goto endloop;
+
+            /*
+             * If a PEM name matches more than one handler, the handlers are
+             * badly coded.
+             */
+            if (!ossl_assert(pem_name == NULL || matchcount <= 1)) {
+                ctx->errcnt++;
+                goto endloop;
+            }
+
+            if (matchcount > 1) {
+                OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
+                              OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE);
+            } else if (matchcount == 1) {
+                /*
+                 * If there are other errors on the stack, they already show
+                 * what the problem is.
+                 */
+                if (ERR_peek_error() == 0) {
+                    OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
+                                  OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE);
+                    if (pem_name != NULL)
+                        ERR_add_error_data(3, "PEM type is '", pem_name, "'");
+                }
+            }
+            if (matchcount > 0)
+                ctx->errcnt++;
+
+         endloop:
+            OPENSSL_free(pem_name);
+            OPENSSL_free(pem_header);
+            OPENSSL_free(data);
+        } while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx));
+
+        /* We bail out on ambiguity */
+        if (matchcount > 1)
+            return NULL;
+    }
+
+    return result;
+}
+
+static int file_error(OSSL_STORE_LOADER_CTX *ctx)
+{
+    return ctx->errcnt > 0;
+}
+
+static int file_eof(OSSL_STORE_LOADER_CTX *ctx)
+{
+    if (ctx->type == is_dir)
+        return ctx->_.dir.end_reached;
+
+    if (ctx->_.file.last_handler != NULL
+        && !ctx->_.file.last_handler->eof(ctx->_.file.last_handler_ctx))
+        return 0;
+    return BIO_eof(ctx->_.file.file);
+}
+
+static int file_close(OSSL_STORE_LOADER_CTX *ctx)
+{
+    if (ctx->type == is_dir) {
+        OPENSSL_DIR_end(&ctx->_.dir.ctx);
+    } else {
+        BIO_free_all(ctx->_.file.file);
+    }
+    OSSL_STORE_LOADER_CTX_free(ctx);
+    return 1;
+}
+
+static OSSL_STORE_LOADER file_loader =
+    {
+        "file",
+        NULL,
+        file_open,
+        NULL,
+        file_load,
+        file_eof,
+        file_error,
+        file_close
+    };
+
+static void store_file_loader_deinit(void)
+{
+    ossl_store_unregister_loader_int(file_loader.scheme);
+}
+
+int ossl_store_file_loader_init(void)
+{
+    int ret = ossl_store_register_loader_int(&file_loader);
+
+    OPENSSL_atexit(store_file_loader_deinit);
+    return ret;
+}
diff --git a/crypto/store/store_err.c b/crypto/store/store_err.c
new file mode 100644
index 0000000..681c9ff
--- /dev/null
+++ b/crypto/store/store_err.c
@@ -0,0 +1,116 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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/storeerr.h>
+
+#ifndef OPENSSL_NO_ERR
+
+static const ERR_STRING_DATA OSSL_STORE_str_functs[] = {
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_GET_PASS, 0),
+     "file_get_pass"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD, 0), "file_load"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD_TRY_DECODE, 0),
+     "file_load_try_decode"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_NAME_TO_URI, 0),
+     "file_name_to_uri"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_OPEN, 0), "file_open"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT, 0),
+     "ossl_store_get0_loader_int"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT, 0),
+     "OSSL_STORE_INFO_get1_CERT"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL, 0),
+     "OSSL_STORE_INFO_get1_CRL"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME, 0),
+     "OSSL_STORE_INFO_get1_NAME"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION, 0),
+     "OSSL_STORE_INFO_get1_NAME_description"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_PARAMS, 0),
+     "OSSL_STORE_INFO_get1_PARAMS"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_PKEY, 0),
+     "OSSL_STORE_INFO_get1_PKEY"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_NEW_CERT, 0),
+     "OSSL_STORE_INFO_new_CERT"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_NEW_CRL, 0),
+     "OSSL_STORE_INFO_new_CRL"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED, 0),
+     "ossl_store_info_new_EMBEDDED"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_NEW_NAME, 0),
+     "OSSL_STORE_INFO_new_NAME"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_NEW_PARAMS, 0),
+     "OSSL_STORE_INFO_new_PARAMS"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_NEW_PKEY, 0),
+     "OSSL_STORE_INFO_new_PKEY"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_SET0_NAME_DESCRIPTION, 0),
+     "OSSL_STORE_INFO_set0_NAME_description"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INIT_ONCE, 0),
+     "ossl_store_init_once"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_LOADER_NEW, 0),
+     "OSSL_STORE_LOADER_new"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_OPEN, 0),
+     "OSSL_STORE_open"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_OPEN_INT, 0), ""},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT, 0),
+     "ossl_store_register_loader_int"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT, 0),
+     "ossl_store_unregister_loader_int"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_TRY_DECODE_PARAMS, 0),
+     "try_decode_params"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_TRY_DECODE_PKCS12, 0),
+     "try_decode_PKCS12"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED, 0),
+     "try_decode_PKCS8Encrypted"},
+    {0, NULL}
+};
+
+static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = {
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE),
+    "ambiguous content type"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_BAD_PASSWORD_READ),
+    "bad password read"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC),
+    "error verifying pkcs12 mac"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_INVALID_SCHEME),
+    "invalid scheme"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_IS_NOT_A), "is not a"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_CERTIFICATE),
+    "not a certificate"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_CRL), "not a crl"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_KEY), "not a key"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_NAME), "not a name"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_PARAMETERS),
+    "not parameters"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR),
+    "passphrase callback error"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE),
+    "path must be absolute"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED),
+    "ui process interrupted or cancelled"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UNREGISTERED_SCHEME),
+    "unregistered scheme"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE),
+    "unsupported content type"},
+    {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED),
+    "uri authority unsuppored"},
+    {0, NULL}
+};
+
+#endif
+
+int ERR_load_OSSL_STORE_strings(void)
+{
+#ifndef OPENSSL_NO_ERR
+    if (ERR_func_error_string(OSSL_STORE_str_functs[0].error) == NULL) {
+        ERR_load_strings_const(OSSL_STORE_str_functs);
+        ERR_load_strings_const(OSSL_STORE_str_reasons);
+    }
+#endif
+    return 1;
+}
diff --git a/crypto/store/store_init.c b/crypto/store/store_init.c
new file mode 100644
index 0000000..4b53108
--- /dev/null
+++ b/crypto/store/store_init.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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 "internal/store.h"
+#include "store_locl.h"
+
+static CRYPTO_ONCE store_init = CRYPTO_ONCE_STATIC_INIT;
+DEFINE_RUN_ONCE_STATIC(do_store_init)
+{
+    return OPENSSL_init_crypto(0, NULL)
+        && ossl_store_file_loader_init();
+}
+
+int ossl_store_init_once()
+{
+    if (!RUN_ONCE(&store_init, do_store_init)) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INIT_ONCE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    return 1;
+}
+
+void ossl_store_cleanup_int(void)
+{
+    ossl_store_destroy_loaders_int();
+}
diff --git a/crypto/store/store_lib.c b/crypto/store/store_lib.c
new file mode 100644
index 0000000..2c8ce86
--- /dev/null
+++ b/crypto/store/store_lib.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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 <stdlib.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/store.h>
+#include "internal/thread_once.h"
+#include "store_locl.h"
+
+struct ossl_store_ctx_st {
+    const OSSL_STORE_LOADER *loader;
+    OSSL_STORE_LOADER_CTX *loader_ctx;
+    const UI_METHOD *ui_method;
+    void *ui_data;
+    OSSL_STORE_post_process_info_fn post_process;
+    void *post_process_data;
+};
+
+OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
+                                void *ui_data,
+                                OSSL_STORE_post_process_info_fn post_process,
+                                void *post_process_data)
+{
+    const OSSL_STORE_LOADER *loader;
+    OSSL_STORE_LOADER_CTX *loader_ctx = NULL;
+    OSSL_STORE_CTX *ctx = NULL;
+    char scheme_copy[256], *p;
+
+    OPENSSL_strlcpy(scheme_copy, uri, sizeof(scheme_copy));
+    if ((p = strchr(scheme_copy, ':')) != NULL) {
+        *p = '\0';
+        p = scheme_copy;
+    } else {
+        p = "file";
+    }
+
+    if ((loader = ossl_store_get0_loader_int(p)) == NULL
+        || (loader_ctx = loader->open(loader, uri, ui_method, ui_data)) == NULL)
+        goto done;
+    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_OPEN, ERR_R_MALLOC_FAILURE);
+        goto done;
+    }
+
+    ctx->loader = loader;
+    ctx->loader_ctx = loader_ctx;
+    loader_ctx = NULL;
+    ctx->ui_method = ui_method;
+    ctx->ui_data = ui_data;
+    ctx->post_process = post_process;
+    ctx->post_process_data = post_process_data;
+
+ done:
+    if (loader_ctx != NULL) {
+        /*
+         * We ignore a returned error because we will return NULL anyway in
+         * this case, so if something goes wrong when closing, that'll simply
+         * just add another entry on the error stack.
+         */
+        (void)loader->close(loader_ctx);
+    }
+    return ctx;
+}
+
+int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ...)
+{
+    va_list args;
+    int ret = 0;
+
+    va_start(args, cmd);
+    if (ctx->loader->ctrl != NULL)
+        ret = ctx->loader->ctrl(ctx->loader_ctx, cmd, args);
+    va_end(args);
+
+    return ret;
+}
+
+OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
+{
+    OSSL_STORE_INFO *v = NULL;
+
+ again:
+    v = ctx->loader->load(ctx->loader_ctx, ctx->ui_method, ctx->ui_data);
+
+    if (ctx->post_process != NULL && v != NULL) {
+        v = ctx->post_process(v, ctx->post_process_data);
+
+        /*
+         * By returning NULL, the callback decides that this object should
+         * be ignored.
+         */
+        if (v == NULL)
+            goto again;
+    }
+
+    return v;
+}
+
+int OSSL_STORE_error(OSSL_STORE_CTX *ctx)
+{
+    return ctx->loader->error(ctx->loader_ctx);
+}
+
+int OSSL_STORE_eof(OSSL_STORE_CTX *ctx)
+{
+    return ctx->loader->eof(ctx->loader_ctx);
+}
+
+int OSSL_STORE_close(OSSL_STORE_CTX *ctx)
+{
+    int loader_ret = ctx->loader->close(ctx->loader_ctx);
+
+    OPENSSL_free(ctx);
+    return loader_ret;
+}
+
+/*
+ * Functions to generate OSSL_STORE_INFOs, one function for each type we
+ * support having in them.  Along with each of them, one macro that
+ * can be used to determine what types are supported.
+ *
+ * In all cases, ownership of the object is transfered to the OSSL_STORE_INFO
+ * and will therefore be freed when the OSSL_STORE_INFO is freed.
+ */
+static OSSL_STORE_INFO *store_info_new(int type, void *data)
+{
+    OSSL_STORE_INFO *info = OPENSSL_zalloc(sizeof(*info));
+
+    if (info == NULL)
+        return NULL;
+
+    info->type = type;
+    info->_.data = data;
+    return info;
+}
+
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_NAME(char *name)
+{
+    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_NAME, NULL);
+
+    if (info == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_NAME,
+                      ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    info->_.name.name = name;
+    info->_.name.desc = NULL;
+
+    return info;
+}
+
+int OSSL_STORE_INFO_set0_NAME_description(OSSL_STORE_INFO *info, char *desc)
+{
+    if (info->type != OSSL_STORE_INFO_NAME) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_SET0_NAME_DESCRIPTION,
+                      ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+
+    info->_.name.desc = desc;
+
+    return 1;
+}
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_PARAMS(EVP_PKEY *params)
+{
+    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_PARAMS, params);
+
+    if (info == NULL)
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_PARAMS,
+                      ERR_R_MALLOC_FAILURE);
+    return info;
+}
+
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey)
+{
+    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_PKEY, pkey);
+
+    if (info == NULL)
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_PKEY,
+                      ERR_R_MALLOC_FAILURE);
+    return info;
+}
+
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509)
+{
+    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_CERT, x509);
+
+    if (info == NULL)
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_CERT,
+                      ERR_R_MALLOC_FAILURE);
+    return info;
+}
+
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl)
+{
+    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_CRL, crl);
+
+    if (info == NULL)
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_CRL,
+                      ERR_R_MALLOC_FAILURE);
+    return info;
+}
+
+/*
+ * Functions to try to extract data from a OSSL_STORE_INFO.
+ */
+int OSSL_STORE_INFO_get_type(const OSSL_STORE_INFO *info)
+{
+    return info->type;
+}
+
+const char *OSSL_STORE_INFO_get0_NAME(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_NAME)
+        return info->_.name.name;
+    return NULL;
+}
+
+char *OSSL_STORE_INFO_get1_NAME(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_NAME) {
+        char *ret = OPENSSL_strdup(info->_.name.name);
+
+        if (ret == NULL)
+            OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME,
+                          ERR_R_MALLOC_FAILURE);
+        return ret;
+    }
+    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME,
+                  OSSL_STORE_R_NOT_A_NAME);
+    return NULL;
+}
+
+const char *OSSL_STORE_INFO_get0_NAME_description(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_NAME)
+        return info->_.name.desc;
+    return NULL;
+}
+
+char *OSSL_STORE_INFO_get1_NAME_description(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_NAME) {
+        char *ret = OPENSSL_strdup(info->_.name.desc
+                                   ? info->_.name.desc : "");
+
+        if (ret == NULL)
+            OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION,
+                     ERR_R_MALLOC_FAILURE);
+        return ret;
+    }
+    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION,
+                  OSSL_STORE_R_NOT_A_NAME);
+    return NULL;
+}
+
+EVP_PKEY *OSSL_STORE_INFO_get0_PARAMS(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_PARAMS)
+        return info->_.params;
+    return NULL;
+}
+
+EVP_PKEY *OSSL_STORE_INFO_get1_PARAMS(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_PARAMS) {
+        EVP_PKEY_up_ref(info->_.params);
+        return info->_.params;
+    }
+    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_PARAMS,
+                  OSSL_STORE_R_NOT_PARAMETERS);
+    return NULL;
+}
+
+EVP_PKEY *OSSL_STORE_INFO_get0_PKEY(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_PKEY)
+        return info->_.pkey;
+    return NULL;
+}
+
+EVP_PKEY *OSSL_STORE_INFO_get1_PKEY(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_PKEY) {
+        EVP_PKEY_up_ref(info->_.pkey);
+        return info->_.pkey;
+    }
+    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_PKEY,
+                  OSSL_STORE_R_NOT_A_KEY);
+    return NULL;
+}
+
+X509 *OSSL_STORE_INFO_get0_CERT(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_CERT)
+        return info->_.x509;
+    return NULL;
+}
+
+X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_CERT) {
+        X509_up_ref(info->_.x509);
+        return info->_.x509;
+    }
+    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT,
+                  OSSL_STORE_R_NOT_A_CERTIFICATE);
+    return NULL;
+}
+
+X509_CRL *OSSL_STORE_INFO_get0_CRL(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_CRL)
+        return info->_.crl;
+    return NULL;
+}
+
+X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_CRL) {
+        X509_CRL_up_ref(info->_.crl);
+        return info->_.crl;
+    }
+    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL,
+                  OSSL_STORE_R_NOT_A_CRL);
+    return NULL;
+}
+
+/*
+ * Free the OSSL_STORE_INFO
+ */
+void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info)
+{
+    if (info != NULL) {
+        switch (info->type) {
+        case OSSL_STORE_INFO_EMBEDDED:
+            BUF_MEM_free(info->_.embedded.blob);
+            OPENSSL_free(info->_.embedded.pem_name);
+            break;
+        case OSSL_STORE_INFO_NAME:
+            OPENSSL_free(info->_.name.name);
+            OPENSSL_free(info->_.name.desc);
+            break;
+        case OSSL_STORE_INFO_PARAMS:
+            EVP_PKEY_free(info->_.params);
+            break;
+        case OSSL_STORE_INFO_PKEY:
+            EVP_PKEY_free(info->_.pkey);
+            break;
+        case OSSL_STORE_INFO_CERT:
+            X509_free(info->_.x509);
+            break;
+        case OSSL_STORE_INFO_CRL:
+            X509_CRL_free(info->_.crl);
+            break;
+        }
+        OPENSSL_free(info);
+    }
+}
+
+/* Internal functions */
+OSSL_STORE_INFO *ossl_store_info_new_EMBEDDED(const char *new_pem_name,
+                                              BUF_MEM *embedded)
+{
+    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_EMBEDDED, NULL);
+
+    if (info == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED,
+                      ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    info->_.embedded.blob = embedded;
+    info->_.embedded.pem_name =
+        new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name);
+
+    if (new_pem_name != NULL && info->_.embedded.pem_name == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED,
+                      ERR_R_MALLOC_FAILURE);
+        OSSL_STORE_INFO_free(info);
+        info = NULL;
+    }
+
+    return info;
+}
+
+BUF_MEM *ossl_store_info_get0_EMBEDDED_buffer(OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_EMBEDDED)
+        return info->_.embedded.blob;
+    return NULL;
+}
+
+char *ossl_store_info_get0_EMBEDDED_pem_name(OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_EMBEDDED)
+        return info->_.embedded.pem_name;
+    return NULL;
+}
diff --git a/crypto/store/store_locl.h b/crypto/store/store_locl.h
new file mode 100644
index 0000000..a954c57
--- /dev/null
+++ b/crypto/store/store_locl.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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/thread_once.h"
+#include <openssl/dsa.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <openssl/lhash.h>
+#include <openssl/x509.h>
+#include <openssl/store.h>
+
+/*-
+ *  OSSL_STORE_INFO stuff
+ *  ---------------------
+ */
+
+struct ossl_store_info_st {
+    int type;
+    union {
+        void *data;              /* used internally as generic pointer */
+
+        struct {
+            BUF_MEM *blob;
+            char *pem_name;
+        } embedded;              /* when type == OSSL_STORE_INFO_EMBEDDED */
+
+        struct {
+            char *name;
+            char *desc;
+        } name;                  /* when type == OSSL_STORE_INFO_NAME */
+
+        EVP_PKEY *params;        /* when type == OSSL_STORE_INFO_PARAMS */
+        EVP_PKEY *pkey;          /* when type == OSSL_STORE_INFO_PKEY */
+        X509 *x509;              /* when type == OSSL_STORE_INFO_CERT */
+        X509_CRL *crl;           /* when type == OSSL_STORE_INFO_CRL */
+    } _;
+};
+
+DEFINE_STACK_OF(OSSL_STORE_INFO)
+
+/*
+ * EMBEDDED is a special type of OSSL_STORE_INFO, specially for the file
+ * handlers.  It should never reach a calling application or any engine.
+ * However, it can be used by a FILE_HANDLER's try_decode function to signal
+ * that it has decoded the incoming blob into a new blob, and that the
+ * attempted decoding should be immediately restarted with the new blob, using
+ * the new PEM name.
+ */
+/*
+ * Because this is an internal type, we don't make it public.
+ */
+#define OSSL_STORE_INFO_EMBEDDED       -1
+OSSL_STORE_INFO *ossl_store_info_new_EMBEDDED(const char *new_pem_name,
+                                              BUF_MEM *embedded);
+BUF_MEM *ossl_store_info_get0_EMBEDDED_buffer(OSSL_STORE_INFO *info);
+char *ossl_store_info_get0_EMBEDDED_pem_name(OSSL_STORE_INFO *info);
+
+/*-
+ *  OSSL_STORE_LOADER stuff
+ *  -----------------------
+ */
+
+int ossl_store_register_loader_int(OSSL_STORE_LOADER *loader);
+OSSL_STORE_LOADER *ossl_store_unregister_loader_int(const char *scheme);
+
+/* loader stuff */
+struct ossl_store_loader_st {
+    const char *scheme;
+    ENGINE *engine;
+    OSSL_STORE_open_fn open;
+    OSSL_STORE_ctrl_fn ctrl;
+    OSSL_STORE_load_fn load;
+    OSSL_STORE_eof_fn eof;
+    OSSL_STORE_error_fn error;
+    OSSL_STORE_close_fn close;
+};
+DEFINE_LHASH_OF(OSSL_STORE_LOADER);
+
+const OSSL_STORE_LOADER *ossl_store_get0_loader_int(const char *scheme);
+void ossl_store_destroy_loaders_int(void);
+
+/*-
+ *  OSSL_STORE init stuff
+ *  ---------------------
+ */
+
+int ossl_store_init_once(void);
+int ossl_store_file_loader_init(void);
diff --git a/crypto/store/store_register.c b/crypto/store/store_register.c
new file mode 100644
index 0000000..bde190e
--- /dev/null
+++ b/crypto/store/store_register.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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 <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include "store_locl.h"
+
+static CRYPTO_RWLOCK *registry_lock;
+static CRYPTO_ONCE registry_init = CRYPTO_ONCE_STATIC_INIT;
+
+DEFINE_RUN_ONCE_STATIC(do_registry_init)
+{
+    registry_lock = CRYPTO_THREAD_lock_new();
+    return registry_lock != NULL;
+}
+
+/*
+ *  Functions for manipulating OSSL_STORE_LOADERs
+ */
+
+OSSL_STORE_LOADER *OSSL_STORE_LOADER_new(ENGINE *e, const char *scheme)
+{
+    OSSL_STORE_LOADER *res = OPENSSL_zalloc(sizeof(*res));
+
+    if (res == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_LOADER_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    /*
+     * We usually don't check NULL arguments.  For loaders, though, the
+     * scheme is crucial and must never be NULL, or the user will get
+     * mysterious errors when trying to register the created loader
+     * later on.
+     */
+    if (scheme == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_LOADER_NEW,
+                      OSSL_STORE_R_INVALID_SCHEME);
+        return NULL;
+    }
+
+    res->engine = e;
+    res->scheme = scheme;
+    return res;
+}
+
+const ENGINE *OSSL_STORE_LOADER_get0_engine(const OSSL_STORE_LOADER *loader)
+{
+    return loader->engine;
+}
+
+const char *OSSL_STORE_LOADER_get0_scheme(const OSSL_STORE_LOADER *loader)
+{
+    return loader->scheme;
+}
+
+int OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER *loader,
+                               OSSL_STORE_open_fn open_function)
+{
+    loader->open = open_function;
+    return 1;
+}
+
+int OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER *loader,
+                               OSSL_STORE_ctrl_fn ctrl_function)
+{
+    loader->ctrl = ctrl_function;
+    return 1;
+}
+
+int OSSL_STORE_LOADER_set_load(OSSL_STORE_LOADER *loader,
+                               OSSL_STORE_load_fn load_function)
+{
+    loader->load = load_function;
+    return 1;
+}
+
+int OSSL_STORE_LOADER_set_eof(OSSL_STORE_LOADER *loader,
+                              OSSL_STORE_eof_fn eof_function)
+{
+    loader->eof = eof_function;
+    return 1;
+}
+
+int OSSL_STORE_LOADER_set_error(OSSL_STORE_LOADER *loader,
+                                OSSL_STORE_error_fn error_function)
+{
+    loader->error = error_function;
+    return 1;
+}
+
+int OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER *loader,
+                                OSSL_STORE_close_fn close_function)
+{
+    loader->close = close_function;
+    return 1;
+}
+
+void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader)
+{
+    OPENSSL_free(loader);
+}
+
+/*
+ *  Functions for registering OSSL_STORE_LOADERs
+ */
+
+static unsigned long store_loader_hash(const OSSL_STORE_LOADER *v)
+{
+    return OPENSSL_LH_strhash(v->scheme);
+}
+
+static int store_loader_cmp(const OSSL_STORE_LOADER *a,
+                            const OSSL_STORE_LOADER *b)
+{
+    if (a->scheme != NULL && b->scheme != NULL)
+        return strcmp(a->scheme, b->scheme);
+    else if (a->scheme == b->scheme)
+        return 0;
+    return a->scheme == NULL ? -1 : 1;
+}
+
+static LHASH_OF(OSSL_STORE_LOADER) *loader_register = NULL;
+
+int ossl_store_register_loader_int(OSSL_STORE_LOADER *loader)
+{
+    const char *scheme = loader->scheme;
+    int ok = 0;
+
+    /*
+     * Check that the given scheme conforms to correct scheme syntax as per
+     * RFC 3986:
+     *
+     * scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+     */
+    if (isalpha(*scheme))
+        while (*scheme != '\0'
+               && (isalpha(*scheme)
+                   || isdigit(*scheme)
+                   || strchr("+-.", *scheme) != NULL))
+            scheme++;
+    if (*scheme != '\0') {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT,
+                      OSSL_STORE_R_INVALID_SCHEME);
+        ERR_add_error_data(4, "scheme=", loader->scheme);
+        return 0;
+    }
+
+    if (!RUN_ONCE(&registry_init, do_registry_init)) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT,
+                      ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    CRYPTO_THREAD_write_lock(registry_lock);
+
+    if (loader_register == NULL) {
+        loader_register = lh_OSSL_STORE_LOADER_new(store_loader_hash,
+                                                   store_loader_cmp);
+    }
+
+    if (loader_register != NULL
+        && (lh_OSSL_STORE_LOADER_insert(loader_register, loader) != NULL
+            || lh_OSSL_STORE_LOADER_error(loader_register) == 0))
+        ok = 1;
+
+    CRYPTO_THREAD_unlock(registry_lock);
+
+    return ok;
+}
+int OSSL_STORE_register_loader(OSSL_STORE_LOADER *loader)
+{
+    if (!ossl_store_init_once())
+        return 0;
+    return ossl_store_register_loader_int(loader);
+}
+
+const OSSL_STORE_LOADER *ossl_store_get0_loader_int(const char *scheme)
+{
+    OSSL_STORE_LOADER template;
+    OSSL_STORE_LOADER *loader = NULL;
+
+    template.scheme = scheme;
+    template.open = NULL;
+    template.load = NULL;
+    template.eof = NULL;
+    template.close = NULL;
+
+    if (!ossl_store_init_once())
+        return NULL;
+
+    if (!RUN_ONCE(&registry_init, do_registry_init)) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT,
+                      ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    CRYPTO_THREAD_write_lock(registry_lock);
+
+    loader = lh_OSSL_STORE_LOADER_retrieve(loader_register, &template);
+
+    if (loader == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT,
+                      OSSL_STORE_R_UNREGISTERED_SCHEME);
+        ERR_add_error_data(2, "scheme=", scheme);
+    }
+
+    CRYPTO_THREAD_unlock(registry_lock);
+
+    return loader;
+}
+
+OSSL_STORE_LOADER *ossl_store_unregister_loader_int(const char *scheme)
+{
+    OSSL_STORE_LOADER template;
+    OSSL_STORE_LOADER *loader = NULL;
+
+    template.scheme = scheme;
+    template.open = NULL;
+    template.load = NULL;
+    template.eof = NULL;
+    template.close = NULL;
+
+    if (!RUN_ONCE(&registry_init, do_registry_init)) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT,
+                      ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    CRYPTO_THREAD_write_lock(registry_lock);
+
+    loader = lh_OSSL_STORE_LOADER_delete(loader_register, &template);
+
+    if (loader == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT,
+                      OSSL_STORE_R_UNREGISTERED_SCHEME);
+        ERR_add_error_data(2, "scheme=", scheme);
+    }
+
+    CRYPTO_THREAD_unlock(registry_lock);
+
+    return loader;
+}
+OSSL_STORE_LOADER *OSSL_STORE_unregister_loader(const char *scheme)
+{
+    if (!ossl_store_init_once())
+        return 0;
+    return ossl_store_unregister_loader_int(scheme);
+}
+
+void ossl_store_destroy_loaders_int(void)
+{
+    assert(lh_OSSL_STORE_LOADER_num_items(loader_register) == 0);
+    lh_OSSL_STORE_LOADER_free(loader_register);
+    loader_register = NULL;
+    CRYPTO_THREAD_lock_free(registry_lock);
+    registry_lock = NULL;
+}
+
+/*
+ *  Functions to list OSSL_STORE loaders
+ */
+
+IMPLEMENT_LHASH_DOALL_ARG_CONST(OSSL_STORE_LOADER, void);
+int OSSL_STORE_do_all_loaders(void (*do_function) (const OSSL_STORE_LOADER
+                                                   *loader, void *do_arg),
+                              void *do_arg)
+{
+    lh_OSSL_STORE_LOADER_doall_void(loader_register, do_function, do_arg);
+    return 1;
+}
diff --git a/crypto/store/store_strings.c b/crypto/store/store_strings.c
new file mode 100644
index 0000000..76cf316
--- /dev/null
+++ b/crypto/store/store_strings.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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/store.h>
+
+static char *type_strings[] = {
+    "Name",                      /* OSSL_STORE_INFO_NAME */
+    "Parameters",                /* OSSL_STORE_INFO_PARAMS */
+    "Pkey",                      /* OSSL_STORE_INFO_PKEY */
+    "Certificate",               /* OSSL_STORE_INFO_CERT */
+    "CRL"                        /* OSSL_STORE_INFO_CRL */
+};
+
+const char *OSSL_STORE_INFO_type_string(int type)
+{
+    int types = sizeof(type_strings) / sizeof(type_strings[0]);
+
+    if (type < 1 || type > types)
+        return NULL;
+
+    return type_strings[type - 1];
+}
diff --git a/doc/man1/storeutl.pod b/doc/man1/storeutl.pod
new file mode 100644
index 0000000..8874f34
--- /dev/null
+++ b/doc/man1/storeutl.pod
@@ -0,0 +1,76 @@
+=pod
+
+=head1 NAME
+
+storeutl - STORE utility
+
+=head1 SYNOPSIS
+
+B<openssl> B<storeutl>
+[B<-help>]
+[B<-out file>]
+[B<-noout>]
+[B<-passin arg>]
+[B<-text arg>]
+[B<-engine id>]
+B<uri> ...
+
+=head1 DESCRIPTION
+
+The B<storeutl> command can be used to display the contents (after decryption
+as the case may be) fetched from the given URIs.
+
+=head1 COMMAND OPTIONS
+
+=over 4
+
+=item B<-help>
+
+Print out a usage message.
+
+=item B<-out filename>
+
+specifies the output filename to write to or standard output by
+default.
+
+=item B<-noout>
+
+this option prevents output of the PEM data.
+
+=item B<-passin arg>
+
+the key password source. For more information about the format of B<arg>
+see the B<PASS PHRASE ARGUMENTS> section in L<openssl(1)>.
+
+=item B<-text>
+
+Prints out the objects in text form, similarly to the B<-text> output from
+B<openssl x509>, B<openssl pkey>, etc.
+
+=item B<-engine id>
+
+specifying an engine (by its unique B<id> string) will cause B<storeutl>
+to attempt to obtain a functional reference to the specified engine,
+thus initialising it if needed.
+The engine will then be set as the default for all available algorithms.
+
+=back
+
+=head1 SEE ALSO
+
+L<openssl(1)>
+
+=head1 HISTORY
+
+B<openssl> B<storeutl> was added to OpenSSL 1.1.1.
+
+=head1 COPYRIGHT
+
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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_STORE_INFO.pod b/doc/man3/OSSL_STORE_INFO.pod
new file mode 100644
index 0000000..22ab666
--- /dev/null
+++ b/doc/man3/OSSL_STORE_INFO.pod
@@ -0,0 +1,196 @@
+=pod
+
+=head1 NAME
+
+OSSL_STORE_INFO, OSSL_STORE_INFO_get_type, OSSL_STORE_INFO_get0_NAME,
+OSSL_STORE_INFO_get0_NAME_description, OSSL_STORE_INFO_get0_PARAMS,
+OSSL_STORE_INFO_get0_PKEY, OSSL_STORE_INFO_get0_CERT, OSSL_STORE_INFO_get0_CRL,
+OSSL_STORE_INFO_get1_NAME, OSSL_STORE_INFO_get1_NAME_description,
+OSSL_STORE_INFO_get1_PARAMS, OSSL_STORE_INFO_get1_PKEY,
+OSSL_STORE_INFO_get1_CERT,
+OSSL_STORE_INFO_get1_CRL, OSSL_STORE_INFO_type_string, OSSL_STORE_INFO_free, 
+OSSL_STORE_INFO_new_NAME, OSSL_STORE_INFO_set0_NAME_description,
+OSSL_STORE_INFO_new_PARAMS, OSSL_STORE_INFO_new_PKEY, OSSL_STORE_INFO_new_CERT,
+OSSL_STORE_INFO_new_CRL - Functions to manipulate OSSL_STORE_INFO objects 
+
+=head1 SYNOPSIS
+
+ #include <openssl/store.h>
+ 
+ typedef struct ossl_store_info_st OSSL_STORE_INFO;
+
+ int OSSL_STORE_INFO_get_type(const OSSL_STORE_INFO *store_info);
+ const char *OSSL_STORE_INFO_get0_NAME(const OSSL_STORE_INFO *store_info);
+ char *OSSL_STORE_INFO_get1_NAME(const OSSL_STORE_INFO *store_info);
+ const char *OSSL_STORE_INFO_get0_NAME_description(const OSSL_STORE_INFO
+                                                   *store_info);
+ char *OSSL_STORE_INFO_get1_NAME_description(const OSSL_STORE_INFO *store_info);
+ EVP_PKEY *OSSL_STORE_INFO_get0_PARAMS(const OSSL_STORE_INFO *store_info);
+ EVP_PKEY *OSSL_STORE_INFO_get1_PARAMS(const OSSL_STORE_INFO *store_info);
+ EVP_PKEY *OSSL_STORE_INFO_get0_PKEY(const OSSL_STORE_INFO *store_info);
+ EVP_PKEY *OSSL_STORE_INFO_get1_PKEY(const OSSL_STORE_INFO *store_info);
+ X509 *OSSL_STORE_INFO_get0_CERT(const OSSL_STORE_INFO *store_info);
+ X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *store_info);
+ X509_CRL *OSSL_STORE_INFO_get0_CRL(const OSSL_STORE_INFO *store_info);
+ X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *store_info);
+
+ const char *OSSL_STORE_INFO_type_string(int type);
+
+ void OSSL_STORE_INFO_free(OSSL_STORE_INFO *store_info);
+
+ OSSL_STORE_INFO *OSSL_STORE_INFO_new_NAME(char *name);
+ int OSSL_STORE_INFO_set0_NAME_description(OSSL_STORE_INFO *info, char *desc);
+ OSSL_STORE_INFO *OSSL_STORE_INFO_new_PARAMS(DSA *dsa_params);
+ OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey);
+ OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509);
+ OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl);
+
+=head1 DESCRIPTION
+
+These functions are primarly useful for applications to retrieve
+supported objects from B<OSSL_STORE_INFO> objects and for scheme specific
+loaders to create B<OSSL_STORE_INFO> holders.
+
+=head2 Types
+
+B<OSSL_STORE_INFO> is an opaque type that's just an intermediary holder for
+the objects that have been retrieved by OSSL_STORE_load() and similar
+functions.
+Supported OpenSSL type object can be extracted using one of
+STORE_INFO_get0_TYPE().
+The life time of this extracted object is as long as the life time of
+the B<OSSL_STORE_INFO> it was extracted from, so care should be taken not
+to free the latter too early.
+As an alternative, STORE_INFO_get1_TYPE() extracts a duplicate (or the
+same object with its reference count increased), which can be used
+after the containing B<OSSL_STORE_INFO> has been freed.
+The object returned by STORE_INFO_get1_TYPE() must be freed separately
+by the caller.
+See L</SUPPORTED OBJECTS> for more information on the types that are
+supported.
+
+=head2 Functions
+
+OSSL_STORE_INFO_get_type() takes a B<OSSL_STORE_INFO> and returns the STORE
+type number for the object inside.
+STORE_INFO_get_type_string() takes a STORE type number and returns a
+short string describing it.
+
+OSSL_STORE_INFO_get0_NAME(), OSSL_STORE_INFO_get0_NAME_description(),
+OSSL_STORE_INFO_get0_PARAMS(), OSSL_STORE_INFO_get0_PKEY(),
+OSSL_STORE_INFO_get0_CERT() and OSSL_STORE_INFO_get0_CRL() all take a
+B<OSSL_STORE_INFO> and return the held object of the appropriate OpenSSL
+type provided that's what's held.
+
+OSSL_STORE_INFO_get1_NAME(), OSSL_STORE_INFO_get1_NAME_description(),
+OSSL_STORE_INFO_get1_PARAMS(), OSSL_STORE_INFO_get1_PKEY(),
+OSSL_STORE_INFO_get1_CERT() and OSSL_STORE_INFO_get1_CRL() all take a
+B<OSSL_STORE_INFO> and return a duplicate of the held object of the
+appropriate OpenSSL type provided that's what's held.
+
+OSSL_STORE_INFO_free() frees a B<OSSL_STORE_INFO> and its contained type.
+
+OSSL_STORE_INFO_new_NAME() , OSSL_STORE_INFO_new_PARAMS(),
+OSSL_STORE_INFO_new_PKEY(), OSSL_STORE_INFO_new_CERT() and
+OSSL_STORE_INFO_new_CRL() create a B<OSSL_STORE_INFO>
+object to hold the given input object.
+Additionally, for B<OSSL_STORE_INFO_NAME>` objects,
+OSSL_STORE_INFO_set0_NAME_description() can be used to add an extra
+description.
+This description is meant to be human readable and should be used for
+information printout.
+
+=head1 SUPPORTED OBJECTS
+
+Currently supported object types are:
+
+=over 4
+
+=item OSSL_STORE_INFO_NAME
+
+A name is exactly that, a name.
+It's like a name in a directory, but formatted as a complete URI.
+For example, the path in URI C<file:/foo/bar/> could include a file
+named C<cookie.pem>, and in that case, the returned B<OSSL_STORE_INFO_NAME>
+object would have the URI C<file:/foo/bar/cookie.pem>, which can be
+used by the application to get the objects in that file.
+This can be applied to all schemes that can somehow support a listing
+of object URIs.
+
+For C<file:> URIs that are used without the explicit scheme, or paths
+given to L<OSSL_STORE_open_file(3)>, the returned name will be the path of
+each object, so if C</foo/bar> was given and that path has the file
+C<cookie.pem>, the name C</foo/bar/cookie.pem> will be returned.
+
+At the discretion of the loader that was used to get these names, an
+extra description may be attached as well.
+
+=item OSSL_STORE_INFO_PARAMS
+
+Key parameters.
+
+=item OSSL_STORE_INFO_PKEY
+
+A private/public key of some sort.
+
+=item OSSL_STORE_INFO_CERT
+
+An X.509 certificate.
+
+=item OSSL_STORE_INFO_CRL
+
+A X.509 certificate reocation list.
+
+=back
+
+=head1 RETURN VALUES
+
+OSSL_STORE_INFO_get_type() returns the STORE type number of the given
+B<OSSL_STORE_INFO>.
+There is no error value.
+
+OSSL_STORE_INFO_get0_NAME(), OSSL_STORE_INFO_get0_NAME_description(),
+OSSL_STORE_INFO_get0_PARAMS(), OSSL_STORE_INFO_get0_PKEY(),
+OSSL_STORE_INFO_get0_CERT() and OSSL_STORE_INFO_get0_CRL() all return
+a pointer to the OpenSSL object on success, NULL otherwise.
+
+OSSL_STORE_INFO_get0_NAME(), OSSL_STORE_INFO_get0_NAME_description(),
+OSSL_STORE_INFO_get0_PARAMS(), OSSL_STORE_INFO_get0_PKEY(),
+OSSL_STORE_INFO_get0_CERT() and OSSL_STORE_INFO_get0_CRL() all return
+a pointer to a duplicate of the OpenSSL object on success, NULL otherwise.
+
+OSSL_STORE_INFO_type_string() returns a string on success, or B<NULL> on
+failure.
+
+OSSL_STORE_INFO_new_NAME(), OSSL_STORE_INFO_new_PARAMS(),
+OSSL_STORE_INFO_new_PKEY(), OSSL_STORE_INFO_new_CERT() and
+OSSL_STORE_INFO_new_CRL() return a B<OSSL_STORE_INFO>
+pointer on success, or B<NULL> on failure.
+
+OSSL_STORE_INFO_set0_NAME_description() returns 1 on success, or 0 on
+failure.
+
+=head1 SEE ALSO
+
+L<ossl_store(7)>, L<OSSL_STORE_open(3)>, L<OSSL_STORE_register_loader(3)>
+
+=head1 HISTORY
+
+OSSL_STORE_INFO(), OSSL_STORE_INFO_get_type(), OSSL_STORE_INFO_get0_NAME(),
+OSSL_STORE_INFO_get0_PARAMS(), OSSL_STORE_INFO_get0_PKEY(),
+OSSL_STORE_INFO_get0_CERT(), OSSL_STORE_INFO_get0_CRL(),
+OSSL_STORE_INFO_type_string(), OSSL_STORE_INFO_free(), OSSL_STORE_INFO_new_NAME(),
+OSSL_STORE_INFO_new_PARAMS(), OSSL_STORE_INFO_new_PKEY(),
+OSSL_STORE_INFO_new_CERT() and OSSL_STORE_INFO_new_CRL()
+were added to OpenSSL 1.1.1.
+
+=head1 COPYRIGHT
+
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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_STORE_LOADER.pod b/doc/man3/OSSL_STORE_LOADER.pod
new file mode 100644
index 0000000..4386c28
--- /dev/null
+++ b/doc/man3/OSSL_STORE_LOADER.pod
@@ -0,0 +1,229 @@
+=pod
+
+=head1 NAME
+
+OSSL_STORE_LOADER, OSSL_STORE_LOADER_CTX, OSSL_STORE_LOADER_new,
+OSSL_STORE_LOADER_get0_engine, OSSL_STORE_LOADER_get0_scheme,
+OSSL_STORE_LOADER_set_open, OSSL_STORE_LOADER_set_ctrl,
+OSSL_STORE_LOADER_set_load, OSSL_STORE_LOADER_set_eof,
+OSSL_STORE_LOADER_set_error, OSSL_STORE_LOADER_set_close,
+OSSL_STORE_LOADER_free, OSSL_STORE_register_loader,
+OSSL_STORE_unregister_loader, OSSL_STORE_open_fn, OSSL_STORE_ctrl_fn,
+OSSL_STORE_load_fn, OSSL_STORE_eof_fn, OSSL_STORE_error_fn,
+OSSL_STORE_close_fn - Types and functions to manipulate, register and
+unregister STORE loaders for different URI schemes
+
+=head1 SYNOPSIS
+
+ #include <openssl/store.h>
+
+ typedef struct ossl_store_loader_st OSSL_STORE_LOADER;
+
+ OSSL_STORE_LOADER *OSSL_STORE_LOADER_new(ENGINE *e, const char *scheme);
+ const ENGINE *OSSL_STORE_LOADER_get0_engine(const OSSL_STORE_LOADER
+                                             *store_loader);
+ const char *OSSL_STORE_LOADER_get0_scheme(const OSSL_STORE_LOADER
+                                           *store_loader);
+
+ /* struct ossl_store_loader_ctx_st is defined differently by each loader */
+ typedef struct ossl_store_loader_ctx_st OSSL_STORE_LOADER_CTX;
+
+ typedef OSSL_STORE_LOADER_CTX *(*OSSL_STORE_open_fn)(const char *uri,
+                                                      const UI_METHOD *ui_method,
+                                                      void *ui_data);
+ int OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER *store_loader,
+                                OSSL_STORE_open_fn store_open_function);
+ typedef int (*OSSL_STORE_ctrl_fn)(OSSL_STORE_LOADER_CTX *ctx, int cmd,
+                                   va_list args);
+ int OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER *store_loader,
+                                OSSL_STORE_ctrl_fn store_ctrl_function);
+ typedef OSSL_STORE_INFO *(*OSSL_STORE_load_fn)(OSSL_STORE_LOADER_CTX *ctx,
+                                                UI_METHOD *ui_method,
+                                                void *ui_data);
+ int OSSL_STORE_LOADER_set_load(OSSL_STORE_LOADER *store_loader,
+                                OSSL_STORE_load_fn store_load_function);
+ typedef int (*OSSL_STORE_eof_fn)(OSSL_STORE_LOADER_CTX *ctx);
+ int OSSL_STORE_LOADER_set_eof(OSSL_STORE_LOADER *store_loader,
+                               OSSL_STORE_eof_fn store_eof_function);
+ typedef int (*OSSL_STORE_error_fn)(OSSL_STORE_LOADER_CTX *ctx);
+ int OSSL_STORE_LOADER_set_error(OSSL_STORE_LOADER *store_loader,
+                                 OSSL_STORE_error_fn store_error_function);
+ typedef int (*OSSL_STORE_close_fn)(OSSL_STORE_LOADER_CTX *ctx);
+ int OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER *store_loader,
+                                 OSSL_STORE_close_fn store_close_function);
+ void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *store_loader);
+ 
+ int OSSL_STORE_register_loader(OSSL_STORE_LOADER *loader);
+ OSSL_STORE_LOADER *OSSL_STORE_unregister_loader(const char *scheme);
+
+=head1 DESCRIPTION
+
+These functions help applications and engines to create loaders for
+schemes they support.
+
+=head2 Types
+
+B<OSSL_STORE_LOADER> is the type to hold a loader.
+It contains a scheme and the functions needed to implement
+OSSL_STORE_open(), OSSL_STORE_load(), OSSL_STORE_eof(), OSSL_STORE_error() and
+OSSL_STORE_close() for this scheme.
+
+B<OSSL_STORE_LOADER_CTX> is a type template, to be defined by each loader
+using B<struct ossl_store_loader_ctx_st { ... }>.
+
+B<OSSL_STORE_open_fn>, B<OSSL_STORE_ctrl_fn>, B<OSSL_STORE_load_fn>,
+B<OSSL_STORE_eof_fn> and B<OSSL_STORE_close_fn> are the function pointer
+types used within a STORE loader.
+The functions pointed at define the functionality of the given loader.
+
+=over 4
+
+=item B<OSSL_STORE_open_fn>
+
+This function takes a URI and is expected to interpret it in the best
+manner possible according to the scheme the loader implements, it also
+takes a B<UI_METHOD> and associated data, to be used any time
+something needs to be prompted for.
+Furthermore, this function is expected to initialize what needs to be
+initialized, to create a privata data store (B<OSSL_STORE_LOADER_CTX>, see
+above), and to return it.
+If something goes wrong, this function is expected to return NULL.
+
+=item B<OSSL_STORE_ctrl_fn>
+
+This function takes a B<OSSL_STORE_LOADER_CTX> pointer, a command number
+B<cmd> and a B<va_list> B<args> and is used to manipulate loader
+specific parameters.
+
+=begin comment
+
+Globally known command numbers are documented in L<OSSL_STORE_ctrl(3)>,
+along with what B<args> are expected with each of them.
+
+=end comment
+
+Loader specific command numbers must begin at B<OSSL_STORE_C_CUSTOM_START>.
+Any number below that is reserved for future globally known command
+numbers.
+
+This function is expected to return 1 on success, 0 on error.
+
+=item B<OSSL_STORE_load_fn>
+
+This function takes a B<OSSL_STORE_LOADER_CTX> pointer and a B<UI_METHOD>
+with associated data.
+It's expected to load the next available data, mold it into a data
+structure that can be wrapped in a B<OSSL_STORE_INFO> using one of the
+L<OSSL_STORE_INFO(3)> functions.
+If no more data is available or an error occurs, this function is
+expected to return NULL.
+The B<OSSL_STORE_eof_fn> and B<OSSL_STORE_error_fn> functions must indicate if
+it was in fact the end of data or if an error occured.
+
+Note that this function retrives I<one> data item only.
+
+=item B<OSSL_STORE_eof_fn>
+
+This function takes a B<OSSL_STORE_LOADER_CTX> pointer and is expected to
+return 1 to indicate that the end of available data has been reached.
+It is otherwise expected to return 0.
+
+=item B<OSSL_STORE_error_fn>
+
+This function takes a B<OSSL_STORE_LOADER_CTX> pointer and is expected to
+return 1 to indicate that an error occured in a previous call to the
+B<OSSL_STORE_load_fn> function.
+It is otherwise expected to return 0.
+
+=item B<OSSL_STORE_close_fn>
+
+This function takes a B<OSSL_STORE_LOADER_CTX> pointer and is expected to
+close or shut down what needs to be closed, and finally free the
+contents of the B<OSSL_STORE_LOADER_CTX> pointer.
+It returns 1 on success and 0 on error.
+
+=back
+
+=head2 Functions
+
+OSSL_STORE_LOADER_new() creates a new B<OSSL_STORE_LOADER>.
+It takes an B<ENGINE> B<e> and a string B<scheme>.
+B<scheme> must I<always> be set.
+Both B<e> and B<scheme> are used as is and must therefore be alive as
+long as the created loader is.
+
+OSSL_STORE_LOADER_get0_engine() returns the engine of the B<store_loader>.
+OSSL_STORE_LOADER_get0_scheme() returns the scheme of the B<store_loader>.
+
+OSSL_STORE_LOADER_set_open() sets the opener function for the
+B<store_loader>.
+
+OSSL_STORE_LOADER_set_ctrl() sets the control function for the
+B<store_loader>.
+
+OSSL_STORE_LOADER_set_load() sets the loader function for the
+B<store_loader>.
+
+OSSL_STORE_LOADER_set_eof() sets the end of file checker function for the
+B<store_loader>.
+
+OSSL_STORE_LOADER_set_close() sets the closing function for the
+B<store_loader>.
+
+OSSL_STORE_LOADER_free() frees the given B<store_loader>.
+
+OSSL_STORE_register_loader() register the given B<store_loader> and thereby
+makes it available for use with OSSL_STORE_open(), OSSL_STORE_load(),
+OSSL_STORE_eof() and OSSL_STORE_close().
+
+OSSL_STORE_unregister_loader() unregister the store loader for the given
+B<scheme>.
+
+=head1 NOTES
+
+The B<file:> scheme has built in support.
+
+=head1 RETURN VALUES
+
+The functions with the types B<OSSL_STORE_open_fn>, B<OSSL_STORE_ctrl_fn>,
+B<OSSL_STORE_load_fn>, B<OSSL_STORE_eof_fn> and B<OSSL_STORE_close_fn> have the
+same return values as OSSL_STORE_open(), OSSL_STORE_load(), OSSL_STORE_eof() and
+OSSL_STORE_close(), respectively.
+
+OSSL_STORE_LOADER_new() returns a pointer to a B<OSSL_STORE_LOADER> on success,
+or B<NULL> on failure.
+
+OSSL_STORE_LOADER_set_open(), OSSL_STORE_LOADER_set_ctrl(),
+OSSL_STORE_LOADER_set_load(), OSSL_STORE_LOADER_set_eof() and
+OSSL_STORE_LOADER_set_close() return 1 on success, or 0 on failure.
+
+OSSL_STORE_register_loader() returns 1 on success, or 0 on failure.
+
+OSSL_STORE_unregister_loader() returns the unregistered loader on success,
+or B<NULL> on failure.
+
+=head1 SEE ALSO
+
+L<ossl_store(7)>, L<OSSL_STORE_open(3)>
+
+=head1 HISTORY
+
+OSSL_STORE_LOADER(), OSSL_STORE_LOADER_CTX(), OSSL_STORE_LOADER_new(),
+OSSL_STORE_LOADER_set0_scheme(), OSSL_STORE_LOADER_set_open(),
+OSSL_STORE_LOADER_set_ctrl(), OSSL_STORE_LOADER_set_load(),
+OSSL_STORE_LOADER_set_eof(), OSSL_STORE_LOADER_set_close(),
+OSSL_STORE_LOADER_free(), OSSL_STORE_register_loader(),
+OSSL_STORE_unregister_loader(), OSSL_STORE_open_fn(), OSSL_STORE_ctrl_fn(),
+OSSL_STORE_load_fn(), OSSL_STORE_eof_fn() and OSSL_STORE_close_fn()
+were added to OpenSSL 1.1.1.
+
+=head1 COPYRIGHT
+
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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_STORE_open.pod b/doc/man3/OSSL_STORE_open.pod
new file mode 100644
index 0000000..9a05443
--- /dev/null
+++ b/doc/man3/OSSL_STORE_open.pod
@@ -0,0 +1,145 @@
+=pod
+
+=head1 NAME
+
+OSSL_STORE_CTX, OSSL_STORE_post_process_info_fn, OSSL_STORE_open,
+OSSL_STORE_ctrl, OSSL_STORE_load, OSSL_STORE_eof, OSSL_STORE_error,
+OSSL_STORE_close - Types and functions to read objects from a URI
+
+=head1 SYNOPSIS
+
+ #include <openssl/store.h>
+ 
+ typedef struct ossl_store_ctx_st OSSL_STORE_CTX;
+
+ typedef OSSL_STORE_INFO *(*OSSL_STORE_post_process_info_fn)(OSSL_STORE_INFO *,
+                                                             void *);
+
+ OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
+                                 void *ui_data,
+                                 OSSL_STORE_post_process_info_fn post_process,
+                                 void *post_process_data);
+ int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ... /* args */);
+ OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx);
+ int OSSL_STORE_eof(OSSL_STORE_CTX *ctx);
+ int OSSL_STORE_error(OSSL_STORE_CTX *ctx);
+ int OSSL_STORE_close(OSSL_STORE_CTX *ctx);
+
+=head1 DESCRIPTION
+
+These functions help the application to fetch supported objects (see
+L<OSSL_STORE_INFO(3)/SUPPORTED OBJECTS> for information on which those are)
+from a given URI (see L</SUPPORTED SCHEMES> for more information on
+the supported URI schemes).
+The general method to do so is to "open" the URI using OSSL_STORE_open(),
+read each available and supported object using OSSL_STORE_load() as long as
+OSSL_STORE_eof() hasn't been reached, and finish it off with OSSL_STORE_close().
+
+The retrieved information is stored in a B<OSSL_STORE_INFO>, which is further
+described in L<OSSL_STORE_INFO(3)>.
+
+=head2 Types
+
+B<OSSL_STORE_CTX> is a context variable that holds all the internal
+information for OSSL_STORE_open(), OSSL_STORE_load(), OSSL_STORE_eof() and
+OSSL_STORE_close() to work together.
+
+=head2 Functions
+
+OSSL_STORE_open() takes a uri or path B<uri>, password UI method
+B<ui_method> with associated data B<ui_data>, and post processing
+callback B<post_process> with associated data B<post_process_data>,
+opens a channel to the data located at that URI and returns a
+B<OSSL_STORE_CTX> with all necessary internal information.
+The given B<ui_method> and B<ui_data_data> will be reused by all
+functions that use B<OSSL_STORE_CTX> when interaction is needed.
+The given B<post_process> and B<post_process_data> will be reused by
+OSSL_STORE_load() to manipulate or drop the value to be returned.
+
+OSSL_STORE_ctrl() takes a B<OSSL_STORE_CTX>, and command number B<cmd> and
+more arguments not specified here.
+The available command numbers and arguments they each take depends on
+the loader that's used and is documented together with that loader.
+
+OSSL_STORE_load() takes a B<OSSL_STORE_CTX>, tries to load the next available
+object and return it wrapped with  B<OSSL_STORE_INFO>.
+
+OSSL_STORE_eof() takes a B<OSSL_STORE_CTX> and checks if we've reached the end
+of data.
+
+OSSL_STORE_error() takes a B<OSSL_STORE_CTX> and checks if an error occured in
+the last OSSL_STORE_load() call.
+Note that it may still be meaningful to try and load more objects, unless
+OSSL_STORE_eof() shows that the end of data has been reached.
+
+OSSL_STORE_close() takes a B<OSSL_STORE_CTX>, closes the channel that was opened
+by OSSL_STORE_open() and frees all other information that was stored in the
+B<OSSL_STORE_CTX>, as well as the B<OSSL_STORE_CTX> itself.
+
+=head1 SUPPORTED SCHEMES
+
+The basic supported scheme is B<file:>.
+Any other scheme can be added dynamically, using
+OSSL_STORE_register_loader().
+
+=head1 NOTES
+
+When unsure whether a given string contains a simple file or directory
+reference, or if it's a full blown URI, the question is how to figure
+that out.
+One way is to try OSSL_STORE_open_file() and if that fails, try
+OSSL_STORE_open().
+The other way is the other way around.
+Either way you choose, there are corner cases,
+F<file:/foo/bar/cookie.txt> might very will be a simple file reference
+on a system that supports the notion of volumes.
+
+This manual won't tell you which way is better, that's up to each
+application developer to decide on their own.
+However, there are some tools that can be used together with
+OSSL_STORE_open() to determine if any failure is caused by an unparsable
+URI, or if it's a different error (such as memory allocation
+failures); if the URI was parsable but the scheme unregistered, the
+top error will have the reason C<OSSL_STORE_R_UNREGISTERED_SCHEME>.
+If you decide to use OSSL_STORE_open() with OSSL_STORE_open_file() as a
+fallback, those reasons can be good tools to decide if the fallback
+should be taken or not.
+
+=head1 RETURN VALUES
+
+OSSL_STORE_open() returns a pointer to a B<OSSL_STORE_CTX> on success, or
+B<NULL> on failure.
+
+OSSL_STORE_load() returns a pointer to a B<OSSL_STORE_INFO> on success, or
+B<NULL> on error or when end of data is reached.
+Use OSSL_STORE_error() and OSSL_STORE_eof() to determine the meaning of a
+returned B<NULL>.
+
+OSSL_STORE_eof() returns 1 if the end of data has been reached, otherwise
+0.
+
+OSSL_STORE_error() returns 1 if an error occured in a OSSL_STORE_load() call,
+otherwise 0.
+
+OSSL_STORE_ctrl() and OSSL_STORE_close() returns 1 on success, or 0 on failure.
+
+=head1 SEE ALSO
+
+L<ossl_store(7)>, L<OSSL_STORE_INFO(3)>, L<OSSL_STORE_register_loader(3)>
+
+=head1 HISTORY
+
+OSSL_STORE_CTX(), OSSL_STORE_post_process_info_fn(), OSSL_STORE_open(),
+OSSL_STORE_ctrl(), OSSL_STORE_load(), OSSL_STORE_eof() and OSSL_STORE_close()
+were added to OpenSSL 1.1.1.
+
+=head1 COPYRIGHT
+
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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/man7/ossl_store.pod b/doc/man7/ossl_store.pod
new file mode 100644
index 0000000..b4b76dd
--- /dev/null
+++ b/doc/man7/ossl_store.pod
@@ -0,0 +1,103 @@
+=pod
+
+=head1 NAME
+
+ossl_store - Store retrieval functions
+
+=head1 SYNOPSIS
+
+=for comment generic
+
+#include <openssl/store.h>
+
+=head1 DESCRIPTION
+
+=head2 General
+
+A STORE is a layer of functionality to retrieve a number of supported
+objects from a repository of any kind, addressable as a file name or
+as a URI.
+
+The functionality supports the pattern "open a channel to the
+repository", "loop and retrieve one object at a time", and "finish up
+by closing the channel".
+
+The retrieved objects are returned as a wrapper type B<OSSL_STORE_INFO>,
+from which an OpenSSL type can be retrieved.
+
+=head2 URI schemes and loaders
+
+Support for a URI scheme is called a STORE "loader", and can be added
+dynamically from the calling application or from a loadable engine.
+
+=head2 The 'file' scheme
+
+Support for the 'file' scheme is already built into C<libcrypto>.
+Since files come in all kinds of formats and content types, the 'file'
+scheme has its own layer of functionality called "file handlers",
+which are used to try to decode diverse types of file contents.
+
+In case a file is formatted as PEM, each called file handler receives
+the PEM name (everything following any 'C<-----BEGIN >') as well as
+possible PEM headers, together with the decoded PEM body.  Since PEM
+formatted files can contain more than one object, the file handlers
+are called upon for each such object.
+
+If the file isn't determined to be formatted as PEM, the content is
+loaded in raw form in its entirety and passed to the available file
+handlers as is, with no PEM name or headers.
+
+Each file handler is expected to handle PEM and non-PEM content as
+appropriate.  Some may refuse non-PEM content for the sake of
+determinism (for example, there are keys out in the wild that are
+represented as an ASN.1 OCTET STRING.  In raw form, it's not easily
+possible to distinguish those from any other data coming as an ASN.1
+OCTET STRING, so such keys would naturally be accepted as PEM files
+only).
+
+=head1 EXAMPLES
+
+=head2 A generic call
+
+ /*
+  * There is also a OSSL_STORE_open_file() that can be used for file paths
+  * that can't be represented as URIs, such as Windows backslashes
+  */
+ OSSL_STORE_CTX *ctx = OSSL_STORE_open("file:/foo/bar/data.pem");
+
+ /*
+  * OSSL_STORE_eof() simulates file semantics for any repository to signal
+  * that no more data can be expected
+  */ 
+ while (!OSSL_STORE_eof(ctx)) {
+     OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
+
+     /*
+      * Do whatever is necessary with the OSSL_STORE_INFO,
+      * here just one example
+      */
+     switch (OSSL_STORE_INFO_get_type(info)) {
+     case OSSL_STORE_INFO_X509:
+         /* Print the X.509 certificate text */
+         X509_print_fp(stdout, OSSL_STORE_INFO_get0_CERT(info));
+         /* Print the X.509 certificate PEM output */
+         PEM_write_X509(stdout, OSSL_STORE_INFO_get0_CERT(info));
+         break;
+     }
+ }
+
+ OSSL_STORE_close(ctx);
+
+=head1 SEE ALSO
+L<OSSL_STORE_open(3)>, L<OSSL_STORE_INFO(3)>, L<OSSL_STORE_LOADER(3)>
+
+=head1 COPYRIGHT
+
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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/openssl/bio.h b/include/openssl/bio.h
index 5f8f83a..75aa884 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -88,6 +88,7 @@ extern "C" {
 # define BIO_CTRL_SET_CALLBACK   14/* opt - set callback function */
 # define BIO_CTRL_GET_CALLBACK   15/* opt - set callback function */
 
+# define BIO_CTRL_PEEK           29/* BIO_f_buffer special */
 # define BIO_CTRL_SET_FILENAME   30/* BIO_s_file special */
 
 /* dgram BIO stuff */
@@ -494,6 +495,7 @@ size_t BIO_ctrl_wpending(BIO *b);
 
 /* For the BIO_f_buffer() type */
 # define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL)
+# define BIO_buffer_peek(b,s,l) BIO_ctrl(b,BIO_CTRL_PEEK,(l),(s))
 
 /* For BIO_s_bio() */
 # define BIO_set_write_buf_size(b,size) (int)BIO_ctrl(b,BIO_C_SET_WRITE_BUF_SIZE,size,NULL)
diff --git a/include/openssl/err.h b/include/openssl/err.h
index e60640b..d518d60 100644
--- a/include/openssl/err.h
+++ b/include/openssl/err.h
@@ -84,7 +84,7 @@ typedef struct err_state_st {
 # define ERR_LIB_COMP            41
 # define ERR_LIB_ECDSA           42
 # define ERR_LIB_ECDH            43
-# define ERR_LIB_STORE           44
+# define ERR_LIB_OSSL_STORE      44
 # define ERR_LIB_FIPS            45
 # define ERR_LIB_CMS             46
 # define ERR_LIB_TS              47
@@ -123,7 +123,7 @@ typedef struct err_state_st {
 # define COMPerr(f,r) ERR_PUT_error(ERR_LIB_COMP,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define ECDSAerr(f,r)  ERR_PUT_error(ERR_LIB_ECDSA,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define ECDHerr(f,r)  ERR_PUT_error(ERR_LIB_ECDH,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
-# define STOREerr(f,r) ERR_PUT_error(ERR_LIB_STORE,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
+# define OSSL_STOREerr(f,r) ERR_PUT_error(ERR_LIB_OSSL_STORE,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define FIPSerr(f,r) ERR_PUT_error(ERR_LIB_FIPS,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define CMSerr(f,r) ERR_PUT_error(ERR_LIB_CMS,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define TSerr(f,r) ERR_PUT_error(ERR_LIB_TS,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
@@ -131,6 +131,7 @@ typedef struct err_state_st {
 # define CTerr(f,r) ERR_PUT_error(ERR_LIB_CT,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define ASYNCerr(f,r) ERR_PUT_error(ERR_LIB_ASYNC,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define KDFerr(f,r) ERR_PUT_error(ERR_LIB_KDF,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
+# define OSSL_STOREerr(f,r) ERR_PUT_error(ERR_LIB_OSSL_STORE,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 
 # define ERR_PACK(l,f,r) ( \
         (((unsigned int)(l) & 0x0FF) << 24L) | \
@@ -163,6 +164,7 @@ typedef struct err_state_st {
 # define SYS_F_OPEN              19
 # define SYS_F_CLOSE             20
 # define SYS_F_IOCTL             21
+# define SYS_F_STAT              22
 
 /* reasons */
 # define ERR_R_SYS_LIB   ERR_LIB_SYS/* 2 */
@@ -181,7 +183,9 @@ typedef struct err_state_st {
 # define ERR_R_PKCS7_LIB ERR_LIB_PKCS7/* 33 */
 # define ERR_R_X509V3_LIB ERR_LIB_X509V3/* 34 */
 # define ERR_R_ENGINE_LIB ERR_LIB_ENGINE/* 38 */
+# define ERR_R_UI_LIB    ERR_LIB_UI/* 40 */
 # define ERR_R_ECDSA_LIB ERR_LIB_ECDSA/* 42 */
+# define ERR_R_OSSL_STORE_LIB ERR_LIB_OSSL_STORE/* 44 */
 
 # define ERR_R_NESTED_ASN1_ERROR                 58
 # define ERR_R_MISSING_ASN1_EOS                  63
diff --git a/include/openssl/ossl_typ.h b/include/openssl/ossl_typ.h
index deea038..173a42d 100644
--- a/include/openssl/ossl_typ.h
+++ b/include/openssl/ossl_typ.h
@@ -171,6 +171,8 @@ typedef struct ctlog_st CTLOG;
 typedef struct ctlog_store_st CTLOG_STORE;
 typedef struct ct_policy_eval_ctx_st CT_POLICY_EVAL_CTX;
 
+typedef struct ossl_store_info_st OSSL_STORE_INFO;
+
 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
     defined(INTMAX_MAX) && defined(UINTMAX_MAX)
 typedef intmax_t ossl_intmax_t;
diff --git a/include/openssl/store.h b/include/openssl/store.h
new file mode 100644
index 0000000..d3947df
--- /dev/null
+++ b/include/openssl/store.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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 HEADER_OSSL_STORE_H
+# define HEADER_OSSL_STORE_H
+
+# include <stdarg.h>
+# include <openssl/ossl_typ.h>
+# include <openssl/pem.h>
+# include <openssl/storeerr.h>
+
+# ifdef  __cplusplus
+extern "C" {
+# endif
+
+/*-
+ *  The main OSSL_STORE functions.
+ *  ------------------------------
+ *
+ *  These allow applications to open a channel to a resource with supported
+ *  data (keys, certs, crls, ...), read the data a piece at a time and decide
+ *  what to do with it, and finally close.
+ */
+
+typedef struct ossl_store_ctx_st OSSL_STORE_CTX;
+
+/*
+ * Typedef for the OSSL_STORE_INFO post processing callback.  This can be used
+ * to massage the given OSSL_STORE_INFO, or to drop it entirely (by returning
+ * NULL).
+ */
+typedef OSSL_STORE_INFO *(*OSSL_STORE_post_process_info_fn)(OSSL_STORE_INFO *,
+                                                            void *);
+
+/*
+ * Open a channel given a URI.  The given UI method will be used any time the
+ * loader needs extra input, for example when a password or pin is needed, and
+ * will be passed the same user data every time it's needed in this context.
+ *
+ * Returns a context reference which represents the channel to communicate
+ * through.
+ */
+OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
+                                void *ui_data,
+                                OSSL_STORE_post_process_info_fn post_process,
+                                void *post_process_data);
+
+/*
+ * Control / fine tune the OSSL_STORE channel.  |cmd| determines what is to be
+ * done, and depends on the underlying loader (use OSSL_STORE_get0_scheme to
+ * determine which loader is used), except for common commands (see below).
+ * Each command takes different arguments.
+ */
+int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ... /* args */);
+
+/*
+ * Common ctrl commands that different loaders may choose to support.
+ */
+/* Where custom commands start */
+# define OSSL_STORE_C_CUSTOM_START    100
+
+/*
+ * Read one data item (a key, a cert, a CRL) that is supported by the OSSL_STORE
+ * functionality, given a context.
+ * Returns a OSSL_STORE_INFO pointer, from which OpenSSL typed data can be
+ * extracted with OSSL_STORE_INFO_get0_PKEY(), OSSL_STORE_INFO_get0_CERT(), ...
+ * NULL is returned on error, which may include that the data found at the URI
+ * can't be figured out for certain or is ambiguous.
+ */
+OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx);
+
+/*
+ * Check if end of data (end of file) is reached
+ * Returns 1 on end, 0 otherwise.
+ */
+int OSSL_STORE_eof(OSSL_STORE_CTX *ctx);
+
+/*
+ * Check if an error occured
+ * Returns 1 if it did, 0 otherwise.
+ */
+int OSSL_STORE_error(OSSL_STORE_CTX *ctx);
+
+/*
+ * Close the channel
+ * Returns 1 on success, 0 on error.
+ */
+int OSSL_STORE_close(OSSL_STORE_CTX *ctx);
+
+
+/*-
+ *  Extracting OpenSSL types from and creating new OSSL_STORE_INFOs
+ *  ---------------------------------------------------------------
+ */
+
+/*
+ * Types of data that can be ossl_stored in a OSSL_STORE_INFO.
+ * OSSL_STORE_INFO_NAME is typically found when getting a listing of
+ * available "files" / "tokens" / what have you.
+ */
+# define OSSL_STORE_INFO_NAME           1   /* char * */
+# define OSSL_STORE_INFO_PARAMS         2   /* EVP_PKEY * */
+# define OSSL_STORE_INFO_PKEY           3   /* EVP_PKEY * */
+# define OSSL_STORE_INFO_CERT           4   /* X509 * */
+# define OSSL_STORE_INFO_CRL            5   /* X509_CRL * */
+
+/*
+ * Functions to generate OSSL_STORE_INFOs, one function for each type we
+ * support having in them.  Along with each of them, one macro that
+ * can be used to determine what types are supported.
+ *
+ * In all cases, ownership of the object is transfered to the OSSL_STORE_INFO
+ * and will therefore be freed when the OSSL_STORE_INFO is freed.
+ */
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_NAME(char *name);
+int OSSL_STORE_INFO_set0_NAME_description(OSSL_STORE_INFO *info, char *desc);
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_PARAMS(EVP_PKEY *params);
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey);
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509);
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl);
+
+/*
+ * Functions to try to extract data from a OSSL_STORE_INFO.
+ */
+int OSSL_STORE_INFO_get_type(const OSSL_STORE_INFO *info);
+const char *OSSL_STORE_INFO_get0_NAME(const OSSL_STORE_INFO *info);
+char *OSSL_STORE_INFO_get1_NAME(const OSSL_STORE_INFO *info);
+const char *OSSL_STORE_INFO_get0_NAME_description(const OSSL_STORE_INFO *info);
+char *OSSL_STORE_INFO_get1_NAME_description(const OSSL_STORE_INFO *info);
+EVP_PKEY *OSSL_STORE_INFO_get0_PARAMS(const OSSL_STORE_INFO *info);
+EVP_PKEY *OSSL_STORE_INFO_get1_PARAMS(const OSSL_STORE_INFO *info);
+EVP_PKEY *OSSL_STORE_INFO_get0_PKEY(const OSSL_STORE_INFO *info);
+EVP_PKEY *OSSL_STORE_INFO_get1_PKEY(const OSSL_STORE_INFO *info);
+X509 *OSSL_STORE_INFO_get0_CERT(const OSSL_STORE_INFO *info);
+X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *info);
+X509_CRL *OSSL_STORE_INFO_get0_CRL(const OSSL_STORE_INFO *info);
+X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *info);
+
+const char *OSSL_STORE_INFO_type_string(int type);
+
+/*
+ * Free the OSSL_STORE_INFO
+ */
+void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info);
+
+
+/*-
+ *  Function to register a loader for the given URI scheme.
+ *  -------------------------------------------------------
+ *
+ *  The loader receives all the main components of an URI except for the
+ *  scheme.
+ */
+
+typedef struct ossl_store_loader_st OSSL_STORE_LOADER;
+OSSL_STORE_LOADER *OSSL_STORE_LOADER_new(ENGINE *e, const char *scheme);
+const ENGINE *OSSL_STORE_LOADER_get0_engine(const OSSL_STORE_LOADER *loader);
+const char *OSSL_STORE_LOADER_get0_scheme(const OSSL_STORE_LOADER *loader);
+/* struct ossl_store_loader_ctx_st is defined differently by each loader */
+typedef struct ossl_store_loader_ctx_st OSSL_STORE_LOADER_CTX;
+typedef OSSL_STORE_LOADER_CTX *(*OSSL_STORE_open_fn)(const OSSL_STORE_LOADER
+                                                     *loader,
+                                                     const char *uri,
+                                                     const UI_METHOD *ui_method,
+                                                     void *ui_data);
+int OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER *loader,
+                               OSSL_STORE_open_fn open_function);
+typedef int (*OSSL_STORE_ctrl_fn)(OSSL_STORE_LOADER_CTX *ctx, int cmd,
+                                  va_list args);
+int OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER *loader,
+                               OSSL_STORE_ctrl_fn ctrl_function);
+typedef OSSL_STORE_INFO *(*OSSL_STORE_load_fn)(OSSL_STORE_LOADER_CTX *ctx,
+                                               const UI_METHOD *ui_method,
+                                               void *ui_data);
+int OSSL_STORE_LOADER_set_load(OSSL_STORE_LOADER *loader,
+                               OSSL_STORE_load_fn load_function);
+typedef int (*OSSL_STORE_eof_fn)(OSSL_STORE_LOADER_CTX *ctx);
+int OSSL_STORE_LOADER_set_eof(OSSL_STORE_LOADER *loader,
+                              OSSL_STORE_eof_fn eof_function);
+typedef int (*OSSL_STORE_error_fn)(OSSL_STORE_LOADER_CTX *ctx);
+int OSSL_STORE_LOADER_set_error(OSSL_STORE_LOADER *loader,
+                                OSSL_STORE_error_fn error_function);
+typedef int (*OSSL_STORE_close_fn)(OSSL_STORE_LOADER_CTX *ctx);
+int OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER *loader,
+                                OSSL_STORE_close_fn close_function);
+void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader);
+
+int OSSL_STORE_register_loader(OSSL_STORE_LOADER *loader);
+OSSL_STORE_LOADER *OSSL_STORE_unregister_loader(const char *scheme);
+
+/*-
+ *  Functions to list STORE loaders
+ *  -------------------------------
+ */
+int OSSL_STORE_do_all_loaders(void (*do_function) (const OSSL_STORE_LOADER
+                                                   *loader, void *do_arg),
+                              void *do_arg);
+
+
+/*
+ * Error strings
+ */
+int ERR_load_OSSL_STORE_strings(void);
+
+# ifdef  __cplusplus
+}
+# endif
+#endif
diff --git a/include/openssl/storeerr.h b/include/openssl/storeerr.h
new file mode 100644
index 0000000..1e0d23c
--- /dev/null
+++ b/include/openssl/storeerr.h
@@ -0,0 +1,74 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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 HEADER_OSSL_STOREERR_H
+# define HEADER_OSSL_STOREERR_H
+
+# ifdef  __cplusplus
+extern "C" {
+# endif
+int ERR_load_OSSL_STORE_strings(void);
+# ifdef  __cplusplus
+}
+# endif
+
+/*
+ * OSSL_STORE function codes.
+ */
+# define OSSL_STORE_F_FILE_GET_PASS                       118
+# define OSSL_STORE_F_FILE_LOAD                           119
+# define OSSL_STORE_F_FILE_LOAD_TRY_DECODE                124
+# define OSSL_STORE_F_FILE_NAME_TO_URI                    126
+# define OSSL_STORE_F_FILE_OPEN                           120
+# define OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT          100
+# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT           101
+# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL            102
+# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME           103
+# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION 135
+# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_PARAMS         104
+# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_PKEY           105
+# define OSSL_STORE_F_OSSL_STORE_INFO_NEW_CERT            106
+# define OSSL_STORE_F_OSSL_STORE_INFO_NEW_CRL             107
+# define OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED        123
+# define OSSL_STORE_F_OSSL_STORE_INFO_NEW_NAME            109
+# define OSSL_STORE_F_OSSL_STORE_INFO_NEW_PARAMS          110
+# define OSSL_STORE_F_OSSL_STORE_INFO_NEW_PKEY            111
+# define OSSL_STORE_F_OSSL_STORE_INFO_SET0_NAME_DESCRIPTION 134
+# define OSSL_STORE_F_OSSL_STORE_INIT_ONCE                112
+# define OSSL_STORE_F_OSSL_STORE_LOADER_NEW               113
+# define OSSL_STORE_F_OSSL_STORE_OPEN                     114
+# define OSSL_STORE_F_OSSL_STORE_OPEN_INT                 115
+# define OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT      117
+# define OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT    116
+# define OSSL_STORE_F_TRY_DECODE_PARAMS                   121
+# define OSSL_STORE_F_TRY_DECODE_PKCS12                   122
+# define OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED           125
+
+/*
+ * OSSL_STORE reason codes.
+ */
+# define OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE              107
+# define OSSL_STORE_R_BAD_PASSWORD_READ                   115
+# define OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC          113
+# define OSSL_STORE_R_INVALID_SCHEME                      106
+# define OSSL_STORE_R_IS_NOT_A                            112
+# define OSSL_STORE_R_NOT_A_CERTIFICATE                   100
+# define OSSL_STORE_R_NOT_A_CRL                           101
+# define OSSL_STORE_R_NOT_A_KEY                           102
+# define OSSL_STORE_R_NOT_A_NAME                          103
+# define OSSL_STORE_R_NOT_PARAMETERS                      104
+# define OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR           114
+# define OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE               108
+# define OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED 109
+# define OSSL_STORE_R_UNREGISTERED_SCHEME                 105
+# define OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE            110
+# define OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED            111
+
+#endif
diff --git a/test/recipes/90-test_store.t b/test/recipes/90-test_store.t
new file mode 100644
index 0000000..65cf9fb
--- /dev/null
+++ b/test/recipes/90-test_store.t
@@ -0,0 +1,349 @@
+#! /usr/bin/env perl
+# Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (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 File::Spec;
+use MIME::Base64;
+use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_file data_file);
+
+my $test_name = "test_store";
+setup($test_name);
+
+my @noexist_files =
+    ( "test/blahdiblah.pem",
+      "test/blahdibleh.der" );
+my @src_files =
+    ( "test/testx509.pem",
+      "test/testrsa.pem",
+      "test/testrsapub.pem",
+      "test/testcrl.pem",
+      "apps/server.pem" );
+my @generated_files =
+    (
+     ### generated from the source files
+
+     "testx509.der",
+     "testrsa.der",
+     "testrsapub.der",
+     "testcrl.der",
+
+     ### generated locally
+
+     "rsa-key-pkcs1.pem", "rsa-key-pkcs1.der",
+     "rsa-key-pkcs1-aes128.pem",
+     "rsa-key-pkcs8.pem", "rsa-key-pkcs8.der",
+     "rsa-key-pkcs8-pbes1-sha1-3des.pem", "rsa-key-pkcs8-pbes1-sha1-3des.der",
+     "rsa-key-pkcs8-pbes2-sha1.pem", "rsa-key-pkcs8-pbes2-sha1.der",
+     "rsa-key-sha1-3des-sha1.p12", "rsa-key-sha1-3des-sha256.p12",
+     "rsa-key-aes256-cbc-sha256.p12",
+     "rsa-key-md5-des-sha1.p12",
+     "rsa-key-aes256-cbc-md5-des-sha256.p12",
+     "rsa-key-pkcs8-pbes2-sha256.pem", "rsa-key-pkcs8-pbes2-sha256.der",
+     "rsa-key-pkcs8-pbes1-md5-des.pem", "rsa-key-pkcs8-pbes1-md5-des.der",
+     "dsa-key-pkcs1.pem", "dsa-key-pkcs1.der",
+     "dsa-key-pkcs1-aes128.pem",
+     "dsa-key-pkcs8.pem", "dsa-key-pkcs8.der",
+     "dsa-key-pkcs8-pbes2-sha1.pem", "dsa-key-pkcs8-pbes2-sha1.der",
+     "dsa-key-aes256-cbc-sha256.p12",
+     "ec-key-pkcs1.pem", "ec-key-pkcs1.der",
+     "ec-key-pkcs1-aes128.pem",
+     "ec-key-pkcs8.pem", "ec-key-pkcs8.der",
+     "ec-key-pkcs8-pbes2-sha1.pem", "ec-key-pkcs8-pbes2-sha1.der",
+     "ec-key-aes256-cbc-sha256.p12",
+    );
+
+my $n = (2 * scalar @noexist_files)
+    + (5 * scalar @src_files)
+    + (3 * scalar @generated_files)
+    + 2;
+
+plan tests => $n;
+
+indir "store_$$" => sub {
+ SKIP:
+    {
+        skip "failed initialisation", $n unless init();
+
+        foreach (@noexist_files) {
+            my $file = srctop_file($_);
+            ok(!run(app(["openssl", "storeutl", $file])));
+            ok(!run(app(["openssl", "storeutl", to_file_uri($file)])));
+        }
+        foreach (@src_files) {
+            my $file = srctop_file($_);
+            ok(run(app(["openssl", "storeutl", $file])));
+            ok(run(app(["openssl", "storeutl", to_file_uri($file)])));
+            ok(run(app(["openssl", "storeutl", to_file_uri($file, 0,
+                                                           "")])));
+            ok(run(app(["openssl", "storeutl", to_file_uri($file, 0,
+                                                           "localhost")])));
+            ok(!run(app(["openssl", "storeutl", to_file_uri($file, 0,
+                                                            "dummy")])));
+        }
+        foreach (@generated_files) {
+            ok(run(app(["openssl", "storeutl", "-passin", "pass:password",
+                        $_])));
+            ok(run(app(["openssl", "storeutl", "-passin", "pass:password",
+                        to_file_uri($_)])));
+            ok(!run(app(["openssl", "storeutl", "-passin", "pass:password",
+                         to_rel_file_uri($_)])));
+        }
+        {
+            my $dir = srctop_dir("test", "certs");
+            ok(run(app(["openssl", "storeutl", $dir])));
+            ok(run(app(["openssl", "storeutl", to_file_uri($dir, 1)])));
+        }
+    }
+}, create => 1, cleanup => 1;
+
+sub init {
+    return (
+            # rsa-key-pkcs1.pem
+            run(app(["openssl", "genrsa",
+                     "-out", "rsa-key-pkcs1.pem", "2432"]))
+            # dsa-key-pkcs1.pem
+            && run(app(["openssl", "dsaparam", "-genkey",
+                        "-out", "dsa-key-pkcs1.pem", "1024"]))
+            # ec-key-pkcs1.pem (one might think that 'genec' would be practical)
+            && run(app(["openssl", "ecparam", "-genkey", "-name", "prime256v1",
+                        "-out", "ec-key-pkcs1.pem"]))
+            # rsa-key-pkcs1-aes128.pem
+            && run(app(["openssl", "rsa", "-passout", "pass:password", "-aes128",
+                        "-in", "rsa-key-pkcs1.pem",
+                        "-out", "rsa-key-pkcs1-aes128.pem"]))
+            # dsa-key-pkcs1-aes128.pem
+            && run(app(["openssl", "dsa", "-passout", "pass:password", "-aes128",
+                        "-in", "dsa-key-pkcs1.pem",
+                        "-out", "dsa-key-pkcs1-aes128.pem"]))
+            # ec-key-pkcs1-aes128.pem
+            && run(app(["openssl", "ec", "-passout", "pass:password", "-aes128",
+                        "-in", "ec-key-pkcs1.pem",
+                        "-out", "ec-key-pkcs1-aes128.pem"]))
+            # *-key-pkcs8.pem
+            && runall(sub {
+                          my $dstfile = shift;
+                          (my $srcfile = $dstfile)
+                              =~ s/-key-pkcs8\.pem$/-key-pkcs1.pem/i;
+                          run(app(["openssl", "pkcs8", "-topk8", "-nocrypt",
+                                   "-in", $srcfile, "-out", $dstfile]));
+                      }, grep(/-key-pkcs8\.pem$/, @generated_files))
+            # *-key-pkcs8-pbes1-sha1-3des.pem
+            && runall(sub {
+                          my $dstfile = shift;
+                          (my $srcfile = $dstfile)
+                              =~ s/-key-pkcs8-pbes1-sha1-3des\.pem$
+                                  /-key-pkcs8.pem/ix;
+                          run(app(["openssl", "pkcs8", "-topk8",
+                                   "-passout", "pass:password",
+                                   "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
+                                   "-in", $srcfile, "-out", $dstfile]));
+                      }, grep(/-key-pkcs8-pbes1-sha1-3des\.pem$/, @generated_files))
+            # *-key-pkcs8-pbes1-md5-des.pem
+            && runall(sub {
+                          my $dstfile = shift;
+                          (my $srcfile = $dstfile)
+                              =~ s/-key-pkcs8-pbes1-md5-des\.pem$
+                                  /-key-pkcs8.pem/ix;
+                          run(app(["openssl", "pkcs8", "-topk8",
+                                   "-passout", "pass:password",
+                                   "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
+                                   "-in", $srcfile, "-out", $dstfile]));
+                      }, grep(/-key-pkcs8-pbes1-md5-des\.pem$/, @generated_files))
+            # *-key-pkcs8-pbes2-sha1.pem
+            && runall(sub {
+                          my $dstfile = shift;
+                          (my $srcfile = $dstfile)
+                              =~ s/-key-pkcs8-pbes2-sha1\.pem$
+                                  /-key-pkcs8.pem/ix;
+                          run(app(["openssl", "pkcs8", "-topk8",
+                                   "-passout", "pass:password",
+                                   "-v2", "aes256", "-v2prf", "hmacWithSHA1",
+                                   "-in", $srcfile, "-out", $dstfile]));
+                      }, grep(/-key-pkcs8-pbes2-sha1\.pem$/, @generated_files))
+            # *-key-pkcs8-pbes2-sha1.pem
+            && runall(sub {
+                          my $dstfile = shift;
+                          (my $srcfile = $dstfile)
+                              =~ s/-key-pkcs8-pbes2-sha256\.pem$
+                                  /-key-pkcs8.pem/ix;
+                          run(app(["openssl", "pkcs8", "-topk8",
+                                   "-passout", "pass:password",
+                                   "-v2", "aes256", "-v2prf", "hmacWithSHA256",
+                                   "-in", $srcfile, "-out", $dstfile]));
+                      }, grep(/-key-pkcs8-pbes2-sha256\.pem$/, @generated_files))
+            # *-cert.pem (intermediary for the .p12 inits)
+            && run(app(["openssl", "req", "-x509",
+                        "-config", data_file("ca.cnf"), "-nodes",
+                        "-out", "cacert.pem", "-keyout", "cakey.pem"]))
+            && runall(sub {
+                          my $srckey = shift;
+                          (my $dstfile = $srckey) =~ s|-key-pkcs8\.|-cert.|;
+                          (my $csr = $dstfile) =~ s|\.pem|.csr|;
+
+                          (run(app(["openssl", "req", "-new",
+                                    "-config", data_file("user.cnf"),
+                                    "-key", $srckey, "-out", $csr]))
+                           &&
+                           run(app(["openssl", "x509", "-days", "3650",
+                                    "-CA", "cacert.pem",
+                                    "-CAkey", "cakey.pem",
+                                    "-set_serial", time(), "-req",
+                                    "-in", $csr, "-out", $dstfile])));
+                      }, grep(/-key-pkcs8\.pem$/, @generated_files))
+            # *.p12
+            && runall(sub {
+                          my $dstfile = shift;
+                          my ($type, $certpbe_index, $keypbe_index,
+                              $macalg_index) =
+                              $dstfile =~ m{^(.*)-key-(?|
+                                                # cert and key PBE are same
+                                                ()             #
+                                                ([^-]*-[^-]*)- # key & cert PBE
+                                                ([^-]*)        # MACalg
+                                            |
+                                                # cert and key PBE are not same
+                                                ([^-]*-[^-]*)- # cert PBE
+                                                ([^-]*-[^-]*)- # key PBE
+                                                ([^-]*)        # MACalg
+                                            )\.}x;
+                          if (!$certpbe_index) {
+                              $certpbe_index = $keypbe_index;
+                          }
+                          my $srckey = "$type-key-pkcs8.pem";
+                          my $srccert = "$type-cert.pem";
+                          my %pbes =
+                              (
+                               "sha1-3des" => "pbeWithSHA1And3-KeyTripleDES-CBC",
+                               "md5-des" => "pbeWithMD5AndDES-CBC",
+                               "aes256-cbc" => "AES-256-CBC",
+                              );
+                          my %macalgs =
+                              (
+                               "sha1" => "SHA1",
+                               "sha256" => "SHA256",
+                              );
+                          my $certpbe = $pbes{$certpbe_index};
+                          my $keypbe = $pbes{$keypbe_index};
+                          my $macalg = $macalgs{$macalg_index};
+                          if (!defined($certpbe) || !defined($keypbe)
+                              || !defined($macalg)) {
+                              print STDERR "Cert PBE for $pbe_index not defined\n"
+                                  unless defined $certpbe;
+                              print STDERR "Key PBE for $pbe_index not defined\n"
+                                  unless defined $keypbe;
+                              print STDERR "MACALG for $macalg_index not defined\n"
+                                  unless defined $macalg;
+                              print STDERR "(destination file was $dstfile)\n";
+                              return 0;
+                          }
+                          run(app(["openssl", "pkcs12", "-inkey", $srckey,
+                                   "-in", $srccert, "-passout", "pass:password",
+                                   "-export", "-macalg", $macalg,
+                                   "-certpbe", $certpbe, "-keypbe", $keypbe,
+                                   "-out", $dstfile]));
+                      }, grep(/\.p12/, @generated_files))
+            # *.der (the end all init)
+            && runall(sub {
+                          my $dstfile = shift;
+                          (my $srcfile = $dstfile) =~ s/\.der$/.pem/i;
+                          if (! -f $srcfile) {
+                              $srcfile = srctop_file("test", $srcfile);
+                          }
+                          my $infh;
+                          unless (open $infh, $srcfile) {
+                              return 0;
+                          }
+                          my $l;
+                          while (($l = <$infh>) !~ /^-----BEGIN\s/
+                                 || $l =~ /^-----BEGIN.*PARAMETERS-----/) {
+                          }
+                          my $b64 = "";
+                          while (($l = <$infh>) !~ /^-----END\s/) {
+                              $l =~ s|\R$||;
+                              $b64 .= $l unless $l =~ /:/;
+                          }
+                          close $infh;
+                          my $der = decode_base64($b64);
+                          unless (length($b64) / 4 * 3 - length($der) < 3) {
+                              print STDERR "Length error, ",length($b64),
+                                  " bytes of base64 became ",length($der),
+                                  " bytes of der? ($srcfile => $dstfile)\n";
+                              return 0;
+                          }
+                          my $outfh;
+                          unless (open $outfh, ">:raw", $dstfile) {
+                              return 0;
+                          }
+                          print $outfh $der;
+                          close $outfh;
+                          return 1;
+                      }, grep(/\.der$/, @generated_files))
+           );
+}
+
+sub runall {
+    my ($function, @items) = @_;
+
+    foreach (@items) {
+        return 0 unless $function->($_);
+    }
+    return 1;
+}
+
+# According to RFC8089, a relative file: path is invalid.  We still produce
+# them for testing purposes.
+sub to_rel_file_uri {
+    my ($file, $isdir, $authority) = @_;
+    my $vol;
+    my $dir;
+
+    die "to_rel_file_uri: No file given\n" if !defined($file) || $file eq '';
+
+    ($vol, $dir, $file) = File::Spec->splitpath($file, $isdir // 0);
+
+    # Make sure we have a Unix style directory.
+    $dir = join('/', File::Spec->splitdir($dir));
+    # Canonicalise it (note: it seems to be only needed on Unix)
+    while (1) {
+        my $newdir = $dir;
+        $newdir =~ s|/[^/]*[^/\.]+[^/]*/\.\./|/|g;
+        last if $newdir eq $dir;
+        $dir = $newdir;
+    }
+    # Take care of the corner cases the loop can't handle, and that $dir
+    # ends with a / unless it's empty
+    $dir =~ s|/[^/]*[^/\.]+[^/]*/\.\.$|/|;
+    $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\./|/|;
+    $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\.$||;
+    if ($isdir // 0) {
+        $dir =~ s|/$|| if $dir ne '/';
+    } else {
+        $dir .= '/' if $dir ne '' && $dir !~ m|/$|;
+    }
+
+    # If the file system has separate volumes (at present, Windows and VMS)
+    # we need to handle them.  In URIs, they are invariably the first
+    # component of the path, which is always absolute.
+    # On VMS, user:[foo.bar] translates to /user/foo/bar
+    # On Windows, c:\Users\Foo translates to /c:/Users/Foo
+    if ($vol ne '') {
+        $vol =~ s|:||g if ($^O eq "VMS");
+        $dir = '/' . $dir if $dir ne '' && $dir !~ m|^/|;
+        $dir = '/' . $vol . $dir;
+    }
+    $file = $dir . $file;
+
+    return "file://$authority$file" if defined $authority;
+    return "file:$file";
+}
+
+sub to_file_uri {
+    my ($file, $isdir, $authority) = @_;
+
+    die "to_file_uri: No file given\n" if !defined($file) || $file eq '';
+    return to_rel_file_uri(File::Spec->rel2abs($file), $isdir, $authority);
+}
diff --git a/test/recipes/90-test_store_data/ca.cnf b/test/recipes/90-test_store_data/ca.cnf
new file mode 100644
index 0000000..bda6eec
--- /dev/null
+++ b/test/recipes/90-test_store_data/ca.cnf
@@ -0,0 +1,56 @@
+####################################################################
+[ req ]
+default_bits		= 2432
+default_keyfile 	= cakey.pem
+default_md	        = sha256
+distinguished_name	= req_DN
+string_mask             = utf8only
+x509_extensions         = v3_selfsign
+
+[ req_DN ]
+commonName                      = "Common Name"
+commonName_value              = "CA"
+
+[ v3_selfsign ]
+basicConstraints = critical,CA:true
+keyUsage = keyCertSign
+subjectKeyIdentifier=hash
+
+####################################################################
+[ ca ]
+default_ca      = CA_default            # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir             = ./demoCA
+certificate	= ./demoCA/cacert.pem
+serial		= ./demoCA/serial
+private_key	= ./demoCA/private/cakey.pem
+new_certs_dir   = ./demoCA/newcerts
+
+certificate     = cacert.pem
+private_key     = cakey.pem
+
+x509_extensions = v3_user
+
+name_opt        = ca_default            # Subject Name options
+cert_opt        = ca_default            # Certificate field options
+
+policy          = policy_anything
+
+[ policy_anything ]
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ v3_user ]
+basicConstraints=critical,CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+issuerAltName=issuer:copy
+
diff --git a/test/recipes/90-test_store_data/user.cnf b/test/recipes/90-test_store_data/user.cnf
new file mode 100644
index 0000000..91f7969
--- /dev/null
+++ b/test/recipes/90-test_store_data/user.cnf
@@ -0,0 +1,19 @@
+####################################################################
+[ req ]
+default_bits            = 2432
+default_md	        = sha256
+distinguished_name	= req_DN
+string_mask = utf8only
+
+req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_DN ]
+commonName                      = "Common Name"
+commonName_value              = "A user"
+userId = "User ID"
+userId_value = "test"
+
+[ v3_req ]
+extendedKeyUsage = clientAuth
+subjectKeyIdentifier = hash
+basicConstraints = CA:false
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 523a281..d734461 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4300,3 +4300,45 @@ ERR_load_strings_const                  4242	1_1_1	EXIST::FUNCTION:
 ASN1_TIME_to_tm                         4243	1_1_1	EXIST::FUNCTION:
 ASN1_TIME_set_string_X509               4244	1_1_1	EXIST::FUNCTION:
 OCSP_resp_get1_id                       4245	1_1_1	EXIST::FUNCTION:OCSP
+OSSL_STORE_register_loader              4246	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_set_error             4247	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get0_PKEY               4248	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get_type                4249	1_1_1	EXIST::FUNCTION:
+ERR_load_OSSL_STORE_strings             4250	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_free                  4251	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get1_PKEY               4252	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_free                    4253	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_open_file                    4254	1_1_1	NOEXIST::FUNCTION:
+OSSL_STORE_LOADER_set_eof               4255	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_new                   4256	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get0_CERT               4257	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_set_close             4258	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_new_PARAMS              4259	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_new_PKEY                4260	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get1_PARAMS             4261	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get1_CRL                4262	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_error                        4263	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get1_CERT               4264	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get0_PARAMS             4265	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_type_string             4266	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get1_NAME               4267	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_set_load              4268	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_get0_scheme           4269	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_open                         4270	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_close                        4271	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_new_CERT                4272	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get0_CRL                4273	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_load                         4274	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get0_NAME               4275	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_unregister_loader            4276	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_new_CRL                 4277	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_new_NAME                4278	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_eof                          4279	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_set_open              4280	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_set_ctrl              4281	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_ctrl                         4282	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get0_NAME_description   4283	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_set0_NAME_description   4284	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_INFO_get1_NAME_description   4285	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_do_all_loaders               4286	1_1_1	EXIST::FUNCTION:
+OSSL_STORE_LOADER_get0_engine           4287	1_1_1	EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index 2ad754f..203b531 100644
--- a/util/private.num
+++ b/util/private.num
@@ -20,6 +20,17 @@ CRYPTO_EX_new                           datatype
 EVP_PKEY_gen_cb                         datatype
 GEN_SESSION_CB                          datatype
 OPENSSL_Applink                         external
+OSSL_STORE_CTX                          datatype
+OSSL_STORE_INFO                         datatype
+OSSL_STORE_LOADER                       datatype
+OSSL_STORE_LOADER_CTX                   datatype
+OSSL_STORE_close_fn                     datatype
+OSSL_STORE_ctrl_fn                      datatype
+OSSL_STORE_eof_fn                       datatype
+OSSL_STORE_error_fn                     datatype
+OSSL_STORE_load_fn                      datatype
+OSSL_STORE_open_fn                      datatype
+OSSL_STORE_post_process_info_fn         datatype
 SSL_CTX_keylog_cb_func                  datatype
 SSL_early_cb_fn                         datatype
 SSL_psk_client_cb_func                  datatype


More information about the openssl-commits mailing list