Coverage Report

Created: 2024-09-11 06:39

/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 */