Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/fuzz/ml-dsa.c
107539 views
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
/* Test ML-DSA operation. */
12
#include <string.h>
13
#include <openssl/evp.h>
14
#include <openssl/err.h>
15
#include <openssl/rand.h>
16
#include <openssl/byteorder.h>
17
#include "internal/nelem.h"
18
#include "fuzzer.h"
19
#include "crypto/ml_dsa.h"
20
21
/**
22
* @brief Consumes an 8-bit unsigned integer from a buffer.
23
*
24
* This function extracts an 8-bit unsigned integer from the provided buffer,
25
* updates the buffer pointer, and adjusts the remaining length.
26
*
27
* @param buf Pointer to the input buffer.
28
* @param len Pointer to the size of the remaining buffer; updated after consumption.
29
* @param val Pointer to store the extracted 8-bit value.
30
*
31
* @return Pointer to the updated buffer position after reading the value,
32
* or NULL if the buffer does not contain enough data.
33
*/
34
static uint8_t *consume_uint8_t(const uint8_t *buf, size_t *len, uint8_t *val)
35
{
36
if (*len < sizeof(uint8_t))
37
return NULL;
38
*val = *buf;
39
*len -= sizeof(uint8_t);
40
return (uint8_t *)buf + 1;
41
}
42
43
/**
44
* @brief Consumes a size_t from a buffer.
45
*
46
* This function extracts a size_t from the provided buffer, updates the buffer
47
* pointer, and adjusts the remaining length.
48
*
49
* @param buf Pointer to the input buffer.
50
* @param len Pointer to the size of the remaining buffer; updated after consumption.
51
* @param val Pointer to store the extracted size_t value.
52
*
53
* @return Pointer to the updated buffer position after reading the value,
54
* or NULL if the buffer does not contain enough data.
55
*/
56
static uint8_t *consume_size_t(const uint8_t *buf, size_t *len, size_t *val)
57
{
58
if (*len < sizeof(size_t))
59
return NULL;
60
*val = *buf;
61
*len -= sizeof(size_t);
62
return (uint8_t *)buf + sizeof(size_t);
63
}
64
65
/**
66
* @brief Selects a key type and size from a buffer.
67
*
68
* This function reads a key size value from the buffer, determines the
69
* corresponding key type and length, and updates the buffer pointer
70
* accordingly. If `only_valid` is set, it restricts selection to valid key
71
* sizes; otherwise, it includes some invalid sizes for testing.
72
*
73
* @param buf Pointer to the buffer pointer; updated after reading.
74
* @param len Pointer to the remaining buffer size; updated accordingly.
75
* @param keytype Pointer to store the selected key type string.
76
* @param keylen Pointer to store the selected key length.
77
* @param only_valid Flag to restrict selection to valid key sizes.
78
*
79
* @return 1 if a key type is successfully selected, 0 on failure.
80
*/
81
static int select_keytype_and_size(uint8_t **buf, size_t *len,
82
char **keytype, size_t *keylen,
83
int only_valid)
84
{
85
uint16_t keysize;
86
uint16_t modulus = 6;
87
88
/*
89
* Note: We don't really care about endianness here, we just want a random
90
* 16 bit value
91
*/
92
*buf = (uint8_t *)OPENSSL_load_u16_le(&keysize, *buf);
93
*len -= sizeof(uint16_t);
94
95
if (*buf == NULL)
96
return 0;
97
98
/*
99
* If `only_valid` is set, select only ML-DSA-44, ML-DSA-65, and ML-DSA-87.
100
* Otherwise, include some invalid sizes to trigger error paths.
101
*/
102
103
if (only_valid)
104
modulus = 3;
105
106
/*
107
* Note, keylens for valid values (cases 0-2) are taken based on input
108
* values from our unit tests
109
*/
110
switch (keysize % modulus) {
111
case 0:
112
*keytype = "ML-DSA-44";
113
*keylen = ML_DSA_44_PUB_LEN;
114
break;
115
case 1:
116
*keytype = "ML-DSA-65";
117
*keylen = ML_DSA_65_PUB_LEN;
118
break;
119
case 2:
120
*keytype = "ML-DSA-87";
121
*keylen = ML_DSA_87_PUB_LEN;
122
break;
123
case 3:
124
/* select invalid alg */
125
*keytype = "ML-DSA-33";
126
*keylen = 33;
127
break;
128
case 4:
129
/* Select valid alg, but bogus size */
130
*keytype = "ML-DSA-87";
131
*buf = (uint8_t *)OPENSSL_load_u16_le(&keysize, *buf);
132
*len -= sizeof(uint16_t);
133
*keylen = (size_t)keysize;
134
*keylen %= ML_DSA_87_PUB_LEN; /* size to our key buffer */
135
break;
136
default:
137
*keytype = NULL;
138
*keylen = 0;
139
break;
140
}
141
return 1;
142
}
143
144
/**
145
* @brief Creates an ML-DSA raw key from a buffer.
146
*
147
* This function selects a key type and size from the buffer, generates a random
148
* key of the appropriate length, and creates either a public or private ML-DSA
149
* key using OpenSSL's EVP_PKEY interface.
150
*
151
* @param buf Pointer to the buffer pointer; updated after reading.
152
* @param len Pointer to the remaining buffer size; updated accordingly.
153
* @param key1 Pointer to store the generated EVP_PKEY key (public or private).
154
* @param key2 Unused parameter (reserved for future use).
155
*
156
* @note The generated key is allocated using OpenSSL's EVP_PKEY functions
157
* and should be freed appropriately using `EVP_PKEY_free()`.
158
*/
159
static void create_ml_dsa_raw_key(uint8_t **buf, size_t *len,
160
void **key1, void **key2)
161
{
162
EVP_PKEY *pubkey;
163
char *keytype = NULL;
164
size_t keylen = 0;
165
/* MAX_ML_DSA_PRIV_LEN is longer of that and ML_DSA_87_PUB_LEN */
166
uint8_t key[MAX_ML_DSA_PRIV_LEN];
167
int pub = 0;
168
169
if (!select_keytype_and_size(buf, len, &keytype, &keylen, 0))
170
return;
171
172
/*
173
* Select public or private key creation based on the low order bit of the
174
* next buffer value.
175
* Note that keylen as returned from select_keytype_and_size is a public key
176
* length, so make the adjustment to private key lengths here.
177
*/
178
if ((*buf)[0] & 0x1) {
179
pub = 1;
180
} else {
181
switch (keylen) {
182
case (ML_DSA_44_PUB_LEN):
183
keylen = ML_DSA_44_PRIV_LEN;
184
break;
185
case (ML_DSA_65_PUB_LEN):
186
keylen = ML_DSA_65_PRIV_LEN;
187
break;
188
case (ML_DSA_87_PUB_LEN):
189
keylen = ML_DSA_87_PRIV_LEN;
190
break;
191
default:
192
return;
193
}
194
}
195
196
/*
197
* libfuzzer provides by default up to 4096 bit input buffers, but it's
198
* typically much less (between 1 and 100 bytes) so use RAND_bytes here
199
* instead
200
*/
201
if (!RAND_bytes(key, keylen))
202
return;
203
204
/*
205
* Try to generate either a raw public or private key using random data
206
* Because the input is completely random, it's effectively certain this
207
* operation will fail, but it will still exercise the code paths below,
208
* which is what we want the fuzzer to do
209
*/
210
if (pub == 1)
211
pubkey = EVP_PKEY_new_raw_public_key_ex(NULL, keytype, NULL, key, keylen);
212
else
213
pubkey = EVP_PKEY_new_raw_private_key_ex(NULL, keytype, NULL, key, keylen);
214
215
*key1 = pubkey;
216
return;
217
}
218
219
static int keygen_ml_dsa_real_key_helper(uint8_t **buf, size_t *len,
220
EVP_PKEY **key)
221
{
222
char *keytype = NULL;
223
size_t keylen = 0;
224
EVP_PKEY_CTX *ctx = NULL;
225
int ret = 0;
226
227
/*
228
* Only generate valid key types and lengths. Note, no adjustment is made to
229
* keylen here, as the provider is responsible for selecting the keys and
230
* sizes for us during the EVP_PKEY_keygen call
231
*/
232
if (!select_keytype_and_size(buf, len, &keytype, &keylen, 1))
233
goto err;
234
235
ctx = EVP_PKEY_CTX_new_from_name(NULL, keytype, NULL);
236
if (!ctx) {
237
fprintf(stderr, "Failed to generate ctx\n");
238
goto err;
239
}
240
241
if (!EVP_PKEY_keygen_init(ctx)) {
242
fprintf(stderr, "Failed to init keygen ctx\n");
243
goto err;
244
}
245
246
*key = EVP_PKEY_new();
247
if (*key == NULL)
248
goto err;
249
250
if (!EVP_PKEY_generate(ctx, key)) {
251
fprintf(stderr, "Failed to generate new real key\n");
252
goto err;
253
}
254
255
ret = 1;
256
err:
257
EVP_PKEY_CTX_free(ctx);
258
return ret;
259
}
260
261
/**
262
* @brief Generates a valid ML-DSA key using OpenSSL.
263
*
264
* This function selects a valid ML-DSA key type and size from the buffer,
265
* initializes an OpenSSL EVP_PKEY context, and generates a cryptographic key
266
* accordingly.
267
*
268
* @param buf Pointer to the buffer pointer; updated after reading.
269
* @param len Pointer to the remaining buffer size; updated accordingly.
270
* @param key1 Pointer to store the first generated EVP_PKEY key.
271
* @param key2 Pointer to store the second generated EVP_PKEY key.
272
*
273
* @note The generated key is allocated using OpenSSL's EVP_PKEY functions
274
* and should be freed using `EVP_PKEY_free()`.
275
*/
276
static void keygen_ml_dsa_real_key(uint8_t **buf, size_t *len,
277
void **key1, void **key2)
278
{
279
if (!keygen_ml_dsa_real_key_helper(buf, len, (EVP_PKEY **)key1)
280
|| !keygen_ml_dsa_real_key_helper(buf, len, (EVP_PKEY **)key2))
281
fprintf(stderr, "Unable to generate valid keys");
282
}
283
284
/**
285
* @brief Performs key sign and verify using an EVP_PKEY.
286
*
287
* This function generates a random key, signs random data using the provided
288
* public key, then verifies it. It makes use of OpenSSL's EVP_PKEY API for
289
* encryption and decryption.
290
*
291
* @param[out] buf Unused output buffer (reserved for future use).
292
* @param[out] len Unused length parameter (reserved for future use).
293
* @param[in] key1 Pointer to an EVP_PKEY structure used for key operations.
294
* @param[in] in2 Unused input parameter (reserved for future use).
295
* @param[out] out1 Unused output parameter (reserved for future use).
296
* @param[out] out2 Unused output parameter (reserved for future use).
297
*/
298
static void ml_dsa_sign_verify(uint8_t **buf, size_t *len, void *key1,
299
void *in2, void **out1, void **out2)
300
{
301
EVP_PKEY *key = (EVP_PKEY *)key1;
302
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL);
303
EVP_SIGNATURE *sig_alg = NULL;
304
unsigned char *sig = NULL;
305
size_t sig_len = 0, tbslen;
306
unsigned char *tbs = NULL;
307
/* Ownership of alg is retained by the pkey object */
308
const char *alg = EVP_PKEY_get0_type_name(key);
309
const OSSL_PARAM params[] = {
310
OSSL_PARAM_octet_string("context-string",
311
(unsigned char *)"A context string", 16),
312
OSSL_PARAM_END
313
};
314
315
if (!consume_size_t(*buf, len, &tbslen)) {
316
fprintf(stderr, "Failed to set tbslen");
317
goto err;
318
}
319
/* Keep tbslen within a reasonable value we can malloc */
320
tbslen = (tbslen % 2048) + 1;
321
322
if ((tbs = OPENSSL_malloc(tbslen)) == NULL
323
|| ctx == NULL || alg == NULL
324
|| !RAND_bytes_ex(NULL, tbs, tbslen, 0)) {
325
fprintf(stderr, "Failed basic initialization\n");
326
goto err;
327
}
328
329
/*
330
* Because ML-DSA is fundamentally a one-shot algorithm like "pure" Ed25519
331
* and Ed448, we don't have any immediate plans to implement intermediate
332
* sign/verify functions. Therefore, we only test the one-shot functions.
333
*/
334
335
if ((sig_alg = EVP_SIGNATURE_fetch(NULL, alg, NULL)) == NULL
336
|| EVP_PKEY_sign_message_init(ctx, sig_alg, params) <= 0
337
|| EVP_PKEY_sign(ctx, NULL, &sig_len, tbs, tbslen) <= 0
338
|| (sig = OPENSSL_zalloc(sig_len)) == NULL
339
|| EVP_PKEY_sign(ctx, sig, &sig_len, tbs, tbslen) <= 0) {
340
fprintf(stderr, "Failed to sign message\n");
341
goto err;
342
}
343
344
/* Verify signature */
345
EVP_PKEY_CTX_free(ctx);
346
ctx = NULL;
347
348
if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL)) == NULL
349
|| EVP_PKEY_verify_message_init(ctx, sig_alg, params) <= 0
350
|| EVP_PKEY_verify(ctx, sig, sig_len, tbs, tbslen) <= 0) {
351
fprintf(stderr, "Failed to verify message\n");
352
goto err;
353
}
354
355
err:
356
OPENSSL_free(tbs);
357
EVP_PKEY_CTX_free(ctx);
358
EVP_SIGNATURE_free(sig_alg);
359
OPENSSL_free(sig);
360
return;
361
}
362
363
/**
364
* @brief Performs key sign and verify using an EVP_PKEY.
365
*
366
* This function generates a random key, signs random data using the provided
367
* public key, then verifies it. It makes use of OpenSSL's EVP_PKEY API for
368
* encryption and decryption.
369
*
370
* @param[out] buf Unused output buffer (reserved for future use).
371
* @param[out] len Unused length parameter (reserved for future use).
372
* @param[in] key1 Pointer to an EVP_PKEY structure used for key operations.
373
* @param[in] in2 Unused input parameter (reserved for future use).
374
* @param[out] out1 Unused output parameter (reserved for future use).
375
* @param[out] out2 Unused output parameter (reserved for future use).
376
*/
377
static void ml_dsa_digest_sign_verify(uint8_t **buf, size_t *len, void *key1,
378
void *in2, void **out1, void **out2)
379
{
380
EVP_PKEY *key = (EVP_PKEY *)key1;
381
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
382
EVP_SIGNATURE *sig_alg = NULL;
383
unsigned char *sig = NULL;
384
size_t sig_len, tbslen;
385
unsigned char *tbs = NULL;
386
const OSSL_PARAM params[] = {
387
OSSL_PARAM_octet_string("context-string",
388
(unsigned char *)"A context string", 16),
389
OSSL_PARAM_END
390
};
391
392
if (!consume_size_t(*buf, len, &tbslen)) {
393
fprintf(stderr, "Failed to set tbslen");
394
goto err;
395
}
396
/* Keep tbslen within a reasonable value we can malloc */
397
tbslen = (tbslen % 2048) + 1;
398
399
if ((tbs = OPENSSL_malloc(tbslen)) == NULL
400
|| ctx == NULL
401
|| !RAND_bytes_ex(NULL, tbs, tbslen, 0)) {
402
fprintf(stderr, "Failed basic initialization\n");
403
goto err;
404
}
405
406
/*
407
* Because ML-DSA is fundamentally a one-shot algorithm like "pure" Ed25519
408
* and Ed448, we don't have any immediate plans to implement intermediate
409
* sign/verify functions. Therefore, we only test the one-shot functions.
410
*/
411
412
if (!EVP_DigestSignInit_ex(ctx, NULL, NULL, NULL, "?fips=true", key, params)
413
|| EVP_DigestSign(ctx, NULL, &sig_len, tbs, tbslen) <= 0
414
|| (sig = OPENSSL_malloc(sig_len)) == NULL
415
|| EVP_DigestSign(ctx, sig, &sig_len, tbs, tbslen) <= 0) {
416
fprintf(stderr, "Failed to sign digest with EVP_DigestSign\n");
417
goto err;
418
}
419
420
/* Verify signature */
421
EVP_MD_CTX_free(ctx);
422
ctx = NULL;
423
424
if ((ctx = EVP_MD_CTX_new()) == NULL
425
|| EVP_DigestVerifyInit_ex(ctx, NULL, NULL, NULL, "?fips=true", key,
426
params)
427
<= 0
428
|| EVP_DigestVerify(ctx, sig, sig_len, tbs, tbslen) <= 0) {
429
fprintf(stderr, "Failed to verify digest with EVP_DigestVerify\n");
430
goto err;
431
}
432
433
err:
434
OPENSSL_free(tbs);
435
EVP_MD_CTX_free(ctx);
436
EVP_SIGNATURE_free(sig_alg);
437
OPENSSL_free(sig);
438
return;
439
}
440
441
/**
442
* @brief Exports and imports an ML-DSA key.
443
*
444
* This function extracts key material from the given key (`key1`), exports it
445
* as parameters, and then attempts to reconstruct a new key from those
446
* parameters. It uses OpenSSL's `EVP_PKEY_todata()` and `EVP_PKEY_fromdata()`
447
* functions for this process.
448
*
449
* @param[out] buf Unused output buffer (reserved for future use).
450
* @param[out] len Unused output length (reserved for future use).
451
* @param[in] key1 The key to be exported and imported.
452
* @param[in] key2 Unused input key (reserved for future use).
453
* @param[out] out1 Unused output parameter (reserved for future use).
454
* @param[out] out2 Unused output parameter (reserved for future use).
455
*
456
* @note If any step in the export-import process fails, the function
457
* logs an error and cleans up allocated resources.
458
*/
459
static void ml_dsa_export_import(uint8_t **buf, size_t *len, void *key1,
460
void *key2, void **out1, void **out2)
461
{
462
EVP_PKEY *alice = (EVP_PKEY *)key1;
463
EVP_PKEY *new_key = NULL;
464
EVP_PKEY_CTX *ctx = NULL;
465
OSSL_PARAM *params = NULL;
466
467
if (!EVP_PKEY_todata(alice, EVP_PKEY_KEYPAIR, &params)) {
468
fprintf(stderr, "Failed todata\n");
469
goto err;
470
}
471
472
ctx = EVP_PKEY_CTX_new_from_pkey(NULL, alice, NULL);
473
if (ctx == NULL) {
474
fprintf(stderr, "Failed new ctx\n");
475
goto err;
476
}
477
478
if (!EVP_PKEY_fromdata(ctx, &new_key, EVP_PKEY_KEYPAIR, params)) {
479
fprintf(stderr, "Failed fromdata\n");
480
goto err;
481
}
482
483
err:
484
EVP_PKEY_CTX_free(ctx);
485
EVP_PKEY_free(new_key);
486
OSSL_PARAM_free(params);
487
}
488
489
/**
490
* @brief Compares two cryptographic keys and performs equality checks.
491
*
492
* This function takes in two cryptographic keys, casts them to `EVP_PKEY`
493
* structures, and checks their equality using `EVP_PKEY_eq()`. The purpose of
494
* `buf`, `len`, `out1`, and `out2` parameters is not clear from the function's
495
* current implementation.
496
*
497
* @param buf Unused parameter (purpose unclear).
498
* @param len Unused parameter (purpose unclear).
499
* @param key1 First key, expected to be an `EVP_PKEY *`.
500
* @param key2 Second key, expected to be an `EVP_PKEY *`.
501
* @param out1 Unused parameter (purpose unclear).
502
* @param out2 Unused parameter (purpose unclear).
503
*/
504
static void ml_dsa_compare(uint8_t **buf, size_t *len, void *key1,
505
void *key2, void **out1, void **out2)
506
{
507
EVP_PKEY *alice = (EVP_PKEY *)key1;
508
EVP_PKEY *bob = (EVP_PKEY *)key2;
509
510
EVP_PKEY_eq(alice, alice);
511
EVP_PKEY_eq(alice, bob);
512
}
513
514
/**
515
* @brief Frees allocated ML-DSA keys.
516
*
517
* This function releases memory associated with up to four EVP_PKEY objects by
518
* calling `EVP_PKEY_free()` on each provided key.
519
*
520
* @param key1 Pointer to the first key to be freed.
521
* @param key2 Pointer to the second key to be freed.
522
* @param key3 Pointer to the third key to be freed.
523
* @param key4 Pointer to the fourth key to be freed.
524
*
525
* @note This function assumes that each key is either a valid EVP_PKEY
526
* object or NULL. Passing NULL is safe and has no effect.
527
*/
528
static void cleanup_ml_dsa_keys(void *key1, void *key2,
529
void *key3, void *key4)
530
{
531
EVP_PKEY_free((EVP_PKEY *)key1);
532
EVP_PKEY_free((EVP_PKEY *)key2);
533
EVP_PKEY_free((EVP_PKEY *)key3);
534
EVP_PKEY_free((EVP_PKEY *)key4);
535
}
536
537
/**
538
* @brief Represents an operation table entry for cryptographic operations.
539
*
540
* This structure defines a table entry containing function pointers for setting
541
* up, executing, and cleaning up cryptographic operations, along with
542
* associated metadata such as a name and description.
543
*
544
* @struct op_table_entry
545
*/
546
struct op_table_entry {
547
/** Name of the operation. */
548
char *name;
549
550
/** Description of the operation. */
551
char *desc;
552
553
/**
554
* @brief Function pointer for setting up the operation.
555
*
556
* @param buf Pointer to the buffer pointer; may be updated.
557
* @param len Pointer to the remaining buffer size; may be updated.
558
* @param out1 Pointer to store the first output of the setup function.
559
* @param out2 Pointer to store the second output of the setup function.
560
*/
561
void (*setup)(uint8_t **buf, size_t *len, void **out1, void **out2);
562
563
/**
564
* @brief Function pointer for executing the operation.
565
*
566
* @param buf Pointer to the buffer pointer; may be updated.
567
* @param len Pointer to the remaining buffer size; may be updated.
568
* @param in1 First input parameter for the operation.
569
* @param in2 Second input parameter for the operation.
570
* @param out1 Pointer to store the first output of the operation.
571
* @param out2 Pointer to store the second output of the operation.
572
*/
573
void (*doit)(uint8_t **buf, size_t *len, void *in1, void *in2,
574
void **out1, void **out2);
575
576
/**
577
* @brief Function pointer for cleaning up after the operation.
578
*
579
* @param in1 First input parameter to be cleaned up.
580
* @param in2 Second input parameter to be cleaned up.
581
* @param out1 First output parameter to be cleaned up.
582
* @param out2 Second output parameter to be cleaned up.
583
*/
584
void (*cleanup)(void *in1, void *in2, void *out1, void *out2);
585
};
586
587
static struct op_table_entry ops[] = {
588
{ "Generate ML-DSA raw key",
589
"Try generate a raw keypair using random data. Usually fails",
590
create_ml_dsa_raw_key,
591
NULL,
592
cleanup_ml_dsa_keys },
593
{ "Generate ML-DSA keypair, using EVP_PKEY_keygen",
594
"Generates a real ML-DSA keypair, should always work",
595
keygen_ml_dsa_real_key,
596
NULL,
597
cleanup_ml_dsa_keys },
598
{ "Do a sign/verify operation on a key",
599
"Generate key, sign random data, verify it, should work",
600
keygen_ml_dsa_real_key,
601
ml_dsa_sign_verify,
602
cleanup_ml_dsa_keys },
603
{ "Do a digest sign/verify operation on a key",
604
"Generate key, digest sign random data, verify it, should work",
605
keygen_ml_dsa_real_key,
606
ml_dsa_digest_sign_verify,
607
cleanup_ml_dsa_keys },
608
{ "Do an export/import of key data",
609
"Exercise EVP_PKEY_todata/fromdata",
610
keygen_ml_dsa_real_key,
611
ml_dsa_export_import,
612
cleanup_ml_dsa_keys },
613
{ "Compare keys for equality",
614
"Compare key1/key1 and key1/key2 for equality",
615
keygen_ml_dsa_real_key,
616
ml_dsa_compare,
617
cleanup_ml_dsa_keys }
618
};
619
620
int FuzzerInitialize(int *argc, char ***argv)
621
{
622
return 0;
623
}
624
625
/**
626
* @brief Processes a fuzzing input by selecting and executing an operation.
627
*
628
* This function interprets the first byte of the input buffer to determine an
629
* operation to execute. It then follows a setup, execution, and cleanup
630
* sequence based on the selected operation.
631
*
632
* @param buf Pointer to the input buffer.
633
* @param len Length of the input buffer.
634
*
635
* @return 0 on successful execution, -1 if the input is too short.
636
*
637
* @note The function requires at least 32 bytes in the buffer to proceed.
638
* It utilizes the `ops` operation table to dynamically determine and
639
* execute the selected operation.
640
*/
641
int FuzzerTestOneInput(const uint8_t *buf, size_t len)
642
{
643
uint8_t operation;
644
uint8_t *buffer_cursor;
645
void *in1 = NULL, *in2 = NULL;
646
void *out1 = NULL, *out2 = NULL;
647
648
if (len < 32)
649
return -1;
650
651
/* Get the first byte of the buffer to tell us what operation to perform */
652
buffer_cursor = consume_uint8_t(buf, &len, &operation);
653
if (buffer_cursor == NULL)
654
return -1;
655
656
/* Adjust for operational array size */
657
operation %= OSSL_NELEM(ops);
658
659
/* And run our setup/doit/cleanup sequence */
660
if (ops[operation].setup != NULL)
661
ops[operation].setup(&buffer_cursor, &len, &in1, &in2);
662
if (ops[operation].doit != NULL)
663
ops[operation].doit(&buffer_cursor, &len, in1, in2, &out1, &out2);
664
if (ops[operation].cleanup != NULL)
665
ops[operation].cleanup(in1, in2, out1, out2);
666
667
return 0;
668
}
669
670
void FuzzerCleanup(void)
671
{
672
OPENSSL_cleanup();
673
}
674
675