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