=== modified file 'configure.in'
--- configure.in	2010-11-06 23:34:12 +0000
+++ configure.in	2010-11-09 19:49:22 +0000
@@ -1496,40 +1496,51 @@
   SQUID_YESNO([$enableval],[unrecognized argument to --disable-ident-lookups: $enableval])
 ])
 AC_MSG_NOTICE([Support for Ident lookups enabled: ${enable_ident_lookups:=yes}])
 SQUID_DEFINE_BOOL(USE_IDENT,$enable_ident_lookups,[Support for Ident (RFC 931) lookups])
 
 squid_opt_use_dnsserver="no"
 AC_ARG_ENABLE(internal-dns,
   AS_HELP_STRING([--disable-internal-dns],
            [Prevents Squid from directly sending and receiving DNS messages, 
             and instead enables the old external 'dnsserver' processes.]), [
   if test "x$enableval" = "xno" ; then
     AC_MSG_WARN([Disabling Internal DNS queries])
     squid_opt_use_dnsserver="yes"
   fi
 ])
 SQUID_DEFINE_BOOL(USE_DNSSERVERS,$squid_opt_use_dnsserver,
   [Use dnsserver processes instead of the internal DNS protocol support])
 AM_CONDITIONAL([USE_DNSSERVER],[test "x$squid_opt_use_dnsserver" = "xyes" ])
 
 
+AM_CONDITIONAL(USE_SSL_CRTD, false)
+AC_ARG_ENABLE(ssl-crtd,
+  AC_HELP_STRING([--enable-ssl-crtd],
+                 [Prevent Squid from directly generation of SSL private key and 
+                  certificate request and instead enables the ssl_crtd processes.]),
+[ if test "x$enable_ssl" = "xyes" ; then
+    AC_DEFINE(USE_SSL_CRTD,1,[Use ssl_crtd daemon])
+    AM_CONDITIONAL(USE_SSL_CRTD, true)
+  fi
+])
+
 dnl Select Default hosts file location
 AC_ARG_ENABLE(default-hostsfile,
   AS_HELP_STRING([--enable-default-hostsfile=path],
                  [Select default location for hosts file.
                   See hosts_file directive in squid.conf for details]), [
 if test "x$enableval" != "xnone" -a "x$enableval" != "xno" ; then
   if test \! -f "$enableval"; then
     AC_MSG_WARN([Unable to find file $enableval. I hope you know what you are doing.])
   fi
   squid_opt_default_hosts=$enableval
 else
   squid_opt_default_hosts="none"
 fi
 ])
 AC_MSG_NOTICE([Default hosts file set to: ${squid_opt_default_hosts:=/etc/hosts}])
 DEFAULT_HOSTS=$squid_opt_default_hosts
 AC_SUBST(DEFAULT_HOSTS)
 
 # Select auth schemes modules to build
 AC_ARG_ENABLE(auth,
@@ -3315,40 +3326,41 @@
 	lib/rfcnb/Makefile \
 	lib/smblib/Makefile \
 	scripts/Makefile \
 	src/Makefile \
 	src/base/Makefile \
 	src/acl/Makefile \
 	src/fs/Makefile \
 	src/repl/Makefile \
 	src/auth/Makefile \
 	src/adaptation/Makefile \
 	src/adaptation/icap/Makefile \
 	src/adaptation/ecap/Makefile \
 	src/comm/Makefile \
 	src/esi/Makefile \
 	src/eui/Makefile \
 	src/icmp/Makefile \
 	src/ident/Makefile \
 	src/ip/Makefile \
 	src/log/Makefile \
 	src/ipc/Makefile \
+	src/ssl/Makefile \
 	src/mgr/Makefile \
 	contrib/Makefile \
 	snmplib/Makefile \
 	icons/Makefile \
 	errors/Makefile \
 	test-suite/Makefile \
 	doc/Makefile \
 	doc/manuals/Makefile \
 	helpers/Makefile \
 	helpers/basic_auth/Makefile \
 	helpers/basic_auth/DB/Makefile \
 	helpers/basic_auth/fake/Makefile \
 	helpers/basic_auth/getpwnam/Makefile \
 	helpers/basic_auth/LDAP/Makefile \
 	helpers/basic_auth/MSNT/Makefile \
 	helpers/basic_auth/MSNT-multi-domain/Makefile \
 	helpers/basic_auth/NCSA/Makefile \
 	helpers/basic_auth/NIS/Makefile \
 	helpers/basic_auth/PAM/Makefile \
 	helpers/basic_auth/POP3/Makefile \

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2010-11-06 14:58:44 +0000
+++ src/Makefile.am	2010-11-09 20:36:25 +0000
@@ -24,40 +24,49 @@
 	MemBlob.h \
 	MemBlob.cc
 
 SNMP_ALL_SOURCE = \
 	snmp_core.cc \
 	snmp_agent.cc
 if USE_SNMP
 SNMP_SOURCE = $(SNMP_ALL_SOURCE)
 else
 SNMP_SOURCE = 
 endif
 
 LOADABLE_MODULES_SOURCES = \
 	LoadableModule.h \
 	LoadableModule.cc \
 	LoadableModules.h \
 	LoadableModules.cc
 
 SUBDIRS	= base comm eui acl fs repl auth ip icmp ident log ipc mgr
 
+if ENABLE_SSL
+SUBDIRS += ssl
+SSL_LIBS = \
+	ssl/libsslutil.la \
+	ssl/libsslsquid.la
+else
+SSL_LOCAL_LIBS =
+endif
+
 if USE_ADAPTATION
 SUBDIRS += adaptation
 endif
 
 if USE_ESI
 SUBDIRS += esi
 ESI_LOCAL_LIBS = \
 	esi/libesi.la \
 	$(top_builddir)/lib/libTrie/src/libTrie.a
 ESI_LIBS = $(ESI_LOCAL_LIBS) \
 	$(XMLLIB) \
 	$(EXPATLIB)
 else
 ESI_LIBS = 
 endif
 
 DELAY_POOL_ALL_SOURCE = \
 	CommonPool.h \
 	CompositePoolNode.h \
 	delay_pools.cc \
@@ -97,50 +106,40 @@
 endif
 
 if ENABLE_HTCP
 HTCPSOURCE = htcp.cc htcp.h
 endif
 
 if MAKE_LEAKFINDER
 LEAKFINDERSOURCE =  LeakFinder.cc
 else
 LEAKFINDERSOURCE = 
 endif
 
 if ENABLE_UNLINKD
 UNLINKDSOURCE = unlinkd.cc
 UNLINKD = unlinkd
 else
 UNLINKDSOURCE = 
 UNLINKD = 
 endif
 
-SSL_ALL_SOURCE = \
-	ssl_support.cc \
-	ssl_support.h
-
-if ENABLE_SSL
-SSL_SOURCE = $(SSL_ALL_SOURCE)
-else
-SSL_SOURCE = 
-endif
-
 WIN32_ALL_SOURCE = \
 	win32.cc \
 	WinSvc.cc
 if ENABLE_WIN32SPECIFIC
 WIN32_SOURCE = win32.cc
 WINSVC_SOURCE = WinSvc.cc
 else
 WIN32_SOURCE =
 WINSVC_SOURCE =
 endif
 
 if USE_IPC_WIN32
 IPC_SOURCE = ipc_win32.cc
 else
 IPC_SOURCE = ipc.cc
 endif
 
 AIO_WIN32_ALL_SOURCES = \
 	DiskIO/AIO/aio_win32.cc \
 	DiskIO/AIO/aio_win32.h
@@ -413,41 +412,40 @@
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	PeerSelectState.h \
 	PingData.h \
 	protos.h \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	RemovalPolicy.h \
 	send-announce.cc \
 	$(SBUF_SOURCE) \
 	$(SNMP_SOURCE) \
 	squid.h \
 	SquidMath.h \
 	SquidMath.cc \
 	SquidNew.cc \
-	$(SSL_SOURCE) \
 	stat.cc \
 	StatHist.cc \
 	String.cc \
 	stmem.cc \
 	stmem.h \
 	store.cc \
 	Store.h \
 	StoreFileSystem.cc \
 	StoreFileSystem.h \
 	StoreHashIndex.h \
 	store_io.cc \
 	StoreIOBuffer.h \
 	StoreIOState.cc \
 	StoreIOState.h \
 	store_client.cc \
 	StoreClient.h \
 	store_digest.cc \
 	store_dir.cc \
 	store_key_md5.cc \
 	store_log.cc \
@@ -500,42 +498,40 @@
 
 EXTRA_squid_SOURCES = \
 	$(AIO_WIN32_ALL_SOURCES) \
 	$(all_AUTHMODULES) \
 	ConfigOption.h \
 	$(DELAY_POOL_ALL_SOURCE) \
 	dns.cc \
 	dnsserver.cc \
 	dns_internal.cc \
 	DnsLookupDetails.cc \
 	DnsLookupDetails.h \
 	htcp.cc \
 	htcp.h \
 	ipc.cc \
 	ipc_win32.cc \
 	ProfStats.cc \
 	LeakFinder.cc \
 	LeakFinder.h \
 	$(SNMP_ALL_SOURCE) \
 	$(UNLINKDSOURCE) \
-	$(SSL_ALL_SOURCE) \
-	$(WIN32_ALL_SOURCE) \
 	$(LOADABLE_MODULES_SOURCES) \
 	DiskIO/DiskThreads/aiops.cc \
 	DiskIO/DiskThreads/aiops_win32.cc
 
 noinst_HEADERS = \
 	client_side_request.cci \
 	MemBuf.cci \
 	MemBuf.h \
 	Store.cci \
 	StoreEntryStream.h \
 	String.cci \
 	SquidString.h \
 	SquidTime.h
 
 BUILT_SOURCES = \
 	cf_gen_defines.cci \
 	cf_parser.cci \
 	err_type.cc \
 	err_detail_type.cc \
 	globals.cc \
@@ -550,56 +546,58 @@
 nodist_squid_SOURCES = \
 	$(DISKIO_GEN_SOURCE) \
 	$(BUILT_SOURCES)
 
 squid_LDADD = \
 	$(COMMON_LIBS) \
 	comm/libcomm-listener.la \
 	eui/libeui.la \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	log/liblog.la \
 	$(XTRA_OBJS) \
 	$(DISK_LINKOBJS) \
 	$(REPL_OBJS) \
 	$(DISK_LIBS) \
 	$(DISK_OS_LIBS) \
 	$(CRYPTLIB) \
 	$(REGEXLIB) \
 	$(SNMPLIB) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(SSLLIB) \
 	$(EPOLL_LIBS) \
 	$(MINGW_LIBS) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 squid_DEPENDENCIES = \
 	$(DISK_LIBS) \
 	$(DISK_LINKOBJS) \
 	$(REPL_OBJS) \
 	$(SNMPLIB) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LOCAL_LIBS) \
+	$(SSL_LIBS) \
 	$(COMMON_LIBS)
 
 if USE_LOADABLE_MODULES
 squid_SOURCES += $(LOADABLE_MODULES_SOURCES)
 squid_LDADD += -L$(top_builddir) $(LIBLTDL)
 squid_LDFLAGS = -export-dynamic -dlopen force
 ## when static module linking is supported and enabled:
 ## squid_LDFLAGS = -all-static -dlopen self
 ##
 ## LTDL headers require their local include path...
 INCLUDES += $(INCLTDL)
 endif
 
 ## Kerberos libraries require their include path...
 INCLUDES += $(KRB5INCS)
 
 
 unlinkd_SOURCES = unlinkd_daemon.cc
 dnsserver_SOURCES = dnsserver.cc SquidNew.cc tests/stub_debug.cc test_tools.cc time.cc
 recv_announce_SOURCES = recv-announce.cc
@@ -744,46 +742,48 @@
 		DiskIO/DiskThreads/DiskThreadsIOStrategy.cc \
 		DiskIO/DiskThreads/DiskThreadsIOStrategy.h
 
 DiskIO_DiskDaemon_diskd_SOURCES = DiskIO/DiskDaemon/diskd.cc
 nodist_DiskIO_DiskDaemon_diskd_SOURCES = time.cc
 DiskIO_DiskDaemon_diskd_LDADD = \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 
 
 DEFAULT_HTTP_PORT	= 3128
 DEFAULT_ICP_PORT	= 3130
 DEFAULT_PREFIX		= $(prefix)
 DEFAULT_CONFIG_DIR	= $(sysconfdir)
 DEFAULT_CONFIG_FILE	= $(DEFAULT_CONFIG_DIR)/squid.conf
 DEFAULT_MIME_TABLE	= $(DEFAULT_CONFIG_DIR)/mime.conf
 DEFAULT_DNSSERVER	= $(libexecdir)/`echo dnsserver | sed '$(transform);s/$$/$(EXEEXT)/'`
+DEFAULT_SSL_CRTD	= $(libexecdir)/`echo ssl_crtd  | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_LOG_PREFIX	= $(DEFAULT_LOG_DIR)
 DEFAULT_CACHE_LOG	= $(DEFAULT_LOG_PREFIX)/cache.log
 DEFAULT_ACCESS_LOG	= $(DEFAULT_LOG_PREFIX)/access.log
 DEFAULT_STORE_LOG	= $(DEFAULT_LOG_PREFIX)/store.log
 DEFAULT_NETDB_FILE	= $(DEFAULT_LOG_PREFIX)/netdb.state
 DEFAULT_SWAP_DIR	= $(localstatedir)/cache
+DEFAULT_SSL_DB_DIR	= $(localstatedir)/ssl_db
 DEFAULT_PINGER		= $(libexecdir)/`echo pinger | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_UNLINKD		= $(libexecdir)/`echo unlinkd | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_LOGFILED	= $(libexecdir)/`echo log_file_daemon | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_DISKD		= $(libexecdir)/`echo diskd | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_ICON_DIR	= $(datadir)/icons
 DEFAULT_ERROR_DIR	= $(datadir)/errors
 
 # Make location configure settings available to the code
 DEFS += -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -DDEFAULT_SQUID_DATA_DIR=\"$(datadir)\" -DDEFAULT_SQUID_CONFIG_DIR=\"$(sysconfdir)\"
 
 snmp_core.o snmp_agent.o: ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.h
 
 globals.cc: globals.h mk-globals-c.awk
 	$(AWK) -f $(srcdir)/mk-globals-c.awk < $(srcdir)/globals.h > $@ || ($(RM) -f $@ && exit 1)
 
 ## Generate files containing string arrays for various enums....
 hier_code.cc: hier_code.h mk-string-arrays.awk
 	$(AWK) -f $(srcdir)/mk-string-arrays.awk < $(srcdir)/hier_code.h > $@ || ($(RM) -f $@ && exit 1)
 
 err_type.cc: err_type.h mk-string-arrays.awk
@@ -816,50 +816,52 @@
 # squid.conf.default is built by cf_gen when making cf_parser.cci
 squid.conf.default squid.conf.documented: cf_parser.cci
 	true
 
 cf_parser.cci: cf.data cf_gen$(EXEEXT)
 	./cf_gen cf.data $(srcdir)/cf.data.depend
 
 cf_gen_defines.cci: $(srcdir)/cf_gen_defines $(srcdir)/cf.data.pre
 	$(AWK) -f $(srcdir)/cf_gen_defines <$(srcdir)/cf.data.pre >$@ || ($(RM) -f $@ && exit 1)
 
 
 ## FIXME: generate a sed command file from configure. Then this doesn't
 ## depend on the Makefile.
 cf.data: cf.data.pre Makefile
 	sed \
 	-e "s%[@]DEFAULT_HTTP_PORT[@]%$(DEFAULT_HTTP_PORT)%g" \
 	-e "s%[@]DEFAULT_ICP_PORT[@]%$(DEFAULT_ICP_PORT)%g" \
 	-e "s%[@]DEFAULT_CACHE_EFFECTIVE_USER[@]%${CACHE_EFFECTIVE_USER}%g" \
 	-e "s%[@]DEFAULT_MIME_TABLE[@]%$(DEFAULT_MIME_TABLE)%g" \
 	-e "s%[@]DEFAULT_DNSSERVER[@]%$(DEFAULT_DNSSERVER)%g" \
+	-e "s%[@]DEFAULT_SSL_CRTD[@]%$(DEFAULT_SSL_CRTD)%g" \
 	-e "s%[@]DEFAULT_UNLINKD[@]%$(DEFAULT_UNLINKD)%g" \
 	-e "s%[@]DEFAULT_PINGER[@]%$(DEFAULT_PINGER)%g" \
 	-e "s%[@]DEFAULT_DISKD[@]%$(DEFAULT_DISKD)%g" \
 	-e "s%[@]DEFAULT_LOGFILED[@]%$(DEFAULT_LOGFILED)%g;" \
 	-e "s%[@]DEFAULT_CACHE_LOG[@]%$(DEFAULT_CACHE_LOG)%g" \
 	-e "s%[@]DEFAULT_ACCESS_LOG[@]%$(DEFAULT_ACCESS_LOG)%g" \
 	-e "s%[@]DEFAULT_STORE_LOG[@]%$(DEFAULT_STORE_LOG)%g" \
 	-e "s%[@]DEFAULT_PID_FILE[@]%$(DEFAULT_PID_FILE)%g" \
 	-e "s%[@]DEFAULT_NETDB_FILE[@]%$(DEFAULT_NETDB_FILE)%g" \
 	-e "s%[@]DEFAULT_SWAP_DIR[@]%$(DEFAULT_SWAP_DIR)%g" \
+	-e "s%[@]DEFAULT_SSL_DB_DIR[@]%$(DEFAULT_SSL_DB_DIR)%g" \
 	-e "s%[@]DEFAULT_ICON_DIR[@]%$(DEFAULT_ICON_DIR)%g" \
 	-e "s%[@]DEFAULT_CONFIG_DIR[@]%$(DEFAULT_CONFIG_DIR)%g" \
 	-e "s%[@]DEFAULT_PREFIX[@]%$(DEFAULT_PREFIX)%g" \
 	-e "s%[@]DEFAULT_HOSTS[@]%$(DEFAULT_HOSTS)%g" \
 	-e "s%[@]SQUID[@]%SQUID\ $(VERSION)%g" \
 	< $(srcdir)/cf.data.pre >$@
 
 repl_modules.cc: repl_modules.sh Makefile
 	$(SHELL) $(srcdir)/repl_modules.sh $(REPL_POLICIES) > repl_modules.cc
 
 include $(top_srcdir)/doc/manuals/Substitute.am
 
 squid.8: $(srcdir)/squid.8.in Makefile
 	$(SUBSTITUTE) < $(srcdir)/squid.8.in > $@
 
 man_MANS = squid.8
 EXTRA_DIST += squid.8.in
 CLEANFILES += squid.8
 
 install-data-local: install-sysconfDATA install-dataDATA
@@ -1217,41 +1219,40 @@
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
@@ -1268,40 +1269,41 @@
 	url.cc \
 	URLScheme.cc \
 	urn.cc \
 	useragent.cc \
 	wccp2.cc \
 	whois.cc \
 	FadingCounter.cc \
 	$(WIN32_SOURCE) \
 	wordlist.cc
 nodist_tests_testCacheManager_SOURCES = \
 	$(BUILT_SOURCES)
 # comm.cc only requires comm/libcomm-listener.la until fdc_table is dead.
 tests_testCacheManager_LDADD = \
 	$(COMMON_LIBS) \
 	comm/libcomm-listener.la \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	log/liblog.la \
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(REGEXLIB) \
 	$(SNMPLIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(SSLLIB) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_testCacheManager_LDFLAGS = $(LIBADD_DL)
 tests_testCacheManager_DEPENDENCIES = \
 	$(REPL_OBJS) \
 	$(SQUID_CPPUNIT_LA)
 
 tests_testDiskIO_SOURCES = \
 	$(SWAP_TEST_SOURCES) \
 	tests/testDiskIO.cc \
 	tests/testDiskIO.h \
@@ -1421,41 +1423,40 @@
 	multicast.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
@@ -1471,40 +1472,41 @@
 	SwapDir.cc \
 	url.cc \
 	URLScheme.cc \
 	urn.cc \
 	useragent.cc \
 	wccp2.cc \
 	whois.cc \
 	FadingCounter.cc \
 	$(WIN32_SOURCE) \
 	wordlist.cc
 nodist_tests_testEvent_SOURCES = \
 	$(BUILT_SOURCES)
 tests_testEvent_LDADD = \
 	$(COMMON_LIBS) \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	comm/libcomm-listener.la \
 	log/liblog.la \
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(REGEXLIB) \
 	$(SNMPLIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(SSLLIB) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_testEvent_LDFLAGS = $(LIBADD_DL)
 tests_testEvent_DEPENDENCIES = \
 	$(REPL_OBJS) \
 	$(SQUID_CPPUNIT_LA)
 
 ## Tests of the EventLoop module.
 tests_testEventLoop_SOURCES = \
 	$(ACL_REGISTRATION_SOURCES) \
 	debug.cc \
@@ -1584,41 +1586,40 @@
 	multicast.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
@@ -1634,40 +1635,41 @@
 	SwapDir.cc \
 	url.cc \
 	URLScheme.cc \
 	urn.cc \
 	useragent.cc \
 	wccp2.cc \
 	whois.cc \
 	FadingCounter.cc \
 	$(WIN32_SOURCE) \
 	wordlist.cc
 nodist_tests_testEventLoop_SOURCES = \
 	$(BUILT_SOURCES)
 tests_testEventLoop_LDADD = \
 	$(COMMON_LIBS) \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	comm/libcomm-listener.la \
 	log/liblog.la \
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(REGEXLIB) \
 	$(SNMPLIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(SSLLIB) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_testEventLoop_LDFLAGS = $(LIBADD_DL)
 tests_testEventLoop_DEPENDENCIES = \
 	$(REPL_OBJS) \
 	$(SQUID_CPPUNIT_LA)
 
 tests_test_http_range_SOURCES = \
 	$(ACL_REGISTRATION_SOURCES) \
 	tests/test_http_range.cc \
 	BodyPipe.cc \
@@ -1738,41 +1740,40 @@
 	mem.cc \
 	mem_node.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	multicast.cc \
 	neighbors.cc \
 	Parsing.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	pconn.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_key_md5.cc \
 	store_io.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
@@ -1792,40 +1793,41 @@
 	URLScheme.cc \
 	urn.cc \
 	useragent.cc \
 	wccp2.cc \
 	whois.cc \
 	FadingCounter.cc \
 	$(WIN32_SOURCE) \
 	wordlist.cc \
 	Packer.cc \
 	MemBuf.cc
 nodist_tests_test_http_range_SOURCES = \
 	$(BUILT_SOURCES)
 tests_test_http_range_LDADD = \
 	$(COMMON_LIBS) \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	comm/libcomm-listener.la \
 	log/liblog.la \
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(REGEXLIB) \
 	$(SNMPLIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(SSLLIB) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_test_http_range_LDFLAGS = $(LIBADD_DL)
 tests_test_http_range_DEPENDENCIES = \
 	$(SQUID_CPPUNIT_LA)
 
 
 ## Tests of the HttpRequest module.
 tests_testHttpRequest_SOURCES = \
 	$(ACL_REGISTRATION_SOURCES) \
 	HttpRequest.cc \
@@ -1905,41 +1907,40 @@
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
@@ -1955,40 +1956,41 @@
 	SwapDir.cc \
 	url.cc \
 	URLScheme.cc \
 	urn.cc \
 	useragent.cc \
 	wccp2.cc \
 	whois.cc \
 	FadingCounter.cc \
 	$(WIN32_SOURCE) \
 	wordlist.cc
 nodist_tests_testHttpRequest_SOURCES = \
 	$(BUILT_SOURCES)
 tests_testHttpRequest_LDADD = \
 	$(COMMON_LIBS) \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	comm/libcomm-listener.la \
 	log/liblog.la \
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(REGEXLIB) \
 	$(SNMPLIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(SSLLIB) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_testHttpRequest_LDFLAGS = $(LIBADD_DL)
 tests_testHttpRequest_DEPENDENCIES = \
 	$(REPL_OBJS) \
 	$(SQUID_CPPUNIT_LA)
 
 # TODO:mime.cc drags in HttpReply.cc
 # delay pools need client_side_request.cc
 # store_key_md5 wants the method.
 STORE_TEST_SOURCES=\
@@ -2322,41 +2324,40 @@
 	multicast.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
@@ -2371,40 +2372,41 @@
 	tunnel.cc \
 	SwapDir.cc \
 	urn.cc \
 	useragent.cc \
 	wccp2.cc \
 	whois.cc \
 	FadingCounter.cc \
 	$(WIN32_SOURCE) \
 	wordlist.cc
 nodist_tests_testURL_SOURCES = \
 	$(BUILT_SOURCES)
 tests_testURL_LDADD = \
 	$(COMMON_LIBS) \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	comm/libcomm-listener.la \
 	log/liblog.la \
 	$(REGEXLIB) \
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(SNMPLIB) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(COMPAT_LIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(SSLLIB) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_testURL_LDFLAGS = $(LIBADD_DL)
 tests_testURL_DEPENDENCIES = \
 	$(REPL_OBJS) \
 	$(SQUID_CPPUNIT_LA)
 
 
 TESTS += testHeaders
 
 ## Special Universal .h dependency test script

=== modified file 'src/ProtoPort.cc'
--- src/ProtoPort.cc	2009-12-31 02:35:01 +0000
+++ src/ProtoPort.cc	2010-11-10 11:33:44 +0000
@@ -1,44 +1,46 @@
 /*
  * $Id$
  */
 
 #include "squid.h"
 #include "ProtoPort.h"
+#include <limits>
 
 http_port_list::http_port_list(const char *aProtocol)
 #if USE_SSL
         :
-        http(*this)
+        http(*this), dynamicCertMemCacheSize(std::numeric_limits<size_t>::max())
 #endif
 {
     protocol = xstrdup(aProtocol);
 }
 
 http_port_list::~http_port_list()
 {
     delete listener;
 
     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
 }
 
 
 #if USE_SSL
 
 https_port_list::https_port_list(): http_port_list("https")
 {
 }
 
 #endif

=== modified file 'src/ProtoPort.h'
--- src/ProtoPort.h	2010-04-17 02:29:04 +0000
+++ src/ProtoPort.h	2010-11-10 11:33:14 +0000
@@ -1,30 +1,34 @@
 /*
  * $Id$
  */
 #ifndef SQUID_PROTO_PORT_H
 #define SQUID_PROTO_PORT_H
 
 //#include "typedefs.h"
 #include "cbdata.h"
 #include "comm/ListenStateData.h"
 
+#if USE_SSL
+#include "ssl/gadgets.h"
+#endif
+
 struct http_port_list {
     http_port_list(const char *aProtocol);
     ~http_port_list();
 
     http_port_list *next;
 
     Ip::Address s;
     char *protocol;            /* protocol name */
     char *name;                /* visible name */
     char *defaultsite;         /* default web site */
 
     unsigned int intercepted:1;        /**< intercepting proxy port */
     unsigned int spoof_client_ip:1;    /**< spoof client ip if possible */
     unsigned int accel:1;              /**< HTTP accelerator */
     unsigned int allow_direct:1;       /**< Allow direct forwarding in accelerator mode */
     unsigned int vhost:1;              /**< uses host header */
     unsigned int sslBump:1;            /**< intercepts CONNECT requests */
     unsigned int ignore_cc:1;          /**< Ignore request Cache-Control directives */
 
     int vport;                 /* virtual port support, -1 for dynamic, >0 static*/
@@ -43,37 +47,42 @@
      * If not NULL we are actively listening for client requests.
      * delete to close the socket.
      */
     Comm::ListenStateData *listener;
 
 #if USE_SSL
     // XXX: temporary hack to ease move of SSL options to http_port
     http_port_list &http;
 
     char *cert;
     char *key;
     int version;
     char *cipher;
     char *options;
     char *clientca;
     char *cafile;
     char *capath;
     char *crlfile;
     char *dhfile;
     char *sslflags;
-    char *sslcontext;
-    SSL_CTX *sslContext;
+    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
 #endif
 
     CBDATA_CLASS2(http_port_list);
 };
 
 
 #if USE_SSL
 
 struct https_port_list: public http_port_list {
     https_port_list();
 };
 
 #endif
 
 #endif /* SQUID_PROTO_PORT_H */

=== modified file 'src/acl/Certificate.h'
--- src/acl/Certificate.h	2009-03-08 21:53:27 +0000
+++ src/acl/Certificate.h	2010-11-09 15:37:15 +0000
@@ -21,41 +21,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.
  *
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #ifndef SQUID_ACLCERTIFICATE_H
 #define SQUID_ACLCERTIFICATE_H
 
 #include "acl/Acl.h"
 #include "acl/Data.h"
 #include "acl/Checklist.h"
-#include "ssl_support.h"
+#include "ssl/support.h"
 #include "acl/Strategised.h"
 
 /// \ingroup ACLAPI
 class ACLCertificateStrategy : public ACLStrategy<SSL *>
 {
 
 public:
     virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     static ACLCertificateStrategy *Instance();
     /* Not implemented to prevent copies of the instance. */
     /* Not private to prevent brain dead g+++ warnings about
      * private constructors with no friends */
     ACLCertificateStrategy(ACLCertificateStrategy const &);
 
 private:
     static ACLCertificateStrategy Instance_;
     ACLCertificateStrategy() {}
 
     ACLCertificateStrategy&operator=(ACLCertificateStrategy const &);
 };

=== modified file 'src/acl/CertificateData.h'
--- src/acl/CertificateData.h	2009-03-31 12:39:30 +0000
+++ src/acl/CertificateData.h	2010-11-09 15:36:56 +0000
@@ -21,41 +21,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.
  *
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #ifndef SQUID_ACLCERTIFICATEDATA_H
 #define SQUID_ACLCERTIFICATEDATA_H
 
 #include "splay.h"
 #include "acl/Acl.h"
 #include "acl/Data.h"
-#include "ssl_support.h"
+#include "ssl/support.h"
 #include "acl/StringData.h"
 
 /// \ingroup ACLAPI
 class ACLCertificateData : public ACLData<SSL *>
 {
 
 public:
     MEMPROXY_CLASS(ACLCertificateData);
 
     ACLCertificateData(SSLGETATTRIBUTE *);
     ACLCertificateData(ACLCertificateData const &);
     ACLCertificateData &operator= (ACLCertificateData const &);
     virtual ~ACLCertificateData();
     bool match(SSL *);
     wordlist *dump();
     void parse();
     bool empty() const;
     virtual ACLData<SSL *> *clone() const;
 
     char *attribute;

=== modified file 'src/acl/SslErrorData.h'
--- src/acl/SslErrorData.h	2009-03-08 19:34:36 +0000
+++ src/acl/SslErrorData.h	2010-11-09 15:37:39 +0000
@@ -1,31 +1,31 @@
 
 /*
  * $Id$
  */
 
 #ifndef SQUID_ACLSSL_ERRORDATA_H
 #define SQUID_ACLSSL_ERRORDATA_H
 #include "acl/Acl.h"
 #include "acl/Data.h"
 #include "CbDataList.h"
-#include "ssl_support.h"
+#include "ssl/support.h"
 
 class ACLSslErrorData : public ACLData<ssl_error_t>
 {
 
 public:
     MEMPROXY_CLASS(ACLSslErrorData);
 
     ACLSslErrorData();
     ACLSslErrorData(ACLSslErrorData const &);
     ACLSslErrorData &operator= (ACLSslErrorData const &);
     virtual ~ACLSslErrorData();
     bool match(ssl_error_t);
     wordlist *dump();
     void parse();
     bool empty() const;
     virtual ACLData<ssl_error_t> *clone() const;
 
     CbDataList<ssl_error_t> *values;
 };
 

=== modified file 'src/base/Makefile.am'
--- src/base/Makefile.am	2010-10-07 07:53:45 +0000
+++ src/base/Makefile.am	2010-11-05 13:26:21 +0000
@@ -1,19 +1,20 @@
 
 include $(top_srcdir)/src/Common.am
 include $(top_srcdir)/src/TestHeaders.am
 
 noinst_LTLIBRARIES = libbase.la
 
 libbase_la_SOURCES = \
 	AsyncCall.cc \
 	AsyncCall.h \
 	AsyncJob.h \
 	AsyncJob.cc \
 	AsyncJobCalls.h \
 	AsyncCallQueue.cc \
 	AsyncCallQueue.h \
+	TidyPointer.h \
 	CbcPointer.h \
 	InstanceId.h \
 	Subscription.h \
 	TextException.cc \
 	TextException.h

=== added file 'src/base/TidyPointer.h'
--- src/base/TidyPointer.h	1970-01-01 00:00:00 +0000
+++ src/base/TidyPointer.h	2010-11-10 11:51:32 +0000
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_BASE_TIDYPOINTER_H
+#define SQUID_BASE_TIDYPOINTER_H
+
+#include "config.h"
+
+/**
+ * A pointer that deletes the object it points to when the pointer's owner or
+ * context is gone. Similar to std::auto_ptr but without confusing assignment
+ * and with a customizable cleanup method. Prevents memory leaks in
+ * the presence of exceptions and processing short cuts.
+*/
+template <typename T, void (*DeAllocator)(T *t)> class TidyPointer
+{
+public:
+    /// Delete callback.
+    typedef void DCB (T *t);
+    TidyPointer(T *t = NULL)
+            :   raw(t), deAllocator(DeAllocator) {}
+public:
+    bool operator !() const { return !raw; }
+    /// Returns raw and possibly NULL pointer
+    T *get() const { return raw; }
+    /// Address of the raw pointer, for pointer-setting functions
+    T **addr() { return &raw; }
+    /// Reset raw pointer - delete last one and save new one.
+    void reset(T *t) {
+        deletePointer();
+        raw = t;
+    }
+
+    /// Forget the raw pointer without freeing it. Become a nil pointer.
+    T *release() {
+        T *ret = raw;
+        raw = NULL;
+        return ret;
+    }
+    /// Deallocate raw pointer.
+    ~TidyPointer() {
+        deletePointer();
+    }
+private:
+    /// Forbidden copy constructor.
+    TidyPointer(TidyPointer<T, DeAllocator> const &);
+    /// Forbidden assigment operator.
+    TidyPointer <T, DeAllocator> & operator = (TidyPointer<T, DeAllocator> const &);
+    /// Deallocate raw pointer. Become a nil pointer.
+    void deletePointer() {
+        if (raw) {
+            deAllocator(raw);
+        }
+        raw = NULL;
+    }
+    T *raw; ///< pointer to T object or NULL
+    DCB *deAllocator; ///< cleanup function
+};
+
+/// DeAllocator for pointers that need free(3) from the std C library
+template<typename T> void tidyFree(T *p)
+{
+    xfree(p);
+}
+
+#endif // SQUID_BASE_TIDYPOINTER_H

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2010-10-29 00:12:28 +0000
+++ src/cache_cf.cc	2010-11-10 11:48:20 +0000
@@ -65,40 +65,44 @@
 #include "Parsing.h"
 #include "ProtoPort.h"
 #include "rfc1738.h"
 #if SQUID_SNMP
 #include "snmp.h"
 #endif
 #include "Store.h"
 #include "StoreFileSystem.h"
 #include "SwapDir.h"
 #include "wordlist.h"
 #include "ipc/Kids.h"
 
 #if HAVE_GLOB_H
 #include <glob.h>
 #endif
 
 #if HAVE_LIMITS_H
 #include <limits>
 #endif
 
+#if USE_SSL
+#include "ssl/gadgets.h"
+#endif
+
 #if USE_ADAPTATION
 static void parse_adaptation_service_set_type();
 static void parse_adaptation_service_chain_type();
 static void parse_adaptation_access_type();
 #endif
 
 #if ICAP_CLIENT
 static void parse_icap_service_type(Adaptation::Icap::Config *);
 static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &);
 static void free_icap_service_type(Adaptation::Icap::Config *);
 static void parse_icap_class_type();
 static void parse_icap_access_type();
 
 static void parse_icap_service_failure_limit(Adaptation::Icap::Config *);
 static void dump_icap_service_failure_limit(StoreEntry *, const char *, const Adaptation::Icap::Config &);
 static void free_icap_service_failure_limit(Adaptation::Icap::Config *);
 #endif
 
 #if USE_ECAP
 static void parse_ecap_service_type(Adaptation::Ecap::Config *);
@@ -129,40 +133,43 @@
 static void parse_access_log(customlog ** customlog_definitions);
 static int check_null_access_log(customlog *customlog_definitions);
 
 static void dump_logformat(StoreEntry * entry, const char *name, logformat * definitions);
 static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
 static void free_logformat(logformat ** definitions);
 static void free_access_log(customlog ** definitions);
 
 static void update_maxobjsize(void);
 static void configDoConfigure(void);
 static void parse_refreshpattern(refresh_t **);
 static int parseTimeUnits(const char *unit);
 static void parseTimeLine(time_t * tptr, const char *units);
 static void parse_ushort(u_short * var);
 static void parse_string(char **);
 static void default_all(void);
 static void defaults_if_none(void);
 static int parse_line(char *);
 static void parse_obsolete(const char *);
 static void parseBytesLine(size_t * bptr, const char *units);
+#if USE_SSL
+static void parseBytesOptionValue(size_t * bptr, const char *units, char const * value);
+#endif
 #if !USE_DNSSERVERS
 static void parseBytesLineSigned(ssize_t * bptr, const char *units);
 #endif
 static size_t parseBytesUnits(const char *unit);
 static void free_all(void);
 void requirePathnameExists(const char *name, const char *path);
 static OBJH dump_config;
 #if USE_HTTP_VIOLATIONS
 static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
 static void parse_http_header_access(header_mangler header[]);
 static void free_http_header_access(header_mangler header[]);
 static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
 static void parse_http_header_replace(header_mangler * header);
 static void free_http_header_replace(header_mangler * header);
 #endif
 static void parse_denyinfo(acl_deny_info_list ** var);
 static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
 static void free_denyinfo(acl_deny_info_list ** var);
 
 #if USE_WCCPv2
@@ -858,52 +865,62 @@
         peer *p;
 
         for (p = Config.peers; p != NULL; p = p->next) {
             if (p->use_ssl) {
                 debugs(3, 1, "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);
             }
         }
     }
 
     {
 
         http_port_list *s;
 
         for (s = Config.Sockaddr.http; s != NULL; s = (http_port_list *) s->next) {
             if (!s->cert && !s->key)
                 continue;
 
             debugs(3, 1, "Initializing http_port " << s->http.s << " SSL context");
 
-            s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath, s->crlfile, s->dhfile, s->sslcontext);
+            s->staticSslContext.reset(
+                sslCreateServerContext(s->cert, s->key,
+                                       s->version, s->cipher, s->options, s->sslflags, s->clientca,
+                                       s->cafile, s->capath, s->crlfile, s->dhfile,
+                                       s->sslContextSessionId));
+
+            Ssl::readCertAndPrivateKeyFromFiles(s->signingCert, s->signPkey, s->cert, s->key);
         }
     }
 
     {
 
         https_port_list *s;
 
         for (s = Config.Sockaddr.https; s != NULL; s = (https_port_list *) s->http.next) {
             debugs(3, 1, "Initializing https_port " << s->http.s << " SSL context");
 
-            s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath, s->crlfile, s->dhfile, s->sslcontext);
+            s->staticSslContext.reset(
+                sslCreateServerContext(s->cert, s->key,
+                                       s->version, s->cipher, s->options, s->sslflags, s->clientca,
+                                       s->cafile, s->capath, s->crlfile, s->dhfile,
+                                       s->sslContextSessionId));
         }
     }
 
 #endif
 }
 
 /** Parse a line containing an obsolete directive.
  * To upgrade it where possible instead of just "Bungled config" for
  * directives which cannot be marked as simply aliases of the some name.
  * For example if the parameter order and content has changed.
  * Or if the directive has been completely removed.
  */
 void
 parse_obsolete(const char *name)
 {
     // Directives which have been radically changed rather than removed
     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.");
@@ -1096,40 +1113,78 @@
     m = u;			/* default to 'units' if none specified */
 
     if (0.0 == d)
         (void) 0;
     else if ((token = strtok(NULL, w_space)) == NULL)
         debugs(3, 0, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " <<  units  );
     else if ((m = parseBytesUnits(token)) == 0) {
         self_destruct();
         return;
     }
 
     *bptr = static_cast<size_t>(m * d / u);
 
     if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
         self_destruct();
 }
 #endif
 
+#if USE_SSL
+/**
+ * Parse bytes from a string.
+ * Similar to the parseBytesLine function but parses the string value instead of
+ * the current token value.
+ */
+static void parseBytesOptionValue(size_t * bptr, const char *units, char const * value)
+{
+    int u;
+    if ((u = parseBytesUnits(units)) == 0) {
+        self_destruct();
+        return;
+    }
+
+    // Find number from string beginning.
+    char const * number_begin = value;
+    char const * number_end = value;
+
+    while ((*number_end >= '0' && *number_end <= '9')) {
+        number_end++;
+    }
+
+    String number;
+    number.limitInit(number_begin, number_end - number_begin);
+
+    int d = xatoi(number.termedBuf());
+    int m;
+    if ((m = parseBytesUnits(number_end)) == 0) {
+        self_destruct();
+        return;
+    }
+
+    *bptr = static_cast<size_t>(m * d / u);
+    if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
+        self_destruct();
+}
+#endif
+
 static size_t
 parseBytesUnits(const char *unit)
 {
     if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
         return 1;
 
     if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
         return 1 << 10;
 
     if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
         return 1 << 20;
 
     if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
         return 1 << 30;
 
     debugs(3, DBG_CRITICAL, "WARNING: Unknown bytes unit '" << unit << "'");
 
     return 0;
 }
 
@@ -3554,42 +3609,50 @@
         s->cipher = xstrdup(token + 7);
     } else if (strncmp(token, "clientca=", 9) == 0) {
         safe_free(s->clientca);
         s->clientca = xstrdup(token + 9);
     } else if (strncmp(token, "cafile=", 7) == 0) {
         safe_free(s->cafile);
         s->cafile = xstrdup(token + 7);
     } else if (strncmp(token, "capath=", 7) == 0) {
         safe_free(s->capath);
         s->capath = xstrdup(token + 7);
     } else if (strncmp(token, "crlfile=", 8) == 0) {
         safe_free(s->crlfile);
         s->crlfile = xstrdup(token + 8);
     } else if (strncmp(token, "dhparams=", 9) == 0) {
         safe_free(s->dhfile);
         s->dhfile = xstrdup(token + 9);
     } else if (strncmp(token, "sslflags=", 9) == 0) {
         safe_free(s->sslflags);
         s->sslflags = xstrdup(token + 9);
     } else if (strncmp(token, "sslcontext=", 11) == 0) {
-        safe_free(s->sslcontext);
-        s->sslcontext = xstrdup(token + 11);
+        safe_free(s->sslContextSessionId);
+        s->sslContextSessionId = xstrdup(token + 11);
+    } else if (strcmp(token, "generate-host-certificates") == 0) {
+        s->generateHostCertificates = true;
+    } else if (strcmp(token, "generate-host-certificates=on") == 0) {
+        s->generateHostCertificates = true;
+    } else if (strcmp(token, "generate-host-certificates=off") == 0) {
+        s->generateHostCertificates = false;
+    } else if (strncmp(token, "dynamic_cert_mem_cache_size=", 28) == 0) {
+        parseBytesOptionValue(&s->dynamicCertMemCacheSize, B_BYTES_STR, token + 28);
 #endif
     } else {
         self_destruct();
     }
 }
 
 static http_port_list *
 create_http_port(char *portspec)
 {
     http_port_list *s = new http_port_list("http");
     parse_http_port_specification(s, portspec);
     return s;
 }
 
 void
 add_http_port(char *portspec)
 {
     http_port_list *s = create_http_port(portspec);
     // we may need to merge better of the above returns a list with clones
     assert(s->next == NULL);
@@ -3621,41 +3684,41 @@
     memcpy( &(b->tcp_keepalive), &(a->tcp_keepalive), sizeof(a->tcp_keepalive));
 
 #if 0
     // AYJ: 2009-07-18: for now SSL does not clone. Configure separate ports with IPs and SSL settings
 
 #if USE_SSL
     // XXX: temporary hack to ease move of SSL options to http_port
     http_port_list &http;
 
     char *cert;
     char *key;
     int version;
     char *cipher;
     char *options;
     char *clientca;
     char *cafile;
     char *capath;
     char *crlfile;
     char *dhfile;
     char *sslflags;
-    char *sslcontext;
+    char *sslContextSessionId;
     SSL_CTX *sslContext;
 #endif
 
 #endif /*0*/
 
     return b;
 }
 
 static void
 parse_http_port_list(http_port_list ** head)
 {
     char *token = strtok(NULL, w_space);
 
     if (!token) {
         self_destruct();
         return;
     }
 
     http_port_list *s = create_http_port(token);
 
@@ -3745,42 +3808,48 @@
         storeAppendPrintf(e, " options=%s", s->options);
 
     if (s->cipher)
         storeAppendPrintf(e, " cipher=%s", s->cipher);
 
     if (s->cafile)
         storeAppendPrintf(e, " cafile=%s", s->cafile);
 
     if (s->capath)
         storeAppendPrintf(e, " capath=%s", s->capath);
 
     if (s->crlfile)
         storeAppendPrintf(e, " crlfile=%s", s->crlfile);
 
     if (s->dhfile)
         storeAppendPrintf(e, " dhparams=%s", s->dhfile);
 
     if (s->sslflags)
         storeAppendPrintf(e, " sslflags=%s", s->sslflags);
 
-    if (s->sslcontext)
-        storeAppendPrintf(e, " sslcontext=%s", s->sslcontext);
+    if (s->sslContextSessionId)
+        storeAppendPrintf(e, " sslcontext=%s", s->sslContextSessionId);
+
+    if (s->generateHostCertificates)
+        storeAppendPrintf(e, " generate-host-certificates");
+
+    if (s->dynamicCertMemCacheSize != std::numeric_limits<size_t>::max())
+        storeAppendPrintf(e, "dynamic_cert_mem_cache_size=%lu%s\n", (unsigned long)s->dynamicCertMemCacheSize, B_BYTES_STR);
 #endif
 }
 
 static void
 dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
 {
     while (s) {
         dump_generic_http_port(e, n, s);
         storeAppendPrintf(e, "\n");
         s = s->next;
     }
 }
 
 static void
 free_http_port_list(http_port_list ** head)
 {
     http_port_list *s;
 
     while ((s = *head) != NULL) {
         *head = s->next;

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2010-10-25 18:25:19 +0000
+++ src/cf.data.pre	2010-11-09 09:16:24 +0000
@@ -1373,40 +1373,58 @@
 	   sslflags=	Various flags modifying the use of SSL:
 			    DELAYED_AUTH
 				Don't request client certificates
 				immediately, but wait until acl processing
 				requires a certificate (not yet implemented).
 			    NO_DEFAULT_CA
 				Don't use the default CA lists built in
 				to OpenSSL.
 			    NO_SESSION_REUSE
 				Don't allow for session reuse. Each connection
 				will result in a new SSL session.
 			    VERIFY_CRL
 				Verify CRL lists when accepting client
 				certificates.
 			    VERIFY_CRL_ALL
 				Verify CRL lists for all certificates in the
 				client certificate chain.
 
 	   sslcontext=	SSL session ID context identifier.
 
+	   generate-host-certificates[=<on|off>]
+			Dynamically create SSL server certificates for the
+			destination hosts of bumped CONNECT requests. If this 
+			option is enable, cert and key options use to sign 
+			generated certificate. Otherwise generated certificate
+			will be selfsigned. 
+			If there is CA certificate life time of generated 
+			certificate equals lifetime of CA certificate. If
+			generated certificate is selfsigned lifetime is three 
+			years.
+			This option is enabled by default. See the sslBump option
+			above for more information.
+			
+	   dynamic_cert_mem_cache_size=SIZE
+			Approximate total RAM size spent on cached generated
+			certificates. If set to zero, caching is disabled. The
+			default value is 4MB. An average XXX-bit certificate
+			consumes about XXX bytes of RAM.
 
 	Other Options:
 
 	   connection-auth[=on|off]
 	                use connection-auth=off to tell Squid to prevent 
 	                forwarding Microsoft connection oriented authentication
 			(NTLM, Negotiate and Kerberos)
 
 	   disable-pmtu-discovery=
 			Control Path-MTU discovery usage:
 			    off		lets OS decide on what to do (default).
 			    transparent	disable PMTU discovery when transparent
 					support is enabled.
 			    always	disable always PMTU discovery.
 
 			In many setups of transparently intercepting proxies
 			Path-MTU discovery can not work on traffic towards the
 			clients. This is the case when the intercepting device
 			does not fully track connections and fails to forward
 			ICMP must fragment messages to the cache server. If you
@@ -1951,40 +1969,88 @@
 
 
 
 NAME: sslpassword_program
 IFDEF: USE_SSL
 DEFAULT: none
 LOC: Config.Program.ssl_password
 TYPE: string
 DOC_START
 	Specify a program used for entering SSL key passphrases
 	when using encrypted SSL certificate keys. If not specified
 	keys must either be unencrypted, or Squid started with the -N
 	option to allow it to query interactively for the passphrase.
 
 	The key file name is given as argument to the program allowing
 	selection of the right password if you have multiple encrypted
 	keys.
 DOC_END
 
 COMMENT_START
+ OPTIONS RELATING TO EXTERNAL SSL_CRTD 
+ -----------------------------------------------------------------------------
+COMMENT_END
+
+NAME: sslcrtd_program
+TYPE: eol 
+IFDEF: USE_SSL_CRTD
+DEFAULT: @DEFAULT_SSL_CRTD@ -s @DEFAULT_SSL_DB_DIR@ -M 4MB
+LOC: Config.Program.ssl_crtd
+DOC_START
+	Specify the location and options of the executable for ssl_crtd process.
+	@DEFAULT_SSL_CRTD@ program SHOULD receive -s and -m options to correct
+	run. For more information use:
+		@DEFAULT_SSL_CRTD@ -h
+DOC_END
+
+NAME: sslcrtd_children
+TYPE: HelperChildConfig
+IFDEF: USE_SSL_CRTD
+DEFAULT: 32 startup=5 idle=1
+LOC: Config.ssl_crtdChildren
+DOC_START
+	The maximum number of processes spawn to service ssl server.
+	The maximum this may be safely set to is 32.
+	
+	The startup= and idle= options allow some measure of skew in your
+	tuning.
+	
+		startup=N
+	
+	Sets the minimum number of processes to spawn when Squid
+	starts or reconfigures. When set to zero the first request will
+	cause spawning of the first child process to handle it.
+	
+	Starting too few children temporary slows Squid under load while it
+	tries to spawn enough additional processes to cope with traffic.
+	
+		idle=N
+	
+	Sets a minimum of how many processes Squid is to try and keep available
+	at all times. When traffic begins to rise above what the existing
+	processes can handle this many more will be spawned up to the maximum
+	configured. A minimum setting of 1 is required.
+	
+	You must have at least one ssl_crtd process.
+DOC_END
+
+COMMENT_START
  OPTIONS WHICH AFFECT THE NEIGHBOR SELECTION ALGORITHM
  -----------------------------------------------------------------------------
 COMMENT_END
 
 NAME: cache_peer
 TYPE: peer
 DEFAULT: none
 LOC: Config.peers
 DOC_START
 	To specify other caches in a hierarchy, use the format:
 	
 		cache_peer hostname type http-port icp-port [options]
 	
 	For example,
 	
 	#                                        proxy  icp
 	#          hostname             type     port   port  options
 	#          -------------------- -------- ----- -----  -----------
 	cache_peer parent.foo.net       parent    3128  3130  default
 	cache_peer sib1.foo.net         sibling   3128  3130  proxy-only

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2010-10-26 00:17:17 +0000
+++ src/client_side.cc	2010-11-10 11:48:45 +0000
@@ -98,40 +98,52 @@
 #include "eui/Config.h"
 #include "fde.h"
 #include "HttpHdrContRange.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "ident/Config.h"
 #include "ident/Ident.h"
 #include "ip/Intercept.h"
 #include "ipc/StartListening.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "ProtoPort.h"
 #include "rfc1738.h"
 #include "SquidTime.h"
 #include "Store.h"
 
 #if DELAY_POOLS
 #include "ClientInfo.h"
 #endif
 
+#if USE_SSL
+#include "ssl/context_storage.h"
+#include "ssl/helper.h"
+#include "ssl/gadgets.h"
+#endif
+#if USE_SSL_CRTD
+#include "ssl/crtd_message.h"
+#include "ssl/certificate_db.h"
+#endif
+
+#include <limits>
+
 #if LINGERING_CLOSE
 #define comm_close comm_lingering_close
 #endif
 
 /// dials clientHttpConnectionOpened or clientHttpsConnectionOpened call
 class ListeningStartedDialer: public CallDialer, public Ipc::StartListeningCb
 {
 public:
     typedef void (*Handler)(int fd, int errNo, http_port_list *portCfg);
     ListeningStartedDialer(Handler aHandler, http_port_list *aPortCfg):
             handler(aHandler), portCfg(aPortCfg) {}
 
     virtual void print(std::ostream &os) const {
         startPrint(os) <<
         ", port=" << (void*)portCfg << ')';
     }
 
     virtual bool canDial(AsyncCall &) const { return true; }
     virtual void dial(AsyncCall &) { (handler)(fd, errNo, portCfg); }
 
@@ -3329,41 +3341,41 @@
         debugs(83, 3, "clientNegotiateSSL: FD " << fd <<
                " client certificate: issuer: " <<
                X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
 
 
         X509_free(client_cert);
     } else {
         debugs(83, 5, "clientNegotiateSSL: FD " << fd <<
                " has no certificate.");
     }
 
     conn->readSomeData();
 }
 
 /** handle a new HTTPS connection */
 static void
 httpsAccept(int sock, int newfd, ConnectionDetail *details,
             comm_err_t flag, int xerrno, void *data)
 {
     https_port_list *s = (https_port_list *)data;
-    SSL_CTX *sslContext = s->sslContext;
+    SSL_CTX *sslContext = s->staticSslContext.get();
 
     if (flag != COMM_OK) {
         errno = xerrno;
         debugs(33, 1, "httpsAccept: FD " << sock << ": accept failure: " << xstrerr(xerrno));
         return;
     }
 
     SSL *ssl = NULL;
     if (!(ssl = httpsCreate(newfd, details, sslContext)))
         return;
 
     debugs(33, 5, "httpsAccept: FD " << newfd << " accepted, starting SSL negotiation.");
     fd_note(newfd, "client https connect");
     ConnStateData *connState = connStateCreate(details->peer, details->me,
                                newfd, &s->http);
     typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
     AsyncCall::Pointer call = JobCallback(33, 5,
                                           Dialer, connState, ConnStateData::connStateClosed);
     comm_add_close_handler(newfd, call);
 
@@ -3379,73 +3391,175 @@
     if (Ident::TheConfig.identLookup) {
         ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
         identChecklist.src_addr = details->peer;
         identChecklist.my_addr = details->me;
         if (identChecklist.fastCheck())
             Ident::Start(details->me, details->peer, clientIdentDone, connState);
     }
 #endif
 
     if (s->http.tcp_keepalive.enabled) {
         commSetTcpKeepalive(newfd, s->http.tcp_keepalive.idle, s->http.tcp_keepalive.interval, s->http.tcp_keepalive.timeout);
     }
 
     commSetSelect(newfd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
 
     clientdbEstablished(details->peer, 1);
 
     incoming_sockets_accepted++;
 }
 
+void
+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, 1, 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 " << sslHostName << " is incorrect");
+        } else {
+            if (reply_message.getCode() != "ok") {
+                debugs(33, 5, HERE << "Certificate for " << sslHostName << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
+            } else {
+                debugs(33, 5, HERE << "Certificate for " << sslHostName << " was successfully recieved from ssl_crtd");
+                getSslContextDone(Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str()), true);
+                return;
+            }
+        }
+    }
+    getSslContextDone(NULL);
+}
+
 bool
-ConnStateData::switchToHttps()
+ConnStateData::getSslContextStart()
 {
-    assert(!switchedToHttps_);
+    char const * host = sslHostName.termedBuf();
+    if (port->generateHostCertificates && host && strcmp(host, "") != 0) {
+        debugs(33, 5, HERE << "Finding SSL certificate for " << host << " in cache");
+        Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
+        SSL_CTX * dynCtx = ssl_ctx_cache.find(host);
+        if (dynCtx) {
+            debugs(33, 5, HERE << "SSL certificate for " << host << " have found in cache");
+            if (Ssl::verifySslCertificateDate(dynCtx)) {
+                debugs(33, 5, HERE << "Cached SSL certificate for " << host << " is valid");
+                return getSslContextDone(dynCtx);
+            } else {
+                debugs(33, 5, HERE << "Cached SSL certificate for " << host << " is out of date. Delete this certificate from cache");
+                ssl_ctx_cache.remove(host);
+            }
+        } else {
+            debugs(33, 5, HERE << "SSL certificate for " << host << " haven't found in cache");
+        }
 
-    //HTTPMSGLOCK(currentobject->http->request);
-    assert(areAllContextsForThisConnection());
-    freeAllContexts();
-    //currentobject->connIsFinished();
+#ifdef USE_SSL_CRTD
+        debugs(33, 5, HERE << "Generating SSL certificate for " << host << " using ssl_crtd.");
+        Ssl::CrtdMessage request_message;
+        request_message.setCode(Ssl::CrtdMessage::code_new_certificate);
+        Ssl::CrtdMessage::BodyParams map;
+        map.insert(std::make_pair(Ssl::CrtdMessage::param_host, host));
+        std::string bufferToWrite;
+        Ssl::writeCertAndPrivateKeyToMemory(port->signingCert, port->signPkey, bufferToWrite);
+        request_message.composeBody(map, bufferToWrite);
+        Ssl::Helper::GetInstance()->sslSubmit(request_message, sslCrtdHandleReplyWrapper, this);
+        return true;
+#else
+        debugs(33, 5, HERE << "Generating SSL certificate for " << host);
+        dynCtx = generateSslContext(host, port->signingCert, port->signPkey);
+        return getSslContextDone(dynCtx, true);
+#endif //USE_SSL_CRTD
+    }
+    return getSslContextDone(NULL);
+}
 
-    debugs(33, 5, HERE << "converting FD " << fd << " to SSL");
+bool
+ConnStateData::getSslContextDone(SSL_CTX * sslContext, bool isNew)
+{
+    // Try to add generated ssl context to storage.
+    if (port->generateHostCertificates && isNew) {
+        Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
+        if (sslContext && sslHostName != "") {
+            if (!ssl_ctx_cache.add(sslHostName.termedBuf(), sslContext)) {
+                // If it is not in storage delete after using. Else storage deleted it.
+                fd_table[fd].dynamicSslContext = sslContext;
+            }
+        } else {
+            debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslHostName);
+        }
+    }
+
+    // If generated ssl context = NULL, try to use static ssl context.
+    if (!sslContext) {
+        if (!port->staticSslContext) {
+            debugs(83, 1, "Closing SSL FD " << fd << " as lacking SSL context");
+            comm_close(fd);
+            return false;
+        } else {
+            debugs(33, 5, HERE << "Using static ssl context.");
+            sslContext = port->staticSslContext.get();
+        }
+    }
 
     // fake a ConnectionDetail object; XXX: make ConnState a ConnectionDetail?
     ConnectionDetail detail;
     detail.me = me;
     detail.peer = peer;
 
-    SSL_CTX *sslContext = port->sslContext;
     SSL *ssl = NULL;
     if (!(ssl = httpsCreate(fd, &detail, sslContext)))
         return false;
 
     // commSetTimeout() was called for this request before we switched.
 
     // Disable the client read handler until peer selection is complete
     commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
 
     commSetSelect(fd, COMM_SELECT_READ, clientNegotiateSSL, this, 0);
 
     switchedToHttps_ = true;
     return true;
 }
 
+bool
+ConnStateData::switchToHttps(const char *host)
+{
+    assert(!switchedToHttps_);
+
+    sslHostName = host;
+
+    //HTTPMSGLOCK(currentobject->http->request);
+    assert(areAllContextsForThisConnection());
+    freeAllContexts();
+    //currentobject->connIsFinished();
+
+    debugs(33, 5, HERE << "converting FD " << fd << " to SSL");
+
+    return getSslContextStart();
+}
+
 #endif /* USE_SSL */
 
 /// check FD after clientHttp[s]ConnectionOpened, adjust HttpSockets as needed
 static bool
 OpenedHttpSocket(int fd, const char *msgIfFail)
 {
     if (fd < 0) {
         Must(NHttpSockets > 0); // we tried to open some
         --NHttpSockets; // there will be fewer sockets than planned
         Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
 
         if (!NHttpSockets) // we could not open any listen sockets at all
             fatal(msgIfFail);
 
         return false;
     }
     return true;
 }
 
 /// find any unused HttpSockets[] slot and store fd there or return false
@@ -3459,48 +3573,55 @@
     }
     return found;
 }
 
 static void
 clientHttpConnectionsOpen(void)
 {
     http_port_list *s = NULL;
 #if USE_SSL
     int bumpCount = 0; // counts http_ports with sslBump option
 #endif
 
     for (s = Config.Sockaddr.http; s; s = s->next) {
         if (MAXHTTPPORTS == NHttpSockets) {
             debugs(1, 1, "WARNING: You have too many 'http_port' lines.");
             debugs(1, 1, "         The limit is " << MAXHTTPPORTS);
             continue;
         }
 
 #if USE_SSL
-        if (s->sslBump && s->sslContext == NULL) {
+        if (s->sslBump &&
+                !s->staticSslContext && !s->generateHostCertificates) {
             debugs(1, 1, "Will not bump SSL at http_port " <<
                    s->http.s << " due to SSL initialization failure.");
             s->sslBump = 0;
         }
-        if (s->sslBump)
+        if (s->sslBump) {
             ++bumpCount;
+            // Create ssl_ctx cache for this port.
+            Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->dynamicCertMemCacheSize == std::numeric_limits<size_t>::max() ? 4194304 : s->dynamicCertMemCacheSize);
+        }
 #endif
+#if USE_SSL_CRTD
+        Ssl::Helper::GetInstance();
+#endif //USE_SSL_CRTD
 
         /* AYJ: 2009-12-27: bit bumpy. new ListenStateData(...) should be doing all the Comm:: stuff ... */
 
         const int openFlags = COMM_NONBLOCKING |
                               (s->spoof_client_ip ? COMM_TRANSPARENT : 0);
 
         AsyncCall::Pointer callback = asyncCall(33,2,
                                                 "clientHttpConnectionOpened",
                                                 ListeningStartedDialer(&clientHttpConnectionOpened, s));
         Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->s, openFlags,
                             Ipc::fdnHttpSocket, callback);
 
         HttpSockets[NHttpSockets++] = -1; // set in clientHttpConnectionOpened
     }
 
 #if USE_SSL
     if (bumpCount && !Config.accessList.ssl_bump)
         debugs(33, 1, "WARNING: http_port(s) with SslBump found, but no " <<
                std::endl << "\tssl_bump ACL configured. No requests will be " <<
                "bumped.");
@@ -3528,41 +3649,41 @@
            (s->accel ? " accelerated" : "")
            << " HTTP connections at " << s->s
            << ", FD " << fd << "." );
 
     Must(AddOpenedHttpSocket(fd)); // otherwise, we have received a fd we did not ask for
 }
 
 #if USE_SSL
 static void
 clientHttpsConnectionsOpen(void)
 {
     https_port_list *s;
 
     for (s = Config.Sockaddr.https; s; s = (https_port_list *)s->http.next) {
         if (MAXHTTPPORTS == NHttpSockets) {
             debugs(1, 1, "Ignoring 'https_port' lines exceeding the limit.");
             debugs(1, 1, "The limit is " << MAXHTTPPORTS << " HTTPS ports.");
             continue;
         }
 
-        if (s->sslContext == NULL) {
+        if (!s->staticSslContext) {
             debugs(1, 1, "Ignoring https_port " << s->http.s <<
                    " due to SSL initialization failure.");
             continue;
         }
 
         AsyncCall::Pointer call = asyncCall(33, 2, "clientHttpsConnectionOpened",
                                             ListeningStartedDialer(&clientHttpsConnectionOpened, &s->http));
 
         Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->http.s, COMM_NONBLOCKING,
                             Ipc::fdnHttpsSocket, call);
 
         HttpSockets[NHttpSockets++] = -1;
     }
 }
 
 /// process clientHttpsConnectionsOpen result
 static void
 clientHttpsConnectionOpened(int fd, int, http_port_list *s)
 {
     if (!OpenedHttpSocket(fd, "Cannot open HTTPS Port"))

=== modified file 'src/client_side.h'
--- src/client_side.h	2010-09-10 20:56:24 +0000
+++ src/client_side.h	2010-11-09 22:29:49 +0000
@@ -258,56 +258,70 @@
     int validatePinnedConnection(HttpRequest *request, const struct peer *peer);
     /**
      * returts the pinned peer if exists, NULL otherwise
      */
     struct peer *pinnedPeer() const {return pinning.peer;}
     bool pinnedAuth() const {return pinning.auth;}
 
     // pining related comm callbacks
     void clientPinnedConnectionClosed(const CommCloseCbParams &io);
 
     // comm callbacks
     void clientReadRequest(const CommIoCbParams &io);
     void connStateClosed(const CommCloseCbParams &io);
     void requestTimeout(const CommTimeoutCbParams &params);
 
     // AsyncJob API
     virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
     virtual void swanSong();
 
 #if USE_SSL
-    bool switchToHttps();
+    /// Start to create dynamic SSL_CTX for host or uses static port SSL context.
+    bool getSslContextStart();
+    /**
+     * Done create dynamic ssl certificate.
+     *
+     * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
+     */
+    bool getSslContextDone(SSL_CTX * sslContext, bool isNew = false);
+    /// Callback function. It is called when squid receive message from ssl_crtd.
+    static void sslCrtdHandleReplyWrapper(void *data, char *reply);
+    /// Proccess response from ssl_crtd.
+    void sslCrtdHandleReply(const char * reply);
+
+    bool switchToHttps(const char *host);
     bool switchedToHttps() const { return switchedToHttps_; }
 #else
     bool switchedToHttps() const { return false; }
 #endif
 
 protected:
     void startDechunkingRequest();
     void finishDechunkingRequest(bool withSuccess);
     void abortChunkedRequestBody(const err_type error);
     err_type handleChunkedRequestBody(size_t &putSize);
 
 private:
     int connReadWasError(comm_err_t flag, int size, int xerrno);
     int connFinishedWithConn(int size);
     void clientMaybeReadData(int do_next_read);
     void clientAfterReadingRequests(int do_next_read);
 
 private:
     CBDATA_CLASS2(ConnStateData);
     bool transparent_;
     bool closing_;
 
     bool switchedToHttps_;
+    String sslHostName; ///< Host name for SSL certificate generation
     AsyncCall::Pointer reader; ///< set when we are reading
     BodyPipe::Pointer bodyPipe; // set when we are reading request body
 };
 
 /* convenience class while splitting up body handling */
 /* temporary existence only - on stack use expected */
 
 void setLogUri(ClientHttpRequest * http, char const *uri);
 
 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
 
 #endif /* SQUID_CLIENTSIDE_H */

=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2010-10-21 08:13:41 +0000
+++ src/client_side_request.cc	2010-11-09 22:29:49 +0000
@@ -1172,41 +1172,41 @@
 {
     ClientHttpRequest *r = static_cast<ClientHttpRequest*>(data);
     debugs(85, 5, HERE << "responded to CONNECT: " << r << " ? " << errflag);
 
     assert(r && cbdataReferenceValid(r));
     r->sslBumpEstablish(errflag);
 }
 
 void
 ClientHttpRequest::sslBumpEstablish(comm_err_t errflag)
 {
     // Bail out quickly on COMM_ERR_CLOSING - close handlers will tidy up
     if (errflag == COMM_ERR_CLOSING)
         return;
 
     if (errflag) {
         getConn()->startClosing("CONNECT response failure in SslBump");
         return;
     }
 
-    getConn()->switchToHttps();
+    getConn()->switchToHttps(request->GetHost());
 }
 
 void
 ClientHttpRequest::sslBumpStart()
 {
     debugs(85, 5, HERE << "ClientHttpRequest::sslBumpStart");
 
     // send an HTTP 200 response to kick client SSL negotiation
     const int fd = getConn()->fd;
     debugs(33, 7, HERE << "Confirming CONNECT tunnel on FD " << fd);
 
     // TODO: Unify with tunnel.cc and add a Server(?) header
     static const char *const conn_established =
         "HTTP/1.0 200 Connection established\r\n\r\n";
     comm_write(fd, conn_established, strlen(conn_established),
                &SslBumpEstablish, this, NULL);
 }
 
 #endif
 

=== modified file 'src/comm.cc'
--- src/comm.cc	2010-11-03 16:28:34 +0000
+++ src/comm.cc	2010-11-09 22:29:49 +0000
@@ -1523,40 +1523,44 @@
 #if USE_SSL
     fde *F = &fd_table[fd];
     if (F->ssl)
         ssl_shutdown_method(fd);
 
 #endif
 
 }
 
 void
 comm_close_complete(int fd, void *data)
 {
 #if USE_SSL
     fde *F = &fd_table[fd];
 
     if (F->ssl) {
         SSL_free(F->ssl);
         F->ssl = NULL;
     }
 
+    if (F->dynamicSslContext) {
+        SSL_CTX_free(F->dynamicSslContext);
+        F->dynamicSslContext = NULL;
+    }
 #endif
     fd_close(fd);		/* update fdstat */
 
     close(fd);
 
     statCounter.syscalls.sock.closes++;
 
     /* When an fd closes, give accept() a chance, if need be */
     Comm::AcceptLimiter::Instance().kick();
 }
 
 /*
  * Close the socket fd.
  *
  * + call write handlers with ERR_CLOSING
  * + call read handlers with ERR_CLOSING
  * + call closing handlers
  *
  * NOTE: COMM_ERR_CLOSING will NOT be called for CommReads' sitting in a
  * DeferredReadManager.

=== modified file 'src/fde.h'
--- src/fde.h	2010-10-25 21:49:58 +0000
+++ src/fde.h	2010-11-09 22:29:49 +0000
@@ -96,40 +96,41 @@
     ClientInfo * clientInfo;/* pointer to client info used in client write limiter or NULL if not present */
 #endif
     unsigned epoll_state;
 
     struct _fde_disk disk;
     PF *read_handler;
     void *read_data;
     PF *write_handler;
     void *write_data;
     AsyncCall::Pointer timeoutHandler;
     time_t timeout;
     time_t writeStart;
     void *lifetime_data;
     AsyncCall::Pointer closeHandler;
     AsyncCall::Pointer halfClosedReader; /// read handler for half-closed fds
     CommWriteStateData *wstate;         /* State data for comm_write */
     READ_HANDLER *read_method;
     WRITE_HANDLER *write_method;
 #if USE_SSL
     SSL *ssl;
+    SSL_CTX *dynamicSslContext; ///< cached and then freed when fd is closed
 #endif
 #ifdef _SQUID_MSWIN_
     struct {
         long handle;
     } win32;
 #endif
     tos_t tosFromServer;                /**< Stores the TOS flags of the packets from the remote server.
                                             See FwdState::dispatch(). Note that this differs to
                                             tosToServer in that this is the value we *receive* from the,
                                             connection, whereas tosToServer is the value to set on packets
                                             *leaving* Squid.  */
     unsigned int nfmarkFromServer;      /**< Stores the Netfilter mark value of the connection from the remote
                                             server. See FwdState::dispatch(). Note that this differs to
                                             nfmarkToServer in that this is the value we *receive* from the,
                                             connection, whereas nfmarkToServer is the value to set on packets
                                             *leaving* Squid.   */
 
 private:
     /** Clear the fde class back to NULL equivalent. */
     inline void clear() {
@@ -149,35 +150,36 @@
 #if DELAY_POOLS
         clientInfo = NULL;
 #endif
         epoll_state = 0;
         memset(&disk, 0, sizeof(_fde_disk));
         read_handler = NULL;
         read_data = NULL;
         write_handler = NULL;
         write_data = NULL;
         timeoutHandler = NULL;
         timeout = 0;
         writeStart = 0;
         lifetime_data = NULL;
         closeHandler = NULL;
         halfClosedReader = NULL;
         wstate = NULL;
         read_method = NULL;
         write_method = NULL;
 #if USE_SSL
         ssl = NULL;
+        dynamicSslContext = NULL;
 #endif
 #ifdef _SQUID_MSWIN_
         win32.handle = NULL;
 #endif
         tosFromServer = '\0';
         nfmarkFromServer = 0;
     }
 };
 
 SQUIDCEXTERN int fdNFree(void);
 
 #define FD_READ_METHOD(fd, buf, len) (*fd_table[fd].read_method)(fd, buf, len)
 #define FD_WRITE_METHOD(fd, buf, len) (*fd_table[fd].write_method)(fd, buf, len)
 
 #endif /* SQUID_FDE_H */

=== modified file 'src/helper.cc'
--- src/helper.cc	2010-09-20 19:27:24 +0000
+++ src/helper.cc	2010-11-09 22:29:49 +0000
@@ -775,40 +775,89 @@
 
     if ((r = srv->request)) {
         void *cbdata;
 
         if (cbdataReferenceValidDone(r->data, &cbdata))
             r->callback(cbdata, srv, NULL);
 
         helperStatefulRequestFree(r);
 
         srv->request = NULL;
     }
 
     if (srv->data != NULL)
         hlp->datapool->freeOne(srv->data);
 
     cbdataReferenceDone(srv->parent);
 
     cbdataFree(srv);
 }
 
+/// Calls back with a pointer to the buffer with the helper output
+static void helperReturnBuffer(int request_number, helper_server * srv, helper * hlp, char * msg, char * msg_end)
+{
+    helper_request *r = srv->requests[request_number];
+    if (r) {
+        HLPCB *callback = r->callback;
+
+        srv->requests[request_number] = NULL;
+
+        r->callback = NULL;
+
+        void *cbdata = NULL;
+        if (cbdataReferenceValidDone(r->data, &cbdata))
+            callback(cbdata, msg);
+
+        srv->stats.pending--;
+
+        hlp->stats.replies++;
+
+        srv->answer_time = current_time;
+
+        srv->dispatch_time = r->dispatch_time;
+
+        hlp->stats.avg_svc_time =
+            Math::intAverage(hlp->stats.avg_svc_time,
+                       tvSubMsec(r->dispatch_time, current_time),
+                       hlp->stats.replies, REDIRECT_AV_FACTOR);
+
+        helperRequestFree(r);
+    } else {
+        debugs(84, 1, "helperHandleRead: unexpected reply on channel " <<
+               request_number << " from " << hlp->id_name << " #" << srv->index + 1 <<
+               " '" << srv->rbuf << "'");
+    }
+    srv->roffset -= (msg_end - srv->rbuf);
+    memmove(srv->rbuf, msg_end, srv->roffset + 1);
+
+    if (!srv->flags.shutdown) {
+        helperKickQueue(hlp);
+    } else if (!srv->flags.closing && !srv->stats.pending) {
+        int wfd = srv->wfd;
+        srv->wfd = -1;
+        if (srv->rfd == wfd)
+            srv->rfd = -1;
+        srv->flags.closing=1;
+        comm_close(wfd);
+        return;
+    }
+}
 
 static void
 helperHandleRead(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
 {
     char *t = NULL;
     helper_server *srv = (helper_server *)data;
     helper *hlp = srv->parent;
     assert(cbdataReferenceValid(data));
 
     /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
 
     if (flag == COMM_ERR_CLOSING) {
         return;
     }
 
     assert(fd == srv->rfd);
 
     debugs(84, 5, "helperHandleRead: " << len << " bytes from " << hlp->id_name << " #" << srv->index + 1);
 
     if (flag != COMM_OK || len <= 0) {
@@ -817,103 +866,63 @@
 
         comm_close(fd);
 
         return;
     }
 
     srv->roffset += len;
     srv->rbuf[srv->roffset] = '\0';
     debugs(84, 9, "helperHandleRead: '" << srv->rbuf << "'");
 
     if (!srv->stats.pending) {
         /* someone spoke without being spoken to */
         debugs(84, 1, "helperHandleRead: unexpected read from " <<
                hlp->id_name << " #" << srv->index + 1 << ", " << (int)len <<
                " bytes '" << srv->rbuf << "'");
 
         srv->roffset = 0;
         srv->rbuf[0] = '\0';
     }
 
-    while ((t = strchr(srv->rbuf, '\n'))) {
-        /* end of reply found */
-        helper_request *r;
-        char *msg = srv->rbuf;
-        int i = 0;
-        debugs(84, 3, "helperHandleRead: end of reply found");
-
-        if (t > srv->rbuf && t[-1] == '\r')
-            t[-1] = '\0';
-
-        *t++ = '\0';
-
-        if (hlp->childs.concurrency) {
-            i = strtol(msg, &msg, 10);
-
-            while (*msg && xisspace(*msg))
-                msg++;
-        }
-
-        r = srv->requests[i];
-
-        if (r) {
-            HLPCB *callback = r->callback;
-            void *cbdata;
-
-            srv->requests[i] = NULL;
-
-            r->callback = NULL;
-
-            if (cbdataReferenceValidDone(r->data, &cbdata))
-                callback(cbdata, msg);
-
-            srv->stats.pending--;
-
-            hlp->stats.replies++;
-
-            srv->answer_time = current_time;
-
-            srv->dispatch_time = r->dispatch_time;
-
-            hlp->stats.avg_svc_time = Math::intAverage(hlp->stats.avg_svc_time, tvSubMsec(r->dispatch_time, current_time), hlp->stats.replies, REDIRECT_AV_FACTOR);
-
-            helperRequestFree(r);
-        } else {
-            debugs(84, 1, "helperHandleRead: unexpected reply on channel " <<
-                   i << " from " << hlp->id_name << " #" << srv->index + 1 <<
-                   " '" << srv->rbuf << "'");
-
-        }
-
-        srv->roffset -= (t - srv->rbuf);
-        memmove(srv->rbuf, t, srv->roffset + 1);
+    if (hlp->return_full_reply) {
+        debugs(84, 3, HERE << "Return entire buffer");
+        helperReturnBuffer(0, srv, hlp, srv->rbuf, srv->rbuf + srv->roffset);
+    } else {
+        while ((t = strchr(srv->rbuf, '\n'))) {
+            /* end of reply found */
+            char *msg = srv->rbuf;
+            int i = 0;
+            debugs(84, 3, "helperHandleRead: end of reply found");
+
+            if (t > srv->rbuf && t[-1] == '\r')
+                t[-1] = '\0';
+
+            *t++ = '\0';
+
+            if (hlp->childs.concurrency) {
+                i = strtol(msg, &msg, 10);
+
+                while (*msg && xisspace(*msg))
+                    msg++;
+            }
 
-        if (!srv->flags.shutdown) {
-            helperKickQueue(hlp);
-        } else if (!srv->flags.closing && !srv->stats.pending) {
-            int wfd = srv->wfd;
-            srv->wfd = -1;
-            if (srv->rfd == wfd)
-                srv->rfd = -1;
-            srv->flags.closing=1;
-            comm_close(wfd);
-            return;
+            helperReturnBuffer(i, srv, hlp, msg, t);
         }
     }
 
     if (srv->rfd != -1)
         comm_read(fd, srv->rbuf + srv->roffset, srv->rbuf_sz - srv->roffset - 1, helperHandleRead, srv);
 }
 
 static void
 helperStatefulHandleRead(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
 {
     char *t = NULL;
     helper_stateful_server *srv = (helper_stateful_server *)data;
     helper_stateful_request *r;
     statefulhelper *hlp = srv->parent;
     assert(cbdataReferenceValid(data));
 
     /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
 
     if (flag == COMM_ERR_CLOSING) {
         return;

=== modified file 'src/helper.h'
--- src/helper.h	2010-05-02 19:32:42 +0000
+++ src/helper.h	2010-11-09 22:29:49 +0000
@@ -52,40 +52,42 @@
     inline helper(const char *name) : cmdline(NULL), id_name(name) {};
     ~helper();
 
 public:
     wordlist *cmdline;
     dlink_list servers;
     dlink_list queue;
     const char *id_name;
     HelperChildConfig childs;    ///< Configuration settings for number running.
     int ipc_type;
     Ip::Address addr;
     time_t last_queue_warn;
     time_t last_restart;
 
     struct _stats {
         int requests;
         int replies;
         int queue_size;
         int avg_svc_time;
     } stats;
+    /// True if callback expects the whole helper output, as a c-string.
+    bool return_full_reply;
 
 private:
     CBDATA_CLASS2(helper);
 };
 
 class statefulhelper : public helper
 {
 public:
     inline statefulhelper(const char *name) : helper(name) {};
     inline ~statefulhelper() {};
 
 public:
     MemAllocator *datapool;
     HLPSAVAIL *IsAvailable;
     HLPSONEQ *OnEmptyQueue;
 
 private:
     CBDATA_CLASS2(statefulhelper);
 };
 

=== modified file 'src/main.cc'
--- src/main.cc	2010-11-01 05:44:28 +0000
+++ src/main.cc	2010-11-09 22:29:49 +0000
@@ -71,40 +71,49 @@
 #include "comm_poll.h"
 #endif
 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
 #include "comm_select.h"
 #endif
 #include "SquidTime.h"
 #include "SwapDir.h"
 #include "forward.h"
 #include "MemPool.h"
 #include "icmp/IcmpSquid.h"
 #include "icmp/net_db.h"
 
 #if DELAY_POOLS
 #include "ClientDelayConfig.h"
 #endif
 
 #if USE_LOADABLE_MODULES
 #include "LoadableModules.h"
 #endif
 
+#if USE_SSL_CRTD
+#include "ssl/helper.h"
+#include "ssl/certificate_db.h"
+#endif
+
+#if USE_SSL
+#include "ssl/context_storage.h"
+#endif
+
 #if ICAP_CLIENT
 #include "adaptation/icap/Config.h"
 #endif
 #if USE_ECAP
 #include "adaptation/ecap/Config.h"
 #endif
 #if USE_ADAPTATION
 #include "adaptation/Config.h"
 #endif
 #if USE_SQUID_ESI
 #include "esi/Module.h"
 #endif
 #include "fs/Module.h"
 
 #if HAVE_PATHS_H
 #include <paths.h>
 #endif
 
 #if USE_WIN32_SERVICE
 #include "squid_windows.h"
@@ -716,41 +725,46 @@
     reconfiguring = 1;
 
     // Initiate asynchronous closing sequence
     serverConnectionsClose();
     icpConnectionClose();
 #if USE_HTCP
 
     htcpSocketClose();
 #endif
 #if SQUID_SNMP
 
     snmpConnectionClose();
 #endif
 #if USE_DNSSERVERS
 
     dnsShutdown();
 #else
 
     idnsShutdown();
 #endif
-
+#if USE_SSL_CRTD
+    Ssl::Helper::GetInstance()->Shutdown();
+#endif
+#if USE_SSL
+    Ssl::TheGlobalContextStorage.reconfigureStart();
+#endif
     redirectShutdown();
     authenticateReset();
     externalAclShutdown();
     storeDirCloseSwapLogs();
     storeLogClose();
     accessLogClose();
 #if ICAP_CLIENT
     icapLogClose();
 #endif
     useragentLogClose();
     refererCloseLog();
 
     eventAdd("mainReconfigureFinish", &mainReconfigureFinish, NULL, 0, 1,
              false);
 }
 
 static void
 mainReconfigureFinish(void *)
 {
     debugs(1, 3, "finishing reconfiguring");
@@ -802,40 +816,43 @@
 #if USE_ECAP
     Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
     enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
 #endif
     Adaptation::Config::Finalize(enableAdaptation);
 #endif
 
 #if ICAP_CLIENT
     icapLogOpen();
 #endif
     storeLogOpen();
     useragentOpenLog();
     refererOpenLog();
 #if USE_DNSSERVERS
 
     dnsInit();
 #else
 
     idnsInit();
 #endif
+#if USE_SSL_CRTD
+    Ssl::Helper::GetInstance()->Init();
+#endif
 
     redirectInit();
     authenticateInit(&Auth::TheConfig);
     externalAclInit();
 
     if (IamPrimaryProcess()) {
 #if USE_WCCP
 
         wccpInit();
 #endif
 #if USE_WCCPv2
 
         wccp2Init();
 #endif
     }
 
     serverConnectionsOpen();
 
     neighbors_init();
 
@@ -1795,41 +1812,43 @@
 SquidShutdown()
 {
     /* XXX: This function is called after the main loop has quit, which
      * means that no AsyncCalls would be called, including close handlers.
      * TODO: We need to close/shut/free everything that needs calls before
      * exiting the loop.
      */
 
 #if USE_WIN32_SERVICE
     WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
 #endif
 
     debugs(1, 1, "Shutting down...");
 #if USE_DNSSERVERS
 
     dnsShutdown();
 #else
 
     idnsShutdown();
 #endif
-
+#if USE_SSL_CRTD
+    Ssl::Helper::GetInstance()->Shutdown();
+#endif
     redirectShutdown();
     externalAclShutdown();
     icpConnectionClose();
 #if USE_HTCP
 
     htcpSocketClose();
 #endif
 #if SQUID_SNMP
 
     snmpConnectionClose();
 #endif
 #if USE_WCCP
 
     wccpConnectionClose();
 #endif
 #if USE_WCCPv2
 
     wccp2ConnectionClose();
 #endif
 

=== modified file 'src/squid.h'
--- src/squid.h	2010-11-01 05:44:28 +0000
+++ src/squid.h	2010-11-09 22:29:49 +0000
@@ -138,41 +138,41 @@
 
 #ifndef MAXPATHLEN
 #define MAXPATHLEN SQUID_MAXPATHLEN
 #endif
 
 #if LEAK_CHECK_MODE
 #define LOCAL_ARRAY(type,name,size) \
         static type *local_##name=NULL; \
         type *name = local_##name ? local_##name : \
                 ( local_##name = (type *)xcalloc(size, sizeof(type)) )
 #else
 #define LOCAL_ARRAY(type,name,size) static type name[size]
 #endif
 
 #if defined(_SQUID_NEXT_) && !defined(S_ISDIR)
 #define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR))
 #endif
 
 #include "md5.h"
 #if USE_SSL
-#include "ssl_support.h"
+#include "ssl/support.h"
 #endif
 #if SQUID_SNMP
 #include "cache_snmp.h"
 #endif
 #include "hash.h"
 #include "rfc3596.h"
 #include "defines.h"
 #include "enums.h"
 #include "typedefs.h"
 #include "util.h"
 #include "profiler/Profiler.h"
 #include "MemPool.h"
 #include "ip/Address.h"
 #include "structs.h"
 #include "protos.h"
 #include "globals.h"
 
 /*
  * I'm sick of having to keep doing this ..
  */

=== added directory 'src/ssl'
=== added file 'src/ssl/Makefile.am'
--- src/ssl/Makefile.am	1970-01-01 00:00:00 +0000
+++ src/ssl/Makefile.am	2010-11-10 14:36:16 +0000
@@ -0,0 +1,37 @@
+include $(top_srcdir)/src/Common.am
+include $(top_srcdir)/src/TestHeaders.am
+
+noinst_LTLIBRARIES = libsslsquid.la libsslutil.la
+
+EXTRA_PROGRAMS = \
+	ssl_crtd
+
+if USE_SSL_CRTD
+SSL_CRTD = ssl_crtd
+SSL_CRTD_SOURCE = \
+    helper.cc \
+    helper.h
+else
+SSL_CRTD =
+SSL_CRTD_SOURCE =
+endif
+
+libsslsquid_la_SOURCES = \
+	context_storage.cc \
+	context_storage.h
+
+libsslutil_la_SOURCES = \
+	support.cc \
+	support.h \
+	gadgets.cc \
+	gadgets.h \
+	crtd_message.cc \
+	crtd_message.h \
+	$(SSL_CRTD_SOURCE)
+
+libexec_PROGRAMS = \
+	$(SSL_CRTD)
+
+ssl_crtd_SOURCES = ssl_crtd.cc certificate_db.cc certificate_db.h
+
+ssl_crtd_LDADD = @SSLLIB@ -lsslutil -L$(top_builddir)/compat -lcompat-squid

=== added file 'src/ssl/certificate_db.cc'
--- src/ssl/certificate_db.cc	1970-01-01 00:00:00 +0000
+++ src/ssl/certificate_db.cc	2010-11-10 12:12:20 +0000
@@ -0,0 +1,477 @@
+/*
+ * $Id$
+ */
+
+#include "config.h"
+#include "ssl/certificate_db.h"
+#include <fstream>
+#include <stdexcept>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h>
+
+Ssl::FileLocker::FileLocker(std::string const & filename)
+        :    fd(-1)
+{
+#ifdef _SQUID_MSWIN_
+    hFile = CreateFile(TEXT(filename.c_str()), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile != INVALID_HANDLE_VALUE)
+        LockFile(hFile, 0, 0, 1, 0);
+#else
+    fd = open(filename.c_str(), 0);
+    if (fd != -1)
+        flock(fd, LOCK_EX);
+#endif
+}
+
+Ssl::FileLocker::~FileLocker()
+{
+#ifdef _SQUID_MSWIN_
+    if (hFile != INVALID_HANDLE_VALUE) {
+        UnlockFile(hFile, 0, 0, 1, 0);
+        CloseHandle(hFile);
+    }
+#else
+    if (fd != -1) {
+        flock(fd, LOCK_UN);
+        close(fd);
+    }
+#endif
+}
+
+Ssl::CertificateDb::Row::Row()
+        :   width(cnlNumber)
+{
+    row = new char *[width + 1];
+    for (size_t i = 0; i < width + 1; i++)
+        row[i] = NULL;
+}
+
+Ssl::CertificateDb::Row::~Row()
+{
+    if (row) {
+        for (size_t i = 0; i < width + 1; i++) {
+            delete[](row[i]);
+        }
+        delete[](row);
+    }
+}
+
+void Ssl::CertificateDb::Row::reset()
+{
+    row = NULL;
+}
+
+void Ssl::CertificateDb::Row::setValue(size_t cell, char const * value)
+{
+    assert(cell < width);
+    if (row[cell]) {
+        free(row[cell]);
+    }
+    if (value) {
+        row[cell] = static_cast<char *>(malloc(sizeof(char) * (strlen(value) + 1)));
+        memcpy(row[cell], value, sizeof(char) * (strlen(value) + 1));
+    } else
+        row[cell] = NULL;
+}
+
+char ** Ssl::CertificateDb::Row::getRow()
+{
+    return row;
+}
+
+unsigned long Ssl::CertificateDb::index_serial_hash(const char **a)
+{
+    const char *n = a[Ssl::CertificateDb::cnlSerial];
+    while (*n == '0') n++;
+    return lh_strhash(n);
+}
+
+int Ssl::CertificateDb::index_serial_cmp(const char **a, const char **b)
+{
+    const char *aa, *bb;
+    for (aa = a[Ssl::CertificateDb::cnlSerial]; *aa == '0'; aa++);
+    for (bb = b[Ssl::CertificateDb::cnlSerial]; *bb == '0'; bb++);
+    return strcmp(aa, bb);
+}
+
+unsigned long Ssl::CertificateDb::index_name_hash(const char **a)
+{
+    return(lh_strhash(a[Ssl::CertificateDb::cnlName]));
+}
+
+int Ssl::CertificateDb::index_name_cmp(const char **a, const char **b)
+{
+    return(strcmp(a[Ssl::CertificateDb::cnlName], b[CertificateDb::cnlName]));
+}
+
+const std::string Ssl::CertificateDb::serial_file("serial");
+const std::string Ssl::CertificateDb::db_file("index.txt");
+const std::string Ssl::CertificateDb::cert_dir("certs");
+const std::string Ssl::CertificateDb::size_file("size");
+const size_t Ssl::CertificateDb::min_db_size(4096);
+
+Ssl::CertificateDb::CertificateDb(std::string const & aDb_path, size_t aMax_db_size, size_t aFs_block_size)
+        :  db_path(aDb_path),
+        serial_full(aDb_path + "/" + serial_file),
+        db_full(aDb_path + "/" + db_file),
+        cert_full(aDb_path + "/" + cert_dir),
+        size_full(aDb_path + "/" + size_file),
+        db(NULL),
+        max_db_size(aMax_db_size),
+        fs_block_size(aFs_block_size),
+        enabled_disk_store(true)
+{
+    if (db_path.empty() && !max_db_size)
+        enabled_disk_store = false;
+    else if ((db_path.empty() && max_db_size) || (!db_path.empty() && !max_db_size))
+        throw std::runtime_error("ssl_crtd is missing the required parameter. There should be -s and -M parameters together.");
+    else
+        load();
+}
+
+bool Ssl::CertificateDb::find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
+{
+    FileLocker db_locker(db_full);
+    load();
+    return pure_find(host_name, cert, pkey);
+}
+
+bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
+{
+    FileLocker db_locker(db_full);
+    load();
+    if (!db || !cert || !pkey || min_db_size > max_db_size)
+        return false;
+    Row row;
+    ASN1_INTEGER * ai = X509_get_serialNumber(cert.get());
+    std::string serial_string;
+    Ssl::BIGNUM_Pointer serial(ASN1_INTEGER_to_BN(ai, NULL));
+    {
+        TidyPointer<char, tidyFree> hex_bn(BN_bn2hex(serial.get()));
+        serial_string = std::string(hex_bn.get());
+    }
+    row.setValue(cnlSerial, serial_string.c_str());
+    char ** rrow = TXT_DB_get_by_index(db.get(), cnlSerial, row.getRow());
+    if (rrow != NULL)
+        return false;
+
+    {
+        TidyPointer<char, tidyFree> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), NULL, 0));
+        if (pure_find(subject.get(), cert, pkey))
+            return true;
+    }
+    // check db size.
+    while (max_db_size < size()) {
+        if (!deleteInvalidCertificate())
+            break;
+    }
+
+    while (max_db_size < size()) {
+        deleteOldestCertificate();
+    }
+
+    row.setValue(cnlType, "V");
+    ASN1_UTCTIME * tm = X509_get_notAfter(cert.get());
+    row.setValue(cnlExp_date, std::string(reinterpret_cast<char *>(tm->data), tm->length).c_str());
+    row.setValue(cnlFile, "unknown");
+    {
+        TidyPointer<char, tidyFree> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), NULL, 0));
+        row.setValue(cnlName, subject.get());
+    }
+
+    if (!TXT_DB_insert(db.get(), row.getRow()))
+        return false;
+
+    row.reset();
+    std::string filename(cert_full + "/" + serial_string + ".pem");
+    FileLocker cert_locker(filename);
+    if (!writeCertAndPrivateKeyToFile(cert, pkey, filename.c_str()))
+        return false;
+    addSize(filename);
+
+    save();
+    return true;
+}
+
+BIGNUM * Ssl::CertificateDb::getCurrentSerialNumber()
+{
+    FileLocker serial_locker(serial_full);
+    // load serial number from file.
+    Ssl::BIO_Pointer file(BIO_new(BIO_s_file()));
+    if (!file)
+        return NULL;
+
+    if (BIO_rw_filename(file.get(), const_cast<char *>(serial_full.c_str())) <= 0)
+        return NULL;
+
+    Ssl::ASN1_INT_Pointer serial_ai(ASN1_INTEGER_new());
+    if (!serial_ai)
+        return NULL;
+
+    char buffer[1024];
+    if (!a2i_ASN1_INTEGER(file.get(), serial_ai.get(), buffer, sizeof(buffer)))
+        return NULL;
+
+    Ssl::BIGNUM_Pointer serial(ASN1_INTEGER_to_BN(serial_ai.get(), NULL));
+
+    if (!serial)
+        return NULL;
+
+    // increase serial number.
+    Ssl::BIGNUM_Pointer increased_serial(BN_dup(serial.get()));
+    if (!increased_serial)
+        return NULL;
+
+    BN_add_word(increased_serial.get(), 1);
+
+    // save increased serial number.
+    if (BIO_seek(file.get(), 0))
+        return NULL;
+
+    Ssl::ASN1_INT_Pointer increased_serial_ai(BN_to_ASN1_INTEGER(increased_serial.get(), NULL));
+    if (!increased_serial_ai)
+        return NULL;
+
+    i2a_ASN1_INTEGER(file.get(), increased_serial_ai.get());
+    BIO_puts(file.get(),"\n");
+
+    return serial.release();
+}
+
+void Ssl::CertificateDb::create(std::string const & db_path, int serial)
+{
+    if (db_path == "")
+        throw std::runtime_error("Path to db is empty");
+    std::string serial_full(db_path + "/" + serial_file);
+    std::string db_full(db_path + "/" + db_file);
+    std::string cert_full(db_path + "/" + cert_dir);
+    std::string size_full(db_path + "/" + size_file);
+
+#ifdef _SQUID_MSWIN_
+    if (mkdir(db_path.c_str()))
+#else
+    if (mkdir(db_path.c_str(), 0777))
+#endif
+        throw std::runtime_error("Cannot create " + db_path);
+
+#ifdef _SQUID_MSWIN_
+    if (mkdir(cert_full.c_str()))
+#else
+    if (mkdir(cert_full.c_str(), 0777))
+#endif
+        throw std::runtime_error("Cannot create " + cert_full);
+
+    Ssl::ASN1_INT_Pointer i(ASN1_INTEGER_new());
+    ASN1_INTEGER_set(i.get(), serial);
+
+    Ssl::BIO_Pointer file(BIO_new(BIO_s_file()));
+    if (!file)
+        throw std::runtime_error("SSL error");
+
+    if (BIO_write_filename(file.get(), const_cast<char *>(serial_full.c_str())) <= 0)
+        throw std::runtime_error("Cannot open " + cert_full + " to open");
+
+    i2a_ASN1_INTEGER(file.get(), i.get());
+
+    std::ofstream size(size_full.c_str());
+    if (size)
+        size << 0;
+    else
+        throw std::runtime_error("Cannot open " + size_full + " to open");
+    std::ofstream db(db_full.c_str());
+    if (!db)
+        throw std::runtime_error("Cannot open " + db_full + " to open");
+}
+
+void Ssl::CertificateDb::check(std::string const & db_path, size_t max_db_size)
+{
+    CertificateDb db(db_path, max_db_size, 0);
+}
+
+std::string Ssl::CertificateDb::getSNString()
+{
+    FileLocker serial_locker(serial_full);
+    std::ifstream file(serial_full.c_str());
+    if (!file)
+        return "";
+    std::string serial;
+    file >> serial;
+    return serial;
+}
+
+bool Ssl::CertificateDb::pure_find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
+{
+    if (!db)
+        return false;
+
+    Row row;
+    row.setValue(cnlName, host_name.c_str());
+
+    char **rrow = TXT_DB_get_by_index(db.get(), cnlName, row.getRow());
+    if (rrow == NULL)
+        return false;
+
+    if (!sslDateIsInTheFuture(rrow[cnlExp_date])) {
+        deleteByHostname(rrow[cnlName]);
+        return false;
+    }
+
+    // read cert and pkey from file.
+    std::string filename(cert_full + "/" + rrow[cnlSerial] + ".pem");
+    FileLocker cert_locker(filename);
+    readCertAndPrivateKeyFromFiles(cert, pkey, filename.c_str(), NULL);
+    if (!cert || !pkey)
+        return false;
+    return true;
+}
+
+size_t Ssl::CertificateDb::size()
+{
+    FileLocker size_locker(size_full);
+    return readSize();
+}
+
+void Ssl::CertificateDb::addSize(std::string const & filename)
+{
+    FileLocker size_locker(size_full);
+    writeSize(readSize() + getFileSize(filename));
+}
+
+void Ssl::CertificateDb::subSize(std::string const & filename)
+{
+    FileLocker size_locker(size_full);
+    writeSize(readSize() - getFileSize(filename));
+}
+
+size_t Ssl::CertificateDb::readSize()
+{
+    size_t db_size;
+    std::ifstream size_file(size_full.c_str());
+    if (!size_file && enabled_disk_store)
+        throw std::runtime_error("cannot read \"" + size_full + "\" file");
+    size_file >> db_size;
+    return db_size;
+}
+
+void Ssl::CertificateDb::writeSize(size_t db_size)
+{
+    std::ofstream size_file(size_full.c_str());
+    if (!size_file && enabled_disk_store)
+        throw std::runtime_error("cannot write \"" + size_full + "\" file");
+    size_file << db_size;
+}
+
+size_t Ssl::CertificateDb::getFileSize(std::string const & filename)
+{
+    std::ifstream file(filename.c_str(), std::ios::binary);
+    file.seekg(0, std::ios_base::end);
+    size_t file_size = file.tellg();
+    return ((file_size + fs_block_size - 1) / fs_block_size) * fs_block_size;
+}
+
+void Ssl::CertificateDb::load()
+{
+    // Load db from file.
+    Ssl::BIO_Pointer in(BIO_new(BIO_s_file()));
+    if (!in || BIO_read_filename(in.get(), db_full.c_str()) <= 0)
+        throw std::runtime_error("Uninitialized SSL certificate database directory: " + db_path + ". To initialize, run \"ssl_crtd -c -s " + db_path + "\".");
+
+    bool corrupt = false;
+    Ssl::TXT_DB_Pointer temp_db(TXT_DB_read(in.get(), cnlNumber));
+    if (!temp_db)
+        corrupt = true;
+
+    // Create indexes in db.
+    if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlSerial, NULL, LHASH_HASH_FN(index_serial_hash), LHASH_COMP_FN(index_serial_cmp)))
+        corrupt = true;
+
+    if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlName, NULL, LHASH_HASH_FN(index_name_hash), LHASH_COMP_FN(index_name_cmp)))
+        corrupt = true;
+
+    if (corrupt)
+        throw std::runtime_error("The SSL certificate database " + db_path + " is curruted. Please rebuild");
+
+    db.reset(temp_db.release());
+}
+
+void Ssl::CertificateDb::save()
+{
+    if (!db)
+        throw std::runtime_error("The certificates database is not loaded");;
+
+    // To save the db to file,  create a new BIO with BIO file methods.
+    Ssl::BIO_Pointer out(BIO_new(BIO_s_file()));
+    if (!out || !BIO_write_filename(out.get(), const_cast<char *>(db_full.c_str())))
+        throw std::runtime_error("Failed to initialize " + db_full + " file for writing");;
+
+    if (TXT_DB_write(out.get(), db.get()) < 0)
+        throw std::runtime_error("Failed to write " + db_full + " file");
+}
+
+bool Ssl::CertificateDb::deleteInvalidCertificate()
+{
+    if (!db)
+        return false;
+
+    bool removed_one = false;
+    for (int i = 0; i < sk_num(db.get()->data); i++) {
+        const char ** current_row = ((const char **)sk_value(db.get()->data, i));
+
+        if (!sslDateIsInTheFuture(current_row[cnlExp_date])) {
+            std::string filename(cert_full + "/" + current_row[cnlSerial] + ".pem");
+            FileLocker cert_locker(filename);
+            sk_delete(db.get()->data, i);
+            subSize(filename);
+            remove(filename.c_str());
+            removed_one = true;
+            break;
+        }
+    }
+
+    if (!removed_one)
+        return false;
+    return true;
+}
+
+bool Ssl::CertificateDb::deleteOldestCertificate()
+{
+    if (!db)
+        return false;
+
+    if (sk_num(db.get()->data) == 0)
+        return false;
+
+    std::string filename(cert_full + "/" + ((const char **)sk_value(db.get()->data, 0))[cnlSerial] + ".pem");
+    FileLocker cert_locker(filename);
+    sk_delete(db.get()->data, 0);
+    subSize(filename);
+    remove(filename.c_str());
+
+    return true;
+}
+
+bool Ssl::CertificateDb::deleteByHostname(std::string const & host)
+{
+    if (!db)
+        return false;
+
+    for (int i = 0; i < sk_num(db.get()->data); i++) {
+        const char ** current_row = ((const char **)sk_value(db.get()->data, i));
+        if (host == current_row[cnlName]) {
+            std::string filename(cert_full + "/" + current_row[cnlSerial] + ".pem");
+            FileLocker cert_locker(filename);
+            sk_delete(db.get()->data, i);
+            subSize(filename);
+            remove(filename.c_str());
+            return true;
+        }
+    }
+    return false;
+}
+
+bool Ssl::CertificateDb::IsEnabledDiskStore() const
+{
+    return enabled_disk_store;
+}

=== added file 'src/ssl/certificate_db.h'
--- src/ssl/certificate_db.h	1970-01-01 00:00:00 +0000
+++ src/ssl/certificate_db.h	2010-11-10 12:20:42 +0000
@@ -0,0 +1,137 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_SSL_CERTIFICATE_DB_H
+#define SQUID_SSL_CERTIFICATE_DB_H
+
+#include "ssl/gadgets.h"
+#include "ssl/support.h"
+#include <string>
+
+namespace Ssl
+{
+/// Cross platform file locker.
+class FileLocker
+{
+public:
+    /// Lock file
+    FileLocker(std::string const & aFilename);
+    /// Unlock file
+    ~FileLocker();
+private:
+#ifdef _SQUID_MSWIN_
+    HANDLE hFile; ///< Windows file handle.
+#else
+    int fd; ///< Linux file descriptor.
+#endif
+};
+
+/**
+ * Database class for storing ssl certificates and their private keys.
+ * A database consist by:
+ *     - A disk file to store current serial number
+ *     - A disk file to store the current database size
+ *     - A disk file which is a normal TXT_DB openssl database
+ *     - A directory under which the certificates and their private keys stored.
+ *  The database before used must initialized with CertificateDb::create static method.
+ */
+class CertificateDb
+{
+public:
+    /// Names of db columns.
+    enum Columns {
+        cnlType = 0,
+        cnlExp_date,
+        cnlRev_date,
+        cnlSerial,
+        cnlFile,
+        cnlName,
+        cnlNumber
+    };
+
+    /// A wrapper for OpenSSL database row of TXT_DB database.
+    class Row
+    {
+    public:
+        /// Create row wrapper.
+        Row();
+        /// Delete all row.
+        ~Row();
+        void setValue(size_t number, char const * value); ///< Set cell's value in row
+        char ** getRow(); ///< Raw row
+        void reset(); ///< Abandon row and don't free memory
+    private:
+        char **row; ///< Raw row
+        size_t width; ///< Number of cells in the row
+    };
+
+    CertificateDb(std::string const & db_path, size_t aMax_db_size, size_t aFs_block_size);
+    /// Find certificate and private key for host name
+    bool find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
+    /// Save certificate to disk.
+    bool addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
+    /// Get a serial number to use for generating a new certificate.
+    BIGNUM * getCurrentSerialNumber();
+    /// Create and initialize a database  under the  db_path
+    static void create(std::string const & db_path, int serial);
+    /// Check the database stored under the db_path.
+    static void check(std::string const & db_path, size_t max_db_size);
+    std::string getSNString(); ///< Get serial number as string.
+    bool IsEnabledDiskStore() const; ///< Check enabled of dist store.
+private:
+    void load(); ///< Load db from disk.
+    void save(); ///< Save db to disk.
+    size_t size(); ///< Get db size on disk in bytes.
+    /// Increase db size by the given file size and update size_file
+    void addSize(std::string const & filename);
+    /// Decrease db size by the given file size and update size_file
+    void subSize(std::string const & filename);
+    size_t readSize(); ///< Read size from file size_file
+    void writeSize(size_t db_size); ///< Write size to file size_file.
+    size_t getFileSize(std::string const & filename); ///< get file size on disk.
+    /// Only find certificate in current db and return it.
+    bool pure_find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
+
+    bool deleteInvalidCertificate(); ///< Delete invalid certificate.
+    bool deleteOldestCertificate(); ///< Delete oldest certificate.
+    bool deleteByHostname(std::string const & host); ///< Delete using host name.
+
+    /// Callback hash function for serials. Used to create TXT_DB index of serials.
+    static unsigned long index_serial_hash(const char **a);
+    /// Callback compare function for serials. Used to create TXT_DB index of serials.
+    static int index_serial_cmp(const char **a, const char **b);
+    /// Callback hash function for names. Used to create TXT_DB index of names..
+    static unsigned long index_name_hash(const char **a);
+    /// Callback compare function for  names. Used to create TXT_DB index of names..
+    static int index_name_cmp(const char **a, const char **b);
+
+    /// Definitions required by openssl, to use the index_* functions defined above
+    ///with TXT_DB_create_index.
+    static IMPLEMENT_LHASH_HASH_FN(index_serial_hash,const char **)
+    static IMPLEMENT_LHASH_COMP_FN(index_serial_cmp,const char **)
+    static IMPLEMENT_LHASH_HASH_FN(index_name_hash,const char **)
+    static IMPLEMENT_LHASH_COMP_FN(index_name_cmp,const char **)
+
+    static const std::string serial_file; ///< Base name of the file to store serial number.
+    static const std::string db_file; ///< Base name of the database index file.
+    static const std::string cert_dir; ///< Base name of the directory to store the certs.
+    static const std::string size_file; ///< Base name of the file to store db size.
+    /// Min size of disk db. If real size < min_db_size the  db will be disabled.
+    static const size_t min_db_size;
+
+    const std::string db_path; ///< The database directory.
+    const std::string serial_full; ///< Full path of the file to store serial number.
+    const std::string db_full; ///< Full path of the database index file.
+    const std::string cert_full; ///< Full path of the directory to store the certs.
+    const std::string size_full; ///< Full path of the file to store the db size.
+
+    TXT_DB_Pointer db; ///< Database with certificates info.
+    const size_t max_db_size; ///< Max size of db.
+    const size_t fs_block_size; ///< File system block size.
+
+    bool enabled_disk_store; ///< The storage on the disk is enabled.
+};
+
+} // namespace Ssl
+#endif // SQUID_SSL_CERTIFICATE_DB_H

=== added file 'src/ssl/context_storage.cc'
--- src/ssl/context_storage.cc	1970-01-01 00:00:00 +0000
+++ src/ssl/context_storage.cc	2010-11-10 11:45:33 +0000
@@ -0,0 +1,180 @@
+/*
+ * $Id$
+ */
+
+#include "Store.h"
+#include "StoreEntryStream.h"
+#include "ssl/context_storage.h"
+#include "mgr/Registration.h"
+#include <limits>
+
+Ssl::CertificateStorageAction::CertificateStorageAction(const Mgr::Command::Pointer &cmd)
+        :   Mgr::Action(cmd)
+{}
+
+Ssl::CertificateStorageAction::Pointer
+Ssl::CertificateStorageAction::Create(const Mgr::Command::Pointer &cmd)
+{
+    return new CertificateStorageAction(cmd);
+}
+
+void Ssl::CertificateStorageAction::dump (StoreEntry *sentry)
+{
+    StoreEntryStream stream(sentry);
+    const char delimiter = '\t';
+    const char endString = '\n';
+    // Page title.
+    stream << "Cached ssl certificates statistic.\n";
+    // Title of statistic table.
+    stream << "Port" << delimiter << "Max mem(KB)" << delimiter << "Cert number" << delimiter << "KB/cert" << delimiter << "Mem used(KB)" << delimiter << "Mem free(KB)" << endString;
+
+    // Add info for each port.
+    for (std::map<Ip::Address, LocalContextStorage *>::iterator i = TheGlobalContextStorage.storage.begin(); i != TheGlobalContextStorage.storage.end(); i++) {
+        stream << i->first << delimiter;
+        LocalContextStorage & ssl_store_policy(*(i->second));
+        stream << ssl_store_policy.max_memory / 1024 << delimiter;
+        stream << ssl_store_policy.memory_used / SSL_CTX_SIZE << delimiter;
+        stream << SSL_CTX_SIZE / 1024 << delimiter;
+        stream << ssl_store_policy.memory_used / 1024 << delimiter;
+        stream << (ssl_store_policy.max_memory - ssl_store_policy.memory_used) / 1024 << endString;
+    }
+    stream << endString;
+    stream.flush();
+}
+
+Ssl::LocalContextStorage::LocalContextStorage(size_t aMax_memory)
+        :   max_memory(aMax_memory), memory_used(0)
+{}
+
+Ssl::LocalContextStorage::~LocalContextStorage()
+{
+    for (QueueIterator i = lru_queue.begin(); i != lru_queue.end(); i++) {
+        delete *i;
+    }
+}
+
+SSL_CTX * Ssl::LocalContextStorage::add(const char * host_name, SSL_CTX * ssl_ctx)
+{
+    if (max_memory < SSL_CTX_SIZE) {
+        return NULL;
+    }
+    remove(host_name);
+    while (SSL_CTX_SIZE + memory_used > max_memory) {
+        purgeOne();
+    }
+    lru_queue.push_front(new Item(ssl_ctx, host_name));
+    storage.insert(MapPair(host_name, lru_queue.begin()));
+    memory_used += SSL_CTX_SIZE;
+    return ssl_ctx;
+}
+
+SSL_CTX * Ssl::LocalContextStorage::find(char const * host_name)
+{
+    MapIterator i = storage.find(host_name);
+    if (i == storage.end()) {
+        return NULL;
+    }
+    lru_queue.push_front(*(i->second));
+    lru_queue.erase(i->second);
+    i->second = lru_queue.begin();
+    return (*lru_queue.begin())->ssl_ctx;
+}
+
+void Ssl::LocalContextStorage::remove(char const * host_name)
+{
+    deleteAt(storage.find(host_name));
+}
+
+void Ssl::LocalContextStorage::purgeOne()
+{
+    QueueIterator i = lru_queue.end();
+    i--;
+    if (i != lru_queue.end()) {
+        remove((*i)->host_name.c_str());
+    }
+}
+
+void Ssl::LocalContextStorage::deleteAt(LocalContextStorage::MapIterator i)
+{
+    if (i != storage.end()) {
+
+        delete *(i->second);
+        lru_queue.erase(i->second);
+        storage.erase(i);
+        memory_used -= SSL_CTX_SIZE;
+    }
+}
+
+void Ssl::LocalContextStorage::SetSize(size_t aMax_memory)
+{
+    max_memory = aMax_memory;
+}
+
+Ssl::LocalContextStorage::Item::Item(SSL_CTX * aSsl_ctx, std::string const & aName)
+        :   ssl_ctx(aSsl_ctx), host_name(aName)
+{}
+
+Ssl::LocalContextStorage::Item::~Item()
+{
+    SSL_CTX_free(ssl_ctx);
+}
+
+///////////////////////////////////////////////////////
+
+Ssl::GlobalContextStorage::GlobalContextStorage()
+        :   reconfiguring(true)
+{
+    RegisterAction("cached_ssl_cert", "Statistic of cached generated ssl certificates", &CertificateStorageAction::Create, 0, 1);
+}
+
+Ssl::GlobalContextStorage::~GlobalContextStorage()
+{
+    for (std::map<Ip::Address, LocalContextStorage *>::iterator i = storage.begin(); i != storage.end(); i++) {
+        delete i->second;
+    }
+}
+
+void Ssl::GlobalContextStorage::addLocalStorage(Ip::Address const & address, size_t size_of_store)
+{
+    assert(reconfiguring);
+    configureStorage.insert(std::pair<Ip::Address, size_t>(address, size_of_store));
+}
+
+Ssl::LocalContextStorage & Ssl::GlobalContextStorage::getLocalStorage(Ip::Address const & address)
+{
+    reconfigureFinish();
+    std::map<Ip::Address, LocalContextStorage *>::iterator i = storage.find(address);
+    assert (i != storage.end());
+    return *(i->second);
+}
+
+void Ssl::GlobalContextStorage::reconfigureStart()
+{
+    reconfiguring = true;
+}
+
+void Ssl::GlobalContextStorage::reconfigureFinish()
+{
+    if (reconfiguring) {
+        reconfiguring = false;
+
+        // remove or change old local storages.
+        for (std::map<Ip::Address, LocalContextStorage *>::iterator i = storage.begin(); i != storage.end(); i++) {
+            std::map<Ip::Address, size_t>::iterator conf_i = configureStorage.find(i->first);
+            if (conf_i == configureStorage.end()) {
+                storage.erase(i);
+            } else {
+                i->second->SetSize(conf_i->second);
+            }
+        }
+
+        // add new local storages.
+        for (std::map<Ip::Address, size_t>::iterator conf_i = configureStorage.begin(); conf_i != configureStorage.end(); conf_i++ ) {
+            if (storage.find(conf_i->first) == storage.end()) {
+                storage.insert(std::pair<Ip::Address, LocalContextStorage *>(conf_i->first, new LocalContextStorage(conf_i->second)));
+            }
+        }
+    }
+}
+
+Ssl::GlobalContextStorage Ssl::TheGlobalContextStorage;

=== added file 'src/ssl/context_storage.h'
--- src/ssl/context_storage.h	1970-01-01 00:00:00 +0000
+++ src/ssl/context_storage.h	2010-11-10 15:02:04 +0000
@@ -0,0 +1,117 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_SSL_CONTEXT_STORAGE_H
+#define SQUID_SSL_CONTEXT_STORAGE_H
+
+#if USE_SSL
+
+#include "SquidTime.h"
+#include "CacheManager.h"
+#include "mgr/Action.h"
+#include "mgr/Command.h"
+#include <map>
+#include <list>
+#include <memory>
+
+/// TODO: Replace on real size.
+#define SSL_CTX_SIZE 1024
+
+namespace  Ssl
+{
+
+/** Reports cached ssl certificate stats to Cache Manager.
+ * TODO: Use "Report" functions instead friend class.
+ */
+class CertificateStorageAction : public Mgr::Action
+{
+public:
+    CertificateStorageAction(const Mgr::Command::Pointer &cmd);
+    static Pointer Create(const Mgr::Command::Pointer &cmd);
+    virtual void dump (StoreEntry *sentry);
+    /**
+     * We do not support aggregation of information across workers
+     * TODO: aggregate these stats
+     */
+    virtual bool aggregatable() const { return false; }
+};
+
+/**
+ * Memory cache for store generated Ssl context. Enforces total size limits
+ * using an LRU algorithm.
+ */
+class LocalContextStorage
+{
+    friend class CertificateStorageAction;
+public:
+    /// Cache item is an (SSL_CTX, host name) tuple.
+    class Item
+    {
+    public:
+        Item(SSL_CTX * aSsl_ctx, std::string const & aName);
+        ~Item();
+    public:
+        SSL_CTX * ssl_ctx; ///< The SSL context.
+        std::string host_name; ///< The host name of the SSL context.
+    };
+
+    typedef std::list<Item *> Queue;
+    typedef Queue::iterator QueueIterator;
+
+    /// host_name:queue_item mapping for fast lookups by host name
+    typedef std::map<std::string, QueueIterator> Map;
+    typedef Map::iterator MapIterator;
+    typedef std::pair<std::string, QueueIterator> MapPair;
+
+    LocalContextStorage(size_t aMax_memory);
+    ~LocalContextStorage();
+    /// Set maximum memory size for this storage.
+    void SetSize(size_t aMax_memory);
+    /// Return a pointer to the  added ssl_ctx or NULL if fails (eg. max cache size equal 0).
+    SSL_CTX * add(char const * host_name, SSL_CTX * ssl_ctx);
+    /// Find SSL_CTX in storage by host name. Lru queue will be updated.
+    SSL_CTX * find(char const * host_name);
+    void remove(char const * host_name); ///< Delete the ssl context by hostname
+
+private:
+    void purgeOne(); ///< Delete oldest object.
+    /// Delete object by iterator. It is used in deletePurge() and remove(...) methods.
+    void deleteAt(MapIterator i);
+
+    size_t max_memory; ///< Max cache size.
+    size_t memory_used; ///< Used cache size.
+    Map storage; ///< The hostnames/SSL_CTX * pairs
+    Queue lru_queue; ///< LRU cache index
+};
+
+
+/// Class for storing/manipulating LocalContextStorage per local listening address/port.
+class GlobalContextStorage
+{
+    friend class CertificateStorageAction;
+public:
+    GlobalContextStorage();
+    ~GlobalContextStorage();
+    /// Create new Ssl context storage for the local listening address/port.
+    void addLocalStorage(Ip::Address const & address, size_t size_of_store);
+    /// Return the local storage for the given listening address/port.
+    LocalContextStorage & getLocalStorage(Ip::Address const & address);
+    /// When reconfigring should be called this method.
+    void reconfigureStart();
+private:
+    /// Called by getLocalStorage method
+    void reconfigureFinish();
+    bool reconfiguring; ///< True if system reconfiguring now.
+    /// Storage used on configure or reconfigure.
+    std::map<Ip::Address, size_t> configureStorage;
+    /// Map for storing all local ip address and their local storages.
+    std::map<Ip::Address, LocalContextStorage *> storage;
+};
+
+/// Global cache for store all ssl server certificates.
+extern GlobalContextStorage TheGlobalContextStorage;
+} //namespace Ssl
+#endif // USE_SSL
+
+#endif // SQUID_SSL_CONTEXT_STORAGE_H

=== added file 'src/ssl/crtd_message.cc'
--- src/ssl/crtd_message.cc	1970-01-01 00:00:00 +0000
+++ src/ssl/crtd_message.cc	2010-11-10 11:45:33 +0000
@@ -0,0 +1,173 @@
+/*
+ * $Id$
+ */
+
+#include "config.h"
+#include "ssl/crtd_message.h"
+#include <cstdlib>
+#include <cstring>
+
+Ssl::CrtdMessage::CrtdMessage()
+        :   body_size(0), state(BEFORE_CODE)
+{}
+
+Ssl::CrtdMessage::ParseResult Ssl::CrtdMessage::parse(const char * buffer, size_t len)
+{
+    char const *current_pos = buffer;
+    while (current_pos != buffer + len && state != END) {
+        switch (state) {
+        case BEFORE_CODE: {
+            if (xisspace(*current_pos)) {
+                current_pos++;
+                break;
+            }
+            if (xisalpha(*current_pos)) {
+                state = CODE;
+                break;
+            }
+            clear();
+            return ERROR;
+        }
+        case CODE: {
+            if (xisalnum(*current_pos) || *current_pos == '_') {
+                current_block += *current_pos;
+                current_pos++;
+                break;
+            }
+            if (xisspace(*current_pos)) {
+                code = current_block;
+                current_block.clear();
+                state = BEFORE_LENGTH;
+                break;
+            }
+            clear();
+            return ERROR;
+        }
+        case BEFORE_LENGTH: {
+            if (xisspace(*current_pos)) {
+                current_pos++;
+                break;
+            }
+            if (xisdigit(*current_pos)) {
+                state = LENGTH;
+                break;
+            }
+            clear();
+            return ERROR;
+        }
+        case LENGTH: {
+            if (xisdigit(*current_pos)) {
+                current_block += *current_pos;
+                current_pos++;
+                break;
+            }
+            if (xisspace(*current_pos)) {
+                body_size = atoi(current_block.c_str());
+                current_block.clear();
+                state = BEFORE_BODY;
+                break;
+            }
+            clear();
+            return ERROR;
+        }
+        case BEFORE_BODY: {
+            if (body_size == 0) {
+                state = END;
+                break;
+            }
+            if (xisspace(*current_pos)) {
+                current_pos++;
+                break;
+            } else {
+                state = BODY;
+                break;
+            }
+        }
+        case BODY: {
+            size_t body_len = (static_cast<size_t>(buffer + len - current_pos) >= body_size - current_block.length())
+                              ? body_size - current_block.length()
+                              : static_cast<size_t>(buffer + len - current_pos);
+            current_block += std::string(current_pos, body_len);
+            current_pos += body_len;
+            if (current_block.length() == body_size) {
+                body = current_block;
+                state = END;
+            }
+            if (current_block.length() > body_size) {
+                clear();
+                return ERROR;
+            }
+            break;
+        }
+        case END: {
+            return OK;
+        }
+        }
+    }
+    if (state != END) return INCOMPLETE;
+    return OK;
+}
+
+std::string const & Ssl::CrtdMessage::getBody() const { return body; }
+
+std::string const & Ssl::CrtdMessage::getCode() const { return code; }
+
+void Ssl::CrtdMessage::setBody(std::string const & aBody) { body = aBody; }
+
+void Ssl::CrtdMessage::setCode(std::string const & aCode) { code = aCode; }
+
+
+std::string Ssl::CrtdMessage::compose() const
+{
+    if (code.empty()) return std::string();
+    char buffer[10];
+    snprintf(buffer, sizeof(buffer), "%zd", body.length());
+    return code + ' ' + buffer + ' ' + body + '\n';
+}
+
+void Ssl::CrtdMessage::clear()
+{
+    body_size = 0;
+    state = BEFORE_CODE;
+    body.clear();
+    code.clear();
+    current_block.clear();
+}
+
+void Ssl::CrtdMessage::parseBody(CrtdMessage::BodyParams & map, std::string & other_part) const
+{
+    other_part.clear();
+    // Copy string for using it as temp buffer.
+    std::string temp_body(body.c_str(), body.length());
+    char * buffer = const_cast<char *>(temp_body.c_str());
+    char * token = strtok(buffer, "\r\n");
+    while (token != NULL) {
+        std::string current_string(token);
+        size_t equal_pos = current_string.find('=');
+        if (equal_pos == std::string::npos) {
+            size_t offset_body_part = token - temp_body.c_str();
+            other_part = std::string(body.c_str() + offset_body_part, body.length() - offset_body_part);
+            break;
+        } else {
+            std::string param(current_string.c_str(), current_string.c_str() + equal_pos);
+            std::string value(current_string.c_str() + equal_pos + 1);
+            map.insert(std::make_pair(param, value));
+        }
+        token = strtok(NULL, "\r\n");
+    }
+}
+
+void Ssl::CrtdMessage::composeBody(CrtdMessage::BodyParams const & map, std::string const & other_part)
+{
+    body.clear();
+    for (BodyParams::const_iterator i = map.begin(); i != map.end(); i++) {
+        if (i != map.begin())
+            body += "\n";
+        body += i->first + "=" + i->second;
+    }
+    if (!other_part.empty())
+        body += other_part;
+}
+
+const std::string Ssl::CrtdMessage::code_new_certificate("new_certificate");
+const std::string Ssl::CrtdMessage::param_host("host");

=== added file 'src/ssl/crtd_message.h'
--- src/ssl/crtd_message.h	1970-01-01 00:00:00 +0000
+++ src/ssl/crtd_message.h	2010-11-10 11:45:33 +0000
@@ -0,0 +1,81 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_SSL_CRTD_MESSAGE_H
+#define SQUID_SSL_CRTD_MESSAGE_H
+
+#include <string>
+#include <map>
+
+namespace Ssl
+{
+/**
+ * This class is responsible for composing and parsing messages destined to, or comming
+ * from an ssl_crtd server. Format of these mesages is:
+ *   <response/request code> <whitespace> <body length> <whitespace> <body>
+ */
+class CrtdMessage
+{
+public:
+    typedef std::map<std::string, std::string> BodyParams;
+    /// Parse result codes.
+    enum ParseResult {
+        OK,
+        INCOMPLETE,
+        ERROR
+    };
+    CrtdMessage();
+    /**\brief Parse buffer of length len
+     * \return OK if parsing completes,  INCOMPLETE if more data required
+     *  and ERROR if there is an error.
+     */
+    ParseResult parse(const char * buffer, size_t len);
+    /// Current  body. If parsing is not finished the method returns incompleted body.
+    std::string const & getBody() const;
+    /// Current response/request code. If parsing is not finished the method may return incompleted code.
+    std::string const & getCode() const;
+    void setBody(std::string const & aBody); ///< Set new body to encode.
+    void setCode(std::string const & aCode); ///< Set new request/reply code to compose.
+    std::string compose() const; ///< Compose current (request) code and body to string.
+    /// Reset the class.
+    void clear();
+    /**
+     *Parse body data which has the form: \verbatim
+         param1=value1
+         param2=value2
+         The other multistring part of body.  \endverbatim
+     * The parameters of the body stored to map and the remaining part to other_part
+     */
+    void parseBody(BodyParams & map, std::string & other_part) const;
+    /**
+     *Compose parameters given by map with their values and the other part given by
+     * other_part to body data. The constructed body will have the form:  \verbatim
+         param1=value1
+         param2=value2
+         The other multistring part of body.  \endverbatim
+    */
+    void composeBody(BodyParams const & map, std::string const & other_part);
+    /// String code for "new_certificate" messages
+    static const std::string code_new_certificate;
+    /// Parameter name for passing hostname
+    static const std::string param_host;
+private:
+    enum ParseState {
+        BEFORE_CODE,
+        CODE,
+        BEFORE_LENGTH,
+        LENGTH,
+        BEFORE_BODY,
+        BODY,
+        END
+    };
+    size_t body_size; ///< The body size if exist or 0.
+    ParseState state; ///< Parsing state.
+    std::string body; ///< Current body.
+    std::string code; ///< Current response/request code.
+    std::string current_block; ///< Current block buffer.
+};
+
+} //namespace Ssl
+#endif // SQUID_SSL_CRTD_MESSAGE_H

=== added file 'src/ssl/gadgets.cc'
--- src/ssl/gadgets.cc	1970-01-01 00:00:00 +0000
+++ src/ssl/gadgets.cc	2010-11-10 11:45:33 +0000
@@ -0,0 +1,272 @@
+/*
+ * $Id$
+ */
+
+#include "ssl/gadgets.h"
+
+/**
+ \ingroup ServerProtocolSSLInternal
+ * Add CN to subject in request.
+ */
+static bool addCnToRequest(Ssl::X509_REQ_Pointer & request, char const * cn)
+{
+    Ssl::X509_NAME_Pointer name(X509_REQ_get_subject_name(request.get()));
+    if (!name)
+        return false;
+    if (!X509_NAME_add_entry_by_txt(name.get(), "CN", MBSTRING_ASC, (unsigned char *)cn, -1, -1, 0))
+        return false;
+    name.release();
+    return true;
+}
+
+/**
+ \ingroup ServerProtocolSSLInternal
+ * Make request on sign using private key and hostname.
+ */
+static bool makeRequest(Ssl::X509_REQ_Pointer & request, Ssl::EVP_PKEY_Pointer const & pkey, char const * host)
+{
+    if (!X509_REQ_set_version(request.get(), 0L))
+        return false;
+
+    if (!addCnToRequest(request, host))
+        return false;
+
+    if (!X509_REQ_set_pubkey(request.get(), pkey.get()))
+        return false;
+    return true;
+}
+
+void Ssl::BIO_free_wrapper(BIO * bio)
+{
+    BIO_free(bio);
+}
+
+EVP_PKEY * Ssl::createSslPrivateKey()
+{
+    Ssl::EVP_PKEY_Pointer pkey(EVP_PKEY_new());
+
+    if (!pkey)
+        return NULL;
+
+    Ssl::RSA_Pointer rsa(RSA_generate_key(1024, RSA_F4, NULL, NULL));
+
+    if (!rsa)
+        return NULL;
+
+    if (!EVP_PKEY_assign_RSA(pkey.get(), (rsa.get())))
+        return NULL;
+
+    rsa.release();
+    return pkey.release();
+}
+
+X509_REQ * Ssl::createNewX509Request(Ssl::EVP_PKEY_Pointer const & pkey, const char * hostname)
+{
+    Ssl::X509_REQ_Pointer request(X509_REQ_new());
+
+    if (!request)
+        return NULL;
+
+    if (!makeRequest(request, pkey, hostname))
+        return NULL;
+    return request.release();
+}
+
+/**
+ \ingroup ServerProtocolSSLInternal
+ * Set serial random serial number or set random serial number.
+ */
+static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const* serial)
+{
+    if (!ai)
+        return false;
+    Ssl::BIGNUM_Pointer bn(BN_new());
+    if (serial) {
+        bn.reset(BN_dup(serial));
+    } else {
+        if (!bn)
+            return false;
+
+        if (!BN_pseudo_rand(bn.get(), 64, 0, 0))
+            return false;
+    }
+
+    if (ai && !BN_to_ASN1_INTEGER(bn.get(), ai))
+        return false;
+    return true;
+}
+
+X509 * Ssl::signRequest(Ssl::X509_REQ_Pointer const & request, Ssl::X509_Pointer const & x509, Ssl::EVP_PKEY_Pointer const & pkey, ASN1_TIME * timeNotAfter, BIGNUM const * serial)
+{
+    Ssl::X509_Pointer cert(X509_new());
+    if (!cert)
+        return NULL;
+
+    if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial))
+        return NULL;
+
+    if (!X509_set_issuer_name(cert.get(), x509.get() ? X509_get_subject_name(x509.get()) : X509_REQ_get_subject_name(request.get())))
+        return NULL;
+
+    if (!X509_gmtime_adj(X509_get_notBefore(cert.get()), (-2)*24*60*60))
+        return NULL;
+
+    if (timeNotAfter) {
+        if (!X509_set_notAfter(cert.get(), timeNotAfter))
+            return NULL;
+    } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
+        return NULL;
+
+    if (!X509_set_subject_name(cert.get(), X509_REQ_get_subject_name(request.get())))
+        return NULL;
+
+    Ssl::EVP_PKEY_Pointer tmppkey(X509_REQ_get_pubkey(request.get()));
+
+    if (!tmppkey || !X509_set_pubkey(cert.get(), tmppkey.get()))
+        return NULL;
+
+    if (!X509_sign(cert.get(), pkey.get(), EVP_sha1()))
+        return NULL;
+
+    return cert.release();
+}
+
+bool Ssl::writeCertAndPrivateKeyToMemory(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, std::string & bufferToWrite)
+{
+    bufferToWrite.clear();
+    if (!pkey || !cert)
+        return false;
+    BIO_Pointer bio(BIO_new(BIO_s_mem()));
+    if (!bio)
+        return false;
+
+    if (!PEM_write_bio_X509 (bio.get(), cert.get()))
+        return false;
+
+    if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
+        return false;
+
+    char *ptr = NULL;
+    long len = BIO_get_mem_data(bio.get(), &ptr);
+    if (!ptr)
+        return false;
+
+    bufferToWrite = std::string(ptr, len);
+    return true;
+}
+
+bool Ssl::writeCertAndPrivateKeyToFile(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, char const * filename)
+{
+    if (!pkey || !cert)
+        return false;
+
+    Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
+    if (!bio)
+        return false;
+    if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
+        return false;
+
+    if (!PEM_write_bio_X509(bio.get(), cert.get()))
+        return false;
+
+    if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
+        return false;
+
+    return true;
+}
+
+bool Ssl::readCertAndPrivateKeyFromMemory(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * bufferToRead)
+{
+    Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
+    BIO_puts(bio.get(), bufferToRead);
+
+    X509 * certPtr = NULL;
+    cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
+    if (!cert)
+        return false;
+
+    EVP_PKEY * pkeyPtr = NULL;
+    pkey.reset(PEM_read_bio_PrivateKey(bio.get(), &pkeyPtr, 0, 0));
+    if (!pkey)
+        return false;
+
+    return true;
+}
+
+bool Ssl::generateSslCertificateAndPrivateKey(char const *host, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, BIGNUM const * serial)
+{
+    pkey.reset(createSslPrivateKey());
+    if (!pkey)
+        return false;
+
+    Ssl::X509_REQ_Pointer request(createNewX509Request(pkey, host));
+    if (!request)
+        return false;
+
+    if (signedX509.get() && signedPkey.get())
+        cert.reset(signRequest(request, signedX509, signedPkey, X509_get_notAfter(signedX509.get()), serial));
+    else
+        cert.reset(signRequest(request, signedX509, pkey, NULL, serial));
+
+    if (!cert)
+        return false;
+
+    return true;
+}
+
+/**
+ \ingroup ServerProtocolSSLInternal
+ * Read certificate from file.
+ */
+static X509 * readSslX509Certificate(char const * certFilename)
+{
+    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);
+    return certificate;
+}
+
+/**
+ \ingroup ServerProtocolSSLInternal
+ * Read private key from file. Make sure that this is not encrypted file.
+ */
+static EVP_PKEY * readSslPrivateKey(char const * keyFilename)
+{
+    if (!keyFilename)
+        return NULL;
+    Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
+    if (!bio)
+        return NULL;
+    if (!BIO_read_filename(bio.get(), keyFilename))
+        return NULL;
+    EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL);
+    return pkey;
+}
+
+void Ssl::readCertAndPrivateKeyFromFiles(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename)
+{
+    if (keyFilename == NULL)
+        keyFilename = certFilename;
+    pkey.reset(readSslPrivateKey(keyFilename));
+    cert.reset(readSslX509Certificate(certFilename));
+    if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
+        pkey.reset(NULL);
+        cert.reset(NULL);
+    }
+}
+
+bool Ssl::sslDateIsInTheFuture(char const * date)
+{
+    ASN1_UTCTIME tm;
+    tm.flags = 0;
+    tm.type = 23;
+    tm.data = (unsigned char *)date;
+    tm.length = strlen(date);
+
+    return (X509_cmp_current_time(&tm) > 0);
+}

=== added file 'src/ssl/gadgets.h'
--- src/ssl/gadgets.h	1970-01-01 00:00:00 +0000
+++ src/ssl/gadgets.h	2010-11-10 11:45:33 +0000
@@ -0,0 +1,111 @@
+/*
+ * 2009/01/17
+ */
+
+#ifndef SQUID_SSL_GADGETS_H
+#define SQUID_SSL_GADGETS_H
+
+#include "config.h"
+#include "base/TidyPointer.h"
+
+#if HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#include <openssl/txt_db.h>
+#endif
+
+#include <string>
+
+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.
+ */
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Function for BIO delete for Deleter template.
+*/
+void BIO_free_wrapper(BIO * bio);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * TidyPointer typedefs for  common SSL objects
+ */
+typedef TidyPointer<X509, X509_free> X509_Pointer;
+typedef TidyPointer<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Pointer;
+typedef TidyPointer<BIGNUM, BN_free> BIGNUM_Pointer;
+typedef TidyPointer<BIO, BIO_free_wrapper> BIO_Pointer;
+typedef TidyPointer<ASN1_INTEGER, ASN1_INTEGER_free> ASN1_INT_Pointer;
+typedef TidyPointer<TXT_DB, TXT_DB_free> TXT_DB_Pointer;
+typedef TidyPointer<X509_NAME, X509_NAME_free> X509_NAME_Pointer;
+typedef TidyPointer<RSA, RSA_free> RSA_Pointer;
+typedef TidyPointer<X509_REQ, X509_REQ_free> X509_REQ_Pointer;
+typedef TidyPointer<SSL_CTX, SSL_CTX_free> SSL_CTX_Pointer;
+typedef  TidyPointer<SSL, SSL_free> SSL_Pointer;
+
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Create 1024 bits rsa key.
+ */
+EVP_PKEY * createSslPrivateKey();
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Create request on certificate for a host.
+ */
+X509_REQ * createNewX509Request(EVP_PKEY_Pointer const & pkey, const char * hostname);
+
+/**
+ \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
+ * Write private key and ssl certificate to file.
+ */
+bool writeCertAndPrivateKeyToFile(X509_Pointer const & cert, EVP_PKEY_Pointer const & pkey, char const * filename);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Write private key and ssl certificate to memory.
+ */
+bool readCertAndPrivateKeyFromMemory(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, char const * bufferToRead);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Sign ssl request.
+ * \param x509 if this param equals NULL, returning certificate will be selfsigned.
+ * \return X509 Signed certificate.
+ */
+X509 * signRequest(X509_REQ_Pointer const & request, X509_Pointer const & x509, EVP_PKEY_Pointer const & pkey, ASN1_TIME * timeNotAfter, BIGNUM const * serial);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Decide on the kind of certificate and generate a CA- or self-signed one.
+ * Return generated certificate and private key in resultX509 and resultPkey
+ * variables.
+ */
+bool generateSslCertificateAndPrivateKey(char const *host, X509_Pointer const & signedX509, EVP_PKEY_Pointer const & signedPkey, X509_Pointer & cert, EVP_PKEY_Pointer & pkey, BIGNUM const* serial);
+
+/**
+ \ingroup SslCrtdSslAPI
+ *  Read certificate and private key from files.
+ * \param certFilename name of file with certificate.
+ * \param keyFilename name of file with private key.
+ */
+void readCertAndPrivateKeyFromFiles(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Verify date. Date format it ASN1_UTCTIME. if there is out of date error,
+ * return false.
+*/
+bool sslDateIsInTheFuture(char const * date);
+
+} // namespace Ssl
+#endif // SQUID_SSL_GADGETS_H

=== added file 'src/ssl/helper.cc'
--- src/ssl/helper.cc	1970-01-01 00:00:00 +0000
+++ src/ssl/helper.cc	2010-11-10 11:45:33 +0000
@@ -0,0 +1,90 @@
+/*
+ * 2008/11/14
+ */
+
+#include "ssl/helper.h"
+#include "SquidTime.h"
+#include "SwapDir.h"
+
+Ssl::Helper * Ssl::Helper::GetInstance()
+{
+    static Ssl::Helper sslHelper;
+    return &sslHelper;
+}
+
+Ssl::Helper::Helper()
+{
+    Init();
+}
+
+Ssl::Helper::~Helper()
+{
+    Shutdown();
+}
+
+void Ssl::Helper::Init()
+{
+    if (ssl_crtd == NULL)
+        ssl_crtd = new helper("ssl_crtd");
+    ssl_crtd->childs = Config.ssl_crtdChildren;
+    ssl_crtd->ipc_type = IPC_STREAM;
+    assert(ssl_crtd->cmdline == NULL);
+    {
+        char *tmp = xstrdup(Config.Program.ssl_crtd);
+        char *tmp_begin = tmp;
+        char * token = NULL;
+        bool db_path_was_found = false;
+        bool block_size_was_found = false;
+        char buffer[20] = "2048";
+        while ((token = strwordtok(NULL, &tmp))) {
+            wordlistAdd(&ssl_crtd->cmdline, token);
+            if (!strcmp(token, "-b"))
+                block_size_was_found = true;
+            if (!strcmp(token, "-s")) {
+                db_path_was_found = true;
+            } else if (db_path_was_found) {
+                db_path_was_found = false;
+                int fs_block_size = 0;
+                storeDirGetBlkSize(token, &fs_block_size);
+                snprintf(buffer, sizeof(buffer), "%i", fs_block_size);
+            }
+        }
+        if (!block_size_was_found) {
+            wordlistAdd(&ssl_crtd->cmdline, "-b");
+            wordlistAdd(&ssl_crtd->cmdline, buffer);
+        }
+        safe_free(tmp_begin);
+    }
+    ssl_crtd->return_full_reply = true;
+    helperOpenServers(ssl_crtd);
+}
+
+void Ssl::Helper::Shutdown()
+{
+    if (!ssl_crtd)
+        return;
+    helperShutdown(ssl_crtd);
+    wordlistDestroy(&ssl_crtd->cmdline);
+    if (!shutting_down)
+        return;
+    delete ssl_crtd;
+    ssl_crtd = NULL;
+}
+
+void Ssl::Helper::sslSubmit(CrtdMessage const & message, HLPCB * callback, void * data)
+{
+    static time_t first_warn = 0;
+
+    if (ssl_crtd->stats.queue_size >= (int)(ssl_crtd->childs.n_running * 2)) {
+        if (first_warn == 0)
+            first_warn = squid_curtime;
+        if (squid_curtime - first_warn > 3 * 60)
+            fatal("SSL servers not responding for 3 minutes");
+        debugs(34, 1, HERE << "Queue overload, rejecting");
+        callback(data, (char *)"error 45 Temporary network problem, please retry later");
+        return;
+    }
+
+    first_warn = 0;
+    helperSubmit(ssl_crtd, message.compose().c_str(), callback, data);
+}

=== added file 'src/ssl/helper.h'
--- src/ssl/helper.h	1970-01-01 00:00:00 +0000
+++ src/ssl/helper.h	2010-11-10 11:45:33 +0000
@@ -0,0 +1,34 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_SSL_HELPER_H
+#define SQUID_SSL_HELPER_H
+
+#include "../helper.h"
+#include "ssl/crtd_message.h"
+
+namespace Ssl
+{
+/**
+ * Set of thread for ssl_crtd. This class is singleton. Use this class only
+ * over GetIntance() static method. This class use helper structure
+ * for threads management.
+ */
+class Helper
+{
+public:
+    static Helper * GetInstance(); ///< Instance class.
+    void Init(); ///< Init helper structure.
+    void Shutdown(); ///< Shutdown helper structure.
+    /// Submit ssl message to external ssl server.
+    void sslSubmit(CrtdMessage const & message, HLPCB * callback, void *data);
+private:
+    Helper();
+    ~Helper();
+
+    helper * ssl_crtd; ///< helper for management of ssl_crtd.
+};
+
+} //namespace Ssl
+#endif // SQUID_SSL_HELPER_H

=== added file 'src/ssl/ssl_crtd.cc'
--- src/ssl/ssl_crtd.cc	1970-01-01 00:00:00 +0000
+++ src/ssl/ssl_crtd.cc	2010-11-10 12:12:13 +0000
@@ -0,0 +1,338 @@
+/*
+ * $Id$
+ */
+
+#include "config.h"
+#include "ssl/gadgets.h"
+#include "ssl/crtd_message.h"
+#include "ssl/certificate_db.h"
+
+#include <cstring>
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+/**
+ \defgroup ssl_crtd ssl_crtd
+ \ingroup ExternalPrograms
+ \par
+    Because the standart generation of ssl certificate for
+    sslBump feature, Squid must use external proccess to
+    actually make these calls. This process generate new ssl
+    certificates and worked with ssl certificates disk cache.
+    Typically there will be five ssl_crtd processes spawned
+    from Squid. Communication occurs via TCP sockets bound
+    to the loopback interface. The class in helper.h are
+    primally concerned with starting and stopping the ssl_crtd.
+    Reading and writing to and from the ssl_crtd occurs in the
+    \link IPCacheAPI IP\endlink and the dnsservers occurs in
+    the \link IPCacheAPI IP\endlink and \link FQDNCacheAPI
+    FQDN\endlink cache modules.
+
+ \section ssl_crtdInterface Command Line Interface
+ \verbatim
+usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size
+    -h                   Help
+    -v                   Version
+    -s ssl_storage_path  Path to specific disk storage of ssl server
+                         certificates.
+    -M storage_max_size  max size of ssl certificates storage.
+    -b fs_block_size     File system block size in bytes. Need for processing
+                         natural size of certificate on disk. Default value is
+                         2048 bytes."
+
+    After running write requests in the next format:
+    <request code><whitespace><body_len><whitespace><body>
+    There are two kind of request now:
+    new_certificate 14 host=host.dom
+        Create new private key and selfsigned certificate for "host.dom".
+
+    new_certificate xxx host=host.dom
+    -----BEGIN CERTIFICATE-----
+    ...
+    -----END CERTIFICATE-----
+    -----BEGIN RSA PRIVATE KEY-----
+    ...
+    -----END RSA PRIVATE KEY-----
+        Create new private key and certificate request for "host.dom".
+        Sign new request by received certificate and private key.
+
+usage: ssl_crtd -c -s ssl_store_path\n -n new_serial_number
+    -c                   Init ssl db directories and exit.
+    -n new_serial_number HEX serial number to use when initializing db.
+                         The default value of serial number is
+                         the number of seconds since Epoch minus 1200000000
+
+usage: ssl_crtd -g -s ssl_store_path
+    -g                   Show current serial number and exit.
+ \endverbatim
+ */
+
+static const char *const B_KBYTES_STR = "KB";
+static const char *const B_MBYTES_STR = "MB";
+static const char *const B_GBYTES_STR = "GB";
+static const char *const B_BYTES_STR = "B";
+
+/**
+  \ingroup ssl_crtd
+ * Get current time.
+*/
+time_t getCurrentTime(void)
+{
+    struct timeval current_time;
+#if GETTIMEOFDAY_NO_TZP
+    gettimeofday(&current_time);
+#else
+    gettimeofday(&current_time, NULL);
+#endif
+    return current_time.tv_sec;
+}
+
+/**
+  \ingroup ssl_crtd
+ * Parse bytes unit. It would be one of the next value: MB, GB, KB or B.
+ * This function is caseinsensitive.
+ */
+static size_t parseBytesUnits(const char * unit)
+{
+    if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)) ||
+            !strncasecmp(unit, "", strlen(unit)))
+        return 1;
+
+    if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
+        return 1 << 10;
+
+    if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
+        return 1 << 20;
+
+    if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
+        return 1 << 30;
+
+    return 0;
+}
+
+/**
+ \ingroup ssl_crtd
+ * Parse uninterrapted string of bytes value. It looks like "4MB".
+ */
+static bool parseBytesOptionValue(size_t * bptr, char const * value)
+{
+    // Find number from string beginning.
+    char const * number_begin = value;
+    char const * number_end = value;
+
+    while ((*number_end >= '0' && *number_end <= '9')) {
+        number_end++;
+    }
+
+    std::string number(number_begin, number_end - number_begin);
+    std::istringstream in(number);
+    int d = 0;
+    if (!(in >> d))
+        return false;
+
+    int m;
+    if ((m = parseBytesUnits(number_end)) == 0) {
+        return false;
+    }
+
+    *bptr = static_cast<size_t>(m * d);
+    if (static_cast<long>(*bptr * 2) != m * d * 2)
+        return false;
+
+    return true;
+}
+
+/**
+ \ingroup ssl_crtd
+ * Print help using response code.
+ */
+static void usage()
+{
+    std::string example_host_name = "host.dom";
+    std::string request_string = Ssl::CrtdMessage::param_host + "=" + example_host_name;
+    std::stringstream request_string_size_stream;
+    request_string_size_stream << request_string.length();
+    std::string help_string =
+        "usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size\n"
+        "\t-h                   Help\n"
+        "\t-v                   Version\n"
+        "\t-s ssl_storage_path  Path to specific disk storage of ssl server\n"
+        "\t                     certificates.\n"
+        "\t-M storage_max_size  max size of ssl certificates storage.\n"
+        "\t-b fs_block_size     File system block size in bytes. Need for processing\n"
+        "\t                     natural size of certificate on disk. Default value is\n"
+        "\t                     2048 bytes.\n"
+        "\n"
+        "After running write requests in the next format:\n"
+        "<request code><whitespace><body_len><whitespace><body>\n"
+        "There are two kind of request now:\n"
+        + Ssl::CrtdMessage::code_new_certificate + " " + request_string_size_stream.str() + " " + request_string + "\n" +
+        "\tCreate new private key and selfsigned certificate for \"host.dom\".\n"
+        + Ssl::CrtdMessage::code_new_certificate + " xxx " + request_string + "\n" +
+        "-----BEGIN CERTIFICATE-----\n"
+        "...\n"
+        "-----END CERTIFICATE-----\n"
+        "-----BEGIN RSA PRIVATE KEY-----\n"
+        "...\n"
+        "-----END RSA PRIVATE KEY-----\n"
+        "\tCreate new private key and certificate request for \"host.dom\"\n"
+        "\tSign new request by received certificate and private key.\n"
+        "usage: ssl_crtd -c -s ssl_store_path -n new_serial_number\n"
+        "\t-c                   Init ssl db directories and exit.\n"
+        "\t-n new_serial_number HEX serial number to use when initializing db.\n"
+        "\t                     The default value of serial number is\n"
+        "\t                     the number of seconds since Epoch minus 1200000000\n"
+        "usage: ssl_crtd -g -s ssl_store_path\n"
+        "\t-g                   Show current serial number and exit.";
+    std::cerr << help_string << std::endl;
+}
+
+/**
+ \ingroup ssl_crtd
+ * Proccess new request message.
+ */
+static bool proccessNewRequest(Ssl::CrtdMessage const & request_message, std::string const & db_path, size_t max_db_size, size_t fs_block_size)
+{
+    Ssl::CrtdMessage::BodyParams map;
+    std::string body_part;
+    request_message.parseBody(map, body_part);
+
+    Ssl::CrtdMessage::BodyParams::iterator i = map.find(Ssl::CrtdMessage::param_host);
+    if (i == map.end())
+        throw std::runtime_error("Cannot find \"" + Ssl::CrtdMessage::param_host + "\" parameter in request message.");
+    std::string host = i->second;
+
+    Ssl::CertificateDb db(db_path, max_db_size, fs_block_size);
+
+    Ssl::X509_Pointer cert;
+    Ssl::EVP_PKEY_Pointer pkey;
+    db.find("/CN=" + host, cert, pkey);
+
+    if (!cert || !pkey) {
+        Ssl::X509_Pointer certToSign;
+        Ssl::EVP_PKEY_Pointer pkeyToSign;
+        Ssl::readCertAndPrivateKeyFromMemory(certToSign, pkeyToSign, body_part.c_str());
+
+        Ssl::BIGNUM_Pointer serial(db.getCurrentSerialNumber());
+
+        if (!Ssl::generateSslCertificateAndPrivateKey(host.c_str(), certToSign, pkeyToSign, cert, pkey, serial.get()))
+            throw std::runtime_error("Cannot create ssl certificate or private key.");
+        if (!db.addCertAndPrivateKey(cert, pkey) && db.IsEnabledDiskStore())
+            throw std::runtime_error("Cannot add certificate to db.");
+    }
+
+    std::string bufferToWrite;
+    if (!Ssl::writeCertAndPrivateKeyToMemory(cert, pkey, bufferToWrite))
+        throw std::runtime_error("Cannot write ssl certificate or/and private key to memory.");
+
+    Ssl::CrtdMessage response_message;
+    response_message.setCode("ok");
+    response_message.setBody(bufferToWrite);
+
+    std::cout << response_message.compose();
+
+    return true;
+}
+
+/**
+ \ingroup ssl_crtd
+ * This is the external ssl_crtd process.
+ */
+int main(int argc, char *argv[])
+{
+    try {
+        int serial = (getCurrentTime() -  1200000000);
+        size_t max_db_size = 0;
+        size_t fs_block_size = 2048;
+        char c;
+        bool create_new_db = false;
+        bool show_sn = false;
+        std::string db_path;
+        // proccess options.
+        while ((c = getopt(argc, argv, "cghvs:M:b:n:")) != -1) {
+            switch (c) {
+            case 'b':
+                if (!parseBytesOptionValue(&fs_block_size, optarg)) {
+                    throw std::runtime_error("Error when parsing -b options value");
+                }
+                break;
+            case 's':
+                db_path = optarg;
+                break;
+            case 'n': {
+                std::stringstream sn_stream(optarg);
+                sn_stream >> std::hex >> serial;
+                break;
+            }
+            case 'M':
+                if (!parseBytesOptionValue(&max_db_size, optarg)) {
+                    throw std::runtime_error("Error when parsing -M options value");
+                }
+                break;
+            case 'v':
+                std::cout << "ssl_crtd version " << VERSION << std::endl;
+                exit(0);
+                break;
+            case 'c':
+                create_new_db = true;
+                break;
+            case 'g':
+                show_sn = true;
+                break;
+            case 'h':
+                usage();
+                exit(0);
+            default:
+                exit(0);
+            }
+        }
+
+        if (create_new_db) {
+            std::cout << "Initialization SSL db..." << std::endl;
+            Ssl::CertificateDb::create(db_path, serial);
+            std::cout << "Done" << std::endl;
+            exit(0);
+        }
+
+        if (show_sn) {
+            Ssl::CertificateDb db(db_path, 4096, 0);
+            std::cout << db.getSNString() << std::endl;
+            exit(0);
+        }
+        {
+            Ssl::CertificateDb::check(db_path, max_db_size);
+        }
+        // proccess request.
+        for (;;) {
+            char request[512];
+            size_t const REQ_SZ = sizeof(request);
+            Ssl::CrtdMessage request_message;
+            Ssl::CrtdMessage::ParseResult parse_result = Ssl::CrtdMessage::INCOMPLETE;
+
+            while (parse_result == Ssl::CrtdMessage::INCOMPLETE) {
+                if (fgets(request, REQ_SZ, stdin) == NULL)
+                    return 1;
+                size_t gcount = strlen(request);
+                parse_result = request_message.parse(request, gcount);
+            }
+
+            if (parse_result == Ssl::CrtdMessage::ERROR) {
+                throw std::runtime_error("Cannot parse request message.");
+            } else if (request_message.getCode() == Ssl::CrtdMessage::code_new_certificate) {
+                proccessNewRequest(request_message, db_path, max_db_size, fs_block_size);
+            } else {
+                throw std::runtime_error("Unknown request code: \"" + request_message.getCode() + "\".");
+            }
+            std::cout.flush();
+        }
+    } catch (std::runtime_error & error) {
+        std::cerr << argv[0] << ": " << error.what() << std::endl;
+        return 0;
+    }
+    return 0;
+}

=== renamed file 'src/ssl_support.cc' => 'src/ssl/support.cc'
--- src/ssl_support.cc	2010-03-31 15:59:21 +0000
+++ src/ssl/support.cc	2010-11-10 11:45:33 +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.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 "ssl/gadgets.h"
 
 /**
  \defgroup ServerProtocolSSLInternal Server-Side SSL Internals
  \ingroup ServerProtocolSSLAPI
  */
 
 /// \ingroup ServerProtocolSSLInternal
 static int
 ssl_ask_password_cb(char *buf, int size, int rwflag, void *userdata)
 {
     FILE *in;
     int len = 0;
     char cmdline[1024];
 
     snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", Config.Program.ssl_password, (const char *)userdata);
     in = popen(cmdline, "r");
 
     if (fgets(buf, size, in))
 
         len = strlen(buf);
@@ -1189,21 +1190,75 @@
         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;
 }
 
+/// \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)
+{
+    Ssl::SSL_CTX_Pointer sslContext(SSL_CTX_new(SSLv23_server_method()));
+
+    if (!SSL_CTX_use_certificate(sslContext.get(), x509.get()))
+        return NULL;
+
+    if (!SSL_CTX_use_PrivateKey(sslContext.get(), pkey.get()))
+        return NULL;
+    return sslContext.release();
+}
+
+SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data)
+{
+    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);
+}
+
+SSL_CTX * Ssl::generateSslContext(char const *host, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey)
+{
+    Ssl::X509_Pointer cert;
+    Ssl::EVP_PKEY_Pointer pkey;
+    if (!generateSslCertificateAndPrivateKey(host, signedX509, signedPkey, cert, pkey, NULL)) {
+        return NULL;
+    }
+    if (!cert)
+        return NULL;
+
+    if (!pkey)
+        return NULL;
+
+    return createSSLContext(cert, pkey);
+}
+
+bool Ssl::verifySslCertificateDate(SSL_CTX * sslContext)
+{
+    // 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);
+    return ret;
+}
+
 #endif /* USE_SSL */

=== renamed file 'src/ssl_support.h' => 'src/ssl/support.h'
--- src/ssl_support.h	2010-02-03 12:36:21 +0000
+++ src/ssl/support.h	2010-11-10 11:45:33 +0000
@@ -19,40 +19,42 @@
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  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.
  *
  */
 
 #ifndef SQUID_SSL_SUPPORT_H
 #define SQUID_SSL_SUPPORT_H
 
 #include "config.h"
+#include "ssl/gadgets.h"
+
 #if HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
 #endif
 #if HAVE_OPENSSL_X509V3_H
 #include <openssl/x509v3.h>
 #endif
 #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
  */
 
 /// \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);
@@ -75,40 +77,64 @@
 
 /// \ingroup ServerProtocolSSLAPI
 typedef char const *SSLGETATTRIBUTE(SSL *, const char *);
 
 /// \ingroup ServerProtocolSSLAPI
 SSLGETATTRIBUTE sslGetUserAttribute;
 
 /// \ingroup ServerProtocolSSLAPI
 SSLGETATTRIBUTE sslGetCAAttribute;
 
 /// \ingroup ServerProtocolSSLAPI
 const char *sslGetUserCertificatePEM(SSL *ssl);
 
 /// \ingroup ServerProtocolSSLAPI
 const char *sslGetUserCertificateChainPEM(SSL *ssl);
 
 typedef int ssl_error_t;
 ssl_error_t sslParseErrorString(const char *name);
 const char *sslFindErrorString(ssl_error_t value);
 
+namespace Ssl
+{
+/**
+  \ingroup ServerProtocolSSLAPI
+  * Decide on the kind of certificate and generate a CA- or self-signed one
+*/
+SSL_CTX *generateSslContext(char const *host, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey);
+
+/**
+  \ingroup ServerProtocolSSLAPI
+  * Check date of certificate signature. If there is out of date error fucntion
+  * returns false, true otherwise.
+ */
+bool verifySslCertificateDate(SSL_CTX * sslContext);
+
+/**
+  \ingroup ServerProtocolSSLAPI
+  * Read private key and certificate from memory and generate ssl context
+  * using their.
+ */
+SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data);
+
+} //namespace Ssl
+
 // Custom SSL errors; assumes all official errors are positive
 #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_DOMAIN_MISMATCH
 #define SQUID_SSL_ERROR_MAX INT_MAX
 
 #ifdef _SQUID_MSWIN_
 
 #ifdef __cplusplus
 
 /** \cond AUTODOCS-IGNORE */
 namespace Squid
 {
 /** \endcond */
 
 /// \ingroup ServerProtocolSSLAPI
 inline
 int SSL_set_fd(SSL *ssl, int fd)
 {
     return ::SSL_set_fd(ssl, _get_osfhandle(fd));

=== modified file 'src/structs.h'
--- src/structs.h	2010-10-28 18:52:59 +0000
+++ src/structs.h	2010-11-09 22:29:49 +0000
@@ -287,45 +287,53 @@
     char *visible_appname_string;
     char *effectiveGroup;
 
     struct {
 #if USE_DNSSERVERS
         char *dnsserver;
 #endif
 
         wordlist *redirect;
 #if USE_UNLINKD
 
         char *unlinkd;
 #endif
 
         char *diskd;
 #if USE_SSL
 
         char *ssl_password;
 #endif
 
+#if USE_SSL_CRTD
+        char *ssl_crtd; ///< Name of external ssl_crtd application.
+#endif
+
     } Program;
 #if USE_DNSSERVERS
 
     HelperChildConfig dnsChildren;
 #endif
+#if USE_SSL_CRTD
+    /// The number of processes spawn for ssl_crtd.
+    HelperChildConfig ssl_crtdChildren;
+#endif
 
     HelperChildConfig redirectChildren;
     time_t authenticateGCInterval;
     time_t authenticateTTL;
     time_t authenticateIpTTL;
 
     struct {
         char *surrogate_id;
     } Accel;
     char *appendDomain;
     size_t appendDomainLen;
     char *pidFilename;
     char *netdbFilename;
     char *mimeTablePathname;
     char *etcHostsPath;
     char *visibleHostname;
     char *uniqueHostname;
     wordlist *hostnameAliases;
     char *errHtmlText;
 


