From 3b73f82938464b75d12e9f76dacf6b19a27ae886 Mon Sep 17 00:00:00 2001 From: PoliEcho Date: Fri, 2 May 2025 13:24:10 +0200 Subject: [PATCH] init --- .gitignore | 6 ++ Makefile | 58 ++++++++++++ client/main.cpp | 155 ++++++++++++++++++++++++++++++++ common/defines.h | 1 + misc/certgen.sh | 64 +++++++++++++ relay/main.cpp | 227 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 511 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 client/main.cpp create mode 100644 common/defines.h create mode 100644 misc/certgen.sh create mode 100644 relay/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52b6533 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +certs +build +.cache +.vscode +compile_commands.json +test.c \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3732ada --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +# Compiler and flags +CPPC = g++ +CPPC_FLAGS = -std=c++23 -s -O3 -Wall -Wextra -Wno-write-strings -lssl -lcrypto -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough -Werror=format-security -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -fstrict-flex-arrays=3 -fstack-clash-protection -fstack-protector-strong -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -fPIE -pie -fcf-protection=full -fstack-protector -fstack-protector-all -fstack-protector-strong +DEBUG_FLAGS = -ggdb -std=c++23 -Wall -Wextra -Wno-write-strings -lssl -lcrypto -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough -Werror=format-security -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -fstrict-flex-arrays=3 -fstack-clash-protection -fstack-protector-strong -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -fPIE -pie -fcf-protection=full -fstack-protector -fstack-protector-all -fstack-protector-strong +DEBUG_ASANITIZE = -fsanitize=address -ggdb -fno-omit-frame-pointer -std=c++23 -Wall -Wextra -Wno-write-strings -lssl -lcrypto -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough -Werror=format-security -D_FORTIFY_SOURCE=5 -D_GLIBCXX_ASSERTIONS -fstrict-flex-arrays=3 -fstack-clash-protection -fstack-protector-strong -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -fPIE -pie -fcf-protection=full -fstack-protector -fstack-protector-all -fstack-protector-strong + + +SRC_PATH_CLIENT := client +SRC_PATH_RELAY := relay +OBJ_PATH_CLIENT := build/obj/client +OBJ_PATH_RELAY := build/obj/relay +OBJ_PATH := build/obj +BIN_PATH := build/bin + + +SRC_FILES_CLIENT := $(shell find $(SRC_PATH_CLIENT) -name '*.cpp') +OBJ_FILES_CLIENT := $(patsubst $(SRC_PATH_CLIENT)/%.cpp,$(OBJ_PATH_CLIENT)/%.o,$(SRC_FILES_CLIENT)) + +SRC_FILES_RELAY := $(shell find $(SRC_PATH_RELAY) -name '*.cpp') +OBJ_FILES_RELAY := $(patsubst $(SRC_PATH_RELAY)/%.cpp,$(OBJ_PATH_RELAY)/%.o,$(SRC_FILES_RELAY)) + +all: make-build-dir $(BIN_PATH)/pupes-message $(BIN_PATH)/pupes-message-relay + + +debug: CPPC_FLAGS = $(DEBUG_FLAGS) +debug: make-build-dir $(BIN_PATH)/pupes-message $(BIN_PATH)/pupes-message-relay + +asan: CPPC_FLAGS = $(DEBUG_ASANITIZE) +asan: make-build-dir $(BIN_PATH)/pupes-message $(BIN_PATH)/pupes-message-relay + + +make-build-dir: + mkdir -p $(OBJ_PATH_CLIENT) + mkdir -p $(OBJ_PATH_RELAY) + mkdir -p $(BIN_PATH) + + +$(BIN_PATH)/pupes-message: $(OBJ_FILES_CLIENT) + $(CPPC) $(CPPC_FLAGS) $^ -o $@ + +$(BIN_PATH)/pupes-message-relay: $(OBJ_FILES_RELAY) + $(CPPC) $(CPPC_FLAGS) $^ -o $@ + + +$(OBJ_PATH_CLIENT)/%.o: $(SRC_PATH_CLIENT)/%.cpp + $(CPPC) $(CPPC_FLAGS) -c $< -o $@ + +$(OBJ_PATH_RELAY)/%.o: $(SRC_PATH_RELAY)/%.cpp + $(CPPC) $(CPPC_FLAGS) -c $< -o $@ + + +install: + @install -vpm 755 -o root -g root $(BIN_PATH)/pupes-message /usr/bin/ + +clean: + rm -fr build + +.PHONY: all clean install debug asan diff --git a/client/main.cpp b/client/main.cpp new file mode 100644 index 0000000..efaea0a --- /dev/null +++ b/client/main.cpp @@ -0,0 +1,155 @@ +#include "../common/defines.h" +#include +#include +#include +#include +#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); + + // 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"); + } + + // Create a TCP socket + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + error("Socket creation failed"); + + // Set up server address + struct sockaddr_in serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(atoi(argv[2])); + if (inet_pton(AF_INET, argv[1], &serv_addr.sin_addr) <= 0) + error("Invalid address/address not supported"); + + // Connect to server + if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + 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)); + + // Fork to handle sending and receiving + pid_t pid = fork(); + if (pid < 0) + error("Fork failed"); + + if (pid == 0) { // Child process: receive from server + char buffer[BUFFER_SIZE]; + int bytes_read; + + while (1) { + bytes_read = SSL_read(ssl, buffer, BUFFER_SIZE); + + if (bytes_read > 0) { + fwrite(buffer, 1, bytes_read, stdout); + fflush(stdout); + memset(buffer, 0, BUFFER_SIZE); + } else { + int err = SSL_get_error(ssl, bytes_read); + if (err == SSL_ERROR_WANT_READ) + continue; + else + break; + } + } + + kill(getppid(), SIGTERM); // Signal parent to terminate + exit(0); + } else { // Parent process: send to server + char buffer[BUFFER_SIZE]; + int bytes_read; + + while ((bytes_read = 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; + } + } + + kill(pid, SIGTERM); // Signal child to terminate + } + + // Clean up + SSL_shutdown(ssl); + SSL_free(ssl); + close(sockfd); + SSL_CTX_free(ctx); + + return 0; +} diff --git a/common/defines.h b/common/defines.h new file mode 100644 index 0000000..954fd97 --- /dev/null +++ b/common/defines.h @@ -0,0 +1 @@ +#define BUFFER_SIZE 1024 \ No newline at end of file diff --git a/misc/certgen.sh b/misc/certgen.sh new file mode 100644 index 0000000..9c26420 --- /dev/null +++ b/misc/certgen.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Script to generate ML-DSA-87 certificates for wolfSSL +# Creates both root CA and entity certificates using ML-DSA-87 + +set -e # Exit on any error + +# Create certificates directory if it doesn't exist +mkdir -p certs + +echo "==== Generating ML-DSA-87 Root CA ====" + +# Generate the root private key +openssl genpkey -algorithm mldsa87 -out certs/mldsa87_root_key.pem +echo "Root private key generated." + +# Generate self-signed root certificate +openssl req -new -x509 -key certs/mldsa87_root_key.pem -out certs/mldsa87_root_cert.pem \ + -days 3650 -subj "/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Development/CN=www.wolfssl.com" \ + -addext "basicConstraints=critical,CA:true" \ + -addext "keyUsage=critical,keyCertSign,cRLSign" +echo "Root certificate generated." + +echo "==== Generating ML-DSA-87 Entity Certificate ====" + +# Generate entity private key +openssl genpkey -algorithm mldsa87 -out certs/mldsa87_entity_key.pem +echo "Entity private key generated." + +# Generate certificate request +openssl req -new -key certs/mldsa87_entity_key.pem -out certs/mldsa87_entity.csr \ + -subj "/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Development/CN=www.wolfssl.com" +echo "Entity certificate request generated." + +# Create an extension file for the certificate +cat > certs/mldsa87_entity_extfile.cnf << EOF +basicConstraints=CA:FALSE +keyUsage=digitalSignature,keyEncipherment +extendedKeyUsage=serverAuth,clientAuth +EOF + +# Sign the certificate with the root CA +openssl x509 -req -in certs/mldsa87_entity.csr -out certs/mldsa87_entity_cert.pem \ + -CA certs/mldsa87_root_cert.pem -CAkey certs/mldsa87_root_key.pem \ + -CAcreateserial -days 3650 \ + -extfile certs/mldsa87_entity_extfile.cnf +echo "Entity certificate generated." + +# Clean up temporary files +rm -f certs/mldsa87_entity.csr certs/mldsa87_entity_extfile.cnf certs/mldsa87_root_cert.srl + +echo "==== Certificate Verification ====" +# Verify entity certificate against root +openssl verify -CAfile certs/mldsa87_root_cert.pem certs/mldsa87_entity_cert.pem +echo "Verification completed." + +echo "==== Certificate Generation Complete ====" +echo "Files generated:" +ls -la certs/ + +echo "==== Instructions for Use with wolfSSL ====" +echo "In your wolfSSL code, use the following file paths:" +echo " Root CA: certs/mldsa87_root_cert.pem" +echo " Entity Certificate: certs/mldsa87_entity_cert.pem" +echo " Entity Private Key: certs/mldsa87_entity_key.pem" diff --git a/relay/main.cpp b/relay/main.cpp new file mode 100644 index 0000000..fd04dc5 --- /dev/null +++ b/relay/main.cpp @@ -0,0 +1,227 @@ +#include "../common/defines.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define PORT 9009 + +struct Client { + SSL *ssl; + int socket; +}; + +std::vector clients; +std::mutex clients_mutex; + +void handle_client(SSL *ssl, int client_socket) { + char buffer[BUFFER_SIZE]; + + while (true) { + // Read data securely using OpenSSL + int bytes_read = SSL_read(ssl, buffer, sizeof(buffer)); + if (bytes_read <= 0) { + // Check for OpenSSL specific errors + int err = SSL_get_error(ssl, bytes_read); + if (err == SSL_ERROR_WANT_READ) + continue; + break; // Client disconnected or error occurred + } + + // Broadcast to all other clients + std::lock_guard lock(clients_mutex); + for (const auto &client : clients) { + if (client.socket != client_socket) { + // Send data securely using OpenSSL + SSL_write(client.ssl, buffer, bytes_read); + } + } + } + + // Clean up when client disconnects + std::lock_guard lock(clients_mutex); + clients.erase(std::remove_if(clients.begin(), clients.end(), + [client_socket](const Client &c) { + return c.socket == client_socket; + }), + clients.end()); + + // Free OpenSSL resources + SSL_free(ssl); + close(client_socket); +} + +int main() { + // Initialize OpenSSL + SSL_library_init(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + + // Create a TLS 1.3 server context + SSL_CTX *ctx = SSL_CTX_new(TLS_server_method()); + if (ctx == NULL) { + std::cerr << "Failed to create SSL_CTX" << std::endl; + ERR_print_errors_fp(stderr); + return 1; + } + + // Set min/max protocol to TLS 1.3 + SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); + + // Load ML-DSA post-quantum certificates and keys + if (SSL_CTX_use_certificate_file(ctx, "certs/mldsa87_entity_cert.pem", + SSL_FILETYPE_PEM) != 1) { + std::cerr << "Error loading certificate file" << std::endl; + ERR_print_errors_fp(stderr); + + std::ifstream file("certs/mldsa87_entity_cert.pem"); + if (file) { + std::cout << "Certificate file exists and is readable" << std::endl; + } else { + std::cout << "Cannot access certificate file" << std::endl; + } + + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + if (SSL_CTX_use_PrivateKey_file(ctx, "certs/mldsa87_entity_key.pem", + SSL_FILETYPE_PEM) != 1) { + std::cerr << "Error loading private key file" << std::endl; + ERR_print_errors_fp(stderr); + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + // Load CA certificate for client verification + if (SSL_CTX_load_verify_locations(ctx, "certs/mldsa87_root_cert.pem", NULL) != + 1) { + std::cerr << "Error loading CA certificate" << std::endl; + ERR_print_errors_fp(stderr); + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + // Configure TLS 1.3 cipher suites + if (SSL_CTX_set_ciphersuites(ctx, "TLS_AES_256_GCM_SHA384") != 1) { + std::cerr << "Error setting cipher suites" << std::endl; + ERR_print_errors_fp(stderr); + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + // Create a TCP socket + int server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd < 0) { + std::cerr << "Socket creation failed" << std::endl; + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + // Set socket options + int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + std::cerr << "setsockopt failed" << std::endl; + close(server_fd); + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + // Bind socket to port + sockaddr_in address{}; + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(PORT); + if (bind(server_fd, (sockaddr *)&address, sizeof(address)) < 0) { + std::cerr << "Bind failed" << std::endl; + close(server_fd); + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + // Listen for connections + if (listen(server_fd, 5) < 0) { + std::cerr << "Listen failed" << std::endl; + close(server_fd); + SSL_CTX_free(ctx); + EVP_cleanup(); + return 1; + } + + std::cout << "Secure server started on port " << PORT << std::endl; + std::cout << "Using TLS 1.3 with post-quantum cryptography" << std::endl; + + // Accept and handle client connections + while (true) { + sockaddr_in client_addr{}; + socklen_t client_len = sizeof(client_addr); + int client_socket = + accept(server_fd, (sockaddr *)&client_addr, &client_len); + + if (client_socket < 0) { + std::cerr << "Accept failed" << std::endl; + continue; + } + + char client_ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN); + std::cout << "New connection from " << client_ip << std::endl; + + // Create a new SSL object for this connection + SSL *ssl = SSL_new(ctx); + if (ssl == NULL) { + std::cerr << "SSL_new failed" << std::endl; + ERR_print_errors_fp(stderr); + close(client_socket); + continue; + } + + // Associate the socket with SSL + if (SSL_set_fd(ssl, client_socket) != 1) { + std::cerr << "SSL_set_fd failed" << std::endl; + ERR_print_errors_fp(stderr); + SSL_free(ssl); + close(client_socket); + continue; + } + + // Accept the TLS connection + if (SSL_accept(ssl) != 1) { + std::cerr << "TLS handshake failed: " << SSL_get_error(ssl, 0) + << std::endl; + ERR_print_errors_fp(stderr); + SSL_free(ssl); + close(client_socket); + continue; + } + + // Add client to the list + std::lock_guard lock(clients_mutex); + clients.push_back({ssl, client_socket}); + + // Create a thread to handle this client + std::thread(handle_client, ssl, client_socket).detach(); + std::cout << "Client connected and secured with TLS 1.3" << std::endl; + } + + // Clean up resources + close(server_fd); + SSL_CTX_free(ctx); + EVP_cleanup(); + return 0; +}