]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Backport of r760866:
authorRuediger Pluem <rpluem@apache.org>
Sat, 25 Apr 2009 09:50:27 +0000 (09:50 +0000)
committerRuediger Pluem <rpluem@apache.org>
Sat, 25 Apr 2009 09:50:27 +0000 (09:50 +0000)
* Add SSLProxyCheckPeerExpire and SSLProxyCheckPeerCN directives to enable
  stricter checking of remote server certificates.

  (docs/manual/mod/mod_ssl.xml)
    Documentation of SSLProxyCheckPeerExpire and SSLProxyCheckPeerCN.

  (modules/proxy/mod_proxy_http.c)
    Set the hostname of the request URL as note on the connection.

  (modules/ssl/ssl_private.h)
    Add proxy_ssl_check_peer_expire and proxy_ssl_check_peer_cn fields to
    the SSLSrvConfigRec.

  (modules/ssl/ssl_engine_config.c)
    Directives stuff for SSLProxyCheckPeerExpire and SSLProxyCheckPeerCN.

  (modules/ssl/ssl_engine_io.c)
    Check whether the remote servers certificate is expired / if there is a
    mismatch between the requested hostanme and the remote server certificates
    CN field.
    Be able to parse ASN1 times.

  (modules/ssl/mod_ssl.c)
    Directives stuff for SSLProxyCheckPeerExpire and SSLProxyCheckPeerCN.

Submitted by: rpluem
Reviewed by: rpluem, jim, jfclere

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@768504 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
docs/manual/mod/mod_ssl.xml
modules/proxy/mod_proxy_http.c
modules/ssl/mod_ssl.c
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_io.c
modules/ssl/ssl_private.h

diff --git a/CHANGES b/CHANGES
index fdd5836818c43108f6ba426d87ae01502af5dd16..2697cd9344193bdb3eebc94bc44ea428b67a497d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.2.12
 
+  *) mod_ssl: Add SSLProxyCheckPeerExpire and SSLProxyCheckPeerCN directives
+     to enable stricter checking of remote server certificates.
+     [Ruediger Pluem]
+
   *) mod_substitute: Fix a memory leak. PR 44948
      [Dan Poirier <poirier pobox.com>]
 
diff --git a/STATUS b/STATUS
index 246fea3e400c1ebd7404b7fcd09b0de17814e831..b3ed5a88a9664560cc2aaa0b26181ef03c53dbea 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -97,14 +97,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
      Trunk version of patch works
   +1: rpluem, wrowe, jfclere
 
- * mod_ssl: Add SSLProxyCheckPeerExpire and SSLProxyCheckPeerCN directives
-   to enable stricter checking of remote server certificates.
-   Trunk version of patch:
-      http://svn.apache.org/viewvc?rev=760866&view=rev
-   Backport version for 2.2.x of patch:
-      http://people.apache.org/~rpluem/patches/SSLProxyCheckPeer.diff
-   +1: rpluem, jim, jfclere
-
  * mod_proxy_ajp: Check more strictly that the backend follows the AJP protocol.
    Trunk version of patch:
       http://svn.apache.org/viewvc?rev=764239&view=rev
index 2f4b05316429cdd6fb5a7860734f72aec45da5ec..1a93b791ff9d1040cbaf7be5d5b4b45b69636548 100644 (file)
@@ -1502,6 +1502,48 @@ SSLProxyVerifyDepth 10
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLProxyCheckPeerExpire</name>
+<description>Whether to check if remote server certificate is expired
+</description>
+<syntax>SSLProxyCheckPeerExpire on|off|optional</syntax>
+<default>SSLProxyCheckPeerExpire off</default>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+
+<usage>
+<p>
+This directive sets whether it is checked if the remote server certificate
+is expired or not. If the check fails a 502 status code (Bad Gateway) is
+sent.
+</p>
+<example><title>Example</title>
+SSLProxyCheckPeerExpire on
+</example>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>SSLProxyCheckPeerCN</name>
+<description>Whether to check the remote server certificates CN field
+</description>
+<syntax>SSLProxyCheckPeerCN on|off|optional</syntax>
+<default>SSLProxyCheckPeerCN off</default>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+
+<usage>
+<p>
+This directive sets whether the remote server certificates CN field is
+compared against the hostname of the request URL. If both are not equal
+a 502 status code (Bad Gateway) is sent.
+</p>
+<example><title>Example</title>
+SSLProxyCheckPeerCN on
+</example>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLProxyEngine</name>
 <description>SSL Proxy Engine Operation Switch</description>
index cf695fda924c6bde037ceb287c1f881295cefac5..846504f1af8103471f2dc5059858414a88abe5d4 100644 (file)
@@ -1966,6 +1966,15 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
         if ((status = ap_proxy_connection_create(proxy_function, backend,
                                                  c, r->server)) != OK)
             goto cleanup;
+        /*
+         * On SSL connections set a note on the connection what CN is
+         * requested, such that mod_ssl can check if it is requested to do
+         * so.
+         */
+        if (is_ssl) {
+            apr_table_set(backend->connection->notes, "proxy-request-hostname",
+                          uri->hostname);
+        }
     }
 
     /* Step Four: Send the Request */
index f8a88a2adb5dd0050a85f5e1429cc5b50adafedd..f90585de2ddc7aa0879e92e5936648fce5cc430a 100644 (file)
@@ -182,6 +182,10 @@ static const command_rec ssl_config_cmds[] = {
     SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1,
                "SSL Proxy: directory containing client certificates "
                "(`/path/to/dir' - contains PEM encoded certificates)")
+    SSL_CMD_SRV(ProxyCheckPeerExpire, FLAG,
+                "SSL Proxy: check the peers certificate expiration date")
+    SSL_CMD_SRV(ProxyCheckPeerCN, FLAG,
+                "SSL Proxy: check the peers certificate CN")
 
     /*
      * Per-directory context configuration directives
index 3b22c4a10b69e535d15778a127f56b0213e1f8de..48ef535bd8d19e43e339ee538103b28f98f802d8 100644 (file)
@@ -169,6 +169,8 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p)
     sc->vhost_id_len           = 0;     /* set during module init */
     sc->session_cache_timeout  = UNSET;
     sc->cipher_server_pref     = UNSET;
+    sc->proxy_ssl_check_peer_expire = SSL_ENABLED_UNSET;
+    sc->proxy_ssl_check_peer_cn     = SSL_ENABLED_UNSET;
 
     modssl_ctx_init_proxy(sc, p);
 
@@ -257,6 +259,8 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
     cfgMergeBool(proxy_enabled);
     cfgMergeInt(session_cache_timeout);
     cfgMergeBool(cipher_server_pref);
+    cfgMerge(proxy_ssl_check_peer_expire, SSL_ENABLED_UNSET);
+    cfgMerge(proxy_ssl_check_peer_cn, SSL_ENABLED_UNSET);
 
     modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy);
 
@@ -1428,6 +1432,24 @@ const char *ssl_cmd_SSLUserName(cmd_parms *cmd, void *dcfg,
     return NULL;
 }
 
+const char *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+    sc->proxy_ssl_check_peer_expire = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+    return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+    sc->proxy_ssl_check_peer_cn = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+    return NULL;
+}
+
 void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
 {
     if (!ap_exists_config_define("DUMP_CERTS")) {
index c46e9eec9bed64579e5ea85727f284f93ac31f0f..a4b21584653d84302114d5054a6005938d491f70 100644 (file)
@@ -28,6 +28,7 @@
                                   core keeps dumping.''
                                             -- Unknown    */
 #include "ssl_private.h"
+#include "apr_date.h"
 
 /*  _________________________________________________________________
 **
@@ -1010,6 +1011,31 @@ static apr_status_t ssl_io_filter_cleanup(void *data)
     return APR_SUCCESS;
 }
 
+/*
+ * Parse an ASN1time string as returned by ASN1_UTCTIME_print into an
+ * apr_time_t.
+ */
+static apr_time_t parseASN1time(apr_pool_t *p, const char *asn1time)
+{
+    char *asctime;
+
+    /*
+     * Little bit ugly hack:
+     * The ASN1time looks very similar to the asctime format which can be
+     * parsed by apr_date_parse_rfc:
+     * It misses the weekday at the beginning (which is ignored by
+     * apr_date_parse_rfc anyway) and it has a GMT at the end which
+     * does not into the asctime pattern. So add a dummy "Sun " before
+     * the ASN1time and remove the GMT string at the end.
+     */
+    asctime = apr_pstrcat(p, "Sun ", asn1time, NULL);
+    if (strlen(asctime) < 25) {
+        return APR_DATE_BAD;
+    }
+    asctime[24] = '\0';
+    return apr_date_parse_rfc(asctime);
+}
+
 /*
  * The hook is NOT registered with ap_hook_process_connection. Instead, it is
  * called manually from the churn () before it tries to read any data.
@@ -1032,6 +1058,8 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
     }
 
     if (sslconn->is_proxy) {
+        const char *hostname_note;
+
         if ((n = SSL_connect(filter_ctx->pssl)) <= 0) {
             ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
                           "SSL Proxy connect failed");
@@ -1041,6 +1069,47 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
             return HTTP_BAD_GATEWAY;
         }
 
+        if (sc->proxy_ssl_check_peer_expire == SSL_ENABLED_TRUE) {
+            apr_time_t start_time;
+            apr_time_t end_time;
+            apr_time_t now;
+
+            start_time = parseASN1time(c->pool,
+                                       ssl_var_lookup(NULL, c->base_server,
+                                                      c, NULL,
+                                                      "SSL_CLIENT_V_START"));
+            end_time = parseASN1time(c->pool,
+                                     ssl_var_lookup(NULL, c->base_server,
+                                                    c, NULL,
+                                                    "SSL_CLIENT_V_END"));
+            now = apr_time_now();
+            if ((now > end_time) || (now < start_time)) {
+                ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
+                              "SSL Proxy: Peer certificate is expired");
+                /* ensure that the SSL structures etc are freed, etc: */
+                ssl_filter_io_shutdown(filter_ctx, c, 1);
+                return HTTP_BAD_GATEWAY;
+            }
+        }
+        if ((sc->proxy_ssl_check_peer_cn == SSL_ENABLED_TRUE)
+            && ((hostname_note =
+                 apr_table_get(c->notes, "proxy-request-hostname")) != NULL)) {
+            const char *hostname;
+
+            hostname = ssl_var_lookup(NULL, c->base_server, c, NULL,
+                                      "SSL_CLIENT_S_DN_CN");
+            apr_table_unset(c->notes, "proxy-request-hostname");
+            if (strcasecmp(hostname, hostname_note)) {
+                ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
+                              "SSL Proxy: Peer certificate CN mismatch:"
+                              " Certificate CN: %s Requested hostname: %s",
+                              hostname, hostname_note);
+                /* ensure that the SSL structures etc are freed, etc: */
+                ssl_filter_io_shutdown(filter_ctx, c, 1);
+                return HTTP_BAD_GATEWAY;
+            }
+        }
+
         return APR_SUCCESS;
     }
 
index 2dfa16f65404f908af02f2a3b4a265efd84c55ce..54ca9d274dfb9891dba31d5692af990132f68c41 100644 (file)
@@ -454,6 +454,8 @@ struct SSLSrvConfigRec {
     BOOL             cipher_server_pref;
     modssl_ctx_t    *server;
     modssl_ctx_t    *proxy;
+    ssl_enabled_t    proxy_ssl_check_peer_expire;
+    ssl_enabled_t    proxy_ssl_check_peer_cn;
 };
 
 /**
@@ -532,6 +534,8 @@ const char  *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *)
 const char  *ssl_cmd_SSLProxyCARevocationFile(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_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag);
+const char  *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag);
 
 /**  module initialization  */
 int          ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *);