Coverage Report

Created: 2026-02-14 07:23

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
20.2k
void fuzz_rand(uint8_t *random_array, size_t bytes_to_read) {
33
5.52M
  for (size_t i = 0; i < bytes_to_read; i++) {
34
5.50M
    random_array[i] = (uint8_t)rand();
35
5.50M
  }
36
20.2k
}
37
38
7.93k
fuzz_ctx_t init_fuzz_context(const uint8_t *data, size_t data_len) {
39
40
7.93k
  fuzz_ctx_t ctx = {{0, 0}, NULL, 0};
41
7.93k
  if (data_len > sizeof(fuzz_init_ctx_t)) {
42
7.89k
    memcpy(&ctx.init, data, sizeof(fuzz_init_ctx_t));
43
7.89k
    ctx.data = data + sizeof(fuzz_init_ctx_t);
44
7.89k
    ctx.data_len = data_len - sizeof(fuzz_init_ctx_t);
45
46
7.89k
    ctx.init.algorithm_index %= OQS_SIG_algs_length;
47
7.89k
  } else {
48
41
    ctx.data = data;
49
41
    ctx.data_len = data_len;
50
41
  }
51
52
7.93k
  srand(ctx.init.random_seed);
53
7.93k
  OQS_randombytes_custom_algorithm(&fuzz_rand);
54
55
7.93k
  return ctx;
56
7.93k
}
57
58
void cleanup_heap(uint8_t *public_key, uint8_t *secret_key, uint8_t *signature,
59
                  OQS_SIG *sig);
60
61
6.15k
static OQS_STATUS fuzz_sig(const uint8_t *data, size_t data_len) {
62
6.15k
  OQS_SIG *sig = NULL;
63
6.15k
  uint8_t *public_key = NULL;
64
6.15k
  uint8_t *secret_key = NULL;
65
6.15k
  uint8_t *signature = NULL;
66
6.15k
  size_t signature_len;
67
6.15k
  OQS_STATUS rc;
68
69
6.15k
  fuzz_ctx_t ctx = init_fuzz_context(data, data_len);
70
71
6.15k
  const char *algorithm = OQS_SIG_alg_identifier(ctx.init.algorithm_index);
72
73
6.15k
  sig = OQS_SIG_new(algorithm);
74
6.15k
  if (sig == NULL) {
75
0
    printf("%s was not enabled at compile-time.\n", algorithm);
76
0
    return OQS_ERROR;
77
0
  }
78
79
6.15k
  public_key = malloc(sig->length_public_key);
80
6.15k
  secret_key = malloc(sig->length_secret_key);
81
6.15k
  signature = malloc(sig->length_signature);
82
6.15k
  if ((public_key == NULL) || (secret_key == NULL) || (ctx.data == NULL) ||
83
6.15k
          (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
6.15k
  rc = OQS_SIG_keypair(sig, public_key, secret_key);
90
6.15k
  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
6.15k
  rc = OQS_SIG_sign(sig, signature, &signature_len, ctx.data, ctx.data_len,
96
6.15k
                    secret_key);
97
6.15k
  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
6.15k
  rc = OQS_SIG_verify(sig, ctx.data, ctx.data_len, signature, signature_len,
103
6.15k
                      public_key);
104
6.15k
  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
6.15k
  cleanup_heap(public_key, secret_key, signature, sig);
111
6.15k
  return OQS_SUCCESS; // success
112
6.15k
}
113
114
void cleanup_heap(uint8_t *public_key, uint8_t *secret_key, uint8_t *signature,
115
7.93k
                  OQS_SIG *sig) {
116
7.93k
  if (sig != NULL) {
117
7.93k
    OQS_MEM_secure_free(secret_key, sig->length_secret_key);
118
7.93k
  }
119
7.93k
  OQS_MEM_insecure_free(public_key);
120
7.93k
  OQS_MEM_insecure_free(signature);
121
7.93k
  OQS_SIG_free(sig);
122
7.93k
}
123
124
7.93k
int LLVMFuzzerTestOneInput(const char *data, size_t size) {
125
7.93k
  OQS_init();
126
7.93k
  if (OQS_ERROR == fuzz_sig((const uint8_t *)data, size)) {
127
    // If we get an error prune testcase from corpus.
128
3
    return -1;
129
3
  }
130
7.93k
  OQS_destroy();
131
7.93k
  return 0;
132
7.93k
}