Coverage Report

Created: 2022-08-24 06:37

/src/cryptofuzz-sp-math-all/modules/wolfcrypt/ecdsa_generic.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "ecdsa_generic.h"
2
#include "module_internal.h"
3
#include "shared.h"
4
#include "bn_ops.h"
5
#include <cryptofuzz/util.h>
6
#include <iostream>
7
8
namespace cryptofuzz {
9
namespace module {
10
namespace wolfCrypt_detail {
11
12
#if !defined(WOLFSSL_SP_MATH)
13
#include "custom_curves.h"
14
#endif
15
16
#if defined(CRYPTOFUZZ_WOLFCRYPT_ALLOCATION_FAILURES)
17
    extern bool haveAllocFailure;
18
#endif
19
20
WC_RNG* GetRNG(void);
21
22
ECCKey::ECCKey(Datasource& ds) :
23
29.7k
    ds(ds) {
24
29.7k
    if ( (key = wc_ecc_key_new(nullptr)) == nullptr ) {
25
1.86k
        throw std::exception();
26
1.86k
    }
27
29.7k
}
28
29
27.8k
ECCKey::~ECCKey() {
30
27.8k
    CF_NORET(wc_ecc_key_free(key));
31
27.8k
}
32
33
72.2k
ecc_key* ECCKey::GetPtr(void) {
34
72.2k
    uint8_t* x963 = nullptr;
35
72.2k
    ecc_key* newKey = nullptr;
36
37
72.2k
    bool exportToX963 = false;
38
72.2k
    try {
39
72.2k
        exportToX963 = ds.Get<bool>();
40
72.2k
    } catch ( ... ) { }
41
42
72.2k
    if ( exportToX963 == true ) {
43
5.47k
        CF_CHECK_NE(newKey = wc_ecc_key_new(nullptr), nullptr);
44
45
3.53k
        word32 outLen = 0;
46
47
3.53k
        bool compressed = false;
48
3.53k
        try { compressed  = ds.Get<bool>();} catch ( ... ) { }
49
50
6.32k
        WC_CHECK_EQ(wc_ecc_export_x963_ex(key, nullptr, &outLen, compressed), LENGTH_ONLY_E);
51
6.32k
        x963 = util::malloc(outLen);
52
6.32k
        WC_CHECK_EQ(wc_ecc_export_x963_ex(key, x963, &outLen, compressed), 0);;
53
54
        /* Get the curve id of the old key */
55
1.11k
        int curveID;
56
1.11k
        CF_CHECK_NE(curveID = wc_ecc_get_curve_id(key->idx), ECC_CURVE_INVALID);
57
58
1.11k
        const bool valid = wc_ecc_check_key(key) == 0;
59
60
1.11k
        haveAllocFailure = false;
61
1.11k
        if ( wc_ecc_import_x963_ex(x963, outLen, newKey, curveID) != 0 ) {
62
            /* Allowed to fail if either:
63
             *
64
             * - Compression is used and the input key is invalid
65
             * - An allocation failure occured during wc_ecc_import_x963_ex
66
             */
67
326
            CF_ASSERT((compressed && !valid) || haveAllocFailure, "Cannot import X963-exported ECC key");
68
326
            goto end;
69
326
        }
70
71
788
        if ( compressed ) {
72
184
            CF_CHECK_TRUE(valid);
73
38
        }
74
75
642
        CF_NORET(wc_ecc_key_free(key));
76
642
        key = newKey;
77
642
        newKey = nullptr;
78
642
    }
79
80
72.2k
end:
81
72.2k
    util::free(x963);
82
72.2k
    CF_NORET(wc_ecc_key_free(newKey));
83
84
72.2k
    return key;
85
72.2k
}
86
87
9.23k
bool ECCKey::SetCurve(const Type& curveType) {
88
9.23k
    bool ret = false;
89
90
9.23k
#if !defined(WOLFSSL_SP_MATH)
91
9.23k
    bool useCustomCurve = false;
92
93
9.23k
    try {
94
9.23k
        useCustomCurve = ds.Get<uint8_t>();
95
9.23k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
96
9.23k
    useCustomCurve = false;
97
98
9.23k
    if ( useCustomCurve == false )
99
9.23k
#endif
100
9.23k
    {
101
#if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG)
102
        std::cout << "Using native curve" << std::endl;
103
#endif
104
9.23k
        std::optional<int> curveID;
105
106
9.23k
        CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(curveType), std::nullopt);
107
7.29k
        this->curveID = *curveID;
108
109
7.29k
        WC_CHECK_EQ(wc_ecc_set_curve(GetPtr(), 0, *curveID), 0);
110
7.11k
    }
111
0
#if !defined(WOLFSSL_SP_MATH)
112
0
    else {
113
 #if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG)
114
        std::cout << "Using custom curve" << std::endl;
115
 #endif
116
0
        const ecc_set_type* curveSpec;
117
0
        CF_CHECK_NE(curveSpec = GetCustomCurve(curveType.Get()), nullptr);
118
0
        WC_CHECK_EQ(wc_ecc_set_custom_curve(GetPtr(), curveSpec), 0);
119
0
        this->curveID = ECC_CURVE_CUSTOM;
120
0
    }
121
7.11k
#endif
122
123
7.11k
    ret = true;
124
125
9.23k
end:
126
9.23k
    return ret;
127
7.11k
}
128
129
9.48k
bool ECCKey::LoadPrivateKey(const component::Bignum& priv) {
130
9.48k
    bool ret = false;
131
9.48k
    std::optional<std::vector<uint8_t>> priv_bytes;
132
133
9.48k
    CF_CHECK_NE(priv_bytes = wolfCrypt_bignum::Bignum::ToBin(ds, priv), std::nullopt);
134
135
9.11k
    WC_CHECK_EQ(wc_ecc_import_private_key_ex(priv_bytes->data(), priv_bytes->size(), nullptr, 0, GetPtr(), *curveID), 0);
136
137
8.72k
    ret = true;
138
139
9.48k
end:
140
9.48k
    return ret;
141
8.72k
}
142
143
6.42k
std::optional<ECCPoint> ECCKey::MakePub(void) {
144
6.42k
    std::optional<ECCPoint> ret = std::nullopt;
145
146
6.42k
    ECCPoint pub(ds, *curveID);
147
6.42k
    WC_CHECK_EQ(wc_ecc_make_pub(GetPtr(), pub.GetPtr()), 0);
148
6.05k
    pub.SetInitialized();
149
150
6.05k
    return pub;
151
152
363
end:
153
363
    return ret;
154
6.42k
}
155
156
3.59k
bool ECCKey::SetRNG(void) {
157
3.59k
    bool ret = false;
158
159
3.59k
    WC_CHECK_EQ(wc_ecc_set_rng(GetPtr(), wolfCrypt_detail::GetRNG()), 0);
160
161
3.59k
    ret = true;
162
3.59k
end:
163
3.59k
    return ret;
164
3.59k
}
165
166
ECCPoint::ECCPoint(Datasource& ds, const int curveID) :
167
    ds(ds),
168
22.4k
    curveID(curveID) {
169
22.4k
    if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) {
170
687
        throw std::exception();
171
687
    }
172
22.4k
}
173
174
/* Copy constructor */
175
ECCPoint::ECCPoint(const ECCPoint& other) :
176
    ds(other.ds),
177
    curveID(other.curveID),
178
    locked(other.locked),
179
    initialized(other.initialized)
180
5.96k
{
181
5.96k
    if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) {
182
9
        throw std::exception();
183
9
    }
184
185
5.95k
    if ( wc_ecc_copy_point(other.point, point) != 0 ) {
186
0
        CF_NORET(wc_ecc_del_point(point));
187
0
        throw std::exception();
188
0
    }
189
5.95k
}
190
191
27.6k
ECCPoint::~ECCPoint() {
192
27.6k
    CF_NORET(wc_ecc_del_point(point));
193
27.6k
}
194
195
40.1k
ecc_point* ECCPoint::GetPtr() {
196
40.1k
    uint8_t* out = nullptr;
197
40.1k
    ecc_point* newPoint = nullptr;
198
199
40.1k
    if ( locked == false && initialized == true ) {
200
11.3k
        bool exportToDER = false;
201
202
11.3k
        try {
203
11.3k
            exportToDER = ds.Get<bool>();
204
11.3k
        } catch ( ... ) { }
205
206
11.3k
        if ( exportToDER == true ) {
207
821
            bool compressed = false;
208
821
            try {
209
821
                compressed = ds.Get<bool>();
210
821
            } catch ( ... ) { }
211
212
821
            const int curveIdx = wc_ecc_get_curve_idx(curveID);
213
821
            CF_CHECK_NE(newPoint = wc_ecc_new_point_h(nullptr), nullptr);
214
215
605
            word32 outSz = 0xFFFF;
216
605
            try { outSz = ds.Get<word32>() & 0xFFFF; } catch ( ... ) { }
217
218
605
            out = util::malloc(outSz);
219
220
605
            if ( compressed == false ) {
221
266
                WC_CHECK_EQ(wc_ecc_export_point_der(curveIdx, point, out, &outSz), 0);
222
339
            } else {
223
339
                WC_CHECK_EQ(wc_ecc_export_point_der(curveIdx, point, out, &outSz), 0);
224
                //WC_CHECK_EQ(wc_ecc_export_point_der_compressed(curveIdx, point, out, &outSz), 0);
225
110
            }
226
227
214
            {
228
214
                haveAllocFailure = false;
229
214
                const bool success = wc_ecc_import_point_der(out, outSz, curveIdx, newPoint) == 0;
230
231
214
                if ( success ) {
232
                    /* Point imported. Replace old point with new point. */
233
234
214
                    CF_NORET(wc_ecc_del_point(point));
235
214
                    point = newPoint;
236
214
                    newPoint = nullptr;
237
214
                } else {
238
                    /* Failure */
239
240
0
                    if ( haveAllocFailure == false ) {
241
                        /* Failure is only acceptable if an allocation failure occured, crash otherwise */
242
0
                        CF_ASSERT(0, "Cannot import DER-exported ECC point");
243
0
                    }
244
0
                }
245
214
            }
246
214
        }
247
11.3k
    }
248
249
40.1k
end:
250
40.1k
    util::free(out);
251
40.1k
    CF_NORET(wc_ecc_del_point(newPoint));
252
253
40.1k
    return point;
254
40.1k
}
255
256
8.70k
bool ECCPoint::Set(const component::BignumPair& xy, const bool pointCheck) {
257
8.70k
    bool ret = false;
258
259
8.70k
    wolfCrypt_bignum::Bignum x(ds), y(ds), z(ds);
260
261
8.70k
    CF_CHECK_TRUE(x.Set(xy.first));
262
8.54k
    CF_CHECK_TRUE(y.Set(xy.second));
263
8.44k
    CF_CHECK_TRUE(z.Set("1"));
264
265
8.44k
    WC_CHECK_EQ(mp_copy(x.GetPtr(), point->x), MP_OKAY);
266
8.44k
    WC_CHECK_EQ(mp_copy(y.GetPtr(), point->y), MP_OKAY);
267
8.44k
    WC_CHECK_EQ(mp_copy(z.GetPtr(), point->z), MP_OKAY);
268
269
8.44k
    if ( pointCheck ) {
270
0
        CF_CHECK_TRUE(CurveCheck());
271
0
    }
272
273
8.44k
    SetInitialized();
274
275
8.44k
    ret = true;
276
277
8.70k
end:
278
8.70k
    return ret;
279
8.44k
}
280
281
4.49k
bool ECCPoint::ToProjective(wolfCrypt_bignum::Bignum& prime) {
282
4.49k
    bool ret = false;
283
284
4.49k
    wolfCrypt_bignum::Bignum mu(ds);
285
286
4.49k
    WC_CHECK_EQ(mp_montgomery_calc_normalization(mu.GetPtr(), prime.GetPtr()), MP_OKAY);
287
288
4.49k
    if ( mp_cmp_d(mu.GetPtr(), 1) != MP_EQ ) {
289
3.12k
        WC_CHECK_EQ(mp_mulmod(point->x, mu.GetPtr(), prime.GetPtr(), point->x), MP_OKAY);
290
3.06k
        WC_CHECK_EQ(mp_mulmod(point->y, mu.GetPtr(), prime.GetPtr(), point->y), MP_OKAY);
291
2.99k
        WC_CHECK_EQ(mp_mulmod(point->z, mu.GetPtr(), prime.GetPtr(), point->z), MP_OKAY);
292
2.95k
    }
293
294
    /* Lock so it isn't attempted to export/import the projective point in GetPtr(),
295
     * which will lead to incorrect results
296
     */
297
4.33k
    Lock();
298
299
4.33k
    ret = true;
300
301
4.49k
end:
302
4.49k
    return ret;
303
4.33k
}
304
305
6.58k
bool ECCPoint::CurveCheck(void) const {
306
6.58k
    const int curveIdx = wc_ecc_get_curve_idx(curveID);
307
6.58k
    return wc_ecc_point_is_on_curve(point, curveIdx) == 0;
308
6.58k
}
309
310
12.0k
void ECCPoint::Lock(void) {
311
12.0k
    locked = true;
312
12.0k
}
313
314
14.4k
void ECCPoint::SetInitialized(void) {
315
14.4k
    initialized = true;
316
14.4k
}
317
318
5.85k
std::optional<component::BignumPair> ECCPoint::ToBignumPair(void) {
319
5.85k
    std::optional<component::BignumPair> ret = std::nullopt;
320
321
5.85k
    wolfCrypt_bignum::Bignum pub_x(GetPtr()->x, ds);
322
323
    /* Pointer is stored in pub_x; lock to prevent UAF */
324
5.85k
    Lock();
325
326
5.85k
    wolfCrypt_bignum::Bignum pub_y(GetPtr()->y, ds);
327
328
5.85k
    std::optional<std::string> pub_x_str, pub_y_str;
329
5.85k
    CF_CHECK_NE(pub_x_str = pub_x.ToDecString(), std::nullopt);
330
5.85k
    CF_CHECK_NE(pub_y_str = pub_y.ToDecString(), std::nullopt);
331
332
5.84k
    ret = { *pub_x_str, *pub_y_str };
333
5.85k
end:
334
335
5.85k
    return ret;
336
5.84k
}
337
338
2.13k
int ECCPoint::Compare(ECCPoint& other) {
339
2.13k
    return wc_ecc_cmp_point(GetPtr(), other.GetPtr());
340
2.13k
}
341
342
2.29k
std::optional<bool> ECCPoint::IsNeg(ECCPoint& other, wolfCrypt_bignum::Bignum& prime) {
343
2.29k
    std::optional<bool> ret = std::nullopt;
344
345
2.29k
    wolfCrypt_bignum::Bignum neg(ds);
346
2.29k
    if ( mp_sub(prime.GetPtr(), other.GetPtr()->y, neg.GetPtr()) == MP_OKAY) {
347
2.29k
        ret = static_cast<bool>(mp_cmp(point->y, neg.GetPtr()) == MP_EQ);
348
2.29k
    }
349
350
2.29k
    return ret;
351
2.29k
}
352
353
4.82k
std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Generic(operation::ECC_PrivateToPublic& op) {
354
4.82k
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
355
4.82k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
356
4.82k
    wolfCrypt_detail::SetGlobalDs(&ds);
357
358
4.82k
    try {
359
4.82k
        ECCKey key(ds);
360
361
        /* Initialize */
362
4.82k
        {
363
4.82k
            CF_CHECK_EQ(key.SetCurve(op.curveType), true);
364
2.65k
            CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true);
365
2.18k
        }
366
367
        /* Process/Finalize */
368
0
        {
369
2.18k
            auto pub = key.MakePub();
370
2.18k
            CF_CHECK_NE(pub, std::nullopt);
371
372
1.95k
            ret = pub->ToBignumPair();
373
1.95k
        }
374
1.95k
    } catch ( ... ) { }
375
376
4.82k
end:
377
378
4.82k
    wolfCrypt_detail::UnsetGlobalDs();
379
4.82k
    return ret;
380
4.82k
}
381
382
5.73k
std::optional<bool> OpECC_ValidatePubkey_Generic(operation::ECC_ValidatePubkey& op) {
383
5.73k
    std::optional<bool> ret = std::nullopt;
384
5.73k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
385
5.73k
    wolfCrypt_detail::SetGlobalDs(&ds);
386
387
5.73k
    std::optional<int> curveID;
388
389
5.73k
    try {
390
5.73k
        ECCKey key(ds);
391
5.73k
        {
392
5.73k
            const char* name = nullptr;
393
394
5.73k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
395
396
4.09k
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
397
398
3.86k
            WC_CHECK_EQ(wc_ecc_import_raw(
399
3.40k
                        key.GetPtr(),
400
3.40k
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
401
3.40k
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
402
3.40k
                        nullptr,
403
3.40k
                        name), 0);
404
3.40k
            haveAllocFailure = false;
405
3.40k
            ret = wc_ecc_check_key(key.GetPtr()) == 0;
406
3.40k
            if ( *ret == false && haveAllocFailure == true ) {
407
620
                ret = std::nullopt;
408
620
            }
409
3.40k
        }
410
3.40k
    } catch ( ... ) { }
411
412
5.73k
end:
413
414
5.73k
    wolfCrypt_detail::UnsetGlobalDs();
415
5.73k
    return ret;
416
5.73k
}
417
418
6.92k
std::optional<bool> OpECDSA_Verify_Generic(operation::ECDSA_Verify& op) {
419
6.92k
    std::optional<bool> ret = std::nullopt;
420
6.92k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
421
6.92k
    wolfCrypt_detail::SetGlobalDs(&ds);
422
423
6.92k
    std::optional<int> curveID;
424
6.92k
    uint8_t* sig = nullptr;
425
6.92k
    uint8_t* hash = nullptr;
426
6.92k
    word32 sigSz = ECC_MAX_SIG_SIZE;
427
6.92k
    int verify;
428
429
6.92k
    {
430
6.92k
        try {
431
6.92k
            sigSz = ds.Get<uint8_t>();
432
6.92k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
433
434
6.92k
        sig = util::malloc(sigSz);
435
6.92k
    }
436
437
6.92k
    try {
438
6.92k
        ECCKey key(ds);
439
6.92k
        {
440
6.92k
            const char* name = nullptr;
441
442
6.92k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
443
444
6.25k
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
445
446
5.89k
            WC_CHECK_EQ(wc_ecc_import_raw(
447
5.63k
                        key.GetPtr(),
448
5.63k
                        util::DecToHex(op.signature.pub.first.ToTrimmedString()).c_str(),
449
5.63k
                        util::DecToHex(op.signature.pub.second.ToTrimmedString()).c_str(),
450
5.63k
                        nullptr,
451
5.63k
                        name), 0);
452
5.63k
            WC_CHECK_EQ(wc_ecc_check_key(key.GetPtr()), 0);
453
5.19k
        }
454
455
5.19k
        WC_CHECK_EQ(wc_ecc_rs_to_sig(
456
4.83k
                    util::DecToHex(op.signature.signature.first.ToTrimmedString()).c_str(),
457
4.83k
                    util::DecToHex(op.signature.signature.second.ToTrimmedString()).c_str(),
458
4.83k
                    sig, &sigSz), 0);
459
460
4.83k
        if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
461
4.54k
            const auto CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
462
4.54k
            WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0);
463
4.09k
        } else {
464
298
            std::optional<wc_HashType> hashType;
465
298
            CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt);
466
467
298
            const auto hashSize = wc_HashGetDigestSize(*hashType);
468
298
            hash = util::malloc(hashSize);
469
470
298
            WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0);
471
472
298
            const auto CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType);
473
298
            WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0);
474
298
        }
475
476
4.39k
        ret = verify ? true : false;
477
4.39k
    } catch ( ... ) { }
478
479
6.92k
end:
480
481
6.92k
    util::free(sig);
482
6.92k
    util::free(hash);
483
484
6.92k
    wolfCrypt_detail::UnsetGlobalDs();
485
486
6.92k
    return ret;
487
6.92k
}
488
489
6.07k
std::optional<component::ECDSA_Signature> OpECDSA_Sign_Generic(operation::ECDSA_Sign& op) {
490
6.07k
    std::optional<component::ECDSA_Signature> ret = std::nullopt;
491
6.07k
    if ( op.UseRandomNonce() == false && op.UseSpecifiedNonce() == false ) {
492
326
        return ret;
493
326
    }
494
495
5.74k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
496
5.74k
    wolfCrypt_detail::SetGlobalDs(&ds);
497
498
5.74k
    uint8_t* sig = nullptr;
499
5.74k
    word32 sigSz = ECC_MAX_SIG_SIZE;
500
5.74k
    Buffer CT;
501
5.74k
    uint8_t* hash = nullptr;
502
5.74k
    size_t hashSize = 0;
503
5.74k
    uint8_t* nonce_bytes = nullptr;
504
5.74k
    wolfCrypt_bignum::Bignum nonce(ds), r(ds), s(ds);
505
506
5.74k
    CF_CHECK_NE(op.priv.ToTrimmedString(), "0");
507
508
5.39k
    {
509
5.39k
        try {
510
5.39k
            sigSz = ds.Get<uint8_t>();
511
5.39k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
512
513
5.39k
        sig = util::malloc(sigSz);
514
5.39k
    }
515
516
5.39k
    try {
517
5.39k
        ECCKey key(ds);
518
5.39k
        CF_CHECK_EQ(key.SetCurve(op.curveType), true);
519
5.04k
        CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true);
520
4.95k
        key.GetPtr()->type = ECC_PRIVATEKEY_ONLY;
521
522
4.95k
        if ( op.UseSpecifiedNonce() == true ) {
523
2.36k
            CF_CHECK_EQ(nonce.Set(op.nonce.ToString(ds)), true);
524
525
2.32k
            const size_t nonce_bytes_size = mp_unsigned_bin_size(nonce.GetPtr());
526
527
            /* Convert nonce to byte array */
528
2.32k
            nonce_bytes = util::malloc(nonce_bytes_size);
529
2.32k
            CF_CHECK_EQ(mp_to_unsigned_bin(nonce.GetPtr(), nonce_bytes), 0);
530
531
            /* Set nonce */
532
2.27k
            WC_CHECK_EQ(wc_ecc_sign_set_k(nonce_bytes, nonce_bytes_size, key.GetPtr()), 0);
533
2.17k
        }
534
535
4.76k
        auto pub = key.MakePub();
536
4.76k
        CF_CHECK_NE(pub, std::nullopt);
537
538
4.63k
        if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
539
4.29k
            CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
540
4.29k
        } else {
541
334
            std::optional<wc_HashType> hashType;
542
334
            CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt);
543
544
334
            hashSize = wc_HashGetDigestSize(*hashType);
545
334
            hash = util::malloc(hashSize);
546
547
334
            WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0);
548
549
334
            CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType);
550
334
        }
551
552
        /* Sign */
553
8.64k
        WC_CHECK_EQ(wc_ecc_sign_hash(CT.GetPtr(), CT.GetSize(), sig, &sigSz, wolfCrypt_detail::GetRNG(), key.GetPtr()), 0);
554
555
        /* Verify */
556
8.64k
        {
557
8.64k
            int verify;
558
8.64k
            haveAllocFailure = false;
559
8.64k
            if ( wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()) == 0 && haveAllocFailure == false ) {
560
3.57k
                CF_ASSERT(verify, "Cannot verify generated signature");
561
3.57k
            }
562
8.64k
        }
563
564
4.00k
        CF_CHECK_EQ(DecodeECC_DSA_Sig(sig, sigSz, r.GetPtr(), s.GetPtr()), 0);
565
4.00k
        {
566
4.00k
            std::optional<std::string> r_str, s_str;
567
568
4.00k
            if ( op.curveType.Get() == CF_ECC_CURVE("secp256k1") ) {
569
287
                wolfCrypt_bignum::Bignum SMax(ds);
570
287
                CF_CHECK_EQ(SMax.Set("57896044618658097711785492504343953926418782139537452191302581570759080747168"), true);
571
287
                if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) {
572
154
                    wolfCrypt_bignum::Bignum SSub(ds);
573
154
                    CF_CHECK_EQ(SSub.Set("115792089237316195423570985008687907852837564279074904382605163141518161494337"), true);
574
154
                    CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0);
575
154
                }
576
3.72k
            } else if ( op.curveType.Get() == CF_ECC_CURVE("secp256r1") ) {
577
1.10k
                wolfCrypt_bignum::Bignum SMax(ds);
578
1.10k
                CF_CHECK_EQ(SMax.Set("57896044605178124381348723474703786764998477612067880171211129530534256022184"), true);
579
1.10k
                if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) {
580
595
                    wolfCrypt_bignum::Bignum SSub(ds);
581
595
                    CF_CHECK_EQ(SSub.Set("115792089210356248762697446949407573529996955224135760342422259061068512044369"), true);
582
595
                    CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0);
583
595
                }
584
1.10k
            }
585
586
4.00k
            CF_CHECK_NE(r_str = r.ToDecString(), std::nullopt);
587
4.00k
            CF_CHECK_NE(s_str = s.ToDecString(), std::nullopt);
588
589
4.00k
            const auto pub2 = pub->ToBignumPair();
590
4.00k
            CF_CHECK_NE(pub2, std::nullopt);
591
592
3.99k
            ret = component::ECDSA_Signature({*r_str, *s_str}, *pub2);
593
3.99k
        }
594
3.99k
    } catch ( ... ) { }
595
5.74k
end:
596
597
5.74k
    util::free(sig);
598
5.74k
    util::free(hash);
599
5.74k
    util::free(nonce_bytes);
600
601
5.74k
    wolfCrypt_detail::UnsetGlobalDs();
602
603
5.74k
    return ret;
604
5.39k
}
605
606
2.00k
std::optional<component::Ciphertext> OpECIES_Encrypt_Generic(operation::ECIES_Encrypt& op) {
607
2.00k
    std::optional<component::Ciphertext> ret = std::nullopt;
608
#if !defined(HAVE_ECC_ENCRYPT)
609
    (void)op;
610
#else
611
2.00k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
612
2.00k
    wolfCrypt_detail::SetGlobalDs(&ds);
613
2.00k
    uint8_t* out = nullptr;
614
615
2.00k
    CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC")));
616
1.55k
    CF_CHECK_EQ(op.iv, std::nullopt);
617
618
1.50k
    try {
619
1.50k
        ECCKey priv(ds), pub(ds);
620
1.50k
        word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF;
621
622
        /* Initialize private key */
623
1.50k
        {
624
1.50k
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
625
1.43k
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
626
1.36k
            CF_CHECK_TRUE(priv.SetRNG());
627
1.36k
        }
628
629
        /* Initialize public key */
630
0
        {
631
1.36k
            std::optional<int> curveID;
632
1.36k
            const char* name = nullptr;
633
634
1.36k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
635
636
1.36k
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
637
638
1.36k
            WC_CHECK_EQ(wc_ecc_import_raw(
639
1.30k
                        pub.GetPtr(),
640
1.30k
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
641
1.30k
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
642
1.30k
                        nullptr,
643
1.30k
                        name), 0);
644
645
1.30k
            CF_CHECK_TRUE(pub.SetRNG());
646
1.30k
        }
647
648
0
        out = util::malloc(outSz);
649
650
1.30k
        WC_CHECK_EQ(wc_ecc_encrypt(priv.GetPtr(), pub.GetPtr(), op.cleartext.GetPtr(), op.cleartext.GetSize(), out, &outSz, nullptr), 0);
651
652
704
        ret = component::Ciphertext(Buffer(out, outSz));
653
704
    } catch ( ... ) { }
654
655
2.00k
end:
656
2.00k
    util::free(out);
657
658
2.00k
    wolfCrypt_detail::UnsetGlobalDs();
659
2.00k
#endif
660
2.00k
    return ret;
661
1.50k
}
662
663
1.56k
std::optional<component::Cleartext> OpECIES_Decrypt_Generic(operation::ECIES_Decrypt& op) {
664
1.56k
    std::optional<component::Cleartext> ret = std::nullopt;
665
#if !defined(HAVE_ECC_ENCRYPT)
666
    (void)op;
667
#else
668
1.56k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
669
1.56k
    wolfCrypt_detail::SetGlobalDs(&ds);
670
1.56k
    uint8_t* out = nullptr;
671
672
1.56k
    CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC")));
673
1.14k
    CF_CHECK_EQ(op.iv, std::nullopt);
674
675
1.09k
    try {
676
1.09k
        ECCKey priv(ds), pub(ds);
677
1.09k
        word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF;
678
679
        /* Initialize private key */
680
1.09k
        {
681
1.09k
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
682
1.02k
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
683
956
            CF_CHECK_TRUE(priv.SetRNG());
684
956
        }
685
686
        /* Initialize public key */
687
0
        {
688
956
            std::optional<int> curveID;
689
956
            const char* name = nullptr;
690
691
956
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
692
693
956
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
694
695
956
            WC_CHECK_EQ(wc_ecc_import_raw(
696
905
                        pub.GetPtr(),
697
905
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
698
905
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
699
905
                        nullptr,
700
905
                        name), 0);
701
702
905
            CF_CHECK_TRUE(pub.SetRNG());
703
905
        }
704
705
0
        out = util::malloc(outSz);
706
707
905
        WC_CHECK_EQ(wc_ecc_decrypt(priv.GetPtr(), pub.GetPtr(), op.ciphertext.GetPtr(), op.ciphertext.GetSize(), out, &outSz, nullptr), 0);
708
709
326
        ret = component::Cleartext(Buffer(out, outSz));
710
326
    } catch ( ... ) { }
711
712
1.56k
end:
713
1.56k
    util::free(out);
714
715
1.56k
    wolfCrypt_detail::UnsetGlobalDs();
716
1.56k
#endif
717
1.56k
    return ret;
718
1.09k
}
719
720
1.13k
std::optional<component::Secret> OpECDH_Derive(operation::ECDH_Derive& op) {
721
1.13k
    std::optional<component::Secret> ret = std::nullopt;
722
1.13k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
723
1.13k
    wolfCrypt_detail::SetGlobalDs(&ds);
724
725
    /* try/catch because ECCKey constructor may throw if allocation fails */
726
1.13k
    try {
727
        /* TODO dynamic size */
728
1.13k
        uint8_t out[1024];
729
1.13k
        word32 outlen = sizeof(out);
730
1.13k
        ECCKey priv(ds), pub(ds);
731
732
        /* Initialize private key */
733
1.13k
        {
734
1.13k
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
735
887
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
736
818
            CF_CHECK_TRUE(priv.SetRNG());
737
818
        }
738
739
        /* Initialize public key */
740
0
        {
741
818
            std::optional<int> curveID;
742
818
            const char* name = nullptr;
743
744
818
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
745
746
818
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
747
748
818
            WC_CHECK_EQ(wc_ecc_import_raw(
749
729
                        pub.GetPtr(),
750
729
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
751
729
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
752
729
                        nullptr,
753
729
                        name), 0);
754
729
            WC_CHECK_EQ(wc_ecc_check_key(pub.GetPtr()), 0);
755
585
        }
756
757
585
        WC_CHECK_EQ(wc_ecc_shared_secret(priv.GetPtr(), pub.GetPtr(), out, &outlen), 0);
758
759
514
        ret = component::Secret(Buffer(out, outlen));
760
514
    } catch ( ... ) { }
761
762
1.13k
end:
763
1.13k
    wolfCrypt_detail::UnsetGlobalDs();
764
765
1.13k
    return ret;
766
1.13k
}
767
768
2.08k
std::optional<component::ECC_Point> OpECC_Point_Add(operation::ECC_Point_Add& op) {
769
2.08k
    std::optional<component::ECC_Point> ret = std::nullopt;
770
2.08k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
771
2.08k
    wolfCrypt_detail::SetGlobalDs(&ds);
772
773
2.08k
    std::optional<int> curveID;
774
2.08k
    int curveIdx;
775
2.08k
    const ecc_set_type* curve = nullptr;
776
777
2.08k
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
778
779
1.87k
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
780
1.77k
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
781
782
    /* try/catch because ECCPoint constructor may throw if allocation fails */
783
1.77k
    try {
784
1.77k
        ECCPoint res(ds, *curveID), a(ds, *curveID), b(ds, *curveID);
785
1.77k
        wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds);
786
1.77k
        mp_digit mp;
787
1.77k
        bool valid = false;
788
1.77k
        std::optional<bool> is_neg = std::nullopt;
789
790
        /* Set points */
791
1.77k
        CF_CHECK_TRUE(a.Set(op.a));
792
1.70k
        CF_CHECK_TRUE(b.Set(op.b));
793
794
1.65k
        valid = a.CurveCheck() && b.CurveCheck();
795
796
        /* Retrieve curve parameter */
797
1.65k
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
798
1.65k
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
799
800
1.65k
        is_neg = a.IsNeg(b, prime);
801
802
1.65k
        CF_CHECK_TRUE(a.ToProjective(prime));
803
1.57k
        CF_CHECK_TRUE(b.ToProjective(prime));
804
805
1.52k
        WC_CHECK_EQ(mp_montgomery_setup(prime.GetPtr(), &mp), MP_OKAY);
806
807
#if defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
808
        goto end;
809
#else
810
1.52k
        {
811
1.52k
            bool dbl = false;
812
1.52k
            bool safe = false;
813
814
1.52k
            if ( a.Compare(b) == MP_EQ ) {
815
411
                try { dbl = ds.Get<bool>(); } catch ( ... ) { }
816
411
            }
817
818
1.52k
#if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL))
819
1.52k
            try { safe = ds.Get<bool>(); } catch ( ... ) { }
820
1.52k
#endif
821
822
1.52k
            if ( safe ) {
823
#if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
824
                CF_UNREACHABLE();
825
#else
826
105
                int infinity;
827
828
105
                if ( dbl == true ) {
829
45
                    WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
830
60
                } else {
831
60
                    WC_CHECK_EQ(ecc_projective_add_point_safe(a.GetPtr(), b.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp, &infinity), 0);
832
52
                }
833
105
#endif
834
1.19k
            } else {
835
1.19k
                if ( dbl == true ) {
836
23
                    WC_CHECK_EQ(ecc_projective_dbl_point(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
837
1.17k
                } else {
838
1.17k
                    WC_CHECK_EQ(ecc_projective_add_point(a.GetPtr(), b.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
839
840
                    /* Do not return result if inputs are negations of the same point */
841
988
                    CF_CHECK_FALSE(is_neg && *is_neg);
842
944
                }
843
1.19k
            }
844
845
            /* Lock to prevent exporting the projective point */
846
1.04k
            res.Lock();
847
1.04k
        }
848
0
#endif
849
850
        /* To affine */
851
1.04k
        WC_CHECK_EQ(ecc_map(res.GetPtr(), prime.GetPtr(), mp), MP_OKAY);
852
853
        /* Only return the result if the input points are valid */
854
968
        CF_CHECK_TRUE(valid);
855
856
        /* Only return the result if the output point is valid */
857
133
        CF_CHECK_TRUE(res.CurveCheck());
858
859
122
        ret = res.ToBignumPair();
860
223
    } catch ( ... ) { }
861
862
2.08k
end:
863
2.08k
    wolfCrypt_detail::UnsetGlobalDs();
864
865
2.08k
    return ret;
866
1.77k
}
867
868
4.97k
std::optional<component::ECC_Point> OpECC_Point_Mul(operation::ECC_Point_Mul& op) {
869
4.97k
    std::optional<component::ECC_Point> ret = std::nullopt;
870
4.97k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
871
4.97k
    wolfCrypt_detail::SetGlobalDs(&ds);
872
873
4.97k
    std::optional<int> curveID;
874
4.97k
    int curveIdx;
875
4.97k
    const ecc_set_type* curve = nullptr;
876
877
4.97k
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
878
879
4.60k
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
880
4.21k
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
881
882
    /* try/catch because ECCPoint constructor may throw if allocation fails */
883
4.21k
    try {
884
4.21k
        ECCPoint res(ds, *curveID), a(ds, *curveID);
885
4.21k
        wolfCrypt_bignum::Bignum b(ds), Af(ds), prime(ds);
886
4.21k
        bool valid = false;
887
888
        /* Set point */
889
4.21k
        CF_CHECK_TRUE(a.Set(op.a));
890
4.09k
        valid = a.CurveCheck();
891
892
        /* Set multiplier */
893
4.09k
        CF_CHECK_EQ(b.Set(op.b.ToString(ds)), true);
894
895
        /* Retrieve curve parameters */
896
4.03k
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
897
4.03k
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
898
899
        /* Multiply */
900
4.03k
        WC_CHECK_EQ(wc_ecc_mulmod_ex(b.GetPtr(), a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), 1, nullptr), 0);
901
902
        /* Only return the result if the input point is valid */
903
3.11k
        CF_CHECK_TRUE(valid);
904
905
690
        ret = res.ToBignumPair();
906
690
    } catch ( ... ) { }
907
908
4.97k
end:
909
4.97k
    wolfCrypt_detail::UnsetGlobalDs();
910
911
4.97k
    return ret;
912
4.21k
}
913
914
0
std::optional<component::ECC_Point> OpECC_Point_Dbl(operation::ECC_Point_Dbl& op) {
915
0
    std::optional<component::ECC_Point> ret = std::nullopt;
916
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
917
0
    wolfCrypt_detail::SetGlobalDs(&ds);
918
919
0
    std::optional<int> curveID;
920
0
    int curveIdx;
921
0
    const ecc_set_type* curve = nullptr;
922
923
0
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
924
925
0
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
926
0
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
927
928
    /* try/catch because ECCPoint constructor may throw if allocation fails */
929
0
    try {
930
0
        ECCPoint res(ds, *curveID), a(ds, *curveID);
931
0
        wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds);
932
0
        mp_digit mp;
933
0
        bool valid = false;
934
935
        /* Set points */
936
0
        CF_CHECK_TRUE(a.Set(op.a));
937
938
0
        valid = a.CurveCheck();
939
940
        /* Retrieve curve parameter */
941
0
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
942
0
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
943
944
0
        CF_CHECK_TRUE(a.ToProjective(prime));
945
946
0
        WC_CHECK_EQ(mp_montgomery_setup(prime.GetPtr(), &mp), MP_OKAY);
947
948
#if defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
949
        goto end;
950
#else
951
0
        {
952
0
            bool safe = false;
953
954
0
#if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL))
955
0
            try { safe = ds.Get<bool>(); } catch ( ... ) { }
956
0
#endif
957
958
0
            if ( safe ) {
959
#if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
960
                CF_UNREACHABLE();
961
#else
962
0
                WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
963
0
#endif
964
0
            } else {
965
0
                WC_CHECK_EQ(ecc_projective_dbl_point(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
966
0
            }
967
968
            /* Lock to prevent exporting the projective point */
969
0
            res.Lock();
970
0
        }
971
0
#endif
972
973
        /* To affine */
974
0
        WC_CHECK_EQ(ecc_map(res.GetPtr(), prime.GetPtr(), mp), MP_OKAY);
975
976
        /* Only return the result if the input points are valid */
977
0
        CF_CHECK_TRUE(valid);
978
979
        /* Only return the result if the output point is valid */
980
0
        CF_CHECK_TRUE(res.CurveCheck());
981
982
0
        ret = res.ToBignumPair();
983
0
    } catch ( ... ) { }
984
985
0
end:
986
0
    wolfCrypt_detail::UnsetGlobalDs();
987
988
0
    return ret;
989
0
}
990
991
} /* namespace wolfCrypt_detail */
992
} /* namespace module */
993
} /* namespace cryptofuzz */