Coverage Report

Created: 2022-08-24 06:31

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