From e19eeb69015899de68c1314e8aca80552e8c5e6d Mon Sep 17 00:00:00 2001 From: PoliEcho Date: Sat, 3 May 2025 16:23:19 +0200 Subject: [PATCH] minor changes --- client/crypt.cpp | 32 +++++++++ client/crypt.h | 1 + client/flow_help.cpp | 70 ++++++++++++++++++++ client/flow_help.h | 9 +++ client/global_vars.h | 9 +++ client/init.cpp | 33 ++++++++++ client/init.h | 5 ++ client/main.cpp | 132 ++++--------------------------------- client/message_control.cpp | 35 ++++++++++ client/message_control.h | 0 client/ssl.cpp | 80 ++++++++++++++++++++++ client/ssl.h | 10 +++ client/tcp.cpp | 65 ++++++++++++++++++ client/tcp.h | 6 ++ client/types.h | 11 ++++ common/color.h | 23 +++++++ relay/main.cpp | 3 +- 17 files changed, 404 insertions(+), 120 deletions(-) create mode 100644 client/crypt.cpp create mode 100644 client/crypt.h create mode 100644 client/flow_help.cpp create mode 100644 client/flow_help.h create mode 100644 client/global_vars.h create mode 100644 client/init.cpp create mode 100644 client/init.h create mode 100644 client/message_control.cpp create mode 100644 client/message_control.h create mode 100644 client/ssl.cpp create mode 100644 client/ssl.h create mode 100644 client/tcp.cpp create mode 100644 client/tcp.h create mode 100644 client/types.h create mode 100644 common/color.h diff --git a/client/crypt.cpp b/client/crypt.cpp new file mode 100644 index 0000000..576dce9 --- /dev/null +++ b/client/crypt.cpp @@ -0,0 +1,32 @@ +#include "../common/color.h" +#include "flow_help.h" +#include +#include +#include + +namespace pupes_message_client_lib { +EVP_PKEY *generate_keypair() { + std::clog << BLUE "[LOG]" RESET << " Generating keypair...\n"; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ML_DSA_87, NULL); + if (!ctx) { + std::cerr << "Failed to create key generation context" << std::endl; + return nullptr; + } + + if (EVP_PKEY_keygen_init(ctx) <= 0) { + std::cerr << "Failed to initialize key generation" << std::endl; + EVP_PKEY_CTX_free(ctx); + return nullptr; + } + + // Generate the key pair + EVP_PKEY *keypair = NULL; + if (EVP_PKEY_keygen(ctx, &keypair) <= 0) { + std::cerr << "Failed to generate key pair" << std::endl; + EVP_PKEY_CTX_free(ctx); + return nullptr; + } + SaveOrGetKeypair(keypair); + return keypair; +} +} // namespace pupes_message_client_lib \ No newline at end of file diff --git a/client/crypt.h b/client/crypt.h new file mode 100644 index 0000000..cd30422 --- /dev/null +++ b/client/crypt.h @@ -0,0 +1 @@ +namespace pupes_message_client_lib {} \ No newline at end of file diff --git a/client/flow_help.cpp b/client/flow_help.cpp new file mode 100644 index 0000000..4d0f186 --- /dev/null +++ b/client/flow_help.cpp @@ -0,0 +1,70 @@ +#include "../common/color.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +# + +namespace pupes_message_client_lib { +void error(std::string msg) { + std::cerr << msg << ": " << strerror(errno) << std::endl; + exit(EXIT_FAILURE); +} + +// TODO: CHANGE THIS TO OS KEYRING +EVP_PKEY *SaveOrGetKeypair(EVP_PKEY *keypair = nullptr) { + + std::string home = std::getenv("HOME"); + if (home.empty()) { + error("HOME environment variable not set.\n"); + } + + std::string savedir_path = home; + savedir_path.append("/.local/share/pupes-message"); + + if (!std::filesystem::exists(savedir_path)) { + if (!std::filesystem::create_directories(savedir_path)) { + error("Failed to create directory: " + savedir_path + "\n"); + } + } + + std::string private_key_file_path = savedir_path + "/private_key.pem"; + + if (keypair != nullptr) { + FILE *private_key_file = fopen(private_key_file_path.c_str(), "wb"); + if (private_key_file == nullptr) { + error("Failed to open private key file for writing.\n"); + } + PEM_write_PrivateKey(private_key_file, keypair, nullptr, nullptr, 0, + nullptr, nullptr); + fclose(private_key_file); + return nullptr; + } else { + FILE *private_key_file = fopen(private_key_file_path.c_str(), "rb"); + if (private_key_file == nullptr) { + if (errno == ENOENT) { + std::clog << BLUE + "[LOG]" RESET + " Private key file not found. Generating a new keypair.\n"; + + return nullptr; + } + error("Failed to open private key file for reading.\n"); + } + + keypair = PEM_read_PrivateKey(private_key_file, nullptr, nullptr, nullptr); + if (keypair == nullptr) { + fclose(private_key_file); + error("Failed to read private key from file.\n"); + } + fclose(private_key_file); + return keypair; + } +} + +} // namespace pupes_message_client_lib \ No newline at end of file diff --git a/client/flow_help.h b/client/flow_help.h new file mode 100644 index 0000000..a460779 --- /dev/null +++ b/client/flow_help.h @@ -0,0 +1,9 @@ +#include +#include +#ifndef FLOW_HELP_H +#define FLOW_HELP_H +namespace pupes_message_client_lib { +void error(std::string msg); +EVP_PKEY *SaveOrGetKeypair(EVP_PKEY *keypair = nullptr); +} // namespace pupes_message_client_lib +#endif \ No newline at end of file diff --git a/client/global_vars.h b/client/global_vars.h new file mode 100644 index 0000000..94c98f6 --- /dev/null +++ b/client/global_vars.h @@ -0,0 +1,9 @@ +#include "types.h" +#include +#ifndef PM_GLOBAL_VARS_H +#define PM_GLOBAL_VARS_H +extern void (*receive_callback)(std::vector, std::string); +extern SSL_CTX *ctx_global; +extern SSL *ssl_global; +extern int sockfd_global; +#endif \ No newline at end of file diff --git a/client/init.cpp b/client/init.cpp new file mode 100644 index 0000000..da7b422 --- /dev/null +++ b/client/init.cpp @@ -0,0 +1,33 @@ +#include "init.h" +#include "global_vars.h" +#include "ssl.h" +#include "tcp.h" +#include "types.h" +#include + +void (*receive_callback)(std::vector, std::string) = nullptr; +SSL_CTX *ctx_global = nullptr; +SSL *ssl_global = nullptr; +int sockfd_global = -1; + +namespace pupes_message_client_lib { + +void init(const char *hostname, const char *port) { + OpenSSL_add_all_algorithms(); + + ctx_global = pupes_message_client_lib::InitTLS(); + + sockfd_global = + pupes_message_client_lib::create_socket_and_connect(hostname, port); + + ssl_global = + pupes_message_client_lib::TLS_handshake(ctx_global, sockfd_global); +} + +void register_receive_callback(void (*callback)(std::vector, + std::string)) { + receive_callback = callback; +} + +void start_message_listener() {} +} // namespace pupes_message_client_lib \ No newline at end of file diff --git a/client/init.h b/client/init.h new file mode 100644 index 0000000..bdef592 --- /dev/null +++ b/client/init.h @@ -0,0 +1,5 @@ +#include "types.h" +#ifndef PM_INIT_H +#define PM_INIT_H +extern void (*receive_callback)(std::vector, std::string); +#endif \ No newline at end of file diff --git a/client/main.cpp b/client/main.cpp index ac45aba..016cdb1 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -1,9 +1,11 @@ #include "../common/defines.h" +#include "flow_help.h" +#include "ssl.h" +#include "tcp.h" #include -#include +#include #include #include -#include #include #include #include @@ -12,131 +14,28 @@ #include #include #include +#include #include #include #include -void error(const char *msg) { - perror(msg); - exit(EXIT_FAILURE); -} - int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(EXIT_FAILURE); } - // Initialize OpenSSL (for OpenSSL 1.1.0+ this is optional as it's automatic) - OPENSSL_init_ssl(0, NULL); + SSL_CTX *ctx = pupes_message_client_lib::InitTLS(); - // Create a TLS 1.3 client context - SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); - if (ctx == NULL) { - ERR_print_errors_fp(stderr); - error("Failed to create SSL_CTX"); - } + int sockfd = + pupes_message_client_lib::create_socket_and_connect(argv[1], argv[2]); - // Set minimum TLS version to 1.3 - if (SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION) != 1) { - SSL_CTX_free(ctx); - ERR_print_errors_fp(stderr); - error("Error setting minimum TLS version"); - } - - // Load CA certificate for server verification - if (SSL_CTX_load_verify_locations(ctx, "certs/mldsa87_root_cert.pem", NULL) != - 1) { - SSL_CTX_free(ctx); - ERR_print_errors_fp(stderr); - error("Error loading CA certificate"); - } - - // Set cipher suite for TLS 1.3 - if (SSL_CTX_set_ciphersuites(ctx, "TLS_AES_256_GCM_SHA384") != 1) { - SSL_CTX_free(ctx); - ERR_print_errors_fp(stderr); - error("Error setting cipher list"); - } - - // Socket creation will be handled in the connection loop - int sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) - error("Socket creation failed"); - - // Set up server address - struct sockaddr_storage serv_addr; - memset(&serv_addr, 0, sizeof(serv_addr)); - - struct addrinfo hints, *res; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // Enable IPv4/IPv6 dual support - hints.ai_socktype = SOCK_STREAM; - - // Resolve hostname and port together - int status = getaddrinfo(argv[1], argv[2], &hints, &res); - if (status != 0) { - std::cerr << "Resolution failed: " << gai_strerror(status) << "\n"; - std::exit(EINVAL); - } - - // Try all addresses until successful connection - struct addrinfo *rp; - for (rp = res; rp != NULL; rp = rp->ai_next) { - sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (sockfd == -1) - continue; - - if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) - break; // Success - - close(sockfd); - sockfd = -1; - } - freeaddrinfo(res); // Free after connection attempts - - if (sockfd == -1) { - std::cerr << "Failed to connect to all resolved addresses\n"; - freeaddrinfo(res); - error("Connection failed"); - } - printf("Connected to %s:%s\n", argv[1], argv[2]); - - // Create an SSL object - SSL *ssl = SSL_new(ctx); - if (ssl == NULL) { - close(sockfd); - SSL_CTX_free(ctx); - ERR_print_errors_fp(stderr); - error("Failed to create SSL object"); - } - - // Associate the socket with SSL - if (SSL_set_fd(ssl, sockfd) != 1) { - SSL_free(ssl); - close(sockfd); - SSL_CTX_free(ctx); - ERR_print_errors_fp(stderr); - error("Failed to set SSL file descriptor"); - } - - // Connect using TLS - int ret = SSL_connect(ssl); - if (ret != 1) { - fprintf(stderr, "TLS handshake failed: %d\n", SSL_get_error(ssl, ret)); - ERR_print_errors_fp(stderr); - SSL_free(ssl); - close(sockfd); - SSL_CTX_free(ctx); - exit(EXIT_FAILURE); - } - - printf("TLS 1.3 handshake successful using %s\n", SSL_get_cipher(ssl)); + SSL *ssl = pupes_message_client_lib::TLS_handshake(ctx, sockfd); // Fork to handle sending and receiving pid_t pid = fork(); if (pid < 0) - error("Fork failed"); + pupes_message_client_lib::error("Fork failed"); if (pid == 0) { // Child process: receive from server char buffer[BUFFER_SIZE]; @@ -146,7 +45,7 @@ int main(int argc, char *argv[]) { bytes_read = SSL_read(ssl, buffer, BUFFER_SIZE); if (bytes_read > 0) { - fwrite(buffer, 1, bytes_read, stdout); + fwrite(buffer, 1, static_cast(bytes_read), stdout); fflush(stdout); memset(buffer, 0, BUFFER_SIZE); } else { @@ -164,7 +63,8 @@ int main(int argc, char *argv[]) { char buffer[BUFFER_SIZE]; int bytes_read; - while ((bytes_read = read(STDIN_FILENO, buffer, BUFFER_SIZE)) > 0) { + while ((bytes_read = static_cast( + read(STDIN_FILENO, buffer, BUFFER_SIZE))) > 0) { if (SSL_write(ssl, buffer, bytes_read) < 0) { fprintf(stderr, "SSL_write error: %d\n", SSL_get_error(ssl, 0)); break; @@ -174,11 +74,7 @@ int main(int argc, char *argv[]) { kill(pid, SIGTERM); // Signal child to terminate } - // Clean up - SSL_shutdown(ssl); - SSL_free(ssl); - close(sockfd); - SSL_CTX_free(ctx); + pupes_message_client_lib::SSLcleanup(ssl, ctx, sockfd); return 0; } diff --git a/client/message_control.cpp b/client/message_control.cpp new file mode 100644 index 0000000..a72eed1 --- /dev/null +++ b/client/message_control.cpp @@ -0,0 +1,35 @@ +#include "../common/defines.h" +#include "global_vars.h" +#include +#include + +using nlohmann::json; + +namespace pupes_message_client_lib { +void message_listener() { + char buffer[BUFFER_SIZE]; + int bytes_read; + + while (1) { + bytes_read = SSL_read(ssl_global, buffer, BUFFER_SIZE); + + if (bytes_read > 0) { + json message = + json::parse(std::string(buffer, static_cast(bytes_read))); + + switch (message["type"].get()) { + case CHALLENGE: { + + break; + } + } + } else { + int err = SSL_get_error(ssl_global, bytes_read); + if (err == SSL_ERROR_WANT_READ) + continue; + else + break; + } + } +} +} // namespace pupes_message_client_lib \ No newline at end of file diff --git a/client/message_control.h b/client/message_control.h new file mode 100644 index 0000000..e69de29 diff --git a/client/ssl.cpp b/client/ssl.cpp new file mode 100644 index 0000000..4c910f2 --- /dev/null +++ b/client/ssl.cpp @@ -0,0 +1,80 @@ +#include "ssl.h" +#include "flow_help.h" +#include +namespace pupes_message_client_lib { + +SSL_CTX *InitTLS() { + OPENSSL_init_ssl(0, NULL); + + // Create a TLS 1.3 client context + SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); + if (ctx == NULL) { + ERR_print_errors_fp(stderr); + error("Failed to create SSL_CTX"); + } + + // Set minimum TLS version to 1.3 + if (SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION) != 1) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + error("Error setting minimum TLS version"); + } + + // Load CA certificate for server verification + if (SSL_CTX_load_verify_locations(ctx, "certs/mldsa87_root_cert.pem", NULL) != + 1) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + error("Error loading CA certificate"); + } + + // Set cipher suite for TLS 1.3 + if (SSL_CTX_set_ciphersuites(ctx, "TLS_AES_256_GCM_SHA384") != 1) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + error("Error setting cipher list"); + } + return ctx; +} + +SSL *TLS_handshake(SSL_CTX *ctx, int sockfd) { + // Create an SSL object + SSL *ssl = SSL_new(ctx); + if (ssl == NULL) { + close(sockfd); + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + error("Failed to create SSL object"); + } + + // Associate the socket with SSL + if (SSL_set_fd(ssl, sockfd) != 1) { + SSL_free(ssl); + close(sockfd); + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + error("Failed to set SSL file descriptor"); + } + + // Connect using TLS + int ret = SSL_connect(ssl); + if (ret != 1) { + fprintf(stderr, "TLS handshake failed: %d\n", SSL_get_error(ssl, ret)); + ERR_print_errors_fp(stderr); + SSL_free(ssl); + close(sockfd); + SSL_CTX_free(ctx); + exit(EXIT_FAILURE); + } + + printf("TLS 1.3 handshake successful using %s\n", SSL_get_cipher(ssl)); + return ssl; +} + +void SSLcleanup(SSL *ssl, SSL_CTX *ctx, int sockfd) { + SSL_shutdown(ssl); + SSL_free(ssl); + close(sockfd); + SSL_CTX_free(ctx); +} +} // namespace pupes_message_client_lib \ No newline at end of file diff --git a/client/ssl.h b/client/ssl.h new file mode 100644 index 0000000..08ff4b2 --- /dev/null +++ b/client/ssl.h @@ -0,0 +1,10 @@ +#include +#include +#ifndef PM_SSL_H +#define PM_SSL_H +namespace pupes_message_client_lib { +SSL_CTX *InitTLS(); +SSL *TLS_handshake(SSL_CTX *ctx, int sockfd); +void SSLcleanup(SSL *ssl, SSL_CTX *ctx, int sockfd); +} // namespace pupes_message_client_lib +#endif \ No newline at end of file diff --git a/client/tcp.cpp b/client/tcp.cpp new file mode 100644 index 0000000..9ae1380 --- /dev/null +++ b/client/tcp.cpp @@ -0,0 +1,65 @@ +#include "flow_help.h" +#include "ssl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pupes_message_client_lib { +int create_socket_and_connect(const char *hostname, const char *port) { + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + error("Socket creation failed"); + + // Set up server address + struct sockaddr_storage serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + + struct addrinfo hints, *res; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // Enable IPv4/IPv6 dual support + hints.ai_socktype = SOCK_STREAM; + + // Resolve hostname and port together + int status = getaddrinfo(hostname, port, &hints, &res); + if (status != 0) { + std::cerr << "Resolution failed: " << gai_strerror(status) << "\n"; + std::exit(EINVAL); + } + + // Try all addresses until successful connection + struct addrinfo *rp; + for (rp = res; rp != NULL; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) + continue; + + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) + break; // Success + + close(sockfd); + sockfd = -1; + } + freeaddrinfo(res); // Free after connection attempts + + if (sockfd == -1) { + std::cerr << "Failed to connect to all resolved addresses\n"; + freeaddrinfo(res); + error("Connection failed"); + } + printf("Connected to %s:%s\n", hostname, port); + return sockfd; +} +} // namespace pupes_message_client_lib \ No newline at end of file diff --git a/client/tcp.h b/client/tcp.h new file mode 100644 index 0000000..f886398 --- /dev/null +++ b/client/tcp.h @@ -0,0 +1,6 @@ +#ifndef PM_TCP_H +#define PM_TCP_H +namespace pupes_message_client_lib { +int create_socket_and_connect(const char *hostname, const char *port); +} +#endif \ No newline at end of file diff --git a/client/types.h b/client/types.h new file mode 100644 index 0000000..5508782 --- /dev/null +++ b/client/types.h @@ -0,0 +1,11 @@ +#include +#include +#include +#include +#ifndef PM_TYPES_H +#define PM_TYPES_H +typedef struct { + std::vector pulic_key; + std::string name; +} user; +#endif diff --git a/common/color.h b/common/color.h new file mode 100644 index 0000000..a424b8d --- /dev/null +++ b/common/color.h @@ -0,0 +1,23 @@ + +// Header guard +#ifndef RESET + +#define RESET "\033[0m" +#define BLACK "\033[30m" /* Black */ +#define RED "\033[31m" /* Red */ +#define GREEN "\033[32m" /* Green */ +#define YELLOW "\033[33m" /* Yellow */ +#define BLUE "\033[34m" /* Blue */ +#define MAGENTA "\033[35m" /* Magenta */ +#define CYAN "\033[36m" /* Cyan */ +#define WHITE "\033[37m" /* White */ +#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */ +#define BOLDRED "\033[1m\033[31m" /* Bold Red */ +#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */ +#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */ +#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */ +#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */ +#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */ +#define BOLDWHITE "\033[1m\033[37m" /* Bold White */ + +#endif \ No newline at end of file diff --git a/relay/main.cpp b/relay/main.cpp index d32381b..84907ee 100644 --- a/relay/main.cpp +++ b/relay/main.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -63,7 +62,7 @@ void handle_client(SSL *ssl, int client_socket) { case MESSAGE: { std::lock_guard lock(clients_mutex); - for (const int &destination_socket : cldata["destinations"]) { + for (const int destination_socket : cldata["destinations"]) { auto it = std::find_if(clients.begin(), clients.end(), [destination_socket](const Client &client) { return client.socket == destination_socket;