Re: syslogd SSL3_WRITE_PENDING:bad write retry
On Tue, Feb 17, 2015 at 09:10:05AM +0100, Reyk Floeter wrote: But workaround is a harsh word - this is the way you were supposed to use SSL_write(). It is adapted from relayd and was turned into tls_write(). I came from the other direction. I had no idea about SSL API and expected to use libtls as a simple replacement for plain TCP. The partial write and moving buffer semantics are not documented within libtls, so I tried the naive way. I even wonder why you didn't pick this up in your evbuffer TLS implementation for syslogd; looks a bit reinvented. My goal was to keep my TLS buffer imlementation as close as possible to libevent. So I can merge it back into libevent. If we don't want this, I can still clean it up. - set SSL_MODE_ENABLE_PARTIAL_WRITE in libtls - remove the clt_buf workaround in httpd - ignore ftp client This approach sounds sane and I would love to have tls_write(3) behave just like write(2). Yes, but after unlock. - What is the impact of adding the flags by default? I think it makes sense for non-blocking operations in httpd and syslogd. They do propper buffer handling anyway. The ftp client is blocking and just wants to write the HTTP header. There short writes are uncomfortable. - What is the reason for OpenSSL's defaults? There is an old thread with some dicussion about it: http://marc.info/?l=openssl-devm=118766345824094w=2 I found another thread from 2006. http://marc.info/?t=11510126221r=1w=2 I have the impression Bodo Moeller knows something about it. | If SSL_write() has started writing a first record, but delayed other | data to later records, then it may have to return -1 to indicate | a WANT_WRITE or WANT_READ condition. My interpretation is, OpenSSL cannot indicate a short write in a want read condition. You must not change the buffer content or decrease its length. This buffer move check is a hint that you must be careful. Anyway, libtls is locked. We can either release a broken syslogd over TLS implementation or commit this diff. It has the smallest impact of everything I have tried. ok or better idea? bluhm Index: usr.sbin/syslogd/evbuffer_tls.c === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/evbuffer_tls.c,v retrieving revision 1.2 diff -u -p -r1.2 evbuffer_tls.c --- usr.sbin/syslogd/evbuffer_tls.c 30 Jan 2015 14:00:55 - 1.2 +++ usr.sbin/syslogd/evbuffer_tls.c 19 Feb 2015 16:47:44 - @@ -186,6 +186,7 @@ buffertls_writecb(int fd, short event, v if (res = 0) goto error; } + buftls-bt_flags = ~BT_WRITE_AGAIN; event_set(bufev-ev_write, fd, EV_WRITE, buffertls_writecb, buftls); if (EVBUFFER_LENGTH(bufev-output) != 0) @@ -202,6 +203,7 @@ buffertls_writecb(int fd, short event, v return; reschedule: + buftls-bt_flags |= BT_WRITE_AGAIN; if (EVBUFFER_LENGTH(bufev-output) != 0) bufferevent_add(bufev-ev_write, bufev-timeout_write); return; @@ -276,6 +278,7 @@ buffertls_set(struct buffertls *buftls, event_set(bufev-ev_write, fd, EV_WRITE, buffertls_writecb, buftls); buftls-bt_bufev = bufev; buftls-bt_ctx = ctx; + buftls-bt_flags = 0; } void Index: usr.sbin/syslogd/evbuffer_tls.h === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/evbuffer_tls.h,v retrieving revision 1.1 diff -u -p -r1.1 evbuffer_tls.h --- usr.sbin/syslogd/evbuffer_tls.h 18 Jan 2015 19:37:59 - 1.1 +++ usr.sbin/syslogd/evbuffer_tls.h 19 Feb 2015 16:47:44 - @@ -28,6 +28,8 @@ struct buffertls { struct bufferevent *bt_bufev; struct tls *bt_ctx; const char *bt_hostname; + int bt_flags; +#define BT_WRITE_AGAIN 0x1 }; void buffertls_set(struct buffertls *, struct bufferevent *, struct tls *, Index: usr.sbin/syslogd/syslogd.c === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v retrieving revision 1.156 diff -u -p -r1.156 syslogd.c --- usr.sbin/syslogd/syslogd.c 14 Feb 2015 09:02:15 - 1.156 +++ usr.sbin/syslogd/syslogd.c 19 Feb 2015 16:47:44 - @@ -1265,8 +1265,22 @@ fprintlog(struct filed *f, int flags, ch } break; - case F_FORWTCP: case F_FORWTLS: + if (f-f_un.f_forw.f_buftls.bt_flags BT_WRITE_AGAIN) { + /* +* After an OpenSSL SSL_ERROR_WANT_WRITE you must not +* modify the buffer pointer or length until the next +* successful write. Otherwise there will be an +* error SSL3_WRITE_PENDING:bad write retry. +* XXX This should be handled in
Re: syslogd SSL3_WRITE_PENDING:bad write retry
Alexander Bluhm wrote: Anyway, libtls is locked. We can either release a broken syslogd over TLS implementation or commit this diff. It has the smallest impact of everything I have tried. ok or better idea? ok
Re: syslogd SSL3_WRITE_PENDING:bad write retry
On Mon, Feb 16, 2015 at 10:17:05AM +0100, Reyk Floeter wrote: On Sun, Feb 15, 2015 at 11:21:45PM +0100, Alexander Bluhm wrote: On Fri, Feb 13, 2015 at 02:44:18PM -0500, Ted Unangst wrote: I think this is ok, but it needs some basic load testing with httpd (and ftp) as well. I have tested ftp https by downloading ports distfiles. I have done basic testing with httpd. Could someone test this diff who has a busy httpd server using https? bluhm I'm running it on some domains without problems so far but the pages aren't so busy. Otherwise OK reyk@ I have tried to download the 227 MB install56.iso from httpd. It is very slow and fails after half the data. There is a copied buffer in server_tls_writecb() to workaround the pending write. Without that httpd works. The ftp client does not check for parital writes in tls_write(). That seems to work anyway as it only writes a short HTTP header and the socket is blocking. What to do now? - set SSL_MODE_ENABLE_PARTIAL_WRITE in libtls - remove the clt_buf workaround in httpd - ignore ftp client - set SSL_MODE_ENABLE_PARTIAL_WRITE in libtls optionally - only syslogd does that bluhm Index: usr.sbin/httpd/httpd.h === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/httpd/httpd.h,v retrieving revision 1.80 diff -u -p -r1.80 httpd.h --- usr.sbin/httpd/httpd.h 12 Feb 2015 10:05:29 - 1.80 +++ usr.sbin/httpd/httpd.h 16 Feb 2015 20:11:55 - @@ -283,8 +283,6 @@ struct client { in_port_tclt_port; struct sockaddr_storage clt_ss; struct bufferevent *clt_bev; - char*clt_buf; - size_t clt_buflen; struct evbuffer *clt_output; struct event clt_ev; void*clt_descreq; Index: usr.sbin/httpd/server.c === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/httpd/server.c,v retrieving revision 1.59 diff -u -p -r1.59 server.c --- usr.sbin/httpd/server.c 12 Feb 2015 04:40:23 - 1.59 +++ usr.sbin/httpd/server.c 16 Feb 2015 20:21:05 - @@ -613,17 +613,8 @@ server_tls_writecb(int fd, short event, } if (EVBUFFER_LENGTH(bufev-output)) { - if (clt-clt_buf == NULL) { - clt-clt_buflen = EVBUFFER_LENGTH(bufev-output); - if ((clt-clt_buf = malloc(clt-clt_buflen)) == NULL) { - what |= EVBUFFER_ERROR; - goto err; - } - bcopy(EVBUFFER_DATA(bufev-output), - clt-clt_buf, clt-clt_buflen); - } - ret = tls_write(clt-clt_tls_ctx, clt-clt_buf, - clt-clt_buflen, len); + ret = tls_write(clt-clt_tls_ctx, EVBUFFER_DATA(bufev-output), + EVBUFFER_LENGTH(bufev-output), len); if (ret == TLS_READ_AGAIN || ret == TLS_WRITE_AGAIN) { goto retry; } else if (ret != 0) { @@ -632,11 +623,6 @@ server_tls_writecb(int fd, short event, } evbuffer_drain(bufev-output, len); } - if (clt-clt_buf != NULL) { - free(clt-clt_buf); - clt-clt_buf = NULL; - clt-clt_buflen = 0; - } if (EVBUFFER_LENGTH(bufev-output) != 0) server_bufferevent_add(bufev-ev_write, bufev-timeout_write); @@ -647,16 +633,11 @@ server_tls_writecb(int fd, short event, return; retry: - if (clt-clt_buflen != 0) + if (EVBUFFER_LENGTH(bufev-output) != 0) server_bufferevent_add(bufev-ev_write, bufev-timeout_write); return; err: - if (clt-clt_buf != NULL) { - free(clt-clt_buf); - clt-clt_buf = NULL; - clt-clt_buflen = 0; - } (*bufev-errorcb)(bufev, what, bufev-cbarg); } Index: lib/libtls/tls.c === RCS file: /data/mirror/openbsd/cvs/src/lib/libtls/tls.c,v retrieving revision 1.7 diff -u -p -r1.7 tls.c --- lib/libtls/tls.c7 Feb 2015 09:50:09 - 1.7 +++ lib/libtls/tls.c16 Feb 2015 19:58:35 - @@ -183,6 +183,9 @@ err: int tls_configure_ssl(struct tls *ctx) { + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv3);
Re: syslogd SSL3_WRITE_PENDING:bad write retry
On Mon, Feb 16, 2015 at 10:03:51PM +0100, Alexander Bluhm wrote: On Mon, Feb 16, 2015 at 10:17:05AM +0100, Reyk Floeter wrote: On Sun, Feb 15, 2015 at 11:21:45PM +0100, Alexander Bluhm wrote: On Fri, Feb 13, 2015 at 02:44:18PM -0500, Ted Unangst wrote: I think this is ok, but it needs some basic load testing with httpd (and ftp) as well. I have tested ftp https by downloading ports distfiles. I have done basic testing with httpd. Could someone test this diff who has a busy httpd server using https? bluhm I'm running it on some domains without problems so far but the pages aren't so busy. Otherwise OK reyk@ I have tried to download the 227 MB install56.iso from httpd. It is very slow and fails after half the data. There is a copied buffer in server_tls_writecb() to workaround the pending write. Without that httpd works. OK, good finding. I haven't tested large files yet. But workaround is a harsh word - this is the way you were supposed to use SSL_write(). It is adapted from relayd and was turned into tls_write(). I even wonder why you didn't pick this up in your evbuffer TLS implementation for syslogd; looks a bit reinvented. The ftp client does not check for parital writes in tls_write(). That seems to work anyway as it only writes a short HTTP header and the socket is blocking. What to do now? - set SSL_MODE_ENABLE_PARTIAL_WRITE in libtls - remove the clt_buf workaround in httpd - ignore ftp client This approach sounds sane and I would love to have tls_write(3) behave just like write(2). But It was not a workaround. The OpenSSL people didn't like SSL_MODE_ENABLE_PARTIAL_WRITE and SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER and they weren't the default for a reason. httpd and relayd are currently doing it the recommended way - and we have to figure out if this recommendation was wrong. I initially asked tedu@ about the impacts of these flags in httpd and I had the described workaround in mind but I failed to point it out. As I said, I would like to get your patch applied but I'd also like to understand OpenSSL's reasons to change the semantics: - What is the impact of adding the flags by default? - What is the reason for OpenSSL's defaults? There is an old thread with some dicussion about it: http://marc.info/?l=openssl-devm=118766345824094w=2 But I still don't get it. Was it just an optimization for speed? Reyk - set SSL_MODE_ENABLE_PARTIAL_WRITE in libtls optionally - only syslogd does that bluhm Index: usr.sbin/httpd/httpd.h === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/httpd/httpd.h,v retrieving revision 1.80 diff -u -p -r1.80 httpd.h --- usr.sbin/httpd/httpd.h12 Feb 2015 10:05:29 - 1.80 +++ usr.sbin/httpd/httpd.h16 Feb 2015 20:11:55 - @@ -283,8 +283,6 @@ struct client { in_port_tclt_port; struct sockaddr_storage clt_ss; struct bufferevent *clt_bev; - char*clt_buf; - size_t clt_buflen; struct evbuffer *clt_output; struct event clt_ev; void*clt_descreq; Index: usr.sbin/httpd/server.c === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/httpd/server.c,v retrieving revision 1.59 diff -u -p -r1.59 server.c --- usr.sbin/httpd/server.c 12 Feb 2015 04:40:23 - 1.59 +++ usr.sbin/httpd/server.c 16 Feb 2015 20:21:05 - @@ -613,17 +613,8 @@ server_tls_writecb(int fd, short event, } if (EVBUFFER_LENGTH(bufev-output)) { - if (clt-clt_buf == NULL) { - clt-clt_buflen = EVBUFFER_LENGTH(bufev-output); - if ((clt-clt_buf = malloc(clt-clt_buflen)) == NULL) { - what |= EVBUFFER_ERROR; - goto err; - } - bcopy(EVBUFFER_DATA(bufev-output), - clt-clt_buf, clt-clt_buflen); - } - ret = tls_write(clt-clt_tls_ctx, clt-clt_buf, - clt-clt_buflen, len); + ret = tls_write(clt-clt_tls_ctx, EVBUFFER_DATA(bufev-output), + EVBUFFER_LENGTH(bufev-output), len); if (ret == TLS_READ_AGAIN || ret == TLS_WRITE_AGAIN) { goto retry; } else if (ret != 0) { @@ -632,11 +623,6 @@ server_tls_writecb(int fd, short event, } evbuffer_drain(bufev-output, len); } - if (clt-clt_buf != NULL) { - free(clt-clt_buf); - clt-clt_buf = NULL; - clt-clt_buflen = 0; - } if (EVBUFFER_LENGTH(bufev-output) != 0) server_bufferevent_add(bufev-ev_write, bufev-timeout_write); @@ -647,16 +633,11 @@
Re: syslogd SSL3_WRITE_PENDING:bad write retry
On Sun, Feb 15, 2015 at 11:21:45PM +0100, Alexander Bluhm wrote: On Fri, Feb 13, 2015 at 02:44:18PM -0500, Ted Unangst wrote: I think this is ok, but it needs some basic load testing with httpd (and ftp) as well. I have tested ftp https by downloading ports distfiles. I have done basic testing with httpd. Could someone test this diff who has a busy httpd server using https? bluhm I'm running it on some domains without problems so far but the pages aren't so busy. Otherwise OK reyk@ Reyk Index: lib/libtls/tls.c === RCS file: /data/mirror/openbsd/cvs/src/lib/libtls/tls.c,v retrieving revision 1.7 diff -u -p -r1.7 tls.c --- lib/libtls/tls.c 7 Feb 2015 09:50:09 - 1.7 +++ lib/libtls/tls.c 13 Feb 2015 18:33:31 - @@ -183,6 +183,9 @@ err: int tls_configure_ssl(struct tls *ctx) { + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv3); --
Re: syslogd SSL3_WRITE_PENDING:bad write retry
On Fri, Feb 13, 2015 at 02:44:18PM -0500, Ted Unangst wrote: I think this is ok, but it needs some basic load testing with httpd (and ftp) as well. I have tested ftp https by downloading ports distfiles. I have done basic testing with httpd. Could someone test this diff who has a busy httpd server using https? bluhm Index: lib/libtls/tls.c === RCS file: /data/mirror/openbsd/cvs/src/lib/libtls/tls.c,v retrieving revision 1.7 diff -u -p -r1.7 tls.c --- lib/libtls/tls.c7 Feb 2015 09:50:09 - 1.7 +++ lib/libtls/tls.c13 Feb 2015 18:33:31 - @@ -183,6 +183,9 @@ err: int tls_configure_ssl(struct tls *ctx) { + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv3);
Re: syslogd SSL3_WRITE_PENDING:bad write retry
On Thu, Feb 12, 2015 at 08:34:23PM +0100, Alexander Bluhm wrote: On Wed, Feb 11, 2015 at 11:30:03PM -0500, Ted Unangst wrote: Ted Unangst wrote: Alexander Bluhm wrote: Hi, During testing syslogd I got some strange error messages from libtls: syslogd: loghost @tls://localhost:15878 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry I found out that after an SSL_ERROR_WANT_WRITE, SSL_write must be called with exactly the same parameter. So I remember this event and do not modify the event buffer. This is one of the hardest things to fix with the current tls_write implementation. Yes, we inherited the underlying API's requirement to reuse the same buffer until it's completely written out. I dream of making tls_write work just like write, but until then you'll need to do this. Actually, I think this may be much easier to fix. SSL_write can be configured to support short writes. Try this. This has no effect. I still get syslogd: loghost @tls://localhost:7972 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry libevent buffer are reallocated when growing. So I also need SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER. This works. Do we want both options in libtls? ok? bluhm Index: lib/libtls/tls.c === RCS file: /data/mirror/openbsd/cvs/src/lib/libtls/tls.c,v retrieving revision 1.7 diff -u -p -r1.7 tls.c --- lib/libtls/tls.c7 Feb 2015 09:50:09 - 1.7 +++ lib/libtls/tls.c13 Feb 2015 18:33:31 - @@ -183,6 +183,9 @@ err: int tls_configure_ssl(struct tls *ctx) { + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv3);
Re: syslogd SSL3_WRITE_PENDING:bad write retry
Alexander Bluhm wrote: On Thu, Feb 12, 2015 at 08:34:23PM +0100, Alexander Bluhm wrote: On Wed, Feb 11, 2015 at 11:30:03PM -0500, Ted Unangst wrote: Ted Unangst wrote: Alexander Bluhm wrote: Hi, During testing syslogd I got some strange error messages from libtls: syslogd: loghost @tls://localhost:15878 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry I found out that after an SSL_ERROR_WANT_WRITE, SSL_write must be called with exactly the same parameter. So I remember this event and do not modify the event buffer. This is one of the hardest things to fix with the current tls_write implementation. Yes, we inherited the underlying API's requirement to reuse the same buffer until it's completely written out. I dream of making tls_write work just like write, but until then you'll need to do this. Actually, I think this may be much easier to fix. SSL_write can be configured to support short writes. Try this. This has no effect. I still get syslogd: loghost @tls://localhost:7972 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry libevent buffer are reallocated when growing. So I also need SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER. This works. Do we want both options in libtls? ok? This makes sense. These are the semantics we want tls_write() to have. I wasn't sure if both flags were needed or not, exactly the kind of confusion we're trying to avoid. I think this is ok, but it needs some basic load testing with httpd (and ftp) as well. bluhm Index: lib/libtls/tls.c === RCS file: /data/mirror/openbsd/cvs/src/lib/libtls/tls.c,v retrieving revision 1.7 diff -u -p -r1.7 tls.c --- lib/libtls/tls.c 7 Feb 2015 09:50:09 - 1.7 +++ lib/libtls/tls.c 13 Feb 2015 18:33:31 - @@ -183,6 +183,9 @@ err: int tls_configure_ssl(struct tls *ctx) { + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv3);
Re: syslogd SSL3_WRITE_PENDING:bad write retry
On Wed, Feb 11, 2015 at 11:30:03PM -0500, Ted Unangst wrote: Ted Unangst wrote: Alexander Bluhm wrote: Hi, During testing syslogd I got some strange error messages from libtls: syslogd: loghost @tls://localhost:15878 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry I found out that after an SSL_ERROR_WANT_WRITE, SSL_write must be called with exactly the same parameter. So I remember this event and do not modify the event buffer. This is one of the hardest things to fix with the current tls_write implementation. Yes, we inherited the underlying API's requirement to reuse the same buffer until it's completely written out. I dream of making tls_write work just like write, but until then you'll need to do this. Actually, I think this may be much easier to fix. SSL_write can be configured to support short writes. Try this. This has no effect. I still get syslogd: loghost @tls://localhost:7972 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry bluhm Index: tls.c === RCS file: /cvs/src/lib/libtls/tls.c,v retrieving revision 1.7 diff -u -p -r1.7 tls.c --- tls.c 7 Feb 2015 09:50:09 - 1.7 +++ tls.c 12 Feb 2015 04:28:27 - @@ -183,6 +183,8 @@ err: int tls_configure_ssl(struct tls *ctx) { + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv3);
syslogd SSL3_WRITE_PENDING:bad write retry
Hi, During testing syslogd I got some strange error messages from libtls: syslogd: loghost @tls://localhost:15878 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry I found out that after an SSL_ERROR_WANT_WRITE, SSL_write must be called with exactly the same parameter. So I remember this event and do not modify the event buffer. ok? bluhm Index: usr.sbin/syslogd/evbuffer_tls.c === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/evbuffer_tls.c,v retrieving revision 1.2 diff -u -p -r1.2 evbuffer_tls.c --- usr.sbin/syslogd/evbuffer_tls.c 30 Jan 2015 14:00:55 - 1.2 +++ usr.sbin/syslogd/evbuffer_tls.c 12 Feb 2015 00:39:23 - @@ -168,6 +168,7 @@ buffertls_writecb(int fd, short event, v buffertls_writecb, buftls); goto reschedule; case TLS_WRITE_AGAIN: + buftls-bt_flags |= BT_WRITE_AGAIN; event_set(bufev-ev_write, fd, EV_WRITE, buffertls_writecb, buftls); goto reschedule; @@ -186,6 +187,7 @@ buffertls_writecb(int fd, short event, v if (res = 0) goto error; } + buftls-bt_flags = ~BT_WRITE_AGAIN; event_set(bufev-ev_write, fd, EV_WRITE, buffertls_writecb, buftls); if (EVBUFFER_LENGTH(bufev-output) != 0) @@ -276,6 +278,7 @@ buffertls_set(struct buffertls *buftls, event_set(bufev-ev_write, fd, EV_WRITE, buffertls_writecb, buftls); buftls-bt_bufev = bufev; buftls-bt_ctx = ctx; + buftls-bt_flags = 0; } void Index: usr.sbin/syslogd/evbuffer_tls.h === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/evbuffer_tls.h,v retrieving revision 1.1 diff -u -p -r1.1 evbuffer_tls.h --- usr.sbin/syslogd/evbuffer_tls.h 18 Jan 2015 19:37:59 - 1.1 +++ usr.sbin/syslogd/evbuffer_tls.h 12 Feb 2015 00:03:58 - @@ -28,6 +28,8 @@ struct buffertls { struct bufferevent *bt_bufev; struct tls *bt_ctx; const char *bt_hostname; + int bt_flags; +#define BT_WRITE_AGAIN 0x1 }; void buffertls_set(struct buffertls *, struct bufferevent *, struct tls *, Index: usr.sbin/syslogd/syslogd.c === RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v retrieving revision 1.153 diff -u -p -r1.153 syslogd.c --- usr.sbin/syslogd/syslogd.c 10 Feb 2015 18:30:20 - 1.153 +++ usr.sbin/syslogd/syslogd.c 12 Feb 2015 00:03:27 - @@ -1266,8 +1266,22 @@ fprintlog(struct filed *f, int flags, ch } break; - case F_FORWTCP: case F_FORWTLS: + if (f-f_un.f_forw.f_buftls.bt_flags BT_WRITE_AGAIN) { + /* +* After an OpenSSL SSL_ERROR_WANT_WRITE you must not +* modify the buffer pointer or length until the next +* successful write. Otherwise there will be an +* error SSL3_WRITE_PENDING:bad write retry. +* XXX This should be handled in the buffertls layer. +*/ + dprintf( %s (dropped tls write again)\n, + f-f_un.f_forw.f_loghost); + f-f_un.f_forw.f_dropped++; + break; + } + /* FALLTHROUGH */ + case F_FORWTCP: dprintf( %s, f-f_un.f_forw.f_loghost); if (EVBUFFER_LENGTH(f-f_un.f_forw.f_bufev-output) = MAX_TCPBUF) {
Re: syslogd SSL3_WRITE_PENDING:bad write retry
Alexander Bluhm wrote: Hi, During testing syslogd I got some strange error messages from libtls: syslogd: loghost @tls://localhost:15878 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry I found out that after an SSL_ERROR_WANT_WRITE, SSL_write must be called with exactly the same parameter. So I remember this event and do not modify the event buffer. This is one of the hardest things to fix with the current tls_write implementation. Yes, we inherited the underlying API's requirement to reuse the same buffer until it's completely written out. I dream of making tls_write work just like write, but until then you'll need to do this.
Re: syslogd SSL3_WRITE_PENDING:bad write retry
Ted Unangst wrote: Alexander Bluhm wrote: Hi, During testing syslogd I got some strange error messages from libtls: syslogd: loghost @tls://localhost:15878 connection error: write failed: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry I found out that after an SSL_ERROR_WANT_WRITE, SSL_write must be called with exactly the same parameter. So I remember this event and do not modify the event buffer. This is one of the hardest things to fix with the current tls_write implementation. Yes, we inherited the underlying API's requirement to reuse the same buffer until it's completely written out. I dream of making tls_write work just like write, but until then you'll need to do this. Actually, I think this may be much easier to fix. SSL_write can be configured to support short writes. Try this. Index: tls.c === RCS file: /cvs/src/lib/libtls/tls.c,v retrieving revision 1.7 diff -u -p -r1.7 tls.c --- tls.c 7 Feb 2015 09:50:09 - 1.7 +++ tls.c 12 Feb 2015 04:28:27 - @@ -183,6 +183,8 @@ err: int tls_configure_ssl(struct tls *ctx) { + SSL_CTX_set_mode(ctx-ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx-ssl_ctx, SSL_OP_NO_SSLv3);