Skip to content

Commit

Permalink
Bring test coverage back to decent levels
Browse files Browse the repository at this point in the history
  • Loading branch information
0xg0nz0 committed Apr 2, 2024
1 parent e16efa6 commit 23e9601
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ find_package(unofficial-sodium CONFIG REQUIRED)
# these do not correctly support CMake
find_path(ADA_INCLUDE_DIR ada.h REQUIRED)
find_path(SODIUM_INCLUDE_DIR sodium.h REQUIRED)
find_path(UTF8H_INCLUDE_DIRS "utf8h/utf8.h")

# customize the builds of key networking components; WolfSSL is not
# well supported in vcpkg and we want to have more control here
Expand Down Expand Up @@ -89,6 +90,7 @@ target_include_directories(iggy PRIVATE
${NGHTTP3_INCLUDE_DIR}
${NGTCP2_INCLUDE_DIR}
${CURL_INCLUDE_DIR}
${UTF8H_INCLUDE_DIRS}
)
add_dependencies(iggy curl wolfssl)
target_link_libraries(
Expand Down
13 changes: 11 additions & 2 deletions sdk/net/crypto/ssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,17 @@ iggy::ssl::SSLContext::SSLContext(const SSLOptions& options, const PKIEnvironmen
// before we make any other wolfSSL calls, make sure library is initialized once and only once
std::call_once(sslInitDone, []() { wolfSSL_Init(); });

// for now we only support a TLS 1.3 client context; if we generalize this code we can expand
this->ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
auto protocolVersion = options.getMinimumSupportedProtocolVersion();
if (protocolVersion == iggy::ssl::ProtocolVersion::TLSV1_2) {
this->ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
wolfSSL_CTX_set_min_proto_version(this->ctx, TLS1_2_VERSION);
} else if (protocolVersion == iggy::ssl::ProtocolVersion::TLSV1_3) {
this->ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
wolfSSL_CTX_set_min_proto_version(this->ctx, TLS1_3_VERSION);
} else {
auto protocolVersionName = iggy::ssl::getProtocolVersionName(protocolVersion);
throw std::runtime_error(fmt::format("Unsupported protocol version: {}", protocolVersionName));
}
if (!this->ctx) {
char* errMsg = wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr);
throw std::runtime_error(fmt::format("Failed to allocate WolfSSL TLS context: {}", errMsg));
Expand Down
25 changes: 14 additions & 11 deletions sdk/serialization.cc
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
#include "serialization.h"
#include <unicode/ucnv.h>
#include <fmt/format.h>
#include <utf8h/utf8.h>
#include <stdexcept>

std::string iggy::serialization::WireFormat::convertToUTF8(const std::string& source) {
UErrorCode status = U_ZERO_ERROR;
char target[256];

// Convert the string to UTF-8
ucnv_convert("UTF-8", "UTF-16", target, sizeof(target), source.c_str(), source.length(), &status);
if (U_FAILURE(status)) {
throw std::runtime_error("Failed to convert string to UTF-8");
std::string iggy::serialization::convertToUTF8(const std::string& source, bool strict) {
if (utf8valid(source.c_str()) == 0) {
return source;
} else {
if (strict) {
throw std::invalid_argument(fmt::format("The input string is not a valid UTF-8 string: '{}'", source));
} else {
char* data = new char[source.size() + 1];
std::snprintf(data, source.size() + 1, "%s", source.c_str());
utf8makevalid(data, '?');
return std::string(data);
}
}

return std::string(target);
}
6 changes: 3 additions & 3 deletions sdk/serialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

namespace iggy {
namespace serialization {
class WireFormat {
private:
std::string convertToUTF8(const std::string& source);

std::string convertToUTF8(const std::string& source, bool strict = true);

class WireFormat {
public:
virtual ~WireFormat() = 0;

Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ if(BUILD_TESTS)
crypto_test.cc
iggy_protocol_provider_test.cc
model_test.cc
serialization_test.cc
ssl_test.cc
unit_testutils.cc
)
Expand Down
16 changes: 16 additions & 0 deletions tests/serialization_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "../sdk/serialization.h"
#include "unit_testutils.h"

TEST_CASE("serialization utilities", UT_TAG) {
SECTION("valid UTF-8") {
auto utf8 = iggy::serialization::convertToUTF8("hello world");
REQUIRE(utf8 == "hello world");
}
SECTION("invalid UTF-8, strict checking") {
REQUIRE_THROWS_AS(iggy::serialization::convertToUTF8("hello \x80 world", true), std::invalid_argument);
}
SECTION("invalid UTF-8, non-strict checking") {
auto utf8 = iggy::serialization::convertToUTF8("hello \x80 world", false);
REQUIRE(utf8 == "hello ? world");
}
}
66 changes: 66 additions & 0 deletions tests/ssl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,69 @@ TEST_CASE("SSL configuration", UT_TAG) {
REQUIRE_NOTHROW(options.validate(true));
}
}

TEST_CASE_METHOD(iggy::testutil::SelfSignedCertificate, "SSL context init", UT_TAG) {
auto certPath = getCertificatePath().filename();
auto keyPath = getKeyPath().filename();

auto ca = iggy::crypto::CertificateAuthority();
auto certStore = iggy::crypto::LocalCertificateStore(std::filesystem::temp_directory_path());
auto keyStore = iggy::crypto::LocalKeyStore(std::filesystem::temp_directory_path());

auto options = iggy::ssl::SSLOptions();
options.setPeerCertificatePath(certPath);

iggy::ssl::PKIEnvironment pkiEnv(ca, certStore, keyStore);

SECTION("TLS 1.2") {
options.setMinimumSupportedProtocolVersion(iggy::ssl::ProtocolVersion::TLSV1_2);
auto sslCtx = iggy::ssl::SSLContext(options, pkiEnv);

REQUIRE(sslCtx.getNativeHandle() != nullptr);

WOLFSSL_CTX* handle = static_cast<WOLFSSL_CTX*>(sslCtx.getNativeHandle());
REQUIRE(wolfSSL_CTX_get_min_proto_version(handle) == TLS1_2_VERSION);
REQUIRE(wolfSSL_CTX_get_max_proto_version(handle) == TLS1_3_VERSION);

// test copy and move constructors
auto sslCtxNew = sslCtx;
REQUIRE(sslCtx.getNativeHandle() != sslCtxNew.getNativeHandle());

auto sslCtxMoved = std::move(sslCtxNew);
REQUIRE(sslCtxNew.getNativeHandle() == nullptr);
REQUIRE(sslCtxMoved.getNativeHandle() != nullptr);

// test copy and move operators
sslCtxNew = sslCtxMoved;
REQUIRE(sslCtx.getNativeHandle() != sslCtxNew.getNativeHandle());

iggy::ssl::SSLContext sslCtxNew2;
sslCtxNew2 = std::move(sslCtx);
}

SECTION("TLS 1.3") {
options.setMinimumSupportedProtocolVersion(iggy::ssl::ProtocolVersion::TLSV1_3);
auto sslCtx = iggy::ssl::SSLContext(options, pkiEnv);
REQUIRE(sslCtx.getNativeHandle() != nullptr);

WOLFSSL_CTX* handle = static_cast<WOLFSSL_CTX*>(sslCtx.getNativeHandle());
REQUIRE(wolfSSL_CTX_get_min_proto_version(handle) == TLS1_3_VERSION);
REQUIRE(wolfSSL_CTX_get_max_proto_version(handle) == TLS1_3_VERSION);

auto sslCtxNew = sslCtx;
auto sslCtxMoved = std::move(sslCtxNew);
REQUIRE(sslCtxNew.getNativeHandle() == nullptr);
REQUIRE(sslCtxMoved.getNativeHandle() != nullptr);
}
}

TEST_CASE("error message conversion", UT_TAG) {
SECTION("TLS 1.2") {
auto displayName = iggy::ssl::getProtocolVersionName(iggy::ssl::ProtocolVersion::TLSV1_2);
REQUIRE(displayName == "TLSV1_2");
}
SECTION("TLS 1.3") {
auto displayName = iggy::ssl::getProtocolVersionName(iggy::ssl::ProtocolVersion::TLSV1_3);
REQUIRE(displayName == "TLSV1_3");
}
}
2 changes: 1 addition & 1 deletion vcpkg-configuration.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"default-registry": {
"kind": "git",
"baseline": "fba75d09065fcc76a25dcf386b1d00d33f5175af",
"baseline": "a164ace504d8fe6f50aeec7e235d22b9089ad0d5",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
Expand Down
4 changes: 2 additions & 2 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"dependencies": [
"ada-url",
"catch2",
"icu",
"fmt",
"libsodium",
"libuv",
"reproc",
"spdlog"
"spdlog",
"utf8h"
]
}

0 comments on commit 23e9601

Please sign in to comment.