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