diff --git a/.github/workflows/build-and-test-dtls-client.yml b/.github/workflows/build-and-test-dtls-client.yml new file mode 100644 index 00000000..bb78cb8a --- /dev/null +++ b/.github/workflows/build-and-test-dtls-client.yml @@ -0,0 +1,105 @@ +name: Build and Test DTLS Client Example + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + build-and-test-dtls: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + # Checkout repositories + - name: Checkout wolfHSM + uses: actions/checkout@v4 + + - name: Checkout wolfSSL + uses: actions/checkout@v4 + with: + repository: wolfssl/wolfssl + path: wolfssl + + # Build wolfSSL with DTLS support + - name: Build wolfSSL with DTLS + run: | + cd wolfssl + ./autogen.sh + ./configure --enable-dtls --enable-dtls13 --enable-ecc + make -j + + # Build wolfHSM server + - name: Build wolfHSM POSIX server + run: | + cd examples/posix/wh_posix_server + make clean + make -j WOLFSSL_DIR=../../../wolfssl + + # Build DTLS client + - name: Build DTLS client + run: | + cd examples/posix/tls/wh_posix_dtls_client + make clean + make + + # Start wolfHSM server in background + - name: Start wolfHSM server + run: | + cd examples/posix/wh_posix_server + ./Build/wh_posix_server.elf --type tcp \ + --key ../../../wolfssl/certs/ecc-client-key.der \ + --id 1 \ + --client 12 & + SERVER_PID=$! + echo "WOLFHSM_SERVER_PID=$SERVER_PID" >> $GITHUB_ENV + echo "Started wolfHSM server with PID $SERVER_PID" + sleep 2 + + # Start wolfSSL DTLS server in background + - name: Start wolfSSL DTLS server + run: | + cd wolfssl + ./examples/server/server -u -v 4 \ + -c ./certs/server-ecc.pem \ + -k ./certs/ecc-key.pem \ + -A ./certs/client-ecc-cert.pem \ + -p 11111 \ + -i & + DTLS_SERVER_PID=$! + echo "DTLS_SERVER_PID=$DTLS_SERVER_PID" >> $GITHUB_ENV + echo "Started DTLS server with PID $DTLS_SERVER_PID" + sleep 2 + + # Run DTLS client test + - name: Run DTLS client test + run: | + cd examples/posix/tls/wh_posix_dtls_client + + # Send test message with 5 second timeout + echo "Hello from CI test" | timeout 5 ./Build/wh_posix_dtls_client.elf 127.0.0.1 > client_output.txt 2>&1 || CLIENT_EXIT=$? + + # Display output for debugging + cat client_output.txt + + # Check for successful handshake (exit code 0 = clean exit, 124 = timeout) + if grep -q "DTLS handshake successful!" client_output.txt; then + echo "✓ DTLS client test completed successfully" + exit 0 + else + echo "✗ DTLS handshake did not complete" + exit 1 + fi + + # Cleanup servers (always run) + - name: Cleanup servers + if: always() + run: | + echo "Cleaning up server processes..." + kill ${{ env.WOLFHSM_SERVER_PID }} 2>/dev/null || true + kill ${{ env.DTLS_SERVER_PID }} 2>/dev/null || true + sleep 1 + kill -9 ${{ env.WOLFHSM_SERVER_PID }} 2>/dev/null || true + kill -9 ${{ env.DTLS_SERVER_PID }} 2>/dev/null || true + echo "Cleanup complete" diff --git a/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/user_settings.h.70BDD9097831BA2D.idx b/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/user_settings.h.70BDD9097831BA2D.idx new file mode 100644 index 00000000..505b1c57 Binary files /dev/null and b/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/user_settings.h.70BDD9097831BA2D.idx differ diff --git a/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/wh_posix_dtls_client.c.E5862DCB5B11F175.idx b/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/wh_posix_dtls_client.c.E5862DCB5B11F175.idx new file mode 100644 index 00000000..8a662c8a Binary files /dev/null and b/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/wh_posix_dtls_client.c.E5862DCB5B11F175.idx differ diff --git a/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/wolfhsm_cfg.h.BE11D43E6AF362BB.idx b/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/wolfhsm_cfg.h.BE11D43E6AF362BB.idx new file mode 100644 index 00000000..f470b0b2 Binary files /dev/null and b/examples/posix/tls/wh_posix_dtls_client/.cache/clangd/index/wolfhsm_cfg.h.BE11D43E6AF362BB.idx differ diff --git a/examples/posix/tls/wh_posix_dtls_client/Makefile b/examples/posix/tls/wh_posix_dtls_client/Makefile new file mode 100644 index 00000000..c81ab71c --- /dev/null +++ b/examples/posix/tls/wh_posix_dtls_client/Makefile @@ -0,0 +1,184 @@ +## Makefile for wolfHSM DTLS Client example using POSIX port + +## Project name +# Sets output filenames +BIN = wh_posix_dtls_client + +## Important directories +# Base directory for additional project files +PROJECT_DIR ?= . +CONFIG_DIR ?= $(PROJECT_DIR) +SHARED_CONFIG_DIR ?= $(PROJECT_DIR)/../../ +# wolfSSL and wolfHSM directories +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$(SHARED_CONFIG_DIR) \ + -I$(WOLFSSL_DIR) \ + -I$(WOLFHSM_DIR) \ + -I$(WOLFHSM_PORT_DIR) + +# 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 + +# Architecture flags for assembler, C compiler and linker +ARCHFLAGS ?= + +# Enable extra C compiler warnings +CFLAGS_EXTRA = -Werror -Wall -Wextra +# Place functions / data into separate sections to allow unused code removal +CFLAGS_EXTRA += -ffunction-sections -fdata-sections + +# C standard to use +CSTD ?= -std=c99 + +ASFLAGS ?= $(ARCHFLAGS) +CFLAGS ?= $(ARCHFLAGS) $(CSTD) $(CFLAGS_EXTRA) +LDFLAGS ?= $(ARCHFLAGS) + +# Enable garbage collection. Inexact handling of dead_strip +OS_NAME := $(shell uname -s | tr A-Z a-z) +ifeq ($(OS_NAME),darwin) + LDFLAGS += -Wl,-dead_strip +else + LDFLAGS += -Wl,--gc-sections +endif + +# Libc for printf, libm for math (used with DH) +LIBS = -lc -lm + +## Makefile options + +# Set to @ if you want to suppress command echo +CMD_ECHO ?= + +# Check if DEBUG is set to 1 and append debug flags +ifeq ($(DEBUG),1) + DBGFLAGS = -ggdb -g3 + CFLAGS += $(DBGFLAGS) + LDFLAGS += $(DBGFLAGS) + DEF += -DWOLFHSM_CFG_DEBUG +endif + +# Check if DEBUG_VERBOSE is set to 1 and enable verbose WOLFHSM debug output +# Note: DEBUG_VERBOSE implies DEBUG +ifeq ($(DEBUG_VERBOSE),1) + DBGFLAGS = -ggdb -g3 + CFLAGS += $(DBGFLAGS) + LDFLAGS += $(DBGFLAGS) + DEF += -DWOLFHSM_CFG_DEBUG -DWOLFHSM_CFG_DEBUG_VERBOSE +endif + +# Add address sanitizer option +ifeq ($(ASAN),1) + CFLAGS += -fsanitize=address + LDFLAGS += -fsanitize=address +endif + +## Source files +# Assembly source files +SRC_ASM += + +# wolfCrypt source files +WOLFCRYPT_SRC := $(wildcard $(WOLFSSL_DIR)/wolfcrypt/src/*.c) +SRC_C += $(filter-out %/evp.c %/misc.c,$(WOLFCRYPT_SRC)) + +# wolfSSL source files (needed for DTLS) +WOLFSSL_SRC := $(wildcard $(WOLFSSL_DIR)/src/*.c) +SRC_C += $(filter-out %/bio.c %/conf.c %/pk.c %/ssl_asn1.c %/ssl_bn.c %/ssl_certman.c %/ssl_crypto.c %/ssl_load.c %/ssl_misc.c %/ssl_p7p12.c %/ssl_sess.c %/ssl_sk.c %/x509.c %/x509_str.c,$(WOLFSSL_SRC)) + +# wolfHSM source files +SRC_C += $(wildcard $(WOLFHSM_DIR)/src/*.c) + +# wolfHSM port/HAL code +SRC_C += $(wildcard $(WOLFHSM_PORT_DIR)/*.c) + +# Project source files +SRC_C += $(wildcard $(PROJECT_DIR)/*.c) + +# Set the default device ID for wolfCrypt operations +DEF += -DWC_USE_DEVID=0x5748534D + +ifeq ($(SCAN),1) +SCAN_LOG = scan_posix_dtls_client.log +# Default target +.DEFAULT_GOAL := scan +endif + +## Automated processing below + +FILENAMES_C = $(notdir $(SRC_C)) +OBJS_C = $(addprefix $(BUILD_DIR)/, $(FILENAMES_C:.c=.o)) +vpath %.c $(dir $(SRC_C)) + +OBJS_ASM = $(addprefix $(BUILD_DIR)/, $(notdir $(SRC_ASM:.s=.o))) +vpath %.s $(dir $(SRC_ASM)) + + +## Makefile Targets + +.PHONY: build_app build_hex build_static clean run + +build_app: $(BUILD_DIR) $(BUILD_DIR)/$(BIN).elf + @echo Build complete. + +build_hex: $(BUILD_DIR) $(BUILD_DIR)/$(BIN).hex + @echo "" + $(CMD_ECHO) $(SIZE) $(BUILD_DIR)/$(BIN).elf + +build_static: $(BUILD_DIR) $(BUILD_DIR)/$(BIN).a + @echo "" + $(CMD_ECHO) $(SIZE) $(BUILD_DIR)/$(BIN).a + +$(BUILD_DIR): + $(CMD_ECHO) mkdir -p $(BUILD_DIR) + +$(BUILD_DIR)/$(BIN).hex: $(BUILD_DIR)/$(BIN).elf + @echo "Generating HEX binary: $(notdir $@)" + $(CMD_ECHO) $(OBJCOPY) -O ihex $< $@ + +$(BUILD_DIR)/%.o: %.s + @echo "Compiling ASM file: $(notdir $<)" + $(CMD_ECHO) $(AS) $(ASFLAGS) $(DEF) $(INC) -c -o $@ $< + +$(BUILD_DIR)/%.o: %.c + @echo "Compiling C file: $(notdir $<)" + $(CMD_ECHO) $(CC) $(CFLAGS) $(DEF) $(INC) -c -o $@ $< + +$(BUILD_DIR)/$(BIN).elf: $(OBJS_ASM) $(OBJS_C) + @echo "Linking ELF binary: $(notdir $@)" + $(CMD_ECHO) $(CC) $(LDFLAGS) $(SRC_LD) -o $@ $^ $(LIBS) + +$(BUILD_DIR)/$(BIN).a: $(OBJS_ASM) $(OBJS_C) + @echo "Building static library: $(notdir $@)" + $(CMD_ECHO) $(AR) -r $@ $^ + +analyze: $(OBJS_ASM) $(OBJS_C) + +scan:$(BUILD_DIR) + @echo "Running scan-build static analysis" + @mkdir -p $(WOLFHSM_DIR)/scan_out/ + @scan-build --exclude $(WOLFSSL_DIR)/wolfcrypt \ + --exclude $(WOLFSSL_DIR)/src \ + --status-bugs $(MAKE) analyze 2> $(WOLFHSM_DIR)/scan_out/$(SCAN_LOG) + +clean: + @echo "Cleaning build files" + @rm -f \ + $(BUILD_DIR)/*.elf \ + $(BUILD_DIR)/*.hex \ + $(BUILD_DIR)/*.map \ + $(BUILD_DIR)/*.o \ + $(BUILD_DIR)/*.a \ + $(BUILD_DIR)/*.sym \ + $(BUILD_DIR)/*.disasm diff --git a/examples/posix/tls/wh_posix_dtls_client/user_settings.h b/examples/posix/tls/wh_posix_dtls_client/user_settings.h new file mode 100644 index 00000000..8750aac9 --- /dev/null +++ b/examples/posix/tls/wh_posix_dtls_client/user_settings.h @@ -0,0 +1,52 @@ +#ifndef USER_SETTINGS_H_ +#define USER_SETTINGS_H_ + +/** wolfHSM Client required settings */ + +/* POSIX system headers */ +#define HAVE_SYS_TIME_H + +/* CryptoCB support - required for offloading crypto to HSM */ +#define WOLF_CRYPTO_CB +#define HAVE_ANONYMOUS_INLINE_AGGREGATES 1 + +/* PK callbacks - required for TLS-level HSM key operations */ +#define HAVE_PK_CALLBACKS + +/* Enable DTLS support */ +#define WOLFSSL_DTLS +#define WOLFSSL_DTLS13 +#define WOLFSSL_TLS13 +#define HAVE_TLS_EXTENSIONS +#define WOLFSSL_SEND_HRR_COOKIE + +/* Remove old TLS versions */ +#define NO_OLD_TLS + +/** Crypto Algorithm Options */ + +/* ECC for ECDHE key exchange and ECDSA authentication */ +#define HAVE_ECC +#define HAVE_SUPPORTED_CURVES + +/* AES-GCM for symmetric encryption */ +#define HAVE_AESGCM + +/* HKDF for key derivation */ +#define HAVE_HKDF + +/* Timing resistance / side-channel attack protection */ +#define TFM_TIMING_RESISTANT +#define ECC_TIMING_RESISTANT +#define WC_RSA_BLINDING + +/* Use wolfSSL's internal string comparison instead of system strcasecmp */ +#define USE_WOLF_STRCASECMP + +/* Remove unneeded features */ +#define NO_MAIN_DRIVER +#define NO_DO178 +#define NO_RSA +#define NO_DH + +#endif /* USER_SETTINGS_H_ */ diff --git a/examples/posix/tls/wh_posix_dtls_client/wh_posix_dtls_client.c b/examples/posix/tls/wh_posix_dtls_client/wh_posix_dtls_client.c new file mode 100644 index 00000000..e03e3475 --- /dev/null +++ b/examples/posix/tls/wh_posix_dtls_client/wh_posix_dtls_client.c @@ -0,0 +1,453 @@ +/* + * 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 . + */ +/* + * wh_posix_dtls_client.c + * + * wolfHSM DTLS Client Example + * + * This example demonstrates a DTLS client that uses wolfHSM as a cryptographic + * backend. All private key operations (ECDSA signing) and ephemeral key + * generation (ECDHE) are performed on the HSM - private keys never leave the + * secure environment. + * + * The client makes two connections: + * 1. TCP to wolfHSM server - for all cryptographic operations + * 2. UDP to external DTLS server - for secure application communication + * + * Usage: + * 1. Start wolfHSM server with client private key: + * ./wh_posix_server.elf --type tcp \ + * --key --id 1 --client 12 + * + * 2. Start external DTLS server (from wolfssl directory): + * ./examples/server/server -u -v 3 \ + * -c ./certs/server-ecc-cert.pem -k ./certs/ecc-key.pem \ + * -A ./certs/client-ecc-cert.pem -V + * + * 3. Run this DTLS client: + * ./wh_posix_dtls_client.elf 127.0.0.1 + * + * Note: Client certificates are built-in from certs_test.h, eliminating + * the need for a fixed wolfssl directory location. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* wolfSSL headers */ +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/ssl.h" +#include "wolfssl/wolfcrypt/ecc.h" +#include "wolfssl/wolfcrypt/cryptocb.h" + +/* Enable 256-bit ECC certificate buffers */ +#define USE_CERT_BUFFERS_256 +#include "wolfssl/certs_test.h" + +/* wolfHSM headers */ +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_client_crypto.h" +#include "wolfhsm/wh_client_cryptocb.h" + +/* posix headers */ +#include "port/posix/posix_transport_tcp.h" +#include "../../wh_posix_cfg.h" + +/* DTLS server connection parameters */ +#define DTLS_SERVER_PORT 11111 +#define MAX_LINE 4096 + +/* Default HSM key ID for client private key (must match server --id parameter) */ +#define HSM_KEY_ID 1 + +/* Context passed to crypto callback containing wolfHSM client info */ +typedef struct { + whClientContext* whClient; /* wolfHSM client context */ + whKeyId clientKeyId; /* HSM key ID for client private key */ +} DtlsHsmCtx; + +static DtlsHsmCtx hsmCtx; + +static posixTransportTcpClientContext tccTcp; +static posixTransportTcpConfig tcpConfig; +static whCommClientConfig commConfig; +static whTransportClientCb tcpCb = PTT_CLIENT_CB; + +/* wolfHSM client configuration setup for TCP transport */ +static int InitWolfHSMPosixTcpConfig(whClientConfig* conf) +{ + + memset(&tccTcp, 0, sizeof(posixTransportTcpClientContext)); + memset(&commConfig, 0, sizeof(whCommClientConfig)); + + tcpConfig.server_ip_string = WH_POSIX_SERVER_TCP_IPSTRING; + tcpConfig.server_port = WH_POSIX_SERVER_TCP_PORT; + + commConfig.transport_cb = &tcpCb; + commConfig.transport_context = (void*)&tccTcp; + commConfig.transport_config = (void*)&tcpConfig; + commConfig.client_id = WH_POSIX_CLIENT_ID; + conf->comm = &commConfig; + + return WH_ERROR_OK; +} +/** + * ECC Sign callback - called during TLS CertificateVerify + * + * This callback intercepts ECC signing operations during TLS handshake. + * Instead of using a local private key, it delegates signing to the HSM + * where the private key is stored. + * + * @param ssl wolfSSL session pointer (unused) + * @param in Hash to sign + * @param inSz Size of hash + * @param out Output buffer for signature + * @param outSz Input/output signature size + * @param keyDer DER-encoded key (unused - we use HSM key) + * @param keySz Size of DER key (unused) + * @param ctx User context containing HSM client and key ID + * @return 0 on success, negative on error + */ +static int myEccSignCb(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, + unsigned char* out, word32* outSz, + const unsigned char* keyDer, unsigned int keySz, + void* ctx) +{ + DtlsHsmCtx* hsmCtx = (DtlsHsmCtx*)ctx; + ecc_key eccKey[1]; + int ret; + uint16_t sigLen; + + (void)ssl; + (void)keyDer; + (void)keySz; /* unused - we use HSM key */ + + /* Initialize ECC key structure with HSM device ID */ + ret = wc_ecc_init_ex(eccKey, NULL, WH_DEV_ID); + if (ret != 0) { + printf(" EccSignCb: wc_ecc_init_ex failed: %d\n", ret); + return ret; + } + + /* Set curve parameters (P-256) */ + ret = wc_ecc_set_curve(eccKey, 32, ECC_SECP256R1); + if (ret != 0) { + printf(" EccSignCb: wc_ecc_set_curve failed: %d\n", ret); + wc_ecc_free(eccKey); + return ret; + } + + /* Associate the HSM key ID with this ecc_key structure */ + ret = wh_Client_EccSetKeyId(eccKey, hsmCtx->clientKeyId); + if (ret != 0) { + printf(" EccSignCb: wh_Client_EccSetKeyId failed: %d\n", ret); + wc_ecc_free(eccKey); + return ret; + } + + /* Perform signing on HSM - private key never leaves the HSM */ + sigLen = (uint16_t)*outSz; + ret = wh_Client_EccSign(hsmCtx->whClient, eccKey, in, (uint16_t)inSz, out, + &sigLen); + if (ret == 0) { + *outSz = sigLen; + } + else { + printf(" EccSignCb: wh_Client_EccSign failed: %d\n", ret); + } + + wc_ecc_free(eccKey); + return ret; +} + +static void Usage(const char* progName) +{ + printf("Usage: %s \n", progName); + printf(" DTLS server IP: IP address of the external DTLS server\n"); + printf("\nExample: %s 127.0.0.1\n", progName); +} + +int main(int argc, char** argv) +{ + int ret; + int sockfd = -1; + const char* dtlsServerIp; + whKeyId hsmKeyId = HSM_KEY_ID; + struct sockaddr_in servAddr; + char sendLine[MAX_LINE]; + char recvLine[MAX_LINE]; + int n; + + /* wolfHSM client */ + whClientContext whClient[1]; + whClientConfig whConfig[1]; + + /* wolfSSL/DTLS */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int err; + + /* Parse command line arguments */ + if (argc != 2) { + Usage(argv[0]); + return 1; + } + dtlsServerIp = argv[1]; + + printf("wolfHSM DTLS Client Example\n"); + printf(" HSM Key ID: %u\n", hsmKeyId); + printf(" DTLS Server: %s:%d\n", dtlsServerIp, DTLS_SERVER_PORT); + + /* + * Initialize wolfHSM client (TCP connection to HSM server) + */ + printf("\n[1] Connecting to wolfHSM server...\n"); + memset(whConfig, 0, sizeof(whClientConfig)); + ret = InitWolfHSMPosixTcpConfig(whConfig); + if (ret != 0) { + printf("ERROR: wh_PosixDtlsClient_TcpConfig failed with %d\n", ret); + return 1; + } + + ret = wh_Client_Init(whClient, whConfig); + if (ret != 0) { + printf("ERROR: wh_Client_Init failed with %d\n", ret); + return 1; + } + + ret = wh_Client_CommInit(whClient, NULL, NULL); + if (ret != 0) { + printf("ERROR: wh_Client_CommInit failed with %d\n", ret); + goto cleanup_whclient; + } + printf(" Connected to wolfHSM server\n"); + + /* + * Set up a global context to be used in the callbacks + */ + hsmCtx.whClient = whClient; + hsmCtx.clientKeyId = hsmKeyId; + + /* + * Initialize wolfSSL library + */ + ret = wolfSSL_Init(); + if (ret != WOLFSSL_SUCCESS) { + printf("ERROR: wolfSSL_Init failed\n"); + goto cleanup; + } + + /* + * Register wolfHSM crypto callback This callback will intercepts wolfCrypt + * cryptographic operations and offloads them to HSM. + */ + ret = wc_CryptoCb_RegisterDevice(WH_DEV_ID, wh_Client_CryptoCb, whClient); + if (ret != 0) { + printf("ERROR: wc_CryptoCb_RegisterDevice failed with %d\n", ret); + goto cleanup; + } + printf(" Registered wolfHSM crypto callback (devId=0x%08X)\n", WH_DEV_ID); + + /* + * Create DTLS client context + */ + printf("\n[2] Creating DTLS context...\n"); + ctx = wolfSSL_CTX_new(wolfDTLS_client_method()); + if (ctx == NULL) { + printf("ERROR: wolfSSL_CTX_new failed\n"); + goto cleanup; + } + + /* + * Configure crypto callback device ID + * This tells wolfSSL to use our HSM for crypto operations + */ + ret = wolfSSL_CTX_SetDevId(ctx, WH_DEV_ID); + if (ret != WOLFSSL_SUCCESS) { + printf("ERROR: wolfSSL_CTX_SetDevId failed\n"); + goto cleanup; + } + printf(" Configured HSM device ID for crypto operations\n"); + + /* + * Register PK callbacks for HSM operations + * These callbacks intercept (D)TLS-level ECC operations (signing during + * CertificateVerify + Shared secret generation) and delegate them to the + * HSM. It allows to use the id of a private key stored on the HSM without + * ever exposing the private key itself. + */ + wolfSSL_CTX_SetEccSignCb(ctx, myEccSignCb); + wolfSSL_CTX_SetEccSignCtx(ctx, &hsmCtx); + printf(" Registered ECC PK callbacks for HSM operations\n"); + + /* + * Load CA certificate for verifying DTLS server + */ + ret = wolfSSL_CTX_load_verify_buffer(ctx, ca_ecc_cert_der_256, + sizeof_ca_ecc_cert_der_256, + WOLFSSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + printf("ERROR: Failed to load CA certificate buffer\n"); + goto cleanup; + } + printf(" Loaded CA certificate from buffer\n"); + + /* + * Load client certificate (public part only) + * The private key is NOT loaded here - it stays on the HSM + */ + ret = wolfSSL_CTX_use_certificate_buffer(ctx, cliecc_cert_der_256, + sizeof_cliecc_cert_der_256, + WOLFSSL_FILETYPE_ASN1); + if (ret != WOLFSSL_SUCCESS) { + printf("ERROR: Failed to load client certificate buffer\n"); + goto cleanup; + } + printf(" Loaded client certificate from buffer\n"); + + /* + * Create UDP socket for DTLS + */ + printf("\n[3] Creating UDP socket...\n"); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + printf("ERROR: Cannot create socket\n"); + goto cleanup; + } + + /* Set up DTLS server address */ + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_port = htons(DTLS_SERVER_PORT); + if (inet_pton(AF_INET, dtlsServerIp, &servAddr.sin_addr) != 1) { + printf("ERROR: Invalid IP address: %s\n", dtlsServerIp); + goto cleanup; + } + printf(" Created UDP socket\n"); + + /* + * Create DTLS session + */ + printf("\n[4] Creating DTLS session...\n"); + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + printf("ERROR: wolfSSL_new failed\n"); + goto cleanup; + } + + /* Configure DTLS peer and socket */ + ret = wolfSSL_dtls_set_peer(ssl, &servAddr, sizeof(servAddr)); + if (ret != WOLFSSL_SUCCESS) { + printf("ERROR: wolfSSL_dtls_set_peer failed\n"); + goto cleanup; + } + + ret = wolfSSL_set_fd(ssl, sockfd); + if (ret != WOLFSSL_SUCCESS) { + printf("ERROR: wolfSSL_set_fd failed\n"); + goto cleanup; + } + printf(" DTLS session configured\n"); + + /* + * Step 12: Perform DTLS handshake + */ + printf("\n[5] Performing DTLS handshake...\n"); + ret = wolfSSL_connect(ssl); + if (ret != WOLFSSL_SUCCESS) { + err = wolfSSL_get_error(ssl, ret); + printf("ERROR: wolfSSL_connect failed: %d (%s)\n", + err, wolfSSL_ERR_reason_error_string(err)); + goto cleanup; + } + printf(" DTLS handshake successful!\n"); + printf(" Cipher: %s\n", wolfSSL_get_cipher(ssl)); + + /* + * Application data exchange + */ + printf("\n[6] Ready for application data\n"); + printf("Enter message to send (or empty line to quit): "); + fflush(stdout); + + if (fgets(sendLine, sizeof(sendLine), stdin) != NULL) { + size_t len = strlen(sendLine); + + /* Remove trailing newline if present */ + if (len > 0 && sendLine[len - 1] == '\n') { + sendLine[len - 1] = '\0'; + len--; + } + + if (len > 0) { + /* Send message to server */ + ret = wolfSSL_write(ssl, sendLine, (int)len); + if (ret != (int)len) { + printf("ERROR: wolfSSL_write failed\n"); + goto cleanup; + } + printf(" Sent: %s\n", sendLine); + + /* Receive response from server */ + memset(recvLine, 0, sizeof(recvLine)); + n = wolfSSL_read(ssl, recvLine, sizeof(recvLine) - 1); + if (n < 0) { + err = wolfSSL_get_error(ssl, n); + if (err != WOLFSSL_ERROR_WANT_READ) { + printf("ERROR: wolfSSL_read failed: %d\n", err); + } + } + else { + recvLine[n] = '\0'; + printf(" Received: %s\n", recvLine); + } + } + } + + /* + * Step 14: Clean shutdown + */ + printf("\n[7] Closing connection...\n"); + wolfSSL_shutdown(ssl); + printf(" DTLS connection closed\n"); + +cleanup: + wolfSSL_free(ssl); + if (sockfd >= 0) { + close(sockfd); + } + wolfSSL_CTX_free(ctx); + + wolfSSL_Cleanup(); + +cleanup_whclient: + wh_Client_CommClose(whClient); + wh_Client_Cleanup(whClient); + printf(" wolfHSM client disconnected\n"); + + printf("\nDone.\n"); + return (ret == WOLFSSL_SUCCESS) ? 0 : 1; +} diff --git a/examples/posix/tls/wh_posix_dtls_client/wolfhsm_cfg.h b/examples/posix/tls/wh_posix_dtls_client/wolfhsm_cfg.h new file mode 100644 index 00000000..b1a6fe92 --- /dev/null +++ b/examples/posix/tls/wh_posix_dtls_client/wolfhsm_cfg.h @@ -0,0 +1,37 @@ +/* + * 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 . + */ +/* + * wolfhsm_cfg.h + * + * wolfHSM compile-time options for DTLS client example + */ + +#ifndef WOLFHSM_CFG_H_ +#define WOLFHSM_CFG_H_ + +#include "port/posix/posix_time.h" + +#define WOLFHSM_CFG_PORT_GETTIME posixGetTime + +/** wolfHSM settings */ +#define WOLFHSM_CFG_ENABLE_CLIENT +#define WOLFHSM_CFG_HEXDUMP +#define WOLFHSM_CFG_COMM_DATA_LEN 5000 + +#endif /* WOLFHSM_CFG_H_ */