/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 | } |
27 | 0 | } |
28 | | |
29 | 0 | void Wycheproof::write(const uint64_t operation, fuzzing::datasource::Datasource& dsOut2) { |
30 | 0 | fuzzing::datasource::Datasource dsOut(nullptr, 0); |
31 | | |
32 | | /* Operation ID */ |
33 | 0 | dsOut.Put<uint64_t>(operation); |
34 | |
|
35 | 0 | dsOut.PutData(dsOut2.GetOut()); |
36 | | |
37 | | /* Modifier */ |
38 | 0 | dsOut.PutData(std::vector<uint8_t>(0)); |
39 | | |
40 | | /* Module ID */ |
41 | 0 | dsOut.Put<uint64_t>(CF_MODULE("OpenSSL")); |
42 | | |
43 | | /* Terminator */ |
44 | 0 | dsOut.Put<bool>(false); |
45 | |
|
46 | 0 | { |
47 | | //std::string filename = outDir + std::string("/") + std::to_string(counter++); |
48 | 0 | std::string filename = outDir + std::string("/") + util::SHA1(dsOut.GetOut()); |
49 | 0 | FILE* fp = fopen(filename.c_str(), "wb"); |
50 | 0 | fwrite(dsOut.GetOut().data(), dsOut.GetOut().size(), 1, fp); |
51 | 0 | fclose(fp); |
52 | 0 | } |
53 | 0 | } |
54 | | |
55 | 0 | void Wycheproof::ECDSA_Verify(const nlohmann::json& groups) { |
56 | 0 | for (const auto &group : groups) { |
57 | 0 | for (const auto &test : group["tests"]) { |
58 | 0 | nlohmann::json |
59 | 0 | p_ecdsa_verify, |
60 | 0 | p_ecc_point_add, |
61 | 0 | p_ecc_point_mul_1, |
62 | 0 | p_ecc_point_mul_2, |
63 | 0 | p_ecc_validatepubkey_1, |
64 | 0 | p_ecc_validatepubkey_2; |
65 | 0 | std::string digest; |
66 | |
|
67 | 0 | { |
68 | 0 | const std::string curve = group["key"]["curve"]; |
69 | 0 | auto curveID = repository::ECC_CurveFromString(curve); |
70 | |
|
71 | 0 | if ( curveID == std::nullopt ) { |
72 | 0 | if ( curve == "brainpoolP224r1" ) { |
73 | 0 | curveID = CF_ECC_CURVE("brainpool224r1"); |
74 | 0 | } else if ( curve == "brainpoolP224t1" ) { |
75 | 0 | curveID = CF_ECC_CURVE("brainpool224t1"); |
76 | 0 | } else if ( curve == "brainpoolP256r1" ) { |
77 | 0 | curveID = CF_ECC_CURVE("brainpool256r1"); |
78 | 0 | } else if ( curve == "brainpoolP256t1" ) { |
79 | 0 | curveID = CF_ECC_CURVE("brainpool256t1"); |
80 | 0 | } else if ( curve == "brainpoolP320r1" ) { |
81 | 0 | curveID = CF_ECC_CURVE("brainpool320r1"); |
82 | 0 | } else if ( curve == "brainpoolP320t1" ) { |
83 | 0 | curveID = CF_ECC_CURVE("brainpool320t1"); |
84 | 0 | } else if ( curve == "brainpoolP384r1" ) { |
85 | 0 | curveID = CF_ECC_CURVE("brainpool384r1"); |
86 | 0 | } else if ( curve == "brainpoolP384t1" ) { |
87 | 0 | curveID = CF_ECC_CURVE("brainpool384t1"); |
88 | 0 | } else if ( curve == "brainpoolP512r1" ) { |
89 | 0 | curveID = CF_ECC_CURVE("brainpool512r1"); |
90 | 0 | } else if ( curve == "brainpoolP512t1" ) { |
91 | 0 | curveID = CF_ECC_CURVE("brainpool512t1"); |
92 | 0 | } else { |
93 | 0 | CF_ASSERT(0, "Curve not recognized"); |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | 0 | p_ecdsa_verify["curveType"] = *curveID; |
98 | 0 | p_ecc_point_add["curveType"] = *curveID; |
99 | 0 | p_ecc_point_mul_1["curveType"] = *curveID; |
100 | 0 | p_ecc_point_mul_2["curveType"] = *curveID; |
101 | 0 | p_ecc_validatepubkey_1["curveType"] = *curveID; |
102 | 0 | p_ecc_validatepubkey_2["curveType"] = *curveID; |
103 | 0 | } |
104 | | |
105 | 0 | { |
106 | 0 | digest = group["sha"]; |
107 | |
|
108 | 0 | if ( digest == "SHA-224") { |
109 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA224"); |
110 | 0 | } else if ( digest == "SHA-256") { |
111 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA256"); |
112 | 0 | } else if ( digest == "SHA-384") { |
113 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA384"); |
114 | 0 | } else if ( digest == "SHA-512") { |
115 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA512"); |
116 | 0 | } else if ( digest == "SHA3-224") { |
117 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-224"); |
118 | 0 | } else if ( digest == "SHA3-256") { |
119 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-256"); |
120 | 0 | } else if ( digest == "SHA3-384") { |
121 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-384"); |
122 | 0 | } else if ( digest == "SHA3-512") { |
123 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("SHA3-512"); |
124 | 0 | } else { |
125 | 0 | CF_ASSERT(0, "Digest not recognized"); |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | 0 | p_ecdsa_verify["signature"]["pub"][0] = util::HexToDec(group["key"]["wx"]); |
130 | 0 | p_ecdsa_verify["signature"]["pub"][1] = util::HexToDec(group["key"]["wy"]); |
131 | |
|
132 | 0 | p_ecc_point_add["a_x"] = util::HexToDec(group["key"]["wx"]); |
133 | 0 | p_ecc_point_add["a_y"] = util::HexToDec(group["key"]["wy"]); |
134 | |
|
135 | 0 | p_ecc_point_mul_1["a_x"] = util::HexToDec(group["key"]["wx"]); |
136 | 0 | p_ecc_point_mul_1["a_y"] = util::HexToDec(group["key"]["wy"]); |
137 | |
|
138 | 0 | p_ecc_validatepubkey_1["pub_x"] = util::HexToDec(group["key"]["wx"]); |
139 | 0 | p_ecc_validatepubkey_1["pub_y"] = util::HexToDec(group["key"]["wy"]); |
140 | |
|
141 | 0 | { |
142 | 0 | const auto sig = util::SignatureFromDER(test["sig"].get<std::string>()); |
143 | 0 | CF_CHECK_NE(sig, std::nullopt); |
144 | |
|
145 | 0 | p_ecdsa_verify["signature"]["signature"][0] = sig->first; |
146 | 0 | p_ecdsa_verify["signature"]["signature"][1] = sig->second; |
147 | |
|
148 | 0 | p_ecc_point_add["b_x"] = sig->first; |
149 | 0 | p_ecc_point_add["b_y"] = sig->second; |
150 | |
|
151 | 0 | p_ecc_point_mul_2["a_x"] = sig->first; |
152 | 0 | p_ecc_point_mul_2["a_y"] = sig->second; |
153 | |
|
154 | 0 | p_ecc_validatepubkey_2["pub_x"] = sig->first; |
155 | 0 | p_ecc_validatepubkey_2["pub_y"] = sig->second; |
156 | 0 | } |
157 | | |
158 | 0 | p_ecdsa_verify["cleartext"] = test["msg"].get<std::string>(); |
159 | | |
160 | | /* Construct and write ECDSA_Verify */ |
161 | 0 | { |
162 | 0 | p_ecdsa_verify["modifier"] = ""; |
163 | |
|
164 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
165 | 0 | cryptofuzz::operation::ECDSA_Verify op(p_ecdsa_verify); |
166 | 0 | op.Serialize(dsOut2); |
167 | |
|
168 | 0 | write(CF_OPERATION("ECDSA_Verify"), dsOut2); |
169 | 0 | } |
170 | | |
171 | | /* If digest type is SHA256, compute the SHA256 hash of the message, |
172 | | * and use this to write an input that uses the NULL digest */ |
173 | 0 | if ( digest == "SHA-256" ) { |
174 | | /* Hex-decode cleartext */ |
175 | 0 | std::vector<uint8_t> ct_sha256; |
176 | 0 | boost::algorithm::unhex( |
177 | 0 | test["msg"].get<std::string>(), |
178 | 0 | std::back_inserter(ct_sha256)); |
179 | 0 | const auto ct = crypto::sha256(ct_sha256); |
180 | |
|
181 | 0 | std::string ct_hex; |
182 | 0 | boost::algorithm::hex(ct, std::back_inserter(ct_hex)); |
183 | |
|
184 | 0 | p_ecdsa_verify["cleartext"] = ct_hex; |
185 | 0 | p_ecdsa_verify["digestType"] = CF_DIGEST("NULL"); |
186 | |
|
187 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
188 | 0 | cryptofuzz::operation::ECDSA_Verify op(p_ecdsa_verify); |
189 | 0 | op.Serialize(dsOut2); |
190 | |
|
191 | 0 | write(CF_OPERATION("ECDSA_Verify"), dsOut2); |
192 | 0 | } |
193 | |
|
194 | 0 | { |
195 | 0 | p_ecc_point_add["modifier"] = ""; |
196 | |
|
197 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
198 | 0 | cryptofuzz::operation::ECC_Point_Add op(p_ecc_point_add); |
199 | 0 | op.Serialize(dsOut2); |
200 | |
|
201 | 0 | write(CF_OPERATION("ECC_Point_Add"), dsOut2); |
202 | 0 | } |
203 | |
|
204 | 0 | { |
205 | 0 | p_ecc_point_mul_1["modifier"] = ""; |
206 | 0 | p_ecc_point_mul_1["b"] = "1"; |
207 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
208 | 0 | cryptofuzz::operation::ECC_Point_Mul op(p_ecc_point_mul_1); |
209 | 0 | op.Serialize(dsOut2); |
210 | |
|
211 | 0 | write(CF_OPERATION("ECC_Point_Mul"), dsOut2); |
212 | 0 | } |
213 | |
|
214 | 0 | { |
215 | 0 | p_ecc_point_mul_2["modifier"] = ""; |
216 | 0 | p_ecc_point_mul_2["b"] = "1"; |
217 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
218 | 0 | cryptofuzz::operation::ECC_Point_Mul op(p_ecc_point_mul_2); |
219 | 0 | op.Serialize(dsOut2); |
220 | |
|
221 | 0 | write(CF_OPERATION("ECC_Point_Mul"), dsOut2); |
222 | 0 | } |
223 | |
|
224 | 0 | { |
225 | 0 | p_ecc_validatepubkey_1["modifier"] = ""; |
226 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
227 | 0 | cryptofuzz::operation::ECC_ValidatePubkey op(p_ecc_validatepubkey_1); |
228 | 0 | op.Serialize(dsOut2); |
229 | |
|
230 | 0 | write(CF_OPERATION("ECC_ValidatePubkey"), dsOut2); |
231 | 0 | } |
232 | |
|
233 | 0 | { |
234 | 0 | p_ecc_validatepubkey_2["modifier"] = ""; |
235 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
236 | 0 | cryptofuzz::operation::ECC_ValidatePubkey op(p_ecc_validatepubkey_2); |
237 | 0 | op.Serialize(dsOut2); |
238 | |
|
239 | 0 | write(CF_OPERATION("ECC_ValidatePubkey"), dsOut2); |
240 | 0 | } |
241 | |
|
242 | 0 | end: |
243 | 0 | (void)1; |
244 | 0 | } |
245 | 0 | } |
246 | 0 | } |
247 | | |
248 | 0 | void Wycheproof::EDDSA_Verify(const nlohmann::json& groups) { |
249 | 0 | for (const auto &group : groups) { |
250 | 0 | for (const auto &test : group["tests"]) { |
251 | 0 | nlohmann::json parameters; |
252 | |
|
253 | 0 | { |
254 | 0 | const std::string curve = group["key"]["curve"]; |
255 | |
|
256 | 0 | if ( curve == "edwards448" ) { |
257 | 0 | parameters["curveType"] = CF_ECC_CURVE("ed448"); |
258 | 0 | } else { |
259 | 0 | CF_ASSERT(0, "Curve not recognized"); |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | 0 | parameters["digestType"] = CF_DIGEST("NULL"); |
264 | |
|
265 | 0 | parameters["signature"]["pub"][0] = util::HexToDec(group["key"]["pk"]); |
266 | 0 | parameters["signature"]["pub"][1] = "0"; |
267 | |
|
268 | 0 | { |
269 | 0 | const auto sig = test["sig"].get<std::string>(); |
270 | 0 | CF_CHECK_EQ(sig.size() % 4, 0); |
271 | |
|
272 | 0 | const auto R = std::string(sig.data(), sig.data() + (sig.size() / 2)); |
273 | 0 | const auto S = std::string(sig.data() + (sig.size() / 2), sig.data() + sig.size()); |
274 | |
|
275 | 0 | parameters["signature"]["signature"][0] = util::HexToDec(R); |
276 | 0 | parameters["signature"]["signature"][1] = util::HexToDec(S); |
277 | 0 | } |
278 | | |
279 | 0 | parameters["cleartext"] = test["msg"].get<std::string>(); |
280 | |
|
281 | 0 | parameters["modifier"] = std::string(1000, '0'); |
282 | 0 | { |
283 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
284 | 0 | cryptofuzz::operation::ECDSA_Verify op(parameters); |
285 | 0 | op.Serialize(dsOut2); |
286 | |
|
287 | 0 | write(CF_OPERATION("ECDSA_Verify"), dsOut2); |
288 | 0 | } |
289 | |
|
290 | 0 | end: |
291 | 0 | (void)1; |
292 | 0 | } |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | 0 | void Wycheproof::ECDH(const nlohmann::json& groups) { |
297 | 0 | for (const auto &group : groups) { |
298 | 0 | for (const auto &test : group["tests"]) { |
299 | 0 | nlohmann::json parameters; |
300 | |
|
301 | 0 | parameters["modifier"] = ""; |
302 | |
|
303 | 0 | { |
304 | 0 | const std::string curve = group["curve"]; |
305 | 0 | auto curveID = repository::ECC_CurveFromString(curve); |
306 | |
|
307 | 0 | if ( curveID == std::nullopt ) { |
308 | 0 | if ( curve == "brainpoolP224r1" ) { |
309 | 0 | curveID = CF_ECC_CURVE("brainpool224r1"); |
310 | 0 | } else if ( curve == "brainpoolP224t1" ) { |
311 | 0 | curveID = CF_ECC_CURVE("brainpool224t1"); |
312 | 0 | } else if ( curve == "brainpoolP256r1" ) { |
313 | 0 | curveID = CF_ECC_CURVE("brainpool256r1"); |
314 | 0 | } else if ( curve == "brainpoolP256t1" ) { |
315 | 0 | curveID = CF_ECC_CURVE("brainpool256t1"); |
316 | 0 | } else if ( curve == "brainpoolP320r1" ) { |
317 | 0 | curveID = CF_ECC_CURVE("brainpool320r1"); |
318 | 0 | } else if ( curve == "brainpoolP320t1" ) { |
319 | 0 | curveID = CF_ECC_CURVE("brainpool320t1"); |
320 | 0 | } else if ( curve == "brainpoolP384r1" ) { |
321 | 0 | curveID = CF_ECC_CURVE("brainpool384r1"); |
322 | 0 | } else if ( curve == "brainpoolP384t1" ) { |
323 | 0 | curveID = CF_ECC_CURVE("brainpool384t1"); |
324 | 0 | } else if ( curve == "brainpoolP512r1" ) { |
325 | 0 | curveID = CF_ECC_CURVE("brainpool512r1"); |
326 | 0 | } else if ( curve == "brainpoolP512t1" ) { |
327 | 0 | curveID = CF_ECC_CURVE("brainpool512t1"); |
328 | 0 | } else { |
329 | 0 | CF_ASSERT(0, "Curve not recognized"); |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | 0 | parameters["curveType"] = *curveID; |
334 | |
|
335 | 0 | parameters["priv"] = util::HexToDec(test["private"]); |
336 | |
|
337 | 0 | { |
338 | 0 | const auto pub = util::PubkeyFromASN1(*curveID, test["public"].get<std::string>()); |
339 | 0 | CF_CHECK_NE(pub, std::nullopt); |
340 | |
|
341 | 0 | parameters["pub_x"] = pub->first; |
342 | 0 | parameters["pub_y"] = pub->second; |
343 | 0 | } |
344 | 0 | } |
345 | | |
346 | 0 | { |
347 | 0 | fuzzing::datasource::Datasource dsOut2(nullptr, 0); |
348 | 0 | cryptofuzz::operation::ECDH_Derive op(parameters); |
349 | 0 | op.Serialize(dsOut2); |
350 | |
|
351 | 0 | write(CF_OPERATION("ECDH_Derive"), dsOut2); |
352 | 0 | } |
353 | 0 | end: |
354 | 0 | (void)1; |
355 | 0 | } |
356 | 0 | } |
357 | 0 | } |
358 | | |
359 | | } /* namespace cryptofuzz */ |