]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge r1929308, r1929333, r1929361, r1929503 from trunk:
authorJoe Orton <jorton@apache.org>
Thu, 6 Nov 2025 09:09:18 +0000 (09:09 +0000)
committerJoe Orton <jorton@apache.org>
Thu, 6 Nov 2025 09:09:18 +0000 (09:09 +0000)
mod_ssl: Add SSLVHostSNIPolicy directive to set the compatibility
level required for VirtualHost matching.

For "secure" and "authonly" modes, a hash of the policy-relevant vhost
configuration is created and stored in the post_config hooks, reducing
the runtime code complexity (and overhead).

* modules/ssl/ssl_engine_kernel.c (ssl_check_vhost_sni_policy): New
  function, replacing ssl_server_compatible et al.

* modules/ssl/ssl_engine_config.c (ssl_cmd_SSLVHostSNIPolicy): New
  function.

* modules/ssl/ssl_engine_init.c (md5_strarray_cmp, md5_strarray_hash,
  hash_sni_policy_pk, hash_sni_policy_auth, create_sni_policy_hash):
  New functions.
  (ssl_init_Module): Invoke create_sni_policy_hash to store the hash
  for every SSLSrvConfigRec.

* modules/ssl/ssl_private.h (SSLModConfigRec): Add snivh_policy field.
  (SSLSrvConfigRec): Add sni_policy_hash field.

PR: 69743
GitHub: closes #562
Reviewed by: jorton, rpluem, covener

Docs changes:
misplaced tags in english version and fr doc XML file update.
Update docs on SSLVhostSNIPolicy to cover the impact on
non-SNI connections. Reorder the table for clarity.

Submitted by: jorton, Aaron Ogburn <aogburn redhat.com>, rpluem, lgentis

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

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_engine_kernel.c
modules/ssl/ssl_private.h

index 137b1f74dd2722b8ec4dad964e43b650feb8e6cf..d4d1a4d274153d1fcc8c0f7ad60b39af99166ca5 100644 (file)
@@ -1816,6 +1816,97 @@ SSLStrictSNIVHostCheck on
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLVHostSNIPolicy</name>
+<description>Set compatibility policy for SNI client access to virtual hosts.</description>
+<syntax>SSLVHostSNIPolicy strict|secure|authonly|insecure</syntax>
+<default>SSLVHostSNIPolicy secure</default>
+<contextlist><context>server config</context></contextlist>
+<compatibility>Available in httpd 2.5 and later</compatibility>
+
+<usage><p>This directive sets the policy applied when checking whether the
+<directive module="core" type="section">VirtualHost</directive>
+identified by the <code>Host</code> request header in an HTTP request
+is compatible with the <directive module="core"
+type="section">VirtualHost</directive> identified from the SNI
+extension sent during the initial TLS connection handshake. If an HTTP
+request is associated with a virtual host which has an incompatible
+SSL/TLS configuration under the policy used, an HTTP error response
+with status code 421 ("Misdirected Request") will be sent.</p>
+
+<p>The policy also applies to TLS connections where an SNI extension
+is not sent during the handshake, implicitly using the default or
+first virtual host definition. If the Host header in an HTTP request
+on such a connection identifies any other non-default virtual host,
+the compatibility policy is tested.</p>
+
+<p>The <code>strict</code> policy blocks all HTTP requests which are
+identified with a different virtual host to that identifed by SNI.
+The <code>insecure</code> policy allows all HTTP requests regardless
+of virtual host identified; such a configuration may be vulnerable to
+<a
+href="https://httpd.apache.org/security/vulnerabilities_24.html">CVE-2025-23048</a>.
+</p>
+
+<p>The (default) <code>secure</code>, and <code>authonly</code>
+policies compare specific aspects of the SSL configuration for the two
+virtual hosts, which are grouped into two categories:</p>
+
+<ul>
+  <li><strong>server certificate/key, or protocol/cipher
+  restrictions</strong>: directives which determine the server
+  certificate or key (<directive
+  module="mod_ssl">SSLCertificateKeyFile</directive> etc), cipher or
+  protocol restrictions (<directive
+  module="mod_ssl">SSLCipherSuite</directive> and <directive
+  module="mod_ssl">SSLProtocol</directive>)</li>
+
+  <li><strong>client vertification and authentication
+  settings</strong>: directives which affect TLS client certificate
+  verification or authentication, such as <directive
+  module="mod_ssl">SSLVerifyClient</directive>, <directive
+  module="mod_ssl">SSLVerifyMode</directive>, <directive
+  module="mod_ssl">SSLCACertificatePath</directive>, <directive
+  module="mod_ssl">SSLSRPVerifierFile</directive>; any use of <directive
+  module="mod_ssl">SSLOpenSSLConfCmd</directive></li>
+</ul>
+
+<p>This table illustrates whether an HTTP request will be blocked or
+allowed when the virtual host configurations differ as described,
+under each different policy setting:</p>
+
+<table border="1" style="zebra">
+<columnspec><column width=".3"/><column width=".2"/><column width=".5"/>
+</columnspec>
+<tr>
+  <th>Policy mode</th>
+  <th>Any VirtualHost mismatch</th>
+  <th>Server certificate/key, <br />or protocol/cipher restrictions</th>
+  <th>Client verification/<br />authentication settings</th>
+</tr>
+<tr>
+  <td><code>strict</code></td><td>blocked</td><td>blocked</td><td>blocked</td>
+</tr>
+<tr>
+  <td><code>secure</code></td><td>allowed</td><td>blocked</td><td>blocked</td>
+</tr>
+<tr>
+  <td><code>authonly</code></td><td>allowed</td><td>allowed</td><td>blocked</td>
+</tr>
+<tr>
+  <td><code>insecure</code></td><td>allowed</td><td>allowed</td><td>allowed</td>
+</tr>
+</table>
+
+<example><title>Example</title>
+<highlight language="config">
+SSLVHostSNIPolicy authonly
+</highlight>
+
+</example>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>SSLProxyMachineCertificatePath</name>
 <description>Directory of PEM-encoded client certificates and keys to be used by the proxy</description>
index fb66d1825e6ee9d80eab4bdcd4882fb7281a8b93..c0fdafd58213ca6bfd6837a5ea73350fb5744c18 100644 (file)
@@ -80,6 +80,8 @@ static const command_rec ssl_config_cmds[] = {
     SSL_CMD_SRV(RandomSeed, TAKE23,
                 "SSL Pseudo Random Number Generator (PRNG) seeding source "
                 "('startup|connect builtin|file:/path|exec:/path [bytes]')")
+    SSL_CMD_SRV(VHostSNIPolicy, TAKE1,
+                "SSL VirtualHost SNI compatibility policy setting")
 
     /*
      * Per-server context configuration directives
index d1f4fad8e236d17b991eb69caba2ccd812fc150b..84831dc5a47518ffe7678750f657230d100efdc6 100644 (file)
@@ -63,6 +63,9 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s)
     mc->sesscache_mode         = SSL_SESS_CACHE_OFF;
     mc->sesscache              = NULL;
     mc->pMutex                 = NULL;
+#ifdef HAVE_TLSEXT
+    mc->snivh_policy           = MODSSL_SNIVH_SECURE;
+#endif
     mc->aRandSeed              = apr_array_make(pool, 4,
                                                 sizeof(ssl_randseed_t));
     mc->tVHostKeys             = apr_hash_make(pool);
@@ -1909,6 +1912,41 @@ const char  *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag
 #endif
 }
 
+const char *ssl_cmd_SSLVHostSNIPolicy(cmd_parms *cmd, void *dcfg, const char *arg)
+{
+#ifdef HAVE_TLSEXT
+    SSLModConfigRec *mc = myModConfig(cmd->server);
+    const char *err;
+
+    if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+        return err;
+    }
+
+    if (strcEQ(arg, "secure")) {
+        mc->snivh_policy = MODSSL_SNIVH_SECURE;
+    }
+    else if (strcEQ(arg, "strict")) {
+        mc->snivh_policy = MODSSL_SNIVH_STRICT;
+    }
+    else if (strcEQ(arg, "insecure")) {
+        mc->snivh_policy = MODSSL_SNIVH_INSECURE;
+    }
+    else if (strcEQ(arg, "authonly")) {
+        mc->snivh_policy = MODSSL_SNIVH_AUTHONLY;
+    }
+    else {
+        return apr_psprintf(cmd->pool, "Invalid SSLVhostSNIPolicy "
+                            "argument '%s'", arg);
+    }
+
+    return NULL;
+#else
+    return "SSLVHostSNIPolicy cannot be used, OpenSSL is not built with "
+        "support for TLS extensions and SNI indication. Refer to the "
+        "documentation, and build a compatible version of OpenSSL."
+#endif
+}
+
 #ifdef HAVE_OCSP_STAPLING
 
 const char *ssl_cmd_SSLStaplingCache(cmd_parms *cmd,
index 94cc2772e013a1453ac9d7a6a0ecfc21c0588bfb..0fecdcfa6e8422f2de3725b0eea6c69893ee6896 100644 (file)
@@ -28,6 +28,8 @@
                                         -- Unknown   */
 #include "ssl_private.h"
 
+#include <apr_md5.h>
+
 #include "mpm_common.h"
 #include "mod_md.h"
 
@@ -186,6 +188,110 @@ static void ssl_add_version_components(apr_pool_t *ptemp, apr_pool_t *pconf,
                  modver, AP_SERVER_BASEVERSION, incver);
 }
 
+#ifdef HAVE_TLSEXT
+/* Helper functions to create the SNI vhost policy hash. The policy
+ * hash captures the configuration elements relevant to the mode
+ * selected at runtime by SSLVHostSNIPolicy. */
+
+#define md5_str_update(ctx_, pfx_, str_) do { apr_md5_update(ctx_, pfx_, strlen(pfx_)); apr_md5_update(ctx_, str_, strlen(str_)); } while (0)
+#define md5_ifstr_update(ctx_, pfx_, str_) do { apr_md5_update(ctx_, pfx_, strlen(pfx_)); if (str_) apr_md5_update(ctx_, str_, strlen(str_)); } while (0)
+#define md5_fmt_update(ctx_, fmt_, i_) do { char s_[128]; apr_snprintf(s_, sizeof s_, fmt_, i_); \
+        apr_md5_update(ctx_, s_, strlen(s_)); } while (0)
+
+static int md5_strarray_cmp(const void *p1, const void *p2)
+{
+    return strcmp(*(char **)p1, *(char **)p2);
+}
+
+/* Hashes an array of strings in sorted order. */
+static void md5_strarray_hash(apr_pool_t *ptemp, apr_md5_ctx_t *hash,
+                              const char *pfx, apr_array_header_t *s)
+{
+    char **elts = apr_pmemdup(ptemp, s->elts, s->nelts * sizeof *elts);
+    int i;
+
+    qsort(elts, s->nelts, sizeof(char *), md5_strarray_cmp);
+
+    apr_md5_update(hash, pfx, strlen(pfx));
+    for (i = 0; i < s->nelts; i++) {
+        md5_str_update(hash, "elm:", elts[i]);
+    }
+}
+
+static void hash_sni_policy_pk(apr_pool_t *ptemp, apr_md5_ctx_t *hash, modssl_ctx_t *ctx)
+{
+    md5_fmt_update(hash, "protocol:%d", ctx->protocol);
+
+    md5_ifstr_update(hash, "ciphers:", ctx->auth.cipher_suite);
+    md5_ifstr_update(hash, "tls13_ciphers:", ctx->auth.tls13_ciphers);
+
+    md5_strarray_hash(ptemp, hash, "cert_files:", ctx->pks->cert_files);
+    md5_strarray_hash(ptemp, hash, "key_files:", ctx->pks->key_files);
+}
+
+static void hash_sni_policy_auth(apr_md5_ctx_t *hash, modssl_ctx_t *ctx)
+{
+    modssl_pk_server_t *pks = ctx->pks;
+    modssl_auth_ctx_t *a = &ctx->auth;
+
+    md5_fmt_update(hash, "verify_depth:%d", a->verify_depth);
+    md5_fmt_update(hash, "verify_mode:%d", a->verify_mode);
+
+    md5_ifstr_update(hash, "ca_name_path:", pks->ca_name_path);
+    md5_ifstr_update(hash, "ca_name_file:", pks->ca_name_file);
+    md5_ifstr_update(hash, "ca_cert_path:", a->ca_cert_path);
+    md5_ifstr_update(hash, "ca_cert_file:", a->ca_cert_file);
+    md5_ifstr_update(hash, "crl_path:", ctx->crl_path);
+    md5_ifstr_update(hash, "crl_file:", ctx->crl_file);
+    md5_fmt_update(hash, "crl_check_mask:%d", ctx->crl_check_mask);
+    md5_fmt_update(hash, "ocsp_mask:%d", ctx->ocsp_mask);
+    md5_fmt_update(hash, "ocsp_force_default:%d", ctx->ocsp_force_default);
+    md5_ifstr_update(hash, "ocsp_responder:", ctx->ocsp_responder);
+
+#ifdef HAVE_SRP
+    md5_ifstr_update(hash, "srp_vfile:", ctx->srp_vfile);
+#endif
+
+#ifdef HAVE_SSL_CONF_CMD
+    {
+        apr_array_header_t *parms = ctx->ssl_ctx_param;
+        int n;
+
+        for (n = 0; n < parms->nelts; n++) {
+            ssl_ctx_param_t *p = &APR_ARRAY_IDX(parms, n, ssl_ctx_param_t);
+
+            md5_str_update(hash, "param:", p->name);
+            md5_str_update(hash, "value:", p->value);
+        }
+    }
+#endif
+}
+#endif
+
+static char *create_sni_policy_hash(apr_pool_t *p, apr_pool_t *ptemp,
+                                    modssl_snivhpolicy_t policy,
+                                    SSLSrvConfigRec *sc)
+{
+    char *rv = NULL;
+#ifdef HAVE_TLSEXT
+    if (policy != MODSSL_SNIVH_STRICT && policy != MODSSL_SNIVH_INSECURE) {
+        apr_md5_ctx_t hash;
+        unsigned char digest[APR_MD5_DIGESTSIZE];
+
+        /* Create the vhost policy hash for comparison later. */
+        apr_md5_init(&hash);
+        hash_sni_policy_auth(&hash, sc->server);
+        if (policy == MODSSL_SNIVH_SECURE)
+            hash_sni_policy_pk(ptemp, &hash, sc->server);
+        apr_md5_final(digest, &hash);
+
+        rv = apr_palloc(p, 2 * APR_MD5_DIGESTSIZE + 1);
+        ap_bin2hex(digest, APR_MD5_DIGESTSIZE, rv); /* sets final '\0' */
+    }
+#endif
+    return rv;
+}
+
 /*  _________________________________________________________________
 **
 **  Let other answer special connection attempts. 
@@ -439,6 +545,8 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
                 return rv;
             }
         }
+
+        sc->sni_policy_hash = create_sni_policy_hash(p, ptemp, mc->snivh_policy, sc);
     }
 
     /*
index 33aa1f71dc75221851c4325a5c712d16c54066ae..a6af6332f43a1f0e0d726cdab8fedf9ed9d57540 100644 (file)
@@ -101,112 +101,28 @@ static int fill_reneg_buffer(request_rec *r, SSLDirConfigRec *dc)
 }
 
 #ifdef HAVE_TLSEXT
-static int ap_array_same_str_set(apr_array_header_t *s1, apr_array_header_t *s2)
+/* Check whether a transition from vhost sc1 to sc2 from SNI to Host:
+ * vhost selection is permitted according to the SSLVHostSNIPolicy
+ * setting.  Returns 1 if the policy treats the vhosts as compatible,
+ * else 0. */
+static int ssl_check_vhost_sni_policy(SSLSrvConfigRec *sc1,
+                                      SSLSrvConfigRec *sc2)
 {
-    int i;
-    const char *c;
-    
-    if (s1 == s2) {
+    modssl_snivhpolicy_t policy = sc1->mc->snivh_policy;
+
+    /* Policy: insecure => allow everything. */
+    if (policy == MODSSL_SNIVH_INSECURE)
         return 1;
-    }
-    else if (!s1 || !s2 || (s1->nelts != s2->nelts)) {
-        return 0;
-    }
     
-    for (i = 0; i < s1->nelts; i++) {
-        c = APR_ARRAY_IDX(s1, i, const char *);
-        if (!c || !ap_array_str_contains(s2, c)) {
-            return 0;
-        }
-    }
-    return 1;
-}
-
-static int ssl_pk_server_compatible(modssl_pk_server_t *pks1, 
-                                    modssl_pk_server_t *pks2) 
-{
-    if (!pks1 || !pks2) {
-        return 0;
-    }
-    /* both have the same certificates? */
-    if ((pks1->ca_name_path != pks2->ca_name_path)
-        && (!pks1->ca_name_path || !pks2->ca_name_path 
-            || strcmp(pks1->ca_name_path, pks2->ca_name_path))) {
-        return 0;
-    }
-    if ((pks1->ca_name_file != pks2->ca_name_file)
-        && (!pks1->ca_name_file || !pks2->ca_name_file 
-            || strcmp(pks1->ca_name_file, pks2->ca_name_file))) {
-        return 0;
-    }
-    if (!ap_array_same_str_set(pks1->cert_files, pks2->cert_files)
-        || !ap_array_same_str_set(pks1->key_files, pks2->key_files)) {
-        return 0;
-    }
-    return 1;
-}
-
-static int ssl_auth_compatible(modssl_auth_ctx_t *a1, 
-                               modssl_auth_ctx_t *a2) 
-{
-    if (!a1 || !a2) {
-        return 0;
-    }
-    /* both have the same verification */
-    if ((a1->verify_depth != a2->verify_depth)
-        || (a1->verify_mode != a2->verify_mode)) {
-        return 0;
-    }
-    /* both have the same ca path/file */
-    if ((a1->ca_cert_path != a2->ca_cert_path)
-        && (!a1->ca_cert_path || !a2->ca_cert_path 
-            || strcmp(a1->ca_cert_path, a2->ca_cert_path))) {
-        return 0;
-    }
-    if ((a1->ca_cert_file != a2->ca_cert_file)
-        && (!a1->ca_cert_file || !a2->ca_cert_file 
-            || strcmp(a1->ca_cert_file, a2->ca_cert_file))) {
-        return 0;
-    }
-    /* both have the same ca cipher suite string */
-    if ((a1->cipher_suite != a2->cipher_suite)
-        && (!a1->cipher_suite || !a2->cipher_suite 
-            || strcmp(a1->cipher_suite, a2->cipher_suite))) {
-        return 0;
-    }
-    /* both have the same ca cipher suite string */
-    if ((a1->tls13_ciphers != a2->tls13_ciphers)
-        && (!a1->tls13_ciphers || !a2->tls13_ciphers 
-            || strcmp(a1->tls13_ciphers, a2->tls13_ciphers))) {
-        return 0;
-    }
-    return 1;
-}
-
-static int ssl_ctx_compatible(modssl_ctx_t *ctx1, 
-                              modssl_ctx_t *ctx2) 
-{
-    if (!ctx1 || !ctx2 
-        || (ctx1->protocol != ctx2->protocol)
-        || !ssl_auth_compatible(&ctx1->auth, &ctx2->auth)
-        || !ssl_pk_server_compatible(ctx1->pks, ctx2->pks)) {
+    /* Policy: strict => fail for any vhost transition. */
+    if (policy == MODSSL_SNIVH_STRICT && sc1 != sc2)
         return 0;
-    }
-    return 1;
-}
 
-static int ssl_server_compatible(server_rec *s1, server_rec *s2)
-{
-    SSLSrvConfigRec *sc1 = s1? mySrvConfig(s1) : NULL;
-    SSLSrvConfigRec *sc2 = s2? mySrvConfig(s2) : NULL;
+    /* For authonly/secure policy, compare the hash. */
+    AP_DEBUG_ASSERT(sc1->sni_policy_hash);
+    AP_DEBUG_ASSERT(sc2->sni_policy_hash);
 
-    /* both use the same TLS protocol? */
-    if (!sc1 || !sc2 
-        || !ssl_ctx_compatible(sc1->server, sc2->server)) {
-        return 0;
-    }
-    
-    return 1;
+    return strcmp(sc1->sni_policy_hash, sc2->sni_policy_hash) == 0;
 }
 #endif
 
@@ -275,6 +191,8 @@ int ssl_hook_ReadReq(request_rec *r)
         server_rec *handshakeserver = sslconn->server;
         SSLSrvConfigRec *hssc = mySrvConfig(handshakeserver);
 
+        AP_DEBUG_ASSERT(hssc);
+
         if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
             /*
              * The SNI extension supplied a hostname. So don't accept requests
@@ -315,19 +233,14 @@ int ssl_hook_ReadReq(request_rec *r)
                            "which is required to access this server.<br />\n");
             return HTTP_FORBIDDEN;
         }
-        if (r->server != handshakeserver
-            && !ssl_server_compatible(sslconn->server, r->server)) {
-            /*
-             * The request does not select the virtual host that was
-             * selected for handshaking and its SSL parameters are different
-             */
-
+        /* Enforce SSL SNI vhost compatibility policy. */
+        if (!ssl_check_vhost_sni_policy(sc, hssc)) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02032)
                          "Hostname %s %s and hostname %s provided"
-                         " via HTTP have no compatible SSL setup",
+                         " via HTTP have no compatible SSL setup for policy '%s'",
                          servername ? servername : handshakeserver->server_hostname,
                          servername ? "provided via SNI" : "(default host as no SNI was provided)",
-                         r->hostname);
+                          r->hostname, MODSSL_SNIVH_NAME(sc->mc->snivh_policy));
             return HTTP_MISDIRECTED_REQUEST;
         }
     }
index 794e51aa9374ee9f9df5766060e7dee9acbdd457..1ec02f31aef363d302b51c9fbacbd73f7b5c4eed 100644 (file)
@@ -556,6 +556,19 @@ typedef struct {
     int          nBytes;
 } ssl_randseed_t;
 
+/* SNI vhost compatibility policy. */
+typedef enum {
+    MODSSL_SNIVH_STRICT   = 0,
+    MODSSL_SNIVH_SECURE   = 1,
+    MODSSL_SNIVH_AUTHONLY = 2,
+    MODSSL_SNIVH_INSECURE = 3
+} modssl_snivhpolicy_t;
+
+/* Maps modssl_snivhpolicy_t back into a config option string. */
+#define MODSSL_SNIVH_NAME(p_) ((p_) == MODSSL_SNIVH_STRICT ? "strict" : \
+                               ((p_) == MODSSL_SNIVH_SECURE ? "secure" : \
+                                ((p_) == MODSSL_SNIVH_AUTHONLY ? "authonly" : "insecure" )))
+
 /**
  * Define the structure of an ASN.1 anything
  */
@@ -689,6 +702,8 @@ typedef struct {
 #ifdef HAVE_FIPS
     BOOL             fips;
 #endif
+
+    modssl_snivhpolicy_t snivh_policy;
 } SSLModConfigRec;
 
 /** Structure representing configured filenames for certs and keys for
@@ -843,6 +858,7 @@ struct SSLSrvConfigRec {
     modssl_ctx_t    *server;
 #ifdef HAVE_TLSEXT
     ssl_enabled_t    strict_sni_vhost_check;
+    const char      *sni_policy_hash;
 #endif
 #ifndef OPENSSL_NO_COMP
     BOOL             compression;
@@ -918,6 +934,7 @@ const char  *ssl_cmd_SSLRequire(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLUserName(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg);
 const char  *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag);
+const char  *ssl_cmd_SSLVHostSNIPolicy(cmd_parms *cmd, void *dcfg, const char *arg);
 const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag);
 
 const char  *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag);