Coverage Report

Created: 2026-02-14 07:22

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.09k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
23
1.09k
    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
32
            case 0: {
45
                // Test Hash creation and update
46
32
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
47
32
                if (hash) {
48
32
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
49
32
                    if (!input_data.empty()) {
50
32
                        hash->update(input_data.data(), input_data.size());
51
32
                    }
52
32
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
53
32
                    delete hash;
54
32
                }
55
32
                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
476
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
64
369
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
65
369
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
66
369
                        if (!chunk.empty()) {
67
233
                            hash->update(chunk.data(), chunk.size());
68
233
                        }
69
369
                    }
70
107
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
71
107
                    delete hash;
72
107
                }
73
107
                break;
74
0
            }
75
            
76
147
            case 2: {
77
                // Test Hash with OutputBuffer
78
147
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
79
147
                if (hash) {
80
147
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
81
147
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
82
147
                    );
83
147
                    if (!input_data.empty()) {
84
65
                        hash->update(input_data.data(), input_data.size());
85
65
                    }
86
147
                    isc::util::OutputBuffer result(hash->getOutputLength());
87
147
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hash->getOutputLength() * 2);
88
147
                    hash->final(result, len);
89
147
                    delete hash;
90
147
                }
91
147
                break;
92
0
            }
93
            
94
127
            case 3: {
95
                // Test Hash with void* result
96
127
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
97
127
                if (hash) {
98
127
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
99
127
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
100
127
                    );
101
127
                    if (!input_data.empty()) {
102
64
                        hash->update(input_data.data(), input_data.size());
103
64
                    }
104
127
                    std::vector<uint8_t> result(hash->getOutputLength() * 2);
105
127
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, result.size());
106
127
                    hash->final(result.data(), len);
107
127
                    delete hash;
108
127
                }
109
127
                break;
110
0
            }
111
            
112
70
            case 4: {
113
                // Test HMAC creation and signing
114
70
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
115
70
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
116
70
                if (secret.empty()) {
117
7
                    secret.push_back(0);  // Ensure non-empty secret
118
7
                }
119
                
120
70
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
121
70
                    secret.data(), secret.size(), hash_alg
122
70
                );
123
70
                if (hmac) {
124
70
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
125
70
                    if (!input_data.empty()) {
126
49
                        hmac->update(input_data.data(), input_data.size());
127
49
                    }
128
70
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
129
70
                    delete hmac;
130
70
                }
131
70
                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
655
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
148
509
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
149
509
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
150
509
                        if (!chunk.empty()) {
151
297
                            hmac->update(chunk.data(), chunk.size());
152
297
                        }
153
509
                    }
154
146
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
155
146
                    delete hmac;
156
146
                }
157
146
                break;
158
0
            }
159
            
160
188
            case 6: {
161
                // Test HMAC with OutputBuffer
162
188
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
163
188
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
164
188
                if (secret.empty()) {
165
10
                    secret.push_back(0);
166
10
                }
167
                
168
188
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
169
188
                    secret.data(), secret.size(), hash_alg
170
188
                );
171
188
                if (hmac) {
172
188
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
173
188
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
174
188
                    );
175
188
                    if (!input_data.empty()) {
176
103
                        hmac->update(input_data.data(), input_data.size());
177
103
                    }
178
188
                    isc::util::OutputBuffer result(hmac->getOutputLength());
179
188
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hmac->getOutputLength() * 2);
180
188
                    hmac->sign(result, len);
181
188
                    delete hmac;
182
188
                }
183
188
                break;
184
0
            }
185
            
186
145
            case 7: {
187
                // Test HMAC verification
188
145
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
189
145
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
190
145
                if (secret.empty()) {
191
11
                    secret.push_back(0);
192
11
                }
193
                
194
145
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
195
145
                    secret.data(), secret.size(), hash_alg
196
145
                );
197
145
                if (hmac) {
198
145
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
199
145
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
200
145
                    );
201
145
                    if (!input_data.empty()) {
202
89
                        hmac->update(input_data.data(), input_data.size());
203
89
                    }
204
                    
205
                    // Generate signature
206
145
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
207
                    
208
                    // Verify with same data (should succeed)
209
145
                    HMAC* verify_hmac = CryptoLink::getCryptoLink().createHMAC(
210
145
                        secret.data(), secret.size(), hash_alg
211
145
                    );
212
145
                    if (verify_hmac) {
213
145
                        if (!input_data.empty()) {
214
89
                            verify_hmac->update(input_data.data(), input_data.size());
215
89
                        }
216
145
                        verify_hmac->verify(signature.data(), signature.size());
217
145
                        delete verify_hmac;
218
145
                    }
219
145
                    delete hmac;
220
145
                }
221
145
                break;
222
0
            }
223
            
224
100
            case 8: {
225
                // Test HMAC with long secret (should be hashed)
226
100
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(256, 1024);
227
100
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
228
100
                if (secret.size() < 64) {
229
37
                    secret.resize(64, 0x42);  // Pad to ensure long secret
230
37
                }
231
                
232
100
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
233
100
                    secret.data(), secret.size(), hash_alg
234
100
                );
235
100
                if (hmac) {
236
100
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
237
100
                    if (!input_data.empty()) {
238
53
                        hmac->update(input_data.data(), input_data.size());
239
53
                    }
240
100
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
241
100
                    delete hmac;
242
100
                }
243
100
                break;
244
0
            }
245
            
246
33
            case 9: {
247
                // Test RNG generation
248
33
                size_t rng_len = fdp.ConsumeIntegralInRange<size_t>(0, 1024);
249
33
                std::vector<uint8_t> random_data = isc::cryptolink::random(rng_len);
250
                
251
                // Test Qid generation
252
33
                uint16_t qid = isc::cryptolink::generateQid();
253
33
                (void)qid;  // Use the variable
254
33
                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
}