Coverage Report

Created: 2024-11-21 06:38

/src/cryptofuzz/modules/bearssl/module.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "module.h"
2
#include <cryptofuzz/util.h>
3
#include <boost/multiprecision/cpp_int.hpp>
4
#include <cryptofuzz/repository.h>
5
#include <sstream>
6
#include <algorithm>
7
8
extern "C" {
9
    #include <bearssl.h>
10
}
11
12
namespace cryptofuzz {
13
namespace module {
14
15
namespace BearSSL_detail {
16
    static br_hmac_drbg_context rng;
17
18
    template <class Context, size_t Size>
19
    std::optional<component::Digest> digest(
20
            void(*init)(Context*),
21
            void(*update)(Context*, const void*, size_t),
22
            void(*finish)(const Context*, void*),
23
            const component::Cleartext& in,
24
            Datasource& ds
25
        )
26
817
    {
27
817
        std::optional<component::Digest> ret = std::nullopt;
28
29
817
        Context ctx;
30
817
        uint8_t* out = util::malloc(Size);
31
32
817
        init(&ctx);
33
34
817
        const auto parts = util::ToParts(ds, in);
35
101k
        for (const auto& part : parts) {
36
101k
            update(&ctx, part.first, part.second);
37
101k
        }
38
39
817
        finish(&ctx, out);
40
41
817
        ret = component::Digest(out, Size);
42
43
817
        util::free(out);
44
45
817
        return ret;
46
817
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_md5_context, 16ul>(void (*)(br_md5_context*), void (*)(br_md5_context*, void const*, unsigned long), void (*)(br_md5_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&)
Line
Count
Source
26
179
    {
27
179
        std::optional<component::Digest> ret = std::nullopt;
28
29
179
        Context ctx;
30
179
        uint8_t* out = util::malloc(Size);
31
32
179
        init(&ctx);
33
34
179
        const auto parts = util::ToParts(ds, in);
35
18.7k
        for (const auto& part : parts) {
36
18.7k
            update(&ctx, part.first, part.second);
37
18.7k
        }
38
39
179
        finish(&ctx, out);
40
41
179
        ret = component::Digest(out, Size);
42
43
179
        util::free(out);
44
45
179
        return ret;
46
179
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_md5sha1_context, 36ul>(void (*)(br_md5sha1_context*), void (*)(br_md5sha1_context*, void const*, unsigned long), void (*)(br_md5sha1_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&)
Line
Count
Source
26
82
    {
27
82
        std::optional<component::Digest> ret = std::nullopt;
28
29
82
        Context ctx;
30
82
        uint8_t* out = util::malloc(Size);
31
32
82
        init(&ctx);
33
34
82
        const auto parts = util::ToParts(ds, in);
35
1.80k
        for (const auto& part : parts) {
36
1.80k
            update(&ctx, part.first, part.second);
37
1.80k
        }
38
39
82
        finish(&ctx, out);
40
41
82
        ret = component::Digest(out, Size);
42
43
82
        util::free(out);
44
45
82
        return ret;
46
82
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha1_context, 20ul>(void (*)(br_sha1_context*), void (*)(br_sha1_context*, void const*, unsigned long), void (*)(br_sha1_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&)
Line
Count
Source
26
142
    {
27
142
        std::optional<component::Digest> ret = std::nullopt;
28
29
142
        Context ctx;
30
142
        uint8_t* out = util::malloc(Size);
31
32
142
        init(&ctx);
33
34
142
        const auto parts = util::ToParts(ds, in);
35
10.0k
        for (const auto& part : parts) {
36
10.0k
            update(&ctx, part.first, part.second);
37
10.0k
        }
38
39
142
        finish(&ctx, out);
40
41
142
        ret = component::Digest(out, Size);
42
43
142
        util::free(out);
44
45
142
        return ret;
46
142
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha224_context, 28ul>(void (*)(br_sha224_context*), void (*)(br_sha224_context*, void const*, unsigned long), void (*)(br_sha224_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&)
Line
Count
Source
26
107
    {
27
107
        std::optional<component::Digest> ret = std::nullopt;
28
29
107
        Context ctx;
30
107
        uint8_t* out = util::malloc(Size);
31
32
107
        init(&ctx);
33
34
107
        const auto parts = util::ToParts(ds, in);
35
17.0k
        for (const auto& part : parts) {
36
17.0k
            update(&ctx, part.first, part.second);
37
17.0k
        }
38
39
107
        finish(&ctx, out);
40
41
107
        ret = component::Digest(out, Size);
42
43
107
        util::free(out);
44
45
107
        return ret;
46
107
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha224_context, 32ul>(void (*)(br_sha224_context*), void (*)(br_sha224_context*, void const*, unsigned long), void (*)(br_sha224_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&)
Line
Count
Source
26
116
    {
27
116
        std::optional<component::Digest> ret = std::nullopt;
28
29
116
        Context ctx;
30
116
        uint8_t* out = util::malloc(Size);
31
32
116
        init(&ctx);
33
34
116
        const auto parts = util::ToParts(ds, in);
35
14.2k
        for (const auto& part : parts) {
36
14.2k
            update(&ctx, part.first, part.second);
37
14.2k
        }
38
39
116
        finish(&ctx, out);
40
41
116
        ret = component::Digest(out, Size);
42
43
116
        util::free(out);
44
45
116
        return ret;
46
116
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha384_context, 48ul>(void (*)(br_sha384_context*), void (*)(br_sha384_context*, void const*, unsigned long), void (*)(br_sha384_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&)
Line
Count
Source
26
93
    {
27
93
        std::optional<component::Digest> ret = std::nullopt;
28
29
93
        Context ctx;
30
93
        uint8_t* out = util::malloc(Size);
31
32
93
        init(&ctx);
33
34
93
        const auto parts = util::ToParts(ds, in);
35
9.45k
        for (const auto& part : parts) {
36
9.45k
            update(&ctx, part.first, part.second);
37
9.45k
        }
38
39
93
        finish(&ctx, out);
40
41
93
        ret = component::Digest(out, Size);
42
43
93
        util::free(out);
44
45
93
        return ret;
46
93
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha384_context, 64ul>(void (*)(br_sha384_context*), void (*)(br_sha384_context*, void const*, unsigned long), void (*)(br_sha384_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&)
Line
Count
Source
26
98
    {
27
98
        std::optional<component::Digest> ret = std::nullopt;
28
29
98
        Context ctx;
30
98
        uint8_t* out = util::malloc(Size);
31
32
98
        init(&ctx);
33
34
98
        const auto parts = util::ToParts(ds, in);
35
30.3k
        for (const auto& part : parts) {
36
30.3k
            update(&ctx, part.first, part.second);
37
30.3k
        }
38
39
98
        finish(&ctx, out);
40
41
98
        ret = component::Digest(out, Size);
42
43
98
        util::free(out);
44
45
98
        return ret;
46
98
    }
47
48
3.11k
    const br_hash_class* To_br_hash_class(const component::DigestType& digestType) {
49
3.11k
        switch ( digestType.Get() ) {
50
514
            case    CF_DIGEST("MD5"):
51
514
                return &br_md5_vtable;
52
569
            case    CF_DIGEST("SHA1"):
53
569
                return &br_sha1_vtable;
54
239
            case    CF_DIGEST("MD5_SHA1"):
55
239
                return &br_md5sha1_vtable;
56
327
            case    CF_DIGEST("SHA224"):
57
327
                return &br_sha224_vtable;
58
708
            case    CF_DIGEST("SHA256"):
59
708
                return &br_sha256_vtable;
60
293
            case    CF_DIGEST("SHA384"):
61
293
                return &br_sha384_vtable;
62
372
            case    CF_DIGEST("SHA512"):
63
372
                return &br_sha512_vtable;
64
94
            default:
65
94
                return nullptr;
66
3.11k
        }
67
3.11k
    }
68
69
5.98k
    static bool EncodeBignum(const std::string s, uint8_t* out, const size_t maxSize, const bool reverse = false) {
70
5.98k
        std::vector<uint8_t> v;
71
5.98k
        boost::multiprecision::cpp_int c(s);
72
5.98k
        boost::multiprecision::export_bits(c, std::back_inserter(v), 8);
73
5.98k
        if ( v.size() > maxSize ) {
74
103
            return false;
75
103
        }
76
5.87k
        const auto diff = maxSize - v.size();
77
78
5.87k
        memset(out, 0, maxSize);
79
5.87k
        memcpy(out + diff, v.data(), v.size());
80
81
5.87k
        if ( reverse == true ) {
82
371
            std::reverse(out, out + maxSize);
83
371
        }
84
85
5.87k
        return true;
86
5.98k
    }
87
88
4.22k
    static std::string toString(const uint8_t* data, const size_t size) {
89
4.22k
        boost::multiprecision::cpp_int i;
90
4.22k
        boost::multiprecision::import_bits(i, data, data + size);
91
92
4.22k
        std::stringstream ss;
93
4.22k
        ss << i;
94
95
4.22k
        if ( ss.str().empty() ) {
96
0
            return "0";
97
4.22k
        } else {
98
4.22k
            return ss.str();
99
4.22k
        }
100
4.22k
    }
101
102
6.50k
    int toCurveID(const component::CurveType& curveType) {
103
6.50k
        static const std::map<uint64_t, int> LUT = {
104
6.50k
            { CF_ECC_CURVE("brainpool256r1"), BR_EC_brainpoolP256r1},
105
6.50k
            { CF_ECC_CURVE("brainpool384r1"), BR_EC_brainpoolP384r1},
106
6.50k
            { CF_ECC_CURVE("brainpool512r1"), BR_EC_brainpoolP512r1},
107
6.50k
            { CF_ECC_CURVE("x25519"), BR_EC_curve25519},
108
#if 0
109
            { CF_ECC_CURVE("x448"), BR_EC_curve448},
110
#endif
111
6.50k
            { CF_ECC_CURVE("secp160k1"), BR_EC_secp160k1},
112
6.50k
            { CF_ECC_CURVE("secp160r1"), BR_EC_secp160r1},
113
6.50k
            { CF_ECC_CURVE("secp160r2"), BR_EC_secp160r2},
114
6.50k
            { CF_ECC_CURVE("secp192k1"), BR_EC_secp192k1},
115
6.50k
            { CF_ECC_CURVE("secp192r1"), BR_EC_secp192r1},
116
6.50k
            { CF_ECC_CURVE("secp224k1"), BR_EC_secp224k1},
117
6.50k
            { CF_ECC_CURVE("secp224r1"), BR_EC_secp224r1},
118
6.50k
            { CF_ECC_CURVE("secp256k1"), BR_EC_secp256k1},
119
6.50k
            { CF_ECC_CURVE("secp256r1"), BR_EC_secp256r1},
120
6.50k
            { CF_ECC_CURVE("secp384r1"), BR_EC_secp384r1},
121
6.50k
            { CF_ECC_CURVE("secp521r1"), BR_EC_secp521r1},
122
6.50k
            { CF_ECC_CURVE("sect163k1"), BR_EC_sect163k1},
123
6.50k
            { CF_ECC_CURVE("sect163r1"), BR_EC_sect163r1},
124
6.50k
            { CF_ECC_CURVE("sect163r2"), BR_EC_sect163r2},
125
6.50k
            { CF_ECC_CURVE("sect193r1"), BR_EC_sect193r1},
126
6.50k
            { CF_ECC_CURVE("sect193r2"), BR_EC_sect193r2},
127
6.50k
            { CF_ECC_CURVE("sect233k1"), BR_EC_sect233k1},
128
6.50k
            { CF_ECC_CURVE("sect233r1"), BR_EC_sect233r1},
129
6.50k
            { CF_ECC_CURVE("sect239k1"), BR_EC_sect239k1},
130
6.50k
            { CF_ECC_CURVE("sect283k1"), BR_EC_sect283k1},
131
6.50k
            { CF_ECC_CURVE("sect283r1"), BR_EC_sect283r1},
132
6.50k
            { CF_ECC_CURVE("sect409k1"), BR_EC_sect409k1},
133
6.50k
            { CF_ECC_CURVE("sect409r1"), BR_EC_sect409r1},
134
6.50k
            { CF_ECC_CURVE("sect571k1"), BR_EC_sect571k1},
135
6.50k
            { CF_ECC_CURVE("sect571r1"), BR_EC_sect571r1},
136
6.50k
        };
137
138
6.50k
        if ( LUT.find(curveType.Get()) == LUT.end() ) {
139
2.76k
            return -1;
140
2.76k
        }
141
142
3.73k
        return LUT.at(curveType.Get());
143
6.50k
    }
144
145
1.64k
    component::BignumPair EncodePubkey(const component::CurveType& curveType, const uint8_t* data, const size_t size) {
146
1.64k
        switch ( curveType.Get() ) {
147
533
            case    CF_ECC_CURVE("x25519"):
148
533
                {
149
533
                    CF_ASSERT(size == 32, "x25519 pubkey is not 32 bytes");
150
533
                    return {
151
533
                        BearSSL_detail::toString(data, 32),
152
533
                        "0" };
153
533
                }
154
0
                break;
155
1.10k
            default:
156
1.10k
                {
157
1.10k
                    if ( (size % 2) != 1 || data[0] != 0x04 ) {
158
0
                        abort();
159
0
                    }
160
1.10k
                    size_t halfSize = (size - 1) / 2;
161
162
1.10k
                    return {
163
1.10k
                        BearSSL_detail::toString(data + 1, halfSize),
164
1.10k
                        BearSSL_detail::toString(data + 1 + halfSize, halfSize) };
165
1.10k
                }
166
1.64k
        }
167
1.64k
    }
168
  
169
4.69k
    const br_block_ctrcbc_class* Get_br_block_ctrcbc_class(Datasource& ds) {
170
4.69k
        try {
171
4.69k
            switch ( ds.Get<uint8_t>() ) {
172
103
                case    0:
173
103
                    return &br_aes_big_ctrcbc_vtable;
174
922
                case    1:
175
922
                    return &br_aes_small_ctrcbc_vtable;
176
288
                case    2:
177
288
                    return &br_aes_ct_ctrcbc_vtable;
178
623
                case    3:
179
623
                    return &br_aes_ct64_ctrcbc_vtable;
180
516
                case    4:
181
516
                    {
182
516
                        const auto ret = br_aes_x86ni_ctrcbc_get_vtable();
183
516
                        if ( ret == nullptr ) {
184
0
                            goto end;
185
0
                        }
186
516
                        return ret;
187
516
                    }
188
0
                    break;
189
180
                default:
190
180
                        goto end;
191
4.69k
            }
192
4.69k
        } catch ( ... ) { }
193
194
2.24k
end:
195
2.24k
        return &br_aes_big_ctrcbc_vtable;
196
4.69k
    }
197
198
6.57k
    const br_ec_impl* Get_br_ec_impl(Datasource& ds, const component::CurveType& curveType) {
199
6.57k
        try {
200
6.57k
            switch ( ds.Get<uint8_t>() ) {
201
1.14k
                case    0:
202
1.14k
                    switch ( curveType.Get() ) {
203
73
                        case    CF_ECC_CURVE("secp256r1"):
204
208
                        case    CF_ECC_CURVE("secp384r1"):
205
314
                        case    CF_ECC_CURVE("secp521r1"):
206
314
                            return &br_ec_prime_i15;
207
833
                        default:
208
833
                            goto end;
209
1.14k
                    }
210
943
                case    1:
211
943
                    switch ( curveType.Get() ) {
212
117
                        case    CF_ECC_CURVE("secp256r1"):
213
236
                        case    CF_ECC_CURVE("secp384r1"):
214
386
                        case    CF_ECC_CURVE("secp521r1"):
215
386
                            return &br_ec_prime_i31;
216
557
                        default:
217
557
                            goto end;
218
943
                    }
219
272
                case    2:
220
272
                    CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1"));
221
143
                    return &br_ec_p256_m15;
222
359
                case    3:
223
359
                    CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1"));
224
211
                    return &br_ec_p256_m31;
225
206
                case    4:
226
206
                    {
227
206
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1"));
228
71
                        const auto ret = br_ec_p256_m62_get();
229
71
                        CF_CHECK_NE(ret, nullptr);
230
71
                        return ret;
231
71
                    }
232
0
                    break;
233
128
                case    5:
234
128
                    {
235
128
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1"));
236
16
                        const auto ret = br_ec_p256_m64_get();
237
16
                        CF_CHECK_NE(ret, nullptr);
238
16
                        return ret;
239
16
                    }
240
0
                    break;
241
126
                case    6:
242
126
                    {
243
126
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519"));
244
18
                        const auto ret = br_ec_c25519_m62_get();
245
18
                        CF_CHECK_NE(ret, nullptr);
246
18
                        return ret;
247
18
                    }
248
0
                    break;
249
111
                case    7:
250
111
                    {
251
111
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519"));
252
11
                        const auto ret = br_ec_c25519_m64_get();
253
11
                        CF_CHECK_NE(ret, nullptr);
254
11
                        return ret;
255
11
                    }
256
0
                    break;
257
127
                case    8:
258
127
                    {
259
127
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519"));
260
21
                        return &br_ec_c25519_i15;
261
127
                    }
262
0
                    break;
263
131
                case    9:
264
131
                    {
265
131
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519"));
266
15
                        return &br_ec_c25519_i31;
267
131
                    }
268
0
                    break;
269
143
                case    10:
270
143
                    {
271
143
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519"));
272
16
                        return &br_ec_c25519_m15;
273
143
                    }
274
0
                    break;
275
143
                case    11:
276
143
                    {
277
143
                        CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519"));
278
16
                        return &br_ec_c25519_m31;
279
143
                    }
280
0
                    break;
281
1.48k
                default:
282
1.48k
                        goto end;
283
6.57k
            }
284
6.57k
        } catch ( ... ) { }
285
286
5.33k
end:
287
5.33k
        return br_ec_get_default();
288
6.57k
    }
289
290
1.32k
    br_chacha20_run Get_br_chacha20_run(Datasource& ds) {
291
1.32k
        try {
292
1.32k
            switch ( ds.Get<uint8_t>() ) {
293
109
                case    0:
294
109
                    return &br_chacha20_ct_run;
295
467
                case    1:
296
467
                    {
297
467
                        const auto ret = br_chacha20_sse2_get();
298
467
                        if ( ret == nullptr ) {
299
0
                            goto end;
300
0
                        }
301
467
                        return ret;
302
467
                    }
303
0
                    break;
304
126
                default:
305
126
                        goto end;
306
1.32k
            }
307
1.32k
        } catch ( ... ) { }
308
309
749
end:
310
749
        return &br_chacha20_ct_run;
311
1.32k
    }
312
313
629
    br_ecdsa_sign Get_br_ecdsa_sign(Datasource& ds) {
314
629
        try {
315
629
            switch ( ds.Get<uint8_t>() ) {
316
17
                case    0:
317
17
                    return &br_ecdsa_i31_sign_raw;
318
189
                case    1:
319
189
                    return &br_ecdsa_i15_sign_raw;
320
187
                default:
321
187
                        goto end;
322
629
            }
323
629
        } catch ( ... ) { }
324
325
423
end:
326
423
        return &br_ecdsa_i31_sign_raw;
327
629
    }
328
329
1.20k
    br_ecdsa_vrfy Get_br_ecdsa_vrfy(Datasource& ds) {
330
1.20k
        try {
331
1.20k
            switch ( ds.Get<uint8_t>() ) {
332
20
                case    0:
333
20
                    return &br_ecdsa_i31_vrfy_raw;
334
244
                case    1:
335
244
                    return &br_ecdsa_i15_vrfy_raw;
336
235
                default:
337
235
                        goto end;
338
1.20k
            }
339
1.20k
        } catch ( ... ) { }
340
341
936
end:
342
936
        return &br_ecdsa_i31_vrfy_raw;
343
1.20k
    }
344
345
1.52k
    bool IsValidPrivateKey(const component::Bignum& priv, const component::CurveType& curveType) {
346
1.52k
        if ( curveType.Is(CF_ECC_CURVE("x25519")) ) {
347
418
            return true;
348
418
        }
349
350
1.10k
        const auto s = priv.ToTrimmedString();
351
1.10k
        if ( s == "0" ) {
352
27
            return false;
353
27
        }
354
355
1.07k
        const auto order = repository::ECC_CurveToOrder(curveType.Get());
356
1.07k
        if ( order == std::nullopt ) {
357
0
            return false;
358
0
        }
359
360
1.07k
        boost::multiprecision::cpp_int priv_cpp_int(s);
361
1.07k
        boost::multiprecision::cpp_int order_cpp_int(*order);
362
363
1.07k
        return priv_cpp_int < order_cpp_int;
364
1.07k
    }
365
}
366
367
BearSSL::BearSSL(void) :
368
2
    Module("BearSSL") {
369
2
        /* noret */ br_hmac_drbg_init(&BearSSL_detail::rng, &br_sha256_vtable, NULL, 0);
370
2
        br_prng_seeder seeder = br_prng_seeder_system(NULL);
371
2
        if ( seeder == 0 ) {
372
0
            printf("Cannot initialize PRNG seeder\n");
373
0
            abort();
374
0
        }
375
2
        if ( seeder(&BearSSL_detail::rng.vtable) == 0 ) {
376
0
            printf("Cannot seed PRNG\n");
377
0
            abort();
378
0
        }
379
2
}
380
381
382
1.14k
std::optional<component::Digest> BearSSL::OpDigest(operation::Digest& op) {
383
1.14k
    std::optional<component::Digest> ret = std::nullopt;
384
1.14k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
385
386
1.14k
    switch ( op.digestType.Get() ) {
387
179
        case    CF_DIGEST("MD5"):
388
179
            return BearSSL_detail::digest<br_md5_context, br_md5_SIZE>(br_md5_init, br_md5_update, br_md5_out, op.cleartext, ds);
389
82
        case    CF_DIGEST("MD5_SHA1"):
390
82
            return BearSSL_detail::digest<br_md5sha1_context, br_md5sha1_SIZE>(br_md5sha1_init, br_md5sha1_update, br_md5sha1_out, op.cleartext, ds);
391
142
        case    CF_DIGEST("SHA1"):
392
142
            return BearSSL_detail::digest<br_sha1_context, br_sha1_SIZE>(br_sha1_init, br_sha1_update, br_sha1_out, op.cleartext, ds);
393
107
        case    CF_DIGEST("SHA224"):
394
107
            return BearSSL_detail::digest<br_sha224_context, br_sha224_SIZE>(br_sha224_init, br_sha224_update, br_sha224_out, op.cleartext, ds);
395
116
        case    CF_DIGEST("SHA256"):
396
116
            return BearSSL_detail::digest<br_sha256_context, br_sha256_SIZE>(br_sha256_init, br_sha256_update, br_sha256_out, op.cleartext, ds);
397
93
        case    CF_DIGEST("SHA384"):
398
93
            return BearSSL_detail::digest<br_sha384_context, br_sha384_SIZE>(br_sha384_init, br_sha384_update, br_sha384_out, op.cleartext, ds);
399
98
        case    CF_DIGEST("SHA512"):
400
98
            return BearSSL_detail::digest<br_sha512_context, br_sha512_SIZE>(br_sha512_init, br_sha512_update, br_sha512_out, op.cleartext, ds);
401
153
        case    CF_DIGEST("SHAKE128"):
402
153
            {
403
153
                uint8_t out[16];
404
153
                br_shake_context ctx;
405
153
                const auto parts = util::ToParts(ds, op.cleartext);
406
407
                /* noret */ br_shake_init(&ctx, 128);
408
3.01k
                for (const auto& part : parts) {
409
3.01k
                    /* noret */ br_shake_inject(&ctx, part.first, part.second);
410
3.01k
                }
411
153
                /* noret */ br_shake_flip(&ctx);
412
153
                /* noret */ br_shake_produce(&ctx, out, 16);
413
414
153
                ret = component::Digest(out, sizeof(out));
415
153
            }
416
153
            break;
417
173
        case    CF_DIGEST("SHAKE256"):
418
173
            {
419
173
                uint8_t out[32];
420
173
                br_shake_context ctx;
421
173
                const auto parts = util::ToParts(ds, op.cleartext);
422
423
                /* noret */ br_shake_init(&ctx, 256);
424
7.50k
                for (const auto& part : parts) {
425
7.50k
                    /* noret */ br_shake_inject(&ctx, part.first, part.second);
426
7.50k
                }
427
173
                /* noret */ br_shake_flip(&ctx);
428
173
                /* noret */ br_shake_produce(&ctx, out, 32);
429
430
173
                ret = component::Digest(out, sizeof(out));
431
173
            }
432
173
            break;
433
1.14k
    }
434
435
326
    return ret;
436
1.14k
}
437
438
560
std::optional<component::MAC> BearSSL::OpHMAC(operation::HMAC& op) {
439
560
    std::optional<component::MAC> ret = std::nullopt;
440
560
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
441
442
560
    br_hmac_context ctx;
443
560
    br_hmac_key_context kctx;
444
560
    uint8_t out[64];
445
560
    const auto parts = util::ToParts(ds, op.cleartext);
446
560
    const br_hash_class* hash_class;
447
448
    /* Initialize */
449
560
    {
450
560
        CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr);
451
452
        /* noret */ br_hmac_key_init(&kctx, hash_class, op.cipher.key.GetPtr(), op.cipher.key.GetSize());
453
512
        /* noret */ br_hmac_init(&ctx, &kctx, 0);
454
512
    }
455
456
    /* Process */
457
46.3k
    for (const auto& part : parts) {
458
46.3k
        br_hmac_update(&ctx, part.first, part.second);
459
46.3k
    }
460
461
512
    {
462
512
        const auto size = br_hmac_out(&ctx, out);
463
464
512
        ret = component::MAC(out, size);
465
512
    }
466
467
560
end:
468
560
    return ret;
469
512
}
470
471
4.14k
std::optional<component::Ciphertext> BearSSL::OpSymmetricEncrypt(operation::SymmetricEncrypt& op) {
472
4.14k
    std::optional<component::Ciphertext> ret = std::nullopt;
473
4.14k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
474
4.14k
    uint8_t* tag = nullptr;
475
476
4.14k
    switch ( op.cipher.cipherType.Get() ) {
477
767
        case    CF_CIPHER("AES_128_GCM"):
478
1.01k
        case    CF_CIPHER("AES_192_GCM"):
479
1.28k
        case    CF_CIPHER("AES_256_GCM"):
480
1.28k
            {
481
1.28k
                br_aes_ct_ctr_keys bc;
482
1.28k
                br_gcm_context gc;
483
1.28k
                tag = util::malloc(16);
484
1.28k
                auto in = op.cleartext.Get();
485
1.28k
                auto parts = util::ToParts(ds, in);
486
487
1.28k
                switch ( op.cipher.cipherType.Get() ) {
488
767
                    case    CF_CIPHER("AES_128_GCM"):
489
767
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 16);
490
703
                        break;
491
245
                    case    CF_CIPHER("AES_192_GCM"):
492
245
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 24);
493
187
                        break;
494
268
                    case    CF_CIPHER("AES_256_GCM"):
495
268
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
496
163
                        break;
497
1.28k
                }
498
499
1.05k
                if ( op.tagSize != std::nullopt ) {
500
356
                    CF_CHECK_EQ(*op.tagSize, 16);
501
220
                }
502
503
917
                CF_CHECK_GT(op.cipher.iv.GetSize(), 0);
504
505
                /* noret */ br_aes_ct_ctr_init(&bc, op.cipher.key.GetPtr(), op.cipher.key.GetSize());
506
850
                /* noret */ br_gcm_init(&gc, &bc.vtable, br_ghash_ctmul32);
507
508
                /* noret */ br_gcm_reset(&gc, op.cipher.iv.GetPtr(), op.cipher.iv.GetSize());
509
850
                if ( op.aad != std::nullopt ) {
510
210
                    const auto aadParts = util::ToParts(ds, *op.aad);
511
                    /* "Additional data may be provided in several chunks of arbitrary length" */
512
969
                    for (auto& part : aadParts) {
513
969
                        /* noret */ br_gcm_aad_inject(&gc, part.first, part.second);
514
969
                    }
515
210
                }
516
850
                /* noret */ br_gcm_flip(&gc);
517
518
20.7k
                for (auto& part : parts) {
519
                    /* "Data may be provided in several chunks of arbitrary length" */
520
20.7k
                    /* noret */ br_gcm_run(&gc, 1, (void*)part.first, part.second);
521
20.7k
                }
522
523
850
                if ( op.tagSize != std::nullopt ) {
524
219
                    /* noret */ br_gcm_get_tag(&gc, tag);
525
219
                    ret = component::Ciphertext(Buffer(in), Buffer(tag, 16));
526
631
                } else {
527
631
                    ret = component::Ciphertext(Buffer(in));
528
631
                }
529
850
            }
530
0
            break;
531
957
        case    CF_CIPHER("AES_128_CCM"):
532
1.47k
        case    CF_CIPHER("AES_192_CCM"):
533
1.84k
        case    CF_CIPHER("AES_256_CCM"):
534
1.84k
            {
535
1.84k
                br_aes_gen_ctrcbc_keys bc;
536
1.84k
                br_ccm_context ec;
537
1.84k
                auto in = op.cleartext.Get();
538
1.84k
                auto parts = util::ToParts(ds, in);
539
1.84k
                const auto vt = BearSSL_detail::Get_br_block_ctrcbc_class(ds);
540
1.84k
                CF_CHECK_NE(vt, nullptr);
541
542
1.84k
                switch ( op.cipher.cipherType.Get() ) {
543
957
                    case    CF_CIPHER("AES_128_CCM"):
544
957
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 16);
545
812
                        break;
546
516
                    case    CF_CIPHER("AES_192_CCM"):
547
516
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 24);
548
475
                        break;
549
376
                    case    CF_CIPHER("AES_256_CCM"):
550
376
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
551
339
                        break;
552
1.84k
                }
553
554
1.62k
                if ( op.tagSize != std::nullopt ) {
555
1.35k
                    tag = util::malloc(*op.tagSize);
556
1.35k
                }
557
558
1.62k
                CF_CHECK_GT(op.cipher.iv.GetSize(), 0);
559
560
                /* noret */ vt->init(&bc.vtable, op.cipher.key.GetPtr(), op.cipher.key.GetSize());
561
1.56k
                /* noret */ br_ccm_init(&ec, &bc.vtable);
562
563
1.56k
                CF_CHECK_NE(br_ccm_reset(&ec,
564
1.56k
                            op.cipher.iv.GetPtr(), op.cipher.iv.GetSize(),
565
1.56k
                            op.aad == std::nullopt ? 0 : op.aad->GetSize(),
566
1.56k
                            op.cleartext.GetSize(),
567
1.56k
                            op.tagSize == std::nullopt ? 0 : *op.tagSize), 0);
568
569
1.22k
                if ( op.aad != std::nullopt ) {
570
773
                    const auto aadParts = util::ToParts(ds, *op.aad);
571
                    /* "Additional data may be provided in several chunks of arbitrary length" */
572
3.87k
                    for (auto& part : aadParts) {
573
3.87k
                        /* noret */ br_ccm_aad_inject(&ec, part.first, part.second);
574
3.87k
                    }
575
773
                }
576
1.22k
                /* noret */ br_ccm_flip(&ec);
577
578
22.3k
                for (auto& part : parts) {
579
                    /* "Data may be provided in several chunks of arbitrary length" */
580
22.3k
                    /* noret */ br_ccm_run(&ec, 1, (void*)part.first, part.second);
581
22.3k
                }
582
583
1.22k
                if ( op.tagSize != std::nullopt ) {
584
1.22k
                    /* noret */ br_ccm_get_tag(&ec, tag);
585
1.22k
                    ret = component::Ciphertext(Buffer(in), Buffer(tag, *op.tagSize));
586
1.22k
                } else {
587
0
                    ret = component::Ciphertext(Buffer(in));
588
0
                }
589
1.22k
            }
590
0
            break;
591
428
        case    CF_CIPHER("CHACHA20"):
592
428
            {
593
428
                CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
594
329
                CF_CHECK_EQ(op.cipher.iv.GetSize(), 12);
595
596
266
                auto in = op.cleartext.Get();
597
598
266
                auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds);
599
266
                cc20(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), 0, in.data(), in.size());
600
266
                ret = component::Ciphertext(Buffer(in));
601
266
            }
602
0
            break;
603
590
        case    CF_CIPHER("CHACHA20_POLY1305"):
604
590
            {
605
590
                CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
606
483
                CF_CHECK_EQ(op.cipher.iv.GetSize(), 12);
607
608
448
                if ( op.tagSize != std::nullopt ) {
609
89
                    CF_CHECK_EQ(*op.tagSize, 16);
610
35
                }
611
612
394
                uint8_t tag[16];
613
394
                auto in = op.cleartext.Get();
614
394
                auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds);
615
616
394
                br_poly1305_ctmul_run(
617
394
                        op.cipher.key.GetPtr(),
618
394
                        op.cipher.iv.GetPtr(),
619
394
                        in.data(),
620
394
                        in.size(),
621
394
                        op.aad == std::nullopt ? nullptr : op.aad->GetPtr(),
622
394
                        op.aad == std::nullopt ? 0 : op.aad->GetSize(),
623
394
                        tag,
624
394
                        cc20,
625
394
                        1);
626
627
394
                if ( op.tagSize != std::nullopt ) {
628
35
                    ret = component::Ciphertext(Buffer(in), Buffer(tag, 16));
629
359
                } else {
630
359
                    ret = component::Ciphertext(Buffer(in));
631
359
                }
632
394
            }
633
0
            break;
634
4.14k
    }
635
636
4.14k
end:
637
4.14k
    util::free(tag);
638
639
4.14k
    return ret;
640
4.14k
}
641
642
4.96k
std::optional<component::Cleartext> BearSSL::OpSymmetricDecrypt(operation::SymmetricDecrypt& op) {
643
4.96k
    std::optional<component::Cleartext> ret = std::nullopt;
644
4.96k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
645
646
4.96k
    switch ( op.cipher.cipherType.Get() ) {
647
689
        case    CF_CIPHER("AES_128_GCM"):
648
931
        case    CF_CIPHER("AES_192_GCM"):
649
1.12k
        case    CF_CIPHER("AES_256_GCM"):
650
1.12k
            {
651
1.12k
                br_aes_ct_ctr_keys bc;
652
1.12k
                br_gcm_context gc;
653
1.12k
                auto in = op.ciphertext.Get();
654
1.12k
                auto parts = util::ToParts(ds, in);
655
656
1.12k
                switch ( op.cipher.cipherType.Get() ) {
657
689
                    case    CF_CIPHER("AES_128_GCM"):
658
689
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 16);
659
634
                        break;
660
242
                    case    CF_CIPHER("AES_192_GCM"):
661
242
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 24);
662
183
                        break;
663
196
                    case    CF_CIPHER("AES_256_GCM"):
664
196
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
665
166
                        break;
666
1.12k
                }
667
668
983
                if ( op.tag != std::nullopt ) {
669
261
                    CF_CHECK_EQ(op.tag->GetSize(), 16);
670
199
                }
671
672
921
                CF_CHECK_GT(op.cipher.iv.GetSize(), 0);
673
674
                /* noret */ br_aes_ct_ctr_init(&bc, op.cipher.key.GetPtr(), op.cipher.key.GetSize());
675
887
                /* noret */ br_gcm_init(&gc, &bc.vtable, br_ghash_ctmul32);
676
677
                /* noret */ br_gcm_reset(&gc, op.cipher.iv.GetPtr(), op.cipher.iv.GetSize());
678
887
                if ( op.aad != std::nullopt ) {
679
221
                    const auto aadParts = util::ToParts(ds, *op.aad);
680
                    /* "Additional data may be provided in several chunks of arbitrary length" */
681
873
                    for (auto& part : aadParts) {
682
873
                        /* noret */ br_gcm_aad_inject(&gc, part.first, part.second);
683
873
                    }
684
221
                }
685
887
                /* noret */ br_gcm_flip(&gc);
686
687
9.91k
                for (auto& part : parts) {
688
                    /* "Data may be provided in several chunks of arbitrary length" */
689
9.91k
                    /* noret */ br_gcm_run(&gc, 0, (void*)part.first, part.second);
690
9.91k
                }
691
692
887
                if ( op.tag != std::nullopt ) {
693
199
                    CF_CHECK_EQ(br_gcm_check_tag(&gc, op.tag->GetPtr()), 1);
694
150
                }
695
696
838
                ret = component::Cleartext(Buffer(in));
697
838
            }
698
0
            break;
699
1.39k
        case    CF_CIPHER("AES_128_CCM"):
700
2.33k
        case    CF_CIPHER("AES_192_CCM"):
701
2.84k
        case    CF_CIPHER("AES_256_CCM"):
702
2.84k
            {
703
2.84k
                br_aes_gen_ctrcbc_keys bc;
704
2.84k
                br_ccm_context ec;
705
2.84k
                auto in = op.ciphertext.Get();
706
2.84k
                auto parts = util::ToParts(ds, in);
707
2.84k
                const auto vt = BearSSL_detail::Get_br_block_ctrcbc_class(ds);
708
2.84k
                CF_CHECK_NE(vt, nullptr);
709
710
2.84k
                switch ( op.cipher.cipherType.Get() ) {
711
1.39k
                    case    CF_CIPHER("AES_128_CCM"):
712
1.39k
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 16);
713
1.19k
                        break;
714
946
                    case    CF_CIPHER("AES_192_CCM"):
715
946
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 24);
716
901
                        break;
717
511
                    case    CF_CIPHER("AES_256_CCM"):
718
511
                        CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
719
470
                        break;
720
2.84k
                }
721
722
2.56k
                CF_CHECK_GT(op.cipher.iv.GetSize(), 0);
723
724
                /* noret */ vt->init(&bc.vtable, op.cipher.key.GetPtr(), op.cipher.key.GetSize());
725
2.50k
                /* noret */ br_ccm_init(&ec, &bc.vtable);
726
727
2.50k
                CF_CHECK_NE(br_ccm_reset(&ec,
728
2.50k
                            op.cipher.iv.GetPtr(), op.cipher.iv.GetSize(),
729
2.50k
                            op.aad == std::nullopt ? 0 : op.aad->GetSize(),
730
2.50k
                            op.ciphertext.GetSize(),
731
2.50k
                            op.tag == std::nullopt ? 0 : op.tag->GetSize()), 0);
732
733
2.39k
                if ( op.aad != std::nullopt ) {
734
1.07k
                    const auto aadParts = util::ToParts(ds, *op.aad);
735
                    /* "Additional data may be provided in several chunks of arbitrary length" */
736
5.68k
                    for (auto& part : aadParts) {
737
5.68k
                        /* noret */ br_ccm_aad_inject(&ec, part.first, part.second);
738
5.68k
                    }
739
1.07k
                }
740
2.39k
                /* noret */ br_ccm_flip(&ec);
741
742
9.56k
                for (auto& part : parts) {
743
                    /* "Data may be provided in several chunks of arbitrary length" */
744
9.56k
                    /* noret */ br_ccm_run(&ec, 0, (void*)part.first, part.second);
745
9.56k
                }
746
747
2.39k
                if ( op.tag != std::nullopt ) {
748
2.39k
                    CF_CHECK_EQ(br_ccm_check_tag(&ec, op.tag->GetPtr()), 1);
749
1.06k
                }
750
751
1.06k
                ret = component::Cleartext(Buffer(in));
752
1.06k
            }
753
0
            break;
754
361
        case    CF_CIPHER("CHACHA20"):
755
361
            {
756
361
                CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
757
278
                CF_CHECK_EQ(op.cipher.iv.GetSize(), 12);
758
759
227
                auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds);
760
227
                auto in = op.ciphertext.Get();
761
762
227
                cc20(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), 0, in.data(), in.size());
763
227
                ret = component::Cleartext(Buffer(in));
764
227
            }
765
0
            break;
766
625
        case    CF_CIPHER("CHACHA20_POLY1305"):
767
625
            {
768
625
                CF_CHECK_EQ(op.cipher.key.GetSize(), 32);
769
508
                CF_CHECK_EQ(op.cipher.iv.GetSize(), 12);
770
771
484
                if ( op.tag != std::nullopt ) {
772
123
                    CF_CHECK_EQ(op.tag->GetSize(), 16);
773
77
                }
774
775
438
                uint8_t tag[16];
776
438
                auto in = op.ciphertext.Get();
777
438
                auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds);
778
779
438
                br_poly1305_ctmul_run(
780
438
                        op.cipher.key.GetPtr(),
781
438
                        op.cipher.iv.GetPtr(),
782
438
                        in.data(),
783
438
                        in.size(),
784
438
                        op.aad == std::nullopt ? nullptr : op.aad->GetPtr(),
785
438
                        op.aad == std::nullopt ? 0 : op.aad->GetSize(),
786
438
                        tag,
787
438
                        cc20,
788
438
                        0);
789
790
438
                if ( op.tag != std::nullopt ) {
791
77
                    CF_CHECK_EQ(memcmp(op.tag->GetPtr(), tag, 16), 0);
792
21
                }
793
794
382
                ret = component::Cleartext(Buffer(in));
795
382
            }
796
0
            break;
797
4.96k
    }
798
799
4.96k
end:
800
4.96k
    return ret;
801
4.96k
}
802
803
968
std::optional<component::Key> BearSSL::OpKDF_HKDF(operation::KDF_HKDF& op) {
804
968
    std::optional<component::Key> ret = std::nullopt;
805
968
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
806
807
968
    br_hkdf_context ctx;
808
968
    const br_hash_class* hash_class;
809
968
    uint8_t* out = util::malloc(op.keySize);
810
811
    /* Initialize */
812
968
    {
813
968
        const auto digestSize = repository::DigestSize(op.digestType.Get());
814
968
        CF_CHECK_NE(digestSize, std::nullopt);
815
880
        CF_CHECK_LTE(op.keySize, 255 * *digestSize);
816
817
756
        CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr);
818
756
        /* noret */ br_hkdf_init(&ctx, hash_class, op.salt.GetPtr(), op.salt.GetSize());
819
756
    }
820
821
    /* Process */
822
0
    {
823
756
        const auto parts = util::ToParts(ds, op.password);
824
825
        /* "This function may be called several times" https://bearssl.org/apidoc/bearssl__kdf_8h.html */
826
82.7k
        for (const auto& part : parts) {
827
82.7k
            /* noret */ br_hkdf_inject(&ctx, part.first, part.second);
828
82.7k
        }
829
756
    }
830
831
    /* noret */ br_hkdf_flip(&ctx);
832
833
    /* Finalize */
834
756
    {
835
756
        br_hkdf_produce(&ctx, op.info.GetPtr(), op.info.GetSize(), out, op.keySize);
836
837
756
        ret = component::Key(out, op.keySize);
838
756
    }
839
840
968
end:
841
968
    util::free(out);
842
843
968
    return ret;
844
756
}
845
846
310
std::optional<component::Key> BearSSL::OpKDF_TLS1_PRF(operation::KDF_TLS1_PRF& op) {
847
310
    std::optional<component::Key> ret = std::nullopt;
848
310
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
849
850
310
    const auto parts = util::ToParts(ds, op.seed);
851
310
    br_tls_prf_seed_chunk* seed_chunks = (br_tls_prf_seed_chunk*)util::malloc(parts.size() * sizeof(br_tls_prf_seed_chunk));
852
310
    uint8_t* out = util::malloc(op.keySize);
853
854
310
    CF_CHECK_EQ(op.digestType.Get(), CF_DIGEST("MD5_SHA1"));
855
856
259
    {
857
259
        size_t i = 0;
858
1.39k
        for (const auto& part : parts) {
859
1.39k
            seed_chunks[i].data = part.first;
860
1.39k
            seed_chunks[i].len = part.second;
861
1.39k
            i++;
862
1.39k
        }
863
259
    }
864
865
    /* noret */ br_tls10_prf(
866
259
            out,
867
259
            op.keySize,
868
259
            op.secret.GetPtr(), op.secret.GetSize(),
869
259
            "",
870
259
            parts.size(),
871
259
            seed_chunks);
872
873
259
    ret = component::Key(out, op.keySize);
874
875
310
end:
876
310
    util::free(out);
877
310
    util::free(seed_chunks);
878
879
310
    return ret;
880
259
}
881
882
3.48k
std::optional<component::ECC_KeyPair> BearSSL::OpECC_GenerateKeyPair(operation::ECC_GenerateKeyPair& op) {
883
3.48k
    std::optional<component::ECC_KeyPair> ret = std::nullopt;
884
3.48k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
885
886
3.48k
    br_ec_private_key sk;
887
3.48k
    br_ec_public_key pk;
888
3.48k
    uint8_t priv[BR_EC_KBUF_PRIV_MAX_SIZE];
889
3.48k
    uint8_t pub[BR_EC_KBUF_PUB_MAX_SIZE];
890
3.48k
    size_t privSize, pubSize;
891
3.48k
    int curve;
892
3.48k
    const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType);
893
894
3.48k
    CF_CHECK_NE(curve = BearSSL_detail::toCurveID(op.curveType), -1);
895
896
1.04k
    CF_CHECK_NE(privSize = br_ec_keygen(&BearSSL_detail::rng.vtable, ec_impl, &sk, priv, curve), 0);
897
608
    CF_CHECK_NE(pubSize = br_ec_compute_pub(ec_impl, &pk, pub, &sk), 0);
898
899
608
    if ( op.curveType.Is(CF_ECC_CURVE("x25519")) ) {
900
162
        std::reverse(priv, priv + privSize);
901
162
    }
902
903
608
    ret = { BearSSL_detail::toString(priv, privSize), BearSSL_detail::EncodePubkey(op.curveType, pub, pubSize) };
904
3.48k
end:
905
3.48k
    return ret;
906
608
}
907
908
1.26k
std::optional<component::ECC_PublicKey> BearSSL::OpECC_PrivateToPublic(operation::ECC_PrivateToPublic& op) {
909
1.26k
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
910
1.26k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
911
912
1.26k
    br_ec_private_key sk;
913
1.26k
    br_ec_public_key pk;
914
1.26k
    uint8_t priv[BR_EC_KBUF_PRIV_MAX_SIZE];
915
1.26k
    uint8_t pub[BR_EC_KBUF_PUB_MAX_SIZE];
916
1.26k
    size_t privSize;
917
1.26k
    size_t pubSize;
918
1.26k
    const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType);
919
920
1.26k
    CF_CHECK_NE(sk.curve = BearSSL_detail::toCurveID(op.curveType), -1);
921
932
    CF_CHECK_EQ(BearSSL_detail::IsValidPrivateKey(op.priv, op.curveType), true);
922
849
    {
923
849
        bool reverse;
924
925
849
        if ( op.curveType.Is(CF_ECC_CURVE("x25519")) ) {
926
418
            privSize = 32;
927
418
            reverse = true;
928
431
        } else {
929
431
            reverse = false;
930
431
            privSize = sizeof(priv);
931
431
        }
932
849
        CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.priv.ToTrimmedString(), priv, privSize, reverse), true);
933
802
    }
934
935
0
    sk.x = priv;
936
802
    sk.xlen = privSize;
937
938
802
    memset(&pk, 0, sizeof(pk));
939
802
    CF_CHECK_NE(pubSize = br_ec_compute_pub(ec_impl, &pk, pub, &sk), 0);
940
598
    ret = BearSSL_detail::EncodePubkey(op.curveType, pub, pubSize);
941
942
1.26k
end:
943
1.26k
    return ret;
944
598
}
945
946
2.13k
std::optional<bool> BearSSL::OpECDSA_Verify(operation::ECDSA_Verify& op) {
947
2.13k
    std::optional<bool> ret = std::nullopt;
948
2.13k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
949
950
2.13k
    size_t generator_len;
951
2.13k
    size_t signature_len;
952
2.13k
    switch ( op.curveType.Get() ) {
953
572
        case CF_ECC_CURVE("secp256r1"):
954
572
            generator_len = 65;
955
572
            signature_len = 64;
956
572
            break;
957
330
        case CF_ECC_CURVE("secp384r1"):
958
330
            generator_len = 97;
959
330
            signature_len = 96;
960
330
            break;
961
298
        case CF_ECC_CURVE("secp521r1"):
962
298
            generator_len = 133;
963
298
            signature_len = 132;
964
298
            break;
965
930
        default:
966
930
            return std::nullopt;
967
2.13k
    }
968
969
1.20k
    size_t pubkeyHalfSize = (generator_len - 1) / 2;
970
1.20k
    size_t signatureHalfSize = signature_len / 2;
971
1.20k
    uint8_t* signature = util::malloc(signature_len);
972
1.20k
    uint8_t* pub = util::malloc(generator_len);
973
1.20k
    br_ec_public_key pk;
974
1.20k
    const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType);
975
1.20k
    auto verify = BearSSL_detail::Get_br_ecdsa_vrfy(ds);
976
1.20k
    const br_hash_class* hash_class;
977
1.20k
    uint8_t _hash[64];
978
1.20k
    const uint8_t* hash;
979
1.20k
    size_t hash_size = 0;
980
981
1.20k
    if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
982
0
        hash = op.cleartext.GetPtr();
983
0
        hash_size = op.cleartext.GetSize();
984
1.20k
    } else {
985
1.20k
        br_hash_compat_context hc;
986
987
1.20k
        CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr);
988
989
1.16k
        hash_class->init(&hc.vtable);
990
1.16k
        hash_class->update(&hc.vtable, op.cleartext.GetPtr(), op.cleartext.GetSize());
991
1.16k
        hash_class->out(&hc.vtable, _hash);
992
1.16k
        hash = _hash;
993
1.16k
        hash_size = (hash_class->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
994
1.16k
    }
995
1.16k
    CF_CHECK_NE(pk.curve = BearSSL_detail::toCurveID(op.curveType), -1);
996
997
1.16k
    CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.signature.first.ToTrimmedString(), signature, signatureHalfSize), true);
998
1.14k
    CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.signature.second.ToTrimmedString(), signature + signatureHalfSize, signatureHalfSize), true);
999
1000
1.12k
    pub[0] = 0x04;
1001
1.12k
    CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.pub.first.ToTrimmedString(), pub + 1, pubkeyHalfSize), true);
1002
1.11k
    CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.pub.second.ToTrimmedString(), pub + 1 + pubkeyHalfSize, pubkeyHalfSize), true);
1003
1004
1.10k
    pk.q = pub;
1005
1.10k
    pk.qlen = generator_len;
1006
1007
1.10k
    ret = verify(
1008
1.10k
            ec_impl,
1009
1.10k
            hash,
1010
1.10k
            hash_size,
1011
1.10k
            &pk,
1012
1.10k
            signature,
1013
1.10k
            signature_len);
1014
1.20k
end:
1015
1016
1.20k
    util::free(signature);
1017
1.20k
    util::free(pub);
1018
1019
1.20k
    return ret;
1020
1.10k
}
1021
1022
1.46k
std::optional<component::ECDSA_Signature> BearSSL::OpECDSA_Sign(operation::ECDSA_Sign& op) {
1023
1.46k
    std::optional<component::ECDSA_Signature> ret = std::nullopt;
1024
1.46k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1025
1026
1.46k
    size_t signature_len;
1027
1.46k
    switch ( op.curveType.Get() ) {
1028
167
        case CF_ECC_CURVE("secp256r1"):
1029
167
            signature_len = 64;
1030
167
            break;
1031
237
        case CF_ECC_CURVE("secp384r1"):
1032
237
            signature_len = 96;
1033
237
            break;
1034
225
        case CF_ECC_CURVE("secp521r1"):
1035
225
            signature_len = 132;
1036
225
            break;
1037
835
        default:
1038
835
            return std::nullopt;
1039
1.46k
    }
1040
1041
629
    br_ec_private_key sk;
1042
629
    br_ec_public_key pk;
1043
629
    uint8_t priv[BR_EC_KBUF_PRIV_MAX_SIZE];
1044
629
    uint8_t pub[BR_EC_KBUF_PUB_MAX_SIZE];
1045
629
    size_t pubSize;
1046
629
    uint8_t* signature = util::malloc(signature_len);
1047
629
    size_t sigSize;
1048
629
    uint8_t hash[64];
1049
629
    br_hash_compat_context hc;
1050
629
    const br_hash_class* hash_class;
1051
629
    const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType);
1052
629
    auto sign = BearSSL_detail::Get_br_ecdsa_sign(ds);
1053
1054
629
    CF_CHECK_EQ(op.UseRFC6979Nonce(), true);
1055
600
    CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr);
1056
1057
590
    CF_CHECK_NE(sk.curve = BearSSL_detail::toCurveID(op.curveType), -1);
1058
590
    CF_CHECK_EQ(BearSSL_detail::IsValidPrivateKey(op.priv, op.curveType), true);
1059
580
    CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.priv.ToTrimmedString(), priv, sizeof(priv)), true);
1060
1061
580
    hash_class->init(&hc.vtable);
1062
580
    hash_class->update(&hc.vtable, op.cleartext.GetPtr(), op.cleartext.GetSize());
1063
580
    hash_class->out(&hc.vtable, hash);
1064
1065
580
    sk.x = priv;
1066
580
    sk.xlen = sizeof(priv);
1067
1068
580
    memset(&pk, 0, sizeof(pk));
1069
580
    CF_CHECK_NE(pubSize = br_ec_compute_pub(ec_impl, &pk, pub, &sk), 0);
1070
1071
580
    CF_CHECK_NE(sigSize = sign(ec_impl, hash_class, hash, &sk, signature), 0);
1072
1073
580
    if ( sigSize % 2 != 0 ) {
1074
0
        abort();
1075
0
    }
1076
1077
    /* Disabled because signature S needs to be corrected for compatibility with Botan/Trezor */
1078
580
    CF_CHECK_NE(op.curveType.Get(), CF_ECC_CURVE("secp256r1"));
1079
1080
434
    ret = {
1081
434
            {BearSSL_detail::toString(signature, sigSize / 2), BearSSL_detail::toString(signature + (sigSize/2), sigSize / 2) },
1082
434
            BearSSL_detail::EncodePubkey(op.curveType, pub, pubSize)
1083
434
    };
1084
1085
629
end:
1086
629
    util::free(signature);
1087
629
    return ret;
1088
434
}
1089
1090
} /* namespace module */
1091
} /* namespace cryptofuzz */