Coverage Report

Created: 2025-11-16 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cryptofuzz-fastmath/modules/wolfcrypt/ecdsa_generic.cpp
Line
Count
Source
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
23.8k
    ds(ds) {
24
23.8k
    if ( (key = wc_ecc_key_new(nullptr)) == nullptr ) {
25
2.24k
        throw std::exception();
26
2.24k
    }
27
23.8k
}
28
29
21.6k
ECCKey::~ECCKey() {
30
21.6k
    CF_NORET(wc_ecc_key_free(key));
31
21.6k
}
32
33
53.1k
ecc_key* ECCKey::GetPtr(void) {
34
53.1k
    uint8_t* x963 = nullptr;
35
53.1k
    ecc_key* newKey = nullptr;
36
37
53.1k
    bool exportToX963 = false;
38
53.1k
    try {
39
53.1k
        exportToX963 = ds.Get<bool>();
40
53.1k
    } catch ( ... ) { }
41
42
53.1k
    if ( exportToX963 == true ) {
43
5.51k
        CF_CHECK_NE(newKey = wc_ecc_key_new(nullptr), nullptr);
44
45
3.88k
        word32 outLen = 0;
46
47
3.88k
        bool compressed = false;
48
3.88k
        try { compressed  = ds.Get<bool>();} catch ( ... ) { }
49
50
7.18k
        WC_CHECK_EQ(wc_ecc_export_x963_ex(key, nullptr, &outLen, compressed), LENGTH_ONLY_E);
51
7.18k
        x963 = util::malloc(outLen);
52
7.18k
        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.68k
        int curveID;
56
1.68k
        CF_CHECK_NE(curveID = wc_ecc_get_curve_id(key->idx), ECC_CURVE_INVALID);
57
58
1.68k
        const bool valid = wc_ecc_check_key(key) == 0;
59
60
1.68k
        haveAllocFailure = false;
61
1.68k
        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
593
            CF_ASSERT((compressed && !valid) || haveAllocFailure, "Cannot import X963-exported ECC key");
68
593
            goto end;
69
593
        }
70
71
1.09k
        if ( compressed ) {
72
532
            CF_CHECK_TRUE(valid);
73
30
        }
74
75
589
        CF_NORET(wc_ecc_key_free(key));
76
589
        key = newKey;
77
589
        newKey = nullptr;
78
589
    }
79
80
53.1k
end:
81
53.1k
    util::free(x963);
82
53.1k
    CF_NORET(wc_ecc_key_free(newKey));
83
84
53.1k
    return key;
85
53.1k
}
86
87
9.16k
bool ECCKey::SetCurve(const Type& curveType) {
88
9.16k
    bool ret = false;
89
90
9.16k
#if !defined(WOLFSSL_SP_MATH)
91
9.16k
    bool useCustomCurve = false;
92
93
9.16k
    try {
94
9.16k
        useCustomCurve = ds.Get<uint8_t>();
95
9.16k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
96
9.16k
    useCustomCurve = false;
97
98
9.16k
    if ( useCustomCurve == false )
99
9.16k
#endif
100
9.16k
    {
101
#if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG)
102
        std::cout << "Using native curve" << std::endl;
103
#endif
104
9.16k
        std::optional<int> curveID;
105
106
9.16k
        CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(curveType), std::nullopt);
107
6.88k
        this->curveID = *curveID;
108
109
6.88k
        WC_CHECK_EQ(wc_ecc_set_curve(GetPtr(), 0, *curveID), 0);
110
6.88k
    }
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
6.88k
#endif
122
123
6.88k
    ret = true;
124
125
9.16k
end:
126
9.16k
    return ret;
127
6.88k
}
128
129
7.29k
bool ECCKey::LoadPrivateKey(const component::Bignum& priv) {
130
7.29k
    bool ret = false;
131
7.29k
    std::optional<std::vector<uint8_t>> priv_bytes;
132
133
7.29k
    CF_CHECK_NE(priv_bytes = wolfCrypt_bignum::Bignum::ToBin(ds, priv), std::nullopt);
134
135
6.96k
    WC_CHECK_EQ(wc_ecc_import_private_key_ex(priv_bytes->data(), priv_bytes->size(), nullptr, 0, GetPtr(), *curveID), 0);
136
137
6.09k
    ret = true;
138
139
7.29k
end:
140
7.29k
    return ret;
141
6.09k
}
142
143
3.96k
std::optional<ECCPoint> ECCKey::MakePub(void) {
144
3.96k
    std::optional<ECCPoint> ret = std::nullopt;
145
146
3.96k
    ECCPoint pub(ds, *curveID);
147
3.96k
    WC_CHECK_EQ(wc_ecc_make_pub(GetPtr(), pub.GetPtr()), 0);
148
3.61k
    pub.SetInitialized();
149
150
3.61k
    return pub;
151
152
343
end:
153
343
    return ret;
154
3.96k
}
155
156
3.39k
bool ECCKey::SetRNG(void) {
157
3.39k
    bool ret = false;
158
159
3.39k
    WC_CHECK_EQ(wc_ecc_set_rng(GetPtr(), wolfCrypt_detail::GetRNG()), 0);
160
161
3.39k
    ret = true;
162
3.39k
end:
163
3.39k
    return ret;
164
3.39k
}
165
166
ECCPoint::ECCPoint(Datasource& ds, const int curveID) :
167
27.1k
    ds(ds),
168
27.1k
    curveID(curveID) {
169
27.1k
    if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) {
170
906
        throw std::exception();
171
906
    }
172
27.1k
}
173
174
/* Copy constructor */
175
ECCPoint::ECCPoint(const ECCPoint& other) :
176
3.56k
    ds(other.ds),
177
3.56k
    curveID(other.curveID),
178
3.56k
    locked(other.locked),
179
3.56k
    initialized(other.initialized)
180
3.56k
{
181
3.56k
    if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) {
182
2
        throw std::exception();
183
2
    }
184
185
3.56k
    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
3.56k
}
190
191
29.7k
ECCPoint::~ECCPoint() {
192
29.7k
    CF_NORET(wc_ecc_del_point(point));
193
29.7k
}
194
195
35.9k
ecc_point* ECCPoint::GetPtr() {
196
35.9k
    uint8_t* out = nullptr;
197
35.9k
    ecc_point* newPoint = nullptr;
198
199
35.9k
    if ( locked == false && initialized == true ) {
200
7.26k
        bool exportToDER = false;
201
202
7.26k
        try {
203
7.26k
            exportToDER = ds.Get<bool>();
204
7.26k
        } catch ( ... ) { }
205
206
7.26k
        if ( exportToDER == true ) {
207
555
            bool compressed = false;
208
555
            try {
209
555
                compressed = ds.Get<bool>();
210
555
            } catch ( ... ) { }
211
212
555
            const int curveIdx = wc_ecc_get_curve_idx(curveID);
213
555
            CF_CHECK_NE(newPoint = wc_ecc_new_point_h(nullptr), nullptr);
214
215
432
            word32 outSz = 0xFFFF;
216
432
            try { outSz = ds.Get<word32>() & 0xFFFF; } catch ( ... ) { }
217
218
432
            out = util::malloc(outSz);
219
220
432
            if ( compressed == false ) {
221
254
                WC_CHECK_EQ(wc_ecc_export_point_der(curveIdx, point, out, &outSz), 0);
222
178
            } else {
223
178
                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
57
            }
226
227
154
            {
228
154
                haveAllocFailure = false;
229
154
                const bool success = wc_ecc_import_point_der(out, outSz, curveIdx, newPoint) == 0;
230
231
154
                if ( success ) {
232
                    /* Point imported. Replace old point with new point. */
233
234
151
                    CF_NORET(wc_ecc_del_point(point));
235
151
                    point = newPoint;
236
151
                    newPoint = nullptr;
237
151
                } else {
238
                    /* Failure */
239
240
3
                    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
3
                }
245
154
            }
246
154
        }
247
7.26k
    }
248
249
35.9k
end:
250
35.9k
    util::free(out);
251
35.9k
    CF_NORET(wc_ecc_del_point(newPoint));
252
253
35.9k
    return point;
254
35.9k
}
255
256
bool ECCPoint::Set(
257
        const component::BignumPair& xy,
258
        const uint64_t curveType,
259
        const bool pointCheck,
260
11.8k
        const bool mp_init_size_ok) {
261
11.8k
    bool ret = false;
262
263
11.8k
    bool projective = false;
264
11.8k
    try {
265
11.8k
        projective = ds.Get<bool>();
266
11.8k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
267
268
11.8k
    wolfCrypt_bignum::Bignum x(ds, mp_init_size_ok);
269
11.8k
    wolfCrypt_bignum::Bignum y(ds, mp_init_size_ok);
270
11.8k
    wolfCrypt_bignum::Bignum z(ds, mp_init_size_ok);
271
272
11.8k
    if ( projective == false ) {
273
6.65k
        CF_CHECK_TRUE(x.Set(xy.first));
274
6.53k
        CF_CHECK_TRUE(y.Set(xy.second));
275
6.44k
        CF_CHECK_TRUE(z.Set("1"));
276
6.43k
    } else {
277
5.16k
        const auto proj = util::ToRandomProjective(
278
5.16k
                ds,
279
5.16k
                xy.first.ToTrimmedString(),
280
5.16k
                xy.second.ToTrimmedString(),
281
5.16k
                curveType);
282
5.16k
        CF_CHECK_TRUE(x.Set(proj[0]));
283
4.27k
        CF_CHECK_TRUE(y.Set(proj[1]));
284
3.84k
        CF_CHECK_TRUE(z.Set(proj[2]));
285
3.66k
    }
286
287
20.1k
    WC_CHECK_EQ(mp_copy(x.GetPtr(), point->x), MP_OKAY);
288
20.1k
    WC_CHECK_EQ(mp_copy(y.GetPtr(), point->y), MP_OKAY);
289
10.0k
    WC_CHECK_EQ(mp_copy(z.GetPtr(), point->z), MP_OKAY);
290
291
10.0k
    if ( pointCheck ) {
292
0
        CF_CHECK_TRUE(CurveCheck());
293
0
    }
294
295
10.0k
    SetInitialized();
296
297
10.0k
    ret = true;
298
299
11.4k
end:
300
11.4k
    return ret;
301
10.0k
}
302
303
6.48k
bool ECCPoint::ToProjective(wolfCrypt_bignum::Bignum& prime) {
304
6.48k
    bool ret = false;
305
306
6.48k
    wolfCrypt_bignum::Bignum mu(ds);
307
308
6.48k
    WC_CHECK_EQ(mp_montgomery_calc_normalization(mu.GetPtr(), prime.GetPtr()), MP_OKAY);
309
310
6.41k
    if ( mp_cmp_d(mu.GetPtr(), 1) != MP_EQ ) {
311
5.36k
        WC_CHECK_EQ(mp_mulmod(point->x, mu.GetPtr(), prime.GetPtr(), point->x), MP_OKAY);
312
5.22k
        WC_CHECK_EQ(mp_mulmod(point->y, mu.GetPtr(), prime.GetPtr(), point->y), MP_OKAY);
313
5.17k
        WC_CHECK_EQ(mp_mulmod(point->z, mu.GetPtr(), prime.GetPtr(), point->z), MP_OKAY);
314
5.13k
    }
315
316
    /* Lock so it isn't attempted to export/import the projective point in GetPtr(),
317
     * which will lead to incorrect results
318
     */
319
6.17k
    Lock();
320
321
6.17k
    ret = true;
322
323
6.48k
end:
324
6.48k
    return ret;
325
6.17k
}
326
327
8.43k
bool ECCPoint::CurveCheck(void) const {
328
8.43k
    const int curveIdx = wc_ecc_get_curve_idx(curveID);
329
8.43k
    return wc_ecc_point_is_on_curve(point, curveIdx) == 0;
330
8.43k
}
331
332
13.9k
void ECCPoint::Lock(void) {
333
13.9k
    locked = true;
334
13.9k
}
335
336
13.2k
void ECCPoint::SetInitialized(void) {
337
13.2k
    initialized = true;
338
13.2k
}
339
340
3.54k
std::optional<component::BignumPair> ECCPoint::ToBignumPair(void) {
341
3.54k
    std::optional<component::BignumPair> ret = std::nullopt;
342
343
3.54k
    wolfCrypt_bignum::Bignum pub_x(GetPtr()->x, ds);
344
345
    /* Pointer is stored in pub_x; lock to prevent UAF */
346
3.54k
    Lock();
347
348
3.54k
    wolfCrypt_bignum::Bignum pub_y(GetPtr()->y, ds);
349
350
3.54k
    std::optional<std::string> pub_x_str, pub_y_str;
351
3.54k
    CF_CHECK_NE(pub_x_str = pub_x.ToDecString(), std::nullopt);
352
3.53k
    CF_CHECK_NE(pub_y_str = pub_y.ToDecString(), std::nullopt);
353
354
3.52k
    ret = { *pub_x_str, *pub_y_str };
355
3.54k
end:
356
357
3.54k
    return ret;
358
3.52k
}
359
360
1.53k
int ECCPoint::Compare(ECCPoint& other) {
361
1.53k
    return wc_ecc_cmp_point(GetPtr(), other.GetPtr());
362
1.53k
}
363
364
1.70k
std::optional<bool> ECCPoint::IsNeg(ECCPoint& other, wolfCrypt_bignum::Bignum& prime) {
365
1.70k
    std::optional<bool> ret = std::nullopt;
366
367
1.70k
    wolfCrypt_bignum::Bignum neg(ds);
368
1.70k
    if ( mp_sub(prime.GetPtr(), other.GetPtr()->y, neg.GetPtr()) == MP_OKAY) {
369
1.62k
        ret = static_cast<bool>(mp_cmp(point->y, neg.GetPtr()) == MP_EQ);
370
1.62k
    }
371
372
1.70k
    return ret;
373
1.70k
}
374
375
3.68k
std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Generic(operation::ECC_PrivateToPublic& op) {
376
3.68k
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
377
3.68k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
378
3.68k
    wolfCrypt_detail::SetGlobalDs(&ds);
379
380
3.68k
    try {
381
3.68k
        ECCKey key(ds);
382
383
        /* Initialize */
384
3.68k
        {
385
3.68k
            CF_CHECK_EQ(key.SetCurve(op.curveType), true);
386
2.28k
            CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true);
387
1.56k
        }
388
389
        /* Process/Finalize */
390
0
        {
391
1.56k
            auto pub = key.MakePub();
392
1.56k
            CF_CHECK_NE(pub, std::nullopt);
393
394
1.38k
            ret = pub->ToBignumPair();
395
1.38k
        }
396
1.38k
    } catch ( ... ) { }
397
398
3.68k
end:
399
400
3.68k
    wolfCrypt_detail::UnsetGlobalDs();
401
3.68k
    return ret;
402
3.68k
}
403
404
5.69k
std::optional<bool> OpECC_ValidatePubkey_Generic(operation::ECC_ValidatePubkey& op) {
405
5.69k
    std::optional<bool> ret = std::nullopt;
406
5.69k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
407
5.69k
    wolfCrypt_detail::SetGlobalDs(&ds);
408
409
5.69k
    std::optional<int> curveID;
410
411
5.69k
    try {
412
5.69k
        ECCKey key(ds);
413
5.69k
        {
414
5.69k
            const char* name = nullptr;
415
416
5.69k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
417
418
4.75k
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
419
420
4.75k
            WC_CHECK_EQ(wc_ecc_import_raw(
421
4.22k
                        key.GetPtr(),
422
4.22k
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
423
4.22k
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
424
4.22k
                        nullptr,
425
4.22k
                        name), 0);
426
4.22k
            haveAllocFailure = false;
427
4.22k
            ret = wc_ecc_check_key(key.GetPtr()) == 0;
428
4.22k
            if ( *ret == false && haveAllocFailure == true ) {
429
623
                ret = std::nullopt;
430
623
            }
431
4.22k
        }
432
4.22k
    } catch ( ... ) { }
433
434
5.69k
end:
435
436
5.69k
    wolfCrypt_detail::UnsetGlobalDs();
437
5.69k
    return ret;
438
5.69k
}
439
440
4.10k
std::optional<bool> OpECDSA_Verify_Generic(operation::ECDSA_Verify& op) {
441
    /* These are currently not supported by wc_Hash
442
     * See also ZD 16119
443
     */
444
4.10k
    switch ( op.digestType.Get() ) {
445
0
        case CF_DIGEST("MD2"):
446
0
        case CF_DIGEST("MD4"):
447
0
        case CF_DIGEST("BLAKE2B512"):
448
0
        case CF_DIGEST("BLAKE2S256"):
449
0
        case CF_DIGEST("SHA3-224"):
450
0
        case CF_DIGEST("SHA3-256"):
451
0
        case CF_DIGEST("SHA3-384"):
452
0
        case CF_DIGEST("SHA3-512"):
453
0
            return std::nullopt;
454
4.10k
    }
455
456
4.10k
    std::optional<bool> ret = std::nullopt;
457
4.10k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
458
4.10k
    wolfCrypt_detail::SetGlobalDs(&ds);
459
460
4.10k
    std::optional<int> curveID;
461
4.10k
    uint8_t* sig = nullptr;
462
4.10k
    uint8_t* hash = nullptr;
463
4.10k
    word32 sigSz = ECC_MAX_SIG_SIZE;
464
4.10k
    int verify;
465
466
4.10k
    bool ctIsEmpty = false;
467
4.10k
    bool randomSigSz = false;
468
4.10k
    bool hashNotFound = false;
469
470
4.10k
    {
471
4.10k
        try {
472
4.10k
            randomSigSz = ds.Get<bool>();
473
4.10k
            if ( randomSigSz ) {
474
873
                sigSz = ds.Get<uint8_t>();
475
873
            }
476
4.10k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
477
478
4.10k
        sig = util::malloc(sigSz);
479
4.10k
    }
480
481
4.10k
    try {
482
4.10k
        ECCKey key(ds);
483
4.10k
        {
484
4.10k
            const char* name = nullptr;
485
486
4.10k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
487
488
3.63k
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
489
490
3.63k
            haveAllocFailure = false;
491
3.63k
            ret = false;
492
493
3.63k
            WC_CHECK_EQ(wc_ecc_import_raw(
494
3.49k
                        key.GetPtr(),
495
3.49k
                        util::DecToHex(op.signature.pub.first.ToTrimmedString()).c_str(),
496
3.49k
                        util::DecToHex(op.signature.pub.second.ToTrimmedString()).c_str(),
497
3.49k
                        nullptr,
498
3.49k
                        name), 0);
499
3.49k
            WC_CHECK_EQ(wc_ecc_check_key(key.GetPtr()), 0);
500
3.20k
        }
501
502
3.20k
        WC_CHECK_EQ(wc_ecc_rs_to_sig(
503
2.91k
                    util::DecToHex(op.signature.signature.first.ToTrimmedString()).c_str(),
504
2.91k
                    util::DecToHex(op.signature.signature.second.ToTrimmedString()).c_str(),
505
2.91k
                    sig, &sigSz), 0);
506
507
2.91k
        if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
508
2.51k
            const auto CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
509
2.51k
            ctIsEmpty = CT.GetSize() == 0;
510
2.51k
            WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0);
511
2.12k
        } else {
512
398
            std::optional<wc_HashType> hashType;
513
398
            hashNotFound = true;
514
398
            CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt);
515
398
            hashNotFound = false;
516
517
398
            const auto hashSize = wc_HashGetDigestSize(*hashType);
518
398
            hash = util::malloc(hashSize);
519
520
398
            WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0);
521
522
398
            const auto CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType);
523
398
            ctIsEmpty = CT.GetSize() == 0;
524
398
            WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0);
525
398
        }
526
527
2.52k
        ret = verify ? true : false;
528
2.52k
    } catch ( ... ) { }
529
530
4.10k
end:
531
532
4.10k
    util::free(sig);
533
4.10k
    util::free(hash);
534
535
4.10k
    wolfCrypt_detail::UnsetGlobalDs();
536
537
4.10k
    if ( ret && *ret == false ) {
538
1.41k
        if ( haveAllocFailure ) {
539
294
            ret = std::nullopt;
540
1.11k
        } else if ( randomSigSz ) {
541
243
            ret = std::nullopt;
542
875
        } else if ( ctIsEmpty ) {
543
            /* wolfCrypt ECDSA verification will fail if the input msg is empty */
544
47
            ret = std::nullopt;
545
828
        } else if ( hashNotFound ) {
546
0
            ret = std::nullopt;
547
828
        } else if ( op.digestType.Is(CF_DIGEST("NULL")) && op.cleartext.IsZero() ) {
548
120
            ret = std::nullopt;
549
120
        }
550
1.41k
    }
551
552
4.10k
    return ret;
553
4.10k
}
554
555
489
std::optional<component::ECCSI_Signature> OpECCSI_Sign(operation::ECCSI_Sign& op) {
556
#if !defined(WOLFCRYPT_HAVE_ECCSI)
557
    (void)op;
558
    return std::nullopt;
559
#else
560
489
    std::optional<component::ECCSI_Signature> ret = std::nullopt;
561
562
489
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
563
489
    wolfCrypt_detail::SetGlobalDs(&ds);
564
565
489
    uint8_t hashSz = WC_MAX_DIGEST_SIZE;
566
489
    static_assert(WC_MAX_DIGEST_SIZE < 256);
567
568
489
    uint8_t* hash = util::malloc(hashSz);
569
570
489
    uint8_t* encoded = nullptr;
571
489
    EccsiKey eccsi;
572
489
    bool eccsi_initialized = false;
573
574
489
    try {
575
489
        int size;
576
489
        std::optional<component::BignumPair> pubbn = std::nullopt;
577
578
489
        {
579
            /* Private to public */
580
489
            ECCKey key(ds);
581
489
            CF_CHECK_EQ(key.SetCurve(op.curveType), true);
582
409
            CF_CHECK_GT(size = key.GetPtr()->dp->size, 0);
583
409
            CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true);
584
314
            auto pub = key.MakePub();
585
314
            CF_CHECK_NE(pub, std::nullopt);
586
256
            CF_CHECK_NE(pubbn = pub->ToBignumPair(), std::nullopt);
587
588
            /* Encode private and public */
589
253
            encoded = util::malloc(size * 3);
590
591
253
            WC_CHECK_EQ(mp_to_unsigned_bin_len(key.GetPtr()->k, encoded, size), 0);
592
220
            WC_CHECK_EQ(mp_to_unsigned_bin_len(pub->GetPtr()->x, encoded + size, size), 0);
593
220
            WC_CHECK_EQ(mp_to_unsigned_bin_len(pub->GetPtr()->y, encoded + (size * 2), size), 0);
594
220
        }
595
596
0
        {
597
220
            std::optional<int> curveId;
598
220
            CF_CHECK_NE(curveId = toCurveID(op.curveType), std::nullopt);
599
600
220
            WC_CHECK_EQ(wc_InitEccsiKey_ex(&eccsi, size, *curveId, nullptr, -1), 0);
601
219
            eccsi_initialized = true;
602
603
219
            WC_CHECK_EQ(wc_ImportEccsiKey(&eccsi, encoded, size * 3), 0);
604
219
            {
605
219
                uint8_t sig[257]; /* XXX random size */
606
219
                word32 sigSz = sizeof(sig);
607
219
                ECCPoint pvt(ds, *curveId);
608
219
                wolfCrypt_bignum::Bignum ssk(ds);
609
219
                std::optional<wc_HashType> hashType;
610
219
                CF_CHECK_NE(hashType = toHashType(op.digestType), std::nullopt);
611
104
                WC_CHECK_EQ(wc_MakeEccsiPair(
612
104
                            &eccsi,
613
104
                            &rng,
614
104
                            *hashType,
615
104
                            op.id.GetPtr(),
616
104
                            op.id.GetSize(),
617
104
                            ssk.GetPtr(),
618
104
                            pvt.GetPtr()), 0);
619
104
                WC_CHECK_EQ(wc_HashEccsiId(
620
104
                            &eccsi,
621
104
                            *hashType,
622
104
                            op.id.GetPtr(),
623
104
                            op.id.GetSize(),
624
104
                            pvt.GetPtr(),
625
104
                            hash,
626
104
                            &hashSz), 0);
627
104
                WC_CHECK_EQ(wc_SetEccsiHash(&eccsi, hash, hashSz), 0);
628
104
                WC_CHECK_EQ(wc_SetEccsiPair(&eccsi, ssk.GetPtr(), pvt.GetPtr()), 0);
629
104
                WC_CHECK_EQ(wc_SignEccsiHash(
630
104
                            &eccsi,
631
104
                            &rng,
632
104
                            *hashType,
633
104
                            op.cleartext.GetPtr(),
634
104
                            op.cleartext.GetSize(),
635
104
                            sig, &sigSz), 0);
636
104
                CF_ASSERT(sigSz == static_cast<size_t>(size) * 4 + 1, "Unexpected signature size");
637
104
                {
638
104
                    wolfCrypt_bignum::Bignum r(ds), s(ds);
639
104
                    std::optional<std::string> r_str, s_str;
640
104
                    std::optional<component::BignumPair> pvtbn = std::nullopt;
641
642
104
                    WC_CHECK_EQ(mp_read_unsigned_bin(r.GetPtr(), sig, size), 0);
643
104
                    CF_CHECK_NE(r_str = r.ToDecString(), std::nullopt);
644
645
104
                    WC_CHECK_EQ(mp_read_unsigned_bin(s.GetPtr(), sig + size, size), 0);
646
104
                    CF_CHECK_NE(s_str = s.ToDecString(), std::nullopt);
647
648
104
                    CF_CHECK_NE(pvtbn = pvt.ToBignumPair(), std::nullopt);
649
650
104
                    ret = component::ECCSI_Signature{
651
104
                        component::BignumPair{*r_str, *s_str},
652
104
                        *pubbn,
653
104
                        *pvtbn};
654
104
                }
655
104
            }
656
104
        }
657
104
    } catch ( ... ) { }
658
659
489
end:
660
489
    if ( eccsi_initialized ) {
661
116
        CF_NORET(wc_FreeEccsiKey(&eccsi));
662
116
    }
663
489
    util::free(hash);
664
489
    util::free(encoded);
665
489
    wolfCrypt_detail::UnsetGlobalDs();
666
489
    return ret;
667
489
#endif
668
489
}
669
670
123
std::optional<bool> OpECCSI_Verify(operation::ECCSI_Verify& op) {
671
#if !defined(WOLFCRYPT_HAVE_ECCSI)
672
    (void)op;
673
    return std::nullopt;
674
#else
675
123
    std::optional<bool> ret = std::nullopt;
676
123
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
677
123
    wolfCrypt_detail::SetGlobalDs(&ds);
678
679
123
    uint8_t hashSz = WC_MAX_DIGEST_SIZE;
680
123
    static_assert(WC_MAX_DIGEST_SIZE < 256);
681
682
123
    EccsiKey eccsi;
683
684
123
    uint8_t* hash = util::malloc(hashSz);
685
123
    std::optional<wc_HashType> hashType;
686
123
    std::optional<int> curveId;
687
123
    std::vector<uint8_t> pub, sig;
688
123
    int verified;
689
123
    int size;
690
123
    bool eccsi_initialized = false;
691
692
123
    CF_CHECK_NE(curveId = toCurveID(op.curveType), std::nullopt);
693
61
    CF_CHECK_NE(hashType = toHashType(op.digestType), std::nullopt);
694
695
0
    haveAllocFailure = false;
696
0
    ret = false;
697
698
0
    try {
699
0
    {
700
0
        ECCKey key(ds);
701
0
        CF_CHECK_EQ(key.SetCurve(op.curveType), true);
702
0
        CF_CHECK_GT(size = key.GetPtr()->dp->size, 0);
703
0
    }
704
705
    /* Pub to binary */
706
0
    {
707
0
        const auto x = op.signature.pub.first.ToBin(size);
708
0
        CF_CHECK_NE(x, std::nullopt);
709
0
        pub.insert(pub.end(), x->begin(), x->end());
710
711
0
        const auto y = op.signature.pub.second.ToBin(size);
712
0
        CF_CHECK_NE(y, std::nullopt);
713
0
        pub.insert(pub.end(), y->begin(), y->end());
714
0
    }
715
716
    /* Sig to binary */
717
0
    {
718
0
        const auto r = op.signature.signature.first.ToBin(size);
719
0
        CF_CHECK_NE(r, std::nullopt);
720
0
        sig.insert(sig.end(), r->begin(), r->end());
721
722
0
        const auto s = op.signature.signature.second.ToBin(size);
723
0
        CF_CHECK_NE(s, std::nullopt);
724
0
        sig.insert(sig.end(), s->begin(), s->end());
725
726
0
        sig.push_back(0x04);
727
728
0
        const auto pvt_x = op.signature.pvt.first.ToBin(size);
729
0
        CF_CHECK_NE(pvt_x, std::nullopt);
730
0
        sig.insert(sig.end(), pvt_x->begin(), pvt_x->end());
731
732
0
        const auto pvt_y = op.signature.pvt.second.ToBin(size);
733
0
        CF_CHECK_NE(pvt_y, std::nullopt);
734
0
        sig.insert(sig.end(), pvt_y->begin(), pvt_y->end());
735
0
    }
736
737
0
    {
738
0
        ECCPoint pvt(ds, *curveId);
739
740
0
        WC_CHECK_EQ(wc_InitEccsiKey_ex(&eccsi, size, *curveId, nullptr, -1), 0);
741
0
        eccsi_initialized = true;
742
743
0
        WC_CHECK_EQ(wc_ImportEccsiPublicKey(&eccsi,
744
0
                    pub.data(), pub.size(), 0), 0);
745
0
        WC_CHECK_EQ(wc_DecodeEccsiPvtFromSig(&eccsi, sig.data(), sig.size(), pvt.GetPtr()), 0);
746
0
        WC_CHECK_EQ(wc_HashEccsiId(
747
0
                    &eccsi,
748
0
                    *hashType,
749
0
                    op.id.GetPtr(&ds), op.id.GetSize(),
750
0
                    pvt.GetPtr(),
751
0
                    hash,
752
0
                    &hashSz), 0);
753
0
        WC_CHECK_EQ(wc_SetEccsiHash(&eccsi, hash, hashSz), 0);
754
0
        WC_CHECK_EQ(wc_VerifyEccsiHash(
755
0
                    &eccsi,
756
0
                    *hashType,
757
0
                    op.cleartext.GetPtr(&ds), op.cleartext.GetSize(),
758
0
                    sig.data(), sig.size(),
759
0
                    &verified), 0);
760
0
        ret = verified == 1;
761
0
    }
762
0
    } catch ( ... ) { }
763
764
123
end:
765
123
    if ( eccsi_initialized ) {
766
0
        CF_NORET(wc_FreeEccsiKey(&eccsi));
767
0
    }
768
123
    util::free(hash);
769
123
    wolfCrypt_detail::UnsetGlobalDs();
770
123
    if ( ret && *ret == false ) {
771
0
        if ( haveAllocFailure ) {
772
0
            ret = std::nullopt;
773
0
        }
774
0
    }
775
123
    return ret;
776
0
#endif
777
0
}
778
779
4.24k
std::optional<component::ECDSA_Signature> OpECDSA_Sign_Generic(operation::ECDSA_Sign& op) {
780
4.24k
    std::optional<component::ECDSA_Signature> ret = std::nullopt;
781
4.24k
    if ( op.UseRandomNonce() == false && op.UseSpecifiedNonce() == false ) {
782
364
        return ret;
783
364
    }
784
785
3.88k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
786
3.88k
    wolfCrypt_detail::SetGlobalDs(&ds);
787
788
3.88k
    uint8_t* sig = nullptr;
789
3.88k
    word32 sigSz = ECC_MAX_SIG_SIZE;
790
3.88k
    Buffer CT;
791
3.88k
    uint8_t* hash = nullptr;
792
3.88k
    size_t hashSize = 0;
793
3.88k
    uint8_t* nonce_bytes = nullptr;
794
3.88k
    wolfCrypt_bignum::Bignum nonce(ds);
795
796
    /* Initialize r, s using mp_init(), not mp_init_size(),
797
     * as the latter is not compatible with DecodeECC_DSA_Sig().
798
     *
799
     * See ZD 15728.
800
     */
801
3.88k
    wolfCrypt_bignum::Bignum r(ds, false), s(ds, false);
802
803
3.88k
    CF_CHECK_NE(op.priv.ToTrimmedString(), "0");
804
805
3.71k
    {
806
3.71k
        try {
807
3.71k
            sigSz = ds.Get<uint8_t>();
808
3.71k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
809
810
3.71k
        sig = util::malloc(sigSz);
811
3.71k
    }
812
813
3.71k
    try {
814
3.71k
        ECCKey key(ds);
815
3.71k
        CF_CHECK_EQ(key.SetCurve(op.curveType), true);
816
3.19k
        CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true);
817
3.04k
        key.GetPtr()->type = ECC_PRIVATEKEY_ONLY;
818
819
3.04k
        if ( op.UseSpecifiedNonce() == true ) {
820
1.21k
            CF_CHECK_EQ(nonce.Set(op.nonce.ToString(ds)), true);
821
822
1.18k
            const size_t nonce_bytes_size = mp_unsigned_bin_size(nonce.GetPtr());
823
824
            /* Convert nonce to byte array */
825
1.18k
            nonce_bytes = util::malloc(nonce_bytes_size);
826
1.18k
            CF_CHECK_EQ(mp_to_unsigned_bin(nonce.GetPtr(), nonce_bytes), 0);
827
828
            /* Set nonce */
829
1.16k
            WC_CHECK_EQ(wc_ecc_sign_set_k(nonce_bytes, nonce_bytes_size, key.GetPtr()), 0);
830
1.02k
        }
831
832
2.85k
        auto pub = key.MakePub();
833
2.85k
        CF_CHECK_NE(pub, std::nullopt);
834
835
2.74k
        if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
836
2.40k
            CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
837
2.40k
        } else {
838
343
            std::optional<wc_HashType> hashType;
839
343
            CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt);
840
841
343
            hashSize = wc_HashGetDigestSize(*hashType);
842
343
            hash = util::malloc(hashSize);
843
844
343
            WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0);
845
846
343
            CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType);
847
343
        }
848
849
        /* Sign */
850
4.99k
        WC_CHECK_EQ(wc_ecc_sign_hash(CT.GetPtr(), CT.GetSize(), sig, &sigSz, wolfCrypt_detail::GetRNG(), key.GetPtr()), 0);
851
852
        /* Verify */
853
4.99k
        {
854
4.99k
            int verify;
855
4.99k
            haveAllocFailure = false;
856
4.99k
            if ( wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()) == 0 && haveAllocFailure == false ) {
857
1.88k
                CF_ASSERT(verify, "Cannot verify generated signature");
858
1.88k
            }
859
4.99k
        }
860
861
2.24k
        CF_CHECK_EQ(DecodeECC_DSA_Sig(sig, sigSz, r.GetPtr(), s.GetPtr()), 0);
862
2.24k
        {
863
2.24k
            std::optional<std::string> r_str, s_str;
864
865
2.24k
            if ( op.curveType.Get() == CF_ECC_CURVE("secp256k1") ) {
866
222
                wolfCrypt_bignum::Bignum SMax(ds);
867
222
                CF_CHECK_EQ(SMax.Set("57896044618658097711785492504343953926418782139537452191302581570759080747168"), true);
868
222
                if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) {
869
115
                    wolfCrypt_bignum::Bignum SSub(ds);
870
115
                    CF_CHECK_EQ(SSub.Set("115792089237316195423570985008687907852837564279074904382605163141518161494337"), true);
871
115
                    CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0);
872
115
                }
873
2.02k
            } else if ( op.curveType.Get() == CF_ECC_CURVE("secp256r1") ) {
874
357
                wolfCrypt_bignum::Bignum SMax(ds);
875
357
                CF_CHECK_EQ(SMax.Set("57896044605178124381348723474703786764998477612067880171211129530534256022184"), true);
876
357
                if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) {
877
190
                    wolfCrypt_bignum::Bignum SSub(ds);
878
190
                    CF_CHECK_EQ(SSub.Set("115792089210356248762697446949407573529996955224135760342422259061068512044369"), true);
879
190
                    CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0);
880
190
                }
881
357
            }
882
883
2.24k
            CF_CHECK_NE(r_str = r.ToDecString(), std::nullopt);
884
2.24k
            CF_CHECK_NE(s_str = s.ToDecString(), std::nullopt);
885
886
2.24k
            const auto pub2 = pub->ToBignumPair();
887
2.24k
            CF_CHECK_NE(pub2, std::nullopt);
888
889
2.23k
            ret = component::ECDSA_Signature({*r_str, *s_str}, *pub2);
890
2.23k
        }
891
2.23k
    } catch ( ... ) { }
892
3.88k
end:
893
894
3.88k
    util::free(sig);
895
3.88k
    util::free(hash);
896
3.88k
    util::free(nonce_bytes);
897
898
3.88k
    wolfCrypt_detail::UnsetGlobalDs();
899
900
3.88k
    return ret;
901
3.71k
}
902
903
1.64k
std::optional<component::Ciphertext> OpECIES_Encrypt_Generic(operation::ECIES_Encrypt& op) {
904
1.64k
    std::optional<component::Ciphertext> ret = std::nullopt;
905
#if !defined(HAVE_ECC_ENCRYPT)
906
    (void)op;
907
#else
908
1.64k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
909
1.64k
    wolfCrypt_detail::SetGlobalDs(&ds);
910
1.64k
    uint8_t* out = nullptr;
911
912
1.64k
    CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC")));
913
1.11k
    CF_CHECK_EQ(op.iv, std::nullopt);
914
915
1.08k
    try {
916
1.08k
        ECCKey priv(ds), pub(ds);
917
1.08k
        word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF;
918
919
        /* Initialize private key */
920
1.08k
        {
921
1.08k
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
922
1.02k
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
923
944
            CF_CHECK_TRUE(priv.SetRNG());
924
944
        }
925
926
        /* Initialize public key */
927
0
        {
928
944
            std::optional<int> curveID;
929
944
            const char* name = nullptr;
930
931
944
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
932
933
944
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
934
935
944
            WC_CHECK_EQ(wc_ecc_import_raw(
936
903
                        pub.GetPtr(),
937
903
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
938
903
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
939
903
                        nullptr,
940
903
                        name), 0);
941
942
903
            CF_CHECK_TRUE(pub.SetRNG());
943
903
        }
944
945
0
        out = util::malloc(outSz);
946
947
903
        WC_CHECK_EQ(wc_ecc_encrypt(priv.GetPtr(), pub.GetPtr(), op.cleartext.GetPtr(), op.cleartext.GetSize(), out, &outSz, nullptr), 0);
948
949
552
        ret = component::Ciphertext(Buffer(out, outSz));
950
552
    } catch ( ... ) { }
951
952
1.64k
end:
953
1.64k
    util::free(out);
954
955
1.64k
    wolfCrypt_detail::UnsetGlobalDs();
956
1.64k
#endif
957
1.64k
    return ret;
958
1.08k
}
959
960
1.85k
std::optional<component::Cleartext> OpECIES_Decrypt_Generic(operation::ECIES_Decrypt& op) {
961
1.85k
    std::optional<component::Cleartext> ret = std::nullopt;
962
#if !defined(HAVE_ECC_ENCRYPT)
963
    (void)op;
964
#else
965
1.85k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
966
1.85k
    wolfCrypt_detail::SetGlobalDs(&ds);
967
1.85k
    uint8_t* out = nullptr;
968
969
1.85k
    CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC")));
970
1.36k
    CF_CHECK_EQ(op.iv, std::nullopt);
971
972
1.35k
    try {
973
1.35k
        ECCKey priv(ds), pub(ds);
974
1.35k
        word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF;
975
976
        /* Initialize private key */
977
1.35k
        {
978
1.35k
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
979
1.29k
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
980
1.21k
            CF_CHECK_TRUE(priv.SetRNG());
981
1.21k
        }
982
983
        /* Initialize public key */
984
0
        {
985
1.21k
            std::optional<int> curveID;
986
1.21k
            const char* name = nullptr;
987
988
1.21k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
989
990
1.21k
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
991
992
1.21k
            WC_CHECK_EQ(wc_ecc_import_raw(
993
1.15k
                        pub.GetPtr(),
994
1.15k
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
995
1.15k
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
996
1.15k
                        nullptr,
997
1.15k
                        name), 0);
998
999
1.15k
            CF_CHECK_TRUE(pub.SetRNG());
1000
1.15k
        }
1001
1002
0
        out = util::malloc(outSz);
1003
1004
1.15k
        WC_CHECK_EQ(wc_ecc_decrypt(priv.GetPtr(), pub.GetPtr(), op.ciphertext.GetPtr(), op.ciphertext.GetSize(), out, &outSz, nullptr), 0);
1005
1006
316
        ret = component::Cleartext(Buffer(out, outSz));
1007
316
    } catch ( ... ) { }
1008
1009
1.85k
end:
1010
1.85k
    util::free(out);
1011
1012
1.85k
    wolfCrypt_detail::UnsetGlobalDs();
1013
1.85k
#endif
1014
1.85k
    return ret;
1015
1.35k
}
1016
1017
872
std::optional<component::Secret> OpECDH_Derive(operation::ECDH_Derive& op) {
1018
872
    std::optional<component::Secret> ret = std::nullopt;
1019
872
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1020
872
    wolfCrypt_detail::SetGlobalDs(&ds);
1021
1022
    /* try/catch because ECCKey constructor may throw if allocation fails */
1023
872
    try {
1024
        /* TODO dynamic size */
1025
872
        uint8_t out[1024];
1026
872
        word32 outlen = sizeof(out);
1027
872
        ECCKey priv(ds), pub(ds);
1028
1029
        /* Initialize private key */
1030
872
        {
1031
872
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
1032
688
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
1033
616
            CF_CHECK_TRUE(priv.SetRNG());
1034
616
            WC_CHECK_EQ(
1035
616
                    wc_ecc_set_flags(priv.GetPtr(), WC_ECC_FLAG_COFACTOR), 0);
1036
616
        }
1037
1038
        /* Initialize public key */
1039
0
        {
1040
616
            std::optional<int> curveID;
1041
616
            const char* name = nullptr;
1042
1043
616
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
1044
1045
616
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
1046
1047
616
            WC_CHECK_EQ(wc_ecc_import_raw(
1048
522
                        pub.GetPtr(),
1049
522
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
1050
522
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
1051
522
                        nullptr,
1052
522
                        name), 0);
1053
522
            WC_CHECK_EQ(wc_ecc_check_key(pub.GetPtr()), 0);
1054
408
        }
1055
1056
408
        WC_CHECK_EQ(wc_ecc_shared_secret(priv.GetPtr(), pub.GetPtr(), out, &outlen), 0);
1057
1058
375
        ret = component::Secret(Buffer(out, outlen));
1059
375
    } catch ( ... ) { }
1060
1061
872
end:
1062
872
    wolfCrypt_detail::UnsetGlobalDs();
1063
1064
872
    return ret;
1065
872
}
1066
1067
2.39k
std::optional<component::ECC_Point> OpECC_Point_Add(operation::ECC_Point_Add& op) {
1068
2.39k
    std::optional<component::ECC_Point> ret = std::nullopt;
1069
2.39k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1070
2.39k
    wolfCrypt_detail::SetGlobalDs(&ds);
1071
1072
2.39k
    std::optional<int> curveID;
1073
2.39k
    int curveIdx;
1074
2.39k
    const ecc_set_type* curve = nullptr;
1075
2.39k
    bool failed = false;
1076
2.39k
    bool valid = false;
1077
2.39k
    std::optional<bool> is_neg = std::nullopt;
1078
1079
2.39k
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
1080
1081
2.10k
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
1082
2.10k
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
1083
1084
    /* try/catch because ECCPoint constructor may throw if allocation fails */
1085
2.10k
    try {
1086
2.10k
        ECCPoint res(ds, *curveID), a(ds, *curveID), b(ds, *curveID);
1087
2.10k
        wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds);
1088
2.10k
        mp_digit mp;
1089
1090
        /* Set points */
1091
2.10k
        CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get()));
1092
1.93k
        CF_CHECK_TRUE(b.Set(op.b, op.curveType.Get()));
1093
1094
1.80k
        valid = a.CurveCheck() && b.CurveCheck();
1095
1096
        /* Retrieve curve parameter */
1097
1.80k
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
1098
1.77k
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
1099
1100
1.73k
        is_neg = a.IsNeg(b, prime);
1101
1102
1.73k
        CF_CHECK_TRUE(a.ToProjective(prime));
1103
1.62k
        CF_CHECK_TRUE(b.ToProjective(prime));
1104
1105
1.58k
        WC_CHECK_EQ(mp_montgomery_setup(prime.GetPtr(), &mp), MP_OKAY);
1106
1107
#if defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
1108
        goto end;
1109
#else
1110
1.58k
        {
1111
1.58k
            bool dbl = false;
1112
1.58k
            bool safe = false;
1113
1114
1.58k
            if ( a.Compare(b) == MP_EQ ) {
1115
319
                try { dbl = ds.Get<bool>(); } catch ( ... ) { }
1116
319
            }
1117
1118
1.58k
#if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL))
1119
1.58k
            try { safe = ds.Get<bool>(); } catch ( ... ) { }
1120
1.58k
#endif
1121
1122
1.58k
            if ( safe ) {
1123
#if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
1124
                CF_UNREACHABLE();
1125
#else
1126
100
                int infinity;
1127
1128
100
                if ( dbl == true ) {
1129
15
                    failed = true;
1130
15
                    haveAllocFailure = false;
1131
15
                    WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
1132
11
                    failed = false;
1133
85
                } else {
1134
85
                    failed = true;
1135
85
                    haveAllocFailure = false;
1136
85
                    WC_CHECK_EQ(ecc_projective_add_point_safe(a.GetPtr(), b.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp, &infinity), 0);
1137
50
                    failed = false;
1138
50
                }
1139
100
#endif
1140
1.21k
            } else {
1141
1.21k
                if ( dbl == true ) {
1142
11
                    failed = true;
1143
11
                    haveAllocFailure = false;
1144
11
                    WC_CHECK_EQ(ecc_projective_dbl_point(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
1145
5
                    failed = false;
1146
1.20k
                } else {
1147
1.20k
                    failed = true;
1148
1.20k
                    haveAllocFailure = false;
1149
1.20k
                    WC_CHECK_EQ(ecc_projective_add_point(a.GetPtr(), b.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
1150
1.09k
                    failed = false;
1151
1152
                    /* Do not return result if inputs are negations of the same point */
1153
1.09k
                    CF_CHECK_NE(is_neg, std::nullopt);
1154
1.06k
                    CF_CHECK_FALSE(*is_neg);
1155
1.02k
                }
1156
1.21k
            }
1157
1158
            /* Lock to prevent exporting the projective point */
1159
1.08k
            res.Lock();
1160
1.08k
        }
1161
0
#endif
1162
1163
        /* To affine */
1164
1.08k
        WC_CHECK_EQ(ecc_map(res.GetPtr(), prime.GetPtr(), mp), MP_OKAY);
1165
1166
        /* Only return the result if the input points are valid */
1167
1.02k
        CF_CHECK_TRUE(valid);
1168
1169
        /* Only return the result if the output point is valid */
1170
177
        CF_CHECK_TRUE(res.CurveCheck());
1171
1172
167
        ret = res.ToBignumPair();
1173
275
    } catch ( ... ) { }
1174
1175
2.39k
end:
1176
2.39k
    wolfCrypt_detail::UnsetGlobalDs();
1177
1178
2.39k
    if ( valid ) {
1179
221
        if ( !haveAllocFailure ) {
1180
211
            if ( is_neg && !*is_neg ) {
1181
174
                CF_ASSERT(!failed, "Point adding failed");
1182
174
            }
1183
211
        }
1184
221
    }
1185
1186
2.39k
    return ret;
1187
2.39k
}
1188
1189
3.76k
std::optional<component::ECC_Point> OpECC_Point_Mul(operation::ECC_Point_Mul& op) {
1190
3.76k
    std::optional<component::ECC_Point> ret = std::nullopt;
1191
3.76k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1192
3.76k
    wolfCrypt_detail::SetGlobalDs(&ds);
1193
1194
3.76k
    std::optional<int> curveID;
1195
3.76k
    int curveIdx;
1196
3.76k
    const ecc_set_type* curve = nullptr;
1197
1198
3.76k
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
1199
1200
3.53k
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
1201
3.53k
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
1202
1203
    /* try/catch because ECCPoint constructor may throw if allocation fails */
1204
3.53k
    try {
1205
3.53k
        ECCPoint res(ds, *curveID), a(ds, *curveID);
1206
3.53k
        wolfCrypt_bignum::Bignum b(ds), Af(ds), prime(ds);
1207
3.53k
        bool valid = false;
1208
1209
        /* Set point */
1210
3.53k
        CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get()));
1211
3.10k
        valid = a.CurveCheck();
1212
1213
        /* Set multiplier */
1214
3.10k
        CF_CHECK_EQ(b.Set(op.b.ToString(ds)), true);
1215
1216
        /* Retrieve curve parameters */
1217
3.02k
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
1218
2.96k
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
1219
1220
        /* Multiply */
1221
2.93k
        WC_CHECK_EQ(wc_ecc_mulmod_ex(b.GetPtr(), a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), 1, nullptr), 0);
1222
1223
        /* Only return the result if the input point is valid */
1224
2.45k
        CF_CHECK_TRUE(valid);
1225
1226
640
        ret = res.ToBignumPair();
1227
640
    } catch ( ... ) { }
1228
1229
3.76k
end:
1230
3.76k
    wolfCrypt_detail::UnsetGlobalDs();
1231
1232
3.76k
    return ret;
1233
3.53k
}
1234
1235
4.80k
std::optional<component::ECC_Point> OpECC_Point_Dbl(operation::ECC_Point_Dbl& op) {
1236
4.80k
    std::optional<component::ECC_Point> ret = std::nullopt;
1237
4.80k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1238
4.80k
    wolfCrypt_detail::SetGlobalDs(&ds);
1239
1240
4.80k
    std::optional<int> curveID;
1241
4.80k
    int curveIdx;
1242
4.80k
    const ecc_set_type* curve = nullptr;
1243
4.80k
    bool failed = false;
1244
4.80k
    bool valid = false;
1245
1246
4.80k
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
1247
1248
4.60k
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
1249
4.60k
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
1250
1251
    /* try/catch because ECCPoint constructor may throw if allocation fails */
1252
4.60k
    try {
1253
4.60k
        ECCPoint res(ds, *curveID), a(ds, *curveID);
1254
4.60k
        wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds);
1255
4.60k
        mp_digit mp;
1256
1257
        /* Set points */
1258
4.60k
        CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get()));
1259
1260
3.67k
        valid = a.CurveCheck();
1261
1262
        /* Retrieve curve parameter */
1263
3.67k
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
1264
3.59k
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
1265
1266
3.53k
        CF_CHECK_TRUE(a.ToProjective(prime));
1267
1268
3.40k
        WC_CHECK_EQ(mp_montgomery_setup(prime.GetPtr(), &mp), MP_OKAY);
1269
1270
#if defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
1271
        goto end;
1272
#else
1273
3.40k
        {
1274
3.40k
            bool safe = false;
1275
1276
3.40k
#if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL))
1277
3.40k
            try { safe = ds.Get<bool>(); } catch ( ... ) { }
1278
3.40k
#endif
1279
1280
3.40k
            if ( safe ) {
1281
#if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
1282
                CF_UNREACHABLE();
1283
#else
1284
39
                failed = true;
1285
39
                haveAllocFailure = false;
1286
39
                WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
1287
21
                failed = false;
1288
21
#endif
1289
2.94k
            } else {
1290
2.94k
                failed = true;
1291
2.94k
                haveAllocFailure = false;
1292
2.94k
                WC_CHECK_EQ(ecc_projective_dbl_point(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
1293
2.87k
                failed = false;
1294
2.87k
            }
1295
1296
            /* Lock to prevent exporting the projective point */
1297
2.89k
            res.Lock();
1298
2.89k
        }
1299
0
#endif
1300
1301
        /* To affine */
1302
2.89k
        WC_CHECK_EQ(ecc_map(res.GetPtr(), prime.GetPtr(), mp), MP_OKAY);
1303
1304
        /* Only return the result if the input points are valid */
1305
2.87k
        CF_CHECK_TRUE(valid);
1306
1307
        /* Only return the result if the output point is valid */
1308
157
        CF_CHECK_TRUE(res.CurveCheck());
1309
1310
110
        ret = res.ToBignumPair();
1311
425
    } catch ( ... ) { }
1312
1313
4.80k
end:
1314
4.80k
    if ( valid ) {
1315
165
        if ( !haveAllocFailure ) {
1316
149
            CF_ASSERT(!failed, "Point doubling failed");
1317
149
        }
1318
165
    }
1319
1320
4.80k
    wolfCrypt_detail::UnsetGlobalDs();
1321
1322
4.80k
    return ret;
1323
4.80k
}
1324
1325
0
std::optional<bool> OpECC_Point_Cmp(operation::ECC_Point_Cmp& op) {
1326
#if 0
1327
    std::optional<bool> ret = std::nullopt;
1328
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1329
    wolfCrypt_detail::SetGlobalDs(&ds);
1330
1331
    std::optional<int> curveID;
1332
    int curveIdx;
1333
    const ecc_set_type* curve = nullptr;
1334
1335
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
1336
1337
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
1338
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
1339
1340
    /* try/catch because ECCPoint constructor may throw if allocation fails */
1341
    try {
1342
        ECCPoint res(ds, *curveID), a(ds, *curveID), b(ds, *curveID);
1343
        wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds);
1344
        bool valid = false;
1345
1346
        /* Set points */
1347
        CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get()));
1348
        CF_CHECK_TRUE(b.Set(op.b, op.curveType.Get()));
1349
1350
        valid = a.CurveCheck() && b.CurveCheck();
1351
        (void)valid;
1352
1353
        /* Retrieve curve parameter */
1354
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
1355
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
1356
1357
        CF_CHECK_TRUE(a.ToProjective(prime));
1358
        CF_CHECK_TRUE(b.ToProjective(prime));
1359
1360
        ret = wc_ecc_cmp_point(a.GetPtr(), b.GetPtr()) == MP_EQ;
1361
    } catch ( ... ) { }
1362
1363
end:
1364
    wolfCrypt_detail::UnsetGlobalDs();
1365
1366
    return ret;
1367
#else
1368
    /* ZD 15599 */
1369
0
    (void)op;
1370
0
    return std::nullopt;
1371
0
#endif
1372
0
}
1373
1374
} /* namespace wolfCrypt_detail */
1375
} /* namespace module */
1376
} /* namespace cryptofuzz */