diff options
author | Ben Laurie <ben@apache.org> | 2001-02-18 03:10:27 +0100 |
---|---|---|
committer | Ben Laurie <ben@apache.org> | 2001-02-18 03:10:27 +0100 |
commit | 0ca2444b8a33a2fd67cdc333da451f1286c98188 (patch) | |
tree | e4bc38d0770bac00050065744600dda53c931372 /modules/tls | |
parent | use "conf" rather than "sec" for the configuration data. misc style, (diff) | |
download | apache2-0ca2444b8a33a2fd67cdc333da451f1286c98188.tar.xz apache2-0ca2444b8a33a2fd67cdc333da451f1286c98188.zip |
Working SSL/TLS! Yay!
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88223 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/tls')
-rw-r--r-- | modules/tls/mod_tls.c | 212 | ||||
-rw-r--r-- | modules/tls/openssl_state_machine.c | 15 | ||||
-rw-r--r-- | modules/tls/openssl_state_machine.h | 1 |
3 files changed, 153 insertions, 75 deletions
diff --git a/modules/tls/mod_tls.c b/modules/tls/mod_tls.c index 04c8858568..fda4240854 100644 --- a/modules/tls/mod_tls.c +++ b/modules/tls/mod_tls.c @@ -63,6 +63,7 @@ #include "openssl_state_machine.h" #include "apr_strings.h" #include "http_protocol.h" +#include "http_log.h" // temp #include <assert.h> @@ -81,7 +82,8 @@ typedef struct SSLStateMachine *pStateMachine; ap_filter_t *pInputFilter; ap_filter_t *pOutputFilter; - apr_bucket_brigade *pbbInput; + apr_bucket_brigade *pbbInput; /* encrypted input */ + apr_bucket_brigade *pbbPendingInput; /* decrypted input */ } TLSFilterCtx; static void *create_tls_server_config(apr_pool_t *p, server_rec *s) @@ -132,11 +134,12 @@ static int tls_filter_inserter(conn_rec *c) pCtx->pInputFilter=ap_add_input_filter(s_szTLSFilterName,pCtx,NULL,c); pCtx->pOutputFilter=ap_add_output_filter(s_szTLSFilterName,pCtx,NULL,c); pCtx->pbbInput=apr_brigade_create(c->pool); + pCtx->pbbPendingInput=apr_brigade_create(c->pool); return OK; } -static apr_status_t churn(TLSFilterCtx *pCtx) +static apr_status_t churn_output(TLSFilterCtx *pCtx) { apr_bucket_brigade *pbbOutput=NULL; int done; @@ -148,16 +151,25 @@ static apr_status_t churn(TLSFilterCtx *pCtx) 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);*/ + if(SSLStateMachine_write_can_extract(pCtx->pStateMachine)) { + n=SSLStateMachine_write_extract(pCtx->pStateMachine,buf, + sizeof buf); + if(n > 0) { + char *pbuf; + + if(!pbbOutput) + pbbOutput=apr_brigade_create(pCtx->pOutputFilter->c->pool); + + pbuf=apr_pmemdup(pCtx->pOutputFilter->c->pool,buf,n); + pbkt=apr_bucket_pool_create(pbuf,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);*/ + } + assert(n > 0); } } while(done); @@ -174,87 +186,59 @@ static apr_status_t churn(TLSFilterCtx *pCtx) return APR_SUCCESS; } -static apr_status_t tls_out_filter(ap_filter_t *f,apr_bucket_brigade *pbbIn) +static apr_status_t churn(TLSFilterCtx *pCtx,apr_read_type_e eReadType) { - TLSFilterCtx *pCtx=f->ctx; + ap_input_mode_t eMode=eReadType == APR_BLOCK_READ ? AP_MODE_BLOCKING + : AP_MODE_NONBLOCKING; 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); + if(APR_BRIGADE_EMPTY(pCtx->pbbInput)) { + ap_get_brigade(pCtx->pInputFilter->next,pCtx->pbbInput,eMode); + if(APR_BRIGADE_EMPTY(pCtx->pbbInput)) + return APR_EOF; } - 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_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); - - if(APR_BRIGADE_EMPTY(pCtx->pbbInput)) - ap_get_brigade(f->next,pCtx->pbbInput,eMode); APR_BRIGADE_FOREACH(pbktIn,pCtx->pbbInput) { const char *data; apr_size_t len; int n; char buf[1024]; + apr_status_t ret; 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); + ret=apr_bucket_read(pbktIn,&data,&len,eReadType); + + APR_BUCKET_REMOVE(pbktIn); + + if(ret == APR_SUCCESS && len == 0 && eReadType == APR_BLOCK_READ) + ret=APR_EOF; - // presumably this can only happen when we are non-blocking if(len == 0) { + // Lazy frickin browsers just reset instead of shutting down. + if(ret == APR_EOF || ret == APR_ECONNRESET) + if(APR_BRIGADE_EMPTY(pCtx->pbbPendingInput)) + return APR_EOF; + else + /* Next time around, the incoming brigade will be empty, + * so we'll return EOF then + */ + return APR_SUCCESS; + + if(eReadType != APR_NONBLOCK_READ) + ap_log_error(APLOG_MARK,APLOG_ERR,ret,NULL, + "Read failed in tls_in_filter"); assert(eReadType == APR_NONBLOCK_READ); - break; + assert(ret == APR_SUCCESS || ret == APR_EAGAIN); + /* In this case, we have data in the output bucket, or we were + * non-blocking, so returning nothing is fine. + */ + return APR_SUCCESS; } assert(len > 0); @@ -271,7 +255,7 @@ static apr_status_t tls_in_filter(ap_filter_t *f,apr_bucket_brigade *pbbOut, // 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); + APR_BRIGADE_INSERT_TAIL(pCtx->pbbPendingInput,pbktOut); // Once we've read something, we can move to non-blocking mode (if // we weren't already). @@ -284,9 +268,87 @@ static apr_status_t tls_in_filter(ap_filter_t *f,apr_bucket_brigade *pbbOut, } assert(n >= 0); + ret=churn_output(pCtx); + if(ret != APR_SUCCESS) + return ret; + } + + return churn_output(pCtx); +} + +static apr_status_t tls_out_filter(ap_filter_t *f,apr_bucket_brigade *pbbIn) +{ + TLSFilterCtx *pCtx=f->ctx; + apr_bucket *pbktIn; + + APR_BRIGADE_FOREACH(pbktIn,pbbIn) { + const char *data; + apr_size_t len; + apr_status_t ret; + + if(APR_BUCKET_IS_EOS(pbktIn)) { + // XXX: demote to debug + ap_log_error(APLOG_MARK,APLOG_ERR,0,NULL,"Got EOS on output"); + SSLStateMachine_write_close(pCtx->pStateMachine); + // XXX: dubious - does this always terminate? Does it return the right thing? + for( ; ; ) { + ret=churn_output(pCtx); + if(ret != APR_SUCCESS) + return ret; + ret=churn(pCtx,APR_NONBLOCK_READ); + if(ret != APR_SUCCESS) + if(ret == APR_EOF) + return APR_SUCCESS; + else + return ret; + } + break; + } + + if(APR_BUCKET_IS_FLUSH(pbktIn)) { + // assume that churn will flush (or already has) if there's output + ret=churn(pCtx,APR_NONBLOCK_READ); + if(ret != APR_SUCCESS) + return ret; + 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 - // XXX: check for errors - churn(pCtx); + ret=churn_output(pCtx); + if(ret != APR_SUCCESS) + return ret; + } + + return APR_SUCCESS; +} + +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_read_type_e eReadType=eMode == AP_MODE_BLOCKING ? APR_BLOCK_READ : + APR_NONBLOCK_READ; + apr_status_t ret; + + // XXX: we don't currently support peek + assert(eMode != AP_MODE_PEEK); + + // churn the state machine + ret=churn(pCtx,eReadType); + if(ret != APR_SUCCESS) + return ret; + + // XXX: shame that APR_BRIGADE_FOREACH doesn't work here + while(!APR_BRIGADE_EMPTY(pCtx->pbbPendingInput)) { + apr_bucket *pbktIn=APR_BRIGADE_FIRST(pCtx->pbbPendingInput); + APR_BUCKET_REMOVE(pbktIn); + APR_BRIGADE_INSERT_TAIL(pbbOut,pbktIn); } return APR_SUCCESS; diff --git a/modules/tls/openssl_state_machine.c b/modules/tls/openssl_state_machine.c index d6d01bd878..82c86a404a 100644 --- a/modules/tls/openssl_state_machine.c +++ b/modules/tls/openssl_state_machine.c @@ -240,6 +240,16 @@ void SSLStateMachine_write_inject(SSLStateMachine *pMachine, const unsigned char *aucBuf,int nBuf) { int n=SSL_write(pMachine->pSSL,aucBuf,nBuf); + if(n < 0) + { + if(ERR_peek_error() == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL_WRITE, + SSL_R_PROTOCOL_IS_SHUTDOWN)) + { + SSLStateMachine_print_error(pMachine,"SSL_write error (someone wrote after shutdown)"); + return; + } + SSLStateMachine_print_error(pMachine,"SSL_write error"); + } /* 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. @@ -247,3 +257,8 @@ void SSLStateMachine_write_inject(SSLStateMachine *pMachine, assert(n == nBuf); fprintf(stderr,"%d bytes of unencrypted data fed to state machine\n",n); } + +void SSLStateMachine_write_close(SSLStateMachine *pMachine) + { + SSL_shutdown(pMachine->pSSL); + } diff --git a/modules/tls/openssl_state_machine.h b/modules/tls/openssl_state_machine.h index 84df580f41..10be69a3b0 100644 --- a/modules/tls/openssl_state_machine.h +++ b/modules/tls/openssl_state_machine.h @@ -12,3 +12,4 @@ int SSLStateMachine_write_extract(SSLStateMachine *pMachine, unsigned char *aucBuf,int nBuf); void SSLStateMachine_write_inject(SSLStateMachine *pMachine, const unsigned char *aucBuf,int nBuf); +void SSLStateMachine_write_close(SSLStateMachine *pMachine); |