=== modified file 'configure.in'
--- configure.in	2010-11-06 23:34:12 +0000
+++ configure.in	2010-11-12 14:57:23 +0000
@@ -1513,6 +1513,21 @@
 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.]), [
+  SQUID_YESNO([$enableval],
+  [unrecogized argument to --enable-ssl-crtd: $enableval])
+])
+
+if test "x$enable_ssl_crtd" = "xyes" -a "x$enable_ssl" = "xno" ; then
+   AC_MSG_ERROR([You need to enable ssl gatewaying support to use ssl_crtd feature. Try to use --enable-ssl. ])
+fi
+SQUID_DEFINE_BOOL(USE_SSL_CRTD, ${enable_ssl_crtd:=no},[Use ssl_crtd daemon])
+AM_CONDITIONAL(USE_SSL_CRTD, [test "x$enable_ssl_crtd" = "xyes"])
+
 dnl Select Default hosts file location
 AC_ARG_ENABLE(default-hostsfile,
   AS_HELP_STRING([--enable-default-hostsfile=path],
@@ -2187,6 +2202,7 @@
   crypt.h \
   cstdlib \
   cstring \
+  list \
   ctype.h \
   errno.h \
   execinfo.h \
@@ -2199,6 +2215,7 @@
   iosfwd \
   iomanip \
   iostream \
+  fstream \
   climits \
   ip_compat.h \
   ip_fil_compat.h \
@@ -2217,6 +2234,7 @@
   map \
   math.h \
   memory.h \
+  memory \
   mount.h \
   netdb.h \
   netinet/in.h \
@@ -2228,6 +2246,7 @@
   openssl/x509v3.h \
   netinet/tcp.h \
   openssl/engine.h \
+  openssl/txt_db.h \
   ostream \
   paths.h \
   poll.h \
@@ -3332,6 +3351,7 @@
 	src/ip/Makefile \
 	src/log/Makefile \
 	src/ipc/Makefile \
+	src/ssl/Makefile \
 	src/mgr/Makefile \
 	contrib/Makefile \
 	snmplib/Makefile \

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2010-11-06 14:58:44 +0000
+++ src/Makefile.am	2010-11-11 16:23:39 +0000
@@ -41,6 +41,15 @@
 
 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
@@ -114,16 +123,6 @@
 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
@@ -430,7 +429,6 @@
 	SquidMath.h \
 	SquidMath.cc \
 	SquidNew.cc \
-	$(SSL_SOURCE) \
 	stat.cc \
 	StatHist.cc \
 	String.cc \
@@ -517,8 +515,6 @@
 	LeakFinder.h \
 	$(SNMP_ALL_SOURCE) \
 	$(UNLINKDSOURCE) \
-	$(SSL_ALL_SOURCE) \
-	$(WIN32_ALL_SOURCE) \
 	$(LOADABLE_MODULES_SOURCES) \
 	DiskIO/DiskThreads/aiops.cc \
 	DiskIO/DiskThreads/aiops_win32.cc
@@ -567,6 +563,7 @@
 	$(SNMPLIB) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -583,6 +580,7 @@
 	$(SNMPLIB) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LOCAL_LIBS) \
+	$(SSL_LIBS) \
 	$(COMMON_LIBS)
 
 if USE_LOADABLE_MODULES
@@ -761,12 +759,14 @@
 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)/lib/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)/'`
@@ -833,6 +833,7 @@
 	-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" \
@@ -843,6 +844,7 @@
 	-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" \
@@ -1234,7 +1236,6 @@
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
@@ -1285,6 +1286,7 @@
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -1438,7 +1440,6 @@
 	refresh.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
@@ -1488,6 +1489,7 @@
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -1601,7 +1603,6 @@
 	refresh.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
@@ -1651,6 +1652,7 @@
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -1755,7 +1757,6 @@
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
@@ -1809,6 +1810,7 @@
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -1922,7 +1924,6 @@
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
@@ -1972,6 +1973,7 @@
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -2339,7 +2341,6 @@
 	refresh.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
-	$(SSL_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
@@ -2388,6 +2389,7 @@
 	$(REPL_OBJS) \
 	${ADAPTATION_LIBS} \
 	$(ESI_LIBS) \
+	$(SSL_LIBS) \
 	$(SNMPLIB) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \

=== modified file 'src/ProtoPort.cc'
--- src/ProtoPort.cc	2009-12-31 02:35:01 +0000
+++ src/ProtoPort.cc	2010-11-11 16:01:09 +0000
@@ -4,11 +4,14 @@
 
 #include "squid.h"
 #include "ProtoPort.h"
+#if HAVE_LIMITS
+#include <limits>
+#endif
 
 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);
@@ -31,6 +34,7 @@
     safe_free(capath);
     safe_free(dhfile);
     safe_free(sslflags);
+    safe_free(sslContextSessionId);
 #endif
 }
 

=== modified file 'src/ProtoPort.h'
--- src/ProtoPort.h	2010-04-17 02:29:04 +0000
+++ src/ProtoPort.h	2010-11-15 15:40:05 +0000
@@ -8,6 +8,10 @@
 #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();
@@ -60,8 +64,13 @@
     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);

=== modified file 'src/acl/Certificate.h'
--- src/acl/Certificate.h	2009-03-08 21:53:27 +0000
+++ src/acl/Certificate.h	2010-11-15 15:40:05 +0000
@@ -38,7 +38,7 @@
 #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

=== modified file 'src/acl/CertificateData.h'
--- src/acl/CertificateData.h	2009-03-31 12:39:30 +0000
+++ src/acl/CertificateData.h	2010-11-15 15:40:05 +0000
@@ -38,7 +38,7 @@
 #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

=== 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
@@ -8,7 +8,7 @@
 #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>
 {

=== 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
@@ -12,6 +12,7 @@
 	AsyncJobCalls.h \
 	AsyncCallQueue.cc \
 	AsyncCallQueue.h \
+	TidyPointer.h \
 	CbcPointer.h \
 	InstanceId.h \
 	Subscription.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-15 22:06:58 +0000
@@ -46,6 +46,9 @@
 #if USE_ECAP
 #include "adaptation/ecap/Config.h"
 #endif
+#if USE_SSL
+#include "ssl/Config.h"
+#endif
 #include "auth/Config.h"
 #include "auth/Scheme.h"
 #include "ConfigParser.h"
@@ -82,6 +85,10 @@
 #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();
@@ -146,6 +153,9 @@
 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
@@ -875,7 +885,13 @@
 
             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);
         }
     }
 
@@ -886,7 +902,11 @@
         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));
         }
     }
 
@@ -1113,6 +1133,44 @@
 }
 #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)
 {
@@ -3571,8 +3629,16 @@
         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();
@@ -3638,7 +3704,7 @@
     char *crlfile;
     char *dhfile;
     char *sslflags;
-    char *sslcontext;
+    char *sslContextSessionId;
     SSL_CTX *sslContext;
 #endif
 
@@ -3762,8 +3828,14 @@
     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
 }
 

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2010-10-25 18:25:19 +0000
+++ src/cf.data.pre	2010-11-12 16:11:52 +0000
@@ -1390,6 +1390,24 @@
 
 	   sslcontext=	SSL session ID context identifier.
 
+	   generate-host-certificates[=<on|off>]
+			Dynamically create SSL server certificates for the
+			destination hosts of bumped CONNECT requests.When 
+			enabled, the cert and key options are used to sign
+			generated certificates. 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 when SslBump is used.
+			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:
 
@@ -1968,6 +1986,54 @@
 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: Ssl::TheConfig.ssl_crtd
+DOC_START
+	Specify the location and options of the executable for ssl_crtd process.
+	@DEFAULT_SSL_CRTD@ program requires -s and -M parameters
+	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: Ssl::TheConfig.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

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2010-10-26 00:17:17 +0000
+++ src/client_side.cc	2010-11-15 15:40:05 +0000
@@ -115,6 +115,20 @@
 #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
+
+#if HAVE_LIMITS
+#include <limits>
+#endif
+
 #if LINGERING_CLOSE
 #define comm_close comm_lingering_close
 #endif
@@ -3346,7 +3360,7 @@
             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;
@@ -3396,24 +3410,109 @@
     incoming_sockets_accepted++;
 }
 
-bool
-ConnStateData::switchToHttps()
-{
-    assert(!switchedToHttps_);
-
-    //HTTPMSGLOCK(currentobject->http->request);
-    assert(areAllContextsForThisConnection());
-    freeAllContexts();
-    //currentobject->connIsFinished();
-
-    debugs(33, 5, HERE << "converting FD " << fd << " to SSL");
+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::getSslContextStart()
+{
+    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");
+        }
+
+#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);
+}
+
+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;
@@ -3429,6 +3528,23 @@
     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
@@ -3476,14 +3592,21 @@
         }
 
 #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 ... */
 
@@ -3545,7 +3668,7 @@
             continue;
         }
 
-        if (s->sslContext == NULL) {
+        if (!s->staticSslContext) {
             debugs(1, 1, "Ignoring https_port " << s->http.s <<
                    " due to SSL initialization failure.");
             continue;
@@ -3713,7 +3836,7 @@
 
 CBDATA_CLASS_INIT(ConnStateData);
 
-ConnStateData::ConnStateData() :AsyncJob("ConnStateData"), transparent_ (false), closing_ (false)
+ConnStateData::ConnStateData() :AsyncJob("ConnStateData"), transparent_ (false), closing_ (false), switchedToHttps_(false)
 {
     pinning.fd = -1;
     pinning.pinned = false;

=== modified file 'src/client_side.h'
--- src/client_side.h	2010-09-10 20:56:24 +0000
+++ src/client_side.h	2010-11-15 15:40:05 +0000
@@ -275,7 +275,20 @@
     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; }
@@ -299,6 +312,7 @@
     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
 };

=== 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-15 15:22:27 +0000
@@ -1189,7 +1189,7 @@
         return;
     }
 
-    getConn()->switchToHttps();
+    getConn()->switchToHttps(request->GetHost());
 }
 
 void

=== modified file 'src/comm.cc'
--- src/comm.cc	2010-11-03 16:28:34 +0000
+++ src/comm.cc	2010-11-15 15:40:05 +0000
@@ -1540,6 +1540,10 @@
         F->ssl = NULL;
     }
 
+    if (F->dynamicSslContext) {
+        SSL_CTX_free(F->dynamicSslContext);
+        F->dynamicSslContext = NULL;
+    }
 #endif
     fd_close(fd);		/* update fdstat */
 

=== modified file 'src/fde.h'
--- src/fde.h	2010-10-25 21:49:58 +0000
+++ src/fde.h	2010-11-15 15:40:05 +0000
@@ -113,6 +113,7 @@
     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 {
@@ -166,6 +167,7 @@
         write_method = NULL;
 #if USE_SSL
         ssl = NULL;
+        dynamicSslContext = NULL;
 #endif
 #ifdef _SQUID_MSWIN_
         win32.handle = NULL;

=== 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
@@ -792,6 +792,55 @@
     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)
@@ -834,69 +883,29 @@
         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 (!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;
+    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++;
+            }
+
+            helperReturnBuffer(i, srv, hlp, msg, t);
         }
     }
 

=== 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
@@ -69,6 +69,8 @@
         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);

=== 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
@@ -88,6 +88,15 @@
 #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
@@ -733,7 +742,12 @@
 
     idnsShutdown();
 #endif
-
+#if USE_SSL_CRTD
+    Ssl::Helper::GetInstance()->Shutdown();
+#endif
+#if USE_SSL
+    Ssl::TheGlobalContextStorage.reconfigureStart();
+#endif
     redirectShutdown();
     authenticateReset();
     externalAclShutdown();
@@ -819,6 +833,9 @@
 
     idnsInit();
 #endif
+#if USE_SSL_CRTD
+    Ssl::Helper::GetInstance()->Init();
+#endif
 
     redirectInit();
     authenticateInit(&Auth::TheConfig);
@@ -1812,7 +1829,9 @@
 
     idnsShutdown();
 #endif
-
+#if USE_SSL_CRTD
+    Ssl::Helper::GetInstance()->Shutdown();
+#endif
     redirectShutdown();
     externalAclShutdown();
     icpConnectionClose();

=== 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
@@ -155,7 +155,7 @@
 
 #include "md5.h"
 #if USE_SSL
-#include "ssl_support.h"
+#include "ssl/support.h"
 #endif
 #if SQUID_SNMP
 #include "cache_snmp.h"

=== added directory 'src/ssl'
=== added file 'src/ssl/Config.cc'
--- src/ssl/Config.cc	1970-01-01 00:00:00 +0000
+++ src/ssl/Config.cc	2010-11-12 15:59:26 +0000
@@ -0,0 +1,21 @@
+/*
+ * $Id$
+ */
+
+#include "ssl/Config.h"
+
+Ssl::Config Ssl::TheConfig;
+
+Ssl::Config::Config():
+#if USE_SSL_CRTD
+ssl_crtd(NULL)
+#endif
+{
+}
+
+Ssl::Config::~Config()
+{
+#if USE_SSL_CRTD
+    xfree(ssl_crtd);
+#endif
+}

=== added file 'src/ssl/Config.h'
--- src/ssl/Config.h	1970-01-01 00:00:00 +0000
+++ src/ssl/Config.h	2010-11-12 16:10:40 +0000
@@ -0,0 +1,32 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_SSL_CONFIG_H
+#define SQUID_SSL_CONFIG_H
+
+#include "config.h"
+#include "HelperChildConfig.h"
+
+namespace Ssl
+{
+
+class Config
+{
+public:
+#if USE_SSL_CRTD
+    char *ssl_crtd; ///< Name of external ssl_crtd application.
+    /// The number of processes spawn for ssl_crtd.
+    HelperChildConfig ssl_crtdChildren;
+#endif
+    Config();
+    ~Config();
+private:
+    Config(const Config &); // not implemented
+    Config &operator =(const Config &); // not implemented
+};
+
+extern Config TheConfig;
+
+} // namespace Ssl
+#endif

=== added file 'src/ssl/Makefile.am'
--- src/ssl/Makefile.am	1970-01-01 00:00:00 +0000
+++ src/ssl/Makefile.am	2010-11-15 15:40:05 +0000
@@ -0,0 +1,40 @@
+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 \
+	Config.cc \
+	Config.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)
+
+if USE_SSL_CRTD
+ssl_crtd_SOURCES = ssl_crtd.cc certificate_db.cc certificate_db.h
+ssl_crtd_LDADD = @SSLLIB@ -lsslutil $(COMPAT_LIB)
+endif

=== 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-12 11:43:46 +0000
@@ -0,0 +1,486 @@
+/*
+ * $Id$
+ */
+
+#include "config.h"
+#include "ssl/certificate_db.h"
+#if HAVE_FSTREAM
+#include <fstream>
+#endif
+#if HAVE_STDEXCEPT
+#include <stdexcept>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+Ssl::FileLocker::FileLocker(std::string const & filename)
+        :    fd(-1)
+{
+#if _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() const
+{
+    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() const
+{
+    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() const
+{
+    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-12 11:44:11 +0000
@@ -0,0 +1,139 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_SSL_CERTIFICATE_DB_H
+#define SQUID_SSL_CERTIFICATE_DB_H
+
+#include "ssl/gadgets.h"
+#include "ssl/support.h"
+#if HAVE_STRING
+#include <string>
+#endif
+
+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() const; ///< 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() const; ///< 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() const; ///< 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-15 15:40:05 +0000
@@ -0,0 +1,182 @@
+/*
+ * $Id$
+ */
+
+#include "Store.h"
+#include "StoreEntryStream.h"
+#include "ssl/context_storage.h"
+#include "mgr/Registration.h"
+#if HAVE_LIMITS
+#include <limits>
+#endif
+
+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-15 15:40:05 +0000
@@ -0,0 +1,120 @@
+/*
+ * $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"
+#if HAVE_MAP
+#include <map>
+#endif
+#if HAVE_LIST
+#include <list>
+#endif
+
+/// 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-12 11:46:32 +0000
@@ -0,0 +1,177 @@
+/*
+ * $Id$
+ */
+
+#include "config.h"
+#include "ssl/crtd_message.h"
+#if HAVE_CSTDLIB
+#include <cstdlib>
+#endif
+#if HAVE_CSTRING
+#include <cstring>
+#endif
+
+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-12 11:45:40 +0000
@@ -0,0 +1,86 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_SSL_CRTD_MESSAGE_H
+#define SQUID_SSL_CRTD_MESSAGE_H
+
+#if HAVE_STRING
+#include <string>
+#endif
+#if HAVE_MAP
+#include <map>
+#endif
+
+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();
+    /**Parse buffer of length len
+     \retval OK          if parsing completes
+     \retval INCOMPLETE  if more data required
+     \retval 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-11 17:19:15 +0000
@@ -0,0 +1,273 @@
+/*
+ * $Id$
+ */
+
+#include "config.h"
+#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-15 15:40:05 +0000
@@ -0,0 +1,113 @@
+/*
+ * 2009/01/17
+ */
+
+#ifndef SQUID_SSL_GADGETS_H
+#define SQUID_SSL_GADGETS_H
+
+#include "base/TidyPointer.h"
+
+#if HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
+#if HAVE_OPENSSL_TXT_DB_H
+#include <openssl/txt_db.h>
+#endif
+#if HAVE_STRING
+#include <string>
+#endif
+
+namespace Ssl
+{
+/**
+ \defgroup SslCrtdSslAPI ssl_crtd SSL api.
+ These functions must not depend on Squid runtime code such as debug()
+ because they are used by ssl_crtd.
+ */
+
+/**
+ \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-12 16:11:30 +0000
@@ -0,0 +1,92 @@
+/*
+ * 2008/11/14
+ */
+
+#include "config.h"
+#include "ssl/Config.h"
+#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 = Ssl::TheConfig.ssl_crtdChildren;
+    ssl_crtd->ipc_type = IPC_STREAM;
+    assert(ssl_crtd->cmdline == NULL);
+    {
+        char *tmp = xstrdup(Ssl::TheConfig.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-11 17:01:26 +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 crtd message to external crtd 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-12 15:19:34 +0000
@@ -0,0 +1,351 @@
+/*
+ * $Id$
+ */
+
+#include "config.h"
+#include "helpers/defines.h"
+#include "ssl/gadgets.h"
+#include "ssl/crtd_message.h"
+#include "ssl/certificate_db.h"
+
+#if HAVE_CSTRING
+#include <cstring>
+#endif
+#if HAVE_SSTREAM
+#include <sstream>
+#endif
+#if HAVE_IOSTREAM
+#include <iostream>
+#endif
+#if HAVE_STDEXCEPT
+#include <stdexcept>
+#endif
+#if HAVE_STRING
+#include <string>
+#endif
+#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, "dcghvs:M:b:n:")) != -1) {
+            switch (c) {
+            case 'd':
+                debug_enabled = 1;
+                break;
+            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[HELPER_INPUT_BUFFER];
+            Ssl::CrtdMessage request_message;
+            Ssl::CrtdMessage::ParseResult parse_result = Ssl::CrtdMessage::INCOMPLETE;
+
+            while (parse_result == Ssl::CrtdMessage::INCOMPLETE) {
+                if (fgets(request, HELPER_INPUT_BUFFER, 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-15 15:40:05 +0000
@@ -42,6 +42,7 @@
 
 #include "fde.h"
 #include "acl/FilledChecklist.h"
+#include "ssl/gadgets.h"
 
 /**
  \defgroup ServerProtocolSSLInternal Server-Side SSL Internals
@@ -1206,4 +1207,58 @@
     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-15 15:40:05 +0000
@@ -36,6 +36,8 @@
 #define SQUID_SSL_SUPPORT_H
 
 #include "config.h"
+#include "ssl/gadgets.h"
+
 #if HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
 #endif
@@ -92,6 +94,30 @@
 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



