diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2016-11-25 18:16:05 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2016-11-25 18:16:05 +0000 |
commit | 018025f0f36a4847df265c9948dbaf7073ed3245 (patch) | |
tree | 984c9a4bba06ef8abc02d0fbe81a70ec28c6f529 | |
parent | 6421a5e923b0f695047b429e4176bca2873c5189 (diff) | |
download | s6-networking-018025f0f36a4847df265c9948dbaf7073ed3245.tar.xz |
Alpha version of the SSL work.
Doesn't build yet, but I'm scared of losing it, so using git as
storage.
Will fix the stupid bugs now, the tricky bugs later.
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) ; + } +} |