diff -ruN -x '*~' stunnel-4.54b4.orig/doc/stunnel.8 stunnel-4.54b4/doc/stunnel.8 --- stunnel-4.54b4.orig/doc/stunnel.8 2012-06-27 22:58:47.702927772 +0200 +++ stunnel-4.54b4/doc/stunnel.8 2012-06-27 23:24:18.597867466 +0200 @@ -582,6 +582,18 @@ .IP "\fBpty\fR = yes | no (Unix only)" 4 .IX Item "pty = yes | no (Unix only)" allocate pseudo terminal for 'exec' option +.IP "\fBrenegotiation\fR = yes | no" 4 +.IX Item "renegotiation = yes | no" +support SSL renegotiation +.Sp +Renegotiation can be a security risk (see CVE-2009-3555, although it +is patched in any recent OpenSSL version) and also can make certain +DoS attacks easier (see http://www.thc.org/thc-ssl-dos/). In most +cases it can be disabled, but be advised that it is needed sometimes +(for example in some cases of certificate based client +authentication). +.Sp +default: yes (if OpenSSL supports it) .IP "\fBreset\fR = yes | no" 4 .IX Item "reset = yes | no" attempt to use \s-1TCP\s0 \s-1RST\s0 flag to indicate an error diff -ruN -x '*~' stunnel-4.54b4.orig/src/client.c stunnel-4.54b4/src/client.c --- stunnel-4.54b4.orig/src/client.c 2012-06-27 22:58:47.704927772 +0200 +++ stunnel-4.54b4/src/client.c 2012-06-27 23:15:41.747887826 +0200 @@ -605,6 +605,11 @@ longjmp(c->err, 1); } + if(c->reneg_state == RENEG_DETECTED && !c->opt->option.renegotiation) { + s_log(LOG_NOTICE, "Aborting due to renegotiation request"); + longjmp(c->err, 1); + } + /****************************** send SSL close_notify alert */ if(shutdown_wants_read || shutdown_wants_write) { num=SSL_shutdown(c->ssl); /* send close_notify alert */ diff -ruN -x '*~' stunnel-4.54b4.orig/src/ctx.c stunnel-4.54b4/src/ctx.c --- stunnel-4.54b4.orig/src/ctx.c 2012-06-27 22:58:47.705927772 +0200 +++ stunnel-4.54b4/src/ctx.c 2012-06-27 23:17:51.684882707 +0200 @@ -614,6 +614,28 @@ const #endif SSL *ssl, int where, int ret) { + CLI *c; + + c = SSL_get_ex_data(ssl, cli_index); + if(c) { + if((where & SSL_CB_HANDSHAKE_DONE) && + c->reneg_state == RENEG_INIT) { + /* first (initial) handshake was completed, remember this, + * so that further renegotiation attempts can be detected */ + c->reneg_state = RENEG_ESTABLISHED; + } else if((where & SSL_CB_ACCEPT_LOOP) && + c->reneg_state == RENEG_ESTABLISHED) { + int state = SSL_get_state(ssl); + + if (state == SSL3_ST_SR_CLNT_HELLO_A || + state == SSL23_ST_SR_CLNT_HELLO_A) { + /* client hello received after initial handshake, this + * means renegotiation, mark it */ + c->reneg_state = RENEG_DETECTED; + } + } + } + if(global_options.debug_leveloption.renegotiation=1; + break; + case CMD_EXEC: + if(strcasecmp(opt, "renegotiation")) + break; + if(!strcasecmp(arg, "yes")) + section->option.renegotiation=1; + else if(!strcasecmp(arg, "no")) + section->option.renegotiation=0; + else + return "argument should be either 'yes' or 'no'"; + return NULL; /* OK */ + case CMD_DEFAULT: + break; + case CMD_HELP: + s_log(LOG_NOTICE, "%-15s = yes|no support renegotiation", + "renegotiation"); + break; + } + /* reset */ switch(cmd) { case CMD_INIT: diff -ruN -x '*~' stunnel-4.54b4.orig/src/prototypes.h stunnel-4.54b4/src/prototypes.h --- stunnel-4.54b4.orig/src/prototypes.h 2012-06-27 22:58:47.705927772 +0200 +++ stunnel-4.54b4/src/prototypes.h 2012-06-27 23:14:44.883890065 +0200 @@ -219,6 +219,7 @@ unsigned int ocsp:1; #endif unsigned int reset:1; /* reset sockets on error */ + unsigned int renegotiation:1; } option; } SERVICE_OPTIONS; @@ -397,6 +398,12 @@ /**************************************** prototypes for client.c */ +typedef enum { + RENEG_INIT, /* initial state */ + RENEG_ESTABLISHED, /* initial handshake completed */ + RENEG_DETECTED /* renegotiation detected */ +} RENEG_STATE; + typedef struct { jmp_buf err; /* exception handler needs to be 16-byte aligned on Itanium */ SSL *ssl; /* SSL connnection */ @@ -420,6 +427,8 @@ FD *ssl_rfd, *ssl_wfd; /* read and write SSL descriptors */ int sock_bytes, ssl_bytes; /* bytes written to socket and SSL */ s_poll_set *fds; /* file descriptors */ + + RENEG_STATE reneg_state; /* used to track renegotiation attempts */ } CLI; CLI *alloc_client_session(SERVICE_OPTIONS *, int, int);