Coverage Report

Created: 2025-11-09 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/liboqs/tests/fuzz_test_sig.c
Line
Count
Source
1
/*
2
 * fuzz_test_sig.c
3
 *
4
 * Minimal fuzz test for liboqs.
5
 *
6
 * SPDX-License-Identifier: MIT
7
 */
8
9
#include "oqs/sig.h"
10
#include <stdbool.h>
11
#include <stdio.h>
12
#include <stdlib.h>
13
#include <string.h>
14
15
#include <oqs/oqs.h>
16
17
18
typedef struct {
19
  uint32_t random_seed;
20
  uint32_t algorithm_index;
21
} fuzz_init_ctx_t;
22
23
typedef struct {
24
  fuzz_init_ctx_t init;
25
  const uint8_t *data;
26
  size_t data_len;
27
} fuzz_ctx_t;
28
29
fuzz_ctx_t init_fuzz_context(const uint8_t *data, size_t data_len);
30
void fuzz_rand(uint8_t *random_array, size_t bytes_to_read);
31
32
0
void fuzz_rand(uint8_t *random_array, size_t bytes_to_read) {
33
0
  for (size_t i = 0; i < bytes_to_read; i++) {
34
0
    random_array[i] = (uint8_t)rand();
35
0
  }
36
0
}
37
38
0
fuzz_ctx_t init_fuzz_context(const uint8_t *data, size_t data_len) {
39
40
0
  fuzz_ctx_t ctx = {{0, 0}, NULL, 0};
41
0
  if (data_len > sizeof(fuzz_init_ctx_t)) {
42
0
    memcpy(&ctx.init, data, sizeof(fuzz_init_ctx_t));
43
0
    ctx.data = data + sizeof(fuzz_init_ctx_t);
44
0
    ctx.data_len = data_len - sizeof(fuzz_init_ctx_t);
45
46
0
    ctx.init.algorithm_index %= OQS_SIG_algs_length;
47
0
  } else {
48
0
    ctx.data = data;
49
0
    ctx.data_len = data_len;
50
0
  }
51
52
0
  srand(ctx.init.random_seed);
53
0
  OQS_randombytes_custom_algorithm(&fuzz_rand);
54
55
0
  return ctx;
56
0
}
57
58
void cleanup_heap(uint8_t *public_key, uint8_t *secret_key, uint8_t *signature,
59
                  OQS_SIG *sig);
60
61
0
static OQS_STATUS fuzz_sig(const uint8_t *data, size_t data_len) {
62
0
  OQS_SIG *sig = NULL;
63
0
  uint8_t *public_key = NULL;
64
0
  uint8_t *secret_key = NULL;
65
0
  uint8_t *signature = NULL;
66
0
  size_t signature_len;
67
0
  OQS_STATUS rc;
68
69
0
  fuzz_ctx_t ctx = init_fuzz_context(data, data_len);
70
71
0
  const char *algorithm = OQS_SIG_alg_identifier(ctx.init.algorithm_index);
72
73
0
  sig = OQS_SIG_new(algorithm);
74
0
  if (sig == NULL) {
75
0
    printf("%s was not enabled at compile-time.\n", algorithm);
76
0
    return OQS_ERROR;
77
0
  }
78
79
0
  public_key = malloc(sig->length_public_key);
80
0
  secret_key = malloc(sig->length_secret_key);
81
0
  signature = malloc(sig->length_signature);
82
0
  if ((public_key == NULL) || (secret_key == NULL) || (ctx.data == NULL) ||
83
0
          (signature == NULL)) {
84
0
    fprintf(stderr, "ERROR: malloc failed!\n");
85
0
    cleanup_heap(public_key, secret_key, signature, sig);
86
0
    return OQS_ERROR;
87
0
  }
88
89
0
  rc = OQS_SIG_keypair(sig, public_key, secret_key);
90
0
  if (rc != OQS_SUCCESS) {
91
0
    fprintf(stderr, "ERROR: OQS_SIG_keypair failed!\n");
92
0
    cleanup_heap(public_key, secret_key, signature, sig);
93
0
    return OQS_ERROR;
94
0
  }
95
0
  rc = OQS_SIG_sign(sig, signature, &signature_len, ctx.data, ctx.data_len,
96
0
                    secret_key);
97
0
  if (rc != OQS_SUCCESS) {
98
0
    fprintf(stderr, "ERROR: OQS_SIG_sign failed!\n");
99
0
    cleanup_heap(public_key, secret_key, signature, sig);
100
0
    return OQS_ERROR;
101
0
  }
102
0
  rc = OQS_SIG_verify(sig, ctx.data, ctx.data_len, signature, signature_len,
103
0
                      public_key);
104
0
  if (rc != OQS_SUCCESS) {
105
0
    fprintf(stderr, "ERROR: OQS_SIG_verify failed!\n");
106
0
    cleanup_heap(public_key, secret_key, signature, sig);
107
0
    exit(1);
108
0
  }
109
110
0
  cleanup_heap(public_key, secret_key, signature, sig);
111
0
  return OQS_SUCCESS; // success
112
0
}
113
114
void cleanup_heap(uint8_t *public_key, uint8_t *secret_key, uint8_t *signature,
115
0
                  OQS_SIG *sig) {
116
0
  if (sig != NULL) {
117
0
    OQS_MEM_secure_free(secret_key, sig->length_secret_key);
118
0
  }
119
0
  OQS_MEM_insecure_free(public_key);
120
0
  OQS_MEM_insecure_free(signature);
121
0
  OQS_SIG_free(sig);
122
0
}
123
124
0
int LLVMFuzzerTestOneInput(const char *data, size_t size) {
125
0
  OQS_init();
126
0
  if (OQS_ERROR == fuzz_sig((const uint8_t *)data, size)) {
127
    // If we get an error prune testcase from corpus.
128
0
    return -1;
129
0
  }
130
0
  OQS_destroy();
131
0
  return 0;
132
0
}