diff --git a/.github/workflows/build-and-run-generic-port.yml b/.github/workflows/build-and-run-generic-port.yml
new file mode 100644
index 000000000..e4456fe0a
--- /dev/null
+++ b/.github/workflows/build-and-run-generic-port.yml
@@ -0,0 +1,40 @@
+name: Build and Run Generic Port
+
+on:
+ push:
+ branches: [ 'master', 'main', 'release/**' ]
+ pull_request:
+ branches: [ '*' ]
+
+jobs:
+ build:
+ strategy:
+ matrix:
+ include:
+ - name: "Standard"
+ flags: ""
+ - name: "ASAN"
+ flags: "ASAN=1"
+ - name: "DEBUG"
+ flags: "DEBUG=1"
+ - name: "DEBUG ASAN"
+ flags: "DEBUG=1 ASAN=1"
+
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ name: Generic Port (${{ matrix.name }})
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Checkout wolfssl
+ uses: actions/checkout@v4
+ with:
+ repository: wolfssl/wolfssl
+ path: wolfssl
+
+ - name: Build generic server
+ run: cd port/posix/server && make -j ${{ matrix.flags }} WOLFSSL_DIR=../../../wolfssl
+
+ - name: Build generic client
+ run: cd port/posix/client && make -j ${{ matrix.flags }} WOLFSSL_DIR=../../../wolfssl
diff --git a/benchmark/wh_bench.c b/benchmark/wh_bench.c
index 12c47e79b..82d3ded1d 100644
--- a/benchmark/wh_bench.c
+++ b/benchmark/wh_bench.c
@@ -16,6 +16,9 @@
* You should have received a copy of the GNU General Public License
* along with wolfHSM. If not, see .
*/
+
+#include "wolfhsm/wh_settings.h"
+
#include
#include /* For memset, memcpy */
@@ -25,7 +28,6 @@
#include /* For sleep */
#endif
-#include "wolfhsm/wh_settings.h"
#include "wolfhsm/wh_error.h"
#include "wolfhsm/wh_comm.h"
@@ -751,6 +753,7 @@ typedef struct {
int transport;
} whBenchClientTaskData;
+#if defined(WOLFHSM_CFG_ENABLE_SERVER) && defined(WOLFHSM_CFG_ENABLE_CLIENT)
static void* _whBenchClientTask(void* data)
{
whBenchClientTaskData* taskData = (whBenchClientTaskData*)data;
@@ -838,7 +841,8 @@ static void _whBenchClientServerThreadTest(whClientConfig* c_conf,
}
}
-/* Global static variables for transport configurations */
+/* Global static variables for transport configurations (used by
+ * wh_Bench_ClientServer_Posix which requires both client and server) */
static uint8_t g_mem_req[BUFFER_SIZE] = {0};
static uint8_t g_mem_resp[BUFFER_SIZE] = {0};
static whTransportMemConfig g_mem_tmcf = {
@@ -1016,7 +1020,6 @@ static int _configureServerTransport(whBenchTransportType transport,
return ret;
}
-
/* transport is the type of transport to use */
int wh_Bench_ClientServer_Posix(int transport, int moduleIndex)
{
@@ -1131,6 +1134,7 @@ int wh_Bench_ClientServer_Posix(int transport, int moduleIndex)
return WH_ERROR_OK;
}
+#endif /* WOLFHSM_CFG_ENABLE_SERVER && WOLFHSM_CFG_ENABLE_CLIENT */
#endif /* WOLFHSM_CFG_TEST_POSIX */
diff --git a/docs/draft/porting.md b/docs/draft/porting.md
new file mode 100644
index 000000000..dc81d4c5c
--- /dev/null
+++ b/docs/draft/porting.md
@@ -0,0 +1,317 @@
+# Porting wolfHSM
+
+This guide describes how to port wolfHSM to a new platform. A port provides
+platform-specific implementations of transport, flash/NVM, and the `wh_Port_*`
+generic API so that the platform-independent client and server examples in
+`examples/generic/` can run on your hardware.
+
+The POSIX port in `port/posix/` serves as a reference implementation throughout
+this guide.
+
+## Directory Layout
+
+A port lives under `port//` and typically has this structure:
+
+```
+port//
+├── Makefile # Top-level: delegates to client/ and server/
+├── .c/h # Platform-specific shared code
+├── client/
+│ ├── Makefile
+│ ├── wolfhsm_cfg.h # wolfHSM compile-time configuration
+│ ├── user_settings.h # wolfSSL compile-time configuration
+│ └── wh__client_port.c # wh_Port_* client implementation
+└── server/
+ ├── Makefile
+ ├── wolfhsm_cfg.h
+ ├── user_settings.h
+ └── wh__server_port.c # wh_Port_* server implementation
+```
+
+The client and server are built as separate binaries with separate configuration
+headers. This separation is important because the client and server typically
+have different wolfSSL feature sets, crypto algorithm support, and wolfHSM roles.
+
+## Step 1: Implement a Transport
+
+wolfHSM communicates between client and server through a transport layer. You
+must provide callback tables that match these interfaces (defined in
+`wolfhsm/wh_comm.h`):
+
+### Client Transport Callbacks
+
+```c
+typedef struct {
+ int (*Init)(void* context, const void* config,
+ whCommSetConnectedCb connectcb, void* connectcb_arg);
+ int (*Send)(void* context, uint16_t size, const void* data);
+ int (*Recv)(void* context, uint16_t *out_size, void* data);
+ int (*Cleanup)(void* context);
+} whTransportClientCb;
+```
+
+### Server Transport Callbacks
+
+```c
+typedef struct {
+ int (*Init)(void* context, const void* config,
+ whCommSetConnectedCb connectcb, void* connectcb_arg);
+ int (*Recv)(void* context, uint16_t *out_size, void* data);
+ int (*Send)(void* context, uint16_t size, const void* data);
+ int (*Cleanup)(void* context);
+} whTransportServerCb;
+```
+
+### Return Codes
+
+All transport callbacks must return:
+
+- `WH_ERROR_OK` (0) — Success.
+- `WH_ERROR_BADARGS` — NULL context/config or invalid parameters.
+- `WH_ERROR_NOTREADY` — Operation cannot complete yet; caller should retry.
+- `WH_ERROR_ABORTED` — Fatal error; caller should clean up.
+
+### Guidelines
+
+- `Init` must store the `connectcb` and call it with `WH_COMM_CONNECTED` when
+ the transport link is established. The generic server loop relies on this
+ notification to know when a client has connected.
+- `Send` and `Recv` should be non-blocking. Return `WH_ERROR_NOTREADY` if the
+ operation cannot complete immediately.
+- Transport implementations typically define a macro (e.g. `PTT_CLIENT_CB`,
+ `PTT_SERVER_CB`) that expands to the callback table initializer.
+
+See `port/posix/posix_transport_tcp.c` for a TCP socket-based reference
+implementation.
+
+wolfHSM also provides a shared memory transport (`wh_transport_mem`) that uses a
+shared memory region containing request and response buffers plus an optional DMA
+block. One side creates the shared region; the other maps it by name or address.
+The DMA region allows the client to use DMA-style requests by setting its DMA
+base address to the mapped address of the shared block. This transport is well
+suited for platforms where client and server share an address space or have
+hardware-mapped shared memory (e.g. dual-core HSM designs).
+
+## Step 2: Implement Flash and NVM (Server Only)
+
+The server requires a flash backend for NVM storage. Implement the `whFlashCb`
+callback table defined in `wolfhsm/wh_flash.h`:
+
+```c
+typedef struct {
+ int (*Init)(void* context, const void* config);
+ int (*Cleanup)(void* context);
+ uint32_t (*PartitionSize)(void* context);
+ int (*WriteLock)(void* context, uint32_t offset, uint32_t size);
+ int (*WriteUnlock)(void* context, uint32_t offset, uint32_t size);
+ int (*Read)(void* context, uint32_t offset, uint32_t size, uint8_t* data);
+ int (*Program)(void* context, uint32_t offset, uint32_t size,
+ const uint8_t* data);
+ int (*Erase)(void* context, uint32_t offset, uint32_t size);
+ int (*Verify)(void* context, uint32_t offset, uint32_t size,
+ const uint8_t* data);
+ int (*BlankCheck)(void* context, uint32_t offset, uint32_t size);
+} whFlashCb;
+```
+
+For development and testing, wolfHSM provides `wh_flash_ramsim` — a RAM-based
+flash simulator that can be used on any platform. The POSIX server port uses
+this. For production, you will typically implement callbacks that talk to your
+platform's actual flash hardware.
+
+The flash backend is wired into NVM through `whNvmFlashConfig` and
+`whNvmFlashContext`, then into the server via `whNvmConfig`. See
+`port/posix/server/wh_posix_server_port.c` (`wh_Port_ConfigureServer`) for the
+full wiring example.
+
+## Step 3: Implement the wh_Port_* API
+
+The `wh_Port_*` functions (declared in `wolfhsm/wh_port.h`) are the glue
+between the generic examples and your platform. You implement them in your
+port's `wh__client_port.c` and `wh__server_port.c`.
+
+### Common Functions
+
+```c
+int wh_Port_InitBoard(void);
+```
+
+Called once at startup. Initialize any shared platform resources: crypto
+libraries, IPC mechanisms, signal handlers, or hardware peripherals.
+
+```c
+int wh_Port_CleanupBoard(void);
+```
+
+Called at shutdown. Release resources allocated by `InitBoard`.
+
+### Client Functions
+
+```c
+int wh_Port_ConfigureClient(whClientConfig* clientCfg);
+```
+
+Populate `clientCfg` with transport callbacks, transport context/config, client
+ID, and optionally a connect callback. The transport context and configuration
+structures must be statically allocated (they must outlive the client).
+
+```c
+int wh_Port_InitClient(whClientConfig* clientCfg, whClientContext* clientCtx);
+```
+
+Initialize the client context and establish communication. Typically calls
+`wh_Client_Init()` followed by `wh_Client_CommInit()`.
+
+```c
+int wh_Port_RunClient(whClientContext* clientCtx);
+```
+
+Execute the client workload. This is where your application logic goes — echo
+requests, key operations, crypto operations, etc. Should call
+`wh_Client_CommClose()` and `wh_Client_Cleanup()` before returning.
+
+### Server Functions
+
+```c
+int wh_Port_ConfigureServer(size_t instance, whServerConfig* serverCfg);
+```
+
+Populate `serverCfg` with transport, NVM, and crypto configuration for the given
+server instance. The `instance` parameter supports multiple server instances
+(e.g. serving multiple clients concurrently).
+
+```c
+int wh_Port_InitServer(size_t instance, whServerConfig* serverCfg,
+ whServerContext* serverCtx);
+```
+
+Initialize a server instance. Typically calls `wh_Server_Init()`.
+
+```c
+int wh_Port_CleanupServer(size_t instance, whServerContext* serverCtx);
+```
+
+Clean up a server instance. Typically calls `wh_Server_Cleanup()`.
+
+```c
+int wh_Port_ClientConnected(size_t instance);
+int wh_Port_ClientDisconnected(size_t instance);
+```
+
+Polling functions that return 1 **once** when a client connects or disconnects
+from the given server instance, and 0 otherwise. The generic server loop uses
+these to decide when to initialize or tear down server instances.
+
+How you implement the notification mechanism is platform-specific. The POSIX port
+uses a named FIFO: the client's `connect_cb` writes a byte to the FIFO on
+connect/disconnect, and the server reads from it in these polling functions.
+Other ports might use shared memory flags, hardware interrupts, or mailbox
+registers.
+
+## Step 4: Create Configuration Headers
+
+### wolfhsm_cfg.h
+
+This header defines wolfHSM compile-time options. It must be on the include path
+before any wolfHSM headers are included (achieved by putting the project
+directory first in `-I` flags).
+
+**Required defines:**
+
+| Define | Description |
+|--------|-------------|
+| `WOLFHSM_CFG_ENABLE_CLIENT` | Enable client functionality (client build) |
+| `WOLFHSM_CFG_ENABLE_SERVER` | Enable server functionality (server build) |
+| `WOLFHSM_CFG_COMM_DATA_LEN` | Max comm payload size in bytes |
+| `WOLFHSM_CFG_NVM_OBJECT_COUNT` | Max NVM objects (must match client and server) |
+
+**Port-specific defines** (naming convention: `WOLFHSM_CFG_PORT_*`):
+
+| Define | Description |
+|--------|-------------|
+| `WOLFHSM_CFG_PORT_GETTIME` | Function returning current time in microseconds (`uint64_t`) |
+| `WOLFHSM_CFG_PORT_CLIENT_ID` | Client identifier byte |
+| `WOLFHSM_CFG_PORT_SERVER_ID` | Server identifier byte |
+| `WOLFHSM_CFG_PORT_SERVER_COUNT` | Number of server instances |
+
+You may define additional `WOLFHSM_CFG_PORT_*` macros for your platform's
+transport configuration (IP addresses, ports, memory regions, etc.).
+
+**Server-specific defines** (see `wolfhsm/wh_settings.h` for full list):
+
+| Define | Description |
+|--------|-------------|
+| `WOLFHSM_CFG_SERVER_KEYCACHE_COUNT` | Number of key cache slots |
+| `WOLFHSM_CFG_SERVER_KEYCACHE_SIZE` | Size of each key cache slot |
+| `WOLFHSM_CFG_SERVER_DMAADDR_COUNT` | Number of DMA address entries |
+| `WOLFHSM_CFG_SERVER_CUSTOMCB_COUNT` | Number of custom callback slots |
+
+**Optional test/benchmark defines:**
+
+| Define | Description |
+|--------|-------------|
+| `WOLFHSM_CFG_PORT_ENABLE_WOLFHSM_TESTS` | Build and run wolfHSM tests |
+| `WOLFHSM_CFG_PORT_ENABLE_BENCHMARK` | Build and run benchmarks |
+| `WOLFHSM_CFG_TEST_POSIX` | Enable POSIX-specific test infrastructure |
+| `WOLFHSM_CFG_TEST_CLIENT_ONLY` | Suppress combined client+server test code |
+
+### user_settings.h
+
+This header defines wolfSSL compile-time options. Both client and server need
+one, but they will differ.
+
+**Common required defines:**
+
+```c
+#define WOLF_CRYPTO_CB /* CryptoCB support */
+#define WOLFSSL_KEY_GEN /* Key DER export/import */
+#define WOLFSSL_ASN_TEMPLATE /* ASN.1 template support */
+#define WOLFSSL_BASE64_ENCODE /* Base64 encoding */
+#define HAVE_ANONYMOUS_INLINE_AGGREGATES 1
+#define NO_INLINE /* C90 compatibility */
+#define TFM_TIMING_RESISTANT /* Side-channel resistance */
+#define ECC_TIMING_RESISTANT
+#define WC_RSA_BLINDING
+```
+
+Then enable the crypto algorithms your application needs (`HAVE_ECC`,
+`HAVE_AESGCM`, `HAVE_CURVE25519`, etc.).
+
+**Important:** `WOLFHSM_CFG_NVM_OBJECT_COUNT` and `WOLFHSM_CFG_COMM_DATA_LEN`
+must have the same values in both client and server configurations. Mismatches
+cause runtime failures.
+
+## Step 5: Create the Build System
+
+Your Makefile needs to:
+
+1. Put the project directory (containing `wolfhsm_cfg.h` and `user_settings.h`)
+ **first** on the include path.
+2. Define `-DWOLFSSL_USER_SETTINGS -DWOLFHSM_CFG` so the libraries pick up your
+ configuration headers.
+3. Compile and link:
+ - wolfSSL/wolfCrypt sources (unless building without crypto)
+ - wolfHSM sources from `src/`
+ - Your port's shared code
+ - Your port's `wh_Port_*` implementation
+ - The generic entry point (`examples/generic/wh_generic_client.c` or
+ `wh_generic_server.c`)
+ - Test and benchmark sources if enabled
+
+See `port/posix/client/Makefile` for a complete example.
+
+## Checklist
+
+- [ ] Transport callbacks implemented (Init, Send, Recv, Cleanup)
+- [ ] Flash callbacks implemented (or using `wh_flash_ramsim` for development)
+- [ ] `wh_Port_InitBoard` / `wh_Port_CleanupBoard` implemented for both sides
+- [ ] `wh_Port_ConfigureClient` / `wh_Port_InitClient` / `wh_Port_RunClient`
+ implemented
+- [ ] `wh_Port_ConfigureServer` / `wh_Port_InitServer` / `wh_Port_CleanupServer`
+ implemented
+- [ ] `wh_Port_ClientConnected` / `wh_Port_ClientDisconnected` implemented
+- [ ] `wolfhsm_cfg.h` created for client and server with matching
+ `WOLFHSM_CFG_COMM_DATA_LEN` and `WOLFHSM_CFG_NVM_OBJECT_COUNT`
+- [ ] `user_settings.h` created for client and server
+- [ ] Build system compiles and links both binaries
+- [ ] Client can connect, send echo requests, and disconnect cleanly
diff --git a/examples/generic/README.md b/examples/generic/README.md
new file mode 100644
index 000000000..81d73de61
--- /dev/null
+++ b/examples/generic/README.md
@@ -0,0 +1,24 @@
+# Generic Examples
+
+Generic client and server entry points that use the `wh_Port_*` abstraction API
+defined in `wolfhsm/wh_port.h`. These examples are platform-independent and
+rely on a port implementation (e.g. `port/posix/`) to provide the concrete
+transport, NVM, and crypto configuration.
+
+## Files
+
+- `wh_generic_client.c` - Client entry point. Optionally runs wolfHSM tests and
+ benchmarks, then connects to the server and executes echo requests.
+- `wh_generic_server.c` - Server entry point. Listens for client connections and
+ handles request messages in a polling loop.
+
+## Building
+
+These files are not built directly. Each port provides its own Makefile that
+compiles the generic examples together with the port-specific `wh_Port_*`
+implementation. For example:
+
+```
+cd port/posix
+make
+```
diff --git a/examples/generic/wh_generic_client.c b/examples/generic/wh_generic_client.c
new file mode 100644
index 000000000..08df2a9a8
--- /dev/null
+++ b/examples/generic/wh_generic_client.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * examples/generic/wh_generic_client.c
+ *
+ * Generic client entry point using the wh_Port_* abstraction API.
+ */
+
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_port.h"
+
+#ifdef WOLFHSM_CFG_PORT_ENABLE_WOLFHSM_TESTS
+#include "test/wh_test.h"
+#endif /* WOLFHSM_CFG_PORT_ENABLE_WOLFHSM_TESTS */
+
+#ifdef WOLFHSM_CFG_PORT_ENABLE_BENCHMARK
+#include "benchmark/wh_bench.h"
+#endif /* WOLFHSM_CFG_PORT_ENABLE_BENCHMARK */
+
+int main(void)
+{
+ int err;
+ whClientConfig clientCfg;
+ whClientContext clientCtx;
+
+ WOLFHSM_CFG_PRINTF("Starting generic client...\n");
+
+ err = wh_Port_InitBoard();
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Port_InitBoard failed: %d\n", err);
+ goto loop;
+ }
+
+ err = wh_Port_ConfigureClient(&clientCfg);
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Port_ConfigureClient failed: %d\n", err);
+ goto loop;
+ }
+
+#ifdef WOLFHSM_CFG_PORT_ENABLE_WOLFHSM_TESTS
+
+ WOLFHSM_CFG_PRINTF("\n========== CLIENT TESTS ==========\n\n");
+ err = whTest_ClientConfig(&clientCfg);
+ if (err) {
+ WOLFHSM_CFG_PRINTF("whTest_ClientConfig failed: %d\n", err);
+ goto loop;
+ }
+
+#endif /* WOLFHSM_CFG_PORT_ENABLE_WOLFHSM_TESTS */
+
+#ifdef WOLFHSM_CFG_PORT_ENABLE_BENCHMARK
+
+ WOLFHSM_CFG_PRINTF("\n========== BENCHMARKS ==========\n\n");
+ err = wh_Bench_ClientCfg(&clientCfg, WOLFHSM_CFG_PORT_BENCH_TRANSPORT);
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Bench_ClientCfg failed: %d\n", err);
+ goto loop;
+ }
+
+#endif /* WOLFHSM_CFG_PORT_ENABLE_BENCHMARK */
+
+ WOLFHSM_CFG_PRINTF("Connecting to server...\n");
+ err = wh_Port_InitClient(&clientCfg, &clientCtx);
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Port_InitClient failed: %d\n", err);
+ goto loop;
+ }
+ WOLFHSM_CFG_PRINTF("Client initialized\n");
+
+ WOLFHSM_CFG_PRINTF("Running client...\n");
+ err = wh_Port_RunClient(&clientCtx);
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Port_RunClient failed: %d\n", err);
+ }
+
+ err = wh_Port_CleanupClient(&clientCtx);
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Port_CleanupClient failed: %d\n", err);
+ }
+
+ WOLFHSM_CFG_PRINTF("Client finished\n");
+ wh_Port_CleanupBoard();
+
+loop:
+ while (1);
+
+ return 0;
+}
diff --git a/examples/generic/wh_generic_server.c b/examples/generic/wh_generic_server.c
new file mode 100644
index 000000000..b59eefd09
--- /dev/null
+++ b/examples/generic/wh_generic_server.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * examples/generic/wh_generic_server.c
+ *
+ * Generic server entry point using the wh_Port_* abstraction API.
+ */
+
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_server.h"
+#include "wolfhsm/wh_port.h"
+
+int main(void)
+{
+ int err;
+ int isConnected[WOLFHSM_CFG_PORT_SERVER_COUNT] = {0};
+ whServerContext serverCtx[WOLFHSM_CFG_PORT_SERVER_COUNT];
+ whServerConfig serverCfg[WOLFHSM_CFG_PORT_SERVER_COUNT];
+
+ WOLFHSM_CFG_PRINTF("Starting generic server...\n");
+
+ err = wh_Port_InitBoard();
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Port_InitBoard failed: %d\n", err);
+ goto loop;
+ }
+
+ for (size_t i = 0; i < WOLFHSM_CFG_PORT_SERVER_COUNT; ++i) {
+ err = wh_Port_ConfigureServer(i, &serverCfg[i]);
+ if (err) {
+ WOLFHSM_CFG_PRINTF("wh_Port_ConfigureServer(%zu) failed: %d\n", i,
+ err);
+ goto loop;
+ }
+ }
+
+ WOLFHSM_CFG_PRINTF("Server configured, waiting for connections...\n");
+
+ while (1) {
+ for (size_t i = 0; i < WOLFHSM_CFG_PORT_SERVER_COUNT; ++i) {
+ if (!isConnected[i]) {
+ if (wh_Port_ClientConnected(i)) {
+ err = wh_Port_InitServer(i, &serverCfg[i], &serverCtx[i]);
+ if (err) {
+ WOLFHSM_CFG_PRINTF(
+ "wh_Port_InitServer(%zu) failed: %d\n", i, err);
+ goto loop;
+ }
+
+ err = wh_Server_SetConnected(&serverCtx[i],
+ WH_COMM_CONNECTED);
+ if (err) {
+ WOLFHSM_CFG_PRINTF(
+ "wh_Server_SetConnected(%zu) failed: %d\n", i, err);
+ goto loop;
+ }
+ isConnected[i] = 1;
+ WOLFHSM_CFG_PRINTF("Client connected on instance %zu\n", i);
+ }
+ }
+ else {
+ if (wh_Port_ClientDisconnected(i)) {
+ WOLFHSM_CFG_PRINTF("Client disconnected on instance %zu\n",
+ i);
+ err = wh_Port_CleanupServer(i, &serverCtx[i]);
+ if (err) {
+ WOLFHSM_CFG_PRINTF(
+ "wh_Port_CleanupServer(%zu) failed: %d\n", i, err);
+ goto loop;
+ }
+ isConnected[i] = 0;
+ }
+ else {
+ err = wh_Server_HandleRequestMessage(&serverCtx[i]);
+ if (err != WH_ERROR_OK && err != WH_ERROR_NOTREADY) {
+ WOLFHSM_CFG_PRINTF(
+ "wh_Server_HandleRequestMessage(%zu) failed: "
+ "%d\n",
+ i, err);
+ goto loop;
+ }
+ }
+ }
+ }
+ }
+
+loop:
+ while (1)
+ ;
+}
diff --git a/port/posix/Makefile b/port/posix/Makefile
new file mode 100644
index 000000000..6d8d1f78f
--- /dev/null
+++ b/port/posix/Makefile
@@ -0,0 +1,16 @@
+## Makefile for building the generic wolfHSM client and server
+## using the POSIX port implementation.
+
+.PHONY: all client server clean
+
+all: client server
+
+client:
+ $(MAKE) -C client build_app
+
+server:
+ $(MAKE) -C server build_app
+
+clean:
+ $(MAKE) -C client clean
+ $(MAKE) -C server clean
diff --git a/port/posix/client/Makefile b/port/posix/client/Makefile
new file mode 100644
index 000000000..633f4e1c3
--- /dev/null
+++ b/port/posix/client/Makefile
@@ -0,0 +1,133 @@
+## Makefile for wolfHSM generic client using POSIX port
+
+BIN = client
+
+## Important directories
+PROJECT_DIR ?= .
+WOLFSSL_DIR ?= ../../../../wolfssl
+WOLFHSM_DIR ?= ../../../
+PORT_DIR ?= ../
+GENERIC_DIR ?= $(WOLFHSM_DIR)/examples/generic
+
+BUILD_DIR ?= $(PROJECT_DIR)/Build
+
+# Includes (project dir first for wolfhsm_cfg.h / user_settings.h)
+INC = -I$(PROJECT_DIR) \
+ -I$(WOLFSSL_DIR) \
+ -I$(WOLFHSM_DIR) \
+ -I$(WOLFHSM_DIR)/test \
+ -I$(WOLFHSM_DIR)/benchmark \
+ -I$(WOLFHSM_DIR)/benchmark/bench_modules \
+ -I$(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
+
+ARCHFLAGS ?=
+CFLAGS_EXTRA ?= -Werror -Wall -Wextra -ffunction-sections -fdata-sections -g
+CSTD ?= -std=c99
+CFLAGS ?= $(ARCHFLAGS) $(CSTD) $(CFLAGS_EXTRA)
+LDFLAGS ?= $(ARCHFLAGS)
+
+OS_NAME := $(shell uname -s | tr A-Z a-z)
+ifeq ($(OS_NAME),darwin)
+ LDFLAGS += -Wl,-dead_strip
+else
+ LDFLAGS += -Wl,--gc-sections
+endif
+
+LIBS = -lc -lm
+CMD_ECHO ?=
+
+ifeq ($(DEBUG),1)
+ DBGFLAGS = -ggdb -g3
+ CFLAGS += $(DBGFLAGS)
+ LDFLAGS += $(DBGFLAGS)
+ DEF += -DWOLFHSM_CFG_DEBUG
+endif
+
+ifeq ($(DEBUG_VERBOSE),1)
+ DBGFLAGS = -ggdb -g3
+ CFLAGS += $(DBGFLAGS)
+ LDFLAGS += $(DBGFLAGS)
+ DEF += -DWOLFHSM_CFG_DEBUG -DWOLFHSM_CFG_DEBUG_VERBOSE
+endif
+
+ifeq ($(ASAN),1)
+ CFLAGS += -fsanitize=address
+ LDFLAGS += -fsanitize=address
+endif
+
+## Source files
+SRC_C =
+
+ifneq ($(NOCRYPTO),1)
+SRC_C += $(wildcard $(WOLFSSL_DIR)/wolfcrypt/src/*.c)
+SRC_C += $(wildcard $(WOLFSSL_DIR)/wolfcrypt/test/*.c)
+SRC_C += $(wildcard $(WOLFSSL_DIR)/wolfcrypt/benchmark/*.c)
+SRC_C += $(wildcard $(WOLFSSL_DIR)/src/*.c)
+DEF += -DWC_USE_DEVID=0x5748534D
+else
+DEF += -DWOLFHSM_CFG_NO_CRYPTO
+endif
+
+# wolfHSM source files
+SRC_C += $(wildcard $(WOLFHSM_DIR)/src/*.c)
+
+# POSIX port shared code
+SRC_C += $(wildcard $(PORT_DIR)/*.c)
+
+# Port client implementation (wh_Port_* functions)
+SRC_C += $(PROJECT_DIR)/wh_posix_client_port.c
+
+# wolfHSM test sources
+SRC_C += $(wildcard $(WOLFHSM_DIR)/test/*.c)
+
+# wolfHSM benchmark sources
+SRC_C += $(WOLFHSM_DIR)/benchmark/wh_bench.c
+SRC_C += $(WOLFHSM_DIR)/benchmark/wh_bench_data.c
+SRC_C += $(WOLFHSM_DIR)/benchmark/wh_bench_ops.c
+SRC_C += $(wildcard $(WOLFHSM_DIR)/benchmark/bench_modules/*.c)
+
+# Generic client entry point
+SRC_C += $(GENERIC_DIR)/wh_generic_client.c
+
+## Object files in Build directory
+OBJS_C = $(addprefix $(BUILD_DIR)/, $(notdir $(SRC_C:.c=.o)))
+
+## Compile rule: find source by trying each source directory
+COMPILE = $(CC) $(CFLAGS) $(DEF) $(INC) -c -o $@ $<
+
+# Collect unique source directories
+SRC_DIRS = $(sort $(dir $(SRC_C)))
+
+# Generate a pattern rule for each source directory
+define COMPILE_RULE
+$(BUILD_DIR)/%.o: $(1)%.c | $(BUILD_DIR)
+ @echo "Compiling: $$(notdir $$<)"
+ $$(CMD_ECHO) $$(COMPILE)
+endef
+
+$(foreach dir,$(SRC_DIRS),$(eval $(call COMPILE_RULE,$(dir))))
+
+## Makefile Targets
+
+.PHONY: build_app clean
+
+build_app: | $(BUILD_DIR)
+build_app: $(BUILD_DIR)/$(BIN).elf
+ @echo Build complete.
+
+$(BUILD_DIR)/$(BIN).elf: $(OBJS_C) | $(BUILD_DIR)
+ @echo "Linking: $(notdir $@)"
+ $(CMD_ECHO) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+$(BUILD_DIR):
+ $(CMD_ECHO) mkdir -p $(BUILD_DIR)
+
+clean:
+ @echo "Cleaning build files"
+ @rm -rf $(BUILD_DIR)
diff --git a/port/posix/client/user_settings.h b/port/posix/client/user_settings.h
new file mode 100644
index 000000000..42b8bf937
--- /dev/null
+++ b/port/posix/client/user_settings.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/posix/client/user_settings.h
+ *
+ * wolfSSL compile-time options for the POSIX generic client.
+ */
+
+#ifndef USER_SETTINGS_H_
+#define USER_SETTINGS_H_
+
+/** wolfHSM Client required settings */
+
+/* CryptoCB support */
+#define WOLF_CRYPTO_CB
+#define HAVE_ANONYMOUS_INLINE_AGGREGATES 1
+
+/* Key DER export/import support */
+#define WOLFSSL_KEY_GEN
+#define WOLFSSL_ASN_TEMPLATE
+#define WOLFSSL_BASE64_ENCODE
+
+/* C90 compatibility, which doesn't support inline keyword */
+#define NO_INLINE
+/* Suppresses warning in evp.c */
+#define WOLFSSL_IGNORE_FILE_WARN
+
+/* Either NO_HARDEN or set resistance and blinding */
+#define TFM_TIMING_RESISTANT
+#define ECC_TIMING_RESISTANT
+#define WC_RSA_BLINDING
+
+/** Application Settings */
+
+/* Crypto Algo Options */
+#define HAVE_CURVE25519
+#define HAVE_ECC
+#define HAVE_AES_CBC
+#define WOLFSSL_AES_COUNTER
+#define HAVE_AESGCM
+#define WOLFSSL_AES_DIRECT
+#define WOLFSSL_CMAC
+#define HAVE_HKDF
+
+/* Disable PKCS12 (not needed for HSM operations) */
+#define NO_PKCS12
+
+/* wolfCrypt test/benchmark settings */
+#define NO_MAIN_DRIVER
+#define NO_FILESYSTEM
+
+/* Include to ensure clock_gettime is declared for benchmark.c */
+#include
+/* Include to support strcasecmp with POSIX build */
+#include
+
+#endif /* USER_SETTINGS_H_ */
diff --git a/port/posix/client/wh_posix_client_port.c b/port/posix/client/wh_posix_client_port.c
new file mode 100644
index 000000000..6bec519ec
--- /dev/null
+++ b/port/posix/client/wh_posix_client_port.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/posix/client/wh_posix_client_port.c
+ *
+ * POSIX client implementation of the wh_Port_* generic port API.
+ * Uses TCP transport. Configuration is provided through WOLFHSM_CFG_PORT_*
+ * defines which must be set by the application (e.g. via a config header).
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_comm.h"
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_port.h"
+
+#include "port/posix/posix_transport_tcp.h"
+
+/* Transport context and configuration - must persist for lifetime of client */
+static posixTransportTcpClientContext tcpClientCtx;
+static posixTransportTcpConfig tcpConfig;
+static whCommClientConfig commConfig;
+static whTransportClientCb tcpCb = PTT_CLIENT_CB;
+
+/* Notification FIFO fd — opened once and kept open */
+static int notifyFd = -1;
+
+int wh_Port_InitBoard(void)
+{
+ /* Create the FIFO if it doesn't exist (EEXIST is OK) */
+ if (mkfifo(WOLFHSM_CFG_PORT_NOTIFY_PATH, 0666) != 0 && errno != EEXIST) {
+ return WH_ERROR_ABORTED;
+ }
+
+ /* O_RDWR avoids blocking when no reader is open yet */
+ notifyFd = open(WOLFHSM_CFG_PORT_NOTIFY_PATH, O_RDWR | O_NONBLOCK);
+ if (notifyFd < 0) {
+ return WH_ERROR_ABORTED;
+ }
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_CleanupBoard(void)
+{
+ if (notifyFd >= 0) {
+ if (close(notifyFd) != 0) {
+ return WH_ERROR_ABORTED;
+ }
+ notifyFd = -1;
+ }
+
+ return WH_ERROR_OK;
+}
+
+static int connectCb(void* context, whCommConnected connected)
+{
+ uint8_t msg;
+
+ (void)context;
+
+ if (notifyFd < 0) {
+ return WH_ERROR_ABORTED;
+ }
+
+ msg = (connected == WH_COMM_CONNECTED) ? 1 : 0;
+ if (write(notifyFd, &msg, 1) != 1) {
+ return WH_ERROR_ABORTED;
+ }
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_ConfigureClient(whClientConfig* clientCfg)
+{
+ if (clientCfg == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ memset(&tcpClientCtx, 0, sizeof(tcpClientCtx));
+ memset(&commConfig, 0, sizeof(commConfig));
+
+ tcpConfig.server_ip_string = WOLFHSM_CFG_PORT_TCP_IPSTRING;
+ tcpConfig.server_port = WOLFHSM_CFG_PORT_TCP_PORT;
+
+ commConfig.transport_cb = &tcpCb;
+ commConfig.transport_context = (void*)&tcpClientCtx;
+ commConfig.transport_config = (void*)&tcpConfig;
+ commConfig.client_id = WOLFHSM_CFG_PORT_CLIENT_ID;
+ commConfig.connect_cb = connectCb;
+
+ clientCfg->comm = &commConfig;
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_InitClient(whClientConfig* clientCfg, whClientContext* clientCtx)
+{
+ int ret;
+
+ if (clientCfg == NULL || clientCtx == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ ret = wh_Client_Init(clientCtx, clientCfg);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ ret = wh_Client_CommInit(clientCtx, NULL, NULL);
+ if (ret != WH_ERROR_OK) {
+ (void)wh_Client_Cleanup(clientCtx);
+ return ret;
+ }
+
+ return WH_ERROR_OK;
+}
+
+static void sleepMs(long milliseconds)
+{
+ struct timespec req;
+ req.tv_sec = milliseconds / 1000;
+ req.tv_nsec = (milliseconds % 1000) * 1000000;
+ nanosleep(&req, NULL);
+}
+
+int wh_Port_RunClient(whClientContext* clientCtx)
+{
+ int ret;
+ int counter;
+ uint8_t tx_req[32] = {0};
+ uint16_t tx_req_len = 0;
+ uint8_t rx_resp[64] = {0};
+ uint16_t rx_resp_len = 0;
+
+ if (clientCtx == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ WOLFHSM_CFG_PRINTF("Client connected, sending echo requests...\n");
+
+ for (counter = 0; counter < 20; counter++) {
+ sprintf((char*)tx_req, "Request:%u", counter);
+ tx_req_len = strlen((char*)tx_req);
+
+ do {
+ ret = wh_Client_EchoRequest(clientCtx, tx_req_len, tx_req);
+ if (ret == WH_ERROR_NOTREADY) {
+ sleepMs(1);
+ }
+ } while (ret == WH_ERROR_NOTREADY);
+
+ if (ret != WH_ERROR_OK) {
+ WOLFHSM_CFG_PRINTF("EchoRequest failed: %d\n", ret);
+ break;
+ }
+
+ rx_resp_len = 0;
+ memset(rx_resp, 0, sizeof(rx_resp));
+
+ do {
+ ret = wh_Client_EchoResponse(clientCtx, &rx_resp_len, rx_resp);
+ if (ret == WH_ERROR_NOTREADY) {
+ sleepMs(1);
+ }
+ } while (ret == WH_ERROR_NOTREADY);
+
+ if (ret != WH_ERROR_OK) {
+ WOLFHSM_CFG_PRINTF("EchoResponse failed: %d\n", ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int wh_Port_CleanupClient(whClientContext* clientCtx)
+{
+ int ret;
+
+ if (clientCtx == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ ret = wh_Client_CommClose(clientCtx);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ ret = wh_Client_Cleanup(clientCtx);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ return WH_ERROR_OK;
+}
diff --git a/port/posix/client/wolfhsm_cfg.h b/port/posix/client/wolfhsm_cfg.h
new file mode 100644
index 000000000..16ced9809
--- /dev/null
+++ b/port/posix/client/wolfhsm_cfg.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/posix/client/wolfhsm_cfg.h
+ *
+ * wolfHSM compile-time options for the POSIX generic client.
+ */
+
+#ifndef WOLFHSM_CFG_H_
+#define WOLFHSM_CFG_H_
+
+#include "port/posix/posix_time.h"
+
+#define WOLFHSM_CFG_PORT_GETTIME posixGetTime
+
+/** Port configuration */
+#define WOLFHSM_CFG_PORT_CLIENT_ID 12
+#define WOLFHSM_CFG_PORT_TCP_PORT 23456
+#define WOLFHSM_CFG_PORT_TCP_IPSTRING "127.0.0.1"
+#define WOLFHSM_CFG_PORT_NOTIFY_PATH "/tmp/wolfhsm_notify"
+
+/** wolfHSM settings */
+#define WOLFHSM_CFG_ENABLE_CLIENT
+#define WOLFHSM_CFG_PORT_ENABLE_WOLFHSM_TESTS
+#define WOLFHSM_CFG_TEST_WOLFCRYPTTEST
+#define WOLFHSM_CFG_TEST_UNIT_NO_MAIN
+#define WOLFHSM_CFG_TEST_POSIX
+#define WOLFHSM_CFG_TEST_CLIENT_ONLY
+#define WOLFHSM_CFG_PORT_ENABLE_BENCHMARK
+#define WOLFHSM_CFG_BENCH_ENABLE
+#include "benchmark/wh_bench_ops.h"
+#define WOLFHSM_CFG_PORT_BENCH_TRANSPORT WH_BENCH_TRANSPORT_POSIX_TCP
+#define WOLFHSM_CFG_COMM_DATA_LEN 5000
+#define WOLFHSM_CFG_NVM_OBJECT_COUNT 30
+
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+#define WOLFHSM_CFG_KEYWRAP
+#define WOLFHSM_CFG_GLOBAL_KEYS
+#endif
+
+#endif /* WOLFHSM_CFG_H_ */
diff --git a/port/posix/server/Makefile b/port/posix/server/Makefile
new file mode 100644
index 000000000..f5103493b
--- /dev/null
+++ b/port/posix/server/Makefile
@@ -0,0 +1,117 @@
+## Makefile for wolfHSM generic server using POSIX port
+
+BIN = server
+
+## Important directories
+PROJECT_DIR ?= .
+WOLFSSL_DIR ?= ../../../../wolfssl
+WOLFHSM_DIR ?= ../../../
+PORT_DIR ?= ../
+GENERIC_DIR ?= $(WOLFHSM_DIR)/examples/generic
+
+BUILD_DIR ?= $(PROJECT_DIR)/Build
+
+# Includes (project dir first for wolfhsm_cfg.h / user_settings.h)
+INC = -I$(PROJECT_DIR) \
+ -I$(WOLFSSL_DIR) \
+ -I$(WOLFHSM_DIR) \
+ -I$(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
+
+ARCHFLAGS ?=
+CFLAGS_EXTRA ?= -Wextra -g
+CFLAGS ?= $(ARCHFLAGS) -Wno-cpp -std=c99 -Wall -Werror $(CFLAGS_EXTRA)
+LDFLAGS ?= $(ARCHFLAGS)
+
+OS_NAME := $(shell uname -s | tr A-Z a-z)
+ifeq ($(OS_NAME),darwin)
+ LDFLAGS += -Wl,-dead_strip
+else
+ LDFLAGS += -Wl,--gc-sections
+endif
+
+LIBS = -lc -lm
+CMD_ECHO ?=
+
+ifeq ($(DEBUG),1)
+ DBGFLAGS = -ggdb -g3
+ CFLAGS += $(DBGFLAGS)
+ LDFLAGS += $(DBGFLAGS)
+ DEF += -DWOLFHSM_CFG_DEBUG
+endif
+
+ifeq ($(DEBUG_VERBOSE),1)
+ DBGFLAGS = -ggdb -g3
+ CFLAGS += $(DBGFLAGS)
+ LDFLAGS += $(DBGFLAGS)
+ DEF += -DWOLFHSM_CFG_DEBUG -DWOLFHSM_CFG_DEBUG_VERBOSE
+endif
+
+ifeq ($(ASAN),1)
+ CFLAGS += -fsanitize=address
+ LDFLAGS += -fsanitize=address
+endif
+
+## Source files
+SRC_C =
+
+ifneq ($(NOCRYPTO),1)
+SRC_C += $(wildcard $(WOLFSSL_DIR)/wolfcrypt/src/*.c)
+SRC_C += $(wildcard $(WOLFSSL_DIR)/src/*.c)
+else
+DEF += -DWOLFHSM_CFG_NO_CRYPTO
+endif
+
+# wolfHSM source files
+SRC_C += $(wildcard $(WOLFHSM_DIR)/src/*.c)
+
+# POSIX port shared code
+SRC_C += $(wildcard $(PORT_DIR)/*.c)
+
+# Port server implementation (wh_Port_* functions)
+SRC_C += $(PROJECT_DIR)/wh_posix_server_port.c
+
+# Generic server entry point
+SRC_C += $(GENERIC_DIR)/wh_generic_server.c
+
+## Object files in Build directory
+OBJS_C = $(addprefix $(BUILD_DIR)/, $(notdir $(SRC_C:.c=.o)))
+
+## Compile rule: find source by trying each source directory
+COMPILE = $(CC) $(CFLAGS) $(DEF) $(INC) -c -o $@ $<
+
+# Collect unique source directories
+SRC_DIRS = $(sort $(dir $(SRC_C)))
+
+# Generate a pattern rule for each source directory
+define COMPILE_RULE
+$(BUILD_DIR)/%.o: $(1)%.c | $(BUILD_DIR)
+ @echo "Compiling: $$(notdir $$<)"
+ $$(CMD_ECHO) $$(COMPILE)
+endef
+
+$(foreach dir,$(SRC_DIRS),$(eval $(call COMPILE_RULE,$(dir))))
+
+## Makefile Targets
+
+.PHONY: build_app clean
+
+build_app: | $(BUILD_DIR)
+build_app: $(BUILD_DIR)/$(BIN).elf
+ @echo Build complete.
+
+$(BUILD_DIR)/$(BIN).elf: $(OBJS_C) | $(BUILD_DIR)
+ @echo "Linking: $(notdir $@)"
+ $(CMD_ECHO) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+$(BUILD_DIR):
+ $(CMD_ECHO) mkdir -p $(BUILD_DIR)
+
+clean:
+ @echo "Cleaning build files"
+ @rm -rf $(BUILD_DIR)
diff --git a/port/posix/server/user_settings.h b/port/posix/server/user_settings.h
new file mode 100644
index 000000000..e9ad8ef20
--- /dev/null
+++ b/port/posix/server/user_settings.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/posix/server/user_settings.h
+ *
+ * wolfSSL compile-time options for the POSIX generic server.
+ */
+
+#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
+
+/* These macros reduce footprint size when TLS functionality is not needed */
+#define NO_TLS
+#define WOLFSSL_USER_IO
+#define WOLFSSL_NO_TLS12
+#define NO_PSK
+
+/* For ACert support (also requires WOLFSSL_ASN_TEMPLATE) */
+#define WOLFSSL_ACERT
+
+/** Math library selection */
+#define USE_FAST_MATH
+
+/** wolfHSM recommended */
+#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_ERROR_STRINGS
+#define NO_ERROR_QUEUE
+#define NO_INLINE
+#define NO_OLD_TLS
+#define NO_DO178
+#define WC_NO_DEFAULT_DEVID
+
+/** 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
+#define FP_MAX_BITS 8192
+
+/** ECC Options */
+#define HAVE_ECC
+#define TFM_ECC256
+#define ECC_SHAMIR
+
+/** Curve25519 Options */
+#define HAVE_CURVE25519
+
+/** Ed25519 Options */
+#define HAVE_ED25519
+
+/** DH and DHE Options */
+#define HAVE_DH_DEFAULT_PARAMS
+#define HAVE_FFDHE_2048
+
+/** AES Options */
+#define HAVE_AESGCM
+#define WOLFSSL_AES_COUNTER
+#define GCM_TABLE_4BIT
+#define WOLFSSL_AES_DIRECT
+#define HAVE_AES_ECB
+#define WOLFSSL_CMAC
+
+/** SHA Options */
+#define WOLFSSL_SHA224
+#define WOLFSSL_SHA384
+#define WOLFSSL_SHA512
+#define WOLFSSL_SHA512_HASHTYPE
+
+/* Dilithium Options */
+#define HAVE_DILITHIUM
+#define WOLFSSL_WC_DILITHIUM
+#define WOLFSSL_SHA3
+#define WOLFSSL_SHAKE128
+#define WOLFSSL_SHAKE256
+
+/** Composite features */
+#define HAVE_HKDF
+#define HAVE_CMAC_KDF
+
+/* Remove unneeded crypto */
+#define NO_DSA
+#define NO_RC4
+#define NO_MD4
+#define NO_MD5
+
+/* POSIX version of strcasecmp */
+#include
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USER_SETTINGS_H */
diff --git a/port/posix/server/wh_posix_server_port.c b/port/posix/server/wh_posix_server_port.c
new file mode 100644
index 000000000..3f3eb2033
--- /dev/null
+++ b/port/posix/server/wh_posix_server_port.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/posix/server/wh_posix_server_port.c
+ *
+ * POSIX server implementation of the wh_Port_* generic port API.
+ * Uses TCP transport with RamSim flash and NVM. Configuration is provided
+ * through WOLFHSM_CFG_PORT_* defines which must be set by the application.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_comm.h"
+#include "wolfhsm/wh_server.h"
+#include "wolfhsm/wh_nvm.h"
+#include "wolfhsm/wh_nvm_flash.h"
+#include "wolfhsm/wh_flash_ramsim.h"
+#include "wolfhsm/wh_port.h"
+
+#include "port/posix/posix_transport_tcp.h"
+
+#if WOLFHSM_CFG_PORT_SERVER_COUNT > 1
+#error "POSIX port only supports WOLFHSM_CFG_PORT_SERVER_COUNT == 1"
+#endif
+
+/* Transport context and configuration - must persist for lifetime of server */
+static posixTransportTcpServerContext tcpServerCtx;
+static posixTransportTcpConfig tcpConfig;
+static whCommServerConfig commConfig;
+static whTransportServerCb tcpCb = PTT_SERVER_CB;
+
+/* NVM and flash state */
+static uint8_t flashMemory[WOLFHSM_CFG_PORT_FLASH_RAM_SIZE];
+static whFlashRamsimCfg flashCfg;
+static whFlashRamsimCtx flashCtx;
+static const whFlashCb flashCb = WH_FLASH_RAMSIM_CB;
+static whNvmFlashConfig nvmFlashCfg;
+static whNvmFlashContext nvmFlashCtx;
+static whNvmCb nvmCb[1] = {WH_NVM_FLASH_CB};
+static whNvmConfig nvmConfig;
+static whNvmContext nvmCtx;
+
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+static whServerCryptoContext cryptoCtx;
+#endif
+
+/* Notification FIFO fd — opened once and kept open */
+static int notifyFd = -1;
+
+static void cleanupHandler(int sig)
+{
+ wh_Port_CleanupBoard();
+ _exit(128 + sig);
+}
+
+int wh_Port_InitBoard(void)
+{
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+ wolfCrypt_Init();
+#endif
+
+ /* Register signal handler to clean up FIFO on exit */
+ signal(SIGINT, cleanupHandler);
+ signal(SIGTERM, cleanupHandler);
+
+ /* Create the FIFO if it doesn't exist (EEXIST is OK) */
+ if (mkfifo(WOLFHSM_CFG_PORT_NOTIFY_PATH, 0666) != 0 && errno != EEXIST) {
+ return WH_ERROR_ABORTED;
+ }
+ /* O_RDWR prevents EOF when no writer is connected yet */
+ notifyFd = open(WOLFHSM_CFG_PORT_NOTIFY_PATH, O_RDWR | O_NONBLOCK);
+ if (notifyFd < 0) {
+ return WH_ERROR_ABORTED;
+ }
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_CleanupBoard(void)
+{
+ if (notifyFd >= 0) {
+ if (close(notifyFd) != 0) {
+ return WH_ERROR_ABORTED;
+ }
+ notifyFd = -1;
+ }
+ if (unlink(WOLFHSM_CFG_PORT_NOTIFY_PATH) != 0 && errno != ENOENT) {
+ return WH_ERROR_ABORTED;
+ }
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_ConfigureServer(size_t instance, whServerConfig* serverCfg)
+{
+ int ret;
+
+ if (serverCfg == NULL || instance >= WOLFHSM_CFG_PORT_SERVER_COUNT) {
+ return WH_ERROR_BADARGS;
+ }
+
+ memset(serverCfg, 0, sizeof(*serverCfg));
+ memset(&tcpServerCtx, 0, sizeof(tcpServerCtx));
+ memset(&commConfig, 0, sizeof(commConfig));
+ memset(flashMemory, 0, sizeof(flashMemory));
+
+ /* TCP transport configuration */
+ tcpConfig.server_ip_string = WOLFHSM_CFG_PORT_TCP_IPSTRING;
+ tcpConfig.server_port = WOLFHSM_CFG_PORT_TCP_PORT;
+
+ commConfig.transport_cb = &tcpCb;
+ commConfig.transport_context = (void*)&tcpServerCtx;
+ commConfig.transport_config = (void*)&tcpConfig;
+ commConfig.server_id = WOLFHSM_CFG_PORT_SERVER_ID;
+
+ serverCfg->comm_config = &commConfig;
+
+ /* Flash simulation configuration */
+ flashCfg.size = WOLFHSM_CFG_PORT_FLASH_RAM_SIZE;
+ flashCfg.sectorSize = WOLFHSM_CFG_PORT_FLASH_RAM_SIZE / 2;
+ flashCfg.pageSize = 8;
+ flashCfg.erasedByte = (uint8_t)0;
+ flashCfg.memory = flashMemory;
+
+ /* NVM configuration */
+ memset(&flashCtx, 0, sizeof(flashCtx));
+ memset(&nvmFlashCtx, 0, sizeof(nvmFlashCtx));
+ nvmFlashCfg.cb = &flashCb;
+ nvmFlashCfg.context = &flashCtx;
+ nvmFlashCfg.config = &flashCfg;
+
+ nvmConfig.cb = nvmCb;
+ nvmConfig.context = &nvmFlashCtx;
+ nvmConfig.config = &nvmFlashCfg;
+
+ ret = wh_Nvm_Init(&nvmCtx, &nvmConfig);
+ if (ret != WH_ERROR_OK) {
+ WOLFHSM_CFG_PRINTF("Failed to initialize NVM: %d\n", ret);
+ return ret;
+ }
+
+ serverCfg->nvm = &nvmCtx;
+
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+ memset(&cryptoCtx, 0, sizeof(cryptoCtx));
+ serverCfg->crypto = &cryptoCtx;
+ serverCfg->devId = INVALID_DEVID;
+
+ ret = wc_InitRng_ex(cryptoCtx.rng, NULL, INVALID_DEVID);
+ if (ret != 0) {
+ WOLFHSM_CFG_PRINTF("Failed to initialize RNG: %d\n", ret);
+ return ret;
+ }
+#endif
+
+ (void)instance;
+ return WH_ERROR_OK;
+}
+
+int wh_Port_InitServer(size_t instance, whServerConfig* serverCfg,
+ whServerContext* serverCtx)
+{
+ if (serverCfg == NULL || serverCtx == NULL ||
+ instance >= WOLFHSM_CFG_PORT_SERVER_COUNT) {
+ return WH_ERROR_BADARGS;
+ }
+
+ return wh_Server_Init(serverCtx, serverCfg);
+}
+
+int wh_Port_CleanupServer(size_t instance, whServerContext* serverCtx)
+{
+ if (serverCtx == NULL || instance >= WOLFHSM_CFG_PORT_SERVER_COUNT) {
+ return WH_ERROR_BADARGS;
+ }
+
+ return wh_Server_Cleanup(serverCtx);
+}
+
+int wh_Port_ClientConnected(size_t instance)
+{
+ uint8_t msg;
+ ssize_t rc;
+
+ (void)instance;
+
+ if (notifyFd < 0) {
+ return 0;
+ }
+
+ rc = read(notifyFd, &msg, 1);
+ if (rc == 1 && msg == 1) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int wh_Port_ClientDisconnected(size_t instance)
+{
+ uint8_t msg;
+ ssize_t rc;
+
+ (void)instance;
+
+ if (notifyFd < 0) {
+ return 0;
+ }
+
+ rc = read(notifyFd, &msg, 1);
+ if (rc == 1 && msg == 0) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/port/posix/server/wolfhsm_cfg.h b/port/posix/server/wolfhsm_cfg.h
new file mode 100644
index 000000000..99e132999
--- /dev/null
+++ b/port/posix/server/wolfhsm_cfg.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/posix/server/wolfhsm_cfg.h
+ *
+ * wolfHSM compile-time options for the POSIX generic server.
+ */
+
+#ifndef WOLFHSM_CFG_H_
+#define WOLFHSM_CFG_H_
+
+#include "port/posix/posix_time.h"
+
+#define WOLFHSM_CFG_PORT_GETTIME posixGetTime
+
+/** Port configuration */
+#define WOLFHSM_CFG_PORT_SERVER_ID 57
+#define WOLFHSM_CFG_PORT_SERVER_COUNT 1
+#define WOLFHSM_CFG_PORT_TCP_PORT 23456
+#define WOLFHSM_CFG_PORT_TCP_IPSTRING "127.0.0.1"
+#define WOLFHSM_CFG_PORT_NOTIFY_PATH "/tmp/wolfhsm_notify"
+#define WOLFHSM_CFG_PORT_FLASH_RAM_SIZE (1024 * 1024) /* 1MB */
+
+/** wolfHSM settings */
+#define WOLFHSM_CFG_ENABLE_SERVER
+
+/* Large enough for ML-DSA level 5 key */
+#define WOLFHSM_CFG_COMM_DATA_LEN 5000
+
+#define WOLFHSM_CFG_NVM_OBJECT_COUNT 30
+#define WOLFHSM_CFG_SERVER_KEYCACHE_COUNT 9
+#define WOLFHSM_CFG_SERVER_KEYCACHE_SIZE 1024
+#define WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE 4096
+#define WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT 5
+
+#define WOLFHSM_CFG_SERVER_DMAADDR_COUNT 8
+#define WOLFHSM_CFG_SERVER_CUSTOMCB_COUNT 6
+
+#define WOLFHSM_CFG_CERTIFICATE_MANAGER
+#define WOLFHSM_CFG_CERTIFICATE_MANAGER_ACERT
+
+#define XMEMFENCE() __atomic_thread_fence(__ATOMIC_SEQ_CST)
+
+#define WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE 5000
+
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+#define WOLFHSM_CFG_KEYWRAP
+#define WOLFHSM_CFG_GLOBAL_KEYS
+#endif
+
+#endif /* WOLFHSM_CFG_H_ */
diff --git a/port/skeleton/README.md b/port/skeleton/README.md
deleted file mode 100644
index 378f065db..000000000
--- a/port/skeleton/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Skeleton Port
-
-The Skeleton port source code provides a non-functioning layout to be used as a starting point for future hardware/platform ports. Each function provides the basic description and expected flow with error cases explained so that ports can be used interchangeably with consistent results.
-
-The Skeleton port provides implementations of:
-- Transport
-- NVM Device
-- Flash Device
-- Crypto Device
diff --git a/port/template/README.md b/port/template/README.md
new file mode 100644
index 000000000..42b021b27
--- /dev/null
+++ b/port/template/README.md
@@ -0,0 +1,21 @@
+# Template Port
+
+This directory provides a starting point for porting wolfHSM to a new platform.
+Each file contains stub implementations of the required interfaces with
+documentation explaining what each function should do.
+
+## Getting Started
+
+1. Copy this directory to `port//`.
+2. Implement the transport layer for your platform (or use an existing one).
+3. Fill in the `wh_Port_*` function stubs in `client/wh_client_port.c` and
+ `server/wh_server_port.c`.
+4. Edit `client/wolfhsm_cfg.h` and `server/wolfhsm_cfg.h` with your
+ platform's configuration values.
+5. Edit `client/user_settings.h` and `server/user_settings.h` with the
+ wolfSSL features your application requires.
+6. Create a build system (Makefile, CMake, IDE project, etc.) that compiles
+ the generic examples together with your port. See `port/posix/` for a
+ Makefile-based reference.
+
+See `docs/draft/porting.md` for a detailed porting guide.
diff --git a/port/template/client/user_settings.h b/port/template/client/user_settings.h
new file mode 100644
index 000000000..3f19ed3ce
--- /dev/null
+++ b/port/template/client/user_settings.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/template/client/user_settings.h
+ *
+ * Template wolfSSL compile-time options for a client build.
+ * Enable the crypto algorithms and features your application requires.
+ */
+
+#ifndef USER_SETTINGS_H_
+#define USER_SETTINGS_H_
+
+/** wolfHSM required settings */
+#define WOLF_CRYPTO_CB
+#define HAVE_ANONYMOUS_INLINE_AGGREGATES 1
+#define WOLFSSL_KEY_GEN
+#define WOLFSSL_ASN_TEMPLATE
+#define WOLFSSL_BASE64_ENCODE
+
+/* C90 compatibility */
+#define NO_INLINE
+#define WOLFSSL_IGNORE_FILE_WARN
+
+/* Side-channel resistance */
+#define TFM_TIMING_RESISTANT
+#define ECC_TIMING_RESISTANT
+#define WC_RSA_BLINDING
+
+/** Crypto algorithm selection
+ * TODO: Enable the algorithms your application needs. Common choices: */
+/* #define HAVE_ECC */
+/* #define HAVE_CURVE25519 */
+/* #define HAVE_AES_CBC */
+/* #define HAVE_AESGCM */
+/* #define WOLFSSL_AES_COUNTER */
+/* #define WOLFSSL_AES_DIRECT */
+/* #define WOLFSSL_CMAC */
+/* #define HAVE_HKDF */
+
+/** Platform settings
+ * TODO: Adjust for your platform. */
+#define NO_MAIN_DRIVER
+/* #define NO_FILESYSTEM */
+
+#endif /* USER_SETTINGS_H_ */
diff --git a/port/template/client/wh_client_port.c b/port/template/client/wh_client_port.c
new file mode 100644
index 000000000..28a19cb53
--- /dev/null
+++ b/port/template/client/wh_client_port.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/template/client/wh_client_port.c
+ *
+ * Template client implementation of the wh_Port_* generic port API.
+ * Replace the TODO stubs with your platform-specific logic.
+ */
+
+#include
+#include
+
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_comm.h"
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_port.h"
+
+/* TODO: Include your transport header here, e.g.:
+ * #include "port//_transport.h"
+ */
+
+/* TODO: Declare static transport context and configuration structures.
+ * These must persist for the lifetime of the client. Example:
+ *
+ * static myTransportClientContext transportCtx;
+ * static myTransportConfig transportCfg;
+ * static whCommClientConfig commConfig;
+ * static whTransportClientCb transportCb = MY_CLIENT_CB;
+ */
+
+
+int wh_Port_InitBoard(void)
+{
+ /* TODO: Initialize any shared platform resources needed by the client.
+ * This is called once at startup before any client operations.
+ *
+ * Examples:
+ * - Initialize hardware peripherals
+ * - Set up IPC mechanisms for server notifications
+ * - Initialize crypto libraries
+ */
+ return WH_ERROR_OK;
+}
+
+int wh_Port_CleanupBoard(void)
+{
+ /* TODO: Release resources allocated by wh_Port_InitBoard.
+ * This is called at shutdown.
+ */
+ return WH_ERROR_OK;
+}
+
+/* TODO: If your transport supports a connect callback, implement it here.
+ * The callback is invoked by the transport layer when the connection state
+ * changes. It should notify the server side so that wh_Port_ClientConnected
+ * and wh_Port_ClientDisconnected work correctly.
+ *
+ * static int connectCb(void* context, whCommConnected connected)
+ * {
+ * (void)context;
+ * if (connected == WH_COMM_CONNECTED) {
+ * // Notify server that client has connected
+ * } else {
+ * // Notify server that client has disconnected
+ * }
+ * return WH_ERROR_OK;
+ * }
+ */
+
+int wh_Port_ConfigureClient(whClientConfig* clientCfg)
+{
+ if (clientCfg == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* TODO: Initialize and populate the comm configuration with your
+ * transport callbacks, context, config, client ID, and optionally
+ * a connect callback. Then assign it to clientCfg->comm. Example:
+ *
+ * memset(&transportCtx, 0, sizeof(transportCtx));
+ * memset(&commConfig, 0, sizeof(commConfig));
+ *
+ * transportCfg.server_addr = WOLFHSM_CFG_PORT_SERVER_ADDR;
+ *
+ * commConfig.transport_cb = &transportCb;
+ * commConfig.transport_context = (void*)&transportCtx;
+ * commConfig.transport_config = (void*)&transportCfg;
+ * commConfig.client_id = WOLFHSM_CFG_PORT_CLIENT_ID;
+ * commConfig.connect_cb = connectCb;
+ *
+ * clientCfg->comm = &commConfig;
+ */
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_InitClient(whClientConfig* clientCfg, whClientContext* clientCtx)
+{
+ int ret;
+
+ if (clientCfg == NULL || clientCtx == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ ret = wh_Client_Init(clientCtx, clientCfg);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ ret = wh_Client_CommInit(clientCtx, NULL, NULL);
+ if (ret != WH_ERROR_OK) {
+ (void)wh_Client_Cleanup(clientCtx);
+ return ret;
+ }
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_RunClient(whClientContext* clientCtx)
+{
+ if (clientCtx == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* TODO: Implement your client application logic here. For example:
+ * - Send echo requests
+ * - Perform crypto operations
+ * - Store/retrieve NVM objects
+ * - Run key management operations
+ *
+ * Use wh_Client_* APIs. For async operations, poll with a retry loop:
+ *
+ * do {
+ * ret = wh_Client_EchoRequest(clientCtx, len, data);
+ * } while (ret == WH_ERROR_NOTREADY);
+ */
+
+ return WH_ERROR_OK;
+}
+
+int wh_Port_CleanupClient(whClientContext* clientCtx)
+{
+ int ret;
+
+ if (clientCtx == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ ret = wh_Client_CommClose(clientCtx);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ ret = wh_Client_Cleanup(clientCtx);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ return WH_ERROR_OK;
+}
diff --git a/port/template/client/wolfhsm_cfg.h b/port/template/client/wolfhsm_cfg.h
new file mode 100644
index 000000000..c44b37827
--- /dev/null
+++ b/port/template/client/wolfhsm_cfg.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/template/client/wolfhsm_cfg.h
+ *
+ * Template wolfHSM compile-time options for a client build.
+ */
+
+#ifndef WOLFHSM_CFG_H_
+#define WOLFHSM_CFG_H_
+
+/* TODO: Include your platform's time function header and define
+ * WOLFHSM_CFG_PORT_GETTIME to a function returning uint64_t microseconds.
+ *
+ * #include "port//_time.h"
+ * #define WOLFHSM_CFG_PORT_GETTIME myPlatformGetTime
+ */
+
+/* TODO: Define a printf-like function for your platform if the default
+ * stdlib printf is not available.
+ *
+ * #define WOLFHSM_CFG_PRINTF myPlatformPrintf
+ */
+
+/** Port configuration
+ * TODO: Set these to match your platform and server configuration. */
+#define WOLFHSM_CFG_PORT_CLIENT_ID 12
+/* TODO: Add transport-specific defines here, e.g.:
+ * #define WOLFHSM_CFG_PORT_TCP_PORT 23456
+ * #define WOLFHSM_CFG_PORT_TCP_IPSTRING "127.0.0.1"
+ */
+
+/** wolfHSM settings */
+#define WOLFHSM_CFG_ENABLE_CLIENT
+
+/* Communication data length — must match server */
+#define WOLFHSM_CFG_COMM_DATA_LEN 5000
+
+/* NVM object count — must match server */
+#define WOLFHSM_CFG_NVM_OBJECT_COUNT 30
+
+/* TODO: Uncomment to enable tests and benchmarks:
+ * #define WOLFHSM_CFG_PORT_ENABLE_WOLFHSM_TESTS
+ * #define WOLFHSM_CFG_TEST_WOLFCRYPTTEST
+ * #define WOLFHSM_CFG_TEST_UNIT_NO_MAIN
+ * #define WOLFHSM_CFG_TEST_CLIENT_ONLY
+ * #define WOLFHSM_CFG_PORT_ENABLE_BENCHMARK
+ * #define WOLFHSM_CFG_BENCH_ENABLE
+ * #include "benchmark/wh_bench_ops.h"
+ * #define WOLFHSM_CFG_PORT_BENCH_TRANSPORT WH_BENCH_TRANSPORT_...
+ */
+
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+#define WOLFHSM_CFG_KEYWRAP
+#define WOLFHSM_CFG_GLOBAL_KEYS
+#endif
+
+#endif /* WOLFHSM_CFG_H_ */
diff --git a/port/template/server/user_settings.h b/port/template/server/user_settings.h
new file mode 100644
index 000000000..feda268c3
--- /dev/null
+++ b/port/template/server/user_settings.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/template/server/user_settings.h
+ *
+ * Template wolfSSL compile-time options for a server build.
+ * The server typically needs a broader set of crypto algorithms than the
+ * client since it must support all operations clients may request.
+ */
+
+#ifndef USER_SETTINGS_H_
+#define USER_SETTINGS_H_
+
+/** wolfHSM required settings */
+#define WOLF_CRYPTO_CB
+#define HAVE_ANONYMOUS_INLINE_AGGREGATES 1
+#define WOLFSSL_KEY_GEN
+#define WOLFSSL_ASN_TEMPLATE
+#define WOLFSSL_BASE64_ENCODE
+
+/* TLS is not needed for wolfHSM server operation */
+#define NO_TLS
+#define WOLFSSL_USER_IO
+#define WOLFSSL_NO_TLS12
+#define NO_PSK
+
+/** Math library selection
+ * TODO: Choose the math library appropriate for your platform.
+ * USE_FAST_MATH is recommended for most platforms. */
+#define USE_FAST_MATH
+
+/** wolfHSM recommended */
+#define WOLFSSL_USE_ALIGN
+#define WOLFSSL_IGNORE_FILE_WARN
+#define TFM_TIMING_RESISTANT
+#define ECC_TIMING_RESISTANT
+#define WC_RSA_BLINDING
+
+/* C90 compatibility */
+#define NO_INLINE
+#define NO_MAIN_DRIVER
+
+/** Remove unneeded features
+ * TODO: Adjust based on your requirements. */
+#define NO_ERROR_STRINGS
+#define NO_ERROR_QUEUE
+#define NO_OLD_TLS
+#define NO_DO178
+#define WC_NO_DEFAULT_DEVID
+#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
+#define FP_MAX_BITS 8192
+
+/** Crypto algorithm selection
+ * TODO: Enable the algorithms your application needs. The server should
+ * support all algorithms that any client may request. */
+/* #define HAVE_ECC */
+/* #define TFM_ECC256 */
+/* #define ECC_SHAMIR */
+/* #define HAVE_CURVE25519 */
+/* #define HAVE_ED25519 */
+/* #define HAVE_AESGCM */
+/* #define WOLFSSL_AES_COUNTER */
+/* #define WOLFSSL_AES_DIRECT */
+/* #define HAVE_AES_ECB */
+/* #define WOLFSSL_CMAC */
+/* #define HAVE_HKDF */
+
+/** Remove unneeded crypto
+ * TODO: Disable algorithms you don't need. */
+#define NO_DSA
+#define NO_RC4
+#define NO_MD4
+
+#endif /* USER_SETTINGS_H_ */
diff --git a/port/template/server/wh_server_port.c b/port/template/server/wh_server_port.c
new file mode 100644
index 000000000..1562add1a
--- /dev/null
+++ b/port/template/server/wh_server_port.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/template/server/wh_server_port.c
+ *
+ * Template server implementation of the wh_Port_* generic port API.
+ * Replace the TODO stubs with your platform-specific logic.
+ */
+
+#include
+#include
+
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_comm.h"
+#include "wolfhsm/wh_server.h"
+#include "wolfhsm/wh_nvm.h"
+#include "wolfhsm/wh_nvm_flash.h"
+#include "wolfhsm/wh_flash_ramsim.h"
+#include "wolfhsm/wh_port.h"
+
+/* TODO: Include your transport header here, e.g.:
+ * #include "port//_transport.h"
+ */
+
+/* TODO: Declare static transport context and configuration structures.
+ * These must persist for the lifetime of the server. Example:
+ *
+ * static myTransportServerContext transportCtx;
+ * static myTransportConfig transportCfg;
+ * static whCommServerConfig commConfig;
+ * static whTransportServerCb transportCb = MY_SERVER_CB;
+ */
+
+/* TODO: Declare NVM and flash state. You can use wh_flash_ramsim for
+ * development or provide your own flash callbacks. Example using ramsim:
+ *
+ * static uint8_t flashMemory[WOLFHSM_CFG_PORT_FLASH_RAM_SIZE];
+ * static whFlashRamsimCfg flashCfg;
+ * static whFlashRamsimCtx flashCtx;
+ * static const whFlashCb flashCb = WH_FLASH_RAMSIM_CB;
+ * static whNvmFlashConfig nvmFlashCfg;
+ * static whNvmFlashContext nvmFlashCtx;
+ * static whNvmCb nvmCb[1] = {WH_NVM_FLASH_CB};
+ * static whNvmConfig nvmConfig;
+ * static whNvmContext nvmCtx;
+ */
+
+/* TODO: If crypto is enabled, declare crypto context:
+ *
+ * #ifndef WOLFHSM_CFG_NO_CRYPTO
+ * static whServerCryptoContext cryptoCtx;
+ * #endif
+ */
+
+
+int wh_Port_InitBoard(void)
+{
+ /* TODO: Initialize shared platform resources for the server.
+ * This is called once at startup.
+ *
+ * Examples:
+ * - Initialize crypto libraries (e.g. wolfCrypt_Init())
+ * - Set up signal handlers for graceful shutdown
+ * - Create IPC mechanisms for client connection notifications
+ * - Initialize hardware peripherals
+ */
+ return WH_ERROR_OK;
+}
+
+int wh_Port_CleanupBoard(void)
+{
+ /* TODO: Release resources allocated by wh_Port_InitBoard.
+ *
+ * Examples:
+ * - Close file descriptors or IPC handles
+ * - Remove temporary files
+ * - Deinitialize hardware
+ */
+ return WH_ERROR_OK;
+}
+
+int wh_Port_ConfigureServer(size_t instance, whServerConfig* serverCfg)
+{
+ if (serverCfg == NULL || instance >= WOLFHSM_CFG_PORT_SERVER_COUNT) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* TODO: Populate serverCfg with transport, NVM, and crypto configuration.
+ *
+ * 1. Set up transport:
+ * commConfig.transport_cb = &transportCb;
+ * commConfig.transport_context = (void*)&transportCtx;
+ * commConfig.transport_config = (void*)&transportCfg;
+ * commConfig.server_id = WOLFHSM_CFG_PORT_SERVER_ID;
+ * serverCfg->comm_config = &commConfig;
+ *
+ * 2. Set up flash and NVM:
+ * - Configure flash backend (ramsim or hardware flash)
+ * - Initialize NVM with wh_Nvm_Init()
+ * - Assign: serverCfg->nvm = &nvmCtx;
+ *
+ * 3. Set up crypto (if not WOLFHSM_CFG_NO_CRYPTO):
+ * - Initialize RNG with wc_InitRng_ex()
+ * - Assign: serverCfg->crypto = &cryptoCtx;
+ * - Assign: serverCfg->devId = INVALID_DEVID;
+ */
+
+ (void)instance;
+ return WH_ERROR_OK;
+}
+
+int wh_Port_InitServer(size_t instance, whServerConfig* serverCfg,
+ whServerContext* serverCtx)
+{
+ if (serverCfg == NULL || serverCtx == NULL ||
+ instance >= WOLFHSM_CFG_PORT_SERVER_COUNT) {
+ return WH_ERROR_BADARGS;
+ }
+
+ return wh_Server_Init(serverCtx, serverCfg);
+}
+
+int wh_Port_CleanupServer(size_t instance, whServerContext* serverCtx)
+{
+ if (serverCtx == NULL || instance >= WOLFHSM_CFG_PORT_SERVER_COUNT) {
+ return WH_ERROR_BADARGS;
+ }
+
+ return wh_Server_Cleanup(serverCtx);
+}
+
+int wh_Port_ClientConnected(size_t instance)
+{
+ (void)instance;
+
+ /* TODO: Check if a client has connected to this server instance.
+ * Return 1 exactly once per connection event, 0 otherwise.
+ *
+ * The mechanism is platform-specific. Examples:
+ * - Read from a FIFO/pipe for a connect notification byte
+ * - Check a shared memory flag and clear it
+ * - Poll a hardware mailbox register
+ */
+
+ return 0;
+}
+
+int wh_Port_ClientDisconnected(size_t instance)
+{
+ (void)instance;
+
+ /* TODO: Check if a client has disconnected from this server instance.
+ * Return 1 exactly once per disconnection event, 0 otherwise.
+ *
+ * Uses the same mechanism as wh_Port_ClientConnected but checks for
+ * the disconnect notification.
+ */
+
+ return 0;
+}
diff --git a/port/template/server/wolfhsm_cfg.h b/port/template/server/wolfhsm_cfg.h
new file mode 100644
index 000000000..b5d7079b3
--- /dev/null
+++ b/port/template/server/wolfhsm_cfg.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2026 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 .
+ */
+/*
+ * port/template/server/wolfhsm_cfg.h
+ *
+ * Template wolfHSM compile-time options for a server build.
+ */
+
+#ifndef WOLFHSM_CFG_H_
+#define WOLFHSM_CFG_H_
+
+/* TODO: Include your platform's time function header and define
+ * WOLFHSM_CFG_PORT_GETTIME to a function returning uint64_t microseconds.
+ *
+ * #include "port//_time.h"
+ * #define WOLFHSM_CFG_PORT_GETTIME myPlatformGetTime
+ */
+
+/* TODO: Define a printf-like function for your platform if the default
+ * stdlib printf is not available.
+ *
+ * #define WOLFHSM_CFG_PRINTF myPlatformPrintf
+ */
+
+/** Port configuration
+ * TODO: Set these to match your platform. */
+#define WOLFHSM_CFG_PORT_SERVER_ID 57
+#define WOLFHSM_CFG_PORT_SERVER_COUNT 1
+/* TODO: Add transport-specific defines here, e.g.:
+ * #define WOLFHSM_CFG_PORT_TCP_PORT 23456
+ * #define WOLFHSM_CFG_PORT_TCP_IPSTRING "127.0.0.1"
+ */
+
+/* TODO: Define flash size for NVM storage. Example for RAM simulation:
+ * #define WOLFHSM_CFG_PORT_FLASH_RAM_SIZE (1024 * 1024)
+ */
+
+/** wolfHSM settings */
+#define WOLFHSM_CFG_ENABLE_SERVER
+
+/* Communication data length — must match client */
+#define WOLFHSM_CFG_COMM_DATA_LEN 5000
+
+/* NVM object count — must match client */
+#define WOLFHSM_CFG_NVM_OBJECT_COUNT 30
+
+/** Server resource configuration */
+#define WOLFHSM_CFG_SERVER_KEYCACHE_COUNT 9
+#define WOLFHSM_CFG_SERVER_KEYCACHE_SIZE 1024
+#define WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT 5
+#define WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE 4096
+#define WOLFHSM_CFG_SERVER_DMAADDR_COUNT 8
+#define WOLFHSM_CFG_SERVER_CUSTOMCB_COUNT 6
+
+/* TODO: Uncomment if your platform needs a memory fence override:
+ * #define XMEMFENCE() __atomic_thread_fence(__ATOMIC_SEQ_CST)
+ */
+
+#define WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE 5000
+
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+#define WOLFHSM_CFG_KEYWRAP
+#define WOLFHSM_CFG_GLOBAL_KEYS
+#endif
+
+#endif /* WOLFHSM_CFG_H_ */
diff --git a/test/wh_test_wolfcrypt_test.c b/test/wh_test_wolfcrypt_test.c
index f1db0ca7c..267177781 100644
--- a/test/wh_test_wolfcrypt_test.c
+++ b/test/wh_test_wolfcrypt_test.c
@@ -135,13 +135,15 @@ static int whTest_ServerCfgLoop(whServerConfig* serverCfg)
}
#endif /* WOLFHSM_CFG_TEST_POSIX && WOLFHSM_CFG_ENABLE_SERVER */
-#if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT)
+#if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \
+ defined(WOLFHSM_CFG_ENABLE_SERVER)
static void* _whClientTask(void* cf)
{
WH_TEST_ASSERT(0 == whTest_WolfCryptTestCfg(cf));
return NULL;
}
-#endif /* WOLFHSM_CFG_TEST_POSIX && WOLFHSM_CFG_ENABLE_CLIENT */
+#endif /* WOLFHSM_CFG_TEST_POSIX && WOLFHSM_CFG_ENABLE_CLIENT && \
+ WOLFHSM_CFG_ENABLE_SERVER */
#if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_SERVER)
static void* _whServerTask(void* cf)
diff --git a/wolfhsm/wh_port.h b/wolfhsm/wh_port.h
new file mode 100644
index 000000000..22fd4a66e
--- /dev/null
+++ b/wolfhsm/wh_port.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2026 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/wh_port.h
+ *
+ * Abstract port API for wolfHSM generic examples. Each port (e.g. POSIX,
+ * bare-metal) provides its own implementation of these functions.
+ */
+
+#ifndef WOLFHSM_WH_PORT_H_
+#define WOLFHSM_WH_PORT_H_
+
+#include
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_server.h"
+
+/** @defgroup Port Port API
+ * @brief Platform-specific board, client, and server initialization functions.
+ * @{
+ */
+
+/* Common API */
+
+/**
+ * @brief Initialize the board and any shared platform resources.
+ *
+ * Called once at startup before any client or server operations. Performs
+ * platform-specific initialization.
+ *
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_InitBoard(void);
+
+/**
+ * @brief Clean up board resources allocated by wh_Port_InitBoard.
+ *
+ * Called at shutdown to release any shared platform resources.
+ *
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_CleanupBoard(void);
+
+/* Client API */
+
+/**
+ * @brief Populate a client configuration structure with port-specific settings.
+ *
+ * Sets up transport, communication, and callback configuration for the client.
+ * The resulting configuration can be passed to wh_Port_InitClient.
+ *
+ * @param[out] clientCfg Pointer to the client configuration to populate.
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_ConfigureClient(whClientConfig* clientCfg);
+
+/**
+ * @brief Initialize and connect a client using the given configuration.
+ *
+ * Initializes the client context and establishes communication with the server.
+ *
+ * @param[in] clientCfg Pointer to the client configuration.
+ * @param[out] clientCtx Pointer to the client context to initialize.
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_InitClient(whClientConfig* clientCfg, whClientContext* clientCtx);
+
+/**
+ * @brief Run the main client application logic.
+ *
+ * Executes the client workload (e.g. echo requests, tests, benchmarks).
+ *
+ * @param[in] clientCtx Pointer to an initialized client context.
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_RunClient(whClientContext* clientCtx);
+
+/**
+ * @brief Clean up a client and release its resources.
+ *
+ * Closes the communication channel and cleans up the client context.
+ *
+ * @param[in] clientCtx Pointer to the client context to clean up.
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_CleanupClient(whClientContext* clientCtx);
+
+/* Server API */
+
+/**
+ * @brief Populate a server configuration structure for a given instance.
+ *
+ * Sets up transport, NVM, flash, and crypto configuration for the specified
+ * server instance.
+ *
+ * @param[in] instance Server instance index.
+ * @param[out] serverCfg Pointer to the server configuration to populate.
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_ConfigureServer(size_t instance, whServerConfig* serverCfg);
+
+/**
+ * @brief Initialize a server instance using the given configuration.
+ *
+ * @param[in] instance Server instance index.
+ * @param[in] serverCfg Pointer to the server configuration.
+ * @param[out] serverCtx Pointer to the server context to initialize.
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_InitServer(size_t instance, whServerConfig* serverCfg,
+ whServerContext* serverCtx);
+
+/**
+ * @brief Clean up a server instance and release its resources.
+ *
+ * @param[in] instance Server instance index.
+ * @param[in] serverCtx Pointer to the server context to clean up.
+ * @return 0 on success, negative error code on failure.
+ */
+int wh_Port_CleanupServer(size_t instance, whServerContext* serverCtx);
+
+/**
+ * @brief Check if a new client connection notification has been received.
+ *
+ * Returns true once when a client has connected to the given server instance.
+ * Subsequent calls will return 0 until the next client connects.
+ *
+ * @param[in] instance Server instance index.
+ * @return 1 if a client connected notification was received, 0 otherwise.
+ */
+int wh_Port_ClientConnected(size_t instance);
+
+/**
+ * @brief Check if a client disconnection notification has been received.
+ *
+ * Returns true once when a client has disconnected from the given server
+ * instance. Subsequent calls will return 0 until the next client disconnects.
+ *
+ * @param[in] instance Server instance index.
+ * @return 1 if a client disconnected notification was received, 0 otherwise.
+ */
+int wh_Port_ClientDisconnected(size_t instance);
+
+/** @} */ /* end Port */
+
+#endif /* WOLFHSM_WH_PORT_H_ */