/src/cryptofuzz/ecc_diff_fuzzer_exporter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include <cryptofuzz/ecc_diff_fuzzer_exporter.h> |
2 | | #include <cryptofuzz/repository.h> |
3 | | #include <cryptofuzz/operations.h> |
4 | | #include <cryptofuzz/util.h> |
5 | | #include <cryptofuzz/crypto.h> |
6 | | #include <stdio.h> |
7 | | #include <fstream> |
8 | | #if defined(CRYPTOFUZZ_EXPORT_ECC_DIFF_FUZZER) |
9 | | #include <openssl/ec.h> |
10 | | #include <openssl/obj_mac.h> |
11 | | #endif |
12 | | |
13 | | namespace cryptofuzz { |
14 | | |
15 | | namespace ecc_diff_fuzzer_exporter { |
16 | | |
17 | | std::optional<std::vector<uint8_t>> compressPoint( |
18 | | const std::string& ax, |
19 | | const std::string& ay, |
20 | 0 | const uint16_t tlsId) { |
21 | 0 | #if !defined(CRYPTOFUZZ_EXPORT_ECC_DIFF_FUZZER) |
22 | 0 | (void)ax; |
23 | 0 | (void)ay; |
24 | 0 | (void)tlsId; |
25 | 0 | CF_ASSERT(0, "Cryptofuzz was compiled without support for ECC Diff Fuzzer exporter"); |
26 | | #else |
27 | | std::optional<std::vector<uint8_t>> ret = std::nullopt; |
28 | | |
29 | | static const int nid_list[28] = { |
30 | | NID_sect163k1, /* sect163k1 (1) */ |
31 | | NID_sect163r1, /* sect163r1 (2) */ |
32 | | NID_sect163r2, /* sect163r2 (3) */ |
33 | | NID_sect193r1, /* sect193r1 (4) */ |
34 | | NID_sect193r2, /* sect193r2 (5) */ |
35 | | NID_sect233k1, /* sect233k1 (6) */ |
36 | | NID_sect233r1, /* sect233r1 (7) */ |
37 | | NID_sect239k1, /* sect239k1 (8) */ |
38 | | NID_sect283k1, /* sect283k1 (9) */ |
39 | | NID_sect283r1, /* sect283r1 (10) */ |
40 | | NID_sect409k1, /* sect409k1 (11) */ |
41 | | NID_sect409r1, /* sect409r1 (12) */ |
42 | | NID_sect571k1, /* sect571k1 (13) */ |
43 | | NID_sect571r1, /* sect571r1 (14) */ |
44 | | NID_secp160k1, /* secp160k1 (15) */ |
45 | | NID_secp160r1, /* secp160r1 (16) */ |
46 | | NID_secp160r2, /* secp160r2 (17) */ |
47 | | NID_secp192k1, /* secp192k1 (18) */ |
48 | | NID_X9_62_prime192v1, /* secp192r1 (19) */ |
49 | | NID_secp224k1, /* secp224k1 (20) */ |
50 | | NID_secp224r1, /* secp224r1 (21) */ |
51 | | NID_secp256k1, /* secp256k1 (22) */ |
52 | | NID_X9_62_prime256v1, /* secp256r1 (23) */ |
53 | | NID_secp384r1, /* secp384r1 (24) */ |
54 | | NID_secp521r1, /* secp521r1 (25) */ |
55 | | NID_brainpoolP256r1, /* brainpoolP256r1 (26) */ |
56 | | NID_brainpoolP384r1, /* brainpoolP384r1 (27) */ |
57 | | NID_brainpoolP512r1, /* brainpool512r1 (28) */ |
58 | | }; |
59 | | |
60 | | if (tlsId < 1 || tlsId > 28) { |
61 | | return ret; |
62 | | } |
63 | | |
64 | | const auto nid = nid_list[tlsId - 1]; |
65 | | |
66 | | EC_GROUP* group = nullptr; |
67 | | EC_POINT* point = nullptr; |
68 | | BN_CTX* ctx = nullptr; |
69 | | BIGNUM *x = nullptr, *y = nullptr, *compressed = nullptr; |
70 | | unsigned char* point_bytes = nullptr; |
71 | | size_t point_size = 0; |
72 | | |
73 | | CF_CHECK_NE(group = EC_GROUP_new_by_curve_name(nid), nullptr); |
74 | | CF_CHECK_NE(point = EC_POINT_new(group), nullptr); |
75 | | CF_CHECK_NE(ctx = BN_CTX_new(), nullptr); |
76 | | CF_CHECK_NE(x = BN_new(), nullptr); |
77 | | CF_CHECK_NE(y = BN_new(), nullptr); |
78 | | CF_CHECK_NE(BN_dec2bn(&x, ax.c_str()), 0); |
79 | | CF_CHECK_NE(BN_dec2bn(&y, ay.c_str()), 0); |
80 | | CF_CHECK_NE(EC_POINT_set_affine_coordinates_GFp(group, point, x, y, nullptr), 0); |
81 | | CF_CHECK_NE(EC_POINT_is_on_curve(group, point, nullptr), 0); |
82 | | CF_CHECK_NE(compressed = BN_new(), nullptr); |
83 | | CF_CHECK_NE(EC_POINT_point2bn(group, point, POINT_CONVERSION_COMPRESSED, compressed, ctx), nullptr); |
84 | | point_size = BN_num_bytes(compressed); |
85 | | CF_CHECK_GT(point_size, 0); |
86 | | point_bytes = (unsigned char*)malloc(point_size); |
87 | | BN_bn2bin(compressed, point_bytes); |
88 | | |
89 | | ret = std::vector<uint8_t>(point_bytes + 1, point_bytes + point_size); |
90 | | |
91 | | end: |
92 | | EC_GROUP_clear_free(group); |
93 | | EC_POINT_clear_free(point); |
94 | | BN_CTX_free(ctx); |
95 | | BN_clear_free(x); |
96 | | BN_clear_free(y); |
97 | | BN_clear_free(compressed); |
98 | | free(point_bytes); |
99 | | |
100 | | return ret; |
101 | | #endif |
102 | 0 | } |
103 | | |
104 | 0 | std::optional<uint16_t> toTlsId(const uint64_t curveType) { |
105 | 0 | switch ( curveType ) { |
106 | 0 | case CF_ECC_CURVE("brainpool256r1"): |
107 | 0 | return 26; |
108 | 0 | case CF_ECC_CURVE("brainpool384r1"): |
109 | 0 | return 27; |
110 | 0 | case CF_ECC_CURVE("brainpool512r1"): |
111 | 0 | return 28; |
112 | 0 | case CF_ECC_CURVE("secp192k1"): |
113 | 0 | return 18; |
114 | 0 | case CF_ECC_CURVE("secp192r1"): |
115 | 0 | return 19; |
116 | 0 | case CF_ECC_CURVE("secp224k1"): |
117 | 0 | return 20; |
118 | 0 | case CF_ECC_CURVE("secp224r1"): |
119 | 0 | return 21; |
120 | 0 | case CF_ECC_CURVE("secp256k1"): |
121 | 0 | return 22; |
122 | 0 | case CF_ECC_CURVE("secp256r1"): |
123 | 0 | return 23; |
124 | 0 | case CF_ECC_CURVE("secp384r1"): |
125 | 0 | return 24; |
126 | 0 | case CF_ECC_CURVE("secp521r1"): |
127 | 0 | return 25; |
128 | 0 | default: |
129 | 0 | return std::nullopt; |
130 | 0 | } |
131 | 0 | } |
132 | | |
133 | 0 | static size_t bitlenFromTlsId(const uint16_t tlsId) { |
134 | 0 | switch ( tlsId ) { |
135 | 0 | case 18: |
136 | | //secp192k1 |
137 | 0 | return 192; |
138 | 0 | case 19: |
139 | | //secp192r1 |
140 | 0 | return 192; |
141 | 0 | case 20: |
142 | | //secp224k1 |
143 | 0 | return 224; |
144 | 0 | case 21: |
145 | | //secp224r1 |
146 | 0 | return 224; |
147 | 0 | case 22: |
148 | | //secp256k1 |
149 | 0 | return 256; |
150 | 0 | case 23: |
151 | | //secp256r1 |
152 | 0 | return 256; |
153 | 0 | case 24: |
154 | | //secp384r1 |
155 | 0 | return 384; |
156 | 0 | case 25: |
157 | | //secp521r1 |
158 | 0 | return 521; |
159 | 0 | case 26: |
160 | | //brainpoolP256r1 |
161 | 0 | return 256; |
162 | 0 | case 27: |
163 | | //brainpoolP384r1 |
164 | 0 | return 384; |
165 | 0 | case 28: |
166 | | //brainpoolP512r1 |
167 | 0 | return 512; |
168 | 0 | } |
169 | | |
170 | 0 | return 0; |
171 | 0 | } |
172 | | |
173 | 0 | static size_t ecdf_byteceil(const size_t numBits) { |
174 | 0 | return ((numBits) + 7) >> 3; |
175 | 0 | } |
176 | | |
177 | | } /* namespace ecc_diff_fuzzer_exporter */ |
178 | | |
179 | | ECC_Diff_Fuzzer_Exporter::ECC_Diff_Fuzzer_Exporter(const std::string filename, const std::string outDir) : |
180 | 0 | filename(filename), outDir(outDir) { |
181 | 0 | } |
182 | | |
183 | 0 | void ECC_Diff_Fuzzer_Exporter::Run(void) { |
184 | 0 | std::ifstream instream(filename, std::ios::in | std::ios::binary); |
185 | 0 | std::vector<uint8_t> data((std::istreambuf_iterator<char>(instream)), std::istreambuf_iterator<char>()); |
186 | |
|
187 | 0 | LoadInput(data); |
188 | 0 | } |
189 | | |
190 | 0 | void ECC_Diff_Fuzzer_Exporter::LoadInput(const std::vector<uint8_t> data) { |
191 | 0 | try { |
192 | 0 | Datasource ds(data.data(), data.size()); |
193 | 0 | const auto operation = ds.Get<uint64_t>(); |
194 | 0 | if ( operation != CF_OPERATION("ECC_Point_Add") && operation != CF_OPERATION("ECC_Point_Mul") ) { |
195 | 0 | return; |
196 | 0 | } |
197 | 0 | const auto payload = ds.GetData(0, 1); |
198 | 0 | const auto modifier = ds.GetData(0); |
199 | 0 | Datasource ds2(payload.data(), payload.size()); |
200 | 0 | if ( operation == CF_OPERATION("ECC_Point_Add") ) { |
201 | 0 | const auto op = operation::ECC_Point_Add(ds2, component::Modifier(modifier.data(), modifier.size())); |
202 | |
|
203 | 0 | const auto curveType = op.curveType.Get(); |
204 | |
|
205 | 0 | const auto ax = op.a.first.ToTrimmedString(); |
206 | 0 | const auto ay = op.a.second.ToTrimmedString(); |
207 | |
|
208 | 0 | const auto bx = op.b.first.ToTrimmedString(); |
209 | 0 | const auto by = op.b.second.ToTrimmedString(); |
210 | |
|
211 | 0 | write_Add(curveType, ax, ay, bx, by); |
212 | 0 | } else if ( operation == CF_OPERATION("ECC_Point_Mul") ) { |
213 | 0 | const auto op = operation::ECC_Point_Mul(ds2, component::Modifier(modifier.data(), modifier.size())); |
214 | |
|
215 | 0 | const auto curveType = op.curveType.Get(); |
216 | |
|
217 | 0 | const auto ax = op.a.first.ToTrimmedString(); |
218 | 0 | const auto ay = op.a.second.ToTrimmedString(); |
219 | |
|
220 | 0 | const auto b = op.b.ToTrimmedString(); |
221 | |
|
222 | 0 | write_Mul(curveType, ax, ay, b); |
223 | 0 | } |
224 | 0 | } catch ( ... ) { } |
225 | 0 | } |
226 | | |
227 | | void ECC_Diff_Fuzzer_Exporter::write_Add( |
228 | | const uint64_t curveType, |
229 | | const std::string ax, |
230 | | const std::string ay, |
231 | | const std::string bx, |
232 | 0 | const std::string by) { |
233 | 0 | std::vector<uint8_t> out; |
234 | |
|
235 | 0 | const auto tlsId = ecc_diff_fuzzer_exporter::toTlsId(curveType); |
236 | 0 | if ( tlsId == std::nullopt ) { |
237 | 0 | return; |
238 | 0 | } |
239 | | |
240 | 0 | auto groupBitLen = ecc_diff_fuzzer_exporter::bitlenFromTlsId(*tlsId); |
241 | |
|
242 | 0 | if ( groupBitLen == 0 ) { |
243 | 0 | return; |
244 | 0 | } |
245 | | |
246 | 0 | groupBitLen = ecc_diff_fuzzer_exporter::ecdf_byteceil(groupBitLen); |
247 | |
|
248 | 0 | out.push_back((*tlsId >> 8) & 0xFF); |
249 | 0 | out.push_back(*tlsId & 0xFF); |
250 | 0 | out.push_back(0x20); |
251 | |
|
252 | 0 | { |
253 | 0 | const auto A = ecc_diff_fuzzer_exporter::compressPoint(ax, ay, *tlsId); |
254 | 0 | if ( A == std::nullopt ) { |
255 | 0 | return; |
256 | 0 | } |
257 | | |
258 | 0 | out.insert(std::end(out), std::begin(*A), std::end(*A)); |
259 | 0 | } |
260 | | |
261 | 0 | { |
262 | 0 | const auto B = ecc_diff_fuzzer_exporter::compressPoint(bx, by, *tlsId); |
263 | 0 | if ( B == std::nullopt ) { |
264 | 0 | return; |
265 | 0 | } |
266 | 0 | out.insert(std::end(out), std::begin(*B), std::end(*B)); |
267 | 0 | } |
268 | | |
269 | 0 | write(out); |
270 | 0 | } |
271 | | |
272 | | void ECC_Diff_Fuzzer_Exporter::write_Mul( |
273 | | const uint64_t curveType, |
274 | | const std::string ax, |
275 | | const std::string ay, |
276 | 0 | const std::string b) { |
277 | 0 | std::vector<uint8_t> out; |
278 | |
|
279 | 0 | const auto tlsId = ecc_diff_fuzzer_exporter::toTlsId(curveType); |
280 | 0 | if ( tlsId == std::nullopt ) { |
281 | 0 | return; |
282 | 0 | } |
283 | | |
284 | 0 | auto groupBitLen = ecc_diff_fuzzer_exporter::bitlenFromTlsId(*tlsId); |
285 | |
|
286 | 0 | if ( groupBitLen == 0 ) { |
287 | 0 | return; |
288 | 0 | } |
289 | | |
290 | 0 | groupBitLen = ecc_diff_fuzzer_exporter::ecdf_byteceil(groupBitLen); |
291 | |
|
292 | 0 | out.push_back((*tlsId >> 8) & 0xFF); |
293 | 0 | out.push_back(*tlsId & 0xFF); |
294 | |
|
295 | 0 | { |
296 | 0 | const auto A = ecc_diff_fuzzer_exporter::compressPoint(ax, ay, *tlsId); |
297 | 0 | if ( A == std::nullopt ) { |
298 | 0 | return; |
299 | 0 | } |
300 | | |
301 | 0 | const auto B = util::DecToBin(b, A->size()); |
302 | |
|
303 | 0 | if ( B == std::nullopt ) { |
304 | 0 | return; |
305 | 0 | } |
306 | | |
307 | 0 | out.insert(std::end(out), std::begin(*B), std::end(*B)); |
308 | 0 | out.push_back(0x00); |
309 | 0 | out.insert(std::end(out), std::begin(*A), std::end(*A)); |
310 | 0 | } |
311 | | |
312 | 0 | write(out); |
313 | 0 | } |
314 | | |
315 | 0 | void ECC_Diff_Fuzzer_Exporter::write(const std::vector<uint8_t> data) { |
316 | 0 | std::string filename = outDir + std::string("/") + util::SHA1(data); |
317 | 0 | FILE* fp = fopen(filename.c_str(), "wb"); |
318 | 0 | fwrite(data.data(), data.size(), 1, fp); |
319 | 0 | fclose(fp); |
320 | 0 | } |
321 | | |
322 | | |
323 | | } /* namespace cryptofuzz */ |