[openssl] master update

Richard Levitte levitte at openssl.org
Wed May 13 16:52:50 UTC 2020


The branch master has been updated
       via  f55838f34dd5c65420662f7eacf6c6ffd7f261a2 (commit)
       via  bac4bffbfbfaf2d16d248e8bc32023d1d2d48d10 (commit)
       via  6ab6ecfd6d2d659326f427dceb1b65ae1b4b012b (commit)
      from  78906fff4a6cfd5857045df770b47ae9ebcf0766 (commit)


- Log -----------------------------------------------------------------
commit f55838f34dd5c65420662f7eacf6c6ffd7f261a2
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Oct 12 16:56:44 2018 +0200

    OSSL_STORE: Make the 'file' scheme loader handle MSBLOB and PVK files
    
    This involves exposing two pvkfmt.c functions, but only internally.
    
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11756)

commit bac4bffbfbfaf2d16d248e8bc32023d1d2d48d10
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Oct 12 16:52:15 2018 +0200

    OSSL_STORE: Better information when prompting for pass phrases
    
    The prompt includes the URI, to make it clear which object needs a
    pass phrase.
    
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11756)

commit 6ab6ecfd6d2d659326f427dceb1b65ae1b4b012b
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Oct 12 16:46:41 2018 +0200

    OSSL_STORE: Make it possible to attach an OSSL_STORE to an opened BIO
    
    This capability existed internally, and is now made public.
    
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/11756)

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

Summary of changes:
 crypto/err/openssl.txt            |   9 +-
 crypto/include/internal/pem_int.h |  23 +++
 crypto/pem/pem_pkey.c             |  19 ++-
 crypto/pem/pvkfmt.c               |  39 ++---
 crypto/store/loader_file.c        | 296 ++++++++++++++++++++++++++------------
 crypto/store/store_err.c          |   2 +-
 crypto/store/store_lib.c          |  44 ++----
 crypto/store/store_local.h        |  11 +-
 crypto/store/store_register.c     |   7 +
 doc/man3/OSSL_STORE_LOADER.pod    |  29 +++-
 doc/man3/OSSL_STORE_attach.pod    |  45 ++++++
 include/openssl/store.h           |  28 ++++
 include/openssl/storeerr.h        |   8 +-
 util/libcrypto.num                |   2 +
 util/other.syms                   |   1 +
 15 files changed, 389 insertions(+), 174 deletions(-)
 create mode 100644 crypto/include/internal/pem_int.h
 create mode 100644 doc/man3/OSSL_STORE_attach.pod

diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 133a935b0f..9fa051f5c3 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -948,6 +948,7 @@ OCSP_F_OCSP_MATCH_ISSUERID:109:ocsp_match_issuerid
 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
+OSSL_STORE_F_FILE_ATTACH:128:
 OSSL_STORE_F_FILE_CTRL:129:file_ctrl
 OSSL_STORE_F_FILE_FIND:138:file_find
 OSSL_STORE_F_FILE_GET_PASS:118:file_get_pass
@@ -955,10 +956,8 @@ 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_ATTACH_PEM_BIO:127:ossl_store_attach_pem_bio
+OSSL_STORE_F_OSSL_STORE_ATTACH:127:
 OSSL_STORE_F_OSSL_STORE_EXPECT:130:OSSL_STORE_expect
-OSSL_STORE_F_OSSL_STORE_FILE_ATTACH_PEM_BIO_INT:128:\
-	ossl_store_file_attach_pem_bio_int
 OSSL_STORE_F_OSSL_STORE_FIND:131:OSSL_STORE_find
 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
@@ -1001,12 +1000,12 @@ PEM_F_D2I_PKCS8PRIVATEKEY_BIO:120:d2i_PKCS8PrivateKey_bio
 PEM_F_D2I_PKCS8PRIVATEKEY_FP:121:d2i_PKCS8PrivateKey_fp
 PEM_F_DO_B2I:132:do_b2i
 PEM_F_DO_B2I_BIO:133:do_b2i_bio
-PEM_F_DO_BLOB_HEADER:134:do_blob_header
+PEM_F_OSSL_DO_BLOB_HEADER:134:ossl_do_blob_header
 PEM_F_DO_I2B:146:do_i2b
 PEM_F_DO_PK8PKEY:126:do_pk8pkey
 PEM_F_DO_PK8PKEY_FP:125:do_pk8pkey_fp
 PEM_F_DO_PVK_BODY:135:do_PVK_body
-PEM_F_DO_PVK_HEADER:136:do_PVK_header
+PEM_F_OSSL_DO_PVK_HEADER:136:ossl_do_PVK_header
 PEM_F_GET_HEADER_AND_DATA:143:get_header_and_data
 PEM_F_GET_NAME:144:get_name
 PEM_F_I2B_PVK:137:i2b_PVK
diff --git a/crypto/include/internal/pem_int.h b/crypto/include/internal/pem_int.h
new file mode 100644
index 0000000000..e065ac75a5
--- /dev/null
+++ b/crypto/include/internal/pem_int.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018 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_PEM_INT_H
+# define HEADER_PEM_INT_H
+
+# include <openssl/pem.h>
+
+/* Found in crypto/pem/pvkfmt.c */
+int ossl_do_blob_header(const unsigned char **in, unsigned int length,
+                        unsigned int *pmagic, unsigned int *pbitlen,
+                        int *pisdss, int *pispub);
+int ossl_do_PVK_header(const unsigned char **in, unsigned int length,
+                       int skip_magic,
+                       unsigned int *psaltlen, unsigned int *pkeylen);
+
+#endif
diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c
index a1e8403e2b..ee9b6764a6 100644
--- a/crypto/pem/pem_pkey.c
+++ b/crypto/pem/pem_pkey.c
@@ -39,8 +39,8 @@ EVP_PKEY *PEM_read_bio_PrivateKey_ex(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
     if ((ui_method = UI_UTIL_wrap_read_pem_callback(cb, 0)) == NULL)
         return NULL;
 
-    if ((ctx = ossl_store_attach_pem_bio(bp, ui_method, u, libctx,
-                                         propq)) == NULL)
+    if ((ctx = OSSL_STORE_attach(bp, libctx, "file", propq, ui_method, u,
+                                 NULL, NULL)) == NULL)
         goto err;
 #ifndef OPENSSL_NO_SECURE_HEAP
     {
@@ -56,13 +56,14 @@ EVP_PKEY *PEM_read_bio_PrivateKey_ex(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
             break;
         }
         OSSL_STORE_INFO_free(info);
+        info = NULL;
     }
 
     if (ret != NULL && x != NULL)
         *x = ret;
 
  err:
-    ossl_store_detach_pem_bio(ctx);
+    OSSL_STORE_close(ctx);
     UI_destroy_method(ui_method);
     OSSL_STORE_INFO_free(info);
     return ret;
@@ -105,7 +106,8 @@ EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x)
     OSSL_STORE_CTX *ctx = NULL;
     OSSL_STORE_INFO *info = NULL;
 
-    if ((ctx = ossl_store_attach_pem_bio(bp, UI_null(), NULL, NULL, NULL)) == NULL)
+    if ((ctx = OSSL_STORE_attach(bp, NULL, "file", NULL, UI_null(), NULL,
+                                 NULL, NULL)) == NULL)
         goto err;
 
     while (!OSSL_STORE_eof(ctx) && (info = OSSL_STORE_load(ctx)) != NULL) {
@@ -114,13 +116,14 @@ EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x)
             break;
         }
         OSSL_STORE_INFO_free(info);
+        info = NULL;
     }
 
     if (ret != NULL && x != NULL)
         *x = ret;
 
  err:
-    ossl_store_detach_pem_bio(ctx);
+    OSSL_STORE_close(ctx);
     OSSL_STORE_INFO_free(info);
     return ret;
 }
@@ -198,7 +201,8 @@ DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u)
     if ((ui_method = UI_UTIL_wrap_read_pem_callback(cb, 0)) == NULL)
         return NULL;
 
-    if ((ctx = ossl_store_attach_pem_bio(bp, ui_method, u, NULL, NULL)) == NULL)
+    if ((ctx = OSSL_STORE_attach(bp, NULL, "file", NULL, ui_method, u,
+                                 NULL, NULL)) == NULL)
         goto err;
 
     while (!OSSL_STORE_eof(ctx) && (info = OSSL_STORE_load(ctx)) != NULL) {
@@ -211,13 +215,14 @@ DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u)
             }
         }
         OSSL_STORE_INFO_free(info);
+        info = NULL;
     }
 
     if (ret != NULL && x != NULL)
         *x = ret;
 
  err:
-    ossl_store_detach_pem_bio(ctx);
+    OSSL_STORE_close(ctx);
     UI_destroy_method(ui_method);
     OSSL_STORE_INFO_free(info);
     return ret;
diff --git a/crypto/pem/pvkfmt.c b/crypto/pem/pvkfmt.c
index 1a24ce755a..e2f5702880 100644
--- a/crypto/pem/pvkfmt.c
+++ b/crypto/pem/pvkfmt.c
@@ -20,6 +20,7 @@
 
 #include "internal/cryptlib.h"
 #include <openssl/pem.h>
+#include "internal/pem_int.h"
 #include <openssl/rand.h>
 #include <openssl/bn.h>
 #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA)
@@ -89,9 +90,9 @@ static EVP_PKEY *b2i_rsa(const unsigned char **in,
 static EVP_PKEY *b2i_dss(const unsigned char **in,
                          unsigned int bitlen, int ispub);
 
-static int do_blob_header(const unsigned char **in, unsigned int length,
-                          unsigned int *pmagic, unsigned int *pbitlen,
-                          int *pisdss, int *pispub)
+int ossl_do_blob_header(const unsigned char **in, unsigned int length,
+                        unsigned int *pmagic, unsigned int *pbitlen,
+                        int *pisdss, int *pispub)
 {
     const unsigned char *p = *in;
     if (length < 16)
@@ -99,13 +100,13 @@ static int do_blob_header(const unsigned char **in, unsigned int length,
     /* bType */
     if (*p == MS_PUBLICKEYBLOB) {
         if (*pispub == 0) {
-            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
+            PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
             return 0;
         }
         *pispub = 1;
     } else if (*p == MS_PRIVATEKEYBLOB) {
         if (*pispub == 1) {
-            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
+            PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
             return 0;
         }
         *pispub = 0;
@@ -114,7 +115,7 @@ static int do_blob_header(const unsigned char **in, unsigned int length,
     p++;
     /* Version */
     if (*p++ != 0x2) {
-        PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_VERSION_NUMBER);
+        PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_BAD_VERSION_NUMBER);
         return 0;
     }
     /* Ignore reserved, aiKeyAlg */
@@ -129,7 +130,7 @@ static int do_blob_header(const unsigned char **in, unsigned int length,
         /* fall thru */
     case MS_RSA1MAGIC:
         if (*pispub == 0) {
-            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
+            PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
             return 0;
         }
         break;
@@ -139,13 +140,13 @@ static int do_blob_header(const unsigned char **in, unsigned int length,
         /* fall thru */
     case MS_RSA2MAGIC:
         if (*pispub == 1) {
-            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
+            PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
             return 0;
         }
         break;
 
     default:
-        PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_MAGIC_NUMBER);
+        PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_BAD_MAGIC_NUMBER);
         return -1;
     }
     *in = p;
@@ -191,7 +192,7 @@ static EVP_PKEY *do_b2i(const unsigned char **in, unsigned int length,
     const unsigned char *p = *in;
     unsigned int bitlen, magic;
     int isdss;
-    if (do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) {
+    if (ossl_do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) {
         PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_HEADER_PARSE_ERROR);
         return NULL;
     }
@@ -218,7 +219,7 @@ static EVP_PKEY *do_b2i_bio(BIO *in, int ispub)
         return NULL;
     }
     p = hdr_buf;
-    if (do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0)
+    if (ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0)
         return NULL;
 
     length = blob_length(bitlen, isdss, ispub);
@@ -617,26 +618,26 @@ int i2b_PublicKey_bio(BIO *out, const EVP_PKEY *pk)
 
 # ifndef OPENSSL_NO_RC4
 
-static int do_PVK_header(const unsigned char **in, unsigned int length,
-                         int skip_magic,
-                         unsigned int *psaltlen, unsigned int *pkeylen)
+int ossl_do_PVK_header(const unsigned char **in, unsigned int length,
+                       int skip_magic,
+                       unsigned int *psaltlen, unsigned int *pkeylen)
 {
     const unsigned char *p = *in;
     unsigned int pvk_magic, is_encrypted;
 
     if (skip_magic) {
         if (length < 20) {
-            PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
+            PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
             return 0;
         }
     } else {
         if (length < 24) {
-            PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
+            PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
             return 0;
         }
         pvk_magic = read_ledword(&p);
         if (pvk_magic != MS_PVKMAGIC) {
-            PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER);
+            PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER);
             return 0;
         }
     }
@@ -653,7 +654,7 @@ static int do_PVK_header(const unsigned char **in, unsigned int length,
         return 0;
 
     if (is_encrypted && *psaltlen == 0) {
-        PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_INCONSISTENT_HEADER);
+        PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_INCONSISTENT_HEADER);
         return 0;
     }
 
@@ -766,7 +767,7 @@ EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u)
     }
     p = pvk_hdr;
 
-    if (!do_PVK_header(&p, 24, 0, &saltlen, &keylen))
+    if (!ossl_do_PVK_header(&p, 24, 0, &saltlen, &keylen))
         return 0;
     buflen = (int)keylen + saltlen;
     buf = OPENSSL_malloc(buflen);
diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c
index 02178b29a8..9f6158ff79 100644
--- a/crypto/store/loader_file.c
+++ b/crypto/store/loader_file.c
@@ -18,6 +18,7 @@
 #include <openssl/err.h>
 #include <openssl/evp.h>
 #include <openssl/pem.h>
+#include "internal/pem_int.h"
 #include <openssl/pkcs12.h>      /* For the PKCS8 stuff o.O */
 #include <openssl/rsa.h>         /* For d2i_RSAPrivateKey */
 #include <openssl/safestack.h>
@@ -48,7 +49,8 @@ DEFINE_STACK_OF(X509)
  */
 
 static char *file_get_pass(const UI_METHOD *ui_method, char *pass,
-                           size_t maxsize, const char *prompt_info, void *data)
+                           size_t maxsize, const char *desc, const char *info,
+                           void *data)
 {
     UI *ui = UI_new();
     char *prompt = NULL;
@@ -62,8 +64,7 @@ static char *file_get_pass(const UI_METHOD *ui_method, char *pass,
         UI_set_method(ui, ui_method);
     UI_add_user_data(ui, data);
 
-    if ((prompt = UI_construct_prompt(ui, "pass phrase",
-                                      prompt_info)) == NULL) {
+    if ((prompt = UI_construct_prompt(ui, desc, 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,
@@ -94,18 +95,20 @@ static char *file_get_pass(const UI_METHOD *ui_method, char *pass,
 struct pem_pass_data {
     const UI_METHOD *ui_method;
     void *data;
+    const char *prompt_desc;
     const char *prompt_info;
 };
 
 static int file_fill_pem_pass_data(struct pem_pass_data *pass_data,
-                                   const char *prompt_info,
+                                   const char *desc, const char *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;
+    pass_data->prompt_desc = desc;
+    pass_data->prompt_info = info;
     return 1;
 }
 
@@ -114,7 +117,8 @@ 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);
+                               pass_data->prompt_desc, pass_data->prompt_info,
+                               pass_data->data);
 
     return pass == NULL ? 0 : strlen(pass);
 }
@@ -168,7 +172,7 @@ typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name,
                                                size_t len, void **handler_ctx,
                                                int *matchcount,
                                                const UI_METHOD *ui_method,
-                                               void *ui_data,
+                                               void *ui_data, const char *uri,
                                                OPENSSL_CTX *libctx,
                                                const char *propq);
 /*
@@ -205,7 +209,8 @@ static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,
                                           size_t len, void **pctx,
                                           int *matchcount,
                                           const UI_METHOD *ui_method,
-                                          void *ui_data, OPENSSL_CTX *libctx,
+                                          void *ui_data, const char *uri,
+                                          OPENSSL_CTX *libctx,
                                           const char *propq)
 {
     OSSL_STORE_INFO *store_info = NULL;
@@ -234,7 +239,7 @@ static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,
                 pass = "";
             } else {
                 if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE,
-                                          "PKCS12 import password",
+                                          "PKCS12 import pass phrase", uri,
                                           ui_data)) == NULL) {
                     OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS12,
                                   OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR);
@@ -335,6 +340,7 @@ static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name,
                                                   int *matchcount,
                                                   const UI_METHOD *ui_method,
                                                   void *ui_data,
+                                                  const char *uri,
                                                   OPENSSL_CTX *libctx,
                                                   const char *propq)
 {
@@ -366,7 +372,8 @@ static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name,
     }
 
     if ((pass = file_get_pass(ui_method, kbuf, PEM_BUFSIZE,
-                              "PKCS8 decrypt password", ui_data)) == NULL) {
+                              "PKCS8 decrypt pass phrase", uri,
+                              ui_data)) == NULL) {
         OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED,
                       OSSL_STORE_R_BAD_PASSWORD_READ);
         goto nop8;
@@ -412,7 +419,8 @@ static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name,
                                               size_t len, void **pctx,
                                               int *matchcount,
                                               const UI_METHOD *ui_method,
-                                              void *ui_data, OPENSSL_CTX *libctx,
+                                              void *ui_data, const char *uri,
+                                              OPENSSL_CTX *libctx,
                                               const char *propq)
 {
     OSSL_STORE_INFO *store_info = NULL;
@@ -491,7 +499,8 @@ static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name,
                                           size_t len, void **pctx,
                                           int *matchcount,
                                           const UI_METHOD *ui_method,
-                                          void *ui_data, OPENSSL_CTX *libctx,
+                                          void *ui_data, const char *uri,
+                                          OPENSSL_CTX *libctx,
                                           const char *propq)
 {
     OSSL_STORE_INFO *store_info = NULL;
@@ -526,7 +535,8 @@ static OSSL_STORE_INFO *try_decode_params(const char *pem_name,
                                           size_t len, void **pctx,
                                           int *matchcount,
                                           const UI_METHOD *ui_method,
-                                          void *ui_data, OPENSSL_CTX *libctx,
+                                          void *ui_data, const char *uri,
+                                          OPENSSL_CTX *libctx,
                                           const char *propq)
 {
     OSSL_STORE_INFO *store_info = NULL;
@@ -611,6 +621,7 @@ static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name,
                                                    int *matchcount,
                                                    const UI_METHOD *ui_method,
                                                    void *ui_data,
+                                                   const char *uri,
                                                    OPENSSL_CTX *libctx,
                                                    const char *propq)
 {
@@ -662,7 +673,8 @@ static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name,
                                            size_t len, void **pctx,
                                            int *matchcount,
                                            const UI_METHOD *ui_method,
-                                           void *ui_data, OPENSSL_CTX *libctx,
+                                           void *ui_data, const char *uri,
+                                           OPENSSL_CTX *libctx,
                                            const char *propq)
 {
     OSSL_STORE_INFO *store_info = NULL;
@@ -711,6 +723,7 @@ static const FILE_HANDLER *file_handlers[] = {
  */
 
 struct ossl_store_loader_ctx_st {
+    char *uri;                   /* The URI we currently try to load */
     enum {
         is_raw = 0,
         is_pem,
@@ -718,6 +731,7 @@ struct ossl_store_loader_ctx_st {
     } type;
     int errcnt;
 #define FILE_FLAG_SECMEM         (1<<0)
+#define FILE_FLAG_ATTACHED       (1<<1)
     unsigned int flags;
     union {
         struct {                 /* Used with is_raw and is_pem */
@@ -733,7 +747,6 @@ struct ossl_store_loader_ctx_st {
         struct {                 /* Used with is_dir */
             OPENSSL_DIR_CTX *ctx;
             int end_reached;
-            char *uri;
 
             /*
              * When a search expression is given, these are filled in.
@@ -761,9 +774,11 @@ struct ossl_store_loader_ctx_st {
 
 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 == NULL)
+        return;
+
+    OPENSSL_free(ctx->uri);
+    if (ctx->type != is_dir) {
         if (ctx->_.file.last_handler != NULL) {
             ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);
             ctx->_.file.last_handler_ctx = NULL;
@@ -774,6 +789,23 @@ static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)
     OPENSSL_free(ctx);
 }
 
+static int file_find_type(OSSL_STORE_LOADER_CTX *ctx)
+{
+    BIO *buff = NULL;
+    char peekbuf[4096] = { 0, };
+
+    if ((buff = BIO_new(BIO_f_buffer())) == NULL)
+        return 0;
+
+    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 1;
+}
+
 static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
                                         const char *uri,
                                         const UI_METHOD *ui_method,
@@ -865,19 +897,14 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
         OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
+    ctx->uri = OPENSSL_strdup(uri);
+    if (ctx->uri == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
 
     if (S_ISDIR(st.st_mode)) {
-        /*
-         * 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) {
@@ -891,22 +918,10 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
             }
             ctx->_.dir.end_reached = 1;
         }
-    } else {
-        BIO *buff = NULL;
-        char peekbuf[4096] = { 0, };
-
-        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;
-        }
+    } else if ((ctx->_.file.file = BIO_new_file(path, "rb")) == NULL
+               || !file_find_type(ctx)) {
+        BIO_free_all(ctx->_.file.file);
+        goto err;
     }
 
     return ctx;
@@ -915,6 +930,34 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
     return NULL;
 }
 
+static OSSL_STORE_LOADER_CTX *file_attach(const OSSL_STORE_LOADER *loader,
+                                          BIO *bp, OPENSSL_CTX *libctx,
+                                          const char *propq,
+                                          const UI_METHOD *ui_method,
+                                          void *ui_data)
+{
+    OSSL_STORE_LOADER_CTX *ctx;
+
+    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL
+        || (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)) {
+        OSSL_STOREerr(OSSL_STORE_F_FILE_ATTACH, ERR_R_MALLOC_FAILURE);
+        OSSL_STORE_LOADER_CTX_free(ctx);
+        return NULL;
+    }
+
+    ctx->libctx = libctx;
+    ctx->flags |= FILE_FLAG_ATTACHED;
+    ctx->_.file.file = bp;
+    if (!file_find_type(ctx)) {
+        /* Safety measure */
+        ctx->_.file.file = NULL;
+        OSSL_STORE_LOADER_CTX_free(ctx);
+        ctx = NULL;
+    }
+
+    return ctx;
+}
+
 static int file_ctrl(OSSL_STORE_LOADER_CTX *ctx, int cmd, va_list args)
 {
     int ret = 1;
@@ -984,36 +1027,6 @@ static int file_find(OSSL_STORE_LOADER_CTX *ctx,
     return 0;
 }
 
-/* Internal function to decode an already opened PEM file */
-OSSL_STORE_LOADER_CTX *ossl_store_file_attach_pem_bio_int(BIO *bp,
-                                                          OPENSSL_CTX *libctx,
-                                                          const char *propq)
-{
-    OSSL_STORE_LOADER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
-
-    if (ctx == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_FILE_ATTACH_PEM_BIO_INT,
-                      ERR_R_MALLOC_FAILURE);
-        return NULL;
-    }
-
-    ctx->_.file.file = bp;
-    ctx->type = is_pem;
-
-    ctx->libctx = libctx;
-    if (propq != NULL) {
-        ctx->propq = OPENSSL_strdup(propq);
-        if (ctx->propq == NULL) {
-            OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_FILE_ATTACH_PEM_BIO_INT,
-                          ERR_R_MALLOC_FAILURE);
-            OPENSSL_free(ctx);
-            return NULL;
-        }
-    }
-
-    return ctx;
-}
-
 static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,
                                              const char *pem_name,
                                              const char *pem_header,
@@ -1048,7 +1061,8 @@ static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,
             OSSL_STORE_INFO *tmp_result =
                 handler->try_decode(pem_name, pem_header, data, len,
                                     &tmp_handler_ctx, &try_matchcount,
-                                    ui_method, ui_data, ctx->libctx, ctx->propq);
+                                    ui_method, ui_data, ctx->uri,
+                                    ctx->libctx, ctx->propq);
 
             if (try_matchcount > 0) {
 
@@ -1115,7 +1129,7 @@ static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx,
             ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0,
                                                  &ctx->_.file.last_handler_ctx,
                                                  &try_matchcount,
-                                                 ui_method, ui_data,
+                                                 ui_method, ui_data, ctx->uri,
                                                  ctx->libctx, ctx->propq);
 
         if (result == NULL) {
@@ -1136,8 +1150,8 @@ static void pem_free_flag(void *pem_data, int secure, size_t num)
 }
 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 secure)
+                         const UI_METHOD *ui_method, void *ui_data,
+                         const char *uri, int secure)
 {
     int i = secure
         ? PEM_read_bio_ex(bp, pem_name, pem_header, data, len,
@@ -1158,7 +1172,8 @@ static int file_read_pem(BIO *bp, char **pem_name, char **pem_header,
         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)
+            || !file_fill_pem_pass_data(&pass_data, "PEM pass phrase", uri,
+                                        ui_method, ui_data)
             || !PEM_do_header(&cipher, *data, len, file_get_pem_pass,
                               &pass_data)) {
             return 0;
@@ -1167,6 +1182,84 @@ static int file_read_pem(BIO *bp, char **pem_name, char **pem_header,
     return 1;
 }
 
+static OSSL_STORE_INFO *file_try_read_msblob(BIO *bp, int *matchcount)
+{
+#ifdef OPENSSL_NO_DSA
+    return NULL;
+#else
+    OSSL_STORE_INFO *result = NULL;
+    int ispub = -1;
+
+    {
+        unsigned int magic = 0, bitlen = 0;
+        int isdss = 0;
+        unsigned char peekbuf[16] = { 0, };
+        const unsigned char *p = peekbuf;
+
+        if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0)
+            return 0;
+        if (!ossl_do_blob_header(&p, sizeof(peekbuf), &magic, &bitlen,
+                                 &isdss, &ispub))
+            return 0;
+    }
+
+    (*matchcount)++;
+
+    {
+        EVP_PKEY *tmp = ispub
+            ? b2i_PublicKey_bio(bp)
+            : b2i_PrivateKey_bio(bp);
+
+        if (tmp == NULL
+            || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) {
+            EVP_PKEY_free(tmp);
+            return 0;
+        }
+    }
+
+    return result;
+#endif
+}
+
+static OSSL_STORE_INFO *file_try_read_PVK(BIO *bp, const UI_METHOD *ui_method,
+                                          void *ui_data, const char *uri,
+                                          int *matchcount)
+{
+#if defined(OPENSSL_NO_DSA) || defined(OPENSSL_NO_RC4)
+    return NULL;
+#else
+    OSSL_STORE_INFO *result = NULL;
+
+    {
+        unsigned int saltlen = 0, keylen = 0;
+        unsigned char peekbuf[24] = { 0, };
+        const unsigned char *p = peekbuf;
+
+        if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0)
+            return 0;
+        if (!ossl_do_PVK_header(&p, sizeof(peekbuf), 0, &saltlen, &keylen))
+            return 0;
+    }
+
+    (*matchcount)++;
+
+    {
+        EVP_PKEY *tmp = NULL;
+        struct pem_pass_data pass_data;
+
+        if (!file_fill_pem_pass_data(&pass_data, "PVK pass phrase", uri,
+                                     ui_method, ui_data)
+            || (tmp = b2i_PVK_bio(bp, file_get_pem_pass, &pass_data)) == NULL
+            || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) {
+            EVP_PKEY_free(tmp);
+            return 0;
+        }
+    }
+
+    return result;
+#endif
+}
+
 static int file_read_asn1(BIO *bp, unsigned char **data, long *len)
 {
     BUF_MEM *mem = NULL;
@@ -1201,8 +1294,8 @@ static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name,
     assert(name != NULL);
     assert(data != NULL);
     {
-        const char *pathsep = ends_with_dirsep(ctx->_.dir.uri) ? "" : "/";
-        long calculated_length = strlen(ctx->_.dir.uri) + strlen(pathsep)
+        const char *pathsep = ends_with_dirsep(ctx->uri) ? "" : "/";
+        long calculated_length = strlen(ctx->uri) + strlen(pathsep)
             + strlen(name) + 1 /* \0 */;
 
         *data = OPENSSL_zalloc(calculated_length);
@@ -1211,7 +1304,7 @@ static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name,
             return 0;
         }
 
-        OPENSSL_strlcat(*data, ctx->_.dir.uri, calculated_length);
+        OPENSSL_strlcat(*data, ctx->uri, calculated_length);
         OPENSSL_strlcat(*data, pathsep, calculated_length);
         OPENSSL_strlcat(*data, name, calculated_length);
     }
@@ -1318,8 +1411,7 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
              * 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_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri);
             ctx->_.dir.last_errno = errno;
             if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0)
                 ctx->_.dir.end_reached = 1;
@@ -1351,12 +1443,19 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
             matchcount = -1;
             if (ctx->type == is_pem) {
                 if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header,
-                                   &data, &len, ui_method, ui_data,
+                                   &data, &len, ui_method, ui_data, ctx->uri,
                                    (ctx->flags & FILE_FLAG_SECMEM) != 0)) {
                     ctx->errcnt++;
                     goto endloop;
                 }
             } else {
+                if ((result = file_try_read_msblob(ctx->_.file.file,
+                                                   &matchcount)) != NULL
+                    || (result = file_try_read_PVK(ctx->_.file.file,
+                                                   ui_method, ui_data, ctx->uri,
+                                                   &matchcount)) != NULL)
+                    goto endloop;
+
                 if (!file_read_asn1(ctx->_.file.file, &data, &len)) {
                     ctx->errcnt++;
                     goto endloop;
@@ -1435,17 +1534,25 @@ static int file_eof(OSSL_STORE_LOADER_CTX *ctx)
 
 static int file_close(OSSL_STORE_LOADER_CTX *ctx)
 {
-    if (ctx->type == is_dir) {
-        OPENSSL_DIR_end(&ctx->_.dir.ctx);
+    if ((ctx->flags & FILE_FLAG_ATTACHED) == 0) {
+        if (ctx->type == is_dir)
+            OPENSSL_DIR_end(&ctx->_.dir.ctx);
+        else
+            BIO_free_all(ctx->_.file.file);
     } else {
-        BIO_free_all(ctx->_.file.file);
-    }
-    OSSL_STORE_LOADER_CTX_free(ctx);
-    return 1;
-}
+        /*
+         * Because file_attach() called file_find_type(), we know that a
+         * BIO_f_buffer() has been pushed on top of the regular BIO.
+         */
+        BIO *buff = ctx->_.file.file;
 
-int ossl_store_file_detach_pem_bio_int(OSSL_STORE_LOADER_CTX *ctx)
-{
+        /* Detach buff */
+        (void)BIO_pop(ctx->_.file.file);
+        /* Safety measure */
+        ctx->_.file.file = NULL;
+
+        BIO_free(buff);
+    }
     OSSL_STORE_LOADER_CTX_free(ctx);
     return 1;
 }
@@ -1455,6 +1562,7 @@ static OSSL_STORE_LOADER file_loader =
         "file",
         NULL,
         file_open,
+        file_attach,
         file_ctrl,
         file_expect,
         file_find,
diff --git a/crypto/store/store_err.c b/crypto/store/store_err.c
index aa8ab4f9b0..3abb50bb21 100644
--- a/crypto/store/store_err.c
+++ b/crypto/store/store_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
diff --git a/crypto/store/store_lib.c b/crypto/store/store_lib.c
index 5bcd17b13b..15c0862019 100644
--- a/crypto/store/store_lib.c
+++ b/crypto/store/store_lib.c
@@ -651,47 +651,33 @@ char *ossl_store_info_get0_EMBEDDED_pem_name(OSSL_STORE_INFO *info)
     return NULL;
 }
 
-OSSL_STORE_CTX *ossl_store_attach_pem_bio(BIO *bp, const UI_METHOD *ui_method,
-                                          void *ui_data, OPENSSL_CTX *libctx,
-                                          const char *propq)
+OSSL_STORE_CTX *OSSL_STORE_attach(BIO *bp, OPENSSL_CTX *libctx,
+                                  const char *scheme, const char *propq,
+                                  const UI_METHOD *ui_method, void *ui_data,
+                                  OSSL_STORE_post_process_info_fn post_process,
+                                  void *post_process_data)
 {
     OSSL_STORE_CTX *ctx = NULL;
     const OSSL_STORE_LOADER *loader = NULL;
     OSSL_STORE_LOADER_CTX *loader_ctx = NULL;
 
-    if ((loader = ossl_store_get0_loader_int("file")) == NULL
-        || ((loader_ctx = ossl_store_file_attach_pem_bio_int(bp, libctx,
-                                                             propq)) == NULL))
-        goto done;
+    if ((loader =
+         ossl_store_get0_loader_int(scheme != NULL ? scheme : "file")) == NULL
+        || (loader_ctx = loader->attach(loader, bp, libctx, propq,
+                                        ui_method, ui_data)) == NULL)
+        return NULL;
+
     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_ATTACH_PEM_BIO,
-                     ERR_R_MALLOC_FAILURE);
-        goto done;
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_ATTACH, ERR_R_MALLOC_FAILURE);
+        return NULL;
     }
 
     ctx->loader = loader;
     ctx->loader_ctx = loader_ctx;
-    loader_ctx = NULL;
     ctx->ui_method = ui_method;
     ctx->ui_data = ui_data;
-    ctx->post_process = NULL;
-    ctx->post_process_data = NULL;
+    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_detach_pem_bio(OSSL_STORE_CTX *ctx)
-{
-    int loader_ret = ossl_store_file_detach_pem_bio_int(ctx->loader_ctx);
-
-    OPENSSL_free(ctx);
-    return loader_ret;
-}
diff --git a/crypto/store/store_local.h b/crypto/store/store_local.h
index 7c86419031..31e04d13ad 100644
--- a/crypto/store/store_local.h
+++ b/crypto/store/store_local.h
@@ -102,6 +102,7 @@ struct ossl_store_loader_st {
     const char *scheme;
     ENGINE *engine;
     OSSL_STORE_open_fn open;
+    OSSL_STORE_attach_fn attach;
     OSSL_STORE_ctrl_fn ctrl;
     OSSL_STORE_expect_fn expect;
     OSSL_STORE_find_fn find;
@@ -122,13 +123,3 @@ void ossl_store_destroy_loaders_int(void);
 
 int ossl_store_init_once(void);
 int ossl_store_file_loader_init(void);
-
-/*-
- *  'file' scheme stuff
- *  -------------------
- */
-
-OSSL_STORE_LOADER_CTX *ossl_store_file_attach_pem_bio_int(BIO *bp,
-                                                          OPENSSL_CTX *libctx,
-                                                          const char *propq);
-int ossl_store_file_detach_pem_bio_int(OSSL_STORE_LOADER_CTX *ctx);
diff --git a/crypto/store/store_register.c b/crypto/store/store_register.c
index 399ec8c625..45fbd2fa1c 100644
--- a/crypto/store/store_register.c
+++ b/crypto/store/store_register.c
@@ -71,6 +71,13 @@ int OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER *loader,
     return 1;
 }
 
+int OSSL_STORE_LOADER_set_attach(OSSL_STORE_LOADER *loader,
+                                 OSSL_STORE_attach_fn attach_function)
+{
+    loader->attach = attach_function;
+    return 1;
+}
+
 int OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER *loader,
                                OSSL_STORE_ctrl_fn ctrl_function)
 {
diff --git a/doc/man3/OSSL_STORE_LOADER.pod b/doc/man3/OSSL_STORE_LOADER.pod
index 101857d543..97fde1268f 100644
--- a/doc/man3/OSSL_STORE_LOADER.pod
+++ b/doc/man3/OSSL_STORE_LOADER.pod
@@ -4,12 +4,14 @@
 
 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_expect, OSSL_STORE_LOADER_set_find,
-OSSL_STORE_LOADER_set_load, OSSL_STORE_LOADER_set_eof,
-OSSL_STORE_LOADER_set_error, OSSL_STORE_LOADER_set_close,
+OSSL_STORE_LOADER_set_open, OSSL_STORE_LOADER_set_attach,
+OSSL_STORE_LOADER_set_ctrl, OSSL_STORE_LOADER_set_expect,
+OSSL_STORE_LOADER_set_find, 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_unregister_loader,
+OSSL_STORE_open_fn, OSSL_STORE_attach_fn, OSSL_STORE_ctrl_fn,
 OSSL_STORE_expect_fn, OSSL_STORE_find_fn,
 OSSL_STORE_load_fn, OSSL_STORE_eof_fn, OSSL_STORE_error_fn,
 OSSL_STORE_close_fn - Types and functions to manipulate, register and
@@ -35,6 +37,16 @@ unregister STORE loaders for different URI schemes
                                                       void *ui_data);
  int OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER *store_loader,
                                 OSSL_STORE_open_fn store_open_function);
+ typedef OSSL_STORE_LOADER_CTX *(*OSSL_STORE_attach_fn)(const OSSL_STORE_LOADER
+                                                        *loader,
+                                                        BIO *bio,
+                                                        OPENSSL_CTX *libctx,
+                                                        const char *propq,
+                                                        const UI_METHOD
+                                                        *ui_method,
+                                                        void *ui_data);
+ int OSSL_STORE_LOADER_set_attach(OSSL_STORE_LOADER *loader,
+                                  OSSL_STORE_attach_fn attach_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,
@@ -99,6 +111,10 @@ initialized, to create a private 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_open_fn>
+
+This function takes a B<BIO>, otherwise works like B<OSSL_STORE_open_fn>.
+
 =item B<OSSL_STORE_ctrl_fn>
 
 This function takes a B<OSSL_STORE_LOADER_CTX> pointer, a command number
@@ -189,6 +205,9 @@ 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_attach() sets the attacher function for the
+B<store_loader>.
+
 OSSL_STORE_LOADER_set_ctrl() sets the control function for the
 B<store_loader>.
 
diff --git a/doc/man3/OSSL_STORE_attach.pod b/doc/man3/OSSL_STORE_attach.pod
new file mode 100644
index 0000000000..7df2804964
--- /dev/null
+++ b/doc/man3/OSSL_STORE_attach.pod
@@ -0,0 +1,45 @@
+=pod
+
+=head1 NAME
+
+OSSL_STORE_attach - Functions to read objects from a BIO
+
+=head1 SYNOPSIS
+
+ #include <openssl/store.h>
+
+ OSSL_STORE_CTX *OSSL_STORE_attach(BIO *bio, OPENSSL_CTX *libctx,
+                                   const char *scheme, const char *propq,
+                                   const UI_METHOD *ui_method, void *ui_data,
+                                   OSSL_STORE_post_process_info_fn post_process,
+                                   void *post_process_data);
+
+=head1 DESCRIPTION
+
+OSSL_STORE_attach() works like L<OSSL_STORE_open(3)>, except it takes a B<BIO>
+I<bio> instead of a I<uri>, along with a I<scheme> to determine what loader
+should be used to process the data.
+
+=head1 RETURN VALUES
+
+OSSL_STORE_attach() returns a pointer to a B<OSSL_STORE_CTX> on success, or
+NULL on failure.
+
+=head1 SEE ALSO
+
+L<ossl_store(7)>, L<OSSL_STORE_open(3)>
+
+=head1 HISTORY
+
+OSSL_STORE_attach() was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/store.h b/include/openssl/store.h
index 7b2561c2d5..619829dc97 100644
--- a/include/openssl/store.h
+++ b/include/openssl/store.h
@@ -102,6 +102,24 @@ int OSSL_STORE_error(OSSL_STORE_CTX *ctx);
  */
 int OSSL_STORE_close(OSSL_STORE_CTX *ctx);
 
+/*
+ * Attach to a BIO.  This works like OSSL_STORE_open() except it takes a
+ * BIO instead of a uri, along with a scheme to use when reading.
+ * 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.
+ *
+ * Note that this function is considered unsafe, all depending on what the
+ * BIO actually reads.
+ */
+OSSL_STORE_CTX *OSSL_STORE_attach(BIO *bio, OPENSSL_CTX *libctx,
+                                  const char *scheme, const char *propq,
+                                  const UI_METHOD *ui_method, void *ui_data,
+                                  OSSL_STORE_post_process_info_fn post_process,
+                                  void *post_process_data);
 
 /*-
  *  Extracting OpenSSL types from and creating new OSSL_STORE_INFOs
@@ -228,6 +246,16 @@ typedef OSSL_STORE_LOADER_CTX *(*OSSL_STORE_open_fn)(const OSSL_STORE_LOADER
                                                      void *ui_data);
 int OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER *loader,
                                OSSL_STORE_open_fn open_function);
+typedef OSSL_STORE_LOADER_CTX *(*OSSL_STORE_attach_fn)(const OSSL_STORE_LOADER
+                                                       *loader,
+                                                       BIO *bio,
+                                                       OPENSSL_CTX *libctx,
+                                                       const char *propq,
+                                                       const UI_METHOD
+                                                       *ui_method,
+                                                       void *ui_data);
+int OSSL_STORE_LOADER_set_attach(OSSL_STORE_LOADER *loader,
+                                 OSSL_STORE_attach_fn attach_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,
diff --git a/include/openssl/storeerr.h b/include/openssl/storeerr.h
index db27938247..ed8f7988fe 100644
--- a/include/openssl/storeerr.h
+++ b/include/openssl/storeerr.h
@@ -8,8 +8,8 @@
  * https://www.openssl.org/source/license.html
  */
 
-#ifndef OPENSSL_STOREERR_H
-# define OPENSSL_STOREERR_H
+#ifndef OPENSSL_OSSL_STOREERR_H
+# define OPENSSL_OSSL_STOREERR_H
 # pragma once
 
 # include <openssl/opensslconf.h>
@@ -25,6 +25,7 @@ int ERR_load_OSSL_STORE_strings(void);
  * OSSL_STORE function codes.
  */
 # ifndef OPENSSL_NO_DEPRECATED_3_0
+#  define OSSL_STORE_F_FILE_ATTACH                         0
 #  define OSSL_STORE_F_FILE_CTRL                           0
 #  define OSSL_STORE_F_FILE_FIND                           0
 #  define OSSL_STORE_F_FILE_GET_PASS                       0
@@ -32,9 +33,8 @@ int ERR_load_OSSL_STORE_strings(void);
 #  define OSSL_STORE_F_FILE_LOAD_TRY_DECODE                0
 #  define OSSL_STORE_F_FILE_NAME_TO_URI                    0
 #  define OSSL_STORE_F_FILE_OPEN                           0
-#  define OSSL_STORE_F_OSSL_STORE_ATTACH_PEM_BIO           0
+#  define OSSL_STORE_F_OSSL_STORE_ATTACH                   0
 #  define OSSL_STORE_F_OSSL_STORE_EXPECT                   0
-#  define OSSL_STORE_F_OSSL_STORE_FILE_ATTACH_PEM_BIO_INT  0
 #  define OSSL_STORE_F_OSSL_STORE_FIND                     0
 #  define OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT          0
 #  define OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT           0
diff --git a/util/libcrypto.num b/util/libcrypto.num
index e91c265e20..590157fe8b 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5086,3 +5086,5 @@ EVP_default_properties_is_fips_enabled  ?	3_0_0	EXIST::FUNCTION:
 EVP_default_properties_enable_fips      ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_new_raw_private_key_with_libctx ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_new_raw_public_key_with_libctx ?	3_0_0	EXIST::FUNCTION:
+OSSL_STORE_attach                       ?	3_0_0	EXIST::FUNCTION:
+OSSL_STORE_LOADER_set_attach            ?	3_0_0	EXIST::FUNCTION:
diff --git a/util/other.syms b/util/other.syms
index 9f44034fd5..d993485931 100644
--- a/util/other.syms
+++ b/util/other.syms
@@ -49,6 +49,7 @@ OSSL_STORE_INFO                         datatype
 OSSL_STORE_LOADER                       datatype
 OSSL_STORE_LOADER_CTX                   datatype
 OSSL_STORE_SEARCH                       datatype
+OSSL_STORE_attach_fn                    datatype
 OSSL_STORE_close_fn                     datatype
 OSSL_STORE_ctrl_fn                      datatype
 OSSL_STORE_expect_fn                    datatype


More information about the openssl-commits mailing list