]> granicus.if.org Git - apache/commitdiff
First cut of TLS support.
authorBen Laurie <ben@apache.org>
Sun, 11 Feb 2001 17:46:19 +0000 (17:46 +0000)
committerBen Laurie <ben@apache.org>
Sun, 11 Feb 2001 17:46:19 +0000 (17:46 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88090 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
include/util_filter.h
modules/tls/.cvsignore [new file with mode: 0644]
modules/tls/Makefile.in [new file with mode: 0644]
modules/tls/Makefile.libdir [new file with mode: 0644]
modules/tls/README [new file with mode: 0644]
modules/tls/config.m4 [new file with mode: 0644]
modules/tls/mod_tls.c [new file with mode: 0644]
modules/tls/openssl_state_machine.c [new file with mode: 0644]
modules/tls/openssl_state_machine.h [new file with mode: 0644]
server/util_filter.c

diff --git a/CHANGES b/CHANGES
index f76bfb5fe4b9676ad57825b3ccb41cd8b7385284..f3a8e3b165103fd891ba36fa3877484bfb71ebba 100644 (file)
--- 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 <cliffwoolley@yahoo.com>]
index 5914bf2a941c2da43eaab8455e8502dcc4d3f152..7e3858a00cb5eee0ffc41eace7d05224108455f1 100644 (file)
@@ -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 (file)
index 0000000..3e699dd
--- /dev/null
@@ -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 (file)
index 0000000..361b134
--- /dev/null
@@ -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 (file)
index 0000000..7b52540
--- /dev/null
@@ -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 (file)
index 0000000..355482d
--- /dev/null
@@ -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<where OpenSSL is> -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 <file>" 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 (file)
index 0000000..9874f6b
--- /dev/null
@@ -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 (file)
index 0000000..d4795d2
--- /dev/null
@@ -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
+ * <http://www.apache.org/>.
+ *
+ * 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 <assert.h>
+
+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 (file)
index 0000000..94d9cee
--- /dev/null
@@ -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 <openssl/ssl.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <openssl/err.h>
+#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 (file)
index 0000000..84df580
--- /dev/null
@@ -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);
index c4fef0de5e1c5af27e254ca550517879ef179fae..f3447626042724965625bbf28024eee1725c7312 100644 (file)
@@ -124,11 +124,11 @@ AP_DECLARE(void) ap_register_output_filter(const char *name,
     register_filter(name, f, ftype, &registered_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)