Coverage Report

Created: 2026-06-30 07:33

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.10k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
23
1.10k
    if (size < 3) {
24
2
        return 0;
25
2
    }
26
27
1.09k
    FuzzedDataProvider fdp(data, size);
28
    
29
    // Choose which crypto operation to test
30
1.09k
    uint8_t path = fdp.ConsumeIntegralInRange<uint8_t>(0, 9);
31
    
32
    // Pick a hash algorithm
33
1.09k
    HashAlgorithm hash_alg = fdp.PickValueInArray({
34
1.09k
        HashAlgorithm::MD5,
35
1.09k
        HashAlgorithm::SHA1,
36
1.09k
        HashAlgorithm::SHA224,
37
1.09k
        HashAlgorithm::SHA256,
38
1.09k
        HashAlgorithm::SHA384,
39
1.09k
        HashAlgorithm::SHA512
40
1.09k
    });
41
    
42
1.09k
    try {
43
1.09k
        switch (path) {
44
35
            case 0: {
45
                // Test Hash creation and update
46
35
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
47
35
                if (hash) {
48
35
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
49
35
                    if (!input_data.empty()) {
50
35
                        hash->update(input_data.data(), input_data.size());
51
35
                    }
52
35
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
53
35
                    delete hash;
54
35
                }
55
35
                break;
56
0
            }
57
            
58
113
            case 1: {
59
                // Test Hash with multiple updates
60
113
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
61
113
                if (hash) {
62
113
                    size_t num_updates = fdp.ConsumeIntegralInRange<size_t>(1, 10);
63
511
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
64
398
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
65
398
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
66
398
                        if (!chunk.empty()) {
67
218
                            hash->update(chunk.data(), chunk.size());
68
218
                        }
69
398
                    }
70
113
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
71
113
                    delete hash;
72
113
                }
73
113
                break;
74
0
            }
75
            
76
153
            case 2: {
77
                // Test Hash with OutputBuffer
78
153
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
79
153
                if (hash) {
80
153
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
81
153
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
82
153
                    );
83
153
                    if (!input_data.empty()) {
84
78
                        hash->update(input_data.data(), input_data.size());
85
78
                    }
86
153
                    isc::util::OutputBuffer result(hash->getOutputLength());
87
153
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hash->getOutputLength() * 2);
88
153
                    hash->final(result, len);
89
153
                    delete hash;
90
153
                }
91
153
                break;
92
0
            }
93
            
94
124
            case 3: {
95
                // Test Hash with void* result
96
124
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
97
124
                if (hash) {
98
124
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
99
124
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
100
124
                    );
101
124
                    if (!input_data.empty()) {
102
67
                        hash->update(input_data.data(), input_data.size());
103
67
                    }
104
124
                    std::vector<uint8_t> result(hash->getOutputLength() * 2);
105
124
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, result.size());
106
124
                    hash->final(result.data(), len);
107
124
                    delete hash;
108
124
                }
109
124
                break;
110
0
            }
111
            
112
71
            case 4: {
113
                // Test HMAC creation and signing
114
71
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
115
71
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
116
71
                if (secret.empty()) {
117
7
                    secret.push_back(0);  // Ensure non-empty secret
118
7
                }
119
                
120
71
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
121
71
                    secret.data(), secret.size(), hash_alg
122
71
                );
123
71
                if (hmac) {
124
71
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
125
71
                    if (!input_data.empty()) {
126
51
                        hmac->update(input_data.data(), input_data.size());
127
51
                    }
128
71
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
129
71
                    delete hmac;
130
71
                }
131
71
                break;
132
0
            }
133
            
134
148
            case 5: {
135
                // Test HMAC with multiple updates
136
148
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
137
148
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
138
148
                if (secret.empty()) {
139
9
                    secret.push_back(0);
140
9
                }
141
                
142
148
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
143
148
                    secret.data(), secret.size(), hash_alg
144
148
                );
145
148
                if (hmac) {
146
148
                    size_t num_updates = fdp.ConsumeIntegralInRange<size_t>(1, 10);
147
592
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
148
444
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
149
444
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
150
444
                        if (!chunk.empty()) {
151
310
                            hmac->update(chunk.data(), chunk.size());
152
310
                        }
153
444
                    }
154
148
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
155
148
                    delete hmac;
156
148
                }
157
148
                break;
158
0
            }
159
            
160
174
            case 6: {
161
                // Test HMAC with OutputBuffer
162
174
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
163
174
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
164
174
                if (secret.empty()) {
165
10
                    secret.push_back(0);
166
10
                }
167
                
168
174
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
169
174
                    secret.data(), secret.size(), hash_alg
170
174
                );
171
174
                if (hmac) {
172
174
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
173
174
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
174
174
                    );
175
174
                    if (!input_data.empty()) {
176
83
                        hmac->update(input_data.data(), input_data.size());
177
83
                    }
178
174
                    isc::util::OutputBuffer result(hmac->getOutputLength());
179
174
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hmac->getOutputLength() * 2);
180
174
                    hmac->sign(result, len);
181
174
                    delete hmac;
182
174
                }
183
174
                break;
184
0
            }
185
            
186
144
            case 7: {
187
                // Test HMAC verification
188
144
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
189
144
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
190
144
                if (secret.empty()) {
191
11
                    secret.push_back(0);
192
11
                }
193
                
194
144
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
195
144
                    secret.data(), secret.size(), hash_alg
196
144
                );
197
144
                if (hmac) {
198
144
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
199
144
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
200
144
                    );
201
144
                    if (!input_data.empty()) {
202
84
                        hmac->update(input_data.data(), input_data.size());
203
84
                    }
204
                    
205
                    // Generate signature
206
144
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
207
                    
208
                    // Verify with same data (should succeed)
209
144
                    HMAC* verify_hmac = CryptoLink::getCryptoLink().createHMAC(
210
144
                        secret.data(), secret.size(), hash_alg
211
144
                    );
212
144
                    if (verify_hmac) {
213
144
                        if (!input_data.empty()) {
214
84
                            verify_hmac->update(input_data.data(), input_data.size());
215
84
                        }
216
144
                        verify_hmac->verify(signature.data(), signature.size());
217
144
                        delete verify_hmac;
218
144
                    }
219
144
                    delete hmac;
220
144
                }
221
144
                break;
222
0
            }
223
            
224
103
            case 8: {
225
                // Test HMAC with long secret (should be hashed)
226
103
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(256, 1024);
227
103
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
228
103
                if (secret.size() < 64) {
229
38
                    secret.resize(64, 0x42);  // Pad to ensure long secret
230
38
                }
231
                
232
103
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
233
103
                    secret.data(), secret.size(), hash_alg
234
103
                );
235
103
                if (hmac) {
236
103
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
237
103
                    if (!input_data.empty()) {
238
54
                        hmac->update(input_data.data(), input_data.size());
239
54
                    }
240
103
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
241
103
                    delete hmac;
242
103
                }
243
103
                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.09k
        }
257
1.09k
    } 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.09k
    return 0;
264
1.09k
}