From c1d59b2c6f0f0498565f7b2ad4b1d25d91430824 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 11:10:52 +0200 Subject: [PATCH] [ADD] Add MbedTLS support --- CHANGELOG.md | 14 ++ configure | 4 + include/Cytoplasm/Tls.h | 1 + src/Sha/Sha1.c | 1 + src/Sha/Sha256.c | 1 + src/Tls/TlsMbedTLS.c | 369 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 390 insertions(+) create mode 100644 src/Tls/TlsMbedTLS.c diff --git a/CHANGELOG.md b/CHANGELOG.md index a646e92..e9c846e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ Cytoplasm. It is intended to be updated with every commit that makes a user-faci change worth reporting in the change log. As such, it changes frequently between releases. Final change log entries are published as [Releases](releases). +## v0.5.0 + +**TO BE WRITTEN** + +### Breaking Changes +- `ShaToHex` now requires what hash was used. + +### New Features +- LMDB support is available with the `--with-lmdb` flag. +- MbedTLS summort is available with the `--with-mbed` flag. Please note that Cytoplasm +programs using it must be used with the `CYTO_TLS_CA` environment defined to map to a +valid CA file, and that the `CYTO_TLS_SEED` flag can be set to use a seedfile, increasing +entropy on systems where it is unavailable. + ## v0.4.1 Cytoplasm is now a C99 library! Upgrading from C89 to C99 makes Cytoplasm more portable diff --git a/configure b/configure index deb186e..ce25874 100755 --- a/configure +++ b/configure @@ -76,6 +76,10 @@ for arg in $SCRIPT_ARGS; do TLS_IMPL="TLS_LIBRESSL" TLS_LIBS="-ltls -lcrypto -lssl" ;; + --with-mbed) + TLS_IMPL="TLS_MBEDTLS" + TLS_LIBS="-lmbedtls" + ;; --disable-tls) TLS_IMPL="" TLS_LIBS="" diff --git a/include/Cytoplasm/Tls.h b/include/Cytoplasm/Tls.h index 047ffbd..dc829e8 100644 --- a/include/Cytoplasm/Tls.h +++ b/include/Cytoplasm/Tls.h @@ -50,6 +50,7 @@ #define TLS_LIBRESSL 2 #define TLS_OPENSSL 3 +#define TLS_MBEDTLS 4 /** * Create a new TLS client stream using the given file descriptor and diff --git a/src/Sha/Sha1.c b/src/Sha/Sha1.c index c4f9db8..43a1742 100644 --- a/src/Sha/Sha1.c +++ b/src/Sha/Sha1.c @@ -29,6 +29,7 @@ #include /* TODO: Verify LibreSSL support later */ +#include #if defined(TLS_IMPL) && (TLS_IMPL == TLS_OPENSSL) #include diff --git a/src/Sha/Sha256.c b/src/Sha/Sha256.c index 0b44b7e..80317cd 100644 --- a/src/Sha/Sha256.c +++ b/src/Sha/Sha256.c @@ -31,6 +31,7 @@ /* TODO: Verify LibreSSL support later */ +#include #if defined(TLS_IMPL) && (TLS_IMPL == TLS_OPENSSL) #include diff --git a/src/Tls/TlsMbedTLS.c b/src/Tls/TlsMbedTLS.c new file mode 100644 index 0000000..a9768b7 --- /dev/null +++ b/src/Tls/TlsMbedTLS.c @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with + * other valuable contributors. See CONTRIBUTORS.txt for the full list. + * + * 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 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. + */ +#include + +#if TLS_IMPL == TLS_MBEDTLS + +#include "mbedtls/net_sockets.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/debug.h" +#include "mbedtls/error.h" + +#include +#include + +#include + +/* + * #include statements and any implementation structures + * needed should go here. + */ +typedef struct MbedCookie { + int fd; + bool serverside; + + mbedtls_net_context serverFD; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctrDrbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_x509_crt cert; + + mbedtls_pk_context serverkey; +} MbedCookie; + +static void my_debug(void *ctx, int level, + const char *file, int line, + const char *str) +{ + ((void) level); + + fprintf((FILE *) ctx, "%s:%04d: %s\n", file, line, str); + fflush((FILE *) ctx); +} + + +void * +TlsInitClient(int fd, const char *serverName) +{ + MbedCookie *cookie; + char *cafile; + char *seed; + int err; + if (!serverName) + { + return NULL; + } + + cookie = Malloc(sizeof(MbedCookie)); + memset(cookie, 0, sizeof(MbedCookie)); + cookie->fd = fd; + cookie->serverside = false; + + /* Initialise MbedTLS */ + mbedtls_net_init(&cookie->serverFD); + mbedtls_ssl_init(&cookie->ssl); + mbedtls_ssl_config_init(&cookie->conf); + mbedtls_x509_crt_init(&cookie->cert); + mbedtls_ctr_drbg_init(&cookie->ctrDrbg); + mbedtls_pk_init(&cookie->serverkey); + + mbedtls_entropy_init(&cookie->entropy); + err = mbedtls_ctr_drbg_seed( + &cookie->ctrDrbg, + mbedtls_entropy_func, + &cookie->entropy, + (const unsigned char *) serverName, strlen(serverName) + ); + if (err != 0) + { + Log(LOG_ERR, "MbedTLS failure on client init: %d", err); + goto error; + } + /* Add a source of entropy if possible(using the CYTO_TLS_SEED env). + * Note that we ignore the error code. */ + seed = getenv("CYTO_TLS_SEED"); + mbedtls_entropy_update_seed_file(&cookie->entropy, seed); + + /* TODO */ + cookie->serverFD.fd = fd; + + err = mbedtls_ssl_config_defaults( + &cookie->conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT + ); + if (err != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on client certs: %s", message); + goto error; + } + + /* Setup key verification */ + cafile = getenv("CYTO_TLS_CA"); + if ((err = mbedtls_x509_crt_parse_file(&cookie->cert, cafile)) != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on client certs: %s", message); + //goto error; + } + mbedtls_ssl_conf_ca_chain(&cookie->conf, &cookie->cert, NULL); + + /* Setup some callbacks */ + mbedtls_ssl_conf_rng( + &cookie->conf, + mbedtls_ctr_drbg_random, + &cookie->ctrDrbg + ); + mbedtls_ssl_conf_dbg(&cookie->conf, my_debug, stdout); + if ((err = mbedtls_ssl_setup(&cookie->ssl, &cookie->conf)) != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on SSL setup: %s", message); + goto error; + } + + /* Setup the servername */ + if ((err = mbedtls_ssl_set_hostname(&cookie->ssl, serverName)) != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on client hostname: %s", message); + goto error; + } + + /* Setup some functions */ + mbedtls_ssl_set_bio( + &cookie->ssl, &cookie->serverFD, + mbedtls_net_send, mbedtls_net_recv, NULL + ); + return cookie; +error: + + mbedtls_net_free(&cookie->serverFD); + mbedtls_ssl_free(&cookie->ssl); + mbedtls_ssl_config_free(&cookie->conf); + mbedtls_ctr_drbg_free(&cookie->ctrDrbg); + mbedtls_entropy_free(&cookie->entropy); + Free(cookie); + return NULL; +} + +void * +TlsInitServer(int fd, const char *crt, const char *key) +{ + MbedCookie *cookie; + char *seed; + int err; + if (!crt || !key) + { + return NULL; + } + + cookie = Malloc(sizeof(MbedCookie)); + memset(cookie, 0, sizeof(MbedCookie)); + cookie->fd = fd; + cookie->serverside = true; + + /* Initialise MbedTLS */ + mbedtls_net_init(&cookie->serverFD); + mbedtls_ssl_init(&cookie->ssl); + mbedtls_ssl_config_init(&cookie->conf); + mbedtls_x509_crt_init(&cookie->cert); + mbedtls_ctr_drbg_init(&cookie->ctrDrbg); + mbedtls_pk_init(&cookie->serverkey); + + mbedtls_entropy_init(&cookie->entropy); + err = mbedtls_ctr_drbg_seed( + &cookie->ctrDrbg, + mbedtls_entropy_func, + &cookie->entropy, + (const unsigned char *) key, strlen(key) + ); + if (err != 0) + { + Log(LOG_ERR, "MbedTLS failure on server init: %d", err); + goto error; + } + /* Add a source of entropy if possible(using the CYTO_TLS_SEED env). + * Note that we ignore the error code. */ + seed = getenv("CYTO_TLS_SEED"); + mbedtls_entropy_update_seed_file(&cookie->entropy, seed); + + /* Setup key verification */ + if ((err = mbedtls_x509_crt_parse_file(&cookie->cert, crt)) != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on server certs: %s", message); + goto error; + } + + if ((err = mbedtls_pk_parse_keyfile(&cookie->serverkey, key, NULL)) != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on server certs: %s", message); + goto error; + } + mbedtls_ssl_conf_ca_chain(&cookie->conf, cookie->cert.next, NULL); + if ((err = mbedtls_ssl_conf_own_cert(&cookie->conf, &cookie->cert, &cookie->serverkey)) != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on server certs: %s", message); + goto error; + } + + /* Setup SSL */ + cookie->serverFD.fd = fd; + err = mbedtls_ssl_config_defaults( + &cookie->conf, + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT + ); + if (err != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on server SSL: %s", message); + goto error; + } + + /* Setup some callbacks */ + mbedtls_ssl_conf_rng( + &cookie->conf, + mbedtls_ctr_drbg_random, + &cookie->ctrDrbg + ); + mbedtls_ssl_conf_dbg(&cookie->conf, my_debug, stdout); + mbedtls_ssl_conf_ca_chain(&cookie->conf, cookie->cert.next, NULL); + if ((err = mbedtls_ssl_setup(&cookie->ssl, &cookie->conf)) != 0) + { + char message[256]; + mbedtls_strerror(err, message, 255); + Log(LOG_ERR, "MbedTLS failure on SSL setup: %s", message); + goto error; + } + + /* Client connexion */ + /* Setup some functions */ + mbedtls_ssl_set_bio( + &cookie->ssl, &cookie->serverFD, + mbedtls_net_send, mbedtls_net_recv, NULL + ); + + /* Handshake the client */ + while ((err = mbedtls_ssl_handshake(&cookie->ssl)) != 0) + { + switch (err) + { + case MBEDTLS_ERR_SSL_WANT_WRITE: + case MBEDTLS_ERR_SSL_WANT_READ: + break; + default: + goto error; + } + } + return cookie; +error: + + mbedtls_net_free(&cookie->serverFD); + mbedtls_ssl_free(&cookie->ssl); + mbedtls_ssl_config_free(&cookie->conf); + mbedtls_ctr_drbg_free(&cookie->ctrDrbg); + mbedtls_entropy_free(&cookie->entropy); + Free(cookie); + return NULL; +} + +ssize_t +TlsRead(void *cookie, void *buf, size_t nBytes) +{ + MbedCookie *cooked = cookie; + int ret; + if (!cookie || !buf) + { + return -1; + } + ret = mbedtls_ssl_read(&cooked->ssl, buf, nBytes); + if (ret <= 0) + { + ret = -1; + } + return ret; +} + +ssize_t +TlsWrite(void *cookie, void *buf, size_t nBytes) +{ + MbedCookie *cooked = cookie; + int ret; + if (!cookie || !buf) + { + return -1; + } + ret = mbedtls_ssl_write(&cooked->ssl, buf, nBytes); + if (ret <= 0) + { + ret = -1; + } + + return ret; +} + +int +TlsClose(void *cookie) +{ + MbedCookie *cooked = cookie; + if (!cookie) + { + return -1; + } + + mbedtls_net_free(&cooked->serverFD); + mbedtls_ssl_free(&cooked->ssl); + mbedtls_ssl_config_free(&cooked->conf); + mbedtls_ctr_drbg_free(&cooked->ctrDrbg); + mbedtls_entropy_free(&cooked->entropy); + mbedtls_x509_crt_free(&cooked->cert); + + if (cooked->serverside) + { + mbedtls_pk_free(&cooked->serverkey); + } + Free(cooked); + return 0; +} + +#endif