Blame SOURCES/httpd-2.4.37-mod-md-mod-ssl-hooks.patch

26c8e2
diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h
26c8e2
index 24a65a0..a360911 100644
26c8e2
--- a/modules/ssl/mod_ssl.h
26c8e2
+++ b/modules/ssl/mod_ssl.h
26c8e2
@@ -29,6 +29,7 @@
26c8e2
 #include "httpd.h"
26c8e2
 #include "http_config.h"
26c8e2
 #include "apr_optional.h"
26c8e2
+#include "apr_tables.h" /* for apr_array_header_t */
26c8e2
 
26c8e2
 /* Create a set of SSL_DECLARE(type), SSL_DECLARE_NONSTD(type) and
26c8e2
  * SSL_DECLARE_DATA with appropriate export and import tags for the platform
26c8e2
@@ -86,6 +87,34 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
26c8e2
 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *,
26c8e2
                                               ap_conf_vector_t *,
26c8e2
                                               int proxy, int enable));
26c8e2
+                                              
26c8e2
+/* Check for availability of new hooks */
26c8e2
+#define SSL_CERT_HOOKS
26c8e2
+#ifdef SSL_CERT_HOOKS
26c8e2
+
26c8e2
+/** Lets others add certificate and key files to the given server.
26c8e2
+ * For each cert a key must also be added.
26c8e2
+ * @param cert_file and array of const char* with the path to the certificate chain
26c8e2
+ * @param key_file and array of const char* with the path to the private key file
26c8e2
+ */
26c8e2
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, add_cert_files,
26c8e2
+                          (server_rec *s, apr_pool_t *p, 
26c8e2
+                           apr_array_header_t *cert_files,
26c8e2
+                           apr_array_header_t *key_files))
26c8e2
+
26c8e2
+/** In case no certificates are available for a server, this
26c8e2
+ * lets other modules add a fallback certificate for the time
26c8e2
+ * being. Regular requests against this server will be answered
26c8e2
+ * with a 503. 
26c8e2
+ * @param cert_file and array of const char* with the path to the certificate chain
26c8e2
+ * @param key_file and array of const char* with the path to the private key file
26c8e2
+ */
26c8e2
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, add_fallback_cert_files,
26c8e2
+                          (server_rec *s, apr_pool_t *p, 
26c8e2
+                           apr_array_header_t *cert_files,
26c8e2
+                           apr_array_header_t *key_files))
26c8e2
+
26c8e2
+#endif /* SSL_CERT_HOOKS */
26c8e2
 
26c8e2
 #endif /* __MOD_SSL_H__ */
26c8e2
 /** @} */
26c8e2
diff --git a/modules/ssl/mod_ssl_openssl.h b/modules/ssl/mod_ssl_openssl.h
26c8e2
index 0fa654a..d4f684f 100644
26c8e2
--- a/modules/ssl/mod_ssl_openssl.h
26c8e2
+++ b/modules/ssl/mod_ssl_openssl.h
26c8e2
@@ -69,5 +69,45 @@ APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, pre_handshake,
26c8e2
 APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, proxy_post_handshake,
26c8e2
                           (conn_rec *c, SSL *ssl))
26c8e2
 
26c8e2
+/** On TLS connections that do not relate to a configured virtual host,
26c8e2
+ * allow other modules to provide a X509 certificate and EVP_PKEY to
26c8e2
+ * be used on the connection. This first hook which does not
26c8e2
+ * return DECLINED will determine the outcome. */
26c8e2
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, answer_challenge,
26c8e2
+                          (conn_rec *c, const char *server_name, 
26c8e2
+                          X509 **pcert, EVP_PKEY **pkey))
26c8e2
+
26c8e2
+/** During post_config phase, ask around if someone wants to provide
26c8e2
+ * OCSP stapling status information for the given cert (with the also
26c8e2
+ * provided issuer certificate). The first hook which does not
26c8e2
+ * return DECLINED promises to take responsibility (and respond
26c8e2
+ * in later calls via hook ssl_get_stapling_status).
26c8e2
+ * If no hook takes over, mod_ssl's own stapling implementation will
26c8e2
+ * be applied (if configured).
26c8e2
+ */
26c8e2
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, init_stapling_status,
26c8e2
+                          (server_rec *s, apr_pool_t *p, 
26c8e2
+                          X509 *cert, X509 *issuer))
26c8e2
+
26c8e2
+/** Anyone answering positive to ssl_init_stapling_status for a 
26c8e2
+ * certificate, needs to register here and supply the actual OCSP stapling
26c8e2
+ * status data (OCSP_RESP) for a new connection.
26c8e2
+ * A hook supplying the response data must return APR_SUCCESS.
26c8e2
+ * The data is returned in DER encoded bytes via pder and pderlen. The
26c8e2
+ * returned pointer may be NULL, which indicates that data is (currently)
26c8e2
+ * unavailable.
26c8e2
+ * If DER data is returned, it MUST come from a response with
26c8e2
+ * status OCSP_RESPONSE_STATUS_SUCCESSFUL and V_OCSP_CERTSTATUS_GOOD
26c8e2
+ * or V_OCSP_CERTSTATUS_REVOKED, not V_OCSP_CERTSTATUS_UNKNOWN. This means
26c8e2
+ * errors in OCSP retrieval are to be handled/logged by the hook and
26c8e2
+ * are not done by mod_ssl.
26c8e2
+ * Any DER bytes returned MUST be allocated via malloc() and ownership
26c8e2
+ * passes to mod_ssl. Meaning, the hook must return a malloced copy of
26c8e2
+ * the data it has. mod_ssl (or OpenSSL) will free it. 
26c8e2
+ */
26c8e2
+APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, get_stapling_status,
26c8e2
+                          (unsigned char **pder, int *pderlen, 
26c8e2
+                          conn_rec *c, server_rec *s, X509 *cert))
26c8e2
+                          
26c8e2
 #endif /* __MOD_SSL_OPENSSL_H__ */
26c8e2
 /** @} */
26c8e2
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
26c8e2
index 21e41e2..ef631c1 100644
26c8e2
--- a/modules/ssl/ssl_engine_init.c
26c8e2
+++ b/modules/ssl/ssl_engine_init.c
26c8e2
@@ -36,6 +36,25 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_server,
26c8e2
                                     (server_rec *s,apr_pool_t *p,int is_proxy,SSL_CTX *ctx),
26c8e2
                                     (s,p,is_proxy,ctx), OK, DECLINED)
26c8e2
 
26c8e2
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, add_cert_files,
26c8e2
+                                    (server_rec *s, apr_pool_t *p, 
26c8e2
+                                    apr_array_header_t *cert_files, apr_array_header_t *key_files),
26c8e2
+                                    (s, p, cert_files, key_files),
26c8e2
+                                    OK, DECLINED)
26c8e2
+
26c8e2
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, add_fallback_cert_files,
26c8e2
+                                    (server_rec *s, apr_pool_t *p, 
26c8e2
+                                    apr_array_header_t *cert_files, apr_array_header_t *key_files),
26c8e2
+                                    (s, p, cert_files, key_files),
26c8e2
+                                    OK, DECLINED)
26c8e2
+
26c8e2
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, answer_challenge,
26c8e2
+                                    (conn_rec *c, const char *server_name, 
26c8e2
+                                    X509 **pcert, EVP_PKEY **pkey),
26c8e2
+                                    (c, server_name, pcert, pkey),
26c8e2
+                                    DECLINED, DECLINED)
26c8e2
+
26c8e2
+
26c8e2
 /*  _________________________________________________________________
26c8e2
 **
26c8e2
 **  Module Initialization
26c8e2
@@ -165,18 +184,18 @@ static void ssl_add_version_components(apr_pool_t *p,
26c8e2
                  modver, AP_SERVER_BASEVERSION, incver);
26c8e2
 }
26c8e2
 
26c8e2
-/**************************************************************************************************/
26c8e2
-/* Managed Domains Interface */
26c8e2
-
26c8e2
-static APR_OPTIONAL_FN_TYPE(md_is_managed) *md_is_managed;
26c8e2
-static APR_OPTIONAL_FN_TYPE(md_get_certificate) *md_get_certificate;
26c8e2
-static APR_OPTIONAL_FN_TYPE(md_is_challenge) *md_is_challenge;
26c8e2
+/*  _________________________________________________________________
26c8e2
+**
26c8e2
+**  Let other answer special connection attempts. 
26c8e2
+**  Used in ACME challenge handling by mod_md.
26c8e2
+**  _________________________________________________________________
26c8e2
+*/
26c8e2
 
26c8e2
 int ssl_is_challenge(conn_rec *c, const char *servername, 
26c8e2
                      X509 **pcert, EVP_PKEY **pkey)
26c8e2
 {
26c8e2
-    if (md_is_challenge) {
26c8e2
-        return md_is_challenge(c, servername, pcert, pkey);
26c8e2
+    if (APR_SUCCESS == ssl_run_answer_challenge(c, servername, pcert, pkey)) {
26c8e2
+        return 1;
26c8e2
     }
26c8e2
     *pcert = NULL;
26c8e2
     *pkey = NULL;
26c8e2
@@ -231,16 +250,6 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
26c8e2
     ssl_config_global_create(base_server); /* just to avoid problems */
26c8e2
     ssl_config_global_fix(mc);
26c8e2
 
26c8e2
-    /* Initialize our interface to mod_md, if it is loaded 
26c8e2
-     */
26c8e2
-    md_is_managed = APR_RETRIEVE_OPTIONAL_FN(md_is_managed);
26c8e2
-    md_get_certificate = APR_RETRIEVE_OPTIONAL_FN(md_get_certificate);
26c8e2
-    md_is_challenge = APR_RETRIEVE_OPTIONAL_FN(md_is_challenge);
26c8e2
-    if (!md_is_managed || !md_get_certificate) {
26c8e2
-        md_is_managed = NULL;
26c8e2
-        md_get_certificate = NULL;
26c8e2
-    }
26c8e2
-
26c8e2
     /*
26c8e2
      *  try to fix the configuration and open the dedicated SSL
26c8e2
      *  logfile as early as possible
26c8e2
@@ -1392,8 +1401,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
26c8e2
          * loaded via SSLOpenSSLConfCmd Certificate), so for 1.0.2 and
26c8e2
          * later, we defer to the code in ssl_init_server_ctx.
26c8e2
          */
26c8e2
-        if ((mctx->stapling_enabled == TRUE) &&
26c8e2
-            !ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) {
26c8e2
+        if (!ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) {
26c8e2
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567)
26c8e2
                          "Unable to configure certificate %s for stapling",
26c8e2
                          key_id);
26c8e2
@@ -1788,11 +1796,13 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
26c8e2
                                         apr_array_header_t *pphrases)
26c8e2
 {
26c8e2
     apr_status_t rv;
26c8e2
+    modssl_pk_server_t *pks;
26c8e2
 #ifdef HAVE_SSL_CONF_CMD
26c8e2
     ssl_ctx_param_t *param = (ssl_ctx_param_t *)sc->server->ssl_ctx_param->elts;
26c8e2
     SSL_CONF_CTX *cctx = sc->server->ssl_ctx_config;
26c8e2
     int i;
26c8e2
 #endif
26c8e2
+    int n;
26c8e2
 
26c8e2
     /*
26c8e2
      *  Check for problematic re-initializations
26c8e2
@@ -1804,50 +1814,24 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
26c8e2
         return APR_EGENERAL;
26c8e2
     }
26c8e2
 
26c8e2
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10083)
26c8e2
-                 "Init: (%s) mod_md support is %s.", ssl_util_vhostid(p, s),
26c8e2
-                 md_is_managed? "available" : "unavailable");
26c8e2
-    if (md_is_managed && md_is_managed(s)) {
26c8e2
-        modssl_pk_server_t *const pks = sc->server->pks;
26c8e2
-        if (pks->cert_files->nelts > 0 || pks->key_files->nelts > 0) {
26c8e2
-            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10084)
26c8e2
-                         "Init: (%s) You configured certificate/key files on this host, but "
26c8e2
-                         "is is covered by a Managed Domain. You need to remove these directives "
26c8e2
-                         "for the Managed Domain to take over.", ssl_util_vhostid(p, s));
26c8e2
-        }
26c8e2
-        else {
26c8e2
-            const char *key_file, *cert_file, *chain_file;
26c8e2
-            
26c8e2
-            key_file = cert_file = chain_file = NULL;
26c8e2
-            
26c8e2
-            if (md_get_certificate) {
26c8e2
-                rv = md_get_certificate(s, p, &key_file, &cert_file);
26c8e2
-            }
26c8e2
-            else {
26c8e2
-                rv = APR_ENOTIMPL;
26c8e2
-            }
26c8e2
-            
26c8e2
-            if (key_file && cert_file) {
26c8e2
-                ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, 
26c8e2
-                             "%s: installing key=%s, cert=%s, chain=%s", 
26c8e2
-                             ssl_util_vhostid(p, s), key_file, cert_file, chain_file);
26c8e2
-                APR_ARRAY_PUSH(pks->key_files, const char *) = key_file;
26c8e2
-                APR_ARRAY_PUSH(pks->cert_files, const char *) = cert_file;
26c8e2
-                sc->server->cert_chain = chain_file;
26c8e2
-            }
26c8e2
-            
26c8e2
-            if (APR_STATUS_IS_EAGAIN(rv)) {
26c8e2
-                /* Managed Domain not ready yet. This is not a reason to fail the config */
26c8e2
-                ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085)
26c8e2
-                             "Init: %s will respond with '503 Service Unavailable' for now. This "
26c8e2
-                             "host is part of a Managed Domain, but no SSL certificate is "
26c8e2
-                             "available (yet).", ssl_util_vhostid(p, s));
26c8e2
-                pks->service_unavailable = 1;
26c8e2
-            }
26c8e2
-            else if (rv != APR_SUCCESS) {
26c8e2
-                return rv;
26c8e2
-            }
26c8e2
-        }
26c8e2
+    /* Allow others to provide certificate files */
26c8e2
+    pks = sc->server->pks;
26c8e2
+    n = pks->cert_files->nelts;
26c8e2
+    ssl_run_add_cert_files(s, p, pks->cert_files, pks->key_files);
26c8e2
+
26c8e2
+    if (n < pks->cert_files->nelts) {
26c8e2
+        /* this overrides any old chain configuration */
26c8e2
+        sc->server->cert_chain = NULL;
26c8e2
+    }
26c8e2
+    
26c8e2
+    if (apr_is_empty_array(pks->cert_files) && !sc->server->cert_chain) {
26c8e2
+        ssl_run_add_fallback_cert_files(s, p, pks->cert_files, pks->key_files);
26c8e2
+        
26c8e2
+        pks->service_unavailable = 1;
26c8e2
+        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085)
26c8e2
+                     "Init: %s will respond with '503 Service Unavailable' for now. There "
26c8e2
+                     "are no SSL certificates configured and no other module contributed any.",
26c8e2
+                     ssl_util_vhostid(p, s));
26c8e2
     }
26c8e2
     
26c8e2
     if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) {
26c8e2
@@ -1900,7 +1884,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
26c8e2
      * (late) point makes sure that we catch both certificates loaded
26c8e2
      * via SSLCertificateFile and SSLOpenSSLConfCmd Certificate.
26c8e2
      */
26c8e2
-    if (sc->server->stapling_enabled == TRUE) {
26c8e2
+    do {
26c8e2
         X509 *cert;
26c8e2
         int i = 0;
26c8e2
         int ret = SSL_CTX_set_current_cert(sc->server->ssl_ctx,
26c8e2
@@ -1917,7 +1901,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
26c8e2
                                            SSL_CERT_SET_NEXT);
26c8e2
             i++;
26c8e2
         }
26c8e2
-    }
26c8e2
+    } while(0);
26c8e2
 #endif
26c8e2
 
26c8e2
 #ifdef HAVE_TLS_SESSION_TICKETS
26c8e2
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
26c8e2
index e6a9f67..a5e86e4 100644
26c8e2
--- a/modules/ssl/ssl_engine_kernel.c
26c8e2
+++ b/modules/ssl/ssl_engine_kernel.c
26c8e2
@@ -2303,6 +2303,37 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
26c8e2
 }
26c8e2
 
26c8e2
 #ifdef HAVE_TLSEXT
26c8e2
+
26c8e2
+static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
26c8e2
+                                        SSL *ssl, X509 *cert, EVP_PKEY *key)
26c8e2
+{
26c8e2
+    SSLConnRec *sslcon = myConnConfig(c);
26c8e2
+    
26c8e2
+    sslcon->service_unavailable = 1;
26c8e2
+    if ((SSL_use_certificate(ssl, cert) < 1)) {
26c8e2
+        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086)
26c8e2
+                      "Failed to configure challenge certificate %s",
26c8e2
+                      servername);
26c8e2
+        return APR_EGENERAL;
26c8e2
+    }
26c8e2
+    
26c8e2
+    if (!SSL_use_PrivateKey(ssl, key)) {
26c8e2
+        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10087)
26c8e2
+                      "error '%s' using Challenge key: %s",
26c8e2
+                      ERR_error_string(ERR_peek_last_error(), NULL), 
26c8e2
+                      servername);
26c8e2
+        return APR_EGENERAL;
26c8e2
+    }
26c8e2
+    
26c8e2
+    if (SSL_check_private_key(ssl) < 1) {
26c8e2
+        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088)
26c8e2
+                      "Challenge certificate and private key %s "
26c8e2
+                      "do not match", servername);
26c8e2
+        return APR_EGENERAL;
26c8e2
+    }
26c8e2
+    return APR_SUCCESS;
26c8e2
+}
26c8e2
+  
26c8e2
 /*
26c8e2
  * This function sets the virtual host from an extended
26c8e2
  * client hello with a server name indication extension ("SNI", cf. RFC 6066).
26c8e2
@@ -2332,30 +2363,12 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl)
26c8e2
                 return APR_SUCCESS;
26c8e2
             }
26c8e2
             else if (ssl_is_challenge(c, servername, &cert, &key)) {
26c8e2
-            
26c8e2
-                sslcon->service_unavailable = 1;
26c8e2
-                if ((SSL_use_certificate(ssl, cert) < 1)) {
26c8e2
-                    ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086)
26c8e2
-                                  "Failed to configure challenge certificate %s",
26c8e2
-                                  servername);
26c8e2
+                /* With ACMEv1 we can have challenge connections to a unknown domains
26c8e2
+                 * that need to be answered with a special certificate and will
26c8e2
+                 * otherwise not answer any requests. */
26c8e2
+                if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) {
26c8e2
                     return APR_EGENERAL;
26c8e2
                 }
26c8e2
-                
26c8e2
-                if (!SSL_use_PrivateKey(ssl, key)) {
26c8e2
-                    ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10087)
26c8e2
-                                  "error '%s' using Challenge key: %s",
26c8e2
-                                  ERR_error_string(ERR_peek_last_error(), NULL), 
26c8e2
-                                  servername);
26c8e2
-                    return APR_EGENERAL;
26c8e2
-                }
26c8e2
-                
26c8e2
-                if (SSL_check_private_key(ssl) < 1) {
26c8e2
-                    ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088)
26c8e2
-                                  "Challenge certificate and private key %s "
26c8e2
-                                  "do not match", servername);
26c8e2
-                    return APR_EGENERAL;
26c8e2
-                }
26c8e2
-                
26c8e2
             }
26c8e2
             else {
26c8e2
                 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02044)
26c8e2
@@ -2648,6 +2661,23 @@ int ssl_callback_alpn_select(SSL *ssl,
26c8e2
                           proposed);
26c8e2
             return SSL_TLSEXT_ERR_ALERT_FATAL;
26c8e2
         }
26c8e2
+        
26c8e2
+        /* protocol was switched, this could be a challenge protocol such as "acme-tls/1".
26c8e2
+         * For that to work, we need to allow overrides to our ssl certificate. 
26c8e2
+         * However, exclude challenge checks on our best known traffic protocol.
26c8e2
+         * (http/1.1 is the default, we never switch to it anyway.)
26c8e2
+         */
26c8e2
+        if (strcmp("h2", proposed)) {
26c8e2
+            const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
26c8e2
+            X509 *cert;
26c8e2
+            EVP_PKEY *key;
26c8e2
+            
26c8e2
+            if (ssl_is_challenge(c, servername, &cert, &key)) {
26c8e2
+                if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) {
26c8e2
+                    return SSL_TLSEXT_ERR_ALERT_FATAL;
26c8e2
+                }
26c8e2
+            }
26c8e2
+        }
26c8e2
     }
26c8e2
 
26c8e2
     return SSL_TLSEXT_ERR_OK;
26c8e2
diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c
26c8e2
index c3e2cfa..4df0a9a 100644
26c8e2
--- a/modules/ssl/ssl_util_stapling.c
26c8e2
+++ b/modules/ssl/ssl_util_stapling.c
26c8e2
@@ -31,12 +31,28 @@
26c8e2
 #include "ssl_private.h"
26c8e2
 #include "ap_mpm.h"
26c8e2
 #include "apr_thread_mutex.h"
26c8e2
+#include "mod_ssl_openssl.h"
26c8e2
+
26c8e2
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_stapling_status,
26c8e2
+                                    (server_rec *s, apr_pool_t *p, 
26c8e2
+                                     X509 *cert, X509 *issuer),
26c8e2
+                                     (s, p, cert, issuer),
26c8e2
+                                    DECLINED, DECLINED)
26c8e2
+
26c8e2
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, get_stapling_status,
26c8e2
+                                    (unsigned char **pder, int *pderlen, 
26c8e2
+                                     conn_rec *c, server_rec *s, X509 *cert),
26c8e2
+                                     (pder, pderlen, c, s, cert), 
26c8e2
+                                    DECLINED, DECLINED)
26c8e2
+                         
26c8e2
 
26c8e2
 #ifdef HAVE_OCSP_STAPLING
26c8e2
 
26c8e2
 static int stapling_cache_mutex_on(server_rec *s);
26c8e2
 static int stapling_cache_mutex_off(server_rec *s);
26c8e2
 
26c8e2
+static int stapling_cb(SSL *ssl, void *arg);
26c8e2
+
26c8e2
 /**
26c8e2
  * Maxiumum OCSP stapling response size. This should be the response for a
26c8e2
  * single certificate and will typically include the responder certificate chain
26c8e2
@@ -119,7 +135,38 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
26c8e2
     OCSP_CERTID *cid = NULL;
26c8e2
     STACK_OF(OPENSSL_STRING) *aia = NULL;
26c8e2
 
26c8e2
-    if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1))
26c8e2
+    if (x == NULL)
26c8e2
+        return 0;
26c8e2
+
26c8e2
+    if (!(issuer = stapling_get_issuer(mctx, x))) {
26c8e2
+        /* In Apache pre 2.4.40, we use to come here only when mod_ssl stapling
26c8e2
+         * was enabled. With the new hooks, we give other modules the chance
26c8e2
+         * to provide stapling status. However, we do not want to log ssl errors
26c8e2
+         * where we did not do so in the past. */
26c8e2
+        if (mctx->stapling_enabled == TRUE) {
26c8e2
+            ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217)
26c8e2
+                           "ssl_stapling_init_cert: can't retrieve issuer "
26c8e2
+                           "certificate!");
26c8e2
+            return 0;
26c8e2
+        }
26c8e2
+        return 1;
26c8e2
+    }
26c8e2
+
26c8e2
+    if (ssl_run_init_stapling_status(s, p, x, issuer) == APR_SUCCESS) {
26c8e2
+        /* Someone's taken over or mod_ssl's own implementation is not enabled */
26c8e2
+        if (mctx->stapling_enabled != TRUE) {
26c8e2
+            SSL_CTX_set_tlsext_status_cb(mctx->ssl_ctx, stapling_cb);
26c8e2
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO() "OCSP stapling added via hook");
26c8e2
+        }
26c8e2
+        return 1;
26c8e2
+    }
26c8e2
+    
26c8e2
+    if (mctx->stapling_enabled != TRUE) {
26c8e2
+        /* mod_ssl's own implementation is not enabled */
26c8e2
+        return 1;
26c8e2
+    }
26c8e2
+    
26c8e2
+    if (X509_digest(x, EVP_sha1(), idx, NULL) != 1)
26c8e2
         return 0;
26c8e2
 
26c8e2
     cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx));
26c8e2
@@ -139,13 +186,6 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
26c8e2
         return 1;
26c8e2
     }
26c8e2
 
26c8e2
-    if (!(issuer = stapling_get_issuer(mctx, x))) {
26c8e2
-        ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217)
26c8e2
-                       "ssl_stapling_init_cert: can't retrieve issuer "
26c8e2
-                       "certificate!");
26c8e2
-        return 0;
26c8e2
-    }
26c8e2
-
26c8e2
     cid = OCSP_cert_to_id(NULL, x, issuer);
26c8e2
     X509_free(issuer);
26c8e2
     if (!cid) {
26c8e2
@@ -182,18 +222,16 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
26c8e2
                    mctx->sc->vhost_id);
26c8e2
 
26c8e2
     apr_hash_set(stapling_certinfo, cinf->idx, sizeof(cinf->idx), cinf);
26c8e2
-
26c8e2
+    
26c8e2
     return 1;
26c8e2
 }
26c8e2
 
26c8e2
-static certinfo *stapling_get_certinfo(server_rec *s, modssl_ctx_t *mctx,
26c8e2
+static certinfo *stapling_get_certinfo(server_rec *s, X509 *x, modssl_ctx_t *mctx,
26c8e2
                                         SSL *ssl)
26c8e2
 {
26c8e2
     certinfo *cinf;
26c8e2
-    X509 *x;
26c8e2
     UCHAR idx[SHA_DIGEST_LENGTH];
26c8e2
-    x = SSL_get_certificate(ssl);
26c8e2
-    if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1))
26c8e2
+    if (X509_digest(x, EVP_sha1(), idx, NULL) != 1)
26c8e2
         return NULL;
26c8e2
     cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx));
26c8e2
     if (cinf && cinf->cid)
26c8e2
@@ -750,18 +788,34 @@ static int stapling_cb(SSL *ssl, void *arg)
26c8e2
     OCSP_RESPONSE *rsp = NULL;
26c8e2
     int rv;
26c8e2
     BOOL ok = TRUE;
26c8e2
+    X509 *x;
26c8e2
+    unsigned char *rspder = NULL;
26c8e2
+    int rspderlen;
26c8e2
 
26c8e2
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951)
26c8e2
+                 "stapling_cb: OCSP Stapling callback called");
26c8e2
+
26c8e2
+    x = SSL_get_certificate(ssl);
26c8e2
+    if (x == NULL) {
26c8e2
+        return SSL_TLSEXT_ERR_NOACK;
26c8e2
+    }
26c8e2
+
26c8e2
+    if (ssl_run_get_stapling_status(&rspder, &rspderlen, conn, s, x) == APR_SUCCESS) {
26c8e2
+        /* a hook handles stapling for this certicate and determines the response */
26c8e2
+        if (rspder == NULL || rspderlen <= 0) {
26c8e2
+            return SSL_TLSEXT_ERR_NOACK;
26c8e2
+        }
26c8e2
+        SSL_set_tlsext_status_ocsp_resp(ssl, rspder, rspderlen);
26c8e2
+        return SSL_TLSEXT_ERR_OK;
26c8e2
+    }
26c8e2
+    
26c8e2
     if (sc->server->stapling_enabled != TRUE) {
26c8e2
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01950)
26c8e2
                      "stapling_cb: OCSP Stapling disabled");
26c8e2
         return SSL_TLSEXT_ERR_NOACK;
26c8e2
     }
26c8e2
 
26c8e2
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951)
26c8e2
-                 "stapling_cb: OCSP Stapling callback called");
26c8e2
-
26c8e2
-    cinf = stapling_get_certinfo(s, mctx, ssl);
26c8e2
-    if (cinf == NULL) {
26c8e2
+    if ((cinf = stapling_get_certinfo(s, x, mctx, ssl)) == NULL) {
26c8e2
         return SSL_TLSEXT_ERR_NOACK;
26c8e2
     }
26c8e2
 
26c8e2
@@ -864,9 +918,10 @@ apr_status_t modssl_init_stapling(server_rec *s, apr_pool_t *p,
26c8e2
     if (mctx->stapling_responder_timeout == UNSET) {
26c8e2
         mctx->stapling_responder_timeout = 10 * APR_USEC_PER_SEC;
26c8e2
     }
26c8e2
+
26c8e2
     SSL_CTX_set_tlsext_status_cb(ctx, stapling_cb);
26c8e2
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01960) "OCSP stapling initialized");
26c8e2
-
26c8e2
+    
26c8e2
     return APR_SUCCESS;
26c8e2
 }
26c8e2