From fae86d2eb50278f2a9917fe6ca5a34595e98546e Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Sun, 25 Oct 2026 16:57:42 -0500 Subject: [PATCH] Fix NX, add constant time compare, add TF_Span --- .gitea/workflows/tag.yaml | 9 +- changelog.md | 3 + cmake/findmbed.cmake | 2 +- cmake/version.cmake | 2 +- include/TessesFramework/Common.hpp | 62 ++++++++ include/TessesFramework/Crypto/Crypto.hpp | 3 + .../TessesFramework/Streams/NetworkStream.hpp | 9 ++ include/TessesFramework/Streams/Stream.hpp | 17 +++ src/Crypto/MbedTLS/ClientTLSStream.cpp | 136 +++++++++++++----- src/Crypto/MbedTLS/Crypto.cpp | 16 +++ 10 files changed, 213 insertions(+), 46 deletions(-) diff --git a/.gitea/workflows/tag.yaml b/.gitea/workflows/tag.yaml index a8ba0f4..e6fcc8a 100644 --- a/.gitea/workflows/tag.yaml +++ b/.gitea/workflows/tag.yaml @@ -11,12 +11,11 @@ env: jobs: build-ppc: name: "🔨 Build for PowerPC" - runs-on: asrock + runs-on: msi-walmart container: image: git.tesses.org/tesses50/linux-ppc:latest steps: - uses: actions/checkout@v4 - url: https://git.tesses.org/tesses50/tessesframework.git - run: bash build-for-ppc.sh - uses: akkuman/gitea-release-action@v1 env: @@ -27,7 +26,7 @@ jobs: artifacts/** update-tap-and-build-win32: name: "🔨 Build win32 and update the tap 🍺" - runs-on: msi-walmart + runs-on: asrock container: git.tesses.org/tesses50/global-containers-mingw:latest steps: - uses: actions/checkout@v4 @@ -73,11 +72,11 @@ jobs: nfpmName: "386" debianName: "i386-linux-gnu" - container: "git.tesses.org/tesses50/linux-arm:latest" - puter: "fw13-ubuntu-latest" + puter: "msi-walmart" nfpmName: "arm7" debianName: "arm-linux-gnueabihf" - container: "git.tesses.org/tesses50/linux-arm64:latest" - puter: "msi-walmart" + puter: "asrock" nfpmName: "arm64" debianName: "aarch64-linux-gnu" - container: "git.tesses.org/tesses50/linux-riscv64:latest" diff --git a/changelog.md b/changelog.md index 9c9f8f3..fa5cd8e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,8 @@ # Changelog +## 0.0.10 +Fix NX, add constant time compare, add TF_Span + ## 0.0.9 Make html parser use case insensitive unordered_map for attributes diff --git a/cmake/findmbed.cmake b/cmake/findmbed.cmake index 54ba365..8c6f508 100644 --- a/cmake/findmbed.cmake +++ b/cmake/findmbed.cmake @@ -11,7 +11,7 @@ endif() FetchContent_Declare( mbedtls - URL https://downloads.tesses.net/cache/libraries/source/mbedtls-3.6.4.tar.bz2 + URL https://downloads.tesses.net/cache/libraries/source/mbedtls-3.6.7.tar.bz2 ) if(NOT mbedtls_POPULATED) diff --git a/cmake/version.cmake b/cmake/version.cmake index f6f5b00..cc2f9ad 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -1,3 +1,3 @@ set(TESSESFRAMEWORK_MAJOR_VERSION 0) set(TESSESFRAMEWORK_MINOR_VERSION 0) -set(TESSESFRAMEWORK_PATCH_VERSION 9) +set(TESSESFRAMEWORK_PATCH_VERSION 10) diff --git a/include/TessesFramework/Common.hpp b/include/TessesFramework/Common.hpp index 21f04f9..4e217fe 100644 --- a/include/TessesFramework/Common.hpp +++ b/include/TessesFramework/Common.hpp @@ -36,8 +36,70 @@ #include #include + + namespace Tesses::Framework { +template +class TF_Span { + public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + constexpr TF_Span(pointer data, size_type size) : data_(data), size_(size) {} + template + constexpr TF_Span(T (&arr)[N]) : data_(arr), size_(N) {} + template + constexpr TF_Span(const Container& container) : data_(container.data()), size_(container.size()) { + static_assert(std::is_same::value,"Container value_type must match Span's type"); + } + reference operator[](size_type index) { + return data_[index]; + } + + const_reference operator[](size_type index) const { + return data_[index]; + } + + const_reference at(size_type index) const { + if (index >= size_) { + throw std::out_of_range("Index out of range"); + } + return data_[index]; + } + + // Data and size + pointer data() noexcept { return data_; } + const_pointer data() const noexcept { return data_; } + + size_type size() const noexcept { return size_; } + bool empty() const noexcept { return size_ == 0; } + + // Iterators + pointer begin() noexcept { return data_; } + pointer end() noexcept { return data_ + size_; } + + const_pointer begin() const noexcept { return data_; } + const_pointer end() const noexcept { return data_ + size_; } + TF_Span subspan(size_type offset, size_type count = static_cast(-1)) const { + if (offset > size_) { + throw std::out_of_range("Offset out of range"); + } + count = (count == static_cast(-1)) ? (size_ - offset) : count; + if (count > size_ - offset) { + throw std::out_of_range("Count exceeds remaining elements"); + } + return TF_Span(data_ + offset, count); + } + + + private: + pointer data_; + size_type size_; +}; class TF_Timer_Handle; // Used for internal purposes, don't use unless you want to run timer events on // another thread diff --git a/include/TessesFramework/Crypto/Crypto.hpp b/include/TessesFramework/Crypto/Crypto.hpp index d40e13f..ff74ba3 100644 --- a/include/TessesFramework/Crypto/Crypto.hpp +++ b/include/TessesFramework/Crypto/Crypto.hpp @@ -316,6 +316,9 @@ typedef enum { */ bool PBKDF2(std::vector &output, std::string pass, std::vector &salt, long itterations, ShaVersion version); + +bool ConstantEquals(const TF_Span left, const TF_Span right); + /** * @brief Get secure random bytes * diff --git a/include/TessesFramework/Streams/NetworkStream.hpp b/include/TessesFramework/Streams/NetworkStream.hpp index e222f30..40163ce 100644 --- a/include/TessesFramework/Streams/NetworkStream.hpp +++ b/include/TessesFramework/Streams/NetworkStream.hpp @@ -80,6 +80,15 @@ class NetworkStream : public Stream { size_t ReadFrom(uint8_t *buff, size_t sz, std::string &ip, uint16_t &port); size_t WriteTo(const uint8_t *buff, size_t sz, std::string ip, uint16_t port); + size_t ReadFrom(TF_Span buff, std::string &ip, uint16_t &port) + { + return ReadFrom(buff.data(),buff.size(),ip, port); + } + size_t WriteTo(const TF_Span buff, std::string ip, + uint16_t port) + { + return WriteTo(buff.data(),buff.size(),ip, port); + } static std::vector> GetIPs(bool ipV6 = false); diff --git a/include/TessesFramework/Streams/Stream.hpp b/include/TessesFramework/Streams/Stream.hpp index 0da4b6e..a85f401 100644 --- a/include/TessesFramework/Streams/Stream.hpp +++ b/include/TessesFramework/Streams/Stream.hpp @@ -35,6 +35,23 @@ class Stream { virtual size_t Write(const uint8_t *buff, size_t sz); size_t ReadBlock(uint8_t *buff, size_t sz); void WriteBlock(const uint8_t *buff, size_t sz); + size_t Read(TF_Span buff) { + return Read(buff.data(), buff.size()); + } + size_t Write(const TF_Span buff) + { + return Write(buff.data(), buff.size()); + } + size_t ReadBlock(TF_Span buff) + { + return ReadBlock(buff.data(), buff.size()); + } + void WriteBlock(const TF_Span buff) + { + WriteBlock(buff.data(),buff.size()); + } + + virtual bool CanRead(); virtual bool CanWrite(); virtual bool CanSeek(); diff --git a/src/Crypto/MbedTLS/ClientTLSStream.cpp b/src/Crypto/MbedTLS/ClientTLSStream.cpp index 8b30292..fcd4e5a 100644 --- a/src/Crypto/MbedTLS/ClientTLSStream.cpp +++ b/src/Crypto/MbedTLS/ClientTLSStream.cpp @@ -35,6 +35,7 @@ using StreamReader = Tesses::Framework::TextStreams::StreamReader; #include #include #include +#include #endif #include using namespace Tesses::Framework::Streams; @@ -56,7 +57,6 @@ class ClientTLSPrivateData { mbedtls_pk_context client_key; ~ClientTLSPrivateData() { - strm->SetSendTimeout((uint64_t)7); mbedtls_ssl_close_notify(&ssl); if (mTLS) { mbedtls_x509_crt_free(&client_cert); @@ -127,15 +127,23 @@ ClientTLSStream::ClientTLSStream( if ((ret = mbedtls_ctr_drbg_seed( &data->ctr_drbg, mbedtls_entropy_func, &data->entropy, (const unsigned char *)pers, strlen(pers))) != 0) { - printf("FAILED mbedtls_ctr_drbg_seed\n"); - return; + + char buffer[100]; + mbedtls_strerror(ret, buffer, sizeof(buffer)); + std::string msg = "mbedtls_ctr_drbg_seed failed: " + std::string(buffer); + delete data; + throw std::runtime_error(msg); } ret = mbedtls_x509_crt_parse( &data->cachain, (const unsigned char *)cert.c_str(), cert.size() + 1); if (ret != 0) { - printf("FAILED mbedtls_x509_crt_parse cert %i\n", ret); - return; + char buffer[100]; + mbedtls_strerror(ret, buffer, sizeof(buffer)); + std::string msg = "mbedtls_x509_crt_parse failed: " + std::string(buffer); + delete data; + throw std::runtime_error(msg); + } if ((ret = mbedtls_ssl_config_defaults(&data->conf, MBEDTLS_SSL_IS_CLIENT, @@ -143,8 +151,9 @@ ClientTLSStream::ClientTLSStream( MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { char buffer[100]; mbedtls_strerror(ret, buffer, sizeof(buffer)); - printf("FAILED mbedtls_ssl_conf_defaults %s\n", buffer); - return; + std::string msg = "mbedtls_ssl_conf_defaults failed: " + std::string(buffer); + delete data; + throw std::runtime_error(msg); } mbedtls_ssl_conf_rng(&data->conf, mbedtls_ctr_drbg_random, &data->ctr_drbg); @@ -161,18 +170,25 @@ ClientTLSStream::ClientTLSStream( mbedtls_ssl_set_bio(&data->ssl, static_cast(data), strm_send, strm_recv, NULL); if ((ret = mbedtls_ssl_setup(&data->ssl, &data->conf) != 0)) { - printf("FAILED mbedtls_ssl_setup %i\n", ret); - return; + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + std::string msg = "SSL setup failed: " + std::string(errbuf); + delete data; + throw std::runtime_error(msg); } if ((ret = mbedtls_ssl_set_hostname(&data->ssl, domain.c_str()) != 0)) { - printf("FAILED mbedtls_ssl_set_hostname %i\n", ret); - return; + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_ssl_set_hostname failed: " + std::string(errbuf)); } if ((ret = mbedtls_ssl_handshake(&data->ssl)) != 0) { - char buffer[100]; - mbedtls_strerror(ret, buffer, sizeof(buffer)); - printf("FAILED mbedtls_ssl_handshake %s\n", buffer); - return; + + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_ssl_handshake failed: " + std::string(errbuf)); + } uint32_t flags; if ((flags = mbedtls_ssl_get_verify_result(&data->ssl)) != 0) { @@ -224,16 +240,20 @@ ClientTLSStream::ClientTLSStream( if ((ret = mbedtls_ctr_drbg_seed( &data->ctr_drbg, mbedtls_entropy_func, &data->entropy, (const unsigned char *)pers, strlen(pers))) != 0) { - printf("FAILED mbedtls_ctr_drbg_seed\n"); - return; + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_ctr_drbg_seed failed: " + std::string(errbuf)); } ret = mbedtls_x509_crt_parse( &data->cachain, (const unsigned char *)cert.c_str(), cert.size() + 1); if (ret != 0) { - printf("FAILED mbedtls_x509_crt_parse chain %i\n", ret); - return; + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_x509_crt_parse chain failed: " + std::string(errbuf)); } ret = mbedtls_x509_crt_parse( @@ -241,30 +261,44 @@ ClientTLSStream::ClientTLSStream( keyStore.certificate.size() + 1); if (ret != 0) { - printf("FAILED mbedtls_x509_crt_parse client_certificate %i\n", ret); - return; + + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_x509_crt_parse client_certificate failed: " + std::string(errbuf)); + } ret = mbedtls_pk_parse_key( - &data->client_key, (const unsigned char *)keyStore.certificate.c_str(), - keyStore.certificate.size() + 1, + &data->client_key, (const unsigned char *)keyStore.key.c_str(), + keyStore.key.size() + 1, keyStore.password.empty() ? NULL : (const unsigned char *)keyStore.password.c_str(), - keyStore.password.size(), mbedtls_entropy_func, &data->entropy); + keyStore.password.size() + 1 + #if MBEDTLS_VERSION_MAJOR == 3 + , mbedtls_entropy_func, &data->entropy + #endif + ); if (ret != 0) { - printf("FAILED mbedtls_x509_crt_parse client_certificate %i\n", ret); - return; + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_pk_parse_key failed: " + std::string(errbuf)); + + } if ((ret = mbedtls_ssl_config_defaults(&data->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { - char buffer[100]; - mbedtls_strerror(ret, buffer, sizeof(buffer)); - printf("FAILED mbedtls_ssl_conf_defaults %s\n", buffer); - return; + + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_ssl_conf_defaults failed: " + std::string(errbuf)); + } mbedtls_ssl_conf_rng(&data->conf, mbedtls_ctr_drbg_random, &data->ctr_drbg); @@ -284,18 +318,26 @@ ClientTLSStream::ClientTLSStream( mbedtls_ssl_set_bio(&data->ssl, static_cast(data), strm_send, strm_recv, NULL); if ((ret = mbedtls_ssl_setup(&data->ssl, &data->conf) != 0)) { - printf("FAILED mbedtls_ssl_setup %i\n", ret); - return; + + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_ssl_setup failed: " + std::string(errbuf)); + } if ((ret = mbedtls_ssl_set_hostname(&data->ssl, domain.c_str()) != 0)) { - printf("FAILED mbedtls_ssl_set_hostname %i\n", ret); - return; + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_ssl_set_hostname failed: " + std::string(errbuf)); } if ((ret = mbedtls_ssl_handshake(&data->ssl)) != 0) { - char buffer[100]; - mbedtls_strerror(ret, buffer, sizeof(buffer)); - printf("FAILED mbedtls_ssl_handshake %s\n", buffer); - return; + + char errbuf[100]; + mbedtls_strerror(ret, errbuf, sizeof(errbuf)); + delete data; + throw std::runtime_error("mbedtls_ssl_handshake failed: " + std::string(errbuf)); + } uint32_t flags; if ((flags = mbedtls_ssl_get_verify_result(&data->ssl)) != 0) { @@ -327,10 +369,16 @@ size_t ClientTLSStream::Read(uint8_t *buffer, size_t len) { return 0; int r = mbedtls_ssl_read(&priv->ssl, buffer, len); - if (r == -30848) { + if (r == 0) { priv->eos = true; return 0; } + if (r < 0) { + char errbuf[100]; + mbedtls_strerror(r, errbuf, sizeof(errbuf)); + std::string msg = "Read failed: " + std::string(errbuf); + throw std::runtime_error(msg); + } return (size_t)r; #else return (size_t)0; @@ -342,6 +390,16 @@ size_t ClientTLSStream::Write(const uint8_t *buffer, size_t len) { if (!priv->success) return 0; int r = mbedtls_ssl_write(&priv->ssl, buffer, len); + if (r == 0) { + priv->eos = true; + return 0; + } + if (r < 0) { + char errbuf[100]; + mbedtls_strerror(r, errbuf, sizeof(errbuf)); + std::string msg = "Write failed: " + std::string(errbuf); + throw std::runtime_error(msg); + } return (size_t)r; #else return (size_t)0; diff --git a/src/Crypto/MbedTLS/Crypto.cpp b/src/Crypto/MbedTLS/Crypto.cpp index 1717175..73ba7e3 100644 --- a/src/Crypto/MbedTLS/Crypto.cpp +++ b/src/Crypto/MbedTLS/Crypto.cpp @@ -377,4 +377,20 @@ bool RandomBytes(std::vector &output, std::string personal_str) { #endif return false; } +bool ConstantEquals(const TF_Span left, const TF_Span right) +{ + if (left.size() != right.size()) return false; + if (left.empty()) return true; + + const auto* pa = left.data(); + const auto* pb = right.data(); + const auto n = left.size(); + + uint8_t diff = 0; + for (size_t i = 0; i < n; i++) + diff |= pa[i] ^ pb[i]; + + return diff == 0; +} + } // namespace Tesses::Framework::Crypto