]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
mod_ssl: Add support for OpenSSL provider based certificate trunk trunk
authorGraham Leggett <minfrin@apache.org>
Mon, 3 Aug 2026 22:48:57 +0000 (22:48 +0000)
committerGraham Leggett <minfrin@apache.org>
Mon, 3 Aug 2026 22:48:57 +0000 (22:48 +0000)
stores.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1936849 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/log-message-tags/next-number
docs/manual/mod/mod_ssl.xml
modules/ssl/mod_ssl.c
modules/ssl/mod_ssl_openssl.h
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_engine_pphrase.c
modules/ssl/ssl_private.h

diff --git a/CHANGES b/CHANGES
index 1b7ada499938ebe4ebb44158a8455cbef1f1b6e2..2344887d8c8a1431f612fb6e11ab564e1b1c9b31 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  * mod_ssl: Add support for OpenSSL provider based certificate
+    stores. [Graham Leggett]
+
   *) mod_proxy_beacon: Back-end reverse proxy servers can announce
      themselves and be auto-added to their front-end proxy balancer.
      [Jim Jagielski]
   *) mod_proxy_beacon: Back-end reverse proxy servers can announce
      themselves and be auto-added to their front-end proxy balancer.
      [Jim Jagielski]
index 63836ad378c198db4450c5ab7c65ffc798b1b5b0..3f7624fa412e0e391dfd21e4b25f3b95ec7e56ce 100644 (file)
@@ -1 +1 @@
-10600
+10618
index 5bfbf3d8e518d66436dd9e326ed7e3defffda7aa..94b9c8992acc85108013d24ec5432fa312b9a268 100644 (file)
@@ -1167,6 +1167,89 @@ effect.</p>
 </usage>
 </directivesynopsis>
 
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLCertificateURI</name>
+<description>Server certificate and key store</description>
+<syntax>SSLCertificateURI <var>uri</var></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+<compatibility>Available in httpd 2.5.1 and later, when linked with
+OpenSSL v3 or later.</compatibility>
+
+<usage>
+<p>
+This directive points to a certificate store containing certificates,
+intermediate certificates, and private keys, represented by a URI.
+</p>
+<p>
+If no scheme is specified, the path will default to a <var>file:</var>
+URI, pointing at PEM encoded data, or a PKCS12 file. Other schemes
+include, but are not limited to, <var>pkcs11:</var> for smartcards and
+HSMs, <var>cng:</var> for the Windows certificate store, and
+<var>handle:</var> for TPMs. On Windows, where a file path is also a
+valid URI, the <var>file:</var> scheme must be used.
+</p>
+<p>
+The directive can be specified multiple times with tightly scoped
+URIs to target specific certificates and keys, or could be specified
+with a general URI like <var>pkcs11:</var> that considers all possible
+certificates and keys. Certificates, intermediate certificates, and keys
+can be defined in any order.
+</p>
+<p>Certificates and keys are processed as follows.
+</p>
+<ul>
+<li>Leaf certificates that do not have the purpose <var>Server Authentication</var>
+are skipped.</li>
+<li>Remaining leaf certificates are checked whether the
+<directive module="core">ServerName</directive> and all
+<directive module="core">ServerAlias</directive> directives match the
+hostname or IP address of the certificate, and if no match is found they
+are skipped.</li>
+<li>Intermediate certificates are considered for building certificate
+chains on a best effort basis.</li>
+<li>Keys are matched up with leaf certificates, any certificate
+without a private key is skipped.</li>
+<li>Leaf certificates with private keys are sorted oldest to newest and
+passed on for configuration.</li>
+<li>The most recently issued certificate and key pair for each algorithm
+type (RSA, ECDSA, etc) will be used for each virtual host.</li>
+<li>The server will report back to you how many certificates of each type
+were found to help you if no certificates match.</li>
+</ul>
+
+<p>If the private key is encrypted, the pass phrase dialog is forced
+at startup time.</p>
+
+<example><title>Example</title>
+<highlight language="config">
+# Example using a PEM-encoded file.
+SSLCertificateURI "/usr/local/apache2/conf/ssl.crt/server.crt"
+# Example using a PKCS12 file.
+SSLCertificateURI "/usr/local/apache2/conf/ssl.crt/server.p12"
+# Example use of a certificate and private key from a PKCS#11 token:
+SSLCertificateURI "pkcs11:token=My%20Token%20Name;id=45"
+</highlight>
+</example>
+
+<p>These URIs are read at server startup, while the server is still running
+as <code>root</code> (before privilege dropping), so it may be owned by
+and readable only by <code>root</code>. The URI is not re-read during
+normal operation; a server restart is required for changes to take
+effect.</p>
+
+<note type="warning"><title>Using SSLCertificateFile and SSLCertificateURI
+together</title>
+<p>
+You can use both SSLCertificateFile and SSLCertificateURI together, however
+there is no overlap between the mechanisms. A certificate defined by
+SSLCertificateFile will not be matched with a key from SSLCertificateURI.
+</p>
+</note>
+
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLCACertificatePath</name>
 <description>Directory of PEM-encoded CA Certificates for
 <directivesynopsis>
 <name>SSLCACertificatePath</name>
 <description>Directory of PEM-encoded CA Certificates for
@@ -1232,6 +1315,42 @@ effect.</p>
 </usage>
 </directivesynopsis>
 
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLCACertificateURI</name>
+<description>Server CA certificate store for Client Authentication</description>
+<syntax>SSLCACertificateURI <var>uri</var></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+<override>AuthConfig</override>
+<compatibility>Available in httpd 2.5.1 and later, when linked with
+OpenSSL v3 or later.</compatibility>
+
+<usage>
+<p>
+This directive sets the <em>all-in-one</em> URI where you can assemble the
+Certificates of Certification Authorities (CA) whose <em>clients</em> you deal
+with. These are used for Client Authentication. This can be used alternatively
+and/or additionally to <directive module="mod_ssl">SSLCACertificateFile</directive>
+or <directive module="mod_ssl">SSLCACertificatePath</directive>.</p>
+<example><title>Example</title>
+<highlight language="config">
+# trust certs in a PEM encoded certificate bundle
+SSLCACertificateURI "/usr/local/apache2/conf/ssl.crt/ca-bundle-client.crt"
+# trust all certs in a typical Linux machine
+SSLCACertificateURI "pkcs11:token=System%20Trust"
+# trust all certs in the Windows trust store
+SSLCACertificateURI "org.openssl.winstore:"
+</highlight>
+</example>
+
+<p>This URI is read at server startup, while the server is still running
+as <code>root</code> (before privilege dropping), so it may be owned by
+and readable only by <code>root</code>. The URI is not re-read during
+normal operation; a server restart is required for changes to take
+effect.</p>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLCADNRequestFile</name>
 <description>File of concatenated PEM-encoded CA Certificates
 <directivesynopsis>
 <name>SSLCADNRequestFile</name>
 <description>File of concatenated PEM-encoded CA Certificates
@@ -1384,6 +1503,36 @@ effect.</p>
 </usage>
 </directivesynopsis>
 
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLCARevocationURI</name>
+<description>Server CA certificate revocation list store for Client Authentication</description>
+<syntax>SSLCARevocationURI <var>uri</var></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+
+<usage>
+<p>
+This directive sets the <em>all-in-one</em> file where you can
+assemble the Certificate Revocation Lists (CRL) of Certification
+Authorities (CA) whose <em>clients</em> you deal with. These are used
+for Client Authentication. This can be used alternatively and/or
+additionally to <directive
+module="mod_ssl">SSLCARevocationFile</directive> and <directive
+module="mod_ssl">SSLCARevocationPath</directive>.</p>
+<example><title>Example</title>
+<highlight language="config">
+SSLCARevocationURI "/usr/local/apache2/conf/ssl.crl/ca-bundle-client.crl"
+</highlight>
+</example>
+
+<p>This URI is read at server startup, while the server is still running
+as <code>root</code> (before privilege dropping), so it may be owned by
+and readable only by <code>root</code>. The URI is not re-read during
+normal operation; a server restart is required for changes to take
+effect.</p>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLCARevocationCheck</name>
 <description>Enable CRL-based revocation checking</description>
 <directivesynopsis>
 <name>SSLCARevocationCheck</name>
 <description>Enable CRL-based revocation checking</description>
@@ -2162,6 +2311,102 @@ SSLProxyMachineCertificateChainFile "/usr/local/apache2/conf/ssl.crt/proxyCA.pem
 </usage>
 </directivesynopsis>
 
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLProxyMachineCertificateURI</name>
+<description>Proxy certificate and key stores</description>
+<syntax>SSLProxyMachineCertificateURI <var>uri</var></syntax>
+<contextlist><context>server config</context> <context>virtual host</context>
+<context>proxy section</context></contextlist>
+<compatibility>Available in httpd 2.5.1 and later, when linked with
+OpenSSL v3 or later.</compatibility>
+
+<usage>
+<p>
+This directive points to a certificate store containing certificates,
+intermediate certificates, and private keys, represented by a URI,
+to be used when authenticating to another proxy server.
+</p>
+<p>
+If no scheme is specified, the path will default to a <var>file:</var>
+URI, pointing at PEM encoded data, or a PKCS12 file. Other schemes
+include, but are not limited to, <var>pkcs11:</var> for smartcards and
+HSMs, <var>cng:</var> for the Windows certificate store, and
+<var>handle:</var> for TPMs. On Windows, where a file path is also a
+valid URI, the <var>file:</var> scheme must be used.
+</p>
+<p>
+The directive can be specified multiple times with tightly scoped
+URIs to target specific certificates and keys, or could be specified
+with a general URI like <var>pkcs11:</var> that considers all possible
+certificates and keys. Certificates, intermediate certificates, and keys
+can be defined in any order.
+</p>
+<p>Proxy certificates and keys are processed as follows.
+</p>
+<ul>
+<li>Leaf certificates that do not have the purpose <var>Client Authentication</var>
+are skipped.</li>
+<li>Intermediate certificates are considered for building certificate
+chains on a best effort basis.</li>
+<li>Keys are matched up with leaf certificates, any certificate
+without a private key is skipped.</li>
+<li>Leaf certificates with private keys are sorted newest to oldest and
+are considered during each SSL handshake with a proxy.</li>
+<li>The proxy will report back to you how many certificates of each type
+were found to help you if no certificates match.</li>
+</ul>
+
+<p>If the private key is encrypted, the pass phrase dialog is forced
+at startup time.</p>
+
+<example><title>Example</title>
+<highlight language="config">
+# Example using a PEM-encoded file.
+SSLProxyMachineCertificateURI "/usr/local/apache2/conf/ssl.crt/proxy.pem"
+# Example using a PKCS12 file.
+SSLProxyMachineCertificateURI "/usr/local/apache2/conf/ssl.crt/proxy.p12"
+# Example use of a certificate and private key from a PKCS#11 token:
+SSLProxyMachineCertificateURI "pkcs11:token=My%20Token%20Name;id=45"
+</highlight>
+</example>
+
+<p>These URIs are read at server startup, while the server is still running
+as <code>root</code> (before privilege dropping), so it may be owned by
+and readable only by <code>root</code>. The URI is not re-read during
+normal operation; a server restart is required for changes to take
+effect.</p>
+
+<p>When challenged to provide a client certificate by a remote server,
+the server should provide a list of <em>acceptable certificate
+authority names</em> in the challenge.  If such a list is <em>not</em>
+provided, <module>mod_ssl</module> will use the most recently
+issued client certificate and key.  If a list of CA names
+<em>is</em> provided, <module>mod_ssl</module> will iterate through
+that list, and attempt to find a configured client certificate which
+was issued either directly by that CA, or indirectly via any number of
+intermediate CA certificates.
+</p>
+
+<p>If the list of CA names <em>is</em> provided by the remote server,
+and <em>no</em> matching client certificate can be found, no client
+certificate will be provided by <module>mod_ssl</module>, which will
+likely fail the SSL/TLS handshake (depending on the remote server
+configuration).</p>
+
+<note type="warning"><title>Using SSLProxyMachineCertificateFile and
+SSLProxyMachineCertificateURI together</title>
+<p>
+You can use both SSLProxyMachineCertificateFile and
+SSLProxyMachineCertificateURI together, however there is
+no overlap between the mechanisms. A certificate defined by
+SSLProxyMachineCertificateFile will not be matched with a
+key from SSLProxyMachineCertificateURI.
+</p>
+</note>
+
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLProxyVerify</name>
 <description>Type of remote server Certificate verification</description>
 <directivesynopsis>
 <name>SSLProxyVerify</name>
 <description>Type of remote server Certificate verification</description>
@@ -2469,6 +2714,31 @@ SSLProxyCACertificateFile "/usr/local/apache2/conf/ssl.crt/ca-bundle-remote-serv
 </usage>
 </directivesynopsis>
 
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLProxyCACertificateURI</name>
+<description>Proxy CA certificate store for Remote Server Auth</description>
+<syntax>SSLProxyCACertificateURI <var>uri</var></syntax>
+<contextlist><context>server config</context> <context>virtual host</context>
+<context>proxy section</context></contextlist>
+<compatibility>Available in httpd 2.5.1 and later, when linked with
+OpenSSL v3 or later.</compatibility>
+
+<usage>
+<p>
+This directive sets the <em>all-in-one</em> URI where you can assemble the
+Certificates of Certification Authorities (CA) whose <em>remote servers</em> you deal
+with. These are used for Remote Server Authentication. This can be used alternatively
+and/or additionally to
+<directive module="mod_ssl">SSLProxyCACertificateFile</directive> and
+<directive module="mod_ssl">SSLProxyCACertificatePath</directive>.</p>
+<example><title>Example</title>
+<highlight language="config">
+SSLProxyCACertificateURI "/usr/local/apache2/conf/ssl.crt/ca-bundle-remote-server.crt"
+</highlight>
+</example>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLProxyCARevocationPath</name>
 <description>Directory of PEM-encoded CA CRLs for
 <directivesynopsis>
 <name>SSLProxyCARevocationPath</name>
 <description>Directory of PEM-encoded CA CRLs for
@@ -2523,6 +2793,32 @@ SSLProxyCARevocationFile "/usr/local/apache2/conf/ssl.crl/ca-bundle-remote-serve
 </usage>
 </directivesynopsis>
 
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLProxyCARevocationURI</name>
+<description>Proxy CA certificate revocation list store for Remote Server Auth</description>
+<syntax>SSLProxyCARevocationURI <var>uri</var></syntax>
+<contextlist><context>server config</context> <context>virtual host</context>
+<context>proxy section</context></contextlist>
+<compatibility>Available in httpd 2.5.1 and later, when linked with
+OpenSSL v3 or later.</compatibility>
+
+<usage>
+<p>
+This directive sets the <em>all-in-one</em> URI where you can
+assemble the Certificate Revocation Lists (CRL) of Certification
+Authorities (CA) whose <em>remote servers</em> you deal with. These are used
+for Remote Server Authentication.  This can be
+used alternatively and/or additionally to <directive
+module="mod_ssl">SSLProxyCARevocationFile</directive> and <directive
+module="mod_ssl">SSLProxyCARevocationPath</directive>.</p>
+<example><title>Example</title>
+<highlight language="config">
+SSLProxyCARevocationURI "/usr/local/apache2/conf/ssl.crl/ca-bundle-remote-server.crl"
+</highlight>
+</example>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLProxyCARevocationCheck</name>
 <description>Enable CRL-based revocation checking for Remote Server Auth</description>
 <directivesynopsis>
 <name>SSLProxyCARevocationCheck</name>
 <description>Enable CRL-based revocation checking for Remote Server Auth</description>
index 8f79d0a8bc077b24e933d23006a4ee5cc277bdb4..20d3db1a0d5890fc22b6c6521395e358fe16cd75 100644 (file)
@@ -110,6 +110,9 @@ static const command_rec ssl_config_cmds[] = {
     SSL_CMD_ALL(CipherSuite, TAKE12,
                 "Colon-delimited list of permitted SSL Ciphers, optional preceded "
                 "by protocol identifier ('XXX:...:XXX' - see manual)")
     SSL_CMD_ALL(CipherSuite, TAKE12,
                 "Colon-delimited list of permitted SSL Ciphers, optional preceded "
                 "by protocol identifier ('XXX:...:XXX' - see manual)")
+    SSL_CMD_SRV(CertificateURI, TAKE1,
+                "SSL Server Certificate/Key uri "
+                "('file:', 'pkcs11:' - URI of certificate or key)")
     SSL_CMD_SRV(CertificateFile, TAKE1,
                 "SSL Server Certificate file "
                 "('/path/to/file' - PEM or DER encoded)")
     SSL_CMD_SRV(CertificateFile, TAKE1,
                 "SSL Server Certificate file "
                 "('/path/to/file' - PEM or DER encoded)")
@@ -129,6 +132,9 @@ static const command_rec ssl_config_cmds[] = {
                 "TLS ECH Key Directory"
                 "('/path/to/dir' - directory with ECH key pairs)")
 #endif
                 "TLS ECH Key Directory"
                 "('/path/to/dir' - directory with ECH key pairs)")
 #endif
+    SSL_CMD_SRV(CACertificateURI, TAKE1,
+                "SSL CA Certificate uri "
+                "('file:', 'pkcs11:' - URI of CA certificates)")
     SSL_CMD_ALL(CACertificatePath, TAKE1,
                 "SSL CA Certificate path "
                 "('/path/to/dir' - contains PEM encoded files)")
     SSL_CMD_ALL(CACertificatePath, TAKE1,
                 "SSL CA Certificate path "
                 "('/path/to/dir' - contains PEM encoded files)")
@@ -141,6 +147,9 @@ static const command_rec ssl_config_cmds[] = {
     SSL_CMD_SRV(CADNRequestFile, TAKE1,
                 "SSL CA Distinguished Name file "
                 "('/path/to/file' - PEM encoded to derive acceptable CA names to request)")
     SSL_CMD_SRV(CADNRequestFile, TAKE1,
                 "SSL CA Distinguished Name file "
                 "('/path/to/file' - PEM encoded to derive acceptable CA names to request)")
+    SSL_CMD_SRV(CARevocationURI, TAKE1,
+                "SSL CA Certificate Revocation List (CRL) uri "
+                "('file:', 'pkcs11:' - URI of CRLs)")
     SSL_CMD_SRV(CARevocationPath, TAKE1,
                 "SSL CA Certificate Revocation List (CRL) path "
                 "('/path/to/dir' - contains PEM encoded files)")
     SSL_CMD_SRV(CARevocationPath, TAKE1,
                 "SSL CA Certificate Revocation List (CRL) path "
                 "('/path/to/dir' - contains PEM encoded files)")
@@ -216,12 +225,18 @@ static const command_rec ssl_config_cmds[] = {
     SSL_CMD_PXY(ProxyVerifyDepth, TAKE1,
                "SSL Proxy: maximum certificate verification depth "
                "('N' - number of intermediate certificates)")
     SSL_CMD_PXY(ProxyVerifyDepth, TAKE1,
                "SSL Proxy: maximum certificate verification depth "
                "('N' - number of intermediate certificates)")
+    SSL_CMD_PXY(ProxyCACertificateURI, TAKE1,
+                "SSL Proxy: uri referring to server certificates "
+                "('file:', 'pkcs11:' - URI of CA certificates)")
     SSL_CMD_PXY(ProxyCACertificateFile, TAKE1,
                "SSL Proxy: file containing server certificates "
                "('/path/to/file' - PEM encoded certificates)")
     SSL_CMD_PXY(ProxyCACertificatePath, TAKE1,
                "SSL Proxy: directory containing server certificates "
                "('/path/to/dir' - contains PEM encoded certificates)")
     SSL_CMD_PXY(ProxyCACertificateFile, TAKE1,
                "SSL Proxy: file containing server certificates "
                "('/path/to/file' - PEM encoded certificates)")
     SSL_CMD_PXY(ProxyCACertificatePath, TAKE1,
                "SSL Proxy: directory containing server certificates "
                "('/path/to/dir' - contains PEM encoded certificates)")
+    SSL_CMD_PXY(ProxyCARevocationURI, TAKE1,
+                "SSL Proxy: CA Certificate Revocation List (CRL) uri "
+                "('file:', 'pkcs11:' - URI of CRLs)")
     SSL_CMD_PXY(ProxyCARevocationPath, TAKE1,
                 "SSL Proxy: CA Certificate Revocation List (CRL) path "
                 "('/path/to/dir' - contains PEM encoded files)")
     SSL_CMD_PXY(ProxyCARevocationPath, TAKE1,
                 "SSL Proxy: CA Certificate Revocation List (CRL) path "
                 "('/path/to/dir' - contains PEM encoded files)")
@@ -230,6 +245,9 @@ static const command_rec ssl_config_cmds[] = {
                 "('/path/to/file' - PEM encoded)")
     SSL_CMD_PXY(ProxyCARevocationCheck, RAW_ARGS,
                 "SSL Proxy: CA Certificate Revocation List (CRL) checking mode")
                 "('/path/to/file' - PEM encoded)")
     SSL_CMD_PXY(ProxyCARevocationCheck, RAW_ARGS,
                 "SSL Proxy: CA Certificate Revocation List (CRL) checking mode")
+    SSL_CMD_PXY(ProxyMachineCertificateURI, TAKE1,
+                "SSL Proxy: uri referring to client certificates "
+                "('file:', 'pkcs11:' - URI of certificate or key)")
     SSL_CMD_PXY(ProxyMachineCertificateFile, TAKE1,
                "SSL Proxy: file containing client certificates "
                "('/path/to/file' - PEM encoded certificates)")
     SSL_CMD_PXY(ProxyMachineCertificateFile, TAKE1,
                "SSL Proxy: file containing client certificates "
                "('/path/to/file' - PEM encoded certificates)")
index e251bd9b77a5a797458c894df7920e775cb47c37..fa345b4069e11accb4cc8245088361495e89dedc 100644 (file)
@@ -33,6 +33,8 @@
 #include <openssl/opensslv.h>
 #if OPENSSL_VERSION_NUMBER >= 0x30000000
 #include <openssl/macros.h> /* for OPENSSL_API_LEVEL */
 #include <openssl/opensslv.h>
 #if OPENSSL_VERSION_NUMBER >= 0x30000000
 #include <openssl/macros.h> /* for OPENSSL_API_LEVEL */
+#include <openssl/store.h> /* for OSSL_STORE_open_ex */
+#include <openssl/ui.h> /* for UI_null */
 #endif
 #if OPENSSL_VERSION_NUMBER >= 0x10001000
 /* must be defined before including ssl.h */
 #endif
 #if OPENSSL_VERSION_NUMBER >= 0x10001000
 /* must be defined before including ssl.h */
index a38dd943e4c9ee49754f841c0c6e3eeaa60f7c50..af09a12b56158b11c908cfea003636734542c81d 100644 (file)
@@ -113,6 +113,7 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p)
     mctx->sc                  = NULL; /* set during module init */
 
     mctx->ssl_ctx             = NULL; /* set during module init */
     mctx->sc                  = NULL; /* set during module init */
 
     mctx->ssl_ctx             = NULL; /* set during module init */
+    mctx->libctx              = NULL; /* set during module init */
 
     mctx->pks                 = NULL;
     mctx->pkp                 = NULL;
 
     mctx->pks                 = NULL;
     mctx->pkp                 = NULL;
@@ -131,8 +132,10 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p)
 
     mctx->crl_path            = NULL;
     mctx->crl_file            = NULL;
 
     mctx->crl_path            = NULL;
     mctx->crl_file            = NULL;
+    mctx->crl_uri             = NULL;
     mctx->crl_check_mask      = UNSET;
 
     mctx->crl_check_mask      = UNSET;
 
+    mctx->auth.ca_cert_uri   = NULL;
     mctx->auth.ca_cert_path   = NULL;
     mctx->auth.ca_cert_file   = NULL;
     mctx->auth.cipher_suite   = NULL;
     mctx->auth.ca_cert_path   = NULL;
     mctx->auth.ca_cert_file   = NULL;
     mctx->auth.cipher_suite   = NULL;
@@ -200,6 +203,7 @@ static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
 
     mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks));
 
 
     mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks));
 
+    mctx->pks->uris = apr_array_make(p, 3, sizeof(char *));
     mctx->pks->cert_files = apr_array_make(p, 3, sizeof(char *));
     mctx->pks->key_files  = apr_array_make(p, 3, sizeof(char *));
 
     mctx->pks->cert_files = apr_array_make(p, 3, sizeof(char *));
     mctx->pks->key_files  = apr_array_make(p, 3, sizeof(char *));
 
@@ -279,6 +283,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p,
     cfgMerge(crl_file, NULL);
     cfgMergeInt(crl_check_mask);
 
     cfgMerge(crl_file, NULL);
     cfgMergeInt(crl_check_mask);
 
+    cfgMergeString(auth.ca_cert_uri);
     cfgMergeString(auth.ca_cert_path);
     cfgMergeString(auth.ca_cert_file);
     cfgMergeString(auth.cipher_suite);
     cfgMergeString(auth.ca_cert_path);
     cfgMergeString(auth.ca_cert_file);
     cfgMergeString(auth.cipher_suite);
@@ -333,9 +338,11 @@ static void modssl_ctx_cfg_merge_server(apr_pool_t *p,
 {
     modssl_ctx_cfg_merge(p, base, add, mrg);
 
 {
     modssl_ctx_cfg_merge(p, base, add, mrg);
 
+    cfgMergeArray(pks->uris);
     cfgMergeArray(pks->cert_files);
     cfgMergeArray(pks->key_files);
 
     cfgMergeArray(pks->cert_files);
     cfgMergeArray(pks->key_files);
 
+    cfgMergeString(pks->ca_name_uri);
     cfgMergeString(pks->ca_name_path);
     cfgMergeString(pks->ca_name_file);
 
     cfgMergeString(pks->ca_name_path);
     cfgMergeString(pks->ca_name_file);
 
@@ -386,6 +393,7 @@ static void modssl_ctx_init_proxy(SSLDirConfigRec *dc,
 
     mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp));
 
 
     mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp));
 
+    mctx->pkp->uris = apr_array_make(p, 3, sizeof(char *));
     mctx->pkp->cert_file = NULL;
     mctx->pkp->cert_path = NULL;
     mctx->pkp->ca_cert_file = NULL;
     mctx->pkp->cert_file = NULL;
     mctx->pkp->cert_path = NULL;
     mctx->pkp->ca_cert_file = NULL;
@@ -429,6 +437,7 @@ static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p,
 {
     modssl_ctx_cfg_merge(p, base, add, mrg);
 
 {
     modssl_ctx_cfg_merge(p, base, add, mrg);
 
+    cfgMergeArray(pkp->uris);
     cfgMergeString(pkp->cert_file);
     cfgMergeString(pkp->cert_path);
     cfgMergeString(pkp->ca_cert_file);
     cfgMergeString(pkp->cert_file);
     cfgMergeString(pkp->cert_path);
     cfgMergeString(pkp->ca_cert_file);
@@ -962,6 +971,44 @@ static const char *ssl_cmd_check_file(cmd_parms *parms,
 
 }
 
 
 }
 
+static const char *ssl_cmd_check_uri(cmd_parms *parms,
+                                     const char *uri)
+{
+    OSSL_STORE_CTX *ctx;
+    unsigned long err;
+    int reason;
+
+    /* If only dumping the config, don't verify the paths */
+    if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) {
+        return NULL;
+    }
+
+    ctx = OSSL_STORE_open_ex(uri, NULL, NULL, UI_null(),
+                             NULL, NULL, NULL, NULL);
+
+    if (ctx) {
+        OSSL_STORE_close(ctx);
+        return NULL;
+    }
+
+    err = ERR_peek_last_error();
+    if (ERR_GET_LIB(err) == ERR_LIB_OSSL_STORE) {
+        reason = ERR_GET_REASON(err);
+
+        if (reason == OSSL_STORE_R_UNREGISTERED_SCHEME) {
+
+            return apr_pstrcat(parms->pool, parms->cmd->name,
+                               ": uri '", uri,
+                               "' is not recognised", NULL);
+
+        }
+    }
+
+    ERR_clear_error();
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLCompression(cmd_parms *cmd, void *dcfg, int flag)
 {
 #if !defined(OPENSSL_NO_COMP)
 const char *ssl_cmd_SSLCompression(cmd_parms *cmd, void *dcfg, int flag)
 {
 #if !defined(OPENSSL_NO_COMP)
@@ -1048,6 +1095,22 @@ static const char *ssl_cmd_check_dir(cmd_parms *parms,
 
 }
 
 
 }
 
+const char *ssl_cmd_SSLCertificateURI(cmd_parms *cmd,
+                                      void *dcfg,
+                                      const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    const char *err;
+
+    if ((err = ssl_cmd_check_uri(cmd, arg))) {
+        return err;
+    }
+
+    *(const char **)apr_array_push(sc->server->pks->uris) = arg;
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd,
                                        void *dcfg,
                                        const char *arg)
 const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd,
                                        void *dcfg,
                                        const char *arg)
@@ -1121,6 +1184,28 @@ const char *ssl_cmd_SSLSessionTicketKeyFile(cmd_parms *cmd,
 #define NO_PER_DIR_SSL_CA \
     "Your SSL library does not have support for per-directory CA"
 
 #define NO_PER_DIR_SSL_CA \
     "Your SSL library does not have support for per-directory CA"
 
+const char *ssl_cmd_SSLCACertificateURI(cmd_parms *cmd,
+                                        void *dcfg,
+                                        const char *arg)
+{
+    /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    const char *err;
+
+    if ((err = ssl_cmd_check_uri(cmd, arg))) {
+        return err;
+    }
+
+    if (cmd->path) {
+        return NO_PER_DIR_SSL_CA;
+    }
+
+    /* XXX: bring back per-dir */
+    sc->server->auth.ca_cert_uri = arg;
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLCACertificatePath(cmd_parms *cmd,
                                          void *dcfg,
                                          const char *arg)
 const char *ssl_cmd_SSLCACertificatePath(cmd_parms *cmd,
                                          void *dcfg,
                                          const char *arg)
@@ -1165,6 +1250,21 @@ const char *ssl_cmd_SSLCACertificateFile(cmd_parms *cmd,
     return NULL;
 }
 
     return NULL;
 }
 
+const char *ssl_cmd_SSLCADNRequestURI(cmd_parms *cmd, void *dcfg,
+                                      const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    const char *err;
+
+    if ((err = ssl_cmd_check_uri(cmd, arg))) {
+        return err;
+    }
+
+    sc->server->pks->ca_name_uri = arg;
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *cmd, void *dcfg,
                                        const char *arg)
 {
 const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *cmd, void *dcfg,
                                        const char *arg)
 {
@@ -1195,6 +1295,22 @@ const char *ssl_cmd_SSLCADNRequestFile(cmd_parms *cmd, void *dcfg,
     return NULL;
 }
 
     return NULL;
 }
 
+const char *ssl_cmd_SSLCARevocationURI(cmd_parms *cmd,
+                                       void *dcfg,
+                                       const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    const char *err;
+
+    if ((err = ssl_cmd_check_uri(cmd, arg))) {
+        return err;
+    }
+
+    sc->server->crl_uri = arg;
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLCARevocationPath(cmd_parms *cmd,
                                         void *dcfg,
                                         const char *arg)
 const char *ssl_cmd_SSLCARevocationPath(cmd_parms *cmd,
                                         void *dcfg,
                                         const char *arg)
@@ -1740,6 +1856,22 @@ const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd,
     return NULL;
 }
 
     return NULL;
 }
 
+const char *ssl_cmd_SSLProxyCACertificateURI(cmd_parms *cmd,
+                                             void *dcfg,
+                                             const char *arg)
+{
+    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
+    const char *err;
+
+    if ((err = ssl_cmd_check_uri(cmd, arg))) {
+        return err;
+    }
+
+    dc->proxy->auth.ca_cert_uri = arg;
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *cmd,
                                               void *dcfg,
                                               const char *arg)
 const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *cmd,
                                               void *dcfg,
                                               const char *arg)
@@ -1772,6 +1904,22 @@ const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *cmd,
     return NULL;
 }
 
     return NULL;
 }
 
+const char *ssl_cmd_SSLProxyCARevocationURI(cmd_parms *cmd,
+                                            void *dcfg,
+                                            const char *arg)
+{
+    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
+    const char *err;
+
+    if ((err = ssl_cmd_check_uri(cmd, arg))) {
+        return err;
+    }
+
+    dc->proxy->crl_uri = arg;
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *cmd,
                                              void *dcfg,
                                              const char *arg)
 const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *cmd,
                                              void *dcfg,
                                              const char *arg)
@@ -1813,6 +1961,22 @@ const char *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *cmd,
     return ssl_cmd_crlcheck_parse(cmd, arg, &dc->proxy->crl_check_mask);
 }
 
     return ssl_cmd_crlcheck_parse(cmd, arg, &dc->proxy->crl_check_mask);
 }
 
+const char *ssl_cmd_SSLProxyMachineCertificateURI(cmd_parms *cmd,
+                                                  void *dcfg,
+                                                  const char *arg)
+{
+    SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
+    const char *err;
+
+    if ((err = ssl_cmd_check_uri(cmd, arg))) {
+        return err;
+    }
+
+    *(const char **)apr_array_push(dc->proxy->pkp->uris) = arg;
+
+    return NULL;
+}
+
 const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd,
                                                    void *dcfg,
                                                    const char *arg)
 const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd,
                                                    void *dcfg,
                                                    const char *arg)
@@ -2293,7 +2457,7 @@ const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg,
 
 /* OCSP Responder File Function to read in value */
 const char *ssl_cmd_SSLOCSPResponderCertificateFile(cmd_parms *cmd, void *dcfg, 
 
 /* OCSP Responder File Function to read in value */
 const char *ssl_cmd_SSLOCSPResponderCertificateFile(cmd_parms *cmd, void *dcfg, 
-                                          const char *arg)
+                       const char *arg)
 {
     SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
     const char *err;
 {
     SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
     const char *err;
@@ -2332,6 +2496,14 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
                 modssl_pk_server_t *const pks = sc->server->pks;
                 int i;
 
                 modssl_pk_server_t *const pks = sc->server->pks;
                 int i;
 
+                for (i = 0; (i < pks->uris->nelts) &&
+                            APR_ARRAY_IDX(pks->uris, i, const char *);
+                     i++) {
+                    apr_file_printf(out, "  %s\n",
+                                    APR_ARRAY_IDX(pks->uris,
+                                                  i, const char *));
+                }
+
                 for (i = 0; (i < pks->cert_files->nelts) &&
                             APR_ARRAY_IDX(pks->cert_files, i, const char *);
                      i++) {
                 for (i = 0; (i < pks->cert_files->nelts) &&
                             APR_ARRAY_IDX(pks->cert_files, i, const char *);
                      i++) {
@@ -2356,6 +2528,10 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
             SSLSrvConfigRec *sc = mySrvConfig(s);
 
             if (sc && sc->server) {
             SSLSrvConfigRec *sc = mySrvConfig(s);
 
             if (sc && sc->server) {
+                if (sc->server->auth.ca_cert_uri) {
+                    apr_file_printf(out, "  %s\n",
+                                    sc->server->auth.ca_cert_uri);
+                }
                 if (sc->server->auth.ca_cert_path) {
                     apr_file_printf(out, "  %s\n",
                                     sc->server->auth.ca_cert_path);
                 if (sc->server->auth.ca_cert_path) {
                     apr_file_printf(out, "  %s\n",
                                     sc->server->auth.ca_cert_path);
@@ -2623,6 +2799,7 @@ static void modssl_auth_ctx_dump(modssl_auth_ctx_t *auth, apr_pool_t *p, int pro
 #endif
     DMP_VERIFY(proxy? "SSLProxyVerify" : "SSLVerifyClient", auth->verify_mode);
     DMP_LONG(  proxy? "SSLProxyVerify" : "SSLVerifyDepth", auth->verify_depth);
 #endif
     DMP_VERIFY(proxy? "SSLProxyVerify" : "SSLVerifyClient", auth->verify_mode);
     DMP_LONG(  proxy? "SSLProxyVerify" : "SSLVerifyDepth", auth->verify_depth);
+    DMP_STRING(proxy? "SSLProxyCACertificateURI" : "SSLCACertificateURI", auth->ca_cert_uri);
     DMP_STRING(proxy? "SSLProxyCACertificateFile" : "SSLCACertificateFile", auth->ca_cert_file);
     DMP_STRING(proxy? "SSLProxyCACertificatePath" : "SSLCACertificatePath", auth->ca_cert_path);
 }
     DMP_STRING(proxy? "SSLProxyCACertificateFile" : "SSLCACertificateFile", auth->ca_cert_file);
     DMP_STRING(proxy? "SSLProxyCACertificatePath" : "SSLCACertificatePath", auth->ca_cert_path);
 }
@@ -2640,14 +2817,17 @@ static void modssl_ctx_dump(modssl_ctx_t *ctx, apr_pool_t *p, int proxy,
 
     modssl_auth_ctx_dump(&ctx->auth, p, proxy, out, indent, psep);
 
 
     modssl_auth_ctx_dump(&ctx->auth, p, proxy, out, indent, psep);
 
+    DMP_STRING(proxy? "SSLProxyCARevocationURI" : "SSLCARevocationURI", ctx->crl_uri);
     DMP_STRING(proxy? "SSLProxyCARevocationFile" : "SSLCARevocationFile", ctx->crl_file);
     DMP_STRING(proxy? "SSLProxyCARevocationPath" : "SSLCARevocationPath", ctx->crl_path);
     DMP_CRLCHK(proxy? "SSLProxyCARevocationCheck" : "SSLCARevocationCheck", ctx->crl_check_mask);
     if (!proxy) {
         DMP_PHRASE("SSLPassPhraseDialog", ctx->pphrase_dialog_type, ctx->pphrase_dialog_path);
         if (ctx->pks) {
     DMP_STRING(proxy? "SSLProxyCARevocationFile" : "SSLCARevocationFile", ctx->crl_file);
     DMP_STRING(proxy? "SSLProxyCARevocationPath" : "SSLCARevocationPath", ctx->crl_path);
     DMP_CRLCHK(proxy? "SSLProxyCARevocationCheck" : "SSLCARevocationCheck", ctx->crl_check_mask);
     if (!proxy) {
         DMP_PHRASE("SSLPassPhraseDialog", ctx->pphrase_dialog_type, ctx->pphrase_dialog_path);
         if (ctx->pks) {
+            DMP_STRING("SSLCADNRequestURI", ctx->pks->ca_name_uri);
             DMP_STRING("SSLCADNRequestFile", ctx->pks->ca_name_file);
             DMP_STRING("SSLCADNRequestPath", ctx->pks->ca_name_path);
             DMP_STRING("SSLCADNRequestFile", ctx->pks->ca_name_file);
             DMP_STRING("SSLCADNRequestPath", ctx->pks->ca_name_path);
+            DMP_STRARR("SSLCertificateURI", ctx->pks->uris);
             DMP_STRARR("SSLCertificateFile", ctx->pks->cert_files);
             DMP_STRARR("SSLCertificateKeyFile", ctx->pks->key_files);
         }
             DMP_STRARR("SSLCertificateFile", ctx->pks->cert_files);
             DMP_STRARR("SSLCertificateKeyFile", ctx->pks->key_files);
         }
@@ -2698,6 +2878,7 @@ static void modssl_ctx_dump(modssl_ctx_t *ctx, apr_pool_t *p, int proxy,
     }
     else { /* proxy */
         if (ctx->pkp) {
     }
     else { /* proxy */
         if (ctx->pkp) {
+            DMP_STRARR("SSLProxyMachineCertificateURI", ctx->pkp->uris);
             DMP_STRING("SSLProxyMachineCertificateFile", ctx->pkp->cert_file);
             DMP_STRING("SSLProxyMachineCertificatePath", ctx->pkp->cert_path);
             DMP_STRING("SSLProxyMachineCertificateChainFile", ctx->pkp->ca_cert_file);
             DMP_STRING("SSLProxyMachineCertificateFile", ctx->pkp->cert_file);
             DMP_STRING("SSLProxyMachineCertificatePath", ctx->pkp->cert_path);
             DMP_STRING("SSLProxyMachineCertificateChainFile", ctx->pkp->ca_cert_file);
index a557e940dd4b87955cd784c4c2630946c250b3fa..9a03bc45cf32187e2d807a524032dca065e3f044 100644 (file)
@@ -334,6 +334,7 @@ static void hash_sni_policy_pk(apr_pool_t *ptemp, apr_md5_ctx_t *hash, modssl_ct
     md5_ifstr_update(hash, "ciphers:", ctx->auth.cipher_suite);
     md5_ifstr_update(hash, "tls13_ciphers:", ctx->auth.tls13_ciphers);
 
     md5_ifstr_update(hash, "ciphers:", ctx->auth.cipher_suite);
     md5_ifstr_update(hash, "tls13_ciphers:", ctx->auth.tls13_ciphers);
 
+    md5_strarray_hash(ptemp, hash, "uris:", ctx->pks->uris);
     md5_strarray_hash(ptemp, hash, "cert_files:", ctx->pks->cert_files);
     md5_strarray_hash(ptemp, hash, "key_files:", ctx->pks->key_files);
 }
     md5_strarray_hash(ptemp, hash, "cert_files:", ctx->pks->cert_files);
     md5_strarray_hash(ptemp, hash, "key_files:", ctx->pks->key_files);
 }
@@ -346,10 +347,13 @@ static void hash_sni_policy_auth(apr_md5_ctx_t *hash, modssl_ctx_t *ctx)
     md5_fmt_update(hash, "verify_depth:%d", a->verify_depth);
     md5_fmt_update(hash, "verify_mode:%d", a->verify_mode);
 
     md5_fmt_update(hash, "verify_depth:%d", a->verify_depth);
     md5_fmt_update(hash, "verify_mode:%d", a->verify_mode);
 
+    md5_ifstr_update(hash, "ca_name_uri:", pks->ca_name_uri);
     md5_ifstr_update(hash, "ca_name_path:", pks->ca_name_path);
     md5_ifstr_update(hash, "ca_name_file:", pks->ca_name_file);
     md5_ifstr_update(hash, "ca_name_path:", pks->ca_name_path);
     md5_ifstr_update(hash, "ca_name_file:", pks->ca_name_file);
+    md5_ifstr_update(hash, "ca_cert_uri:", a->ca_cert_uri);
     md5_ifstr_update(hash, "ca_cert_path:", a->ca_cert_path);
     md5_ifstr_update(hash, "ca_cert_file:", a->ca_cert_file);
     md5_ifstr_update(hash, "ca_cert_path:", a->ca_cert_path);
     md5_ifstr_update(hash, "ca_cert_file:", a->ca_cert_file);
+    md5_ifstr_update(hash, "crl_uri:", ctx->crl_uri);
     md5_ifstr_update(hash, "crl_path:", ctx->crl_path);
     md5_ifstr_update(hash, "crl_file:", ctx->crl_file);
     md5_fmt_update(hash, "crl_check_mask:%d", ctx->crl_check_mask);
     md5_ifstr_update(hash, "crl_path:", ctx->crl_path);
     md5_ifstr_update(hash, "crl_file:", ctx->crl_file);
     md5_fmt_update(hash, "crl_check_mask:%d", ctx->crl_check_mask);
@@ -848,7 +852,7 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s,
 #endif
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
 #endif
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
-       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L)
+    (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L)
 /*
  * Enable/disable SSLProtocol. If the mod_ssl enables protocol
  * which is disabled by default by OpenSSL, show a warning.
 /*
  * Enable/disable SSLProtocol. If the mod_ssl enables protocol
  * which is disabled by default by OpenSSL, show a warning.
@@ -887,7 +891,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s,
     int protocol = mctx->protocol;
     SSLSrvConfigRec *sc = mySrvConfig(s);
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L  && \
     int protocol = mctx->protocol;
     SSLSrvConfigRec *sc = mySrvConfig(s);
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L  && \
-       (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x20800000L)
+    (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x20800000L)
     /* default is highest supported version, will be overridden below */
 #if SSL_HAVE_PROTOCOL_TLSV1_3 
     int prot = TLS1_3_VERSION;
     /* default is highest supported version, will be overridden below */
 #if SSL_HAVE_PROTOCOL_TLSV1_3 
     int prot = TLS1_3_VERSION;
@@ -978,7 +982,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s,
     SSL_CTX_set_options(ctx, SSL_OP_ALL);
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L  || \
     SSL_CTX_set_options(ctx, SSL_OP_ALL);
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L  || \
-       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L)
+    (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L)
     /* always disable SSLv2, as per RFC 6176 */
     SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
 
     /* always disable SSLv2, as per RFC 6176 */
     SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
 
@@ -1222,6 +1226,103 @@ int modssl_CTX_load_verify_locations(SSL_CTX *ctx,
     return 1;
 }
 
     return 1;
 }
 
+/*
+ * OpenSSL has a SSL_CTX_load_verify_store() function, but
+ * this function loads both leaf certs and CA certs.
+ *
+ * An end user reasonably wants to configure a URI pointing at
+ * CA certs and not have any surprises if the scope of the URI
+ * included leaf certificates.
+ *
+ * As a result we consider CA certs exclusively below.
+ */
+
+static APR_INLINE
+apr_status_t modssl_CTX_load_verify_store(server_rec *s,
+                                          apr_pool_t *ptemp,
+                                          const char *uri,
+                                          int depth,
+                                          modssl_ctx_t *mctx)
+{
+#if MODSSL_HAVE_OPENSSL_STORE
+    OSSL_STORE_CTX *sctx;
+    OSSL_STORE_INFO *info;
+
+    apr_status_t rv = APR_SUCCESS;
+
+    X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
+
+    ap_assert(store != NULL); /* safe to assume always non-NULL? */
+
+    if (!uri) {
+        return APR_SUCCESS;
+    }
+
+    if ((!(sctx = OSSL_STORE_open_ex(uri, mctx->libctx, NULL, NULL, NULL,
+                NULL, NULL, NULL)))) {
+        return APR_EGENERAL;
+    }
+
+    while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) {
+
+        if (!(info = OSSL_STORE_load(sctx))) {
+            continue;
+        }
+
+        switch(OSSL_STORE_INFO_get_type(info)) {
+        case OSSL_STORE_INFO_NAME: {
+
+            if (depth > 0) {
+                rv = modssl_CTX_load_verify_store(s, ptemp,
+                        OSSL_STORE_INFO_get0_NAME(info),
+                        depth - 1, mctx);
+                if (APR_SUCCESS != rv) {
+                    OSSL_STORE_close(sctx);
+                    return rv;
+                }
+            }
+
+            break;
+        }
+        case OSSL_STORE_INFO_CERT: {
+
+            X509 *cert;
+
+            if (!(cert = OSSL_STORE_INFO_get0_CERT(info))) {
+                return APR_EGENERAL;
+            }
+            else if (!X509_check_ca(cert)) {
+                /* ignore leaf certificates */
+                continue;
+            }
+            if (X509_STORE_add_cert(store, cert)) {
+
+                ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10617)
+                             "Host %s: Trusted certificate from URI: %s",
+                             mctx->sc->vhost_id,
+                             modssl_X509_NAME_to_string(ptemp,
+                                     X509_get_subject_name(cert), 0));
+
+            }
+
+            break;
+        }
+        }
+    }
+
+    OSSL_STORE_close(sctx);
+
+    return rv;
+#else
+    if (!uri) {
+        return APR_SUCCESS;
+    }
+
+    return APR_ENOTIMPL;
+#endif
+}
+
+
 static apr_status_t ssl_init_ctx_verify(server_rec *s,
                                         apr_pool_t *p,
                                         apr_pool_t *ptemp,
 static apr_status_t ssl_init_ctx_verify(server_rec *s,
                                         apr_pool_t *p,
                                         apr_pool_t *ptemp,
@@ -1258,10 +1359,24 @@ static apr_status_t ssl_init_ctx_verify(server_rec *s,
     /*
      * Configure Client Authentication details
      */
     /*
      * Configure Client Authentication details
      */
-    if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path) {
+
+    if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path ||
+            mctx->auth.ca_cert_uri) {
+
+        apr_status_t rv;
+
         ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
                      "Configuring client authentication");
 
         ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
                      "Configuring client authentication");
 
+        if ((rv = modssl_CTX_load_verify_store(s, ptemp,
+                mctx->auth.ca_cert_uri, 1, mctx)) != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(10600)
+                    "Unable to configure verify store "
+                    "for client authentication");
+            ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+            return ssl_die(s);
+        }
+
         if (!modssl_CTX_load_verify_locations(ctx, mctx->auth.ca_cert_file,
                                                    mctx->auth.ca_cert_path)) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01895)
         if (!modssl_CTX_load_verify_locations(ctx, mctx->auth.ca_cert_file,
                                                    mctx->auth.ca_cert_path)) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01895)
@@ -1271,22 +1386,32 @@ static apr_status_t ssl_init_ctx_verify(server_rec *s,
             return ssl_die(s);
         }
 
             return ssl_die(s);
         }
 
-        if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) {
+        if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path ||
+                mctx->pks->ca_name_uri)) {
             ca_list = ssl_init_FindCAList(s, ptemp,
             ca_list = ssl_init_FindCAList(s, ptemp,
-                                          mctx->pks->ca_name_file,
-                                          mctx->pks->ca_name_path);
-        } else
+                                mctx->pks->ca_name_file,
+                                mctx->pks->ca_name_path,
+                                mctx->pks->ca_name_uri,
+                                mctx);
+
+        } else {
             ca_list = ssl_init_FindCAList(s, ptemp,
             ca_list = ssl_init_FindCAList(s, ptemp,
-                                          mctx->auth.ca_cert_file,
-                                          mctx->auth.ca_cert_path);
+                                mctx->auth.ca_cert_file,
+                                mctx->auth.ca_cert_path,
+                                mctx->auth.ca_cert_uri,
+                                mctx);
+        }
+
         if (sk_X509_NAME_num(ca_list) <= 0) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01896)
                     "Unable to determine list of acceptable "
                     "CA certificates for client authentication");
         if (sk_X509_NAME_num(ca_list) <= 0) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01896)
                     "Unable to determine list of acceptable "
                     "CA certificates for client authentication");
+            ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
             return ssl_die(s);
         }
 
         SSL_CTX_set_client_CA_list(ctx, ca_list);
             return ssl_die(s);
         }
 
         SSL_CTX_set_client_CA_list(ctx, ca_list);
+
     }
 
     /*
     }
 
     /*
@@ -1354,17 +1479,113 @@ int modssl_X509_STORE_load_locations(X509_STORE *store,
                                      const char *path)
 {
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
                                      const char *path)
 {
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-    if (!X509_STORE_load_locations(store, file, path))
+    if (!X509_STORE_load_locations(store, file, path)) {
         return 0;
         return 0;
+    }
 #else
 #else
-    if (file && !X509_STORE_load_file(store, file))
+    if (file && !X509_STORE_load_file(store, file)) {
         return 0;
         return 0;
-    if (path && !X509_STORE_load_path(store, path))
+    }
+    if (path && !X509_STORE_load_path(store, path)) {
         return 0;
         return 0;
+    }
 #endif
     return 1;
 }
 
 #endif
     return 1;
 }
 
+/*
+ * OpenSSL has a X509_STORE_load_store() function, but this
+ * function has side effects - it loads both CRLs and trusted
+ * CA certificates.
+ *
+ * An end user reasonably wants to configure a URI pointing at
+ * CRLs and not have any surprises if the scope of the URI
+ * included trusted CA certificates for whatever reason.
+ *
+ * As a result we consider CRLs exclusively below.
+ */
+
+static APR_INLINE
+apr_status_t modssl_X509_STORE_load_crl(server_rec *s,
+                                        apr_pool_t *ptemp,
+                                        const char *uri,
+                                        int depth,
+                                        modssl_ctx_t *mctx)
+{
+#if MODSSL_HAVE_OPENSSL_STORE
+    OSSL_STORE_CTX *sctx;
+    OSSL_STORE_INFO *info;
+
+    apr_status_t rv = APR_SUCCESS;
+
+    X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
+
+    ap_assert(store != NULL); /* safe to assume always non-NULL? */
+
+    if (!uri) {
+        return APR_SUCCESS;
+    }
+
+    if ((!(sctx = OSSL_STORE_open_ex(uri, mctx->libctx, NULL, NULL, NULL,
+                NULL, NULL, NULL)))) {
+        return APR_EGENERAL;
+    }
+
+    while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) {
+
+        if (!(info = OSSL_STORE_load(sctx))) {
+            continue;
+        }
+
+        switch(OSSL_STORE_INFO_get_type(info)) {
+        case OSSL_STORE_INFO_NAME: {
+
+            if (depth > 0) {
+                rv = modssl_X509_STORE_load_crl(s, ptemp,
+                        OSSL_STORE_INFO_get0_NAME(info),
+                        depth - 1, mctx);
+                if (APR_SUCCESS != rv) {
+                    OSSL_STORE_close(sctx);
+                    return rv;
+                }
+            }
+
+            break;
+        }
+        case OSSL_STORE_INFO_CRL: {
+
+            X509_CRL *crl;
+
+            if (!(crl = OSSL_STORE_INFO_get0_CRL(info))) {
+                return APR_EGENERAL;
+            }
+            if (X509_STORE_add_crl(store, crl)) {
+
+                ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10601)
+                             "Host %s: Certificate revocation list from URI: %s",
+                             mctx->sc->vhost_id,
+                             modssl_X509_NAME_to_string(ptemp,
+                                     X509_CRL_get_issuer(crl), 0));
+
+            }
+
+            break;
+        }
+        }
+    }
+
+    OSSL_STORE_close(sctx);
+
+    return rv;
+#else
+    if (!uri) {
+        return APR_SUCCESS;
+    }
+
+    return APR_ENOTIMPL;
+#endif
+}
+
 static apr_status_t ssl_init_ctx_crl(server_rec *s,
                                      apr_pool_t *p,
                                      apr_pool_t *ptemp,
 static apr_status_t ssl_init_ctx_crl(server_rec *s,
                                      apr_pool_t *p,
                                      apr_pool_t *ptemp,
@@ -1374,6 +1595,9 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s,
     unsigned long crlflags = 0;
     char *cfgp = mctx->pkp ? "SSLProxy" : "SSL";
     int crl_check_mode;
     unsigned long crlflags = 0;
     char *cfgp = mctx->pkp ? "SSLProxy" : "SSL";
     int crl_check_mode;
+    apr_status_t rv;
+
+    ap_assert(store != NULL); /* safe to assume always non-NULL? */
 
     if (mctx->ocsp_mask == UNSET) {
         mctx->ocsp_mask = SSL_OCSPCHECK_NONE;
 
     if (mctx->ocsp_mask == UNSET) {
         mctx->ocsp_mask = SSL_OCSPCHECK_NONE;
@@ -1388,13 +1612,13 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s,
      * Configure Certificate Revocation List (CRL) Details
      */
 
      * Configure Certificate Revocation List (CRL) Details
      */
 
-    if (!(mctx->crl_file || mctx->crl_path)) {
+    if (!(mctx->crl_uri || mctx->crl_file || mctx->crl_path)) {
         if (crl_check_mode == SSL_CRLCHECK_LEAF ||
             crl_check_mode == SSL_CRLCHECK_CHAIN) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01899)
                          "Host %s: CRL checking has been enabled, but "
         if (crl_check_mode == SSL_CRLCHECK_LEAF ||
             crl_check_mode == SSL_CRLCHECK_CHAIN) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01899)
                          "Host %s: CRL checking has been enabled, but "
-                         "neither %sCARevocationFile nor %sCARevocationPath "
-                         "is configured", mctx->sc->vhost_id, cfgp, cfgp);
+                         "neither %sCARevocationURI, %sCARevocationFile nor %sCARevocationPath "
+                         "is configured", mctx->sc->vhost_id, cfgp, cfgp, cfgp);
             return ssl_die(s);
         }
         return APR_SUCCESS;
             return ssl_die(s);
         }
         return APR_SUCCESS;
@@ -1403,8 +1627,16 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s,
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01900)
                  "Configuring certificate revocation facility");
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01900)
                  "Configuring certificate revocation facility");
 
-    if (!store || !modssl_X509_STORE_load_locations(store, mctx->crl_file,
-                                                           mctx->crl_path)) {
+    if ((rv = modssl_X509_STORE_load_crl(s, ptemp, mctx->crl_uri, 1, mctx)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(10602)
+                     "Host %s: unable to configure X.509 CRL uri "
+                     "for certificate revocation", mctx->sc->vhost_id);
+        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+        return ssl_die(s);
+    }
+
+    if (!modssl_X509_STORE_load_locations(store,
+            mctx->crl_file, mctx->crl_path)) {
         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01901)
                      "Host %s: unable to configure X.509 CRL storage "
                      "for certificate revocation", mctx->sc->vhost_id);
         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01901)
                      "Host %s: unable to configure X.509 CRL storage "
                      "for certificate revocation", mctx->sc->vhost_id);
@@ -1636,6 +1868,386 @@ static int ssl_no_passwd_prompt_cb(char *buf, int size, int rwflag,
    return 0;
 }
 
    return 0;
 }
 
+
+#ifndef DEFINE_STACK_OF_EVP_PKEY
+DEFINE_STACK_OF(EVP_PKEY)
+#endif
+
+#if MODSSL_HAVE_OPENSSL_STORE
+
+static apr_status_t ssl_init_uri_cleanup(void *data)
+{
+    modssl_ctx_uri_t *uctx = (modssl_ctx_uri_t *)data;
+
+    sk_X509_pop_free(uctx->cert_list, X509_free);
+    sk_EVP_PKEY_pop_free(uctx->key_list, EVP_PKEY_free);
+    sk_X509_pop_free(uctx->ca_list, X509_free);
+
+    return APR_SUCCESS;
+}
+
+/*
+ * Sort certificates oldest to newest (last one wins).
+ */
+static int compare_certs_asc(const X509 *const *a, const X509 *const *b)
+{
+    const ASN1_TIME *time_a = X509_get0_notBefore(*a);
+    const ASN1_TIME *time_b = X509_get0_notBefore(*b);
+
+    /* ASN1_TIME_compare returns:
+     * -1 if time_a is earlier than time_b
+     *  0 if they are identical
+     *  1 if time_a is later than time_b
+     */
+    return ASN1_TIME_compare(time_a, time_b);
+}
+
+static int cert_match(apr_pool_t *p, X509 *cert, char *id)
+{
+    if (id[0] == '[') {
+        const char *end = strchr(id, ']');
+        if (end && X509_check_ip_asc(cert,
+                apr_pstrndup(p, id + 1, end - id - 1), 0) == 1) {
+            return 1;
+        }
+        return 0;
+    }
+    if (X509_check_ip_asc(cert, id, 0) == 1) {
+        return 1;
+    }
+    if (X509_check_host(cert, id, 0, 0, NULL) == 1) {
+        return 1;
+    }
+    return 0;
+}
+
+static apr_status_t ssl_init_uri(server_rec *s,
+                                 apr_pool_t *ptemp,
+                                 const char *uri,
+                                 int depth,
+                                 modssl_ctx_uri_t *uctx)
+{
+    OSSL_STORE_CTX *sctx;
+    OSSL_STORE_INFO *info;
+
+    apr_status_t rv = APR_SUCCESS;
+
+    if (!uri) {
+        return rv;
+    }
+
+    if ((!(sctx = OSSL_STORE_open_ex(uri, uctx->mctx->libctx, NULL,
+                                     modssl_get_passphrase_ui(ptemp),
+                                     modssl_get_passphrase_cb(s, ptemp,
+                                             uctx->mctx->sc->vhost_id, uri),
+                                     NULL, NULL, NULL)))) {
+        return APR_EGENERAL;
+    }
+
+    while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) {
+
+        if (!(info = OSSL_STORE_load(sctx))) {
+            continue;
+        }
+
+        switch(OSSL_STORE_INFO_get_type(info)) {
+        case OSSL_STORE_INFO_NAME: {
+
+            if (depth > 0) {
+                rv = ssl_init_uri(s, ptemp,
+                        OSSL_STORE_INFO_get0_NAME(info),
+                        depth - 1, uctx);
+                if (APR_SUCCESS != rv) {
+                    OSSL_STORE_close(sctx);
+                    return rv;
+                }
+            }
+
+            break;
+        }
+        case OSSL_STORE_INFO_CERT: {
+
+            X509 *cert;
+
+            if (!(cert = OSSL_STORE_INFO_get1_CERT(info))) {
+                return APR_EGENERAL;
+            }
+            else if (X509_check_ca(cert)) {
+
+                if (X509_self_signed(cert, 1)) {
+
+                    uctx->num_ca_certs++;
+
+                    /* ignore root certificates */
+                    X509_free(cert);
+                    continue;
+                }
+
+                if (sk_X509_push(uctx->ca_list, cert) <= 0) {
+                    X509_free(cert);
+                    OSSL_STORE_close(sctx);
+                    return APR_EGENERAL;
+                }
+
+                uctx->num_intermediate_certs++;
+
+            }
+            else {
+
+                uctx->num_leaf_certs++;
+
+                if (!X509_check_purpose(cert, X509_PURPOSE_SSL_SERVER, 0)) {
+                    /* ignore non server certs */
+                    X509_free(cert);
+                    continue;
+                }
+
+                /* check for a match on server name */
+                if (s->server_hostname) {
+                    if (!cert_match(ptemp, cert, s->server_hostname)) {
+                        X509_free(cert);
+                        continue;
+                    }
+                }
+
+                /* check for a match on all server aliases */
+                if (s->names && !apr_is_empty_array(s->names)) {
+                    char **aliases = (char **)s->names->elts;
+                    int i;
+                    for (i = 0; i < s->names->nelts; i++) {
+                        if (!cert_match(ptemp, cert, aliases[i])) {
+                            X509_free(cert);
+                            continue;
+                        }
+                    }
+                }
+
+                /* If we get here and a server name or server alias was
+                 * not specified, we use the most recently issued leaf
+                 * certificate in scope and assume the admin knows what
+                 * they are doing.
+                 */
+
+                if (sk_X509_push(uctx->cert_list, cert) <= 0) {
+                    X509_free(cert);
+                    OSSL_STORE_close(sctx);
+                    return APR_EGENERAL;
+                }
+
+                uctx->num_server_certs++;
+
+            }
+
+            uctx->num_certs++;
+
+            break;
+        }
+        case OSSL_STORE_INFO_PKEY: {
+
+            EVP_PKEY *key;
+
+            if (!(key = OSSL_STORE_INFO_get1_PKEY(info))) {
+                OSSL_STORE_close(sctx);
+                return APR_EGENERAL;
+            }
+            if (sk_EVP_PKEY_push(uctx->key_list, key) <= 0) {
+                EVP_PKEY_free(key);
+                OSSL_STORE_close(sctx);
+                return APR_EGENERAL;
+            }
+
+            uctx->num_keys++;
+
+            break;
+        }
+        }
+    }
+
+    OSSL_STORE_close(sctx);
+
+    return rv;
+}
+
+
+/*
+ * Load certs from all URIs.
+ *
+ * The end user might point their URI at a single set of
+ * PEM encoded certs using the file: scheme, or might point
+ * the URI at pkcs11: or the whole MacOS keychain and
+ * expect us to figure it out for them. Lets help as much
+ * as possible.
+ *
+ * - Load all certs across all uris.
+ * - Consider intermediate certs, add them to the store
+ * - Consider leaf certs that match the ServerName and
+ *   ServerAliases and drop if no match.
+ * - Sort certs by start date, oldest to newest
+ * - Load all keys across all uris.
+ * - Consider certs with a private key, drop the rest.
+ * - Pass each cert and key, in order, using
+ *   SSL_CTX_use_certificate and SSL_CTX_use_PrivateKey.
+ * - End result, the most recent cert for each type (RSA,
+ *   ECDSA, etc) wins.
+ *
+ */
+
+static apr_status_t ssl_init_server_uris(server_rec *s,
+                                          apr_pool_t *p,
+                                          apr_pool_t *ptemp,
+                                          modssl_ctx_t *mctx,
+                                          apr_array_header_t *pphrases)
+{
+    const char *uri;
+    int i, k;
+    int found = 0;
+    apr_status_t rv = APR_SUCCESS;
+
+    modssl_ctx_uri_t *uctx = apr_pcalloc(ptemp, sizeof(modssl_ctx_uri_t));
+
+    uctx->mctx = mctx;
+
+    uctx->cert_list = sk_X509_new_null();
+    uctx->key_list = sk_EVP_PKEY_new_null();
+    uctx->ca_list = sk_X509_new_null();
+
+    apr_pool_cleanup_register(ptemp, uctx,
+                              ssl_init_uri_cleanup,
+                              apr_pool_cleanup_null);
+
+    sk_X509_set_cmp_func(uctx->cert_list, compare_certs_asc);
+
+    /* no OpenSSL default prompts for any of the SSL_CTX_use_* calls, please */
+    SSL_CTX_set_default_passwd_cb(mctx->ssl_ctx, ssl_no_passwd_prompt_cb);
+
+    /* Iterate over the SSLCertificateURI array */
+    for (i = 0; (i < mctx->pks->uris->nelts) &&
+                (uri = APR_ARRAY_IDX(mctx->pks->uris, i,
+                                          const char *));
+         i++) {
+
+        if (ssl_init_uri(s, ptemp, uri, 1, uctx) != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10603)
+                         "Host %s: Failed to open URI `%s'",
+                         mctx->sc->vhost_id, uri);
+            ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+            return APR_EGENERAL;
+        }
+
+    }
+
+    /* oldest to newest, last one wins */
+    sk_X509_sort(uctx->cert_list);
+
+    /* Match certs to keys */
+    for (i = sk_X509_num(uctx->cert_list) - 1; i >= 0; i--) {
+        X509 *cert = sk_X509_value(uctx->cert_list, i);
+
+        for (k = 0; k < sk_EVP_PKEY_num(uctx->key_list); k++) {
+            EVP_PKEY *pkey = sk_EVP_PKEY_value(uctx->key_list, k);
+
+            if (X509_check_private_key(cert, pkey) == 1) {
+
+                if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) {
+                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10604)
+                                 "Host %s: Failed to use certificate: %s",
+                                 mctx->sc->vhost_id,
+                                 modssl_X509_NAME_to_string(ptemp,
+                                     X509_get_subject_name(cert), 0));
+                    ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+                    return APR_EGENERAL;
+                }
+
+                if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) {
+                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10605)
+                                 "Host %s: Failed to use private key: %s",
+                                 mctx->sc->vhost_id,
+                                 modssl_X509_NAME_to_string(ptemp,
+                                     X509_get_subject_name(cert), 0));
+                    ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+                    return APR_EGENERAL;
+                }
+
+                ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10606)
+                             "Host %s: Server certificate from URI: %s",
+                             mctx->sc->vhost_id,
+                             modssl_X509_NAME_to_string(ptemp,
+                                     X509_get_subject_name(cert), 0));
+
+                found = 1;
+                break;
+            }
+
+        }
+    }
+
+    if (!found) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10607)
+                     "Host %s: No matching certificate/key pairs found among "
+                     "%d certs, %d CA certs, %d intermediate certs, "
+                     "%d leaf certs, %d server certs, %d keys.",
+                     mctx->sc->vhost_id,
+                     uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs,
+                     uctx->num_leaf_certs,
+                     uctx->num_server_certs, uctx->num_keys);
+        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+        return APR_EGENERAL;
+    }
+
+    /* Handle intermediates, must happen after cert handling */
+    for (i = sk_X509_num(uctx->ca_list) - 1; i >= 0; i--) {
+        X509 *cert = sk_X509_value(uctx->ca_list, i);
+        if (!SSL_CTX_add1_chain_cert(mctx->ssl_ctx, cert)) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10608)
+                         "Host %s: Failed to add intermediate certificate: %s",
+                         mctx->sc->vhost_id,
+                         modssl_X509_NAME_to_string(ptemp,
+                                 X509_get_subject_name(cert), 0));
+            ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+            return APR_EGENERAL;
+        }
+    }
+
+    /*
+     * Do our best to build as much of the chain as possible with
+     * the certs we were provided.
+     */
+
+    if (!SSL_CTX_build_cert_chain(mctx->ssl_ctx, SSL_BUILD_CHAIN_FLAG_NO_ROOT |
+            SSL_BUILD_CHAIN_FLAG_UNTRUSTED |
+            SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR |
+            SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR)) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10609)
+                    "Host %s: Could not build the certificate chain from "
+                    "%d certs, %d CA certs, %d intermediate certs, "
+                       "%d leaf certs, %d server certs, %d keys.",
+                    mctx->sc->vhost_id,
+                    uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs,
+                    uctx->num_leaf_certs,
+                    uctx->num_server_certs, uctx->num_keys);
+        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+        return APR_EGENERAL;
+    }
+
+    return rv;
+}
+#else
+static apr_status_t ssl_init_server_uris(server_rec *s,
+                                          apr_pool_t *p,
+                                          apr_pool_t *ptemp,
+                                          modssl_ctx_t *mctx,
+                                          apr_array_header_t *pphrases)
+{
+    const char *vhost_id = mctx->sc->vhost_id;
+
+    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10610)
+                "Host %s: Server certificate URIs are not supported on this platform.",
+                mctx->sc->vhost_id);
+
+    return APR_ENOTIMPL;
+}
+#endif
+
 /* SSL_CTX_use_PrivateKey_file() can fail either because the private
  * key was encrypted, or due to a mismatch between an already-loaded
  * cert and the key - a common misconfiguration - from calling
 /* SSL_CTX_use_PrivateKey_file() can fail either because the private
  * key was encrypted, or due to a mismatch between an already-loaded
  * cert and the key - a common misconfiguration - from calling
@@ -1896,106 +2508,395 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
         if (!SSL_CTX_set1_curves(mctx->ssl_ctx, &curve_nid, 1)) {
             curve_nid = 0;
         }
         if (!SSL_CTX_set1_curves(mctx->ssl_ctx, &curve_nid, 1)) {
             curve_nid = 0;
         }
-#endif
-        if (curve_nid) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541)
-                         "ECDH curve %s for %s specified in %s",
-                         OBJ_nid2sn(curve_nid), vhost_id, certfile);
+#endif
+        if (curve_nid) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541)
+                         "ECDH curve %s for %s specified in %s",
+                         OBJ_nid2sn(curve_nid), vhost_id, certfile);
+        }
+    }
+    /*
+     * ...otherwise, enable auto curve selection (OpenSSL 1.0.2)
+     * or configure NIST P-256 (required to enable ECDHE for earlier versions)
+     * ECDH is always enabled in 1.1.0 unless excluded from SSLCipherList
+     */
+#if MODSSL_USE_OPENSSL_PRE_1_1_API
+    if (!curve_nid) {
+#if defined(SSL_CTX_set_ecdh_auto)
+        SSL_CTX_set_ecdh_auto(mctx->ssl_ctx, 1);
+#else
+        EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+        if (eckey) {
+            SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey);
+            EC_KEY_free(eckey);
+        }
+#endif
+    }
+#endif
+    /* OpenSSL assures us that _free() is NULL-safe */
+    EC_GROUP_free(ecgroup);
+#endif
+
+    return APR_SUCCESS;
+}
+
+#ifdef HAVE_TLS_SESSION_TICKETS
+static apr_status_t ssl_init_ticket_key(server_rec *s,
+                                        apr_pool_t *p,
+                                        apr_pool_t *ptemp,
+                                        modssl_ctx_t *mctx)
+{
+    apr_status_t rv;
+    apr_file_t *fp;
+    apr_size_t len;
+    char buf[TLSEXT_TICKET_KEY_LEN];
+    char *path;
+    modssl_ticket_key_t *ticket_key = mctx->ticket_key;
+    int res;
+
+    if (!ticket_key->file_path) {
+        return APR_SUCCESS;
+    }
+
+    path = ap_server_root_relative(p, ticket_key->file_path);
+
+    rv = apr_file_open(&fp, path, APR_READ|APR_BINARY,
+                       APR_OS_DEFAULT, ptemp);
+
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02286)
+                     "Failed to open ticket key file %s: (%d) %pm",
+                     path, rv, &rv);
+        return ssl_die(s);
+    }
+
+    rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEY_LEN, &len);
+
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02287)
+                     "Failed to read %d bytes from %s: (%d) %pm",
+                     TLSEXT_TICKET_KEY_LEN, path, rv, &rv);
+        return ssl_die(s);
+    }
+
+    memcpy(ticket_key->key_name, buf, 16);
+    memcpy(ticket_key->aes_key, buf + 32, 16);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    memcpy(ticket_key->hmac_secret, buf + 16, 16);
+    res = SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx,
+                                           ssl_callback_SessionTicket);
+#else
+    ticket_key->mac_params[0] =
+        OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
+                                          apr_pmemdup(p, buf + 16, 16), 16);
+    ticket_key->mac_params[1] =
+        OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "sha256", 0);
+    ticket_key->mac_params[2] =
+        OSSL_PARAM_construct_end();
+    res = SSL_CTX_set_tlsext_ticket_key_evp_cb(mctx->ssl_ctx,
+                                               ssl_callback_SessionTicket);
+#endif
+    OPENSSL_cleanse(buf, sizeof(buf));
+    if (!res) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01913)
+                     "Unable to initialize TLS session ticket key callback "
+                     "(incompatible OpenSSL version?)");
+        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+        return ssl_die(s);
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02288)
+                 "TLS session ticket key for %s successfully loaded from %s",
+                 (mySrvConfig(s))->vhost_id, path);
+
+    return APR_SUCCESS;
+}
+#endif
+
+#if MODSSL_HAVE_OPENSSL_STORE
+
+/*
+ * Sort certificates newest to oldest (first one wins).
+ */
+static int compare_certs_desc(const X509 *const *a, const X509 *const *b)
+{
+    const ASN1_TIME *time_a = X509_get0_notBefore(*a);
+    const ASN1_TIME *time_b = X509_get0_notBefore(*b);
+
+    /* ASN1_TIME_compare returns:
+     * -1 if time_a is earlier than time_b
+     *  0 if they are identical
+     *  1 if time_a is later than time_b
+     */
+    return -ASN1_TIME_compare(time_a, time_b);
+}
+
+static apr_status_t ssl_init_proxy_uri(server_rec *s,
+                                       apr_pool_t *ptemp,
+                                       const char *uri,
+                                       int depth,
+                                       modssl_ctx_uri_t *uctx)
+{
+    OSSL_STORE_CTX *sctx;
+    OSSL_STORE_INFO *info;
+
+    apr_status_t rv = APR_SUCCESS;
+
+    if (!uri) {
+        return rv;
+    }
+
+    if ((!(sctx = OSSL_STORE_open_ex(uri, uctx->mctx->libctx, NULL,
+                                     modssl_get_passphrase_ui(ptemp),
+                                     modssl_get_passphrase_cb(s, ptemp,
+                                             uctx->mctx->sc->vhost_id, uri),
+                                     NULL, NULL, NULL)))) {
+        return APR_EGENERAL;
+    }
+
+    while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) {
+
+        if (!(info = OSSL_STORE_load(sctx))) {
+            continue;
+        }
+
+        switch(OSSL_STORE_INFO_get_type(info)) {
+        case OSSL_STORE_INFO_NAME: {
+
+            if (depth > 0) {
+                rv = ssl_init_uri(s, ptemp,
+                        OSSL_STORE_INFO_get0_NAME(info),
+                        depth - 1, uctx);
+                if (APR_SUCCESS != rv) {
+                    OSSL_STORE_close(sctx);
+                    return rv;
+                }
+            }
+
+            break;
+        }
+        case OSSL_STORE_INFO_CERT: {
+
+            X509 *cert;
+
+            if (!(cert = OSSL_STORE_INFO_get1_CERT(info))) {
+                OSSL_STORE_close(sctx);
+                return APR_EGENERAL;
+            }
+            else if (X509_check_ca(cert)) {
+
+                if (X509_self_signed(cert, 1)) {
+
+                    uctx->num_ca_certs++;
+
+                    /* ignore root certificates */
+                    X509_free(cert);
+                    break;
+                }
+
+                if (sk_X509_push(uctx->ca_list, cert) <= 0) {
+                    X509_free(cert);
+                    return APR_EGENERAL;
+                }
+
+                uctx->num_intermediate_certs++;
+
+            }
+            else {
+
+                uctx->num_leaf_certs++;
+
+                if (!X509_check_purpose(cert, X509_PURPOSE_SSL_CLIENT, 0)) {
+                    /* ignore non client certs */
+                    X509_free(cert);
+                    break;
+                }
+
+                if (sk_X509_push(uctx->cert_list, cert) <= 0) {
+                    X509_free(cert);
+                    OSSL_STORE_close(sctx);
+                    return APR_EGENERAL;
+                }
+
+                uctx->num_client_certs++;
+
+            }
+
+            uctx->num_certs++;
+
+            break;
+        }
+        case OSSL_STORE_INFO_PKEY: {
+
+            EVP_PKEY *key;
+
+            if (!(key = OSSL_STORE_INFO_get1_PKEY(info))) {
+                OSSL_STORE_close(sctx);
+                return APR_EGENERAL;
+            }
+            if (sk_EVP_PKEY_push(uctx->key_list, key) <= 0) {
+                EVP_PKEY_free(key);
+                OSSL_STORE_close(sctx);
+                return APR_EGENERAL;
+            }
+
+            uctx->num_keys++;
+
+            break;
         }
         }
-    }
-    /*
-     * ...otherwise, enable auto curve selection (OpenSSL 1.0.2)
-     * or configure NIST P-256 (required to enable ECDHE for earlier versions)
-     * ECDH is always enabled in 1.1.0 unless excluded from SSLCipherList
-     */
-#if MODSSL_USE_OPENSSL_PRE_1_1_API
-    if (!curve_nid) {
-#if defined(SSL_CTX_set_ecdh_auto)
-        SSL_CTX_set_ecdh_auto(mctx->ssl_ctx, 1);
-#else
-        EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
-        if (eckey) {
-            SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey);
-            EC_KEY_free(eckey);
         }
         }
-#endif
     }
     }
-#endif
-    /* OpenSSL assures us that _free() is NULL-safe */
-    EC_GROUP_free(ecgroup);
-#endif
 
 
-    return APR_SUCCESS;
+    OSSL_STORE_close(sctx);
+
+    return rv;
 }
 
 }
 
-#ifdef HAVE_TLS_SESSION_TICKETS
-static apr_status_t ssl_init_ticket_key(server_rec *s,
+static apr_status_t ssl_init_proxy_uris(server_rec *s,
                                         apr_pool_t *p,
                                         apr_pool_t *ptemp,
                                         modssl_ctx_t *mctx)
 {
                                         apr_pool_t *p,
                                         apr_pool_t *ptemp,
                                         modssl_ctx_t *mctx)
 {
-    apr_status_t rv;
-    apr_file_t *fp;
-    apr_size_t len;
-    char buf[TLSEXT_TICKET_KEY_LEN];
-    char *path;
-    modssl_ticket_key_t *ticket_key = mctx->ticket_key;
-    int res;
+    const char *uri;
+    modssl_pk_proxy_t *pkp = mctx->pkp;
+    modssl_ctx_uri_t *uctx;
+    STACK_OF(X509_INFO) *sk;
 
 
-    if (!ticket_key->file_path) {
+    int i, k;
+    int found = 0;
+    apr_status_t rv = APR_SUCCESS;
+
+    X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
+
+    ap_assert(store != NULL); /* safe to assume always non-NULL? */
+
+    if (!pkp->uris->nelts) {
         return APR_SUCCESS;
     }
 
         return APR_SUCCESS;
     }
 
-    path = ap_server_root_relative(p, ticket_key->file_path);
+    SSL_CTX_set_post_handshake_auth(mctx->ssl_ctx, 1);
 
 
-    rv = apr_file_open(&fp, path, APR_READ|APR_BINARY,
-                       APR_OS_DEFAULT, ptemp);
+    SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
+                               ssl_callback_proxy_cert);
 
 
-    if (rv != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02286)
-                     "Failed to open ticket key file %s: (%d) %pm",
-                     path, rv, &rv);
-        return ssl_die(s);
+    sk = pkp->certs;
+    if (!sk) {
+        pkp->certs = sk = sk_X509_INFO_new_null();
     }
 
     }
 
-    rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEY_LEN, &len);
+    uctx = apr_pcalloc(ptemp, sizeof(modssl_ctx_uri_t));
+
+    uctx->mctx = mctx;
+
+    uctx->cert_list = sk_X509_new_null();
+    uctx->key_list = sk_EVP_PKEY_new_null();
+    uctx->ca_list = sk_X509_new_null();
+
+    apr_pool_cleanup_register(ptemp, uctx,
+                              ssl_init_uri_cleanup,
+                              apr_pool_cleanup_null);
+
+    sk_X509_set_cmp_func(uctx->cert_list, compare_certs_desc);
+
+    /* Iterate over the SSLProxyCertificateURI array */
+    for (i = 0; (i < mctx->pkp->uris->nelts) &&
+                (uri = APR_ARRAY_IDX(mctx->pkp->uris, i,
+                                          const char *));
+         i++) {
+
+        if (uri &&
+                ssl_init_proxy_uri(s, ptemp, uri, 1, uctx) != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10611)
+                         "Host %s: Failed to open proxy URI `%s'",
+                         mctx->sc->vhost_id, uri);
+            return APR_EGENERAL;
+        }
 
 
-    if (rv != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02287)
-                     "Failed to read %d bytes from %s: (%d) %pm",
-                     TLSEXT_TICKET_KEY_LEN, path, rv, &rv);
-        return ssl_die(s);
     }
 
     }
 
-    memcpy(ticket_key->key_name, buf, 16);
-    memcpy(ticket_key->aes_key, buf + 32, 16);
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-    memcpy(ticket_key->hmac_secret, buf + 16, 16);
-    res = SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx,
-                                           ssl_callback_SessionTicket);
-#else
-    ticket_key->mac_params[0] =
-        OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
-                                          apr_pmemdup(p, buf + 16, 16), 16);
-    ticket_key->mac_params[1] =
-        OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "sha256", 0);
-    ticket_key->mac_params[2] =
-        OSSL_PARAM_construct_end();
-    res = SSL_CTX_set_tlsext_ticket_key_evp_cb(mctx->ssl_ctx,
-                                               ssl_callback_SessionTicket);
-#endif
-    OPENSSL_cleanse(buf, sizeof(buf));
-    if (!res) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01913)
-                     "Unable to initialize TLS session ticket key callback "
-                     "(incompatible OpenSSL version?)");
+    /* newest to oldest, first one wins */
+    sk_X509_sort(uctx->cert_list);
+
+    /* Match certs to keys */
+    for (i = sk_X509_num(uctx->cert_list) - 1; i >= 0; i--) {
+        X509 *cert = sk_X509_value(uctx->cert_list, i);
+
+        for (k = 0; k < sk_EVP_PKEY_num(uctx->key_list); k++) {
+            EVP_PKEY *pkey = sk_EVP_PKEY_value(uctx->key_list, k);
+
+            if (X509_check_private_key(cert, pkey) == 1) {
+
+                X509_INFO *info = X509_INFO_new();
+                info->x_pkey = X509_PKEY_new();
+
+                X509_up_ref(cert);
+                info->x509 = cert;
+
+                EVP_PKEY_up_ref(pkey);
+                info->x_pkey->dec_pkey = pkey;
+
+                sk_X509_INFO_push(sk, info);
+
+                ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10612)
+                             "Host %s: Proxy certificate from URI: %s",
+                             mctx->sc->vhost_id,
+                             modssl_X509_NAME_to_string(ptemp,
+                                     X509_get_subject_name(cert), 0));
+
+                found = 1;
+                break;
+            }
+
+        }
+    }
+
+    if (!found) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10613)
+                     "Host %s: No matching proxy certificate/key pairs found among "
+                     "%d certs, %d CA certs, %d intermediate certs, "
+                     "%d leaf certs, %d client certs, %d keys.",
+                     mctx->sc->vhost_id,
+                     uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs,
+                     uctx->num_leaf_certs,
+                     uctx->num_client_certs, uctx->num_keys);
         ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
         ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-        return ssl_die(s);
+        sk_X509_INFO_free(sk);
+        return APR_EGENERAL;
     }
 
     }
 
-    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02288)
-                 "TLS session ticket key for %s successfully loaded from %s",
-                 (mySrvConfig(s))->vhost_id, path);
+    /* Handle intermediates, must happen after cert handling */
+    for (i = sk_X509_num(uctx->ca_list) - 1; i >= 0; i--) {
+        X509 *cert = sk_X509_value(uctx->ca_list, i);
+        X509_STORE_add_cert(store, cert); /* increments cert */
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10614)
+                 "Host %s: loaded %d client certs for SSL proxy among "
+                 "%d certs, %d CA certs, %d intermediate certs, "
+                 "%d leaf certs, %d client certs, %d keys.",
+                 mctx->sc->vhost_id,
+                 sk_X509_INFO_num(sk),
+                 uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs,
+                 uctx->num_leaf_certs,
+                 uctx->num_client_certs, uctx->num_keys);
+
+    return rv;
+}
+#else
+static apr_status_t ssl_init_proxy_uris(server_rec *s,
+                                        apr_pool_t *p,
+                                        apr_pool_t *ptemp,
+                                        modssl_ctx_t *mctx)
+{
+    if (pkp->uris->nelts) {
+        const char *vhost_id = mctx->sc->vhost_id;
+
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10615)
+                    "Host %s: Proxy certificate URIs are not supported on this platform.",
+                    mctx->sc->vhost_id);
+
+        return APR_ENOTIMPL;
+    }
 
     return APR_SUCCESS;
 }
 
     return APR_SUCCESS;
 }
@@ -2030,14 +2931,10 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
                                          apr_pool_t *ptemp,
                                          modssl_ctx_t *mctx)
 {
                                          apr_pool_t *ptemp,
                                          modssl_ctx_t *mctx)
 {
-    int n, ncerts = 0;
     STACK_OF(X509_INFO) *sk;
     modssl_pk_proxy_t *pkp = mctx->pkp;
     STACK_OF(X509_INFO) *sk;
     modssl_pk_proxy_t *pkp = mctx->pkp;
-    STACK_OF(X509) *chain;
-    X509_STORE_CTX *sctx;
     X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
     X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
-    int addl_chain = 0; /* non-zero if additional chain certs were
-                         * added to store */
+    int n, ncerts = 0;
 
     ap_assert(store != NULL); /* safe to assume always non-NULL? */
 
 
     ap_assert(store != NULL); /* safe to assume always non-NULL? */
 
@@ -2047,7 +2944,7 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
      * https://github.com/openssl/openssl/issues/6933 */
     SSL_CTX_set_post_handshake_auth(mctx->ssl_ctx, 1);
 #endif
      * https://github.com/openssl/openssl/issues/6933 */
     SSL_CTX_set_post_handshake_auth(mctx->ssl_ctx, 1);
 #endif
-    
+
     SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
                                ssl_callback_proxy_cert);
 
     SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
                                ssl_callback_proxy_cert);
 
@@ -2082,7 +2979,6 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
             X509_INFO_free(inf);
             sk_X509_INFO_delete(sk, n);
             n--;
             X509_INFO_free(inf);
             sk_X509_INFO_delete(sk, n);
             n--;
-            addl_chain = 1;
             continue;
         }
 
             continue;
         }
 
@@ -2093,7 +2989,7 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
                          "(missing or encrypted private key?)");
             return ssl_die(s);
         }
                          "(missing or encrypted private key?)");
             return ssl_die(s);
         }
-        
+
         if (X509_check_private_key(inf->x509, inf->x_pkey->dec_pkey) != 1) {
             ssl_log_xerror(SSLLOG_MARK, APLOG_STARTUP, 0, ptemp, s, inf->x509,
                            APLOGNO(02326) "proxy client certificate and "
         if (X509_check_private_key(inf->x509, inf->x_pkey->dec_pkey) != 1) {
             ssl_log_xerror(SSLLOG_MARK, APLOG_STARTUP, 0, ptemp, s, inf->x509,
                            APLOGNO(02326) "proxy client certificate and "
@@ -2115,36 +3011,51 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
                  ncerts);
     pkp->certs = sk;
 
                  ncerts);
     pkp->certs = sk;
 
-    /* If any chain certs are configured, build the ->ca_certs chains
-     * corresponding to the loaded keypairs. */
-    if (!pkp->ca_cert_file && !addl_chain) {
-        return APR_SUCCESS;
+    if (pkp->ca_cert_file) {
+        modssl_X509_STORE_load_locations(store, pkp->ca_cert_file, NULL);
     }
 
     }
 
-    /* If SSLProxyMachineCertificateChainFile is configured, load all
-     * the CA certs and have OpenSSL attempt to construct a full chain
-     * from each configured end-entity cert up to a root.  This will
-     * allow selection of the correct cert given a list of root CA
+    return APR_SUCCESS;
+}
+
+static apr_status_t ssl_init_proxy_ca_certs(server_rec *s,
+                                            apr_pool_t *p,
+                                            apr_pool_t *ptemp,
+                                            modssl_ctx_t *mctx)
+{
+    modssl_pk_proxy_t *pkp = mctx->pkp;
+
+    X509_STORE_CTX *sctx;
+    X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
+    STACK_OF(X509) *chain;
+
+    int n, ncerts = 0;
+
+    ap_assert(store != NULL); /* safe to assume always non-NULL? */
+
+    ncerts = pkp->certs ? sk_X509_INFO_num(pkp->certs) : 0;
+
+   /* If intermediate certificates have been configured, have
+     * OpenSSL attempt to construct a full chain from each
+     * configured end-entity cert up to a root.  This will allow
+     * selection of the correct cert given a list of root CA
      * names in the certificate request from the server.  */
      * names in the certificate request from the server.  */
-    pkp->ca_certs = (STACK_OF(X509) **) apr_pcalloc(p, ncerts * sizeof(sk));
+
+    pkp->ca_certs = (STACK_OF(X509) **) apr_pcalloc(p, ncerts * sizeof(STACK_OF(X509_INFO) *));
     sctx = X509_STORE_CTX_new();
 
     if (!sctx) {
         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02208)
                      "SSL proxy client cert initialization failed");
         ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
     sctx = X509_STORE_CTX_new();
 
     if (!sctx) {
         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02208)
                      "SSL proxy client cert initialization failed");
         ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-        sk_X509_INFO_free(sk);
         return ssl_die(s);
     }
 
         return ssl_die(s);
     }
 
-    modssl_X509_STORE_load_locations(store, pkp->ca_cert_file, NULL);
-
     for (n = 0; n < ncerts; n++) {
         int i;
 
         X509_INFO *inf = sk_X509_INFO_value(pkp->certs, n);
         if (!X509_STORE_CTX_init(sctx, store, inf->x509, NULL)) {
     for (n = 0; n < ncerts; n++) {
         int i;
 
         X509_INFO *inf = sk_X509_INFO_value(pkp->certs, n);
         if (!X509_STORE_CTX_init(sctx, store, inf->x509, NULL)) {
-            sk_X509_INFO_free(sk);
             X509_STORE_CTX_free(sctx);
             return ssl_die(s);
         }
             X509_STORE_CTX_free(sctx);
             return ssl_die(s);
         }
@@ -2268,6 +3179,14 @@ static apr_status_t ssl_init_proxy_ctx(server_rec *s,
         return rv;
     }
 
         return rv;
     }
 
+    if ((rv = ssl_init_proxy_uris(s, p, ptemp, proxy)) != APR_SUCCESS) {
+        return rv;
+    }
+
+    if ((rv = ssl_init_proxy_ca_certs(s, p, ptemp, proxy)) != APR_SUCCESS) {
+        return rv;
+    }
+
     return APR_SUCCESS;
 }
 
     return APR_SUCCESS;
 }
 
@@ -2319,16 +3238,30 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
         /* additionally installed certs overrides any old chain configuration */
         sc->server->cert_chain = NULL;
     }
         /* additionally installed certs overrides any old chain configuration */
         sc->server->cert_chain = NULL;
     }
-    
+
     if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) {
         return rv;
     }
 
     if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) {
         return rv;
     }
 
-    if ((rv = ssl_init_server_certs(s, p, ptemp, sc->server, pphrases))
-        != APR_SUCCESS) {
-        return rv;
+    if (pks->cert_files->nelts) {
+
+        if ((rv = ssl_init_server_certs(s, p, ptemp, sc->server, pphrases))
+            != APR_SUCCESS) {
+            return rv;
+        }
+
     }
 
     }
 
+    if (pks->uris->nelts) {
+
+        if ((rv = ssl_init_server_uris(s, p, ptemp, sc->server, pphrases))
+            != APR_SUCCESS) {
+            return rv;
+        }
+
+    }
+
+
 #ifdef HAVE_SSL_CONF_CMD
     SSL_CONF_CTX_set_ssl_ctx(cctx, sc->server->ssl_ctx);
     for (i = 0; i < sc->server->ssl_ctx_param->nelts; i++, param++) {
 #ifdef HAVE_SSL_CONF_CMD
     SSL_CONF_CTX_set_ssl_ctx(cctx, sc->server->ssl_ctx);
     for (i = 0; i < sc->server->ssl_ctx_param->nelts; i++, param++) {
@@ -2425,10 +3358,10 @@ apr_status_t ssl_init_ConfigureServer(server_rec *s,
             return rv;
         }
 
             return rv;
         }
 
-       /* Initialize OCSP Responder certificate if OCSP enabled */
-       #ifndef OPENSSL_NO_OCSP
-               ssl_init_ocsp_certificates(s, sc->server);
-       #endif
+    /* Initialize OCSP Responder certificate if OCSP enabled */
+    #ifndef OPENSSL_NO_OCSP
+            ssl_init_ocsp_certificates(s, sc->server);
+    #endif
 
     }
 
 
     }
 
@@ -2566,6 +3499,101 @@ int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog,
     return OK;
 }
 
     return OK;
 }
 
+static int ssl_init_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
+{
+    return X509_NAME_cmp(*a, *b);
+}
+
+static apr_status_t ssl_init_ca_cert_uri(server_rec *s,
+                                         apr_pool_t *ptemp,
+                                         const char *uri,
+                                         STACK_OF(X509_NAME) *ca_list,
+                                         int depth,
+                                         modssl_ctx_t *mctx)
+{
+#if MODSSL_HAVE_OPENSSL_STORE
+    OSSL_STORE_CTX *sctx;
+    OSSL_STORE_INFO *info;
+
+    apr_status_t rv = APR_SUCCESS;
+
+    sk_X509_NAME_set_cmp_func(ca_list, ssl_init_x509_name_cmp);
+
+    if (!uri) {
+        return rv;
+    }
+
+    if ((!(sctx = OSSL_STORE_open_ex(uri, mctx->libctx, NULL, NULL, NULL,
+                NULL, NULL, NULL)))) {
+        return APR_EGENERAL;
+    }
+
+    while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) {
+
+        if (!(info = OSSL_STORE_load(sctx))) {
+            continue;
+        }
+
+        switch(OSSL_STORE_INFO_get_type(info)) {
+        case OSSL_STORE_INFO_NAME: {
+
+            if (depth > 0) {
+                rv = ssl_init_ca_cert_uri(s, ptemp,
+                        OSSL_STORE_INFO_get0_NAME(info),
+                        ca_list, depth - 1, mctx);
+                if (APR_SUCCESS != rv) {
+                    OSSL_STORE_close(sctx);
+                    return rv;
+                }
+            }
+
+            break;
+        }
+        case OSSL_STORE_INFO_CERT: {
+
+            X509 *cert;
+            const X509_NAME *name;
+            X509_NAME *xname;
+
+            if (!(cert = OSSL_STORE_INFO_get0_CERT(info))) {
+                OSSL_STORE_close(sctx);
+                return APR_EGENERAL;
+            }
+            else if (!X509_check_ca(cert)) {
+                /* ignore leaf certificates */
+                continue;
+            }
+            else if (!(name = X509_get_subject_name(cert)) ||
+                     !(xname = X509_NAME_dup(name))) {
+                return APR_EGENERAL;
+            }
+            if (sk_X509_NAME_find(ca_list, xname) >= 0) {
+                /* duplicate */
+                X509_NAME_free(xname);
+            }
+            else if (!sk_X509_NAME_push(ca_list, xname)) {
+                X509_NAME_free(xname);
+                OSSL_STORE_close(sctx);
+                return APR_EGENERAL;
+            }
+
+            break;
+        }
+        }
+    }
+
+    OSSL_STORE_close(sctx);
+
+    return rv;
+#else
+    if (!uri) {
+        return APR_SUCCESS;
+    }
+
+    return APR_ENOTIMPL;
+#endif
+}
+
 static apr_status_t ssl_init_ca_cert_path(server_rec *s,
                                           apr_pool_t *ptemp,
                                           const char *path,
 static apr_status_t ssl_init_ca_cert_path(server_rec *s,
                                           apr_pool_t *ptemp,
                                           const char *path,
@@ -2603,24 +3631,34 @@ static apr_status_t ssl_init_ca_cert_path(server_rec *s,
 STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s,
                                          apr_pool_t *ptemp,
                                          const char *ca_file,
 STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s,
                                          apr_pool_t *ptemp,
                                          const char *ca_file,
-                                         const char *ca_path)
+                                         const char *ca_path,
+                                         const char *ca_uri,
+                                         modssl_ctx_t *mctx)
 {
     STACK_OF(X509_NAME) *ca_list = sk_X509_NAME_new_null();;
 
 {
     STACK_OF(X509_NAME) *ca_list = sk_X509_NAME_new_null();;
 
+    /*
+     * Process CA certificate store uri
+     */
+    if (ca_uri &&
+        ssl_init_ca_cert_uri(s, ptemp,
+                             ca_uri, ca_list, 1, mctx) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10616)
+                     "Failed to open Certificate URI `%s'", ca_uri);
+        sk_X509_NAME_pop_free(ca_list, X509_NAME_free);
+        return NULL;
+    }
+
     /*
      * Process CA certificate bundle file
      */
     /*
      * Process CA certificate bundle file
      */
-    if (ca_file) {
-        SSL_add_file_cert_subjects_to_stack(ca_list, ca_file);
-        /*
-         * If ca_list is still empty after trying to load ca_file
-         * then the file failed to load, and users should hear about that.
-         */
-        if (sk_X509_NAME_num(ca_list) == 0) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02210)
+    if (ca_file &&
+            !SSL_add_file_cert_subjects_to_stack(ca_list, ca_file)) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02210)
                     "Failed to load SSLCACertificateFile: %s", ca_file);
                     "Failed to load SSLCACertificateFile: %s", ca_file);
-            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
-        }
+        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
+        sk_X509_NAME_pop_free(ca_list, X509_NAME_free);
+        return NULL;
     }
 
     /*
     }
 
     /*
@@ -2675,10 +3713,10 @@ apr_status_t ssl_init_ModuleKill(void *data)
 
         ssl_init_ctx_cleanup(sc->server);
 
 
         ssl_init_ctx_cleanup(sc->server);
 
-       /* Not Sure but possibly clear X509 trusted cert file */
-       #ifndef OPENSSL_NO_OCSP
-               sk_X509_pop_free(sc->server->ocsp_certs, X509_free);
-       #endif
+    /* Not Sure but possibly clear X509 trusted cert file */
+    #ifndef OPENSSL_NO_OCSP
+        sk_X509_pop_free(sc->server->ocsp_certs, X509_free);
+    #endif
 
     }
 
 
     }
 
index 3e96f9efdac75962f77657d50ba53b0a9e28dd30..85118b7a9d0292e224655d1f809ef47e2deb0adf 100644 (file)
@@ -29,6 +29,7 @@
                                   time I was too famous.''
                                             -- Unknown                */
 #include "ssl_private.h"
                                   time I was too famous.''
                                             -- Unknown                */
 #include "ssl_private.h"
+#include "httpd.h"
 #include "mod_ssl.h"
 #include "util_md5.h"
 #include "scoreboard.h"
 #include "mod_ssl.h"
 #include "util_md5.h"
 #include "scoreboard.h"
index 773c4660eb868dfc8df0b76cfa59c6c49b5b4b99..900b91a472aa41bee712156583209adc4581ec0a 100644 (file)
@@ -780,7 +780,7 @@ static apr_status_t pp_ui_method_cleanup(void *uip)
     return APR_SUCCESS;
 }
 
     return APR_SUCCESS;
 }
 
-static UI_METHOD *get_passphrase_ui(apr_pool_t *p)
+UI_METHOD *modssl_get_passphrase_ui(apr_pool_t *p)
 {
     UI_METHOD *ui_method = UI_create_method("Passphrase UI");
 
 {
     UI_METHOD *ui_method = UI_create_method("Passphrase UI");
 
@@ -794,6 +794,21 @@ static UI_METHOD *get_passphrase_ui(apr_pool_t *p)
     
     return ui_method;
 }
     
     return ui_method;
 }
+
+void *modssl_get_passphrase_cb(server_rec *s, apr_pool_t *p,
+                               const char *vhostid,
+                               const char *uri)
+{
+    pphrase_cb_arg_t *ppcb = apr_pcalloc(p, sizeof(pphrase_cb_arg_t));
+
+    ppcb->s = s;
+    ppcb->p = p;
+    ppcb->bPassPhraseDialogOnce = TRUE;
+    ppcb->key_id = vhostid;
+    ppcb->pkey_file = uri;
+
+    return ppcb;
+}
 #endif
 
 #if MODSSL_HAVE_ENGINE_API
 #endif
 
 #if MODSSL_HAVE_ENGINE_API
@@ -819,7 +834,7 @@ static apr_status_t modssl_load_keypair_engine(server_rec *s, apr_pool_t *pconf,
 {
     const char *c, *scheme;
     ENGINE *e;
 {
     const char *c, *scheme;
     ENGINE *e;
-    UI_METHOD *ui_method = get_passphrase_ui(ptemp);
+    UI_METHOD *ui_method = modssl_get_passphrase_ui(ptemp);
     pphrase_cb_arg_t ppcb;
 
     memset(&ppcb, 0, sizeof ppcb);
     pphrase_cb_arg_t ppcb;
 
     memset(&ppcb, 0, sizeof ppcb);
@@ -904,7 +919,7 @@ static OSSL_STORE_INFO *modssl_load_store_uri(server_rec *s, apr_pool_t *p,
                                               const char *uri, int info_type)
 {
     OSSL_STORE_CTX *sctx;
                                               const char *uri, int info_type)
 {
     OSSL_STORE_CTX *sctx;
-    UI_METHOD *ui_method = get_passphrase_ui(p);
+    UI_METHOD *ui_method = modssl_get_passphrase_ui(p);
     pphrase_cb_arg_t ppcb;
     OSSL_STORE_INFO *info = NULL;
 
     pphrase_cb_arg_t ppcb;
     OSSL_STORE_INFO *info = NULL;
 
index a34b034f26591b1319a26de7f8555b8f59e4506f..8814f276e05c91be87f18c7a4cc185d280c7b729 100644 (file)
@@ -755,19 +755,23 @@ typedef struct {
  * a given vhost */
 typedef struct {
     /* Lists of configured certs and keys for this server */
  * a given vhost */
 typedef struct {
     /* Lists of configured certs and keys for this server */
+    apr_array_header_t *uris;
     apr_array_header_t *cert_files;
     apr_array_header_t *key_files;
 
     /** Certificates which specify the set of CA names which should be
      * sent in the CertificateRequest message: */
     apr_array_header_t *cert_files;
     apr_array_header_t *key_files;
 
     /** Certificates which specify the set of CA names which should be
      * sent in the CertificateRequest message: */
+    const char  *ca_name_uri;
     const char  *ca_name_path;
     const char  *ca_name_file;
     const char  *ca_name_path;
     const char  *ca_name_file;
-    
+
     /* TLS service for this server is suspended */
     int service_unavailable;
 } modssl_pk_server_t;
 
 typedef struct {
     /* TLS service for this server is suspended */
     int service_unavailable;
 } modssl_pk_server_t;
 
 typedef struct {
+    /* Lists of configured certs and keys for this proxy */
+    apr_array_header_t *uris;
     /** proxy can have any number of cert/key pairs */
     const char  *cert_file;
     const char  *cert_path;
     /** proxy can have any number of cert/key pairs */
     const char  *cert_file;
     const char  *cert_path;
@@ -784,6 +788,7 @@ typedef struct {
 /** stuff related to authentication that can also be per-dir */
 typedef struct {
     /** known/trusted CAs */
 /** stuff related to authentication that can also be per-dir */
 typedef struct {
     /** known/trusted CAs */
+    const char  *ca_cert_uri;
     const char  *ca_cert_path;
     const char  *ca_cert_file;
 
     const char  *ca_cert_path;
     const char  *ca_cert_file;
 
@@ -822,6 +827,9 @@ typedef struct {
 typedef struct {
     SSLSrvConfigRec *sc; /** pointer back to server config */
     SSL_CTX *ssl_ctx;
 typedef struct {
     SSLSrvConfigRec *sc; /** pointer back to server config */
     SSL_CTX *ssl_ctx;
+#if MODSSL_HAVE_OPENSSL_STORE
+    OSSL_LIB_CTX *libctx;
+#endif
 
     /** we are one or the other */
     modssl_pk_server_t *pks;
 
     /** we are one or the other */
     modssl_pk_server_t *pks;
@@ -841,6 +849,7 @@ typedef struct {
     const char  *cert_chain;
 
     /** certificate revocation list */
     const char  *cert_chain;
 
     /** certificate revocation list */
+    const char    *crl_uri;
     const char    *crl_path;
     const char    *crl_file;
     int            crl_check_mask;
     const char    *crl_path;
     const char    *crl_file;
     int            crl_check_mask;
@@ -892,6 +901,24 @@ typedef struct {
     BOOL ssl_check_peer_expire;
 } modssl_ctx_t;
 
     BOOL ssl_check_peer_expire;
 } modssl_ctx_t;
 
+
+typedef struct {
+       modssl_ctx_t* mctx;
+
+       STACK_OF(X509) *cert_list;
+       STACK_OF(EVP_PKEY) *key_list;
+       STACK_OF(X509) *ca_list;
+
+       int num_certs;
+       int num_ca_certs;
+       int num_intermediate_certs;
+       int num_leaf_certs;
+       int num_server_certs;
+       int num_client_certs;
+       int num_keys;
+
+} modssl_ctx_uri_t;
+
 struct SSLSrvConfigRec {
     SSLModConfigRec *mc;
     ssl_enabled_t    enabled;
 struct SSLSrvConfigRec {
     SSLModConfigRec *mc;
     ssl_enabled_t    enabled;
@@ -963,13 +990,17 @@ const char  *ssl_cmd_SSLEngine(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLECHKeyDir(cmd_parms *cmd, void *dcfg, const char *arg);
 #endif
 const char  *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *, const char *);
 const char  *ssl_cmd_SSLECHKeyDir(cmd_parms *cmd, void *dcfg, const char *arg);
 #endif
 const char  *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *, const char *);
+const char  *ssl_cmd_SSLCertificateURI(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLCACertificateURI(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCACertificatePath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCACertificateFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCACertificatePath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCACertificateFile(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLCADNRequestURI(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCADNRequestPath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCADNRequestFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCADNRequestPath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCADNRequestFile(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLCARevocationURI(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCARevocationPath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCARevocationCheck(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCARevocationPath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCARevocationCheck(cmd_parms *, void *, const char *);
@@ -996,11 +1027,14 @@ const char  *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, void *, const char *, const char *);
 const char  *ssl_cmd_SSLProxyVerify(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, void *, const char *, const char *);
 const char  *ssl_cmd_SSLProxyVerify(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLProxyCACertificateURI(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLProxyCARevocationURI(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLProxyMachineCertificateURI(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *, void *, const char *);
@@ -1046,7 +1080,7 @@ int          ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog,
                                            apr_pool_t *ptemp, server_rec *s,
                                            ap_conf_vector_t *section_config);
 STACK_OF(X509_NAME)
                                            apr_pool_t *ptemp, server_rec *s,
                                            ap_conf_vector_t *section_config);
 STACK_OF(X509_NAME)
-            *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *);
+            *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *, const char *, modssl_ctx_t *);
 void         ssl_init_Child(apr_pool_t *, server_rec *);
 apr_status_t ssl_init_ModuleKill(void *data);
 
 void         ssl_init_Child(apr_pool_t *, server_rec *);
 apr_status_t ssl_init_ModuleKill(void *data);
 
@@ -1181,6 +1215,12 @@ apr_status_t modssl_load_engine_keypair(server_rec *s,
                                         const char *certid, const char *keyid,
                                         X509 **pubkey, EVP_PKEY **privkey);
 
                                         const char *certid, const char *keyid,
                                         X509 **pubkey, EVP_PKEY **privkey);
 
+UI_METHOD *modssl_get_passphrase_ui(apr_pool_t *p);
+void *modssl_get_passphrase_cb(server_rec *s, apr_pool_t *p,
+                               const char *vhostid,
+                               const char *uri);
+
+
 /**  Diffie-Hellman Parameter Support  */
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
 DH           *modssl_dh_from_file(const char *);
 /**  Diffie-Hellman Parameter Support  */
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
 DH           *modssl_dh_from_file(const char *);