TLS/SSL Options does not apply to the dynamically generated certificates

The TLS/SSL options configured with http_port configuration parameter
does not used to generate SSL_CTX context objects used to establish SSL
connections. This is means that certificate based authentication, or SSL
version selection and other SSL/TLS http_port options does not work for
ssl-bumped connection.

This patch fixes this problem.

This is a Measurement Factory project
TLS/SSL Options does not apply to the dynamically generated certificates

The TLS/SSL options configured with http_port configuration parameter does not
used to generate SSL_CTX context objects used to establish SSL connections.
This is means that certificate based authentication, or SSL version selection
and other SSL/TLS http_port options does not work for ssl-bumped connection.
This patch fixes this problem.

This is a Measurement Factory project
=== modified file 'src/anyp/PortCfg.cc'
--- src/anyp/PortCfg.cc	2012-05-14 10:37:40 +0000
+++ src/anyp/PortCfg.cc	2012-07-25 15:15:30 +0000
@@ -30,41 +30,41 @@
     }
 
     safe_free(name);
     safe_free(defaultsite);
     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
 }
 
 AnyP::PortCfg *
-AnyP::PortCfg::clone() const
+ AnyP::PortCfg::clone() const
 {
     AnyP::PortCfg *b = new AnyP::PortCfg(protocol);
 
     b->s = s;
     if (name)
         b->name = xstrdup(name);
     if (defaultsite)
         b->defaultsite = xstrdup(defaultsite);
 
     b->intercepted = intercepted;
     b->spoof_client_ip = spoof_client_ip;
     b->accel = accel;
     b->allow_direct = allow_direct;
     b->vhost = vhost;
     b->sslBump = sslBump;
     b->vport = vport;
     b->connection_auth_disabled = connection_auth_disabled;
     b->disable_pmtu_discovery = disable_pmtu_discovery;
 
     memcpy( &(b->tcp_keepalive), &(tcp_keepalive), sizeof(tcp_keepalive));
@@ -79,55 +79,70 @@
     char *cipher;
     char *options;
     char *clientca;
     char *cafile;
     char *capath;
     char *crlfile;
     char *dhfile;
     char *sslflags;
     char *sslContextSessionId;
     SSL_CTX *sslContext;
 #endif
 
 #endif /*0*/
 
     return b;
 }
 
 #if USE_SSL
 void AnyP::PortCfg::configureSslServerContext()
 {
-    staticSslContext.reset(
-        sslCreateServerContext(cert, key,
-                               version, cipher, options, sslflags, clientca,
-                               cafile, capath, crlfile, dhfile,
-                               sslContextSessionId));
-
-    if (!staticSslContext) {
-        char buf[128];
-        fatalf("%s_port %s initialization error", protocol,  s.ToURL(buf, sizeof(buf)));
-    }
-
-    if (!sslBump)
-        return;
-
     if (cert)
         Ssl::readCertChainAndPrivateKeyFromFiles(signingCert, signPkey, certsToChain, cert, key);
 
     if (!signingCert) {
         char buf[128];
         fatalf("No valid signing SSL certificate configured for %s_port %s", protocol,  s.ToURL(buf, sizeof(buf)));
     }
 
     if (!signPkey)
         debugs(3, DBG_IMPORTANT, "No SSL private key configured for  " <<  protocol << "_port " << s);
 
     Ssl::generateUntrustedCert(untrustedSigningCert, untrustedSignPkey,
                                signingCert, signPkey);
 
     if (!untrustedSigningCert) {
         char buf[128];
         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 (clientca) {
+        clientCA.reset(SSL_load_client_CA_file(clientca));
+        if(clientCA.get() == NULL) {
+            fatalf("Unable to read client CAs! from %s", clientca);
+        }
+    }
+
+    contextMethod = Ssl::contextMethod(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);
+
+    staticSslContext.reset(sslCreateServerContext(*this));
+
+    if (!staticSslContext) {
+        char buf[128];
+        fatalf("%s_port %s initialization error", protocol,  s.ToURL(buf, sizeof(buf)));
+    }
 }
 #endif
 

=== modified file 'src/anyp/PortCfg.h'
--- src/anyp/PortCfg.h	2012-06-19 21:51:49 +0000
+++ src/anyp/PortCfg.h	2012-07-25 09:52:36 +0000
@@ -59,35 +59,42 @@
     char *key;
     int version;
     char *cipher;
     char *options;
     char *clientca;
     char *cafile;
     char *capath;
     char *crlfile;
     char *dhfile;
     char *sslflags;
     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
 
     Ssl::SSL_CTX_Pointer staticSslContext; ///< for HTTPS accelerator or static sslBump
     Ssl::X509_Pointer signingCert; ///< x509 certificate for signing generated certificates
     Ssl::EVP_PKEY_Pointer signPkey; ///< private key for sighing generated certificates
     Ssl::X509_STACK_Pointer certsToChain; ///<  x509 certificates to send with the generated cert
     Ssl::X509_Pointer untrustedSigningCert; ///< x509 certificate for signing untrusted generated certificates
     Ssl::EVP_PKEY_Pointer untrustedSignPkey; ///< private key for signing untrusted generated certificates
+
+    Ssl::X509_CRL_STACK_Pointer clientVerifyCrls; ///< additional CRL lists to use when verifying the client certificate
+    Ssl::X509_NAME_STACK_Pointer clientCA; ///<
+    Ssl::DH_Pointer dhParams; ///<
+    Ssl::ContextMethod contextMethod;
+    long sslContextFlags;
+    long sslOptions;
 #endif
 
     CBDATA_CLASS2(PortCfg); // namespaced
 };
 
 } // namespace AnyP
 
 // Max number of TCP listening ports
 #define MAXTCPLISTENPORTS 128
 
 // TODO: kill this global array. Need to check performance of array vs list though.
 extern int NHttpSockets;
 extern int HttpSockets[MAXTCPLISTENPORTS];
 
 #endif /* SQUID_ANYP_PORTCFG_H */

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2012-08-06 17:21:57 +0000
+++ src/client_side.cc	2012-08-09 12:48:18 +0000
@@ -3671,41 +3671,41 @@
 ConnStateData::sslCrtdHandleReplyWrapper(void *data, char *reply)
 {
     ConnStateData * state_data = (ConnStateData *)(data);
     state_data->sslCrtdHandleReply(reply);
 }
 
 void
 ConnStateData::sslCrtdHandleReply(const char * reply)
 {
     if (!reply) {
         debugs(1, DBG_IMPORTANT, HERE << "\"ssl_crtd\" helper return <NULL> reply");
     } else {
         Ssl::CrtdMessage reply_message;
         if (reply_message.parse(reply, strlen(reply)) != Ssl::CrtdMessage::OK) {
             debugs(33, 5, HERE << "Reply from ssl_crtd for " << sslConnectHostOrIp << " is incorrect");
         } else {
             if (reply_message.getCode() != "OK") {
                 debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
             } else {
                 debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " was successfully recieved from ssl_crtd");
-                SSL_CTX *ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str());
+                SSL_CTX *ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port);
                 getSslContextDone(ctx, true);
                 return;
             }
         }
     }
     getSslContextDone(NULL);
 }
 
 void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties)
 {
     certProperties.commonName =  sslCommonName.defined() ? sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
 
     // fake certificate adaptation requires bump-server-first mode
     if (!sslServerBump) {
         assert(port->signingCert.get());
         certProperties.signWithX509.resetAndLock(port->signingCert.get());
         if (port->signPkey.get())
             certProperties.signWithPkey.resetAndLock(port->signPkey.get());
         certProperties.signAlgorithm = Ssl::algSignTrusted;
         return;
@@ -3816,41 +3816,41 @@
 
 #if USE_SSL_CRTD
         try {
             debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
             Ssl::CrtdMessage request_message;
             request_message.setCode(Ssl::CrtdMessage::code_new_certificate);
             request_message.composeRequest(certProperties);
             debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
             Ssl::Helper::GetInstance()->sslSubmit(request_message, sslCrtdHandleReplyWrapper, this);
             return;
         } catch (const std::exception &e) {
             debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
                    "request for " << certProperties.commonName <<
                    " certificate: " << e.what() << "; will now block to " <<
                    "generate that certificate.");
             // fall through to do blocking in-process generation.
         }
 #endif // USE_SSL_CRTD
 
         debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName);
-        dynCtx = Ssl::generateSslContext(certProperties);
+        dynCtx = Ssl::generateSslContext(certProperties, *port);
         getSslContextDone(dynCtx, true);
         return;
     }
     getSslContextDone(NULL);
 }
 
 void
 ConnStateData::getSslContextDone(SSL_CTX * sslContext, bool isNew)
 {
     // Try to add generated ssl context to storage.
     if (port->generateHostCertificates && isNew) {
 
         if (signAlgorithm == Ssl::algSignTrusted)
             Ssl::addChainToSslContext(sslContext, port->certsToChain.get());
         //else it is self-signed or untrusted do not attrach any certificate
 
         Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
         assert(sslBumpCertKey.defined() && sslBumpCertKey[0] != '\0');
         if (sslContext) {
             if (!ssl_ctx_cache.add(sslBumpCertKey.termedBuf(), sslContext)) {

=== modified file 'src/ssl/gadgets.h'
--- src/ssl/gadgets.h	2012-07-27 23:02:09 +0000
+++ src/ssl/gadgets.h	2012-08-09 12:48:18 +0000
@@ -9,109 +9,131 @@
 #include "ssl/crtd_message.h"
 
 #if HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
 #endif
 #if HAVE_OPENSSL_TXT_DB_H
 #include <openssl/txt_db.h>
 #endif
 #if HAVE_STRING
 #include <string>
 #endif
 
 namespace Ssl
 {
 /**
  \defgroup SslCrtdSslAPI ssl_crtd SSL api.
  These functions must not depend on Squid runtime code such as debug()
  because they are used by ssl_crtd.
  */
 
+#if OPENSSL_VERSION_NUMBER < 0x00909000L
+typedef SSL_METHOD * ContextMethod;
+#else
+typedef const SSL_METHOD * ContextMethod;
+#endif
+
 /**
    \ingroup SslCrtdSslAPI
   * Add SSL locking (a.k.a. reference counting) to TidyPointer
   */
 template <typename T, void (*DeAllocator)(T *t), int lock>
 class LockingPointer: public TidyPointer<T, DeAllocator>
 {
 public:
     typedef TidyPointer<T, DeAllocator> Parent;
 
     LockingPointer(T *t = NULL): Parent(t) {
     }
 
     void resetAndLock(T *t) {
         if (t != this->get()) {
             this->reset(t);
             if (t)
                 CRYPTO_add(&t->references, 1, lock);
         }
     }
 };
 
 // Macro to be used to define the C++ equivalent function of an extern "C"
 // function. The C++ function suffixed with the _cpp extension
 #define CtoCpp1(function, argument) \
         extern "C++" inline void function ## _cpp(argument a) { \
             function(a); \
         }
 
+// Macro to be used to define the C++ wrapper function of a sk_*_pop_free
+// openssl family functions. The C++ function suffixed with the _free_wrapper 
+// extension
+#define sk_free_wrapper(sk_object, argument, freefunction)                          \
+        extern "C++" inline void sk_object ## _free_wrapper(argument a) { \
+            sk_object ## _pop_free(a, freefunction);                                 \
+        }
+
 /**
  \ingroup SslCrtdSslAPI
  * TidyPointer typedefs for  common SSL objects
  */
 CtoCpp1(X509_free, X509 *)
 typedef LockingPointer<X509, X509_free_cpp, CRYPTO_LOCK_X509> X509_Pointer;
 
-CtoCpp1(sk_X509_free, STACK_OF(X509) *)
-typedef TidyPointer<STACK_OF(X509), sk_X509_free_cpp> X509_STACK_Pointer;
+sk_free_wrapper(sk_X509, STACK_OF(X509) *, X509_free)
+typedef TidyPointer<STACK_OF(X509), sk_X509_free_wrapper> X509_STACK_Pointer;
 
 CtoCpp1(EVP_PKEY_free, EVP_PKEY *)
 typedef LockingPointer<EVP_PKEY, EVP_PKEY_free_cpp, CRYPTO_LOCK_EVP_PKEY> EVP_PKEY_Pointer;
 
 CtoCpp1(BN_free, BIGNUM *)
 typedef TidyPointer<BIGNUM, BN_free_cpp> BIGNUM_Pointer;
 
 CtoCpp1(BIO_free, BIO *)
 typedef TidyPointer<BIO, BIO_free_cpp> BIO_Pointer;
 
 CtoCpp1(ASN1_INTEGER_free, ASN1_INTEGER *)
 typedef TidyPointer<ASN1_INTEGER, ASN1_INTEGER_free_cpp> ASN1_INT_Pointer;
 
 CtoCpp1(TXT_DB_free, TXT_DB *)
 typedef TidyPointer<TXT_DB, TXT_DB_free_cpp> TXT_DB_Pointer;
 
 CtoCpp1(X509_NAME_free, X509_NAME *)
 typedef TidyPointer<X509_NAME, X509_NAME_free_cpp> X509_NAME_Pointer;
 
 CtoCpp1(RSA_free, RSA *)
 typedef TidyPointer<RSA, RSA_free_cpp> RSA_Pointer;
 
 CtoCpp1(X509_REQ_free, X509_REQ *)
 typedef TidyPointer<X509_REQ, X509_REQ_free_cpp> X509_REQ_Pointer;
 
 CtoCpp1(SSL_CTX_free, SSL_CTX *)
 typedef TidyPointer<SSL_CTX, SSL_CTX_free_cpp> SSL_CTX_Pointer;
 
 CtoCpp1(SSL_free, SSL *)
 typedef TidyPointer<SSL, SSL_free_cpp> SSL_Pointer;
 
+CtoCpp1(DH_free, DH *);
+typedef TidyPointer<DH, DH_free_cpp> DH_Pointer;
+
+sk_free_wrapper(sk_X509_CRL, STACK_OF(X509_CRL) *, X509_CRL_free)
+typedef TidyPointer<STACK_OF(X509_CRL), sk_X509_CRL_free_wrapper> X509_CRL_STACK_Pointer;
+
+sk_free_wrapper(sk_X509_NAME, STACK_OF(X509_NAME) *, X509_NAME_free)
+typedef TidyPointer<STACK_OF(X509_NAME), sk_X509_NAME_free_wrapper> X509_NAME_STACK_Pointer;
 
 /**
  \ingroup SslCrtdSslAPI
  * Create 1024 bits rsa key.
  */
 EVP_PKEY * createSslPrivateKey();
 
 /**
  \ingroup SslCrtdSslAPI
  * Write private key and SSL certificate to memory.
  */
 bool writeCertAndPrivateKeyToMemory(X509_Pointer const & cert, EVP_PKEY_Pointer const & pkey, std::string & bufferToWrite);
 
 /**
  \ingroup SslCrtdSslAPI
  * Append SSL certificate to bufferToWrite.
  */
 bool appendCertToMemory(X509_Pointer const & cert, std::string & bufferToWrite);
 
 /**

=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc	2012-08-06 17:21:57 +0000
+++ src/ssl/support.cc	2012-08-09 12:48:18 +0000
@@ -25,40 +25,41 @@
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid-old.h"
 
 /* MS Visual Studio Projects are monolithic, so we need the following
  * #if to exclude the SSL code from compile process when not needed.
  */
 #if USE_SSL
 
 #include "fde.h"
 #include "acl/FilledChecklist.h"
+#include "anyp/PortCfg.h"
 #include "ssl/ErrorDetail.h"
 #include "ssl/support.h"
 #include "ssl/gadgets.h"
 
 const char *Ssl::BumpModeStr[] = {
     "none",
     "client-first",
     "server-first",
     NULL
 };
 
 /**
  \defgroup ServerProtocolSSLInternal Server-Side SSL Internals
  \ingroup ServerProtocolSSLAPI
  */
 
 /// \ingroup ServerProtocolSSLInternal
 static int
 ssl_ask_password_cb(char *buf, int size, int rwflag, void *userdata)
 {
@@ -427,42 +428,42 @@
 #endif
 #if SSL_OP_NO_TLSv1_1
     {
         "NO_TLSv1_1", SSL_OP_NO_TLSv1_1
     },
 #endif
 #if SSL_OP_NO_TLSv1_2
     {
         "NO_TLSv1_2", SSL_OP_NO_TLSv1_2
     },
 #endif
     {
         "", 0
     },
     {
         NULL, 0
     }
 };
 
 /// \ingroup ServerProtocolSSLInternal
-static long
-ssl_parse_options(const char *options)
+long
+Ssl::parse_options(const char *options)
 {
     long op = 0;
     char *tmp;
     char *option;
 
     if (!options)
         goto no_options;
 
     tmp = xstrdup(options);
 
     option = strtok(tmp, ":,");
 
     while (option) {
 
         struct ssl_option *opt = NULL, *opttmp;
         long value = 0;
         enum {
             MODE_ADD, MODE_REMOVE
         } mode;
 
@@ -521,42 +522,42 @@
 no_options:
     return op;
 }
 
 /// \ingroup ServerProtocolSSLInternal
 #define SSL_FLAG_NO_DEFAULT_CA		(1<<0)
 /// \ingroup ServerProtocolSSLInternal
 #define SSL_FLAG_DELAYED_AUTH		(1<<1)
 /// \ingroup ServerProtocolSSLInternal
 #define SSL_FLAG_DONT_VERIFY_PEER	(1<<2)
 /// \ingroup ServerProtocolSSLInternal
 #define SSL_FLAG_DONT_VERIFY_DOMAIN	(1<<3)
 /// \ingroup ServerProtocolSSLInternal
 #define SSL_FLAG_NO_SESSION_REUSE	(1<<4)
 /// \ingroup ServerProtocolSSLInternal
 #define SSL_FLAG_VERIFY_CRL		(1<<5)
 /// \ingroup ServerProtocolSSLInternal
 #define SSL_FLAG_VERIFY_CRL_ALL		(1<<6)
 
 /// \ingroup ServerProtocolSSLInternal
-static long
-ssl_parse_flags(const char *flags)
+long
+Ssl::parse_flags(const char *flags)
 {
     long fl = 0;
     char *tmp;
     char *flag;
 
     if (!flags)
         return 0;
 
     tmp = xstrdup(flags);
 
     flag = strtok(tmp, ":,");
 
     while (flag) {
         if (strcmp(flag, "NO_DEFAULT_CA") == 0)
             fl |= SSL_FLAG_NO_DEFAULT_CA;
         else if (strcmp(flag, "DELAYED_AUTH") == 0)
             fl |= SSL_FLAG_DELAYED_AUTH;
         else if (strcmp(flag, "DONT_VERIFY_PEER") == 0)
             fl |= SSL_FLAG_DONT_VERIFY_PEER;
         else if (strcmp(flag, "DONT_VERIFY_DOMAIN") == 0)
@@ -681,51 +682,276 @@
     int count = 0;
 
     if (!in) {
         debugs(83, 2, "WARNING: Failed to open CRL file '" << CRLfile << "'");
         return 0;
     }
 
     while ((crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL))) {
         if (!X509_STORE_add_crl(st, crl))
             debugs(83, 2, "WARNING: Failed to add CRL from file '" << CRLfile << "'");
         else
             ++count;
 
         X509_CRL_free(crl);
     }
 
     BIO_free(in);
     return count;
 }
 
+STACK_OF(X509_CRL) *
+Ssl::loadCrl(const char *CRLFile, long &flags)
+{
+    X509_CRL *crl;
+    BIO *in = BIO_new_file(CRLFile, "r");
+    if (!in) {
+        debugs(83, 2, "WARNING: Failed to open CRL file '" << CRLFile << "'");
+        return NULL;
+    }
+
+    STACK_OF(X509_CRL) *CRLs = sk_X509_CRL_new_null();
+    if (!CRLs) {
+        debugs(83, 2, "WARNING: Failed to allocate X509_CRL stack  to load file '" << CRLFile << "'");
+        return NULL;
+    }
+
+    int count = 0;
+    while ((crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL))) {
+        if (!sk_X509_CRL_push(CRLs, crl))
+            debugs(83, 2, "WARNING: Failed to add CRL from file '" << CRLFile << "'");
+        else
+            ++count;
+    }
+    BIO_free(in);
+
+    if (count)
+        flags |= SSL_FLAG_VERIFY_CRL;
+
+    return CRLs;
+}
+
+DH *Ssl::readDHParams(const char *dhfile)
+{
+    FILE *in = fopen(dhfile, "r");
+    DH *dh = NULL;
+    int codes;
+
+    if (in) {
+        dh = PEM_read_DHparams(in, NULL, NULL, NULL);
+        fclose(in);
+    }
+
+    if (!dh)
+        debugs(83, DBG_IMPORTANT, "WARNING: Failed to read DH parameters '" << dhfile << "'");
+    else if (dh && DH_check(dh, &codes) == 0) {
+        if (codes) {
+            debugs(83, DBG_IMPORTANT, "WARNING: Failed to verify DH parameters '" << dhfile  << "' (" << std::hex << codes  << ")");
+            DH_free(dh);
+            dh = NULL;
+        }
+    }
+    return dh;
+}
+
+static bool configureSslContext(SSL_CTX *sslContext, AnyP::PortCfg &port)
+{
+    int ssl_error;
+    SSL_CTX_set_options(sslContext, port.sslOptions);
+    
+    if (port.sslContextSessionId)
+        SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)port.sslContextSessionId, strlen(port.sslContextSessionId));
+    
+    if (port.sslContextFlags & SSL_FLAG_NO_SESSION_REUSE) {
+        SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
+    }
+
+    if (Config.SSL.unclean_shutdown) {
+        debugs(83, 5, "Enabling quiet SSL shutdowns (RFC violation).");
+
+        SSL_CTX_set_quiet_shutdown(sslContext, 1);
+    }
+
+    if (port.cipher) {
+        debugs(83, 5, "Using chiper suite " << port.cipher << ".");
+
+        if (!SSL_CTX_set_cipher_list(sslContext, port.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));
+            return false;
+        }
+    }
+
+    debugs(83, 9, "Setting RSA key generation callback.");
+    SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
+
+    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, cafile, port.capath)) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL));
+    }
+
+    if (!(port.sslContextFlags & SSL_FLAG_NO_DEFAULT_CA) &&
+            !SSL_CTX_set_default_verify_paths(sslContext)) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL));
+    }
+
+    if (port.clientCA.get()) {
+        ERR_clear_error();
+        SSL_CTX_set_client_CA_list(sslContext, port.clientCA.get());
+
+        if (port.sslContextFlags & SSL_FLAG_DELAYED_AUTH) {
+            debugs(83, 9, "Not requesting client certificates until acl processing requires one");
+            SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+        } else {
+            debugs(83, 9, "Requiring client certificates.");
+            SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+        }
+
+        if (port.clientVerifyCrls.get()) {
+            X509_STORE *st = SSL_CTX_get_cert_store(sslContext);
+            for (int i = 0; i < sk_X509_CRL_num(port.clientVerifyCrls.get()); ++i) {
+                X509_CRL *crl = sk_X509_CRL_value(port.clientVerifyCrls.get(), i);
+                if (!X509_STORE_add_crl(st, crl))
+                    debugs(83, 2, "WARNING: Failed to add CRL");
+            }
+        }
+
+#if X509_V_FLAG_CRL_CHECK
+        if (port.sslContextFlags & SSL_FLAG_VERIFY_CRL_ALL)
+            X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+        else if (port.sslContextFlags & SSL_FLAG_VERIFY_CRL)
+            X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK);
+#endif
+
+    } else {
+        debugs(83, 9, "Not requiring any client certificates");
+        SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+    }
+
+
+    if (port.dhParams.get()) {
+        SSL_CTX_set_tmp_dh(sslContext, port.dhParams.get());
+    }
+
+    if (port.sslContextFlags & SSL_FLAG_DONT_VERIFY_DOMAIN)
+        SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
+
+    return true;
+}
+
+SSL_CTX *
+sslCreateServerContext(AnyP::PortCfg &port)
+{
+    int ssl_error;
+    SSL_CTX *sslContext;
+    const char *keyfile, *certfile;
+    certfile = port.cert;
+    keyfile = port.key;
+
+    ssl_initialize();
+
+    if (!keyfile)
+        keyfile = certfile;
+
+    if (!certfile)
+        certfile = keyfile;
+
+    sslContext = SSL_CTX_new(port.contextMethod);
+
+    if (sslContext == NULL) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate SSL context: " << ERR_error_string(ssl_error, NULL));
+        return NULL;
+    }
+
+    if (!SSL_CTX_use_certificate(sslContext, port.signingCert.get())) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL));
+        SSL_CTX_free(sslContext);
+        return NULL;
+    }
+
+    if (!SSL_CTX_use_PrivateKey(sslContext, port.signPkey.get())) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL));
+        SSL_CTX_free(sslContext);
+        return NULL;
+    }
+
+    Ssl::addChainToSslContext(sslContext, port.certsToChain.get());
+
+
+/* Alternate code;
+    debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile);
+
+    if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL));
+        SSL_CTX_free(sslContext);
+        return NULL;
+    }
+
+    debugs(83, DBG_IMPORTANT, "Using private key in " << keyfile);
+    ssl_ask_password(sslContext, keyfile);
+
+    if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL));
+        SSL_CTX_free(sslContext);
+        return NULL;
+    }
+
+    debugs(83, 5, "Comparing private and public SSL keys.");
+
+    if (!SSL_CTX_check_private_key(sslContext)) {
+        ssl_error = ERR_get_error();
+        debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" <<
+               keyfile << "': " << ERR_error_string(ssl_error, NULL));
+        SSL_CTX_free(sslContext);
+        return NULL;
+    }
+*/
+
+    if (!configureSslContext(sslContext, port)) {
+        debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context");
+        SSL_CTX_free(sslContext);
+        return NULL;
+    }
+
+    return sslContext;
+}
+
 SSL_CTX *
 sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath, const char *CRLfile, const char *dhfile, const char *context)
 {
     int ssl_error;
 #if OPENSSL_VERSION_NUMBER < 0x00909000L
     SSL_METHOD *method;
 #else
     const SSL_METHOD *method;
 #endif
     SSL_CTX *sslContext;
-    long fl = ssl_parse_flags(flags);
+    long fl = Ssl::parse_flags(flags);
 
     ssl_initialize();
 
     if (!keyfile)
         keyfile = certfile;
 
     if (!certfile)
         certfile = keyfile;
 
     if (!CAfile)
         CAfile = clientCA;
 
     if (!certfile) {
         debugs(83, DBG_CRITICAL, "ERROR: No certificate file");
         return NULL;
     }
 
     switch (version) {
 
     case 2:
@@ -767,41 +993,41 @@
         return NULL;
 #endif
         break;
 
     case 1:
 
     default:
         debugs(83, 5, "Using SSLv2/SSLv3.");
         method = SSLv23_server_method();
         break;
     }
 
     sslContext = SSL_CTX_new(method);
 
     if (sslContext == NULL) {
         ssl_error = ERR_get_error();
         debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate SSL context: " << ERR_error_string(ssl_error, NULL));
         return NULL;
     }
 
-    SSL_CTX_set_options(sslContext, ssl_parse_options(options));
+    SSL_CTX_set_options(sslContext, Ssl::parse_options(options));
 
     if (context && *context) {
         SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)context, strlen(context));
     }
 
     if (fl & SSL_FLAG_NO_SESSION_REUSE) {
         SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
     }
 
     if (Config.SSL.unclean_shutdown) {
         debugs(83, 5, "Enabling quiet SSL shutdowns (RFC violation).");
 
         SSL_CTX_set_quiet_shutdown(sslContext, 1);
     }
 
     if (cipher) {
         debugs(83, 5, "Using chiper suite " << cipher << ".");
 
         if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
             ssl_error = ERR_get_error();
@@ -834,41 +1060,41 @@
 
     if (!SSL_CTX_check_private_key(sslContext)) {
         ssl_error = ERR_get_error();
         debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" <<
                keyfile << "': " << ERR_error_string(ssl_error, NULL));
         SSL_CTX_free(sslContext);
         return NULL;
     }
 
     debugs(83, 9, "Setting RSA key generation callback.");
     SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
 
     debugs(83, 9, "Setting CA certificate locations.");
 
     if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, CApath)) {
         ssl_error = ERR_get_error();
         debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL));
     }
 
     if (!(fl & SSL_FLAG_NO_DEFAULT_CA) &&
-            !SSL_CTX_set_default_verify_paths(sslContext)) {
+        !SSL_CTX_set_default_verify_paths(sslContext)) {
         ssl_error = ERR_get_error();
         debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL));
     }
 
     if (clientCA) {
         STACK_OF(X509_NAME) *cert_names;
         debugs(83, 9, "Set client certifying authority list.");
         cert_names = SSL_load_client_CA_file(clientCA);
 
         if (cert_names == NULL) {
             debugs(83, DBG_IMPORTANT, "ERROR: loading the client CA certificates from '" << clientCA << "\': " << ERR_error_string(ERR_get_error(),NULL));
             SSL_CTX_free(sslContext);
             return NULL;
         }
 
         ERR_clear_error();
         SSL_CTX_set_client_CA_list(sslContext, cert_names);
 
         if (fl & SSL_FLAG_DELAYED_AUTH) {
             debugs(83, 9, "Not requesting client certificates until acl processing requires one");
@@ -919,41 +1145,41 @@
         if (dh)
             SSL_CTX_set_tmp_dh(sslContext, dh);
     }
 
     if (fl & SSL_FLAG_DONT_VERIFY_DOMAIN)
         SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
 
     return sslContext;
 }
 
 SSL_CTX *
 sslCreateClientContext(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)
 {
     int ssl_error;
 #if OPENSSL_VERSION_NUMBER < 0x00909000L
     SSL_METHOD *method;
 #else
     const SSL_METHOD *method;
 #endif
     SSL_CTX *sslContext;
-    long fl = ssl_parse_flags(flags);
+    long fl = Ssl::parse_flags(flags);
 
     ssl_initialize();
 
     if (!keyfile)
         keyfile = certfile;
 
     if (!certfile)
         certfile = keyfile;
 
     switch (version) {
 
     case 2:
 #ifndef OPENSSL_NO_SSL2
         debugs(83, 5, "Using SSLv2.");
         method = SSLv2_client_method();
 #else
         debugs(83, DBG_IMPORTANT, "SSLv2 is not available in this Proxy.");
         return NULL;
 #endif
         break;
@@ -987,41 +1213,41 @@
         return NULL;
 #endif
         break;
 
     case 1:
 
     default:
         debugs(83, 5, "Using SSLv2/SSLv3.");
         method = SSLv23_client_method();
         break;
     }
 
     sslContext = SSL_CTX_new(method);
 
     if (sslContext == NULL) {
         ssl_error = ERR_get_error();
         fatalf("Failed to allocate SSL context: %s\n",
                ERR_error_string(ssl_error, NULL));
     }
 
-    SSL_CTX_set_options(sslContext, ssl_parse_options(options));
+    SSL_CTX_set_options(sslContext, Ssl::parse_options(options));
 
     if (cipher) {
         debugs(83, 5, "Using chiper suite " << cipher << ".");
 
         if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
             ssl_error = ERR_get_error();
             fatalf("Failed to set SSL cipher suite '%s': %s\n",
                    cipher, ERR_error_string(ssl_error, NULL));
         }
     }
 
     if (certfile) {
         debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile);
 
         if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) {
             ssl_error = ERR_get_error();
             fatalf("Failed to acquire SSL certificate '%s': %s\n",
                    certfile, ERR_error_string(ssl_error, NULL));
         }
 
@@ -1058,41 +1284,41 @@
 
     if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, 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, CRLfile);
         fl |= SSL_FLAG_VERIFY_CRL;
     }
 
 #if X509_V_FLAG_CRL_CHECK
     if (fl & SSL_FLAG_VERIFY_CRL_ALL)
         X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
     else if (fl & SSL_FLAG_VERIFY_CRL)
         X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK);
 
 #endif
 
     if (!(fl & SSL_FLAG_NO_DEFAULT_CA) &&
-            !SSL_CTX_set_default_verify_paths(sslContext)) {
+        !SSL_CTX_set_default_verify_paths(sslContext)) {
         ssl_error = ERR_get_error();
         debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL));
     }
 
     return sslContext;
 }
 
 /// \ingroup ServerProtocolSSLInternal
 int
 ssl_read_method(int fd, char *buf, int len)
 {
     SSL *ssl = fd_table[fd].ssl;
     int i;
 
 #if DONT_DO_THIS
 
     if (!SSL_is_init_finished(ssl)) {
         errno = ENOTCONN;
         return -1;
     }
@@ -1276,81 +1502,142 @@
         return sslGetUserCertificatePEM(ssl);
 
     mem = BIO_new(BIO_s_mem());
 
     for (i = 0; i < sk_X509_num(chain); ++i) {
         X509 *cert = sk_X509_value(chain, i);
         PEM_write_bio_X509(mem, cert);
     }
 
     len = BIO_get_mem_data(mem, &ptr);
 
     str = (char *)xmalloc(len + 1);
     memcpy(str, ptr, len);
     str[len] = '\0';
 
     BIO_free(mem);
 
     return str;
 }
 
+Ssl::ContextMethod
+Ssl::contextMethod(int version)
+{
+    Ssl::ContextMethod method;
+
+    switch (version) {
+
+    case 2:
+#ifndef OPENSSL_NO_SSL2
+        debugs(83, 5, "Using SSLv2.");
+        method = SSLv2_server_method();
+#else
+        debugs(83, DBG_IMPORTANT, "SSLv2 is not available in this Proxy.");
+        return NULL;
+#endif
+        break;
+
+    case 3:
+        debugs(83, 5, "Using SSLv3.");
+        method = SSLv3_server_method();
+        break;
+
+    case 4:
+        debugs(83, 5, "Using TLSv1.");
+        method = TLSv1_server_method();
+        break;
+
+    case 5:
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L  // NP: not sure exactly which sub-version yet.
+        debugs(83, 5, "Using TLSv1.1.");
+        method = TLSv1_1_server_method();
+#else
+        debugs(83, DBG_IMPORTANT, "TLSv1.1 is not available in this Proxy.");
+        return NULL;
+#endif
+        break;
+
+    case 6:
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet.
+        debugs(83, 5, "Using TLSv1.2");
+        method = TLSv1_2_server_method();
+#else
+        debugs(83, DBG_IMPORTANT, "TLSv1.2 is not available in this Proxy.");
+        return NULL;
+#endif
+        break;
+
+    case 1:
+
+    default:
+        debugs(83, 5, "Using SSLv2/SSLv3.");
+        method = SSLv23_server_method();
+        break;
+    }
+    return method;
+}
+
 /// \ingroup ServerProtocolSSLInternal
 /// Create SSL context and apply ssl certificate and private key to it.
-static SSL_CTX * createSSLContext(Ssl::X509_Pointer & x509, Ssl::EVP_PKEY_Pointer & pkey)
+static SSL_CTX * createSSLContext(Ssl::X509_Pointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port)
 {
-    Ssl::SSL_CTX_Pointer sslContext(SSL_CTX_new(SSLv23_server_method()));
+    Ssl::SSL_CTX_Pointer sslContext(SSL_CTX_new(port.contextMethod));
 
     if (!SSL_CTX_use_certificate(sslContext.get(), x509.get()))
         return NULL;
 
     if (!SSL_CTX_use_PrivateKey(sslContext.get(), pkey.get()))
         return NULL;
+
+    if (!configureSslContext(sslContext.get(), port))
+        return NULL;
+
     return sslContext.release();
 }
 
-SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data)
+SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port)
 {
     Ssl::X509_Pointer cert;
     Ssl::EVP_PKEY_Pointer pkey;
     if (!readCertAndPrivateKeyFromMemory(cert, pkey, data))
         return NULL;
 
     if (!cert || !pkey)
         return NULL;
 
-    return createSSLContext(cert, pkey);
+    return createSSLContext(cert, pkey, port);
 }
 
-SSL_CTX * Ssl::generateSslContext(CertificateProperties const &properties)
+SSL_CTX * Ssl::generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port)
 {
     Ssl::X509_Pointer cert;
     Ssl::EVP_PKEY_Pointer pkey;
     if (!generateSslCertificate(cert, pkey, properties))
         return NULL;
 
     if (!cert)
         return NULL;
 
     if (!pkey)
         return NULL;
 
-    return createSSLContext(cert, pkey);
+    return createSSLContext(cert, pkey, port);
 }
 
 bool Ssl::verifySslCertificate(SSL_CTX * sslContext, CertificateProperties const &properties)
 {
     // Temporary ssl for getting X509 certificate from SSL_CTX.
     Ssl::SSL_Pointer ssl(SSL_new(sslContext));
     X509 * cert = SSL_get_certificate(ssl.get());
     ASN1_TIME * time_notBefore = X509_get_notBefore(cert);
     ASN1_TIME * time_notAfter = X509_get_notAfter(cert);
     bool ret = (X509_cmp_current_time(time_notBefore) < 0 && X509_cmp_current_time(time_notAfter) > 0);
     if (!ret)
         return false;
 
     return certificateMatchesProperties(cert, properties);
 }
 
 bool
 Ssl::setClientSNI(SSL *ssl, const char *fqdn)
 {
     //The SSL_CTRL_SET_TLSEXT_HOSTNAME is a openssl macro which indicates
@@ -1370,79 +1657,85 @@
 }
 
 void Ssl::addChainToSslContext(SSL_CTX *sslContext, STACK_OF(X509) *chain)
 {
     if (!chain)
         return;
 
     for (int i = 0; i < sk_X509_num(chain); ++i) {
         X509 *cert = sk_X509_value(chain, i);
         if (SSL_CTX_add_extra_chain_cert(sslContext, cert)) {
             // increase the certificate lock
             CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
         } else {
             const int ssl_error = ERR_get_error();
             debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL));
         }
     }
 }
 
 /**
- \ingroup ServerProtocolSSLInternal
- * Read certificate from file.
- * See also: static readSslX509Certificate function, gadgets.cc file
- */
+   \ingroup ServerProtocolSSLInternal
+   * Read certificate from file.
+   * See also: static readSslX509Certificate function, gadgets.cc file
+   */
 static X509 * readSslX509CertificatesChain(char const * certFilename,  STACK_OF(X509)* chain)
 {
     if (!certFilename)
         return NULL;
     Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
     if (!bio)
         return NULL;
     if (!BIO_read_filename(bio.get(), certFilename))
         return NULL;
     X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
 
     if (certificate && chain) {
 
         if (X509_check_issued(certificate, certificate) == X509_V_OK)
             debugs(83, 5, "Certificate is self-signed, will not be chained");
         else {
             if (sk_X509_push(chain, certificate))
                 CRYPTO_add(&(certificate->references), 1, CRYPTO_LOCK_X509);
             else
                 debugs(83, DBG_IMPORTANT, "WARNING: unable to add signing certificate to cert chain");
             // and add to the chain any certificate loaded from the file
             while (X509 *ca = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL)) {
                 if (!sk_X509_push(chain, ca))
                     debugs(83, DBG_IMPORTANT, "WARNING: unable to add CA certificate to cert chain");
             }
         }
     }
 
     return certificate;
 }
 
 void Ssl::readCertChainAndPrivateKeyFromFiles(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, X509_STACK_Pointer & chain, char const * certFilename, char const * keyFilename)
 {
     if (keyFilename == NULL)
         keyFilename = certFilename;
+
+    if (certFilename == NULL)
+        certFilename = keyFilename;
+
+    debugs(83, DBG_IMPORTANT, "Using certificate in " << certFilename);
+
     if (!chain)
         chain.reset(sk_X509_new_null());
     if (!chain)
         debugs(83, DBG_IMPORTANT, "WARNING: unable to allocate memory for cert chain");
     pkey.reset(readSslPrivateKey(keyFilename, ssl_ask_password_cb));
     cert.reset(readSslX509CertificatesChain(certFilename, chain.get()));
     if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
         pkey.reset(NULL);
         cert.reset(NULL);
     }
 }
 
 bool Ssl::generateUntrustedCert(X509_Pointer &untrustedCert, EVP_PKEY_Pointer &untrustedPkey, X509_Pointer const  &cert, EVP_PKEY_Pointer const & pkey)
 {
     // Generate the self-signed certificate, using a hard-coded subject prefix
     Ssl::CertificateProperties certProperties;
     if (const char *cn = CommonHostName(cert.get())) {
         certProperties.commonName = "Not trusted by \"";
         certProperties.commonName += cn;
         certProperties.commonName += "\"";

=== modified file 'src/ssl/support.h'
--- src/ssl/support.h	2012-06-19 21:51:49 +0000
+++ src/ssl/support.h	2012-07-25 15:15:54 +0000
@@ -47,52 +47,58 @@
 #if HAVE_OPENSSL_ERR_H
 #include <openssl/err.h>
 #endif
 #if HAVE_OPENSSL_ENGINE_H
 #include <openssl/engine.h>
 #endif
 
 /**
  \defgroup ServerProtocolSSLAPI Server-Side SSL API
  \ingroup ServerProtocol
  */
 
 // Custom SSL errors; assumes all official errors are positive
 #define SQUID_X509_V_ERR_CERT_CHANGE -3
 #define SQUID_ERR_SSL_HANDSHAKE -2
 #define SQUID_X509_V_ERR_DOMAIN_MISMATCH -1
 // All SSL errors range: from smallest (negative) custom to largest SSL error
 #define SQUID_SSL_ERROR_MIN SQUID_X509_V_ERR_CERT_CHANGE
 #define SQUID_SSL_ERROR_MAX INT_MAX
 
+namespace AnyP{
+    class PortCfg;
+};
+
 namespace Ssl
 {
 /// Squid defined error code (<0),  an error code returned by SSL X509 api, or SSL_ERROR_NONE
 typedef int ssl_error_t;
 
 typedef CbDataList<Ssl::ssl_error_t> Errors;
 
 } //namespace Ssl
 
 /// \ingroup ServerProtocolSSLAPI
 SSL_CTX *sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath, const char *CRLfile, const char *dhpath, const char *context);
 
+SSL_CTX *sslCreateServerContext(AnyP::PortCfg &port);
+
 /// \ingroup ServerProtocolSSLAPI
 SSL_CTX *sslCreateClientContext(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);
 
 /// \ingroup ServerProtocolSSLAPI
 int ssl_read_method(int, char *, int);
 
 /// \ingroup ServerProtocolSSLAPI
 int ssl_write_method(int, const char *, int);
 
 /// \ingroup ServerProtocolSSLAPI
 void ssl_shutdown_method(SSL *ssl);
 
 
 /// \ingroup ServerProtocolSSLAPI
 const char *sslGetUserEmail(SSL *ssl);
 
 /// \ingroup ServerProtocolSSLAPI
 typedef char const *SSLGETATTRIBUTE(SSL *, const char *);
 
 /// \ingroup ServerProtocolSSLAPI
@@ -114,66 +120,96 @@
  * Supported ssl-bump modes
  */
 enum BumpMode {bumpNone = 0, bumpClientFirst, bumpServerFirst, bumpEnd};
 
 /**
  \ingroup  ServerProtocolSSLAPI
  * Short names for ssl-bump modes
  */
 extern const char *BumpModeStr[];
 
 /**
  \ingroup ServerProtocolSSLAPI
  * Return the short name of the ssl-bump mode "bm"
  */
 inline const char *bumpMode(int bm)
 {
     return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr[bm] : NULL;
 }
 
 /**
+ \ingroup ServerProtocolSSLAPI
+ * Parses the SSL flags.
+ */
+long parse_flags(const char *flags);
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Parses the SSL options.
+ */
+long parse_options(const char *options);
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Load a CRLs list stored in a file
+ */
+STACK_OF(X509_CRL) *loadCrl(const char *CRLFile, long &flags);
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Load DH params from file
+ */
+DH *readDHParams(const char *dhfile);
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Compute the Ssl::ContextMethod (SSL_METHOD) from SSL version
+ */
+ContextMethod contextMethod(int version);
+
+/**
   \ingroup ServerProtocolSSLAPI
   * Generate a certificate to be used as untrusted signing certificate, based on a trusted CA
 */
 bool generateUntrustedCert(X509_Pointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, X509_Pointer const & cert, EVP_PKEY_Pointer const & pkey);
 
 /**
   \ingroup ServerProtocolSSLAPI
   * Decide on the kind of certificate and generate a CA- or self-signed one
 */
-SSL_CTX * generateSslContext(CertificateProperties const &properties);
+SSL_CTX * generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port);
 
 /**
   \ingroup ServerProtocolSSLAPI
   * Check if the certificate of the given context is still valid
   \param sslContext The context to check
   \param properties Check if the context certificate matches the given properties
   \return true if the contexts certificate is valid, false otherwise
  */
 bool verifySslCertificate(SSL_CTX * sslContext,  CertificateProperties const &properties);
 
 /**
   \ingroup ServerProtocolSSLAPI
   * Read private key and certificate from memory and generate SSL context
   * using their.
  */
-SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data);
+SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port);
 
 /**
   \ingroup ServerProtocolSSLAPI
   * Adds the certificates in certList to the certificate chain of the SSL context
  */
 void addChainToSslContext(SSL_CTX *sslContext, STACK_OF(X509) *certList);
 
 /**
  \ingroup ServerProtocolSSLAPI
  *  Read certificate, private key and any certificates which must be chained from files.
  * See also: Ssl::readCertAndPrivateKeyFromFiles function,  defined in gadgets.h
  * \param certFilename name of file with certificate and certificates which must be chainned.
  * \param keyFilename name of file with private key.
  */
 void readCertChainAndPrivateKeyFromFiles(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, X509_STACK_Pointer & chain, char const * certFilename, char const * keyFilename);
 
 /**
    \ingroup ServerProtocolSSLAPI
    * Iterates over the X509 common and alternate names and to see if  matches with given data
    * using the check_func.

Reply via email to