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