/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 | } |