Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/build-and-run-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,23 @@ jobs:
done
done
done

- name: Build and run the callback-only SLH-DSA client
if: ${{ matrix.transport == 'tcp' }}
run: |
WS="$(pwd)"
SERVER_DIR="$WS/examples/posix/wh_posix_server"
CLIENT_DIR="$WS/examples/posix/wh_posix_client"
make -C "$SERVER_DIR" clean
make -C "$CLIENT_DIR" clean
DEMO_KEK=1 make -C "$SERVER_DIR" -j WOLFSSL_DIR=../../../wolfssl
SLHDSA_CB_ONLY=1 make -C "$CLIENT_DIR" -j WOLFSSL_DIR=../../../wolfssl
rm -f "$SERVER_DIR"/*.bin
cd "$SERVER_DIR"
./Build/wh_posix_server.elf --type tcp &
SERVER_PID=$!
sleep 1
cd "$CLIENT_DIR"
./Build/wh_posix_client.elf --type tcp --test
kill $SERVER_PID 2>/dev/null || true
wait $SERVER_PID 2>/dev/null || true
5 changes: 5 additions & 0 deletions .github/workflows/build-and-test-refactor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ jobs:
if: matrix.group == 'pq-dma'
run: cd test-refactor/posix && make clean && make -j DMA=1 ASAN=1 MLDSA_VERIFY_ONLY=1 WOLFSSL_DIR=../../wolfssl && make run

# Verify-only drops the signing APIs, so this catches code that assumes them.
- name: Build and test refactor DMA ASAN SLHDSA verify-only
if: matrix.group == 'pq-dma'
run: cd test-refactor/posix && make clean && make -j DMA=1 ASAN=1 SLHDSA_VERIFY_ONLY=1 WOLFSSL_DIR=../../wolfssl && make run

# Build and test ASAN build, with wolfCrypt tests enabled.
- name: Build and test refactor ASAN TESTWOLFCRYPT
if: matrix.group == 'wolfcrypt'
Expand Down
7 changes: 7 additions & 0 deletions examples/demo/client/wh_demo_client_all.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,12 @@ int wh_DemoClient_All(whClientContext* clientContext)

#endif /* WOLFSSL_CMAC */

#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY)
rc = wh_DemoClient_CryptoSlhDsa(clientContext);
if (rc != 0) {
return rc;
}
#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */

return rc;
}
92 changes: 92 additions & 0 deletions examples/demo/client/wh_demo_client_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
#include "wolfssl/wolfcrypt/kdf.h"
#endif

#ifdef WOLFSSL_HAVE_SLHDSA
#include "wolfssl/wolfcrypt/wc_slhdsa.h"
#endif

#include "wh_demo_client_crypto.h"

#if !defined(NO_RSA)
Expand Down Expand Up @@ -1692,4 +1696,92 @@ int wh_DemoClient_CryptoCmacKdfCacheInputs(whClientContext* clientContext)

#endif /* HAVE_CMAC_KDF && WOLFSSL_CMAC */

#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY)

/* Generate an SLH-DSA key that stays on the server and reference it by ID. */
int wh_DemoClient_CryptoSlhDsa(whClientContext* clientContext)
{
int ret;
int devId = WH_CLIENT_DEVID(clientContext);
whKeyId keyId = WH_KEYID_ERASED;
SlhDsaKey pub[1];
SlhDsaKey handle[1];
uint8_t label[] = "slhdsa-demo";
byte message[] = "wolfHSM SLH-DSA demo message";
byte signature[WC_SLHDSA_SHAKE128S_SIG_LEN];
word32 sigLen = sizeof(signature);
byte addRnd[WC_SLHDSA_MAX_SEED];

memset(addRnd, 0x42, sizeof(addRnd));

ret = wc_SlhDsaKey_Init(pub, SLHDSA_SHAKE128S, NULL, devId);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to wc_SlhDsaKey_Init %d\n", ret);
return ret;
}

ret = wc_SlhDsaKey_Init(handle, SLHDSA_SHAKE128S, NULL, devId);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to wc_SlhDsaKey_Init %d\n", ret);
wc_SlhDsaKey_Free(pub);
return ret;
}

/* The private key is generated on and never leaves the HSM. Only the
* public key comes back. */
ret = wh_Client_SlhDsaMakeCacheKeyAndExportPublic(
clientContext, SLHDSA_SHAKE128S, &keyId,
WH_NVM_FLAGS_USAGE_SIGN | WH_NVM_FLAGS_USAGE_VERIFY, sizeof(label),
label, pub);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to generate SLH-DSA key %d\n", ret);
goto exit;
}

/* handle contains no key material, just the server key id */
ret = wh_Client_SlhDsaSetKeyId(handle, keyId);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to wh_Client_SlhDsaSetKeyId %d\n", ret);
goto exit;
}

/* handle has no PK.seed, so supply the randomizer */
ret = wc_SlhDsaKey_SignWithRandom(handle, NULL, 0, message, sizeof(message),
signature, &sigLen, addRnd);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to wc_SlhDsaKey_SignWithRandom %d\n", ret);
goto exit;
}

ret = wc_SlhDsaKey_Verify(pub, NULL, 0, message, sizeof(message), signature,
sigLen);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to wc_SlhDsaKey_Verify %d\n", ret);
goto exit;
}

/* A tampered signature must not verify */
signature[0] ^= 0xFF;
if (wc_SlhDsaKey_Verify(pub, NULL, 0, message, sizeof(message), signature,
sigLen) == 0) {
WOLFHSM_CFG_PRINTF("SLH-DSA verified a tampered signature\n");
ret = -1;
goto exit;
}

WOLFHSM_CFG_PRINTF("SLH-DSA sign/verify with a server-resident key: "
"SUCCESS\n");
ret = 0;

exit:
if (!WH_KEYID_ISERASED(keyId)) {
(void)wh_Client_KeyEvict(clientContext, keyId);
}
wc_SlhDsaKey_Free(handle);
wc_SlhDsaKey_Free(pub);
return ret;
}

#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */

#endif /* WOLFHSM_CFG_NO_CRYPTO */
2 changes: 2 additions & 0 deletions examples/demo/client/wh_demo_client_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ int wh_DemoClient_CryptoCmacKdfExport(whClientContext* clientContext);
int wh_DemoClient_CryptoCmacKdfCache(whClientContext* clientContext);
int wh_DemoClient_CryptoCmacKdfCacheInputs(whClientContext* clientContext);

int wh_DemoClient_CryptoSlhDsa(whClientContext* clientContext);

#endif /* !DEMO_CLIENT_CRYPTO_H_ */
4 changes: 4 additions & 0 deletions examples/posix/wh_posix_client/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ ifeq ($(AUTH),1)
DEF += -DWOLFHSM_CFG_ENABLE_AUTHENTICATION
endif

ifeq ($(SLHDSA_CB_ONLY),1)
DEF += -DWH_CFG_SLHDSA_CB_ONLY
endif

else
DEF += -DWOLFHSM_CFG_NO_CRYPTO
endif
Expand Down
14 changes: 14 additions & 0 deletions examples/posix/wh_posix_client/user_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@
#define WOLFSSL_CMAC
#define HAVE_HKDF

/* SLH-DSA: only 128s (7856-byte signature) fits in the default
* WOLFHSM_CFG_COMM_DATA_LEN */
#define WOLFSSL_HAVE_SLHDSA
#define WOLFSSL_SHA3
#define WOLFSSL_SHAKE128
#define WOLFSSL_SHAKE256
#define WOLFSSL_SLHDSA_PARAM_NO_128F
#define WOLFSSL_SLHDSA_PARAM_NO_192
#define WOLFSSL_SLHDSA_PARAM_NO_256

#ifdef WH_CFG_SLHDSA_CB_ONLY
#define WOLF_CRYPTO_CB_ONLY_SLHDSA
#endif

/* wolfCrypt benchmark settings */
#define NO_MAIN_DRIVER
#define BENCH_EMBEDDED
Expand Down
9 changes: 8 additions & 1 deletion examples/posix/wh_posix_server/user_settings.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024 wolfSSL Inc.
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfHSM.
*
Expand Down Expand Up @@ -150,6 +150,13 @@ extern "C" {
#define WOLFSSL_MLDSA_NO_MAKE_KEY
#endif

/* SLH-DSA: only 128s (7856-byte signature) fits in the default
* WOLFHSM_CFG_COMM_DATA_LEN */
#define WOLFSSL_HAVE_SLHDSA
#define WOLFSSL_SLHDSA_PARAM_NO_128F
#define WOLFSSL_SLHDSA_PARAM_NO_192
#define WOLFSSL_SLHDSA_PARAM_NO_256

/* ML-KEM Options */
#define WOLFSSL_HAVE_MLKEM

Expand Down
Loading
Loading