/src/cryptofuzz/wycheproof.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include <cryptofuzz/wycheproof.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 | | |
9 | | namespace cryptofuzz { |
10 | | |
11 | | Wycheproof::Wycheproof(const std::string filename, const std::string outDir) : |
12 | 0 | outDir(outDir) { |
13 | 0 | std::ifstream ifs(filename); |
14 | 0 | j = nlohmann::json::parse(ifs); |
15 | 0 | } |
16 | | |
17 | 0 | void Wycheproof::Run(void) { |
18 | 0 | const auto& groups = j["testGroups"]; |
19 | |
|
20 | 0 | if ( j["schema"].get<std::string>() == "ecdsa_verify_schema.json" ) { |
21 | 0 | ECDSA_Verify(groups); |
22 | 0 | } else if ( j["schema"].get<std::string>() == "eddsa_verify_schema.json" ) { |
23 | 0 | EDDSA_Verify(groups); |
24 | 0 | } else if ( j["schema"].get<std::string>() == "ecdh_test_schema.json" ) { |
25 | 0 | ECDH(groups); |
26 | 0 | } else if ( j["schema"].get<std::string>() == "dsa_verify_schema.json" ) { |
27 | 0 | DSA(groups); |
28 | 0 | } else if ( j["schema"].get<std::string>() == "primality_test_schema.json" ) { |
29 | 0 | PrimalityTest(groups); |
30 | 0 | } |
31 | 0 | } |
32 | | |
33 | 0 | void Wycheproof::write(const uint64_t operation, fuzzing::datasource::Datasource& dsOut2) { |
34 | 0 | fuzzing::datasource::Datasource dsOut(nullptr, 0); |
35 | | |
36 | | /* Operation ID */ |
37 | 0 | dsOut.Put<uint64_t>(operation); |
38 | |
|
39 | 0 | dsOut.PutData(dsOut2.GetOut()); |
40 | | |
41 | | /* Modifier */ |
42 | 0 | dsOut.PutData(std::vector<uint8_t>(0)); |
43 | | |
44 | | /* Module ID */ |
45 | 0 | dsOut.Put<uint64_t>(CF_MODULE("OpenSSL")); |
46 | | |
47 | | /* Terminator */ |
48 | 0 | dsOut.Put<bool>(false); |
49 | |
|
50 | 0 | { |
51 | | //std::string filename = outDir + std::string("/") + std::to_string(counter++); |
52 | 0 | std::string filename = outDir + std::string("/") + util::SHA1(dsOut.GetOut()); |
53 | 0 | FILE* fp = fopen(filename.c_str(), "wb"); |
54 | 0 | fwrite(dsOut.GetOut().data(), dsOut.GetOut().size(), 1, fp); |
55 | 0 | fclose(fp); |
56 | 0 | } |
57 | 0 | } |
58 | | |
59 | 0 | void Wycheproof::ECDSA_Verify(const nlohmann::json& groups) { |
60 | 0 | for (const auto &group : groups) { |
61 | 0 | for (const auto &test : group["tests"]) { |
62 | 0 | nlohmann::json |
63 | 0 | p_ecdsa_verify, |
64 | 0 | p_ecc_point_add, |
65 | 0 | p_ecc_point_mul_1, |
66 | 0 | p_ecc_point_mul_2, |
67 | 0 | p_ecc_validatepubkey_1, |
68 | 0 | p_ecc_validatepubkey_2; |
69 | 0 | std::string digest; |
70 | |
|
71 | 0 | { |
72 | 0 | const std::string curve = group["key"]["curve"]; |
73 | 0 | auto curveID = repository::ECC_CurveFromString(curve); |
74 | |
|
75 | 0 | if ( curveID == std::nullopt ) { |
76 | 0 | if ( curve == "brainpoolP224r1" ) { |
77 | 0 | curveID = CF_ECC_CURVE("brainpool224r1"); |
78 | 0 | } else if ( curve == "brainpoolP224t1" ) { |
79 | 0 | curveID = CF_ECC_CURVE("brainpool224t1"); |
80 | 0 | } else if ( curve == "brainpoolP256r1" ) { |
81 | 0 | curveID = CF_ECC_CURVE("brainpool256r1"); |
82 | 0 | } else if ( curve == "brainpoolP256t1" ) { |
83 | 0 | curveID = CF_ECC_CURVE("brainpool256t1"); |
84 | 0 | } else if ( curve == "brainpoolP320r1" ) { |
85 | 0 | curveID = CF_ECC_CURVE("brainpool320r1"); |
86 | 0 | } else if ( curve == "brainpoolP320t1" ) { |
87 | 0 | curveID = CF_ECC_CURVE("brainpool320t1"); |
88 | 0 | } else if ( curve == "brainpoolP384r1" ) { |
89 | 0 | curveID = CF_ECC_CURVE("brainpool384r1"); |
90 | 0 | } else if ( curve == "brainpoolP384t1" ) { |
91 | 0 | curveID = CF_ECC_CURVE("brainpool384t1"); |
92 | 0 | } else if ( curve == "brainpoolP512r1" ) { |
93 | 0 | curveID = CF_ECC_CURVE("brainpool512r1"); |
94 | 0 | } else if ( curve == "brainpoolP512t1" ) { |
95 | 0 | curveID = CF_ECC_CURVE("brainpool512t1"); |
96 | 0 | } else { |
97 | 0 | CF_ASSERT(0, "Curve not recognized"); |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | 0 | p_ecdsa_verify["curveType"] = *curveID; |
102 | 0 | p_ecc_point_add["curveType"] = *curveID; |
103 | 0 | p_ecc_point_mul_1["curveType"] = *curveID; |
104 | 0 | p_ecc_point_mul_2["curveType"] = *curveID; |
105 | 0 | p_ecc_validatepubkey_1["curveType"] = *curveID; |
106 | 0 | p_ecc_validatepubkey_2["curveType"] = *curveID; |
107 | 0 | } |
108 | | |
109 | 0 | { |
110 | 0 | digest = group["sha"]; |
111 | |
|
112 | 0 | if ( digest == "SHA-224") { |
113 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA224"); |
114 | 0 | } else if ( digest == "SHA-256") { |
115 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA256"); |
116 | 0 | } else if ( digest == "SHA-384") { |
117 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA384"); |
118 | 0 | } else if ( digest == "SHA-512") { |
119 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA512"); |
120 | 0 | } else if ( digest == "SHA3-224") { |
121 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-224"); |
122 | 0 | } else if ( digest == "SHA3-256") { |
123 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-256"); |
124 | 0 | } else if ( digest == "SHA3-384") { |
125 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-384"); |
126 | 0 | } else if ( digest == "SHA3-512") { |
127 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-512"); |
128 | 0 | } else { |
129 | 0 | CF_ASSERT(0, "Digest not recognized"); |
130 | 0 | } |
131 | 0 | } |
132 | | |
133 | 0 | p_ecdsa_verify["signature"]["pub"][0] = util::HexToDec(group["key"]["wx"]); |
134 | 0 | p_ecdsa_verify["signature"]["pub"][1] = util::HexToDec(group["key"]["wy"]); |
135 | |
|
136 | 0 | p_ecc_point_add["a_x"] = util::HexToDec(group["key"]["wx"]); |
137 | 0 | p_ecc_point_add["a_y"] = util::HexToDec(group["key"]["wy"]); |
138 | |
|
139 | 0 | p_ecc_point_mul_1["a_x"] = util::HexToDec(group["key"]["wx"]); |
140 | 0 | p_ecc_point_mul_1["a_y"] = util::HexToDec(group["key"]["wy"]); |
141 | |
|
142 | 0 | p_ecc_validatepubkey_1["pub_x"] = util::HexToDec(group["key"]["wx"]); |
143 | 0 | p_ecc_validatepubkey_1["pub_y"] = util::HexToDec(group["key"]["wy"]); |
144 | |
|
145 | 0 | { |
146 | 0 | const auto sig = util::SignatureFromDER(test["sig"].get<std::string>()); |
147 | 0 | CF_CHECK_NE(sig, std::nullopt); |
148 | |
|
149 | 0 | p_ecdsa_verify["signature"]["signature"][0] = sig->first; |
150 | 0 | p_ecdsa_verify["signature"]["signature"][1] = sig->second; |
151 | |
|
152 | 0 | p_ecc_point_add["b_x"] = sig->first; |
153 | 0 | p_ecc_point_add["b_y"] = sig->second; |
154 | |
|
155 | 0 | p_ecc_point_mul_2["a_x"] = sig->first; |
156 | 0 | p_ecc_point_mul_2["a_y"] = sig->second; |
157 | |
|
158 | 0 | p_ecc_validatepubkey_2["pub_x"] = sig->first; |
159 | 0 | p_ecc_validatepubkey_2["pub_y"] = sig->second; |
160 | 0 | } |
161 | | |
162 | 0 | p_ecdsa_verify["cleartext"] = test["msg"].get<std::string>(); |
163 | | |
164 | | /* Construct and write ECDSA_Verify */ |
165 | 0 | { |
166 | 0 | p_ecdsa_verify["modifier"] = ""; |
167 | |
|
168 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
169 | 0 | cryptofuzz::operation::ECDSA_Verify op(p_ecdsa_verify); |
170 | 0 | op.Serialize(dsOut2); |
171 | |
|
172 | 0 | write(CF_OPERATION("ECDSA_Verify"), dsOut2); |
173 | 0 | } |
174 | | |
175 | | /* If digest type is SHA256, compute the SHA256 hash of the message, |
176 | | * and use this to write an input that uses the NULL digest */ |
177 | 0 | if ( digest == "SHA-256" ) { |
178 | | /* Hex-decode cleartext */ |
179 | 0 | std::vector<uint8_t> ct_sha256; |
180 | 0 | boost::algorithm::unhex( |
181 | 0 | test["msg"].get<std::string>(), |
182 | 0 | std::back_inserter(ct_sha256)); |
183 | 0 | const auto ct = crypto::sha256(ct_sha256); |
184 | |
|
185 | 0 | std::string ct_hex; |
186 | 0 | boost::algorithm::hex(ct, std::back_inserter(ct_hex)); |
187 | |
|
188 | 0 | p_ecdsa_verify["cleartext"] = ct_hex; |
189 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("NULL"); |
190 | |
|
191 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
192 | 0 | cryptofuzz::operation::ECDSA_Verify op(p_ecdsa_verify); |
193 | 0 | op.Serialize(dsOut2); |
194 | |
|
195 | 0 | write(CF_OPERATION("ECDSA_Verify"), dsOut2); |
196 | 0 | } |
197 | |
|
198 | 0 | { |
199 | 0 | p_ecc_point_add["modifier"] = ""; |
200 | |
|
201 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
202 | 0 | cryptofuzz::operation::ECC_Point_Add op(p_ecc_point_add); |
203 | 0 | op.Serialize(dsOut2); |
204 | |
|
205 | 0 | write(CF_OPERATION("ECC_Point_Add"), dsOut2); |
206 | 0 | } |
207 | |
|
208 | 0 | { |
209 | 0 | p_ecc_point_mul_1["modifier"] = ""; |
210 | 0 | p_ecc_point_mul_1["b"] = "1"; |
211 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
212 | 0 | cryptofuzz::operation::ECC_Point_Mul op(p_ecc_point_mul_1); |
213 | 0 | op.Serialize(dsOut2); |
214 | |
|
215 | 0 | write(CF_OPERATION("ECC_Point_Mul"), dsOut2); |
216 | 0 | } |
217 | |
|
218 | 0 | { |
219 | 0 | p_ecc_point_mul_2["modifier"] = ""; |
220 | 0 | p_ecc_point_mul_2["b"] = "1"; |
221 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
222 | 0 | cryptofuzz::operation::ECC_Point_Mul op(p_ecc_point_mul_2); |
223 | 0 | op.Serialize(dsOut2); |
224 | |
|
225 | 0 | write(CF_OPERATION("ECC_Point_Mul"), dsOut2); |
226 | 0 | } |
227 | |
|
228 | 0 | { |
229 | 0 | p_ecc_validatepubkey_1["modifier"] = ""; |
230 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
231 | 0 | cryptofuzz::operation::ECC_ValidatePubkey op(p_ecc_validatepubkey_1); |
232 | 0 | op.Serialize(dsOut2); |
233 | |
|
234 | 0 | write(CF_OPERATION("ECC_ValidatePubkey"), dsOut2); |
235 | 0 | } |
236 | |
|
237 | 0 | { |
238 | 0 | p_ecc_validatepubkey_2["modifier"] = ""; |
239 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
240 | 0 | cryptofuzz::operation::ECC_ValidatePubkey op(p_ecc_validatepubkey_2); |
241 | 0 | op.Serialize(dsOut2); |
242 | |
|
243 | 0 | write(CF_OPERATION("ECC_ValidatePubkey"), dsOut2); |
244 | 0 | } |
245 | |
|
246 | 0 | end: |
247 | 0 | (void)1; |
248 | 0 | } |
249 | 0 | } |
250 | 0 | } |
251 | | |
252 | 0 | void Wycheproof::EDDSA_Verify(const nlohmann::json& groups) { |
253 | 0 | for (const auto &group : groups) { |
254 | 0 | for (const auto &test : group["tests"]) { |
255 | 0 | nlohmann::json parameters; |
256 | |
|
257 | 0 | { |
258 | 0 | const std::string curve = group["key"]["curve"]; |
259 | |
|
260 | 0 | if ( curve == "edwards448" ) { |
261 | 0 | parameters["curveType"] = CF_ECC_CURVE("ed448"); |
262 | 0 | } else { |
263 | 0 | CF_ASSERT(0, "Curve not recognized"); |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | 0 | parameters["digestType"] = CF_DIGEST("NULL"); |
268 | |
|
269 | 0 | parameters["signature"]["pub"][0] = util::HexToDec(group["key"]["pk"]); |
270 | 0 | parameters["signature"]["pub"][1] = "0"; |
271 | |
|
272 | 0 | { |
273 | 0 | const auto sig = test["sig"].get<std::string>(); |
274 | 0 | CF_CHECK_EQ(sig.size() % 4, 0); |
275 | |
|
276 | 0 | const auto R = std::string(sig.data(), sig.data() + (sig.size() / 2)); |
277 | 0 | const auto S = std::string(sig.data() + (sig.size() / 2), sig.data() + sig.size()); |
278 | |
|
279 | 0 | parameters["signature"]["signature"][0] = util::HexToDec(R); |
280 | 0 | parameters["signature"]["signature"][1] = util::HexToDec(S); |
281 | 0 | } |
282 | | |
283 | 0 | parameters["cleartext"] = test["msg"].get<std::string>(); |
284 | |
|
285 | 0 | parameters["modifier"] = std::string(1000, '0'); |
286 | 0 | { |
287 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
288 | 0 | cryptofuzz::operation::ECDSA_Verify op(parameters); |
289 | 0 | op.Serialize(dsOut2); |
290 | |
|
291 | 0 | write(CF_OPERATION("ECDSA_Verify"), dsOut2); |
292 | 0 | } |
293 | |
|
294 | 0 | end: |
295 | 0 | (void)1; |
296 | 0 | } |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | 0 | void Wycheproof::ECDH(const nlohmann::json& groups) { |
301 | 0 | for (const auto &group : groups) { |
302 | 0 | for (const auto &test : group["tests"]) { |
303 | 0 | nlohmann::json parameters; |
304 | |
|
305 | 0 | parameters["modifier"] = ""; |
306 | |
|
307 | 0 | { |
308 | 0 | const std::string curve = group["curve"]; |
309 | 0 | auto curveID = repository::ECC_CurveFromString(curve); |
310 | |
|
311 | 0 | if ( curveID == std::nullopt ) { |
312 | 0 | if ( curve == "brainpoolP224r1" ) { |
313 | 0 | curveID = CF_ECC_CURVE("brainpool224r1"); |
314 | 0 | } else if ( curve == "brainpoolP224t1" ) { |
315 | 0 | curveID = CF_ECC_CURVE("brainpool224t1"); |
316 | 0 | } else if ( curve == "brainpoolP256r1" ) { |
317 | 0 | curveID = CF_ECC_CURVE("brainpool256r1"); |
318 | 0 | } else if ( curve == "brainpoolP256t1" ) { |
319 | 0 | curveID = CF_ECC_CURVE("brainpool256t1"); |
320 | 0 | } else if ( curve == "brainpoolP320r1" ) { |
321 | 0 | curveID = CF_ECC_CURVE("brainpool320r1"); |
322 | 0 | } else if ( curve == "brainpoolP320t1" ) { |
323 | 0 | curveID = CF_ECC_CURVE("brainpool320t1"); |
324 | 0 | } else if ( curve == "brainpoolP384r1" ) { |
325 | 0 | curveID = CF_ECC_CURVE("brainpool384r1"); |
326 | 0 | } else if ( curve == "brainpoolP384t1" ) { |
327 | 0 | curveID = CF_ECC_CURVE("brainpool384t1"); |
328 | 0 | } else if ( curve == "brainpoolP512r1" ) { |
329 | 0 | curveID = CF_ECC_CURVE("brainpool512r1"); |
330 | 0 | } else if ( curve == "brainpoolP512t1" ) { |
331 | 0 | curveID = CF_ECC_CURVE("brainpool512t1"); |
332 | 0 | } else if ( curve == "FRP256v1" ) { |
333 | 0 | curveID = CF_ECC_CURVE("frp256v1"); |
334 | 0 | } else { |
335 | 0 | CF_ASSERT(0, "Curve not recognized"); |
336 | 0 | } |
337 | 0 | } |
338 | | |
339 | 0 | parameters["curveType"] = *curveID; |
340 | |
|
341 | 0 | parameters["priv"] = util::HexToDec(test["private"]); |
342 | |
|
343 | 0 | { |
344 | 0 | const auto pub = util::PubkeyFromASN1(*curveID, test["public"].get<std::string>()); |
345 | 0 | CF_CHECK_NE(pub, std::nullopt); |
346 | |
|
347 | 0 | parameters["pub_x"] = pub->first; |
348 | 0 | parameters["pub_y"] = pub->second; |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | 0 | { |
353 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
354 | 0 | cryptofuzz::operation::ECDH_Derive op(parameters); |
355 | 0 | op.Serialize(dsOut2); |
356 | |
|
357 | 0 | write(CF_OPERATION("ECDH_Derive"), dsOut2); |
358 | 0 | } |
359 | 0 | end: |
360 | 0 | (void)1; |
361 | 0 | } |
362 | 0 | } |
363 | 0 | } |
364 | | |
365 | 0 | void Wycheproof::DSA(const nlohmann::json& groups) { |
366 | 0 | for (const auto &group : groups) { |
367 | 0 | if ( group["sha"] != "SHA-256" ) { |
368 | | /* XXX */ |
369 | 0 | return; |
370 | 0 | } |
371 | | |
372 | 0 | nlohmann::json parameters; |
373 | |
|
374 | 0 | parameters["modifier"] = ""; |
375 | |
|
376 | 0 | nlohmann::json parameters_; |
377 | 0 | parameters_["p"] = util::HexToDec(group["key"]["p"]); |
378 | 0 | parameters_["q"] = util::HexToDec(group["key"]["q"]); |
379 | 0 | parameters_["g"] = util::HexToDec(group["key"]["g"]); |
380 | 0 | parameters["parameters"] = parameters_; |
381 | |
|
382 | 0 | parameters["pub"] = util::HexToDec(group["key"]["y"]); |
383 | |
|
384 | 0 | for (const auto &test : group["tests"]) { |
385 | 0 | { |
386 | | /* Hex-decode cleartext */ |
387 | 0 | std::vector<uint8_t> ct_sha256; |
388 | 0 | boost::algorithm::unhex( |
389 | 0 | test["msg"].get<std::string>(), |
390 | 0 | std::back_inserter(ct_sha256)); |
391 | 0 | const auto ct = crypto::sha256(ct_sha256); |
392 | |
|
393 | 0 | std::string ct_hex; |
394 | 0 | boost::algorithm::hex(ct, std::back_inserter(ct_hex)); |
395 | 0 | parameters["cleartext"] = ct_hex; |
396 | 0 | } |
397 | |
|
398 | 0 | const auto sig = util::SignatureFromDER(test["sig"].get<std::string>()); |
399 | 0 | CF_CHECK_NE(sig, std::nullopt); |
400 | 0 | parameters["signature"][0] = sig->first; |
401 | 0 | parameters["signature"][1] = sig->second; |
402 | |
|
403 | 0 | { |
404 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
405 | 0 | cryptofuzz::operation::DSA_Verify op(parameters); |
406 | 0 | op.Serialize(dsOut2); |
407 | |
|
408 | 0 | write(CF_OPERATION("DSA_Verify"), dsOut2); |
409 | 0 | } |
410 | 0 | } |
411 | 0 | end: |
412 | 0 | (void)1; |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | 0 | void Wycheproof::PrimalityTest(const nlohmann::json& groups) { |
417 | 0 | for (const auto &group : groups) { |
418 | 0 | for (const auto &test : group["tests"]) { |
419 | 0 | nlohmann::json parameters; |
420 | |
|
421 | 0 | parameters["modifier"] = ""; |
422 | 0 | parameters["calcOp"] = CF_CALCOP("IsPrime(A)"); |
423 | 0 | parameters["bn1"] = util::HexToDec(test["value"]); |
424 | 0 | parameters["bn2"] = ""; |
425 | 0 | parameters["bn3"] = ""; |
426 | 0 | parameters["bn4"] = ""; |
427 | |
|
428 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
429 | 0 | cryptofuzz::operation::BignumCalc op(parameters); |
430 | 0 | op.Serialize(dsOut2); |
431 | 0 | write(CF_OPERATION("BignumCalc"), dsOut2); |
432 | 0 | } |
433 | 0 | } |
434 | 0 | } |
435 | | |
436 | | } /* namespace cryptofuzz */ |