This creates an Ssl::Config class to manage SSL configuration settings and creates a ConfigOptions sub-class to hold the settings which are needed passing around in the SSL code.

Functional changes are all in the parsing and SSL options for cache_peer, http(s)_port are aligned and a new directive ssl_proxy_direct is added to combine the DIRECT SSL connection settings with the same set of options.

TODO:
* implement dump/free functions properly
* implement parse for backward-compatible loading of the old DIRECT SSL settings options.

Amos
=== modified file 'src/CachePeer.h'
--- src/CachePeer.h     2012-09-23 09:04:21 +0000
+++ src/CachePeer.h     2012-11-26 01:17:54 +0000
@@ -37,6 +37,7 @@
 #define PEER_MULTICAST_SIBLINGS 1
 
 #if USE_SSL
+#include "ssl/Config.h"
 #include <openssl/ssl.h>
 #endif
 
@@ -190,15 +191,7 @@
 #if USE_SSL
 
     int use_ssl;
-    char *sslcert;
-    char *sslkey;
-    int sslversion;
-    char *ssloptions;
-    char *sslcipher;
-    char *sslcafile;
-    char *sslcapath;
-    char *sslcrlfile;
-    char *sslflags;
+    Ssl::ConfigOptions ssl;
     char *ssldomain;
     SSL_CTX *sslContext;
     SSL_SESSION *sslSession;

=== modified file 'src/anyp/PortCfg.cc'
--- src/anyp/PortCfg.cc 2012-11-23 05:39:27 +0000
+++ src/anyp/PortCfg.cc 2012-11-23 12:48:15 +0000
@@ -34,14 +34,6 @@
     safe_free(protocol);
 
 #if USE_SSL
-    safe_free(cert);
-    safe_free(key);
-    safe_free(options);
-    safe_free(cipher);
-    safe_free(cafile);
-    safe_free(capath);
-    safe_free(dhfile);
-    safe_free(sslflags);
     safe_free(sslContextSessionId);
 #endif
 }
@@ -69,21 +61,12 @@
 
     memcpy( &(b->tcp_keepalive), &(tcp_keepalive), sizeof(tcp_keepalive));
 
+    b->ssl = ssl;
+
 #if 0
     // AYJ: 2009-07-18: for now SSL does not clone. Configure separate ports 
with IPs and SSL settings
 
 #if USE_SSL
-    char *cert;
-    char *key;
-    int version;
-    char *cipher;
-    char *options;
-    char *clientca;
-    char *cafile;
-    char *capath;
-    char *crlfile;
-    char *dhfile;
-    char *sslflags;
     char *sslContextSessionId;
     SSL_CTX *sslContext;
 #endif
@@ -96,8 +79,8 @@
 #if USE_SSL
 void AnyP::PortCfg::configureSslServerContext()
 {
-    if (cert)
-        Ssl::readCertChainAndPrivateKeyFromFiles(signingCert, signPkey, 
certsToChain, cert, key);
+    if (ssl.certfile)
+        Ssl::readCertChainAndPrivateKeyFromFiles(signingCert, signPkey, 
certsToChain, ssl.certfile, ssl.keyfile);
 
     if (!signingCert) {
         char buf[128];
@@ -115,27 +98,27 @@
         fatalf("Unable to generate  signing SSL certificate for untrusted 
sites for %s_port %s", protocol, s.ToURL(buf, sizeof(buf)));
     }
 
-    if (crlfile)
-        clientVerifyCrls.reset(Ssl::loadCrl(crlfile, sslContextFlags));
+    if (ssl.CRLfile)
+        clientVerifyCrls.reset(Ssl::loadCrl(ssl.CRLfile, sslContextFlags));
 
-    if (clientca) {
-        clientCA.reset(SSL_load_client_CA_file(clientca));
+    if (ssl.clientCA) {
+        clientCA.reset(SSL_load_client_CA_file(ssl.clientCA));
         if (clientCA.get() == NULL) {
-            fatalf("Unable to read client CAs! from %s", clientca);
+            fatalf("Unable to read client CAs! from %s", ssl.clientCA);
         }
     }
 
-    contextMethod = Ssl::contextMethod(version);
+    contextMethod = Ssl::contextMethod(ssl.version);
     if (!contextMethod)
         fatalf("Unable to compute context method to use");
 
-    if (dhfile)
-        dhParams.reset(Ssl::readDHParams(dhfile));
-
-    if (sslflags)
-        sslContextFlags = Ssl::parse_flags(sslflags);
-
-    sslOptions = Ssl::parse_options(options);
+    if (ssl.DHfile)
+        dhParams.reset(Ssl::readDHParams(ssl.DHfile));
+
+    if (ssl.flags)
+        sslContextFlags = Ssl::parse_flags(ssl.flags);
+
+    sslOptions = Ssl::parse_options(ssl.options);
 
     Ssl::CreateServerContext(staticSslContext, *this);
 

=== modified file 'src/anyp/PortCfg.h'
--- src/anyp/PortCfg.h  2012-10-09 23:15:44 +0000
+++ src/anyp/PortCfg.h  2012-11-23 12:40:07 +0000
@@ -5,6 +5,7 @@
 #include "comm/Connection.h"
 
 #if USE_SSL
+#include "ssl/Config.h"
 #include "ssl/gadgets.h"
 #endif
 
@@ -57,17 +58,8 @@
     Comm::ConnectionPointer listenConn;
 
 #if USE_SSL
-    char *cert;
-    char *key;
-    int version;
-    char *cipher;
-    char *options;
-    char *clientca;
-    char *cafile;
-    char *capath;
-    char *crlfile;
-    char *dhfile;
-    char *sslflags;
+    Ssl::ConfigOptions ssl; ///< SSL options found in the config file for this 
port.
+
     char *sslContextSessionId; ///< "session id context" for staticSslContext
     bool generateHostCertificates; ///< dynamically make host cert for sslBump
     size_t dynamicCertMemCacheSize; ///< max size of generated certificates 
memory cache

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc     2012-11-23 05:39:27 +0000
+++ src/cache_cf.cc     2013-06-24 09:33:32 +0000
@@ -41,6 +41,7 @@
 #include "anyp/PortCfg.h"
 #include "AuthReg.h"
 #include "base/RunnersRegistry.h"
+#include "base/StringArea.h"
 #include "mgr/ActionPasswordList.h"
 #include "CachePeer.h"
 #include "CachePeerDomainList.h"
@@ -920,13 +921,13 @@
     // XXX: move the ssl_client out of the master Config structure so we can 
re-use its fields and Store a SSL_CTX_Pointer member.
     //  the global structure has memset() applied which screws with 
refcount/locking *_Pointer classes
     Ssl::SSL_CTX_Pointer sslClient;
-    Ssl::CreateClientContext(sslClient, Config.ssl_client.cert, 
Config.ssl_client.key, Config.ssl_client.version, Config.ssl_client.cipher, 
Config.ssl_client.options, Config.ssl_client.flags, Config.ssl_client.cafile, 
Config.ssl_client.capath, Config.ssl_client.crlfile);
+    Ssl::CreateClientContext(sslClient, Ssl::TheConfig.sslProxyDirect);
     Config.ssl_client.sslContext = sslClient.release();
 
     for (CachePeer *p = Config.peers; p != NULL; p = p->next) {
         if (p->use_ssl) {
             debugs(3, DBG_IMPORTANT, "Initializing cache_peer " << p->name << 
" SSL context");
-            Ssl::CreateClientContext(sslClient, p->sslcert, p->sslkey, 
p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, 
p->sslcapath, p->sslcrlfile);
+            Ssl::CreateClientContext(sslClient, p->ssl);
             p->sslContext = sslClient.release();
         }
     }
@@ -2263,35 +2264,15 @@
 
         } else if (strcmp(token, "ssl") == 0) {
             p->use_ssl = 1;
-        } else if (strncmp(token, "sslcert=", 8) == 0) {
-            safe_free(p->sslcert);
-            p->sslcert = xstrdup(token + 8);
-        } else if (strncmp(token, "sslkey=", 7) == 0) {
-            safe_free(p->sslkey);
-            p->sslkey = xstrdup(token + 7);
-        } else if (strncmp(token, "sslversion=", 11) == 0) {
-            p->sslversion = atoi(token + 11);
-        } else if (strncmp(token, "ssloptions=", 11) == 0) {
-            safe_free(p->ssloptions);
-            p->ssloptions = xstrdup(token + 11);
-        } else if (strncmp(token, "sslcipher=", 10) == 0) {
-            safe_free(p->sslcipher);
-            p->sslcipher = xstrdup(token + 10);
-        } else if (strncmp(token, "sslcafile=", 10) == 0) {
-            safe_free(p->sslcafile);
-            p->sslcafile = xstrdup(token + 10);
-        } else if (strncmp(token, "sslcapath=", 10) == 0) {
-            safe_free(p->sslcapath);
-            p->sslcapath = xstrdup(token + 10);
-        } else if (strncmp(token, "sslcrlfile=", 11) == 0) {
-            safe_free(p->sslcrlfile);
-            p->sslcapath = xstrdup(token + 10);
-        } else if (strncmp(token, "sslflags=", 9) == 0) {
-            safe_free(p->sslflags);
-            p->sslflags = xstrdup(token + 9);
         } else if (strncmp(token, "ssldomain=", 10) == 0) {
             safe_free(p->ssldomain);
             p->ssldomain = xstrdup(token + 10);
+        } else if (strncmp(token, "ssl-", 4) == 0) {
+            p->ssl.parseOne(token+4);
+        } else if (strncmp(token, "ssl", 3) == 0) {
+            // old options were 'sslfoo='. Do a quiet upgrade for now.
+            p->ssl.parseOne(token+3);
+            debugs(3, DBG_PARSE_NOTE(2), "UPGRADE: cache_peer option '" << 
token << "' is replaced by 'ssl-" << (token+3) << "'");
 #endif
 
         } else if (strcmp(token, "front-end-https") == 0) {
@@ -3518,6 +3499,9 @@
 parse_port_option(AnyP::PortCfg * s, char *token)
 {
     /* modes first */
+#if USE_SSL
+    static int sslUpgradeWarnLevel = DBG_IMPORTANT;
+#endif
 
     if (strcmp(token, "accel") == 0) {
         if (s->intercepted || s->spoof_client_ip) {
@@ -3657,45 +3641,58 @@
         }
 #if USE_SSL
     } else if (strcasecmp(token, "sslBump") == 0) {
-        debugs(3, DBG_CRITICAL, "WARNING: '" << token << "' is deprecated " <<
+        debugs(3, DBG_PARSE_NOTE(1), "WARNING: '" << token << "' is deprecated 
" <<
                "in http_port. Use 'ssl-bump' instead.");
         s->sslBump = 1; // accelerated when bumped, otherwise not
     } else if (strcmp(token, "ssl-bump") == 0) {
         s->sslBump = 1; // accelerated when bumped, otherwise not
+    } else if (strncmp(token, "ssl-", 5) == 0) {
+        s->ssl.parseOne(token+4); // any SSL option prefixed by 'ssl-'
+
     } else if (strncmp(token, "cert=", 5) == 0) {
-        safe_free(s->cert);
-        s->cert = xstrdup(token + 5);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "key=", 4) == 0) {
-        safe_free(s->key);
-        s->key = xstrdup(token + 4);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "version=", 8) == 0) {
-        s->version = xatoi(token + 8);
-        if (s->version < 1 || s->version > 4)
-            self_destruct();
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "options=", 8) == 0) {
-        safe_free(s->options);
-        s->options = xstrdup(token + 8);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "cipher=", 7) == 0) {
-        safe_free(s->cipher);
-        s->cipher = xstrdup(token + 7);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "clientca=", 9) == 0) {
-        safe_free(s->clientca);
-        s->clientca = xstrdup(token + 9);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "cafile=", 7) == 0) {
-        safe_free(s->cafile);
-        s->cafile = xstrdup(token + 7);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "capath=", 7) == 0) {
-        safe_free(s->capath);
-        s->capath = xstrdup(token + 7);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are now prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "crlfile=", 8) == 0) {
-        safe_free(s->crlfile);
-        s->crlfile = xstrdup(token + 8);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are now prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "dhparams=", 9) == 0) {
-        safe_free(s->dhfile);
-        s->dhfile = xstrdup(token + 9);
+        s->ssl.parseOne(token);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "sslflags=", 9) == 0) {
-        safe_free(s->sslflags);
-        s->sslflags = xstrdup(token + 9);
+        s->ssl.parseOne(token+3);
+        debugs(3, DBG_PARSE_NOTE(sslUpgradeWarnLevel), "UPGRADE: http(s)_port 
SSL options are prefixed with 'ssl-...'. Spotted: " << token);
+        sslUpgradeWarnLevel=2;
     } else if (strncmp(token, "sslcontext=", 11) == 0) {
         safe_free(s->sslContextSessionId);
         s->sslContextSessionId = xstrdup(token + 11);
@@ -3864,35 +3861,35 @@
     if (s->sslBump)
         storeAppendPrintf(e, " ssl-bump");
 
-    if (s->cert)
-        storeAppendPrintf(e, " cert=%s", s->cert);
-
-    if (s->key)
-        storeAppendPrintf(e, " key=%s", s->key);
-
-    if (s->version)
-        storeAppendPrintf(e, " version=%d", s->version);
-
-    if (s->options)
-        storeAppendPrintf(e, " options=%s", s->options);
-
-    if (s->cipher)
-        storeAppendPrintf(e, " cipher=%s", s->cipher);
-
-    if (s->cafile)
-        storeAppendPrintf(e, " cafile=%s", s->cafile);
-
-    if (s->capath)
-        storeAppendPrintf(e, " capath=%s", s->capath);
-
-    if (s->crlfile)
-        storeAppendPrintf(e, " crlfile=%s", s->crlfile);
-
-    if (s->dhfile)
-        storeAppendPrintf(e, " dhparams=%s", s->dhfile);
-
-    if (s->sslflags)
-        storeAppendPrintf(e, " sslflags=%s", s->sslflags);
+    if (s->ssl.certfile)
+        storeAppendPrintf(e, " ssl-cert=%s", s->ssl.certfile);
+
+    if (s->ssl.keyfile)
+        storeAppendPrintf(e, " ssl-key=%s", s->ssl.keyfile);
+
+    if (s->ssl.version)
+        storeAppendPrintf(e, " ssl-version=%d", s->ssl.version);
+
+    if (s->ssl.options)
+        storeAppendPrintf(e, " ssl-options=%s", s->ssl.options);
+
+    if (s->ssl.cipher)
+        storeAppendPrintf(e, " ssl-cipher=%s", s->ssl.cipher);
+
+    if (s->ssl.CAfile)
+        storeAppendPrintf(e, " ssl-cafile=%s", s->ssl.CAfile);
+
+    if (s->ssl.CApath)
+        storeAppendPrintf(e, " ssl-capath=%s", s->ssl.CApath);
+
+    if (s->ssl.CRLfile)
+        storeAppendPrintf(e, " ssl-crlfile=%s", s->ssl.CRLfile);
+
+    if (s->ssl.DHfile)
+        storeAppendPrintf(e, " ssl-dhparams=%s", s->ssl.DHfile);
+
+    if (s->ssl.flags)
+        storeAppendPrintf(e, " ssl-flags=%s", s->ssl.flags);
 
     if (s->sslContextSessionId)
         storeAppendPrintf(e, " sslcontext=%s", s->sslContextSessionId);

=== modified file 'src/cf.data.depend'
--- src/cf.data.depend  2012-10-26 19:42:31 +0000
+++ src/cf.data.depend  2012-11-26 01:01:22 +0000
@@ -57,7 +57,7 @@
 removalpolicy
 size_t
 IpAddress_list
-string
+ssl_options
 string
 time_msec
 time_t

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre     2012-10-29 01:31:29 +0000
+++ src/cf.data.pre     2013-06-26 07:07:34 +0000
@@ -2008,12 +2008,91 @@
        would like to use hardware SSL acceleration for example.
 DOC_END
 
+NAME: ssl_proxy_direct
+IFDEF: USE_SSL
+LOC: none
+DEFAULT: none
+TYPE: ssl_options
+DOC_START
+       SSL options to use when connecting to upstream HTTPS servers.
+
+       This directive accepts a series of key=value pairs the same
+       as would be set on a cache_peer directive, but these options
+       are used for DIRECT traffic.
+
+       ==== OPTIONS ====
+       
+       cert=/path/to/ssl/certificate
+                       A client SSL certificate to use when connecting to
+                       upstream servers.
+       
+       key=/path/to/ssl/key
+                       The private SSL key corresponding to sslcert above.
+                       If 'sslkey' is not specified 'sslcert' is assumed to
+                       reference a combined file containing both the
+                       certificate and the key.
+       
+       version=1|2|3|4|5|6
+                       The SSL version to use when connecting to upstream 
servers
+                               1 = automatic (default)
+                               2 = SSL v2 only
+                               3 = SSL v3 only
+                               4 = TLS v1.0 only
+                               5 = TLS v1.1 only
+                               6 = TLS v1.2 only
+       
+       cipher=...      The list of valid SSL ciphers to use when connecting
+                       to upstream servers.
+       
+       options=...     Specify various SSL implementation options:
+
+                           NO_SSLv2    Disallow the use of SSLv2
+                           NO_SSLv3    Disallow the use of SSLv3
+                           NO_TLSv1    Disallow the use of TLSv1.0
+                           NO_TLSv1_1  Disallow the use of TLSv1.1
+                           NO_TLSv1_2  Disallow the use of TLSv1.2
+                           SINGLE_DH_USE
+                                     Always create a new key when using
+                                     temporary/ephemeral DH key exchanges
+                           ALL       Enable various bug workarounds
+                                     suggested as "harmless" by OpenSSL
+                                     Be warned that this reduces SSL/TLS
+                                     strength to some attacks.
+
+                       See the OpenSSL SSL_CTX_set_options documentation for a
+                       more complete list.
+       
+       cafile=...      A file containing additional CA certificates to use
+                       when verifying the server certificate.
+       
+       capath=...      A directory containing additional CA certificates to
+                       use when verifying the server certificate.
+       
+       crlfile=...     A certificate revocation list file to use when
+                       verifying the server certificate.
+       
+       flags=...       Specify various flags modifying the SSL implementation:
+       
+                       DONT_VERIFY_PEER
+                               Accept all server certificates even if they
+                               fail to verify.
+                       NO_DEFAULT_CA
+                               Don't use the default CA list built in
+                               to OpenSSL.
+                       DONT_VERIFY_DOMAIN
+                               Don't verify the server certificate
+                               matches the server name
+       
+DOC_END
+
 NAME: sslproxy_client_certificate
 IFDEF: USE_SSL
 DEFAULT: none
 LOC: Config.ssl_client.cert
 TYPE: string
 DOC_START
+       Deprecated. Instead use: ssl_proxy_direct cert=...
+
        Client SSL Certificate to use when proxying https:// URLs
 DOC_END
 
@@ -2023,6 +2102,8 @@
 LOC: Config.ssl_client.key
 TYPE: string
 DOC_START
+       Deprecated. Instead use: ssl_proxy_direct key=...
+
        Client SSL Key to use when proxying https:// URLs
 DOC_END
 
@@ -2032,6 +2113,8 @@
 LOC: Config.ssl_client.version
 TYPE: int
 DOC_START
+       Deprecated. Instead use: ssl_proxy_direct version=...
+
        SSL version level to use when proxying https:// URLs
 
        The versions of SSL/TLS supported:
@@ -2042,6 +2125,7 @@
            4   TLSv1.0 only
            5   TLSv1.1 only
            6   TLSv1.2 only
+
 DOC_END
 
 NAME: sslproxy_options
@@ -2050,6 +2134,8 @@
 LOC: Config.ssl_client.options
 TYPE: string
 DOC_START
+       Deprecated. Instead use: ssl_proxy_direct options=...
+
        SSL implementation options to use when proxying https:// URLs
        
        The most important being:
@@ -2080,6 +2166,8 @@
 LOC: Config.ssl_client.cipher
 TYPE: string
 DOC_START
+       Deprecated. Instead use: ssl_proxy_direct cipher=...
+
        SSL cipher list to use when proxying https:// URLs
 
        Colon separated list of supported ciphers.
@@ -2091,6 +2179,8 @@
 LOC: Config.ssl_client.cafile
 TYPE: string
 DOC_START
+       Deprecated. Instead use: ssl_proxy_direct cafile=...
+
        file containing CA certificates to use when verifying server
        certificates while proxying https:// URLs
 DOC_END
@@ -2101,10 +2191,27 @@
 LOC: Config.ssl_client.capath
 TYPE: string
 DOC_START
+       Deprecated. Instead use: ssl_proxy_direct capath=...
+
        directory containing CA certificates to use when verifying
        server certificates while proxying https:// URLs
 DOC_END
 
+NAME: sslproxy_flags
+IFDEF: USE_SSL
+DEFAULT: none
+LOC: Config.ssl_client.flags
+TYPE: string
+DOC_START
+       Deprecated. Instead use: ssl_proxy_direct flags=...
+
+       Various flags modifying the use of SSL while proxying https:// URLs:
+           DONT_VERIFY_PEER    Accept certificates that fail verification.
+                               For refined control, see sslproxy_cert_error.
+           NO_DEFAULT_CA       Don't use the default CA list built in
+                               to OpenSSL.
+DOC_END
+
 NAME: ssl_bump
 IFDEF: USE_SSL
 TYPE: sslproxy_ssl_bump
@@ -2163,19 +2270,6 @@
        ssl_bump server-first all
 DOC_END
 
-NAME: sslproxy_flags
-IFDEF: USE_SSL
-DEFAULT: none
-LOC: Config.ssl_client.flags
-TYPE: string
-DOC_START
-       Various flags modifying the use of SSL while proxying https:// URLs:
-           DONT_VERIFY_PEER    Accept certificates that fail verification.
-                               For refined control, see sslproxy_cert_error.
-           NO_DEFAULT_CA       Don't use the default CA list built in
-                               to OpenSSL.
-DOC_END
-
 NAME: sslproxy_cert_error
 IFDEF: USE_SSL
 DEFAULT: none

=== modified file 'src/ssl/Config.cc'
--- src/ssl/Config.cc   2012-10-04 11:10:17 +0000
+++ src/ssl/Config.cc   2013-07-01 21:10:12 +0000
@@ -1,4 +1,6 @@
 #include "squid.h"
+#include "Debug.h"
+#include "Parsing.h"
 #include "ssl/Config.h"
 
 Ssl::Config Ssl::TheConfig;
@@ -17,3 +19,70 @@
     xfree(ssl_crtd);
 #endif
 }
+
+void
+Ssl::Config::parse(const char *name)
+{
+    // XXX: use name to determine what parsing style
+
+    if (strcmp(name, "ssl_proxy_direct") != 0) {
+      // directive formed from key=value pairs
+      // XXX: need to support quoted string values with whitespace
+
+      const char *token = NULL;
+      while ((token = strtok(NULL, w_space)) != NULL) {
+          if (!sslProxyDirect.parseOne(token)) {
+              debugs(3, DBG_CRITICAL, "ERROR: Ingnoring unknown SSL option '" 
<< token << "'.");
+          }
+      }
+    }
+    else {
+        // XXX: for the deprecated options - parse directly into the 
particular field indicated by name.
+    }
+}
+
+bool
+Ssl::ConfigOptions::parseOne(const char *token)
+{
+    if (strncmp(token, "cert=", 5) == 0) {
+        xfree(certfile);
+        certfile = xstrdup(token + 5);
+    } else if (strncmp(token, "key=", 4) == 0) {
+        xfree(keyfile);
+        keyfile = xstrdup(token + 4);
+    } else if (strncmp(token, "version=", 8) == 0) {
+        version = xatoi(token + 8);
+        if (version < 1 || version > 6) {
+            debugs(0,DBG_IMPORTANT, "Unknown SSL version '" << (token+8) << 
"'");
+            return false;
+        }
+    } else if (strncmp(token, "options=", 8) == 0) {
+        xfree(options);
+        options = xstrdup(token + 8);
+    } else if (strncmp(token, "cipher=", 7) == 0) {
+        xfree(cipher);
+        cipher = xstrdup(token + 7);
+    } else if (strncmp(token, "clientca=", 9) == 0) {
+        xfree(clientCA);
+        clientCA = xstrdup(token + 9);
+    } else if (strncmp(token, "cafile=", 7) == 0) {
+        xfree(CAfile);
+        CAfile = xstrdup(token + 7);
+    } else if (strncmp(token, "capath=", 7) == 0) {
+        xfree(CApath);
+        CApath = xstrdup(token + 7);
+    } else if (strncmp(token, "crlfile=", 8) == 0) {
+        xfree(CRLfile);
+        CRLfile = xstrdup(token + 8);
+    } else if (strncmp(token, "dhparams=", 9) == 0) {
+        xfree(DHfile);
+        DHfile = xstrdup(token + 9);
+    } else if (strncmp(token, "flags=", 6) == 0) {
+        xfree(flags);
+        flags = xstrdup(token + 6);
+    } else {
+        return false;
+    }
+
+    return true;
+}

=== modified file 'src/ssl/Config.h'
--- src/ssl/Config.h    2012-10-04 11:10:17 +0000
+++ src/ssl/Config.h    2013-07-01 21:10:05 +0000
@@ -1,14 +1,63 @@
-#ifndef SQUID_SSL_CONFIG_H
-#define SQUID_SSL_CONFIG_H
+#ifndef SQUID_SRC_SSL_CONFIG_H
+#define SQUID_SRC_SSL_CONFIG_H
 
 #include "HelperChildConfig.h"
 
 namespace Ssl
 {
 
+/// parse and store the configuration options used
+/// for generating an SSL context
+class ConfigOptions
+{
+public:
+    ConfigOptions() { memset(this, 0, sizeof(ConfigOptions)); };
+    ConfigOptions(const Ssl::ConfigOptions &other) :
+        certfile(other.certfile?xstrdup(other.certfile):NULL),
+        keyfile(other.keyfile?xstrdup(other.keyfile):NULL),
+        version(other.version),
+        cipher(other.cipher?xstrdup(other.cipher):NULL),
+        flags(other.flags?xstrdup(other.flags):NULL),
+        clientCA(other.clientCA?xstrdup(other.clientCA):NULL),
+        CAfile(other.CAfile?xstrdup(other.CAfile):NULL),
+        CApath(other.CApath?xstrdup(other.CApath):NULL),
+        CRLfile(other.CRLfile?xstrdup(other.CRLfile):NULL),
+        DHfile(other.DHfile?xstrdup(other.DHfile):NULL)
+    {}
+    ~ConfigOptions() {
+        xfree(certfile);
+        xfree(keyfile);
+        xfree(cipher);
+        xfree(flags);
+        xfree(clientCA);
+        xfree(CAfile);
+        xfree(CApath);
+        xfree(CRLfile);
+        xfree(DHfile);
+    }
+
+public: // options text as found in squid.conf parameters
+    char *certfile; // public cert file
+    char *keyfile;  // private key file
+    int version;
+    char *cipher;
+    char *options;
+    char *flags;
+    char *clientCA;
+    char *CAfile;
+    char *CApath; // path where CAfile may be found
+    char *CRLfile;
+    char *DHfile;
+
+    /// parse one option token as given on http(s)_port and cache_peer 
directives
+    bool parseOne(const char *cfg);
+};
+
 class Config
 {
 public:
+    ConfigOptions sslProxyDirect; ///< options used to generate the DIRECT 
outgoing context
+
 #if USE_SSL_CRTD
     char *ssl_crtd; ///< Name of external ssl_crtd application.
     /// The number of processes spawn for ssl_crtd.
@@ -16,6 +65,7 @@
 #endif
     Config();
     ~Config();
+    void parse(const char *name); ///< parse a SSL config directive.
 private:
     Config(const Config &); // not implemented
     Config &operator =(const Config &); // not implemented
@@ -24,4 +74,9 @@
 extern Config TheConfig;
 
 } // namespace Ssl
+
+#define parse_ssl_options()  Ssl::TheConfig.parse(token);
+#define free_ssl_options()   // TODO
+#define dump_ssl_options(e,n,x)   // TODO
+
 #endif

=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc  2012-11-23 06:03:26 +0000
+++ src/ssl/support.cc  2012-11-23 14:03:56 +0000
@@ -778,12 +778,12 @@
         SSL_CTX_set_quiet_shutdown(sslContext.get(), 1);
     }
 
-    if (port.cipher) {
-        debugs(83, 5, "Using chiper suite " << port.cipher << ".");
+    if (port.ssl.cipher) {
+        debugs(83, 5, "Using chiper suite " << port.ssl.cipher << ".");
 
-        if (!SSL_CTX_set_cipher_list(sslContext.get(), port.cipher)) {
+        if (!SSL_CTX_set_cipher_list(sslContext.get(), port.ssl.cipher)) {
             ssl_error = ERR_get_error();
-            debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" 
<< port.cipher << "': " << ERR_error_string(ssl_error, NULL));
+            debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" 
<< port.ssl.cipher << "': " << ERR_error_string(ssl_error, NULL));
             return false;
         }
     }
@@ -793,8 +793,8 @@
 
     debugs(83, 9, "Setting CA certificate locations.");
 
-    const char *cafile = port.cafile ? port.cafile : port.clientca;
-    if ((cafile || port.capath) && 
!SSL_CTX_load_verify_locations(sslContext.get(), cafile, port.capath)) {
+    const char *cafile = port.ssl.CAfile ? port.ssl.CAfile : port.ssl.clientCA;
+    if ((cafile || port.ssl.CApath) && 
!SSL_CTX_load_verify_locations(sslContext.get(), cafile, port.ssl.CApath)) {
         ssl_error = ERR_get_error();
         debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA 
certificate locations: " << ERR_error_string(ssl_error, NULL));
     }
@@ -856,8 +856,8 @@
     // build the context in a temporary which will do any cleanup
     // store in 'result' parameter only if successfully created.
     const char *keyfile, *certfile;
-    certfile = port.cert;
-    keyfile = port.key;
+    certfile = port.ssl.certfile;
+    keyfile = port.ssl.keyfile;
 
     ssl_initialize();
 
@@ -938,7 +938,8 @@
 }
 
 bool
-Ssl::CreateClientContext(Ssl::SSL_CTX_Pointer &result, const char *certfile, 
const char *keyfile, int version, const char *cipher, const char *options, 
const char *flags, const char *CAfile, const char *CApath, const char *CRLfile)
+Ssl::CreateClientContext(Ssl::SSL_CTX_Pointer &result, const 
Ssl::ConfigOptions &cfg)
+// const char *certfile, const char *keyfile, int version, const char *cipher, 
const char *options, const char *flags, const char *CAfile, const char *CApath, 
const char *CRLfile)
 {
 #if HAVE_OPENSSL
     int ssl_error;
@@ -947,17 +948,19 @@
 #else
     const SSL_METHOD *method;
 #endif
-    long fl = Ssl::parse_flags(flags);
+    long fl = Ssl::parse_flags(cfg.flags);
 
     ssl_initialize();
 
+    char *keyfile = cfg.keyfile;
     if (!keyfile)
-        keyfile = certfile;
+        keyfile = cfg.certfile;
 
+    char *certfile = cfg.certfile;
     if (!certfile)
-        certfile = keyfile;
+        certfile = cfg.keyfile;
 
-    switch (version) {
+    switch (cfg.version) {
 
     case 2:
 #ifndef OPENSSL_NO_SSL2
@@ -1015,15 +1018,15 @@
                ERR_error_string(ssl_error, NULL));
     }
 
-    SSL_CTX_set_options(sslContext.get(), Ssl::parse_options(options));
-
-    if (cipher) {
-        debugs(83, 5, "Using chiper suite " << cipher << ".");
-
-        if (!SSL_CTX_set_cipher_list(sslContext.get(), cipher)) {
+    SSL_CTX_set_options(sslContext.get(), Ssl::parse_options(cfg.options));
+
+    if (cfg.cipher) {
+        debugs(83, 5, "Using chiper suite " << cfg.cipher << ".");
+
+        if (!SSL_CTX_set_cipher_list(sslContext.get(), cfg.cipher)) {
             ssl_error = ERR_get_error();
             fatalf("Failed to set SSL cipher suite '%s': %s\n",
-                   cipher, ERR_error_string(ssl_error, NULL));
+                   cfg.cipher, ERR_error_string(ssl_error, NULL));
         }
     }
 
@@ -1067,13 +1070,13 @@
 
     debugs(83, 9, "Setting CA certificate locations.");
 
-    if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(sslContext.get(), 
CAfile, CApath)) {
+    if ((cfg.CAfile || cfg.CApath) && 
!SSL_CTX_load_verify_locations(sslContext.get(), cfg.CAfile, cfg.CApath)) {
         ssl_error = ERR_get_error();
         debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA 
certificate locations: " << ERR_error_string(ssl_error, NULL));
     }
 
-    if (CRLfile) {
-        ssl_load_crl(sslContext.get(), CRLfile);
+    if (cfg.CRLfile) {
+        ssl_load_crl(sslContext.get(), cfg.CRLfile);
         fl |= SSL_FLAG_VERIFY_CRL;
     }
 

=== modified file 'src/ssl/support.h'
--- src/ssl/support.h   2012-11-23 05:39:27 +0000
+++ src/ssl/support.h   2012-11-23 14:18:55 +0000
@@ -72,6 +72,8 @@
 
 namespace Ssl
 {
+class ConfigOptions;
+
 /// Squid defined error code (<0),  an error code returned by SSL X509 api, or 
SSL_ERROR_NONE
 typedef int ssl_error_t;
 
@@ -81,7 +83,7 @@
 bool CreateServerContext(SSL_CTX_Pointer &sslContext, AnyP::PortCfg &port);
 
 /// \ingroup ServerProtocolSSLAPI
-bool CreateClientContext(SSL_CTX_Pointer &sslContext, const char *certfile, 
const char *keyfile, int version, const char *cipher, const char *options, 
const char *flags, const char *CAfile, const char *CApath, const char *CRLfile);
+bool CreateClientContext(SSL_CTX_Pointer &sslContext, const Ssl::ConfigOptions 
&options);
 
 } //namespace Ssl
 

Reply via email to