mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 16:40:49 +02:00
26a2b793dc
1. Side-aware ML-KEM in TLS (tls.c, tls13.c, ssl.c, internal.h): TLSX_IsGroupSupported/TLSX_UseSupportedCurve take a `side` arg; new TLSX_IsMlKemGroupSupported + client/server support macros. A build only capable of one ML-KEM op no longer advertises groups it can't use for its role. 2. NO_ASN_TIME support (ssl_asn1.c, ssl.h, settings.h): data-only ASN1_TIME APIs now compile without system time; OCSP responder auto-disabled under NO_ASN_TIME. 3. SP ECC (sp_*.c, sp_x86_64_asm.asm): curve `b` constants and sp_ecc_is_point_* always compiled (point-check available in more configs); asm movsxd -> movsx. 4. configure.ac: BUILD_MEMUSE fixed to trigger on != "xno". 5. Test fixes: HRR-aware TLS 1.3 memio tests (new test_memio_msg_is_hello_retry_request); tightened build guards (Ed25519/Ed448 key-import, AES decrypt, XMSS heights, SP sizes, static-PSK).
500 lines
23 KiB
C
500 lines
23 KiB
C
/* test_mldsa_legacy.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
|
|
*/
|
|
|
|
/* Coverage for the temporary Dilithium -> ML-DSA legacy-name shim
|
|
* (<wolfssl/wolfcrypt/dilithium.h>). The shim is purely a set of
|
|
* #define aliases and typedef redirects; correctness reduces to:
|
|
*
|
|
* 1. every legacy name resolves to the canonical symbol / value, and
|
|
* 2. the arg-reordering wrappers dispatch to the canonical function
|
|
* with the arguments in the right slots.
|
|
*
|
|
* This file exercises both axes:
|
|
*
|
|
* - Compile-time: wc_static_assert checks every per-level size-constant
|
|
* spelling and every public-enum alias against the canonical value;
|
|
* typed function-pointer assignments (no casts) verify every
|
|
* symbol-form alias has the canonical signature; a never-called
|
|
* `if (0)` block invokes every arg-reordering macro with correctly
|
|
* typed dummy arguments so the compiler type-checks the expanded
|
|
* canonical call.
|
|
*
|
|
* - Runtime: a single make-key / sign / verify / export / import /
|
|
* DER round-trip drives the arg-reordering macros with valid inputs,
|
|
* so a same-type arg swap (which the compile-time invocation can't
|
|
* catch) shows up as a verification or import failure.
|
|
*
|
|
* Functional coverage of the canonical ML-DSA API itself lives in
|
|
* tests/api/test_mldsa.c (~24 test_mldsa_* functions),
|
|
* wolfcrypt/test/test.c::mldsa_test, and the TLS / X.509 paths in
|
|
* tests/api.c that exercise ML-DSA end-to-end; this file is solely a
|
|
* regression net for the shim. When WOLFSSL_NO_DILITHIUM_LEGACY_NAMES
|
|
* is defined every test below becomes a TEST_SKIPPED stub.
|
|
*
|
|
* Note on verify-only builds: the runtime smoke test below requires the
|
|
* sign side too (to produce a signature against a freshly-made key).
|
|
* In a verify-only build the compile-time invocation block still drives
|
|
* every verify-side shim macro through its arg-reordering expansion, so
|
|
* signature / arg-count regressions are caught at compile time even
|
|
* without a KAT-driven runtime verify. A same-type arg swap on the
|
|
* verify side specifically (e.g. swapping the two `const byte*` /
|
|
* `word32` pairs in `wc_dilithium_verify_ctx_msg`) would not be caught
|
|
* in a verify-only build by this file alone; the canonical KAT-driven
|
|
* tests in test_mldsa.c::test_mldsa_verify_*_kats cover that case in
|
|
* builds that include the canonical headers (which all in-tree builds
|
|
* do). */
|
|
|
|
#include <tests/unit.h>
|
|
|
|
#include <wolfssl/wolfcrypt/asn_public.h>
|
|
#ifdef WOLFSSL_HAVE_MLDSA
|
|
#include <wolfssl/wolfcrypt/dilithium.h>
|
|
#include <wolfssl/wolfcrypt/wc_mldsa.h>
|
|
#endif
|
|
#include <wolfssl/wolfcrypt/types.h>
|
|
#include <tests/api/api.h>
|
|
#include <tests/api/test_mldsa.h>
|
|
|
|
#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_NO_DILITHIUM_LEGACY_NAMES)
|
|
|
|
/* === Compile-time checks =============================================== */
|
|
|
|
/* Type aliases collapse to the canonical struct. A sizeof-equality check is
|
|
* a sufficient and portable proxy for "same type": both legacy spellings
|
|
* are typedefs of `struct wc_MlDsaKey`, so any divergence in the typedef
|
|
* chain would change sizeof and trip the assert at compile time. */
|
|
wc_static_assert(sizeof(dilithium_key) == sizeof(wc_MlDsaKey));
|
|
wc_static_assert(sizeof(MlDsaKey) == sizeof(wc_MlDsaKey));
|
|
wc_static_assert(sizeof(wc_dilithium_params) == sizeof(wc_MlDsaParams));
|
|
|
|
/* Per-parameter-set size constants. Every spelling family (LEVEL{2,3,5}_*,
|
|
* DILITHIUM_LEVEL{2,3,5}_*, DILITHIUM_ML_DSA_{44,65,87}_*) lives in its own
|
|
* `#define` line in <dilithium.h>, so each is checked separately. */
|
|
#define MLDSA_LEGACY_SIZE_ASSERT(LEGACY, CANONICAL) \
|
|
wc_static_assert((LEGACY) == (CANONICAL))
|
|
|
|
/* LEVEL2 = ML-DSA-44 */
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_KEY_SIZE, WC_MLDSA_44_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_PRV_KEY_SIZE, WC_MLDSA_44_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_PUB_KEY_SIZE, WC_MLDSA_44_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_SIG_SIZE, WC_MLDSA_44_SIG_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_PRV_KEY_DER_SIZE, WC_MLDSA_44_PRV_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_PUB_KEY_DER_SIZE, WC_MLDSA_44_PUB_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_BOTH_KEY_DER_SIZE, WC_MLDSA_44_BOTH_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL2_BOTH_KEY_PEM_SIZE, WC_MLDSA_44_BOTH_KEY_PEM_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_KEY_SIZE, WC_MLDSA_44_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_PRV_KEY_SIZE, WC_MLDSA_44_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_PUB_KEY_SIZE, WC_MLDSA_44_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_SIG_SIZE, WC_MLDSA_44_SIG_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_PRV_KEY_DER_SIZE,WC_MLDSA_44_PRV_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_PUB_KEY_DER_SIZE,WC_MLDSA_44_PUB_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_BOTH_KEY_DER_SIZE,WC_MLDSA_44_BOTH_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL2_BOTH_KEY_PEM_SIZE,WC_MLDSA_44_BOTH_KEY_PEM_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_44_KEY_SIZE, WC_MLDSA_44_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_44_PRV_KEY_SIZE, WC_MLDSA_44_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_44_PUB_KEY_SIZE, WC_MLDSA_44_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_44_SIG_SIZE, WC_MLDSA_44_SIG_SIZE);
|
|
|
|
/* LEVEL3 = ML-DSA-65 */
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_KEY_SIZE, WC_MLDSA_65_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_PRV_KEY_SIZE, WC_MLDSA_65_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_PUB_KEY_SIZE, WC_MLDSA_65_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_SIG_SIZE, WC_MLDSA_65_SIG_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_PRV_KEY_DER_SIZE, WC_MLDSA_65_PRV_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_PUB_KEY_DER_SIZE, WC_MLDSA_65_PUB_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_BOTH_KEY_DER_SIZE, WC_MLDSA_65_BOTH_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL3_BOTH_KEY_PEM_SIZE, WC_MLDSA_65_BOTH_KEY_PEM_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_KEY_SIZE, WC_MLDSA_65_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_PRV_KEY_SIZE, WC_MLDSA_65_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_PUB_KEY_SIZE, WC_MLDSA_65_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_SIG_SIZE, WC_MLDSA_65_SIG_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_PRV_KEY_DER_SIZE,WC_MLDSA_65_PRV_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_PUB_KEY_DER_SIZE,WC_MLDSA_65_PUB_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_BOTH_KEY_DER_SIZE,WC_MLDSA_65_BOTH_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL3_BOTH_KEY_PEM_SIZE,WC_MLDSA_65_BOTH_KEY_PEM_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_65_KEY_SIZE, WC_MLDSA_65_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_65_PRV_KEY_SIZE, WC_MLDSA_65_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_65_PUB_KEY_SIZE, WC_MLDSA_65_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_65_SIG_SIZE, WC_MLDSA_65_SIG_SIZE);
|
|
|
|
/* LEVEL5 = ML-DSA-87 */
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_KEY_SIZE, WC_MLDSA_87_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_PRV_KEY_SIZE, WC_MLDSA_87_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_PUB_KEY_SIZE, WC_MLDSA_87_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_SIG_SIZE, WC_MLDSA_87_SIG_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_PRV_KEY_DER_SIZE, WC_MLDSA_87_PRV_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_PUB_KEY_DER_SIZE, WC_MLDSA_87_PUB_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_BOTH_KEY_DER_SIZE, WC_MLDSA_87_BOTH_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(ML_DSA_LEVEL5_BOTH_KEY_PEM_SIZE, WC_MLDSA_87_BOTH_KEY_PEM_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_KEY_SIZE, WC_MLDSA_87_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_PRV_KEY_SIZE, WC_MLDSA_87_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_PUB_KEY_SIZE, WC_MLDSA_87_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_SIG_SIZE, WC_MLDSA_87_SIG_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_PRV_KEY_DER_SIZE,WC_MLDSA_87_PRV_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_PUB_KEY_DER_SIZE,WC_MLDSA_87_PUB_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_BOTH_KEY_DER_SIZE,WC_MLDSA_87_BOTH_KEY_DER_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_LEVEL5_BOTH_KEY_PEM_SIZE,WC_MLDSA_87_BOTH_KEY_PEM_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_87_KEY_SIZE, WC_MLDSA_87_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_87_PRV_KEY_SIZE, WC_MLDSA_87_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_87_PUB_KEY_SIZE, WC_MLDSA_87_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_ML_DSA_87_SIG_SIZE, WC_MLDSA_87_SIG_SIZE);
|
|
|
|
/* Maxima (used as stack/heap sizing on the call sites). */
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_MAX_KEY_SIZE, MLDSA_MAX_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_MAX_PRV_KEY_SIZE, MLDSA_MAX_PRV_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_MAX_PUB_KEY_SIZE, MLDSA_MAX_PUB_KEY_SIZE);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_MAX_SIG_SIZE, MLDSA_MAX_SIG_SIZE);
|
|
|
|
/* FIPS 204 algorithm-parameter constants -- spot-check the families that
|
|
* exist as both DILITHIUM_* and MLDSA_* spellings. */
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_Q, MLDSA_Q);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_N, MLDSA_N);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_SEED_SZ, MLDSA_SEED_SZ);
|
|
MLDSA_LEGACY_SIZE_ASSERT(DILITHIUM_TR_SZ, MLDSA_TR_SZ);
|
|
|
|
#undef MLDSA_LEGACY_SIZE_ASSERT
|
|
|
|
/* Public-enum aliases (asn_public.h / asn.h / oid_sum.h). These are
|
|
* #define aliases for FIPS 204 enumerators that were renamed in this
|
|
* PR; the legacy LEVEL{2,3,5} spellings live behind the same
|
|
* WOLFSSL_NO_DILITHIUM_LEGACY_NAMES gate as the dilithium.h shim. Casts
|
|
* are deliberately omitted: enum constants are integer constant
|
|
* expressions in C, and a hidden enum-width divergence is itself a
|
|
* regression worth surfacing. */
|
|
wc_static_assert(ML_DSA_LEVEL2_TYPE == ML_DSA_44_TYPE);
|
|
wc_static_assert(ML_DSA_LEVEL3_TYPE == ML_DSA_65_TYPE);
|
|
wc_static_assert(ML_DSA_LEVEL5_TYPE == ML_DSA_87_TYPE);
|
|
#ifdef WOLFSSL_CERT_GEN
|
|
wc_static_assert(ML_DSA_LEVEL2_KEY == ML_DSA_44_KEY);
|
|
wc_static_assert(ML_DSA_LEVEL3_KEY == ML_DSA_65_KEY);
|
|
wc_static_assert(ML_DSA_LEVEL5_KEY == ML_DSA_87_KEY);
|
|
#endif
|
|
wc_static_assert(ML_DSA_LEVEL2k == ML_DSA_44k);
|
|
wc_static_assert(ML_DSA_LEVEL3k == ML_DSA_65k);
|
|
wc_static_assert(ML_DSA_LEVEL5k == ML_DSA_87k);
|
|
wc_static_assert(CTC_ML_DSA_LEVEL2 == CTC_ML_DSA_44);
|
|
wc_static_assert(CTC_ML_DSA_LEVEL3 == CTC_ML_DSA_65);
|
|
wc_static_assert(CTC_ML_DSA_LEVEL5 == CTC_ML_DSA_87);
|
|
|
|
/* Error-code rename: the symbol stays at the same numeric value, and the
|
|
* legacy spelling is a #define for the canonical enumerator. */
|
|
wc_static_assert(WC_NO_ERR_TRACE(DILITHIUM_KEY_SIZE_E) ==
|
|
WC_NO_ERR_TRACE(MLDSA_KEY_SIZE_E));
|
|
|
|
/* Function-symbol aliases. Each entry below is a #define legacy canonical
|
|
* (a pure symbol redirect, no arg reordering). Assigning to a typed
|
|
* function pointer **without a cast** is the actual check: the compiler
|
|
* fails the build if the alias's signature drifts from the typedef. The
|
|
* casts are deliberately absent -- adding them would silently coerce
|
|
* signature mismatches and defeat the purpose. */
|
|
static void mldsa_legacy_shim_symbol_aliases_compile_check(void)
|
|
{
|
|
typedef int (*size_fn)(wc_MlDsaKey*);
|
|
typedef int (*check_fn)(wc_MlDsaKey*);
|
|
typedef int (*export_fn)(wc_MlDsaKey*, byte*, word32*);
|
|
|
|
#ifdef WOLFSSL_MLDSA_PRIVATE_KEY
|
|
{
|
|
size_fn f_size = &wc_dilithium_size;
|
|
export_fn f_export_priv = &wc_dilithium_export_private;
|
|
(void)f_size; (void)f_export_priv;
|
|
#ifdef WOLFSSL_MLDSA_PUBLIC_KEY
|
|
{
|
|
size_fn f_priv_size = &wc_dilithium_priv_size;
|
|
(void)f_priv_size;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_MLDSA_PUBLIC_KEY
|
|
{
|
|
size_fn f_pub_size = &wc_dilithium_pub_size;
|
|
export_fn f_export_pub = &wc_dilithium_export_public;
|
|
(void)f_pub_size; (void)f_export_pub;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_MLDSA_CHECK_KEY
|
|
{
|
|
check_fn f_check = &wc_dilithium_check_key;
|
|
(void)f_check;
|
|
}
|
|
#else
|
|
(void)((check_fn)NULL);
|
|
#endif
|
|
|
|
#ifdef WOLF_PRIVATE_KEY_ID
|
|
{
|
|
typedef int (*init_id_fn)(wc_MlDsaKey*, const unsigned char*, int,
|
|
void*, int);
|
|
typedef int (*init_label_fn)(wc_MlDsaKey*, const char*, void*, int);
|
|
init_id_fn f_init_id = &wc_dilithium_init_id;
|
|
init_label_fn f_init_label = &wc_dilithium_init_label;
|
|
(void)f_init_id; (void)f_init_label;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_MLDSA_NO_ASN1)
|
|
{
|
|
#ifdef WC_ENABLE_ASYM_KEY_EXPORT
|
|
{
|
|
typedef int (*to_der_fn)(wc_MlDsaKey*, byte*, word32, int);
|
|
to_der_fn f_pub_to_der = &wc_Dilithium_PublicKeyToDer;
|
|
(void)f_pub_to_der;
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_MLDSA_PRIVATE_KEY
|
|
{
|
|
typedef int (*to_der_priv_fn)(wc_MlDsaKey*, byte*, word32);
|
|
to_der_priv_fn f_priv_to_der = &wc_Dilithium_PrivateKeyToDer;
|
|
to_der_priv_fn f_key_to_der = &wc_Dilithium_KeyToDer;
|
|
(void)f_priv_to_der; (void)f_key_to_der;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Compile-time invocation of every arg-reordering shim macro. The macros
|
|
* are function-like #defines, so they can only be checked by expansion at
|
|
* a call site. The block below is guarded by `if (0)` so it never runs at
|
|
* runtime -- the compiler still parses and type-checks every macro
|
|
* expansion, so a signature regression or arg-count change in the shim
|
|
* trips a build error here even in configurations (e.g. verify-only)
|
|
* where the happy-path runtime test below is skipped.
|
|
*
|
|
* Limitation: a same-type arg swap inside a shim macro (e.g. swapping the
|
|
* two `const byte*` operands in `wc_dilithium_verify_msg`) compiles
|
|
* cleanly here and is caught only by the runtime smoke test, which
|
|
* requires sign+verify. */
|
|
static void mldsa_legacy_shim_macro_invocations_compile_check(void)
|
|
{
|
|
wc_MlDsaKey* key = NULL;
|
|
const byte* inp = NULL;
|
|
byte* outp = NULL;
|
|
word32 inLen = 0;
|
|
word32 outLen = 0;
|
|
word32 idx = 0;
|
|
int res = 0;
|
|
WC_RNG* rng = NULL;
|
|
const byte* seed = NULL;
|
|
|
|
/* The bodies are dead code (`if (0)`), but the macro expansions are
|
|
* still parsed and type-checked. Return values are discarded with a
|
|
* cast to `(void)`. */
|
|
if (0) {
|
|
#ifdef WOLFSSL_MLDSA_PUBLIC_KEY
|
|
(void)wc_dilithium_import_public(inp, inLen, key);
|
|
#endif
|
|
#ifdef WOLFSSL_MLDSA_PRIVATE_KEY
|
|
(void)wc_dilithium_import_private(inp, inLen, key);
|
|
(void)wc_dilithium_import_private_only(inp, inLen, key);
|
|
(void)wc_dilithium_import_key(inp, inLen, inp, inLen, key);
|
|
#endif
|
|
#ifndef WOLFSSL_MLDSA_VERIFY_ONLY
|
|
#ifdef WOLFSSL_MLDSA_NO_CTX
|
|
(void)wc_dilithium_sign_msg(inp, inLen, outp, &outLen, key, rng);
|
|
(void)wc_dilithium_sign_msg_with_seed(inp, inLen, outp, &outLen,
|
|
key, seed);
|
|
#endif
|
|
(void)wc_dilithium_sign_ctx_msg(inp, (byte)0, inp, inLen,
|
|
outp, &outLen, key, rng);
|
|
(void)wc_dilithium_sign_ctx_hash(inp, (byte)0, 0, inp, inLen,
|
|
outp, &outLen, key, rng);
|
|
(void)wc_dilithium_sign_ctx_msg_with_seed(inp, (byte)0, inp, inLen,
|
|
outp, &outLen, key, seed);
|
|
(void)wc_dilithium_sign_ctx_hash_with_seed(inp, (byte)0, 0, inp,
|
|
inLen, outp, &outLen, key, seed);
|
|
(void)wc_dilithium_sign_mu_with_seed(inp, inLen, outp, &outLen,
|
|
key, seed);
|
|
#endif
|
|
#ifdef WOLFSSL_MLDSA_NO_CTX
|
|
(void)wc_dilithium_verify_msg(inp, inLen, inp, inLen, &res, key);
|
|
#endif
|
|
(void)wc_dilithium_verify_ctx_msg(inp, inLen, inp, (byte)0, inp,
|
|
inLen, &res, key);
|
|
(void)wc_dilithium_verify_ctx_hash(inp, inLen, inp, (byte)0, 0, inp,
|
|
inLen, &res, key);
|
|
(void)wc_dilithium_verify_mu(inp, inLen, inp, inLen, &res, key);
|
|
#if !defined(WOLFSSL_MLDSA_NO_ASN1)
|
|
#ifdef WOLFSSL_MLDSA_PRIVATE_KEY
|
|
(void)wc_Dilithium_PrivateKeyDecode(inp, &idx, key, inLen);
|
|
#endif
|
|
#ifdef WOLFSSL_MLDSA_PUBLIC_KEY
|
|
(void)wc_Dilithium_PublicKeyDecode(inp, &idx, key, inLen);
|
|
#endif
|
|
#endif
|
|
/* 1-arg init shim. */
|
|
(void)wc_dilithium_init(key);
|
|
}
|
|
(void)key; (void)inp; (void)outp; (void)inLen; (void)outLen;
|
|
(void)idx; (void)res; (void)rng; (void)seed;
|
|
}
|
|
|
|
/* === Runtime checks ==================================================== */
|
|
|
|
/* Smoke test exercising the arg-reordering macros that are reachable
|
|
* end-to-end via a make-key / sign / verify / export / import / decode
|
|
* happy-path. A same-type arg swap inside any of these macros shows up as
|
|
* a verification or import failure here.
|
|
*
|
|
* Verify-only / sign-only / no-ASN1 builds skip the corresponding
|
|
* sub-blocks; the compile-time invocation check above still type-checks
|
|
* every shim macro in those configurations. */
|
|
int test_mldsa_legacy_shim(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
/* Reference the compile-only checks so the compiler doesn't drop them
|
|
* (and so -Wunused-function stays quiet under strict warning levels).
|
|
* These are no-ops at runtime; the work is in the parse/type-check
|
|
* the compiler did on the file. */
|
|
(void)&mldsa_legacy_shim_symbol_aliases_compile_check;
|
|
(void)&mldsa_legacy_shim_macro_invocations_compile_check;
|
|
|
|
#if !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \
|
|
!defined(WOLFSSL_MLDSA_NO_VERIFY) && !defined(WOLFSSL_NO_ML_DSA_44) && \
|
|
defined(WOLFSSL_MLDSA_PUBLIC_KEY) && defined(WOLFSSL_MLDSA_PRIVATE_KEY) && \
|
|
!defined(WC_NO_RNG)
|
|
{
|
|
dilithium_key key; /* legacy typedef */
|
|
WC_RNG rng;
|
|
byte level = 0;
|
|
byte pubBuf[WC_MLDSA_44_PUB_KEY_SIZE];
|
|
byte privBuf[WC_MLDSA_44_KEY_SIZE];
|
|
word32 pubLen = (word32)sizeof(pubBuf);
|
|
word32 privLen = (word32)sizeof(privBuf);
|
|
static const byte msg[] = "wolfSSL ML-DSA legacy shim smoke test";
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
|
|
/* 1-arg shim macro -> wc_MlDsaKey_Init(key, NULL, INVALID_DEVID). */
|
|
ExpectIntEQ(wc_dilithium_init(&key), 0);
|
|
ExpectIntEQ(wc_dilithium_set_level(&key, WC_ML_DSA_44), 0);
|
|
ExpectIntEQ(wc_dilithium_get_level(&key, &level), 0);
|
|
ExpectIntEQ((int)level, WC_ML_DSA_44);
|
|
|
|
/* Sizes -- pure symbol aliases. PrivSize is the export size of the
|
|
* "private key" form (priv + pub combined), not the raw secret-key
|
|
* buffer. */
|
|
ExpectIntEQ(wc_dilithium_priv_size(&key), WC_MLDSA_44_PRV_KEY_SIZE);
|
|
ExpectIntEQ(wc_dilithium_pub_size(&key), WC_MLDSA_44_PUB_KEY_SIZE);
|
|
ExpectIntEQ(wc_dilithium_sig_size(&key), WC_MLDSA_44_SIG_SIZE);
|
|
|
|
PRIVATE_KEY_UNLOCK();
|
|
ExpectIntEQ(wc_dilithium_make_key(&key, &rng), 0);
|
|
PRIVATE_KEY_LOCK();
|
|
|
|
#ifdef WOLFSSL_MLDSA_CHECK_KEY
|
|
ExpectIntEQ(wc_dilithium_check_key(&key), 0);
|
|
#endif
|
|
|
|
/* Sign + verify drive the arg-reordering sign/verify shim macros
|
|
* with a real signature; a same-type arg swap shows up as a
|
|
* verification failure. */
|
|
#ifdef WOLFSSL_MLDSA_NO_CTX
|
|
{
|
|
byte sig[WC_MLDSA_44_SIG_SIZE];
|
|
word32 sigLen = (word32)sizeof(sig);
|
|
int verifyRes = 0;
|
|
|
|
ExpectIntEQ(wc_dilithium_sign_msg(msg, (word32)sizeof(msg),
|
|
sig, &sigLen, &key, &rng), 0);
|
|
ExpectIntEQ(wc_dilithium_verify_msg(sig, sigLen,
|
|
msg, (word32)sizeof(msg), &verifyRes, &key), 0);
|
|
ExpectIntEQ(verifyRes, 1);
|
|
}
|
|
#else
|
|
{
|
|
byte sig[WC_MLDSA_44_SIG_SIZE];
|
|
word32 sigLen = (word32)sizeof(sig);
|
|
int verifyRes = 0;
|
|
|
|
ExpectIntEQ(wc_dilithium_sign_ctx_msg(NULL, 0,
|
|
msg, (word32)sizeof(msg), sig, &sigLen, &key, &rng), 0);
|
|
ExpectIntEQ(wc_dilithium_verify_ctx_msg(sig, sigLen, NULL, 0,
|
|
msg, (word32)sizeof(msg), &verifyRes, &key), 0);
|
|
ExpectIntEQ(verifyRes, 1);
|
|
}
|
|
#endif
|
|
|
|
/* Export raw key material and re-import via the legacy arg order. */
|
|
ExpectIntEQ(wc_dilithium_export_public(&key, pubBuf, &pubLen), 0);
|
|
ExpectIntEQ((int)pubLen, WC_MLDSA_44_PUB_KEY_SIZE);
|
|
ExpectIntEQ(wc_dilithium_export_private(&key, privBuf, &privLen), 0);
|
|
ExpectIntEQ((int)privLen, WC_MLDSA_44_KEY_SIZE);
|
|
|
|
{
|
|
dilithium_key imported;
|
|
XMEMSET(&imported, 0, sizeof(imported));
|
|
ExpectIntEQ(wc_dilithium_init(&imported), 0);
|
|
ExpectIntEQ(wc_dilithium_set_level(&imported, WC_ML_DSA_44), 0);
|
|
ExpectIntEQ(wc_dilithium_import_public(pubBuf, pubLen, &imported),
|
|
0);
|
|
ExpectIntEQ(wc_dilithium_import_private(privBuf, privLen,
|
|
&imported), 0);
|
|
wc_dilithium_free(&imported);
|
|
}
|
|
|
|
/* ASN.1 round-trip through the legacy Decode wrapper (arg order:
|
|
* input, inOutIdx, key, inSz). */
|
|
#if !defined(WOLFSSL_MLDSA_NO_ASN1)
|
|
{
|
|
byte der[MLDSA_MAX_PRV_KEY_DER_SIZE];
|
|
int derSz;
|
|
word32 idx = 0;
|
|
dilithium_key decoded;
|
|
|
|
XMEMSET(&decoded, 0, sizeof(decoded));
|
|
derSz = wc_Dilithium_PrivateKeyToDer(&key, der,
|
|
(word32)sizeof(der));
|
|
ExpectIntGT(derSz, 0);
|
|
|
|
ExpectIntEQ(wc_dilithium_init(&decoded), 0);
|
|
ExpectIntEQ(wc_dilithium_set_level(&decoded, WC_ML_DSA_44), 0);
|
|
PRIVATE_KEY_UNLOCK();
|
|
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &idx, &decoded,
|
|
(word32)derSz), 0);
|
|
PRIVATE_KEY_LOCK();
|
|
wc_dilithium_free(&decoded);
|
|
}
|
|
#endif
|
|
|
|
wc_dilithium_free(&key);
|
|
wc_FreeRng(&rng);
|
|
}
|
|
#endif /* sign+verify happy-path */
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#else /* !WOLFSSL_HAVE_MLDSA || WOLFSSL_NO_DILITHIUM_LEGACY_NAMES */
|
|
|
|
int test_mldsa_legacy_shim(void)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
#endif
|