On the trunk:
authorStefan Eissing <icing@apache.org>
Wed, 16 Aug 2017 12:22:28 +0000 (12:22 +0000)
committerStefan Eissing <icing@apache.org>
Wed, 16 Aug 2017 12:22:28 +0000 (12:22 +0000)
mod_ssl: adding SSLPolicy and SSLProxyPolicy directives plus documentation.

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

CHANGES
docs/conf/extra/httpd-ssl.conf.in
docs/manual/mod/mod_ssl.xml
modules/ssl/mod_ssl.c
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_private.h

diff --git a/CHANGES b/CHANGES
index 826575b7f0d29c8fe6b9e8ffea83e0b59dde4a6b..e0ff6c45419dea7aaa6fdaba8712265bf8f44278 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_ssl: add SSLPolicy (define/use) and SSLProxyPolicy directives plus documentation. Add
+     core definitions for policies 'modern', 'intermediate' and 'old', as defined by Mozilla
+     in <https://wiki.mozilla.org/Security/Server_Side_TLS>. [Stefan Eissing]
+     
   *) mod_proxy: Fix ProxyAddHeaders merging.  [Joe Orton]
 
   *) mod_md: new module for managing domains across VirtualHosts with ACME protocol 
index ac1776d7c75d26584ec5750784256149ab1bb4c9..541735cfe066fcf22a9237c42e2f928eb20d5b64 100644 (file)
@@ -42,6 +42,34 @@ Listen @@SSLPort@@
 ##  the main server and all SSL-enabled virtual hosts.
 ##
 
+#   SSL Policy:
+#   Choose from a pre-defined setting of SSL* configurations, based on 
+#   the Mozilla recommendations from:
+#      https://wiki.mozilla.org/Security/Server_Side_TLS 
+#   These policies will be updated over time in new releases to keep
+#   settings compatible and secure with "modern" browser, or if you
+#   need to support legacy installtions, "intermediate" might be your
+#   choice.
+#   If you run the following command on your installation, the exact
+#   contents of the defined SSL policies will be listed:
+#
+#     > httpd -t -D DUMP_SSL_POLICIES
+#
+#   Worth noting, a SSLPolicy defines the ground rules. What ever is
+#   configured beside it, is added "on top". If a configuration has
+#   a SSLPolicy *and* a SSLCipherSuite, any cipher suite in the policy
+#   will be overwritten in this context.
+#
+#   If your OpenSSL library does not support TLSv1.2 (OpenSSL 1.0.2
+#   and later), "modern" will not be available.
+#   If you enable one of the policies below, we recommend that you
+#   refrain from configuring any of the following, unless you are
+#   certain that you want to override: 
+#      SSLCipherSuite, SSLProxyCipherSuite, SSLHonorCipherOrder,
+#      SSLProtocol, SSLProxyProtocol
+#SSLPolicy intermediate
+#SSLPolicy modern
+
 #   SSL Cipher Suite:
 #   List the ciphers that the client is permitted to negotiate,
 #   and that httpd will negotiate as the client of a proxied server.
index af29963c46335c13e742346686275b78742f96a0..1000597132ee3ccdbb4820b4b4a5fc6c97a82ffe 100644 (file)
@@ -2813,4 +2813,193 @@ SSLOpenSSLConfCmd SignatureAlgorithms RSA+SHA384:ECDSA+SHA256
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLPolicySection</name>
+<description></description>
+<syntax>&lt;SSLPolicy <em>name</em>&gt;</syntax>
+<contextlist><context>server config</context></contextlist>
+<compatibility>Available in httpd 2.4.28 and later</compatibility>
+
+<usage>
+<p>This directive defines a set of SSL* configurations under
+and gives it a name. This name can be used in the directives
+<directive>SSLPolicy</directive> and <directive>SSLProxyPolicy</directive>
+to apply this configuration set in the current context.</p>
+
+<example><title>Examples</title>
+<highlight language="config">
+&lt;SSLPolicy safe-stapling&gt;
+   SSLUseStapling on
+   SSLStaplingResponderTimeout 2
+   SSLStaplingReturnResponderErrors off
+   SSLStaplingFakeTryLater off
+   SSLStaplingStandardCacheTimeout 86400
+&lt;/SSLPolicy&gt;
+
+   ...
+   &lt;VirtualHost...&gt;
+      SSLPolicy safe-stapling
+      ...
+</highlight>
+</example>
+
+<p>On the one hand, this can make server configurations easier to 
+<em>read</em> and <em>maintain</em>. On the other hand, it is 
+intended to make SSL easier and safer to <em>use</em>. For the 
+latter, Apache httpd ships with a set of pre-defined policies
+that reflect good open source practise. The policy "modern",
+for example, carries the settings to make your server work
+compatible and securely with current browsers.</p>
+
+<p>The list of predefined policies in your Apache can be obtained
+by running the following command. This list shows you the 
+detailed configurations each policy is made of:</p>
+
+<example><title>Examples</title>
+<highlight language="sh">
+> httpd -t -D DUMP_SSL_POLICIES
+</highlight>
+</example>
+
+<p>The directive can only be used in the server config (global context), so 
+there cannot be two policies with the same name. However, policies can
+be redefined:</p>
+
+<example><title>Examples</title>
+<highlight language="config">
+&lt;SSLPolicy proxy-trust&gt;
+   SSLProxyVerify require
+&lt;/SSLPolicy&gt;
+   ...
+&lt;SSLPolicy proxy-trust&gt;
+   SSLProxyVerify none
+&lt;/SSLPolicy&gt;
+</highlight>
+</example>
+
+<p>Policy definitions are <em>added</em> in the order they appear, but are
+<em>applied</em> when the whole configuration is read. This means that any
+use of 'proxy-trust' will mean 'SSLProxyVerify none'. The first definition
+has no effect at all. You can replace policy definitions that have been
+pre-installed without the need to disable them.</p>
+
+<p>Additional to replacing policies, redefinitions may just alter
+an aspect of a policy:</p>
+
+<example><title>Examples</title>
+<highlight language="config">
+&lt;SSLPolicy proxy-trust&gt;
+   SSLProxyVerify require
+&lt;/SSLPolicy&gt;
+   ...
+&lt;SSLPolicy proxy-trust&gt;
+   SSLPolicy proxy-trust
+   SSLProxyVerifyDepth 10
+&lt;/SSLPolicy&gt;
+</highlight>
+</example>
+
+<p>This re-uses all settings from the previous 'proxy-trust' and adds
+one directive on top of it. All others still apply. This is very handy
+when pre-defined policies (from Apache itself or a distributor)
+that <em>almost</em> fit ones needs. Previously, such definitions were
+(copied and) edited. This made updating them difficult. Now they can
+be setup like this:</p>
+
+<example><title>Examples</title>
+<highlight language="config">
+Include ssl-policies.conf
+
+&lt;SSLPolicy modern&gt;
+   SSLPolicy modern
+   SSLProxyVerify none
+&lt;/SSLPolicy&gt;
+</highlight>
+</example>
+
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>SSLPolicy</name>
+<description></description>
+<syntax>SSLPolicy <em>name</em></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+<compatibility>Available in httpd 2.4.28 and later</compatibility>
+
+<usage>
+<p>This directive applies the set of SSL* directives defined
+under 'name' (see <directive>SSLPolicySection</directive>) as the <em>base</em>
+settings in the current context. That means that any other SSL* directives
+you make in the same context remain effective. So, the effective
+<directive>SSLProtocol</directive> value in the following settings are:</p>
+
+<example><title>Examples</title>
+<highlight language="config">
+   &lt;VirtualHost...&gt; # effective: 'all'
+      SSLPolicy modern
+      SSLProtocol all
+   &lt;/VirtualHost&gt;
+
+   &lt;VirtualHost...&gt; # effective: 'all'
+      SSLProtocol all
+      SSLPolicy modern
+   &lt;/VirtualHost&gt;
+
+   SSLPolicy modern
+   &lt;VirtualHost...&gt; # effective: 'all'
+      SSLProtocol all
+   &lt;/VirtualHost&gt;
+   
+   SSLProtocol all
+   &lt;VirtualHost...&gt; # effective: '+TLSv1.2'
+     SSLPolicy modern
+   &lt;/VirtualHost&gt;
+</highlight>
+</example>
+
+<p>There can be more than one policy applied in a context. The
+later ones overshadowing the earlier ones:</p>
+
+<example><title>Examples</title>
+<highlight language="config">
+   &lt;VirtualHost...&gt; # effective: 'intermediate &gt; modern'
+      SSLPolicy modern
+      SSLPolicy intermediate
+   &lt;/VirtualHost&gt;
+
+   &lt;VirtualHost...&gt; # effective: 'modern &gt; intermediate'
+      SSLPolicy intermediate
+      SSLPolicy modern
+   &lt;/VirtualHost&gt;
+</highlight>
+</example>
+
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>SSLProxyPolicy</name>
+<description></description>
+<syntax>SSLProxyPolicy <em>name</em></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+<compatibility>Available in httpd 2.4.28 and later</compatibility>
+
+<usage>
+<p>This directive is similar to <directive>SSLPolicy</directive>, but 
+applies only the SSLProxy* directives defined in the policy. This helps
+when you need different policies for front and backends:</p>
+
+<example><title>Examples</title>
+<highlight language="config">
+SSLPolicy modern
+SSLProxyPolicy intermediate
+</highlight>
+</example>
+
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>
index 6df5d43055df78ba28bf9040e27b02b8f11879ab..d6c87edd8daeee5a40e18a8864a4d0de0b756eae 100644 (file)
@@ -312,6 +312,15 @@ static const command_rec ssl_config_cmds[] = {
     AP_INIT_RAW_ARGS("SSLLogLevel", ap_set_deprecated, NULL, OR_ALL,
       "SSLLogLevel directive is no longer supported - use LogLevel."),
 
+    AP_INIT_TAKE1("<SSLPolicy", ssl_cmd_SSLPolicyDefine, NULL, RSRC_CONF, 
+                "Define a set of SSL* configurations under a new name. Such a policy may "
+                "be used in any location where the SSL* directives are viable. The policy "
+                "may contain both SSL* and SSLProxy* specific settings. Which one is applied "
+                "depends on the use."),
+    AP_INIT_TAKE1("SSLPolicy", ssl_cmd_SSLPolicyApply, NULL, RSRC_CONF, 
+                "Use the SSL* (not the SSLProxy*) settings from the policy with the given name."),
+    AP_INIT_TAKE1("SSLProxyPolicy", ssl_cmd_SSLProxyPolicyApply, NULL, RSRC_CONF|PROXY_CONF, 
+                "Use the SSLProxy* settings from the policy with the given name."),
     AP_END_CMD
 };
 
index 037ba1179bd85b4ba51b4b229630d9259fadb1b2..eea424e688d0b4ecc840f264870f4b9150d674b9 100644 (file)
@@ -26,6 +26,9 @@
                                       /* ``Damned if you do,
                                            damned if you don't.''
                                                -- Unknown        */
+#include <stdio.h>
+#include <stdlib.h>
+
 #include "ssl_private.h"
 #include "util_mutex.h"
 #include "ap_provider.h"
@@ -226,6 +229,8 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p)
     sc->compression            = UNSET;
 #endif
     sc->session_tickets        = UNSET;
+    sc->policies               = NULL;
+    sc->error_policy           = NULL;
 
     modssl_ctx_init_server(sc, p);
 
@@ -339,12 +344,19 @@ static void modssl_ctx_cfg_merge_server(apr_pool_t *p,
 #endif
 }
 
+static void ssl_policy_apply(SSLSrvConfigRec *sc, apr_pool_t *p);
+static void ssl_dir_policy_apply(SSLDirConfigRec *dc, apr_pool_t *p);
+
 void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
 {
     SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev;
     SSLSrvConfigRec *add  = (SSLSrvConfigRec *)addv;
     SSLSrvConfigRec *mrg  = ssl_config_server_new(p);
 
+    /* This is a NOP, unless a policy has not been applied yet */
+    ssl_policy_apply(base, p);
+    ssl_policy_apply(add, p);
+    
     cfgMerge(mc, NULL);
     cfgMerge(enabled, SSL_ENABLED_UNSET);
     cfgMergeInt(session_cache_timeout);
@@ -361,6 +373,9 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
 #endif
     cfgMergeBool(session_tickets);
 
+    mrg->policies = NULL;
+    cfgMergeString(error_policy);
+                         
     modssl_ctx_cfg_merge_server(p, base->server, add->server, mrg->server);
 
     return mrg;
@@ -410,6 +425,9 @@ void *ssl_config_perdir_create(apr_pool_t *p, char *dir)
     modssl_ctx_init_proxy(dc, p);
     dc->proxy_post_config = FALSE;
 
+    dc->policies = NULL;
+    dc->error_policy = NULL;
+    
     return dc;
 }
 
@@ -435,6 +453,9 @@ void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv)
     SSLDirConfigRec *add  = (SSLDirConfigRec *)addv;
     SSLDirConfigRec *mrg  = (SSLDirConfigRec *)apr_palloc(p, sizeof(*mrg));
 
+    ssl_dir_policy_apply(base, p);
+    ssl_dir_policy_apply(add, p);
+    
     cfgMerge(bSSLRequired, FALSE);
     cfgMergeArray(aRequirement);
 
@@ -474,6 +495,9 @@ void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv)
         mrg->proxy = add->proxy;
     }
 
+    mrg->policies = NULL;
+    cfgMergeString(error_policy);
+
     return mrg;
 }
 
@@ -488,6 +512,314 @@ void ssl_config_proxy_merge(apr_pool_t *p,
     modssl_ctx_cfg_merge_proxy(p, base->proxy, conf->proxy, conf->proxy);
 }
 
+/*  _________________________________________________________________
+**
+**  Policy handling
+**  _________________________________________________________________
+*/
+
+#define SSL_MOD_POLICIES_KEY "ssl_module_policies"
+
+/**
+ * Define a core set of policies that are always there:
+ * - 'modern' from https://wiki.mozilla.org/Security/Server_Side_TLS
+ * - 'intermediate' from https://wiki.mozilla.org/Security/Server_Side_TLS
+ * - 'old' from https://wiki.mozilla.org/Security/Server_Side_TLS
+ */
+#ifdef HAVE_TLSV1_X
+    /* Only with OpenSSL > v1.0.2 do we have a chance to implement modern */
+#define SSL_POLICY_LEGACY_PROTOCOLS  \
+    (SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1|SSL_PROTOCOL_TLSV1_1)
+
+#define SSL_POLICY_MODERN_PROTOCOLS  \
+    (SSL_PROTOCOL_ALL & ~SSL_POLICY_LEGACY_PROTOCOLS)
+#define SSL_POLICY_MODERN_CIPHERS  \
+    "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:" \
+    "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:" \
+    "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:" \
+    "ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:" \
+    "ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
+#endif
+    
+#define SSL_POLICY_INTERMEDIATE_PROTOCOLS \
+    (SSL_PROTOCOL_ALL & ~SSL_PROTOCOL_SSLV3)
+#define SSL_POLICY_INTERMEDIATE_CIPHERS \
+    "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:" \
+    "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:" \
+    "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:" \
+    "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:" \
+    "ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:" \
+    "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:" \
+    "ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:" \
+    "DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:" \
+    "ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:" \
+    "AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:" \
+    "AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS"
+
+#define SSL_POLICY_OLD_PROTOCOLS            (SSL_PROTOCOL_ALL)
+#define SSL_POLICY_OLD_CIPHERS \
+    "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:" \
+    "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:" \
+    "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:" \
+    "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:" \
+    "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:" \
+    "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:" \
+    "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:" \
+    "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:" \
+    "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:" \
+    "ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:" \
+    "AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:" \
+    "DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:" \
+    "!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP"
+
+#define SSL_POLICY_PROXY_VERIFY_MODE    SSL_CVERIFY_REQUIRE
+#define SSL_POLICY_PROXY_VERIFY_DEPTH   -1
+
+static void add_policy(apr_hash_t *policies, apr_pool_t *p, const char *name,
+                       int protocols, const char *ciphers, 
+                       int honor_order, int compression, int session_tickets,
+                       ssl_verify_t proxy_verify_mode, int proxy_verify_depth)
+{
+    SSLPolicyRec *policy;
+    
+    policy = apr_pcalloc(p, sizeof(*policy));
+    policy->name = name;
+    policy->sc = ssl_config_server_new(p);
+    policy->dc = ssl_config_perdir_create(p, "/");
+    
+    if (protocols || ciphers) {
+        policy->sc->server->protocol_set      = 1;
+        policy->sc->server->protocol          = protocols;
+        policy->dc->proxy->protocol_set       = 1;
+        policy->dc->proxy->protocol           = protocols;
+    }
+    
+    if (ciphers) {
+        policy->sc->server->auth.cipher_suite = ciphers;
+        policy->dc->proxy->auth.cipher_suite = ciphers;
+    }
+
+    policy->sc->compression               = compression ? TRUE : FALSE;
+    policy->sc->session_tickets           = session_tickets ? TRUE : FALSE;
+    
+    policy->dc->proxy->auth.verify_mode  = proxy_verify_mode;
+    if (proxy_verify_depth >= 0) {
+        policy->dc->proxy->auth.verify_depth = proxy_verify_depth;
+    }
+    
+    apr_hash_set(policies, policy->name, APR_HASH_KEY_STRING, policy);
+}
+
+static apr_hash_t *get_policies(apr_pool_t *p, int create)
+{
+    apr_hash_t *policies;
+    void *vp;
+    
+    apr_pool_userdata_get(&vp, SSL_MOD_POLICIES_KEY, p);
+    if (vp) {
+        return vp; /* reused for lifetime of the pool */
+    }
+    if (create) {
+        policies = apr_hash_make(p);
+        
+        /* We could also invoke the commands here and let them parse strings. */
+#ifdef HAVE_TLSV1_X
+        add_policy(policies, p, "modern", 
+                   SSL_POLICY_MODERN_PROTOCOLS, SSL_POLICY_MODERN_CIPHERS, 
+                   1, 0, 0, 
+                   SSL_POLICY_PROXY_VERIFY_MODE, SSL_POLICY_PROXY_VERIFY_DEPTH);
+#endif        
+        add_policy(policies, p, "intermediate", 
+                   SSL_POLICY_INTERMEDIATE_PROTOCOLS, SSL_POLICY_INTERMEDIATE_CIPHERS, 
+                   1, 0, 0, 
+                   SSL_POLICY_PROXY_VERIFY_MODE, SSL_POLICY_PROXY_VERIFY_DEPTH);
+                   
+        add_policy(policies, p, "old", 
+                   SSL_POLICY_OLD_PROTOCOLS, SSL_POLICY_OLD_CIPHERS, 
+                   1, 0, 0, 
+                   SSL_CVERIFY_NONE, -1);
+        
+        apr_pool_userdata_set(policies, SSL_MOD_POLICIES_KEY,
+                              apr_pool_cleanup_null, p);
+        return policies;
+    }
+    return NULL;
+}
+
+static int policy_collect_names(void *baton, const void *key, apr_ssize_t klen, const void *val)
+{
+    apr_array_header_t *names = baton;
+    APR_ARRAY_PUSH(names, const char *) = (const char*)key;
+    return 1;
+}
+
+static int qstrcmp(const void *v1, const void *v2)
+{
+    return strcmp(*(const char**)v1, *(const char**)v2);
+}
+
+static apr_array_header_t *get_policy_names(apr_pool_t *p, int create)
+{
+    apr_array_header_t *names = apr_array_make(p, 10, sizeof(const char*));
+    apr_hash_t *policies = get_policies(p, create);
+    
+    if (policies) {
+        apr_hash_do(policy_collect_names, names, policies);
+        qsort(names->elts, names->nelts, sizeof(const char*), qstrcmp);
+    }
+    return names;
+}
+
+SSLPolicyRec *ssl_policy_lookup(apr_pool_t *pool, const char *name)
+{
+    apr_hash_t *policies = get_policies(pool, 0);
+    if (policies) {
+        return apr_hash_get(policies, name, APR_HASH_KEY_STRING);
+    }
+    else if ((pool = apr_pool_parent_get(pool))) {
+        return ssl_policy_lookup(pool, name);
+    }
+    return NULL;
+}
+
+static void ssl_policy_set(apr_pool_t *pool, SSLPolicyRec *policy)
+{
+    apr_hash_t *policies = get_policies(pool, 1);
+    return apr_hash_set(policies, policy->name, APR_HASH_KEY_STRING, policy);
+}
+
+const char *ssl_cmd_SSLPolicyDefine(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+    server_rec *s = cmd->server;
+    SSLSrvConfigRec *sc = mySrvConfig(s);
+    SSLDirConfigRec *dc = ap_get_module_config(s->lookup_defaults, &ssl_module);
+    SSLPolicyRec *policy;
+    const char *endp = ap_strrchr_c(arg, '>');
+    const char *err, *name;
+
+    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+        return err;
+    }
+        
+    if (endp == NULL) {
+        return apr_pstrcat(cmd->pool, cmd->cmd->name, "> directive missing closing '>'", NULL);
+    }
+
+    arg = apr_pstrndup(cmd->pool, arg, endp-arg);
+    if (!arg || !*arg) {
+        return "<SSLPolicy > block must specify a name";
+    }
+
+    name = ap_getword_white(cmd->pool, &arg);
+    if (*arg != '\0') {
+        return apr_pstrcat(cmd->pool, cmd->cmd->name, "> takes only 1 argument", NULL);
+    }
+    
+    policy = apr_pcalloc(cmd->pool, sizeof(*policy));
+    policy->name = name;
+    policy->sc = ssl_config_server_new(cmd->pool);
+    policy->dc = ssl_config_perdir_create(cmd->pool, "/");/* TODO */
+
+    ap_set_module_config(s->module_config,  &ssl_module, policy->sc);
+    ap_set_module_config(s->lookup_defaults,  &ssl_module, policy->dc);
+    
+    err = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
+    if (!err) {
+        /* If this new policy uses other policies, we need to merge it
+         * before adding, otherwise a policy cannot re-use an existing one */
+        ssl_policy_apply(policy->sc, cmd->pool);
+        ssl_dir_policy_apply(policy->dc, cmd->pool);
+        /* time to persist */
+        ssl_policy_set(cmd->pool, policy);
+    }
+    
+    ap_set_module_config(s->module_config,  &ssl_module, sc);
+    ap_set_module_config(s->lookup_defaults,  &ssl_module, dc);
+
+    return err;
+}
+
+const char *ssl_cmd_SSLPolicyApply(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+    
+    if (!sc->policies) {
+        sc->policies = apr_array_make(cmd->pool, 5, sizeof(const char*));
+    }
+    APR_ARRAY_PUSH(sc->policies, const char *) = arg;
+
+    /* Also apply the proxy parts of the policy */
+    return ssl_cmd_SSLProxyPolicyApply(cmd, mconfig, arg);
+}
+
+const char *ssl_cmd_SSLProxyPolicyApply(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+    SSLDirConfigRec *dc = ap_get_module_config(cmd->server->lookup_defaults, &ssl_module);
+    
+    if (!dc->policies) {
+        dc->policies = apr_array_make(cmd->pool, 5, sizeof(const char*));
+    }
+    APR_ARRAY_PUSH(dc->policies, const char *) = arg;
+
+    return NULL;
+}
+
+void ssl_policy_apply(SSLSrvConfigRec *sc, apr_pool_t *p)
+{
+    SSLSrvConfigRec *mrg;
+    SSLPolicyRec *policy;
+    apr_array_header_t *policies;
+    const char *name;
+    int i;
+
+    policies = sc->policies;
+    if (policies && policies->nelts > 0 && !sc->error_policy) {
+        sc->policies = NULL;
+        for (i = policies->nelts - 1; i >= 0; --i) {
+            name = APR_ARRAY_IDX(policies, i, const char *);
+            policy = ssl_policy_lookup(p, name);
+            if (policy) {
+                mrg = ssl_config_server_merge(p, policy->sc, sc);
+                /* apply in place */
+                memcpy(sc, mrg, sizeof(*sc));
+            }
+            else {
+                sc->error_policy = name;
+                break;
+                /* report error policies in post_config */
+            }
+        }
+    }
+}
+
+void ssl_dir_policy_apply(SSLDirConfigRec *dc, apr_pool_t *p)
+{
+    SSLDirConfigRec *mrg;
+    SSLPolicyRec *policy;
+    apr_array_header_t *policies;
+    const char *name;
+    int i;
+    
+    policies = dc->policies;
+    if (policies && policies->nelts > 0 &&!dc->error_policy) {
+        dc->policies = NULL;
+        for (i = policies->nelts - 1; i >= 0; --i) {
+            name = APR_ARRAY_IDX(policies, i, const char *);
+            policy = ssl_policy_lookup(p, name);
+            if (policy) {
+                mrg = ssl_config_perdir_merge(p, policy->dc, dc);
+                /* apply in place */
+                memcpy(dc, mrg, sizeof(*dc));
+            }
+            else {
+                dc->error_policy = name;
+                break;
+                /* report error policies in post_config */
+            }
+        }
+    }
+}
+
 /*
  *  Configuration functions for particular directives
  */
@@ -588,6 +920,7 @@ const char *ssl_cmd_SSLRandomSeed(cmd_parms *cmd,
     ssl_randseed_t *seed;
     int arg2len = strlen(arg2);
 
+    /* replace: check_no_policy_and(flags) */
     if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
         return err;
     }
@@ -1996,6 +2329,13 @@ const char *ssl_cmd_SSLOCSPResponderCertificateFile(cmd_parms *cmd, void *dcfg,
     return NULL;
 }
 
+static void ssl_srv_dump(SSLSrvConfigRec *sc, apr_pool_t *p, 
+                            apr_file_t *out, const char *indent, const char **psep);
+static void ssl_dir_dump(SSLDirConfigRec *dc, apr_pool_t *p, 
+                         apr_file_t *out, const char *indent, const char **psep);
+static void ssl_policy_dump(SSLPolicyRec *policy, apr_pool_t *p, 
+                            apr_file_t *out, const char *indent);
+
 void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
 {
     apr_file_t *out = NULL;
@@ -2056,4 +2396,412 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
         return;
     }
 
+    if (ap_exists_config_define("DUMP_SSL_POLICIES")) {
+        apr_array_header_t *names = get_policy_names(pconf, 1);
+        SSLPolicyRec *policy;
+        const char *name, *sep = "";
+        int i;
+        
+        apr_file_open_stdout(&out, pconf);
+        apr_file_printf(out, "SSLPolicies: {");
+        for (i = 0; i < names->nelts; ++i) {
+            name = APR_ARRAY_IDX(names, i, const char*);
+            policy = ssl_policy_lookup(pconf, name);
+            if (policy) {
+                apr_file_printf(out, "%s\n  \"%s\": {", sep, name);
+                sep = ", ";
+                ssl_policy_dump(policy, pconf, out, "    ");
+                apr_file_printf(out, "\n  }");
+            }
+        }
+        apr_file_printf(out, "\n}\n");
+        return;
+    }
+}
+
+/*  _________________________________________________________________
+**
+**  Dump Config Data
+**  _________________________________________________________________
+*/
+
+static const char *json_quote(const char *s, apr_pool_t *p)
+{
+    const char *src, *dq = s;
+    int n = 0;
+    
+    while ((dq = ap_strchr_c(dq, '\"'))) {
+        ++n;
+        ++dq;
+    }
+    if (n > 0) {
+        char *dst, c;
+        src = s;
+        s = dst = apr_pcalloc(p, strlen(s) + n + 1);
+        while ((c = *src++)) {
+            if (c == '\"') {
+                *dst++ = '\\';
+            }
+            *dst++ = c;
+        }
+    }
+    return s;
+}
+
+static void val_str_dump(apr_file_t *out, const char *key, const char *val, 
+                         apr_pool_t *p, const char *indent, const char **psep)
+{
+    if (val) {
+        /* TODO: JSON quite string val */
+        apr_file_printf(out, "%s\n%s\"%s\": \"%s\"", *psep, indent, key, json_quote(val, p));
+        *psep = ", ";
+    }
+}
+
+static void val_str_array_dump(apr_file_t *out, const char *key, apr_array_header_t *val, 
+                               apr_pool_t *p, const char *indent, const char **psep)
+{
+    if (val && val->nelts > 0) {
+        const char *s; 
+        int i;
+        
+        for (i = 0; i < val->nelts; ++i) {
+            s = APR_ARRAY_IDX(val, i, const char*);
+            val_str_dump(out, key, s, p, indent, psep);
+        }
+    }
+}
+
+static void val_long_dump(apr_file_t *out, const char *key, long val, 
+                          apr_pool_t *p, const char *indent, const char **psep)
+{
+    if (val != UNSET) {
+        apr_file_printf(out, "%s\n%s\"%s\": %ld", *psep, indent, key, val);
+        *psep = ", ";
+    }
+}
+
+static void val_itime_dump(apr_file_t *out, const char *key, apr_interval_time_t val, 
+                           apr_pool_t *p, const char *indent, const char **psep)
+{
+    if (val != UNSET) {
+        apr_file_printf(out, "%s\n%s\"%s\": %f", *psep, indent, key, 
+                        ((double)val/APR_USEC_PER_SEC));
+        *psep = ", ";
+    }
+}
+
+static void val_onoff_dump(apr_file_t *out, const char *key, BOOL val, 
+                           apr_pool_t *p, const char *indent, const char **psep)
+{
+    if (val != UNSET) {
+        val_str_dump(out, key, val? "on" : "off", p, indent, psep);
+    }
+}
+
+static void val_uri_dump(apr_file_t *out, const char *key, apr_uri_t *val, 
+                         apr_pool_t *p, const char *indent, const char **psep)
+{
+    if (val) {
+        val_str_dump(out, key, apr_uri_unparse(p, val, 0), p, indent, psep);
+    }
+}
+
+static void val_verify_dump(apr_file_t *out, const char *key, ssl_verify_t mode, 
+                            apr_pool_t *p, const char *indent, const char **psep)
+{
+    switch (mode) {
+        case SSL_CVERIFY_NONE:
+            val_str_dump(out, key, "none", p, indent, psep);
+            return;
+        case SSL_CVERIFY_OPTIONAL:
+            val_str_dump(out, key, "optional", p, indent, psep);
+            return;
+        case SSL_CVERIFY_REQUIRE:
+            val_str_dump(out, key, "require", p, indent, psep);
+            return;
+        case SSL_CVERIFY_OPTIONAL_NO_CA:
+            val_str_dump(out, key, "optional_no_ca", p, indent, psep);
+            return;
+        default:
+            return;
+    }
+}
+
+static void val_enabled_dump(apr_file_t *out, const char *key, ssl_enabled_t val, 
+                             apr_pool_t *p, const char *indent, const char **psep)
+{
+    switch (val) {
+        case SSL_ENABLED_FALSE:
+            val_str_dump(out, key, "off", p, indent, psep);
+            return;
+        case SSL_ENABLED_TRUE:
+            val_str_dump(out, key, "on", p, indent, psep);
+            return;
+        case SSL_ENABLED_OPTIONAL:
+            val_str_dump(out, key, "optional", p, indent, psep);
+            return;
+        default:                   
+            return;
+    }
+}
+
+static void val_pphrase_dump(apr_file_t *out, const char *key, 
+                             ssl_pphrase_t pphrase_type, const char *path, 
+                             apr_pool_t *p, const char *indent, const char **psep)
+{
+    switch (pphrase_type) {
+        case SSL_PPTYPE_BUILTIN: 
+            val_str_dump(out, key, "builtin", p, indent, psep);
+            return;
+        case SSL_PPTYPE_FILTER: 
+            val_str_dump(out, key, apr_pstrcat(p, "|", path, NULL), p, indent, psep);
+            return;
+        case SSL_PPTYPE_PIPE: 
+            val_str_dump(out, key, apr_pstrcat(p, "exec:", path, NULL), p, indent, psep);
+            return;
+        default:
+            return;
+    }
+}
+
+static void val_crl_check_dump(apr_file_t *out, const char *key, int mask, 
+                               apr_pool_t *p, const char *indent, const char **psep)
+{
+    if (mask != UNSET) {
+        if (mask == SSL_CRLCHECK_NONE) {
+            val_str_dump(out, key, "none", p, indent, psep);
+        }
+        else if (mask == SSL_CRLCHECK_LEAF) {
+            val_str_dump(out, key, "leaf", p, indent, psep);
+        }
+        else if (mask == SSL_CRLCHECK_CHAIN) {
+            val_str_dump(out, key, "chain", p, indent, psep);
+        }
+        else if (mask == (SSL_CRLCHECK_CHAIN|SSL_CRLCHECK_NO_CRL_FOR_CERT_OK)) {
+            val_str_dump(out, key, "chain no_crl_for_cert_ok", p, indent, psep);
+        }
+        else {
+            val_str_dump(out, key, "???", p, indent, psep);
+        }
+    }
+}
+
+static void val_option_dump(apr_file_t *out, const char *key, const char *optname,
+                            int val, int set_mask, int add_mask, int del_mask, 
+                            apr_pool_t *p, const char *indent, const char **psep)
+{
+    const char *op = ((val & set_mask)? "" : 
+                      ((val & add_mask)? "+" :
+                       (val & del_mask)? "-" : NULL));
+    if (op) {
+        apr_file_printf(out, "%s\n%s\"%s\": \"%s%s\"", *psep, indent, key, op, 
+                        json_quote(optname, p));
+        *psep = ", ";
+    }
+}
+
+static const char *protocol_str(ssl_proto_t proto, apr_pool_t *p)
+{
+    if (SSL_PROTOCOL_NONE == proto) {
+        return "none";
+    }
+    else if (SSL_PROTOCOL_ALL == proto) {
+        return "all";
+    }
+    else {
+        /* icing: I think it is nuts that we define our own IETF protocol constants
+         * only whent the linked *SSL lib supports them. */
+        apr_array_header_t *names = apr_array_make(p, 5, sizeof(const char*));
+        if ((1<<4) & proto) {
+            APR_ARRAY_PUSH(names, const char*) = "+TLSv1.2";
+        }
+        if ((1<<3) & proto) {
+            APR_ARRAY_PUSH(names, const char*) = "+TLSv1.1";
+        }
+        if ((1<<2) & proto) {
+            APR_ARRAY_PUSH(names, const char*) = "+TLSv1.0";
+        }
+        if ((1<<1) & proto) {
+            APR_ARRAY_PUSH(names, const char*) = "+SSLv3";
+        }
+        return apr_array_pstrcat(p, names, ' ');
+    }
+}
+
+#define DMP_STRING(k,v) \
+    val_str_dump(out, k, v, p, indent, psep)
+#define DMP_LONG(k,v) \
+    val_long_dump(out, k, v, p, indent, psep)
+#define DMP_ITIME(k,v) \
+    val_itime_dump(out, k, v, p, indent, psep)
+#define DMP_STRARR(k,v) \
+    val_str_array_dump(out, k, v, p, indent, psep)
+#define DMP_VERIFY(k,v) \
+    val_verify_dump(out, k, v, p, indent, psep)
+#define DMP_ON_OFF(k,v) \
+    val_onoff_dump(out, k, v, p, indent, psep)
+#define DMP_URI(k,v) \
+    val_uri_dump(out, k, v, p, indent, psep)
+#define DMP_CRLCHK(k,v) \
+    val_crl_check_dump(out, k, v, p, indent, psep)
+#define DMP_PHRASE(k,v, v2) \
+    val_pphrase_dump(out, k, v, v2, p, indent, psep)
+#define DMP_ENABLD(k,v) \
+    val_enabled_dump(out, k, v, p, indent, psep)
+#define DMP_OPTION(n,v) \
+    val_option_dump(out, "SSLOption", n, v, \
+                    dc->nOptions, dc->nOptionsAdd, dc->nOptionsDel, p, indent, psep);
+
+static void modssl_auth_ctx_dump(modssl_auth_ctx_t *auth, apr_pool_t *p, int proxy,
+                                 apr_file_t *out, const char *indent, const char **psep)
+{
+    DMP_STRING(proxy? "SSLProxyCipherSuite" : "SSLCipherSuite", auth->cipher_suite);
+    DMP_VERIFY(proxy? "SSLProxyVerify" : "SSLVerifyClient", auth->verify_mode);
+    DMP_LONG(  proxy? "SSLProxyVerify" : "SSLVerifyDepth", auth->verify_depth);
+    DMP_STRING(proxy? "SSLProxyCACertificateFile" : "SSLCACertificateFile", auth->ca_cert_file);
+    DMP_STRING(proxy? "SSLProxyCACertificatePath" : "SSLCACertificatePath", auth->ca_cert_path);
+}
+
+static void modssl_ctx_dump(modssl_ctx_t *ctx, apr_pool_t *p, int proxy,
+                            apr_file_t *out, const char *indent, const char **psep)
+{
+    int i;
+    
+    if (ctx->protocol_set) {
+        DMP_STRING(proxy? "SSLProxyProtocol" : "SSLProtocol", protocol_str(ctx->protocol, p));
+    }
+
+    modssl_auth_ctx_dump(&ctx->auth, p, proxy, out, indent, psep);
+    
+    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("SSLCADNRequestFile", ctx->pks->ca_name_file);
+            DMP_STRING("SSLCADNRequestPath", ctx->pks->ca_name_path);
+            DMP_STRARR("SSLCertificateFile", ctx->pks->cert_files);
+            DMP_STRARR("SSLCertificateKeyFile", ctx->pks->key_files);
+        }
+#ifdef HAVE_OCSP_STAPLING
+        DMP_ON_OFF("SSLUseStapling", ctx->stapling_enabled);
+        DMP_LONG(  "SSLStaplingResponseTimeSkew", ctx->stapling_resptime_skew);
+        DMP_LONG(  "SSLStaplingResponseMaxAge", ctx->stapling_resp_maxage);
+        DMP_LONG(  "SSLStaplingStandardCacheTimeout", ctx->stapling_cache_timeout);
+        DMP_ON_OFF("SSLStaplingReturnResponderErrors", ctx->stapling_return_errors);
+        DMP_ON_OFF("SSLStaplingFakeTryLater", ctx->stapling_fake_trylater);
+        DMP_LONG(  "SSLStaplingErrorCacheTimeout", ctx->stapling_errcache_timeout);
+        DMP_ITIME( "SSLStaplingResponderTimeout", ctx->stapling_responder_timeout);
+        DMP_STRING("SSLStaplingForceURL", ctx->stapling_force_url);
+#endif /* if HAVE_OCSP_STAPLING */ 
+        
+#ifdef HAVE_SRP
+        DMP_STRING("SSLSRPUnknownUserSeed", ctx->srp_unknown_user_seed);
+        DMP_STRING("SSLSRPVerifierFile", ctx->srp_vfile);
+#endif
+        DMP_ON_OFF("SSLOCSPEnable", ctx->ocsp_enabled);
+        DMP_ON_OFF("SSLOCSPOverrideResponder", ctx->ocsp_force_default);
+        DMP_STRING("SSLOCSPDefaultResponder", ctx->ocsp_responder);
+        DMP_LONG(  "SSLOCSPResponseTimeSkew", ctx->ocsp_resptime_skew);
+        DMP_LONG(  "SSLOCSPResponseMaxAge", ctx->ocsp_resp_maxage);
+        DMP_ITIME( "SSLOCSPResponderTimeout", ctx->ocsp_responder_timeout);
+        DMP_ON_OFF("SSLOCSPUseRequestNonce", ctx->ocsp_use_request_nonce);
+        DMP_URI(   "SSLOCSPProxyURL", ctx->proxy_uri);
+        DMP_ON_OFF("SSLOCSPNoVerify", ctx->ocsp_noverify);
+        DMP_STRING("SSLOCSPResponderCertificateFile", ctx->ocsp_certs_file);
+        
+#ifdef HAVE_SSL_CONF_CMD
+        if (ctx->ssl_ctx_param && ctx->ssl_ctx_param->nelts > 0) {
+            ssl_ctx_param_t *param = (ssl_ctx_param_t *)ctx->ssl_ctx_param->elts;
+            for (i = 0; i < ctx->ssl_ctx_param->nelts; ++i, ++param) {
+                apr_file_printf(out, "%s\n%s\"%s\": \"%s %s\"", *psep, indent, 
+                                "SSLOpenSSLConfCmd", json_quote(param->name, p), 
+                                json_quote(param->value, p));
+                *psep = ", ";
+            }
+        } 
+#endif
+
+#ifdef HAVE_TLS_SESSION_TICKETS
+        if (ctx->ticket_key) {
+            DMP_STRING("SSLSessionTicketKeyFile", ctx->ticket_key->file_path);
+        }
+#endif
+    }
+    else { /* proxy */
+        if (ctx->pkp) {
+            DMP_STRING("SSLProxyMachineCertificateFile", ctx->pkp->cert_file);
+            DMP_STRING("SSLProxyMachineCertificatePath", ctx->pkp->cert_path);
+            DMP_STRING("SSLProxyMachineCertificateChainFile", ctx->pkp->ca_cert_file);
+        }
+        DMP_ON_OFF("SSLProxyCheckPeerCN", ctx->ssl_check_peer_cn);
+        DMP_ON_OFF("SSLProxyCheckPeerName", ctx->ssl_check_peer_cn);
+        DMP_ON_OFF("SSLProxyCheckPeerExpire", ctx->ssl_check_peer_expire);
+    }
+}
+
+static void ssl_srv_dump(SSLSrvConfigRec *sc, apr_pool_t *p, 
+                            apr_file_t *out, const char *indent, const char **psep)
+{
+    DMP_ENABLD("SSLEngine", sc->enabled);
+    DMP_ON_OFF("SSLHonorCipherOrder", sc->cipher_server_pref);
+
+#ifndef OPENSSL_NO_COMP
+    DMP_ON_OFF("SSLCompression", sc->compression);
+#endif
+
+    modssl_ctx_dump(sc->server, p, 0, out, indent, psep);
+
+    DMP_LONG(  "SSLSessionCacheTimeout", sc->session_cache_timeout);
+    DMP_ON_OFF("SSLInsecureRenegotiation", sc->insecure_reneg);
+    DMP_ON_OFF("SSLStrictSNIVHostCheck", sc->strict_sni_vhost_check);
+#ifdef HAVE_FIPS
+    DMP_ON_OFF("SSLFIPS", sc->fips);
+#endif
+    DMP_ON_OFF("SSLSessionTickets", sc->session_tickets);
+    DMP_STRARR("SSLPolicy", sc->policies);
+}
+
+static void ssl_dir_dump(SSLDirConfigRec *dc, apr_pool_t *p, 
+                         apr_file_t *out, const char *indent, const char **psep)
+{
+    int i;
+    
+    DMP_ON_OFF("SSLProxyEngine", dc->proxy_enabled);
+
+    modssl_ctx_dump(dc->proxy, p, 1, out, indent, psep);
+
+    if (dc->bSSLRequired == TRUE) {
+        DMP_ON_OFF("SSLRequireSSL", dc->bSSLRequired);
+    }
+    if (dc->aRequirement && dc->aRequirement->nelts > 0) {
+        ssl_require_t *r = (ssl_require_t *)dc->aRequirement->elts;
+        for (i = 0; i < dc->aRequirement->nelts; ++i, ++r) {
+            DMP_STRING("SSLRequire", r->cpExpr);
+        }
+    }
+    DMP_OPTION("StdEnvVars", SSL_OPT_STDENVVARS);
+    DMP_OPTION("ExportCertData", SSL_OPT_EXPORTCERTDATA);
+    DMP_OPTION("FakeBasicAuth", SSL_OPT_FAKEBASICAUTH);
+    DMP_OPTION("StrictRequire", SSL_OPT_STRICTREQUIRE);
+    DMP_OPTION("OptRenegotiate", SSL_OPT_OPTRENEGOTIATE);
+    DMP_OPTION("LegacyDNStringFormat", SSL_OPT_LEGACYDNFORMAT);
+    DMP_STRARR("SSLProxyPolicy", dc->policies);
+}
+
+static void ssl_policy_dump(SSLPolicyRec *policy, apr_pool_t *p, 
+                            apr_file_t *out, const char *indent)
+{
+    const char *sep = "";
+    if (policy->sc) {
+        ssl_srv_dump(policy->sc, p, out, indent, &sep);
+    }
+    if (policy->dc) {
+        ssl_dir_dump(policy->dc, p, out, indent, &sep);
+    }
 }
+
+
+
index ce84415abf1ccffa66e1f048c89df90f60959557..79e9a58a301e481ed34ef33c182f05ff87745b50 100644 (file)
@@ -280,6 +280,13 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
             sc->fips = FALSE;
         }
 #endif
+
+        if (sc->error_policy) {
+            rv = ssl_policy_lookup(p, sc->error_policy)? APR_EGENERAL : APR_ENOENT;
+            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO() 
+                         "Applying SSLPolicy '%s'", sc->error_policy);
+            return rv;
+        }
     }
 
 #if APR_HAS_THREADS && MODSSL_USE_OPENSSL_PRE_1_1_API
index a46e6c82dfdce38b7baceca330b5c4ab1264b5a5..a6bb59f04cb09029c553b434ef36c39092049c74 100644 (file)
@@ -586,6 +586,7 @@ typedef struct {
     apr_global_mutex_t   *stapling_cache_mutex;
     apr_global_mutex_t   *stapling_refresh_mutex;
 #endif
+
 } SSLModConfigRec;
 
 /** Structure representing configured filenames for certs and keys for
@@ -736,6 +737,9 @@ struct SSLSrvConfigRec {
     BOOL             compression;
 #endif
     BOOL             session_tickets;
+    
+    apr_array_header_t *policies;      /* policy that shall be applied to this config */
+    const char      *error_policy;     /* error in policy merge, bubble up */
 };
 
 /**
@@ -758,8 +762,20 @@ struct SSLDirConfigRec {
     modssl_ctx_t *proxy;
     BOOL          proxy_enabled;
     BOOL          proxy_post_config;
+
+    apr_array_header_t *policies;      /* policy that shall be applied to this config */
+    const char      *error_policy;     /* error in policy merge, bubble up */
+};
+
+typedef struct SSLPolicyRec SSLPolicyRec;
+struct SSLPolicyRec {
+    const char *name;
+    SSLSrvConfigRec *sc;
+    SSLDirConfigRec *dc;
 };
 
+SSLPolicyRec *ssl_policy_lookup(apr_pool_t *pool, const char *name);
+
 /**
  *  function prototypes
  */
@@ -777,6 +793,8 @@ void        *ssl_config_perdir_create(apr_pool_t *, char *);
 void        *ssl_config_perdir_merge(apr_pool_t *, void *, void *);
 void         ssl_config_proxy_merge(apr_pool_t *,
                                     SSLDirConfigRec *, SSLDirConfigRec *);
+const char  *ssl_cmd_SSLPolicyDefine(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLPolicyApply(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLPassPhraseDialog(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLCryptoDevice(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLRandomSeed(cmd_parms *, void *, const char *, const char *, const char *);
@@ -808,6 +826,7 @@ const char  *ssl_cmd_SSLRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *
 const char  *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag);
 const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag);
 
+const char  *ssl_cmd_SSLProxyPolicyApply(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag);
 const char  *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, void *, const char *);