diff --git a/.github/workflows/dtls-demo-test.yml b/.github/workflows/dtls-demo-test.yml new file mode 100644 index 000000000..95a8a8930 --- /dev/null +++ b/.github/workflows/dtls-demo-test.yml @@ -0,0 +1,75 @@ +name: DTLS Demo Test + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + dtls-demo: + runs-on: ubuntu-latest + + steps: + - name: Checkout wolfHSM + uses: actions/checkout@v4 + + - name: Checkout wolfSSL + uses: actions/checkout@v4 + with: + repository: wolfssl/wolfssl + path: wolfssl + + - name: Build wolfHSM POSIX server + run: | + cd examples/posix/wh_posix_server + make -j DMA=1 WOLFSSL_DIR=../../../wolfssl + + - name: Build DTLS server demo + run: | + cd examples/demo/dtls_server + make -j WOLFSSL_DIR=../../../wolfssl + + - name: Build wolfSSL with DTLS 1.3 support + run: | + cd wolfssl + ./autogen.sh + ./configure --enable-dtls --enable-dtls13 + make -j + + - name: Run DTLS demo test + run: | + # Start the wolfHSM POSIX server in background + cd examples/posix/wh_posix_server + ./Build/wh_posix_server.elf --type dma & + WH_SERVER_PID=$! + cd ../../.. + + # Give the server time to start + sleep 1 + + # Start the DTLS server demo in background + cd examples/demo/dtls_server + ./Build/wh_server.elf -A ../../../wolfssl/certs/client-cert.pem & + DTLS_SERVER_PID=$! + cd ../../.. + + # Give the DTLS server time to start + sleep 1 + + # Run the wolfSSL example client. It performs a DTLS 1.3 handshake, + # sends a test message, reads the echo reply, and exits. + # Timeout means the handshake hung, which is a failure. + cd wolfssl + timeout 10 ./examples/client/client -u -v 4 + CLIENT_EXIT=$? + + # Clean up background processes + kill $DTLS_SERVER_PID 2>/dev/null || true + kill $WH_SERVER_PID 2>/dev/null || true + + if [ $CLIENT_EXIT -ne 0 ]; then + echo "DTLS demo test failed with exit code $CLIENT_EXIT" + exit 1 + fi + echo "DTLS demo test passed" diff --git a/examples/demo/dtls_server/Makefile b/examples/demo/dtls_server/Makefile new file mode 100644 index 000000000..e55b04d31 --- /dev/null +++ b/examples/demo/dtls_server/Makefile @@ -0,0 +1,146 @@ +## Makefile for TLS/DTLS Server using wolfHSM for crypto operations +## +## This example demonstrates a server that offloads all cryptographic +## operations to a wolfHSM server running on the POSIX transport with +## DMA support. By default, DTLS (UDP) mode is used. +## +## Usage: +## 1. Build: make DEBUG=1 +## 2. Start the wolfHSM server: cd ../../posix/wh_posix_server && ./Build/wh_posix_server.elf --type dma +## 3. Run this server: ./Build/wh_server.elf +## 4. Connect with a client + +## Project name - sets output filename +BIN = wh_server + +## Important directories +PROJECT_DIR ?= . +CONFIG_DIR ?= $(PROJECT_DIR)/config + +# wolfSSL and wolfHSM directories (relative to this Makefile) +WOLFSSL_DIR ?= ../../../../wolfssl +WOLFHSM_DIR ?= ../../.. +WOLFHSM_PORT_DIR ?= $(WOLFHSM_DIR)/port/posix + +# Output directory for build files +BUILD_DIR ?= $(PROJECT_DIR)/Build + +## Includes +INC = -I$(PROJECT_DIR) \ + -I$(CONFIG_DIR) \ + -I$(WOLFSSL_DIR) \ + -I$(WOLFHSM_DIR) \ + -I$(WOLFHSM_PORT_DIR) + +## Defines +# POSIX requires C source be defined before any header +DEF += -D_POSIX_C_SOURCE=200809L + +# Library configuration defines for user-supplied settings +DEF += -DWOLFSSL_USER_SETTINGS -DWOLFHSM_CFG + +# Enable DMA transport by default (matches server --type dma) +DEF += -DWOLFHSM_CFG_DMA + +## Architecture flags +ARCHFLAGS ?= + +## Compiler and linker flags +ASFLAGS ?= $(ARCHFLAGS) +CFLAGS_EXTRA ?= -Wextra +CFLAGS ?= $(ARCHFLAGS) -Wno-cpp -std=c99 -Wall -Werror $(CFLAGS_EXTRA) +LDFLAGS ?= $(ARCHFLAGS) +LIBS = -lc -lm + +# Platform-specific linker flags for dead code stripping +OS_NAME := $(shell uname -s | tr A-Z a-z) +ifeq ($(OS_NAME),darwin) + LDFLAGS += -Wl,-dead_strip +else + LDFLAGS += -Wl,--gc-sections +endif + +## Makefile options + +# Set to @ to suppress command echo +CMD_ECHO ?= + +# Debug build +ifeq ($(DEBUG),1) + DBGFLAGS = -ggdb -g3 -O0 + CFLAGS += $(DBGFLAGS) + LDFLAGS += $(DBGFLAGS) + DEF += -DWOLFHSM_CFG_DEBUG +endif + +# Verbose debug output +ifeq ($(DEBUG_VERBOSE),1) + DBGFLAGS = -ggdb -g3 -O0 + CFLAGS += $(DBGFLAGS) + LDFLAGS += $(DBGFLAGS) + DEF += -DWOLFHSM_CFG_DEBUG -DWOLFHSM_CFG_DEBUG_VERBOSE +endif + +# Address sanitizer +ifeq ($(ASAN),1) + CFLAGS += -fsanitize=address + LDFLAGS += -fsanitize=address +endif + +## Source files + +# wolfCrypt source files +SRC_C += $(wildcard $(WOLFSSL_DIR)/wolfcrypt/src/*.c) + +# wolfSSL TLS source files +SRC_C += $(wildcard $(WOLFSSL_DIR)/src/*.c) + +# wolfHSM source files +SRC_C += $(wildcard $(WOLFHSM_DIR)/src/*.c) + +# wolfHSM POSIX port/HAL code +SRC_C += $(wildcard $(WOLFHSM_PORT_DIR)/*.c) + +# Project source files +SRC_C += $(PROJECT_DIR)/server.c +SRC_C += $(PROJECT_DIR)/server_io.c + +## Automated processing + +FILENAMES_C = $(notdir $(SRC_C)) +OBJS_C = $(addprefix $(BUILD_DIR)/, $(FILENAMES_C:.c=.o)) +vpath %.c $(dir $(SRC_C)) + +## Makefile Targets + +.PHONY: all build clean help + +all: build + +build: $(BUILD_DIR) $(BUILD_DIR)/$(BIN).elf + +$(BUILD_DIR): + $(CMD_ECHO) mkdir -p $(BUILD_DIR) + +$(BUILD_DIR)/%.o: %.c + @echo "Compiling: $(notdir $<)" + $(CMD_ECHO) $(CC) $(CFLAGS) $(DEF) $(INC) -c -o $@ $< + +$(BUILD_DIR)/$(BIN).elf: $(OBJS_C) + @echo "Linking: $(notdir $@)" + $(CMD_ECHO) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + @echo "Cleaning build files..." + @rm -rf $(BUILD_DIR) + +help: + @echo "TLS/DTLS Server with wolfHSM Crypto Offload" + @echo "" + @echo "Options:" + @echo " DEBUG=1 - Enable debug build with symbols" + @echo " DEBUG_VERBOSE=1 - Enable verbose debug output" + @echo " ASAN=1 - Enable address sanitizer" + @echo "" + @echo "Example:" + @echo " make DEBUG=1" diff --git a/examples/demo/dtls_server/README.md b/examples/demo/dtls_server/README.md new file mode 100644 index 000000000..61775d246 --- /dev/null +++ b/examples/demo/dtls_server/README.md @@ -0,0 +1,219 @@ +# TLS/DTLS Server with wolfHSM Crypto Offload + +This example demonstrates a TLS/DTLS server that offloads cryptographic +operations to a wolfHSM server. By default, DTLS (UDP-based) is used, but +the code can be adapted for TLS (TCP-based) connections. + +The wolfHSM server runs separately and communicates via the chosen transport. + +## Architecture + +``` ++-------------------+ Shared Memory (DMA) +-------------------+ +| | <-----------------------------> | | +| TLS/DTLS Server | Crypto Operations Request | wolfHSM Server | +| (This Example) | <-----------------------------> | (wh_posix_server)| +| | Crypto Operations Response | | ++-------------------+ +-------------------+ + | | + | TLS/DTLS | Performs all + | | crypto ops: + v | - Key Exchange ++-------------------+ | - Signing +| TLS/DTLS Client | | - Encryption +| | | - Hashing ++-------------------+ + +``` + +## How It Works + +1. **wolfHSM Server**: The `wh_posix_server` runs with `--type dma` to provide + crypto services over shared memory with DMA support. + +2. **TLS/DTLS Server**: This example connects to the wolfHSM server as a client + and registers a crypto callback. All wolfSSL/wolfCrypt operations are + forwarded to the HSM. + +3. **Crypto Offload**: When `wolfSSL_CTX_SetDevId()` is called with `WH_DEV_ID`, + wolfSSL routes crypto operations through the registered callback to the + wolfHSM server. + +## Building + +### Prerequisites + +1. wolfSSL library built with crypto callback support +2. wolfHSM library with POSIX port + +### Build Steps + +```bash +# Build the server +cd examples/demo/dtls_server +make + +# Build the wolfHSM POSIX server (if not already built) +cd ../../posix/wh_posix_server +make DMA=1 +``` + +## Running + +### Step 1: Start the wolfHSM Server + +```bash +cd examples/posix/wh_posix_server +./Build/wh_posix_server.elf --type dma +``` + +You should see: +``` +Example wolfHSM POSIX server built with wolfSSL version X.X.X +Using DMA with shared memory transport +Waiting for connection... +``` + +### Step 2: Start the Server + +In a new terminal: + +```bash +cd examples/demo/dtls_server +./Build/wh_server.elf +``` + +#### Command-Line Options + +``` +Usage: ./Build/wh_server.elf [options] + +Options: + -A CA certificate file (PEM or DER format) + If not specified, uses built-in test certificate + -c Server certificate file (PEM or DER format) + -k Server private key file (PEM or DER format) + -p Port to listen on (default: 11111) + -h Show this help message +``` + +#### Examples + +```bash +# Use default built-in certificates +./Build/wh_server.elf + +# Use client-cert.pem from wolfssl bundle for example client to connect +./Build/wh_server.elf -A /path/to/wolfssl/certs/client-cert.pem + +# Use custom certificates and port +./Build/wh_server.elf -A ca.pem -c server.pem -k server-key.pem -p 4433 +``` + +You should see: +``` +DTLS server starting on port 11111... +Connected to wolfHSM server successfully +Waiting for client on port 11111... +``` + +### Step 3: Connect a Client + +In a third terminal: + +```bash +# For DTLS (default mode) - using wolfssl with DTLS 1.3 +./examples/examples/client -u -v 4 +``` + +## Key Integration Points + +### 1. Registering Crypto Callbacks + +In `server.c`, we register the wolfHSM crypto callbacks: + +```c +/* Register crypto callback for non-DMA operations */ +wc_CryptoCb_RegisterDevice(WH_DEV_ID, wh_Client_CryptoCb, (void*)g_client); + +/* Register crypto callback for DMA operations (larger data) */ +wc_CryptoCb_RegisterDevice(WH_DEV_ID_DMA, wh_Client_CryptoCbDma, (void*)g_client); +``` + +### 2. Setting Device ID on wolfSSL Object + +In `server_io.c`, we configure wolfSSL to use the HSM on the WOLFSSL_CTX object: + +```c +wolfSSL_CTX_SetDevId(ctx, WH_DEV_ID); +``` + +### 3. DMA vs Non-DMA + +- **WH_DEV_ID**: Uses standard message-based crypto operations. Suitable for + smaller data sizes. + +- **WH_DEV_ID_DMA**: Uses DMA (Direct Memory Access) for data transfer. + More efficient for larger data like TLS record encryption. + +## Configuration + +### wolfSSL Configuration (`config/user_settings.h`) + +Key settings for TLS/DTLS with wolfHSM: + +```c +/* Enable DTLS 1.3 (for UDP mode) */ +#define WOLFSSL_DTLS +#define WOLFSSL_DTLS13 +#define WOLFSSL_TLS13 + +/* Enable crypto callbacks for wolfHSM */ +#define WOLF_CRYPTO_CB + +/* Hash DRBG for RNG */ +#define HAVE_HASHDRBG +``` + +### wolfHSM Configuration (`config/wolfhsm_cfg.h`) + +Key settings for wolfHSM client: + +```c +/* Enable wolfHSM client */ +#define WOLFHSM_CFG_ENABLE_CLIENT + +/* Enable DMA transport */ +#define WOLFHSM_CFG_DMA +``` + +## Troubleshooting + +### "Failed to connect to wolfHSM server" + +Make sure the `wh_posix_server` is running with `--type dma` before starting +the DTLS server. + +### Handshake Failures + +1. Check that both the wolfHSM server and DTLS server are built with the same + wolfSSL version. + +2. Verify the shared memory name matches between client and server + (default: "wh_example_shm"). + +3. Enable verbose debugging: + ```bash + make DEBUG_VERBOSE=1 + ``` + +## Adapting for TLS + +To use TLS instead of DTLS: + +1. In `server_io.c`, change the method from `wolfDTLS_server_method()` to + `wolfTLSv1_3_server_method()` or another TLS method. + +2. Change the socket initialization from UDP to TCP (replace + `initialize_udp_socket()` with a TCP equivalent). + +3. Remove the DTLS-specific peer address setup in `setup_ssl_accept()`. diff --git a/examples/demo/dtls_server/config/user_settings.h b/examples/demo/dtls_server/config/user_settings.h new file mode 100644 index 000000000..71c104656 --- /dev/null +++ b/examples/demo/dtls_server/config/user_settings.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * user_settings.h - wolfSSL configuration for DTLS server demo + * + * Based on the posix server user_settings.h with TLS enabled. + */ + +#ifndef USER_SETTINGS_H +#define USER_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** wolfHSM required settings for wolfCrypt */ +#define WOLF_CRYPTO_CB +#define WOLFSSL_KEY_GEN +#define WOLFSSL_ASN_TEMPLATE +#define WOLFSSL_BASE64_ENCODE +#define HAVE_ANONYMOUS_INLINE_AGGREGATES 1 + +/** Math library */ +#define USE_FAST_MATH +#define FP_MAX_BITS 8192 + +/** General recommended settings */ +#define WOLFSSL_USE_ALIGN +#define WOLFSSL_IGNORE_FILE_WARN +#define TFM_TIMING_RESISTANT +#define ECC_TIMING_RESISTANT +#define WC_RSA_BLINDING + +/** Remove unneeded features */ +#define NO_MAIN_DRIVER +#define NO_INLINE +#define NO_DO178 + +/** Remove unneeded namespace */ +#define NO_OLD_RNGNAME +#define NO_OLD_WC_NAMES +#define NO_OLD_SSL_NAMES +#define NO_OLD_SHA_NAMES +#define NO_OLD_MD5_NAME + +/** RSA Options */ +#define RSA_MIN_SIZE 1024 +#define WC_RSA_PSS +#define WOLFSSL_PSS_LONG_SALT + +/** ECC Options */ +#define HAVE_ECC +#define TFM_ECC256 +#define ECC_SHAMIR +#define HAVE_ECC_DHE /* Required for ECDH key agreement (TLS 1.3 key share) */ + +/** Curve25519 Options - disabled for this demo + * TLS 1.3 will use ECC (P-256) for key share instead */ +/* #define HAVE_CURVE25519 */ + +/** Ed25519 Options - disabled for this demo */ +/* #define HAVE_ED25519 */ + +/** DH Options */ +#define HAVE_DH_DEFAULT_PARAMS +#define HAVE_FFDHE_2048 + +/** AES Options */ +#define HAVE_AES_CBC +#define HAVE_AESGCM +#define WOLFSSL_AES_COUNTER +#define GCM_TABLE_4BIT +#define WOLFSSL_AES_DIRECT +#define HAVE_AES_ECB +#define WOLFSSL_CMAC + +/** SHA Options */ +/* Keep SHA-1 enabled - required for DTLS 1.2 cipher suites */ +#define WOLFSSL_SHA224 +#define WOLFSSL_SHA384 +#define WOLFSSL_SHA512 +#define WOLFSSL_SHA512_HASHTYPE + +/** Composite features */ +#define HAVE_HKDF + +/** RNG configuration */ +/* Use Hash DRBG (NIST SP 800-90A compliant) */ +#define HAVE_HASHDRBG + +/** Remove unneeded crypto */ +#define NO_DSA +#define NO_RC4 +#define NO_MD4 +/* Keep MD5 for TLS PRF */ +#define NO_DES3 +#define NO_PWDBASED + +/** TLS/DTLS settings */ +#define HAVE_TLS_EXTENSIONS +#define HAVE_SUPPORTED_CURVES +#define HAVE_EXTENDED_MASTER +#define HAVE_ENCRYPT_THEN_MAC +#define HAVE_SERVER_RENEGOTIATION_INFO + +/* DTLS support */ +#define WOLFSSL_DTLS +#define WOLFSSL_DTLS13 +#define WOLFSSL_TLS13 +#define WOLFSSL_SEND_HRR_COOKIE /* Required for DTLS 1.3 server */ + +/* Disable features we don't need */ +#define NO_PSK +#define NO_OLD_TLS + +/* Test certificate buffers for demo */ +#define USE_CERT_BUFFERS_256 +#define USE_CERT_BUFFERS_2048 + +/* Debug (optional - enabled via Makefile DEBUG=1) */ +#ifdef WOLFHSM_CFG_DEBUG +#define DEBUG_WOLFSSL +#endif + +/* Include for POSIX extensions needed by wolfSSL */ +#include /* for struct timeval, gettimeofday */ +#include /* for strcasecmp */ + +#ifdef __cplusplus +} +#endif + +#endif /* USER_SETTINGS_H */ diff --git a/examples/demo/dtls_server/config/wolfhsm_cfg.h b/examples/demo/dtls_server/config/wolfhsm_cfg.h new file mode 100644 index 000000000..1431f62d1 --- /dev/null +++ b/examples/demo/dtls_server/config/wolfhsm_cfg.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfhsm_cfg.h - wolfHSM configuration for DTLS server demo + * + * This configures the wolfHSM client to connect to the HSM server + * for crypto operations. + */ + +#ifndef WOLFHSM_CFG_H_ +#define WOLFHSM_CFG_H_ + +#include "port/posix/posix_time.h" + +/* Time function for wolfHSM */ +#define WOLFHSM_CFG_PORT_GETTIME posixGetTime + +/* Enable wolfHSM client */ +#define WOLFHSM_CFG_ENABLE_CLIENT + +/* DMA transport is enabled via Makefile -DWOLFHSM_CFG_DMA */ +/* Debug output is enabled via Makefile when DEBUG=1 */ + +/* Verbose debug output (uncomment for detailed tracing) */ +/* #define WOLFHSM_CFG_DEBUG_VERBOSE */ + +/* Enable hexdump utility */ +#define WOLFHSM_CFG_HEXDUMP + +/* Communication data length - must match server configuration */ +#define WOLFHSM_CFG_COMM_DATA_LEN 5000 + +/* Enable key wrapping support */ +#define WOLFHSM_CFG_KEYWRAP + +/* Enable global keys feature */ +#define WOLFHSM_CFG_GLOBAL_KEYS + +#endif /* WOLFHSM_CFG_H_ */ diff --git a/examples/demo/dtls_server/server.c b/examples/demo/dtls_server/server.c new file mode 100644 index 000000000..968e8ebc6 --- /dev/null +++ b/examples/demo/dtls_server/server.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * TLS/DTLS Server Demo using wolfHSM for Crypto Operations + * + * This example demonstrates a server that offloads all cryptographic + * operations to a wolfHSM server running on the POSIX transport with + * DMA support. By default, DTLS is used but the code can be adapted + * for TLS connections. + */ + +#include +#include +#include +#include +#include + +#include "server.h" + +/* wolfHSM client includes */ +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_client_cryptocb.h" +#include "port/posix/posix_transport_shm.h" + +/* wolfSSL includes for crypto callback registration */ +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/wolfcrypt/cryptocb.h" + +/* Shared POSIX example configuration */ +#include "examples/posix/wh_posix_cfg.h" + +/* Global wolfHSM client context */ +static whClientContext g_client[1] = {{0}}; +static posixTransportShmClientContext g_shm_client_ctx; +static posixTransportShmConfig g_shm_config; +static whCommClientConfig g_comm_config; +static whClientConfig g_client_config; + +#ifdef WOLFHSM_CFG_DMA +/* DMA configuration for large data transfers */ +static whClientDmaConfig g_dma_config; +#endif + +/* + * Connect to the wolfHSM server over shared memory DMA transport. + * + * This establishes a connection to the HSM server and registers the + * crypto callback so that wolfSSL crypto operations are forwarded to + * the HSM. + */ +static int connect_to_hsm_server(void) +{ + int ret; + static const whTransportClientCb shm_cb = POSIX_TRANSPORT_SHM_CLIENT_CB; + + + /* Initialize transport context */ + memset(&g_shm_client_ctx, 0, sizeof(g_shm_client_ctx)); + memset(&g_comm_config, 0, sizeof(g_comm_config)); + memset(&g_client_config, 0, sizeof(g_client_config)); + + /* Configure shared memory transport with DMA */ + g_shm_config.name = WH_POSIX_SHARED_MEMORY_NAME; + g_shm_config.req_size = WH_POSIX_REQ_SIZE; + g_shm_config.resp_size = WH_POSIX_RESP_SIZE; + g_shm_config.dma_size = WH_POSIX_DMA_SIZE; + + /* Configure comm layer */ + g_comm_config.transport_cb = &shm_cb; + g_comm_config.transport_context = (void*)&g_shm_client_ctx; + g_comm_config.transport_config = (void*)&g_shm_config; + g_comm_config.client_id = WH_POSIX_CLIENT_ID; + +#ifdef WOLFHSM_CFG_DMA + /* Configure DMA callbacks for static memory operations */ + g_dma_config.cb = posixTransportShm_ClientStaticMemDmaCallback; + g_dma_config.dmaAddrAllowList = NULL; + g_client_config.dmaConfig = &g_dma_config; +#endif + + /* Configure client */ + g_client_config.comm = &g_comm_config; + + /* Initialize the client */ + ret = wh_Client_Init(g_client, &g_client_config); + if (ret != WH_ERROR_OK) { + fprintf(stderr, "Failed to initialize wolfHSM client: %d\n", ret); + return -1; + } + + /* Initialize communication with the server */ + ret = wh_Client_CommInit(g_client, NULL, NULL); + if (ret != WH_ERROR_OK) { + fprintf(stderr, "Failed to initialize wolfHSM client communication: %d\n", ret); + wh_Client_Cleanup(g_client); + return -1; + } + + /* Register crypto callback for non-DMA operations */ + ret = wc_CryptoCb_RegisterDevice(WH_DEV_ID, wh_Client_CryptoCb, + (void*)g_client); + if (ret != 0) { + fprintf(stderr, "Failed to register crypto callback: %d\n", ret); + wh_Client_CommClose(g_client); + wh_Client_Cleanup(g_client); + return -1; + } + +#ifdef WOLFHSM_CFG_DMA + /* Register crypto callback for DMA operations */ + ret = wc_CryptoCb_RegisterDevice(WH_DEV_ID_DMA, wh_Client_CryptoCbDma, + (void*)g_client); + if (ret != 0) { + fprintf(stderr, "Failed to register DMA crypto callback: %d\n", ret); + wc_CryptoCb_UnRegisterDevice(WH_DEV_ID); + wh_Client_CommClose(g_client); + wh_Client_Cleanup(g_client); + return -1; + } +#endif + + printf("Connected to wolfHSM server successfully\n"); + return 0; +} + +/* Disconnect from wolfHSM server */ +static void disconnect_from_hsm_server(void) +{ + printf("Disconnecting from wolfHSM server...\n"); + +#ifdef WOLFHSM_CFG_DMA + wc_CryptoCb_UnRegisterDevice(WH_DEV_ID_DMA); +#endif + wc_CryptoCb_UnRegisterDevice(WH_DEV_ID); + + wh_Client_CommClose(g_client); + wh_Client_Cleanup(g_client); +} + +/* Print usage information */ +static void print_usage(const char* progname) +{ + printf("Usage: %s [options]\n", progname); + printf("\n"); + printf("TLS/DTLS server demo using wolfHSM for crypto operations.\n"); + printf("By default, uses DTLS over UDP.\n"); + printf("\n"); + printf("Options:\n"); + printf(" -A CA certificate file (PEM or DER format)\n"); + printf(" If not specified, uses built-in test certificate\n"); + printf(" -c Server certificate file (PEM or DER format)\n"); + printf(" -k Server private key file (PEM or DER format)\n"); + printf(" -p Port to listen on (default: 11111)\n"); + printf(" -h Show this help message\n"); + printf("\n"); + printf("Prerequisites:\n"); + printf(" Start the wolfHSM server first:\n"); + printf(" cd examples/posix/wh_posix_server\n"); + printf(" ./Build/wh_posix_server.elf --type dma\n"); + printf("\n"); + printf("Example:\n"); + printf(" %s -A ca-cert.pem\n", progname); + printf("\n"); +} + +/* + * Main application entry point. + * + * This sets up the wolfHSM client connection, then initializes the + * server which will use wolfHSM for all crypto operations. + */ +int main(int argc, char** argv) +{ + SERVER_CONTEXT* ctx; + ServerConfig config = {0}; + int ret; + int exit_code = 0; + unsigned char buf[256]; + int bytesRead; + int opt; + + /* Set default port */ + config.port = 11111; + + /* Parse command line arguments */ + while ((opt = getopt(argc, argv, "A:c:k:p:h")) != -1) { + switch (opt) { + case 'A': + config.caCertFile = optarg; + break; + case 'c': + config.serverCertFile = optarg; + break; + case 'k': + config.serverKeyFile = optarg; + break; + case 'p': + config.port = atoi(optarg); + if (config.port <= 0 || config.port > 65535) { + fprintf(stderr, "Invalid port number: %s\n", optarg); + return 1; + } + break; + case 'h': + print_usage(argv[0]); + return 0; + default: + print_usage(argv[0]); + return 1; + } + } + + printf("DTLS server starting on port %d...\n", config.port); + + /* Initialize wolfCrypt */ + ret = wolfCrypt_Init(); + if (ret != 0) { + fprintf(stderr, "Failed to initialize wolfCrypt: %d\n", ret); + return 1; + } + + /* Connect to the wolfHSM server */ + if (connect_to_hsm_server() != 0) { + fprintf(stderr, "Failed to connect to wolfHSM server\n"); + fprintf(stderr, "Make sure wh_posix_server is running with --type dma\n"); + wolfCrypt_Cleanup(); + return 1; + } + + /* Get the server context and initialize it */ + ctx = Server_Get(); + ret = Server_Init(ctx, g_client, &config); + if (ret != 0) { + fprintf(stderr, "Failed to initialize server: %d\n", ret); + exit_code = 1; + goto cleanup; + } + + /* Accept a connection */ + printf("Waiting for client...\n"); + ret = Server_Accept(ctx); + if (ret != 0) { + fprintf(stderr, "Failed to accept connection: %d\n", ret); + exit_code = 1; + goto cleanup; + } + + printf("Connected. Entering echo mode...\n"); + while (1) { + memset(buf, 0, sizeof(buf)); + bytesRead = Server_Read(ctx, buf, sizeof(buf) - 1); + if (bytesRead <= 0) { + printf("Client disconnected\n"); + break; + } + + printf("Received %d bytes: %s\n", bytesRead, buf); + + /* Echo back */ + ret = Server_Write(ctx, buf, bytesRead); + if (ret < 0) { + fprintf(stderr, "Failed to write response\n"); + break; + } + } + +cleanup: + Server_Cleanup(ctx); + disconnect_from_hsm_server(); + wolfCrypt_Cleanup(); + return exit_code; +} diff --git a/examples/demo/dtls_server/server.h b/examples/demo/dtls_server/server.h new file mode 100644 index 000000000..90e4fb112 --- /dev/null +++ b/examples/demo/dtls_server/server.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * server.h + * + * Header for the TLS/DTLS server demo that uses wolfHSM for crypto operations. + * This API is protocol-agnostic and can be used for both TLS and DTLS. + */ + +#ifndef SERVER_H_ +#define SERVER_H_ + +#include +#include +#include + +#include "wolfhsm/wh_client.h" + +/* Forward declaration for opaque server structure */ +typedef struct SERVER_CONTEXT SERVER_CONTEXT; + +/* Server configuration */ +typedef struct ServerConfig { + const char* caCertFile; /* Path to CA certificate file (PEM or DER) */ + const char* serverCertFile; /* Path to server certificate file (optional) */ + const char* serverKeyFile; /* Path to server private key file (optional) */ + int port; /* Port to listen on (default: 11111) */ +} ServerConfig; + +/* Server management functions */ +SERVER_CONTEXT* Server_Get(void); +int Server_Init(SERVER_CONTEXT* ctx, whClientContext* client, + const ServerConfig* config); +int Server_Accept(SERVER_CONTEXT* ctx); +void Server_Cleanup(SERVER_CONTEXT* ctx); +int Server_Close(SERVER_CONTEXT* ctx); + +/* Data transfer functions */ +int Server_Read(SERVER_CONTEXT* ctx, unsigned char* data, size_t length); +int Server_Write(SERVER_CONTEXT* ctx, unsigned char* data, size_t length); + +#endif /* SERVER_H_ */ diff --git a/examples/demo/dtls_server/server_io.c b/examples/demo/dtls_server/server_io.c new file mode 100644 index 000000000..76c26b8c3 --- /dev/null +++ b/examples/demo/dtls_server/server_io.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * Server I/O functions for the TLS/DTLS server demo. + * + * This module handles TLS/DTLS I/O operations. By default, DTLS is used. + * The key integration point with wolfHSM is setting the device ID (WH_DEV_ID) + * on the wolfSSL context so that crypto operations are forwarded to the HSM. + */ + +#include "server.h" + +/* wolfSSL includes */ +#include +#include +#include + +/* wolfHSM client includes */ +#include "wolfhsm/wh_client.h" + +/* Standard includes */ +#include +#include +#include +#include +#include +#include +#include + +/* Test certificate buffers from wolfSSL for demo purposes */ +#undef USE_CERT_BUFFERS_2048 +#define USE_CERT_BUFFERS_2048 +#undef USE_CERT_BUFFERS_256 +#define USE_CERT_BUFFERS_256 +#include "wolfssl/certs_test.h" + +/* Default server port */ +#define SERVER_PORT_DEFAULT 11111 + +/* Static wolfSSL context - shared across connections */ +static WOLFSSL_CTX* g_ctx = NULL; + +/* Static configuration - set during init */ +static ServerConfig g_config = {0}; + +/* Server context structure */ +struct SERVER_CONTEXT { + WOLFSSL* ssl; + whClientContext* hsm_client; + int listenfd; + struct sockaddr_in cliaddr; + socklen_t cliLen; + int port; +}; + +/* Single static instance of the server */ +static SERVER_CONTEXT g_server = { + .ssl = NULL, + .hsm_client = NULL, + .listenfd = -1, + .port = 0 +}; + +/* + * Initialize wolfSSL library and create a context. + * + * Uses DTLS server method with version negotiation (prefers DTLS 1.3). + * This can be changed to TLS by modifying the method call below. + * + * The key here is setting the device ID to WH_DEV_ID so that all + * crypto operations are forwarded to the wolfHSM server. + */ +static int initialize_wolfssl(WOLFSSL_CTX** ctx, whClientContext* hsm_client) +{ + int ret = 0; + + ret = wolfSSL_Init(); + if (ret != WOLFSSL_SUCCESS) { + printf("Failed to initialize wolfSSL, ret = %d\n", ret); + return -1; + } + + /* Enable debug output */ + wolfSSL_Debugging_ON(); + + /* Create a new context for server - DTLS with version negotiation + * This will use DTLS 1.3 if both sides support it, otherwise falls back. + * Note: For DTLS 1.3-only, use wolfDTLSv1_3_server_method() but ensure + * the crypto callback supports TLS 1.3 key exchange operations. */ + *ctx = wolfSSL_CTX_new(wolfDTLS_server_method()); + if (*ctx == NULL) { + printf("Failed to create wolfSSL context\n"); + return -1; + } + + /* @TODO have an option for WH_DEV_ID_DMA */ + wolfSSL_CTX_SetDevId(*ctx, WH_DEV_ID); + + /* Load CA certificate for client verification */ + if (g_config.caCertFile != NULL) { + /* wolfSSL_CTX_load_verify_locations auto-detects PEM vs DER format */ + ret = wolfSSL_CTX_load_verify_locations(*ctx, g_config.caCertFile, NULL); + if (ret != WOLFSSL_SUCCESS) { + printf("Failed to load CA certificate from %s, ret = %d\n", + g_config.caCertFile, ret); + wolfSSL_CTX_free(*ctx); + *ctx = NULL; + return -1; + } + } + else { + /* Use built-in test certificate */ + ret = wolfSSL_CTX_load_verify_buffer(*ctx, ca_cert_der_2048, + sizeof_ca_cert_der_2048, + WOLFSSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + printf("Failed to load built-in CA certificate, ret = %d\n", ret); + wolfSSL_CTX_free(*ctx); + *ctx = NULL; + return -1; + } + } + + /* Load server certificate */ + if (g_config.serverCertFile != NULL) { + ret = wolfSSL_CTX_use_certificate_file(*ctx, g_config.serverCertFile, + WOLFSSL_FILETYPE_PEM); + if (ret != WOLFSSL_SUCCESS) { + /* Try DER format */ + ret = wolfSSL_CTX_use_certificate_file(*ctx, g_config.serverCertFile, + WOLFSSL_FILETYPE_ASN1); + } + if (ret != WOLFSSL_SUCCESS) { + printf("Failed to load server certificate from %s, ret = %d\n", + g_config.serverCertFile, ret); + wolfSSL_CTX_free(*ctx); + *ctx = NULL; + return -1; + } + } + else { + ret = wolfSSL_CTX_use_certificate_buffer(*ctx, server_cert_der_2048, + sizeof_server_cert_der_2048, + WOLFSSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + printf("Failed to load built-in server certificate, ret = %d\n", ret); + wolfSSL_CTX_free(*ctx); + *ctx = NULL; + return -1; + } + } + + /* Load server private key */ + if (g_config.serverKeyFile != NULL) { + ret = wolfSSL_CTX_use_PrivateKey_file(*ctx, g_config.serverKeyFile, + WOLFSSL_FILETYPE_PEM); + if (ret != WOLFSSL_SUCCESS) { + /* Try DER format */ + ret = wolfSSL_CTX_use_PrivateKey_file(*ctx, g_config.serverKeyFile, + WOLFSSL_FILETYPE_ASN1); + } + if (ret != WOLFSSL_SUCCESS) { + printf("Failed to load server private key from %s, ret = %d\n", + g_config.serverKeyFile, ret); + wolfSSL_CTX_free(*ctx); + *ctx = NULL; + return -1; + } + } + else { + ret = wolfSSL_CTX_use_PrivateKey_buffer(*ctx, server_key_der_2048, + sizeof_server_key_der_2048, + WOLFSSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + printf("Failed to load built-in server private key, ret = %d\n", ret); + wolfSSL_CTX_free(*ctx); + *ctx = NULL; + return -1; + } + } + + /* Require mutual authentication */ + wolfSSL_CTX_set_verify(*ctx, + WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, + NULL); + + (void)hsm_client; + return 0; +} + +/* + * Initialize the UDP socket for DTLS. + * For TLS, this would need to be changed to TCP socket initialization. + */ +static int initialize_udp_socket(SERVER_CONTEXT* ctx) +{ + int ret; + struct sockaddr_in servAddr; + char peekBuf[1]; + int optval = 1; + + /* Create a UDP socket */ + ctx->listenfd = socket(AF_INET, SOCK_DGRAM, 0); + if (ctx->listenfd < 0) { + perror("socket()"); + return -1; + } + + /* Allow socket reuse */ + ret = setsockopt(ctx->listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); + if (ret < 0) { + perror("setsockopt(SO_REUSEADDR)"); + close(ctx->listenfd); + ctx->listenfd = -1; + return -1; + } + + /* Bind to all interfaces on the specified port */ + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(ctx->port); + + ret = bind(ctx->listenfd, (struct sockaddr*)&servAddr, sizeof(servAddr)); + if (ret < 0) { + perror("bind()"); + close(ctx->listenfd); + ctx->listenfd = -1; + return -1; + } + + /* Wait for the first packet to get client address */ + printf("Waiting for client on port %d...\n", ctx->port); + + ctx->cliLen = sizeof(ctx->cliaddr); + ret = recvfrom(ctx->listenfd, peekBuf, sizeof(peekBuf), MSG_PEEK, + (struct sockaddr*)&ctx->cliaddr, &ctx->cliLen); + if (ret < 0) { + perror("recvfrom()"); + close(ctx->listenfd); + ctx->listenfd = -1; + return -1; + } + + printf("Received initial packet from %s:%d\n", + inet_ntoa(ctx->cliaddr.sin_addr), + ntohs(ctx->cliaddr.sin_port)); + + return 0; +} + +/* + * Set up the WOLFSSL object for accepting a connection. + * For DTLS, this includes setting the peer address. + */ +static int setup_ssl_accept(SERVER_CONTEXT* ctx) +{ + ctx->ssl = wolfSSL_new(g_ctx); + if (ctx->ssl == NULL) { + fprintf(stderr, "wolfSSL_new error - check debug output above\n"); + return -1; + } + + /* Set the peer address (DTLS-specific) */ + if (wolfSSL_dtls_set_peer(ctx->ssl, &ctx->cliaddr, + ctx->cliLen) != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_dtls_set_peer error\n"); + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + return -1; + } + + if (wolfSSL_set_fd(ctx->ssl, ctx->listenfd) != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_set_fd error\n"); + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + return -1; + } + + return 0; +} + +/* + * Perform the TLS/DTLS handshake. + * + * All crypto operations during this handshake (key exchange, signatures, + * encryption) will be performed by the wolfHSM server. + */ +static int perform_ssl_accept(SERVER_CONTEXT* ctx) +{ + int ret; + + printf("Starting handshake (crypto via wolfHSM)...\n"); + + ret = wolfSSL_accept(ctx->ssl); + if (ret != WOLFSSL_SUCCESS) { + int err = wolfSSL_get_error(ctx->ssl, ret); + fprintf(stderr, "wolfSSL_accept failed: error = %d, %s\n", err, + wolfSSL_ERR_reason_error_string(err)); + return -1; + } + + printf("Handshake successful!\n"); + printf("Cipher: %s\n", wolfSSL_get_cipher(ctx->ssl)); + + return 0; +} + +/* Public API implementations */ + +SERVER_CONTEXT* Server_Get(void) +{ + return &g_server; +} + +int Server_Init(SERVER_CONTEXT* ctx, whClientContext* client, + const ServerConfig* config) +{ + int ret; + + if (ctx == NULL || client == NULL) { + return -1; + } + + /* Store config in static variable for use by initialize_wolfssl */ + if (config != NULL) { + g_config = *config; + } else { + memset(&g_config, 0, sizeof(g_config)); + g_config.port = SERVER_PORT_DEFAULT; + } + + memset(ctx, 0, sizeof(SERVER_CONTEXT)); + ctx->listenfd = -1; /* Initialize to invalid fd to prevent closing stdin */ + ctx->hsm_client = client; + ctx->port = (g_config.port > 0) ? g_config.port : SERVER_PORT_DEFAULT; + + /* Initialize wolfSSL with HSM crypto offload */ + ret = initialize_wolfssl(&g_ctx, client); + if (ret != 0) { + fprintf(stderr, "Failed to initialize wolfSSL\n"); + return -1; + } + + /* Initialize UDP socket and wait for client (DTLS mode) */ + ret = initialize_udp_socket(ctx); + if (ret != 0) { + fprintf(stderr, "Failed to initialize socket\n"); + wolfSSL_CTX_free(g_ctx); + g_ctx = NULL; + return -1; + } + + /* Set up SSL for accepting connection */ + ret = setup_ssl_accept(ctx); + if (ret != 0) { + fprintf(stderr, "Failed to set up SSL accept\n"); + close(ctx->listenfd); + ctx->listenfd = -1; + wolfSSL_CTX_free(g_ctx); + g_ctx = NULL; + return -1; + } + + return 0; +} + +int Server_Accept(SERVER_CONTEXT* ctx) +{ + if (ctx == NULL || ctx->ssl == NULL) { + return -1; + } + + return perform_ssl_accept(ctx); +} + +int Server_Read(SERVER_CONTEXT* ctx, unsigned char* data, size_t length) +{ + int ret; + + if (ctx == NULL || ctx->ssl == NULL || data == NULL) { + return -1; + } + + if (length > INT_MAX) { + return -1; + } + + ret = wolfSSL_read(ctx->ssl, data, (int)length); + if (ret < 0) { + int err = wolfSSL_get_error(ctx->ssl, ret); + if (err != WOLFSSL_ERROR_WANT_READ) { + fprintf(stderr, "wolfSSL_read failed: error = %d, %s\n", err, + wolfSSL_ERR_reason_error_string(err)); + } + return -1; + } + + return ret; +} + +int Server_Write(SERVER_CONTEXT* ctx, unsigned char* data, size_t length) +{ + int ret; + + if (ctx == NULL || ctx->ssl == NULL || data == NULL) { + return -1; + } + + if (length > INT_MAX) { + return -1; + } + + ret = wolfSSL_write(ctx->ssl, data, (int)length); + if (ret < 0) { + int err = wolfSSL_get_error(ctx->ssl, ret); + fprintf(stderr, "wolfSSL_write failed: error = %d, %s\n", err, + wolfSSL_ERR_reason_error_string(err)); + return -1; + } + + return ret; +} + +void Server_Cleanup(SERVER_CONTEXT* ctx) +{ + if (ctx == NULL) { + return; + } + + if (ctx->ssl != NULL) { + wolfSSL_shutdown(ctx->ssl); + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + } + + if (ctx->listenfd >= 0) { + close(ctx->listenfd); + ctx->listenfd = -1; + } + + if (g_ctx != NULL) { + wolfSSL_CTX_free(g_ctx); + g_ctx = NULL; + } + + wolfSSL_Cleanup(); +} + +int Server_Close(SERVER_CONTEXT* ctx) +{ + Server_Cleanup(ctx); + return 0; +}