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 <openssl/param_build.h>
13 #include <openssl/rand.h>
14 #include <openssl/pem.h>
15 #include "crypto/slh_dsa.h"
16 #include "internal/nelem.h"
17 #include "testutil.h"
18 #include "slh_dsa.inc"
19
20 typedef enum OPTION_choice {
21 OPT_ERR = -1,
22 OPT_EOF = 0,
23 OPT_CONFIG_FILE,
24 OPT_TEST_ENUM
25 } OPTION_CHOICE;
26
27 static OSSL_LIB_CTX *lib_ctx = NULL;
28 static OSSL_PROVIDER *null_prov = NULL;
29 static OSSL_PROVIDER *lib_prov = NULL;
30
slh_dsa_key_from_data(const char * alg,const unsigned char * data,size_t datalen,int public)31 static EVP_PKEY *slh_dsa_key_from_data(const char *alg,
32 const unsigned char *data, size_t datalen,
33 int public)
34 {
35 int ret;
36 EVP_PKEY_CTX *ctx = NULL;
37 EVP_PKEY *key = NULL;
38 OSSL_PARAM params[2];
39 const char *keytype = public ? OSSL_PKEY_PARAM_PUB_KEY : OSSL_PKEY_PARAM_PRIV_KEY;
40 int selection = public ? EVP_PKEY_PUBLIC_KEY : EVP_PKEY_KEYPAIR;
41
42 params[0] = OSSL_PARAM_construct_octet_string(keytype, (uint8_t *)data, datalen);
43 params[1] = OSSL_PARAM_construct_end();
44 ret = TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(lib_ctx, alg, NULL))
45 && TEST_int_eq(EVP_PKEY_fromdata_init(ctx), 1)
46 && (EVP_PKEY_fromdata(ctx, &key, selection, params) == 1);
47 if (ret == 0) {
48 EVP_PKEY_free(key);
49 key = NULL;
50 }
51 EVP_PKEY_CTX_free(ctx);
52 return key;
53 }
54
slh_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)55 static int slh_dsa_create_keypair(EVP_PKEY **pkey, const char *name,
56 const uint8_t *priv, size_t priv_len,
57 const uint8_t *pub, size_t pub_len)
58 {
59 int ret = 0;
60 EVP_PKEY_CTX *ctx = NULL;
61 OSSL_PARAM_BLD *bld = NULL;
62 OSSL_PARAM *params = NULL;
63 const char *pub_name = OSSL_PKEY_PARAM_PUB_KEY;
64
65 if (!TEST_ptr(bld = OSSL_PARAM_BLD_new())
66 || !TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
67 OSSL_PKEY_PARAM_PRIV_KEY,
68 priv, priv_len) > 0)
69 || !TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
70 pub_name,
71 pub, pub_len) > 0)
72 || !TEST_ptr(params = OSSL_PARAM_BLD_to_param(bld))
73 || !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, EVP_PKEY_KEYPAIR,
76 params), 1))
77 goto err;
78
79 ret = 1;
80 err:
81 OSSL_PARAM_free(params);
82 OSSL_PARAM_BLD_free(bld);
83 EVP_PKEY_CTX_free(ctx);
84 return ret;
85 }
86
slh_dsa_bad_pub_len_test(void)87 static int slh_dsa_bad_pub_len_test(void)
88 {
89 int ret = 0;
90 SLH_DSA_SIG_TEST_DATA *td = &slh_dsa_sig_testdata[0];
91 EVP_PKEY *pkey = NULL;
92 size_t pub_len = 0;
93 unsigned char pubdata[64 + 1];
94
95 if (!TEST_size_t_le(td->pub_len, sizeof(pubdata)))
96 goto end;
97
98 OPENSSL_cleanse(pubdata, sizeof(pubdata));
99 memcpy(pubdata, td->pub, td->pub_len);
100
101 if (!TEST_ptr_null(pkey = slh_dsa_key_from_data(td->alg, pubdata,
102 td->pub_len - 1, 1))
103 || !TEST_ptr_null(pkey = slh_dsa_key_from_data(td->alg, pubdata,
104 td->pub_len + 1, 1)))
105 goto end;
106
107 ret = 1;
108 end:
109 if (ret == 0)
110 TEST_note("Incorrectly accepted public key of length %u (expected %u)",
111 (unsigned)pub_len, (unsigned)td->pub_len);
112 EVP_PKEY_free(pkey);
113 return ret == 1;
114 }
115
slh_dsa_key_eq_test(void)116 static int slh_dsa_key_eq_test(void)
117 {
118 int ret = 0;
119 size_t i;
120 EVP_PKEY *key[4] = { NULL, NULL, NULL, NULL };
121 SLH_DSA_SIG_TEST_DATA *td1 = &slh_dsa_sig_testdata[0];
122 SLH_DSA_SIG_TEST_DATA *td2 = &slh_dsa_sig_testdata[1];
123 #ifndef OPENSSL_NO_EC
124 EVP_PKEY *eckey = NULL;
125 #endif
126
127 if (!TEST_ptr(key[0] = slh_dsa_key_from_data(td1->alg, td1->pub, td1->pub_len, 1))
128 || !TEST_ptr(key[1] = slh_dsa_key_from_data(td1->alg, td1->pub, td1->pub_len, 1))
129 || !TEST_ptr(key[2] = slh_dsa_key_from_data(td2->alg, td2->pub, td2->pub_len, 1))
130 || !TEST_ptr(key[3] = EVP_PKEY_dup(key[0])))
131 goto end;
132
133 if (!TEST_int_eq(EVP_PKEY_eq(key[0], key[1]), 1)
134 || !TEST_int_ne(EVP_PKEY_eq(key[0], key[2]), 1)
135 || !TEST_int_eq(EVP_PKEY_eq(key[0], key[3]), 1))
136 goto end;
137
138 #ifndef OPENSSL_NO_EC
139 if (!TEST_ptr(eckey = EVP_PKEY_Q_keygen(lib_ctx, NULL, "EC", "P-256")))
140 goto end;
141 ret = TEST_int_ne(EVP_PKEY_eq(key[0], eckey), 1);
142 EVP_PKEY_free(eckey);
143 #else
144 ret = 1;
145 #endif
146 end:
147 for (i = 0; i < OSSL_NELEM(key); ++i)
148 EVP_PKEY_free(key[i]);
149 return ret;
150 }
151
slh_dsa_key_validate_test(void)152 static int slh_dsa_key_validate_test(void)
153 {
154 int ret = 0;
155 SLH_DSA_SIG_TEST_DATA *td = &slh_dsa_sig_testdata[0];
156 EVP_PKEY_CTX *vctx = NULL;
157 EVP_PKEY *key = NULL;
158
159 if (!TEST_ptr(key = slh_dsa_key_from_data(td->alg, td->pub, td->pub_len, 1)))
160 return 0;
161 if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, key, NULL)))
162 goto end;
163 if (!TEST_int_eq(EVP_PKEY_public_check(vctx), 1))
164 goto end;
165 if (!TEST_int_eq(EVP_PKEY_private_check(vctx), 0))
166 goto end;
167 if (!TEST_int_eq(EVP_PKEY_pairwise_check(vctx), 0))
168 goto end;
169 ret = 1;
170 end:
171 EVP_PKEY_CTX_free(vctx);
172 EVP_PKEY_free(key);
173 return ret;
174 }
175
slh_dsa_key_validate_failure_test(void)176 static int slh_dsa_key_validate_failure_test(void)
177 {
178 int ret = 0;
179 EVP_PKEY_CTX *vctx = NULL;
180 EVP_PKEY *key = NULL;
181
182 /*
183 * Loading 128s private key data into a 128f algorithm will have an incorrect
184 * public key.
185 */
186 key = slh_dsa_key_from_data("SLH-DSA-SHA2-128f",
187 slh_dsa_sha2_128s_0_keygen_priv,
188 sizeof(slh_dsa_sha2_128s_0_keygen_priv), 0);
189 if (!TEST_ptr(key))
190 goto end;
191 if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, key, NULL)))
192 goto end;
193 if (!TEST_int_eq(EVP_PKEY_pairwise_check(vctx), 0))
194 goto end;
195 ret = 1;
196 end:
197 EVP_PKEY_CTX_free(vctx);
198 EVP_PKEY_free(key);
199 return ret;
200 }
201
202 /*
203 * Rather than having to store the full signature into a file, we just do a
204 * verify using the output of a sign. The sign test already does a Known answer
205 * test (KAT) using the digest of the signature, so this should be sufficient to
206 * run as a KAT for the verify.
207 */
do_slh_dsa_verify(const SLH_DSA_SIG_TEST_DATA * td,uint8_t * sig,size_t sig_len)208 static int do_slh_dsa_verify(const SLH_DSA_SIG_TEST_DATA *td,
209 uint8_t *sig, size_t sig_len)
210 {
211 int ret = 0;
212 EVP_PKEY_CTX *vctx = NULL;
213 EVP_PKEY *key = NULL;
214 EVP_SIGNATURE *sig_alg = NULL;
215 OSSL_PARAM params[2], *p = params;
216 int encode = 0;
217
218 *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode);
219 *p = OSSL_PARAM_construct_end();
220
221 if (!TEST_ptr(key = slh_dsa_key_from_data(td->alg, td->pub, td->pub_len, 1)))
222 return 0;
223 if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, key, NULL)))
224 goto err;
225 if (!TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, td->alg, NULL)))
226 goto err;
227 if (!TEST_int_eq(EVP_PKEY_verify_message_init(vctx, sig_alg, params), 1)
228 || !TEST_int_eq(EVP_PKEY_verify(vctx, sig, sig_len,
229 td->msg, td->msg_len), 1))
230 goto err;
231 ret = 1;
232 err:
233 EVP_SIGNATURE_free(sig_alg);
234 EVP_PKEY_free(key);
235 EVP_PKEY_CTX_free(vctx);
236 return ret;
237 }
238
slh_dsa_sign_verify_test(int tst_id)239 static int slh_dsa_sign_verify_test(int tst_id)
240 {
241 int ret = 0;
242 SLH_DSA_SIG_TEST_DATA *td = &slh_dsa_sig_testdata[tst_id];
243 EVP_PKEY_CTX *sctx = NULL;
244 EVP_PKEY *pkey = NULL;
245 EVP_SIGNATURE *sig_alg = NULL;
246 OSSL_PARAM params[4], *p = params;
247 uint8_t *psig = NULL;
248 size_t psig_len = 0, sig_len2 = 0;
249 uint8_t digest[32];
250 size_t digest_len = sizeof(digest);
251 int encode = 0, deterministic = 1;
252
253 *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, &deterministic);
254 *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode);
255 if (td->add_random != NULL)
256 *p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY,
257 (char *)td->add_random,
258 td->add_random_len);
259 *p = OSSL_PARAM_construct_end();
260
261 /*
262 * This just uses from data here, but keygen also works.
263 * The keygen path is tested via slh_dsa_keygen_test
264 */
265 if (!slh_dsa_create_keypair(&pkey, td->alg, td->priv, td->priv_len,
266 td->pub, td->pub_len))
267 goto err;
268
269 if (!TEST_ptr(sctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pkey, NULL)))
270 goto err;
271 if (!TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, td->alg, NULL)))
272 goto err;
273 if (!TEST_int_eq(EVP_PKEY_sign_message_init(sctx, sig_alg, params), 1)
274 || !TEST_int_eq(EVP_PKEY_sign(sctx, NULL, &psig_len,
275 td->msg, td->msg_len), 1)
276 || !TEST_true(EVP_PKEY_get_size_t_param(pkey, OSSL_PKEY_PARAM_MAX_SIZE,
277 &sig_len2))
278 || !TEST_int_eq(sig_len2, psig_len)
279 || !TEST_ptr(psig = OPENSSL_zalloc(psig_len))
280 || !TEST_int_eq(EVP_PKEY_sign(sctx, psig, &psig_len,
281 td->msg, td->msg_len), 1))
282 goto err;
283 if (!TEST_int_eq(EVP_Q_digest(lib_ctx, "SHA256", NULL, psig, psig_len,
284 digest, &digest_len), 1))
285 goto err;
286 if (!TEST_mem_eq(digest, digest_len, td->sig_digest, td->sig_digest_len))
287 goto err;
288 if (!do_slh_dsa_verify(td, psig, psig_len))
289 goto err;
290 ret = 1;
291 err:
292 EVP_SIGNATURE_free(sig_alg);
293 EVP_PKEY_free(pkey);
294 EVP_PKEY_CTX_free(sctx);
295 OPENSSL_free(psig);
296 return ret;
297 }
298
do_gen_key(const char * alg,const uint8_t * seed,size_t seed_len)299 static EVP_PKEY *do_gen_key(const char *alg,
300 const uint8_t *seed, size_t seed_len)
301 {
302 EVP_PKEY *pkey = NULL;
303 EVP_PKEY_CTX *ctx = NULL;
304 OSSL_PARAM params[2], *p = params;
305
306 if (seed_len != 0)
307 *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_SLH_DSA_SEED,
308 (char *)seed, seed_len);
309 *p = OSSL_PARAM_construct_end();
310
311 if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(lib_ctx, alg, NULL))
312 || !TEST_int_eq(EVP_PKEY_keygen_init(ctx), 1)
313 || !TEST_int_eq(EVP_PKEY_CTX_set_params(ctx, params), 1)
314 || !TEST_int_eq(EVP_PKEY_generate(ctx, &pkey), 1))
315 pkey = NULL;
316
317 EVP_PKEY_CTX_free(ctx);
318 return pkey;
319 }
320
slh_dsa_keygen_test(int tst_id)321 static int slh_dsa_keygen_test(int tst_id)
322 {
323 int ret = 0;
324 const SLH_DSA_KEYGEN_TEST_DATA *tst = &slh_dsa_keygen_testdata[tst_id];
325 EVP_PKEY *pkey = NULL;
326 uint8_t priv[64 * 2], pub[32 * 2];
327 size_t priv_len, pub_len;
328 size_t key_len = tst->priv_len;
329 size_t n = key_len / 4;
330 int bits = 0, sec_bits = 0, sig_len = 0;
331
332 if (!TEST_ptr(pkey = do_gen_key(tst->name, tst->priv, key_len - n)))
333 goto err;
334
335 if (!TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
336 priv, sizeof(priv), &priv_len)))
337 goto err;
338 if (!TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
339 pub, sizeof(pub), &pub_len)))
340 goto err;
341 if (!TEST_true(EVP_PKEY_get_int_param(pkey, OSSL_PKEY_PARAM_BITS, &bits))
342 || !TEST_int_eq(bits, 8 * 2 * n)
343 || !TEST_true(EVP_PKEY_get_int_param(pkey, OSSL_PKEY_PARAM_SECURITY_BITS,
344 &sec_bits))
345 || !TEST_int_eq(sec_bits, 8 * n)
346 || !TEST_true(EVP_PKEY_get_int_param(pkey, OSSL_PKEY_PARAM_MAX_SIZE,
347 &sig_len))
348 || !TEST_int_ge(sig_len, 7856)
349 || !TEST_int_le(sig_len, 49856))
350 goto err;
351
352 if (!TEST_size_t_eq(priv_len, key_len)
353 || !TEST_size_t_eq(pub_len, key_len / 2))
354 goto err;
355 if (!TEST_mem_eq(pub, pub_len, tst->priv + 2 * n, 2 * n))
356 goto err;
357 ret = 1;
358 err:
359 EVP_PKEY_free(pkey);
360 return ret;
361 }
362
slh_dsa_usage_test(void)363 static int slh_dsa_usage_test(void)
364 {
365 int ret = 0;
366 EVP_CIPHER *cipher = NULL; /* Used to encrypt the private key */
367 char *pass = "Password";
368 BIO *pub_bio = NULL, *priv_bio = NULL;
369 EVP_PKEY_CTX *gctx = NULL, *sctx = NULL, *vctx = NULL;
370 EVP_PKEY *gkey = NULL, *pub = NULL, *priv = NULL;
371 EVP_SIGNATURE *sig_alg = NULL;
372 uint8_t *sig = NULL;
373 size_t sig_len = 0;
374 uint8_t msg[] = "Hello World";
375 size_t msg_len = sizeof(msg) - 1;
376
377 /* Generate a key */
378 if (!TEST_ptr(gctx = EVP_PKEY_CTX_new_from_name(lib_ctx, "SLH-DSA-SHA2-128s", NULL))
379 || !TEST_int_eq(EVP_PKEY_keygen_init(gctx), 1)
380 || !TEST_int_eq(EVP_PKEY_keygen(gctx, &gkey), 1))
381 goto err;
382
383 /* Save it to a BIO - it uses a mem bio for testing */
384 if (!TEST_ptr(pub_bio = BIO_new(BIO_s_mem()))
385 || !TEST_ptr(priv_bio = BIO_new(BIO_s_mem()))
386 || !TEST_ptr(cipher = EVP_CIPHER_fetch(lib_ctx, "AES-256-CBC", NULL))
387 || !TEST_true(PEM_write_bio_PUBKEY_ex(pub_bio, gkey, lib_ctx, NULL))
388 || !TEST_true(PEM_write_bio_PrivateKey_ex(priv_bio, gkey, cipher,
389 NULL, 0, NULL, (void *)pass,
390 lib_ctx, NULL)))
391 goto err;
392
393 /* Read the private key and add to a signing ctx */
394 if (!TEST_ptr(PEM_read_bio_PrivateKey_ex(priv_bio, &priv, NULL, pass, lib_ctx, NULL))
395 || !TEST_ptr(sctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, priv, NULL))
396 || !TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, "SLH-DSA-SHA2-128s", NULL))
397 || !TEST_int_eq(EVP_PKEY_sign_message_init(sctx, sig_alg, NULL), 1))
398 goto err;
399 /* Determine the size of the signature & allocate space */
400 if (!TEST_int_eq(EVP_PKEY_sign(sctx, NULL, &sig_len, msg, msg_len), 1)
401 || !TEST_ptr(sig = OPENSSL_malloc(sig_len))
402 || !TEST_int_eq(EVP_PKEY_sign(sctx, sig, &sig_len, msg, msg_len), 1))
403 goto err;
404 if (!TEST_true(EVP_PKEY_pairwise_check(sctx))
405 || !TEST_true(EVP_PKEY_public_check(sctx))
406 || !TEST_true(EVP_PKEY_private_check(sctx)))
407 goto err;
408 /* Read the public key and add to a verify ctx */
409 if (!TEST_ptr(PEM_read_bio_PUBKEY_ex(pub_bio, &pub, NULL, NULL, lib_ctx, NULL))
410 || !TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pub, NULL)))
411 goto err;
412 /* verify the signature */
413 if (!TEST_int_eq(EVP_PKEY_verify_message_init(vctx, sig_alg, NULL), 1)
414 || !TEST_int_eq(EVP_PKEY_verify(vctx, sig, sig_len, msg, msg_len), 1))
415 goto err;
416
417 ret = 1;
418 err:
419 EVP_CIPHER_free(cipher);
420 EVP_SIGNATURE_free(sig_alg);
421 EVP_PKEY_free(gkey);
422 EVP_PKEY_free(pub);
423 EVP_PKEY_free(priv);
424 EVP_PKEY_CTX_free(gctx);
425 EVP_PKEY_CTX_free(sctx);
426 EVP_PKEY_CTX_free(vctx);
427 BIO_free(pub_bio);
428 BIO_free(priv_bio);
429 OPENSSL_free(sig);
430 return ret;
431 }
432
slh_dsa_deterministic_usage_test(void)433 static int slh_dsa_deterministic_usage_test(void)
434 {
435 int ret = 0;
436 EVP_CIPHER *cipher = NULL; /* Used to encrypt the private key */
437 char *pass = "Password";
438 BIO *pub_bio = NULL, *priv_bio = NULL;
439 EVP_PKEY_CTX *gctx = NULL, *sctx = NULL, *vctx = NULL, *dupctx = NULL;
440 EVP_PKEY *gkey = NULL, *pub = NULL, *priv = NULL;
441 EVP_SIGNATURE *sig_alg = NULL;
442 uint8_t *sig = NULL;
443 size_t sig_len = 0, len = 0;
444 uint8_t msg[] = { 0x01, 0x02, 0x03, 0x04 };
445 size_t msg_len = sizeof(msg);
446 const SLH_DSA_KEYGEN_TEST_DATA *tst = &slh_dsa_keygen_testdata[0];
447 size_t key_len = tst->priv_len / 2;
448 size_t n = key_len / 2;
449 int deterministic = 1;
450 OSSL_PARAM params[2], *p = params;
451
452 /* Generate a key */
453 if (!TEST_ptr(gkey = do_gen_key(tst->name, tst->priv, key_len + n)))
454 goto err;
455
456 /* Save it to a BIO - it uses a mem bio for testing */
457 if (!TEST_ptr(pub_bio = BIO_new(BIO_s_mem()))
458 || !TEST_ptr(priv_bio = BIO_new(BIO_s_mem()))
459 || !TEST_ptr(cipher = EVP_CIPHER_fetch(lib_ctx, "AES-256-CBC", NULL))
460 || !TEST_true(PEM_write_bio_PUBKEY_ex(pub_bio, gkey, lib_ctx, NULL))
461 || !TEST_true(PEM_write_bio_PrivateKey_ex(priv_bio, gkey, cipher,
462 NULL, 0, NULL, (void *)pass,
463 lib_ctx, NULL)))
464 goto err;
465
466 *p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, &deterministic);
467 *p = OSSL_PARAM_construct_end();
468
469 /* Read the private key and add to a signing ctx */
470 if (!TEST_ptr(PEM_read_bio_PrivateKey_ex(priv_bio, &priv, NULL, pass, lib_ctx, NULL))
471 || !TEST_ptr(sctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, priv, NULL))
472 /* Init the signature */
473 || !TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, tst->name, NULL))
474 || !TEST_int_eq(EVP_PKEY_sign_message_init(sctx, sig_alg, params), 1))
475 goto err;
476
477 if (!TEST_ptr(dupctx = EVP_PKEY_CTX_dup(sctx)))
478 goto err;
479
480 /* Determine the size of the signature & allocate space */
481 if (!TEST_int_eq(EVP_PKEY_sign(sctx, NULL, &sig_len, msg, msg_len), 1))
482 goto err;
483 len = sig_len;
484 if (!TEST_ptr(sig = OPENSSL_zalloc(sig_len * 2))
485 || !TEST_int_eq(EVP_PKEY_sign(sctx, sig, &len, msg, msg_len), 1)
486 || !TEST_size_t_eq(sig_len, len)
487 || !TEST_int_eq(EVP_PKEY_sign(dupctx, sig + sig_len, &len,
488 msg, msg_len), 1)
489 || !TEST_size_t_eq(sig_len, len))
490 goto err;
491 /* Read the public key and add to a verify ctx */
492 if (!TEST_ptr(PEM_read_bio_PUBKEY_ex(pub_bio, &pub, NULL, NULL, lib_ctx, NULL))
493 || !TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pub, NULL)))
494 goto err;
495 EVP_PKEY_CTX_free(dupctx);
496
497 /* verify the signature */
498 if (!TEST_int_eq(EVP_PKEY_verify_message_init(vctx, sig_alg, NULL), 1)
499 || !TEST_ptr(dupctx = EVP_PKEY_CTX_dup(vctx))
500 || !TEST_int_eq(EVP_PKEY_verify(vctx, sig, sig_len, msg, msg_len), 1)
501 || !TEST_int_eq(EVP_PKEY_verify(dupctx, sig + sig_len, sig_len,
502 msg, msg_len), 1))
503 goto err;
504 ret = 1;
505 err:
506 EVP_CIPHER_free(cipher);
507 EVP_SIGNATURE_free(sig_alg);
508 EVP_PKEY_free(gkey);
509 EVP_PKEY_free(pub);
510 EVP_PKEY_free(priv);
511 EVP_PKEY_CTX_free(gctx);
512 EVP_PKEY_CTX_free(sctx);
513 EVP_PKEY_CTX_free(vctx);
514 EVP_PKEY_CTX_free(dupctx);
515 BIO_free(pub_bio);
516 BIO_free(priv_bio);
517 OPENSSL_free(sig);
518 return ret;
519 }
520
slh_dsa_digest_sign_verify_test(void)521 static int slh_dsa_digest_sign_verify_test(void)
522 {
523 int ret = 0;
524 EVP_PKEY *key = NULL;
525 uint8_t *sig = NULL;
526 size_t sig_len = 0;
527 OSSL_PARAM params[3], *p = params;
528 const char *alg = "SLH-DSA-SHA2-128s";
529 EVP_MD_CTX *mctx = NULL;
530 static uint8_t context[] = "A context String";
531 static uint8_t msg[] = "Hello World";
532 size_t msg_len = sizeof(msg);
533
534 if (!TEST_ptr(key = do_gen_key(alg, NULL, 0)))
535 goto err;
536
537 *p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
538 context, sizeof(context));
539 *p++ = OSSL_PARAM_construct_end();
540
541 if (!TEST_ptr(mctx = EVP_MD_CTX_new())
542 || !TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, "SHA256",
543 lib_ctx, "?fips=true",
544 key, params), 0)
545 || !TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, NULL, lib_ctx,
546 "?fips=true", key, params), 1))
547 goto err;
548 if (!TEST_int_eq(EVP_DigestSign(mctx, NULL, &sig_len, msg, msg_len), 1)
549 || !TEST_ptr(sig = OPENSSL_zalloc(sig_len)))
550 goto err;
551 sig_len--;
552 if (!TEST_int_eq(EVP_DigestSign(mctx, sig, &sig_len, msg, msg_len), 0))
553 goto err;
554 sig_len++;
555 if (!TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, NULL, lib_ctx, "?fips=true",
556 key, params), 1)
557 || !TEST_int_eq(EVP_DigestSign(mctx, sig, &sig_len, msg, msg_len), 1)
558 || !TEST_int_eq(EVP_DigestVerifyInit_ex(mctx, NULL, "SHA256",
559 lib_ctx, "?fips=true",
560 key, params), 0)
561 || !TEST_int_eq(EVP_DigestVerifyInit_ex(mctx, NULL, NULL,
562 lib_ctx, "?fips=true",
563 key, params), 1)
564 || !TEST_int_eq(EVP_DigestVerify(mctx, sig, sig_len, msg, msg_len), 1))
565 goto err;
566 ret = 1;
567 err:
568 EVP_PKEY_free(key);
569 EVP_MD_CTX_free(mctx);
570 OPENSSL_free(sig);
571 return ret;
572 }
573
slh_dsa_keygen_invalid_test(void)574 static int slh_dsa_keygen_invalid_test(void)
575 {
576 int ret = 0;
577 const SLH_DSA_KEYGEN_TEST_DATA *tst = &slh_dsa_keygen_testdata[0];
578 EVP_PKEY *pkey = NULL;
579 EVP_PKEY_CTX *ctx = NULL;
580 OSSL_PARAM params[2], *p = params;
581 size_t key_len = tst->priv_len;
582 size_t n = key_len / 4;
583 uint8_t seed[128] = {0};
584
585 if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(lib_ctx, tst->name, NULL))
586 || !TEST_int_eq(EVP_PKEY_keygen_init(ctx), 1))
587 goto err;
588
589 /* Test the set fails if the seed is larger than the internal buffer */
590 p[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_SLH_DSA_SEED,
591 seed, 97);
592 p[1] = OSSL_PARAM_construct_end();
593 if (!TEST_int_eq(EVP_PKEY_CTX_set_params(ctx, params), 0))
594 goto err;
595
596 /* Test the generate fails if the seed is not the correct size */
597 p[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_SLH_DSA_SEED,
598 seed, n * 3 - 1);
599 p[1] = OSSL_PARAM_construct_end();
600
601 if (!TEST_int_eq(EVP_PKEY_CTX_set_params(ctx, params), 1)
602 || !TEST_int_eq(EVP_PKEY_generate(ctx, &pkey), 0))
603 goto err;
604
605 /* Test the generate fails if the seed is not the correct size */
606 p[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_SLH_DSA_SEED,
607 seed, n * 3 + 1);
608 p[1] = OSSL_PARAM_construct_end();
609 if (!TEST_int_eq(EVP_PKEY_CTX_set_params(ctx, params), 1)
610 || !TEST_int_eq(EVP_PKEY_generate(ctx, &pkey), 0))
611 goto err;
612 ret = 1;
613 err:
614 EVP_PKEY_free(pkey);
615 EVP_PKEY_CTX_free(ctx);
616 return ret;
617 }
618
test_get_options(void)619 const OPTIONS *test_get_options(void)
620 {
621 static const OPTIONS options[] = {
622 OPT_TEST_OPTIONS_DEFAULT_USAGE,
623 { "config", OPT_CONFIG_FILE, '<',
624 "The configuration file to use for the libctx" },
625 { NULL }
626 };
627 return options;
628 }
629
setup_tests(void)630 int setup_tests(void)
631 {
632 OPTION_CHOICE o;
633 char *config_file = NULL;
634
635 while ((o = opt_next()) != OPT_EOF) {
636 switch (o) {
637 case OPT_CONFIG_FILE:
638 config_file = opt_arg();
639 break;
640 case OPT_TEST_CASES:
641 break;
642 default:
643 case OPT_ERR:
644 return 0;
645 }
646 }
647 if (!test_get_libctx(&lib_ctx, &null_prov, config_file, &lib_prov, NULL))
648 return 0;
649
650 ADD_TEST(slh_dsa_bad_pub_len_test);
651 ADD_TEST(slh_dsa_key_validate_test);
652 ADD_TEST(slh_dsa_key_validate_failure_test);
653 ADD_TEST(slh_dsa_key_eq_test);
654 ADD_TEST(slh_dsa_usage_test);
655 ADD_TEST(slh_dsa_deterministic_usage_test);
656 ADD_ALL_TESTS(slh_dsa_sign_verify_test, OSSL_NELEM(slh_dsa_sig_testdata));
657 ADD_ALL_TESTS(slh_dsa_keygen_test, OSSL_NELEM(slh_dsa_keygen_testdata));
658 ADD_TEST(slh_dsa_digest_sign_verify_test);
659 ADD_TEST(slh_dsa_keygen_invalid_test);
660 return 1;
661 }
662
cleanup_tests(void)663 void cleanup_tests(void)
664 {
665 OSSL_PROVIDER_unload(null_prov);
666 OSSL_PROVIDER_unload(lib_prov);
667 OSSL_LIB_CTX_free(lib_ctx);
668 }
669