From b8c651209f1f38843d81b737cf9a484a3d17409c Mon Sep 17 00:00:00 2001 From: Ben Laurie Date: Sun, 11 Feb 2001 17:46:19 +0000 Subject: [PATCH] First cut of TLS support. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88090 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 4 + include/util_filter.h | 15 +- modules/tls/.cvsignore | 5 + modules/tls/Makefile.in | 9 + modules/tls/Makefile.libdir | 4 + modules/tls/README | 19 ++ modules/tls/config.m4 | 5 + modules/tls/mod_tls.c | 350 ++++++++++++++++++++++++++++ modules/tls/openssl_state_machine.c | 247 ++++++++++++++++++++ modules/tls/openssl_state_machine.h | 14 ++ server/util_filter.c | 28 +-- 11 files changed, 679 insertions(+), 21 deletions(-) create mode 100644 modules/tls/.cvsignore create mode 100644 modules/tls/Makefile.in create mode 100644 modules/tls/Makefile.libdir create mode 100644 modules/tls/README create mode 100644 modules/tls/config.m4 create mode 100644 modules/tls/mod_tls.c create mode 100644 modules/tls/openssl_state_machine.c create mode 100644 modules/tls/openssl_state_machine.h diff --git a/CHANGES b/CHANGES index f76bfb5fe4..f3a8e3b165 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ Changes with Apache 2.0b1 + *) Add a very early prototype of SSL support (in mod_tls.c). It is + vital that you read modules/tls/README before attempting to build + it. [Ben Laurie] + *) Fix a potential seg fault on all platforms. David Reid fixed this on BEOS, but the problem could happen anywhere, so we don't want to #ifdef it. [Cliff Woolley ] diff --git a/include/util_filter.h b/include/util_filter.h index 5914bf2a94..7e3858a00c 100644 --- a/include/util_filter.h +++ b/include/util_filter.h @@ -312,8 +312,8 @@ AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade * @param ftype The type of filter function, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION */ AP_DECLARE(void) ap_register_input_filter(const char *name, - ap_in_filter_func filter_func, - ap_filter_type ftype); + ap_in_filter_func filter_func, + ap_filter_type ftype); /** * This function is used to register an output filter with the system. * After this registration is performed, then a filter may be added @@ -326,8 +326,8 @@ AP_DECLARE(void) ap_register_input_filter(const char *name, * @see ::ap_add_output_filter */ AP_DECLARE(void) ap_register_output_filter(const char *name, - ap_out_filter_func filter_func, - ap_filter_type ftype); + ap_out_filter_func filter_func, + ap_filter_type ftype); /* * ap_add_filter(): @@ -352,7 +352,8 @@ AP_DECLARE(void) ap_register_output_filter(const char *name, * @param c The connection to add the fillter for * @deffunc void ap_add_input_filter(const char *name, void *ctx, request_rec *r, conn_rec *c) */ -AP_DECLARE(void) ap_add_input_filter(const char *name, void *ctx, request_rec *r, conn_rec *c); +AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx, + request_rec *r, conn_rec *c); /** * Add a filter to the current request. Filters are added in a FIFO manner. @@ -363,8 +364,8 @@ AP_DECLARE(void) ap_add_input_filter(const char *name, void *ctx, request_rec *r * @param c The connection to add this filter for * @deffunc void ap_add_output_filter(const char *name, void *ctx, request_rec *r, conn_rec *c) */ -AP_DECLARE(void) ap_add_output_filter(const char *name, void *ctx, - request_rec *r, conn_rec *c); +AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx, + request_rec *r, conn_rec *c); AP_DECLARE(void) ap_remove_output_filter(ap_filter_t *f); diff --git a/modules/tls/.cvsignore b/modules/tls/.cvsignore new file mode 100644 index 0000000000..3e699dd433 --- /dev/null +++ b/modules/tls/.cvsignore @@ -0,0 +1,5 @@ +.libs +.deps +Makefile +*.lo +*.la diff --git a/modules/tls/Makefile.in b/modules/tls/Makefile.in new file mode 100644 index 0000000000..361b134e90 --- /dev/null +++ b/modules/tls/Makefile.in @@ -0,0 +1,9 @@ +LTLIBRARY_NAME = libapachemod_tls.la +LTLIBRARY_SOURCES = mod_tls.lo openssl_state_machine.lo + +# temp! +openssl_state_machine.lo: openssl_state_machine.c + gcc -I. -I/usr/home/ben/work/httpd-2.0/modules/tls -I/usr/home/ben/work/httpd-2.0/server/mpm/prefork -I/usr/home/ben/work/httpd-2.0/include -I/usr/home/ben/work/httpd-2.0/srclib/apr/include -I/usr/home/ben/work/httpd-2.0/srclib/apr-util/include -I/usr/home/ben/work/httpd-2.0/os/unix -I/usr/home/ben/work/httpd-2.0/srclib/expat-lite -I/home/ben/work/openssl/include -I/home/ben/work/openssl/include -D_REENTRANT -D_THREAD_SAFE -g -O2 -g -Wall -Wmissing-prototypes -Wmissing-declarations -DAP_DEBUG -DNO_KRB5 -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DPEDANTIC -DDEBUG_SAFESTACK -c openssl_state_machine.c -o openssl_state_machine.lo + +include $(top_srcdir)/build/ltlib.mk + diff --git a/modules/tls/Makefile.libdir b/modules/tls/Makefile.libdir new file mode 100644 index 0000000000..7b5254013a --- /dev/null +++ b/modules/tls/Makefile.libdir @@ -0,0 +1,4 @@ +This is a place-holder which indicates to Configure that it shouldn't +provide the default targets when building the Makefile in this directory. +Instead it'll just prepend all the important variable definitions, and +copy the Makefile.tmpl onto the end. diff --git a/modules/tls/README b/modules/tls/README new file mode 100644 index 0000000000..355482dda6 --- /dev/null +++ b/modules/tls/README @@ -0,0 +1,19 @@ +This currently won't work with Apache unaided. The manual things I +have to do to make it work are: + +edit .../httpd-2.0/config_vars.mk: + +Add "-L -lssl -lcrypto" to EXTRA_LIBS. + +Change "modules/tls/mod_tls.la" to "modules/tls/libapachemod_tls.la" in +BUILTIN_LIBS. + +edit .../httpd-2.0/modules/tls/Makefile.in: + +Diddle with the openssl_state_machine.lo target to match your setup. + +Then all you need is "TLSFilter on" and "TLSCertificateFile " in +your config, and you are away (note that the cert file must also +contain the private key at present). + +Ben Laurie, 11 Feb 2001. diff --git a/modules/tls/config.m4 b/modules/tls/config.m4 new file mode 100644 index 0000000000..9874f6b2b7 --- /dev/null +++ b/modules/tls/config.m4 @@ -0,0 +1,5 @@ +APACHE_MODPATH_INIT(tls) + +APACHE_MODULE(tls, TLS/SSL support, , , no) + +APACHE_MODPATH_FINISH diff --git a/modules/tls/mod_tls.c b/modules/tls/mod_tls.c new file mode 100644 index 0000000000..d4795d29a4 --- /dev/null +++ b/modules/tls/mod_tls.c @@ -0,0 +1,350 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2001 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR + * ITS 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +#include "httpd.h" +#include "http_config.h" +#include "util_filter.h" +#include "http_connection.h" +#include "openssl_state_machine.h" +#include "apr_strings.h" +#include "http_protocol.h" + +// temp +#include + +AP_DECLARE_DATA module tls_module; +static const char s_szTLSFilterName[]="TLSFilter"; +typedef struct +{ + int bEnabled; + const char *szCertificateFile; + const char *szKeyFile; +} TLSServerConfig; + +typedef struct +{ + SSLStateMachine *pStateMachine; + ap_filter_t *pInputFilter; + ap_filter_t *pOutputFilter; +} TLSFilterCtx; + +static void *create_tls_server_config(apr_pool_t *p, server_rec *s) +{ + TLSServerConfig *pConfig = apr_pcalloc(p, sizeof *pConfig); + + pConfig->bEnabled = 0; + pConfig->szCertificateFile = pConfig->szKeyFile = NULL; + + return pConfig; +} + +static const char *tls_on(cmd_parms *cmd, void *dummy, int arg) +{ + TLSServerConfig *pConfig = ap_get_module_config(cmd->server->module_config, + &tls_module); + pConfig->bEnabled = arg; + + return NULL; +} + +static const char *tls_cert_file(cmd_parms *cmd, void *dummy, const char *arg) +{ + TLSServerConfig *pConfig = ap_get_module_config(cmd->server->module_config, + &tls_module); + pConfig->szCertificateFile = arg; + + // temp + pConfig->szKeyFile=pConfig->szCertificateFile; + + return NULL; +} + +static int tls_filter_inserter(conn_rec *c) +{ + TLSServerConfig *pConfig = + ap_get_module_config(c->base_server->module_config, + &tls_module); + TLSFilterCtx *pCtx; + + if (!pConfig->bEnabled) + return DECLINED; + + pCtx=apr_pcalloc(c->pool,sizeof *pCtx); + pCtx->pStateMachine=SSLStateMachine_new(pConfig->szCertificateFile, + pConfig->szKeyFile); + + pCtx->pInputFilter=ap_add_input_filter(s_szTLSFilterName,pCtx,NULL,c); + pCtx->pOutputFilter=ap_add_output_filter(s_szTLSFilterName,pCtx,NULL, + c); + + return OK; +} + +static apr_status_t churn(TLSFilterCtx *pCtx) +{ + apr_bucket_brigade *pbbOutput=NULL; + int done; + + do { + char buf[1024]; + int n; + apr_bucket *pbkt; + + done=0; + + n=SSLStateMachine_write_extract(pCtx->pStateMachine,buf,sizeof buf); + if(n > 0) { + if(!pbbOutput) + pbbOutput=apr_brigade_create(pCtx->pOutputFilter->c->pool); + pbkt=apr_bucket_pool_create(buf,n,pCtx->pOutputFilter->c->pool); + APR_BRIGADE_INSERT_TAIL(pbbOutput,pbkt); + done=1; + /* } else if(n == 0) { + apr_bucket *pbktEOS=apr_bucket_create_eos(); + APR_BRIGADE_INSERT_TAIL(pbbOutput,pbktEOS);*/ + } + } while(done); + + // XXX: check for errors + if(pbbOutput) { + apr_bucket *pbkt; + + // XXX: it may be possible to not always flush + pbkt=apr_bucket_flush_create(); + APR_BRIGADE_INSERT_TAIL(pbbOutput,pbkt); + ap_pass_brigade(pCtx->pOutputFilter->next,pbbOutput); + } + + return APR_SUCCESS; +} + +static apr_status_t tls_out_filter(ap_filter_t *f,apr_bucket_brigade *pbbIn) +{ + TLSFilterCtx *pCtx=f->ctx; + apr_bucket *pbktIn; + int bFlush=0; + apr_status_t ret; + + APR_BRIGADE_FOREACH(pbktIn,pbbIn) { + const char *data; + apr_size_t len; + + if(APR_BUCKET_IS_EOS(pbktIn)) { + // XXX: why can't I reuse pbktIn??? + // XXX: isn't this wrong? + // Write eof! + break; + } + + if(APR_BUCKET_IS_FLUSH(pbktIn)) { + bFlush=1; + continue; + } + + // read filter + apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ); + + // write SSL + SSLStateMachine_write_inject(pCtx->pStateMachine,data,len); + + } + + // churn the state machine + ret=churn(pCtx); + + if(bFlush) { + apr_bucket_brigade *pbbOut; + apr_bucket *pbktOut; + + pbbOut=apr_brigade_create(f->c->pool); + pbktOut=apr_bucket_flush_create(); + APR_BRIGADE_INSERT_TAIL(pbbOut,pbktOut); + // XXX: and what if this returns an error??? + ap_pass_brigade(f->next,pbbOut); + } + return ret; +} + +static apr_status_t tls_in_filter(ap_filter_t *f,apr_bucket_brigade *pbbOut, + ap_input_mode_t eMode) +{ + TLSFilterCtx *pCtx=f->ctx; + apr_bucket *pbktIn; + apr_bucket_brigade *pbbIn; + apr_read_type_e eReadType=eMode == AP_MODE_BLOCKING ? APR_BLOCK_READ : + APR_NONBLOCK_READ; + + // XXX: we don't currently support peek + assert(eMode != AP_MODE_PEEK); + + pbbIn=apr_brigade_create(f->c->pool); + ap_get_brigade(f->next,pbbIn,eMode); + + APR_BRIGADE_FOREACH(pbktIn,pbbIn) { + const char *data; + apr_size_t len; + int n; + char buf[1024]; + + if(APR_BUCKET_IS_EOS(pbktIn)) { + // XXX: why can't I reuse pbktIn??? + // XX: isn't this wrong? + // Write eof! + break; + } + + // read filter + apr_bucket_read(pbktIn,&data,&len,eReadType); + + // presumably this can only happen when we are non-blocking + if(len == 0) { + assert(eReadType == APR_NONBLOCK_READ); + break; + } + + assert(len > 0); + + // write SSL + SSLStateMachine_read_inject(pCtx->pStateMachine,data,len); + + n=SSLStateMachine_read_extract(pCtx->pStateMachine,buf,sizeof buf); + if(n > 0) { + apr_bucket *pbktOut; + char *pbuf; + + pbuf=apr_memdup(pCtx->pInputFilter->c->pool,buf,n); + // XXX: should we use a heap bucket instead? Or a transient (in + // which case we need a separate brigade for each bucket)? + pbktOut=apr_bucket_pool_create(pbuf,n,pCtx->pInputFilter->c->pool); + APR_BRIGADE_INSERT_TAIL(pbbOut,pbktOut); + + // Once we've read something, we can move to non-blocking mode (if + // we weren't already). + eReadType=APR_NONBLOCK_READ; + + // XXX: deal with EOF! + /* } else if(n == 0) { + apr_bucket *pbktEOS=apr_bucket_create_eos(); + APR_BRIGADE_INSERT_TAIL(pbbInput,pbktEOS);*/ + } + assert(n >= 0); + + // churn the state machine + // XXX: check for errors + churn(pCtx); + } + + return APR_SUCCESS; +} + +static const char *tls_method(const request_rec *r) +{ + TLSServerConfig *pConfig = + ap_get_module_config(r->connection->base_server->module_config, + &tls_module); + + if (!pConfig->bEnabled) + return NULL; + + return "https"; +} + +static unsigned short tls_port(const request_rec *r) +{ + TLSServerConfig *pConfig = + ap_get_module_config(r->connection->base_server->module_config, + &tls_module); + + if (!pConfig->bEnabled) + return 0; + + return 443; +} + +static const command_rec tls_cmds[] = +{ + /* XXX: We should be able to add the filter using AddOutputFilter */ + AP_INIT_FLAG("TLSFilter", tls_on, NULL, RSRC_CONF, + "Run TLS/SSL on this host"), + AP_INIT_TAKE1("TLSCertificateFile", tls_cert_file, NULL, RSRC_CONF, + "Set the certificate file for this host"), + { NULL } +}; + +static void register_hooks(apr_pool_t *p) +{ + SSLStateMachine_init(); + + ap_register_output_filter(s_szTLSFilterName,tls_out_filter, + AP_FTYPE_NETWORK); + ap_register_input_filter(s_szTLSFilterName,tls_in_filter, + AP_FTYPE_NETWORK); + ap_hook_pre_connection(tls_filter_inserter,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_default_port(tls_port,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_http_method(tls_method,NULL,NULL,APR_HOOK_MIDDLE); +} + +AP_DECLARE_DATA module tls_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + create_tls_server_config, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + tls_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; diff --git a/modules/tls/openssl_state_machine.c b/modules/tls/openssl_state_machine.c new file mode 100644 index 0000000000..94d9cee1a1 --- /dev/null +++ b/modules/tls/openssl_state_machine.c @@ -0,0 +1,247 @@ +/* This is adapted from the OpenSSL state_machine demo */ + +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 THE OpenSSL PROJECT OR + * ITS 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* + * Nuron, a leader in hardware encryption technology, generously + * sponsored the development of this demo by Ben Laurie. + * + * See http://www.nuron.com/. + */ + +/* + * the aim of this demo is to provide a fully working state-machine + * style SSL implementation, i.e. one where the main loop acquires + * some data, then converts it from or to SSL by feeding it into the + * SSL state machine. It then does any I/O required by the state machine + * and loops. + * + * In order to keep things as simple as possible, this implementation + * listens on a TCP socket, which it expects to get an SSL connection + * on (for example, from s_client) and from then on writes decrypted + * data to stdout and encrypts anything arriving on stdin. Verbose + * commentary is written to stderr. + * + * This implementation acts as a server, but it can also be done for a client. */ + +#include +#include +#include +#include +#include +#include "openssl_state_machine.h" + +/* die_unless is intended to work like assert, except that it happens + always, even if NDEBUG is defined. Use assert as a stopgap. */ + +#define die_unless(x) assert(x) + +struct SSLStateMachine + { + SSL_CTX *pCtx; + BIO *pbioRead; + BIO *pbioWrite; + SSL *pSSL; + }; + +void SSLStateMachine_init(void) +{ + static int s_bInitDone; + + if(s_bInitDone) + return; + + SSL_library_init(); + OpenSSL_add_ssl_algorithms(); + SSL_load_error_strings(); + ERR_load_crypto_strings(); + + s_bInitDone=1; +} + +static void SSLStateMachine_print_error(SSLStateMachine *pMachine, + const char *szErr) + { + unsigned long l; + + fprintf(stderr,"%s\n",szErr); + while((l=ERR_get_error())) + { + char buf[1024]; + + ERR_error_string_n(l,buf,sizeof buf); + fprintf(stderr,"Error %lx: %s\n",l,buf); + } + } + +SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile, + const char *szKeyFile) + { + SSLStateMachine *pMachine=malloc(sizeof *pMachine); + int n; + + die_unless(pMachine); + + pMachine->pCtx=SSL_CTX_new(SSLv23_server_method()); + die_unless(pMachine->pCtx); + + n=SSL_CTX_use_certificate_file(pMachine->pCtx,szCertificateFile, + SSL_FILETYPE_PEM); + die_unless(n > 0); + + n=SSL_CTX_use_PrivateKey_file(pMachine->pCtx,szKeyFile,SSL_FILETYPE_PEM); + die_unless(n > 0); + + pMachine->pSSL=SSL_new(pMachine->pCtx); + die_unless(pMachine->pSSL); + + pMachine->pbioRead=BIO_new(BIO_s_mem()); + + pMachine->pbioWrite=BIO_new(BIO_s_mem()); + + SSL_set_bio(pMachine->pSSL,pMachine->pbioRead,pMachine->pbioWrite); + + SSL_set_accept_state(pMachine->pSSL); + + return pMachine; + } + +void SSLStateMachine_read_inject(SSLStateMachine *pMachine, + const unsigned char *aucBuf,int nBuf) + { + int n=BIO_write(pMachine->pbioRead,aucBuf,nBuf); + /* If it turns out this assert fails, then buffer the data here + * and just feed it in in churn instead. Seems to me that it + * should be guaranteed to succeed, though. + */ + assert(n == nBuf); + fprintf(stderr,"%d bytes of encrypted data fed to state machine\n",n); + } + +int SSLStateMachine_read_extract(SSLStateMachine *pMachine, + unsigned char *aucBuf,int nBuf) + { + int n; + + if(!SSL_is_init_finished(pMachine->pSSL)) + { + fprintf(stderr,"Doing SSL_accept\n"); + n=SSL_accept(pMachine->pSSL); + if(n == 0) + fprintf(stderr,"SSL_accept returned zero\n"); + if(n < 0) + { + int err; + + if((err=SSL_get_error(pMachine->pSSL,n)) == SSL_ERROR_WANT_READ) + { + fprintf(stderr,"SSL_accept wants more data\n"); + return 0; + } + + SSLStateMachine_print_error(pMachine,"SSL_accept error"); + exit(7); + } + return 0; + } + + n=SSL_read(pMachine->pSSL,aucBuf,nBuf); + if(n < 0) + { + int err=SSL_get_error(pMachine->pSSL,n); + + if(err == SSL_ERROR_WANT_READ) + { + fprintf(stderr,"SSL_read wants more data\n"); + return 0; + } + } + + fprintf(stderr,"%d bytes of decrypted data read from state machine\n",n); + return n; + } + +int SSLStateMachine_write_can_extract(SSLStateMachine *pMachine) + { + int n=BIO_pending(pMachine->pbioWrite); + if(n) + fprintf(stderr,"There is encrypted data available to write\n"); + else + fprintf(stderr,"There is no encrypted data available to write\n"); + + return n; + } + +int SSLStateMachine_write_extract(SSLStateMachine *pMachine, + unsigned char *aucBuf,int nBuf) + { + int n; + + n=BIO_read(pMachine->pbioWrite,aucBuf,nBuf); + fprintf(stderr,"%d bytes of encrypted data read from state machine\n",n); + return n; + } + +void SSLStateMachine_write_inject(SSLStateMachine *pMachine, + const unsigned char *aucBuf,int nBuf) + { + int n=SSL_write(pMachine->pSSL,aucBuf,nBuf); + /* If it turns out this assert fails, then buffer the data here + * and just feed it in in churn instead. Seems to me that it + * should be guaranteed to succeed, though. + */ + assert(n == nBuf); + fprintf(stderr,"%d bytes of unencrypted data fed to state machine\n",n); + } diff --git a/modules/tls/openssl_state_machine.h b/modules/tls/openssl_state_machine.h new file mode 100644 index 0000000000..84df580f41 --- /dev/null +++ b/modules/tls/openssl_state_machine.h @@ -0,0 +1,14 @@ +typedef struct SSLStateMachine SSLStateMachine; + +void SSLStateMachine_init(void); +SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile, + const char *szKeyFile); +void SSLStateMachine_read_inject(SSLStateMachine *pMachine, + const unsigned char *aucBuf,int nBuf); +int SSLStateMachine_read_extract(SSLStateMachine *pMachine, + unsigned char *aucBuf,int nBuf); +int SSLStateMachine_write_can_extract(SSLStateMachine *pMachine); +int SSLStateMachine_write_extract(SSLStateMachine *pMachine, + unsigned char *aucBuf,int nBuf); +void SSLStateMachine_write_inject(SSLStateMachine *pMachine, + const unsigned char *aucBuf,int nBuf); diff --git a/server/util_filter.c b/server/util_filter.c index c4fef0de5e..f344762604 100644 --- a/server/util_filter.c +++ b/server/util_filter.c @@ -124,11 +124,11 @@ AP_DECLARE(void) ap_register_output_filter(const char *name, register_filter(name, f, ftype, ®istered_output_filters); } -static void add_any_filter(const char *name, void *ctx, - request_rec *r, conn_rec *c, - ap_filter_rec_t *frec, - ap_filter_t **r_filters, - ap_filter_t **c_filters) +static ap_filter_t *add_any_filter(const char *name, void *ctx, + request_rec *r, conn_rec *c, + ap_filter_rec_t *frec, + ap_filter_t **r_filters, + ap_filter_t **c_filters) { for (; frec != NULL; frec = frec->next) { if (!strcasecmp(name, frec->name)) { @@ -153,7 +153,7 @@ static void add_any_filter(const char *name, void *ctx, fscan->next = f; } - return; + return f; } } @@ -161,18 +161,18 @@ static void add_any_filter(const char *name, void *ctx, "an unknown filter was not added: %s", name); } -AP_DECLARE(void) ap_add_input_filter(const char *name, void *ctx, - request_rec *r, conn_rec *c) +AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx, + request_rec *r, conn_rec *c) { - add_any_filter(name, ctx, r, c, registered_input_filters, - r ? &r->input_filters : NULL, &c->input_filters); + return add_any_filter(name, ctx, r, c, registered_input_filters, + r ? &r->input_filters : NULL, &c->input_filters); } -AP_DECLARE(void) ap_add_output_filter(const char *name, void *ctx, - request_rec *r, conn_rec *c) +AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx, + request_rec *r, conn_rec *c) { - add_any_filter(name, ctx, r, c, registered_output_filters, - r ? &r->output_filters : NULL, &c->output_filters); + return add_any_filter(name, ctx, r, c, registered_output_filters, + r ? &r->output_filters : NULL, &c->output_filters); } AP_DECLARE(void) ap_remove_output_filter(ap_filter_t *f) -- 2.50.0