diff --git a/.github/workflows/build-and-run-examples.yml b/.github/workflows/build-and-run-examples.yml index 441dd361..ca3c6bd3 100644 --- a/.github/workflows/build-and-run-examples.yml +++ b/.github/workflows/build-and-run-examples.yml @@ -10,7 +10,7 @@ jobs: build: strategy: matrix: - transport: [ 'tcp', 'shm', 'dma' ] + transport: [ 'tcp', 'shm', 'dma', 'tls', 'psk' ] asan: [ 'ASAN=1', 'ASAN=0' ] debug: [ '', 'DEBUG_VERBOSE=1' ] test: [ '', '--test' ] @@ -27,27 +27,40 @@ jobs: repository: wolfssl/wolfssl path: wolfssl + - name: Set TLS Environment Variable + run: | + if [ "${{ matrix.transport }}" = "tls" ] || [ "${{ matrix.transport }}" = "psk" ]; then + echo "TLS=1" >> $GITHUB_ENV + else + echo "TLS=0" >> $GITHUB_ENV + fi + # Build examples - name: Build POSIX server run: | if [ "${{ matrix.transport }}" = "dma" ]; then cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} DMA=1 make -j WOLFSSL_DIR=../../../wolfssl else - cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} make -j WOLFSSL_DIR=../../../wolfssl + cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} TLS=${{ env.TLS }} make -j WOLFSSL_DIR=../../../wolfssl fi + - name: Build POSIX client run: | if [ "${{ matrix.transport }}" = "dma" ]; then cd examples/posix/wh_posix_client && ${{ matrix.asan }} ${{ matrix.debug }} DMA=1 make -j WOLFSSL_DIR=../../../wolfssl else - cd examples/posix/wh_posix_client && ${{ matrix.asan }} ${{ matrix.debug }} make -j WOLFSSL_DIR=../../../wolfssl + cd examples/posix/wh_posix_client && ${{ matrix.asan }} ${{ matrix.debug }} TLS=${{ env.TLS }} make -j WOLFSSL_DIR=../../../wolfssl fi # Start the server in the background - name: Run POSIX server run: | cd examples/posix/wh_posix_server - ./Build/wh_posix_server.elf --type ${{ matrix.transport }} & + if [ "${{ matrix.transport }}" = "psk" ]; then + echo "test_password" | ./Build/wh_posix_server.elf --type ${{ matrix.transport }} & + else + ./Build/wh_posix_server.elf --type ${{ matrix.transport }} & + fi POSIX_SERVER_PID=$! echo "POSIX_SERVER_PID=$POSIX_SERVER_PID" >> $GITHUB_ENV @@ -55,7 +68,11 @@ jobs: - name: Run POSIX client run: | cd examples/posix/wh_posix_client - ./Build/wh_posix_client.elf --type ${{ matrix.transport }} ${{ matrix.test }} + if [ "${{ matrix.transport }}" = "psk" ]; then + echo "test_password" | ./Build/wh_posix_client.elf --type ${{ matrix.transport }} ${{ matrix.test }} + else + ./Build/wh_posix_client.elf --type ${{ matrix.transport }} ${{ matrix.test }} + fi # Optional: Kill the server process if it doesn't exit on its own - name: Cleanup POSIX server diff --git a/.github/workflows/build-and-test-clientonly.yml b/.github/workflows/build-and-test-clientonly.yml index ef4a2334..af34da4a 100644 --- a/.github/workflows/build-and-test-clientonly.yml +++ b/.github/workflows/build-and-test-clientonly.yml @@ -8,7 +8,9 @@ on: jobs: build: - + strategy: + matrix: + transport: [ 'tcp', 'tls' ] runs-on: ubuntu-latest steps: @@ -33,32 +35,40 @@ jobs: - name: Build POSIX server run: | cd examples/posix/wh_posix_server - make -j SHE=1 WOLFSSL_DIR=../../../wolfssl + if [ "${{ matrix.transport }}" = "tcp" ]; then + make -j SHE=1 WOLFSSL_DIR=../../../wolfssl + else + make -j TLS=1 SHE=1 WOLFSSL_DIR=../../../wolfssl + fi # Start the server in the background - name: Run POSIX server run: | cd examples/posix/wh_posix_server - ./Build/wh_posix_server.elf & - TCP_SERVER_PID=$! - echo "TCP_SERVER_PID=$TCP_SERVER_PID" >> $GITHUB_ENV + ./Build/wh_posix_server.elf --type ${{ matrix.transport }} & + SERVER_PID=$! + echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV # Build and test client-only build with everything enabled and ASAN - name: Build client-only unit tests with ASAN run: | cd test make clean - make -j CLIENT_ONLY_TCP=1 SHE=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run + if [ "${{ matrix.transport }}" = "tcp" ]; then + make -j CLIENT_ONLY=1 SHE=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run + else + make -j CLIENT_ONLY=1 TLS=1 SHE=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run + fi # Restart server with fresh state for second test run - name: Restart POSIX server run: | - kill $TCP_SERVER_PID || true + kill $SERVER_PID || true cd examples/posix/wh_posix_server rm -f *.bin || true - ./Build/wh_posix_server.elf & - TCP_SERVER_PID=$! - echo "TCP_SERVER_PID=$TCP_SERVER_PID" >> $GITHUB_ENV + ./Build/wh_posix_server.elf --type ${{ matrix.transport }} & + SERVER_PID=$! + echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV sleep 2 # Build and test client-only with DEBUG_VERBOSE=1 (includes DEBUG) @@ -66,10 +76,14 @@ jobs: run: | cd test make clean - make -j CLIENT_ONLY_TCP=1 SHE=1 DEBUG_VERBOSE=1 WOLFSSL_DIR=../wolfssl && make run + if [ "${{ matrix.transport }}" = "tcp" ]; then + make -j CLIENT_ONLY=1 SHE=1 DEBUG_VERBOSE=1 WOLFSSL_DIR=../wolfssl && make run + else + make -j CLIENT_ONLY=1 TLS=1 SHE=1 DEBUG_VERBOSE=1 WOLFSSL_DIR=../wolfssl && make run + fi # Optional: Kill the server process if it doesn't exit on its own - - name: Cleanup POSIX TCP server + - name: Cleanup POSIX server if: always() - run: kill $TCP_SERVER_PID || true - + run: kill $SERVER_PID || true + diff --git a/examples/posix/wh_posix_client/Makefile b/examples/posix/wh_posix_client/Makefile index 1b862518..be048123 100644 --- a/examples/posix/wh_posix_client/Makefile +++ b/examples/posix/wh_posix_client/Makefile @@ -112,7 +112,10 @@ DEF += -DWC_USE_DEVID=0x57444D41 -DWC_NO_DEFAULT_DEVID CFLAGS += -DWOLFHSM_CFG_DMA else DEF += -DWC_USE_DEVID=0x5748534D +endif +ifeq ($(TLS),1) +CFLAGS += -DWOLFHSM_CFG_TLS endif #wolfCrypt test/benchmark source files diff --git a/examples/posix/wh_posix_client/wh_posix_client.c b/examples/posix/wh_posix_client/wh_posix_client.c index 311c198c..36c5a61b 100644 --- a/examples/posix/wh_posix_client/wh_posix_client.c +++ b/examples/posix/wh_posix_client/wh_posix_client.c @@ -160,7 +160,17 @@ void Usage(const char* exeName) { WOLFHSM_CFG_PRINTF("Usage: %s --type --test\n", exeName); WOLFHSM_CFG_PRINTF("Example: %s --type tcp\n", exeName); - WOLFHSM_CFG_PRINTF("type: tcp (default), shm\n"); + WOLFHSM_CFG_PRINTF("type: tcp (default), shm"); +#ifdef WOLFHSM_CFG_TLS + WOLFHSM_CFG_PRINTF(", tls"); +#if !defined(NO_PSK) + WOLFHSM_CFG_PRINTF(", psk"); +#endif +#endif /* WOLFHSM_CFG_TLS */ +#ifdef WOLFSSL_STATIC_MEMORY + WOLFHSM_CFG_PRINTF(", dma"); +#endif + WOLFHSM_CFG_PRINTF("\n"); } int main(int argc, char** argv) @@ -204,6 +214,18 @@ int main(int argc, char** argv) WOLFHSM_CFG_PRINTF("Using shared memory transport\n"); wh_PosixClient_ExampleShmConfig(c_conf); } +#ifdef WOLFHSM_CFG_TLS + else if (strcmp(type, "tls") == 0) { + WOLFHSM_CFG_PRINTF("Using TLS transport\n"); + wh_PosixClient_ExampleTlsConfig(c_conf); + } +#if !defined(NO_PSK) + else if (strcmp(type, "psk") == 0) { + WOLFHSM_CFG_PRINTF("Using TLS PSK transport\n"); + wh_PosixClient_ExamplePskConfig(c_conf); + } +#endif /* !NO_PSK */ +#endif /* WOLFHSM_CFG_TLS */ #ifdef WOLFSSL_STATIC_MEMORY else if (strcmp(type, "dma") == 0) { WOLFHSM_CFG_PRINTF("Using DMA with shared memory transport\n"); diff --git a/examples/posix/wh_posix_client/wh_posix_client_cfg.c b/examples/posix/wh_posix_client/wh_posix_client_cfg.c index 4e01eb9d..8f54faca 100644 --- a/examples/posix/wh_posix_client/wh_posix_client_cfg.c +++ b/examples/posix/wh_posix_client/wh_posix_client_cfg.c @@ -10,19 +10,31 @@ #include "port/posix/posix_transport_shm.h" #include "port/posix/posix_transport_tcp.h" +#ifdef WOLFHSM_CFG_TLS +#include "port/posix/posix_transport_tls.h" +#endif #include posixTransportShmClientContext tccShm; posixTransportTcpClientContext tccTcp; +#ifdef WOLFHSM_CFG_TLS +posixTransportTlsClientContext tccTls; +#endif posixTransportShmConfig shmConfig; posixTransportTcpConfig tcpConfig; +#ifdef WOLFHSM_CFG_TLS +posixTransportTlsConfig tlsConfig; +#endif whCommClientConfig c_comm; whTransportClientCb shmCb = POSIX_TRANSPORT_SHM_CLIENT_CB; whTransportClientCb tcpCb = PTT_CLIENT_CB; +#ifdef WOLFHSM_CFG_TLS +whTransportClientCb tlsCb = PTTLS_CLIENT_CB; +#endif #ifdef WOLFSSL_STATIC_MEMORY whTransportClientCb dmaCb = POSIX_TRANSPORT_SHM_CLIENT_CB; @@ -123,6 +135,85 @@ int wh_PosixClient_ExampleTcpConfig(void* conf) return WH_ERROR_OK; } +#if defined(WOLFHSM_CFG_TLS) +/* client configuration setup example for TLS transport */ +#undef USE_CERT_BUFFERS_2048 +#define USE_CERT_BUFFERS_2048 +#include "wolfssl/certs_test.h" + +int wh_PosixClient_ExampleTlsConfig(void* conf) +{ + whClientConfig* c_conf = (whClientConfig*)conf; + + memset(&tccTls, 0, sizeof(posixTransportTlsClientContext)); + + /* Initialize TLS context fields that need specific values */ + tccTls.state = 0; + tccTls.connect_fd_p1 = 0; /* Invalid fd */ + + tlsConfig.server_ip_string = WH_POSIX_SERVER_TCP_IPSTRING; + tlsConfig.server_port = WH_POSIX_SERVER_TCP_PORT; + tlsConfig.disable_peer_verification = false; + + tlsConfig.ca_cert = ca_cert_der_2048; + tlsConfig.ca_cert_len = sizeof_ca_cert_der_2048; + tlsConfig.cert = client_cert_der_2048; + tlsConfig.cert_len = sizeof_client_cert_der_2048; + tlsConfig.key = client_key_der_2048; + tlsConfig.key_len = sizeof_client_key_der_2048; + tlsConfig.heap_hint = NULL; + + c_comm.transport_cb = &tlsCb; + c_comm.transport_context = (void*)&tccTls; + c_comm.transport_config = (void*)&tlsConfig; + c_comm.client_id = WH_POSIX_CLIENT_ID; + c_conf->comm = &c_comm; + + return WH_ERROR_OK; +} + + +#ifndef NO_PSK +/* Simple PSK example callback */ +static unsigned int psk_tls12_client_cb(WOLFSSL* ssl, const char* hint, + char* identity, unsigned int id_max_len, + unsigned char* key, + unsigned int key_max_len) +{ + size_t len; + + memset(key, 0, key_max_len); + const char* exampleIdentity = "PSK_EXAMPLE_CLIENT_IDENTITY"; + + printf("PSK server identity hint: %s\n", hint); + printf("PSK using identity: %s\n", exampleIdentity); + strncpy(identity, exampleIdentity, id_max_len); + + printf("Enter PSK password: "); + if (fgets((char*)key, key_max_len - 1, stdin) == NULL) { + memset(key, 0, key_max_len); + return 0U; + } + + (void)ssl; + len = strcspn((char*)key, "\n"); + ((char*)key)[len] = '\0'; + return (unsigned int)len; +} + + +int wh_PosixClient_ExamplePskConfig(void* conf) +{ + if (wh_PosixClient_ExampleTlsConfig(conf) != WH_ERROR_OK) { + return WH_ERROR_ABORTED; + } + tlsConfig.psk_client_cb = psk_tls12_client_cb; + + return WH_ERROR_OK; +} +#endif /* NO_PSK */ +#endif /* WOLFHSM_CFG_TLS */ + /* client configuration setup example for transport */ int wh_PosixClient_ExampleShmConfig(void* conf) diff --git a/examples/posix/wh_posix_client/wh_posix_client_cfg.h b/examples/posix/wh_posix_client/wh_posix_client_cfg.h index 5931150c..27cdf9ea 100644 --- a/examples/posix/wh_posix_client/wh_posix_client_cfg.h +++ b/examples/posix/wh_posix_client/wh_posix_client_cfg.h @@ -4,5 +4,11 @@ int wh_PosixClient_ExampleShmDmaConfig(void* c_conf); int wh_PosixClient_ExampleShmConfig(void* c_conf); int wh_PosixClient_ExampleTcpConfig(void* c_conf); +#ifdef WOLFHSM_CFG_TLS +int wh_PosixClient_ExampleTlsConfig(void* c_conf); +#if !defined(NO_PSK) +int wh_PosixClient_ExamplePskConfig(void* c_conf); +#endif /* !NO_PSK */ +#endif /* WOLFHSM_CFG_TLS */ int wh_PosixClient_ExampleSetupDmaMemory(void* ctx, void* c_conf); -#endif /* WH_POSIX_CLIENT_CFG_H */ \ No newline at end of file +#endif /* WH_POSIX_CLIENT_CFG_H */ diff --git a/examples/posix/wh_posix_server/Makefile b/examples/posix/wh_posix_server/Makefile index bee381a3..c5a86cd9 100644 --- a/examples/posix/wh_posix_server/Makefile +++ b/examples/posix/wh_posix_server/Makefile @@ -87,6 +87,11 @@ ifeq ($(SHE),1) CFLAGS += -DWOLFHSM_CFG_SHE_EXTENSION endif +# Support a TLS-capable build +ifeq ($(TLS),1) +CFLAGS += -DWOLFHSM_CFG_TLS +endif + ifeq ($(DMA),1) CFLAGS += -DWOLFHSM_CFG_DMA endif diff --git a/examples/posix/wh_posix_server/user_settings.h b/examples/posix/wh_posix_server/user_settings.h index 70df2dc6..99e120ca 100644 --- a/examples/posix/wh_posix_server/user_settings.h +++ b/examples/posix/wh_posix_server/user_settings.h @@ -47,10 +47,15 @@ extern "C" { #define WOLFSSL_BASE64_ENCODE #define HAVE_ANONYMOUS_INLINE_AGGREGATES 1 -/* For cert manager */ +#ifndef WOLFHSM_CFG_TLS +/* These macros reduce footprint size when TLS functionality is not needed */ #define NO_TLS /* Eliminates need for IO layer since we only use CM */ #define WOLFSSL_USER_IO +#define WOLFSSL_NO_TLS12 +#define NO_PSK +#endif /* WOLFHSM_CFG_TLS */ + /* For ACert support (also requires WOLFSSL_ASN_TEMPLATE) */ #define WOLFSSL_ACERT @@ -71,7 +76,6 @@ extern "C" { #define NO_ERROR_QUEUE #define NO_INLINE #define NO_OLD_TLS -#define WOLFSSL_NO_TLS12 #define NO_DO178 /* Prevents certain functions (SHA, hash.c) on server from falling back to * client cryptoCb when using non-devId APIs */ @@ -154,7 +158,6 @@ extern "C" { /* Remove unneeded crypto */ #define NO_DSA #define NO_RC4 -#define NO_PSK #define NO_MD4 #define NO_MD5 #define NO_DES3 @@ -190,11 +193,17 @@ extern "C" { #endif /* optional malloc check */ #endif /* optional static memory */ -#ifdef WOLFHSM_CFG_DMA +#if defined(WOLFHSM_CFG_DMA) || defined(WOLFHSM_CFG_TLS) +/* If using DMA or TLS use static memory for no dynamic memory allocation */ #undef WOLFSSL_STATIC_MEMORY #define WOLFSSL_STATIC_MEMORY #endif +/* additional memory debugging macros, prints out each alloc and free */ +/* #define WOLFSSL_DEBUG_MEMORY */ +/* #define WOLFSSL_DEBUG_MEMORY_PRINT */ + +/* #define DEBUG_WOLFSSL */ #ifdef __cplusplus } #endif diff --git a/examples/posix/wh_posix_server/wh_posix_server.c b/examples/posix/wh_posix_server/wh_posix_server.c index ca49dd8f..0f0d9bca 100644 --- a/examples/posix/wh_posix_server/wh_posix_server.c +++ b/examples/posix/wh_posix_server/wh_posix_server.c @@ -276,7 +276,17 @@ static void Usage(const char* exeName) WOLFHSM_CFG_PRINTF("Example: %s --key key.bin --id 123 --client 456 " "--nvminit nvm_init.txt --type tcp --flags 0\n", exeName); - WOLFHSM_CFG_PRINTF("type: tcp (default), shm, dma\n"); + WOLFHSM_CFG_PRINTF("type: tcp (default), shm"); +#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_TLS) + WOLFHSM_CFG_PRINTF(", tls"); +#if !defined(NO_PSK) + WOLFHSM_CFG_PRINTF(", psk"); +#endif +#endif /* !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_TLS) */ +#ifdef WOLFHSM_CFG_DMA + WOLFHSM_CFG_PRINTF(", dma"); +#endif + WOLFHSM_CFG_PRINTF("\n"); } @@ -340,18 +350,52 @@ int main(int argc, char** argv) memset(s_conf, 0, sizeof(whServerConfig)); if (strcmp(type, "tcp") == 0) { WOLFHSM_CFG_PRINTF("Using TCP transport\n"); - wh_PosixServer_ExampleTcpConfig(s_conf); + rc = wh_PosixServer_ExampleTcpConfig(s_conf); + if (rc != WH_ERROR_OK) { + WOLFHSM_CFG_PRINTF("Failed to initialize TCP transport\n"); + return -1; + } } else if (strcmp(type, "shm") == 0) { WOLFHSM_CFG_PRINTF("Using shared memory transport\n"); - wh_PosixServer_ExampleShmConfig(s_conf); + rc = wh_PosixServer_ExampleShmConfig(s_conf); + if (rc != WH_ERROR_OK) { + WOLFHSM_CFG_PRINTF( + "Failed to initialize shared memory transport\n"); + return -1; + } } -#ifdef WOLFSSL_STATIC_MEMORY +#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_TLS) + else if (strcmp(type, "tls") == 0) { + WOLFHSM_CFG_PRINTF("Using TLS transport\n"); + rc = wh_PosixServer_ExampleTlsConfig(s_conf); + if (rc != WH_ERROR_OK) { + WOLFHSM_CFG_PRINTF("Failed to initialize TLS transport\n"); + return -1; + } + } +#if !defined(NO_PSK) + else if (strcmp(type, "psk") == 0) { + WOLFHSM_CFG_PRINTF("Using TLS PSK transport\n"); + rc = wh_PosixServer_ExamplePskConfig(s_conf); + if (rc != WH_ERROR_OK) { + WOLFHSM_CFG_PRINTF("Failed to initialize TLS PSK transport\n"); + return -1; + } + } +#endif /* !defined(NO_PSK) */ +#endif /* !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_TLS) */ +#ifdef WOLFHSM_CFG_DMA else if (strcmp(type, "dma") == 0) { WOLFHSM_CFG_PRINTF("Using DMA with shared memory transport\n"); - wh_PosixServer_ExampleShmDmaConfig(s_conf); + rc = wh_PosixServer_ExampleShmDmaConfig(s_conf); + if (rc != WH_ERROR_OK) { + WOLFHSM_CFG_PRINTF( + "Failed to initialize DMA with shared memory transport\n"); + return -1; + } } -#endif +#endif /* WOLFHSM_CFG_DMA */ else { WOLFHSM_CFG_PRINTF("Invalid server type: %s\n", type); return -1; diff --git a/examples/posix/wh_posix_server/wh_posix_server_cfg.c b/examples/posix/wh_posix_server/wh_posix_server_cfg.c index 5f194e82..754a0b82 100644 --- a/examples/posix/wh_posix_server/wh_posix_server_cfg.c +++ b/examples/posix/wh_posix_server/wh_posix_server_cfg.c @@ -17,6 +17,9 @@ #include "port/posix/posix_transport_shm.h" #include "port/posix/posix_transport_tcp.h" +#ifdef WOLFHSM_CFG_TLS +#include "port/posix/posix_transport_tls.h" +#endif posixTransportShmConfig shmConfig; posixTransportTcpConfig tcpConfig; @@ -27,8 +30,13 @@ whTransportServerCb tcpCb = PTT_SERVER_CB; whTransportServerCb shmCb = POSIX_TRANSPORT_SHM_SERVER_CB; posixTransportShmServerContext tscShm; posixTransportTcpServerContext tscTcp; +#ifdef WOLFHSM_CFG_TLS +posixTransportTlsConfig tlsConfig; +whTransportServerCb tlsCb = PTTLS_SERVER_CB; +posixTransportTlsServerContext tscTls; +#endif -#ifdef WOLFSSL_STATIC_MEMORY +#ifdef WOLFHSM_CFG_DMA whTransportServerCb dmaCb = POSIX_TRANSPORT_SHM_SERVER_CB; posixTransportShmServerContext tscDma; whServerDmaConfig dmaConfig; @@ -110,6 +118,137 @@ int wh_PosixServer_ExampleTcpConfig(void* conf) return WH_ERROR_OK; } +#if defined(WOLFHSM_CFG_TLS) +/* Server configuration setup example for TLS transport + * Does not setup flash, nvm, crypto, she, etc. */ + +#undef USE_CERT_BUFFERS_2048 +#define USE_CERT_BUFFERS_2048 +#include "wolfssl/certs_test.h" + +#ifdef WOLFSSL_STATIC_MEMORY +#define EXAMPLE_STATIC_MEMORY_SIZE 70000 +WOLFSSL_HEAP_HINT* heap = NULL; +static unsigned char memoryBuffer[EXAMPLE_STATIC_MEMORY_SIZE]; +unsigned int staticMemoryList[] = {176, 304, 384, 480, 1008, + 3328, 4560, 5152, 8928}; +unsigned int staticMemoryDist[] = {14, 4, 3, 3, 4, 10, 2, 1, 1}; + +static void* GetHeapHint() +{ + /* Initialize static memory buffer */ + if (wc_LoadStaticMemory_ex(&heap, WH_POSIX_STATIC_MEM_LIST_SIZE, + staticMemoryList, staticMemoryDist, memoryBuffer, + EXAMPLE_STATIC_MEMORY_SIZE, 0, 0) != 0) { + return NULL; + } + return (void*)heap; +} +#endif /* WOLFSSL_STATIC_MEMORY */ + +int wh_PosixServer_ExampleTlsConfig(void* ctx) +{ + whServerConfig* s_conf = (whServerConfig*)ctx; + + /* Server configuration/context */ + memset(&tscTls, 0, sizeof(posixTransportTlsServerContext)); + + /* Initialize TCP context fields that need specific values */ + tscTls.listen_fd_p1 = 0; /* Invalid fd */ + tscTls.accept_fd_p1 = 0; /* Invalid fd */ + tscTls.request_recv = 0; + tscTls.buffer_offset = 0; + + tlsConfig.server_ip_string = WH_POSIX_SERVER_TCP_IPSTRING; + tlsConfig.server_port = WH_POSIX_SERVER_TCP_PORT; + tlsConfig.disable_peer_verification = false; + tlsConfig.ca_cert = client_cert_der_2048; + tlsConfig.ca_cert_len = sizeof_client_cert_der_2048; + tlsConfig.cert = server_cert_der_2048; + tlsConfig.cert_len = sizeof_server_cert_der_2048; + tlsConfig.key = server_key_der_2048; + tlsConfig.key_len = sizeof_server_key_der_2048; +#ifdef WOLFSSL_STATIC_MEMORY + tlsConfig.heap_hint = GetHeapHint(); +#endif /* WOLFSSL_STATIC_MEMORY */ + + s_comm.transport_cb = &tlsCb; + s_comm.transport_context = (void*)&tscTls; + s_comm.transport_config = (void*)&tlsConfig; + s_comm.server_id = WH_POSIX_SERVER_ID; + + s_conf->comm_config = &s_comm; + + return WH_ERROR_OK; +} + + +#ifndef NO_PSK + +#ifdef WOLFSSL_TLS13 +static unsigned int psk_tls13_server_cb(WOLFSSL* ssl, const char* identity, + unsigned char* key, + unsigned int key_max_len, + const char** ciphersuite) +{ + size_t len; + + memset(key, 0, key_max_len); + printf("PSK TLS13 server callback\n"); + printf("PSK client identity: %s\n", identity); + *ciphersuite = "TLS13-AES128-GCM-SHA256"; + + printf("Enter PSK password: "); + if (fgets((char*)key, key_max_len - 1, stdin) == NULL) { + memset(key, 0, key_max_len); + return 0U; + } + len = strcspn((char*)key, "\n"); + ((char*)key)[len] = '\0'; + + (void)ssl; + return (unsigned int)len; +} +#endif /* WOLFSSL_TLS13 */ + +static unsigned int psk_tls12_server_cb(WOLFSSL* ssl, const char* identity, + unsigned char* key, + unsigned int key_max_len) +{ + size_t len; + + memset(key, 0, key_max_len); + printf("PSK TLS12 server callback\n"); + printf("PSK client identity: %s\n", identity); + printf("Enter PSK password to accept: "); + if (fgets((char*)key, key_max_len - 1, stdin) == NULL) { + memset(key, 0, key_max_len); + return 0U; + } + len = strcspn((char*)key, "\n"); + ((char*)key)[len] = '\0'; + (void)ssl; + return (unsigned int)len; +} + + +int wh_PosixServer_ExamplePskConfig(void* conf) +{ + if (wh_PosixServer_ExampleTlsConfig(conf) != WH_ERROR_OK) { + return WH_ERROR_ABORTED; + } + + tlsConfig.psk_server_cb = psk_tls12_server_cb; +#ifdef WOLFSSL_TLS13 + tlsConfig.psk_server_tls13_cb = psk_tls13_server_cb; +#endif /* WOLFSSL_TLS13 */ + tlsConfig.psk_identity_hint = "wolfHSM Example Server"; + + return WH_ERROR_OK; +} +#endif /* NO_PSK */ +#endif /* WOLFHSM_CFG_TLS */ + static const whFlashCb fcb = WH_FLASH_RAMSIM_CB; static whFlashRamsimCfg fc_conf; diff --git a/examples/posix/wh_posix_server/wh_posix_server_cfg.h b/examples/posix/wh_posix_server/wh_posix_server_cfg.h index 6b859887..1b95d26f 100644 --- a/examples/posix/wh_posix_server/wh_posix_server_cfg.h +++ b/examples/posix/wh_posix_server/wh_posix_server_cfg.h @@ -6,7 +6,13 @@ int wh_PosixServer_ExampleShmDmaConfig(void* s_conf); int wh_PosixServer_ExampleShmConfig(void* s_conf); int wh_PosixServer_ExampleTcpConfig(void* s_conf); +#ifdef WOLFHSM_CFG_TLS +int wh_PosixServer_ExampleTlsConfig(void* s_conf); +#if !defined(NO_PSK) +int wh_PosixServer_ExamplePskConfig(void* s_conf); +#endif +#endif /* WOLFHSM_CFG_TLS */ int wh_PosixServer_ExampleNvmConfig(void* conf, const char* nvmInitFilePath); int wh_PosixServer_ExampleRamSimConfig(void* conf, uint8_t* memory); -#endif /* WH_POSIX_SERVER_CFG_H */ \ No newline at end of file +#endif /* WH_POSIX_SERVER_CFG_H */ diff --git a/port/posix/posix_transport_tcp.c b/port/posix/posix_transport_tcp.c index 1b2247b6..9e652d4f 100644 --- a/port/posix/posix_transport_tcp.c +++ b/port/posix/posix_transport_tcp.c @@ -57,9 +57,9 @@ static int posixTransportTcp_Recv(int fd, uint16_t* buffer_offset, uint8_t* buffer, uint16_t *out_size, void* data); /* Start a non-blocking connect */ -static int posixTransportTcp_HandleConnect(posixTransportTcpClientContext* c); +int posixTransportTcp_HandleConnect(posixTransportTcpClientContext* c); -/* CLose connection and reset state */ +/* Close connection and reset state */ static int posixTransportTcp_Close(posixTransportTcpClientContext* c); @@ -240,8 +240,7 @@ static int posixTransportTcp_Recv(int fd, uint16_t* buffer_offset, } /** Client functions */ - -static int posixTransportTcp_HandleConnect(posixTransportTcpClientContext* c) +int posixTransportTcp_HandleConnect(posixTransportTcpClientContext* c) { int ret = WH_ERROR_OK; diff --git a/port/posix/posix_transport_tls.c b/port/posix/posix_transport_tls.c new file mode 100644 index 00000000..eba2322f --- /dev/null +++ b/port/posix/posix_transport_tls.c @@ -0,0 +1,655 @@ +/* + * 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 . + */ +/* + * port/posix/posix_transport_tls.c + * + * wolfHSM Transport binding using TLS sockets with wolfSSL + * + * This implementation provides basic TLS server functionality using wolfSSL + * with embedded certificates for authentication. + */ + +#include "posix_transport_tls.h" +#include "wolfhsm/wh_error.h" + +#if defined(WOLFHSM_CFG_TLS) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef WOLFHSM_CFG_NO_CRYPTO + +/* returns 1 (true) if the error passed in is a notice for non blocking + * 0 if the error is a fatal error */ +static int NonBlockingError(int err) +{ + return (err == WOLFSSL_ERROR_WANT_READ) || + (err == WOLFSSL_ERROR_WANT_WRITE); +} + +/* Load certificates and keys from config structure into SSL context */ +static int LoadTlsCertificates(WOLFSSL_CTX* ssl_ctx, + const posixTransportTlsConfig* cfg) +{ + int rc; + + if (!ssl_ctx || !cfg) { + return WH_ERROR_BADARGS; + } + + /* Load CA certificate for peer verification */ + if (cfg->ca_cert != NULL && cfg->ca_cert_len > 0) { + rc = wolfSSL_CTX_load_verify_buffer( + ssl_ctx, cfg->ca_cert, cfg->ca_cert_len, WOLFSSL_FILETYPE_ASN1); + if (rc != WOLFSSL_SUCCESS) { + return WH_ERROR_ABORTED; + } + } + + /* Load certificate (client cert for client, server cert for server) */ + if (cfg->cert != NULL && cfg->cert_len > 0) { + rc = wolfSSL_CTX_use_certificate_buffer( + ssl_ctx, cfg->cert, cfg->cert_len, WOLFSSL_FILETYPE_ASN1); + if (rc != WOLFSSL_SUCCESS) { + return WH_ERROR_ABORTED; + } + } + + /* Load private key (client key for client, server key for server) */ + if (cfg->key != NULL && cfg->key_len > 0) { + rc = wolfSSL_CTX_use_PrivateKey_buffer(ssl_ctx, cfg->key, cfg->key_len, + WOLFSSL_FILETYPE_ASN1); + if (rc != WOLFSSL_SUCCESS) { + return WH_ERROR_ABORTED; + } + } + + /* Set verification mode */ + if (cfg->disable_peer_verification) { + wolfSSL_CTX_set_verify(ssl_ctx, WOLFSSL_VERIFY_NONE, NULL); + } + else { + wolfSSL_CTX_set_verify(ssl_ctx, WOLFSSL_VERIFY_PEER, NULL); + } + + return WH_ERROR_OK; +} +#endif /* WOLFHSM_CFG_NO_CRYPTO */ + +/** Client-side TLS transport functions */ + +int posixTransportTls_InitConnect(void* context, const void* config, + whCommSetConnectedCb connectcb, + void* connectcb_arg) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsClientContext* ctx = + (posixTransportTlsClientContext*)context; + posixTransportTlsConfig* cfg = (posixTransportTlsConfig*)config; + int rc; + + if (!ctx || !cfg) { + return WH_ERROR_BADARGS; + } + + memset(ctx, 0, sizeof(posixTransportTlsClientContext)); + + /* Create SSL context using static memory if heap_hint is provided */ +#ifdef WOLFSSL_STATIC_MEMORY + if (cfg->heap_hint != NULL) { + ctx->ssl_ctx = wolfSSL_CTX_new_ex( + wolfSSLv23_client_method_ex(cfg->heap_hint), cfg->heap_hint); + } + else { + ctx->ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + } +#else + ctx->ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); +#endif + if (!ctx->ssl_ctx) { + return WH_ERROR_ABORTED; + } + + /* don't use wolfHSM for TLS crypto when communicating with wolfHSM */ + wolfSSL_CTX_SetDevId(ctx->ssl_ctx, INVALID_DEVID); + + /* Load certificates from config structure */ + rc = LoadTlsCertificates(ctx->ssl_ctx, cfg); + if (rc != WH_ERROR_OK) { + wolfSSL_CTX_free(ctx->ssl_ctx); + ctx->ssl_ctx = NULL; + return rc; + } + +#ifndef NO_PSK + /* Setup PSK callbacks if provided */ + if (cfg->psk_client_cb != NULL) { + wolfSSL_CTX_set_psk_client_callback(ctx->ssl_ctx, cfg->psk_client_cb); + } +#endif /* NO_PSK */ + + /* Setup underlying TCP transport */ + rc = posixTransportTcp_InitConnect((void*)&ctx->tcpCtx, cfg, connectcb, + connectcb_arg); + if (rc != WH_ERROR_OK) { + if (ctx->ssl_ctx != NULL) { + wolfSSL_CTX_free(ctx->ssl_ctx); + ctx->ssl_ctx = NULL; + } + return rc; + } + + /* At the point of the TCP claiming to be connected, the TLS handshake will + * happen during send/recv calls */ + if (ctx->connectcb != NULL) { + ctx->connectcb(ctx->connectcb_arg, WH_COMM_CONNECTED); + } + return WH_ERROR_OK; +#else + (void)context; + (void)config; + (void)connectcb; + (void)connectcb_arg; + return WH_ERROR_NOTIMPL; +#endif +} + +extern int posixTransportTcp_HandleConnect(posixTransportTcpClientContext* c); + +int posixTransportTls_SendRequest(void* context, uint16_t size, + const void* data) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsClientContext* ctx = + (posixTransportTlsClientContext*)context; + int err; + int rc = 0; + + if (!ctx || !data || size == 0) { + return WH_ERROR_BADARGS; + } + + if (ctx->state != PTTLS_STATE_CONNECTED) { + if (posixTransportTcp_HandleConnect((void*)&ctx->tcpCtx) != + WH_ERROR_OK) { + return WH_ERROR_NOTREADY; + } + + /* Create SSL object if not already created + * (posixTransportTcp_HandleConnect can change the socket used if server + * is not listening yet, thats why we need to wait to set the fd in + * wolfSSL until after the connect() has completed) */ + if (ctx->ssl == NULL) { + int fd; + + if (posixTransportTcp_GetConnectFd( + (void*)&ctx->tcpCtx, &fd) != WH_ERROR_OK) { + return WH_ERROR_NOTREADY; + } + ctx->connect_fd_p1 = fd + 1; /* follow +1 convetions, 0 is invalid */ + + ctx->ssl = wolfSSL_new(ctx->ssl_ctx); + if (!ctx->ssl) { + posixTransportTcp_CleanupConnect((void*)&ctx->tcpCtx); + return WH_ERROR_ABORTED; + } + + /* Set the current socket file descriptor */ + rc = wolfSSL_set_fd(ctx->ssl, fd); + if (rc != WOLFSSL_SUCCESS) { + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + posixTransportTcp_CleanupConnect((void*)&ctx->tcpCtx); + return WH_ERROR_ABORTED; + } + } + + rc = wolfSSL_connect(ctx->ssl); + err = wolfSSL_get_error(ctx->ssl, rc); + if (rc != WOLFSSL_SUCCESS) { + if (NonBlockingError(err)) { + return WH_ERROR_NOTREADY; + } + else { + if (err == SOCKET_ERROR_E) { + /* There is a case where TCP connect() returned successfully + * but the server has not called accept() and the pending + * send was in the TCP backlog waiting on the server. But + * if the server closes down the listen port then RST gets + * returned. Retry the TCP connect() */ + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + + /* Close the failed socket fd and set state for retry */ + if (ctx->tcpCtx.connect_fd_p1 != 0) { + ctx->tcpCtx.connect_fd_p1 = 0; + } + ctx->connect_fd_p1 = 0; + ctx->tcpCtx.state = PTT_STATE_UNCONNECTED; + return WH_ERROR_NOTREADY; + } + + if (ctx->connectcb != NULL) { + ctx->connectcb(ctx->connectcb_arg, WH_COMM_DISCONNECTED); + } + return WH_ERROR_ABORTED; + } + } + else { + ctx->state = PTTLS_STATE_CONNECTED; + } + } + + rc = wolfSSL_write(ctx->ssl, data, size); + err = wolfSSL_get_error(ctx->ssl, rc); + if (rc > 0) { + return WH_ERROR_OK; + } + else if (NonBlockingError(err)) { + return WH_ERROR_NOTREADY; + } + else { + return WH_ERROR_ABORTED; + } +#else + (void)context; + (void)data; + (void)size; + return WH_ERROR_NOTIMPL; +#endif +} + +int posixTransportTls_RecvResponse(void* context, uint16_t* out_size, + void* data) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsClientContext* ctx = + (posixTransportTlsClientContext*)context; + int rc; + int err; + + if (!ctx || !data || !out_size) { + return WH_ERROR_BADARGS; + } + + /* Create SSL object if not already created */ + if (ctx->ssl == NULL) { + return WH_ERROR_BADARGS; + } + + rc = wolfSSL_read(ctx->ssl, data, PTTLS_PACKET_MAX_SIZE); + err = wolfSSL_get_error(ctx->ssl, rc); + if (rc > 0) { + *out_size = (uint16_t)rc; + return WH_ERROR_OK; + } + else if (NonBlockingError(err)) { + return WH_ERROR_NOTREADY; + } + else { + return WH_ERROR_ABORTED; + } + +#else + (void)context; + (void)data; + (void)out_size; + return WH_ERROR_NOTIMPL; +#endif +} + +int posixTransportTls_CleanupConnect(void* context) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsClientContext* ctx = + (posixTransportTlsClientContext*)context; + + if (!ctx) { + return WH_ERROR_BADARGS; + } + + if (ctx->ssl) { + (void)wolfSSL_shutdown(ctx->ssl); + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + } + + if (ctx->ssl_ctx) { + (void)wolfSSL_CTX_free(ctx->ssl_ctx); + ctx->ssl_ctx = NULL; + } + + ctx->state = PTTLS_STATE_UNCONNECTED; + ctx->connect_fd_p1 = 0; + posixTransportTcp_CleanupConnect((void*)&ctx->tcpCtx); + return WH_ERROR_OK; +#else + (void)context; + return WH_ERROR_OK; +#endif +} + +/** Server-side TLS transport functions */ + +int posixTransportTls_InitListen(void* context, const void* config, + whCommSetConnectedCb connectcb, + void* connectcb_arg) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsServerContext* ctx = + (posixTransportTlsServerContext*)context; + posixTransportTlsConfig* cfg = (posixTransportTlsConfig*)config; + int rc; + + if (!ctx || !cfg) { + return WH_ERROR_BADARGS; + } + + memset(ctx, 0, sizeof(posixTransportTlsServerContext)); + + /* Initialize TCP server context */ + rc = posixTransportTcp_InitListen(&ctx->tcpCtx, cfg, connectcb, + connectcb_arg); + if (rc != WH_ERROR_OK) { + return rc; + } + + ctx->connectcb = connectcb; + ctx->connectcb_arg = connectcb_arg; + ctx->server_addr = ctx->tcpCtx.server_addr; + ctx->listen_fd_p1 = ctx->tcpCtx.listen_fd_p1; + + /* Create SSL context using static memory if heap_hint is provided */ +#ifdef WOLFSSL_STATIC_MEMORY + if (cfg->heap_hint != NULL) { + ctx->ssl_ctx = wolfSSL_CTX_new_ex( + wolfSSLv23_server_method_ex(cfg->heap_hint), cfg->heap_hint); + } + else { + ctx->ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()); + } +#else + ctx->ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()); +#endif + if (!ctx->ssl_ctx) { + return WH_ERROR_ABORTED; + } + + /* don't use wolfHSM for TLS crypto when communicating with wolfHSM */ + wolfSSL_CTX_SetDevId(ctx->ssl_ctx, INVALID_DEVID); + + /* Load certificates from config structure */ + rc = LoadTlsCertificates(ctx->ssl_ctx, cfg); + if (rc != WH_ERROR_OK) { + wolfSSL_CTX_free(ctx->ssl_ctx); + ctx->ssl_ctx = NULL; + return rc; + } + +#ifndef NO_PSK + /* Setup PSK callbacks if provided */ + if (cfg->psk_server_cb != NULL) { + wolfSSL_CTX_set_psk_server_callback(ctx->ssl_ctx, cfg->psk_server_cb); + } +#ifdef WOLFSSL_TLS13 + if (cfg->psk_server_tls13_cb != NULL) { + wolfSSL_CTX_set_psk_server_tls13_callback(ctx->ssl_ctx, + cfg->psk_server_tls13_cb); + } +#endif /* WOLFSSL_TLS13 */ + /* Set PSK identity hint if provided */ + if (cfg->psk_identity_hint != NULL) { + wolfSSL_CTX_use_psk_identity_hint(ctx->ssl_ctx, cfg->psk_identity_hint); + } +#endif /* NO_PSK */ + + if (ctx->connectcb != NULL) { + ctx->connectcb(ctx->connectcb_arg, WH_COMM_CONNECTED); + } + + return WH_ERROR_OK; +#else + (void)context; + (void)config; + (void)connectcb; + (void)connectcb_arg; + return WH_ERROR_NOTIMPL; +#endif +} + +int posixTransportTls_RecvRequest(void* context, uint16_t* out_size, void* data) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsServerContext* ctx = + (posixTransportTlsServerContext*)context; + int rc; + int err; + + if (!ctx || !data || !out_size) { + return WH_ERROR_BADARGS; + } + + *out_size = 0; + /* If no client connected, try to accept one using TCP context */ + if (ctx->accept_fd_p1 == 0) { + struct sockaddr_in client_addr; + socklen_t client_len = sizeof(client_addr); + + rc = accept(ctx->listen_fd_p1 - 1, (struct sockaddr*)&client_addr, + &client_len); + if (rc < 0) { + switch (errno) { + case EAGAIN: + case EINPROGRESS: + case EINTR: + /* Not connected yet or no client */ + return WH_ERROR_NOTREADY; + + default: + return WH_ERROR_ABORTED; + } + } + ctx->accept_fd_p1 = rc + 1; + ctx->client_addr = client_addr; + + /* Make accepted socket non-blocking */ + if (fcntl(ctx->accept_fd_p1 - 1, F_SETFL, O_NONBLOCK) != 0) { + return WH_ERROR_ABORTED; + } + + /* Create SSL object for this connection */ + ctx->ssl = wolfSSL_new(ctx->ssl_ctx); + if (!ctx->ssl) { + return WH_ERROR_ABORTED; + } + + /* Set the socket file descriptor */ + rc = wolfSSL_set_fd(ctx->ssl, ctx->accept_fd_p1 - 1); + if (rc != WOLFSSL_SUCCESS) { + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + return WH_ERROR_ABORTED; + } + + /* Perform TLS handshake */ + rc = wolfSSL_accept(ctx->ssl); + if (rc != WOLFSSL_SUCCESS) { + int err = wolfSSL_get_error(ctx->ssl, rc); + if (err == WOLFSSL_ERROR_WANT_READ || + err == WOLFSSL_ERROR_WANT_WRITE) { + return WH_ERROR_NOTREADY; + } + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + return WH_ERROR_ABORTED; + } + + /* Notify connection established */ + if (ctx->connectcb) { + ctx->connectcb(ctx->connectcb_arg, WH_COMM_CONNECTED); + } + } + + /* Read data from SSL connection (also handles continuing on with + * handshake if not complete yet) */ + rc = wolfSSL_read(ctx->ssl, data, PTTLS_PACKET_MAX_SIZE); + err = wolfSSL_get_error(ctx->ssl, rc); + if (rc > 0) { + *out_size = (uint16_t)rc; + return WH_ERROR_OK; + } + else if (NonBlockingError(err)) { + return WH_ERROR_NOTREADY; + } + else { + /* Connection closed */ + return WH_ERROR_ABORTED; + } +#else + (void)context; + (void)data; + (void)out_size; + return WH_ERROR_NOTIMPL; +#endif +} + +int posixTransportTls_SendResponse(void* context, uint16_t size, + const void* data) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsServerContext* ctx = + (posixTransportTlsServerContext*)context; + int rc; + + if (!ctx || !data || size == 0) { + return WH_ERROR_BADARGS; + } + + if (ctx->ssl == NULL) { + return WH_ERROR_NOTREADY; + } + + /* Send data over SSL connection */ + rc = wolfSSL_write(ctx->ssl, data, size); + if (rc > 0) { + return WH_ERROR_OK; + } + else { + int err = wolfSSL_get_error(ctx->ssl, rc); + if ((NonBlockingError(err))) { + return WH_ERROR_NOTREADY; + } + return WH_ERROR_ABORTED; + } +#else + (void)context; + (void)data; + (void)size; + return WH_ERROR_NOTIMPL; +#endif +} + +int posixTransportTls_CleanupListen(void* context) +{ +#ifndef WOLFHSM_CFG_NO_CRYPTO + posixTransportTlsServerContext* ctx = + (posixTransportTlsServerContext*)context; + + if (!ctx) { + return WH_ERROR_BADARGS; + } + + if (ctx->ssl) { + /* Give a quick shutdown signal to the client but do not wait for a + * response from the client before tearing down the transport. */ + (void)wolfSSL_shutdown(ctx->ssl); + wolfSSL_free(ctx->ssl); + ctx->ssl = NULL; + } + + if (ctx->ssl_ctx) { + (void)wolfSSL_CTX_free(ctx->ssl_ctx); + ctx->ssl_ctx = NULL; + } + + /* Clean up TCP context */ + posixTransportTcp_CleanupListen(&ctx->tcpCtx); + + /* Reset TLS context fields */ + ctx->accept_fd_p1 = 0; + ctx->listen_fd_p1 = 0; + + return WH_ERROR_OK; +#else + (void)context; + return WH_ERROR_OK; +#endif +} + +/* Return the file descriptor of the listen socket to support poll/select */ +int posixTransportTls_GetListenFd(posixTransportTlsServerContext* context, + int* out_fd) +{ + int ret = WH_ERROR_OK; + + if (context == NULL) { + return WH_ERROR_BADARGS; + } + + if (context->listen_fd_p1 != 0) { + if (out_fd != NULL) { + *out_fd = context->listen_fd_p1 - 1; + } + } + else { + ret = WH_ERROR_NOTREADY; + } + return ret; +} + +/* Return the file descriptor of the accepted socket to support poll/select */ +int posixTransportTls_GetAcceptFd(posixTransportTlsServerContext* context, + int* out_fd) +{ + int ret = WH_ERROR_OK; + + if (context == NULL) { + return WH_ERROR_BADARGS; + } + + if (context->accept_fd_p1 != 0) { + if (out_fd != NULL) { + *out_fd = context->accept_fd_p1 - 1; + } + } + else { + ret = WH_ERROR_NOTREADY; + } + return ret; +} +#endif /* WOLFHSM_CFG_TLS */ diff --git a/port/posix/posix_transport_tls.h b/port/posix/posix_transport_tls.h new file mode 100644 index 00000000..5a6e2752 --- /dev/null +++ b/port/posix/posix_transport_tls.h @@ -0,0 +1,184 @@ +/* + * 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 . + */ +/* + * port/posix/posix_transport_tls.h + * + * wolfHSM Transport binding using TLS sockets with wolfSSL + * + * This transport extends the TCP transport with TLS encryption using + * wolfSSL's embedded certificate buffers for authentication. + * + */ + +#ifndef PORT_POSIX_POSIX_TRANSPORT_TLS_H_ +#define PORT_POSIX_POSIX_TRANSPORT_TLS_H_ + +#include +#include +#include + +#include "wolfhsm/wh_comm.h" + +/* Adds TLS on top of the existing TCP transport */ +#include "port/posix/posix_transport_tcp.h" + +#ifdef WOLFHSM_CFG_TLS +#ifndef WOLFSSL_USER_SETTINGS +#include "wolfssl/options.h" +#endif +#include "wolfssl/ssl.h" +#include "wolfssl/wolfcrypt/memory.h" + +#define PTTLS_PACKET_MAX_SIZE WH_COMM_MTU +#define PTTLS_BUFFER_SIZE (sizeof(uint32_t) + PTTLS_PACKET_MAX_SIZE) + +/** TLS configuration structure */ +typedef struct { + char* server_ip_string; + int server_port; + bool disable_peer_verification; /* Whether to verify certificates, + defaults to verifying peer certificates */ + /* Certificate configuration - can be provided as buffers or filenames */ + const unsigned char* ca_cert; /* CA certificate buffer (DER format) */ + int ca_cert_len; /* Length of CA certificate buffer */ + const unsigned char* cert; /* Certificate buffer (DER format) */ + int cert_len; /* Length of certificate buffer */ + const unsigned char* key; /* Private key buffer (DER format) */ + int key_len; /* Length of private key buffer */ +#ifndef NO_PSK + /* PSK configuration */ + /* Client PSK callback: unsigned int (*)(WOLFSSL* ssl, const char* hint, + * char* identity, unsigned int + * id_max_len, unsigned char* key, unsigned int key_max_len) */ + unsigned int (*psk_client_cb)(WOLFSSL* ssl, const char* hint, + char* identity, unsigned int id_max_len, + unsigned char* key, unsigned int key_max_len); + /* Server PSK callback for TLS 1.2: unsigned int (*)(WOLFSSL* ssl, + * const char* identity, + * unsigned char* key, + * unsigned int + * key_max_len) */ + unsigned int (*psk_server_cb)(WOLFSSL* ssl, const char* identity, + unsigned char* key, unsigned int key_max_len); +#ifdef WOLFSSL_TLS13 + /* Server PSK callback for TLS 1.3: unsigned int (*)(WOLFSSL* ssl, + * const char* identity, + * unsigned char* key, + * unsigned int + * key_max_len, const char** ciphersuite) */ + unsigned int (*psk_server_tls13_cb)(WOLFSSL* ssl, const char* identity, + unsigned char* key, + unsigned int key_max_len, + const char** ciphersuite); +#endif /* WOLFSSL_TLS13 */ + const char* psk_identity_hint; /* Server PSK identity hint */ +#endif /* NO_PSK */ + void* heap_hint; /* A pointer to a WOLFSSL_HEAP_HINT structure for static + * memory allocation */ +} posixTransportTlsConfig; + +/** Client context and functions */ +typedef enum { + PTTLS_STATE_UNCONNECTED = 0, /* Not initialized */ + PTTLS_STATE_CONNECT_WAIT, /* Async connect called */ + PTTLS_STATE_TLS_HANDSHAKE, /* TLS handshake in progress */ + PTTLS_STATE_CONNECTED, /* Connected and able to handle traffic */ + PTTLS_STATE_DONE /* Was connected, now not */ +} pttlsClientState; + +typedef struct { + whCommSetConnectedCb connectcb; + void* connectcb_arg; + struct sockaddr_in server_addr; + pttlsClientState state; + int connect_fd_p1; /* fd plus 1 so 0 is invalid */ +#ifndef WOLFHSM_CFG_NO_CRYPTO + WOLFSSL_CTX* ssl_ctx; + WOLFSSL* ssl; +#endif + posixTransportTcpClientContext tcpCtx; +} posixTransportTlsClientContext; + +int posixTransportTls_InitConnect(void* context, const void* config, + whCommSetConnectedCb connectcb, + void* connectcb_arg); +int posixTransportTls_SendRequest(void* context, uint16_t size, + const void* data); +int posixTransportTls_RecvResponse(void* context, uint16_t* out_size, + void* data); +int posixTransportTls_CleanupConnect(void* context); + +#define PTTLS_CLIENT_CB \ + { \ + .Init = posixTransportTls_InitConnect, \ + .Send = posixTransportTls_SendRequest, \ + .Recv = posixTransportTls_RecvResponse, \ + .Cleanup = posixTransportTls_CleanupConnect, \ + } + +/* Return the file descriptor of the connected socket to support poll/select */ +int posixTransportTls_GetConnectFd(posixTransportTlsClientContext* context, + int* out_fd); + +/** Server context and functions */ + +typedef struct { + whCommSetConnectedCb connectcb; + void* connectcb_arg; + struct sockaddr_in server_addr; + struct sockaddr_in client_addr; + int listen_fd_p1; /* fd plus 1 so 0 is invalid */ + int accept_fd_p1; /* fd plus 1 so 0 is invalid */ + int request_recv; + uint16_t buffer_offset; + uint8_t buffer[PTTLS_BUFFER_SIZE]; +#ifndef WOLFHSM_CFG_NO_CRYPTO + WOLFSSL_CTX* ssl_ctx; + WOLFSSL* ssl; +#endif + posixTransportTcpServerContext tcpCtx; +} posixTransportTlsServerContext; + +int posixTransportTls_InitListen(void* context, const void* config, + whCommSetConnectedCb connectcb, + void* connectcb_arg); +int posixTransportTls_RecvRequest(void* context, uint16_t* out_size, + void* data); +int posixTransportTls_SendResponse(void* context, uint16_t size, + const void* data); +int posixTransportTls_CleanupListen(void* context); + +#define PTTLS_SERVER_CB \ + { \ + .Init = posixTransportTls_InitListen, \ + .Recv = posixTransportTls_RecvRequest, \ + .Send = posixTransportTls_SendResponse, \ + .Cleanup = posixTransportTls_CleanupListen, \ + } + +/* Return the file descriptor of the listen socket to support poll/select */ +int posixTransportTls_GetListenFd(posixTransportTlsServerContext* context, + int* out_fd); + +/* Return the file descriptor of the accepted socket to support poll/select */ +int posixTransportTls_GetAcceptFd(posixTransportTlsServerContext* context, + int* out_fd); + +#endif /* WOLFHSM_CFG_TLS */ +#endif /* !PORT_POSIX_POSIX_TRANSPORT_TLS_H_ */ diff --git a/test/Makefile b/test/Makefile index d35ac286..f3dd6971 100644 --- a/test/Makefile +++ b/test/Makefile @@ -119,16 +119,21 @@ ifeq ($(SHE),1) DEF += -DWOLFHSM_CFG_SHE_EXTENSION endif +# Support a TLS-capable build +ifeq ($(TLS),1) + DEF += -DWOLFHSM_CFG_TLS +endif + ## Project defines # Option to build wolfcrypt tests ifeq ($(TESTWOLFCRYPT),1) DEF += -DWOLFHSM_CFG_TEST_WOLFCRYPTTEST endif -ifeq ($(CLIENT_ONLY_TCP),1) -# Build a client-only test driver to connect to a remote server over TCP +ifeq ($(CLIENT_ONLY),1) +# Build a client-only test driver to connect to a remote server DEF += -DWOLFHSM_CFG_ENABLE_CLIENT - DEF += -DWOLFHSM_CFG_TEST_CLIENT_ONLY_TCP + DEF += -DWOLFHSM_CFG_TEST_CLIENT_ONLY else # Build both and client server DEF += -DWOLFHSM_CFG_ENABLE_CLIENT diff --git a/test/config/user_settings.h b/test/config/user_settings.h index b2eab3e0..e8638934 100644 --- a/test/config/user_settings.h +++ b/test/config/user_settings.h @@ -45,13 +45,16 @@ #define WOLFSSL_IGNORE_FILE_WARN -/* For cert manager */ -#define NO_TLS -/* Eliminates need for IO layer since we only use CM */ -#define WOLFSSL_USER_IO /* For ACert support (also requires WOLFSSL_ASN_TEMPLATE) */ #define WOLFSSL_ACERT +/* The following settings reduce memory footprint when not using the TLS + * transport. If TLS is needed, these settings should be removed. */ +#ifndef WOLFHSM_CFG_TLS +#define NO_TLS +#define WOLFSSL_USER_IO +#endif /* WOLFHSM_CFG_TLS */ + /** Math library selection for test */ #define USE_FAST_MATH @@ -78,7 +81,6 @@ #define NO_ERROR_STRINGS #define NO_ERROR_QUEUE #define NO_OLD_TLS -#define WOLFSSL_NO_TLS12 #define NO_DO178 /* Prevents certain functions (SHA, hash.c) on server from falling back to diff --git a/test/wh_test.c b/test/wh_test.c index eb80cf03..29ba86b8 100644 --- a/test/wh_test.c +++ b/test/wh_test.c @@ -28,6 +28,7 @@ #include "wolfhsm/wh_error.h" #include "wh_test_common.h" +#include "wh_test.h" /* Individual unit test drivers */ #include "wh_test_comm.h" @@ -54,6 +55,9 @@ #if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) #include "port/posix/posix_transport_tcp.h" +#if defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) && defined(WOLFHSM_CFG_TLS) +#include "port/posix/posix_transport_tls.h" +#endif /* WOLFHSM_CFG_TEST_CLIENT_ONLY && WOLFHSM_CFG_TLS */ #endif #include "wolfhsm/wh_client.h" @@ -146,7 +150,8 @@ int whTest_ClientConfig(whClientConfig* clientCfg) return WH_ERROR_OK; } -#if defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) && defined(WOLFHSM_CFG_TEST_POSIX) +#if defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) && defined(WOLFHSM_CFG_TEST_POSIX) +#if !defined(WOLFHSM_CFG_TLS) /* * Run all the client-only tests on a default client configuration matching the * example server TCP configuration. @@ -173,7 +178,75 @@ int whTest_ClientTcp(void) return whTest_ClientConfig(c_conf); } -#endif /* WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP && WOLFHSM_CFG_TEST_POSIX */ +#endif /* WOLFHSM_CFG_TEST_POSIX && !WOLFHSM_CFG_TLS */ + +#if defined(WOLFHSM_CFG_TLS) +/* client configuration setup example for TLS transport */ + +#define WH_POSIX_SERVER_TCP_PORT 23456 +#define WH_POSIX_SERVER_TCP_IPSTRING "127.0.0.1" +#define WH_POSIX_CLIENT_ID 12 + +#undef USE_CERT_BUFFERS_2048 +#define USE_CERT_BUFFERS_2048 +#include "wolfssl/certs_test.h" + +posixTransportTlsClientContext tccTls; +posixTransportTlsConfig tlsConfig; +whCommClientConfig c_comm; +whTransportClientCb tlsCb = PTTLS_CLIENT_CB; + +static int whPosixClient_ExampleTlsConfig(void* conf) +{ + whClientConfig* c_conf = (whClientConfig*)conf; + + memset(&tccTls, 0, sizeof(posixTransportTlsClientContext)); + + /* Initialize TLS context fields that need specific values */ + tccTls.state = 0; + tccTls.connect_fd_p1 = 0; /* Invalid fd */ + + tlsConfig.server_ip_string = WH_POSIX_SERVER_TCP_IPSTRING; + tlsConfig.server_port = WH_POSIX_SERVER_TCP_PORT; + tlsConfig.disable_peer_verification = false; + + /* Set certificate buffers in config structure */ + tlsConfig.ca_cert = ca_cert_der_2048; + tlsConfig.ca_cert_len = sizeof_ca_cert_der_2048; + tlsConfig.cert = client_cert_der_2048; + tlsConfig.cert_len = sizeof_client_cert_der_2048; + tlsConfig.key = client_key_der_2048; + tlsConfig.key_len = sizeof_client_key_der_2048; + + c_comm.transport_cb = &tlsCb; + c_comm.transport_context = (void*)&tccTls; + c_comm.transport_config = (void*)&tlsConfig; + c_comm.client_id = WH_POSIX_CLIENT_ID; + c_conf->comm = &c_comm; + + return WH_ERROR_OK; +} + + +/* + * Run all the client-only tests on a default client configuration matching the + * example server TLS configuration. + */ +int whTest_ClientTls(void) +{ + int ret; + whClientConfig c_conf[1]; + + if (whPosixClient_ExampleTlsConfig(c_conf) != WH_ERROR_OK) { + ret = -1; + } + else { + ret = whTest_ClientConfig(c_conf); + } + return ret; +} +#endif /* WOLFHSM_CFG_TLS */ +#endif /* WOLFHSM_CFG_TEST_CLIENT_ONLY && WOLFHSM_CFG_TEST_POSIX */ #endif /* WOLFHSM_CFG_ENABLE_CLIENT */ #if !defined(WOLFHSM_CFG_TEST_UNIT_NO_MAIN) @@ -182,10 +255,16 @@ int main(void) { int ret = 0; -#if defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) && \ +#if defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) && \ defined(WOLFHSM_CFG_ENABLE_CLIENT) && defined(WOLFHSM_CFG_TEST_POSIX) - /* Test driver should run TCP client tests against the example server */ + /* Test driver should run client tests against the example server */ +#if defined(WOLFHSM_CFG_TLS) + /* Run TLS client tests */ + ret = whTest_ClientTls(); +#else + /* Run TCP client tests (default) */ ret = whTest_ClientTcp(); +#endif #elif defined(WOLFHSM_CFG_ENABLE_CLIENT) && defined(WOLFHSM_CFG_ENABLE_SERVER) /* Default case: Test driver should run all the unit tests locally */ ret = whTest_Unit(); diff --git a/test/wh_test.h b/test/wh_test.h index 5e71b3ba..c773f4f2 100644 --- a/test/wh_test.h +++ b/test/wh_test.h @@ -21,6 +21,15 @@ #include "wolfhsm/wh_client.h" +/* + * WOLFHSM_CFG_TEST_POSIX : Run tests using POSIX transport + * + * WOLFHSM_CFG_TEST_CLIENT_ONLY : Run client-only tests connecting to a running + * server. The default is using a TCP transport + * connection. When another specific transports + * are enabled then they will be used instead i.e + * WOLFHSM_CFG_TLS will use TLS transport. + */ int whTest_Unit(void); int whTest_ClientConfig(whClientConfig* clientCfg); diff --git a/test/wh_test_clientserver.c b/test/wh_test_clientserver.c index 989dd537..82003597 100644 --- a/test/wh_test_clientserver.c +++ b/test/wh_test_clientserver.c @@ -1565,7 +1565,7 @@ int whTest_ServerCfgLoop(whServerConfig* serverCfg) #endif /* WOLFHSM_CFG_ENABLE_SERVER */ #if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ - !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) + !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) static void* _whClientTask(void *cf) { WH_TEST_ASSERT(0 == whTest_ClientServerClientConfig(cf)); diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 7bcb11a4..b925cfa6 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -3526,8 +3526,7 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) } } -#if defined(WOLFHSM_CFG_CANCEL_API) && \ - !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) +#if defined(WOLFHSM_CFG_CANCEL_API) && !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) /* test CMAC cancellation for supported devIds */ if (ret == 0 #ifdef WOLFHSM_CFG_DMA @@ -5376,7 +5375,7 @@ int whTest_CryptoServerConfig(whServerConfig* config) #endif /* WOLFHSM_CFG_ENABLE_SERVER */ #if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ - !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) + !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) static void* _whClientTask(void *cf) { int rc = whTest_CryptoClientConfig(cf); diff --git a/test/wh_test_she.c b/test/wh_test_she.c index 24020d9c..3e710e93 100644 --- a/test/wh_test_she.c +++ b/test/wh_test_she.c @@ -461,7 +461,7 @@ int whTest_SheServerConfig(whServerConfig* config) #endif /* WOLFHSM_CFG_ENABLE_SERVER */ #if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ - !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) + !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) static void* _whClientTask(void* cf) { WH_TEST_ASSERT(0 == whTest_SheClientConfig(cf)); diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h index f02dda5f..b33ecc9e 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -385,7 +385,7 @@ #error "wolfHSM requires wolfCrypt built without NO_RNG" #endif -#if defined WOLFHSM_CFG_SHE_EXTENSION +#if defined(WOLFHSM_CFG_SHE_EXTENSION) #if defined(NO_AES) || \ !defined(WOLFSSL_CMAC) || \ !defined(WOLFSSL_AES_DIRECT) || \