summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2016-11-25 18:16:05 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2016-11-25 18:16:05 +0000
commit018025f0f36a4847df265c9948dbaf7073ed3245 (patch)
tree984c9a4bba06ef8abc02d0fbe81a70ec28c6f529 /src
parent6421a5e923b0f695047b429e4176bca2873c5189 (diff)
downloads6-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.
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) ;
+ }
+}