summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/conn-tools/deps-exe/s6-tlsc5
-rw-r--r--src/conn-tools/deps-exe/s6-tlsclient1
-rw-r--r--src/conn-tools/deps-exe/s6-tlsd5
-rw-r--r--src/conn-tools/deps-exe/s6-tlsserver1
-rw-r--r--src/conn-tools/s6-tlsc.c102
-rw-r--r--src/conn-tools/s6-tlsclient.c181
-rw-r--r--src/conn-tools/s6-tlsd.c86
-rw-r--r--src/conn-tools/s6-tlsserver.c241
-rw-r--r--src/include/s6-networking/sbearssl.h202
-rw-r--r--src/include/s6-networking/stls.h23
-rw-r--r--src/sbearssl/deps-lib/sbearssl33
-rw-r--r--src/sbearssl/sbearssl-internal.h23
-rw-r--r--src/sbearssl/sbearssl_append.c12
-rw-r--r--src/sbearssl/sbearssl_cert_from.c13
-rw-r--r--src/sbearssl/sbearssl_cert_readfile.c52
-rw-r--r--src/sbearssl/sbearssl_cert_to.c10
-rw-r--r--src/sbearssl/sbearssl_ec_pkey_from.c14
-rw-r--r--src/sbearssl/sbearssl_ec_pkey_to.c11
-rw-r--r--src/sbearssl/sbearssl_ec_skey_from.c14
-rw-r--r--src/sbearssl/sbearssl_ec_skey_to.c11
-rw-r--r--src/sbearssl/sbearssl_error_str.c361
-rw-r--r--src/sbearssl/sbearssl_isder.c25
-rw-r--r--src/sbearssl/sbearssl_pem_decode_from_buffer.c53
-rw-r--r--src/sbearssl/sbearssl_pem_decode_from_string.c36
-rw-r--r--src/sbearssl/sbearssl_pem_push.c38
-rw-r--r--src/sbearssl/sbearssl_pkey_from.c23
-rw-r--r--src/sbearssl/sbearssl_pkey_to.c22
-rw-r--r--src/sbearssl/sbearssl_rsa_pkey_from.c17
-rw-r--r--src/sbearssl/sbearssl_rsa_pkey_to.c12
-rw-r--r--src/sbearssl/sbearssl_rsa_skey_from.c28
-rw-r--r--src/sbearssl/sbearssl_rsa_skey_to.c19
-rw-r--r--src/sbearssl/sbearssl_run.c186
-rw-r--r--src/sbearssl/sbearssl_s6tlsc.c82
-rw-r--r--src/sbearssl/sbearssl_s6tlsd.c99
-rw-r--r--src/sbearssl/sbearssl_skey_from.c23
-rw-r--r--src/sbearssl/sbearssl_skey_readfile.c71
-rw-r--r--src/sbearssl/sbearssl_skey_to.c22
-rw-r--r--src/sbearssl/sbearssl_ta_cert.c43
-rw-r--r--src/sbearssl/sbearssl_ta_from.c22
-rw-r--r--src/sbearssl/sbearssl_ta_readdir.c61
-rw-r--r--src/sbearssl/sbearssl_ta_readfile.c16
-rw-r--r--src/sbearssl/sbearssl_ta_readfile_internal.c46
-rw-r--r--src/sbearssl/sbearssl_ta_to.c12
-rw-r--r--src/stls/deps-lib/stls5
-rw-r--r--src/stls/stls_run.c274
-rw-r--r--src/stls/stls_s6tlsc.c95
-rw-r--r--src/stls/stls_s6tlsd.c91
47 files changed, 2822 insertions, 0 deletions
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) ;
+ }
+}