/src/openssl41/fuzz/slh-dsa.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * |
4 | | * Licensed under the Apache License 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * https://www.openssl.org/source/license.html |
8 | | * or in the file LICENSE in the source distribution. |
9 | | */ |
10 | | |
11 | | /* |
12 | | * Test slh-dsa operation. |
13 | | */ |
14 | | #include <string.h> |
15 | | #include <openssl/evp.h> |
16 | | #include <openssl/err.h> |
17 | | #include <openssl/rand.h> |
18 | | #include <openssl/byteorder.h> |
19 | | #include <openssl/core_names.h> |
20 | | #include "crypto/slh_dsa.h" |
21 | | #include "internal/nelem.h" |
22 | | #include "fuzzer.h" |
23 | | |
24 | | /** |
25 | | * @brief Consumes an 8-bit unsigned integer from a buffer. |
26 | | * |
27 | | * This function extracts an 8-bit unsigned integer from the provided buffer, |
28 | | * updates the buffer pointer, and adjusts the remaining length. |
29 | | * |
30 | | * @param buf Pointer to the input buffer. |
31 | | * @param len Pointer to the size of the remaining buffer; updated after consumption. |
32 | | * @param val Pointer to store the extracted 8-bit value. |
33 | | * |
34 | | * @return Pointer to the updated buffer position after reading the value, |
35 | | * or NULL if the buffer does not contain enough data. |
36 | | */ |
37 | | static uint8_t *consume_uint8t(const uint8_t *buf, size_t *len, uint8_t *val) |
38 | 4.50k | { |
39 | 4.50k | if (*len < sizeof(uint8_t)) |
40 | 0 | return NULL; |
41 | 4.50k | *val = *buf; |
42 | 4.50k | *len -= sizeof(uint8_t); |
43 | 4.50k | return (uint8_t *)buf + 1; |
44 | 4.50k | } |
45 | | |
46 | | /** |
47 | | * @brief Generates a DSA key pair using OpenSSL EVP API. |
48 | | * |
49 | | * This function creates a DSA key pair based on the specified key size and |
50 | | * parameters. It supports generating keys using explicit parameters if provided. |
51 | | * |
52 | | * @param name The name of the key type (e.g., "DSA"). |
53 | | * @param keysize The desired key size in bits. |
54 | | * @param params Optional OpenSSL parameters for key generation. |
55 | | * @param param_broken A flag indicating if the parameters are broken. |
56 | | * If true, key generation will fail. |
57 | | * |
58 | | * @return A pointer to the generated EVP_PKEY structure on success, |
59 | | * or NULL on failure. |
60 | | */ |
61 | | static EVP_PKEY *slh_dsa_gen_key(const char *name, uint32_t keysize, |
62 | | OSSL_PARAM params[], uint8_t *param_broken) |
63 | 236 | { |
64 | 236 | EVP_PKEY_CTX *ctx; |
65 | 236 | EVP_PKEY *new = NULL; |
66 | | |
67 | 236 | ctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL); |
68 | 236 | if (ctx == NULL) |
69 | 0 | return NULL; |
70 | 236 | if (params != NULL) { |
71 | 38 | new = EVP_PKEY_new(); |
72 | 38 | if (new == NULL) |
73 | 0 | goto out; |
74 | 38 | if (!EVP_PKEY_fromdata_init(ctx)) { |
75 | 0 | EVP_PKEY_free(new); |
76 | 0 | new = NULL; |
77 | 0 | goto out; |
78 | 0 | } |
79 | 38 | if (EVP_PKEY_fromdata(ctx, &new, EVP_PKEY_KEYPAIR, params) != 1) { |
80 | 24 | EVP_PKEY_free(new); |
81 | 24 | new = NULL; |
82 | 24 | } |
83 | 38 | goto out; |
84 | 38 | } |
85 | | |
86 | 198 | if (!EVP_PKEY_keygen_init(ctx)) |
87 | 0 | goto out; |
88 | 198 | if (!EVP_PKEY_generate(ctx, &new)) { |
89 | 0 | EVP_PKEY_free(new); |
90 | 0 | new = NULL; |
91 | 0 | } |
92 | | |
93 | 236 | out: |
94 | 236 | EVP_PKEY_CTX_free(ctx); |
95 | 236 | return new; |
96 | 198 | } |
97 | | |
98 | | /** |
99 | | * @brief Selects a key type and determines the key size. |
100 | | * |
101 | | * This function maps a selector value to a specific SLH-DSA algorithm |
102 | | * using a modulo operation. It then retrieves the corresponding |
103 | | * algorithm name and assigns an appropriate key size based on the |
104 | | * selected algorithm. |
105 | | * |
106 | | * @param selector A random selector value used to determine the key type. |
107 | | * @param keysize Pointer to a variable where the determined key size |
108 | | * (in bytes) will be stored. |
109 | | * |
110 | | * @return A pointer to a string containing the long name of the |
111 | | * selected key type, or NULL if invalid. |
112 | | */ |
113 | | static const char *select_keytype(uint8_t selector, uint32_t *keysize) |
114 | 1.87k | { |
115 | 1.87k | unsigned int choice; |
116 | 1.87k | const char *name = NULL; |
117 | | |
118 | 1.87k | *keysize = 0; |
119 | | /* |
120 | | * There are 12 SLH-DSA algs with registered NIDS at the moment |
121 | | * So use our random selector value to get one of them by computing |
122 | | * its modulo 12 value and adding the offset of the first NID, 1460 |
123 | | * Then convert that to a long name |
124 | | */ |
125 | 1.87k | choice = (selector % 12) + 1460; |
126 | | |
127 | 1.87k | name = OBJ_nid2ln(choice); |
128 | | |
129 | | /* |
130 | | * Select a keysize, values taken from |
131 | | * man7/EVP_PKEY-SLH-DSA.pod |
132 | | */ |
133 | 1.87k | switch (choice) { |
134 | 276 | case NID_SLH_DSA_SHA2_128s: |
135 | 534 | case NID_SLH_DSA_SHA2_128f: |
136 | 612 | case NID_SLH_DSA_SHAKE_128s: |
137 | 665 | case NID_SLH_DSA_SHAKE_128f: |
138 | 665 | *keysize = 16; |
139 | 665 | break; |
140 | 93 | case NID_SLH_DSA_SHA2_192s: |
141 | 467 | case NID_SLH_DSA_SHA2_192f: |
142 | 569 | case NID_SLH_DSA_SHAKE_192s: |
143 | 753 | case NID_SLH_DSA_SHAKE_192f: |
144 | 753 | *keysize = 24; |
145 | 753 | break; |
146 | 99 | case NID_SLH_DSA_SHA2_256s: |
147 | 232 | case NID_SLH_DSA_SHA2_256f: |
148 | 348 | case NID_SLH_DSA_SHAKE_256s: |
149 | 455 | case NID_SLH_DSA_SHAKE_256f: |
150 | 455 | *keysize = 32; |
151 | 455 | break; |
152 | 0 | default: |
153 | 0 | fprintf(stderr, "Selecting invalid key size\n"); |
154 | 0 | *keysize = 0; |
155 | 0 | break; |
156 | 1.87k | } |
157 | 1.87k | return name; |
158 | 1.87k | } |
159 | | |
160 | | /** |
161 | | * @brief Generates two SLH-DSA key pairs based on consumed selector values. |
162 | | * |
163 | | * This function extracts two selector values from the provided buffer, |
164 | | * determines the corresponding key types and sizes, and generates two |
165 | | * SLH-DSA key pairs. |
166 | | * |
167 | | * @param buf Pointer to a buffer containing selector values. The buffer |
168 | | * pointer is updated as values are consumed. |
169 | | * @param len Pointer to the remaining buffer length, updated as values |
170 | | * are consumed. |
171 | | * @param out1 Pointer to store the first generated key. |
172 | | * @param out2 Pointer to store the second generated key. |
173 | | */ |
174 | | static void slh_dsa_gen_keys(uint8_t **buf, size_t *len, |
175 | | void **out1, void **out2) |
176 | 326 | { |
177 | 326 | uint8_t selector = 0; |
178 | 326 | const char *keytype = NULL; |
179 | 326 | uint32_t keysize; |
180 | | |
181 | 326 | *buf = consume_uint8t(*buf, len, &selector); |
182 | 326 | keytype = select_keytype(selector, &keysize); |
183 | 326 | *out1 = (void *)slh_dsa_gen_key(keytype, keysize, NULL, 0); |
184 | | |
185 | 326 | *buf = consume_uint8t(*buf, len, &selector); |
186 | 326 | keytype = select_keytype(selector, &keysize); |
187 | 326 | *out2 = (void *)slh_dsa_gen_key(keytype, keysize, NULL, 0); |
188 | 326 | return; |
189 | 326 | } |
190 | | |
191 | 114 | #define PARAM_BUF_SZ 256 |
192 | | |
193 | | /** |
194 | | * @brief Generates an SLH-DSA key pair with custom parameters. |
195 | | * |
196 | | * This function extracts a selector value from the provided buffer, |
197 | | * determines the corresponding key type and size, and generates an |
198 | | * SLH-DSA key pair using randomly generated public and private key |
199 | | * buffers. It also introduces intentional modifications to test |
200 | | * invalid parameter handling. |
201 | | * |
202 | | * @param buf Pointer to a buffer containing the selector value. The |
203 | | * buffer pointer is updated as values are consumed. |
204 | | * @param len Pointer to the remaining buffer length, updated as values |
205 | | * are consumed. |
206 | | * @param out1 Pointer to store the generated key. Will be NULL if key |
207 | | * generation fails due to invalid parameters. |
208 | | * @param out2 Unused output parameter (placeholder for symmetry with |
209 | | * other key generation functions). |
210 | | */ |
211 | | static void slh_dsa_gen_key_with_params(uint8_t **buf, size_t *len, |
212 | | void **out1, void **out2) |
213 | 38 | { |
214 | 38 | uint8_t selector = 0; |
215 | 38 | const char *keytype = NULL; |
216 | 38 | uint32_t keysize; |
217 | 38 | uint8_t pubbuf[PARAM_BUF_SZ]; /* expressly bigger than max key size * 3 */ |
218 | 38 | uint8_t prvbuf[PARAM_BUF_SZ]; /* expressly bigger than max key size * 3 */ |
219 | 38 | uint8_t sdbuf[PARAM_BUF_SZ]; /* expressly bigger than max key size * 3 */ |
220 | 38 | uint8_t *bufptr; |
221 | 38 | OSSL_PARAM params[3]; |
222 | 38 | size_t buflen; |
223 | 38 | uint8_t broken = 0; |
224 | | |
225 | 38 | *out1 = NULL; |
226 | | |
227 | 38 | *buf = consume_uint8t(*buf, len, &selector); |
228 | 38 | keytype = select_keytype(selector, &keysize); |
229 | | |
230 | 38 | if (!RAND_bytes(pubbuf, PARAM_BUF_SZ) |
231 | 38 | || !RAND_bytes(prvbuf, PARAM_BUF_SZ) |
232 | 38 | || !RAND_bytes(sdbuf, PARAM_BUF_SZ)) |
233 | 0 | return; |
234 | | |
235 | | /* |
236 | | * select an invalid length if the buffer 0th bit is one |
237 | | * make it too big if the 2nd bit is 0, smaller otherwise |
238 | | */ |
239 | 38 | buflen = keysize * 2; /* these params are 2 * the keysize */ |
240 | 38 | if ((*buf)[0] & 0x1) { |
241 | 14 | buflen = ((*buf)[0] & 0x2) ? buflen - 1 : buflen + 1; |
242 | 14 | broken = 1; |
243 | 14 | } |
244 | | |
245 | | /* pass a null buffer if the third bit of the buffer is 1 */ |
246 | 38 | bufptr = ((*buf)[0] & 0x4) ? NULL : pubbuf; |
247 | 38 | if (!broken) |
248 | 24 | broken = (bufptr == NULL) ? 1 : 0; |
249 | | |
250 | 38 | params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, |
251 | 38 | (char *)bufptr, buflen); |
252 | | |
253 | 38 | buflen = keysize * 2; |
254 | | /* select an invalid length if the 4th bit is true */ |
255 | 38 | if ((*buf)[0] & 0x8) { |
256 | 13 | buflen = (*buf[0] & 0x1) ? buflen - 1 : buflen + 1; |
257 | 13 | broken = 1; |
258 | 13 | } |
259 | | |
260 | | /* pass a null buffer if the 5th bit is true */ |
261 | 38 | bufptr = ((*buf)[0] & 0x10) ? NULL : prvbuf; |
262 | 38 | if (!broken) |
263 | 15 | broken = (bufptr == NULL) ? 1 : 0; |
264 | 38 | params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, |
265 | 38 | (char *)bufptr, buflen); |
266 | | |
267 | 38 | params[2] = OSSL_PARAM_construct_end(); |
268 | | |
269 | 38 | *out1 = (void *)slh_dsa_gen_key(keytype, keysize, params, &broken); |
270 | 38 | return; |
271 | 38 | } |
272 | | |
273 | | /** |
274 | | * @brief Frees allocated SLH-DSA key structures. |
275 | | * |
276 | | * This function releases memory allocated for SLH-DSA key pairs |
277 | | * by freeing the provided EVP_PKEY structures. |
278 | | * |
279 | | * @param in1 Pointer to the first input key to be freed. |
280 | | * @param in2 Pointer to the second input key to be freed. |
281 | | * @param out1 Pointer to the first output key to be freed. |
282 | | * @param out2 Pointer to the second output key to be freed. |
283 | | */ |
284 | | static void slh_dsa_clean_keys(void *in1, void *in2, void *out1, void *out2) |
285 | 1.55k | { |
286 | 1.55k | EVP_PKEY_free((EVP_PKEY *)in1); |
287 | 1.55k | EVP_PKEY_free((EVP_PKEY *)in2); |
288 | 1.55k | EVP_PKEY_free((EVP_PKEY *)out1); |
289 | 1.55k | EVP_PKEY_free((EVP_PKEY *)out2); |
290 | 1.55k | } |
291 | | |
292 | | /** |
293 | | * @brief Performs SLH-DSA signing and verification on a given message. |
294 | | * |
295 | | * This function generates an SLH-DSA key, signs a message, and verifies |
296 | | * the generated signature. It extracts necessary parameters from the buffer |
297 | | * to determine signing options. |
298 | | * |
299 | | * @param buf Pointer to a buffer containing the selector and message data. |
300 | | * The buffer pointer is updated as values are consumed. |
301 | | * @param len Pointer to the remaining buffer length, updated as values |
302 | | * are consumed. |
303 | | * @param key1 Unused key parameter (placeholder for function signature consistency). |
304 | | * @param key2 Unused key parameter (placeholder for function signature consistency). |
305 | | * @param out1 Pointer to store the generated key (for cleanup purposes). |
306 | | * @param out2 Unused output parameter (placeholder for consistency). |
307 | | */ |
308 | | static void slh_dsa_sign_verify(uint8_t **buf, size_t *len, void *key1, |
309 | | void *key2, void **out1, void **out2) |
310 | | { |
311 | | EVP_PKEY_CTX *ctx = NULL; |
312 | | EVP_PKEY *key = NULL; |
313 | | EVP_SIGNATURE *sig_alg = NULL; |
314 | | const char *keytype; |
315 | | uint32_t keylen; |
316 | | uint8_t selector = 0; |
317 | | unsigned char *msg = NULL; |
318 | | size_t msg_len; |
319 | | size_t sig_len; |
320 | | unsigned char *sig = NULL; |
321 | | OSSL_PARAM params[4]; |
322 | | int paramidx = 0; |
323 | | int intval1, intval2; |
324 | | |
325 | | *buf = consume_uint8t(*buf, len, &selector); |
326 | | if (*buf == NULL) |
327 | | return; |
328 | | |
329 | | keytype = select_keytype(selector, &keylen); |
330 | | |
331 | | /* |
332 | | * Consume another byte to figure out our params |
333 | | */ |
334 | | *buf = consume_uint8t(*buf, len, &selector); |
335 | | if (*buf == NULL) |
336 | | return; |
337 | | |
338 | | /* |
339 | | * Remainder of the buffer is the msg to sign |
340 | | */ |
341 | | msg = (unsigned char *)*buf; |
342 | | msg_len = *len; |
343 | | |
344 | | *len = 0; |
345 | | |
346 | | if (selector & 0x1) |
347 | | params[paramidx++] = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, |
348 | | msg, msg_len); |
349 | | |
350 | | if (selector & 0x2) { |
351 | | intval1 = selector & 0x4; |
352 | | params[paramidx++] = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, |
353 | | &intval1); |
354 | | } |
355 | | |
356 | | if (selector & 0x8) { |
357 | | intval2 = selector & 0x10; |
358 | | params[paramidx++] = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, |
359 | | &intval2); |
360 | | } |
361 | | |
362 | | params[paramidx] = OSSL_PARAM_construct_end(); |
363 | | |
364 | | key = (void *)slh_dsa_gen_key(keytype, keylen, NULL, 0); |
365 | | if (key == NULL) |
366 | | return; |
367 | | *out1 = key; /* for cleanup */ |
368 | | |
369 | | ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL); |
370 | | if (ctx == NULL) |
371 | | goto out; |
372 | | |
373 | | sig_alg = EVP_SIGNATURE_fetch(NULL, keytype, NULL); |
374 | | if (sig_alg == NULL) |
375 | | goto out; |
376 | | |
377 | | /* |
378 | | * the context_string parameter can be no more than 255 bytes, so if |
379 | | * our random input buffer is greater than that, sign_message_init will |
380 | | * fail, in which case there's nothing more we can do here so bail out |
381 | | */ |
382 | | if (EVP_PKEY_sign_message_init(ctx, sig_alg, params) != 1) |
383 | | goto out; |
384 | | |
385 | | if (EVP_PKEY_sign(ctx, NULL, &sig_len, msg, msg_len) != 1) |
386 | | goto out; |
387 | | sig = OPENSSL_zalloc(sig_len); |
388 | | if (sig == NULL) |
389 | | goto out; |
390 | | |
391 | | if (EVP_PKEY_sign(ctx, sig, &sig_len, msg, msg_len) != 1) |
392 | | goto out; |
393 | | |
394 | | if (EVP_PKEY_verify_message_init(ctx, sig_alg, params) != 1) |
395 | | goto out; |
396 | | if (EVP_PKEY_verify(ctx, sig, sig_len, msg, msg_len) != 1) |
397 | | fprintf(stderr, "Failed to verify message\n"); |
398 | | |
399 | | out: |
400 | | OPENSSL_free(sig); |
401 | | EVP_SIGNATURE_free(sig_alg); |
402 | | EVP_PKEY_CTX_free(ctx); |
403 | | } |
404 | | |
405 | | /** |
406 | | * @brief Exports and imports SLH-DSA key pairs, verifying equivalence. |
407 | | * |
408 | | * This function extracts key data from two given SLH-DSA keys (`alice` and `bob`), |
409 | | * reconstructs new keys from the extracted data, and verifies that the imported |
410 | | * keys are equivalent to the originals. It ensures that key export/import |
411 | | * functionality is working correctly. |
412 | | * |
413 | | * @param buf Unused buffer parameter (placeholder for function signature consistency). |
414 | | * @param len Unused length parameter (placeholder for function signature consistency). |
415 | | * @param key1 Pointer to the first key (`alice`) to be exported and imported. |
416 | | * @param key2 Pointer to the second key (`bob`) to be exported and imported. |
417 | | * @param out1 Unused output parameter (placeholder for consistency). |
418 | | * @param out2 Unused output parameter (placeholder for consistency). |
419 | | */ |
420 | | static void slh_dsa_export_import(uint8_t **buf, size_t *len, void *key1, |
421 | | void *key2, void **out1, void **out2) |
422 | 56 | { |
423 | 56 | EVP_PKEY *alice = (EVP_PKEY *)key1; |
424 | 56 | EVP_PKEY *bob = (EVP_PKEY *)key2; |
425 | 56 | EVP_PKEY *new = NULL; |
426 | 56 | EVP_PKEY_CTX *ctx = NULL; |
427 | 56 | OSSL_PARAM *params = NULL; |
428 | | |
429 | 56 | if (alice == NULL || bob == NULL) |
430 | 0 | return; |
431 | | |
432 | 56 | if (!EVP_PKEY_todata(alice, EVP_PKEY_KEYPAIR, ¶ms)) |
433 | 0 | goto alice_done; |
434 | | |
435 | 56 | ctx = EVP_PKEY_CTX_new_from_pkey(NULL, alice, NULL); |
436 | 56 | if (ctx == NULL) |
437 | 0 | goto alice_done; |
438 | | |
439 | 56 | if (!EVP_PKEY_fromdata_init(ctx)) |
440 | 0 | goto alice_done; |
441 | | |
442 | 56 | new = EVP_PKEY_new(); |
443 | 56 | if (new == NULL) |
444 | 0 | goto alice_done; |
445 | 56 | if (EVP_PKEY_fromdata(ctx, &new, EVP_PKEY_KEYPAIR, params) != 1) |
446 | 0 | goto alice_done; |
447 | | |
448 | 56 | (void)EVP_PKEY_eq(alice, new); |
449 | | |
450 | 56 | alice_done: |
451 | 56 | EVP_PKEY_free(new); |
452 | 56 | EVP_PKEY_CTX_free(ctx); |
453 | 56 | OSSL_PARAM_free(params); |
454 | 56 | params = NULL; |
455 | 56 | ctx = NULL; |
456 | 56 | new = NULL; |
457 | | |
458 | 56 | if (!EVP_PKEY_todata(bob, EVP_PKEY_KEYPAIR, ¶ms)) |
459 | 0 | goto bob_done; |
460 | | |
461 | 56 | ctx = EVP_PKEY_CTX_new_from_pkey(NULL, bob, NULL); |
462 | 56 | if (ctx == NULL) |
463 | 0 | goto bob_done; |
464 | | |
465 | 56 | if (!EVP_PKEY_fromdata_init(ctx)) |
466 | 0 | goto bob_done; |
467 | | |
468 | 56 | new = EVP_PKEY_new(); |
469 | 56 | if (new == NULL) |
470 | 0 | goto bob_done; |
471 | 56 | if (EVP_PKEY_fromdata(ctx, &new, EVP_PKEY_KEYPAIR, params) != 1) |
472 | 0 | goto bob_done; |
473 | | |
474 | 56 | (void)EVP_PKEY_eq(bob, new); |
475 | 56 | (void)EVP_PKEY_eq(alice, new); |
476 | | |
477 | 56 | bob_done: |
478 | 56 | EVP_PKEY_CTX_free(ctx); |
479 | 56 | EVP_PKEY_free(new); |
480 | 56 | OSSL_PARAM_free(params); |
481 | 56 | } |
482 | | |
483 | | /** |
484 | | * @brief Represents an operation table entry for cryptographic operations. |
485 | | * |
486 | | * This structure defines a table entry containing function pointers for |
487 | | * setting up, executing, and cleaning up cryptographic operations, along |
488 | | * with associated metadata such as a name and description. |
489 | | * |
490 | | * @struct op_table_entry |
491 | | */ |
492 | | struct op_table_entry { |
493 | | /** Name of the operation. */ |
494 | | char *name; |
495 | | |
496 | | /** |
497 | | * @brief Function pointer for setting up the operation. |
498 | | * |
499 | | * @param buf Pointer to the buffer pointer; may be updated. |
500 | | * @param len Pointer to the remaining buffer size; may be updated. |
501 | | * @param out1 Pointer to store the first output of the setup function. |
502 | | * @param out2 Pointer to store the second output of the setup function. |
503 | | */ |
504 | | void (*setup)(uint8_t **buf, size_t *len, void **out1, void **out2); |
505 | | |
506 | | /** |
507 | | * @brief Function pointer for executing the operation. |
508 | | * |
509 | | * @param buf Pointer to the buffer pointer; may be updated. |
510 | | * @param len Pointer to the remaining buffer size; may be updated. |
511 | | * @param in1 First input parameter for the operation. |
512 | | * @param in2 Second input parameter for the operation. |
513 | | * @param out1 Pointer to store the first output of the operation. |
514 | | * @param out2 Pointer to store the second output of the operation. |
515 | | */ |
516 | | void (*doit)(uint8_t **buf, size_t *len, void *in1, void *in2, |
517 | | void **out1, void **out2); |
518 | | |
519 | | /** |
520 | | * @brief Function pointer for cleaning up after the operation. |
521 | | * |
522 | | * @param in1 First input parameter to be cleaned up. |
523 | | * @param in2 Second input parameter to be cleaned up. |
524 | | * @param out1 First output parameter to be cleaned up. |
525 | | * @param out2 Second output parameter to be cleaned up. |
526 | | */ |
527 | | void (*cleanup)(void *in1, void *in2, void *out1, void *out2); |
528 | | }; |
529 | | |
530 | | static struct op_table_entry ops[] = { |
531 | | { "Generate SLH-DSA keys", |
532 | | slh_dsa_gen_keys, |
533 | | NULL, |
534 | | slh_dsa_clean_keys }, |
535 | | { "Generate SLH-DSA keys with params", |
536 | | slh_dsa_gen_key_with_params, |
537 | | NULL, |
538 | | slh_dsa_clean_keys }, |
539 | | { "SLH-DSA Export/Import", |
540 | | slh_dsa_gen_keys, |
541 | | slh_dsa_export_import, |
542 | | slh_dsa_clean_keys }, |
543 | | { "SLH-DSA sign and verify", |
544 | | NULL, |
545 | | slh_dsa_sign_verify, |
546 | | slh_dsa_clean_keys } |
547 | | }; |
548 | | |
549 | | int FuzzerInitialize(int *argc, char ***argv) |
550 | 229 | { |
551 | 229 | return 0; |
552 | 229 | } |
553 | | |
554 | | /** |
555 | | * @brief Processes a fuzzing input by selecting and executing an operation. |
556 | | * |
557 | | * This function interprets the first byte of the input buffer to determine |
558 | | * an operation to execute. It then follows a setup, execution, and cleanup |
559 | | * sequence based on the selected operation. |
560 | | * |
561 | | * @param buf Pointer to the input buffer. |
562 | | * @param len Length of the input buffer. |
563 | | * |
564 | | * @return 0 on successful execution, -1 if the input is too short. |
565 | | * |
566 | | * @note The function requires at least 32 bytes in the buffer to proceed. |
567 | | * It utilizes the `ops` operation table to dynamically determine and |
568 | | * execute the selected operation. |
569 | | */ |
570 | | int FuzzerTestOneInput(const uint8_t *buf, size_t len) |
571 | 663 | { |
572 | 663 | uint8_t operation; |
573 | 663 | uint8_t *buffer_cursor; |
574 | 663 | void *in1 = NULL, *in2 = NULL; |
575 | 663 | void *out1 = NULL, *out2 = NULL; |
576 | | |
577 | 663 | if (len < 32) |
578 | 24 | return -1; |
579 | | /* |
580 | | * Get the first byte of the buffer to tell us what operation |
581 | | * to perform |
582 | | */ |
583 | 639 | buffer_cursor = consume_uint8t(buf, &len, &operation); |
584 | 639 | if (buffer_cursor == NULL) |
585 | 0 | return -1; |
586 | | |
587 | | /* |
588 | | * Adjust for operational array size |
589 | | */ |
590 | 639 | operation %= OSSL_NELEM(ops); |
591 | | |
592 | | /* |
593 | | * And run our setup/doit/cleanup sequence |
594 | | */ |
595 | 639 | if (ops[operation].setup != NULL) |
596 | 634 | ops[operation].setup(&buffer_cursor, &len, &in1, &in2); |
597 | 639 | if (ops[operation].doit != NULL && in1 != NULL) |
598 | 417 | ops[operation].doit(&buffer_cursor, &len, in1, in2, &out1, &out2); |
599 | 639 | if (ops[operation].cleanup != NULL) |
600 | 639 | ops[operation].cleanup(in1, in2, out1, out2); |
601 | | |
602 | 639 | return 0; |
603 | 639 | } |
604 | | |
605 | | void FuzzerCleanup(void) |
606 | 0 | { |
607 | 0 | OPENSSL_cleanup(); |
608 | 0 | } |