From ca17b1e4e74b3c428f16777a7a49765882d32e8d Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 2 Sep 2024 15:23:25 +0200 Subject: [PATCH 01/10] redbean: add tls socket lua binding --- tool/net/definitions.lua | 42 ++++++ tool/net/ltls.inc | 293 +++++++++++++++++++++++++++++++++++++++ tool/net/redbean.c | 5 + 3 files changed, 340 insertions(+) create mode 100644 tool/net/ltls.inc diff --git a/tool/net/definitions.lua b/tool/net/definitions.lua index 2424f9241..8d823ebc2 100644 --- a/tool/net/definitions.lua +++ b/tool/net/definitions.lua @@ -4982,6 +4982,48 @@ unix = { X_OK = nil } +---@class TlsContext +---@field connect fun(self: TlsContext, server_name: string, server_port: string): boolean, string? +---@field write fun(self: TlsContext, data: string): integer, string? +---@field read fun(self: TlsContext, bufsiz?: integer): string?, string? +---@field close fun(self: TlsContext) + +---@class tls +local tls = {} + +--- Creates a new TLS socket. +---@param verify? boolean Whether to verify the server's certificate (default: true) +---@param timeout? integer Read timeout in milliseconds (default: 0, no timeout) +---@return TlsContext|nil context +---@return string? error +function tls.socket(verify, timeout) end + +--- Connects to a server using TLS. +---@param context TlsContext +---@param server_name string +---@param server_port string +---@return boolean success +---@return string? error +function tls:connect(server_name, server_port) end + +--- Writes data to the TLS connection. +---@param context TlsContext +---@param data string +---@return integer bytes_written +---@return string? error +function tls:write(data) end + +--- Reads data from the TLS connection. +---@param context TlsContext +---@param bufsiz? integer Maximum number of bytes to read (default: BUFSIZ) +---@return string? data +---@return string? error +function tls:read(bufsiz) end + +--- Closes the TLS connection. +---@param context TlsContext +function tls:close() end + --- Opens file. --- --- Returns a file descriptor integer that needs to be closed, e.g. diff --git a/tool/net/ltls.inc b/tool/net/ltls.inc new file mode 100644 index 000000000..1735c983e --- /dev/null +++ b/tool/net/ltls.inc @@ -0,0 +1,293 @@ +#include "libc/intrin/kprintf.h" +static const char *const tls_meta = ":mbedtls"; + +typedef enum { + TLS_STATE_INIT, + TLS_STATE_CONNECTED, + TLS_STATE_CLOSED +} TlsConnectionState; + +typedef struct { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_net_context server_fd; + int ref; // Reference to self in the Lua registry + TlsConnectionState connection_state; + char *read_buffer; + size_t read_buffer_size; +} TlsContext; + +static TlsContext **checktls(lua_State *L) { + TlsContext **tls = (TlsContext **)luaL_checkudata(L, 1, tls_meta); + if (tls == NULL || *tls == NULL) + luaL_typeerror(L, 1, tls_meta); + return tls; +} + +static int tls_gc(lua_State *L) { + TlsContext **tlsp = checktls(L); + TlsContext *tls = *tlsp; + + if (tls) { + if (tls->connection_state != TLS_STATE_CLOSED) { + mbedtls_net_free(&tls->server_fd); + mbedtls_ssl_free(&tls->ssl); + mbedtls_ssl_config_free(&tls->conf); + mbedtls_ctr_drbg_free(&tls->ctr_drbg); + mbedtls_entropy_free(&tls->entropy); + } + mbedtls_ssl_free(&tls->ssl); + luaL_unref(L, LUA_REGISTRYINDEX, tls->ref); + free(tls->read_buffer); + free(tls); + *tlsp = NULL; + } + return 0; +} + +static int tls_socket(lua_State *L) { + if (!sslinitialized) { + TlsInit(); + } + + TlsContext **tlsp = (TlsContext **)lua_newuserdata(L, sizeof(TlsContext *)); + *tlsp = NULL; + + luaL_getmetatable(L, tls_meta); + lua_setmetatable(L, -2); + + TlsContext *tls = (TlsContext *)malloc(sizeof(TlsContext)); + if (tls == NULL) { + lua_pushnil(L); + lua_pushstring(L, "Failed to allocate memory for TLS context"); + return 2; + } + *tlsp = tls; + + tls->connection_state = TLS_STATE_INIT; + tls->read_buffer = NULL; + tls->read_buffer_size = 0; + + mbedtls_net_init(&tls->server_fd); + mbedtls_ssl_init(&tls->ssl); + mbedtls_ssl_config_init(&tls->conf); + mbedtls_ctr_drbg_init(&tls->ctr_drbg); + mbedtls_entropy_init(&tls->entropy); + int sslVerify = lua_isnone(L, 1) ? 1 : lua_toboolean(L, 1); + if (sslVerify) { + mbedtls_ssl_conf_ca_chain(&tls->conf, GetSslRoots(), 0); + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + } else { + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); + } + + int timeout = lua_isnone(L, 2) ? 0 : luaL_checkinteger(L, 2); + mbedtls_ssl_conf_read_timeout(&tls->conf, timeout); + + const char *pers = "tls_socket"; + int ret; + if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg, mbedtls_entropy_func, + &tls->entropy, (const unsigned char *)pers, + strlen(pers))) != 0) { + free(tls); + *tlsp = NULL; + lua_pushnil(L); + lua_pushfstring(L, "mbedtls_ctr_drbg_seed returned %d", ret); + return 2; + } + + if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { + free(tls); + *tlsp = NULL; + lua_pushnil(L); + lua_pushfstring(L, "mbedtls_ssl_setup returned %d", ret); + return 2; + } + + tls->ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_rawgeti(L, LUA_REGISTRYINDEX, tls->ref); + + return 1; +} + +static void my_debug(void *ctx, int level, const char *file, int line, + const char *str) { + ((void)level); + fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str); + fflush((FILE *)ctx); +} + +static int tls_connect(lua_State *L) { + TlsContext **tlsp = checktls(L); + TlsContext *tls = *tlsp; + const char *server_name = luaL_checkstring(L, 2); + const char *server_port = luaL_checkstring(L, 3); + + int ret; + if ((ret = mbedtls_net_connect(&tls->server_fd, server_name, server_port, + MBEDTLS_NET_PROTO_TCP)) != 0) { + lua_pushnil(L); + lua_pushfstring(L, "connect failed: %d", ret); + return 2; + } + + if ((ret = mbedtls_ssl_config_defaults(&tls->conf, MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + lua_pushnil(L); + lua_pushfstring(L, "mbedtls_ssl_config_defaults failed: %d", ret); + return 2; + } + + // mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); // only for + // test, conf mbedtls_x509_crt_init instead + + mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg); + mbedtls_ssl_conf_dbg(&tls->conf, my_debug, stdout); + + if ((ret = mbedtls_ssl_set_hostname(&tls->ssl, server_name)) != 0) { + lua_pushnil(L); + lua_pushfstring(L, "mbedtls_ssl_set_hostname failed: %d", ret); + return 2; + } + + mbedtls_ssl_set_bio(&tls->ssl, &tls->server_fd, mbedtls_net_send, NULL, + mbedtls_net_recv_timeout); + + if ((ret = mbedtls_ssl_handshake(&tls->ssl)) != 0) { + lua_pushnil(L); + lua_pushfstring(L, "SSL handshake failed: %d", ret); + return 2; + } + + tls->connection_state = TLS_STATE_CONNECTED; + + lua_pushboolean(L, 1); + return 1; +} + +static int tls_write(lua_State *L) { + TlsContext **tlsp = checktls(L); + TlsContext *tls = *tlsp; + size_t len; + const char *data = luaL_checklstring(L, 2, &len); + int ret = mbedtls_ssl_write(&tls->ssl, (const unsigned char *)data, len); + + if (ret < 0) { + lua_pushnil(L); + lua_pushfstring(L, "SSL write failed: %d", ret); + return 2; + } + + lua_pushinteger(L, ret); + return 1; +} + +static int tls_read(lua_State *L) { + TlsContext **tlsp = checktls(L); + TlsContext *tls = *tlsp; + lua_Integer bufsiz = luaL_optinteger(L, 2, BUFSIZ); + bufsiz = MIN(bufsiz, 0x7ffff000); + + if (tls->read_buffer == NULL || tls->read_buffer_size < bufsiz) { + char *new_buffer = realloc(tls->read_buffer, bufsiz); + if (new_buffer == NULL) { + lua_pushnil(L); + lua_pushstring(L, "Memory allocation failed"); + return 2; + } + tls->read_buffer = new_buffer; + tls->read_buffer_size = bufsiz; + } + + int ret = + mbedtls_ssl_read(&tls->ssl, (unsigned char *)tls->read_buffer, bufsiz); + + if (ret > 0) { + lua_pushlstring(L, tls->read_buffer, ret); + return 1; + } else if (ret == 0) { + // End of file + lua_pushnil(L); + return 1; + } else { + lua_pushnil(L); + if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + lua_pushstring(L, "EAGAIN"); + } else { + lua_pushfstring(L, "Read error: %d", ret); + } + return 2; + } +} + +static int tls_close(lua_State *L) { + TlsContext **tlsp = checktls(L); + TlsContext *tls = *tlsp; + + mbedtls_net_free(&tls->server_fd); + mbedtls_ssl_free(&tls->ssl); + mbedtls_ssl_config_free(&tls->conf); + mbedtls_ctr_drbg_free(&tls->ctr_drbg); + mbedtls_entropy_free(&tls->entropy); + free(tls->read_buffer); + tls->read_buffer = NULL; + tls->read_buffer_size = 0; + tls->connection_state = TLS_STATE_CLOSED; + + return 0; +} + +static int tls_tostring(lua_State *L) { + TlsContext **tlsp = checktls(L); + TlsContext *tls = *tlsp; + const char *state_str; + + switch (tls->connection_state) { + case TLS_STATE_INIT: + state_str = "initialized"; + break; + case TLS_STATE_CONNECTED: + state_str = "connected"; + break; + case TLS_STATE_CLOSED: + state_str = "closed"; + break; + default: + state_str = "unknown"; + } + + lua_pushfstring(L, "TLS connection (%p): %s", tls, state_str); + return 1; +} + +static const struct luaL_Reg tls_methods[] = {{"connect", tls_connect}, + {"write", tls_write}, + {"read", tls_read}, + {"close", tls_close}, + {"__gc", tls_gc}, + {"__tostring", tls_tostring}, + {NULL, NULL}}; + +static const struct luaL_Reg tlslib[] = {{"socket", tls_socket}, {NULL, NULL}}; + +static void create_meta(lua_State *L, const char *name, + const luaL_Reg *methods) { + luaL_newmetatable(L, name); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, methods, 0); +} + +LUALIB_API int luaopen_tls(lua_State *L) { + create_meta(L, tls_meta, tls_methods); + + luaL_newlib(L, tlslib); + + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); + + return 1; +} diff --git a/tool/net/redbean.c b/tool/net/redbean.c index eeb2e3116..cf6c02344 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -129,6 +129,7 @@ #include "third_party/mbedtls/ssl_ticket.h" #include "third_party/mbedtls/x509.h" #include "third_party/mbedtls/x509_crt.h" +#include "third_party/mbedtls/entropy.h" #include "third_party/musl/netdb.h" #include "third_party/zlib/zlib.h" #include "tool/build/lib/case.h" @@ -3977,6 +3978,7 @@ static int LuaNilTlsError(lua_State *L, const char *s, int r) { } #include "tool/net/fetch.inc" +#include "tool/net/ltls.inc" static int LuaGetDate(lua_State *L) { lua_pushinteger(L, shared->nowish.tv_sec); @@ -5401,6 +5403,9 @@ static const luaL_Reg kLuaFuncs[] = { static const luaL_Reg kLuaLibs[] = { {"argon2", luaopen_argon2}, // {"lsqlite3", luaopen_lsqlite3}, // +#ifndef UNSECURE + {"tls", luaopen_tls}, // +#endif {"maxmind", LuaMaxmind}, // {"finger", LuaFinger}, // {"path", LuaPath}, // From 168a093508bf7c7a8c5712273ca6d031dcfff7aa Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 14:49:03 +0200 Subject: [PATCH 02/10] [tls socket] rm include kprintf --- tool/net/ltls.inc | 1 - 1 file changed, 1 deletion(-) diff --git a/tool/net/ltls.inc b/tool/net/ltls.inc index 1735c983e..d18e697ea 100644 --- a/tool/net/ltls.inc +++ b/tool/net/ltls.inc @@ -1,4 +1,3 @@ -#include "libc/intrin/kprintf.h" static const char *const tls_meta = ":mbedtls"; typedef enum { From 222cb6ba7307c935df092dfe2cc9e7b3befa2e2f Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 14:52:43 +0200 Subject: [PATCH 03/10] [tls socket] rm non-blocking i/o code --- tool/net/ltls.inc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tool/net/ltls.inc b/tool/net/ltls.inc index d18e697ea..a3b697376 100644 --- a/tool/net/ltls.inc +++ b/tool/net/ltls.inc @@ -212,12 +212,9 @@ static int tls_read(lua_State *L) { lua_pushnil(L); return 1; } else { + // All negative values are treated as errors lua_pushnil(L); - if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { - lua_pushstring(L, "EAGAIN"); - } else { - lua_pushfstring(L, "Read error: %d", ret); - } + lua_pushfstring(L, "Read error: %d", ret); return 2; } } From 66f57f0f3471a0d7d5e683f5d9be786619ff21fa Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 14:54:38 +0200 Subject: [PATCH 04/10] [tls socket] indentation problem --- tool/net/ltls.inc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tool/net/ltls.inc b/tool/net/ltls.inc index a3b697376..ee4add294 100644 --- a/tool/net/ltls.inc +++ b/tool/net/ltls.inc @@ -259,13 +259,15 @@ static int tls_tostring(lua_State *L) { return 1; } -static const struct luaL_Reg tls_methods[] = {{"connect", tls_connect}, - {"write", tls_write}, - {"read", tls_read}, - {"close", tls_close}, - {"__gc", tls_gc}, - {"__tostring", tls_tostring}, - {NULL, NULL}}; +static const struct luaL_Reg tls_methods[] = { + {"connect", tls_connect}, + {"write", tls_write}, + {"read", tls_read}, + {"close", tls_close}, + {"__gc", tls_gc}, + {"__tostring", tls_tostring}, + {NULL, NULL} +}; static const struct luaL_Reg tlslib[] = {{"socket", tls_socket}, {NULL, NULL}}; From 470ee521599150badc55d4b7c7879e0078ab5c8f Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 17:15:26 +0200 Subject: [PATCH 05/10] [tls socket] use tls.TlsClient(fd) --- tool/net/BUILD.mk | 3 +- tool/net/definitions.lua | 3 +- tool/net/{ltls.inc => ltls.c} | 211 +++++++++++++++++++--------------- tool/net/ltls.h | 9 ++ tool/net/redbean.c | 2 +- 5 files changed, 130 insertions(+), 98 deletions(-) rename tool/net/{ltls.inc => ltls.c} (59%) create mode 100644 tool/net/ltls.h diff --git a/tool/net/BUILD.mk b/tool/net/BUILD.mk index 52d55f7ec..7b5bf58d0 100644 --- a/tool/net/BUILD.mk +++ b/tool/net/BUILD.mk @@ -100,7 +100,8 @@ TOOL_NET_REDBEAN_LUA_MODULES = \ o/$(MODE)/tool/net/lmaxmind.o \ o/$(MODE)/tool/net/lsqlite3.o \ o/$(MODE)/tool/net/largon2.o \ - o/$(MODE)/tool/net/launch.o + o/$(MODE)/tool/net/launch.o \ + o/$(MODE)/tool/net/ltls.o o/$(MODE)/tool/net/redbean.dbg: \ $(TOOL_NET_DEPS) \ diff --git a/tool/net/definitions.lua b/tool/net/definitions.lua index 8d823ebc2..13a4fef8c 100644 --- a/tool/net/definitions.lua +++ b/tool/net/definitions.lua @@ -4992,11 +4992,12 @@ unix = { local tls = {} --- Creates a new TLS socket. +---@param fd integer File descriptor of the socket ---@param verify? boolean Whether to verify the server's certificate (default: true) ---@param timeout? integer Read timeout in milliseconds (default: 0, no timeout) ---@return TlsContext|nil context ---@return string? error -function tls.socket(verify, timeout) end +function tls.TlsClient(fd, verify, timeout) end --- Connects to a server using TLS. ---@param context TlsContext diff --git a/tool/net/ltls.inc b/tool/net/ltls.c similarity index 59% rename from tool/net/ltls.inc rename to tool/net/ltls.c index ee4add294..4be0d256e 100644 --- a/tool/net/ltls.inc +++ b/tool/net/ltls.c @@ -1,21 +1,51 @@ -static const char *const tls_meta = ":mbedtls"; +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ltls.h" +#include "libc/calls/struct/iovec.h" +#include "third_party/mbedtls/ctr_drbg.h" +#include "third_party/mbedtls/debug.h" +#include "third_party/mbedtls/iana.h" +#include "third_party/mbedtls/net_sockets.h" +#include "third_party/mbedtls/oid.h" +#include "third_party/mbedtls/san.h" +#include "third_party/mbedtls/ssl.h" +#include "third_party/mbedtls/ssl_ticket.h" +#include "third_party/mbedtls/x509.h" +#include "third_party/mbedtls/x509_crt.h" +#include "third_party/mbedtls/entropy.h" +#include "net/https/https.h" -typedef enum { - TLS_STATE_INIT, - TLS_STATE_CONNECTED, - TLS_STATE_CLOSED -} TlsConnectionState; +#ifndef MIN +#define MIN(a,b) ( (a) < (b) ? (a) :(b) ) +#endif + +static const char *const tls_meta = ":mbedtls"; typedef struct { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; - mbedtls_net_context server_fd; int ref; // Reference to self in the Lua registry - TlsConnectionState connection_state; char *read_buffer; size_t read_buffer_size; + int fd; // File descriptor } TlsContext; static TlsContext **checktls(lua_State *L) { @@ -25,19 +55,53 @@ static TlsContext **checktls(lua_State *L) { return tls; } + +static int TlsSend(void *c, const unsigned char *p, size_t n) { + int rc; + if ((rc = write(*(int *)c, p, n)) == -1) { + perror("TlsSend"); + fprintf(stderr, "TlsSend error: rc=%d, c=%d\n", rc, *(int *)c); + exit(1); + } + return rc; +} + +static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t o) { + int r; + struct iovec v[2]; + static unsigned a, b; + static unsigned char t[4096]; + if (a < b) { + r = MIN(n, b - a); + memcpy(p, t + a, r); + if ((a += r) == b) { + a = b = 0; + } + return r; + } + v[0].iov_base = p; + v[0].iov_len = n; + v[1].iov_base = t; + v[1].iov_len = sizeof(t); + if ((r = readv(*(int *)c, v, 2)) == -1) { + perror("TlsRecv"); + exit(1); + } + if (r > n) { + b = r - n; + } + return MIN(n, r); +} + static int tls_gc(lua_State *L) { TlsContext **tlsp = checktls(L); TlsContext *tls = *tlsp; if (tls) { - if (tls->connection_state != TLS_STATE_CLOSED) { - mbedtls_net_free(&tls->server_fd); - mbedtls_ssl_free(&tls->ssl); - mbedtls_ssl_config_free(&tls->conf); - mbedtls_ctr_drbg_free(&tls->ctr_drbg); - mbedtls_entropy_free(&tls->entropy); - } mbedtls_ssl_free(&tls->ssl); + mbedtls_ssl_config_free(&tls->conf); + mbedtls_ctr_drbg_free(&tls->ctr_drbg); + mbedtls_entropy_free(&tls->entropy); luaL_unref(L, LUA_REGISTRYINDEX, tls->ref); free(tls->read_buffer); free(tls); @@ -46,10 +110,16 @@ static int tls_gc(lua_State *L) { return 0; } -static int tls_socket(lua_State *L) { - if (!sslinitialized) { - TlsInit(); - } +static void my_debug(void *ctx, int level, const char *file, int line, + const char *str) { + ((void)level); + fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str); + fflush((FILE *)ctx); +} +static int tls_client(lua_State *L) { + int fd = luaL_checkinteger(L, 1); + + printf("fd: %d\n", fd); TlsContext **tlsp = (TlsContext **)lua_newuserdata(L, sizeof(TlsContext *)); *tlsp = NULL; @@ -65,16 +135,16 @@ static int tls_socket(lua_State *L) { } *tlsp = tls; - tls->connection_state = TLS_STATE_INIT; tls->read_buffer = NULL; tls->read_buffer_size = 0; + tls->fd = fd; - mbedtls_net_init(&tls->server_fd); mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_config_init(&tls->conf); mbedtls_ctr_drbg_init(&tls->ctr_drbg); mbedtls_entropy_init(&tls->entropy); - int sslVerify = lua_isnone(L, 1) ? 1 : lua_toboolean(L, 1); + + int sslVerify = lua_isnone(L, 2) ? 1 : lua_toboolean(L, 2); if (sslVerify) { mbedtls_ssl_conf_ca_chain(&tls->conf, GetSslRoots(), 0); mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); @@ -82,10 +152,10 @@ static int tls_socket(lua_State *L) { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); } - int timeout = lua_isnone(L, 2) ? 0 : luaL_checkinteger(L, 2); + int timeout = lua_isnone(L, 3) ? 0 : luaL_checkinteger(L, 3); mbedtls_ssl_conf_read_timeout(&tls->conf, timeout); - const char *pers = "tls_socket"; + const char *pers = "tls_client"; int ret; if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg, mbedtls_entropy_func, &tls->entropy, (const unsigned char *)pers, @@ -97,6 +167,19 @@ static int tls_socket(lua_State *L) { return 2; } + if ((ret = mbedtls_ssl_config_defaults(&tls->conf, MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + free(tls); + *tlsp = NULL; + lua_pushnil(L); + lua_pushfstring(L, "mbedtls_ssl_config_defaults failed: %d", ret); + return 2; + } + + mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg); + mbedtls_ssl_conf_dbg(&tls->conf, my_debug, stdout); + if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { free(tls); *tlsp = NULL; @@ -105,55 +188,7 @@ static int tls_socket(lua_State *L) { return 2; } - tls->ref = luaL_ref(L, LUA_REGISTRYINDEX); - lua_rawgeti(L, LUA_REGISTRYINDEX, tls->ref); - - return 1; -} - -static void my_debug(void *ctx, int level, const char *file, int line, - const char *str) { - ((void)level); - fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str); - fflush((FILE *)ctx); -} - -static int tls_connect(lua_State *L) { - TlsContext **tlsp = checktls(L); - TlsContext *tls = *tlsp; - const char *server_name = luaL_checkstring(L, 2); - const char *server_port = luaL_checkstring(L, 3); - - int ret; - if ((ret = mbedtls_net_connect(&tls->server_fd, server_name, server_port, - MBEDTLS_NET_PROTO_TCP)) != 0) { - lua_pushnil(L); - lua_pushfstring(L, "connect failed: %d", ret); - return 2; - } - - if ((ret = mbedtls_ssl_config_defaults(&tls->conf, MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { - lua_pushnil(L); - lua_pushfstring(L, "mbedtls_ssl_config_defaults failed: %d", ret); - return 2; - } - - // mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); // only for - // test, conf mbedtls_x509_crt_init instead - - mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg); - mbedtls_ssl_conf_dbg(&tls->conf, my_debug, stdout); - - if ((ret = mbedtls_ssl_set_hostname(&tls->ssl, server_name)) != 0) { - lua_pushnil(L); - lua_pushfstring(L, "mbedtls_ssl_set_hostname failed: %d", ret); - return 2; - } - - mbedtls_ssl_set_bio(&tls->ssl, &tls->server_fd, mbedtls_net_send, NULL, - mbedtls_net_recv_timeout); + mbedtls_ssl_set_bio(&tls->ssl, &tls->fd, TlsSend, 0, TlsRecv); if ((ret = mbedtls_ssl_handshake(&tls->ssl)) != 0) { lua_pushnil(L); @@ -161,9 +196,9 @@ static int tls_connect(lua_State *L) { return 2; } - tls->connection_state = TLS_STATE_CONNECTED; + tls->ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_rawgeti(L, LUA_REGISTRYINDEX, tls->ref); - lua_pushboolean(L, 1); return 1; } @@ -223,7 +258,6 @@ static int tls_close(lua_State *L) { TlsContext **tlsp = checktls(L); TlsContext *tls = *tlsp; - mbedtls_net_free(&tls->server_fd); mbedtls_ssl_free(&tls->ssl); mbedtls_ssl_config_free(&tls->conf); mbedtls_ctr_drbg_free(&tls->ctr_drbg); @@ -231,7 +265,6 @@ static int tls_close(lua_State *L) { free(tls->read_buffer); tls->read_buffer = NULL; tls->read_buffer_size = 0; - tls->connection_state = TLS_STATE_CLOSED; return 0; } @@ -239,37 +272,25 @@ static int tls_close(lua_State *L) { static int tls_tostring(lua_State *L) { TlsContext **tlsp = checktls(L); TlsContext *tls = *tlsp; - const char *state_str; - switch (tls->connection_state) { - case TLS_STATE_INIT: - state_str = "initialized"; - break; - case TLS_STATE_CONNECTED: - state_str = "connected"; - break; - case TLS_STATE_CLOSED: - state_str = "closed"; - break; - default: - state_str = "unknown"; - } - - lua_pushfstring(L, "TLS connection (%p): %s", tls, state_str); + lua_pushfstring(L, "tls.TlsClient(fd=%d)", tls->fd); return 1; } static const struct luaL_Reg tls_methods[] = { - {"connect", tls_connect}, {"write", tls_write}, {"read", tls_read}, {"close", tls_close}, {"__gc", tls_gc}, {"__tostring", tls_tostring}, + {"__repr", tls_tostring}, {NULL, NULL} }; -static const struct luaL_Reg tlslib[] = {{"socket", tls_socket}, {NULL, NULL}}; +static const struct luaL_Reg tlslib[] = { + {"TlsClient", tls_client}, + {NULL, NULL} +}; static void create_meta(lua_State *L, const char *name, const luaL_Reg *methods) { diff --git a/tool/net/ltls.h b/tool/net/ltls.h new file mode 100644 index 000000000..9bf171d82 --- /dev/null +++ b/tool/net/ltls.h @@ -0,0 +1,9 @@ +#ifndef COSMOPOLITAN_TOOL_NET_LTLS_H_ +#define COSMOPOLITAN_TOOL_NET_LTLS_H_ +#include "third_party/lua/lauxlib.h" +COSMOPOLITAN_C_START_ + +int luaopen_tls(lua_State *); + +COSMOPOLITAN_C_END_ +#endif /* COSMOPOLITAN_TOOL_NET_LTLS_H_ */ diff --git a/tool/net/redbean.c b/tool/net/redbean.c index cf6c02344..1dcfd813d 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -137,6 +137,7 @@ #include "tool/net/lfuncs.h" #include "tool/net/ljson.h" #include "tool/net/lpath.h" +#include "tool/net/ltls.h" #include "tool/net/luacheck.h" #include "tool/net/sandbox.h" @@ -3978,7 +3979,6 @@ static int LuaNilTlsError(lua_State *L, const char *s, int r) { } #include "tool/net/fetch.inc" -#include "tool/net/ltls.inc" static int LuaGetDate(lua_State *L) { lua_pushinteger(L, shared->nowish.tv_sec); From b8fb38d8ff4e6453d740b00fe257af5322cb78d6 Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 17:22:44 +0200 Subject: [PATCH 06/10] [tls socket] update definition --- tool/net/definitions.lua | 14 +------------- tool/net/ltls.c | 16 ---------------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/tool/net/definitions.lua b/tool/net/definitions.lua index 13a4fef8c..e3857b364 100644 --- a/tool/net/definitions.lua +++ b/tool/net/definitions.lua @@ -4991,7 +4991,7 @@ unix = { ---@class tls local tls = {} ---- Creates a new TLS socket. +--- Creates a new TLS client. ---@param fd integer File descriptor of the socket ---@param verify? boolean Whether to verify the server's certificate (default: true) ---@param timeout? integer Read timeout in milliseconds (default: 0, no timeout) @@ -4999,14 +4999,6 @@ local tls = {} ---@return string? error function tls.TlsClient(fd, verify, timeout) end ---- Connects to a server using TLS. ----@param context TlsContext ----@param server_name string ----@param server_port string ----@return boolean success ----@return string? error -function tls:connect(server_name, server_port) end - --- Writes data to the TLS connection. ---@param context TlsContext ---@param data string @@ -5021,10 +5013,6 @@ function tls:write(data) end ---@return string? error function tls:read(bufsiz) end ---- Closes the TLS connection. ----@param context TlsContext -function tls:close() end - --- Opens file. --- --- Returns a file descriptor integer that needs to be closed, e.g. diff --git a/tool/net/ltls.c b/tool/net/ltls.c index 4be0d256e..539e2efbf 100644 --- a/tool/net/ltls.c +++ b/tool/net/ltls.c @@ -254,21 +254,6 @@ static int tls_read(lua_State *L) { } } -static int tls_close(lua_State *L) { - TlsContext **tlsp = checktls(L); - TlsContext *tls = *tlsp; - - mbedtls_ssl_free(&tls->ssl); - mbedtls_ssl_config_free(&tls->conf); - mbedtls_ctr_drbg_free(&tls->ctr_drbg); - mbedtls_entropy_free(&tls->entropy); - free(tls->read_buffer); - tls->read_buffer = NULL; - tls->read_buffer_size = 0; - - return 0; -} - static int tls_tostring(lua_State *L) { TlsContext **tlsp = checktls(L); TlsContext *tls = *tlsp; @@ -280,7 +265,6 @@ static int tls_tostring(lua_State *L) { static const struct luaL_Reg tls_methods[] = { {"write", tls_write}, {"read", tls_read}, - {"close", tls_close}, {"__gc", tls_gc}, {"__tostring", tls_tostring}, {"__repr", tls_tostring}, From f47487a052dd5d228c07e132130ceb2c635f8416 Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 18:28:53 +0200 Subject: [PATCH 07/10] [tls socket] rm import entropy --- tool/net/redbean.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 1dcfd813d..34fa18c47 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -129,7 +129,6 @@ #include "third_party/mbedtls/ssl_ticket.h" #include "third_party/mbedtls/x509.h" #include "third_party/mbedtls/x509_crt.h" -#include "third_party/mbedtls/entropy.h" #include "third_party/musl/netdb.h" #include "third_party/zlib/zlib.h" #include "tool/build/lib/case.h" From 24366615177c565a2c88f4cf40277b2a81924e2e Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 18:29:27 +0200 Subject: [PATCH 08/10] [tls socket] change tls_tostring --- tool/net/ltls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/net/ltls.c b/tool/net/ltls.c index 539e2efbf..972182336 100644 --- a/tool/net/ltls.c +++ b/tool/net/ltls.c @@ -258,7 +258,7 @@ static int tls_tostring(lua_State *L) { TlsContext **tlsp = checktls(L); TlsContext *tls = *tlsp; - lua_pushfstring(L, "tls.TlsClient(fd=%d)", tls->fd); + lua_pushfstring(L, "tls.TlsClient({fd=%d})", tls->fd); return 1; } From 9cb82ea7bc124804bfb8c6c4a265f69bca2917fa Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 18:31:35 +0200 Subject: [PATCH 09/10] [tls socket] rm perror --- tool/net/ltls.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tool/net/ltls.c b/tool/net/ltls.c index 972182336..1218bdd97 100644 --- a/tool/net/ltls.c +++ b/tool/net/ltls.c @@ -55,13 +55,10 @@ static TlsContext **checktls(lua_State *L) { return tls; } - static int TlsSend(void *c, const unsigned char *p, size_t n) { int rc; if ((rc = write(*(int *)c, p, n)) == -1) { - perror("TlsSend"); - fprintf(stderr, "TlsSend error: rc=%d, c=%d\n", rc, *(int *)c); - exit(1); + return -1; // Return error code instead of exiting } return rc; } @@ -84,8 +81,7 @@ static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t o) { v[1].iov_base = t; v[1].iov_len = sizeof(t); if ((r = readv(*(int *)c, v, 2)) == -1) { - perror("TlsRecv"); - exit(1); + return -1; // Return error code instead of exiting } if (r > n) { b = r - n; From 4a144e861ac13b2448e26b91e62aa9dbfa4b706d Mon Sep 17 00:00:00 2001 From: alan crouau Date: Mon, 9 Sep 2024 18:32:43 +0200 Subject: [PATCH 10/10] [tls socket] clang format --- tool/net/ltls.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tool/net/ltls.c b/tool/net/ltls.c index 1218bdd97..6d4af9e10 100644 --- a/tool/net/ltls.c +++ b/tool/net/ltls.c @@ -18,8 +18,10 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "ltls.h" #include "libc/calls/struct/iovec.h" +#include "net/https/https.h" #include "third_party/mbedtls/ctr_drbg.h" #include "third_party/mbedtls/debug.h" +#include "third_party/mbedtls/entropy.h" #include "third_party/mbedtls/iana.h" #include "third_party/mbedtls/net_sockets.h" #include "third_party/mbedtls/oid.h" @@ -28,11 +30,9 @@ #include "third_party/mbedtls/ssl_ticket.h" #include "third_party/mbedtls/x509.h" #include "third_party/mbedtls/x509_crt.h" -#include "third_party/mbedtls/entropy.h" -#include "net/https/https.h" #ifndef MIN -#define MIN(a,b) ( (a) < (b) ? (a) :(b) ) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif static const char *const tls_meta = ":mbedtls";