Coverage Report

Created: 2025-12-31 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.04k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
23
1.04k
    if (size < 3) {
24
2
        return 0;
25
2
    }
26
27
1.04k
    FuzzedDataProvider fdp(data, size);
28
    
29
    // Choose which crypto operation to test
30
1.04k
    uint8_t path = fdp.ConsumeIntegralInRange<uint8_t>(0, 9);
31
    
32
    // Pick a hash algorithm
33
1.04k
    HashAlgorithm hash_alg = fdp.PickValueInArray({
34
1.04k
        HashAlgorithm::MD5,
35
1.04k
        HashAlgorithm::SHA1,
36
1.04k
        HashAlgorithm::SHA224,
37
1.04k
        HashAlgorithm::SHA256,
38
1.04k
        HashAlgorithm::SHA384,
39
1.04k
        HashAlgorithm::SHA512
40
1.04k
    });
41
    
42
1.04k
    try {
43
1.04k
        switch (path) {
44
31
            case 0: {
45
                // Test Hash creation and update
46
31
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
47
31
                if (hash) {
48
31
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
49
31
                    if (!input_data.empty()) {
50
31
                        hash->update(input_data.data(), input_data.size());
51
31
                    }
52
31
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
53
31
                    delete hash;
54
31
                }
55
31
                break;
56
0
            }
57
            
58
106
            case 1: {
59
                // Test Hash with multiple updates
60
106
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
61
106
                if (hash) {
62
106
                    size_t num_updates = fdp.ConsumeIntegralInRange<size_t>(1, 10);
63
423
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
64
317
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
65
317
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
66
317
                        if (!chunk.empty()) {
67
196
                            hash->update(chunk.data(), chunk.size());
68
196
                        }
69
317
                    }
70
106
                    std::vector<uint8_t> digest = hash->final(hash->getOutputLength());
71
106
                    delete hash;
72
106
                }
73
106
                break;
74
0
            }
75
            
76
121
            case 2: {
77
                // Test Hash with OutputBuffer
78
121
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
79
121
                if (hash) {
80
121
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
81
121
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
82
121
                    );
83
121
                    if (!input_data.empty()) {
84
64
                        hash->update(input_data.data(), input_data.size());
85
64
                    }
86
121
                    isc::util::OutputBuffer result(hash->getOutputLength());
87
121
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hash->getOutputLength() * 2);
88
121
                    hash->final(result, len);
89
121
                    delete hash;
90
121
                }
91
121
                break;
92
0
            }
93
            
94
119
            case 3: {
95
                // Test Hash with void* result
96
119
                Hash* hash = CryptoLink::getCryptoLink().createHash(hash_alg);
97
119
                if (hash) {
98
119
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
99
119
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
100
119
                    );
101
119
                    if (!input_data.empty()) {
102
71
                        hash->update(input_data.data(), input_data.size());
103
71
                    }
104
119
                    std::vector<uint8_t> result(hash->getOutputLength() * 2);
105
119
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, result.size());
106
119
                    hash->final(result.data(), len);
107
119
                    delete hash;
108
119
                }
109
119
                break;
110
0
            }
111
            
112
68
            case 4: {
113
                // Test HMAC creation and signing
114
68
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
115
68
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
116
68
                if (secret.empty()) {
117
7
                    secret.push_back(0);  // Ensure non-empty secret
118
7
                }
119
                
120
68
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
121
68
                    secret.data(), secret.size(), hash_alg
122
68
                );
123
68
                if (hmac) {
124
68
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
125
68
                    if (!input_data.empty()) {
126
48
                        hmac->update(input_data.data(), input_data.size());
127
48
                    }
128
68
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
129
68
                    delete hmac;
130
68
                }
131
68
                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
8
                    secret.push_back(0);
140
8
                }
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
685
                    for (size_t i = 0; i < num_updates && fdp.remaining_bytes() > 0; i++) {
148
537
                        size_t chunk_size = fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes());
149
537
                        std::vector<uint8_t> chunk = fdp.ConsumeBytes<uint8_t>(chunk_size);
150
537
                        if (!chunk.empty()) {
151
344
                            hmac->update(chunk.data(), chunk.size());
152
344
                        }
153
537
                    }
154
148
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
155
148
                    delete hmac;
156
148
                }
157
148
                break;
158
0
            }
159
            
160
166
            case 6: {
161
                // Test HMAC with OutputBuffer
162
166
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(1, 256);
163
166
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
164
166
                if (secret.empty()) {
165
9
                    secret.push_back(0);
166
9
                }
167
                
168
166
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
169
166
                    secret.data(), secret.size(), hash_alg
170
166
                );
171
166
                if (hmac) {
172
166
                    std::vector<uint8_t> input_data = fdp.ConsumeBytes<uint8_t>(
173
166
                        fdp.ConsumeIntegralInRange<size_t>(0, size)
174
166
                    );
175
166
                    if (!input_data.empty()) {
176
92
                        hmac->update(input_data.data(), input_data.size());
177
92
                    }
178
166
                    isc::util::OutputBuffer result(hmac->getOutputLength());
179
166
                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, hmac->getOutputLength() * 2);
180
166
                    hmac->sign(result, len);
181
166
                    delete hmac;
182
166
                }
183
166
                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
99
            case 8: {
225
                // Test HMAC with long secret (should be hashed)
226
99
                size_t secret_len = fdp.ConsumeIntegralInRange<size_t>(256, 1024);
227
99
                std::vector<uint8_t> secret = fdp.ConsumeBytes<uint8_t>(secret_len);
228
99
                if (secret.size() < 64) {
229
35
                    secret.resize(64, 0x42);  // Pad to ensure long secret
230
35
                }
231
                
232
99
                HMAC* hmac = CryptoLink::getCryptoLink().createHMAC(
233
99
                    secret.data(), secret.size(), hash_alg
234
99
                );
235
99
                if (hmac) {
236
99
                    std::vector<uint8_t> input_data = fdp.ConsumeRemainingBytes<uint8_t>();
237
99
                    if (!input_data.empty()) {
238
53
                        hmac->update(input_data.data(), input_data.size());
239
53
                    }
240
99
                    std::vector<uint8_t> signature = hmac->sign(hmac->getOutputLength());
241
99
                    delete hmac;
242
99
                }
243
99
                break;
244
0
            }
245
            
246
37
            case 9: {
247
                // Test RNG generation
248
37
                size_t rng_len = fdp.ConsumeIntegralInRange<size_t>(0, 1024);
249
37
                std::vector<uint8_t> random_data = isc::cryptolink::random(rng_len);
250
                
251
                // Test Qid generation
252
37
                uint16_t qid = isc::cryptolink::generateQid();
253
37
                (void)qid;  // Use the variable
254
37
                break;
255
0
            }
256
1.04k
        }
257
1.04k
    } 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.04k
    return 0;
264
1.04k
}