summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-11-16 05:13:06 +0000
committerLaurent Bercot <ska@appnovation.com>2023-11-16 05:13:06 +0000
commit26597a785ec2dd4e9ec9fb7d9765d2ee8779ee16 (patch)
treec2c5602397e9381b1cb04472ed057edd4a00e520
parentd8ca717da164c3e76ebb56c954d0a08544955601 (diff)
downloads6-networking-26597a785ec2dd4e9ec9fb7d9765d2ee8779ee16.tar.xz
Add -J and -j to the TLS tools to check for peer close_notify.
Also, and more importantly, significantly rewrite stls_run() for better full-duplex support. This implementation isn't fully tested yet. Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--doc/s6-tlsc-io.html6
-rw-r--r--doc/s6-tlsc.html5
-rw-r--r--doc/s6-tlsclient.html1
-rw-r--r--doc/s6-tlsd-io.html6
-rw-r--r--doc/s6-tlsd.html5
-rw-r--r--doc/s6-tlsserver.html1
-rw-r--r--doc/s6-ucspitlsc.html5
-rw-r--r--doc/s6-ucspitlsd.html5
-rw-r--r--src/include/s6-networking/stls.h5
-rw-r--r--src/sbearssl/sbearssl_run.c13
-rw-r--r--src/stls/stls_client_init_and_handshake.c4
-rw-r--r--src/stls/stls_run.c360
-rw-r--r--src/stls/stls_server_init_and_handshake.c3
-rw-r--r--src/tls/s6-tlsc-io.c8
-rw-r--r--src/tls/s6-tlsc.c12
-rw-r--r--src/tls/s6-tlsd-io.c6
-rw-r--r--src/tls/s6-tlsd.c8
-rw-r--r--src/tls/s6-ucspitlsc.c10
-rw-r--r--src/tls/s6-ucspitlsd.c8
-rw-r--r--src/tls/s6tls-internal.h2
-rw-r--r--src/tls/s6tls_prep_tlscio.c1
-rw-r--r--src/tls/s6tls_prep_tlsdio.c1
22 files changed, 261 insertions, 214 deletions
diff --git a/doc/s6-tlsc-io.html b/doc/s6-tlsc-io.html
index f4a81a2..17a4e26 100644
--- a/doc/s6-tlsc-io.html
+++ b/doc/s6-tlsc-io.html
@@ -38,7 +38,7 @@ the options given when configuring s6-networking.
<h2> Interface </h2>
<pre>
- s6-tlsc-io [ -S | -s ] [ -Y | -y ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k <em>servername</em> ] [ -d <em>notif</em> ] [ -- ] <em>fdr</em> <em>fdw</em>
+ s6-tlsc-io [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k <em>servername</em> ] [ -d <em>notif</em> ] [ -- ] <em>fdr</em> <em>fdw</em>
</pre>
<ul>
@@ -190,6 +190,10 @@ no effect. </li>
and break the connection when receiving a local EOF. </li>
<li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-J</tt>&nbsp;: treat EOF from the peer without a prior close_notify
+as an error: print a fatal error message and exit 98. </li>
+ <li> <tt>-j</tt>&nbsp;: treat EOF from the peer without a prior close_notify
+as a normal exit condition. This is the default. </li>
<li> <tt>-Y</tt>&nbsp;: Do not send a client certificate. This is the default. </li>
<li> <tt>-y</tt>&nbsp;: Send a client certificate. </li>
<li> <tt>-k&nbsp;<em>servername</em></tt>&nbsp;: use Server Name
diff --git a/doc/s6-tlsc.html b/doc/s6-tlsc.html
index 1d11c5b..aff6828 100644
--- a/doc/s6-tlsc.html
+++ b/doc/s6-tlsc.html
@@ -29,7 +29,7 @@ TLS/SSL.
<h2> Interface </h2>
<pre>
- s6-tlsc [ -S | -s ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k <em>servername</em> ] [ -6 <em>rfd</em> ] [ -7 <em>wfd</em> ] [ -- ] <em>prog...</em>
+ s6-tlsc [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k <em>servername</em> ] [ -6 <em>rfd</em> ] [ -7 <em>wfd</em> ] [ -- ] <em>prog...</em>
</pre>
<ul>
@@ -126,6 +126,9 @@ before execing <em>prog...</em>. This is the default. </li>
and break the connection when <em>prog</em> sends EOF. </li>
<li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-J</tt>&nbsp;: make <a href="s6-tlsc-io.html">s6-tlsc-io</a>
+exit with a nonzero code if the peer sends EOF without a close_notify first </li>
+ <li> <tt>-j</tt>&nbsp;: treat EOF from the peer as a normal exit condition </li>
<li> <tt>-Y</tt>&nbsp;: Do not send a client certificate. This is the default. </li>
<li> <tt>-y</tt>&nbsp;: Send a client certificate. </li>
<li> <tt>-k&nbsp;<em>servername</em></tt>&nbsp;: use Server Name
diff --git a/doc/s6-tlsclient.html b/doc/s6-tlsclient.html
index 287c02c..09276d4 100644
--- a/doc/s6-tlsclient.html
+++ b/doc/s6-tlsclient.html
@@ -144,6 +144,7 @@ generally work: the defaults are sensible.
<li> <tt>-Z</tt>, <tt>-z</tt>&nbsp;: keep or remove the <a href="s6-tlsc-io.html">s6-tlsc-io</a>-specific
variables from the application's environment </li>
<li> <tt>-S</tt>, <tt>-s</tt>&nbsp;: use close_notify or EOF to signal the end of a TLS connection </li>
+ <li> <tt>-J</tt>, <tt>-j</tt>&nbsp;: exit nonzero with an error message when the peer fails to close_notify, or ignore it </li>
<li> <tt>-Y</tt>, <tt>-y</tt>&nbsp;: don't send, or send, a client certificate </li>
<li> <tt>-k <em>servername</em></tt>&nbsp;: use SNI and provide a server name </li>
<li> <tt>-K <em>kimeout</em></tt>&nbsp;: set a timeout for the TLS handshake </li>
diff --git a/doc/s6-tlsd-io.html b/doc/s6-tlsd-io.html
index 0f3b922..55e293f 100644
--- a/doc/s6-tlsd-io.html
+++ b/doc/s6-tlsd-io.html
@@ -38,7 +38,7 @@ the options given when configuring s6-networking.
<h2> Interface </h2>
<pre>
- s6-tlsd-io [ -S | -s ] [ -Y | -y ] [ -v <em>verbosity</em> ] [ -K <em>kimeout</em> ] [ -k <em>snilevel</em> ] [ -d <em>notif</em> ] [ -- ] <em>fdr</em> <em>fdw</em>
+ s6-tlsd-io [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -v <em>verbosity</em> ] [ -K <em>kimeout</em> ] [ -k <em>snilevel</em> ] [ -d <em>notif</em> ] [ -- ] <em>fdr</em> <em>fdw</em>
</pre>
<ul>
@@ -210,6 +210,10 @@ no effect. </li>
and break the connection when receiving a local EOF. </li>
<li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-J</tt>&nbsp;: treat EOF from the peer without a prior close_notify
+as an error: print a fatal error message and exit 98. </li>
+ <li> <tt>-j</tt>&nbsp;: treat EOF from the peer without a prior close_notify
+as a normal exit condition. This is the default. </li>
<li> <tt>-Y</tt>&nbsp;: Request a client certificate.
The certificate is optional: if the client gives none, the connection
proceeds. </li>
diff --git a/doc/s6-tlsd.html b/doc/s6-tlsd.html
index 883777b..73a9f9b 100644
--- a/doc/s6-tlsd.html
+++ b/doc/s6-tlsd.html
@@ -38,7 +38,7 @@ the options given when configuring <tt>s6-networking</tt>.
<h2> Interface </h2>
<pre>
- s6-tlsd [ -S | -s ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K <em>kimeout</em> ] [ -k <em>snilevel</em> ] [ -- ] <em>prog...</em>
+ s6-tlsd [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K <em>kimeout</em> ] [ -k <em>snilevel</em> ] [ -- ] <em>prog...</em>
</pre>
<ul>
@@ -139,6 +139,9 @@ before execing <em>prog...</em>. This is the default. </li>
and break the connection when <em>prog</em> sends EOF. </li>
<li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-J</tt>&nbsp;: make <a href="s6-tlsd-io.html">s6-tlsd-io</a>
+exit with a nonzero code if the peer sends EOF without a close_notify first </li>
+ <li> <tt>-j</tt>&nbsp;: treat EOF from the peer as a normal exit condition </li>
<li> <tt>-Y</tt>&nbsp;: Request an optional client certificate. </li>
<li> <tt>-y</tt>&nbsp;: Request a mandatory client certificate.
The default, with neither the <tt>-Y</tt> nor the <tt>-y</tt> option,
diff --git a/doc/s6-tlsserver.html b/doc/s6-tlsserver.html
index d1ca3e2..8713235 100644
--- a/doc/s6-tlsserver.html
+++ b/doc/s6-tlsserver.html
@@ -177,6 +177,7 @@ certificates, you probably still want TCP access rules.
<li> <tt>-Z</tt>, <tt>-z</tt>&nbsp;: keep or remove the <a href="s6-tlsd-io.html">s6-tlsd-io</a>-specific
variables from the application's environment </li>
<li> <tt>-S</tt>, <tt>-s</tt>&nbsp;: use close_notify or EOF to signal the end of a TLS connection </li>
+ <li> <tt>-J</tt>, <tt>-j</tt>&nbsp;: exit nonzero with an error message when the peer fails to close_notify, or ignore it </li>
<li> <tt>-Y</tt>, <tt>-y</tt>&nbsp;: request an optional or a mandatory client certificate </li>
<li> <tt>-K <em>kimeout</em></tt>&nbsp;: set a timeout for the TLS handshake </li>
<li> <tt>-k <em>snilevel</em></tt>&nbsp;: support SNI-based certificate chains </li>
diff --git a/doc/s6-ucspitlsc.html b/doc/s6-ucspitlsc.html
index e096e24..52af6db 100644
--- a/doc/s6-ucspitlsc.html
+++ b/doc/s6-ucspitlsc.html
@@ -36,7 +36,7 @@ TLS stack in the client itself.
<h2> Interface </h2>
<pre>
- s6-ucspitlsc [ -S | -s ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k <em>servername</em> ] [ -6 <em>rfd</em> ] [ -7 <em>wfd</em> ] [ -- ] <em>prog...</em>
+ s6-ucspitlsc [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k <em>servername</em> ] [ -6 <em>rfd</em> ] [ -7 <em>wfd</em> ] [ -- ] <em>prog...</em>
</pre>
<ul>
@@ -142,6 +142,9 @@ before execing <em>prog...</em>. This is the default. </li>
and break the connection when <em>prog</em> sends EOF. </li>
<li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-J</tt>&nbsp;: make <a href="s6-tlsc-io.html">s6-tlsc-io</a>
+exit with a nonzero code if the peer sends EOF without a close_notify first </li>
+ <li> <tt>-j</tt>&nbsp;: treat EOF from the peer as a normal exit condition </li>
<li> <tt>-Y</tt>&nbsp;: Do not send a client certificate. This is the default. </li>
<li> <tt>-y</tt>&nbsp;: Send a client certificate. </li>
<li> <tt>-k&nbsp;<em>servername</em></tt>&nbsp;: use Server Name
diff --git a/doc/s6-ucspitlsd.html b/doc/s6-ucspitlsd.html
index 8488942..314cc39 100644
--- a/doc/s6-ucspitlsd.html
+++ b/doc/s6-ucspitlsd.html
@@ -36,7 +36,7 @@ TLS stack in the server itself.
<h2> Interface </h2>
<pre>
- s6-ucspitlsd [ -S | -s ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k snilevel ] [ -- ] <em>prog...</em>
+ s6-ucspitlsd [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k snilevel ] [ -- ] <em>prog...</em>
</pre>
<ul>
@@ -146,6 +146,9 @@ before execing <em>prog...</em>. This is the default. </li>
and break the connection when <em>prog</em> sends EOF. </li>
<li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-J</tt>&nbsp;: make <a href="s6-tlsd-io.html">s6-tlsd-io</a>
+exit with a nonzero code if the peer sends EOF without a close_notify first </li>
+ <li> <tt>-j</tt>&nbsp;: treat EOF from the peer as a normal exit condition </li>
<li> <tt>-Y</tt>&nbsp;: Request an optional client certificate. </li>
<li> <tt>-y</tt>&nbsp;: Request a mandatory client certificate.
The default, with neither the <tt>-Y</tt> nor the <tt>-y</tt> option,
diff --git a/src/include/s6-networking/stls.h b/src/include/s6-networking/stls.h
index e9f6136..2eefe36 100644
--- a/src/include/s6-networking/stls.h
+++ b/src/include/s6-networking/stls.h
@@ -8,15 +8,16 @@
#include <tls.h>
#include <skalibs/gccattributes.h>
+#include <skalibs/buffer.h>
#include <skalibs/tai.h>
-#define STLS_BUFSIZE (16384 + 325 + 1)
+#define STLS_BUFSIZE 16384
/* Engine */
extern int stls_send_environment (struct tls *, int) ;
-extern void stls_run (struct tls *, int *, uint32_t, unsigned int) gccattr_noreturn ;
+extern void stls_run (struct tls *, int const *, uint32_t, unsigned int) gccattr_noreturn ;
/* s6-tlsc-io and s6-tlsd-io */
diff --git a/src/sbearssl/sbearssl_run.c b/src/sbearssl/sbearssl_run.c
index 51263ca..d339b69 100644
--- a/src/sbearssl/sbearssl_run.c
+++ b/src/sbearssl/sbearssl_run.c
@@ -68,14 +68,9 @@ void sbearssl_run (br_ssl_engine_context *ctx, int const *fds, tain const *tto,
}
else x[0].events = 0 ;
- if (x[1].fd >= 0)
- x[1].events = IOPAUSE_EXCEPT | (state & BR_SSL_RECVAPP ? IOPAUSE_WRITE : 0) ;
-
- if (x[2].fd >= 0 && state & BR_SSL_RECVREC) x[2].events = IOPAUSE_READ ;
- else x[2].events = 0 ;
-
- if (x[3].fd >= 0)
- x[3].events = IOPAUSE_EXCEPT | (state & BR_SSL_SENDREC ? IOPAUSE_WRITE : 0) ;
+ x[1].events = x[1].fd >= 0 ? IOPAUSE_EXCEPT | (state & BR_SSL_RECVAPP ? IOPAUSE_WRITE : 0) : 0 ;
+ x[2].events = x[2].fd >= 0 && state & BR_SSL_RECVREC) ? IOPAUSE_READ : 0 ;
+ x[3].events = x[3].fd >= 0 ? IOPAUSE_EXCEPT | (state & BR_SSL_SENDREC ? IOPAUSE_WRITE : 0) : 0 ;
/* Wait for events */
@@ -187,6 +182,8 @@ void sbearssl_run (br_ssl_engine_context *ctx, int const *fds, tain const *tto,
}
else if (!r)
{
+ if (handshake_done && options & 2)
+ strerr_dief1x(98, "remote closed connection without a close_notify") ;
fd_shutdown(x[2].fd, 0) ;
fd_close(x[2].fd) ;
x[2].fd = -1 ;
diff --git a/src/stls/stls_client_init_and_handshake.c b/src/stls/stls_client_init_and_handshake.c
index b65c833..6f0e248 100644
--- a/src/stls/stls_client_init_and_handshake.c
+++ b/src/stls/stls_client_init_and_handshake.c
@@ -50,7 +50,7 @@ struct tls *stls_client_init_and_handshake (int const *fds, tain const *tto, uin
{
if (tls_config_set_ca_path(cfg, x) < 0)
diecfg(cfg, "tls_config_set_ca_path") ;
- strerr_warnw1x("some versions of libtls do not work with CADIR, try using CAFILE instead") ;
+ strerr_warnw1x("some versions of libtls do not work with CADIR, if you experience problems with server certificate verification then try using CAFILE instead") ;
}
else strerr_diefu1x(100, "get trust anchor list: neither CADIR nor CAFILE is set") ;
}
@@ -73,7 +73,7 @@ struct tls *stls_client_init_and_handshake (int const *fds, tain const *tto, uin
if (!ctx) strerr_diefu1sys(111, "tls_client") ;
if (tls_configure(ctx, cfg) < 0) diectx(97, ctx, "tls_configure") ;
- if (tls_connect_fds(ctx, fds[0], fds[1], servername) < 0)
+ if (tls_connect_fds(ctx, fds[0], fds[1], servername) == -1)
diectx(97, ctx, "tls_connect_fds") ;
tls_config_free(cfg) ;
stls_handshake(ctx, tto) ;
diff --git a/src/stls/stls_run.c b/src/stls/stls_run.c
index 7385c4e..2456e22 100644
--- a/src/stls/stls_run.c
+++ b/src/stls/stls_run.c
@@ -1,6 +1,7 @@
/* ISC license. */
#include <sys/uio.h>
+#include <stdint.h>
#include <errno.h>
#include <unistd.h>
@@ -14,248 +15,259 @@
#include <s6-networking/stls.h>
-typedef struct tlsbuf_s tlsbuf_t, *tlsbuf_t_ref ;
-struct tlsbuf_s
+
+typedef struct stls_buffer_s stls_buffer, *stls_buffer_ref ;
+struct stls_buffer_s
{
buffer b ;
- unsigned char blockedonother : 1 ;
char buf[STLS_BUFSIZE] ;
+ uint8_t flags ; /* 0x1: flush/fill wants opposite IO; 0x2: close_notify initiated */
} ;
-static inline int buffer_tls_flush (struct tls *ctx, tlsbuf_t *b)
+
+ /*
+ We need access to the state field of struct tls, which is private.
+ So we fake enough stuff that we get the correct field offset.
+ */
+
+#define TLS_EOF_NO_CLOSE_NOTIFY 1
+
+struct fake_tls_error_s
{
- struct iovec v[2] ;
- ssize_t r, w ;
- buffer_rpeek(&b[0].b, v) ;
- r = tls_write(ctx, v[0].iov_base, v[0].iov_len) ;
- switch (r)
- {
- case -1 : return -1 ;
- case TLS_WANT_POLLIN :
- if (b[1].blockedonother) strerr_dief1x(101, "TLS deadlock") ;
- b[0].blockedonother = 1 ;
- case TLS_WANT_POLLOUT : return 0 ;
- default : break ;
- }
- w = r ;
- if ((size_t)w == v[0].iov_len && v[1].iov_len)
+ char *msg ;
+ int num ;
+ int tls ;
+} ;
+
+struct fake_tls_s
+{
+ void *config ;
+ void *keypair ;
+ struct fake_tls_error_s error ;
+ uint32_t flags ;
+ uint32_t state ;
+} ;
+
+ /* All because there's no accessor for this in the official libtls API: */
+
+static inline int tls_eof_got_close_notify (struct tls *ctx)
+{
+ return !(((struct fake_tls_s *)ctx)->state & TLS_EOF_NO_CLOSE_NOTIFY) ;
+}
+
+ /* We want tls_read/write to behave l */
+
+static int tls_allwrite (struct tls *ctx, char const *s, size_t len, size_t *w)
+{
+ while (*w < len)
{
- r = tls_write(ctx, v[1].iov_base, v[1].iov_len) ;
+ ssize_t r = tls_write(ctx, s + *w, len - *w) ;
switch (r)
{
- case TLS_WANT_POLLIN :
- if (b[1].blockedonother) strerr_dief1x(101, "TLS deadlock") ;
- b[0].blockedonother = 1 ;
- case -1 :
- case TLS_WANT_POLLOUT :
- buffer_rseek(&b[0].b, w) ;
- return 0 ;
+ case -1 : strerr_diefu2x(98, "tls_write: ", tls_error(ctx)) ;
+ case TLS_WANT_POLLIN : return 1 ;
+ case TLS_WANT_POLLOUT : return 0 ;
default : break ;
}
- w += r ;
+ *w += r ;
}
- buffer_rseek(&b[0].b, w) ;
- return 1 ;
+ return 0 ;
}
-static inline int buffer_tls_fill (struct tls *ctx, tlsbuf_t *b)
+static void tls_flush (struct tls *ctx, stls_buffer *b)
{
struct iovec v[2] ;
- ssize_t r, w ;
- int ok = 1 ;
- buffer_wpeek(&b[1].b, v) ;
- r = tls_read(ctx, v[0].iov_base, v[0].iov_len) ;
- switch (r)
- {
- case 0 : return -2 ;
- case -1 : return -1 ;
- case TLS_WANT_POLLOUT :
- if (b[0].blockedonother) strerr_dief1x(101, "TLS deadlock") ;
- b[1].blockedonother = 1 ;
- case TLS_WANT_POLLIN : return 0 ;
- default : break ;
- }
- w = r ;
- if ((size_t)w == v[0].iov_len && v[1].iov_len)
+ size_t w = 0 ;
+ int r ;
+ buffer_rpeek(&b[0].b, v) ;
+ r = tls_allwrite(ctx, v[0].iov_base, v[0].iov_len, &w) ;
+ buffer_rseek(&b[0].b, w) ;
+ if (w < v[0].iov_len || !v[1].iov_len) goto out ;
+ w = 0 ;
+ r = tls_allwrite(ctx, v[1].iov_base, v[1].iov_len, &w) ;
+ buffer_rseek(&b[0].b, w) ;
+ out:
+ if (r) b[1].flags |= 1 ; else b[1].flags &= ~1 ;
+}
+
+static int tls_allread (struct tls *ctx, char *s, size_t len, size_t *w)
+{
+ while (*w < len)
{
- r = tls_read(ctx, v[1].iov_base, v[1].iov_len) ;
+ ssize_t r = tls_read(ctx, s + *w, len - *w) ;
switch (r)
{
- case TLS_WANT_POLLOUT :
- if (b[0].blockedonother) strerr_dief1x(101, "TLS deadlock") ;
- b[1].blockedonother = 1 ;
- case -1 :
- case TLS_WANT_POLLIN :
- buffer_wseek(&b[1].b, w) ;
- return 0 ;
- case 0 : ok = -1 ; errno = EPIPE ;
+ case -1 : strerr_diefu2x(98, "tls_read: ", tls_error(ctx)) ;
+ case 0 : return -1 ;
+ case TLS_WANT_POLLIN : return 0 ;
+ case TLS_WANT_POLLOUT : return 1 ;
default : break ;
}
- w += r ;
+ *w += r ;
}
- buffer_wseek(&b[1].b, w) ;
- return ok ;
+ return 0 ;
}
-static void send_closenotify (struct tls *ctx, int const *fds)
+static int tls_fill (struct tls *ctx, stls_buffer *b)
{
- iopause_fd x = { .fd = fds[3], .events = IOPAUSE_WRITE } ;
- while (tls_close(ctx) == TLS_WANT_POLLOUT)
- iopause_g(&x, 1, 0) ;
+ struct iovec v[2] ;
+ size_t w = 0 ;
+ int r ;
+ buffer_wpeek(&b[1].b, v) ;
+ r = tls_allread(ctx, v[0].iov_base, v[0].iov_len, &w) ;
+ buffer_wseek(&b[1].b, w) ;
+ if (w < v[0].iov_len || !v[1].iov_len) goto out ;
+ w = 0 ;
+ r = tls_allread(ctx, v[1].iov_base, v[1].iov_len, &w) ;
+ buffer_wseek(&b[1].b, w) ;
+ out:
+ if (r == -1) return 1 ;
+ if (r) b[0].flags |= 1 ; else b[0].flags &= ~1 ;
+ return 0 ;
}
-static void closeit (struct tls *ctx, int *fds, int closenotify)
+static int tls_close_nb (struct tls *ctx, stls_buffer *b)
{
- if (!closenotify) fd_shutdown(fds[3], 1) ;
- else if (fds[2] >= 0) send_closenotify(ctx, fds) ;
- fd_close(fds[3]) ; fds[3] = -1 ;
+ switch (tls_close(ctx))
+ {
+ case 0 : b[0].flags &= ~2 ; b[1].flags &= ~2 ; b[1].flags |= 4 ; return 1 ;
+ case TLS_WANT_POLLIN : b[0].flags &= ~2 ; b[1].flags |= 2 ; break ;
+ case TLS_WANT_POLLOUT : b[0].flags |= 2 ; b[1].flags &= ~2 ; break ;
+ default : strerr_diefu2x(98, "tls_close: ", tls_error(ctx)) ;
+ }
+ return 0 ;
}
-void stls_run (struct tls *ctx, int *fds, uint32_t options, unsigned int verbosity)
+ /* The engine. */
+
+void stls_run (struct tls *ctx, int const *fds, uint32_t options, unsigned int verbosity)
{
- tlsbuf_t b[2] = { { .blockedonother = 0 }, { .blockedonother = 0 } } ;
- iopause_fd x[4] ;
- unsigned int xindex[4] ;
-
- if (ndelay_on(fds[0]) < 0
- || ndelay_on(fds[1]) < 0
- || ndelay_on(fds[2]) < 0
- || ndelay_on(fds[3]) < 0)
+ stls_buffer b[2] =
+ {
+ { .b = BUFFER_INIT(&buffer_read, fds[0], b[0].buf, STLS_BUFSIZE), .flags = 0 },
+ { .b = BUFFER_INIT(&buffer_write, fds[1], b[1].buf, STLS_BUFSIZE), .flags = 0 },
+ } ;
+ iopause_fd x[4] = { { .fd = fds[0] }, { .fd = fds[1] }, { .fd = fds[2] }, { .fd = fds[3] } } ;
+
+ if (ndelay_on(x[0].fd) == -1
+ || ndelay_on(x[1].fd) == -1
+ || ndelay_on(x[2].fd) == -1
+ || ndelay_on(x[3].fd) == -1)
strerr_diefu1sys(111, "set fds non-blocking") ;
- buffer_init(&b[0].b, &buffer_read, fds[0], b[0].buf, STLS_BUFSIZE) ;
- buffer_init(&b[1].b, &buffer_write, fds[1], b[1].buf, STLS_BUFSIZE) ;
-
- for (;;)
+ while (x[0].fd >= 0 || x[1].fd >= 0 || x[3].fd >= 0)
{
- unsigned int j = 0 ;
- int r ;
-
-
- /* poll() preparation */
-
- if (fds[0] >= 0 && buffer_isreadable(&b[0].b))
- {
- x[j].fd = fds[0] ;
- x[j].events = IOPAUSE_READ ;
- xindex[0] = j++ ;
- }
- else xindex[0] = 4 ;
-
- if (fds[1] >= 0 && buffer_iswritable(&b[1].b))
- {
- x[j].fd = fds[1] ;
- x[j].events = IOPAUSE_WRITE ;
- xindex[1] = j++ ;
- }
- else xindex[1] = 4 ;
-
- if (fds[2] >= 0 && !b[1].blockedonother && buffer_isreadable(&b[1].b))
- {
- x[j].fd = fds[2] ;
- x[j].events = IOPAUSE_READ ;
- xindex[2] = j++ ;
- }
- else xindex[2] = 4 ;
-
- if (fds[3] >= 0 && !b[0].blockedonother && buffer_iswritable(&b[0].b))
- {
- x[j].fd = fds[3] ;
- x[j].events = IOPAUSE_WRITE ;
- xindex[3] = j++ ;
- }
- else xindex[3] = 4 ;
-
- if (xindex[0] == 4 && xindex[1] == 4 && xindex[3] == 4) break ;
+ x[0].events = x[0].fd >= 0 && buffer_isreadable(&b[0].b) ? IOPAUSE_READ : 0 ;
+ x[1].events = x[1].fd >= 0 && buffer_iswritable(&b[1].b) ? IOPAUSE_WRITE : 0 ;
+ x[2].events = x[2].fd >= 0 && (buffer_isreadable(&b[1].b) || (b[1].flags & 1 && buffer_iswritable(&b[0].b))) ? IOPAUSE_READ : 0 ;
+ x[3].events = x[3].fd >= 0 && (buffer_iswritable(&b[0].b) || (b[0].flags & 1 && buffer_isreadable(&b[1].b))) ? IOPAUSE_WRITE : 0 ;
- /* poll() */
-
- r = iopause_g(x, j, 0) ;
- if (r < 0) strerr_diefu1sys(111, "iopause") ;
- else if (!r) break ;
-
- while (j--)
- if (x[j].revents & IOPAUSE_EXCEPT)
- x[j].revents |= IOPAUSE_READ | IOPAUSE_WRITE ;
-
+ if (iopause_g(x, 4, 0) == -1) strerr_diefu1sys(111, "iopause") ;
/* Flush to local */
- if (xindex[1] < 4 && x[xindex[1]].revents & IOPAUSE_WRITE)
+ if (x[1].revents)
{
- r = buffer_flush(&b[1].b) ;
- if (!r && !error_isagain(errno))
+ if (!buffer_flush(&b[1].b))
{
- strerr_warnwu1sys("write to application") ;
- if (fds[2] >= 0)
- {
- if (options & 1) fd_shutdown(fds[2], 0) ;
- fd_close(fds[2]) ; fds[2] = -1 ;
- xindex[2] = 4 ;
- }
- r = 1 ;
+ if (!error_isagain(errno)) strerr_diefu1sys(111, "write to local") ;
}
- if (r && fds[2] < 0)
+ else if (x[2].fd == -1)
{
- fd_close(fds[1]) ; fds[1] = -1 ;
+ fd_close(x[1].fd) ;
+ x[1].fd = -1 ;
}
}
- /* Flush to remote */
+ /* Flush to remote: do everything that had TLS_WANT_POLLOUT */
- if (xindex[3] < 4 && x[xindex[3]].revents & IOPAUSE_WRITE)
+ if (x[3].revents)
{
- r = buffer_tls_flush(ctx, b) ;
- if (r < 0)
+ if (buffer_len(&b[0].b)) tls_flush(ctx, b) ; /* normal write */
+ if ((b[0].flags & 1 && tls_fill(ctx, b)) /* peer sent close_notify and it just completed */
+ || (b[0].flags & 2 && tls_close_nb(ctx, b))) /* we send close_notify and it instantly succeeds */
{
- strerr_warnwu2x("write to peer: ", tls_error(ctx)) ;
- fd_close(fds[0]) ; fds[0] = -1 ;
- xindex[0] = 4 ;
+ if (buffer_isempty(&b[1].b)) break ;
+ fd_close(x[3].fd) ; x[3].fd = -1 ;
+ fd_close(x[2].fd) ; x[2].fd = -1 ;
+ if (x[0].fd >= 0) { fd_close(x[0].fd) ; x[0].fd = -1 ; }
+ continue ;
+ }
+ if (x[0].fd == -1 && buffer_isempty(&b[0].b))
+ {
+ if (!(options & 1) || tls_close_nb(ctx, b))
+ {
+ fd_shutdown(x[3].fd, 1) ;
+ fd_close(x[3].fd) ;
+ x[3].fd = -1 ;
+ }
}
- if (r && fds[0] < 0)
- closeit(ctx, fds, options & 1) ;
}
/* Fill from local */
- if (xindex[0] < 4 && x[xindex[0]].revents & IOPAUSE_READ)
+ if (x[0].revents)
{
- r = sanitize_read(buffer_fill(&b[0].b)) ;
- if (r < 0)
+ ssize_t r = buffer_fill(&b[0].b) ;
+ if (r == -1 && !error_isagain(errno))
+ strerr_diefu1sys(111, "read from local") ;
+ else if (!r)
{
- if (errno != EPIPE) strerr_warnwu1sys("read from application") ;
- fd_close(fds[0]) ; fds[0] = -1 ;
+ fd_close(x[0].fd) ;
+ x[0].fd = -1 ;
if (buffer_isempty(&b[0].b))
- closeit(ctx, fds, options & 1) ;
+ {
+ if (!(options & 1) || tls_close_nb(ctx, b))
+ {
+ fd_shutdown(x[3].fd, 1) ;
+ fd_close(x[3].fd) ;
+ x[3].fd = -1 ;
+ }
+ }
}
}
- /* Fill from remote */
+ /* Fill from remote: do everything that had TLS_WANT_POLLIN */
- if (xindex[2] < 4 && x[xindex[2]].revents & IOPAUSE_READ)
+ if (x[2].revents)
{
- r = buffer_tls_fill(ctx, b) ;
- if (r < 0)
- {
- if (r == -1) strerr_warnwu2x("read from peer: ", tls_error(ctx)) ;
- if (!(options & 1)) fd_shutdown(fds[2], 0) ;
- /*
- XXX: We need a way to detect when we've received a close_notify,
- because then we need to trigger a write and then shut the engine
- down. This is orthogonal to options&1, it only means that the
- peer sent a close_notify.
- As for now, libtls doesn't offer an API to detect that, so we
- do nothing special - we just wait until our app sends EOF.
- */
- fd_close(fds[2]) ; fds[2] = -1 ;
+ if (buffer_isreadable(&b[1].b) && tls_fill(ctx, b))
+ { /* connection closed */
+ fd_shutdown(x[2].fd, 0) ;
+ fd_close(x[2].fd) ;
+ x[2].fd = -1 ;
if (buffer_isempty(&b[1].b))
{
- fd_close(fds[1]) ; fds[1] = -1 ;
+ if (tls_eof_got_close_notify(ctx)) break ;
+ fd_close(x[1].fd) ;
+ x[1].fd = -1 ;
+ }
+ if (options & 2)
+ {
+ if (!tls_eof_got_close_notify(ctx))
+ strerr_dief1x(98, "remote closed connection without a close_notify") ;
+ else if (x[3].fd >= 0)
+ {
+ fd_shutdown(x[3].fd, 1) ;
+ fd_close(x[3].fd) ;
+ x[3].fd = -1 ;
+ }
+ }
+ }
+ else
+ { /* normal case */
+ if (b[1].flags & 1) tls_flush(ctx, b) ;
+ if (b[1].flags & 2 && tls_close_nb(ctx, b))
+ {
+ if (buffer_isempty(&b[1].b)) break ;
+ if (x[3].fd >= 0) { fd_close(x[3].fd) ; x[3].fd = -1 ; }
+ if (x[0].fd >= 0) { fd_close(x[0].fd) ; x[0].fd = -1 ; }
+ fd_close(x[2].fd) ; x[2].fd = -1 ;
}
}
}
diff --git a/src/stls/stls_server_init_and_handshake.c b/src/stls/stls_server_init_and_handshake.c
index 2304598..2a58885 100644
--- a/src/stls/stls_server_init_and_handshake.c
+++ b/src/stls/stls_server_init_and_handshake.c
@@ -86,6 +86,7 @@ struct tls *stls_server_init_and_handshake (int const *fds, tain const *tto, uin
{
if (tls_config_set_ca_path(cfg, x) < 0)
diecfg(cfg, "tls_config_set_ca_path") ;
+ strerr_warnw1x("some versions of libtls do not work with CADIR, if you experience problems with client certificate verification then try using CAFILE instead") ;
}
else
{
@@ -109,7 +110,7 @@ struct tls *stls_server_init_and_handshake (int const *fds, tain const *tto, uin
if (!sctx) strerr_diefu1sys(111, "tls_server") ;
if (tls_configure(sctx, cfg) < 0) diectx(97, sctx, "tls_configure") ;
tls_config_free(cfg) ;
- if (tls_accept_fds(sctx, &ctx, fds[0], fds[1]) < 0)
+ if (tls_accept_fds(sctx, &ctx, fds[0], fds[1]) == -1)
diectx(97, sctx, "tls_accept_fds") ;
/* We can't free sctx, ctx has pointers into it! Stupid API. We let sctx leak. */
/* tls_free(sctx) ; */
diff --git a/src/tls/s6-tlsc-io.c b/src/tls/s6-tlsc-io.c
index e64c014..25347b7 100644
--- a/src/tls/s6-tlsc-io.c
+++ b/src/tls/s6-tlsc-io.c
@@ -13,7 +13,7 @@
#include <s6-networking/config.h>
-#define USAGE "s6-tlsc-io [ -v verbosity ] [ -d notif ] [ -S | -s ] [ -Y | -y ] [ -K timeout ] [ -k servername ] fdr fdw"
+#define USAGE "s6-tlsc-io [ -v verbosity ] [ -d notif ] [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -K timeout ] [ -k servername ] fdr fdw"
#define dieusage() strerr_dieusage(100, USAGE)
static inline void doit (int *, tain const *tto, uint32_t, uint32_t, unsigned int, char const *, unsigned int) gccattr_noreturn ;
@@ -81,7 +81,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
unsigned int t = 0 ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "d:SsYyv:K:k:", &l) ;
+ int opt = subgetopt_r(argc, argv, "d:SsJjYyv:K:k:", &l) ;
if (opt == -1) break ;
switch (opt)
{
@@ -89,8 +89,10 @@ int main (int argc, char const *const *argv, char const *const *envp)
case 'd' : if (!uint0_scan(l.arg, &notif)) dieusage() ; break ;
case 'S' : options |= 1 ; break ;
case 's' : options &= ~1 ; break ;
- case 'Y' : preoptions &= ~1 ; break ;
+ case 'J' : options |= 2 ; break ;
+ case 'j' : options &= ~2 ; break ;
case 'y' : preoptions |= 1 ; break ;
+ case 'Y' : preoptions &= ~1 ; break ;
case 'K' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
case 'k' : servername = l.arg ; break ;
default : dieusage() ;
diff --git a/src/tls/s6-tlsc.c b/src/tls/s6-tlsc.c
index d348599..ebea264 100644
--- a/src/tls/s6-tlsc.c
+++ b/src/tls/s6-tlsc.c
@@ -11,7 +11,7 @@
#include "s6tls-internal.h"
-#define USAGE "s6-tlsc [ -S | -s ] [ -Y | -y ] [ -v verbosity ] [ -K timeout ] [ -k servername ] [ -Z | -z ] [ -6 fdr ] [ -7 fdw ] prog..."
+#define USAGE "s6-tlsc [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -v verbosity ] [ -K timeout ] [ -k servername ] [ -Z | -z ] [ -6 fdr ] [ -7 fdw ] prog..."
#define dieusage() strerr_dieusage(100, USAGE)
int main (int argc, char const *const *argv)
@@ -30,14 +30,16 @@ int main (int argc, char const *const *argv)
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "SsYyv:K:k:Zz6:7:", &l) ;
+ int opt = subgetopt_r(argc, argv, "SsJjyYv:K:k:Zz6:7:", &l) ;
if (opt == -1) break ;
switch (opt)
{
- case 'S' : coptions &= ~4 ; break ;
- case 's' : coptions |= 4 ; break ;
- case 'Y' : coptions &= ~1 ; break ;
+ case 'S' : coptions |= 4 ; break ;
+ case 's' : coptions &= ~4 ; break ;
+ case 'J' : coptions |= 2 ; break ;
+ case 'j' : coptions &= ~2 ; break ;
case 'y' : coptions |= 1 ; break ;
+ case 'Y' : coptions &= ~1 ; break ;
case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
case 'K' : if (!uint0_scan(l.arg, &kimeout)) dieusage() ; break ;
case 'k' : servername = l.arg ; break ;
diff --git a/src/tls/s6-tlsd-io.c b/src/tls/s6-tlsd-io.c
index fac2164..08eee77 100644
--- a/src/tls/s6-tlsd-io.c
+++ b/src/tls/s6-tlsd-io.c
@@ -13,7 +13,7 @@
#include <s6-networking/config.h>
-#define USAGE "s6-tlsd-io [ -v verbosity ] [ -d notif ] [ -S | -s ] [ -Y | -y ] [ -K timeout ] [ -k snilevel ] fdr fdw"
+#define USAGE "s6-tlsd-io [ -v verbosity ] [ -d notif ] [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -K timeout ] [ -k snilevel ] fdr fdw"
#define dieusage() strerr_dieusage(100, USAGE)
static inline void doit (int *, tain const *tto, uint32_t, uint32_t, unsigned int, unsigned int) gccattr_noreturn ;
@@ -78,7 +78,7 @@ int main (int argc, char const *const *argv)
unsigned int t = 0 ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "d:SsYyv:K:k:", &l) ;
+ int opt = subgetopt_r(argc, argv, "d:SsJjYyv:K:k:", &l) ;
if (opt == -1) break ;
switch (opt)
{
@@ -86,6 +86,8 @@ int main (int argc, char const *const *argv)
case 'd' : if (!uint0_scan(l.arg, &notif)) dieusage() ; break ;
case 'S' : options |= 1 ; break ;
case 's' : options &= ~1 ; break ;
+ case 'J' : options |= 2 ; break ;
+ case 'j' : options &= ~2 ; break ;
case 'Y' : preoptions |= 1 ; preoptions &= ~2 ; break ;
case 'y' : preoptions |= 3 ; break ;
case 'K' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
diff --git a/src/tls/s6-tlsd.c b/src/tls/s6-tlsd.c
index 85c0d9f..acd2945 100644
--- a/src/tls/s6-tlsd.c
+++ b/src/tls/s6-tlsd.c
@@ -9,7 +9,7 @@
#include "s6tls-internal.h"
-#define USAGE "s6-tlsd [ -S | -s ] [ -Y | -y ] [ -k snilevel ] [ -v verbosity ] [ -K timeout ] [ -Z | -z ] prog..."
+#define USAGE "s6-tlsd [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -k snilevel ] [ -v verbosity ] [ -K timeout ] [ -Z | -z ] prog..."
#define dieusage() strerr_dieusage(100, USAGE)
int main (int argc, char const *const *argv)
@@ -28,14 +28,16 @@ int main (int argc, char const *const *argv)
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "SsYyv:K:Zzk:", &l) ;
+ int opt = subgetopt_r(argc, argv, "SsJjyYv:K:Zzk:", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'S' : coptions |= 4 ; break ;
case 's' : coptions &= ~4 ; break ;
- case 'Y' : coptions |= 1 ; coptions &= ~2 ; break ;
+ case 'J' : coptions |= 8 ; break ;
+ case 'j' : coptions &= ~8 ; break ;
case 'y' : coptions |= 3 ; break ;
+ case 'Y' : coptions |= 1 ; coptions &= ~2 ; break ;
case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
case 'K' : if (!uint0_scan(l.arg, &kimeout)) dieusage() ; break ;
case 'Z' : poptions &= ~1 ; break ;
diff --git a/src/tls/s6-ucspitlsc.c b/src/tls/s6-ucspitlsc.c
index bb1a2dc..cd29324 100644
--- a/src/tls/s6-ucspitlsc.c
+++ b/src/tls/s6-ucspitlsc.c
@@ -15,7 +15,7 @@
#include <s6-networking/config.h>
#include "s6tls-internal.h"
-#define USAGE "s6-ucspitlsc [ -S | -s ] [ -Y | -y ] [ -v verbosity ] [ -K timeout ] [ -Z | -z ] [ -k servername ] [ -6 fdr ] [ -7 fdw ] prog..."
+#define USAGE "s6-ucspitlsc [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -v verbosity ] [ -K timeout ] [ -Z | -z ] [ -k servername ] [ -6 fdr ] [ -7 fdw ] prog..."
#define dieusage() strerr_dieusage(100, USAGE)
static inline void child (int *, uint32_t, unsigned int, unsigned int, char const *, pid_t) gccattr_noreturn ;
@@ -80,14 +80,16 @@ int main (int argc, char const *const *argv, char const *const *envp)
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "SsYyv:K:Zzk:6:7:", &l) ;
+ int opt = subgetopt_r(argc, argv, "SsJjyYv:K:Zzk:6:7:", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'S' : coptions |= 4 ; break ;
case 's' : coptions &= ~4 ; break ;
- case 'Y' : coptions |= 1 ; coptions &= ~2 ; break ;
- case 'y' : coptions |= 3 ; break ;
+ case 'J' : coptions |= 2 ; break ;
+ case 'j' : coptions &= ~2 ; break ;
+ case 'y' : coptions |= 1 ; break ;
+ case 'Y' : coptions &= ~1 ; break ;
case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
case 'K' : if (!uint0_scan(l.arg, &kimeout)) dieusage() ; break ;
case 'Z' : poptions &= ~1 ; break ;
diff --git a/src/tls/s6-ucspitlsd.c b/src/tls/s6-ucspitlsd.c
index fc0868a..d2b9580 100644
--- a/src/tls/s6-ucspitlsd.c
+++ b/src/tls/s6-ucspitlsd.c
@@ -14,7 +14,7 @@
#include <s6-networking/config.h>
#include "s6tls-internal.h"
-#define USAGE "s6-ucspitlsd [ -S | -s ] [ -Y | -y ] [ -k snilevel ] [ -v verbosity ] [ -K timeout ] [ -Z | -z ] prog..."
+#define USAGE "s6-ucspitlsd [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -k snilevel ] [ -v verbosity ] [ -K timeout ] [ -Z | -z ] prog..."
#define dieusage() strerr_dieusage(100, USAGE)
static inline void child (int *, uint32_t, unsigned int, unsigned int, unsigned int, pid_t) gccattr_noreturn ;
@@ -77,14 +77,16 @@ int main (int argc, char const *const *argv)
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "SsYyv:K:Zzk:", &l) ;
+ int opt = subgetopt_r(argc, argv, "SsJjyYv:K:Zzk:", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'S' : coptions |= 4 ; break ;
case 's' : coptions &= ~4 ; break ;
- case 'Y' : coptions |= 1 ; coptions &= ~2 ; break ;
+ case 'J' : coptions |= 8 ; break ;
+ case 'j' : coptions &= ~8 ; break ;
case 'y' : coptions |= 3 ; break ;
+ case 'Y' : coptions |= 1 ; coptions &= ~2 ; break ;
case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
case 'K' : if (!uint0_scan(l.arg, &kimeout)) dieusage() ; break ;
case 'Z' : poptions &= ~1 ; break ;
diff --git a/src/tls/s6tls-internal.h b/src/tls/s6tls-internal.h
index fdd247f..1ab77f6 100644
--- a/src/tls/s6tls-internal.h
+++ b/src/tls/s6tls-internal.h
@@ -9,7 +9,7 @@
#include <skalibs/gccattributes.h>
#include <skalibs/types.h>
-#define S6TLS_PREP_IO_ARGC 15
+#define S6TLS_PREP_IO_ARGC 16
#define S6TLS_PREP_IO_BUFLEN (5 * UINT_FMT)
extern pid_t s6tls_io_spawn (char const *const *argv, int const *, int) ;
diff --git a/src/tls/s6tls_prep_tlscio.c b/src/tls/s6tls_prep_tlscio.c
index a3f33b0..0b7ff1f 100644
--- a/src/tls/s6tls_prep_tlscio.c
+++ b/src/tls/s6tls_prep_tlscio.c
@@ -26,6 +26,7 @@ void s6tls_prep_tlscio (char const **argv, char *buf, int const *p, uint32_t opt
buf[n++] = 0 ;
}
argv[m++] = options & 4 ? "-S" : "-s" ;
+ argv[m++] = options & 2 ? "-J" : "-j" ;
argv[m++] = options & 1 ? "-y" : "-Y" ;
if (kimeout)
{
diff --git a/src/tls/s6tls_prep_tlsdio.c b/src/tls/s6tls_prep_tlsdio.c
index 73099bf..59cc536 100644
--- a/src/tls/s6tls_prep_tlsdio.c
+++ b/src/tls/s6tls_prep_tlsdio.c
@@ -26,6 +26,7 @@ void s6tls_prep_tlsdio (char const **argv, char *buf, int const *p, uint32_t opt
buf[n++] = 0 ;
}
argv[m++] = options & 4 ? "-S" : "-s" ;
+ argv[m++] = options & 8 ? "-J" : "-j" ;
if (options & 1)
argv[m++] = options & 2 ? "-y" : "-Y" ;
if (kimeout)