[squid-dev] [PATCH] Initial libsecurity API

Amos Jeffries squid3 at treenet.co.nz
Wed Jan 14 15:50:34 UTC 2015


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This is the first step(s) towards a generic TLS/SSL security API for
Squid.

Creates the basic security/libsecurity.la library and Security::
namespace infrastructure. Symbols provided by this API are always
available instead of conditionally compiled (unlike the ssl/* code for
OpenSSL use).

Merge the TLS/SSL context parameters into a Security::PeerOptions
object instead of maintaining multiple member variables in the
CachePeer and SquidConfig objects.
 Squid now provides an error if SSL-specific squid.conf parameters
used for a Squid without OpenSSL support, instead of silently ignoring
them.

Added documentation of an existing bug where the security context for
DIRECT traffic is stored in SquidConfig and leaked on reconfigure.

Amos
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (MingW32)

iQEcBAEBAgAGBQJUtpBIAAoJELJo5wb/XPRjYOcH/0sAFLiWH16ax2zcSbK5Tdq2
bnMl+QzCPYPdx+OSR2ALu27qj3QS4V/TlCj0ASq+3QusJ+tj8f0NO0Se+5+QjIJX
vG1PBwGootGuKRwZUqlSJwAlHJzk0JRz8CZeHQ0FwB6Z2qXnKXIetnw/Smn1ndvW
xeh72eHJbRa/pptI8VmfTbrUpCcWUBnZocYP7nZkTtBL4lY7P0P9cSgFCy/KJtOx
fObOawS9WgGmWdY38eTD58CqBDdCR/pmj30UH+WkWuyWaOuhSlLwxjiRjkQlJtsj
9XZC0UWFJw2/+9tcr4TSk5br0KPwTMBblpk4bD47uAAxympSWuPYWiR6v171gb8=
=4THR
-----END PGP SIGNATURE-----
-------------- next part --------------
=== modified file 'configure.ac'
--- configure.ac	2015-01-13 07:25:36 +0000
+++ configure.ac	2015-01-14 15:09:13 +0000
@@ -3859,36 +3859,37 @@
 	src/base/Makefile
 	src/clients/Makefile
 	src/comm/Makefile
 	src/esi/Makefile
 	src/eui/Makefile
 	src/format/Makefile
 	src/fs/Makefile
 	src/ftp/Makefile
 	src/helper/Makefile
 	src/http/Makefile
 	src/http/one/Makefile
 	src/icmp/Makefile
 	src/ident/Makefile
 	src/ip/Makefile
 	src/ipc/Makefile
 	src/log/Makefile
 	src/mem/Makefile
 	src/mgr/Makefile
 	src/parser/Makefile
 	src/repl/Makefile
+	src/security/Makefile
 	src/servers/Makefile
 	src/snmp/Makefile
 	src/ssl/Makefile
 	test-suite/Makefile
 	tools/Makefile
 	tools/helper-mux/Makefile
 	tools/purge/Makefile
 	tools/squidclient/Makefile
 	tools/systemd/Makefile
 	tools/sysvinit/Makefile
 ])
 
 # must configure libltdl subdir unconditionally for "make distcheck" to work
 #AC_CONFIG_SUBDIRS(libltdl)
 
 AC_OUTPUT

=== modified file 'doc/release-notes/release-3.6.sgml'
--- doc/release-notes/release-3.6.sgml	2015-01-13 07:25:36 +0000
+++ doc/release-notes/release-3.6.sgml	2015-01-14 15:09:41 +0000
@@ -81,40 +81,44 @@
    <em>basic_smb_lm_auth</em> helper performs the same actions without extra
    Perl and Samba dependencies.
 
 
 <sect>Changes to squid.conf since Squid-3.5
 <p>
 There have been changes to Squid's configuration file since Squid-3.5.
 
 This section gives a thorough account of those changes in three categories:
 
 <itemize>
 	<item><ref id="newtags" name="New tags">
 	<item><ref id="modifiedtags" name="Changes to existing tags">
 	<item><ref id="removedtags" name="Removed tags">
 </itemize>
 <p>
 
 <sect1>New tags<label id="newtags">
 <p>
 <descrip>
+	<tag>tls_outgoing_options</tag>
+	<p>New tag to define TLS security context options for outgoing
+	   connections. For example to HTTPS servers.
+
          <tag> url_rewrite_timeout </tag>
          <p> Squid times active requests to redirector. This option sets
              the timeout value and the Squid reaction to a timed out
              request. </p>
 </descrip>
 
 <sect1>Changes to existing tags<label id="modifiedtags">
 <p>
 <descrip>
 	<tag>auth_param</tag>
 	<p>New parameter <em>queue-size=</em> to set the maximum number
 	   of queued requests.
 
 	<tag>cache_peer</tag>
 	<p>All <em>ssloption=</em> and <em>sslversion=</em> values for
 	   SSLv2 configuration or disabling have been removed.
 	<p>Manual squid.conf update may be required on upgrade.
 
 	<tag>external_acl_type<tag>
 	<p>New parameter <em>queue-size=</em> to set the maximum number
@@ -137,40 +141,63 @@
 	<tag>sslcrtvalidator_children</tag>
 	<p>New parameter <em>queue-size=</em> to set the maximum number
 	   of queued requests.
 
 	<tag>sslproxy_options</tag>
 	<p>All values for SSLv2 configuration or disabling have been removed.
 	<p>Manual squid.conf update may be required on upgrade.
 
 	<tag>sslproxy_version</tag>
 	<p>Value '2' for SSLv2-only operation is no longer supported.
 
 	<tag>url_rewrite_children<tag>
 	<p>New parameter <em>queue-size=</em> to set the maximum number
 	   of queued requests.
 
 </descrip>
 
 <sect1>Removed tags<label id="removedtags">
 <p>
 <descrip>
+	<tag>sslproxy_cafile</tag>
+	<p>Replaced by <em>tls_outgoing_options cafile=</em>.
+
+	<tag>sslproxy_capath</tag>
+	<p>Replaced by <em>tls_outgoing_options capath=</em>.
+
+	<tag>sslproxy_cipher</tag>
+	<p>Replaced by <em>tls_outgoing_options cipher=</em>.
+
+	<tag>sslproxy_client_certificate</tag>
+	<p>Replaced by <em>tls_outgoing_options cert=</em>.
+
+	<tag>sslproxy_client_key</tag>
+	<p>Replaced by <em>tls_outgoing_options key=</em>.
+
+	<tag>sslproxy_flags</tag>
+	<p>Replaced by <em>tls_outgoing_options flags=</em>.
+
+	<tag>sslproxy_options</tag>
+	<p>Replaced by <em>tls_outgoing_options options=</em>.
+
+	<tag>sslproxy_version</tag>
+	<p>Replaced by <em>tls_outgoing_options version=</em>.
 
 </descrip>
 
 
 <sect>Changes to ./configure options since Squid-3.5
 <p>
 There have been some changes to Squid's build configuration since Squid-3.5.
 
 This section gives an account of those changes in three categories:
 
 <itemize>
 	<item><ref id="newoptions" name="New options">
 	<item><ref id="modifiedoptions" name="Changes to existing options">
 	<item><ref id="removedoptions" name="Removed options">
 </itemize>
 
 
 <sect1>New options<label id="newoptions">
 <p>
 <descrip>

=== modified file 'src/CachePeer.h'
--- src/CachePeer.h	2015-01-13 07:25:36 +0000
+++ src/CachePeer.h	2015-01-14 15:43:27 +0000
@@ -1,36 +1,37 @@
 /*
  * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #ifndef SQUID_CACHEPEER_H_
 #define SQUID_CACHEPEER_H_
 
 #include "acl/forward.h"
 #include "base/CbcPointer.h"
 #include "enums.h"
 #include "icp_opcode.h"
 #include "ip/Address.h"
+#include "security/PeerOptions.h"
 
 //TODO: remove, it is unconditionally defined and always used.
 #define PEER_MULTICAST_SIBLINGS 1
 
 #if HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
 #endif
 
 class CachePeerDomainList;
 class NeighborTypeDomainList;
 class PconnPool;
 class PeerDigest;
 class PeerPoolMgr;
 
 // currently a POD
 class CachePeer
 {
 public:
     u_int index;
     char *name;
@@ -159,43 +160,35 @@
         double load_factor; /* normalized weight value */
     } userhash;
 #endif
     struct {
         unsigned int hash;
         double load_multiplier;
         double load_factor; /* normalized weight value */
     } sourcehash;
 
     char *login;        /* Proxy authorization */
     time_t connect_timeout;
     int connect_fail_limit;
     int max_conn;
     struct {
         PconnPool *pool; ///< idle connection pool for this peer
         CbcPointer<PeerPoolMgr> mgr; ///< pool manager
         int limit; ///< the limit itself
         bool waitingForClose; ///< a conn must close before we open a standby conn
     } standby; ///< optional "cache_peer standby=limit" feature
     char *domain;       /* Forced domain */
-#if USE_OPENSSL
 
-    int use_ssl;
-    char *sslcert;
-    char *sslkey;
-    int sslversion;
-    char *ssloptions;
-    char *sslcipher;
-    char *sslcafile;
-    char *sslcapath;
-    char *sslcrlfile;
-    char *sslflags;
-    char *ssldomain;
+    /// security settings for peer connection
+    Security::PeerOptions secure;
+
+#if USE_OPENSSL
     SSL_CTX *sslContext;
     SSL_SESSION *sslSession;
 #endif
 
     int front_end_https;
     int connection_auth;
 };
 
 #endif /* SQUID_CACHEPEER_H_ */
 

=== modified file 'src/FwdState.cc'
--- src/FwdState.cc	2015-01-13 07:25:36 +0000
+++ src/FwdState.cc	2015-01-14 15:05:47 +0000
@@ -666,41 +666,41 @@
                 peerConnectFailed(conn->getPeer());
 
             conn->close();
         }
         retryOrBail();
         return;
     }
 
     serverConn = conn;
     flags.connected_okay = true;
 
     debugs(17, 3, HERE << serverConnection() << ": '" << entry->url() << "'" );
 
     comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
 
     if (serverConnection()->getPeer())
         peerConnectSucceded(serverConnection()->getPeer());
 
 #if USE_OPENSSL
     if (!request->flags.pinned) {
-        if ((serverConnection()->getPeer() && serverConnection()->getPeer()->use_ssl) ||
+        if ((serverConnection()->getPeer() && serverConnection()->getPeer()->secure.ssl) ||
                 (!serverConnection()->getPeer() && request->url.getScheme() == AnyP::PROTO_HTTPS) ||
                 request->flags.sslPeek) {
 
             HttpRequest::Pointer requestPointer = request;
             AsyncCall::Pointer callback = asyncCall(17,4,
                                                     "FwdState::ConnectedToPeer",
                                                     FwdStatePeerAnswerDialer(&FwdState::connectedToPeer, this));
             // Use positive timeout when less than one second is left.
             const time_t sslNegotiationTimeout = max(static_cast<time_t>(1), timeLeft());
             Ssl::PeerConnector *connector =
                 new Ssl::PeerConnector(requestPointer, serverConnection(), clientConn, callback, sslNegotiationTimeout);
             AsyncJob::Start(connector); // will call our callback
             return;
         }
     }
 #endif
 
     // should reach ConnStateData before the dispatched Client job starts
     CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
                  ConnStateData::notePeerConnection, serverConnection());

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2015-01-13 07:25:36 +0000
+++ src/Makefile.am	2015-01-14 15:10:20 +0000
@@ -41,50 +41,49 @@
 	StoreMetaVary.cc \
 	StoreMetaVary.h
 
 LOADABLE_MODULES_SOURCES = \
 	LoadableModule.h \
 	LoadableModule.cc \
 	LoadableModules.h \
 	LoadableModules.cc
 
 SUBDIRS	= mem base anyp helper ftp parser comm eui acl format clients servers fs repl
 DIST_SUBDIRS = mem base anyp helper ftp parser comm eui acl format clients servers fs repl
 
 if ENABLE_AUTH
 SUBDIRS += auth
 AUTH_LIBS= auth/libauth.la
 AUTH_ACL_LIBS= auth/libacls.la
 check_PROGRAMS+= tests/testACLMaxUserIP
 endif
 DIST_SUBDIRS += auth
 
-SUBDIRS	+= http ip icmp ident log ipc mgr
-DIST_SUBDIRS += http ip icmp ident log ipc mgr
+SUBDIRS	+= http ip icmp ident log ipc mgr security
+DIST_SUBDIRS += http ip icmp ident log ipc mgr security
 
+SSL_LIBS=
 if ENABLE_SSL
 SUBDIRS += ssl
-SSL_LIBS = \
+SSL_LIBS += \
 	ssl/libsslsquid.la \
 	ssl/libsslutil.la
-else
-SSL_LOCAL_LIBS =
 endif
 DIST_SUBDIRS += ssl
 
 SNMP_ALL_SOURCE = \
 	SnmpRequest.h \
 	snmp_core.h \
 	snmp_core.cc \
 	snmp_agent.h \
 	snmp_agent.cc
 if ENABLE_SNMP
 SNMP_SOURCE = $(SNMP_ALL_SOURCE)
 SUBDIRS += snmp
 SNMP_LIBS = snmp/libsnmp.la $(SNMPLIB)
 else
 SNMP_SOURCE = 
 endif
 DIST_SUBDIRS += snmp
 
 if USE_ADAPTATION
 SUBDIRS += adaptation
@@ -597,40 +596,41 @@
 CLEANFILES += $(BUILT_SOURCES)
 
 nodist_squid_SOURCES = \
 	$(DISKIO_GEN_SOURCE) \
 	$(BUILT_SOURCES)
 
 squid_LDADD = \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \
 	acl/libacls.la \
 	acl/libstate.la \
 	$(AUTH_LIBS) \
 	$(DISK_LIBS) \
 	acl/libapi.la \
 	clients/libclients.la \
 	servers/libservers.la \
 	ftp/libftp.la \
 	helper/libhelper.la \
 	http/libsquid-http.la \
 	parser/libsquid-parser.la \
+	security/libsecurity.la \
 	base/libbase.la \
 	libsquid.la \
 	ip/libip.la \
 	fs/libfs.la \
 	$(SSL_LIBS) \
 	ipc/libipc.la \
 	mgr/libmgr.la \
 	anyp/libanyp.la \
 	comm/libcomm.la \
 	eui/libeui.la \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	log/liblog.la \
 	format/libformat.la \
 	$(XTRA_OBJS) \
 	$(DISK_LINKOBJS) \
 	$(REPL_OBJS) \
 	$(DISK_OS_LIBS) \
 	$(NETTLELIB) \
 	$(CRYPTLIB) \
 	$(REGEXLIB) \
@@ -1460,40 +1460,41 @@
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
+	tests/stub_libsecurity.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	multicast.h \
 	multicast.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
 	mime_header.cc \
 	neighbors.h \
 	neighbors.cc \
 	Notes.cc \
 	Notes.h \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
@@ -1880,40 +1881,41 @@
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	PeerPoolMgr.h \
 	PeerPoolMgr.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
+	tests/stub_libsecurity.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	tests/stub_libmem.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
 	mime_header.cc \
 	multicast.h \
 	multicast.cc \
 	neighbors.h \
 	neighbors.cc \
 	Notes.cc \
 	Notes.h \
 	Packer.cc \
 	Parsing.cc \
@@ -2123,40 +2125,41 @@
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	PeerPoolMgr.h \
 	PeerPoolMgr.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
+	tests/stub_libsecurity.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	MemBuf.cc \
 	MemObject.cc \
 	tests/stub_libmem.cc \
 	mem_node.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
 	mime_header.cc \
 	multicast.h \
 	multicast.cc \
 	neighbors.h \
 	neighbors.cc \
 	Notes.cc \
 	Notes.h \
 	Packer.cc \
 	Parsing.cc \
@@ -2361,40 +2364,41 @@
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	PeerPoolMgr.h \
 	PeerPoolMgr.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
+	tests/stub_libsecurity.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	MemBuf.cc \
 	MemObject.cc \
 	tests/stub_libmem.cc \
 	mem_node.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
 	mime_header.cc \
 	multicast.h \
 	multicast.cc \
 	neighbors.h \
 	neighbors.cc \
 	Notes.cc \
 	Notes.h \
 	Packer.cc \
 	Parsing.cc \
@@ -2654,40 +2658,41 @@
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
+	tests/stub_libsecurity.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	multicast.h \
 	multicast.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
 	mime_header.cc \
 	neighbors.h \
 	neighbors.cc \
 	Notes.cc \
 	Notes.h \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
@@ -3470,40 +3475,41 @@
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	PeerPoolMgr.h \
 	PeerPoolMgr.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
+	tests/stub_libsecurity.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	multicast.h \
 	multicast.cc \
 	tests/stub_libmem.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
 	mime_header.cc \
 	neighbors.h \
 	neighbors.cc \
 	Notes.h \
 	Notes.cc \
 	Packer.cc \
 	Parsing.cc \

=== modified file 'src/PeerPoolMgr.cc'
--- src/PeerPoolMgr.cc	2015-01-13 07:25:36 +0000
+++ src/PeerPoolMgr.cc	2015-01-14 15:05:47 +0000
@@ -96,41 +96,41 @@
     if (!validPeer()) {
         debugs(48, 3, "peer gone");
         if (params.conn != NULL)
             params.conn->close();
         return;
     }
 
     if (params.flag != Comm::OK) {
         /* it might have been a timeout with a partially open link */
         if (params.conn != NULL)
             params.conn->close();
         peerConnectFailed(peer);
         checkpoint("conn opening failure"); // may retry
         return;
     }
 
     Must(params.conn != NULL);
 
 #if USE_OPENSSL
     // Handle SSL peers.
-    if (peer->use_ssl) {
+    if (peer->secure.ssl) {
         typedef CommCbMemFunT<PeerPoolMgr, CommCloseCbParams> CloserDialer;
         closer = JobCallback(48, 3, CloserDialer, this,
                              PeerPoolMgr::handleSecureClosure);
         comm_add_close_handler(params.conn->fd, closer);
 
         securer = asyncCall(48, 4, "PeerPoolMgr::handleSecuredPeer",
                             MyAnswerDialer(this, &PeerPoolMgr::handleSecuredPeer));
 
         const int peerTimeout = peer->connect_timeout > 0 ?
                                 peer->connect_timeout : Config.Timeout.peer_connect;
         const int timeUsed = squid_curtime - params.conn->startTime();
         // Use positive timeout when less than one second is left for conn.
         const int timeLeft = max(1, (peerTimeout - timeUsed));
         Ssl::PeerConnector *connector =
             new Ssl::PeerConnector(request, params.conn, NULL, securer, timeLeft);
         AsyncJob::Start(connector); // will call our callback
         return;
     }
 #endif
 

=== modified file 'src/SquidConfig.h'
--- src/SquidConfig.h	2015-01-13 07:25:36 +0000
+++ src/SquidConfig.h	2015-01-14 15:05:47 +0000
@@ -480,51 +480,41 @@
         char *ssl_engine;
         int session_ttl;
         size_t sessionCacheSize;
         char *certSignHash;
     } SSL;
 #endif
 
     wordlist *ext_methods;
 
     struct {
         int high_rptm;
         int high_pf;
         size_t high_memory;
     } warnings;
     char *store_dir_select_algorithm;
     int sleep_after_fork;   /* microseconds */
     time_t minimum_expiry_time; /* seconds */
     external_acl *externalAclHelperList;
 
 #if USE_OPENSSL
-
     struct {
-        char *cert;
-        char *key;
-        int version;
-        char *options;
-        char *cipher;
-        char *cafile;
-        char *capath;
-        char *crlfile;
-        char *flags;
         acl_access *cert_error;
         SSL_CTX *sslContext;
         sslproxy_cert_sign *cert_sign;
         sslproxy_cert_adapt *cert_adapt;
     } ssl_client;
 #endif
 
     char *accept_filter;
     int umask;
     int max_filedescriptors;
     int workers;
     CpuAffinityMap *cpuAffinityMap;
 
 #if USE_LOADABLE_MODULES
     wordlist *loadable_module_names;
 #endif
 
     int client_ip_max_connections;
 
     char *redirector_extras;

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2015-01-13 07:25:36 +0000
+++ src/cache_cf.cc	2015-01-14 15:05:47 +0000
@@ -868,46 +868,48 @@
         Config2.effectiveGroupID = getegid();
     }
 
     if (NULL != Config.effectiveGroup) {
 
         struct group *grp = getgrnam(Config.effectiveGroup);
 
         if (NULL == grp) {
             fatalf("getgrnam failed to find groupid for effective group '%s'",
                    Config.effectiveGroup);
             return;
         }
 
         Config2.effectiveGroupID = grp->gr_gid;
     }
 
 #if USE_OPENSSL
 
     debugs(3, DBG_IMPORTANT, "Initializing https proxy context");
 
-    Config.ssl_client.sslContext = sslCreateClientContext(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);
+    // BUG: ssl_client.sslContext will leak on reconfigure when Config gets memset()
+    // it makes more sense to create a context per outbound connection instead of this
+    Config.ssl_client.sslContext = Security::ProxyOutgoingConfig.createContext();
 
     for (CachePeer *p = Config.peers; p != NULL; p = p->next) {
-        if (p->use_ssl) {
+        if (p->secure.ssl) {
             debugs(3, DBG_IMPORTANT, "Initializing cache_peer " << p->name << " SSL context");
-            p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath, p->sslcrlfile);
+            p->sslContext = p->secure.createContext();
         }
     }
 
     for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
         if (!s->flags.tunnelSslBumping)
             continue;
 
         debugs(3, DBG_IMPORTANT, "Initializing http_port " << s->s << " SSL context");
         s->configureSslServerContext();
     }
 
     for (AnyP::PortCfgPointer s = HttpsPortList; s != NULL; s = s->next) {
         debugs(3, DBG_IMPORTANT, "Initializing https_port " << s->s << " SSL context");
         s->configureSslServerContext();
     }
 
 #endif
 
     // prevent infinite fetch loops in the request parser
     // due to buffer full but not enough data recived to finish parse
@@ -959,40 +961,70 @@
     if (!strcmp(name, "url_rewrite_concurrency")) {
         int cval;
         parse_int(&cval);
         debugs(3, DBG_CRITICAL, "WARNING: url_rewrite_concurrency upgrade overriding url_rewrite_children settings.");
         Config.redirectChildren.concurrency = cval;
     }
 
     if (!strcmp(name, "log_access"))
         self_destruct();
 
     if (!strcmp(name, "log_icap"))
         self_destruct();
 
     if (!strcmp(name, "ignore_ims_on_miss")) {
         // the replacement directive cache_revalidate_on_miss has opposite meanings for ON/OFF value
         // than the 2.7 directive. We need to parse and invert the configured value.
         int temp = 0;
         parse_onoff(&temp);
         Config.onoff.cache_miss_revalidate = !temp;
     }
+
+    if (!strncmp(name, "sslproxy_", 9)) {
+        // the replacement directive tls_outgoing_options uses options instead of whole-line input
+        SBuf tmp;
+        if (!strcmp(name, "sslproxy_cafile"))
+            tmp.append("cafile=");
+        else if (!strcmp(name, "sslproxy_capath"))
+            tmp.append("capath=");
+        else if (!strcmp(name, "sslproxy_cipher"))
+            tmp.append("cipher=");
+        else if (!strcmp(name, "sslproxy_client_certificate"))
+            tmp.append("cert=");
+        else if (!strcmp(name, "sslproxy_client_key"))
+            tmp.append("key=");
+        else if (!strcmp(name, "sslproxy_flags"))
+            tmp.append("flags=");
+        else if (!strcmp(name, "sslproxy_options"))
+            tmp.append("options=");
+        else if (!strcmp(name, "sslproxy_version"))
+            tmp.append("version=");
+        else {
+            debugs(3, DBG_CRITICAL, "ERROR: unknown directive: " << name);
+            self_destruct();
+        }
+
+        // add the value as unquoted-string because the old values did not support whitespace
+        const char *token = ConfigParser::NextQuotedOrToEol();
+        tmp.append(token, strlen(token));
+        Security::ProxyOutgoingConfig.parse(tmp.c_str());
+    }
 }
 
 /* Parse a time specification from the config file.  Store the
  * result in 'tptr', after converting it to 'units' */
 static void
 parseTimeLine(time_msec_t * tptr, const char *units,  bool allowMsec,  bool expectMoreArguments = false)
 {
     char *token;
     double d;
     time_msec_t m;
     time_msec_t u;
 
     if ((u = parseTimeUnits(units, allowMsec)) == 0)
         self_destruct();
 
     if ((token = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
     d = xatof(token);
 
@@ -2232,77 +2264,49 @@
 #if USE_CACHE_DIGESTS
         } else if (!strncmp(token, "digest-url=", 11)) {
             p->digest_url = xstrdup(token + 11);
 #endif
 
         } else if (!strcmp(token, "allow-miss")) {
             p->options.allow_miss = true;
         } else if (!strncmp(token, "max-conn=", 9)) {
             p->max_conn = xatoi(token + 9);
         } else if (!strncmp(token, "standby=", 8)) {
             p->standby.limit = xatoi(token + 8);
         } else if (!strcmp(token, "originserver")) {
             p->options.originserver = true;
         } else if (!strncmp(token, "name=", 5)) {
             safe_free(p->name);
 
             if (token[5])
                 p->name = xstrdup(token + 5);
         } else if (!strncmp(token, "forceddomain=", 13)) {
             safe_free(p->domain);
-
             if (token[13])
                 p->domain = xstrdup(token + 13);
 
-#if USE_OPENSSL
-
-        } 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 = xatoi(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->sslcrlfile = xstrdup(token + 11);
-        } 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", 3) == 0) {
+#if !USE_OPENSSL
+            debugs(0, DBG_CRITICAL, "WARNING: cache_peer option '" << token << "' requires --with-openssl");
+#else
+            p->secure.ssl = true;
+            p->secure.parse(token+3);
 #endif
 
         } else if (strcmp(token, "front-end-https") == 0) {
             p->front_end_https = 1;
         } else if (strcmp(token, "front-end-https=on") == 0) {
             p->front_end_https = 1;
         } else if (strcmp(token, "front-end-https=auto") == 0) {
             p->front_end_https = 2;
         } else if (strcmp(token, "connection-auth=off") == 0) {
             p->connection_auth = 0;
         } else if (strcmp(token, "connection-auth") == 0) {
             p->connection_auth = 1;
         } else if (strcmp(token, "connection-auth=on") == 0) {
             p->connection_auth = 1;
         } else if (strcmp(token, "connection-auth=auto") == 0) {
             p->connection_auth = 2;
         } else if (token[0] == '#') {
             // start of a text comment. stop reading this line.
             break;
         } else {

=== modified file 'src/cf.data.depend'
--- src/cf.data.depend	2015-01-13 07:25:36 +0000
+++ src/cf.data.depend	2015-01-14 15:05:47 +0000
@@ -49,40 +49,41 @@
 icap_service_type
 icap_service_failure_limit
 ecap_service_type
 int
 kb_int64_t
 kb_size_t
 logformat
 YesNoNone
 memcachemode
 note			acl
 obsolete
 onoff
 peer
 peer_access		cache_peer acl
 pipelinePrefetch
 PortCfg
 QosConfig
 TokenOrQuotedString
 refreshpattern
 removalpolicy
+securePeerOptions
 size_t
 IpAddress_list
 string
 string
 time_msec
 time_t
 tristate
 uri_whitespace
 UrlHelperTimeout	acl
 u_short
 wccp2_method
 wccp2_amethod
 wccp2_service
 wccp2_service_info
 wordlist
 sslproxy_ssl_bump	acl
 sslproxy_ssl_bump_peeked acl
 sslproxy_cert_sign	acl
 sslproxy_cert_adapt	acl
 ftp_epsv                acl

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2015-01-13 07:25:36 +0000
+++ src/cf.data.pre	2015-01-14 15:10:52 +0000
@@ -131,40 +131,89 @@
 DOC_END
 
 NAME: external_refresh_check
 TYPE: obsolete
 DOC_START
 	This option is not yet supported by Squid-3.
 DOC_END
 
 NAME: location_rewrite_program location_rewrite_access location_rewrite_children location_rewrite_concurrency
 TYPE: obsolete
 DOC_START
 	This option is not yet supported by Squid-3.
 DOC_END
 
 NAME: refresh_stale_hit
 TYPE: obsolete
 DOC_START
 	This option is not yet supported by Squid-3.
 DOC_END
 
+# Options removed in 3.6
+NAME: sslproxy_cafile
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options cafile= instead.
+DOC_END
+
+NAME: sslproxy_capath
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options capath= instead.
+DOC_END
+
+NAME: sslproxy_cipher
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options cipher= instead.
+DOC_END
+
+NAME: sslproxy_client_certificate
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options cert= instead.
+DOC_END
+
+NAME: sslproxy_client_key
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options key= instead.
+DOC_END
+
+NAME: sslproxy_flags
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options flags= instead.
+DOC_END
+
+NAME: sslproxy_options
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options options= instead.
+DOC_END
+
+NAME: sslproxy_version
+TYPE: obsolete
+DOC_START
+	Remove this line. Use tls_outgoing_options version= instead.
+DOC_END
+
 # Options removed in 3.5
 NAME: hierarchy_stoplist
 TYPE: obsolete
 DOC_START
 	Remove this line. Use always_direct or cache_peer_access ACLs instead if you need to prevent cache_peer use.
 DOC_END
 
 NAME: log_access
 TYPE: obsolete
 DOC_START
 	Remove this line. Use acls with access_log directives to control access logging
 DOC_END
 
 NAME: log_icap
 TYPE: obsolete
 DOC_START
 	Remove this line. Use acls with icap_log directives to control icap logging
 DOC_END
 
 # Options Removed in 3.3
@@ -2349,160 +2398,139 @@
 	directly to the original client destination IP or seek a faster
 	source using the HTTP Host header.
 	
 	Using Host to locate alternative servers can provide faster
 	connectivity with a range of failure recovery options.
 	But can also lead to connectivity trouble when the client and
 	server are attempting stateful interactions unaware of the proxy.
 	
 	This option (on by default) prevents alternative DNS entries being
 	located to send intercepted traffic DIRECT to an origin server.
 	The clients original destination IP and port will be used instead.
 	
 	Regardless of this option setting, when dealing with intercepted
 	traffic Squid will verify the Host: header and any traffic which
 	fails Host verification will be treated as if this option were ON.
 	
 	see host_verify_strict for details on the verification process.
 DOC_END
 
 COMMENT_START
+ TLS OPTIONS
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: tls_outgoing_options
+IFDEF: USE_GNUTLS||USE_OPENSSL
+TYPE: securePeerOptions
+DEFAULT: disable
+LOC: Security::ProxyOutgoingConfig
+DOC_START
+	disable		Do not support https:// URLs.
+	
+	cert=/path/to/client/certificate
+			A client TLS certificate to use when connecting.
+	
+	key=/path/to/client/private_key
+			The private TLS key corresponding to the cert= above.
+			If key= is not specified cert= is assumed to reference
+			a PEM file containing both the certificate and the key.
+	
+	version=1|3|4|5|6
+			The TLS/SSL version to use when connecting
+				1 = automatic (default)
+				3 = SSL v3 only
+				4 = TLS v1.0 only
+				5 = TLS v1.1 only
+				6 = TLS v1.2 only
+	
+	cipher=...	The list of valid TLS ciphers to use.
+	
+	options=... 	Specify various TLS/SSL implementation options:
+
+			    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 TLS/SSL
+				      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 peer certificate.
+	
+	capath=...	A directory containing additional CA certificates to
+			use when verifying the peer certificate.
+	
+	crlfile=... 	A certificate revocation list file to use when
+			verifying the peer certificate.
+	
+	flags=...	Specify various flags modifying the TLS implementation:
+	
+			DONT_VERIFY_PEER
+				Accept 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 peer certificate
+				matches the server name
+	
+	domain= 	The peer name as advertised in its certificate.
+			Used for verifying the correctness of the received peer
+			certificate. If not specified the peer hostname will be
+			used.
+DOC_END
+
+COMMENT_START
  SSL OPTIONS
  -----------------------------------------------------------------------------
 COMMENT_END
 
 NAME: ssl_unclean_shutdown
 IFDEF: USE_OPENSSL
 TYPE: onoff
 DEFAULT: off
 LOC: Config.SSL.unclean_shutdown
 DOC_START
 	Some browsers (especially MSIE) bugs out on SSL shutdown
 	messages.
 DOC_END
 
 NAME: ssl_engine
 IFDEF: USE_OPENSSL
 TYPE: string
 LOC: Config.SSL.ssl_engine
 DEFAULT: none
 DOC_START
 	The OpenSSL engine to use. You will need to set this if you
 	would like to use hardware SSL acceleration for example.
 DOC_END
 
-NAME: sslproxy_client_certificate
-IFDEF: USE_OPENSSL
-DEFAULT: none
-LOC: Config.ssl_client.cert
-TYPE: string
-DOC_START
-	Client SSL Certificate to use when proxying https:// URLs
-DOC_END
-
-NAME: sslproxy_client_key
-IFDEF: USE_OPENSSL
-DEFAULT: none
-LOC: Config.ssl_client.key
-TYPE: string
-DOC_START
-	Client SSL Key to use when proxying https:// URLs
-DOC_END
-
-NAME: sslproxy_version
-IFDEF: USE_OPENSSL
-DEFAULT: 1
-DEFAULT_DOC: automatic SSL/TLS version negotiation
-LOC: Config.ssl_client.version
-TYPE: int
-DOC_START
-	SSL version level to use when proxying https:// URLs
-
-	The versions of SSL/TLS supported:
-
-	    1	automatic (default)
-	    3	SSLv3 only
-	    4	TLSv1.0 only
-	    5	TLSv1.1 only
-	    6	TLSv1.2 only
-DOC_END
-
-NAME: sslproxy_options
-IFDEF: USE_OPENSSL
-DEFAULT: none
-LOC: Config.ssl_client.options
-TYPE: string
-DOC_START
-	SSL implementation options to use when proxying https:// URLs
-	
-	The most important being:
-
-	    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
-	    SSL_OP_NO_TICKET
-		      Disable use of RFC5077 session tickets. Some servers
-		      may have problems understanding the TLS extension due
-		      to ambiguous specification in RFC4507.
-	    ALL       Enable various bug workarounds suggested as "harmless"
-		      by OpenSSL. Be warned that this may reduce SSL/TLS
-		      strength to some attacks.
-	
-	See the OpenSSL SSL_CTX_set_options documentation for a
-	complete list of possible options.
-DOC_END
-
-NAME: sslproxy_cipher
-IFDEF: USE_OPENSSL
-DEFAULT: none
-LOC: Config.ssl_client.cipher
-TYPE: string
-DOC_START
-	SSL cipher list to use when proxying https:// URLs
-
-	Colon separated list of supported ciphers.
-DOC_END
-
-NAME: sslproxy_cafile
-IFDEF: USE_OPENSSL
-DEFAULT: none
-LOC: Config.ssl_client.cafile
-TYPE: string
-DOC_START
-	file containing CA certificates to use when verifying server
-	certificates while proxying https:// URLs
-DOC_END
-
-NAME: sslproxy_capath
-IFDEF: USE_OPENSSL
-DEFAULT: none
-LOC: Config.ssl_client.capath
-TYPE: string
-DOC_START
-	directory containing CA certificates to use when verifying
-	server certificates while proxying https:// URLs
-DOC_END
-
 NAME: sslproxy_session_ttl
 IFDEF: USE_OPENSSL
 DEFAULT: 300
 LOC: Config.SSL.session_ttl
 TYPE: int
 DOC_START
 	Sets the timeout value for SSL sessions
 DOC_END
 
 NAME: sslproxy_session_cache_size
 IFDEF: USE_OPENSSL
 DEFAULT: 2 MB
 LOC: Config.SSL.sessionCacheSize
 TYPE: b_size_t
 DOC_START
         Sets the cache size to use for ssl session
 DOC_END
 
 NAME: sslproxy_cert_sign_hash
 IFDEF: USE_OPENSSL
@@ -2590,53 +2618,40 @@
 	steps.  Rules with actions that are impossible at the current step are
 	ignored. The first matching ssl_bump action wins and is applied at the
 	end of the current step. If no rules match, the splice action is used.
 	See the at_step ACL for a list of the supported SslBump steps.
 
 	This clause supports both fast and slow acl types.
 	See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
 
 	See also: http_port ssl-bump, https_port ssl-bump, and acl at_step.
 
 
 	# Example: Bump all requests except those originating from
 	# localhost or those going to example.com.
 
 	acl broken_sites dstdomain .example.com
 	ssl_bump splice localhost
 	ssl_bump splice broken_sites
 	ssl_bump bump all
 DOC_END
 
-NAME: sslproxy_flags
-IFDEF: USE_OPENSSL
-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_OPENSSL
 DEFAULT: none
 DEFAULT_DOC: Server certificate errors terminate the transaction.
 LOC: Config.ssl_client.cert_error
 TYPE: acl_access
 DOC_START
 	Use this ACL to bypass server certificate validation errors.
 
 	For example, the following lines will bypass all validation errors
 	when talking to servers for example.com. All other
 	validation errors will result in ERR_SECURE_CONNECT_FAIL error.
 
 		acl BrokenButTrustedServers dstdomain example.com
 		sslproxy_cert_error allow BrokenButTrustedServers
 		sslproxy_cert_error deny all
 
 	This clause only supports fast acl types.
 	See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
 	Using slow acl types may result in server crashes

=== modified file 'src/cf_gen_defines'
--- src/cf_gen_defines	2015-01-13 07:25:36 +0000
+++ src/cf_gen_defines	2015-01-14 15:05:47 +0000
@@ -17,40 +17,41 @@
 	print " * Please see the COPYING and CONTRIBUTORS files for details."
 	print " */"
 	print ""
 	print "#include \"autoconf.h\""
 	print "static struct { const char *name; const char *enable; int defined;} defines[] = {"
 	define["_SQUID_WINDOWS_"]="MS Windows"
 	define["FOLLOW_X_FORWARDED_FOR"]="--enable-follow-x-forwarded-for"
 	define["FOLLOW_X_FORWARDED_FOR&&LINUX_NETFILTER"]="--enable-follow-x-forwarded-for and --enable-linux-netfilter"
 	define["FOLLOW_X_FORWARDED_FOR&&USE_ADAPTATION"]="--enable-follow-x-forwarded-for and (--enable-icap-client and/or --enable-ecap)"
 	define["FOLLOW_X_FORWARDED_FOR&&USE_DELAY_POOLS"]="--enable-follow-x-forwarded-for and --enable-delay-pools"
 	define["HAVE_MSTATS&&HAVE_GNUMALLOC_H"]="GNU Malloc with mstats()"
 	define["ICAP_CLIENT"]="--enable-icap-client"
 	define["SO_MARK&&USE_LIBCAP"]="Packet MARK (Linux)"
 	define["SQUID_SNMP"]="--enable-snmp"
 	define["USE_ADAPTATION"]="--enable-ecap or --enable-icap-client"
 	define["USE_AUTH"]="--enable-auth"
 	define["USE_CACHE_DIGESTS"]="--enable-cache-digests"
 	define["USE_DELAY_POOLS"]="--enable-delay-pools"
 	define["USE_ECAP"]="--enable-ecap"
 	define["USE_ERR_LOCALES"]="--enable-auto-locale"
+	define["USE_GNUTLS||USE_OPENSSL"]="--with-gnutls or --with-openssl"
 	define["USE_HTCP"]="--enable-htcp"
 	define["USE_HTTP_VIOLATIONS"]="--enable-http-violations"
 	define["USE_ICMP"]="--enable-icmp"
 	define["USE_IDENT"]="--enable-ident-lookups"
 	define["USE_LOADABLE_MODULES"]="--enable-loadable-modules"
 	define["USE_OPENSSL"]="--with-openssl"
 	define["USE_QOS_TOS"]="--enable-zph-qos"
 	define["USE_SQUID_ESI"]="--enable-esi"
 	define["USE_SQUID_EUI"]="--enable-eui"
 	define["USE_SSL_CRTD"]="--enable-ssl-crtd"
 	define["USE_UNLINKD"]="--enable-unlinkd"
 	define["USE_WCCP"]="--enable-wccp"
 	define["USE_WCCPv2"]="--enable-wccpv2"
 }
 /^IFDEF:/ {
 	if (define[$2] != "")
 	    DEFINE=define[$2]
 	else
 	    DEFINE="-D" $2 " define"
 	print "{\"" $2 "\", \"" DEFINE "\", "

=== added directory 'src/security'
=== added file 'src/security/Context.h'
--- src/security/Context.h	1970-01-01 00:00:00 +0000
+++ src/security/Context.h	2015-01-14 15:04:28 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_SECURITY_CONTEXT_H
+#define SQUID_SRC_SECURITY_CONTEXT_H
+
+#if USE_OPENSSL
+#include "ssl/gadgets.h"
+#endif
+
+namespace Security {
+
+#if USE_OPENSSL
+// XXX: make this a SSL_CTX_Pointer
+typedef SSL_CTX* ContextPointer;
+
+#else
+// use void* so we can check against NULL
+typedef void* ContextPointer;
+#endif
+
+} // namespace Security
+
+#endif /* SQUID_SRC_SECURITY_CONTEXT_H */

=== added file 'src/security/Makefile.am'
--- src/security/Makefile.am	1970-01-01 00:00:00 +0000
+++ src/security/Makefile.am	2015-01-14 15:04:28 +0000
@@ -0,0 +1,16 @@
+## Copyright (C) 1996-2014 The Squid Software Foundation and contributors
+##
+## Squid software is distributed under GPLv2+ license and includes
+## contributions from numerous individuals and organizations.
+## Please see the COPYING and CONTRIBUTORS files for details.
+##
+
+include $(top_srcdir)/src/Common.am
+include $(top_srcdir)/src/TestHeaders.am
+
+noinst_LTLIBRARIES = libsecurity.la
+
+libsecurity_la_SOURCES= \
+	Context.h \
+	PeerOptions.cc \
+	PeerOptions.h

=== added file 'src/security/PeerOptions.cc'
--- src/security/PeerOptions.cc	1970-01-01 00:00:00 +0000
+++ src/security/PeerOptions.cc	2015-01-14 15:04:28 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "Debug.h"
+#include "globals.h"
+#include "Parsing.h"
+#include "security/PeerOptions.h"
+
+#if USE_OPENSSL
+#include "ssl/support.h"
+#endif
+
+Security::PeerOptions Security::ProxyOutgoingConfig;
+
+void
+Security::PeerOptions::parse(const char *token)
+{
+    if (strncmp(token, "cert=", 5) == 0) {
+        certFile = SBuf(token + 5);
+    } else if (strncmp(token, "key=", 4) == 0) {
+        privateKeyFile = SBuf(token + 4);
+        if (certFile.isEmpty()) {
+            debugs(0, DBG_PARSE_NOTE(1), "WARNING: cert= option needs to be set before key= is used.");
+            certFile = privateKeyFile;
+        }
+    } else if (strncmp(token, "version=", 8) == 0) {
+        sslVersion = xatoi(token + 8);
+    } else if (strncmp(token, "options=", 8) == 0) {
+        sslOptions = SBuf(token + 8);
+    } else if (strncmp(token, "cipher=", 7) == 0) {
+        sslCipher = SBuf(token + 7);
+    } else if (strncmp(token, "cafile=", 7) == 0) {
+        caFile = SBuf(token + 7);
+    } else if (strncmp(token, "capath=", 7) == 0) {
+        caDir = SBuf(token + 7);
+    } else if (strncmp(token, "crlfile=", 8) == 0) {
+        crlFile = SBuf(token + 8);
+    } else if (strncmp(token, "flags=", 6) == 0) {
+        sslFlags = SBuf(token + 6);
+    } else if (strncmp(token, "domain=", 7) == 0) {
+        sslDomain = SBuf(token + 7);
+    }
+}
+
+// XXX: make a GnuTLS variant
+Security::ContextPointer
+Security::PeerOptions::createContext()
+{
+    Security::ContextPointer t = NULL;
+
+    if (privateKeyFile.isEmpty())
+        privateKeyFile = certFile;
+
+#if USE_OPENSSL
+    t = sslCreateClientContext(certFile.c_str(), privateKeyFile.c_str(), sslVersion, sslCipher.c_str(),
+                           sslOptions.c_str(), sslFlags.c_str(), caFile.c_str(), caDir.c_str(), crlFile.c_str());
+#endif
+    return t;
+}

=== added file 'src/security/PeerOptions.h'
--- src/security/PeerOptions.h	1970-01-01 00:00:00 +0000
+++ src/security/PeerOptions.h	2015-01-14 15:04:28 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_SECURITY_PEEROPTIONS_H
+#define SQUID_SRC_SECURITY_PEEROPTIONS_H
+
+#include "ConfigParser.h"
+#include "SBuf.h"
+#include "security/Context.h"
+
+namespace Security
+{
+
+class PeerOptions
+{
+public:
+    PeerOptions() : ssl(false), sslVersion(0) {}
+
+    /// parse a TLS squid.conf option
+    void parse(const char *);
+
+    /// reset the configuration details to default
+    void clear() {*this = PeerOptions();}
+
+    /// generate a security context from the configured options
+    Security::ContextPointer createContext();
+
+    bool ssl;   ///< whether SSL is to be used on this connection
+
+    SBuf certFile;       ///< path of file containing PEM format X509 certificate
+    SBuf privateKeyFile; ///< path of file containing private key in PEM format
+    SBuf sslOptions;     ///< library-specific options string
+    SBuf caFile;         ///< path of file containing trusted Certificate Authority
+    SBuf caDir;          ///< path of directory containign a set of trusted Certificate Authorities
+    SBuf crlFile;        ///< path of file containing Certificate Revoke List
+
+    int sslVersion;
+    SBuf sslCipher;
+    SBuf sslFlags;
+    SBuf sslDomain;
+};
+
+/// configuration options for DIRECT server access
+extern PeerOptions ProxyOutgoingConfig;
+
+} // namespace Security
+
+// parse the tls_outgoing_options directive
+inline void
+parse_securePeerOptions(Security::PeerOptions *opt)
+{
+    while(const char *token = ConfigParser::NextToken()) {
+        opt->parse(token);
+    }
+}
+
+#define free_securePeerOptions(x) Security::ProxyOutgoingConfig.clear()
+#define dump_securePeerOptions(e,n,x) // not supported yet
+
+#endif /* SQUID_SRC_SECURITY_PEEROPTIONS_H */

=== modified file 'src/ssl/PeerConnector.cc'
--- src/ssl/PeerConnector.cc	2015-01-13 07:25:36 +0000
+++ src/ssl/PeerConnector.cc	2015-01-14 15:44:07 +0000
@@ -94,70 +94,73 @@
     if (!Comm::IsConnOpen(serverConn) || fd_table[serverConn->fd].closing()) {
         connectionClosed("Ssl::PeerConnector::prepareSocket");
         return false;
     }
 
     // watch for external connection closures
     typedef CommCbMemFunT<Ssl::PeerConnector, CommCloseCbParams> Dialer;
     closeHandler = JobCallback(9, 5, Dialer, this, Ssl::PeerConnector::commCloseHandler);
     comm_add_close_handler(fd, closeHandler);
     return true;
 }
 
 void
 Ssl::PeerConnector::initializeSsl()
 {
     SSL_CTX *sslContext = NULL;
     const CachePeer *peer = serverConnection()->getPeer();
     const int fd = serverConnection()->fd;
 
     if (peer) {
-        assert(peer->use_ssl);
+        assert(peer->secure.ssl);
         sslContext = peer->sslContext;
     } else {
+        // XXX: locate a per-server context in Security:: instead
         sslContext = ::Config.ssl_client.sslContext;
     }
 
     assert(sslContext);
 
     SSL *ssl = Ssl::CreateClient(sslContext, fd, "server https start");
     if (!ssl) {
         ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, Http::scInternalServerError, request.getRaw());
         anErr->xerrno = errno;
         debugs(83, DBG_IMPORTANT, "Error allocating SSL handle: " << ERR_error_string(ERR_get_error(), NULL));
         bail(anErr);
         return;
     }
 
     if (peer) {
-        if (peer->ssldomain)
-            SSL_set_ex_data(ssl, ssl_ex_index_server, peer->ssldomain);
-
+        if (!peer->secure.sslDomain.isEmpty()) {
+            // const loss is okay here, ssl_ex_index_server is only read and not assigned a destructor
+            SSL_set_ex_data(ssl, ssl_ex_index_server, const_cast<SBuf*>(&peer->secure.sslDomain));
+        }
 #if NOT_YET
 
         else if (peer->name)
             SSL_set_ex_data(ssl, ssl_ex_index_server, peer->name);
 
 #endif
-
+#if WHEN_PEER_HOST_IS_SBUF
         else
             SSL_set_ex_data(ssl, ssl_ex_index_server, peer->host);
+#endif
 
         if (peer->sslSession)
             SSL_set_session(ssl, peer->sslSession);
 
     } else if (request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) {
         // client connection is required for Peek or Stare mode in the case we need to splice
         // or terminate client and server connections
         assert(clientConn != NULL);
         SSL *clientSsl = fd_table[request->clientConnectionManager->clientConnection->fd].ssl;
         BIO *b = SSL_get_rbio(clientSsl);
         Ssl::ClientBio *clnBio = static_cast<Ssl::ClientBio *>(b->ptr);
         const Ssl::Bio::sslFeatures &features = clnBio->getFeatures();
         if (features.sslVersion != -1) {
             features.applyToSSL(ssl);
             // Should we allow it for all protocols?
             if (features.sslVersion >= 3) {
                 b = SSL_get_rbio(ssl);
                 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
                 srvBio->setClientFeatures(features);
                 srvBio->recordInput(true);

=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc	2015-01-13 07:25:36 +0000
+++ src/ssl/support.cc	2015-01-14 15:05:47 +0000
@@ -1091,115 +1091,109 @@
     default:
         debugs(83, 5, "Using SSLv2/SSLv3.");
         return SSLv23_server_method();
         break;
     }
 
     //Not reached
     return NULL;
 }
 
 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;
     Ssl::ContextMethod method;
     SSL_CTX * sslContext;
     long fl = Ssl::parse_flags(flags);
 
     ssl_initialize();
 
-    if (!keyfile)
-        keyfile = certfile;
-
-    if (!certfile)
-        certfile = keyfile;
-
     if (!(method = Ssl::method(version)))
         return NULL;
 
     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));
 
-    if (cipher) {
+    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) {
+    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));
         }
 
         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();
             fatalf("Failed to acquire SSL private key '%s': %s\n",
                    keyfile, ERR_error_string(ssl_error, NULL));
         }
 
         debugs(83, 5, "Comparing private and public SSL keys.");
 
         if (!SSL_CTX_check_private_key(sslContext)) {
             ssl_error = ERR_get_error();
             fatalf("SSL private key '%s' does not match public key '%s': %s\n",
                    certfile, keyfile, ERR_error_string(ssl_error, NULL));
         }
     }
 
     debugs(83, 9, "Setting RSA key generation callback.");
     SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
 
     if (fl & SSL_FLAG_DONT_VERIFY_PEER) {
         debugs(83, 2, "NOTICE: Peer certificates are not verified for validity!");
         SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
     } else {
         debugs(83, 9, "Setting certificate verification callback.");
         SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
     }
 
     debugs(83, 9, "Setting CA certificate locations.");
 
-    if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, CApath)) {
+    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) {
+    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_error = ERR_get_error();
         debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL));
     }
 
     return sslContext;
 }

=== added file 'src/tests/stub_libsecurity.cc'
--- src/tests/stub_libsecurity.cc	1970-01-01 00:00:00 +0000
+++ src/tests/stub_libsecurity.cc	2015-01-14 15:04:28 +0000
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+
+#define STUB_API "security/libsecurity.la"
+#include "tests/STUB.h"
+
+#include "security/PeerOptions.h"
+Security::PeerOptions Security::ProxyOutgoingConfig;
+void Security::PeerOptions::parse(char const*) STUB
+Security::ContextPointer Security::PeerOptions::createContext() STUB_RETVAL(NULL)

=== modified file 'src/tunnel.cc'
--- src/tunnel.cc	2015-01-13 07:25:36 +0000
+++ src/tunnel.cc	2015-01-14 15:05:47 +0000
@@ -936,41 +936,41 @@
                            tunnelClientClosed,
                            tunnelState);
 
     AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
                                      CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
     commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
 
     peerSelect(&(tunnelState->serverDestinations), request, al,
                NULL,
                tunnelPeerSelectComplete,
                tunnelState);
 }
 
 void
 TunnelStateData::connectToPeer()
 {
     const Comm::ConnectionPointer &srv = server.conn;
 
 #if USE_OPENSSL
     if (CachePeer *p = srv->getPeer()) {
-        if (p->use_ssl) {
+        if (p->secure.ssl) {
             AsyncCall::Pointer callback = asyncCall(5,4,
                                                     "TunnelStateData::ConnectedToPeer",
                                                     MyAnswerDialer(&TunnelStateData::connectedToPeer, this));
             Ssl::PeerConnector *connector =
                 new Ssl::PeerConnector(request, srv, client.conn, callback);
             AsyncJob::Start(connector); // will call our callback
             return;
         }
     }
 #endif
 
     tunnelRelayConnectRequest(srv, this);
 }
 
 #if USE_OPENSSL
 /// Ssl::PeerConnector callback
 void
 TunnelStateData::connectedToPeer(Ssl::PeerConnectorAnswer &answer)
 {
     if (ErrorState *error = answer.error.get()) {

-------------- next part --------------
A non-text attachment was scrubbed...
Name: cryptong_libsecurity_mk1.patch.sig
Type: application/octet-stream
Size: 287 bytes
Desc: not available
URL: <http://lists.squid-cache.org/pipermail/squid-dev/attachments/20150115/e722cc86/attachment-0001.obj>


More information about the squid-dev mailing list