Coverage Report

Created: 2024-06-28 06:19

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