xref: /freebsd/crypto/openssl/test/ml_dsa_test.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <openssl/core_names.h>
11 #include <openssl/evp.h>
12 #include "internal/nelem.h"
13 #include "testutil.h"
14 #include "ml_dsa.inc"
15 #include "crypto/ml_dsa.h"
16 
17 typedef enum OPTION_choice {
18     OPT_ERR = -1,
19     OPT_EOF = 0,
20     OPT_CONFIG_FILE,
21     OPT_TEST_ENUM
22 } OPTION_CHOICE;
23 
24 static OSSL_LIB_CTX *lib_ctx = NULL;
25 static OSSL_PROVIDER *null_prov = NULL;
26 static OSSL_PROVIDER *lib_prov = NULL;
27 
do_gen_key(const char * alg,const uint8_t * seed,size_t seed_len)28 static EVP_PKEY *do_gen_key(const char *alg,
29     const uint8_t *seed, size_t seed_len)
30 {
31     EVP_PKEY *pkey = NULL;
32     EVP_PKEY_CTX *ctx = NULL;
33     OSSL_PARAM params[3], *p = params;
34 
35     if (seed_len != 0)
36         *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_ML_DSA_SEED,
37             (char *)seed, seed_len);
38     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_PROPERTIES,
39         "?fips=yes", 0);
40     *p = OSSL_PARAM_construct_end();
41 
42     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(lib_ctx, alg, NULL))
43         || !TEST_int_eq(EVP_PKEY_keygen_init(ctx), 1)
44         || !TEST_int_eq(EVP_PKEY_CTX_set_params(ctx, params), 1)
45         || !TEST_int_eq(EVP_PKEY_generate(ctx, &pkey), 1))
46         pkey = NULL;
47 
48     EVP_PKEY_CTX_free(ctx);
49     return pkey;
50 }
51 
ml_dsa_create_keypair(EVP_PKEY ** pkey,const char * name,const uint8_t * priv,size_t priv_len,const uint8_t * pub,size_t pub_len,int expected)52 static int ml_dsa_create_keypair(EVP_PKEY **pkey, const char *name,
53     const uint8_t *priv, size_t priv_len,
54     const uint8_t *pub, size_t pub_len,
55     int expected)
56 {
57     int ret = 0, selection = 0;
58     EVP_PKEY_CTX *ctx = NULL;
59     OSSL_PARAM params[3], *p = params;
60 
61     if (priv != NULL) {
62         *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PRIV_KEY,
63             (uint8_t *)priv, priv_len);
64         selection = OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
65     }
66     if (pub != NULL) {
67         *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
68             (uint8_t *)pub, pub_len);
69         selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
70     }
71     *p = OSSL_PARAM_construct_end();
72 
73     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(lib_ctx, name, NULL))
74         || !TEST_int_eq(EVP_PKEY_fromdata_init(ctx), 1)
75         || !TEST_int_eq(EVP_PKEY_fromdata(ctx, pkey, selection,
76                             params),
77             expected))
78         goto err;
79 
80     ret = 1;
81 err:
82     EVP_PKEY_CTX_free(ctx);
83     return ret;
84 }
85 
ml_dsa_keygen_test(int tst_id)86 static int ml_dsa_keygen_test(int tst_id)
87 {
88     int ret = 0;
89     const ML_DSA_KEYGEN_TEST_DATA *tst = &ml_dsa_keygen_testdata[tst_id];
90     EVP_PKEY *pkey = NULL;
91     uint8_t priv[5 * 1024], pub[3 * 1024], seed[ML_DSA_SEED_BYTES];
92     size_t priv_len, pub_len, seed_len;
93     int bits = 0, sec_bits = 0, sig_len = 0;
94 
95     if (!TEST_ptr(pkey = do_gen_key(tst->name, tst->seed, tst->seed_len))
96         || !TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ML_DSA_SEED,
97             seed, sizeof(seed), &seed_len))
98         || !TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
99             priv, sizeof(priv), &priv_len))
100         || !TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
101             pub, sizeof(pub), &pub_len))
102         || !TEST_mem_eq(pub, pub_len, tst->pub, tst->pub_len)
103         || !TEST_mem_eq(priv, priv_len, tst->priv, tst->priv_len)
104         || !TEST_mem_eq(seed, seed_len, tst->seed, tst->seed_len)
105         /* The following checks assume that algorithm is ML-DSA-65 */
106         || !TEST_true(EVP_PKEY_get_int_param(pkey, OSSL_PKEY_PARAM_BITS, &bits))
107         || !TEST_int_eq(bits, 1952 * 8)
108         || !TEST_true(EVP_PKEY_get_int_param(pkey, OSSL_PKEY_PARAM_SECURITY_BITS,
109             &sec_bits))
110         || !TEST_int_eq(sec_bits, 192)
111         || !TEST_true(EVP_PKEY_get_int_param(pkey, OSSL_PKEY_PARAM_MAX_SIZE,
112             &sig_len))
113         || !TEST_int_ge(sig_len, 3309))
114         goto err;
115     ret = 1;
116 err:
117     EVP_PKEY_free(pkey);
118     return ret;
119 }
120 
ml_dsa_siggen_test(int tst_id)121 static int ml_dsa_siggen_test(int tst_id)
122 {
123     int ret = 0;
124     const ML_DSA_SIG_GEN_TEST_DATA *td = &ml_dsa_siggen_testdata[tst_id];
125     EVP_PKEY_CTX *sctx = NULL;
126     EVP_PKEY *pkey = NULL;
127     EVP_SIGNATURE *sig_alg = NULL;
128     OSSL_PARAM params[4], *p = params;
129     uint8_t *psig = NULL;
130     size_t psig_len = 0, sig_len2 = 0;
131     uint8_t digest[32];
132     size_t digest_len = sizeof(digest);
133     int encode = 0, deterministic = 1;
134 
135     *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, &deterministic);
136     *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode);
137     if (td->add_random != NULL)
138         *p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY,
139             (char *)td->add_random,
140             td->add_random_len);
141     *p = OSSL_PARAM_construct_end();
142 
143     /*
144      * This just uses from data here, but keygen also works.
145      * The keygen path is tested via ml_dsa_keygen_test
146      */
147     if (!TEST_true(ml_dsa_create_keypair(&pkey, td->alg, td->priv, td->priv_len,
148             NULL, 0, 1))
149         || !TEST_ptr(sctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pkey, NULL))
150         || !TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, td->alg, NULL))
151         || !TEST_int_eq(EVP_PKEY_sign_message_init(sctx, sig_alg, params), 1)
152         || !TEST_int_eq(EVP_PKEY_sign(sctx, NULL, &psig_len,
153                             td->msg, td->msg_len),
154             1)
155         || !TEST_true(EVP_PKEY_get_size_t_param(pkey, OSSL_PKEY_PARAM_MAX_SIZE,
156             &sig_len2))
157         || !TEST_int_eq(sig_len2, psig_len)
158         || !TEST_ptr(psig = OPENSSL_zalloc(psig_len))
159         || !TEST_int_eq(EVP_PKEY_sign(sctx, psig, &psig_len,
160                             td->msg, td->msg_len),
161             1)
162         || !TEST_int_eq(EVP_Q_digest(lib_ctx, "SHA256", NULL, psig, psig_len,
163                             digest, &digest_len),
164             1)
165         || !TEST_mem_eq(digest, digest_len, td->sig_digest, td->sig_digest_len))
166         goto err;
167     ret = 1;
168 err:
169     EVP_SIGNATURE_free(sig_alg);
170     EVP_PKEY_free(pkey);
171     EVP_PKEY_CTX_free(sctx);
172     OPENSSL_free(psig);
173     return ret;
174 }
175 
ml_dsa_sigver_test(int tst_id)176 static int ml_dsa_sigver_test(int tst_id)
177 {
178     int ret = 0;
179     const ML_DSA_SIG_VER_TEST_DATA *td = &ml_dsa_sigver_testdata[tst_id];
180     EVP_PKEY_CTX *vctx = NULL;
181     EVP_PKEY *pkey = NULL;
182     EVP_SIGNATURE *sig_alg = NULL;
183     OSSL_PARAM params[2], *p = params;
184     int encode = 0;
185 
186     *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode);
187     *p = OSSL_PARAM_construct_end();
188 
189     if (!TEST_true(ml_dsa_create_keypair(&pkey, td->alg, NULL, 0,
190             td->pub, td->pub_len, 1)))
191         goto err;
192 
193     if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pkey, NULL)))
194         goto err;
195     if (!TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, td->alg, NULL)))
196         goto err;
197     if (!TEST_int_eq(EVP_PKEY_verify_message_init(vctx, sig_alg, params), 1)
198         || !TEST_int_eq(EVP_PKEY_verify(vctx, td->sig, td->sig_len,
199                             td->msg, td->msg_len),
200             td->expected))
201         goto err;
202     ret = 1;
203 err:
204     EVP_SIGNATURE_free(sig_alg);
205     EVP_PKEY_free(pkey);
206     EVP_PKEY_CTX_free(vctx);
207     return ret;
208 }
209 
ml_dsa_key_dup_test(void)210 static int ml_dsa_key_dup_test(void)
211 {
212     int ret = 0;
213     const ML_DSA_KEYGEN_TEST_DATA *tst = &ml_dsa_keygen_testdata[0];
214     EVP_PKEY *pkey = NULL, *pkey_copy = NULL;
215     EVP_PKEY_CTX *ctx = NULL;
216 
217     if (!TEST_ptr(pkey = do_gen_key(tst->name, tst->seed, tst->seed_len))
218         || !TEST_ptr(pkey_copy = EVP_PKEY_dup(pkey))
219         || !TEST_int_eq(EVP_PKEY_eq(pkey, pkey_copy), 1)
220         || !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pkey_copy, NULL))
221         || !TEST_int_eq(EVP_PKEY_check(ctx), 1))
222         goto err;
223     ret = 1;
224 err:
225     EVP_PKEY_free(pkey);
226     EVP_PKEY_free(pkey_copy);
227     EVP_PKEY_CTX_free(ctx);
228     return ret;
229 }
230 
ml_dsa_key_internal_test(void)231 static int ml_dsa_key_internal_test(void)
232 {
233     int ret = 0;
234     ML_DSA_KEY *key = NULL, *key1 = NULL;
235 
236     /* check passing NULL is ok */
237     ossl_ml_dsa_key_free(NULL);
238 
239     /* We should fail to fetch and fail here if the libctx is not set */
240     if (!TEST_ptr_null(key = ossl_ml_dsa_key_new(NULL, NULL, EVP_PKEY_ML_DSA_44))
241         /* fail if the algorithm is invalid */
242         || !TEST_ptr_null(key = ossl_ml_dsa_key_new(lib_ctx, "", NID_undef))
243         /* Dup should fail if the src is NULL */
244         || !TEST_ptr_null(key1 = ossl_ml_dsa_key_dup(NULL, OSSL_KEYMGMT_SELECT_KEYPAIR))
245         || !TEST_ptr(key = ossl_ml_dsa_key_new(lib_ctx, "?fips=yes",
246                          EVP_PKEY_ML_DSA_44))
247         || !TEST_ptr(key1 = ossl_ml_dsa_key_dup(key, OSSL_KEYMGMT_SELECT_KEYPAIR))
248         || !TEST_true(ossl_ml_dsa_key_pub_alloc(key1))
249         || !TEST_false(ossl_ml_dsa_key_pub_alloc(key1))
250         || !TEST_true(ossl_ml_dsa_key_priv_alloc(key))
251         || !TEST_false(ossl_ml_dsa_key_priv_alloc(key)))
252         goto err;
253 
254     ret = 1;
255 err:
256     ossl_ml_dsa_key_free(key1);
257     ossl_ml_dsa_key_free(key);
258     return ret;
259 }
260 
from_data_invalid_public_test(void)261 static int from_data_invalid_public_test(void)
262 {
263     int ret = 0;
264     const ML_DSA_KEYGEN_TEST_DATA *tst = &ml_dsa_keygen_testdata[0];
265     uint8_t *pub = NULL;
266     EVP_PKEY *pkey = NULL;
267 
268     /* corrupt the public key */
269     if (!TEST_ptr(pub = OPENSSL_memdup(tst->pub, tst->pub_len)))
270         goto err;
271     pub[0] ^= 1;
272 
273     if (!TEST_true(ml_dsa_create_keypair(&pkey, tst->name, tst->priv, tst->priv_len,
274             tst->pub, tst->pub_len, 1))
275         || !TEST_true(ml_dsa_create_keypair(&pkey, tst->name, tst->priv, tst->priv_len,
276             pub, tst->pub_len, 0))
277         || !TEST_true(ml_dsa_create_keypair(&pkey, tst->name, tst->priv, tst->priv_len,
278             tst->pub, tst->pub_len - 1, 0))
279         || !TEST_true(ml_dsa_create_keypair(&pkey, tst->name, tst->priv, tst->priv_len,
280             tst->pub, tst->pub_len + 1, 0))
281         || !TEST_true(ml_dsa_create_keypair(&pkey, tst->name, tst->priv, tst->priv_len - 1,
282             tst->pub, tst->pub_len, 0))
283         || !TEST_true(ml_dsa_create_keypair(&pkey, tst->name, tst->priv, tst->priv_len + 1,
284             tst->pub, tst->pub_len, 0)))
285         goto err;
286 
287     ret = 1;
288 err:
289     OPENSSL_free(pub);
290     EVP_PKEY_free(pkey);
291     return ret;
292 }
293 
from_data_bad_input_test(void)294 static int from_data_bad_input_test(void)
295 {
296     int ret = 0;
297     EVP_PKEY_CTX *ctx = NULL;
298     OSSL_PARAM params[2];
299     EVP_PKEY *pkey = NULL;
300     uint32_t i = 0;
301 
302     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(lib_ctx, "ML-DSA-44", NULL))
303         || !TEST_int_eq(EVP_PKEY_fromdata_init(ctx), 1)
304         || !TEST_ptr(EVP_PKEY_fromdata_settable(ctx, OSSL_KEYMGMT_SELECT_KEYPAIR))
305         || !TEST_ptr_null(EVP_PKEY_fromdata_settable(ctx, 0)))
306         goto err;
307 
308     params[0] = OSSL_PARAM_construct_uint32(OSSL_PKEY_PARAM_PRIV_KEY, &i);
309     params[1] = OSSL_PARAM_construct_end();
310     if (!TEST_int_ne(EVP_PKEY_fromdata(ctx, &pkey, OSSL_KEYMGMT_SELECT_PRIVATE_KEY,
311                          params),
312             1))
313         goto err;
314     params[0] = OSSL_PARAM_construct_uint32(OSSL_PKEY_PARAM_PUB_KEY, &i);
315     params[1] = OSSL_PARAM_construct_end();
316     if (!TEST_int_ne(EVP_PKEY_fromdata(ctx, &pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
317                          params),
318             1))
319         goto err;
320     ret = 1;
321 err:
322     EVP_PKEY_free(pkey);
323     EVP_PKEY_CTX_free(ctx);
324     return ret;
325 }
326 
ml_dsa_keygen_drbg_test(void)327 static int ml_dsa_keygen_drbg_test(void)
328 {
329     int ret = 0;
330     EVP_PKEY *pkey = NULL, *pkey2 = NULL, *pkey3 = NULL, *pkey_pub = NULL;
331     size_t len = 0;
332     uint8_t *priv = NULL, *pub = NULL;
333 
334     if (!TEST_ptr(pkey = do_gen_key("ML-DSA-44", NULL, 0))
335         || !TEST_ptr(pkey2 = do_gen_key("ML-DSA-44", NULL, 0))
336         || !TEST_ptr(pkey3 = do_gen_key("ML-DSA-65", NULL, 0))
337         || !TEST_int_eq(EVP_PKEY_eq(pkey, pkey2), 0)
338         || !TEST_int_eq(EVP_PKEY_eq(pkey, pkey3), -1)
339         || !TEST_int_eq(EVP_PKEY_get_raw_private_key(pkey, NULL, &len), 1)
340         || !TEST_int_gt(len, 0)
341         || !TEST_ptr(priv = OPENSSL_malloc(len))
342         || !TEST_int_eq(EVP_PKEY_get_raw_private_key(pkey, priv, &len), 1)
343         || !TEST_int_eq(EVP_PKEY_get_raw_public_key(pkey, NULL, &len), 1)
344         || !TEST_int_gt(len, 0)
345         || !TEST_ptr(pub = OPENSSL_malloc(len))
346         || !TEST_int_eq(EVP_PKEY_get_raw_public_key(pkey, pub, &len), 1)
347         /* Load just the public part into a PKEY */
348         || !TEST_true(ml_dsa_create_keypair(&pkey_pub, "ML-DSA-44", NULL, 0,
349             pub, len, 1))
350         /* test that the KEY's are equal */
351         || !TEST_int_eq(EVP_PKEY_eq(pkey_pub, pkey), 1))
352         goto err;
353     ret = 1;
354 err:
355     OPENSSL_free(pub);
356     OPENSSL_free(priv);
357     EVP_PKEY_free(pkey);
358     EVP_PKEY_free(pkey2);
359     EVP_PKEY_free(pkey3);
360     EVP_PKEY_free(pkey_pub);
361     return ret;
362 }
363 
364 static uint8_t msg1[] = "Hello World";
365 static uint8_t ctx1[] = "Context Test";
366 /* This message size will not fit into the internal buffer - so an alloc occurs */
367 static uint8_t msg2[2048] = { 0 };
368 /* This ctx is larger than 255 and will fail */
369 static uint8_t ctx2[256] = { 0 };
370 
371 static struct sig_params_st {
372     uint8_t *msg;
373     size_t msg_len;
374     uint8_t *ctx;
375     size_t ctx_len;
376     int encoded;
377     int expected;
378 } sig_params[] = {
379     { msg1, sizeof(msg1), NULL, 0, 0, 1 },
380     { msg1, sizeof(msg1), NULL, 0, 1, 1 },
381     { msg1, sizeof(msg1), ctx1, sizeof(ctx1), 0, 1 },
382     { msg1, sizeof(msg1), ctx1, sizeof(ctx1), 1, 1 },
383     { msg1, sizeof(msg1), ctx2, sizeof(ctx2), 0, 0 },
384     { msg1, sizeof(msg1), ctx2, sizeof(ctx2), 1, 0 },
385     { msg2, sizeof(msg2), NULL, 0, 0, 1 },
386     { msg2, sizeof(msg2), NULL, 0, 1, 1 },
387     { msg2, sizeof(msg2), ctx1, sizeof(ctx1), 0, 1 },
388     { msg2, sizeof(msg2), ctx1, sizeof(ctx1), 1, 1 },
389     { msg2, sizeof(msg2), ctx2, sizeof(ctx2), 0, 0 },
390     { msg2, sizeof(msg2), ctx2, sizeof(ctx2), 1, 0 },
391 };
392 
do_ml_dsa_sign_verify(const char * alg,int tstid)393 static int do_ml_dsa_sign_verify(const char *alg, int tstid)
394 {
395     int ret = 0;
396     const struct sig_params_st *sp = &sig_params[tstid];
397     EVP_PKEY_CTX *sctx = NULL, *vctx = NULL;
398     EVP_PKEY *key = NULL;
399     EVP_SIGNATURE *sig_alg = NULL;
400     uint8_t *sig = NULL;
401     size_t sig_len = 0;
402     OSSL_PARAM params[3], *p = params;
403 
404     if (!TEST_ptr(key = do_gen_key(alg, NULL, 0)))
405         goto err;
406 
407     *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING,
408         (int *)&sp->encoded);
409     if (sp->ctx != NULL)
410         *p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
411             sp->ctx, sp->ctx_len);
412     *p++ = OSSL_PARAM_construct_end();
413 
414     if (!TEST_ptr(sctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, key, NULL))
415         || !TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, alg, NULL))
416         || !TEST_int_eq(EVP_PKEY_sign_message_init(sctx, sig_alg, params), sp->expected))
417         goto err;
418     if (sp->expected == 0) {
419         ret = 1; /* return true as we expected to fail */
420         goto err;
421     }
422     if (!TEST_int_eq(EVP_PKEY_sign(sctx, NULL, &sig_len, sp->msg, sp->msg_len), 1)
423         || !TEST_ptr(sig = OPENSSL_zalloc(sig_len)))
424         goto err;
425     sig_len--;
426     if (!TEST_int_eq(EVP_PKEY_sign(sctx, sig, &sig_len, sp->msg, sp->msg_len), 0))
427         goto err;
428     sig_len++;
429     if (!TEST_int_eq(EVP_PKEY_sign(sctx, sig, &sig_len, sp->msg, sp->msg_len), 1)
430         || !TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, key, NULL))
431         || !TEST_int_eq(EVP_PKEY_verify_message_init(vctx, sig_alg, params), 1)
432         || !TEST_int_eq(EVP_PKEY_verify(vctx, sig, sig_len, sp->msg, sp->msg_len), 1))
433         goto err;
434     ret = 1;
435 err:
436     EVP_PKEY_free(key);
437     EVP_SIGNATURE_free(sig_alg);
438     OPENSSL_free(sig);
439     EVP_PKEY_CTX_free(sctx);
440     EVP_PKEY_CTX_free(vctx);
441     return ret;
442 }
ml_dsa_44_sign_verify_test(int tstid)443 static int ml_dsa_44_sign_verify_test(int tstid)
444 {
445     return do_ml_dsa_sign_verify("ML-DSA-44", tstid);
446 }
ml_dsa_65_sign_verify_test(int tstid)447 static int ml_dsa_65_sign_verify_test(int tstid)
448 {
449     return do_ml_dsa_sign_verify("ML-DSA-65", tstid);
450 }
ml_dsa_87_sign_verify_test(int tstid)451 static int ml_dsa_87_sign_verify_test(int tstid)
452 {
453     return do_ml_dsa_sign_verify("ML-DSA-87", tstid);
454 }
455 
ml_dsa_digest_sign_verify_test(void)456 static int ml_dsa_digest_sign_verify_test(void)
457 {
458     int ret = 0;
459     const struct sig_params_st *sp = &sig_params[0];
460     EVP_PKEY *key = NULL;
461     uint8_t *sig = NULL;
462     size_t sig_len = 0;
463     OSSL_PARAM params[3], *p = params;
464     const char *alg = "ML-DSA-44";
465     EVP_MD_CTX *mctx = NULL;
466 
467     if (!TEST_ptr(key = do_gen_key(alg, NULL, 0)))
468         goto err;
469 
470     *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING,
471         (int *)&sp->encoded);
472     if (sp->ctx != NULL)
473         *p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
474             sp->ctx, sp->ctx_len);
475     *p++ = OSSL_PARAM_construct_end();
476 
477     if (!TEST_ptr(mctx = EVP_MD_CTX_new())
478         || !TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, "SHA256",
479                             lib_ctx, "?fips=true",
480                             key, params),
481             0)
482         || !TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, NULL, lib_ctx,
483                             "?fips=true", key, params),
484             1))
485         goto err;
486     if (sp->expected == 0) {
487         ret = 1; /* return true as we expected to fail */
488         goto err;
489     }
490     if (!TEST_int_eq(EVP_DigestSign(mctx, NULL, &sig_len, sp->msg, sp->msg_len), 1)
491         || !TEST_ptr(sig = OPENSSL_zalloc(sig_len)))
492         goto err;
493     sig_len--;
494     if (!TEST_int_eq(EVP_DigestSign(mctx, sig, &sig_len, sp->msg, sp->msg_len), 0))
495         goto err;
496     sig_len++;
497     if (!TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, NULL, lib_ctx, "?fips=true",
498                          key, params),
499             1)
500         || !TEST_int_eq(EVP_DigestSign(mctx, sig, &sig_len,
501                             sp->msg, sp->msg_len),
502             1)
503         || !TEST_int_eq(EVP_DigestVerifyInit_ex(mctx, NULL, "SHA256",
504                             lib_ctx, "?fips=true",
505                             key, params),
506             0)
507         || !TEST_int_eq(EVP_DigestVerifyInit_ex(mctx, NULL, NULL,
508                             lib_ctx, "?fips=true",
509                             key, params),
510             1)
511         || !TEST_int_eq(EVP_DigestVerify(mctx, sig, sig_len,
512                             sp->msg, sp->msg_len),
513             1))
514         goto err;
515     ret = 1;
516 err:
517     EVP_PKEY_free(key);
518     EVP_MD_CTX_free(mctx);
519     OPENSSL_free(sig);
520     return ret;
521 }
522 
ml_dsa_priv_pub_bad_t0_test(void)523 static int ml_dsa_priv_pub_bad_t0_test(void)
524 {
525     int ret = 0;
526     EVP_PKEY *key = NULL;
527     ML_DSA_SIG_GEN_TEST_DATA *td = &ml_dsa_siggen_testdata[0];
528     uint8_t *priv = OPENSSL_memdup(td->priv, td->priv_len);
529 
530     if (!TEST_ptr(priv))
531         goto err;
532     memcpy(priv, td->priv, td->priv_len);
533     /*
534      * t0 is at the end of the encoding so corrupt it.
535      * This offset is the start of t0 (which is the last 416 * k bytes))
536      */
537     priv[td->priv_len - 6 * 416] ^= 1;
538     if (!TEST_true(ml_dsa_create_keypair(&key, td->alg,
539             priv, td->priv_len, NULL, 0, 0)))
540         goto err;
541 
542     priv[td->priv_len - 6 * 416] ^= 1;
543     if (!TEST_true(ml_dsa_create_keypair(&key, td->alg,
544             priv, td->priv_len, NULL, 0, 1)))
545         goto err;
546     ret = 1;
547 err:
548     OPENSSL_free(priv);
549     EVP_PKEY_free(key);
550     return ret;
551 }
552 
test_get_options(void)553 const OPTIONS *test_get_options(void)
554 {
555     static const OPTIONS options[] = {
556         OPT_TEST_OPTIONS_DEFAULT_USAGE,
557         { "config", OPT_CONFIG_FILE, '<',
558             "The configuration file to use for the libctx" },
559         { NULL }
560     };
561     return options;
562 }
563 
setup_tests(void)564 int setup_tests(void)
565 {
566     OPTION_CHOICE o;
567     char *config_file = NULL;
568 
569     while ((o = opt_next()) != OPT_EOF) {
570         switch (o) {
571         case OPT_CONFIG_FILE:
572             config_file = opt_arg();
573             break;
574         case OPT_TEST_CASES:
575             break;
576         default:
577         case OPT_ERR:
578             return 0;
579         }
580     }
581     if (!test_get_libctx(&lib_ctx, &null_prov, config_file, &lib_prov, NULL))
582         return 0;
583 
584     ADD_ALL_TESTS(ml_dsa_keygen_test, OSSL_NELEM(ml_dsa_keygen_testdata));
585     ADD_ALL_TESTS(ml_dsa_siggen_test, OSSL_NELEM(ml_dsa_siggen_testdata));
586     ADD_ALL_TESTS(ml_dsa_sigver_test, OSSL_NELEM(ml_dsa_sigver_testdata));
587     ADD_TEST(ml_dsa_key_dup_test);
588     ADD_TEST(ml_dsa_key_internal_test);
589     ADD_TEST(ml_dsa_keygen_drbg_test);
590     ADD_ALL_TESTS(ml_dsa_44_sign_verify_test, OSSL_NELEM(sig_params));
591     ADD_ALL_TESTS(ml_dsa_65_sign_verify_test, OSSL_NELEM(sig_params));
592     ADD_ALL_TESTS(ml_dsa_87_sign_verify_test, OSSL_NELEM(sig_params));
593     ADD_TEST(from_data_invalid_public_test);
594     ADD_TEST(from_data_bad_input_test);
595     ADD_TEST(ml_dsa_digest_sign_verify_test);
596     ADD_TEST(ml_dsa_priv_pub_bad_t0_test);
597     return 1;
598 }
599 
cleanup_tests(void)600 void cleanup_tests(void)
601 {
602     OSSL_PROVIDER_unload(null_prov);
603     OSSL_PROVIDER_unload(lib_prov);
604     OSSL_LIB_CTX_free(lib_ctx);
605 }
606