Coverage Report

Created: 2025-11-16 07:29

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