From 996356832e6c59297be656558738dc25667af94e Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 22 Mar 2023 00:41:21 +0000 Subject: [PATCH] Define TLS API, update HttpClient to support optional TLS. Also added a LibreSSL TLS implementation. Client is verified to work; server has not been tested yet. --- TODO.txt | 6 +- contrib/TlsImplTemplate.c | 46 ++++++++++ src/HttpClient.c | 28 +++++-- src/Tls.c | 62 ++++++++++++++ src/Tls/TlsLibreSSL.c | 172 ++++++++++++++++++++++++++++++++++++++ src/include/Tls.h | 35 ++++++++ 6 files changed, 340 insertions(+), 9 deletions(-) create mode 100644 contrib/TlsImplTemplate.c create mode 100644 src/Tls.c create mode 100644 src/Tls/TlsLibreSSL.c create mode 100644 src/include/Tls.h diff --git a/TODO.txt b/TODO.txt index e65fc03..acaefa7 100644 --- a/TODO.txt +++ b/TODO.txt @@ -16,11 +16,12 @@ Milestone: v0.3.0 [x] Convert all code that deals with I/O [!] Multi-output (proof of concept) [!] Memory streams (proof of concept) - [ ] TLS + [~] TLS [ ] SOCKS [x] Move/convert UtilStreamCopy() [ ] Io man page [ ] Stream man page + [ ] Tls man page [~] HTTP Client API [x] Document HttpParseHeaders() [ ] HttpClient man page @@ -42,6 +43,9 @@ Milestone: v0.3.0 [x] json man page [ ] Update man pages for tp and send-patch +[ ] Proper HTTP request router + - Support regex matching + [ ] Move configuration to database [ ] Initial configuration [ ] If no config, create one-time use registration token that diff --git a/contrib/TlsImplTemplate.c b/contrib/TlsImplTemplate.c new file mode 100644 index 0000000..8df1397 --- /dev/null +++ b/contrib/TlsImplTemplate.c @@ -0,0 +1,46 @@ +/* + * Telodendria TLS Implementation Template File. + * + * This file can serve as a baseline for new TLS implementations. + * Please consult the Tls(3) man page for details. + */ +#include + +#if TLS_IMPL == TLS_TEMPLATE /* Set your TLS_* implementation flag here */ + +/* + * #include statements and any implementation structures + * needed should go here. + */ + +void * +TlsInitClient(int fd, const char *serverName) +{ + return NULL; +} + +void * +TlsInitServer(int fd, const char *crt, const char *key) +{ + return NULL; +} + +ssize_t +TlsRead(void *cookie, void *buf, size_t nBytes) +{ + return -1; +} + +ssize_t +TlsWrite(void *cookie, void *buf, size_t nBytes) +{ + return -1; +} + +int +TlsClose(void *cookie) +{ + return -1; +} + +#endif diff --git a/src/HttpClient.c b/src/HttpClient.c index 50fa155..52b3b6a 100644 --- a/src/HttpClient.c +++ b/src/HttpClient.c @@ -36,12 +36,12 @@ #include #include #include +#include struct HttpClientContext { HashMap *responseHeaders; Stream *stream; - int sd; }; HttpClientContext * @@ -60,6 +60,13 @@ HttpRequest(HttpRequestMethod method, int flags, unsigned short port, char *host return NULL; } +#ifndef TLS_IMPL + if (flags & HTTP_TLS) + { + return NULL; + } +#endif + if (!port) { if (flags & HTTP_TLS) @@ -76,11 +83,6 @@ HttpRequest(HttpRequestMethod method, int flags, unsigned short port, char *host sprintf(serv, "%hu", port); } - /* TODO: Not supported yet */ - if (flags & HTTP_TLS) - { - return NULL; - } context = Malloc(sizeof(HttpClientContext)); if (!context) @@ -127,8 +129,19 @@ HttpRequest(HttpRequestMethod method, int flags, unsigned short port, char *host freeaddrinfo(res0); - context->sd = sd; +#ifdef TLS_IMPL + if (flags & HTTP_TLS) + { + context->stream = TlsClientStream(sd, host); + } + else + { + context->stream = StreamFd(sd); + } +#else context->stream = StreamFd(sd); +#endif + if (!context->stream) { Free(context); @@ -185,7 +198,6 @@ HttpRequestSend(HttpClientContext * context) } StreamFlush(context->stream); - shutdown(context->sd, SHUT_WR); lineLen = UtilGetLine(&line, &lineSize, context->stream); diff --git a/src/Tls.c b/src/Tls.c new file mode 100644 index 0000000..815db62 --- /dev/null +++ b/src/Tls.c @@ -0,0 +1,62 @@ +#include + +#ifdef TLS_IMPL + +#include +#include + +Stream * +TlsClientStream(int fd, const char *serverName) +{ + Io *io; + void *cookie; + IoFunctions funcs; + + cookie = TlsInitClient(fd, serverName); + if (!cookie) + { + return NULL; + } + + funcs.read = TlsRead; + funcs.write = TlsWrite; + funcs.seek = NULL; + funcs.close = TlsClose; + + io = IoCreate(cookie, funcs); + if (!io) + { + return NULL; + } + + return StreamIo(io); +} + +Stream * +TlsServerStream(int fd, const char *crt, const char *key) +{ + Io *io; + void *cookie; + IoFunctions funcs; + + cookie = TlsInitServer(fd, crt, key); + if (!cookie) + { + return NULL; + } + + funcs.read = TlsRead; + funcs.write = TlsWrite; + funcs.seek = NULL; + funcs.close = TlsClose; + + io = IoCreate(cookie, funcs); + if (!io) + { + return NULL; + } + + return StreamIo(io); +} + +#endif diff --git a/src/Tls/TlsLibreSSL.c b/src/Tls/TlsLibreSSL.c new file mode 100644 index 0000000..1ab6112 --- /dev/null +++ b/src/Tls/TlsLibreSSL.c @@ -0,0 +1,172 @@ +#include + +#if TLS_IMPL == TLS_LIBRESSL + +#include +#include /* LibreSSL TLS */ + +typedef struct LibreSSLCookie +{ + int fd; + struct tls *ctx; + struct tls *cctx; + struct tls_config *cfg; +} LibreSSLCookie; + +void * +TlsInitClient(int fd, const char *serverName) +{ + LibreSSLCookie *cookie = Malloc(sizeof(LibreSSLCookie)); + + if (!cookie) + { + return NULL; + } + + cookie->ctx = tls_client(); + cookie->cctx = NULL; + cookie->cfg = tls_config_new(); + cookie->fd = fd; + + + if (!cookie->ctx || !cookie->cfg) + { + goto error; + } + + if (tls_config_set_ca_file(cookie->cfg, tls_default_ca_cert_file()) == -1) + { + goto error; + } + + if (tls_configure(cookie->ctx, cookie->cfg) == -1) + { + goto error; + } + + if (tls_connect_socket(cookie->ctx, fd, serverName) == -1) + { + goto error; + } + + return cookie; + +error: + if (cookie->ctx) + { + tls_free(cookie->ctx); + } + + if (cookie->cfg) + { + tls_config_free(cookie->cfg); + } + + Free(cookie); + + return NULL; +} + +void * +TlsInitServer(int fd, const char *crt, const char *key) +{ + LibreSSLCookie *cookie = Malloc(sizeof(LibreSSLCookie)); + + if (!cookie) + { + return NULL; + } + + cookie->ctx = tls_server(); + cookie->cctx = NULL; + cookie->cfg = tls_config_new(); + cookie->fd = fd; + + if (!cookie->ctx || !cookie->cfg) + { + goto error; + } + + if (tls_config_set_cert_file(cookie->cfg, crt) == -1) + { + goto error; + } + + if (tls_config_set_key_file(cookie->cfg, key) == -1) + { + goto error; + } + + if (tls_configure(cookie->ctx, cookie->cfg) == -1) + { + goto error; + } + + if (tls_accept_socket(cookie->ctx, &cookie->cctx, fd) == -1) + { + goto error; + } + + return cookie; + +error: + if (cookie->ctx) + { + tls_free(cookie->ctx); + } + + if (cookie->cctx) + { + tls_free(cookie->cctx); + } + + if (cookie->cfg) + { + tls_config_free(cookie->cfg); + } + + Free(cookie); + + return NULL; +} + +ssize_t +TlsRead(void *cookie, void *buf, size_t nBytes) +{ + LibreSSLCookie *tls = cookie; + + return tls_read(tls->cctx ? tls->cctx : tls->ctx, buf, nBytes); +} + +ssize_t +TlsWrite(void *cookie, void *buf, size_t nBytes) +{ + LibreSSLCookie *tls = cookie; + + return tls_write(tls->cctx ? tls->cctx : tls->ctx, buf, nBytes); +} + +int +TlsClose(void *cookie) +{ + LibreSSLCookie *tls = cookie; + + int tlsRet = tls_close(tls->cctx ? tls->cctx : tls->ctx); + int sdRet; + + if (tls->cctx) + { + tls_free(tls->cctx); + } + + tls_free(tls->ctx); + tls_config_free(tls->cfg); + + sdRet = close(tls->fd); + + Free(tls); + + return (tlsRet == -1 || sdRet == -1) ? -1 : 0; +} + +#endif diff --git a/src/include/Tls.h b/src/include/Tls.h new file mode 100644 index 0000000..a0aac0b --- /dev/null +++ b/src/include/Tls.h @@ -0,0 +1,35 @@ +#ifndef TELODENDRIA_TLS_H +#define TELODENDRIA_TLS_H + +#define TLS_LIBRESSL 1 +#define TLS_MBEDTLS 2 +#define TLS_OPENSSL 3 + +#include + +extern Stream * +TlsClientStream(int, const char *); + +extern Stream * +TlsServerStream(int, const char *, const char *); + +/* + * These are provided by individual TLS implementations. + */ + +extern void * +TlsInitClient(int, const char *); + +extern void * +TlsInitServer(int, const char *, const char *); + +extern ssize_t +TlsRead(void *, void *, size_t); + +extern ssize_t +TlsWrite(void *, void *, size_t); + +extern int +TlsClose(void *); + +#endif /* TELODENDRIA_TLS_H */