Coverage Report

Created: 2026-05-16 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea-fuzzer/fuzz_cryptolink.cc
Line
Count
Source
1
// Copyright (C) 2025 Ada Logics Ltd.
2
//
3
// This Source Code Form is subject to the terms of the Mozilla Public
4
// License, v. 2.0. If a copy of the MPL was not distributed with this
5
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
////////////////////////////////////////////////////////////////////////////////
7
#include <config.h>
8
#include <fuzzer/FuzzedDataProvider.h>
9
10
#include <exceptions/exceptions.h>
11
#include <cryptolink/cryptolink.h>
12
#include <cryptolink/crypto_hash.h>
13
#include <cryptolink/crypto_hmac.h>
14
#include <cryptolink/crypto_rng.h>
15
16
#include <string>
17
#include <vector>
18
#include <cstddef>
19
20
using namespace isc::cryptolink;
21
22
1.08k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
23
1.08k
    if (size < 3) {
24
2
        return 0;
25
2
    }
26
27
1.07k
    FuzzedDataProvider fdp(data, size);
28
    
29
    // Choose which crypto operation to test
30
1.07k
    uint8_t path = fdp.ConsumeIntegralInRange<uint8_t>(0, 9);
31
    
32
    // Pick a hash algorithm
33
1.07k
    HashAlgorithm hash_alg = fdp.PickValueInArray({
34
1.07k
        HashAlgorithm::MD5,
35
1.07k
        HashAlgorithm::SHA1,
36
1.07k
        HashAlgorithm::SHA224,
37
1.07k
        HashAlgorithm::SHA256,
38
1.07k
        HashAlgorithm::SHA384,
39
1.07k
        HashAlgorithm::SHA512
40
1.07k
    });
41
    
42
1.07k
    try {
43
1.07k
        switch (path) {
44
33
            case 0: {
45
                // Test Hash creation and update
46
33
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
47
33
                if (hash) {
48
33
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
49
33
                    if (!input_data.empty()) {
50
33
                        hash->update(input_data.data(), input_data.size());
51
33
                    }
52
33
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
53
33
                    delete hash;
54
33
                }
55
33
                break;
56
0
            }
57
            
58
107
            case 1: {
59
                // Test Hash with multiple updates
60
107
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
61
107
                if (hash) {
62
107
                    size_t num_updates = fdp.ConsumeIntegralInRange<size_t>(1, 10);
63
469
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
64
362
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
65
362
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
66
362
                        if (!chunk.empty()) {
67
220
                            hash->update(chunk.data(), chunk.size());
68
220
                        }
69
362
                    }
70
107
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
71
107
                    delete hash;
72
107
                }
73
107
                break;
74
0
            }
75
            
76
146
            case 2: {
77
                // Test Hash with OutputBuffer
78
146
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
79
146
                if (hash) {
80
146
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
81
146
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
82
146
                    );
83
146
                    if (!input_data.empty()) {
84
70
                        hash->update(input_data.data(), input_data.size());
85
70
                    }
86
146
                    isc::util::OutputBuffer result(hash->getOutputLength());
87
146
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hash->getOutputLength() * 2);
88
146
                    hash->final(result, len);
89
146
                    delete hash;
90
146
                }
91
146
                break;
92
0
            }
93
            
94
121
            case 3: {
95
                // Test Hash with void* result
96
121
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
97
121
                if (hash) {
98
121
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
99
121
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
100
121
                    );
101
121
                    if (!input_data.empty()) {
102
62
                        hash->update(input_data.data(), input_data.size());
103
62
                    }
104
121
                    std::vector<uint8_t> result(hash->getOutputLength() * 2);
105
121
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, result.size());
106
121
                    hash->final(result.data(), len);
107
121
                    delete hash;
108
121
                }
109
121
                break;
110
0
            }
111
            
112
69
            case 4: {
113
                // Test HMAC creation and signing
114
69
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
115
69
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
116
69
                if (secret.empty()) {
117
7
                    secret.push_back(0);  // Ensure non-empty secret
118
7
                }
119
                
120
69
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
121
69
                    secret.data(), secret.size(), hash_alg
122
69
                );
123
69
                if (hmac) {
124
69
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
125
69
                    if (!input_data.empty()) {
126
50
                        hmac->update(input_data.data(), input_data.size());
127
50
                    }
128
69
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
129
69
                    delete hmac;
130
69
                }
131
69
                break;
132
0
            }
133
            
134
146
            case 5: {
135
                // Test HMAC with multiple updates
136
146
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
137
146
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
138
146
                if (secret.empty()) {
139
9
                    secret.push_back(0);
140
9
                }
141
                
142
146
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
143
146
                    secret.data(), secret.size(), hash_alg
144
146
                );
145
146
                if (hmac) {
146
146
                    size_t num_updates = fdp.ConsumeIntegralInRange<size_t>(1, 10);
147
607
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
148
461
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
149
461
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
150
461
                        if (!chunk.empty()) {
151
307
                            hmac->update(chunk.data(), chunk.size());
152
307
                        }
153
461
                    }
154
146
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
155
146
                    delete hmac;
156
146
                }
157
146
                break;
158
0
            }
159
            
160
175
            case 6: {
161
                // Test HMAC with OutputBuffer
162
175
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
163
175
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
164
175
                if (secret.empty()) {
165
10
                    secret.push_back(0);
166
10
                }
167
                
168
175
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
169
175
                    secret.data(), secret.size(), hash_alg
170
175
                );
171
175
                if (hmac) {
172
175
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
173
175
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
174
175
                    );
175
175
                    if (!input_data.empty()) {
176
80
                        hmac->update(input_data.data(), input_data.size());
177
80
                    }
178
175
                    isc::util::OutputBuffer result(hmac->getOutputLength());
179
175
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hmac->getOutputLength() * 2);
180
175
                    hmac->sign(result, len);
181
175
                    delete hmac;
182
175
                }
183
175
                break;
184
0
            }
185
            
186
147
            case 7: {
187
                // Test HMAC verification
188
147
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
189
147
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
190
147
                if (secret.empty()) {
191
12
                    secret.push_back(0);
192
12
                }
193
                
194
147
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
195
147
                    secret.data(), secret.size(), hash_alg
196
147
                );
197
147
                if (hmac) {
198
147
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
199
147
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
200
147
                    );
201
147
                    if (!input_data.empty()) {
202
89
                        hmac->update(input_data.data(), input_data.size());
203
89
                    }
204
                    
205
                    // Generate signature
206
147
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
207
                    
208
                    // Verify with same data (should succeed)
209
147
                    HMAC* verify_hmac = CryptoLink::getCryptoLink().createHMAC(
210
147
                        secret.data(), secret.size(), hash_alg
211
147
                    );
212
147
                    if (verify_hmac) {
213
147
                        if (!input_data.empty()) {
214
89
                            verify_hmac->update(input_data.data(), input_data.size());
215
89
                        }
216
147
                        verify_hmac->verify(signature.data(), signature.size());
217
147
                        delete verify_hmac;
218
147
                    }
219
147
                    delete hmac;
220
147
                }
221
147
                break;
222
0
            }
223
            
224
101
            case 8: {
225
                // Test HMAC with long secret (should be hashed)
226
101
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(256, 1024);
227
101
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
228
101
                if (secret.size() < 64) {
229
37
                    secret.resize(64, 0x42);  // Pad to ensure long secret
230
37
                }
231
                
232
101
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
233
101
                    secret.data(), secret.size(), hash_alg
234
101
                );
235
101
                if (hmac) {
236
101
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
237
101
                    if (!input_data.empty()) {
238
54
                        hmac->update(input_data.data(), input_data.size());
239
54
                    }
240
101
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
241
101
                    delete hmac;
242
101
                }
243
101
                break;
244
0
            }
245
            
246
34
            case 9: {
247
                // Test RNG generation
248
34
                size_t rng_len = fdp.ConsumeIntegralInRange<size_t>(0, 1024);
249
34
                std::vector<uint8_t> random_data = isc::cryptolink::random(rng_len);
250
                
251
                // Test Qid generation
252
34
                uint16_t qid = isc::cryptolink::generateQid();
253
34
                (void)qid;  // Use the variable
254
34
                break;
255
0
            }
256
1.07k
        }
257
1.07k
    } catch (const isc::Exception&) {
258
        // Expected for invalid algorithms, key lengths, etc.
259
0
    } catch (const std::exception&) {
260
        // Catch any standard library exceptions
261
0
    }
262
    
263
1.07k
    return 0;
264
1.07k
}