Coverage Report

Created: 2026-08-27 07:01

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