summaryrefslogtreecommitdiff
path: root/src/sbearssl
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/sbearssl
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/sbearssl')
-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
33 files changed, 1510 insertions, 0 deletions
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) ;
+}