1
0

ml-kem.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  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-kem operation.
  12. */
  13. #include <string.h>
  14. #include <openssl/evp.h>
  15. #include <openssl/err.h>
  16. #include <openssl/rand.h>
  17. #include <openssl/byteorder.h>
  18. #include <openssl/ml_kem.h>
  19. #include "internal/nelem.h"
  20. #include "fuzzer.h"
  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_uint8t(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. * @brief Selects a key type and size from a buffer.
  44. *
  45. * This function reads a key size value from the buffer, determines the
  46. * corresponding key type and length, and updates the buffer pointer
  47. * accordingly. If `only_valid` is set, it restricts selection to valid
  48. * key sizes; otherwise, it includes some invalid sizes for testing.
  49. *
  50. * @param buf Pointer to the buffer pointer; updated after reading.
  51. * @param len Pointer to the remaining buffer size; updated accordingly.
  52. * @param keytype Pointer to store the selected key type string.
  53. * @param keylen Pointer to store the selected key length.
  54. * @param only_valid Flag to restrict selection to valid key sizes.
  55. *
  56. * @return 1 if a key type is successfully selected, 0 on failure.
  57. */
  58. static int select_keytype_and_size(uint8_t **buf, size_t *len,
  59. char **keytype, size_t *keylen,
  60. int only_valid)
  61. {
  62. uint16_t keysize;
  63. uint16_t modulus = 6;
  64. /*
  65. * Note: We don't really care about endianess here, we just
  66. * want a random 16 bit value
  67. */
  68. *buf = (uint8_t *)OPENSSL_load_u16_le(&keysize, *buf);
  69. *len -= sizeof(uint16_t);
  70. if (*buf == NULL)
  71. return 0;
  72. /*
  73. * select from sizes
  74. * ML-KEM-512, ML-KEM-768, and ML-KEM-1024
  75. * also select some invalid sizes to trigger
  76. * error paths
  77. */
  78. if (only_valid)
  79. modulus = 3;
  80. /*
  81. * Note, keylens for valid values (cases 0-2)
  82. * are taken based on input values from our unit tests
  83. */
  84. switch (keysize % modulus) {
  85. case 0:
  86. *keytype = "ML-KEM-512";
  87. *keylen = OSSL_ML_KEM_512_PUBLIC_KEY_BYTES;
  88. break;
  89. case 1:
  90. *keytype = "ML-KEM-768";
  91. *keylen = OSSL_ML_KEM_768_PUBLIC_KEY_BYTES;
  92. break;
  93. case 2:
  94. *keytype = "ML-KEM-1024";
  95. *keylen = OSSL_ML_KEM_1024_PUBLIC_KEY_BYTES;
  96. break;
  97. case 3:
  98. /* select invalid alg */
  99. *keytype = "ML-KEM-13";
  100. *keylen = 13;
  101. break;
  102. case 4:
  103. /* Select valid alg, but bogus size */
  104. *keytype = "ML-KEM-1024";
  105. *buf = (uint8_t *)OPENSSL_load_u16_le(&keysize, *buf);
  106. *len -= sizeof(uint16_t);
  107. *keylen = (size_t)keysize;
  108. *keylen %= 1024; /* size to our key buffer */
  109. break;
  110. default:
  111. *keytype = NULL;
  112. *keylen = 0;
  113. break;
  114. }
  115. return 1;
  116. }
  117. /**
  118. * @brief Creates an ML-KEM raw key from a buffer.
  119. *
  120. * This function selects a key type and size from the buffer, generates
  121. * a random key of the appropriate length, and creates either a public
  122. * or private ML-KEM key using OpenSSL's EVP_PKEY interface.
  123. *
  124. * @param buf Pointer to the buffer pointer; updated after reading.
  125. * @param len Pointer to the remaining buffer size; updated accordingly.
  126. * @param key1 Pointer to store the generated EVP_PKEY key (public or private).
  127. * @param key2 Unused parameter (reserved for future use).
  128. *
  129. * @note The generated key is allocated using OpenSSL's EVP_PKEY functions
  130. * and should be freed appropriately using `EVP_PKEY_free()`.
  131. */
  132. static void create_mlkem_raw_key(uint8_t **buf, size_t *len,
  133. void **key1, void **key2)
  134. {
  135. EVP_PKEY *pubkey;
  136. char *keytype = NULL;
  137. size_t keylen = 0;
  138. uint8_t key[4096];
  139. int pub = 0;
  140. if (!select_keytype_and_size(buf, len, &keytype, &keylen, 0))
  141. return;
  142. /*
  143. * Select public or private key creation based on the low order
  144. * bit of the next buffer value
  145. * Note that keylen as returned from select_keytype_and_size is
  146. * a public key length, private keys for ML-KEM are always double
  147. * the size plus 32, so make that adjustment here
  148. */
  149. if ((*buf)[0] & 0x1)
  150. pub = 1;
  151. else
  152. keylen = (keylen * 2) + 32;
  153. /*
  154. * libfuzzer provides by default up to 4096 bit input
  155. * buffers, but its typically much less (between 1 and 100 bytes)
  156. * so use RAND_bytes here instead
  157. */
  158. if (!RAND_bytes(key, keylen))
  159. return;
  160. /*
  161. * Try to generate either a raw public or private key using random data
  162. * Because the input is completely random, its effectively certain this
  163. * operation will fail, but it will still exercise the code paths below,
  164. * which is what we want the fuzzer to do
  165. */
  166. if (pub == 1)
  167. pubkey = EVP_PKEY_new_raw_public_key_ex(NULL, keytype, NULL, key, keylen);
  168. else
  169. pubkey = EVP_PKEY_new_raw_private_key_ex(NULL, keytype, NULL, key, keylen);
  170. *key1 = pubkey;
  171. return;
  172. }
  173. /**
  174. * @brief Generates a valid ML-KEM key using OpenSSL.
  175. *
  176. * This function selects a valid ML-KEM key type and size from the buffer,
  177. * initializes an OpenSSL EVP_PKEY context, and generates a cryptographic
  178. * key accordingly.
  179. *
  180. * @param buf Pointer to the buffer pointer; updated after reading.
  181. * @param len Pointer to the remaining buffer size; updated accordingly.
  182. * @param key1 Pointer to store the generated EVP_PKEY key.
  183. * @param unused Unused parameter (reserved for future use).
  184. *
  185. * @note The generated key is allocated using OpenSSL's EVP_PKEY functions
  186. * and should be freed using `EVP_PKEY_free()`.
  187. */
  188. static void keygen_mlkem_real_key(uint8_t **buf, size_t *len,
  189. void **key1, void **key2)
  190. {
  191. char *keytype = NULL;
  192. size_t keylen = 0;
  193. EVP_PKEY_CTX *ctx = NULL;
  194. EVP_PKEY **key;
  195. *key1 = *key2 = NULL;
  196. key = (EVP_PKEY **)key1;
  197. again:
  198. /*
  199. * Only generate valid key types and lengths
  200. * Note, no adjustment is made to keylen here, as
  201. * the provider is responsible for selecting the keys and sizes
  202. * for us during the EVP_PKEY_keygen call
  203. */
  204. if (!select_keytype_and_size(buf, len, &keytype, &keylen, 1))
  205. return;
  206. ctx = EVP_PKEY_CTX_new_from_name(NULL, keytype, NULL);
  207. if (!ctx) {
  208. fprintf(stderr, "Failed to generate ctx\n");
  209. return;
  210. }
  211. if (!EVP_PKEY_keygen_init(ctx)) {
  212. fprintf(stderr, "Failed to init keygen ctx\n");
  213. goto err;
  214. }
  215. *key = EVP_PKEY_new();
  216. if (*key == NULL)
  217. goto err;
  218. if (!EVP_PKEY_generate(ctx, key)) {
  219. fprintf(stderr, "Failed to generate new real key\n");
  220. goto err;
  221. }
  222. if (key == (EVP_PKEY **)key1) {
  223. EVP_PKEY_CTX_free(ctx);
  224. key = (EVP_PKEY **)key2;
  225. goto again;
  226. }
  227. err:
  228. EVP_PKEY_CTX_free(ctx);
  229. return;
  230. }
  231. /**
  232. * @brief Performs key encapsulation and decapsulation using an EVP_PKEY.
  233. *
  234. * This function generates a random key, encapsulates it using the provided
  235. * public key, then decapsulates it to retrieve the original key. It makes
  236. * use of OpenSSL's EVP_PKEY API for encryption and decryption.
  237. *
  238. * @param[out] buf Unused output buffer (reserved for future use).
  239. * @param[out] len Unused length parameter (reserved for future use).
  240. * @param[in] key1 Pointer to an EVP_PKEY structure used for key operations.
  241. * @param[in] in2 Unused input parameter (reserved for future use).
  242. * @param[out] out1 Unused output parameter (reserved for future use).
  243. * @param[out] out2 Unused output parameter (reserved for future use).
  244. */
  245. static void mlkem_encap_decap(uint8_t **buf, size_t *len, void *key1, void *in2,
  246. void **out1, void **out2)
  247. {
  248. EVP_PKEY *key = (EVP_PKEY *)key1;
  249. EVP_PKEY_CTX *ctx;
  250. unsigned char genkey[32];
  251. size_t genkey_len = 32;
  252. unsigned char unwrappedkey[32];
  253. size_t unwrappedkey_len = 32;
  254. unsigned char wrapkey[1568];
  255. size_t wrapkey_len = 1568;
  256. ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL);
  257. if (ctx == NULL) {
  258. fprintf(stderr, "Failed to allocate ctx\n");
  259. goto err;
  260. }
  261. if (!EVP_PKEY_encapsulate_init(ctx, NULL)) {
  262. fprintf(stderr, "Failed to init encap context\n");
  263. goto err;
  264. }
  265. if (!RAND_bytes(genkey, genkey_len))
  266. goto err;
  267. if (EVP_PKEY_encapsulate(ctx, wrapkey, &wrapkey_len, genkey, &genkey_len) <= 0) {
  268. fprintf(stderr, "Failed to encapsulate key\n");
  269. goto err;
  270. }
  271. EVP_PKEY_CTX_free(ctx);
  272. ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL);
  273. if (ctx == NULL) {
  274. fprintf(stderr, "Failed to create context\n");
  275. goto err;
  276. }
  277. if (!EVP_PKEY_decapsulate_init(ctx, NULL)) {
  278. fprintf(stderr, "Failed to init decap\n");
  279. goto err;
  280. }
  281. if (EVP_PKEY_decapsulate(ctx, unwrappedkey, &unwrappedkey_len,
  282. wrapkey, wrapkey_len) <= 0) {
  283. fprintf(stderr, "Failed to decap key\n");
  284. goto err;
  285. }
  286. if (memcmp(unwrappedkey, genkey, genkey_len))
  287. fprintf(stderr, "mismatch on secret comparison\n");
  288. err:
  289. EVP_PKEY_CTX_free(ctx);
  290. return;
  291. }
  292. /**
  293. * @brief Derives a shared secret using the provided key and peer key.
  294. *
  295. * This function performs a key derivation operation using the given
  296. * private key and peer public key. The resulting shared secret is
  297. * allocated dynamically and must be freed by the caller.
  298. *
  299. * @param[in] key The private key used for derivation.
  300. * @param[in] peer The peer's public key.
  301. * @param[out] shared Pointer to the derived shared secret (allocated).
  302. * @param[out] shared_len Length of the derived shared secret.
  303. *
  304. * @note The caller is responsible for freeing the memory allocated
  305. * for `shared` using `OPENSSL_free()`.
  306. */
  307. static void do_derive(EVP_PKEY *key, EVP_PKEY *peer, uint8_t **shared, size_t *shared_len)
  308. {
  309. EVP_PKEY_CTX *ctx = NULL;
  310. *shared = NULL;
  311. *shared_len = 0;
  312. ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, NULL);
  313. if (ctx == NULL) {
  314. fprintf(stderr, "failed to create keygen context\n");
  315. goto err;
  316. }
  317. if (!EVP_PKEY_derive_init(ctx)) {
  318. fprintf(stderr, "failed to init derive context\n");
  319. goto err;
  320. }
  321. if (!EVP_PKEY_derive_set_peer(ctx, peer)) {
  322. fprintf(stderr, "failed to set peer\n");
  323. goto err;
  324. }
  325. if (!EVP_PKEY_derive(ctx, NULL, shared_len)) {
  326. fprintf(stderr, "Derive failed 1\n");
  327. goto err;
  328. }
  329. if (*shared_len == 0)
  330. goto err;
  331. *shared = OPENSSL_zalloc(*shared_len);
  332. if (*shared == NULL) {
  333. fprintf(stderr, "Failed to alloc\n");
  334. goto err;
  335. }
  336. if (!EVP_PKEY_derive(ctx, *shared, shared_len)) {
  337. fprintf(stderr, "Derive failed 2\n");
  338. OPENSSL_free(*shared);
  339. *shared = NULL;
  340. *shared_len = 0;
  341. goto err;
  342. }
  343. err:
  344. EVP_PKEY_CTX_free(ctx);
  345. }
  346. /**
  347. * @brief Performs a key exchange using ML-KEM.
  348. *
  349. * This function derives shared secrets using the provided key pairs.
  350. * It calls `do_derive()` to compute shared secrets for both participants
  351. * and frees the allocated memory for the shared secrets.
  352. *
  353. * @param[out] buf Unused output buffer (reserved for future use).
  354. * @param[out] len Unused output length (reserved for future use).
  355. * @param[in] key1 First key (typically Alice's key).
  356. * @param[in] key2 Second key (typically Bob's key).
  357. * @param[out] out1 Unused output parameter (reserved for future use).
  358. * @param[out] out2 Unused output parameter (reserved for future use).
  359. *
  360. * @note Currently, this function does not validate whether the derived
  361. * shared secrets match. A check should be added when ML-KEM
  362. * supports this.
  363. */
  364. static void mlkem_kex(uint8_t **buf, size_t *len, void *key1, void *key2,
  365. void **out1, void **out2)
  366. {
  367. EVP_PKEY *alice = (EVP_PKEY *)key1;
  368. EVP_PKEY *bob = (EVP_PKEY *)key2;
  369. size_t boblen, alicelen;
  370. uint8_t *bobshare = NULL;
  371. uint8_t *aliceshare = NULL;
  372. do_derive(alice, bob, &aliceshare, &alicelen);
  373. do_derive(bob, alice, &bobshare, &boblen);
  374. /*
  375. * TODO add check of shared secrets here when ML-KEM supports this
  376. */
  377. OPENSSL_free(bobshare);
  378. OPENSSL_free(aliceshare);
  379. }
  380. /**
  381. * @brief Exports and imports an ML-KEM key.
  382. *
  383. * This function extracts key material from the given key (`key1`),
  384. * exports it as parameters, and then attempts to reconstruct a new
  385. * key from those parameters. It uses OpenSSL's `EVP_PKEY_todata()`
  386. * and `EVP_PKEY_fromdata()` functions for this process.
  387. *
  388. * @param[out] buf Unused output buffer (reserved for future use).
  389. * @param[out] len Unused output length (reserved for future use).
  390. * @param[in] key1 The key to be exported and imported.
  391. * @param[in] key2 Unused input key (reserved for future use).
  392. * @param[out] out1 Unused output parameter (reserved for future use).
  393. * @param[out] out2 Unused output parameter (reserved for future use).
  394. *
  395. * @note If any step in the export-import process fails, the function
  396. * logs an error and cleans up allocated resources.
  397. */
  398. static void mlkem_export_import(uint8_t **buf, size_t *len, void *key1,
  399. void *key2, void **out1, void **out2)
  400. {
  401. EVP_PKEY *alice = (EVP_PKEY *)key1;
  402. EVP_PKEY *new = NULL;
  403. EVP_PKEY_CTX *ctx = NULL;
  404. OSSL_PARAM *params = NULL;
  405. if (!EVP_PKEY_todata(alice, EVP_PKEY_KEYPAIR, &params)) {
  406. fprintf(stderr, "Failed todata\n");
  407. goto err;
  408. }
  409. ctx = EVP_PKEY_CTX_new_from_pkey(NULL, alice, NULL);
  410. if (ctx == NULL) {
  411. fprintf(stderr, "Failed new ctx\n");
  412. goto err;
  413. }
  414. if (!EVP_PKEY_fromdata(ctx, &new, EVP_PKEY_KEYPAIR, params)) {
  415. fprintf(stderr, "Failed fromdata\n");
  416. goto err;
  417. }
  418. err:
  419. EVP_PKEY_CTX_free(ctx);
  420. EVP_PKEY_free(new);
  421. OSSL_PARAM_free(params);
  422. }
  423. /**
  424. * @brief Compares two cryptographic keys and performs equality checks.
  425. *
  426. * This function takes in two cryptographic keys, casts them to `EVP_PKEY`
  427. * structures, and checks their equality using `EVP_PKEY_eq()`. The purpose
  428. * of `buf`, `len`, `out1`, and `out2` parameters is not clear from the
  429. * function's current implementation.
  430. *
  431. * @param buf Unused parameter (purpose unclear).
  432. * @param len Unused parameter (purpose unclear).
  433. * @param key1 First key, expected to be an `EVP_PKEY *`.
  434. * @param key2 Second key, expected to be an `EVP_PKEY *`.
  435. * @param out1 Unused parameter (purpose unclear).
  436. * @param out2 Unused parameter (purpose unclear).
  437. */
  438. static void mlkem_compare(uint8_t **buf, size_t *len, void *key1,
  439. void *key2, void **out1, void **out2)
  440. {
  441. EVP_PKEY *alice = (EVP_PKEY *)key1;
  442. EVP_PKEY *bob = (EVP_PKEY *)key2;
  443. EVP_PKEY_eq(alice, alice);
  444. EVP_PKEY_eq(alice, bob);
  445. }
  446. /**
  447. * @brief Frees allocated ML-KEM keys.
  448. *
  449. * This function releases memory associated with up to four EVP_PKEY
  450. * objects by calling `EVP_PKEY_free()` on each provided key.
  451. *
  452. * @param key1 Pointer to the first key to be freed.
  453. * @param key2 Pointer to the second key to be freed.
  454. * @param key3 Pointer to the third key to be freed.
  455. * @param key4 Pointer to the fourth key to be freed.
  456. *
  457. * @note This function assumes that each key is either a valid EVP_PKEY
  458. * object or NULL. Passing NULL is safe and has no effect.
  459. */
  460. static void cleanup_mlkem_keys(void *key1, void *key2,
  461. void *key3, void *key4)
  462. {
  463. EVP_PKEY_free((EVP_PKEY *)key1);
  464. EVP_PKEY_free((EVP_PKEY *)key2);
  465. EVP_PKEY_free((EVP_PKEY *)key3);
  466. EVP_PKEY_free((EVP_PKEY *)key4);
  467. return;
  468. }
  469. /**
  470. * @brief Represents an operation table entry for cryptographic operations.
  471. *
  472. * This structure defines a table entry containing function pointers for
  473. * setting up, executing, and cleaning up cryptographic operations, along
  474. * with associated metadata such as a name and description.
  475. *
  476. * @struct op_table_entry
  477. */
  478. struct op_table_entry {
  479. /** Name of the operation. */
  480. char *name;
  481. /** Description of the operation. */
  482. char *desc;
  483. /**
  484. * @brief Function pointer for setting up the operation.
  485. *
  486. * @param buf Pointer to the buffer pointer; may be updated.
  487. * @param len Pointer to the remaining buffer size; may be updated.
  488. * @param out1 Pointer to store the first output of the setup function.
  489. * @param out2 Pointer to store the second output of the setup function.
  490. */
  491. void (*setup)(uint8_t **buf, size_t *len, void **out1, void **out2);
  492. /**
  493. * @brief Function pointer for executing the operation.
  494. *
  495. * @param buf Pointer to the buffer pointer; may be updated.
  496. * @param len Pointer to the remaining buffer size; may be updated.
  497. * @param in1 First input parameter for the operation.
  498. * @param in2 Second input parameter for the operation.
  499. * @param out1 Pointer to store the first output of the operation.
  500. * @param out2 Pointer to store the second output of the operation.
  501. */
  502. void (*doit)(uint8_t **buf, size_t *len, void *in1, void *in2,
  503. void **out1, void **out2);
  504. /**
  505. * @brief Function pointer for cleaning up after the operation.
  506. *
  507. * @param in1 First input parameter to be cleaned up.
  508. * @param in2 Second input parameter to be cleaned up.
  509. * @param out1 First output parameter to be cleaned up.
  510. * @param out2 Second output parameter to be cleaned up.
  511. */
  512. void (*cleanup)(void *in1, void *in2, void *out1, void *out2);
  513. };
  514. static struct op_table_entry ops[] = {
  515. {
  516. "Generate ML-KEM raw key",
  517. "Try generate a raw keypair using random data. Usually fails",
  518. create_mlkem_raw_key,
  519. NULL,
  520. cleanup_mlkem_keys
  521. }, {
  522. "Generate ML-KEM keypair, using EVP_PKEY_keygen",
  523. "Generates a real ML-KEM keypair, should always work",
  524. keygen_mlkem_real_key,
  525. NULL,
  526. cleanup_mlkem_keys
  527. }, {
  528. "Do a key encap/decap operation on a key",
  529. "Generate key, encap it, decap it and compare, should work",
  530. keygen_mlkem_real_key,
  531. mlkem_encap_decap,
  532. cleanup_mlkem_keys
  533. }, {
  534. "Do a key exchange operation on two keys",
  535. "Gen keys, do a key exchange both ways and compare",
  536. keygen_mlkem_real_key,
  537. mlkem_kex,
  538. cleanup_mlkem_keys
  539. }, {
  540. "Do an export/import of key data",
  541. "Exercise EVP_PKEY_todata/fromdata",
  542. keygen_mlkem_real_key,
  543. mlkem_export_import,
  544. cleanup_mlkem_keys
  545. }, {
  546. "Compare keys for equality",
  547. "Compare key1/key1 and key1/key2 for equality",
  548. keygen_mlkem_real_key,
  549. mlkem_compare,
  550. cleanup_mlkem_keys
  551. }
  552. };
  553. int FuzzerInitialize(int *argc, char ***argv)
  554. {
  555. return 0;
  556. }
  557. /**
  558. * @brief Processes a fuzzing input by selecting and executing an operation.
  559. *
  560. * This function interprets the first byte of the input buffer to determine
  561. * an operation to execute. It then follows a setup, execution, and cleanup
  562. * sequence based on the selected operation.
  563. *
  564. * @param buf Pointer to the input buffer.
  565. * @param len Length of the input buffer.
  566. *
  567. * @return 0 on successful execution, -1 if the input is too short.
  568. *
  569. * @note The function requires at least 32 bytes in the buffer to proceed.
  570. * It utilizes the `ops` operation table to dynamically determine and
  571. * execute the selected operation.
  572. */
  573. int FuzzerTestOneInput(const uint8_t *buf, size_t len)
  574. {
  575. uint8_t operation;
  576. uint8_t *buffer_cursor;
  577. void *in1 = NULL, *in2 = NULL;
  578. void *out1 = NULL, *out2 = NULL;
  579. if (len < 32)
  580. return -1;
  581. /*
  582. * Get the first byte of the buffer to tell us what operation
  583. * to preform
  584. */
  585. buffer_cursor = consume_uint8t(buf, &len, &operation);
  586. if (buffer_cursor == NULL)
  587. return -1;
  588. /*
  589. * Adjust for operational array size
  590. */
  591. operation %= OSSL_NELEM(ops);
  592. /*
  593. * And run our setup/doit/cleanup sequence
  594. */
  595. if (ops[operation].setup != NULL)
  596. ops[operation].setup(&buffer_cursor, &len, &in1, &in2);
  597. if (ops[operation].doit != NULL)
  598. ops[operation].doit(&buffer_cursor, &len, in1, in2, &out1, &out2);
  599. if (ops[operation].cleanup != NULL)
  600. ops[operation].cleanup(in1, in2, out1, out2);
  601. return 0;
  602. }
  603. void FuzzerCleanup(void)
  604. {
  605. OPENSSL_cleanup();
  606. }