File openssl-Add_support_for_Windows_CA_certificate_store.patch of Package openssl-3

From 2a071544f7d2e963a1f68f266f4e375568909d38 Mon Sep 17 00:00:00 2001
From: Hugo Landau <hlandau@openssl.org>
Date: Fri, 8 Apr 2022 13:10:52 +0100
Subject: [PATCH 1/8] Fix URI handling in SSL_CERT_DIR/introduce SSL_CERT_URI
 env

Fixes #18068.
---
 CHANGES.md                                               |   21 
 Configure                                                |    7 
 crypto/x509/by_dir.c                                     |   17 
 crypto/x509/by_store.c                                   |   14 
 crypto/x509/x509_def.c                                   |   15 
 doc/build.info                                           |    6 
 doc/man3/X509_get_default_cert_file.pod                  |  113 +++++
 include/internal/cryptlib.h                              |   11 
 include/internal/e_os.h                                  |    2 
 include/openssl/x509.h.in                                |    3 
 providers/implementations/include/prov/implementations.h |    1 
 providers/implementations/storemgmt/build.info           |    3 
 providers/implementations/storemgmt/winstore_store.c     |  327 +++++++++++++++
 providers/stores.inc                                     |    3 
 util/libcrypto.num                                       |    3 
 util/missingcrypto.txt                                   |    4 
 16 files changed, 536 insertions(+), 14 deletions(-)

--- a/CHANGES.md
+++ b/CHANGES.md
@@ -24,6 +24,27 @@ OpenSSL 3.1
 
 ### Changes between 3.1.0 and 3.1.1 [30 May 2023]
 
+ * The `SSL_CERT_PATH` and `SSL_CERT_URI` environment variables are introduced.
+   `SSL_CERT_URI` can be used to specify a URI for a root certificate store. The
+   `SSL_CERT_PATH` environment variable specifies a delimiter-separated list of
+   paths which are searched for root certificates.
+
+   The existing `SSL_CERT_DIR` environment variable is deprecated.
+   `SSL_CERT_DIR` was previously used to specify either a delimiter-separated
+   list of paths or an URI, which is ambiguous. Setting `SSL_CERT_PATH` causes
+   `SSL_CERT_DIR` to be ignored for the purposes of determining root certificate
+   directories, and setting `SSL_CERT_URI` causes `SSL_CERT_DIR` to be ignored
+   for the purposes of determining root certificate stores.
+
+   *Hugo Landau*
+
+ * Support for loading root certificates from the Windows certificate store
+   has been added. The support is in the form of a store which recognises the
+   URI string of `org.openssl.winstore://`. This store is enabled by default and
+   can be disabled using the new compile-time option `no-winstore`.
+
+   *Hugo Landau*
+
  * Mitigate for the time it takes for `OBJ_obj2txt` to translate gigantic
    OBJECT IDENTIFIER sub-identifiers to canonical numeric text form.
 
--- a/Configure
+++ b/Configure
@@ -420,6 +420,7 @@ my @disablables = (
     "cached-fetch",
     "camellia",
     "capieng",
+    "winstore",
     "cast",
     "chacha",
     "cmac",
@@ -1726,6 +1727,12 @@ unless ($disabled{ktls}) {
     }
 }
 
+unless ($disabled{winstore}) {
+    unless ($target =~ /^(?:Cygwin|mingw|VC-|BC-)/) {
+        disable('not-windows', 'winstore');
+    }
+}
+
 push @{$config{openssl_other_defines}}, "OPENSSL_NO_KTLS" if ($disabled{ktls});
 
 # Get the extra flags used when building shared libraries and modules.  We
--- a/crypto/x509/by_dir.c
+++ b/crypto/x509/by_dir.c
@@ -88,13 +88,18 @@ static int dir_ctrl(X509_LOOKUP *ctx, in
     switch (cmd) {
     case X509_L_ADD_DIR:
         if (argl == X509_FILETYPE_DEFAULT) {
-            const char *dir = ossl_safe_getenv(X509_get_default_cert_dir_env());
+            /* If SSL_CERT_PATH is provided and non-empty, use that. */
+            const char *dir = ossl_safe_getenv(X509_get_default_cert_path_env());
 
-            if (dir)
-                ret = add_cert_dir(ld, dir, X509_FILETYPE_PEM);
-            else
-                ret = add_cert_dir(ld, X509_get_default_cert_dir(),
-                                   X509_FILETYPE_PEM);
+            /* Fallback to SSL_CERT_DIR. */
+            if (dir == NULL)
+                dir = ossl_safe_getenv(X509_get_default_cert_dir_env());
+
+            /* Fallback to built-in default. */
+            if (dir == NULL)
+                dir = X509_get_default_cert_dir();
+
+            ret = add_cert_dir(ld, dir, X509_FILETYPE_PEM);
             if (!ret) {
                 ERR_raise(ERR_LIB_X509, X509_R_LOADING_CERT_DIR);
             }
--- a/crypto/x509/by_store.c
+++ b/crypto/x509/by_store.c
@@ -111,11 +111,21 @@ static int by_store_ctrl_ex(X509_LOOKUP
 {
     switch (cmd) {
     case X509_L_ADD_STORE:
-        /* If no URI is given, use the default cert dir as default URI */
+        /* First try the newer default cert URI envvar. */
+        if (argp == NULL)
+            argp = ossl_safe_getenv(X509_get_default_cert_uri_env());
+
+        /* If not set, see if we have a URI in the older cert dir envvar. */
         if (argp == NULL)
             argp = ossl_safe_getenv(X509_get_default_cert_dir_env());
+
+        /* Fallback to default store URI. */
         if (argp == NULL)
-            argp = X509_get_default_cert_dir();
+            argp = X509_get_default_cert_uri();
+
+        /* No point adding an empty URI. */
+        if (!*argp)
+            return 1;
 
         {
             STACK_OF(OPENSSL_STRING) *uris = X509_LOOKUP_get_method_data(ctx);
--- a/crypto/x509/x509_def.c
+++ b/crypto/x509/x509_def.c
@@ -22,6 +22,11 @@ const char *X509_get_default_cert_area(v
     return X509_CERT_AREA;
 }
 
+const char *X509_get_default_cert_uri(void)
+{
+    return X509_CERT_URI;
+}
+
 const char *X509_get_default_cert_dir(void)
 {
     return X509_CERT_DIR;
@@ -32,6 +37,16 @@ const char *X509_get_default_cert_file(v
     return X509_CERT_FILE;
 }
 
+const char *X509_get_default_cert_uri_env(void)
+{
+    return X509_CERT_URI_EVP;
+}
+
+const char *X509_get_default_cert_path_env(void)
+{
+    return X509_CERT_PATH_EVP;
+}
+
 const char *X509_get_default_cert_dir_env(void)
 {
     return X509_CERT_DIR_EVP;
--- a/doc/build.info
+++ b/doc/build.info
@@ -2791,6 +2791,10 @@ DEPEND[html/man3/X509_get0_uids.html]=ma
 GENERATE[html/man3/X509_get0_uids.html]=man3/X509_get0_uids.pod
 DEPEND[man/man3/X509_get0_uids.3]=man3/X509_get0_uids.pod
 GENERATE[man/man3/X509_get0_uids.3]=man3/X509_get0_uids.pod
+DEPEND[html/man3/X509_get_default_cert_file.html]=man3/X509_get_default_cert_file.pod
+GENERATE[html/man3/X509_get_default_cert_file.html]=man3/X509_get_default_cert_file.pod
+DEPEND[man/man3/X509_get_default_cert_file.3]=man3/X509_get_default_cert_file.pod
+GENERATE[man/man3/X509_get_default_cert_file.3]=man3/X509_get_default_cert_file.pod
 DEPEND[html/man3/X509_get_extension_flags.html]=man3/X509_get_extension_flags.pod
 GENERATE[html/man3/X509_get_extension_flags.html]=man3/X509_get_extension_flags.pod
 DEPEND[man/man3/X509_get_extension_flags.3]=man3/X509_get_extension_flags.pod
@@ -3461,6 +3465,7 @@ html/man3/X509_get0_distinguishing_id.ht
 html/man3/X509_get0_notBefore.html \
 html/man3/X509_get0_signature.html \
 html/man3/X509_get0_uids.html \
+html/man3/X509_get_default_cert_file.html \
 html/man3/X509_get_extension_flags.html \
 html/man3/X509_get_pubkey.html \
 html/man3/X509_get_serialNumber.html \
@@ -4064,6 +4069,7 @@ man/man3/X509_get0_distinguishing_id.3 \
 man/man3/X509_get0_notBefore.3 \
 man/man3/X509_get0_signature.3 \
 man/man3/X509_get0_uids.3 \
+man/man3/X509_get_default_cert_file.3 \
 man/man3/X509_get_extension_flags.3 \
 man/man3/X509_get_pubkey.3 \
 man/man3/X509_get_serialNumber.3 \
--- /dev/null
+++ b/doc/man3/X509_get_default_cert_file.pod
@@ -0,0 +1,113 @@
+=pod
+
+=head1 NAME
+
+X509_get_default_cert_file, X509_get_default_cert_file_env,
+X509_get_default_cert_path_env,
+X509_get_default_cert_dir, X509_get_default_cert_dir_env,
+X509_get_default_cert_uri, X509_get_default_cert_uri_env -
+retrieve default locations for trusted CA certificates
+
+=head1 SYNOPSIS
+
+ #include <openssl/x509.h>
+
+ const char *X509_get_default_cert_file(void);
+ const char *X509_get_default_cert_dir(void);
+ const char *X509_get_default_cert_uri(void);
+
+ const char *X509_get_default_cert_file_env(void);
+ const char *X509_get_default_cert_path_env(void);
+ const char *X509_get_default_cert_dir_env(void);
+ const char *X509_get_default_cert_uri_env(void);
+
+=head1 DESCRIPTION
+
+The X509_get_default_cert_file() function returns the default path
+to a file containing trusted CA certificates. OpenSSL will use this as
+the default path when it is asked to load trusted CA certificates
+from a file and no other path is specified. If the file exists, CA certificates
+are loaded from the file.
+
+The X509_get_default_cert_dir() function returns a default delimeter-separated
+list of paths to a directories containing trusted CA certificates named in the
+hashed format. OpenSSL will use this as the default list of paths when it is
+asked to load trusted CA certificates from a directory and no other path is
+specified. If a given directory in the list exists, OpenSSL attempts to lookup
+CA certificates in this directory by calculating a filename based on a hash of
+the certificate's subject name.
+
+The X509_get_default_cert_uri() function returns the default URI for a
+certificate store accessed programmatically via an OpenSSL provider. If there is
+no default store applicable to the system for which OpenSSL was compiled, this
+returns an empty string.
+
+X509_get_default_cert_file_env() and X509_get_default_cert_uri_env() return
+environment variable names which are recommended to specify nondefault values to
+be used instead of the values returned by X509_get_default_cert_file() and
+X509_get_default_cert_uri() respectively. The values returned by the latter
+functions are not affected by these environment variables; you must check for
+these environment variables yourself, using these functions to retrieve the
+correct environment variable names. If an environment variable is not set, the
+value returned by the corresponding function above should be used.
+
+X509_get_default_cert_path_env() returns the environment variable name which is
+recommended to specify a nondefault value to be used instead of the value
+returned by X509_get_default_cert_dir(). This environment variable supercedes
+the deprecated environment variable whose name is returned by
+X509_get_default_cert_dir_env(). This environment variable was deprecated as its
+contents can be interpreted ambiguously; see NOTES.
+
+By default, OpenSSL uses the path list specified in the environment variable
+whose name is returned by X509_get_default_cert_path_env() if it is set;
+otherwise, it uses the path list specified in the environment variable whose
+name is returned by X509_get_default_cert_dir_env() if it is set; otherwise, it
+uses the value returned by X509_get_default_cert_dir()).
+
+=head1 NOTES
+
+X509_get_default_cert_uri(), X509_get_default_cert_uri_env() and
+X509_get_default_cert_path_env() were introduced in OpenSSL 3.1. Prior to this
+release, store URIs were expressed via the environment variable returned by
+X509_get_default_cert_dir_env(); this environment variable could be used to
+specify either a list of directories or a store URI. This creates an ambiguity
+in which the environment variable returned by X509_get_default_cert_dir_env() is
+interpreted both as a list of directories and as a store URI.
+
+This usage and the environment variable returned by
+X509_get_default_cert_dir_env() are now deprecated; to specify a store URI, use
+the environment variable returned by X509_get_default_cert_uri_env(), and to
+specify a list of directories, use the environment variable returned by
+X509_get_default_cert_path_env().
+
+=head1 RETURN VALUES
+
+These functions return pointers to constant strings with static storage
+duration.
+
+=head1 SEE ALSO
+
+L<X509_LOOKUP(3)>,
+L<SSL_CTX_set_default_verify_file(3)>,
+L<SSL_CTX_set_default_verify_dir(3)>,
+L<SSL_CTX_set_default_verify_store(3)>,
+L<SSL_CTX_load_verify_file(3)>,
+L<SSL_CTX_load_verify_dir(3)>,
+L<SSL_CTX_load_verify_store(3)>,
+L<SSL_CTX_load_verify_locations(3)>
+
+=head1 HISTORY
+
+X509_get_default_cert_uri(), X509_get_default_cert_path_env() and
+X509_get_default_cert_uri_env() were introduced in OpenSSL 3.1.
+
+=head1 COPYRIGHT
+
+Copyright 2022 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
--- a/include/internal/cryptlib.h
+++ b/include/internal/cryptlib.h
@@ -13,6 +13,8 @@
 
 # include <stdlib.h>
 # include <string.h>
+# include "openssl/configuration.h"
+# include "internal/e_os.h" /* ossl_inline in many files */
 
 # ifdef OPENSSL_USE_APPLINK
 #  define BIO_FLAGS_UPLINK_INTERNAL 0x8000
@@ -77,6 +79,14 @@ DEFINE_LHASH_OF_EX(MEM);
 #  define CTLOG_FILE              "OSSL$DATAROOT:[000000]ct_log_list.cnf"
 # endif
 
+#ifndef OPENSSL_NO_WINSTORE
+# define X509_CERT_URI            "org.openssl.winstore://"
+#else
+# define X509_CERT_URI            ""
+#endif
+
+# define X509_CERT_URI_EVP        "SSL_CERT_URI"
+# define X509_CERT_PATH_EVP       "SSL_CERT_PATH"
 # define X509_CERT_DIR_EVP        "SSL_CERT_DIR"
 # define X509_CERT_FILE_EVP       "SSL_CERT_FILE"
 # define CTLOG_FILE_EVP           "CTLOG_FILE"
@@ -240,5 +250,4 @@ static ossl_inline int ossl_is_absolute_
 # endif
     return path[0] == '/';
 }
-
 #endif
--- a/include/internal/e_os.h
+++ b/include/internal/e_os.h
@@ -249,7 +249,7 @@ FILE *__iob_func();
 /***********************************************/
 
 # if defined(OPENSSL_SYS_WINDOWS)
-#  if (_MSC_VER >= 1310) && !defined(_WIN32_WCE)
+#  if defined(_MSC_VER) && (_MSC_VER >= 1310) && !defined(_WIN32_WCE)
 #   define open _open
 #   define fdopen _fdopen
 #   define close _close
--- a/include/openssl/x509.h.in
+++ b/include/openssl/x509.h.in
@@ -491,8 +491,11 @@ ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s
 ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj);
 
 const char *X509_get_default_cert_area(void);
+const char *X509_get_default_cert_uri(void);
 const char *X509_get_default_cert_dir(void);
 const char *X509_get_default_cert_file(void);
+const char *X509_get_default_cert_uri_env(void);
+const char *X509_get_default_cert_path_env(void);
 const char *X509_get_default_cert_dir_env(void);
 const char *X509_get_default_cert_file_env(void);
 const char *X509_get_default_private_dir(void);
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -517,3 +517,4 @@ extern const OSSL_DISPATCH ossl_SubjectP
 extern const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[];
 
 extern const OSSL_DISPATCH ossl_file_store_functions[];
+extern const OSSL_DISPATCH ossl_winstore_store_functions[];
--- a/providers/implementations/storemgmt/build.info
+++ b/providers/implementations/storemgmt/build.info
@@ -4,3 +4,6 @@
 $STORE_GOAL=../../libdefault.a
 
 SOURCE[$STORE_GOAL]=file_store.c file_store_any2obj.c
+IF[{- !$disabled{winstore} -}]
+    SOURCE[$STORE_GOAL]=winstore_store.c
+ENDIF
--- /dev/null
+++ b/providers/implementations/storemgmt/winstore_store.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+#include <openssl/store.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/core_object.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/params.h>
+#include <openssl/decoder.h>
+#include <openssl/proverr.h>
+#include <openssl/store.h>       /* The OSSL_STORE_INFO type numbers */
+#include "internal/cryptlib.h"
+#include "internal/o_dir.h"
+#include "crypto/decoder.h"
+#include "crypto/ctype.h"        /* ossl_isdigit() */
+#include "prov/implementations.h"
+#include "prov/bio.h"
+#include "file_store_local.h"
+
+#include <wincrypt.h>
+
+enum {
+    STATE_IDLE,
+    STATE_READ,
+    STATE_EOF,
+};
+
+struct winstore_ctx_st {
+    void                   *provctx;
+    char                   *propq;
+    unsigned char          *subject;
+    size_t                  subject_len;
+
+    HCERTSTORE              win_store;
+    const CERT_CONTEXT     *win_ctx;
+    int                     state;
+
+    OSSL_DECODER_CTX       *dctx;
+};
+
+static void winstore_win_reset(struct winstore_ctx_st *ctx)
+{
+    if (ctx->win_ctx != NULL) {
+        CertFreeCertificateContext(ctx->win_ctx);
+        ctx->win_ctx = NULL;
+    }
+
+    ctx->state = STATE_IDLE;
+}
+
+static void winstore_win_advance(struct winstore_ctx_st *ctx)
+{
+    CERT_NAME_BLOB name = {0};
+
+    if (ctx->state == STATE_EOF)
+        return;
+
+    name.cbData = ctx->subject_len;
+    name.pbData = ctx->subject;
+
+    ctx->win_ctx = (name.cbData == 0 ? NULL :
+        CertFindCertificateInStore(ctx->win_store,
+                                   X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                                   0, CERT_FIND_SUBJECT_NAME,
+                                   &name, ctx->win_ctx));
+
+    ctx->state = (ctx->win_ctx == NULL) ? STATE_EOF : STATE_READ;
+}
+
+static void *winstore_open(void *provctx, const char *uri)
+{
+    struct winstore_ctx_st *ctx = NULL;
+
+    if (!HAS_CASE_PREFIX(uri, "org.openssl.winstore:"))
+        return NULL;
+
+    ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx == NULL)
+        return NULL;
+
+    ctx->provctx    = provctx;
+    ctx->win_store  = CertOpenSystemStoreW(0, L"ROOT");
+    if (ctx->win_store == NULL) {
+        OPENSSL_free(ctx);
+        return NULL;
+    }
+
+    winstore_win_reset(ctx);
+    return ctx;
+}
+
+static void *winstore_attach(void *provctx, OSSL_CORE_BIO *cin)
+{
+    return NULL; /* not supported */
+}
+
+static const OSSL_PARAM *winstore_settable_ctx_params(void *loaderctx, const OSSL_PARAM params[])
+{
+    static const OSSL_PARAM known_settable_ctx_params[] = {
+        OSSL_PARAM_octet_string(OSSL_STORE_PARAM_SUBJECT, NULL, 0),
+        OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_PROPERTIES, NULL, 0),
+        OSSL_PARAM_END
+    };
+    return known_settable_ctx_params;
+}
+
+static int winstore_set_ctx_params(void *loaderctx, const OSSL_PARAM params[])
+{
+    struct winstore_ctx_st *ctx = loaderctx;
+    const OSSL_PARAM *p;
+    int do_reset = 0;
+
+    if (params == NULL)
+        return 1;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_PROPERTIES);
+    if (p != NULL) {
+        do_reset = 1;
+        OPENSSL_free(ctx->propq);
+        ctx->propq = NULL;
+        if (!OSSL_PARAM_get_utf8_string(p, &ctx->propq, 0))
+            return 0;
+    }
+
+    p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT);
+    if (p != NULL) {
+        const unsigned char *der = NULL;
+        size_t der_len = 0;
+
+        if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&der, &der_len))
+            return 0;
+
+        do_reset = 1;
+
+        OPENSSL_free(ctx->subject);
+
+        ctx->subject = OPENSSL_malloc(der_len);
+        if (ctx->subject == NULL) {
+            ctx->subject_len = 0;
+            return 0;
+        }
+
+        ctx->subject_len = der_len;
+        memcpy(ctx->subject, der, der_len);
+    }
+
+    if (do_reset) {
+        winstore_win_reset(ctx);
+        winstore_win_advance(ctx);
+    }
+
+    return 1;
+}
+
+struct load_data_st {
+    OSSL_CALLBACK  *object_cb;
+    void           *object_cbarg;
+};
+
+static int load_construct(OSSL_DECODER_INSTANCE *decoder_inst,
+                           const OSSL_PARAM *params, void *construct_data)
+{
+    struct load_data_st *data = construct_data;
+    return data->object_cb(params, data->object_cbarg);
+}
+
+static void load_cleanup(void *construct_data)
+{
+    /* No-op. */
+}
+
+static int setup_decoder(struct winstore_ctx_st *ctx)
+{
+    OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx);
+    const OSSL_ALGORITHM *to_algo = NULL;
+
+    if (ctx->dctx != NULL)
+        return 1;
+
+    ctx->dctx = OSSL_DECODER_CTX_new();
+    if (ctx->dctx == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!OSSL_DECODER_CTX_set_input_type(ctx->dctx, "DER")) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
+        goto err;
+    }
+
+    if (!OSSL_DECODER_CTX_set_input_structure(ctx->dctx, "Certificate")) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
+        goto err;
+    }
+
+    for (to_algo = ossl_any_to_obj_algorithm;
+         to_algo->algorithm_names != NULL;
+         to_algo++) {
+        OSSL_DECODER *to_obj = NULL;
+        OSSL_DECODER_INSTANCE *to_obj_inst = NULL;
+
+        /*
+         * Create the internal last resort decoder implementation
+         * together with a "decoder instance".
+         * The decoder doesn't need any identification or to be
+         * attached to any provider, since it's only used locally.
+         */
+        to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL);
+        if (to_obj != NULL)
+            to_obj_inst = ossl_decoder_instance_new(to_obj, ctx->provctx);
+
+        OSSL_DECODER_free(to_obj);
+        if (to_obj_inst == NULL)
+            goto err;
+
+        if (!ossl_decoder_ctx_add_decoder_inst(ctx->dctx,
+                                               to_obj_inst)) {
+            ossl_decoder_instance_free(to_obj_inst);
+            ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
+            goto err;
+        }
+    }
+
+    if (!OSSL_DECODER_CTX_add_extra(ctx->dctx, libctx, ctx->propq)) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
+        goto err;
+    }
+
+    if (!OSSL_DECODER_CTX_set_construct(ctx->dctx, load_construct)) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
+        goto err;
+    }
+
+    if (!OSSL_DECODER_CTX_set_cleanup(ctx->dctx, load_cleanup)) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
+        goto err;
+    }
+
+    return 1;
+
+err:
+    OSSL_DECODER_CTX_free(ctx->dctx);
+    ctx->dctx = NULL;
+    return 0;
+}
+
+static int winstore_load_using(struct winstore_ctx_st *ctx,
+                               OSSL_CALLBACK *object_cb, void *object_cbarg,
+                               OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg,
+                               const void *der, size_t der_len)
+{
+    struct load_data_st data;
+    const unsigned char *der_ = der;
+    size_t der_len_ = der_len;
+
+    if (setup_decoder(ctx) == 0)
+        return 0;
+
+    data.object_cb      = object_cb;
+    data.object_cbarg   = object_cbarg;
+
+    OSSL_DECODER_CTX_set_construct_data(ctx->dctx, &data);
+    OSSL_DECODER_CTX_set_passphrase_cb(ctx->dctx, pw_cb, pw_cbarg);
+
+    if (OSSL_DECODER_from_data(ctx->dctx, &der_, &der_len_) == 0)
+        return 0;
+
+    return 1;
+}
+
+static int winstore_load(void *loaderctx,
+                         OSSL_CALLBACK *object_cb, void *object_cbarg,
+                         OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+    int ret = 0;
+    struct winstore_ctx_st *ctx = loaderctx;
+
+    if (ctx->state != STATE_READ)
+        return 0;
+
+    ret = winstore_load_using(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg,
+                              ctx->win_ctx->pbCertEncoded,
+                              ctx->win_ctx->cbCertEncoded);
+
+    if (ret == 1)
+        winstore_win_advance(ctx);
+
+    return ret;
+}
+
+static int winstore_eof(void *loaderctx)
+{
+    struct winstore_ctx_st *ctx = loaderctx;
+
+    return ctx->state != STATE_READ;
+}
+
+static int winstore_close(void *loaderctx)
+{
+    struct winstore_ctx_st *ctx = loaderctx;
+
+    winstore_win_reset(ctx);
+    CertCloseStore(ctx->win_store, 0);
+    OSSL_DECODER_CTX_free(ctx->dctx);
+    OPENSSL_free(ctx->propq);
+    OPENSSL_free(ctx->subject);
+    OPENSSL_free(ctx);
+    return 1;
+}
+
+const OSSL_DISPATCH ossl_winstore_store_functions[] = {
+    { OSSL_FUNC_STORE_OPEN, (void (*)(void))winstore_open },
+    { OSSL_FUNC_STORE_ATTACH, (void (*)(void))winstore_attach },
+    { OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS, (void (*)(void))winstore_settable_ctx_params },
+    { OSSL_FUNC_STORE_SET_CTX_PARAMS, (void (*)(void))winstore_set_ctx_params },
+    { OSSL_FUNC_STORE_LOAD, (void (*)(void))winstore_load },
+    { OSSL_FUNC_STORE_EOF, (void (*)(void))winstore_eof },
+    { OSSL_FUNC_STORE_CLOSE, (void (*)(void))winstore_close },
+    { 0, NULL },
+};
--- a/providers/stores.inc
+++ b/providers/stores.inc
@@ -12,3 +12,6 @@
 #endif
 
 STORE("file", "yes", ossl_file_store_functions)
+#ifndef OPENSSL_NO_WINSTORE
+STORE("org.openssl.winstore", "yes", ossl_winstore_store_functions)
+#endif
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5435,4 +5435,7 @@ EVP_MD_CTX_dup
 EVP_CIPHER_CTX_dup                      5563	3_1_0	EXIST::FUNCTION:
 BN_are_coprime                          5564	3_1_0	EXIST::FUNCTION:
 OSSL_CMP_MSG_update_recipNonce          5565	3_0_9	EXIST::FUNCTION:CMP
+X509_get_default_cert_uri               ?	3_1_0	EXIST::FUNCTION:
+X509_get_default_cert_uri_env           ?	3_1_0	EXIST::FUNCTION:
+X509_get_default_cert_path_env          ?	3_1_0	EXIST::FUNCTION:
 ossl_safe_getenv                        ?	3_0_0	EXIST::FUNCTION:
--- a/util/missingcrypto.txt
+++ b/util/missingcrypto.txt
@@ -1273,10 +1273,6 @@ X509_get0_trust_objects(3)
 X509_get1_email(3)
 X509_get1_ocsp(3)
 X509_get_default_cert_area(3)
-X509_get_default_cert_dir(3)
-X509_get_default_cert_dir_env(3)
-X509_get_default_cert_file(3)
-X509_get_default_cert_file_env(3)
 X509_get_default_private_dir(3)
 X509_get_pubkey_parameters(3)
 X509_get_signature_type(3)
openSUSE Build Service is sponsored by