You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by be...@apache.org on 2001/02/18 03:10:28 UTC

cvs commit: httpd-2.0/modules/tls mod_tls.c openssl_state_machine.c openssl_state_machine.h

ben         01/02/17 18:10:28

  Modified:    .        CHANGES
               modules/tls mod_tls.c openssl_state_machine.c
                        openssl_state_machine.h
  Log:
  Working SSL/TLS! Yay!
  
  Revision  Changes    Path
  1.98      +3 -0      httpd-2.0/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/CHANGES,v
  retrieving revision 1.97
  retrieving revision 1.98
  diff -u -r1.97 -r1.98
  --- CHANGES	2001/02/17 23:58:30	1.97
  +++ CHANGES	2001/02/18 02:10:25	1.98
  @@ -1,5 +1,8 @@
   Changes with Apache 2.0.12-dev
   
  +  *) Get mod_tls to the point where it actually appears to work in all cases.
  +     [Ben Laurie]
  +
     *) implement --enable-modules and --enable-mods-shared for "all" and
        "most".  [Greg Stein]
   
  
  
  
  1.4       +137 -75   httpd-2.0/modules/tls/mod_tls.c
  
  Index: mod_tls.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/tls/mod_tls.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- mod_tls.c	2001/02/12 02:55:52	1.3
  +++ mod_tls.c	2001/02/18 02:10:26	1.4
  @@ -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 @@
       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 @@
       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 @@
   
   	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 @@
       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);
  -
  +    if(APR_BRIGADE_EMPTY(pCtx->pbbInput)) {
  +	ap_get_brigade(pCtx->pInputFilter->next,pCtx->pbbInput,eMode);
  +	if(APR_BRIGADE_EMPTY(pCtx->pbbInput))
  +	    return APR_EOF;
       }
   
  -    // 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_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 @@
   	    // 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 @@
   	}
   	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;
  
  
  
  1.3       +15 -0     httpd-2.0/modules/tls/openssl_state_machine.c
  
  Index: openssl_state_machine.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/tls/openssl_state_machine.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- openssl_state_machine.c	2001/02/11 21:47:41	1.2
  +++ openssl_state_machine.c	2001/02/18 02:10:27	1.3
  @@ -240,10 +240,25 @@
   				  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.
        */
       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);
       }
  
  
  
  1.2       +1 -0      httpd-2.0/modules/tls/openssl_state_machine.h
  
  Index: openssl_state_machine.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/tls/openssl_state_machine.h,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- openssl_state_machine.h	2001/02/11 17:46:19	1.1
  +++ openssl_state_machine.h	2001/02/18 02:10:27	1.2
  @@ -12,3 +12,4 @@
   				  unsigned char *aucBuf,int nBuf);
   void SSLStateMachine_write_inject(SSLStateMachine *pMachine,
   				  const unsigned char *aucBuf,int nBuf);
  +void SSLStateMachine_write_close(SSLStateMachine *pMachine);