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