Coverage Report

Created: 2025-10-10 07:47

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
11.5k
void fuzz_rand(uint8_t *random_array, size_t bytes_to_read) {
33
516k
  for (size_t i = 0; i < bytes_to_read; i++) {
34
504k
    random_array[i] = (uint8_t)rand();
35
504k
  }
36
11.5k
}
37
38
5.44k
fuzz_ctx_t init_fuzz_context(const uint8_t *data, size_t data_len) {
39
40
5.44k
  fuzz_ctx_t ctx = {{0, 0}, NULL, 0};
41
5.44k
  if (data_len > sizeof(fuzz_init_ctx_t)) {
42
5.40k
    memcpy(&ctx.init, data, sizeof(fuzz_init_ctx_t));
43
5.40k
    ctx.data = data + sizeof(fuzz_init_ctx_t);
44
5.40k
    ctx.data_len = data_len - sizeof(fuzz_init_ctx_t);
45
46
5.40k
    ctx.init.algorithm_index %= OQS_SIG_algs_length;
47
5.40k
  } else {
48
34
    ctx.data = data;
49
34
    ctx.data_len = data_len;
50
34
  }
51
52
5.44k
  srand(ctx.init.random_seed);
53
5.44k
  OQS_randombytes_custom_algorithm(&fuzz_rand);
54
55
5.44k
  return ctx;
56
5.44k
}
57
58
void cleanup_heap(uint8_t *public_key, uint8_t *secret_key, uint8_t *signature,
59
                  OQS_SIG *sig);
60
61
5.44k
static OQS_STATUS fuzz_sig(const uint8_t *data, size_t data_len) {
62
5.44k
  OQS_SIG *sig = NULL;
63
5.44k
  uint8_t *public_key = NULL;
64
5.44k
  uint8_t *secret_key = NULL;
65
5.44k
  uint8_t *signature = NULL;
66
5.44k
  size_t signature_len;
67
5.44k
  OQS_STATUS rc;
68
69
5.44k
  fuzz_ctx_t ctx = init_fuzz_context(data, data_len);
70
71
5.44k
  const char *algorithm = OQS_SIG_alg_identifier(ctx.init.algorithm_index);
72
73
5.44k
  sig = OQS_SIG_new(algorithm);
74
5.44k
  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.44k
  public_key = malloc(sig->length_public_key);
80
5.44k
  secret_key = malloc(sig->length_secret_key);
81
5.44k
  signature = malloc(sig->length_signature);
82
5.44k
  if ((public_key == NULL) || (secret_key == NULL) || (ctx.data == NULL) ||
83
5.44k
          (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.44k
  rc = OQS_SIG_keypair(sig, public_key, secret_key);
90
5.44k
  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.44k
  rc = OQS_SIG_sign(sig, signature, &signature_len, ctx.data, ctx.data_len,
96
5.44k
                    secret_key);
97
5.44k
  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
5.44k
  rc = OQS_SIG_verify(sig, ctx.data, ctx.data_len, signature, signature_len,
103
5.44k
                      public_key);
104
5.44k
  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.44k
  cleanup_heap(public_key, secret_key, signature, sig);
111
5.44k
  return OQS_SUCCESS; // success
112
5.44k
}
113
114
void cleanup_heap(uint8_t *public_key, uint8_t *secret_key, uint8_t *signature,
115
5.44k
                  OQS_SIG *sig) {
116
5.44k
  if (sig != NULL) {
117
5.44k
    OQS_MEM_secure_free(secret_key, sig->length_secret_key);
118
5.44k
  }
119
5.44k
  OQS_MEM_insecure_free(public_key);
120
5.44k
  OQS_MEM_insecure_free(signature);
121
5.44k
  OQS_SIG_free(sig);
122
5.44k
}
123
124
5.44k
int LLVMFuzzerTestOneInput(const char *data, size_t size) {
125
5.44k
  OQS_init();
126
5.44k
  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
5.44k
  OQS_destroy();
131
5.44k
  return 0;
132
5.44k
}