/* test_slhdsa.c * * Copyright (C) 2006-2026 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL 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. * * wolfSSL 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #include #ifdef NO_INLINE #include #else #define WOLFSSL_MISC_INCLUDED #include #endif #ifdef WOLFSSL_HAVE_SLHDSA #include #endif #include #include #include #include #include #ifdef WOLFSSL_HAVE_SLHDSA /* Pick the first available parameter set so tests that just need any one valid * SLH-DSA configuration compile and run in SHAKE-only, SHA-2-only, or mixed * builds. Preference order: SHAKE 128s/f, 192s/f, 256s/f, then the SHA-2 * variants in the same order. */ #if defined(WOLFSSL_SLHDSA_PARAM_128S) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE128S #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE128S_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE128S_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE128S_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE128S_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_128F) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE128F #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE128F_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE128F_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE128F_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE128F_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_192S) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE192S #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE192S_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE192S_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE192S_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE192S_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_192F) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE192F #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE192F_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE192F_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE192F_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE192F_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_256S) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE256S #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE256S_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE256S_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE256S_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE256S_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_256F) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE256F #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE256F_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE256F_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE256F_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE256F_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_128S #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_128S_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_128S_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_128S_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_128S_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_128F) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_128F #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_128F_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_128F_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_128F_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_128F_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_192S) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_192S #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_192S_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_192S_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_192S_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_192S_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_192F) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_192F #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_192F_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_192F_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_192F_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_192F_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_256S) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_256S #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_256S_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_256S_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_256S_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_256S_SEED_LEN #elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_256F) #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_256F #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_256F_SIG_LEN #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_256F_PRIV_LEN #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_256F_PUB_LEN #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_256F_SEED_LEN #endif #endif /* WOLFSSL_HAVE_SLHDSA */ /* * Test basic init/free and NULL parameter handling for SLH-DSA key operations. */ int test_wc_slhdsa(void) { EXPECT_DECLS; #ifdef WOLFSSL_HAVE_SLHDSA /* `key` is only used by the per-variant Init/Free blocks below, so * gate its declaration on the same precondition (at least one * parameter set compiled in) to avoid -Wunused-variable when SLH-DSA * is enabled but no params are. */ #ifdef TEST_SLHDSA_DEFAULT_PARAM SlhDsaKey key; /* Test NULL parameter handling for init. Use whichever variant the * build actually has so a SHA-2-only build doesn't pass a SHAKE param * id and conflate BAD_FUNC_ARG (NULL key) with NOT_COMPILED_IN * (variant disabled). */ ExpectIntEQ(wc_SlhDsaKey_Init(NULL, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif /* Test wc_SlhDsaKey_Free with NULL - should not crash. */ wc_SlhDsaKey_Free(NULL); /* Test valid init for each supported parameter set. Each block zeros * `key` first so a future regression where wc_SlhDsaKey_Free leaves * a residual field set cannot be papered over by the next Init's * partial reinitialisation. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_SHA2 #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } /* * Test size functions for SLH-DSA. */ int test_wc_slhdsa_sizes(void) { EXPECT_DECLS; #ifdef WOLFSSL_HAVE_SLHDSA /* See test_wc_slhdsa() for the rationale on this guard. */ #ifdef TEST_SLHDSA_DEFAULT_PARAM SlhDsaKey key; #endif /* Test NULL parameter handling for size functions. */ #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SigSize(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test sizes for each parameter set. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHAKE128S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHAKE128S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHAKE128S_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHAKE128S), WC_SLHDSA_SHAKE128S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHAKE128S), WC_SLHDSA_SHAKE128S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE128S), WC_SLHDSA_SHAKE128S_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHAKE128F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHAKE128F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHAKE128F_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHAKE128F), WC_SLHDSA_SHAKE128F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHAKE128F), WC_SLHDSA_SHAKE128F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE128F), WC_SLHDSA_SHAKE128F_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHAKE192S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHAKE192S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHAKE192S_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHAKE192S), WC_SLHDSA_SHAKE192S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHAKE192S), WC_SLHDSA_SHAKE192S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE192S), WC_SLHDSA_SHAKE192S_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHAKE192F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHAKE192F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHAKE192F_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHAKE192F), WC_SLHDSA_SHAKE192F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHAKE192F), WC_SLHDSA_SHAKE192F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE192F), WC_SLHDSA_SHAKE192F_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHAKE256S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHAKE256S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHAKE256S_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHAKE256S), WC_SLHDSA_SHAKE256S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHAKE256S), WC_SLHDSA_SHAKE256S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE256S), WC_SLHDSA_SHAKE256S_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHAKE256F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHAKE256F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHAKE256F_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHAKE256F), WC_SLHDSA_SHAKE256F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHAKE256F), WC_SLHDSA_SHAKE256F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE256F), WC_SLHDSA_SHAKE256F_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_SHA2 #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_128S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_128S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_128S_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_128S), WC_SLHDSA_SHA2_128S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_128S), WC_SLHDSA_SHA2_128S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_128S), WC_SLHDSA_SHA2_128S_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_128F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_128F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_128F_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_128F), WC_SLHDSA_SHA2_128F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_128F), WC_SLHDSA_SHA2_128F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_128F), WC_SLHDSA_SHA2_128F_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_192S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_192S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_192S_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_192S), WC_SLHDSA_SHA2_192S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_192S), WC_SLHDSA_SHA2_192S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_192S), WC_SLHDSA_SHA2_192S_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_192F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_192F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_192F_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_192F), WC_SLHDSA_SHA2_192F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_192F), WC_SLHDSA_SHA2_192F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_192F), WC_SLHDSA_SHA2_192F_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_256S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_256S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_256S_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_256S), WC_SLHDSA_SHA2_256S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_256S), WC_SLHDSA_SHA2_256S_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_256S), WC_SLHDSA_SHA2_256S_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), 0); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_256F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_256F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_256F_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_256F), WC_SLHDSA_SHA2_256F_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_256F), WC_SLHDSA_SHA2_256F_PUB_LEN); ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_256F), WC_SLHDSA_SHA2_256F_SIG_LEN); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } /* * Test key generation for SLH-DSA. */ int test_wc_slhdsa_make_key(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) SlhDsaKey key; WC_RNG rng; XMEMSET(&rng, 0, sizeof(WC_RNG)); ExpectIntEQ(wc_InitRng(&rng), 0); /* Test NULL parameter handling. */ ExpectIntEQ(wc_SlhDsaKey_MakeKey(NULL, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #ifdef WOLFSSL_SLHDSA_PARAM_128S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_SHA2 #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); wc_SlhDsaKey_Free(&key); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ /* Test MakeKeyWithRandom. */ #ifdef TEST_SLHDSA_DEFAULT_PARAM { byte sk_seed[TEST_SLHDSA_DEFAULT_SEED_LEN]; byte sk_prf[TEST_SLHDSA_DEFAULT_SEED_LEN]; byte pk_seed[TEST_SLHDSA_DEFAULT_SEED_LEN]; XMEMSET(sk_seed, 0x01, sizeof(sk_seed)); XMEMSET(sk_prf, 0x02, sizeof(sk_prf)); XMEMSET(pk_seed, 0x03, sizeof(pk_seed)); /* Test NULL parameter handling. */ ExpectIntEQ(wc_SlhDsaKey_MakeKeyWithRandom(NULL, sk_seed, sizeof(sk_seed), sk_prf, sizeof(sk_prf), pk_seed, sizeof(pk_seed)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKeyWithRandom(&key, NULL, sizeof(sk_seed), sk_prf, sizeof(sk_prf), pk_seed, sizeof(pk_seed)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_MakeKeyWithRandom(&key, sk_seed, sizeof(sk_seed), NULL, sizeof(sk_prf), pk_seed, sizeof(pk_seed)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_MakeKeyWithRandom(&key, sk_seed, sizeof(sk_seed), sk_prf, sizeof(sk_prf), NULL, sizeof(pk_seed)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test wrong size. */ ExpectIntEQ(wc_SlhDsaKey_MakeKeyWithRandom(&key, sk_seed, 8, sk_prf, sizeof(sk_prf), pk_seed, sizeof(pk_seed)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_MakeKeyWithRandom(&key, sk_seed, sizeof(sk_seed), sk_prf, sizeof(sk_prf), pk_seed, sizeof(pk_seed)), 0); wc_SlhDsaKey_Free(&key); } #endif wc_FreeRng(&rng); #endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ return EXPECT_RESULT(); } /* * Test signing for SLH-DSA. */ int test_wc_slhdsa_sign(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) SlhDsaKey key; WC_RNG rng; byte msg[64]; byte* sig = NULL; word32 sigLen; word32 expSigLen; byte ctx[10]; sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig); XMEMSET(&rng, 0, sizeof(WC_RNG)); XMEMSET(msg, 0xAA, sizeof(msg)); XMEMSET(ctx, 0x01, sizeof(ctx)); ExpectIntEQ(wc_InitRng(&rng), 0); /* Test NULL parameter handling. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(NULL, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); expSigLen = TEST_SLHDSA_DEFAULT_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), NULL, sizeof(msg), sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), NULL, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, NULL, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test buffer too small. */ sigLen = 10; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_LENGTH_E)); /* Test successful signing. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, expSigLen); /* Test signing with NULL context (allowed). */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, NULL, 0, msg, sizeof(msg), sig, &sigLen, &rng), 0); wc_SlhDsaKey_Free(&key); /* Test SignDeterministic. */ ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignDeterministic(NULL, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignDeterministic(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen), 0); ExpectIntEQ(sigLen, expSigLen); wc_SlhDsaKey_Free(&key); /* Test SignWithRandom. */ { byte addRnd[WC_SLHDSA_MAX_SEED]; XMEMSET(addRnd, 0x55, sizeof(addRnd)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignWithRandom(NULL, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, addRnd), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignWithRandom(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignWithRandom(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, addRnd), 0); ExpectIntEQ(sigLen, expSigLen); wc_SlhDsaKey_Free(&key); } wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ return EXPECT_RESULT(); } /* * Test verification for SLH-DSA. */ int test_wc_slhdsa_verify(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) SlhDsaKey key; WC_RNG rng; byte msg[64]; byte* sig = NULL; word32 sigLen; byte ctx[10]; sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig); XMEMSET(&rng, 0, sizeof(WC_RNG)); XMEMSET(msg, 0xAA, sizeof(msg)); XMEMSET(ctx, 0x01, sizeof(ctx)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Generate a signature. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); /* Test NULL parameter handling. */ ExpectIntEQ(wc_SlhDsaKey_Verify(NULL, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), NULL, sizeof(msg), sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), NULL, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test successful verification. */ ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); /* Test verification with wrong message. */ msg[0] ^= 0xFF; ExpectIntNE(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); msg[0] ^= 0xFF; /* Test verification with wrong context. */ ctx[0] ^= 0xFF; ExpectIntNE(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); ctx[0] ^= 0xFF; /* Test verification with corrupted signature. */ sig[0] ^= 0xFF; ExpectIntNE(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); sig[0] ^= 0xFF; /* Test verification with NULL context (allowed, but must match signing). */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, NULL, 0, msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, NULL, 0, msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } /* * Test combined sign and verify for all parameter sets. */ int test_wc_slhdsa_sign_vfy(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) SlhDsaKey key; WC_RNG rng; byte msg[64]; byte* sig = NULL; word32 sigLen; byte ctx[10]; sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig); XMEMSET(&rng, 0, sizeof(WC_RNG)); XMEMSET(msg, 0xAA, sizeof(msg)); XMEMSET(ctx, 0x01, sizeof(ctx)); ExpectIntEQ(wc_InitRng(&rng), 0); #ifdef WOLFSSL_SLHDSA_PARAM_128S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHAKE128S_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHAKE128F_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, (word32)wc_SlhDsaKey_SigSize(&key)); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHAKE192F_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHAKE256S_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHAKE256F_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_SHA2 #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_128S_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_128F_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_192S_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_192F_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_256S_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_256F_SIG_LEN); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } /* * Test hash signing and verification for SLH-DSA. */ int test_wc_slhdsa_sign_hash(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) SlhDsaKey key; WC_RNG rng; byte hash[64]; byte* sig = NULL; word32 sigLen; word32 expSigLen; byte ctx[10]; sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig); XMEMSET(&rng, 0, sizeof(WC_RNG)); XMEMSET(hash, 0xBB, sizeof(hash)); XMEMSET(ctx, 0x01, sizeof(ctx)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); expSigLen = TEST_SLHDSA_DEFAULT_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Test SignHash NULL parameter handling. Use 32-byte hash length so the * NULL check trips before the digest-length check (HashSLH-DSA expects * SHA-256 digest = 32 bytes). */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHash(NULL, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), NULL, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, NULL, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, NULL, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* HashSLH-DSA must reject digest lengths that don't match hashType. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 31, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_LENGTH_E)); ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 33, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_LENGTH_E)); /* Generate a real signature first so VerifyHash gets to its length check * rather than failing on signature size. */ ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 31, WC_HASH_TYPE_SHA256, sig, sigLen), WC_NO_ERR_TRACE(BAD_LENGTH_E)); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 33, WC_HASH_TYPE_SHA256, sig, sigLen), WC_NO_ERR_TRACE(BAD_LENGTH_E)); /* Unsupported hashType (FIPS 205 doesn't list WC_HASH_TYPE_NONE) hits * the default branch of slhdsakey_validate_prehash. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_NONE, sig, &sigLen, &rng), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); /* Test SignHash with SHA-256. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), 0); ExpectIntEQ(sigLen, expSigLen); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, sigLen), 0); /* Test VerifyHash NULL parameter handling. */ ExpectIntEQ(wc_SlhDsaKey_VerifyHash(NULL, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), NULL, 32, WC_HASH_TYPE_SHA256, sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, NULL, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test VerifyHash with wrong hash. */ hash[0] ^= 0xFF; ExpectIntNE(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, sigLen), 0); hash[0] ^= 0xFF; /* Test SignHashDeterministic. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHashDeterministic(NULL, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignHashDeterministic(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, sigLen), 0); /* Test SignHashWithRandom. */ { byte addRnd[WC_SLHDSA_MAX_SEED]; XMEMSET(addRnd, 0x55, sizeof(addRnd)); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHashWithRandom(NULL, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, addRnd), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignHashWithRandom(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignHashWithRandom(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, &sigLen, addRnd), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA256, sig, sigLen), 0); } #ifdef WOLFSSL_SHA512 /* SHA-512 round-trip exercises a 64-byte digest path. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 64, WC_HASH_TYPE_SHA512, sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 64, WC_HASH_TYPE_SHA512, sig, sigLen), 0); /* SHA-512 must also reject the wrong digest length. */ ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHA512, sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_LENGTH_E)); #endif #ifdef WOLFSSL_SHAKE128 /* SHAKE128 PHM is fixed at 256 bits per FIPS 205 Section 10.2.2. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHAKE128, sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHAKE128, sig, sigLen), 0); /* SignHash and VerifyHash both reject mismatched digest length. */ ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 64, WC_HASH_TYPE_SHAKE128, sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_LENGTH_E)); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 64, WC_HASH_TYPE_SHAKE128, sig, sigLen), WC_NO_ERR_TRACE(BAD_LENGTH_E)); #endif #ifdef WOLFSSL_SHAKE256 /* SHAKE256 PHM is fixed at 512 bits per FIPS 205 Section 10.2.2. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 64, WC_HASH_TYPE_SHAKE256, sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 64, WC_HASH_TYPE_SHAKE256, sig, sigLen), 0); /* SignHash and VerifyHash both reject mismatched digest length. */ ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHAKE256, sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_LENGTH_E)); ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 32, WC_HASH_TYPE_SHAKE256, sig, sigLen), WC_NO_ERR_TRACE(BAD_LENGTH_E)); #endif wc_SlhDsaKey_Free(&key); wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } /* * Test the FIPS 205 internal interface (M' supplied directly) for SLH-DSA. * Covers wc_SlhDsaKey_SignMsgDeterministic, wc_SlhDsaKey_SignMsgWithRandom, * and wc_SlhDsaKey_VerifyMsg, plus a HashSLH-DSA equivalence cross-check * that proves an externally-built M' matches the SignHash/VerifyHash path. */ int test_wc_slhdsa_sign_msg(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ !defined(NO_SHA256) SlhDsaKey key; WC_RNG rng; byte mprime[64]; byte* sig = NULL; word32 sigLen; byte addRnd[WC_SLHDSA_MAX_SEED]; sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig); XMEMSET(&rng, 0, sizeof(WC_RNG)); XMEMSET(mprime, 0xAA, sizeof(mprime)); XMEMSET(addRnd, 0x55, sizeof(addRnd)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* SignMsgDeterministic NULL-arg checks. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(NULL, mprime, sizeof(mprime), sig, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, NULL, sizeof(mprime), sig, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime, sizeof(mprime), NULL, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime, sizeof(mprime), sig, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* SignMsgDeterministic must reject sigSz smaller than params->sigLen. */ sigLen = 1; ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime, sizeof(mprime), sig, &sigLen), WC_NO_ERR_TRACE(BAD_LENGTH_E)); /* Round-trip: Deterministic. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime, sizeof(mprime), sig, &sigLen), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, mprime, sizeof(mprime), sig, sigLen), 0); /* SignMsgWithRandom NULL-arg checks. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(NULL, mprime, sizeof(mprime), sig, &sigLen, addRnd), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(&key, mprime, sizeof(mprime), sig, &sigLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* SignMsgWithRandom must reject sigSz smaller than params->sigLen. */ sigLen = 1; ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(&key, mprime, sizeof(mprime), sig, &sigLen, addRnd), WC_NO_ERR_TRACE(BAD_LENGTH_E)); /* Round-trip: WithRandom. Reset sigLen explicitly so the test doesn't * silently rely on the previous call having set it to params->sigLen. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(&key, mprime, sizeof(mprime), sig, &sigLen, addRnd), 0); ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, mprime, sizeof(mprime), sig, sigLen), 0); /* VerifyMsg NULL-arg checks. */ ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(NULL, mprime, sizeof(mprime), sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, NULL, sizeof(mprime), sig, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, mprime, sizeof(mprime), NULL, sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Equivalence cross-check: build M' = 0x01 || ctxSz || OID(SHA-256) || * SHA256(orig) externally, sign it via SignMsgDeterministic, and verify * via VerifyHash with the same SHA-256 digest. Both paths must agree. */ { static const byte sha256_oid[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 }; static const byte orig[] = "Hello World!"; byte digest[WC_SHA256_DIGEST_SIZE]; byte built_mprime[2 + sizeof(sha256_oid) + WC_SHA256_DIGEST_SIZE]; word32 idx = 0; word32 sigLen2; ExpectIntEQ(wc_Sha256Hash(orig, (word32)sizeof(orig) - 1, digest), 0); built_mprime[idx++] = 0x01; /* HashSLH-DSA domain separator */ built_mprime[idx++] = 0; /* ctxSz = 0 */ XMEMCPY(built_mprime + idx, sha256_oid, sizeof(sha256_oid)); idx += (word32)sizeof(sha256_oid); XMEMCPY(built_mprime + idx, digest, sizeof(digest)); idx += (word32)sizeof(digest); sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, built_mprime, idx, sig, &sigLen), 0); /* The same signature must verify via the HashSLH-DSA external API. */ ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, NULL, 0, digest, sizeof(digest), WC_HASH_TYPE_SHA256, sig, sigLen), 0); /* And the deterministic HashSLH-DSA path must produce the SAME * signature bytes (this is the strongest interop check). */ sigLen2 = WC_SLHDSA_MAX_SIG_LEN; { byte* sig2 = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig2); ExpectIntEQ(wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0, digest, sizeof(digest), WC_HASH_TYPE_SHA256, sig2, &sigLen2), 0); ExpectIntEQ(sigLen2, sigLen); ExpectIntEQ(XMEMCMP(sig2, sig, sigLen), 0); XFREE(sig2, NULL, DYNAMIC_TYPE_TMP_BUFFER); } } wc_SlhDsaKey_Free(&key); wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); } /* * Test export and import for SLH-DSA keys. */ int test_wc_slhdsa_export_import(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) SlhDsaKey key; SlhDsaKey key2; WC_RNG rng; byte* privKey = NULL; byte* pubKey = NULL; word32 privKeyLen; word32 expPrivKeyLen; word32 pubKeyLen; word32 expPubKeyLen; byte msg[64]; byte* sig = NULL; word32 sigLen; byte ctx[10]; privKey = (byte*)XMALLOC(WC_SLHDSA_MAX_PRIV_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(privKey); pubKey = (byte*)XMALLOC(WC_SLHDSA_MAX_PUB_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(pubKey); sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig); XMEMSET(&rng, 0, sizeof(WC_RNG)); XMEMSET(msg, 0xAA, sizeof(msg)); XMEMSET(ctx, 0x01, sizeof(ctx)); ExpectIntEQ(wc_InitRng(&rng), 0); /* Test NULL parameter handling for export functions. */ privKeyLen = WC_SLHDSA_MAX_PRIV_LEN; pubKeyLen = WC_SLHDSA_MAX_PUB_LEN; ExpectIntEQ(wc_SlhDsaKey_ExportPrivate(NULL, privKey, &privKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_ExportPublic(NULL, pubKey, &pubKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test NULL parameter handling for import functions. */ ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(NULL, privKey, privKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(NULL, pubKey, pubKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); expPrivKeyLen = TEST_SLHDSA_DEFAULT_PRIV_LEN; expPubKeyLen = TEST_SLHDSA_DEFAULT_PUB_LEN; ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Test export with NULL buffer. */ ExpectIntEQ(wc_SlhDsaKey_ExportPrivate(&key, NULL, &privKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_ExportPrivate(&key, privKey, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&key, NULL, &pubKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&key, pubKey, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test export with buffer too small. */ privKeyLen = 10; ExpectIntEQ(wc_SlhDsaKey_ExportPrivate(&key, privKey, &privKeyLen), WC_NO_ERR_TRACE(BAD_LENGTH_E)); pubKeyLen = 10; ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&key, pubKey, &pubKeyLen), WC_NO_ERR_TRACE(BAD_LENGTH_E)); /* Test successful export. */ privKeyLen = WC_SLHDSA_MAX_PRIV_LEN; ExpectIntEQ(wc_SlhDsaKey_ExportPrivate(&key, privKey, &privKeyLen), 0); ExpectIntEQ(privKeyLen, expPrivKeyLen); pubKeyLen = WC_SLHDSA_MAX_PUB_LEN; ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&key, pubKey, &pubKeyLen), 0); ExpectIntEQ(pubKeyLen, expPubKeyLen); /* Sign with original key. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); /* Test import into new key and verify. */ ExpectIntEQ(wc_SlhDsaKey_Init(&key2, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); /* Test import with NULL data. */ ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key2, NULL, privKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key2, NULL, pubKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Test import with wrong size. */ ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key2, privKey, 10), WC_NO_ERR_TRACE(BAD_LENGTH_E)); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key2, pubKey, 10), WC_NO_ERR_TRACE(BAD_LENGTH_E)); /* Test successful import of public key only. */ ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key2, pubKey, pubKeyLen), 0); /* Verify with imported public key. */ ExpectIntEQ(wc_SlhDsaKey_Verify(&key2, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key2); /* Test import of private key. */ ExpectIntEQ(wc_SlhDsaKey_Init(&key2, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key2, privKey, privKeyLen), 0); /* Sign with imported key. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&key2, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), 0); /* Verify with original key. */ ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&key2); wc_SlhDsaKey_Free(&key); wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } /* * Test key check for SLH-DSA. */ int test_wc_slhdsa_check_key(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) SlhDsaKey key; WC_RNG rng; byte* privKey = NULL; byte* pubKey = NULL; word32 privKeyLen; word32 pubKeyLen; privKey = (byte*)XMALLOC(WC_SLHDSA_MAX_PRIV_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(privKey); pubKey = (byte*)XMALLOC(WC_SLHDSA_MAX_PUB_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(pubKey); XMEMSET(&rng, 0, sizeof(WC_RNG)); ExpectIntEQ(wc_InitRng(&rng), 0); /* Test NULL parameter handling. */ ExpectIntEQ(wc_SlhDsaKey_CheckKey(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Test check of valid key. */ ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); /* Export keys. */ privKeyLen = WC_SLHDSA_MAX_PRIV_LEN; ExpectIntEQ(wc_SlhDsaKey_ExportPrivate(&key, privKey, &privKeyLen), 0); pubKeyLen = WC_SLHDSA_MAX_PUB_LEN; ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&key, pubKey, &pubKeyLen), 0); wc_SlhDsaKey_Free(&key); /* Test check with only public key imported - requires private key. */ ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key, pubKey, pubKeyLen), 0); /* CheckKey requires a private key to validate. */ ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), WC_NO_ERR_TRACE(MISSING_KEY)); wc_SlhDsaKey_Free(&key); /* Test check with only private key imported. */ ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key, privKey, privKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); wc_SlhDsaKey_Free(&key); /* Test check with both keys imported. */ ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key, pubKey, pubKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key, privKey, privKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); key.sk[0] ^= 0x01; ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), WC_NO_ERR_TRACE(WC_KEY_MISMATCH_E)); wc_SlhDsaKey_Free(&key); /* Regression: Private-then-Public order. ImportPrivate sets * flags = WC_SLHDSA_FLAG_BOTH_KEYS; if ImportPublic clobbered flags * with `=` instead of `|=`, the FLAG_PRIVATE bit would be dropped and * CheckKey would return MISSING_KEY. */ ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key, privKey, privKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key, pubKey, pubKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); wc_SlhDsaKey_Free(&key); wc_FreeRng(&rng); XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ defined(WC_ENABLE_ASYM_KEY_EXPORT) /* Round-trip a single SLH-DSA parameter set through the DER codec: * generate -> KeyToDer -> PrivateKeyDecode -> sign/verify round-trip. * Also tests PublicKeyToDer -> PublicKeyDecode, and that the decode * correctly auto-detects the parameter set from the OID. */ static int slhdsa_der_roundtrip_one(enum SlhDsaParam param) { EXPECT_DECLS; SlhDsaKey keyGen; SlhDsaKey keyPriv; SlhDsaKey keyPub; WC_RNG rng; byte* derBuf = NULL; byte* sig = NULL; const word32 derBufSz = 16 * 1024; word32 derLen = 0; /* initialize to suppress false -Wmaybe-uninitialized */ word32 idx; word32 sigLen; enum SlhDsaParam placeholder = param; static const byte msg[] = "SLH-DSA DER round-trip"; static const enum SlhDsaParam candidates[] = { SLHDSA_SHAKE256S, SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, SLHDSA_SHAKE192F, SLHDSA_SHAKE256F, SLHDSA_SHAKE128S, #ifdef WOLFSSL_SLHDSA_SHA2 SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F, #endif }; size_t cIdx; /* Pick a placeholder different from the encoded param so a regression * that disables OID auto-detection would fail the post-decode equality * check. Walk the candidate list and probe each via wc_SlhDsaKey_Init; * the first one that initialises successfully (i.e. is compiled in) is * used. Falls back to the encoded param if no other variant is * available, in which case the test reduces to a smoke check. */ for (cIdx = 0; cIdx < sizeof(candidates)/sizeof(candidates[0]); cIdx++) { SlhDsaKey probe; if (candidates[cIdx] == param) { continue; } XMEMSET(&probe, 0, sizeof(probe)); if (wc_SlhDsaKey_Init(&probe, candidates[cIdx], NULL, INVALID_DEVID) == 0) { placeholder = candidates[cIdx]; wc_SlhDsaKey_Free(&probe); break; } } XMEMSET(&rng, 0, sizeof(rng)); XMEMSET(&keyGen, 0, sizeof(keyGen)); XMEMSET(&keyPriv, 0, sizeof(keyPriv)); XMEMSET(&keyPub, 0, sizeof(keyPub)); derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(derBuf); sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(sig); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&keyGen, param, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&keyGen, &rng), 0); /* Size-query contract: passing output=NULL returns the encoded size * without touching the buffer. The real encode below must produce * exactly this many bytes -- a size-query regression (e.g. forgetting * to add verSz) would surface here as a mismatch. */ { int querySize; ExpectIntGT(querySize = wc_SlhDsaKey_KeyToDer(&keyGen, NULL, 0), 0); ExpectIntGT(derLen = (word32)wc_SlhDsaKey_KeyToDer(&keyGen, derBuf, derBufSz), 0); ExpectIntEQ((int)derLen, querySize); /* BUFFER_E contract: too-small buffer is rejected without writing * anything past the limit. Pass inLen = querySize - 1 so the * length check fails for any encoding. */ ExpectIntEQ(wc_SlhDsaKey_KeyToDer(&keyGen, derBuf, (word32)(querySize - 1)), WC_NO_ERR_TRACE(BUFFER_E)); /* PrivateKeyToDer is an RFC 9909 alias of KeyToDer; sizes must * match and BUFFER_E must propagate. */ ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(&keyGen, NULL, 0), querySize); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(&keyGen, derBuf, (word32)(querySize - 1)), WC_NO_ERR_TRACE(BUFFER_E)); } /* Decode into a fresh key. The decode must auto-detect the real * parameter set from the OID embedded in the DER encoding. */ ExpectIntEQ(wc_SlhDsaKey_Init(&keyPriv, placeholder, NULL, INVALID_DEVID), 0); idx = 0; ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idx, &keyPriv, derLen), 0); /* Verify the decoded key reports the ORIGINAL parameter set. */ if (keyPriv.params != NULL) { ExpectIntEQ((int)keyPriv.params->param, (int)param); } /* Byte-level equivalence check: re-encode the decoded private key * and compare against the original DER. This catches a regression * even in single-variant builds where placeholder == param made the * params equality test above tautological -- if the decoder ignored * the OID and kept stale state, the bytes won't match. */ { byte* roundBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); word32 roundLen; ExpectNotNull(roundBuf); ExpectIntGT(roundLen = (word32)wc_SlhDsaKey_KeyToDer(&keyPriv, roundBuf, derBufSz), 0); ExpectIntEQ((int)roundLen, (int)derLen); if (roundBuf != NULL) { ExpectIntEQ(XMEMCMP(roundBuf, derBuf, roundLen), 0); } XFREE(roundBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } /* Sign with the decoded private key and verify with the originally * generated key. This proves the decoded key material is correct. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&keyPriv, NULL, 0, msg, (word32)sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_Verify(&keyGen, NULL, 0, msg, (word32)sizeof(msg), sig, sigLen), 0); /* Also test PrivateKeyToDer -> PrivateKeyDecode round-trip. */ { SlhDsaKey keyPriv2; word32 derLen2; word32 idx2 = 0; XMEMSET(&keyPriv2, 0, sizeof(keyPriv2)); ExpectIntGT(derLen2 = (word32)wc_SlhDsaKey_PrivateKeyToDer(&keyGen, derBuf, derBufSz), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&keyPriv2, placeholder, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idx2, &keyPriv2, derLen2), 0); /* Verify the PrivateKeyToDer output matches KeyToDer. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&keyPriv2, NULL, 0, msg, (word32)sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_Verify(&keyGen, NULL, 0, msg, (word32)sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&keyPriv2); } /* PKCS#8 v2 (RFC 5958) acceptance: the decoder explicitly allows * version=0 or version=1. The encoder only ever writes version=0, * so without a targeted check the v=1 branch would never fire and a * regression that rejected v2 wrappers (legal RFC 5958 OneAsymmetricKey * input from external tools) would slip through. Walk past the outer * SEQUENCE header (which uses short or long-form length depending on * the parameter set's encoded size) to land on the INTEGER version * field, then flip its value from 0 to 1. */ { SlhDsaKey keyPrivV2; word32 idxV2 = 0; word32 verPos; byte saved; XMEMSET(&keyPrivV2, 0, sizeof(keyPrivV2)); ExpectIntGT((int)derLen, 5); ExpectIntEQ((int)derBuf[0], 0x30); /* outer SEQUENCE tag */ if ((derBuf[1] & 0x80) == 0) { verPos = 2; /* short-form length */ } else { verPos = 2 + (derBuf[1] & 0x7F); /* long-form length */ } ExpectIntLT((int)verPos + 3, (int)derLen); ExpectIntEQ((int)derBuf[verPos], 0x02); /* INTEGER tag */ ExpectIntEQ((int)derBuf[verPos + 1], 0x01); /* INTEGER length */ ExpectIntEQ((int)derBuf[verPos + 2], 0x00); /* v0 baseline */ saved = derBuf[verPos + 2]; derBuf[verPos + 2] = 0x01; ExpectIntEQ(wc_SlhDsaKey_Init(&keyPrivV2, placeholder, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idxV2, &keyPrivV2, derLen), 0); if (keyPrivV2.params != NULL) { ExpectIntEQ((int)keyPrivV2.params->param, (int)param); } /* Confirm the v2-decoded private material is functionally * identical: a signature it produces verifies under keyGen. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_Sign(&keyPrivV2, NULL, 0, msg, (word32)sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_Verify(&keyGen, NULL, 0, msg, (word32)sizeof(msg), sig, sigLen), 0); derBuf[verPos + 2] = saved; wc_SlhDsaKey_Free(&keyPrivV2); } /* Now round-trip the public key alone, with size-query and BUFFER_E * contract checks for both withAlg modes. */ { int querySpki, queryRaw; byte rawPub[WC_SLHDSA_MAX_PUB_LEN]; word32 rawPubLen = (word32)sizeof(rawPub); /* withAlg=1: full SubjectPublicKeyInfo (used by certificate code). */ ExpectIntGT(querySpki = wc_SlhDsaKey_PublicKeyToDer(&keyGen, NULL, 0, 1), 0); ExpectIntGT(derLen = (word32)wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, derBufSz, 1), 0); ExpectIntEQ((int)derLen, querySpki); ExpectIntEQ(wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, (word32)(querySpki - 1), 1), WC_NO_ERR_TRACE(BUFFER_E)); /* withAlg=0: raw 2*n public-key bytes only -- this is the path * SetKeyIdFromPublicKey in asn.c walks when computing SKID/AKID * for SLH-DSA certificates. Verify the bytes match what * ExportPublic produces so a regression in this branch (e.g. * accidentally emitting the SPKI envelope, or returning the * wrong length) breaks the test rather than silently corrupting * key identifiers in issued certs. */ ExpectIntGT(queryRaw = wc_SlhDsaKey_PublicKeyToDer(&keyGen, NULL, 0, 0), 0); ExpectIntEQ(queryRaw, (int)(2 * keyGen.params->n)); ExpectIntGT(wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, derBufSz, 0), 0); ExpectIntEQ(wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, (word32)(queryRaw - 1), 0), WC_NO_ERR_TRACE(BUFFER_E)); ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&keyGen, rawPub, &rawPubLen), 0); ExpectIntEQ((int)rawPubLen, queryRaw); ExpectIntEQ(XMEMCMP(derBuf, rawPub, rawPubLen), 0); /* Re-encode the SPKI so the decode test below sees the * withAlg=1 buffer (raw output above is not decodable as SPKI). */ ExpectIntGT(derLen = (word32)wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, derBufSz, 1), 0); } ExpectIntEQ(wc_SlhDsaKey_Init(&keyPub, placeholder, NULL, INVALID_DEVID), 0); idx = 0; ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(derBuf, &idx, &keyPub, derLen), 0); if (keyPub.params != NULL) { ExpectIntEQ((int)keyPub.params->param, (int)param); } /* The decoded public key should verify the signature we just produced. */ ExpectIntEQ(wc_SlhDsaKey_Verify(&keyPub, NULL, 0, msg, (word32)sizeof(msg), sig, sigLen), 0); wc_SlhDsaKey_Free(&keyPub); wc_SlhDsaKey_Free(&keyPriv); wc_SlhDsaKey_Free(&keyGen); wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return EXPECT_RESULT(); } #endif /* * DER codec round-trip test: encode each compiled-in SLH-DSA parameter set * to DER, decode it (without telling the decoder which parameter set it is), * confirm auto-detect produces the right parameter, and verify a signature * produced with the decoded key. This test would fail if PrivateKeyDecode * / PublicKeyDecode did not auto-detect the parameter set from the OID. */ int test_wc_slhdsa_der_roundtrip(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ defined(WC_ENABLE_ASYM_KEY_EXPORT) #ifdef WOLFSSL_SLHDSA_PARAM_128S ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE128S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE128F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE192S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE192F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE256S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE256F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_SHA2 #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_128S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_128F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_192S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_192F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_256S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_256F), TEST_SUCCESS); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ #endif /* WOLFSSL_HAVE_SLHDSA && !VERIFY_ONLY && WC_ENABLE_ASYM_KEY_EXPORT */ return EXPECT_RESULT(); } /* * Negative / error-path tests for the DER encode/decode functions. */ int test_wc_slhdsa_der_negative(void) { EXPECT_DECLS; #ifdef WOLFSSL_HAVE_SLHDSA SlhDsaKey key; word32 idx; byte buf[16]; XMEMSET(&key, 0, sizeof(key)); /* PrivateKeyDecode: NULL parameters */ #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY idx = 0; ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(NULL, &idx, &key, 10), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(buf, NULL, &key, 10), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(buf, &idx, NULL, 10), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(buf, &idx, &key, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* PrivateKeyDecode: truncated data */ idx = 0; XMEMSET(buf, 0, sizeof(buf)); ExpectIntNE(wc_SlhDsaKey_PrivateKeyDecode(buf, &idx, &key, sizeof(buf)), 0); #endif /* PublicKeyDecode: NULL parameters */ idx = 0; ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(NULL, &idx, &key, 10), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(buf, NULL, &key, 10), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(buf, &idx, NULL, 10), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(buf, &idx, &key, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #if defined(WC_ENABLE_ASYM_KEY_EXPORT) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) /* KeyToDer / PrivateKeyToDer: NULL key */ ExpectIntEQ(wc_SlhDsaKey_KeyToDer(NULL, buf, sizeof(buf)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(NULL, buf, sizeof(buf)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* KeyToDer: public-only key should return MISSING_KEY. Build the * public-only state through the public API (generate a key, export * the public part, import it into a fresh key) rather than poking * key->flags directly. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S { SlhDsaKey srcKey; SlhDsaKey pubOnly; WC_RNG rng; byte pub[WC_SLHDSA_MAX_PUB_LEN]; word32 pubLen = (word32)sizeof(pub); XMEMSET(&srcKey, 0, sizeof(srcKey)); XMEMSET(&pubOnly, 0, sizeof(pubOnly)); XMEMSET(&rng, 0, sizeof(rng)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&srcKey, pub, &pubLen), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&pubOnly, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&pubOnly, pub, pubLen), 0); ExpectIntEQ(wc_SlhDsaKey_KeyToDer(&pubOnly, NULL, 0), WC_NO_ERR_TRACE(MISSING_KEY)); ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(&pubOnly, NULL, 0), WC_NO_ERR_TRACE(MISSING_KEY)); wc_SlhDsaKey_Free(&pubOnly); wc_SlhDsaKey_Free(&srcKey); wc_FreeRng(&rng); } #endif #endif /* WC_ENABLE_ASYM_KEY_EXPORT && !VERIFY_ONLY */ /* PublicKeyToDer: NULL key */ #ifdef WC_ENABLE_ASYM_KEY_EXPORT ExpectIntEQ(wc_SlhDsaKey_PublicKeyToDer(NULL, buf, sizeof(buf), 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif /* RFC 5958 OneAsymmetricKey trailing-field validation: * [0] IMPLICIT Attributes OPTIONAL -- at most once * [1] IMPLICIT PublicKey OPTIONAL -- at most once, after [0] * The decoder must reject duplicates, out-of-order tags, and * unrecognised tags. Build a valid SHAKE128S DER then mutate it. */ #if defined(WC_ENABLE_ASYM_KEY_EXPORT) && \ !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ defined(WOLFSSL_SLHDSA_PARAM_128S) { SlhDsaKey srcKey; WC_RNG rng; byte goodDer[256]; int goodLen = 0; size_t i; struct { const byte* trailing; word32 trailingLen; int expectAccept; /* 0 = expect ASN_PARSE_E */ const char* desc; } cases[5]; const byte tDupAttr[] = { 0xA0, 0x00, 0xA0, 0x00 }; const byte tDupPub[] = { 0xA1, 0x00, 0xA1, 0x00 }; const byte tOutOfOrder[]= { 0xA1, 0x00, 0xA0, 0x00 }; const byte tUnknown[] = { 0xA2, 0x00 }; const byte tValidAttr[] = { 0xA0, 0x00 }; cases[0].trailing = tDupAttr; cases[0].trailingLen = (word32)sizeof(tDupAttr); cases[0].expectAccept = 0; cases[0].desc = "duplicate [0] attributes"; cases[1].trailing = tDupPub; cases[1].trailingLen = (word32)sizeof(tDupPub); cases[1].expectAccept = 0; cases[1].desc = "duplicate [1] publicKey"; cases[2].trailing = tOutOfOrder; cases[2].trailingLen = (word32)sizeof(tOutOfOrder); cases[2].expectAccept = 0; cases[2].desc = "[1] before [0]"; cases[3].trailing = tUnknown; cases[3].trailingLen = (word32)sizeof(tUnknown); cases[3].expectAccept = 0; cases[3].desc = "unknown context tag [2]"; /* Sanity: a single [0] is permitted -- if this rejects, the * tightening above is overzealous and the four rejection cases * are testing nothing useful. */ cases[4].trailing = tValidAttr; cases[4].trailingLen = (word32)sizeof(tValidAttr); cases[4].expectAccept = 1; cases[4].desc = "single [0] attributes (accepted)"; XMEMSET(&srcKey, 0, sizeof(srcKey)); XMEMSET(&rng, 0, sizeof(rng)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); ExpectIntGT(goodLen = wc_SlhDsaKey_KeyToDer(&srcKey, goodDer, sizeof(goodDer)), 0); /* The mutator below tweaks goodDer[1] (length byte) in place, * which only works if the encoder used short-form SEQUENCE * length. SHAKE128S body is ~82 bytes so this holds, but assert * it so a future encoder change surfaces here rather than * silently producing buffers that decode despite the mutation. */ ExpectIntEQ((int)goodDer[0], 0x30); ExpectIntLT((int)goodDer[1], 0x80); ExpectIntLT((int)goodDer[1] + 4, 0x80); for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) { byte mut[260]; word32 mutLen; word32 idx2 = 0; SlhDsaKey k; int decRet; XMEMSET(&k, 0, sizeof(k)); XMEMCPY(mut, goodDer, (size_t)goodLen); XMEMCPY(mut + goodLen, cases[i].trailing, cases[i].trailingLen); mutLen = (word32)goodLen + cases[i].trailingLen; mut[1] = (byte)(goodDer[1] + cases[i].trailingLen); ExpectIntEQ(wc_SlhDsaKey_Init(&k, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); decRet = wc_SlhDsaKey_PrivateKeyDecode(mut, &idx2, &k, mutLen); if (cases[i].expectAccept) { ExpectIntEQ(decRet, 0); } else { ExpectIntEQ(decRet, WC_NO_ERR_TRACE(ASN_PARSE_E)); } (void)cases[i].desc; wc_SlhDsaKey_Free(&k); } wc_SlhDsaKey_Free(&srcKey); wc_FreeRng(&rng); } #endif /* WC_ENABLE_ASYM_KEY_EXPORT && !VERIFY_ONLY && PARAM_128S */ #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ !defined(NO_FILESYSTEM) /* Load an RFC 9909 compliant DER file from disk and confirm that * wc_SlhDsaKey_PrivateKeyDecode accepts it, auto-detects the parameter * set from the OID, and produces a usable signing key. This test * exercises the on-disk certs/slhdsa/ fixtures - any future file-format * drift (nested wrapper, seed-only, wrong length) will be caught here. */ /* doSign=0 skips the sign/verify smoke check; the 192s and 256s parameter * sets are slow enough (multi-second per Sign) that running them on every * make-check would balloon test time. The decoder is still exercised. */ static int slhdsa_decode_file_one(const char *path, enum SlhDsaParam expected, int doSign) { EXPECT_DECLS; XFILE f = XBADFILE; byte der[256]; int derSz = 0; SlhDsaKey key; WC_RNG rng; word32 idx = 0; byte sig[WC_SLHDSA_MAX_SIG_LEN]; word32 sigLen = (word32)sizeof(sig); static const byte msg[] = "slhdsa decode-file test"; XMEMSET(&key, 0, sizeof(key)); XMEMSET(&rng, 0, sizeof(rng)); ExpectTrue((f = XFOPEN(path, "rb")) != XBADFILE); if (f != XBADFILE) { ExpectIntGT(derSz = (int)XFREAD(der, 1, sizeof(der), f), 0); XFCLOSE(f); } /* Pick a seed param different from `expected` when more than one * variant is built. The decoder always overwrites this from the OID * in the DER, so a different placeholder actually tests the auto- * detect contract on disk-loaded fixtures (mirroring the helper * logic in slhdsa_der_roundtrip_one). Falls back to `expected` when * no alternative variant is available. */ { static const enum SlhDsaParam candidates[] = { SLHDSA_SHAKE128S, SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, SLHDSA_SHAKE192F, SLHDSA_SHAKE256S, SLHDSA_SHAKE256F, #ifdef WOLFSSL_SLHDSA_SHA2 SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F, #endif }; enum SlhDsaParam placeholder = expected; size_t cIdx; for (cIdx = 0; cIdx < sizeof(candidates)/sizeof(candidates[0]); cIdx++) { SlhDsaKey probe; if (candidates[cIdx] == expected) continue; XMEMSET(&probe, 0, sizeof(probe)); if (wc_SlhDsaKey_Init(&probe, candidates[cIdx], NULL, INVALID_DEVID) == 0) { placeholder = candidates[cIdx]; wc_SlhDsaKey_Free(&probe); break; } } ExpectIntEQ(wc_SlhDsaKey_Init(&key, placeholder, NULL, INVALID_DEVID), 0); } ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(der, &idx, &key, (word32)derSz), 0); ExpectNotNull(key.params); if (key.params != NULL) { ExpectIntEQ((int)key.params->param, (int)expected); } if (doSign) { /* Sanity: signing works with the decoded key. */ ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Sign(&key, NULL, 0, msg, (word32)sizeof(msg), sig, &sigLen, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_Verify(&key, NULL, 0, msg, (word32)sizeof(msg), sig, sigLen), 0); wc_FreeRng(&rng); } else { /* Cheap structural validation when the full sign/verify is * skipped (slow 192s/256s variants): catches an uninitialised SK * half or a botched SHA-2 precompute without paying the * multi-second cost of an actual Sign. */ ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); } wc_SlhDsaKey_Free(&key); return EXPECT_RESULT(); } #endif /* Load each checked-in bench_slhdsa_shake*_key.der fixture and confirm it * decodes via wc_SlhDsaKey_PrivateKeyDecode with correct auto-detection. * These fixtures are RFC 9909 compliant (bare OCTET STRING, 4*n bytes) - * this test would fail if the files drift to a non-compliant encoding * (e.g. nested OCTET STRING, seed-only). */ int test_wc_slhdsa_der_decode_files(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ !defined(NO_FILESYSTEM) #ifdef WOLFSSL_SLHDSA_PARAM_128S ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_shake128s_key.der", SLHDSA_SHAKE128S, 1), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_shake128f_key.der", SLHDSA_SHAKE128F, 1), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_shake192s_key.der", SLHDSA_SHAKE192S, 0), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_shake192f_key.der", SLHDSA_SHAKE192F, 1), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_shake256s_key.der", SLHDSA_SHAKE256S, 0), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_shake256f_key.der", SLHDSA_SHAKE256F, 1), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_SHA2 #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_sha2_128s_key.der", SLHDSA_SHA2_128S, 1), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_sha2_128f_key.der", SLHDSA_SHA2_128F, 1), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_sha2_192s_key.der", SLHDSA_SHA2_192S, 0), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_sha2_192f_key.der", SLHDSA_SHA2_192F, 1), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_sha2_256s_key.der", SLHDSA_SHA2_256S, 0), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F ExpectIntEQ(slhdsa_decode_file_one( "./certs/slhdsa/bench_slhdsa_sha2_256f_key.der", SLHDSA_SHA2_256F, 1), TEST_SUCCESS); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ #endif return EXPECT_RESULT(); } #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) /* Regression: wolfssl_x509_make_der and ConfirmSignature both pass the * raw 2*n public-key bytes (the BIT STRING contents stashed by StoreKey * into cert->publicKey) to wc_SlhDsaKey_PublicKeyDecode. Before the * raw-first fast path landed, that call returned ASN_PARSE_E because * DecodeAsymKeyPublic_Assign requires an SPKI SEQUENCE. This test pins * the new contract: when key->params is already set, raw bytes decode * directly, mirroring wc_Falcon_PublicKeyDecode and * wc_Dilithium_PublicKeyDecode. */ static int slhdsa_raw_public_decode_one(enum SlhDsaParam param) { EXPECT_DECLS; SlhDsaKey src; SlhDsaKey dst; byte pub[WC_SLHDSA_MAX_PUB_LEN]; word32 pubLen = (word32)sizeof(pub); word32 idx = 0; WC_RNG rng; XMEMSET(&src, 0, sizeof(src)); XMEMSET(&dst, 0, sizeof(dst)); XMEMSET(&rng, 0, sizeof(rng)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&src, param, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&src, &rng), 0); ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&src, pub, &pubLen), 0); /* Decode the raw public-key bytes via PublicKeyDecode. The fast * path triggers because key->params is set by Init. */ ExpectIntEQ(wc_SlhDsaKey_Init(&dst, param, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(pub, &idx, &dst, pubLen), 0); ExpectIntEQ((int)idx, (int)pubLen); ExpectNotNull(dst.params); if (dst.params != NULL) { ExpectIntEQ((int)dst.params->param, (int)param); } wc_SlhDsaKey_Free(&dst); wc_SlhDsaKey_Free(&src); wc_FreeRng(&rng); return EXPECT_RESULT(); } #endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ int test_wc_slhdsa_x509_i2d_roundtrip(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) /* Exercise the raw public-key fast path for every compiled-in variant * so a regression in n-dependent buffer math (32/48/64-byte keys) * fails the test even in restricted builds where SHAKE128S / * SHA2_128S happen to be excluded. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE128S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE128F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE192S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE192F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE256S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE256F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_SHA2 #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_128S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_128F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_192S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_192F), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_256S), TEST_SUCCESS); #endif #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_256F), TEST_SUCCESS); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ #endif return EXPECT_RESULT(); } #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ defined(WC_ENABLE_ASYM_KEY_EXPORT) /* Build a DER blob using an enabled SLH-DSA variant and patch the * AlgorithmIdentifier OID's trailing byte to point at a *disabled* * variant, then push it through the decoders. The contract being * pinned is that wc_SlhDsaKey_PrivateKeyDecode / PublicKeyDecode pass * the wc_SlhDsaOidToParam NOT_COMPILED_IN result through verbatim * rather than collapsing it to ASN_PARSE_E -- if that breaks, x509 / * TLS lose the precise "variant unavailable" diagnostic and silently * report malformed-DER instead. * * All SLH-DSA OIDs share the prefix 2.16.840.1.101.3.4.3.X with X<128, * so DER encoding lengths match exactly and the trailing byte is the * sole discriminator -- patching it in place produces a structurally * valid SPKI/PKCS#8 buffer that only fails at the OID-lookup step. * * @param src Enabled parameter set used to generate real DER. * @param targetOidByte Trailing OID byte of the disabled variant. */ /* Marked WC_MAYBE_UNUSED because every call site below is gated on a * per-variant disable macro -- builds that leave every variant enabled * (e.g. --enable-fips=ready) preprocess all callers away. */ static WC_MAYBE_UNUSED int slhdsa_decode_disabled_oid_one(enum SlhDsaParam src, byte targetOidByte) { EXPECT_DECLS; /* OID prefix common to every SLH-DSA variant. */ static const byte oidPrefix[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03 }; SlhDsaKey srcKey; SlhDsaKey dstKey; WC_RNG rng; byte* derBuf = NULL; const word32 derBufSz = 16 * 1024; int derLen = 0; word32 idx; word32 j; int patched; XMEMSET(&srcKey, 0, sizeof(srcKey)); XMEMSET(&dstKey, 0, sizeof(dstKey)); XMEMSET(&rng, 0, sizeof(rng)); derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(derBuf); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, src, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); /* Public-key path: build SPKI, patch the variant byte, decode. */ ExpectIntGT(derLen = wc_SlhDsaKey_PublicKeyToDer(&srcKey, derBuf, derBufSz, 1), 0); patched = 0; for (j = 0; derLen > (int)sizeof(oidPrefix) && j + sizeof(oidPrefix) < (word32)derLen; j++) { if (XMEMCMP(derBuf + j, oidPrefix, sizeof(oidPrefix)) == 0) { derBuf[j + sizeof(oidPrefix)] = targetOidByte; patched = 1; break; } } ExpectIntEQ(patched, 1); /* dstKey is zeroed (no params) so the raw fast path is skipped and * SPKI parsing surfaces the OID-lookup result. */ idx = 0; ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(derBuf, &idx, &dstKey, (word32)derLen), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); /* Private-key path: same scheme using the PKCS#8 wrapper. */ ExpectIntGT(derLen = wc_SlhDsaKey_KeyToDer(&srcKey, derBuf, derBufSz), 0); patched = 0; for (j = 0; derLen > (int)sizeof(oidPrefix) && j + sizeof(oidPrefix) < (word32)derLen; j++) { if (XMEMCMP(derBuf + j, oidPrefix, sizeof(oidPrefix)) == 0) { derBuf[j + sizeof(oidPrefix)] = targetOidByte; patched = 1; break; } } ExpectIntEQ(patched, 1); /* Free any state PublicKeyDecode may have established before the * second decode call reuses the key slot. */ wc_SlhDsaKey_Free(&dstKey); XMEMSET(&dstKey, 0, sizeof(dstKey)); idx = 0; ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idx, &dstKey, (word32)derLen), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); wc_SlhDsaKey_Free(&dstKey); wc_SlhDsaKey_Free(&srcKey); wc_FreeRng(&rng); XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return EXPECT_RESULT(); } /* Round-trip variant: same patcher path but the targetOidByte must equal * the source's own OID byte, so the decode is expected to succeed. Used * as an unconditional smoke check so test_wc_slhdsa_decoder_disabled_oid * exercises the patcher infrastructure even on builds with no per-variant * disable, where every disabled-branch in the caller is #if'd out. */ static int slhdsa_decode_disabled_oid_one_roundtrip(enum SlhDsaParam src, byte targetOidByte) { EXPECT_DECLS; static const byte oidPrefix[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03 }; SlhDsaKey srcKey; SlhDsaKey dstKey; WC_RNG rng; byte* derBuf = NULL; const word32 derBufSz = 16 * 1024; int derLen = 0; word32 idx; word32 j; int patched; XMEMSET(&srcKey, 0, sizeof(srcKey)); XMEMSET(&dstKey, 0, sizeof(dstKey)); XMEMSET(&rng, 0, sizeof(rng)); derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(derBuf); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, src, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); ExpectIntGT(derLen = wc_SlhDsaKey_PublicKeyToDer(&srcKey, derBuf, derBufSz, 1), 0); patched = 0; for (j = 0; derLen > (int)sizeof(oidPrefix) && j + sizeof(oidPrefix) < (word32)derLen; j++) { if (XMEMCMP(derBuf + j, oidPrefix, sizeof(oidPrefix)) == 0) { derBuf[j + sizeof(oidPrefix)] = targetOidByte; patched = 1; break; } } ExpectIntEQ(patched, 1); idx = 0; ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(derBuf, &idx, &dstKey, (word32)derLen), 0); wc_SlhDsaKey_Free(&dstKey); wc_SlhDsaKey_Free(&srcKey); wc_FreeRng(&rng); XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return EXPECT_RESULT(); } /* Probe candidate parameter sets in priority order and return the first * one whose backend is built in. Used to source a real DER buffer for * slhdsa_decode_disabled_oid_one regardless of which variants the * current build excluded. Returns 1 on success, 0 if no variant is * available (which the build's #error guard makes impossible in * practice but the test handles defensively). */ static int slhdsa_pick_enabled_param(enum SlhDsaParam* out) { static const enum SlhDsaParam candidates[] = { SLHDSA_SHAKE128S, SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, SLHDSA_SHAKE192F, SLHDSA_SHAKE256S, SLHDSA_SHAKE256F, #ifdef WOLFSSL_SLHDSA_SHA2 SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F, #endif }; size_t i; for (i = 0; i < sizeof(candidates)/sizeof(candidates[0]); i++) { SlhDsaKey probe; XMEMSET(&probe, 0, sizeof(probe)); if (wc_SlhDsaKey_Init(&probe, candidates[i], NULL, INVALID_DEVID) == 0) { wc_SlhDsaKey_Free(&probe); *out = candidates[i]; return 1; } } return 0; } #endif /* WOLFSSL_HAVE_SLHDSA && !VERIFY_ONLY && WC_ENABLE_ASYM_KEY_EXPORT */ /* Pin the per-variant disable contract: every parameter set whose enum * value is visible (so the test compiles) but whose backend is excluded * by a WOLFSSL_SLHDSA_PARAM_NO_* / WOLFSSL_SLHDSA_NO_* macro must surface * NOT_COMPILED_IN from wc_SlhDsaKey_Init instead of silently succeeding * or returning a generic error. * * This is the only API-level test for the granular disable surface and * also locks in the contract that wc_SlhDsaOidToParam/CertType in asn.c * piggyback on -- if Init drifts away from NOT_COMPILED_IN here, the * mapping helpers will likewise diverge and certificate handling will * lose its "variant unavailable" diagnostic. */ int test_wc_slhdsa_param_disabled(void) { EXPECT_DECLS; #ifdef WOLFSSL_HAVE_SLHDSA SlhDsaKey key; enum SlhDsaParam enabledProbe = SLHDSA_SHAKE128S; int haveEnabled; XMEMSET(&key, 0, sizeof(key)); /* Positive smoke check: at least one variant must initialise. Without * this the disabled-variant branches below can all be #if'd out and * the test would silently pass on default builds, defeating its * documented purpose. The probe also validates the contract from the * other side -- Init must succeed for an enabled param. */ haveEnabled = 0; #if defined(WOLFSSL_SLHDSA_PARAM_128S) enabledProbe = SLHDSA_SHAKE128S; haveEnabled = 1; #elif defined(WOLFSSL_SLHDSA_PARAM_128F) enabledProbe = SLHDSA_SHAKE128F; haveEnabled = 1; #elif defined(WOLFSSL_SLHDSA_PARAM_192S) enabledProbe = SLHDSA_SHAKE192S; haveEnabled = 1; #elif defined(WOLFSSL_SLHDSA_PARAM_192F) enabledProbe = SLHDSA_SHAKE192F; haveEnabled = 1; #elif defined(WOLFSSL_SLHDSA_PARAM_256S) enabledProbe = SLHDSA_SHAKE256S; haveEnabled = 1; #elif defined(WOLFSSL_SLHDSA_PARAM_256F) enabledProbe = SLHDSA_SHAKE256F; haveEnabled = 1; #elif defined(WOLFSSL_SLHDSA_SHA2) && defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S) enabledProbe = SLHDSA_SHA2_128S; haveEnabled = 1; #endif ExpectIntEQ(haveEnabled, 1); if (haveEnabled) { ExpectIntEQ(wc_SlhDsaKey_Init(&key, enabledProbe, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); XMEMSET(&key, 0, sizeof(key)); } #if defined(WOLFSSL_SLHDSA_PARAM_NO_128S) || \ defined(WOLFSSL_SLHDSA_NO_128) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_128F) || \ defined(WOLFSSL_SLHDSA_NO_128) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_192S) || \ defined(WOLFSSL_SLHDSA_NO_192) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_192F) || \ defined(WOLFSSL_SLHDSA_NO_192) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_256S) || \ defined(WOLFSSL_SLHDSA_NO_256) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_256F) || \ defined(WOLFSSL_SLHDSA_NO_256) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #ifdef WOLFSSL_SLHDSA_SHA2 /* SHA-2 enum values are only declared when WOLFSSL_SLHDSA_SHA2 is set; * each per-variant disable below is checked under that gate. */ #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif #endif /* WOLFSSL_SLHDSA_SHA2 */ (void)key; #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } /* Decoder-level companion to test_wc_slhdsa_param_disabled: feed DER for * each disabled SLH-DSA OID into PrivateKeyDecode/PublicKeyDecode and * confirm they pass NOT_COMPILED_IN through verbatim. The Init-level * test above proves the mapping helper is correct; this one proves the * decoders honour it instead of collapsing the result to ASN_PARSE_E. */ int test_wc_slhdsa_decoder_disabled_oid(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ defined(WC_ENABLE_ASYM_KEY_EXPORT) enum SlhDsaParam src = SLHDSA_SHAKE128S; int haveSrc = slhdsa_pick_enabled_param(&src); ExpectIntEQ(haveSrc, 1); if (haveSrc) { /* Positive smoke check: feed src's own OID through the patcher * (round-trip) and expect a clean decode, so the decoder path * actually exercises here even when no per-variant disable is * active. The trailing OID byte for SHAKE128S is 0x1A; we look * up the byte for `src` from a small table because src may not * be SHAKE128S in restricted builds. */ { byte srcOidByte = 0; switch (src) { case SLHDSA_SHAKE128S: srcOidByte = 0x1A; break; case SLHDSA_SHAKE128F: srcOidByte = 0x1B; break; case SLHDSA_SHAKE192S: srcOidByte = 0x1C; break; case SLHDSA_SHAKE192F: srcOidByte = 0x1D; break; case SLHDSA_SHAKE256S: srcOidByte = 0x1E; break; case SLHDSA_SHAKE256F: srcOidByte = 0x1F; break; #ifdef WOLFSSL_SLHDSA_SHA2 case SLHDSA_SHA2_128S: srcOidByte = 0x14; break; case SLHDSA_SHA2_128F: srcOidByte = 0x15; break; case SLHDSA_SHA2_192S: srcOidByte = 0x16; break; case SLHDSA_SHA2_192F: srcOidByte = 0x17; break; case SLHDSA_SHA2_256S: srcOidByte = 0x18; break; case SLHDSA_SHA2_256F: srcOidByte = 0x19; break; #endif default: break; } ExpectIntGT((int)srcOidByte, 0); /* Round-trip: patching src's OID to itself must still decode * successfully -- this fires unconditionally and validates * the patcher infrastructure even when no disable branch * below applies. */ ExpectIntEQ(slhdsa_decode_disabled_oid_one_roundtrip(src, srcOidByte), TEST_SUCCESS); } /* SHAKE family: trailing OID byte = 0x1A..0x1F. */ #if defined(WOLFSSL_SLHDSA_PARAM_NO_128S) || \ defined(WOLFSSL_SLHDSA_NO_128) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1A), TEST_SUCCESS); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_128F) || \ defined(WOLFSSL_SLHDSA_NO_128) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1B), TEST_SUCCESS); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_192S) || \ defined(WOLFSSL_SLHDSA_NO_192) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1C), TEST_SUCCESS); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_192F) || \ defined(WOLFSSL_SLHDSA_NO_192) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1D), TEST_SUCCESS); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_256S) || \ defined(WOLFSSL_SLHDSA_NO_256) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1E), TEST_SUCCESS); #endif #if defined(WOLFSSL_SLHDSA_PARAM_NO_256F) || \ defined(WOLFSSL_SLHDSA_NO_256) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1F), TEST_SUCCESS); #endif /* SHA-2 family: trailing OID byte = 0x14..0x19. The whole * family is also disabled when WOLFSSL_SLHDSA_SHA2 is unset. */ #if !defined(WOLFSSL_SLHDSA_SHA2) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x14), TEST_SUCCESS); #endif #if !defined(WOLFSSL_SLHDSA_SHA2) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x15), TEST_SUCCESS); #endif #if !defined(WOLFSSL_SLHDSA_SHA2) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x16), TEST_SUCCESS); #endif #if !defined(WOLFSSL_SLHDSA_SHA2) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x17), TEST_SUCCESS); #endif #if !defined(WOLFSSL_SLHDSA_SHA2) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x18), TEST_SUCCESS); #endif #if !defined(WOLFSSL_SLHDSA_SHA2) || \ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x19), TEST_SUCCESS); #endif } #endif return EXPECT_RESULT(); } #ifdef TEST_SLHDSA_DEFAULT_PARAM #undef TEST_SLHDSA_DEFAULT_PARAM #undef TEST_SLHDSA_DEFAULT_SIG_LEN #undef TEST_SLHDSA_DEFAULT_PRIV_LEN #undef TEST_SLHDSA_DEFAULT_PUB_LEN #undef TEST_SLHDSA_DEFAULT_SEED_LEN #endif