Files
2026-05-12 20:59:29 +00:00

2744 lines
107 KiB
C

/* 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 <tests/unit.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#ifdef WOLFSSL_HAVE_SLHDSA
#include <wolfssl/wolfcrypt/wc_slhdsa.h>
#endif
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/wolfcrypt/asn.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#include <tests/api/api.h>
#include <tests/api/test_slhdsa.h>
#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