/src/cryptofuzz/ecc_diff_fuzzer_importer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include <cryptofuzz/ecc_diff_fuzzer_importer.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_IMPORT_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_importer { |
16 | | |
17 | | using Point = std::optional<std::pair<std::string, std::string>>; |
18 | | |
19 | | Point decompressPoint( |
20 | | const std::vector<uint8_t> data, |
21 | | const bool compressed, |
22 | 0 | const uint16_t tlsId) { |
23 | 0 | #if !defined(CRYPTOFUZZ_IMPORT_ECC_DIFF_FUZZER) |
24 | 0 | (void)data; |
25 | 0 | (void)compressed; |
26 | 0 | (void)tlsId; |
27 | 0 | CF_ASSERT(0, "Cryptofuzz was compiled without support for ECC Diff Fuzzer importer"); |
28 | | #else |
29 | | Point ret = std::nullopt; |
30 | | |
31 | | static const int nid_list[28] = { |
32 | | NID_sect163k1, /* sect163k1 (1) */ |
33 | | NID_sect163r1, /* sect163r1 (2) */ |
34 | | NID_sect163r2, /* sect163r2 (3) */ |
35 | | NID_sect193r1, /* sect193r1 (4) */ |
36 | | NID_sect193r2, /* sect193r2 (5) */ |
37 | | NID_sect233k1, /* sect233k1 (6) */ |
38 | | NID_sect233r1, /* sect233r1 (7) */ |
39 | | NID_sect239k1, /* sect239k1 (8) */ |
40 | | NID_sect283k1, /* sect283k1 (9) */ |
41 | | NID_sect283r1, /* sect283r1 (10) */ |
42 | | NID_sect409k1, /* sect409k1 (11) */ |
43 | | NID_sect409r1, /* sect409r1 (12) */ |
44 | | NID_sect571k1, /* sect571k1 (13) */ |
45 | | NID_sect571r1, /* sect571r1 (14) */ |
46 | | NID_secp160k1, /* secp160k1 (15) */ |
47 | | NID_secp160r1, /* secp160r1 (16) */ |
48 | | NID_secp160r2, /* secp160r2 (17) */ |
49 | | NID_secp192k1, /* secp192k1 (18) */ |
50 | | NID_X9_62_prime192v1, /* secp192r1 (19) */ |
51 | | NID_secp224k1, /* secp224k1 (20) */ |
52 | | NID_secp224r1, /* secp224r1 (21) */ |
53 | | NID_secp256k1, /* secp256k1 (22) */ |
54 | | NID_X9_62_prime256v1, /* secp256r1 (23) */ |
55 | | NID_secp384r1, /* secp384r1 (24) */ |
56 | | NID_secp521r1, /* secp521r1 (25) */ |
57 | | NID_brainpoolP256r1, /* brainpoolP256r1 (26) */ |
58 | | NID_brainpoolP384r1, /* brainpoolP384r1 (27) */ |
59 | | NID_brainpoolP512r1, /* brainpool512r1 (28) */ |
60 | | }; |
61 | | |
62 | | if (tlsId < 1 || tlsId > 28) { |
63 | | return ret; |
64 | | } |
65 | | |
66 | | const auto nid = nid_list[tlsId - 1]; |
67 | | |
68 | | EC_GROUP* group = nullptr; |
69 | | EC_POINT* point = nullptr; |
70 | | BIGNUM* in = nullptr, *x = nullptr, *y = nullptr;; |
71 | | char* x_str = nullptr, *y_str = nullptr; |
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(in = BN_bin2bn(data.data(), data.size(), nullptr), nullptr); |
76 | | CF_CHECK_NE(EC_POINT_set_compressed_coordinates_GFp(group, point, in, compressed ? 1 : 0, nullptr), 0); |
77 | | CF_CHECK_NE(EC_POINT_is_on_curve(group, point, nullptr), 0); |
78 | | CF_CHECK_NE(x = BN_new(), nullptr); |
79 | | CF_CHECK_NE(y = BN_new(), nullptr); |
80 | | CF_CHECK_NE(EC_POINT_get_affine_coordinates_GFp(group, point, x, y, nullptr), 0); |
81 | | CF_CHECK_NE(x_str = BN_bn2dec(x), nullptr); |
82 | | CF_CHECK_NE(y_str = BN_bn2dec(y), nullptr); |
83 | | |
84 | | ret = {std::string(x_str), std::string(y_str)}; |
85 | | end: |
86 | | EC_GROUP_clear_free(group); |
87 | | EC_POINT_clear_free(point); |
88 | | BN_clear_free(in); |
89 | | BN_clear_free(x); |
90 | | BN_clear_free(y); |
91 | | OPENSSL_free(x_str); |
92 | | OPENSSL_free(y_str); |
93 | | |
94 | | return ret; |
95 | | #endif |
96 | 0 | } |
97 | | |
98 | 0 | static size_t bitlenFromTlsId(const uint16_t tlsId) { |
99 | 0 | switch ( tlsId ) { |
100 | 0 | case 18: |
101 | | //secp192k1 |
102 | 0 | return 192; |
103 | 0 | case 19: |
104 | | //secp192r1 |
105 | 0 | return 192; |
106 | 0 | case 20: |
107 | | //secp224k1 |
108 | 0 | return 224; |
109 | 0 | case 21: |
110 | | //secp224r1 |
111 | 0 | return 224; |
112 | 0 | case 22: |
113 | | //secp256k1 |
114 | 0 | return 256; |
115 | 0 | case 23: |
116 | | //secp256r1 |
117 | 0 | return 256; |
118 | 0 | case 24: |
119 | | //secp384r1 |
120 | 0 | return 384; |
121 | 0 | case 25: |
122 | | //secp521r1 |
123 | 0 | return 521; |
124 | 0 | case 26: |
125 | | //brainpoolP256r1 |
126 | 0 | return 256; |
127 | 0 | case 27: |
128 | | //brainpoolP384r1 |
129 | 0 | return 384; |
130 | 0 | case 28: |
131 | | //brainpoolP512r1 |
132 | 0 | return 512; |
133 | 0 | } |
134 | | |
135 | 0 | return 0; |
136 | 0 | } |
137 | | |
138 | 0 | static size_t ecdf_byteceil(const size_t numBits) { |
139 | 0 | return ((numBits) + 7) >> 3; |
140 | 0 | } |
141 | | |
142 | | } /* namespace ecc_diff_fuzzer_importer */ |
143 | | |
144 | | ECC_Diff_Fuzzer_Importer::ECC_Diff_Fuzzer_Importer(const std::string filename, const std::string outDir) : |
145 | 0 | filename(filename), outDir(outDir) { |
146 | 0 | } |
147 | | |
148 | 0 | void ECC_Diff_Fuzzer_Importer::Run(void) { |
149 | 0 | std::ifstream instream(filename, std::ios::in | std::ios::binary); |
150 | 0 | std::vector<uint8_t> data((std::istreambuf_iterator<char>(instream)), std::istreambuf_iterator<char>()); |
151 | |
|
152 | 0 | LoadInput(data); |
153 | 0 | } |
154 | | |
155 | 0 | void ECC_Diff_Fuzzer_Importer::LoadInput(const std::vector<uint8_t> data) { |
156 | 0 | ecc_diff_fuzzer_importer::Point A, B; |
157 | 0 | std::string multiplier; |
158 | |
|
159 | 0 | size_t left = data.size(); |
160 | |
|
161 | 0 | if ( left < 5 ) { |
162 | 0 | return; |
163 | 0 | } |
164 | | |
165 | 0 | const uint16_t tlsId = ((size_t)data[0] << 8) | data[1]; |
166 | 0 | left -= 2; |
167 | |
|
168 | 0 | auto groupBitLen = ecc_diff_fuzzer_importer::bitlenFromTlsId(tlsId); |
169 | |
|
170 | 0 | if ( groupBitLen == 0 ) { |
171 | 0 | return; |
172 | 0 | } |
173 | | |
174 | 0 | groupBitLen = ecc_diff_fuzzer_importer::ecdf_byteceil(groupBitLen); |
175 | |
|
176 | 0 | if (left < 1 + 2 * groupBitLen) { |
177 | 0 | return; |
178 | 0 | } |
179 | | |
180 | 0 | if (left > 1 + 2 * groupBitLen) { |
181 | 0 | left = groupBitLen; |
182 | 0 | } |
183 | |
|
184 | 0 | const auto bignumSize = left / 2; |
185 | 0 | const bool isAdd = data[bignumSize + 2] & 0x80; |
186 | |
|
187 | 0 | if ( isAdd ) { |
188 | 0 | A = ecc_diff_fuzzer_importer::decompressPoint( |
189 | 0 | std::vector<uint8_t>( |
190 | 0 | data.data() + 3, |
191 | 0 | data.data() + 3 + (left - bignumSize - 1)), |
192 | 0 | data[bignumSize + 2] & 0x2, |
193 | 0 | tlsId); |
194 | 0 | if ( A == std::nullopt ) { |
195 | 0 | return; |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | 0 | B = ecc_diff_fuzzer_importer::decompressPoint( |
200 | 0 | std::vector<uint8_t>( |
201 | 0 | data.data() + 3 + bignumSize, |
202 | 0 | data.data() + 3 + bignumSize + (left - bignumSize - 1)), |
203 | 0 | data[bignumSize + bignumSize + 2] & 0x2, |
204 | 0 | tlsId); |
205 | 0 | if ( B == std::nullopt ) { |
206 | 0 | return; |
207 | 0 | } |
208 | | |
209 | 0 | if ( !isAdd ) { |
210 | 0 | multiplier = cryptofuzz::util::BinToDec(data.data() + 2, bignumSize); |
211 | 0 | } |
212 | |
|
213 | 0 | nlohmann::json parameters; |
214 | 0 | parameters["modifier"] = ""; |
215 | |
|
216 | 0 | switch ( tlsId ) { |
217 | 0 | case 18: |
218 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp192k1"); |
219 | 0 | break; |
220 | 0 | case 19: |
221 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp192r1"); |
222 | 0 | break; |
223 | 0 | case 20: |
224 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp224k1"); |
225 | 0 | break; |
226 | 0 | case 21: |
227 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp224r1"); |
228 | 0 | break; |
229 | 0 | case 22: |
230 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp256k1"); |
231 | 0 | break; |
232 | 0 | case 23: |
233 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp256r1"); |
234 | 0 | break; |
235 | 0 | case 24: |
236 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp384r1"); |
237 | 0 | break; |
238 | 0 | case 25: |
239 | 0 | parameters["curveType"] = CF_ECC_CURVE("secp521r1"); |
240 | 0 | break; |
241 | 0 | case 26: |
242 | 0 | parameters["curveType"] = CF_ECC_CURVE("brainpool256r1"); |
243 | 0 | break; |
244 | 0 | case 27: |
245 | 0 | parameters["curveType"] = CF_ECC_CURVE("brainpool384r1"); |
246 | 0 | break; |
247 | 0 | case 28: |
248 | 0 | parameters["curveType"] = CF_ECC_CURVE("brainpool512r1"); |
249 | 0 | break; |
250 | 0 | default: |
251 | 0 | CF_UNREACHABLE(); |
252 | 0 | } |
253 | | |
254 | 0 | if ( isAdd ) { |
255 | 0 | parameters["a_x"] = A->first; |
256 | 0 | parameters["a_y"] = A->second; |
257 | 0 | parameters["b_x"] = B->first; |
258 | 0 | parameters["b_y"] = B->second; |
259 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
260 | 0 | cryptofuzz::operation::ECC_Point_Add op(parameters); |
261 | 0 | op.Serialize(dsOut2); |
262 | |
|
263 | 0 | write(CF_OPERATION("ECC_Point_Add"), dsOut2); |
264 | 0 | } else { |
265 | 0 | parameters["a_x"] = B->first; |
266 | 0 | parameters["a_y"] = B->second; |
267 | 0 | parameters["b"] = multiplier; |
268 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
269 | 0 | cryptofuzz::operation::ECC_Point_Mul op(parameters); |
270 | 0 | op.Serialize(dsOut2); |
271 | |
|
272 | 0 | write(CF_OPERATION("ECC_Point_Mul"), dsOut2); |
273 | 0 | } |
274 | 0 | } |
275 | | |
276 | 0 | void ECC_Diff_Fuzzer_Importer::write(const uint64_t operation, fuzzing::datasource::Datasource& dsOut2) { |
277 | 0 | fuzzing::datasource::Datasource dsOut(nullptr, 0); |
278 | | |
279 | | /* Operation ID */ |
280 | 0 | dsOut.Put<uint64_t>(operation); |
281 | |
|
282 | 0 | dsOut.PutData(dsOut2.GetOut()); |
283 | | |
284 | | /* Modifier */ |
285 | 0 | dsOut.PutData(std::vector<uint8_t>(0)); |
286 | | |
287 | | /* Module ID */ |
288 | 0 | dsOut.Put<uint64_t>(CF_MODULE("OpenSSL")); |
289 | | |
290 | | /* Terminator */ |
291 | 0 | dsOut.Put<bool>(false); |
292 | |
|
293 | 0 | { |
294 | 0 | std::string filename = outDir + std::string("/") + util::SHA1(dsOut.GetOut()); |
295 | 0 | FILE* fp = fopen(filename.c_str(), "wb"); |
296 | 0 | fwrite(dsOut.GetOut().data(), dsOut.GetOut().size(), 1, fp); |
297 | 0 | fclose(fp); |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | | } /* namespace cryptofuzz */ |