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