diff options
55 files changed, 2977 insertions, 14 deletions
@@ -10,6 +10,10 @@ Build Instructions - execline version 2.2.0.0 or later: http://skarnet.org/software/execline/ - s6 version 2.4.0.0 or later: http://skarnet.org/software/s6/ - s6-dns version 2.1.0.0 or later: http://skarnet.org/software/s6-dns/ + - Depending on whether you build the SSL tools, + libressl version 2.5.0 or later: http://libressl.org/ + or bearssl version 0.1 or later: http://bearssl.org/ + (BearSSL support is experimental for now, don't use it yet.) This software will run on any operating system that implements POSIX.1-2008, available at: @@ -168,3 +172,21 @@ without relying on a PATH search. skarnet.org packages do not support out-of-tree builds. They are small, so it does not cost much to duplicate the entire source tree if parallel builds are needed. + + +* SSL support + ----------- + + s6-networking implements UCSPI tools for TLS1.2 connections: s6-tlsclient, +s6-tlsserver, s6-tlsc and s6-tlsd. Those are built if you give the +--enable-ssl=<implementation> flag to configure. There are two supported +values for <implementation>: libressl (in which case the tools will be +built against libtls) and bearssl (in which case the tools will be built +against libbearssl). You should install the relevant header and library +files for your chosen implementation before building a SSL-enabled +s6-networking. + If your SSL headers and library files are not installed in /usr/include +and /usr/lib, you can use the --with-ssl-path=DIR configure option: +headers will be searched in DIR/include and libraries will be searched in +DIR/lib. For more complex setups, use the generic --with-include and +--with-dir configure options. @@ -44,6 +44,10 @@ Optional features: --enable-absolute-paths do not rely on PATH to access this package's binaries, hardcode absolute BINDIR/foobar paths instead [disabled] +SSL support: + --enable-ssl=libressl|bearssl build SSL tools, w/ libtls or bearssl implementation [disabled] + --with-ssl-path=DIR search for SSL headers/libs in DIR/include and DIR/lib [/usr] + EOF exit 0 } @@ -149,6 +153,7 @@ addlibdpath='' vpaths='' vpathd='' build= +ssl= for arg ; do case "$arg" in @@ -177,6 +182,10 @@ for arg ; do --disable-slashpackage) sproot= ; slashpackage=false ;; --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;; --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;; + --enable-ssl=libressl) ssl=tls ;; + --enable-ssl=bearssl) ssl=bearssl ;; + --disable-ssl|--enable-ssl=none) ssl= ;; + --with-ssl-path=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var/include" ; addlibspath="$addlibspath -L$var/lib" ; vpaths="$vpaths $var/lib" ; addlibdpath="$addlibdpath -L$var/lib" ; vpathd="$vpathd $var/lib" ;; --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;; --host=*|--target=*) target=${arg#*=} ;; --build=*) build=${arg#*=} ;; @@ -395,6 +404,11 @@ if $shared ; then else echo "DO_SHARED :=" fi +if test -n $ssl ; then + echo "SSL_IMPL := $ssl" +else + echo "SSL_IMPL :=" +fi exec 1>&3 3>&- echo " ... done." @@ -423,6 +437,17 @@ else echo "#define ${package_macro_name}_EXTBINPREFIX \"\"" fi echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\"" +if test "tls" = "$ssl" ; then + echo "#define ${package_macro_name}_USE_TLS" +else + echo "#undef ${package_macro_name}_USE_TLS" +fi +if test "bearssl" = "$ssl" ; then + echo "#define ${package_macro_name}_USE_BEARSSL" +else + echo "#undef ${package_macro_name}_USE_BEARSSL" +fi + echo echo "#endif" exec 1>&3 3>&- diff --git a/doc/index.html b/doc/index.html index 1efbc9b..8ad4264 100644 --- a/doc/index.html +++ b/doc/index.html @@ -42,7 +42,7 @@ compiled with IPv6 support, s6-networking is IPv6-ready. <li> A POSIX-compliant system with a standard C development environment </li> <li> GNU make, version 3.81 or later </li> <li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version -2.4.0.0 or later. It's a build-time requirement. It's also a run-time +2.4.0.1 or later. It's a build-time requirement. It's also a run-time requirement if you link against the shared version of the skalibs library. </li> <li> <a href="http://skarnet.org/software/execline/">execline</a> version @@ -53,6 +53,14 @@ library. </li> 2.1.0.0 or later. It's a build-time requirement. It's also a run-time requirement if you link against the shared version of the s6-dns libraries. </li> + <li> If you want to build the TLS tools: + <ul> + <li> Either <a href="http://libressl.org/">LibreSSL</a> version 2.5.0 +or later </li> + <li> Or <a href="http://bearssl.org/">BearSSL</a> version 0.1 +or later. <strong>THIS IS EXPERIMENTAL.</strong> </li> + </ul> The chosen library is a build-time requirement, and also a +run-time requirement if you link against its shared version. </li> </ul> <h3> Licensing </h3> @@ -66,7 +74,7 @@ libraries. </li> <ul> <li> The current released version of s6-networking is -<a href="s6-networking-2.2.0.0.tar.gz">2.2.0.0</a>. </li> +<a href="s6-networking-2.2.1.0.tar.gz">2.2.1.0</a>. </li> <li> Alternatively, you can checkout a copy of the <a href="http://git.skarnet.org/cgi-bin/cgit.cgi/s6-networking/">s6-networking git repository</a>: @@ -126,6 +134,15 @@ relevant page. <li><a href="s6-tcpserver6d.html">The <tt>s6-tcpserver6d</tt> program</a></li> </ul> +<h4> UCSPI tools for TLS 1.2 over TCP </h4> + +<ul> +<li><a href="s6-tlsclient.html">The <tt>s6-tlsclient</tt> program</a></li> +<li><a href="s6-tlsserver.html">The <tt>s6-tlsserver</tt> program</a></li> +<li><a href="s6-tlsc.html">The <tt>s6-tlsc</tt> program</a></li> +<li><a href="s6-tlsd.html">The <tt>s6-tlsd</tt> program</a></li> +</ul> + <h4> TCP access control </h4> <ul> diff --git a/doc/upgrade.html b/doc/upgrade.html index fda61e6..4b20888 100644 --- a/doc/upgrade.html +++ b/doc/upgrade.html @@ -18,6 +18,19 @@ <h1> What has changed in s6-networking </h1> +<h2> in 2.2.1.0 </h2> + +<ul> + <li> skalibs dependency bumped to 2.4.0.1. </li> + <li> TLS 1.2 support added: + <ul> + <li> <a href="s6-tlsclient.html">s6-tlsclient</a> </li> + <li> <a href="s6-tlsserver.html">s6-tlsserver</a> </li> + <li> <a href="s6-tlsc.html">s6-tlsc</a> </li> + <li> <a href="s6-tlsd.html">s6-tlsd</a> </li> + </ul> </li> +</ul> + <h2> in 2.2.0.0 </h2> <ul> diff --git a/package/deps.mak b/package/deps.mak index 4218772..2f9d76f 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -19,6 +19,10 @@ src/conn-tools/s6-tcpserver4d.o src/conn-tools/s6-tcpserver4d.lo: src/conn-tools src/conn-tools/s6-tcpserver6-socketbinder.o src/conn-tools/s6-tcpserver6-socketbinder.lo: src/conn-tools/s6-tcpserver6-socketbinder.c src/conn-tools/s6-tcpserver6.o src/conn-tools/s6-tcpserver6.lo: src/conn-tools/s6-tcpserver6.c src/include/s6-networking/config.h src/conn-tools/s6-tcpserver6d.o src/conn-tools/s6-tcpserver6d.lo: src/conn-tools/s6-tcpserver6d.c +src/conn-tools/s6-tlsc.o src/conn-tools/s6-tlsc.lo: src/conn-tools/s6-tlsc.c src/include/s6-networking/config.h src/include/s6-networking/sbearssl.h src/include/s6-networking/stls.h +src/conn-tools/s6-tlsclient.o src/conn-tools/s6-tlsclient.lo: src/conn-tools/s6-tlsclient.c src/include/s6-networking/config.h +src/conn-tools/s6-tlsd.o src/conn-tools/s6-tlsd.lo: src/conn-tools/s6-tlsd.c src/include/s6-networking/config.h src/include/s6-networking/sbearssl.h src/include/s6-networking/stls.h +src/conn-tools/s6-tlsserver.o src/conn-tools/s6-tlsserver.lo: src/conn-tools/s6-tlsserver.c src/include/s6-networking/config.h src/libs6net/s6net_ident_client.o src/libs6net/s6net_ident_client.lo: src/libs6net/s6net_ident_client.c src/include/s6-networking/ident.h src/libs6net/s6net_ident_error.o src/libs6net/s6net_ident_error.lo: src/libs6net/s6net_ident_error.c src/include/s6-networking/ident.h src/libs6net/s6net_ident_reply_get.o src/libs6net/s6net_ident_reply_get.lo: src/libs6net/s6net_ident_reply_get.c src/include/s6-networking/ident.h @@ -26,9 +30,40 @@ src/libs6net/s6net_ident_reply_parse.o src/libs6net/s6net_ident_reply_parse.lo: src/minidentd/mgetuid-default.o src/minidentd/mgetuid-default.lo: src/minidentd/mgetuid-default.c src/minidentd/mgetuid.h src/minidentd/mgetuid-linux.o src/minidentd/mgetuid-linux.lo: src/minidentd/mgetuid-linux.c src/minidentd/mgetuid.h src/minidentd/minidentd.o src/minidentd/minidentd.lo: src/minidentd/minidentd.c src/minidentd/mgetuid.h -src/tls/s6-tlsc.o src/tls/s6-tlsc.lo: src/tls/s6-tlsc.c src/tls/s6net-tls-internal.h -src/tls/s6-tlsd.o src/tls/s6-tlsd.lo: src/tls/s6-tlsd.c src/tls/s6net-tls-internal.h -src/tls/s6net_tls_mainloop.o src/tls/s6net_tls_mainloop.lo: src/tls/s6net_tls_mainloop.c src/tls/s6net-tls-internal.h +src/sbearssl/sbearssl_append.o src/sbearssl/sbearssl_append.lo: src/sbearssl/sbearssl_append.c +src/sbearssl/sbearssl_cert_from.o src/sbearssl/sbearssl_cert_from.lo: src/sbearssl/sbearssl_cert_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_cert_readfile.o src/sbearssl/sbearssl_cert_readfile.lo: src/sbearssl/sbearssl_cert_readfile.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_cert_to.o src/sbearssl/sbearssl_cert_to.lo: src/sbearssl/sbearssl_cert_to.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ec_pkey_from.o src/sbearssl/sbearssl_ec_pkey_from.lo: src/sbearssl/sbearssl_ec_pkey_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ec_pkey_to.o src/sbearssl/sbearssl_ec_pkey_to.lo: src/sbearssl/sbearssl_ec_pkey_to.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ec_skey_from.o src/sbearssl/sbearssl_ec_skey_from.lo: src/sbearssl/sbearssl_ec_skey_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ec_skey_to.o src/sbearssl/sbearssl_ec_skey_to.lo: src/sbearssl/sbearssl_ec_skey_to.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_error_str.o src/sbearssl/sbearssl_error_str.lo: src/sbearssl/sbearssl_error_str.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_isder.o src/sbearssl/sbearssl_isder.lo: src/sbearssl/sbearssl_isder.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_pem_decode_from_buffer.o src/sbearssl/sbearssl_pem_decode_from_buffer.lo: src/sbearssl/sbearssl_pem_decode_from_buffer.c src/include/s6-networking/sbearssl.h src/sbearssl/sbearssl-internal.h +src/sbearssl/sbearssl_pem_decode_from_string.o src/sbearssl/sbearssl_pem_decode_from_string.lo: src/sbearssl/sbearssl_pem_decode_from_string.c src/include/s6-networking/sbearssl.h src/sbearssl/sbearssl-internal.h +src/sbearssl/sbearssl_pem_push.o src/sbearssl/sbearssl_pem_push.lo: src/sbearssl/sbearssl_pem_push.c src/sbearssl/sbearssl-internal.h +src/sbearssl/sbearssl_pkey_from.o src/sbearssl/sbearssl_pkey_from.lo: src/sbearssl/sbearssl_pkey_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_pkey_to.o src/sbearssl/sbearssl_pkey_to.lo: src/sbearssl/sbearssl_pkey_to.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_rsa_pkey_from.o src/sbearssl/sbearssl_rsa_pkey_from.lo: src/sbearssl/sbearssl_rsa_pkey_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_rsa_pkey_to.o src/sbearssl/sbearssl_rsa_pkey_to.lo: src/sbearssl/sbearssl_rsa_pkey_to.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_rsa_skey_from.o src/sbearssl/sbearssl_rsa_skey_from.lo: src/sbearssl/sbearssl_rsa_skey_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_rsa_skey_to.o src/sbearssl/sbearssl_rsa_skey_to.lo: src/sbearssl/sbearssl_rsa_skey_to.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_run.o src/sbearssl/sbearssl_run.lo: src/sbearssl/sbearssl_run.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_s6tlsc.o src/sbearssl/sbearssl_s6tlsc.lo: src/sbearssl/sbearssl_s6tlsc.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_s6tlsd.o src/sbearssl/sbearssl_s6tlsd.lo: src/sbearssl/sbearssl_s6tlsd.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_skey_from.o src/sbearssl/sbearssl_skey_from.lo: src/sbearssl/sbearssl_skey_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_skey_readfile.o src/sbearssl/sbearssl_skey_readfile.lo: src/sbearssl/sbearssl_skey_readfile.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_skey_to.o src/sbearssl/sbearssl_skey_to.lo: src/sbearssl/sbearssl_skey_to.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ta_cert.o src/sbearssl/sbearssl_ta_cert.lo: src/sbearssl/sbearssl_ta_cert.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ta_from.o src/sbearssl/sbearssl_ta_from.lo: src/sbearssl/sbearssl_ta_from.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ta_readdir.o src/sbearssl/sbearssl_ta_readdir.lo: src/sbearssl/sbearssl_ta_readdir.c src/include/s6-networking/sbearssl.h +src/sbearssl/sbearssl_ta_readfile.o src/sbearssl/sbearssl_ta_readfile.lo: src/sbearssl/sbearssl_ta_readfile.c src/include/s6-networking/sbearssl.h src/sbearssl/sbearssl-internal.h +src/sbearssl/sbearssl_ta_readfile_internal.o src/sbearssl/sbearssl_ta_readfile_internal.lo: src/sbearssl/sbearssl_ta_readfile_internal.c src/include/s6-networking/sbearssl.h src/sbearssl/sbearssl-internal.h +src/sbearssl/sbearssl_ta_to.o src/sbearssl/sbearssl_ta_to.lo: src/sbearssl/sbearssl_ta_to.c src/include/s6-networking/sbearssl.h +src/stls/stls_run.o src/stls/stls_run.lo: src/stls/stls_run.c src/include/s6-networking/stls.h +src/stls/stls_s6tlsc.o src/stls/stls_s6tlsc.lo: src/stls/stls_s6tlsc.c src/include/s6-networking/stls.h +src/stls/stls_s6tlsd.o src/stls/stls_s6tlsd.lo: src/stls/stls_s6tlsd.c src/include/s6-networking/stls.h s6-clockadd: EXTRA_LIBS := ${SYSCLOCK_LIB} s6-clockadd: src/clock/s6-clockadd.o -lskarnet @@ -62,16 +97,22 @@ s6-tcpserver6-socketbinder: EXTRA_LIBS := ${SOCKET_LIB} s6-tcpserver6-socketbinder: src/conn-tools/s6-tcpserver6-socketbinder.o -lskarnet s6-tcpserver6d: EXTRA_LIBS := ${SOCKET_LIB} s6-tcpserver6d: src/conn-tools/s6-tcpserver6d.o -lskarnet +s6-tlsc: EXTRA_LIBS := ${CRYPTO_LIB} ${SOCKET_LIB} ${TAINNOW_LIB} +s6-tlsc: src/conn-tools/s6-tlsc.o ${LIBCRYPTOSUPPORT} -lskarnet +s6-tlsclient: EXTRA_LIBS := +s6-tlsclient: src/conn-tools/s6-tlsclient.o -lskarnet +s6-tlsd: EXTRA_LIBS := ${CRYPTO_LIB} ${SOCKET_LIB} ${TAINNOW_LIB} +s6-tlsd: src/conn-tools/s6-tlsd.o ${LIBCRYPTOSUPPORT} -lskarnet +s6-tlsserver: EXTRA_LIBS := +s6-tlsserver: src/conn-tools/s6-tlsserver.o -lskarnet libs6net.a.xyzzy: src/libs6net/s6net_ident_client.o src/libs6net/s6net_ident_reply_get.o src/libs6net/s6net_ident_reply_parse.o src/libs6net/s6net_ident_error.o libs6net.so.xyzzy: EXTRA_LIBS := -lskarnet libs6net.so.xyzzy: src/libs6net/s6net_ident_client.lo src/libs6net/s6net_ident_reply_get.lo src/libs6net/s6net_ident_reply_parse.lo src/libs6net/s6net_ident_error.lo minidentd: EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} minidentd: src/minidentd/minidentd.o src/minidentd/mgetuid.o -lskarnet -s6-tlsc: EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} -s6-tlsc: src/tls/s6-tlsc.o src/tls/s6net_tls_mainloop.o -lskarnet ${TLS_LIBS} -s6-tlsclient: EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} -s6-tlsclient: src/tls/s6-tlsclient.o -lskarnet -s6-tlsd: EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} -s6-tlsd: src/tls/s6-tlsd.o src/tls/s6net_tls_mainloop.o -lskarnet ${TLS_LIBS} -s6-tlsserver: EXTRA_LIBS := ${SOCKET_LIB} ${TAINNOW_LIB} -s6-tlsserver: src/tls/s6-tlsserver.o -lskarnet +libsbearssl.a.xyzzy: src/sbearssl/sbearssl_append.o src/sbearssl/sbearssl_cert_from.o src/sbearssl/sbearssl_cert_readfile.o src/sbearssl/sbearssl_cert_to.o src/sbearssl/sbearssl_ec_pkey_from.o src/sbearssl/sbearssl_ec_pkey_to.o src/sbearssl/sbearssl_ec_skey_from.o src/sbearssl/sbearssl_ec_skey_to.o src/sbearssl/sbearssl_error_str.o src/sbearssl/sbearssl_isder.o src/sbearssl/sbearssl_pem_decode_from_buffer.o src/sbearssl/sbearssl_pem_decode_from_string.o src/sbearssl/sbearssl_pem_push.o src/sbearssl/sbearssl_pkey_from.o src/sbearssl/sbearssl_pkey_to.o src/sbearssl/sbearssl_rsa_pkey_from.o src/sbearssl/sbearssl_rsa_pkey_to.o src/sbearssl/sbearssl_rsa_skey_from.o src/sbearssl/sbearssl_rsa_skey_to.o src/sbearssl/sbearssl_run.o src/sbearssl/sbearssl_skey_from.o src/sbearssl/sbearssl_skey_readfile.o src/sbearssl/sbearssl_skey_to.o src/sbearssl/sbearssl_ta_cert.o src/sbearssl/sbearssl_ta_from.o src/sbearssl/sbearssl_ta_readdir.o src/sbearssl/sbearssl_ta_readfile.o src/sbearssl/sbearssl_ta_readfile_internal.o src/sbearssl/sbearssl_ta_to.o src/sbearssl/sbearssl_s6tlsc.o src/sbearssl/sbearssl_s6tlsd.o +libsbearssl.so.xyzzy: EXTRA_LIBS := -lbearssl -lskarnet +libsbearssl.so.xyzzy: src/sbearssl/sbearssl_append.lo src/sbearssl/sbearssl_cert_from.lo src/sbearssl/sbearssl_cert_readfile.lo src/sbearssl/sbearssl_cert_to.lo src/sbearssl/sbearssl_ec_pkey_from.lo src/sbearssl/sbearssl_ec_pkey_to.lo src/sbearssl/sbearssl_ec_skey_from.lo src/sbearssl/sbearssl_ec_skey_to.lo src/sbearssl/sbearssl_error_str.lo src/sbearssl/sbearssl_isder.lo src/sbearssl/sbearssl_pem_decode_from_buffer.lo src/sbearssl/sbearssl_pem_decode_from_string.lo src/sbearssl/sbearssl_pem_push.lo src/sbearssl/sbearssl_pkey_from.lo src/sbearssl/sbearssl_pkey_to.lo src/sbearssl/sbearssl_rsa_pkey_from.lo src/sbearssl/sbearssl_rsa_pkey_to.lo src/sbearssl/sbearssl_rsa_skey_from.lo src/sbearssl/sbearssl_rsa_skey_to.lo src/sbearssl/sbearssl_run.lo src/sbearssl/sbearssl_skey_from.lo src/sbearssl/sbearssl_skey_readfile.lo src/sbearssl/sbearssl_skey_to.lo src/sbearssl/sbearssl_ta_cert.lo src/sbearssl/sbearssl_ta_from.lo src/sbearssl/sbearssl_ta_readdir.lo src/sbearssl/sbearssl_ta_readfile.lo src/sbearssl/sbearssl_ta_readfile_internal.lo src/sbearssl/sbearssl_ta_to.lo src/sbearssl/sbearssl_s6tlsc.lo src/sbearssl/sbearssl_s6tlsd.lo +libstls.a.xyzzy: src/stls/stls_run.o src/stls/stls_s6tlsc.o src/stls/stls_s6tlsd.o +libstls.so.xyzzy: EXTRA_LIBS := -ltls -lskarnet +libstls.so.xyzzy: src/stls/stls_run.lo src/stls/stls_s6tlsc.lo src/stls/stls_s6tlsd.lo diff --git a/package/info b/package/info index 7f5cec0..9cb961e 100644 --- a/package/info +++ b/package/info @@ -1,4 +1,4 @@ package=s6-networking -version=2.2.0.0 +version=2.2.1.0 category=net package_macro_name=S6_NETWORKING diff --git a/package/modes b/package/modes index 4d4cb19..b672097 100644 --- a/package/modes +++ b/package/modes @@ -15,3 +15,7 @@ s6-sntpclock 0755 s6-taiclock 0755 s6-taiclockd 0755 minidentd 0755 +s6-tlsclient 0755 +s6-tlsc 0755 +s6-tlsserver 0755 +s6-tlsd 0755 diff --git a/package/targets.mak b/package/targets.mak index e0600cc..5ab8c07 100644 --- a/package/targets.mak +++ b/package/targets.mak @@ -29,3 +29,22 @@ src/minidentd/mgetuid.c: src/minidentd/mgetuid-linux.c src/minidentd/mgetuid-def else \ ln -sf mgetuid-default.c src/minidentd/mgetuid.c ; \ fi + +ifneq ($(SSL_IMPL),) + +BIN_TARGETS += s6-tlsclient s6-tlsc s6-tlsserver s6-tlsd + +ifeq ($(SSL_IMPL),tls) + +LIB_DEFS += STLS=stls +CRYPTO_LIB := -ltls -lssl -lcrypto +LIBCRYPTOSUPPORT := -lstls + +else ifeq ($(SSL_IMPL),bearssl) + +LIB_DEFS += SBEARSSL=sbearssl +CRYPTO_LIB := -lbearssl +LIBCRYPTOSUPPORT := -lsbearssl + +endif +endif diff --git a/src/conn-tools/deps-exe/s6-tlsc b/src/conn-tools/deps-exe/s6-tlsc new file mode 100644 index 0000000..d00d2b8 --- /dev/null +++ b/src/conn-tools/deps-exe/s6-tlsc @@ -0,0 +1,5 @@ +${LIBCRYPTOSUPPORT} +-lskarnet +${CRYPTO_LIB} +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/conn-tools/deps-exe/s6-tlsclient b/src/conn-tools/deps-exe/s6-tlsclient new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/conn-tools/deps-exe/s6-tlsclient @@ -0,0 +1 @@ +-lskarnet diff --git a/src/conn-tools/deps-exe/s6-tlsd b/src/conn-tools/deps-exe/s6-tlsd new file mode 100644 index 0000000..d00d2b8 --- /dev/null +++ b/src/conn-tools/deps-exe/s6-tlsd @@ -0,0 +1,5 @@ +${LIBCRYPTOSUPPORT} +-lskarnet +${CRYPTO_LIB} +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/conn-tools/deps-exe/s6-tlsserver b/src/conn-tools/deps-exe/s6-tlsserver new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/conn-tools/deps-exe/s6-tlsserver @@ -0,0 +1 @@ +-lskarnet diff --git a/src/conn-tools/s6-tlsc.c b/src/conn-tools/s6-tlsc.c new file mode 100644 index 0000000..e2b6f7f --- /dev/null +++ b/src/conn-tools/s6-tlsc.c @@ -0,0 +1,102 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <skalibs/uint64.h> +#include <skalibs/uint.h> +#include <skalibs/gidstuff.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/env.h> +#include <skalibs/djbunix.h> +#include <s6-networking/config.h> + +#ifdef S6_NETWORKING_USE_TLS + +#include <s6-networking/stls.h> +#define s6tlsc stls_s6tlsc + +#else +#ifdef S6_NETWORKING_USE_BEARSSL + +#include <s6-networking/sbearssl.h> +#define s6tlsc sbearssl_s6tlsc + +#else + +#error No SSL backend configured. + +#endif +#endif + + +#define USAGE "s6-tlsc [ -S | -s ] [ -Y | -y ] [ -v verbosity ] [ -K timeout ] [ -6 rfd ] [ -7 wfd ] prog..." +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv, char const *const *envp) +{ + tain_t tto ; + unsigned int verbosity = 1 ; + uid_t uid = 0 ; + gid_t gid = 0 ; + uint32_t preoptions = 0 ; + uint32_t options = 1 ; + int fds[2] = { 6, 7 } ; + + PROG = "s6-tlsc" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "SsYyv:K:6:7:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'S' : options &= ~(uint32_t)1 ; break ; + case 's' : options |= 1 ; break ; + case 'Y' : preoptions &= ~(uint32_t)1 ; break ; + case 'y' : preoptions |= 1 ; break ; + case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; + case 'K' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case '6' : + { + unsigned int fd ; + if (!uint0_scan(l.arg, &fd)) dieusage() ; + fds[0] = fd ; + break ; + } + case '7' : + { + unsigned int fd ; + if (!uint0_scan(l.arg, &fd)) dieusage() ; + fds[1] = fd ; + break ; + } + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&tto, t) ; else tto = tain_infinite_relative ; + } + if (!argc) dieusage() ; + + if (!getuid()) + { + x = env_get2(envp, "TLS_UID") ; + if (x) + { + uint64 u ; + if (!uint640_scan(x, &u)) strerr_dieinvalid(100, "TLS_UID") ; + uid = (uid_t)u ; + } + x = env_get2(envp, "TLS_GID") ; + if (x) + { + if (!gid0_scan(x, &gid)) strerr_dieinvalid(100, "TLS_GID") ; + } + } + + return s6tlsc(argv, envp, &tto, preoptions, options, uid, gid, verbosity) ; +} diff --git a/src/conn-tools/s6-tlsclient.c b/src/conn-tools/s6-tlsclient.c new file mode 100644 index 0000000..6d2249a --- /dev/null +++ b/src/conn-tools/s6-tlsclient.c @@ -0,0 +1,181 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> +#include <skalibs/ip46.h> +#include <s6-networking/config.h> + +#define USAGE "s6-tlsclient [ options ] ip port prog...\n" \ +"s6-tcpclient options: [ -q | -Q | -v ] [ -4 | -6 ] [ -d | -D ] [ -r | -R ] [ -h | -H ] [ -n | -N ] [ -t timeout ] [ -l localname ] [ -T timeoutconn ] [ -i localip ] [ -p localport ]\n" \ +"s6-tlsc options: [ -S | -s ] [ -Y | -y ] [ -K timeout ]" + +#define dieusage() strerr_dieusage(100, USAGE) + +typedef struct options_s options_t, *options_t_ref ; +struct options_s +{ + char const *localname ; + unsigned int timeout ; + unsigned int ximeout ; + unsigned int yimeout ; + unsigned int kimeout ; + uint16 localport ; + ip46full_t localip ; + unsigned int verbosity : 2 ; + unsigned int flag4 : 1 ; + unsigned int flag6 : 1 ; + unsigned int flagD : 1 ; + unsigned int flagH : 1 ; + unsigned int flagr : 1 ; + unsigned int flagN : 1 ; + unsigned int flagS : 1 ; + unsigned int flagy : 1 ; + unsigned int doxy : 1 ; +} ; + +#define OPTIONS_ZERO \ +{ \ + .localname = 0, \ + .timeout = 0, \ + .ximeout = 2, \ + .yimeout = 58, \ + .kimeout = 0, \ + .localport = 0, \ + .localip = IP46FULL_ZERO, \ + .verbosity = 1, \ + .flag4 = 0, \ + .flag6 = 0, \ + .flagD = 0, \ + .flagH = 0, \ + .flagr = 0, \ + .flagN = 0, \ + .flagS = 0, \ + .flagy = 0, \ + .doxy = 0 \ +} + +int main (int argc, char const *const *argv, char const *const *envp) +{ + options_t o = OPTIONS_ZERO ; + PROG = "s6-tlsclient" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "qQv46DdHhRrnNt:l:T:i:p:SsYyK:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : o.verbosity = 0 ; break ; + case 'Q' : o.verbosity = 1 ; break ; + case 'v' : o.verbosity = 2 ; break ; + case '4' : o.flag4 = 1 ; break ; + case '6' : o.flag6 = 1 ; break ; + case 'D' : o.flagD = 1 ; break ; + case 'd' : o.flagD = 0 ; break ; + case 'H' : o.flagH = 1 ; break ; + case 'h' : o.flagh = 0 ; break ; + case 'R' : o.flagr = 0 ; break ; + case 'r' : o.flagr = 1 ; break ; + case 'n' : o.flagN = 0 ; break ; + case 'N' : o.flagN = 1 ; break ; + case 't' : if (!uint0_scan(l.arg, &o.timeout)) dieusage() ; break ; + case 'l' : o.localname = l.arg ; break ; + case 'T' : + { + unsigned int n = uint_scan(l.arg, &o.ximeout) ; + if (!n) dieusage() ; + o.doxy = 1 ; + if (!l.arg[n]) + { + o.yimeout = 0 ; + break ; + } + if (l.arg[n] != '+') dieusage() ; + if (!uint0_scan(l.arg + n + 1, &o.yimeout)) dieusage() ; + break ; + } + case 'i' : if (!ip46full_scan(l.arg, &o.localip)) dieusage() ; break ; + case 'p' : if (!uint160_scan(l.arg, &o.localport)) dieusage() ; break ; + case 'S' : o.flagS = 1 ; break ; + case 's' : o.flagS = 0 ; break ; + case 'Y' : o.flagy = 0 ; break ; + case 'y' : o.flagy = 1 ; break ; + case 'K' : if (!uint0_scan(l.arg, &o.kimeout)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (argc < 3) dieusage() ; + } + + { + unsigned int m = 0 ; + unsigned int pos = 0 ; + char fmt[UINT_FMT * 4 + UINT16_FMT + IP46_FMT] ; + char const *newargv[26 + argc] ; + newargv[m++] = S6_NETWORKING_BINPREFIX "s6-tcpclient" ; + if (o.verbosity != 1) newargv[m++] = o.verbosity ? "-v" ; "-q" ; + if (o.flag4) newargv[m++] = "-4" ; + if (o.flag6) newargv[m++] = "-6" ; + if (o.flagD) newargv[m++] = "-D" ; + if (o.flagH) newargv[m++] = "-H" ; + if (o.flagr) newargv[m++] = "-r" ; + if (o.flagN) newargv[m++] = "-N" ; + if (o.timeout) + { + newargv[m++] = "-t" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, o.timeout) ; + fmt[pos++] = 0 ; + } + if (o.localname) + { + newargv[m++] = "-l" ; + newargv[m++] = o.localname ; + } + if (o.doxy) + { + newargv[m++] = "-T" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, o.ximeout) ; + fmt[pos++] = '+' ; + pos += uint_fmt(fmt + pos, o.yimeout) ; + fmt[pos++] = 0 ; + } + if (byte_diff(o.localip.ip, 16, IP6_ANY)) + { + newargv[m++] = "-i" ; + newargv[m++] = fmt + pos ; + pos += ip46full_fmt(fmt + pos, &o.localip) ; + fmt[pos++] = 0 ; + } + if (o.localport) + { + newargv[m++] = "-p" ; + newargv[m++] = fmt + pos ; + pos += uint16_fmt(fmt + pos, o.localport) ; + fmt[pos++] = 0 ; + } + newargv[m++] = "--" ; + newargv[m++] = S6_NETWORKING_BINPREFIX "s6-tlsc" ; + if (o.flagS) newargv[m++] = "-S" ; + if (o.flagy) newargv[m++] = "-y" ; + if (o.kimeout) + { + newargv[m++] = "-K" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, o.kimeout) ; + fmt[pos++] = 0 ; + } + newargv[m++] = "--" ; + while (*argv) newargv[m++] = *argv++ ; + newargv[m++] = 0 ; + pathexec_run(newargv[0], newargv, envp) ; + strerr_dieexec(111, newargv[0]) ; + } +} diff --git a/src/conn-tools/s6-tlsd.c b/src/conn-tools/s6-tlsd.c new file mode 100644 index 0000000..73758a2 --- /dev/null +++ b/src/conn-tools/s6-tlsd.c @@ -0,0 +1,86 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <skalibs/uint64.h> +#include <skalibs/uint.h> +#include <skalibs/gidstuff.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/env.h> +#include <skalibs/djbunix.h> +#include <s6-networking/config.h> + +#ifdef S6_NETWORKING_USE_TLS + +#include <s6-networking/stls.h> +#define s6tlsd stls_s6tlsd + +#else +#ifdef S6_NETWORKING_USE_BEARSSL + +#include <s6-networking/sbearssl.h> +#define s6tlsd sbearssl_s6tlsd + +#else + +#error No SSL backend configured. + +#endif +#endif + + +#define USAGE "s6-tlsd [ -S | -s ] [ -Y | -y ] [ -v verbosity ] [ -K timeout ] prog..." +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv, char const *const *envp) +{ + tain_t tto ; + unsigned int verbosity = 1 ; + uid_t uid = 0 ; + gid_t gid = 0 ; + uint32_t preoptions = 0 ; + uint32_t options = 1 ; + + PROG = "s6-tlsd" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "SsYyv:K:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'S' : options &= ~(uint32_t)1 ; break ; + case 's' : options |= 1 ; break ; + case 'Y' : preoptions &= ~(uint32_t)1 ; break ; + case 'y' : preoptions |= 1 ; break ; + case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; + case 'K' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&tto, t) ; else tto = tain_infinite_relative ; + } + if (!argc) dieusage() ; + + if (!getuid()) + { + x = env_get2(envp, "TLS_UID") ; + if (x) + { + uint64 u ; + if (!uint640_scan(x, &u)) strerr_dieinvalid(100, "TLS_UID") ; + uid = (uid_t)u ; + } + x = env_get2(envp, "TLS_GID") ; + if (x) + { + if (!gid0_scan(x, &gid)) strerr_dieinvalid(100, "TLS_GID") ; + } + } + + return s6tlsd(argv, envp, &tto, preoptions, options, uid, gid, verbosity) ; +} diff --git a/src/conn-tools/s6-tlsserver.c b/src/conn-tools/s6-tlsserver.c new file mode 100644 index 0000000..0154e24 --- /dev/null +++ b/src/conn-tools/s6-tlsserver.c @@ -0,0 +1,241 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <limits.h> +#include <skalibs/uint64.h> +#include <skalibs/uint.h> +#include <skalibs/gidstuff.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> +#include <s6-networking/config.h> + +#define USAGE "s6-tlsserver [ options ] ip port prog...\n" \ +"s6-tcpserver options: [ -q | -Q | -v ] [ -4 | -6 ] [ -1 ] [ -c maxconn ] [ -C localmaxconn ] [ -b backlog ] [ -G gidlist ] [ -g gid ] [ -u uid ] [ -U ]\n" \ +"s6-tcpserver-access options: [ -W | -w ] [ -D | -d ] [ -H | -h ] [ -R | -r ] [ -P | -p ] [ -l localname ] [ -B banner ] [ -t timeout ] [ -i rulesdir | -x rulesfile ]\n" \ +"s6-tlsd options: [ -S | -s ] [ -Y | -y ] [ -K timeout ]" + +#define dieusage() strerr_dieusage(100, USAGE) + +typedef struct options_s options_t, *options_t_ref ; +struct options_s +{ + uint64 uid ; + char const *localname ; + char const *banner ; + char const *rules ; + gid_t gids[NGROUPS_MAX] ; + gid_t gid ; + unsigned int maxconn ; + unsigned int localmaxconn ; + unsigned int backlog ; + unsigned int gidn ; + unsigned int timeout ; + unsigned int kimeout ; + unsigned int verbosity : 2 ; + unsigned int flag46 : 2 ; + unsigned int flag1 : 1 ; + unsigned int flagU : 1 ; + unsigned int flagw : 1 ; + unsigned int flagD : 1 ; + unsigned int flagH : 1 ; + unsigned int flagr : 1 ; + unsigned int flagp : 1 ; + unsigned int ruleswhat : 2 ; + unsigned int flagS : 1 ; + unsigned int flagy : 1 ; + unsigned int doaccess : 1 ; +} ; + +#define OPTIONS_ZERO \ +{ \ + .uid = 0, \ + .localname = 0, \ + .banner = 0, \ + .rules = 0, \ + .maxconn = 0, \ + .localmaxconn = 0, \ + .backlog = (unsigned int)-1, \ + .gidn = (unsigned int)-1, \ + .gid = 0, \ + .timeout = 0, \ + .kimeout = 0, \ + .verbosity = 1, \ + .flag46 = 0, \ + .flag1 = 0, \ + .flagU = 0, \ + .flagw = 0, \ + .flagD = 0, \ + .flagH = 0, \ + .flagr = 0, \ + .flagp = 0, \ + .ruleswhat = 0, \ + .flagS = 0, \ + .flagy = 0, \ + .doaccess = 0 \ +} + +int main (int argc, char const *const *argv, char const *const *envp) +{ + options_t o = OPTIONS_ZERO ; + PROG = "s6-tlsserver" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "qQv461c:C:b:G:g:u:UWwDdHhRrPpl:B:t:i:x:SsYyK:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : o.verbosity = 0 ; break ; + case 'Q' : o.verbosity = 1 ; break ; + case 'v' : o.verbosity = 2 ; break ; + case '4' : o.flag46 = 1 ; break ; + case '6' : o.flag46 = 2 ; break ; + case '1' : o.flag1 = 1 ; break ; + case 'c' : if (!uint0_scan(l.arg, &o.maxconn)) dieusage() ; if (!o.maxconn) o.maxconn = 1 ; break ; + case 'C' : if (!uint0_scan(l.arg, &o.localmaxconn)) dieusage() ; if (!o.localmaxconn) o.localmaxconn = 1 ; break ; + case 'b' : if (!uint0_scan(l.arg, &o.backlog)) dieusage() ; break ; + case 'G' : if (!gid_scanlist(o.gids, NGROUPS_MAX, l.arg, &o.gidn) && *l.arg) dieusage() ; break ; + case 'g' : if (!uint0_scan(l.arg, &o.gid)) dieusage() ; break ; + case 'u' : if (!uint0_scan(l.arg, &o.uid)) dieusage() ; break ; + case 'U' : o.flagU = 1 ; o.uid = 0 ; o.gid = 0 ; o.gidn = (unsigned int)-1 ; break ; + case 'W' : o.flagw = 0 ; break ; + case 'w' : o.flagw = 1 ; break ; + case 'D' : o.flagD = 1 ; o.doaccess = 1 ; break ; + case 'd' : o.flagD = 0 ; break ; + case 'H' : o.flagH = 1 ; o.doaccess = 1 ; break ; + case 'h' : o.flagh = 0 ; break ; + case 'R' : o.flagr = 0 ; break ; + case 'r' : o.flagr = 1 ; o.doaccess = 1 ; break ; + case 'P' : o.flagp = 0 ; break ; + case 'p' : o.flagp = 1 ; o.doaccess = 1 ; break ; + case 'l' : o.localname = l.arg ; o.doaccess = 1 ; break ; + case 'B' : o.banner = l.arg ; o.doaccess = 1 ; break ; + case 't' : if (!uint0_scan(l.arg, &o.timeout)) dieusage() ; break ; + case 'i' : o.rules = l.arg ; o.ruleswhat = 1 ; o.doaccess = 1 ; break ; + case 'x' : o.rules = l.arg ; o.ruleswhat = 2 ; o.doaccess = 1 ; break ; + case 'S' : o.flagS = 1 ; break ; + case 's' : o.flagS = 0 ; break ; + case 'Y' : o.flagy = 0 ; break ; + case 'y' : o.flagy = 1 ; break ; + case 'K' : if (!uint0_scan(l.arg, &o.kimeout)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (argc < 3) dieusage() ; + } + + { + unsigned int m = 0 ; + unsigned int pos = 0 ; + char fmt[UINT_FMT * 5 + GID_FMT * (NGROUPS_MAX + 1) + UINT64_FMT] ; + char const *newargv[44 + argc] ; + newargv[m++] = S6_NETWORKING_BINPREFIX "s6-tcpserver" ; + if (o.verbosity != 1) newargv[m++] = o.verbosity ? "-v" ; "-q" ; + if (o.flag46) newargv[m++] = o.flag46 == 1 ? "-4" : "-6" ; + if (o.flag1) newargv[m++] = "-1" ; + if (o.maxconn) + { + newargv[m++] = "-c" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, maxconn) ; + fmt[pos++] = 0 ; + } + if (o.localmaxconn) + { + newargv[m++] = "-C" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, o.localmaxconn) ; + fmt[pos++] = 0 ; + } + if (backlog != (unsigned int)-1) + { + newargv[m++] = "-b" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, backlog) ; + fmt[pos++] = 0 ; + } + if (o.gidn != (unsigned int)-1) + { + newargv[m++] = "-G" ; + newargv[m++] = fmt + pos ; + pos += gid_fmtlist(fmt + pos, o.gids, o.gidn) ; + fmt[pos++] = 0 ; + } + if (o.gid) + { + newargv[m++] = "-g" ; + newargv[m++] = fmt + pos ; + pos += gid_fmt(fmt + pos, o.gid) ; + fmt[pos++] = 0 ; + } + if (o.uid) + { + newargv[m++] = "-u" ; + newargv[m++] = fmt + pos ; + pos += uint64_fmt(fmt + pos, o.uid) ; + fmt[pos++] = 0 ; + } + if (o.flagU) newargv[m++] = "-U" ; + newargv[m++] = "--" ; + if (o.doaccess) + { + newargv[m++] = S6_NETWORKING_BINPREFIX "s6-tcpserver-access" ; + if (o.verbosity != 1) + { + newargv[m++] = "-v" ; + newargv[m++] = o.verbosity ? "2" : "0" ; + } + if (o.flagw) newargv[m++] = "-w" ; + if (o.flagD) newargv[m++] = "-D" ; + if (o.flagH) newargv[m++] = "-H" ; + if (o.flagr) newargv[m++] = "-r" ; + if (o.flagp) newargv[m++] = "-p" ; + if (o.localname) + { + newargv[m++] = "-l" ; + newargv[m++] = o.localname ; + } + if (o.banner) + { + newargv[m++] = "-B" ; + newargv[m++] = o.banner ; + } + if (o.timeout) + { + newargv[m++] = "-t" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, o.timeout) ; + fmt[pos++] = 0 ; + } + if (o.ruleswhat) + { + newargv[m++] = o.ruleswhat == 1 ? "-i" : "-x" ; + newargv[m++] = o.rules ; + } + newargv[m++] = "--" ; + } + newargv[m++] = S6_NETWORKING_BINPREFIX "s6-tlsd" ; + if (o.verbosity != 1) + { + newargv[m++] = "-v" ; + newargv[m++] = o.verbosity ? "2" : "0" ; + } + if (o.flagS) newargv[m++] = "-S" ; + if (o.flagy) newargv[m++] = "-y" ; + if (o.kimeout) + { + newargv[m++] = "-K" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, o.kimeout) ; + fmt[pos++] = 0 ; + } + newargv[m++] = "--" ; + while (*argv) newargv[m++] = *argv++ ; + newargv[m++] = 0 ; + pathexec_run(newargv[0], newargv, envp) ; + strerr_dieexec(111, newargv[0]) ; + } +} diff --git a/src/include/s6-networking/sbearssl.h b/src/include/s6-networking/sbearssl.h new file mode 100644 index 0000000..a41ebd2 --- /dev/null +++ b/src/include/s6-networking/sbearssl.h @@ -0,0 +1,202 @@ +/* ISC license. */ + +#ifndef SBEARSSL_H +#define SBEARSSL_H + +#include <sys/types.h> +#include <bearssl.h> +#include <skalibs/buffer.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/tai.h> + + /* + * Support library for bearssl. + * Provides types for relocatable objects (instead of pointers, + * indices, with storage in a stralloc), conversion functions + * from/to native bearssl types, and a higher-level API to + * read secret keys / certificate chains / trust anchors from + * the filesystem. + */ + + + /* Utility functions */ + +extern int sbearssl_isder (unsigned char const *, size_t) ; + + + /* Private keys */ + +typedef struct sbearssl_rsa_skey_s sbearssl_rsa_skey, *sbearssl_rsa_skey_ref ; +struct sbearssl_rsa_skey_s +{ + uint32_t n_bitlen ; + size_t p ; + size_t plen ; + size_t q ; + size_t qlen ; + size_t dp ; + size_t dplen ; + size_t dq ; + size_t dqlen ; + size_t iq ; + size_t iqlen ; +} ; + +extern int sbearssl_rsa_skey_from (sbearssl_rsa_skey *, br_rsa_private_key const *, stralloc *) ; +extern void sbearssl_rsa_privkey_to (sbearssl_rsa_skey const *, br_rsa_private_key *, char const *, size_t) ; + + +typedef struct sbearssl_ec_skey_s sbearssl_ec_skey, *sbearssl_ec_skey_ref ; +struct sbearssl_ec_skey_s +{ + int curve ; + size_t x ; + size_t xlen ; +} ; + +extern int sbearssl_ec_skey_from (sbearssl_ec_skey *, br_ec_private_key const *, stralloc *) ; +extern void sbearssl_ec_skey_to (sbearssl_ec_skey const *, br_ec_private_key *, char const *, size_t) ; + + +union sbearssl_skey_data_u +{ + sbearssl_rsa_skey rsa ; + sbearssl_ec_skey ec ; +} ; + +typedef struct sbearssl_skey_s sbearssl_skey, *sbearssl_skey_ref ; +struct sbearssl_skey_s +{ + unsigned int type ; + union sbearssl_skey_u data ; +} ; + +union br_skey_u +{ + br_rsa_private_key rsa ; + br_ec_private_key ec ; +} ; + +typedef struct br_skey_s br_skey, *br_skey_ref ; +struct br_skey_s +{ + unsigned char type ; + union br_skey_u data ; +} ; + +extern int sbearssl_skey_from (sbearssl_skey *, br_skey const *, stralloc *) ; +extern int sbearssl_skey_to (sbearssl_skey const *, br_skey *, char const *) ; + +extern int sbearssl_skey_readfile (char const *, sbearssl_skey *, stralloc *) ; + + + /* Public keys */ + +typedef struct sbearssl_rsa_pkey_s sbearssl_rsa_pkey, *sbearssl_rsa_pkey_ref ; +struct sbearssl_rsa_pkey_s +{ + size_t n ; + size_t nlen ; + size_t e ; + size_t elen ; +} ; + +extern int sbearssl_rsa_pkey_from (sbearssl_rsa_pkey *, br_rsa_public_key const *, stralloc *) ; +extern void sbearssl_rsa_pkey_to (sbearssl_rsa_pkey const *, br_rsa_public_key *, char const *) ; + + +typedef struct sbearssl_ec_pkey_s sbearssl_ec_pkey, *sbearssl_ec_pkey_ref ; +struct sbearssl_ec_pkey_s +{ + int curve ; + size_t q ; + size_t qlen ; +} ; + +extern int sbearssl_ec_pkey_from (sbearssl_ec_pkey *, br_ec_public_key const *, stralloc *) ; +extern void sbearssl_ec_pkey_to (sbearssl_ec_pkey const *, br_ec_public_key *, char const *) ; + + +union sbearssl_pkey_data_u +{ +' sbearssl_rsa_pkey rsa ; + sbearssl_ec_pkey ec ; +} ; + +typedef struct sbearssl_pkey_s sbearssl_pkey, *sbearssl_pkey_ref ; +struct sbearssl_pkey_s +{ + unsigned char type ; + union sbearssl_pkey_u data ; +} ; + +extern int sbearssl_pkey_from (sbearssl_pkey *, br_x509_pkey const *, stralloc *) ; +extern int sbearssl_pkey_to (sbearssl_pkey const *, br_x509_pkey *, char const *) ; + + + /* Certificates (x509-encoded) */ + +typedef struct sbearssl_cert_s sbearssl_cert, *sbearssl_cert_ref ; +struct sbearssl_cert_s +{ + size_t data ; + size_t datalen ; +} ; + +extern int sbearssl_cert_from (sbearssl_cert *, br_x509_certificate const *, stralloc *) ; +extern void sbearssl_cert_to (sbearssl_cert const *, br_x509_certificate *, char const *) ; + +extern int sbearssl_cert_readfile (char const *, genalloc *, stralloc *) ; + + + /* Generic PEM */ + +typedef struct sbearssl_pemobject_s sbearssl_pemobject, *sbearssl_pemobject_ref ; +struct sbearssl_s +{ + size_t name ; + size_t data ; + size_t datalen ; +} ; + +extern int sbearssl_pem_decode_from_string (char const *, size_t, genalloc *, stralloc *) ; +extern int sbearssl_pem_decode_from_buffer (buffer *, genalloc *, stralloc *) ; + + + /* Trust anchors */ + +typedef struct sbearssl_ta_s sbearssl_ta, *sbearssl_ta_ref ; +struct sbearssl_ta_s +{ + size_t dn ; + size_t dnlen ; + unsigned int flags ; + sbearssl_pkey pkey ; +} ; + +extern int sbearssl_ta_from (sbearssl_ta *, br_x509_trust_anchor const *, stralloc *) ; +extern void sbearssl_ta_to (sbearssl_ta const *, br_x509_trust_anchor *, char const *) ; + +extern int sbearssl_ta_cert (sbearssl_ta *, sbearssl_cert const *, char const *, stralloc *) ; + +extern int sbearssl_ta_readfile (char const *, genalloc *, stralloc *) ; +extern int sbearssl_ta_readdir (char const *, genalloc *, stralloc *) ; + + + /* Errors */ + +extern char const *sbearssl_error_str (int) ; + + + /* Engine */ + +extern int sbearssl_run (br_ssl_engine_context *, int *, unsigned int, uint32, tain_t const *) ; + + + /* s6-tlsc and s6-tlsd implementations */ + +extern int sbearssl_s6tlsc (char const *const *, char const *const *, tain_t const *, uint32_t, uint32_t, uid_t, gid_t, unsigned int, int *) ; +extern int sbearssl_s6tlsd (char const *const *, char const *const *, tain_t const *, uint32_t, uint32_t, uid_t, gid_t, unsigned int) ; + +#endif diff --git a/src/include/s6-networking/stls.h b/src/include/s6-networking/stls.h new file mode 100644 index 0000000..80c3df2 --- /dev/null +++ b/src/include/s6-networking/stls.h @@ -0,0 +1,23 @@ +/* ISC license. */ + +#ifndef STLS_INTERNAL_H +#define STLS_INTERNAL_H + +#include <sys/types.h> +#include <tls.h> +#include <skalibs/tai.h> + +#define STLS_BUFSIZE (16384 + 325 + 1) + + + /* Engine */ + +extern int stls_run (struct tls *, int *, unsigned int, uint32_t, tain_t const *) ; + + + /* s6-tlsc and s6-tlsd implementations */ + +extern int stls_s6tlsc (char const *const *, char const *const *, tain_t const *, uint32_t, uint32_t, uid_t, gid_t, unsigned int, int *) ; +extern int stls_s6tlsd (char const *const *, char const *const *, tain_t const *, uint32_t, uint32_t, uid_t, gid_t, unsigned int) ; + +#endif diff --git a/src/sbearssl/deps-lib/sbearssl b/src/sbearssl/deps-lib/sbearssl new file mode 100644 index 0000000..bace1a7 --- /dev/null +++ b/src/sbearssl/deps-lib/sbearssl @@ -0,0 +1,33 @@ +sbearssl_append.o +sbearssl_cert_from.o +sbearssl_cert_readfile.o +sbearssl_cert_to.o +sbearssl_ec_pkey_from.o +sbearssl_ec_pkey_to.o +sbearssl_ec_skey_from.o +sbearssl_ec_skey_to.o +sbearssl_error_str.o +sbearssl_isder.o +sbearssl_pem_decode_from_buffer.o +sbearssl_pem_decode_from_string.o +sbearssl_pem_push.o +sbearssl_pkey_from.o +sbearssl_pkey_to.o +sbearssl_rsa_pkey_from.o +sbearssl_rsa_pkey_to.o +sbearssl_rsa_skey_from.o +sbearssl_rsa_skey_to.o +sbearssl_run.o +sbearssl_skey_from.o +sbearssl_skey_readfile.o +sbearssl_skey_to.o +sbearssl_ta_cert.o +sbearssl_ta_from.o +sbearssl_ta_readdir.o +sbearssl_ta_readfile.o +sbearssl_ta_readfile_internal.o +sbearssl_ta_to.o +sbearssl_s6tlsc.o +sbearssl_s6tlsd.o +-lbearssl +-lskarnet diff --git a/src/sbearssl/sbearssl-internal.h b/src/sbearssl/sbearssl-internal.h new file mode 100644 index 0000000..bffcb16 --- /dev/null +++ b/src/sbearssl/sbearssl-internal.h @@ -0,0 +1,23 @@ +/* ISC license. */ + +#ifndef SBEARSSL_INTERNAL_H +#define SBEARSSL_INTERNAL_H + +#include <sys/types.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> + +typedef struct sbearssl_strallocerr_s sbearssl_strallocerr, *sbearssl_strallocerr_ref ; +struct sbearssl_strallocerr_s +{ + stralloc *sa ; + int err ; +} ; + +extern void sbearssl_append (void *, void const *, size_t) ; +extern int sbearssl_pem_push (br_pem_decoder_context *, char const *, size_t, sbearssl_pemobject *, genalloc *, sbearssl_strallocerr *, int *) ; + +extern int sbearssl_ta_readfile_internal (char const *, genalloc *, stralloc *, genalloc *, stralloc *) ; + +#endif diff --git a/src/sbearssl/sbearssl_append.c b/src/sbearssl/sbearssl_append.c new file mode 100644 index 0000000..d0a6d64 --- /dev/null +++ b/src/sbearssl/sbearssl_append.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <skalibs/stralloc.h> +#include "sbearssl-internal.h> + +void sbearssl_append (void *stuff, void const *src, size_t len) +{ + sbearssl_strallocerr *blah = stuff ; + blah->err = stralloc_catb(blah->sa, (char const *)src, len) ? 0 : errno ; +} diff --git a/src/sbearssl/sbearssl_cert_from.c b/src/sbearssl/sbearssl_cert_from.c new file mode 100644 index 0000000..b57dca6 --- /dev/null +++ b/src/sbearssl/sbearssl_cert_from.c @@ -0,0 +1,13 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_cert_from (sbearssl_cert *sc, br_x509_certificate const *bc, stralloc *sa) +{ + if (!stralloc_catb(sa, bc->data, bc->data_len)) return 0 ; + sc->data = sa->len - bc->data_len ; + sc->datalen = bc->data_len ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_cert_readfile.c b/src/sbearssl/sbearssl_cert_readfile.c new file mode 100644 index 0000000..6090624 --- /dev/null +++ b/src/sbearssl/sbearssl_cert_readfile.c @@ -0,0 +1,52 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/bytestr.h> +#include <skalibs/buffer.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/djbunix.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_cert_readfile (char const *fn, genalloc *certs, stralloc *sa) ; +{ + char buf[BUFFER_INSIZE] ; + int fd = open_readb(fn) ; + buffer b = BUFFER_INIT(&buffer_read, fd, buf, BUFFER_INSIZE) ; + genalloc pems = GENALLOC_ZERO ; + sbearssl_pemobject *p ; + size_t certsbase = genalloc_len(sbearssl_cert, certs) ; + size_t n ; + size_t i = 0 ; + int certswasnull = !genalloc_s(sbearssl_cert, certs) ; + int r ; + if (fd < 0) return -1 ; + r = sbearssl_pem_decode_from_buffer(buf, n, &pems, sa) ; + if (r) { fd_close(fd) ; return r ; } + fd_close(fd) ; + p = genalloc_s(sbearssl_pemobject, &pems) ; + n = genalloc_len(sbearssl_pemobject, &pems) ; + for (; i < n ; i++) + { + char const *name = sa->s + p[i].name ; + if (!str_diff(name, "CERTIFICATE") + || !str_diff(name, "X509 CERTIFICATE")) + { + sbearssl_cert sc = { .data = p[i].data, .datalen = p[i].datalen } ; + if (!genalloc_append(sbearssl_cert, certs, &sc)) goto fail ; + } + } + + genalloc_free(sbearssl_pemobject, &pems) ; + fd_close(fd) ; + return 0 ; + + fail: + if (certswasnull) genalloc_free(sbearssl_cert, certs) ; + else genalloc_setlen(sbearssl_cert, certs, certsbase) ; + stralloc_free(&sa) ; + genalloc_free(sbearssl_pemobject, pems) ; + return r ; +} diff --git a/src/sbearssl/sbearssl_cert_to.c b/src/sbearssl/sbearssl_cert_to.c new file mode 100644 index 0000000..ee0eeeb --- /dev/null +++ b/src/sbearssl/sbearssl_cert_to.c @@ -0,0 +1,10 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +void sbearssl_cert_to (sbearssl_cert const *sc, br_x509_certificate *bc, char const *s) +{ + bc->data = s + sc->data ; + bc->data_len = sc->datalen ; +} diff --git a/src/sbearssl/sbearssl_ec_pkey_from.c b/src/sbearssl/sbearssl_ec_pkey_from.c new file mode 100644 index 0000000..55c5651 --- /dev/null +++ b/src/sbearssl/sbearssl_ec_pkey_from.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_ec_pkey_from (sbearssl_ec_pkey *l, br_ec_public_key const *k, stralloc *sa) +{ + if (!stralloc_catb(sa, k->q, k->qlen)) return 0 ; + l->curve = k->curve ; + l->q = sa->len - k->qlen ; + l->qlen = k->qlen ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_ec_pkey_to.c b/src/sbearssl/sbearssl_ec_pkey_to.c new file mode 100644 index 0000000..4cc1e65 --- /dev/null +++ b/src/sbearssl/sbearssl_ec_pkey_to.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +void sbearssl_ec_pkey_to (sbearssl_ec_pkey const *l, br_ec_public_key *k, char const *s) +{ + k->curve = l->curve ; + k->q = s + l->q ; + k->qlen = l->qlen ; +} diff --git a/src/sbearssl/sbearssl_ec_skey_from.c b/src/sbearssl/sbearssl_ec_skey_from.c new file mode 100644 index 0000000..79c326f --- /dev/null +++ b/src/sbearssl/sbearssl_ec_skey_from.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_ec_skey_from (sbearssl_ec_skey *l, br_ec_private_key const *k, stralloc *sa) +{ + if (!stralloc_catb(sa, k->x, k->xlen)) return 0 ; + l->curve = k->curve ; + l->x = sa->len - k->xlen ; + l->xlen = k->xlen ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_ec_skey_to.c b/src/sbearssl/sbearssl_ec_skey_to.c new file mode 100644 index 0000000..54b059c --- /dev/null +++ b/src/sbearssl/sbearssl_ec_skey_to.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +void sbearssl_ec_skey_to (sbearssl_ec_skey const *l, br_ec_private_key *k, char const *s) +{ + k->curve = l->curve ; + k->x = s + l->x ; + k->xlen = l->xlen ; +} diff --git a/src/sbearssl/sbearssl_error_str.c b/src/sbearssl/sbearssl_error_str.c new file mode 100644 index 0000000..7e1e22c --- /dev/null +++ b/src/sbearssl/sbearssl_error_str.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Modified by Laurent Bercot <ska-skaware@skarnet.org> + * for inclusion in the sbearssl support library. + */ + + +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +struct error_s +{ + int err ; + const char *comment ; +} ; + +static struct error_s errors[] = +{ + { + BR_ERR_OK, + "No error." + " (BR_ERR_OK)" + }, + { + BR_ERR_BAD_PARAM, + "Caller-provided parameter is incorrect." + " (BR_ERR_BAD_PARAM)" + }, + { + BR_ERR_BAD_STATE, + "Operation requested by the caller cannot be applied with" + " the current context state (e.g. reading data while" + " outgoing data is waiting to be sent)." + " (BR_BAD_STATE)" + }, + { + BR_ERR_UNSUPPORTED_VERSION, + "Incoming protocol or record version is unsupported." + " (BR_ERR_UNSUPPORTED_VERSION)" + }, + { + BR_ERR_BAD_VERSION, + "Incoming record version does not match the expected version." + " (BR_ERR_BAD_VERSION)" + }, + { + BR_ERR_BAD_LENGTH, + "Incoming record length is invalid." + " (BR_ERR_BAD_LENGTH)" + }, + { + BR_ERR_TOO_LARGE, + "Incoming record is too large to be processed, or buffer" + " is too small for the handshake message to send." + " (BR_ERR_TOO_LARGE)" + }, + { + BR_ERR_BAD_MAC, + "Decryption found an invalid padding, or the record MAC is" + " not correct." + " (BR_ERR_BAD_MAC)" + }, + { + BR_ERR_NO_RANDOM, + "No initial entropy was provided, and none can be obtained" + " from the OS." + " (BR_ERR_NO_RANDOM)" + }, + { + BR_ERR_UNKNOWN_TYPE, + "Incoming record type is unknown." + " (BR_ERR_UNKNOWN_TYPE)" + }, + { + BR_ERR_UNEXPECTED, + "Incoming record or message has wrong type with regards to" + " the current engine state." + " (BR_ERR_UNEXPECTED)" + }, + { + BR_ERR_BAD_CCS, + "ChangeCipherSpec message from the peer has invalid contents." + " (BR_ERR_BAD_CCS)" + }, + { + BR_ERR_BAD_ALERT, + "Alert message from the peer has invalid contents" + " (odd length)." + " (BR_ERR_BAD_ALERT)" + }, + { + BR_ERR_BAD_HANDSHAKE, + "Incoming handshake message decoding failed." + " (BR_ERR_BAD_HANDSHAKE)" + }, + { + BR_ERR_OVERSIZED_ID, + "ServerHello contains a session ID which is larger than" + " 32 bytes." + " (BR_ERR_OVERSIZED_ID)" + }, + { + BR_ERR_BAD_CIPHER_SUITE, + "Server wants to use a cipher suite that we did not claim" + " to support. This is also reported if we tried to advertise" + " a cipher suite that we do not support." + " (BR_ERR_BAD_CIPHER_SUITE)" + }, + { + BR_ERR_BAD_COMPRESSION, + "Server wants to use a compression that we did not claim" + " to support." + " (BR_ERR_BAD_COMPRESSION)" + }, + { + BR_ERR_BAD_FRAGLEN, + "Server's max fragment length does not match client's." + " (BR_ERR_BAD_FRAGLEN)" + }, + { + BR_ERR_BAD_SECRENEG, + "Secure renegotiation failed." + " (BR_ERR_BAD_SECRENEG)" + }, + { + BR_ERR_EXTRA_EXTENSION, + "Server sent an extension type that we did not announce," + " or used the same extension type several times in a" + " single ServerHello." + " (BR_ERR_EXTRA_EXTENSION)" + }, + { + BR_ERR_BAD_SNI, + "Invalid Server Name Indication contents (when used by" + " the server, this extension shall be empty)." + " (BR_ERR_BAD_SNI)" + }, + { + BR_ERR_BAD_HELLO_DONE, + "Invalid ServerHelloDone from the server (length is not 0)." + " (BR_ERR_BAD_HELLO_DONE)" + }, + { + BR_ERR_LIMIT_EXCEEDED, + "Internal limit exceeded (e.g. server's public key is too" + " large)." + " (BR_ERR_LIMIT_EXCEEDED)" + }, + { + BR_ERR_BAD_FINISHED, + "Finished message from peer does not match the expected" + " value." + " (BR_ERR_BAD_FINISHED)" + }, + { + BR_ERR_RESUME_MISMATCH, + "Session resumption attempt with distinct version or cipher" + " suite." + " (BR_ERR_RESUME_MISMATCH)" + }, + { + BR_ERR_INVALID_ALGORITHM, + "Unsupported or invalid algorithm (ECDHE curve, signature" + " algorithm, hash function)." + " (BR_ERR_INVALID_ALGORITHM)" + }, + { + BR_ERR_BAD_SIGNATURE, + "Invalid signature on ServerKeyExchange message." + " (BR_ERR_BAD_SIGNATURE)" + }, + { + BR_ERR_IO, + "I/O error or premature close on transport stream." + " (BR_ERR_IO)" + }, + { + BR_ERR_X509_INVALID_VALUE, + "Invalid value in an ASN.1 structure." + " (BR_ERR_X509_INVALID_VALUE)" + }, + { + BR_ERR_X509_TRUNCATED, + "Truncated certificate or other ASN.1 object." + " (BR_ERR_X509_TRUNCATED)" + }, + { + BR_ERR_X509_EMPTY_CHAIN, + "Empty certificate chain (no certificate at all)." + " (BR_ERR_X509_EMPTY_CHAIN)" + }, + { + BR_ERR_X509_INNER_TRUNC, + "Decoding error: inner element extends beyond outer element" + " size." + " (BR_ERR_X509_INNER_TRUNC)" + }, + { + BR_ERR_X509_BAD_TAG_CLASS, + "Decoding error: unsupported tag class (application or" + " private)." + " (BR_ERR_X509_BAD_TAG_CLASS)" + }, + { + BR_ERR_X509_BAD_TAG_VALUE, + "Decoding error: unsupported tag value." + " (BR_ERR_X509_BAD_TAG_VALUE)" + }, + { + BR_ERR_X509_INDEFINITE_LENGTH, + "Decoding error: indefinite length." + " (BR_ERR_X509_INDEFINITE_LENGTH)" + }, + { + BR_ERR_X509_EXTRA_ELEMENT, + "Decoding error: extraneous element." + " (BR_ERR_X509_EXTRA_ELEMENT)" + }, + { + BR_ERR_X509_UNEXPECTED, + "Decoding error: unexpected element." + " (BR_ERR_X509_UNEXPECTED)" + }, + { + BR_ERR_X509_NOT_CONSTRUCTED, + "Decoding error: expected constructed element, but is" + " primitive." + " (BR_ERR_X509_NOT_CONSTRUCTED)" + }, + { + BR_ERR_X509_NOT_PRIMITIVE, + "Decoding error: expected primitive element, but is" + " constructed." + " (BR_ERR_X509_NOT_PRIMITIVE)" + }, + { + BR_ERR_X509_PARTIAL_BYTE, + "Decoding error: BIT STRING length is not multiple of 8." + " (BR_ERR_X509_PARTIAL_BYTE)" + }, + { + BR_ERR_X509_BAD_BOOLEAN, + "Decoding error: BOOLEAN value has invalid length." + " (BR_ERR_X509_BAD_BOOLEAN)" + } + { + BR_ERR_X509_OVERFLOW, + "Decoding error: value is off-limits." + " (BR_ERR_X509_OVERFLOW)" + }, + { + BR_ERR_X509_BAD_DN, + "Invalid distinguished name." + " (BR_ERR_X509_BAD_DN)" + }, + { + BR_ERR_X509_BAD_TIME, + "Invalid date/time representation." + " (BR_ERR_X509_BAD_TIME)" + }, + { + BR_ERR_X509_UNSUPPORTED, + "Certificate contains unsupported features that cannot be" + " ignored." + " (BR_ERR_X509_UNSUPPORTED)" + }, + { + BR_ERR_X509_LIMIT_EXCEEDED, + "Key or signature size exceeds internal limits." + " (BR_ERR_X509_LIMIT_EXCEEDED)" + }, + { + BR_ERR_X509_WRONG_KEY_TYPE, + "Key type does not match that which was expected." + " (BR_ERR_X509_WRONG_KEY_TYPE)" + }, + { + BR_ERR_X509_BAD_SIGNATURE, + "Signature is invalid." + " (BR_ERR_X509_BAD_SIGNATURE)" + }, + { + BR_ERR_X509_TIME_UNKNOWN, + "Validation time is unknown." + " (BR_ERR_X509_TIME_UNKNOWN)" + }, + { + BR_ERR_X509_EXPIRED, + "Certificate is expired or not yet valid." + " (BR_ERR_X509_EXPIRED)" + }, + { + BR_ERR_X509_DN_MISMATCH, + "Issuer/Subject DN mismatch in the chain." + " (BR_ERR_X509_DN_MISMATCH)" + }, + { + BR_ERR_X509_BAD_SERVER_NAME, + "Expected server name was not found in the chain." + " (BR_ERR_X509_BAD_SERVER_NAME)" + }, + { + BR_ERR_X509_CRITICAL_EXTENSION, + "Unknown critical extension in certificate." + " (BR_ERR_X509_CRITICAL_EXTENSION)" + }, + { + BR_ERR_X509_NOT_CA, + "Not a CA, or path length constraint violation." + " (BR_ERR_X509_NOT_CA)" + }, + { + BR_ERR_X509_FORBIDDEN_KEY_USAGE, + "Key Usage extension prohibits intended usage." + " (BR_ERR_X509_FORBIDDEN_KEY_USAGE)" + }, + { + BR_ERR_X509_WEAK_PUBLIC_KEY, + "Public key found in certificate is too small." + " (BR_ERR_X509_WEAK_PUBLIC_KEY)" + }, + { + BR_ERR_X509_NOT_TRUSTED, + "Chain could not be linked to a trust anchor." + " (BR_ERR_X509_NOT_TRUSTED)" + }, + { -1, + "Unknown BearSSL error." + } +} ; + + +char const *sbearssl_error_str (int err) +{ + struct error_s *p = errors ; + while (p->err >= 0 && err != p->err) p++ ; + return p->comment ; +} diff --git a/src/sbearssl/sbearssl_isder.c b/src/sbearssl/sbearssl_isder.c new file mode 100644 index 0000000..c481da9 --- /dev/null +++ b/src/sbearssl/sbearssl_isder.c @@ -0,0 +1,25 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_isder (unsigned char const *s, size_t len) +{ + size_t dlen = 0 ; + unsigned char c ; + + if (len < 2) return 0 ; + if (*s++ != 0x30) return 0 ; + c = *s++ ; len -= 2; + if (c < 0x80) return (size_t)c == len ; + else if (c == 0x80) return 0 ; + c -= 0x80 ; + if (len < (size_t)c + 2) return 0 ; + len -= (size_t)c ; + while (c--) + { + if (dlen > (len >> 8)) return 0 ; + dlen = (dlen << 8) + (size_t)*s++ ; + } + return dlen == len ; +} diff --git a/src/sbearssl/sbearssl_pem_decode_from_buffer.c b/src/sbearssl/sbearssl_pem_decode_from_buffer.c new file mode 100644 index 0000000..8aecfda --- /dev/null +++ b/src/sbearssl/sbearssl_pem_decode_from_buffer.c @@ -0,0 +1,53 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/error.h> +#include <skalibs/siovec.h> +#include <skalibs/buffer.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <s6-networking/sbearssl.h> +#include "sbearssl-internal.h" + +int sbearssl_pem_decode_from_buffer (buffer *b, genalloc *list, stralloc *sa) +{ + br_pem_decoder_context ctx ; + sbearssl_pemobject po ; + sbearssl_strallocerr blah = { .sa = sa, .err = 0 } ; + size_t listbase = genalloc_len(sbearssl_pemobject, list) ; + size_t sabase = sa->len ; + int listwasnull = !genalloc_s(sbearssl_pemobject, list) ; + int sawasnull = !sa->s ; + int inobj = 0 ; + int r ; + + br_pem_decoder_init(&ctx) ; + for (;;) + { + siovec_t v[2] ; + r = buffer_fill(b) ; + if (r < 0) goto fail ; + if (!r) break ; + buffer_rpeek(b, v) ; + r = sbearssl_pem_push(&ctx, v[0].s, v[0].len, &po, list, &blah, &inobj) ; + if (r) goto fail ; + if (v[1].len) + { + r = sbearssl_pem_push(&ctx, v[1].s, v[1].len, &po, list, &blah, &inobj) ; + if (r) goto fail ; + } + buffer_rseek(b, v[0].len + v[1].len) ; + } + if (!inobj) return 0 ; + + r = -1 ; + errno = EPROTO ; + fail: + if (listwasnull) genalloc_free(sbearssl_pemobject, list) ; + else genalloc_setlen(sbearssl_pemobject, list, listbase) ; + if (sawasnull) stralloc_free(sa) ; + else sa->len = sabase ; + return r ; +} diff --git a/src/sbearssl/sbearssl_pem_decode_from_string.c b/src/sbearssl/sbearssl_pem_decode_from_string.c new file mode 100644 index 0000000..efcb431 --- /dev/null +++ b/src/sbearssl/sbearssl_pem_decode_from_string.c @@ -0,0 +1,36 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/error.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <s6-networking/sbearssl.h> +#include "sbearssl-internal.h" + +int sbearssl_pem_decode_from_string (char const *s, size_t len, genalloc *list, stralloc *sa) +{ + br_pem_decoder_context ctx ; + sbearssl_pemobject po ; + sbearssl_strallocerr blah = { .sa = sa, .err = 0 } ; + size_t listbase = genalloc_len(sbearssl_pemobject, list) ; + size_t sabase = sa->len ; + int listwasnull = !genalloc_s(sbearssl_pemobject, list) ; + int sawasnull = !sa->s ; + int inobj = 0 ; + int r ; + + br_pem_decoder_init(&ctx) ; + r = sbearssl_pem_push(&ctx, s, len, &po, list, &blah, &inobj) ; + if (r) goto fail ; + if (!inobj) return 0 ; + + errno = EPROTO ; + fail: + if (listwasnull) genalloc_free(sbearssl_pemobject, list) ; + else genalloc_setlen(sbearssl_pemobject, list, listbase) ; + if (sawasnull) stralloc_free(sa) ; + else sa->len = sabase ; + return r ; +} diff --git a/src/sbearssl/sbearssl_pem_push.c b/src/sbearssl/sbearssl_pem_push.c new file mode 100644 index 0000000..b4903de --- /dev/null +++ b/src/sbearssl/sbearssl_pem_push.c @@ -0,0 +1,38 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include "sbearssl-internal.h" + +int sbearssl_pem_push (br_pem_decoder_context *ctx, char const *s, size_t len, sbearssl_pemobject *po, genalloc *list, sbearssl_strallocerr *blah, int *inobj) +{ + while (len) + { + size_t tlen = br_pem_decoder_push(ctx, s, len) ; + if (blah->err) return (errno = blah->err, -1) ; + s += tlen ; len -= tlen ; + switch (br_pem_decoder_event(ctx)) + { + case BR_PEM_BEGIN_OBJ ; + po->name = blah->sa->len ; + if (!stralloc_cats(blah->sa, br_pem_decoder_name(ctx)) || !stralloc_0(blah->sa)) return -1 ; + po->data = blah->sa->len ; + br_pem_decoder_setdest(&ctx, &sbearssl_append, blah) ; + *inobj = 1 ; + break ; + case BR_PEM_END_OBJ : + if (*inobj) + { + po->datalen = blah->sa->len - po->data ; + if (!genalloc_append(sbearssl_pemobject, list, po)) return 0 ; + *inobj = 0 ; + } + break ; + case BR_PEM_ERROR : return (errno = EINVAL, -1) ; + } + } + return 0 ; +} diff --git a/src/sbearssl/sbearssl_pkey_from.c b/src/sbearssl/sbearssl_pkey_from.c new file mode 100644 index 0000000..e9745e8 --- /dev/null +++ b/src/sbearssl/sbearssl_pkey_from.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <errno.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_pkey_from (sbearssl_pkey *l, br_x509_key const *k, stralloc *sa) +{ + switch (k->key_type) + { + case BR_KEYTYPE_RSA : + if (!sbearssl_rsa_pkey_from(&l->data.rsa, &k->key.rsa, sa) return 0 ; + break ; + case BR_KEYTYPE_EC : + if (!sbearssl_ec_pkey_from(&l->data.ec, &k->key.ec, sa) return 0 ; + break ; + default : + return (errno = EINVAL, 0) ; + } + l->type = k->key_type ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_pkey_to.c b/src/sbearssl/sbearssl_pkey_to.c new file mode 100644 index 0000000..491901b --- /dev/null +++ b/src/sbearssl/sbearssl_pkey_to.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <errno.h> +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_pkey_to (sbearssl_pkey const *l, br_x509_pkey *k, char const *s) +{ + switch (l->type) + { + case BR_KEYTYPE_RSA : + sbearssl_rsa_pkey_to(&l->data.rsa, &k->key.rsa, s) ; + break ; + case BR_KEYTYPE_EC : + sbearssl_ec_pkey_to(&l->data.ec, &k->key.ec, s) ; + break ; + default : + return (errno = EINVAL, 0) ; + } + k->key_type = l->type ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_rsa_pkey_from.c b/src/sbearssl/sbearssl_rsa_pkey_from.c new file mode 100644 index 0000000..a991f0c --- /dev/null +++ b/src/sbearssl/sbearssl_rsa_pkey_from.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_rsa_pkey_from (sbearssl_rsa_pkey *l, br_rsa_public_key const *k, stralloc *sa) +{ + if (!stralloc_readyplus(k->nlen + k->elen)) return 0 ; + l->n = sa->len ; + stralloc_catb(sa, k->n, k->nlen) ; + l->nlen = k->nlen ; + l->e = sa->len ; + stralloc_catb(sa, k->e, k->elen) ; + l->elen = k->elen ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_rsa_pkey_to.c b/src/sbearssl/sbearssl_rsa_pkey_to.c new file mode 100644 index 0000000..13d567e --- /dev/null +++ b/src/sbearssl/sbearssl_rsa_pkey_to.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +void sbearssl_rsa_pkey_ro (sbearssl_rsa_pkey const *l, br_rsa_public_key *k, char const *s) +{ + k->n = s + l->n ; + k->nlen = l->nlen ; + k->e = s + l->e ; + k->elen = l->elen ; +} diff --git a/src/sbearssl/sbearssl_rsa_skey_from.c b/src/sbearssl/sbearssl_rsa_skey_from.c new file mode 100644 index 0000000..3e6a04b --- /dev/null +++ b/src/sbearssl/sbearssl_rsa_skey_from.c @@ -0,0 +1,28 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_rsa_skey_from (sbearssl_rsa_skey *l, br_rsa_private_key const *k, stralloc *sa) +{ + if (!stralloc_readyplus(k->plen + k->qlen + k->dplen + k->dqlen + k->iqlen)) return 0 ; + l->n_bitlen = k->n_bitlen ; + l->p = sa->len ; + stralloc_catb(sa, k->p, k->plen) ; + l->plen = k->plen ; + l->q = sa->len ; + stralloc_catb(sa, k->q, k->qlen) ; + l->qlen = k->qlen ; + l->dp = sa->len ; + stralloc_catb(sa, k->dp, k->dplen) ; + l->dplen = k->dplen ; + l->dq = sa->len ; + stralloc_catb(sa, k->dq, k->dqlen) ; + l->dqlen = k->dqlen ; + l->iq = sa->len ; + stralloc_catb(sa, k->iq, k->iqlen) ; + l->iqlen = k->iqlen ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_rsa_skey_to.c b/src/sbearssl/sbearssl_rsa_skey_to.c new file mode 100644 index 0000000..3c4139b --- /dev/null +++ b/src/sbearssl/sbearssl_rsa_skey_to.c @@ -0,0 +1,19 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +void sbearssl_rsa_skey (sbearssl_rsa_skey const *l, br_rsa_private_key *k, char const *s) +{ + k->n_bitlen = l->n_bitlen ; + k->p = s + l->p ; + k->plen = l->plen ; + k->q = s + l->q ; + k->qlen = l->qlen ; + k->dp = s + l->dp ; + k->dplen = l->dplen ; + k->dq = s + l->dq ; + k->dqlen = l->dqlen ; + k->iq = s + l->iq ; + k->iqlen = l->iqlen ; +} diff --git a/src/sbearssl/sbearssl_run.c b/src/sbearssl/sbearssl_run.c new file mode 100644 index 0000000..af221b5 --- /dev/null +++ b/src/sbearssl/sbearssl_run.c @@ -0,0 +1,186 @@ +/* ISC license. */ + +#include <skalibs/nonposix.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <signal.h> +#include <bearssl.h> +#include <skalibs/error.h> +#include <skalibs/strerr2.h> +#include <skalibs/sig.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> +#include <skalibs/djbunix.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_run (br_ssl_engine_context *ctx, int *fds, unsigned int verbosity, uint32_t options, tain_t const *tto) +{ + iopause_fd x[4] ; + unsigned int xindex[4] ; + + if (ndelay_on(fds[2]) < 0 || ndelay_on(fds[3]) < 0) + strerr_diefu1sys(111, "set fds non-blocking") ; + if (sig_ignore(SIGPIPE) < 0) + strerr_diefu1sys(111, "ignore SIGPIPE") ; + + for (;;) + { + tain_t deadline ; + unsigned int j = 0 ; + unsigned int state = br_ssl_engine_current_state(ctx) ; + int r ; + + tain_add_g(&deadline, isopen[0] && isopen[1] && state & (BR_SSL_SENDAPP | BR_SSL_REVREC) ? tto : &tain_infinite_relative) ; + + if (fds[0] >= 0 && st & BR_SSL_SENDAPP) + { + x[j].fd = fds[0] ; + x[j].events = IOPAUSE_READ ; + xindex[0] = j++ ; + } + else xindex[0] = 4 ; + if (fds[1] >= 0 && st & BR_SSL_RECVAPP) + { + x[j].fd = fds[1] ; + x[j].events = IOPAUSE_WRITE ; + xindex[1] = j++ ; + } + else xindex[1] = 4 ; + if (fds[2] >= 0 && st & BR_SSL_RECVREC) + { + x[j].fd = fds[2] ; + x[j].events = IOPAUSE_READ ; + xindex[2] = j++ ; + } + else xindex[2] = 4 ; + if (fds[3] >= 0 && st & BR_SSL_SENDREC) + { + x[j].fd = fds[3] ; + x[j].events = IOPAUSE_WRITE ; + xindex[3] = j++ ; + } + else xindex[3] = 4 ; + + if (!j) break ; + r = iopause_g(x, j, &deadline) ; + if (r < 0) strerr_diefu1sys(111, "iopause") ; + else if (!r) + { + fd_close(fds[0]) ; fds[0] = -1 ; + br_ssl_engine_close(&ctx) ; + continue ; + } + + while (j--) + if (x[j].revents & IOPAUSE_EXCEPT) + x[j].revents |= IOPAUSE_READ | IOPAUSE_WRITE ; + + + /* Flush to local */ + + if (state & BR_SSL_RECVAPP && x[xindex[1]].revents & IOPAUSE_WRITE) + { + size_t len ; + char const *s = br_ssl_engine_recvapp_buf(ctx, &len) ; + size_t w = allwrite(fds[1], s, len) ; + if (!w) + { + if (!error_isagain(errno)) + strerr_diefu1sys(111, "write to application") ; + } + else + { + br_ssl_engine_recvapp_ack(ctx, w) ; + state = br_ssl_engine_current_state(ctx) ; + if (fds[2] < 0 && w == len) + { + fd_close(fds[1]) ; fds[1] = -1 ; + } + } + } + + + /* Flush to remote */ + + if (state & BR_SSL_SENDREC && x[xindex[3]].revents & IOPAUSE_WRITE) + { + size_t len ; + char const *s = br_ssl_engine_sendrec_buf(ctx, &len) ; + size_t w = allwrite(fds[3], s, len) ; + if (!w) + { + if (!error_isagain(errno)) + strerr_diefu1sys(111, "write to peer") ; + } + else + { + br_ssl_engine_sendrec_ack(ctx, w) ; + state = br_ssl_engine_current_state(ctx) ; + if (fds[0] < 0 && w == len) + { + if (options & 1) shutdown(fds[3], SHUT_WR) ; + fd_close(fds[3]) ; fds[3] = -1 ; + } + } + } + + + /* Fill from local */ + + if (state & BR_SSL_SENDAPP & x[xindex[0]].revents & IOPAUSE_READ) + { + size_t len ; + char *s = br_ssl_engine_sendapp_buf(ctx, &len) ; + size_t w = allread(fds[0], s, len) ; + if (!w) + { + if (!error_isagain(errno)) + { + fd_close(fds[0]) ; fds[0] = -1 ; + if (fds[2] >= 0) br_ssl_engine_close(ctx) ; + if (!br_ssl_engine_sendrec_buf(ctx, &len)) + { + if (options & 1) shutdown(fds[3], SHUT_WR) ; + fd_close(fds[3]) ; fds[3] = -1 ; + } + } + } + else + { + br_ssl_engine_sendapp_ack(ctx, w) ; + br_ssl_engine_flush(ctx, 0) ; + state = br_ssl_engine_current_state(ctx) ; + } + } + + + /* Fill from remote */ + + if (state & BR_SSL_RECVREC & x[xindex[2]].revents & IOPAUSE_READ) + { + size_t len ; + char *s = br_ssl_engine_recvrec_buf(ctx, &len) ; + size_t w = allread(fds[2], s, len) ; + if (!w) + { + if (!error_isagain(errno)) + { + if (options & 1) shutdown(fds[2], SHUT_RD) ; + fd_close(fds[2]) ; fds[2] = -1 ; + if (!br_ssl_engine_recvapp_buf(ctx, &len)) + { + fd_close(fds[1]) ; fds[1] = -1 ; + } + } + } + else br_ssl_engine_recvrec_ack(ctx, w) ; + } + } + + if (fds[1] >= 0) fd_close(fds[1]) ; + if (fds[0] >= 0) fd_close(fds[0]) ; + if (fds[3] >= 0) fd_close(fds[3]) ; + if (fds[2] >= 0) fd_close(fds[2]) ; + return br_ssl_engine_last_error(ctx) ; +} diff --git a/src/sbearssl/sbearssl_s6tlsc.c b/src/sbearssl/sbearssl_s6tlsc.c new file mode 100644 index 0000000..a8a6582 --- /dev/null +++ b/src/sbearssl/sbearssl_s6tlsc.c @@ -0,0 +1,82 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/env.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/random.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_s6tlsc (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity, int *sfd) +{ + int fds[4] = { sfd[0], sfd[1], sfd[0], sfd[1] } ; + stralloc storage = STRALLOC_ZERO ; + genalloc tas = GENALLOC_ZERO ; + size_t chainlen ; + int r ; + + if (preoptions & 1) + strerr_dief1x(100, "client certificates are not supported by BearSSL yet") ; + + x = env_get2(envp, "CADIR") ; + if (x) + r = sbearssl_ta_readdir(x, &tas, &storage) ; + else + { + x = env_get2(envp, "CAFILE") ; + if (!x) strerr_dienotset(100, "CADIR or CAFILE") ; + r = sbearssl_ta_readfile(x, &tas, &storage) ; + } + + if (r < 0) + strerr_diefu2sys(111, "read trust anchors in ", x) ; + else if (r) + strerr_diefu4x(96, "read trust anchors in ", x, ": ", sbearssl_error_str(r)) ; + + talen = genalloc_len(sbearssl_ta, &tas) ; + if (!talen) + strerr_dief2x(96, "no trust anchor found in ", x) ; + + { + unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; + br_x509_minimal_context xc ; + br_ssl_client_context cc ; + br_x509_trust_anchor btas[talen] ; + size_t i = talen ; + pid_t pid ; + + stralloc_shrink(&storage) ; + while (i--) + sbearssl_ta_to(genalloc_s(sbearssl_ta, &tas) + i, btas + i, storage.s) ; + genalloc_free(sbearssl_ta, &tas) ; + br_ssl_client_init_full(&cc, &xc, btas, talen) ; + + if (!random_init()) + strerr_diefu1sys(111, "initialize random generator") ; + random_string(buf, 32) ; + br_ssl_engine_inject_entropy(&cc.eng, buf, 32) ; + random_finish() ; + + pid = child_spawn2(argv[0], argv, envp, fds) ; + if (gid && setgid(gid) < 0) strerr_diefu1sys(111, "setgid") ; + if (uid && setuid(uid) < 0) strerr_diefu1sys(111, "setuid") ; + + br_ssl_engine_set_buffer(&cc.eng, buf, sizeof(buf), 1) ; + br_ssl_client_reset(&cc) ; + + { + int wstat ; + int r = sbearssl_run(&cc.eng, fds, verbosity, options, tto) ; + if (r < 0) strerr_diefu1sys(111, "run SSL engine") ; + else if (r) strerr_diefu3x(98, "run SSL engine", ": ", sbearssl_error_str(r)) ; + if (wait_pid(pid, &wstat) < 0) strerr_diefu1sys(111, "wait_pid") ; + return wait_estatus(wstat) ; + } + } +} diff --git a/src/sbearssl/sbearssl_s6tlsd.c b/src/sbearssl/sbearssl_s6tlsd.c new file mode 100644 index 0000000..1bc1114 --- /dev/null +++ b/src/sbearssl/sbearssl_s6tlsd.c @@ -0,0 +1,99 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/env.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/random.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_s6tlsd (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity) +{ + stralloc storage = STRALLOC_ZERO ; + sbearssl_skey skey ; + genalloc certs = GENALLOC_ZERO ; + size_t chainlen ; + + if (preoptions & 1) + strerr_dief1x(100, "client certificates are not supported by BearSSL yet") ; + + { + char const *x = env_get2(envp, "KEYFILE") ; + int r ; + if (!x) strerr_dienotset(100, "KEYFILE") ; + r = sbearssl_skey_readfile(x, &skey, &storage) ; + if (r < 0) + strerr_diefu2sys(111, "read private key in ", x) ; + else if (r) + strerr_diefu4x(96, "decode private key in ", x, ": ", sbearssl_error_str(r)) ; + + x = env_get2(envp, "CERTFILE") ; + if (!x) strerr_dienotset(100, "CERTFILE") ; + r = sbearssl_cert_readfile(x, &certs, &storage) ; + if (r < 0) + strerr_diefu2sys(111, "read certificate chain in ", x) ; + else if (r) + strerr_diefu4sys(96, "read certificate chain in ", x, ": ", sbearssl_error_str(r)) ; + chainlen = genalloc_len(sbearssl_cert, &certs) ; + if (!chainlen) + strerr_diefu2x(96, "find a certificate in ", x) ; + } + + { + int fds[4] = { 0, 1, 0, 1 } ; + unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; + br_ssl_server_context sc ; + union br_skey_u key ; + br_x509_certificate chain[chainlen] ; + size_t i = chainlen ; + pid_t pid ; + + stralloc_shrink(&storage) ; + while (i--) + sbearssl_cert_to(genalloc_s(sbearssl_cert, &certs) + i, chain + i, storage.s) ; + genalloc_free(sbearssl_cert, &certs) ; + + switch (skey.type) + { + case BR_KEYTYPE_RSA : + sbearssl_rsa_skey_to(&skey.rsa, &key.rsa, storage.s) ; + br_ssl_server_init_full_rsa(&sc, chain, chainlen, &key.rsa) ; + break ; + case BR_KEYTYPE_EC : + sbearssl_ec_skey_to(&skey.ec, &key.ec, storage.s) ; + br_ssl_server_init_full_ec(&sc, chain, chainlen, &key.ec) ; + break ; + default : + strerr_dief1x(96, "unsupported private key type") ; + } + + if (!random_init()) + strerr_diefu1sys(111, "initialize random generator") ; + random_string(buf, 32) ; + br_ssl_engine_inject_entropy(&sc.eng, buf, 32) ; + random_finish() ; + + pid = child_spawn2(argv[0], argv, envp, fds) ; + if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; + if (gid && setgid(gid) < 0) strerr_diefu1sys(111, "setgid") ; + if (uid && setuid(uid) < 0) strerr_diefu1sys(111, "setuid") ; + + br_ssl_engine_set_buffer(&sc.eng, buf, sizeof(buf), 1) ; + br_ssl_server_reset(&sc) ; + + { + int wstat ; + int r = sbearssl_run(&sc.eng, fds, verbosity, options, tto) ; + if (r < 0) strerr_diefu1sys(111, "run SSL engine") ; + else if (r) strerr_diefu3x(98, "run SSL engine", ": ", sbearssl_error_str(r)) ; + if (wait_pid(pid, &wstat) < 0) strerr_diefu1sys(111, "wait_pid") ; + return wait_estatus(wstat) ; + } + } +} diff --git a/src/sbearssl/sbearssl_skey_from.c b/src/sbearssl/sbearssl_skey_from.c new file mode 100644 index 0000000..26b2788 --- /dev/null +++ b/src/sbearssl/sbearssl_skey_from.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <errno.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_skey_from (sbearssl_skey *l, br_skey const *k, stralloc *sa) +{ + switch (k->type) + { + case BR_KEYTYPE_RSA : + if (!sbearssl_rsa_skey_from(&l->data.rsa, &k->data.rsa, sa) return 0 ; + break ; + case BR_KEYTYPE_EC : + if (!sbearssl_ec_pkey_from(&l->data.ec, &k->data.ec, sa) return 0 ; + break ; + default : + return (errno = EINVAL, 0) ; + } + l->type = k->type ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_skey_readfile.c b/src/sbearssl/sbearssl_skey_readfile.c new file mode 100644 index 0000000..64ac28d --- /dev/null +++ b/src/sbearssl/sbearssl_skey_readfile.c @@ -0,0 +1,71 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/bytestr.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/djbunix.h> +#include <s6-networking/sbearssl.h> + +#define MAXKEYFILESIZE 8192 + +static int decode_key (sbearssl_skey *key, char const *s, size_t len, stralloc *sa) +{ + br_skey_decoder_context ctx ; + int ktype ; + br_skey_decoder_init(&ctx) ; + br_skey_decoder_push(&ctx, s, len) ; + ktype = br_skey_decoder_key_type(&ctx) ; + switch (ktype) + { + case 0 : return br_skey_decoder_last_error(&ctx) ; + case BR_KEYTYPE_RSA : + if (!sbearssl_rsa_skey_from(&key->data.rsa, ctx.key.rsa, sa) return -1 ; + break ; + case BR_KEYTYPE_EC : + if (!sbearssl_ec_skey_from(&key->data.ec, ctx.key.ec, sa) return -1 ; + break ; + } + key->type = ktype ; + return 0 ; +} + +int sbearssl_skey_readfile (char const *fn, sbearssl_skey *key, stralloc *sa) ; +{ + char buf[MAXKEYFILESIZE] ; + stralloc tmp = STRALLOC_ZERO ; + genalloc list = GENALLOC_ZERO ; + sbearssl_pemobject *p ; + size_t n ; + size_t i = 0 ; + int r = openreadnclose(fn, buf, MAKKEYFILESIZE) ; + if (r < 0) return r ; + n = r ; + if (sbearssl_isder(buf, n)) return decode_key(key, buf, n) ; + r = sbearssl_pem_decode_from_string(buf, n, &list, &tmp) ; + if (r) return r ; + p = genalloc_s(sbearssl_pemobject, &list) ; + n = genalloc_len(sbearssl_pemobject, &list) ; + for (; i < n ; i++) + { + char const *name = tmp.s + p[i].name ; + if (!str_diff(name, "RSA PRIVATE KEY") + || !str_diff(name, "EC PRIVATE KEY") + || !str_diff(name, "PRIVATE KEY")) + { + r = decode_key(key, tmp.s + p[i].data, p[i].datalen, sa) ; + if (r) goto fail ; + break ; + } + } + stralloc_free(&tmp) ; + if (i < n) return 0 ; + + r = -1 ; errno = EINVAL ; + fail: + stralloc_free(&tmp) ; + genalloc_free(sbearssl_pemobject, list) ; + return r ; +} diff --git a/src/sbearssl/sbearssl_skey_to.c b/src/sbearssl/sbearssl_skey_to.c new file mode 100644 index 0000000..9886606 --- /dev/null +++ b/src/sbearssl/sbearssl_skey_to.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <errno.h> +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_skey_to (sbearssl_skey const *l, br_skey *k, char const *s) +{ + switch (l->type) + { + case BR_KEYTYPE_RSA : + sbearssl_rsa_pkey_to(&l->data.rsa, &k->data.rsa, s) ; + break ; + case BR_KEYTYPE_EC : + sbearssl_ec_pkey_to(&l->data.ec, &k->data.ec, s) ; + break ; + default : + return (errno = EINVAL, 0) ; + } + k->type = l->type ; + return 1 ; +} diff --git a/src/sbearssl/sbearssl_ta_cert.c b/src/sbearssl/sbearssl_ta_cert.c new file mode 100644 index 0000000..d8f26e5 --- /dev/null +++ b/src/sbearssl/sbearssl_ta_cert.c @@ -0,0 +1,43 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_ta_cert (sbearssl_ta *ta, sbearssl_cert const *cert, char const *certstorage, stralloc *tastorage) +{ + br_x509_decoder_context ctx ; + sbearssl_ta tta = { .dn = tastorage->len, .flags = 0 } ; + struct sbearssl_strallocerr_s blah = { .sa = tastorage } ; + size_t tastoragebase = tastorage->len ; + int tastoragewasnull = !tastorage->s ; + br_x509_pkey bpk ; + int r ; + + br_x509_decoder_init(&ctx, &sbearssl_append, &blah) ; + br_x509_decoder_push(&ctx, certstorage + cert->data, cert->datalen) ; + if (blah->err) + { + r = -1 ; + errno = blah->err ; + goto fail ; + } + bpk = br_x509_decoder_get_pkey(&ctx) ; + if (!bpk) + { + r = br_x509_decoder_last_error(&ctx) ; + goto fail ; + } + tta.dnlen = tastorage->len - tastoragebase ; + if (br_x509_decoder_isCA(&ctx)) tta.flags |= BR_X509_TA_CA ; + if (!sbearssl_pkey_from(&tta.pkey, bpk, tastorage)) goto fail ; + *ta = tta ; + return 0 ; + + fail: + if (tastoragewasnull) stralloc_free(tastorage) ; + else tastorage->len = tastoragebase ; + return r ; +} diff --git a/src/sbearssl/sbearssl_ta_from.c b/src/sbearssl/sbearssl_ta_from.c new file mode 100644 index 0000000..d044c27 --- /dev/null +++ b/src/sbearssl/sbearssl_ta_from.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_ta_from (sbearssl_ta *l, br_x509_trust_anchor const *k, stralloc *sa) +{ + size_t sabase = sa->len ; + int sawasnull = !sa->s ; + sbearssl_ta ta = { .dn = sa->len, .dnlen = k->dn_len, .flags = k.flags } ; + if (!stralloc_catb(sa, k->dn, k->dn_len)) return 0 ; + if (!sbearssl_pkey_from(&ta.pkey, &k->pkey, sa)) goto fail ; + *l = ta ; + return 1 ; + + fail: + if (sawasnull) stralloc_free(sa) ; + else sa->len = sabase ; + return 0 ; +} diff --git a/src/sbearssl/sbearssl_ta_readdir.c b/src/sbearssl/sbearssl_ta_readdir.c new file mode 100644 index 0000000..9821dd2 --- /dev/null +++ b/src/sbearssl/sbearssl_ta_readdir.c @@ -0,0 +1,61 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <errno.h> +#include <skalibs/bytestr.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/direntry.h> +#include <skalibs/djbunix.h> +#include <s6-networking/sbearssl.h> + +int sbearssl_ta_readdir (char const *dirfn, genalloc *taga, stralloc *tasa) +{ + stralloc certsa = STRALLOC_ZERO ; + genalloc certga = GENALLOC_ZERO ; + size_t tasabase = tasa->len ; + size_t tagabase = genalloc_len(sbearssl_ta, taga) ; + size_t dirfnlen = str_len(dirfn) ; + int tasawasnull = !tasa->s ; + int tagawasnull = !genalloc_s(sbearssl_ta, taga) ; + DIR *dir = opendir(dirfn) ; + if (!dir) return -1 ; + + for (;;) + { + direntry *d ; + errno = 0 ; + d = readdir(dir) ; + if (!d) break ; + if (d->d_name[0] == '.') continue ; + { + size_t dlen = str_len(d->d_name) ; + char fn[dirfnlen + dlen + 2] ; + byte_copy(fn, dirfnlen, dirfn) ; + fn[dirfnlen] = '/' ; + byte_copy(fn + dirfnlen + 1, dlen, d->d_name) ; + fn[dirfnlen + 1 + dlen] = 0 ; + sbearssl_ta_readfile_internal(fn, taga, tasa, &certga, &certsa) ; + } + } + if (errno) goto fail ; + + dir_close(dir) ; + genalloc_free(sbearssl_cert, &certga) ; + stralloc_free(&certsa) ; + return 0 ; + + fail: + { + int e = errno ; + dir_close(dir) ; + genalloc_free(sbearssl_cert, &certga) ; + stralloc_free(&certsa) ; + if (tagawasnull) genalloc_free(sbearssl_ta, taga) ; + else genalloc_setlen(sbearssl_ta, taga, tagabase) ; + if (tasawasnull) stralloc_free(tasa) ; + else tasa->len = tasabase ; + errno = e ; + } + return -1 ; +} diff --git a/src/sbearssl/sbearssl_ta_readfile.c b/src/sbearssl/sbearssl_ta_readfile.c new file mode 100644 index 0000000..8e7cf8e --- /dev/null +++ b/src/sbearssl/sbearssl_ta_readfile.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <s6-networking/sbearssl.h> +#include "sbearssl-internal.h" + +int sbearssl_ta_readfile (char const *file, genalloc *taga, stralloc *tasa) +{ + stralloc certsa = STRALLOC_ZERO ; + genalloc certga = GENALLOC_ZERO ; + int r = sbearssl_ta_readfile_internal(file, taga, tasa, &certsa, &certga) ; + genalloc_free(sbearssl_ta, &certga) ; + stralloc_free(&certsa) ; + return r ; +} diff --git a/src/sbearssl/sbearssl_ta_readfile_internal.c b/src/sbearssl/sbearssl_ta_readfile_internal.c new file mode 100644 index 0000000..acbba9a --- /dev/null +++ b/src/sbearssl/sbearssl_ta_readfile_internal.c @@ -0,0 +1,46 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <bearssl.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <s6-networking/sbearssl.h> +#include "sbearssl-internal.h" + +int sbearssl_ta_readfile_internal (char const *file, genalloc *taga, stralloc *tasa, genalloc *certga, stralloc *certsa) +{ + size_t i = 0 ; + size_t certsabase = certsa->len ; + size_t certgabase = genalloc_len(sbearssl_ta, certga) ; + size_t tasabase = tasa->len ; + size_t tagabase = genalloc_len(sbearssl_ta, taga) ; + int tasawasnull = !tasa->s ; + int tagawasnull = !genalloc_s(sbearssl_ta, taga) ; + int r = sbearssl_cert_read(file, certga, certsa) ; + sbearssl_cert *p = genalloc_s(sbearssl_cert, certga) ; + size_t n = genalloc_len(sbearssl_cert, certga) ; + if (r) return r ; + + for (; i < n ; i++) + { + sbearssl_ta ta ; + r = sbearssl_ta_cert(&ta, p + i, certsa->s, tasa) ; + if (r) goto fail ; + if (!genalloc_append(sbearssl_ta, taga, &ta)) goto rfail ; + } + + genalloc_setlen(sbearssl_ta, certga, certgabase) ; + certsa->len = certsabase ; + return 0 ; + + rfail: + r = -1 ; + fail: + genalloc_setlen(sbearssl_ta, certga, certgabase) ; + certsa->len = certsabase ; + if (tagawasnull) genalloc_free(sbearssl_ta, taga) ; + else genalloc_setlen(sbearssl_ta, taga, tagabase) ; + if (tasawasnull) stralloc_free(tasa) ; + else tasa->len = tasabase ; + return r ; +} diff --git a/src/sbearssl/sbearssl_ta_to.c b/src/sbearssl/sbearssl_ta_to.c new file mode 100644 index 0000000..4714b47 --- /dev/null +++ b/src/sbearssl/sbearssl_ta_to.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <bearssl.h> +#include <s6-networking/sbearssl.h> + +void sbearssl_ta_to (sbearssl_ta const *sta, br_x509_trust_anchor *bta, char const *s) +{ + bta->dn = s + sta->dn ; + bta->dn_len = sta->dnlen ; + bta->flags = sta->flags ; + sbearssl_pkey_to(&sta->pkey, &bta->pkey, s) ; +} diff --git a/src/stls/deps-lib/stls b/src/stls/deps-lib/stls new file mode 100644 index 0000000..799c7ae --- /dev/null +++ b/src/stls/deps-lib/stls @@ -0,0 +1,5 @@ +stls_run.o +stls_s6tlsc.o +stls_s6tlsd.o +-ltls +-lskarnet diff --git a/src/stls/stls_run.c b/src/stls/stls_run.c new file mode 100644 index 0000000..24ff801 --- /dev/null +++ b/src/stls/stls_run.c @@ -0,0 +1,274 @@ +/* ISC license. */ + +#include <skalibs/nonposix.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <signal.h> +#include <tls.h> +#include <skalibs/uint32.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/error.h> +#include <skalibs/buffer.h> +#include <skalibs/sig.h> +#include <skalibs/selfpipe.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> +#include <skalibs/djbunix.h> +#include <skalibs/siovec.h> +#include <s6-networking/stls.h> + +typedef struct tlsbuf_s tlsbuf_t, *tlsbuf_t_ref ; +struct tlsbuf_s +{ + char buf[STLS_BUFSIZE] ; + buffer b ; + unsigned int blockedonother : 1 ; +} ; + +static inline int buffer_tls_flush (struct tls *ctx, tlsbuf_t *b) +{ + siovec_t v[2] ; + ssize_t r, w ; + buffer_rpeek(&b[0].b, v) ; + r = tls_write(ctx, v[0].s, v[0].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 (v[1].len) + { + r = tls_write(ctx, v[1].s, v[1].len) ; + 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 ; + default : break ; + } + w += r ; + } + buffer_rseek(&b[0].b, w) ; + return 1 ; +} + +static inline int buffer_tls_fill (struct tls *ctx, tlsbuf_t *b) +{ + siovec_t v[2] ; + ssize_t r, w ; + int ok = 1 ; + buffer_wpeek(&b[1].b, v) ; + r = tls_read(ctx, v[0].s, v[0].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 (v[1].len) + { + r = tls_read(ctx, v[1].s, v[1].len) ; + 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 ; + default : break ; + } + w += r ; + } + buffer_wseek(&b[1].b, w) ; + return ok ; +} + +static void do_tls_close (struct tls *ctx, int fd) +{ + iopause_fd x = { .fd = fd, .events = IOPAUSE_WRITE } ; + while (tls_close(ctx) == TLS_WANT_POLLOUT) + if (iopause_g(&x, 1, 0) < 0) + strerr_diefu1sys(111, "iopause") ; +} + +int stls_run (struct tls *ctx, int *fds, unsigned int verbosity, uint32 options, tain_t const *tto) +{ + tlsbuf_t b[2] = { { .blockedonother = 0 }, { .blockedonother = 0 } } ; + iopause_fd x[4] ; + unsigned int xindex[4] ; + register unsigned int i ; + + for (i = 0 ; i < 2 ; i++) + { + buffer_init(&b[i].b, i ? &buffer_write : &buffer_read, fds[i], b[i].buf, STLS_BUFSIZE) ; + if (ndelay_on(fds[2+i]) < 0) strerr_diefu1sys(111, "set fds non-blocking") ; + } + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + + tain_now_g() ; + + for (;;) + { + tain_t deadline ; + unsigned int xlen = 0 ; + register int r ; + + tain_add_g(&deadline, buffer_isempty(&b[0].b) && buffer_isempty(&b[1].b) ? tto : &tain_infinite_relative) ; + + + /* poll() preparation */ + + if (fds[0] >= 0 && buffer_isreadable(&b[0].b)) + { + x[xlen].fd = fds[0] ; + x[xlen].events = IOPAUSE_READ ; + xindex[0] = xlen++ ; + } + else xindex[0] = 4 ; + + if (fds[1] >= 0 && buffer_iswritable(&b[1].b)) + { + x[xlen].fd = fds[1] ; + x[xlen].events = IOPAUSE_WRITE ; + xindex[1] = xlen++ ; + } + else xindex[1] = 4 ; + + if (fds[2] >= 0 && !b[1].blockedonother && buffer_isreadable(&b[1].b)) + { + x[xlen].fd = fds[2] ; + x[xlen].events = IOPAUSE_READ ; + xindex[2] = xlen++ ; + } + else xindex[2] = 4 ; + + if (fds[3] >= 0 && !b[0].blockedonother && buffer_iswritable(&b[0].b)) + { + x[xlen].fd = fds[3] ; + x[xlen].events = IOPAUSE_WRITE ; + xindex[3] = xlen++ ; + } + else xindex[3] = 4 ; + + if (!xlen) break ; + + + /* poll() */ + + r = iopause_g(x, xlen, &deadline) ; + if (r < 0) strerr_diefu1sys(111, "iopause") ; + else if (!r) + { + fd_close(fds[0]) ; + tls_close(ctx) ; + continue ; + } + + while (xlen--) + if (x[xlen].revents & IOPAUSE_EXCEPT) + x[xlen].revents |= IOPAUSE_READ | IOPAUSE_WRITE ; + + + /* Flush to local */ + + if (xindex[1] < 4 && x[xindex[1]].revents & IOPAUSE_WRITE) + { + r = buffer_flush(&b[1].b) ; + if (!r && !error_isagain(errno)) + { + strerr_warnwu1sys("write to application") ; + if (fds[2] >= 0) + { + if (options & 1) shutdown(fds[2], SHUT_RD) ; + fd_close(fds[2]) ; fds[2] = -1 ; + } + r = 1 ; + } + if (r && fds[2] < 0) + { + fd_close(fds[1]) ; fds[1] = -1 ; + } + } + + + /* Flush to remote */ + + if (xindex[3] < 4 && x[xindex[3]].revents & IOPAUSE_WRITE) + { + r = buffer_tls_flush(ctx, b) ; + if (r < 0) + { + strerr_warnwu2x("write to peer: ", tls_error(ctx)) ; + fd_close(fds[0]) ; fds[0] = -1 ; + } + if (r && fds[0] < 0) + { + if (fds[2] >= 0) do_tls_close(ctx, fds[3]) ; + if (options & 1) shutdown(fds[3], SHUT_WR) ; + fd_close(fds[3]) ; fds[3] = -1 ; + } + } + + + /* Fill from local */ + + if (xindex[0] < 4 && x[xindex[0]].revents & IOPAUSE_READ) + { + r = sanitize_read(buffer_fill(&b[0].b)) ; + if (r < 0) + { + if (r == -1) strerr_warnwu1sys("read from application") ; + fd_close(fds[0]) ; fds[0] = -1 ; + if (buffer_isempty(&b[0].b)) + { + if (fds[2] >= 0) do_tls_close(ctx, fds[3]) ; + if (options & 1) shutdown(fds[3], SHUT_WR) ; + fd_close(fds[3]) ; fds[3] = -1 ; + } + } + } + + + /* Fill from remote */ + + if (xindex[2] < 4 && x[xindex[2]].revents & IOPAUSE_READ) + { + r = buffer_tls_fill(ctx, b) ; + if (r < 0) + { + if (errno != EPIPE) strerr_warnwu1sys("read from peer") ; + if (options & 1) shutdown(fds[2], SHUT_RD) ; + fd_close(fds[2]) ; fds[2] = -1 ; + if (buffer_isempty(&b[1].b)) + { + fd_close(fds[1]) ; fds[1] = -1 ; + } + } + } + } + + if (fds[1] >= 0) fd_close(fds[1]) ; + if (fds[0] >= 0) fd_close(fds[0]) ; + if (fds[3] >= 0) fd_close(fds[3]) ; + if (fds[2] >= 0) fd_close(fds[2]) ; + return 0 ; +} diff --git a/src/stls/stls_s6tlsc.c b/src/stls/stls_s6tlsc.c new file mode 100644 index 0000000..7fd4325 --- /dev/null +++ b/src/stls/stls_s6tlsc.c @@ -0,0 +1,95 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <tls.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/env.h> +#include <skalibs/djbunix.h> +#include <s6-networking/stls.h> + +#define diecfg(cfg, s) strerr_diefu3x(96, (s), ": ", tls_config_error(cfg)) +#define diectx(e, ctx, s) strerr_diefu3x(e, (s), ": ", tls_error(ctx)) + +int stls_s6tlsc (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity, int *sfd) +{ + int fds[4] = { sfd[0], sfd[1], sfd[0], sfd[1] } ; + struct tls *cctx ; + struct tls *ctx ; + struct tls_config *cfg ; + pid_t pid ; + char const *x ; + + if (tls_init() < 0) strerr_diefu1sys(111, "tls_init") ; + cfg = tls_config_new() ; + if (!cfg) strerr_diefu1sys(111, "tls_config_new") + + x = env_get2(envp, "CADIR") ; + if (x) + { + if (tls_config_set_ca_path(cfg, x) < 0) + diecfg(cfg, "tls_config_set_ca_path") ; + } + else + { + x = env_get2(envp, "CAFILE") ; + if (x) + { + if (tls_config_set_ca_file(cfg, x) < 0) + diecfg(cfg, "tls_config_set_ca_file") ; + } + else strerr_dief1x(100, "no trust anchor found - please set CADIR or CAFILE") ; + } + + if (preoptions & 1) + { + x = env_get2(envp, "CERTFILE") ; + if (!x) strerr_dienotset(100, "CERTFILE") ; + if (tls_config_set_cert_file(cfg, x) < 0) + diecfg(cfg, "tls_config_set_cert_file") ; + + x = env_get2(envp, "KEYFILE") ; + if (!x) strerr_dienotset(100, "KEYFILE") ; + if (tls_config_set_key_file(cfg, x) < 0) + diecfg(cfg, "tls_config_set_cert_file") ; + } + + if (tls_config_set_ciphers(cfg, "secure") < 0) + diecfg(cfg, "tls_config_set_ciphers") ; + + if (tls_config_set_dheparams(cfg, "auto") < 0) + diecfg(cfg, "tls_config_set_dheparams") ; + + if (tls_config_set_ecdhecurve(cfg, "auto") < 0) + diecfg("tls_config_set_ecdhecurve") ; + + tls_config_verify(cfg) ; + tls_config_set_protocols(cfg, TLS_PROTOCOLS_DEFAULT) ; + tls_config_prefer_ciphers_server(cfg) ; + + ctx = tls_client() ; + if (!ctx) strerr_diefu1sys(111, "tls_client") ; + if (tls_configure(ctx, cfg) < 0) diectx(97, ctx, "tls_configure) ; + tls_config_free(cfg) ; + + pid = child_spawn2(argv[0], argv, envp, fds) ; + if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; + if (gid && setgid(gid) < 0) strerr_diefu1sys(111, "setgid") ; + if (uid && setuid(uid) < 0) strerr_diefu1sys(111, "setuid") ; + + if (tls_accept_fds(ctx, &cctx, fds[2], fds[3]) < 0) + diectx(ctx, "tls_accept_fds") ; + + tls_free(ctx) ; + + { + int wstat ; + int r = stls_run(cctx, fds, verbosity, options, tto) ; + if (r < 0) strerr_diefu1sys(111, "run SSL engine") ; + else if (r) diectx(98, cctx, "run SSL engine") ; + if (wait_pid(pid, &wstat) < 0) strerr_diefu1sys(111, "wait_pid") ; + return wait_estatus(wstat) ; + } +} diff --git a/src/stls/stls_s6tlsd.c b/src/stls/stls_s6tlsd.c new file mode 100644 index 0000000..f6d5e7c --- /dev/null +++ b/src/stls/stls_s6tlsd.c @@ -0,0 +1,91 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <tls.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/env.h> +#include <skalibs/djbunix.h> +#include <s6-networking/stls.h> + +#define diecfg(cfg, s) strerr_diefu3x(96, (s), ": ", tls_config_error(cfg)) +#define diectx(e, ctx, s) strerr_diefu3x(e, (s), ": ", tls_error(ctx)) + +int stls_s6tlsd (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity) +{ + int fds[4] = { 0, 1, 0, 1 } ; + struct tls *cctx ; + struct tls *ctx ; + struct tls_config *cfg ; + pid_t pid ; + char const *x ; + + if (tls_init() < 0) strerr_diefu1sys(111, "tls_init") ; + cfg = tls_config_new() ; + if (!cfg) strerr_diefu1sys(111, "tls_config_new") + + x = env_get2(envp, "CAFILE") ; + if (x) + { + if (tls_config_set_ca_file(cfg, x) < 0) + diecfg(cfg, "tls_config_set_ca_file") ; + } + + x = env_get2(envp, "CADIR") ; + if (x) + { + if (tls_config_set_ca_path(cfg, x) < 0) + diecfg(cfg, "tls_config_set_ca_path") ; + } + + x = env_get2(envp, "CERTFILE") ; + if (!x) strerr_dienotset(100, "CERTFILE") ; + if (tls_config_set_cert_file(cfg, x) < 0) + diecfg(cfg, "tls_config_set_cert_file") ; + + x = env_get2(envp, "KEYFILE") ; + if (!x) strerr_dienotset(100, "KEYFILE") ; + if (tls_config_set_key_file(cfg, x) < 0) + diecfg(cfg, "tls_config_set_cert_file") ; + + if (tls_config_set_ciphers(cfg, "secure") < 0) + diecfg(cfg, "tls_config_set_ciphers") ; + + if (tls_config_set_dheparams(cfg, "auto") < 0) + diecfg(cfg, "tls_config_set_dheparams") ; + + if (tls_config_set_ecdhecurve(cfg, "auto") < 0) + diecfg("tls_config_set_ecdhecurve") ; + + if (preoptions & 1) tls_config_verify_client(cfg) ; + else tls_config_verify_client_optional(cfg) ; + + tls_config_set_protocols(cfg, TLS_PROTOCOLS_DEFAULT) ; + tls_config_prefer_ciphers_server(cfg) ; + + ctx = tls_server() ; + if (!ctx) strerr_diefu1sys(111, "tls_server") ; + if (tls_configure(ctx, cfg) < 0) diectx(97, ctx, "tls_configure") ; + tls_config_free(cfg) ; + + pid = child_spawn2(argv[0], argv, envp, fds) ; + if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; + if (gid && setgid(gid) < 0) strerr_diefu1sys(111, "setgid") ; + if (uid && setuid(uid) < 0) strerr_diefu1sys(111, "setuid") ; + + if (tls_accept_fds(ctx, &cctx, fds[2], fds[3]) < 0) + diectx(ctx, "tls_accept_fds") ; + + tls_free(ctx) ; + + { + int wstat ; + int r = stls_run(cctx, fds, verbosity, options, tto) ; + if (r < 0) strerr_diefu1sys(111, "run SSL engine") ; + else if (r) diectx(98, cctx, "run SSL engine") ; + if (wait_pid(pid, &wstat) < 0) strerr_diefu1sys(111, "wait_pid") ; + return wait_estatus(wstat) ; + } +} |