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_ */