From 71c3a4a55b9b09526b5d506a94608a29313867e6 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Fri, 30 Jan 2026 14:52:54 +0100 Subject: [PATCH] wolfHSM: add DTLS client that uses HSM as cryptographic backend --- README.md | 10 + hsm/README.md | 23 ++ hsm/dtls_client/Makefile | 166 +++++++++++ hsm/dtls_client/README.md | 73 +++++ hsm/dtls_client/user_settings.h | 52 ++++ hsm/dtls_client/wh_dtls_client.c | 467 +++++++++++++++++++++++++++++++ hsm/dtls_client/wolfhsm_cfg.h | 36 +++ 7 files changed, 827 insertions(+) create mode 100644 hsm/README.md create mode 100644 hsm/dtls_client/Makefile create mode 100644 hsm/dtls_client/README.md create mode 100644 hsm/dtls_client/user_settings.h create mode 100644 hsm/dtls_client/wh_dtls_client.c create mode 100644 hsm/dtls_client/wolfhsm_cfg.h diff --git a/README.md b/README.md index 09ecc3fa..6caefd8d 100644 --- a/README.md +++ b/README.md @@ -379,6 +379,16 @@ Please see the [utasker/README.md](utasker/README.md) for further usage and details. +
+ +#### HSM (Hardware Security Module) + +This directory contains examples demonstrating wolfSSL integration with wolfHSM, +a portable Hardware Security Module framework. + +Please see the [wolfhsm/README.md](wolfhsm/README.md) for further details. + +
#### UEFI (wolfCrypt UEFI application Example) diff --git a/hsm/README.md b/hsm/README.md new file mode 100644 index 00000000..8991aaad --- /dev/null +++ b/hsm/README.md @@ -0,0 +1,23 @@ +# wolfHSM Examples + +Examples demonstrating wolfSSL integration with [wolfHSM](https://github.com/wolfssl/wolfhsm), +a portable Hardware Security Module (HSM) framework. + +## Examples + +### DTLS Client (`dtls_client/`) + +DTLS client with HSM-backed cryptography. Private keys stay on the HSM. + +Quick start: +```bash +cd dtls_client +make download_repos all +# Then run each component in separate terminals (see README) +``` + +See [dtls_client/README.md](dtls_client/README.md) for details. + +## Support + +For questions please email support@wolfssl.com diff --git a/hsm/dtls_client/Makefile b/hsm/dtls_client/Makefile new file mode 100644 index 00000000..79bc3e30 --- /dev/null +++ b/hsm/dtls_client/Makefile @@ -0,0 +1,166 @@ +# wolfHSM DTLS Client Example +# +# Usage: +# make download_repos # Clone wolfSSL and wolfHSM repos +# make all # Build everything (wolfSSL server, wolfHSM server, client) +# make run_hsm_server # Start wolfHSM server +# make run_dtls_server # Start wolfSSL DTLS server +# make run_client # Run the DTLS client +# make clean # Clean build artifacts +# make clean_repos # Remove cloned repositories + +BIN = wh_dtls_client + +WOLFSSL_DIR ?= ./wolfssl +WOLFHSM_DIR ?= ./wolfhsm +WOLFHSM_PORT_DIR = $(WOLFHSM_DIR)/port/posix +WOLFHSM_SERVER_DIR = $(WOLFHSM_DIR)/examples/posix/wh_posix_server + +PROJECT_DIR = . +BUILD_DIR = $(PROJECT_DIR)/Build + +# Compiler settings +CC = gcc +CSTD = -std=c99 +CFLAGS_EXTRA = -Werror -Wall -Wextra -ffunction-sections -fdata-sections +CFLAGS = $(CSTD) $(CFLAGS_EXTRA) +DEF = -D_POSIX_C_SOURCE=200809L -DWOLFSSL_USER_SETTINGS -DWOLFHSM_CFG +DEF += -DWC_USE_DEVID=0x5748534D + +INC = -I$(PROJECT_DIR) -I$(WOLFSSL_DIR) -I$(WOLFHSM_DIR) -I$(WOLFHSM_PORT_DIR) + +# Linker settings +LDFLAGS = -Wl,--gc-sections +LIBS = -lc -lm + +# Source files (wolfCrypt, wolfSSL, wolfHSM, port, project) +WOLFCRYPT_SRC := $(wildcard $(WOLFSSL_DIR)/wolfcrypt/src/*.c) +SRC_C = $(filter-out %/evp.c %/misc.c,$(WOLFCRYPT_SRC)) +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)) +SRC_C += $(wildcard $(WOLFHSM_DIR)/src/*.c) +SRC_C += $(wildcard $(WOLFHSM_PORT_DIR)/*.c) +SRC_C += $(wildcard $(PROJECT_DIR)/*.c) + +# Debug support +ifeq ($(DEBUG),1) + CFLAGS += -ggdb -g3 + LDFLAGS += -ggdb -g3 + DEF += -DWOLFHSM_CFG_DEBUG +endif + +# Object files +FILENAMES_C = $(notdir $(SRC_C)) +OBJS_C = $(addprefix $(BUILD_DIR)/, $(FILENAMES_C:.c=.o)) +vpath %.c $(dir $(SRC_C)) + +# Phony targets +.PHONY: all download_repos build_wolfssl build_wolfhsm_server build_app run_hsm_server run_dtls_server run_client clean clean_repos + +# Default target +all: check_repos build_wolfssl build_wolfhsm_server build_app + @echo "Build complete. Run 'make help' for usage instructions." + +# Clone repositories +download_repos: + @echo "=== Cloning repositories ===" + @if [ ! -d "$(WOLFSSL_DIR)" ]; then \ + git clone --depth 1 https://github.com/wolfssl/wolfssl.git $(WOLFSSL_DIR); \ + else \ + echo "wolfssl already exists, skipping clone"; \ + fi + @if [ ! -d "$(WOLFHSM_DIR)" ]; then \ + git clone --depth 1 https://github.com/wolfssl/wolfhsm.git $(WOLFHSM_DIR); \ + else \ + echo "wolfhsm already exists, skipping clone"; \ + fi + +# Check that repos exist +check_repos: + @if [ ! -d "$(WOLFSSL_DIR)" ] || [ ! -d "$(WOLFHSM_DIR)" ]; then \ + echo "Error: Repositories not found. Run 'make download_repos' first."; \ + exit 1; \ + fi + +# Build wolfSSL +# Note: The DTLS client uses its own user_settings.h to build wolfSSL statically, +# so this configure is only for the wolfSSL example server/client binaries. +build_wolfssl: check_repos + @echo "=== Building wolfSSL ===" + @if [ ! -f "$(WOLFSSL_DIR)/examples/server/server" ]; then \ + cd $(WOLFSSL_DIR) && \ + ./autogen.sh && \ + ./configure --enable-dtls --enable-dtls13 --enable-ecc && \ + make -j; \ + else \ + echo "wolfSSL already built, skipping"; \ + fi + +# Build wolfHSM POSIX server +# Note: The wolfHSM server Makefile expects WOLFSSL_DIR relative to its location +# Server is at ./wolfhsm/examples/posix/wh_posix_server/ +# wolfssl is at ./wolfssl/ +# So from server: ../../../../wolfssl +build_wolfhsm_server: check_repos + @echo "=== Building wolfHSM server ===" + @if [ ! -f "$(WOLFHSM_SERVER_DIR)/Build/wh_posix_server.elf" ]; then \ + $(MAKE) -C $(WOLFHSM_SERVER_DIR) clean || true; \ + $(MAKE) -C $(WOLFHSM_SERVER_DIR) WOLFSSL_DIR=../../../../wolfssl -j; \ + else \ + echo "wolfHSM server already built, skipping"; \ + fi + +# Build DTLS client +build_app: $(BUILD_DIR) $(BUILD_DIR)/$(BIN).elf + @echo "DTLS client built: $(BUILD_DIR)/$(BIN).elf" + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +$(BUILD_DIR)/%.o: %.c + @echo "Compiling: $(notdir $<)" + $(CC) $(CFLAGS) $(DEF) $(INC) -c -o $@ $< + +$(BUILD_DIR)/$(BIN).elf: $(OBJS_C) + @echo "Linking: $(notdir $@)" + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +# Convenience targets for running each component in separate terminals + +run_hsm_server: all + @echo "Starting wolfHSM server..." + @echo "Press Ctrl+C to stop" + @echo "" + $(WOLFHSM_SERVER_DIR)/Build/wh_posix_server.elf --type tcp \ + --key $(WOLFSSL_DIR)/certs/ecc-client-key.der \ + --id 1 --client 12 + +run_dtls_server: all + @echo "Starting wolfSSL DTLS server..." + @echo "Press Ctrl+C to stop" + @echo "" + cd $(WOLFSSL_DIR) && ./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 + +run_client: all + $(BUILD_DIR)/$(BIN).elf 127.0.0.1 + +# Clean build artifacts +clean: + @echo "Cleaning build files" + rm -rf $(BUILD_DIR) + @# Clean wolfHSM server build + @if [ -d "$(WOLFHSM_SERVER_DIR)" ]; then \ + $(MAKE) -C $(WOLFHSM_SERVER_DIR) clean 2>/dev/null || true; \ + fi + @# Clean wolfSSL build + @if [ -f "$(WOLFSSL_DIR)/Makefile" ]; then \ + $(MAKE) -C $(WOLFSSL_DIR) clean 2>/dev/null || true; \ + fi + +clean_repos: clean + @echo "Removing cloned repositories" + rm -rf $(WOLFSSL_DIR) $(WOLFHSM_DIR) diff --git a/hsm/dtls_client/README.md b/hsm/dtls_client/README.md new file mode 100644 index 00000000..35a7dd5f --- /dev/null +++ b/hsm/dtls_client/README.md @@ -0,0 +1,73 @@ +# wolfHSM DTLS Client Example + +Demonstrates a DTLS client using wolfHSM for cryptographic operations. +All private key operations are performed on the HSM - keys never leave +the secure environment. +The example uses wolfHSM posix server for HSM communication/simulation. + + +## Quick Start + +### Build +```bash +make download_repos # Clone repos (first time only) +make all # Build everything +``` + +### Run (3 separate terminals) + +**Terminal 1** - Start wolfHSM posix server: +```bash +make run_hsm_server +``` + +**Terminal 2** - Start DTLS server: +```bash +make run_dtls_server +``` + +**Terminal 3** - Run client: +```bash +make run_client +``` + +## Using Existing Repositories + +```bash +make WOLFSSL_DIR=/path/to/wolfssl WOLFHSM_DIR=/path/to/wolfhsm all +``` + +## Architecture + +``` ++------------------+ TCP +------------------+ +| DTLS Client |<------------>| wolfHSM Server | +| | | (crypto ops) | ++--------+---------+ +------------------+ + | UDP/DTLS + v ++------------------+ +| DTLS Server | +| (application) | ++------------------+ +``` + +## Makefile Targets + +| Target | Description | +|--------|-------------| +| `download_repos` | Clone wolfSSL and wolfHSM | +| `all` | Build everything (default) | +| `run_hsm_server` | Start wolfHSM server (Terminal 1) | +| `run_dtls_server` | Start wolfSSL DTLS server (Terminal 2) | +| `run_client` | Run the DTLS client (Terminal 3) | +| `clean` | Clean build artifacts | +| `clean_repos` | Remove cloned repositories | +| `help` | Show help | + +## Debug Build + +```bash +make clean +make DEBUG=1 +``` diff --git a/hsm/dtls_client/user_settings.h b/hsm/dtls_client/user_settings.h new file mode 100644 index 00000000..412bd891 --- /dev/null +++ b/hsm/dtls_client/user_settings.h @@ -0,0 +1,52 @@ +#ifndef USER_SETTINGS_H_ +#define USER_SETTINGS_H_ + + +/* POSIX system headers */ +#define HAVE_SYS_TIME_H + +/** wolfHSM Client required settings */ +/* 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/hsm/dtls_client/wh_dtls_client.c b/hsm/dtls_client/wh_dtls_client.c new file mode 100644 index 00000000..63e05fff --- /dev/null +++ b/hsm/dtls_client/wh_dtls_client.c @@ -0,0 +1,467 @@ +/* + * 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_dtls_client.c + * + * wolfHSM DTLS Client Example + * + * This example demonstrates a DTLS client that uses wolfHSM as a cryptographic + * backend. ECC signing operations 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_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 "wolfhsm/port/posix/posix_transport_tcp.h" + +/* Configuration constants (wolfHSM posix default port wh_posix_cfg.h) */ +#define HSM_POSIX_SERVER_TCP_PORT 23456 +#define HSM_POSIX_SERVER_TCP_IPSTRING "127.0.0.1" +#define HSM_CLIENT_ID 12 + +/* 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 to wolfHSM server */ +static int InitWolfHSMPosixTcpConfig(whClientConfig* conf) +{ + + memset(&tccTcp, 0, sizeof(posixTransportTcpClientContext)); + memset(&commConfig, 0, sizeof(whCommClientConfig)); + + tcpConfig.server_ip_string = HSM_POSIX_SERVER_TCP_IPSTRING; + tcpConfig.server_port = HSM_POSIX_SERVER_TCP_PORT; + + commConfig.transport_cb = &tcpCb; + commConfig.transport_context = (void*)&tccTcp; + commConfig.transport_config = (void*)&tcpConfig; + commConfig.client_id = HSM_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("\nBefore running this client, start the servers in separate terminals:\n"); + printf("\n Terminal 1 - Start wolfHSM server:\n"); + printf(" ./wh_posix_server.elf --type tcp \\\n"); + printf(" --key --id 1 --client 12\n"); + printf("\n Terminal 2 - Start wolfSSL DTLS server (from wolfssl directory):\n"); + printf(" ./examples/server/server -u -v 4 \\\n"); + printf(" -c ./certs/server-ecc.pem -k ./certs/ecc-key.pem \\\n"); + printf(" -A ./certs/client-ecc-cert.pem -p 11111 -i\n"); + printf("\n Terminal 3 - Run this client:\n"); + printf(" %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) 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); + } + } + } + + /* + * Clean shutdown - we made it here so operation was successful + */ + printf("\n[7] Closing connection...\n"); + wolfSSL_shutdown(ssl); + printf(" DTLS connection closed\n"); + + ret = WOLFSSL_SUCCESS; + +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/hsm/dtls_client/wolfhsm_cfg.h b/hsm/dtls_client/wolfhsm_cfg.h new file mode 100644 index 00000000..b1cf4767 --- /dev/null +++ b/hsm/dtls_client/wolfhsm_cfg.h @@ -0,0 +1,36 @@ +/* + * 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 "wolfhsm/port/posix/posix_time.h" + +#define WOLFHSM_CFG_PORT_GETTIME posixGetTime + +/** wolfHSM settings */ +#define WOLFHSM_CFG_ENABLE_CLIENT +#define WOLFHSM_CFG_COMM_DATA_LEN 5000 + +#endif /* WOLFHSM_CFG_H_ */