@@ -686,6 +686,84 @@ int test_wc_dilithium(void)
686686 return EXPECT_RESULT();
687687}
688688
689+ /*
690+ * Test that wc_dilithium_sign_msg() rejects a public-key-only key object.
691+ * A key with prvKeySet=0 must not silently sign with zeroed key data.
692+ */
693+ int test_wc_dilithium_sign_pubonly_fails(void)
694+ {
695+ EXPECT_DECLS;
696+ #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
697+ #if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \
698+ !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
699+ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
700+ !defined(WOLFSSL_DILITHIUM_NO_CTX)
701+ dilithium_key* key;
702+ dilithium_key* pubOnlyKey;
703+ WC_RNG rng;
704+ byte* pubBuf = NULL;
705+ word32 pubLen = DILITHIUM_MAX_PUB_KEY_SIZE;
706+ byte msg[] = "test message for pubonly check";
707+ byte* sig = NULL;
708+ word32 sigLen = DILITHIUM_MAX_SIG_SIZE;
709+
710+ key = (dilithium_key*)XMALLOC(sizeof(*key), NULL,
711+ DYNAMIC_TYPE_TMP_BUFFER);
712+ ExpectNotNull(key);
713+ pubOnlyKey = (dilithium_key*)XMALLOC(sizeof(*pubOnlyKey), NULL,
714+ DYNAMIC_TYPE_TMP_BUFFER);
715+ ExpectNotNull(pubOnlyKey);
716+ pubBuf = (byte*)XMALLOC(DILITHIUM_MAX_PUB_KEY_SIZE, NULL,
717+ DYNAMIC_TYPE_TMP_BUFFER);
718+ ExpectNotNull(pubBuf);
719+ sig = (byte*)XMALLOC(DILITHIUM_MAX_SIG_SIZE, NULL,
720+ DYNAMIC_TYPE_TMP_BUFFER);
721+ ExpectNotNull(sig);
722+
723+ if (key != NULL)
724+ XMEMSET(key, 0, sizeof(*key));
725+ if (pubOnlyKey != NULL)
726+ XMEMSET(pubOnlyKey, 0, sizeof(*pubOnlyKey));
727+ XMEMSET(&rng, 0, sizeof(rng));
728+
729+ ExpectIntEQ(wc_InitRng(&rng), 0);
730+ ExpectIntEQ(wc_dilithium_init(key), 0);
731+ ExpectIntEQ(wc_dilithium_init(pubOnlyKey), 0);
732+
733+ #ifndef WOLFSSL_NO_ML_DSA_44
734+ ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0);
735+ ExpectIntEQ(wc_dilithium_set_level(pubOnlyKey, WC_ML_DSA_44), 0);
736+ #elif !defined(WOLFSSL_NO_ML_DSA_65)
737+ ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_65), 0);
738+ ExpectIntEQ(wc_dilithium_set_level(pubOnlyKey, WC_ML_DSA_65), 0);
739+ #else
740+ ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_87), 0);
741+ ExpectIntEQ(wc_dilithium_set_level(pubOnlyKey, WC_ML_DSA_87), 0);
742+ #endif
743+
744+ /* Generate a real key pair and export its public key. */
745+ ExpectIntEQ(wc_dilithium_make_key(key, &rng), 0);
746+ ExpectIntEQ(wc_dilithium_export_public(key, pubBuf, &pubLen), 0);
747+
748+ /* Import only the public key into a fresh key object. */
749+ ExpectIntEQ(wc_dilithium_import_public(pubBuf, pubLen, pubOnlyKey), 0);
750+
751+ /* Signing with a public-key-only object must fail. */
752+ ExpectIntEQ(wc_dilithium_sign_ctx_msg(NULL, 0, msg, sizeof(msg), sig,
753+ &sigLen, pubOnlyKey, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
754+
755+ DoExpectIntEQ(wc_FreeRng(&rng), 0);
756+ wc_dilithium_free(pubOnlyKey);
757+ wc_dilithium_free(key);
758+ XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
759+ XFREE(pubBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
760+ XFREE(pubOnlyKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
761+ XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
762+ #endif
763+ #endif
764+ return EXPECT_RESULT();
765+ } /* END test_wc_dilithium_sign_pubonly_fails */
766+
689767int test_wc_dilithium_make_key(void)
690768{
691769 EXPECT_DECLS;
0 commit comments