]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
*) core/mod_proxy/mod_ssl:
authorStefan Eissing <icing@apache.org>
Tue, 8 Jun 2021 14:37:44 +0000 (14:37 +0000)
committerStefan Eissing <icing@apache.org>
Tue, 8 Jun 2021 14:37:44 +0000 (14:37 +0000)
     Adding `outgoing` flag to conn_rec, indicating a connection is
     initiated by the server to somewhere, in contrast to incoming
     connections from clients.
     Adding 'ap_ssl_bind_outgoing()` function that marks a connection
     as outgoing and is used by mod_proxy instead of the previous
     optional function `ssl_engine_set`. This enables other SSL
     module to secure proxy connections.
     The optional functions `ssl_engine_set`, `ssl_engine_disable` and
     `ssl_proxy_enable` are now provided by the core to have backward
     compatibility with non-httpd modules that might use them. mod_ssl
     itself no longer registers these functions, but keeps them in its
     header for backward compatibility.
     The core provided optional function wrap any registered function
     like it was done for `ssl_is_ssl`.

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

15 files changed:
changes-entries/ssl_proxy.txt [new file with mode: 0644]
docs/log-message-tags/next-number
include/ap_mmn.h
include/http_ssl.h
include/httpd.h
modules/proxy/mod_proxy.c
modules/proxy/mod_proxy_hcheck.c
modules/proxy/mod_proxy_http.c
modules/ssl/mod_ssl.c
modules/ssl/ssl_engine_io.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_engine_vars.c
modules/ssl/ssl_private.h
modules/ssl/ssl_util_stapling.c
server/ssl.c

diff --git a/changes-entries/ssl_proxy.txt b/changes-entries/ssl_proxy.txt
new file mode 100644 (file)
index 0000000..a82f4b1
--- /dev/null
@@ -0,0 +1,16 @@
+  *) core/mod_proxy/mod_ssl:
+     Adding `outgoing` flag to conn_rec, indicating a connection is
+     initiated by the server to somewhere, in contrast to incoming
+     connections from clients.
+     Adding 'ap_ssl_bind_outgoing()` function that marks a connection
+     as outgoing and is used by mod_proxy instead of the previous
+     optional function `ssl_engine_set`. This enables other SSL
+     module to secure proxy connections.
+     The optional functions `ssl_engine_set`, `ssl_engine_disable` and
+     `ssl_proxy_enable` are now provided by the core to have backward
+     compatibility with non-httpd modules that might use them. mod_ssl
+     itself no longer registers these functions, but keeps them in its
+     header for backward compatibility.
+     The core provided optional function wrap any registered function
+     like it was done for `ssl_is_ssl`.
+     [Stefan Eissing]
\ No newline at end of file
index d36fd9c9126d8c123c5668ebbd3832ed50a2b6a2..755f433b6e25b180b00182ff81b98c0e6fe75021 100644 (file)
@@ -1 +1 @@
-10272
+10273
index 5e2634be3727ff862e15a40ed9d5af9cf592b074..eccfce1e963c02d0a1c148e244d6b9dd3458d499 100644 (file)
  * 20210506.0 (2.5.1-dev)  Add ap_proxy_tunnel_conn_get_read() and
  *                         ap_proxy_tunnel_conn_get_transferred() change
  *                         ap_proxy_transfer_between_connections() sent to apr_off_t *.
+ * 20210531.0 (2.5.1-dev)  add conn_rec->outgoing and ap_ssl_bind_outgoing()
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
 
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 20210506
+#define MODULE_MAGIC_NUMBER_MAJOR 20210531
 #endif
 #define MODULE_MAGIC_NUMBER_MINOR 0             /* 0...n */
 
index 556a58bdb734d72c806c1ec682312e60bb92c9cd..f4c548bf4ebf5272ece91a2052fb1d0f3ab1ab3c 100644 (file)
@@ -34,6 +34,8 @@
 extern "C" {
 #endif
 
+struct ap_conf_vector_t;
+
 /**
  * This hook allows modules that manage SSL connection to register their
  * inquiry function for checking if a connection is using SSL from them.
@@ -49,6 +51,40 @@ AP_DECLARE_HOOK(int,ssl_conn_is_ssl,(conn_rec *c))
  */
 AP_DECLARE(int) ap_ssl_conn_is_ssl(conn_rec *c);
 
+/**
+ * This hook declares a connection to be outgoing and the configuration that applies to it.
+ * This hook can be called several times in the lifetime of an outgoing connection, e.g.
+ * when it is re-used in different request contexts. It will at least be called after the
+ * connection was created and before the pre-connection hooks is invoked.
+ * All outgoing-connection hooks are run until one returns something other than ok or decline.
+ * if enable_ssl != 0, a hook that sets up SSL for the connection needs to return DONE.
+ *
+ * @param c The connection on which requests/data are to be sent.
+ * @param dir_conf The directory configuration in which this connection is being used.
+ * @param enable_ssl If != 0, the SSL protocol should be enabled for this connection.
+ * @return OK or DECLINED, DONE when ssl was enabled
+ */
+AP_DECLARE_HOOK(int, ssl_bind_outgoing,
+               (conn_rec *c, struct ap_conf_vector_t *dir_conf, int enable_ssl))
+
+/**
+ * Assures the connection is marked as outgoing and invokes the ssl_bind_outgoing hook.
+ * This may be called several times on an outgoing connection with varying dir_conf
+ * values. require_ssl is not allowed to change on the same connection.
+ *
+ * @param c The connection on which requests/data are to be sent.
+ * @param dir_conf The directory configuration in which this connection is being used.
+ * @param require_ssl != 0 iff this connection needs to be secured by SSL/TLS protocol.
+ * @return OK iff ssl was required and is enabled, DECLINED otherwise
+ */
+AP_DECLARE(int) ap_ssl_bind_outgoing(conn_rec *c, struct ap_conf_vector_t *dir_conf,
+                                     int require_ssl);
+
+/**
+ * Return != 0 iff handlers/hooks for outgoing connections are registered.
+ */
+AP_DECLARE(int) ap_ssl_has_outgoing_handlers(void);
+
 /**
  * This hook allows modules to look up SSL related variables for a
  * server/connection/request, depending on what they inquire. Some
index 5e4c036d8a6cd76f5242912184eeb93ca0adbf55..5a4a61979db1c88841c9bc0ca590b550349e6880 100644 (file)
@@ -1289,6 +1289,8 @@ struct conn_rec {
 
     /** The minimum level of filter type to allow setaside buckets */
     int async_filter;
+
+    int outgoing;
 };
 
 struct conn_slave_rec {
index dd51fe9641f4aac088ba641410c283d7eb4a18eb..647402d3a1e86c1fa6e33b9ddeec5bfa77f27c30 100644 (file)
@@ -3136,20 +3136,15 @@ PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c)
      * if c == NULL just check if the optional function was imported
      * else run the optional function so ssl filters are inserted
      */
-    if (proxy_ssl_enable) {
-        return c ? proxy_ssl_enable(c) : 1;
+    if (c == NULL) {
+        return ap_ssl_has_outgoing_handlers();
     }
-
-    return 0;
+    return ap_ssl_bind_outgoing(c, NULL, 1) == OK;
 }
 
 PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c)
 {
-    if (proxy_ssl_disable) {
-        return proxy_ssl_disable(c);
-    }
-
-    return 0;
+    return ap_ssl_bind_outgoing(c, NULL, 0) == OK;
 }
 
 PROXY_DECLARE(int) ap_proxy_ssl_engine(conn_rec *c,
@@ -3160,20 +3155,10 @@ PROXY_DECLARE(int) ap_proxy_ssl_engine(conn_rec *c,
      * if c == NULL just check if the optional function was imported
      * else run the optional function so ssl filters are inserted
      */
-    if (proxy_ssl_engine) {
-        return c ? proxy_ssl_engine(c, per_dir_config, 1, enable) : 1;
+    if (c == NULL) {
+        return ap_ssl_has_outgoing_handlers();
     }
-
-    if (!per_dir_config) {
-        if (enable) {
-            return ap_proxy_ssl_enable(c);
-        }
-        else {
-            return ap_proxy_ssl_disable(c);
-        }
-    }
-
-    return 0;
+    return ap_ssl_bind_outgoing(c, per_dir_config, enable) == OK;
 }
 
 PROXY_DECLARE(int) ap_proxy_conn_is_https(conn_rec *c)
index 4d91669ba97a5c58472936fc65ee6e903df02dd2..88723ba67604a484d13b8ec8de1abfe484de46e7 100644 (file)
@@ -20,6 +20,7 @@
 #if APR_HAS_THREADS
 #include "apr_thread_pool.h"
 #endif
+#include "http_ssl.h"
 
 module AP_MODULE_DECLARE_DATA proxy_hcheck_module;
 
@@ -605,7 +606,7 @@ static int hc_get_backend(const char *proxy_function, proxy_conn_rec **backend,
         (*backend)->addr = hc->cp->addr;
         (*backend)->hostname = hc->s->hostname_ex;
         if (strcmp(hc->s->scheme, "https") == 0 || strcmp(hc->s->scheme, "wss") == 0 ) {
-            if (!ap_proxy_ssl_enable(NULL)) {
+            if (!ap_ssl_has_outgoing_handlers()) {
                 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ctx->s, APLOGNO(03252)
                               "mod_ssl not configured?");
                 return !OK;
index 056cfb1f7777dd02fe9fbfe9fb3247e1a4d5ef5c..25239010b67eaa78bda7e7e7d6a8e3c1e906c194 100644 (file)
@@ -1909,7 +1909,7 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
                       "HTTP: declining URL %s", url);
         return DECLINED; /* only interested in HTTP, WS or FTP via proxy */
     }
-    if (is_ssl && !ap_proxy_ssl_enable(NULL)) {
+    if (is_ssl && !ap_ssl_has_outgoing_handlers()) {
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01112)
                       "HTTP: declining URL %s (mod_ssl not configured?)", url);
         return DECLINED;
index 47a28404561b7dfaa6d9b1e758b3e1624f57f202..b54edb602dd3aab7e0c30cf43d0b1f7a3ebc0bf8 100644 (file)
@@ -469,7 +469,7 @@ static int ssl_hook_pre_config(apr_pool_t *pconf,
 
 static SSLConnRec *ssl_init_connection_ctx(conn_rec *c,
                                            ap_conf_vector_t *per_dir_config,
-                                           int new_proxy)
+                                           int reinit)
 {
     SSLConnRec *sslconn = myConnConfig(c);
     int need_setup = 0;
@@ -485,7 +485,7 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c,
         sslconn = apr_pcalloc(c->pool, sizeof(*sslconn));
         need_setup = 1;
     }
-    else if (!new_proxy) {
+    else if (!reinit) {
         return sslconn;
     }
 
@@ -503,8 +503,7 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c,
     if (need_setup) {
         sslconn->server = c->base_server;
         sslconn->verify_depth = UNSET;
-        if (new_proxy) {
-            sslconn->is_proxy = 1;
+        if (c->outgoing) {
             sslconn->cipher_suite = sslconn->dc->proxy->auth.cipher_suite;
         }
         else {
@@ -524,10 +523,11 @@ static int ssl_engine_status(conn_rec *c, SSLConnRec *sslconn)
         return DECLINED;
     }
     if (sslconn) {
+        /* This connection has already been configured. Check what applies. */
         if (sslconn->disabled) {
             return SUSPENDED;
         }
-        if (sslconn->is_proxy) {
+        if (c->outgoing) {
             if (!sslconn->dc->proxy_enabled) {
                 return DECLINED;
             }
@@ -539,53 +539,41 @@ static int ssl_engine_status(conn_rec *c, SSLConnRec *sslconn)
         }
     }
     else {
-        if (mySrvConfig(c->base_server)->enabled != SSL_ENABLED_TRUE) {
+        /* we decline by default for outgoing connections and for incoming
+         * where the base_server is not enabled. */
+        if (c->outgoing || mySrvConfig(c->base_server)->enabled != SSL_ENABLED_TRUE) {
             return DECLINED;
         }
     }
     return OK;
 }
 
-static int ssl_engine_set(conn_rec *c,
-                          ap_conf_vector_t *per_dir_config,
-                          int proxy, int enable)
+static int ssl_hook_ssl_bind_outgoing(conn_rec *c,
+                                 ap_conf_vector_t *per_dir_config,
+                                 int enable_ssl)
 {
     SSLConnRec *sslconn;
     int status;
-    
-    if (proxy) {
-        sslconn = ssl_init_connection_ctx(c, per_dir_config, 1);
-    }
-    else {
-        sslconn = myConnConfig(c);
-    }
 
+    sslconn = ssl_init_connection_ctx(c, per_dir_config, 1);
     status = ssl_engine_status(c, sslconn);
-
-    if (proxy && status == DECLINED) {
-        if (enable) {
+    if (enable_ssl) {
+        if (status != OK) {
             SSLSrvConfigRec *sc = mySrvConfig(sslconn->server);
-            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01961)
-                          "SSL Proxy requested for %s but not enabled "
-                          "[Hint: SSLProxyEngine]", sc->vhost_id);
+            sslconn->disabled = 1;
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10272)
+                          "SSL Proxy requested for %s but not enabled for us.",
+                          sc->vhost_id);
+        }
+        else {
+            sslconn->disabled = 0;
+            return OK;
         }
-        sslconn->disabled = 1;
     }
-    else if (sslconn) {
-        sslconn->disabled = !enable;
+    else {
+        sslconn->disabled = 1;
     }
-
-    return status != DECLINED;
-}
-
-static int ssl_proxy_enable(conn_rec *c)
-{
-    return ssl_engine_set(c, NULL, 1, 1);
-}
-
-static int ssl_engine_disable(conn_rec *c)
-{
-    return ssl_engine_set(c, NULL, 0, 0);
+    return DECLINED;
 }
 
 #if defined(SSL_MAX_SID_CTX_LENGTH) && (APR_MD5_DIGESTSIZE * 2) > SSL_MAX_SID_CTX_LENGTH
@@ -612,9 +600,9 @@ int ssl_init_ssl_connection(conn_rec *c, request_rec *r)
      * Seed the Pseudo Random Number Generator (PRNG)
      */
     ssl_rand_seed(server, c->pool, SSL_RSCTX_CONNECT,
-                  sslconn->is_proxy ? "Proxy: " : "Server: ");
+                  c->outgoing ? "Proxy: " : "Server: ");
 
-    mctx = myCtxConfig(sslconn, sc);
+    mctx = myConnCtxConfig(c, sc);
 
     /*
      * Create a new SSL connection with the configured server SSL context and
@@ -632,7 +620,7 @@ int ssl_init_ssl_connection(conn_rec *c, request_rec *r)
         return DECLINED; /* XXX */
     }
 
-    rc = ssl_run_pre_handshake(c, ssl, sslconn->is_proxy ? 1 : 0);
+    rc = ssl_run_pre_handshake(c, ssl, c->outgoing ? 1 : 0);
     if (rc != OK && rc != DECLINED) {
         return rc;
     }
@@ -760,10 +748,7 @@ static void ssl_register_hooks(apr_pool_t *p)
                       APR_HOOK_MIDDLE);
 
     ssl_var_register(p);
-
-    APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
-    APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
-    APR_REGISTER_OPTIONAL_FN(ssl_engine_set);
+    ap_hook_ssl_bind_outgoing  (ssl_hook_ssl_bind_outgoing, NULL, NULL, APR_HOOK_MIDDLE);
 
     ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl",
                               AUTHZ_PROVIDER_VERSION,
index 218cceacf67e11f28a8f82eae2c4e7f6dc169793..507515b61f2f4617854adda68e618a29a0b813e9 100644 (file)
@@ -1245,7 +1245,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
     }
 
     server = sslconn->server;
-    if (sslconn->is_proxy) {
+    if (c->outgoing) {
 #ifdef HAVE_TLSEXT
         apr_ipsubnet_t *ip;
 #endif
index eb97f6b64ffa4187f9bb59d63720b7ef78295f25..a175d3e07540e51c846780fb3a57bc0b68be0f41 100644 (file)
@@ -1768,7 +1768,7 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
     SSLSrvConfigRec *sc = mySrvConfig(s);
     SSLConnRec *sslconn = myConnConfig(conn);
     SSLDirConfigRec *dc = r ? myDirConfig(r) : sslconn->dc;
-    modssl_ctx_t *mctx  = myCtxConfig(sslconn, sc);
+    modssl_ctx_t *mctx  = myConnCtxConfig(conn, sc);
     int crl_check_mode  = mctx->crl_check_mask & ~SSL_CRLCHECK_FLAGS;
 
     /* Get verify ingredients */
@@ -1792,7 +1792,7 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
      * Check for optionally acceptable non-verifiable issuer situation
      */
     if (dc) {
-        if (sslconn->is_proxy) {
+        if (conn->outgoing) {
             verify = dc->proxy->auth.verify_mode;
         }
         else {
@@ -1904,7 +1904,7 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
      * Finally check the depth of the certificate verification
      */
     if (dc) {
-        if (sslconn->is_proxy) {
+        if (conn->outgoing) {
             depth = dc->proxy->auth.verify_depth;
         }
         else {
@@ -2300,7 +2300,7 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
         /* If the reneg state is to reject renegotiations, check the SSL
          * state machine and move to ABORT if a Client Hello is being
          * read. */
-        if (!sslconn->is_proxy &&
+        if (!c->outgoing &&
                 (where & SSL_CB_HANDSHAKE_START) &&
                 sslconn->reneg_state == RENEG_REJECT) {
             sslconn->reneg_state = RENEG_ABORT;
@@ -2543,7 +2543,7 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
          * Don't switch the protocol if none is configured for this vhost,
          * the default in this case is still the base server's SSLProtocol.
          */
-        if (myCtxConfig(sslcon, sc)->protocol_set) {
+        if (myConnCtxConfig(c, sc)->protocol_set) {
             SSL_set_min_proto_version(ssl, SSL_CTX_get_min_proto_version(ctx));
             SSL_set_max_proto_version(ssl, SSL_CTX_get_max_proto_version(ctx));
         }
@@ -2629,8 +2629,7 @@ int ssl_callback_SessionTicket(SSL *ssl,
     conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
     server_rec *s = mySrvFromConn(c);
     SSLSrvConfigRec *sc = mySrvConfig(s);
-    SSLConnRec *sslconn = myConnConfig(c);
-    modssl_ctx_t *mctx = myCtxConfig(sslconn, sc);
+    modssl_ctx_t *mctx = myConnCtxConfig(c, sc);
     modssl_ticket_key_t *ticket_key = mctx->ticket_key;
 
     if (mode == 1) {
index 56b8702aa88dca20a5c8ce81845c8db9159775d9..08994c177ddb058fc470e8522a0df8a4918e3c73 100644 (file)
@@ -64,10 +64,10 @@ static const SSLConnRec *ssl_get_effective_config(conn_rec *c)
     return sslconn;
 }
 
-static int ssl_is_https(conn_rec *c)
+static int ssl_conn_is_ssl(conn_rec *c)
 {
     const SSLConnRec *sslconn = ssl_get_effective_config(c);
-    return sslconn && sslconn->ssl;
+    return (sslconn && sslconn->ssl)? OK : DECLINED;
 }
 
 /* Returns certificate data, either PEM encoded if 'pem' is non-zero,
@@ -244,7 +244,7 @@ void ssl_var_register(apr_pool_t *p)
 {
     char *cp, *cp2;
 
-    APR_REGISTER_OPTIONAL_FN(ssl_is_https);
+    ap_hook_ssl_conn_is_ssl(ssl_conn_is_ssl, NULL, NULL, APR_HOOK_MIDDLE);
     APR_REGISTER_OPTIONAL_FN(ssl_get_tls_cb);
     APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
     APR_REGISTER_OPTIONAL_FN(ssl_ext_list);
index e5d17da7ac3552c002248aeaf1832f37cc34255b..7d623b216f3d590e76845ab23049b184e732e758 100644 (file)
@@ -315,8 +315,8 @@ APLOG_USE_MODULE(ssl);
     ((SSLSrvConfigRec *)ap_get_module_config(srv->module_config,  &ssl_module))
 #define myDirConfig(req) \
     ((SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module))
-#define myCtxConfig(sslconn, sc) \
-    (sslconn->is_proxy ? sslconn->dc->proxy : sc->server)
+#define myConnCtxConfig(c, sc) \
+    (c->outgoing ? myConnConfig(c)->dc->proxy : sc->server)
 #define myModConfig(srv) mySrvConfig((srv))->mc
 #define mySrvFromConn(c) myConnConfig(c)->server
 #define myDirConfigFromConn(c) myConnConfig(c)->dc
@@ -538,7 +538,6 @@ typedef struct {
     const char *verify_info;
     const char *verify_error;
     int verify_depth;
-    int is_proxy;
     int disabled;
     enum {
         NON_SSL_OK = 0,        /* is SSL request, or error handling completed */
index f9f10b8426486547276bc7f289e1f40354e649a7..88ad0b74192b030fc6df88d9ee658981278a67b8 100644 (file)
@@ -798,8 +798,7 @@ static int stapling_cb(SSL *ssl, void *arg)
     conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
     server_rec *s       = mySrvFromConn(conn);
     SSLSrvConfigRec *sc = mySrvConfig(s);
-    SSLConnRec *sslconn = myConnConfig(conn);
-    modssl_ctx_t *mctx  = myCtxConfig(sslconn, sc);
+    modssl_ctx_t *mctx  = myConnCtxConfig(conn, sc);
     UCHAR idx[SHA_DIGEST_LENGTH];
     ocsp_resp resp;
     certinfo *cinf = NULL;
index d2d9df4ee0e26695ed01f11b045e4863bddd660a..f07efd36186ee82d0e317ad80613f2e7c497d987 100644 (file)
@@ -32,6 +32,7 @@
 #include "ap_config.h"
 #include "httpd.h"
 #include "http_core.h"
+#include "http_connection.h"
 #include "http_protocol.h"
 #include "http_request.h"
 #include "http_ssl.h"
@@ -58,10 +59,20 @@ APR_HOOK_STRUCT(
     APR_HOOK_LINK(ssl_answer_challenge)
     APR_HOOK_LINK(ssl_ocsp_prime_hook)
     APR_HOOK_LINK(ssl_ocsp_get_resp_hook)
+    APR_HOOK_LINK(ssl_bind_outgoing)
 )
 
 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *module_ssl_is_https;
+APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
+static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *module_ssl_proxy_enable;
+APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
+static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *module_ssl_engine_disable;
+APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *,
+                                              ap_conf_vector_t *,
+                                              int proxy, int enable));
+static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *module_ssl_engine_set;
+
 
 static int ssl_is_https(conn_rec *c)
 {
@@ -79,6 +90,77 @@ AP_DECLARE(int) ap_ssl_conn_is_ssl(conn_rec *c)
     return r;
 }
 
+static int ssl_engine_set(conn_rec *c,
+                          ap_conf_vector_t *per_dir_config,
+                          int proxy, int enable)
+{
+    if (proxy) {
+        return ap_ssl_bind_outgoing(c, per_dir_config, enable) == OK;
+    }
+    else if (module_ssl_engine_set) {
+        return module_ssl_engine_set(c, per_dir_config, 0, enable);
+    }
+    else if (enable && module_ssl_proxy_enable) {
+        return module_ssl_proxy_enable(c);
+    }
+    else if (!enable && module_ssl_engine_disable) {
+        return module_ssl_engine_disable(c);
+    }
+    return 0;
+}
+
+static int ssl_proxy_enable(conn_rec *c)
+{
+    return ap_ssl_bind_outgoing(c, NULL, 1);
+}
+
+static int ssl_engine_disable(conn_rec *c)
+{
+    return ap_ssl_bind_outgoing(c, NULL, 0);
+}
+
+AP_DECLARE(int) ap_ssl_bind_outgoing(conn_rec *c, struct ap_conf_vector_t *dir_conf,
+                                     int enable_ssl)
+{
+    int rv, enabled = 0;
+
+    c->outgoing = 1;
+    rv = ap_run_ssl_bind_outgoing(c, dir_conf, enable_ssl);
+    enabled = (rv == OK);
+    if (enable_ssl && !enabled) {
+        /* the hooks did not take over. Is there an old skool optional that will? */
+        if (module_ssl_engine_set) {
+            enabled = module_ssl_engine_set(c, dir_conf, 1, 1);
+        }
+        else if (module_ssl_proxy_enable) {
+            enabled = module_ssl_proxy_enable(c);
+        }
+    }
+    else {
+        /* !enable_ssl || enabled
+         * any existing optional funcs need to not enable here */
+        if (module_ssl_engine_set) {
+            module_ssl_engine_set(c, dir_conf, 1, 0);
+        }
+        else if (module_ssl_engine_disable) {
+            module_ssl_engine_disable(c);
+        }
+    }
+    if (enable_ssl && !enabled) {
+        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0,
+                      c, APLOGNO(01961) " failed to enable ssl support "
+                      "[Hint: if using mod_ssl, see SSLProxyEngine]");
+        return DECLINED;
+    }
+    return OK;
+}
+
+AP_DECLARE(int) ap_ssl_has_outgoing_handlers(void)
+{
+    return (_hooks.link_ssl_bind_outgoing && _hooks.link_ssl_bind_outgoing->nelts > 0)
+        || module_ssl_engine_set || module_ssl_proxy_enable;
+}
+
 APR_DECLARE_OPTIONAL_FN(const char *, ssl_var_lookup,
                         (apr_pool_t *p, server_rec *s,
                          conn_rec *c, request_rec *r,
@@ -123,6 +205,13 @@ AP_DECLARE(void) ap_setup_ssl_optional_fns(apr_pool_t *pool)
     module_ssl_var_lookup = (fn_ssl_var_lookup
         && fn_ssl_var_lookup != ssl_var_lookup)? fn_ssl_var_lookup : NULL;
     APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
+
+    module_ssl_proxy_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
+    APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
+    module_ssl_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
+    APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
+    module_ssl_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set);
+    APR_REGISTER_OPTIONAL_FN(ssl_engine_set);
 }
 
 AP_DECLARE(apr_status_t) ap_ssl_add_cert_files(server_rec *s, apr_pool_t *p,
@@ -186,3 +275,5 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_ocsp_get_resp_hook,
          (server_rec *s, conn_rec *c, const char *id, apr_size_t id_len,
           ap_ssl_ocsp_copy_resp *cb, void *userdata),
          (s, c, id, id_len, cb, userdata), DECLINED)
+AP_IMPLEMENT_HOOK_RUN_FIRST(int,ssl_bind_outgoing,(conn_rec *c, ap_conf_vector_t *dir_conf, int require_ssl),
+                            (c, dir_conf, require_ssl), DECLINED)