From: Joe Orton Date: Thu, 8 Jan 2004 16:26:53 +0000 (+0000) Subject: Add support to mod_ssl for a distributed session cache using X-Git-Tag: pre_ajp_proxy~852 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3c52d23027a17576fe8d1b18dc0441de1f69c562;p=apache Add support to mod_ssl for a distributed session cache using distcache. * LAYOUT: Update for removal of scache_shmht and addition of scache_dc. * modules/ssl/config.m4: Check for libdistcache; build ssl_scache_dc.lo. * modules/ssl/mod_ssl.dsp: Build ssl_scache_dc (with luck). * modules/ssl/mod_ssl.h: Add SSL_SCMODE_DC and scache_dc_* prototypes. * modules/ssl/ssl_engine_config.c (ssl_cmd_SSLSessionCache): Allow use of dc: argument. * modules/ssl/ssl_scache_dc.c: New file. * modules/ssl/ssl_scache.c (ssl_scache_init, ssl_scache_kill, ssl_scache_store, ssl_scache_retrieve, ssl_scache_remove, ssl_ext_status_hook): Hook into scache_dc. Submitted by: Geoff Thorpe git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@102227 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index cda3dad223..f168fea945 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ Changes with Apache 2.1.0-dev [Remove entries to the current 2.0 section below, when backported] + *) mod_ssl: Add support for distributed session cache using 'distcache'. + [Geoff Thorpe ] + *) mod_dav: Disallow requests with an unescaped hash character in the Request-URI. PR 21779. [Amit Athavale ] diff --git a/LAYOUT b/LAYOUT index c5525d76ea..8385e67f0f 100644 --- a/LAYOUT +++ b/LAYOUT @@ -128,7 +128,7 @@ modules/ ................ Manditory and Add-In Apache stock modules ssl_scache.c ............ session cache abstraction layer ssl_scache_dbm.c ........ session cache via DBM file ssl_scache_shmcb.c ...... session cache via shared memory cyclic buffer - ssl_scache_shmht.c ...... session cache via shared memory hash table + ssl_scache_dc.c ......... session cache offloading via 'distcache' ssl_util.c .............. utility functions ssl_util_ssl.c .......... the OpenSSL companion source ssl_util_ssl.h .......... the OpenSSL companion header diff --git a/modules/ssl/config.m4 b/modules/ssl/config.m4 index 956320204c..35f92bcf0e 100644 --- a/modules/ssl/config.m4 +++ b/modules/ssl/config.m4 @@ -46,6 +46,79 @@ dnl ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF dnl ## SUCH DAMAGE. dnl ## ==================================================================== +AC_DEFUN([CHECK_DISTCACHE], [ + AC_MSG_CHECKING(whether Distcache is required) + ap_ssltk_dc="no" + tmp_nomessage="" + tmp_forced="no" + AC_ARG_ENABLE(distcache, + APACHE_HELP_STRING(--enable-distcache,Select distcache support in mod_ssl), + ap_ssltk_dc="$enableval" + tmp_nomessage="" + tmp_forced="yes" + if test "x$ap_ssltk_dc" = "x"; then + ap_ssltk_dc="yes" + dnl our "error"s become "tests revealed that..." + tmp_forced="no" + fi + if test "$ap_ssltk_dc" != "yes" -a "$ap_ssltk_dc" != "no"; then + tmp_nomessage="--enable-distcache had illegal syntax - disabling" + ap_ssltk_dc="no" + fi) + if test "$tmp_forced" = "no"; then + AC_MSG_RESULT($ap_ssltk_dc (default)) + else + AC_MSG_RESULT($ap_ssltk_dc (specified)) + fi + if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno" -a "x$tmp_nomessage" != "x"; then + AC_MSG_ERROR(distcache support failed: $tmp_nomessage) + fi + if test "$ap_ssltk_dc" = "yes"; then + AC_CHECK_HEADER( + [distcache/dc_client.h], + [], + [tmp_nomessage="can't include distcache headers" + ap_ssltk_dc="no"]) + if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno"; then + AC_MSG_ERROR(distcache support failed: $tmp_nomessage) + fi + fi + if test "$ap_ssltk_dc" = "yes"; then + AC_MSG_CHECKING(for Distcache version) + AC_TRY_COMPILE( +[#include ], +[#if DISTCACHE_CLIENT_API != 0x0001 +#error "distcache API version is unrecognised" +#endif], +[], +[tmp_nomessage="distcache has an unsupported API version" +ap_ssltk_dc="no"]) + AC_MSG_RESULT($ap_ssltk_dc) + if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno"; then + AC_MSG_ERROR(distcache support failed: $tmp_nomessage) + fi + fi + if test "$ap_ssltk_dc" = "yes"; then + AC_MSG_CHECKING(for Distcache libraries) + save_libs=$LIBS + LIBS="$LIBS -ldistcache -lnal" + AC_TRY_LINK( + [#include ], + [DC_CTX *foo = DC_CTX_new((const char *)0,0);], + [], + [tmp_no_message="failed to link with distcache libraries" + ap_ssltk_dc="no"]) + LIBS=$save_libs + AC_MSG_RESULT($ap_ssltk_dc) + if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno"; then + AC_MSG_ERROR(distcache support failed: $tmp_nomessage) + else + APR_ADDTO(LIBS,[-ldistcache -lnal]) + AC_DEFINE(HAVE_DISTCACHE, 1, [Define if distcache support is enabled]) + fi + fi +]) + dnl # start of module specific part APACHE_MODPATH_INIT(ssl) @@ -69,12 +142,14 @@ ssl_expr_scan.lo dnl ssl_scache.lo dnl ssl_scache_dbm.lo dnl ssl_scache_shmcb.lo dnl +ssl_scache_dc.lo dnl ssl_util.lo dnl ssl_util_ssl.lo dnl " dnl # hook module into the Autoconf mechanism (--enable-ssl option) APACHE_MODULE(ssl, [SSL/TLS support (mod_ssl)], $ssl_objs, , no, [ APACHE_CHECK_SSL_TOOLKIT + CHECK_DISTCACHE ]) dnl # end of module specific part diff --git a/modules/ssl/mod_ssl.dsp b/modules/ssl/mod_ssl.dsp index 43a106dffa..091539ead1 100644 --- a/modules/ssl/mod_ssl.dsp +++ b/modules/ssl/mod_ssl.dsp @@ -164,6 +164,10 @@ SOURCE=.\ssl_scache_shmcb.c # End Source File # Begin Source File +SOURCE=.\ssl_scache_dc.c +# End Source File +# Begin Source File + SOURCE=.\ssl_util.c # End Source File # Begin Source File diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h index a49ac6f1a9..e93520c6e2 100644 --- a/modules/ssl/mod_ssl.h +++ b/modules/ssl/mod_ssl.h @@ -306,7 +306,8 @@ typedef enum { SSL_SCMODE_UNSET = UNSET, SSL_SCMODE_NONE = 0, SSL_SCMODE_DBM = 1, - SSL_SCMODE_SHMCB = 3 + SSL_SCMODE_SHMCB = 3, + SSL_SCMODE_DC = 4 } ssl_scmode_t; /* @@ -602,7 +603,15 @@ void ssl_scache_shmcb_remove(server_rec *, UCHAR *, int); void ssl_scache_shmcb_expire(server_rec *); void ssl_scache_shmcb_status(request_rec *r, int flags, apr_pool_t *pool); -/* Pass Phrase Support */ +void ssl_scache_dc_init(server_rec *, apr_pool_t *); +void ssl_scache_dc_kill(server_rec *); +BOOL ssl_scache_dc_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); +SSL_SESSION *ssl_scache_dc_retrieve(server_rec *, UCHAR *, int); +void ssl_scache_dc_remove(server_rec *, UCHAR *, int); +void ssl_scache_dc_expire(server_rec *); +void ssl_scache_dc_status(request_rec *r, int flags, apr_pool_t *pool); + +/* PASS Phrase Support */ void ssl_pphrase_Handle(server_rec *, apr_pool_t *); /* Diffie-Hellman Parameter Support */ diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 455fbafb71..53130d1e43 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -1051,6 +1051,19 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, } } } + else if ((arglen > 3) && strcEQn(arg, "dc:", 3)) { +#ifdef HAVE_DISTCACHE + mc->nSessionCacheMode = SSL_SCMODE_DC; + mc->szSessionCacheDataFile = apr_pstrdup(mc->pPool, arg+3); + if (!mc->szSessionCacheDataFile) { + return apr_pstrcat(cmd->pool, + "SSLSessionCache: Invalid cache file path: ", + arg+3, NULL); + } +#else + return "SSLSessionCache: distcache support disabled"; +#endif + } else { return "SSLSessionCache: Invalid argument"; } diff --git a/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c index 67199f7b21..7180c21266 100644 --- a/modules/ssl/ssl_scache.c +++ b/modules/ssl/ssl_scache.c @@ -88,6 +88,10 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_init(s, p); +#ifdef HAVE_DISTCACHE + else if (mc->nSessionCacheMode == SSL_SCMODE_DC) + ssl_scache_dc_init(s, p); +#endif else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) { void *data; const char *userdata_key = "ssl_scache_init"; @@ -110,6 +114,10 @@ void ssl_scache_kill(server_rec *s) ssl_scache_dbm_kill(s); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_kill(s); +#ifdef HAVE_DISTCACHE + else if (mc->nSessionCacheMode == SSL_SCMODE_DC) + ssl_scache_dc_kill(s); +#endif return; } @@ -122,6 +130,10 @@ BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SE rv = ssl_scache_dbm_store(s, id, idlen, expiry, sess); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) rv = ssl_scache_shmcb_store(s, id, idlen, expiry, sess); +#ifdef HAVE_DISTCACHE + else if (mc->nSessionCacheMode == SSL_SCMODE_DC) + rv = ssl_scache_dc_store(s, id, idlen, expiry, sess); +#endif return rv; } @@ -134,6 +146,10 @@ SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen) sess = ssl_scache_dbm_retrieve(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) sess = ssl_scache_shmcb_retrieve(s, id, idlen); +#ifdef HAVE_DISTCACHE + else if (mc->nSessionCacheMode == SSL_SCMODE_DC) + sess = ssl_scache_dc_retrieve(s, id, idlen); +#endif return sess; } @@ -145,6 +161,10 @@ void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen) ssl_scache_dbm_remove(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_remove(s, id, idlen); +#ifdef HAVE_DISTCACHE + else if (mc->nSessionCacheMode == SSL_SCMODE_DC) + ssl_scache_dc_remove(s, id, idlen); +#endif return; } @@ -182,6 +202,10 @@ static int ssl_ext_status_hook(request_rec *r, int flags) ssl_scache_dbm_status(r, flags, r->pool); else if (sc->mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_status(r, flags, r->pool); +#ifdef HAVE_DISTCACHE + else if (sc->mc->nSessionCacheMode == SSL_SCMODE_DC) + ssl_scache_dc_status(r, flags, r->pool); +#endif ap_rputs("\n", r); ap_rputs("\n", r); diff --git a/modules/ssl/ssl_scache_dc.c b/modules/ssl/ssl_scache_dc.c new file mode 100644 index 0000000000..5866568ca4 --- /dev/null +++ b/modules/ssl/ssl_scache_dc.c @@ -0,0 +1,183 @@ +/* _ _ +** _ __ ___ ___ __| | ___ ___| | mod_ssl +** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL +** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org +** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org +** |_____| +** ssl_scache_dc.c +** Distributed Session Cache (client support) +*/ + +/* ==================================================================== + * THIS SOFTWARE IS PROVIDED BY GEOFF THORPE ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR + * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "mod_ssl.h" + +/* Only build this code if it's enabled at configure-time. */ +#ifdef HAVE_DISTCACHE + +#include "distcache/dc_client.h" + +#if !defined(DISTCACHE_CLIENT_API) || (DISTCACHE_CLIENT_API < 0x0001) +#error "You must compile with a more recent version of the distcache-base package" +#endif + +/* + * This cache implementation allows modssl to access 'distcache' servers (or + * proxies) to facilitate distributed session caching. It is based on code + * released as open source by Cryptographic Appliances Inc, and was developed by + * Geoff Thorpe, Steve Robb, and Chris Zimmerman. + */ + +/* +** +** High-Level "handlers" as per ssl_scache.c +** +*/ + +void ssl_scache_dc_init(server_rec *s, apr_pool_t *p) +{ + DC_CTX *ctx; + SSLModConfigRec *mc = myModConfig(s); + /* + * Create a session context + */ + if (mc->szSessionCacheDataFile == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSLSessionCache required"); + ssl_die(); + } +#if 0 + /* If a "persistent connection" mode of operation is preferred, you *must* + * also use the PIDCHECK flag to ensure fork()'d processes don't interlace + * comms on the same connection as each other. */ +#define SESSION_CTX_FLAGS SESSION_CTX_FLAG_PERSISTENT | \ + SESSION_CTX_FLAG_PERSISTENT_PIDCHECK | \ + SESSION_CTX_FLAG_PERSISTENT_RETRY | \ + SESSION_CTX_FLAG_PERSISTENT_LATE +#else + /* This mode of operation will open a temporary connection to the 'target' + * for each cache operation - this makes it safe against fork() + * automatically. This mode is preferred when running a local proxy (over + * unix domain sockets) because overhead is negligable and it reduces the + * performance/stability danger of file-descriptor bloatage. */ +#define SESSION_CTX_FLAGS 0 +#endif + ctx = DC_CTX_new(mc->szSessionCacheDataFile, SESSION_CTX_FLAGS); + if (!ctx) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache failed to obtain context"); + ssl_die(); + } + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "distributed scache context initialised"); + /* + * Success ... + */ + mc->tSessionCacheDataTable = ctx; + return; +} + +void ssl_scache_dc_kill(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (mc->tSessionCacheDataTable) + DC_CTX_free(mc->tSessionCacheDataTable); + mc->tSessionCacheDataTable = NULL; +} + +BOOL ssl_scache_dc_store(server_rec *s, UCHAR *id, int idlen, + time_t timeout, SSL_SESSION * pSession) +{ + unsigned char der[SSL_SESSION_MAX_DER]; + int der_len; + unsigned char *pder = der; + SSLModConfigRec *mc = myModConfig(s); + DC_CTX *ctx = mc->tSessionCacheDataTable; + + /* Serialise the SSL_SESSION object */ + if ((der_len = i2d_SSL_SESSION(pSession, NULL)) > SSL_SESSION_MAX_DER) + return FALSE; + i2d_SSL_SESSION(pSession, &pder); + /* !@#$%^ - why do we deal with *absolute* time anyway??? */ + timeout -= time(NULL); + /* Send the serialised session to the distributed cache context */ + if (!DC_CTX_add_session(ctx, id, idlen, der, der_len, + (unsigned long)timeout * 1000)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'add_session' failed"); + return FALSE; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'add_session' successful"); + return TRUE; +} + +SSL_SESSION *ssl_scache_dc_retrieve(server_rec *s, UCHAR *id, int idlen) +{ + unsigned char der[SSL_SESSION_MAX_DER]; + unsigned int der_len; + SSL_SESSION *pSession; + unsigned char *pder = der; + SSLModConfigRec *mc = myModConfig(s); + DC_CTX *ctx = mc->tSessionCacheDataTable; + + /* Retrieve any corresponding session from the distributed cache context */ + if (!DC_CTX_get_session(ctx, id, idlen, der, SSL_SESSION_MAX_DER, + &der_len)) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' MISS"); + return NULL; + } + if (der_len > SSL_SESSION_MAX_DER) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'get_session' OVERFLOW"); + return NULL; + } + pSession = d2i_SSL_SESSION(NULL, &pder, der_len); + if (!pSession) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'get_session' CORRUPT"); + return NULL; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' HIT"); + return pSession; +} + +void ssl_scache_dc_remove(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + DC_CTX *ctx = mc->tSessionCacheDataTable; + + /* Remove any corresponding session from the distributed cache context */ + if (!DC_CTX_remove_session(ctx, id, idlen)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'remove_session' MISS"); + } else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'remove_session' HIT"); + } +} + +void ssl_scache_dc_expire(server_rec *s) +{ + /* NOP */ + return; +} + +void ssl_scache_dc_status(request_rec *r, int flags, apr_pool_t *pool) +{ + SSLModConfigRec *mc = myModConfig(r->server); + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "distributed scache 'ssl_scache_dc_status'"); + ap_rprintf(r, "cache type: DC (Distributed Cache), " + " target: %s
", mc->szSessionCacheDataFile); +} + +#endif +