Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/fuzz/ml-dsa.c
34878 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) <= 0
427
|| EVP_DigestVerify(ctx, sig, sig_len, tbs, tbslen) <= 0) {
428
fprintf(stderr, "Failed to verify digest with EVP_DigestVerify\n");
429
goto err;
430
}
431
432
err:
433
OPENSSL_free(tbs);
434
EVP_MD_CTX_free(ctx);
435
EVP_SIGNATURE_free(sig_alg);
436
OPENSSL_free(sig);
437
return;
438
}
439
440
/**
441
* @brief Exports and imports an ML-DSA key.
442
*
443
* This function extracts key material from the given key (`key1`), exports it
444
* as parameters, and then attempts to reconstruct a new key from those
445
* parameters. It uses OpenSSL's `EVP_PKEY_todata()` and `EVP_PKEY_fromdata()`
446
* functions for this process.
447
*
448
* @param[out] buf Unused output buffer (reserved for future use).
449
* @param[out] len Unused output length (reserved for future use).
450
* @param[in] key1 The key to be exported and imported.
451
* @param[in] key2 Unused input key (reserved for future use).
452
* @param[out] out1 Unused output parameter (reserved for future use).
453
* @param[out] out2 Unused output parameter (reserved for future use).
454
*
455
* @note If any step in the export-import process fails, the function
456
* logs an error and cleans up allocated resources.
457
*/
458
static void ml_dsa_export_import(uint8_t **buf, size_t *len, void *key1,
459
void *key2, void **out1, void **out2)
460
{
461
EVP_PKEY *alice = (EVP_PKEY *)key1;
462
EVP_PKEY *new_key = NULL;
463
EVP_PKEY_CTX *ctx = NULL;
464
OSSL_PARAM *params = NULL;
465
466
if (!EVP_PKEY_todata(alice, EVP_PKEY_KEYPAIR, &params)) {
467
fprintf(stderr, "Failed todata\n");
468
goto err;
469
}
470
471
ctx = EVP_PKEY_CTX_new_from_pkey(NULL, alice, NULL);
472
if (ctx == NULL) {
473
fprintf(stderr, "Failed new ctx\n");
474
goto err;
475
}
476
477
if (!EVP_PKEY_fromdata(ctx, &new_key, EVP_PKEY_KEYPAIR, params)) {
478
fprintf(stderr, "Failed fromdata\n");
479
goto err;
480
}
481
482
err:
483
EVP_PKEY_CTX_free(ctx);
484
EVP_PKEY_free(new_key);
485
OSSL_PARAM_free(params);
486
}
487
488
/**
489
* @brief Compares two cryptographic keys and performs equality checks.
490
*
491
* This function takes in two cryptographic keys, casts them to `EVP_PKEY`
492
* structures, and checks their equality using `EVP_PKEY_eq()`. The purpose of
493
* `buf`, `len`, `out1`, and `out2` parameters is not clear from the function's
494
* current implementation.
495
*
496
* @param buf Unused parameter (purpose unclear).
497
* @param len Unused parameter (purpose unclear).
498
* @param key1 First key, expected to be an `EVP_PKEY *`.
499
* @param key2 Second key, expected to be an `EVP_PKEY *`.
500
* @param out1 Unused parameter (purpose unclear).
501
* @param out2 Unused parameter (purpose unclear).
502
*/
503
static void ml_dsa_compare(uint8_t **buf, size_t *len, void *key1,
504
void *key2, void **out1, void **out2)
505
{
506
EVP_PKEY *alice = (EVP_PKEY *)key1;
507
EVP_PKEY *bob = (EVP_PKEY *)key2;
508
509
EVP_PKEY_eq(alice, alice);
510
EVP_PKEY_eq(alice, bob);
511
}
512
513
/**
514
* @brief Frees allocated ML-DSA keys.
515
*
516
* This function releases memory associated with up to four EVP_PKEY objects by
517
* calling `EVP_PKEY_free()` on each provided key.
518
*
519
* @param key1 Pointer to the first key to be freed.
520
* @param key2 Pointer to the second key to be freed.
521
* @param key3 Pointer to the third key to be freed.
522
* @param key4 Pointer to the fourth key to be freed.
523
*
524
* @note This function assumes that each key is either a valid EVP_PKEY
525
* object or NULL. Passing NULL is safe and has no effect.
526
*/
527
static void cleanup_ml_dsa_keys(void *key1, void *key2,
528
void *key3, void *key4)
529
{
530
EVP_PKEY_free((EVP_PKEY *)key1);
531
EVP_PKEY_free((EVP_PKEY *)key2);
532
EVP_PKEY_free((EVP_PKEY *)key3);
533
EVP_PKEY_free((EVP_PKEY *)key4);
534
}
535
536
/**
537
* @brief Represents an operation table entry for cryptographic operations.
538
*
539
* This structure defines a table entry containing function pointers for setting
540
* up, executing, and cleaning up cryptographic operations, along with
541
* associated metadata such as a name and description.
542
*
543
* @struct op_table_entry
544
*/
545
struct op_table_entry {
546
/** Name of the operation. */
547
char *name;
548
549
/** Description of the operation. */
550
char *desc;
551
552
/**
553
* @brief Function pointer for setting up the operation.
554
*
555
* @param buf Pointer to the buffer pointer; may be updated.
556
* @param len Pointer to the remaining buffer size; may be updated.
557
* @param out1 Pointer to store the first output of the setup function.
558
* @param out2 Pointer to store the second output of the setup function.
559
*/
560
void (*setup)(uint8_t **buf, size_t *len, void **out1, void **out2);
561
562
/**
563
* @brief Function pointer for executing the operation.
564
*
565
* @param buf Pointer to the buffer pointer; may be updated.
566
* @param len Pointer to the remaining buffer size; may be updated.
567
* @param in1 First input parameter for the operation.
568
* @param in2 Second input parameter for the operation.
569
* @param out1 Pointer to store the first output of the operation.
570
* @param out2 Pointer to store the second output of the operation.
571
*/
572
void (*doit)(uint8_t **buf, size_t *len, void *in1, void *in2,
573
void **out1, void **out2);
574
575
/**
576
* @brief Function pointer for cleaning up after the operation.
577
*
578
* @param in1 First input parameter to be cleaned up.
579
* @param in2 Second input parameter to be cleaned up.
580
* @param out1 First output parameter to be cleaned up.
581
* @param out2 Second output parameter to be cleaned up.
582
*/
583
void (*cleanup)(void *in1, void *in2, void *out1, void *out2);
584
};
585
586
static struct op_table_entry ops[] = {
587
{
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
}, {
594
"Generate ML-DSA keypair, using EVP_PKEY_keygen",
595
"Generates a real ML-DSA keypair, should always work",
596
keygen_ml_dsa_real_key,
597
NULL,
598
cleanup_ml_dsa_keys
599
}, {
600
"Do a sign/verify operation on a key",
601
"Generate key, sign random data, verify it, should work",
602
keygen_ml_dsa_real_key,
603
ml_dsa_sign_verify,
604
cleanup_ml_dsa_keys
605
}, {
606
"Do a digest sign/verify operation on a key",
607
"Generate key, digest sign random data, verify it, should work",
608
keygen_ml_dsa_real_key,
609
ml_dsa_digest_sign_verify,
610
cleanup_ml_dsa_keys
611
}, {
612
"Do an export/import of key data",
613
"Exercise EVP_PKEY_todata/fromdata",
614
keygen_ml_dsa_real_key,
615
ml_dsa_export_import,
616
cleanup_ml_dsa_keys
617
}, {
618
"Compare keys for equality",
619
"Compare key1/key1 and key1/key2 for equality",
620
keygen_ml_dsa_real_key,
621
ml_dsa_compare,
622
cleanup_ml_dsa_keys
623
}
624
};
625
626
int FuzzerInitialize(int *argc, char ***argv)
627
{
628
return 0;
629
}
630
631
/**
632
* @brief Processes a fuzzing input by selecting and executing an operation.
633
*
634
* This function interprets the first byte of the input buffer to determine an
635
* operation to execute. It then follows a setup, execution, and cleanup
636
* sequence based on the selected operation.
637
*
638
* @param buf Pointer to the input buffer.
639
* @param len Length of the input buffer.
640
*
641
* @return 0 on successful execution, -1 if the input is too short.
642
*
643
* @note The function requires at least 32 bytes in the buffer to proceed.
644
* It utilizes the `ops` operation table to dynamically determine and
645
* execute the selected operation.
646
*/
647
int FuzzerTestOneInput(const uint8_t *buf, size_t len)
648
{
649
uint8_t operation;
650
uint8_t *buffer_cursor;
651
void *in1 = NULL, *in2 = NULL;
652
void *out1 = NULL, *out2 = NULL;
653
654
if (len < 32)
655
return -1;
656
657
/* Get the first byte of the buffer to tell us what operation to perform */
658
buffer_cursor = consume_uint8_t(buf, &len, &operation);
659
if (buffer_cursor == NULL)
660
return -1;
661
662
/* Adjust for operational array size */
663
operation %= OSSL_NELEM(ops);
664
665
/* And run our setup/doit/cleanup sequence */
666
if (ops[operation].setup != NULL)
667
ops[operation].setup(&buffer_cursor, &len, &in1, &in2);
668
if (ops[operation].doit != NULL)
669
ops[operation].doit(&buffer_cursor, &len, in1, in2, &out1, &out2);
670
if (ops[operation].cleanup != NULL)
671
ops[operation].cleanup(in1, in2, out1, out2);
672
673
return 0;
674
}
675
676
void FuzzerCleanup(void)
677
{
678
OPENSSL_cleanup();
679
}
680
681