Coverage Report

Created: 2022-08-24 06:26

/src/cryptofuzz-sp-math/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
7.08k
    ds(ds) {
24
7.08k
    if ( (key = wc_ecc_key_new(nullptr)) == nullptr ) {
25
384
        throw std::exception();
26
384
    }
27
7.08k
}
28
29
6.69k
ECCKey::~ECCKey() {
30
6.69k
    CF_NORET(wc_ecc_key_free(key));
31
6.69k
}
32
33
19.1k
ecc_key* ECCKey::GetPtr(void) {
34
19.1k
    uint8_t* x963 = nullptr;
35
19.1k
    ecc_key* newKey = nullptr;
36
37
19.1k
    bool exportToX963 = false;
38
19.1k
    try {
39
19.1k
        exportToX963 = ds.Get<bool>();
40
19.1k
    } catch ( ... ) { }
41
42
19.1k
    if ( exportToX963 == true ) {
43
1.42k
        CF_CHECK_NE(newKey = wc_ecc_key_new(nullptr), nullptr);
44
45
933
        word32 outLen = 0;
46
47
933
        bool compressed = false;
48
933
        try { compressed  = ds.Get<bool>();} catch ( ... ) { }
49
50
1.69k
        WC_CHECK_EQ(wc_ecc_export_x963_ex(key, nullptr, &outLen, compressed), LENGTH_ONLY_E);
51
1.69k
        x963 = util::malloc(outLen);
52
1.69k
        WC_CHECK_EQ(wc_ecc_export_x963_ex(key, x963, &outLen, compressed), 0);;
53
54
        /* Get the curve id of the old key */
55
266
        int curveID;
56
266
        CF_CHECK_NE(curveID = wc_ecc_get_curve_id(key->idx), ECC_CURVE_INVALID);
57
58
266
        const bool valid = wc_ecc_check_key(key) == 0;
59
60
266
        haveAllocFailure = false;
61
266
        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
47
            CF_ASSERT((compressed && !valid) || haveAllocFailure, "Cannot import X963-exported ECC key");
68
47
            goto end;
69
47
        }
70
71
219
        if ( compressed ) {
72
44
            CF_CHECK_TRUE(valid);
73
8
        }
74
75
183
        CF_NORET(wc_ecc_key_free(key));
76
183
        key = newKey;
77
183
        newKey = nullptr;
78
183
    }
79
80
19.1k
end:
81
19.1k
    util::free(x963);
82
19.1k
    CF_NORET(wc_ecc_key_free(newKey));
83
84
19.1k
    return key;
85
19.1k
}
86
87
3.15k
bool ECCKey::SetCurve(const Type& curveType) {
88
3.15k
    bool ret = false;
89
90
#if !defined(WOLFSSL_SP_MATH)
91
    bool useCustomCurve = false;
92
93
    try {
94
        useCustomCurve = ds.Get<uint8_t>();
95
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
96
    useCustomCurve = false;
97
98
    if ( useCustomCurve == false )
99
#endif
100
3.15k
    {
101
#if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG)
102
        std::cout << "Using native curve" << std::endl;
103
#endif
104
3.15k
        std::optional<int> curveID;
105
106
3.15k
        CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(curveType), std::nullopt);
107
2.61k
        this->curveID = *curveID;
108
109
2.61k
        WC_CHECK_EQ(wc_ecc_set_curve(GetPtr(), 0, *curveID), 0);
110
2.36k
    }
111
#if !defined(WOLFSSL_SP_MATH)
112
    else {
113
 #if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG)
114
        std::cout << "Using custom curve" << std::endl;
115
 #endif
116
        const ecc_set_type* curveSpec;
117
        CF_CHECK_NE(curveSpec = GetCustomCurve(curveType.Get()), nullptr);
118
        WC_CHECK_EQ(wc_ecc_set_custom_curve(GetPtr(), curveSpec), 0);
119
        this->curveID = ECC_CURVE_CUSTOM;
120
    }
121
#endif
122
123
0
    ret = true;
124
125
3.15k
end:
126
3.15k
    return ret;
127
2.36k
}
128
129
2.36k
bool ECCKey::LoadPrivateKey(const component::Bignum& priv) {
130
2.36k
    bool ret = false;
131
2.36k
    std::optional<std::vector<uint8_t>> priv_bytes;
132
133
2.36k
    CF_CHECK_NE(priv_bytes = wolfCrypt_bignum::Bignum::ToBin(ds, priv), std::nullopt);
134
135
2.31k
    WC_CHECK_EQ(wc_ecc_import_private_key_ex(priv_bytes->data(), priv_bytes->size(), nullptr, 0, GetPtr(), *curveID), 0);
136
137
2.25k
    ret = true;
138
139
2.36k
end:
140
2.36k
    return ret;
141
2.25k
}
142
143
1.73k
std::optional<ECCPoint> ECCKey::MakePub(void) {
144
1.73k
    std::optional<ECCPoint> ret = std::nullopt;
145
146
1.73k
    ECCPoint pub(ds, *curveID);
147
1.73k
    WC_CHECK_EQ(wc_ecc_make_pub(GetPtr(), pub.GetPtr()), 0);
148
1.68k
    pub.SetInitialized();
149
150
1.68k
    return pub;
151
152
50
end:
153
50
    return ret;
154
1.73k
}
155
156
820
bool ECCKey::SetRNG(void) {
157
820
    bool ret = false;
158
159
820
    WC_CHECK_EQ(wc_ecc_set_rng(GetPtr(), wolfCrypt_detail::GetRNG()), 0);
160
161
820
    ret = true;
162
820
end:
163
820
    return ret;
164
820
}
165
166
ECCPoint::ECCPoint(Datasource& ds, const int curveID) :
167
    ds(ds),
168
6.14k
    curveID(curveID) {
169
6.14k
    if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) {
170
125
        throw std::exception();
171
125
    }
172
6.14k
}
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
1.67k
{
181
1.67k
    if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) {
182
6
        throw std::exception();
183
6
    }
184
185
1.66k
    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
1.66k
}
190
191
7.68k
ECCPoint::~ECCPoint() {
192
7.68k
    CF_NORET(wc_ecc_del_point(point));
193
7.68k
}
194
195
12.1k
ecc_point* ECCPoint::GetPtr() {
196
12.1k
    uint8_t* out = nullptr;
197
12.1k
    ecc_point* newPoint = nullptr;
198
199
12.1k
    if ( locked == false && initialized == true ) {
200
3.09k
        bool exportToDER = false;
201
202
3.09k
        try {
203
3.09k
            exportToDER = ds.Get<bool>();
204
3.09k
        } catch ( ... ) { }
205
206
3.09k
        if ( exportToDER == true ) {
207
200
            bool compressed = false;
208
200
            try {
209
200
                compressed = ds.Get<bool>();
210
200
            } catch ( ... ) { }
211
212
200
            const int curveIdx = wc_ecc_get_curve_idx(curveID);
213
200
            CF_CHECK_NE(newPoint = wc_ecc_new_point_h(nullptr), nullptr);
214
215
132
            word32 outSz = 0xFFFF;
216
132
            try { outSz = ds.Get<word32>() & 0xFFFF; } catch ( ... ) { }
217
218
132
            out = util::malloc(outSz);
219
220
132
            if ( compressed == false ) {
221
76
                WC_CHECK_EQ(wc_ecc_export_point_der(curveIdx, point, out, &outSz), 0);
222
56
            } else {
223
56
                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
27
            }
226
227
58
            {
228
58
                haveAllocFailure = false;
229
58
                const bool success = wc_ecc_import_point_der(out, outSz, curveIdx, newPoint) == 0;
230
231
58
                if ( success ) {
232
                    /* Point imported. Replace old point with new point. */
233
234
58
                    CF_NORET(wc_ecc_del_point(point));
235
58
                    point = newPoint;
236
58
                    newPoint = nullptr;
237
58
                } 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
58
            }
246
58
        }
247
3.09k
    }
248
249
12.1k
end:
250
12.1k
    util::free(out);
251
12.1k
    CF_NORET(wc_ecc_del_point(newPoint));
252
253
12.1k
    return point;
254
12.1k
}
255
256
2.55k
bool ECCPoint::Set(const component::BignumPair& xy, const bool pointCheck) {
257
2.55k
    bool ret = false;
258
259
2.55k
    wolfCrypt_bignum::Bignum x(ds), y(ds), z(ds);
260
261
2.55k
    CF_CHECK_TRUE(x.Set(xy.first));
262
2.52k
    CF_CHECK_TRUE(y.Set(xy.second));
263
2.50k
    CF_CHECK_TRUE(z.Set("1"));
264
265
2.50k
    WC_CHECK_EQ(mp_copy(x.GetPtr(), point->x), MP_OKAY);
266
2.50k
    WC_CHECK_EQ(mp_copy(y.GetPtr(), point->y), MP_OKAY);
267
2.50k
    WC_CHECK_EQ(mp_copy(z.GetPtr(), point->z), MP_OKAY);
268
269
2.50k
    if ( pointCheck ) {
270
0
        CF_CHECK_TRUE(CurveCheck());
271
0
    }
272
273
2.50k
    SetInitialized();
274
275
2.50k
    ret = true;
276
277
2.55k
end:
278
2.55k
    return ret;
279
2.50k
}
280
281
1.71k
bool ECCPoint::ToProjective(wolfCrypt_bignum::Bignum& prime) {
282
1.71k
    bool ret = false;
283
284
1.71k
    wolfCrypt_bignum::Bignum mu(ds);
285
286
1.71k
    WC_CHECK_EQ(mp_montgomery_calc_normalization(mu.GetPtr(), prime.GetPtr()), MP_OKAY);
287
288
1.71k
    if ( mp_cmp_d(mu.GetPtr(), 1) != MP_EQ ) {
289
1.20k
        WC_CHECK_EQ(mp_mulmod(point->x, mu.GetPtr(), prime.GetPtr(), point->x), MP_OKAY);
290
1.19k
        WC_CHECK_EQ(mp_mulmod(point->y, mu.GetPtr(), prime.GetPtr(), point->y), MP_OKAY);
291
1.18k
        WC_CHECK_EQ(mp_mulmod(point->z, mu.GetPtr(), prime.GetPtr(), point->z), MP_OKAY);
292
1.17k
    }
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
1.68k
    Lock();
298
299
1.68k
    ret = true;
300
301
1.71k
end:
302
1.71k
    return ret;
303
1.68k
}
304
305
1.72k
bool ECCPoint::CurveCheck(void) const {
306
1.72k
    const int curveIdx = wc_ecc_get_curve_idx(curveID);
307
1.72k
    return wc_ecc_point_is_on_curve(point, curveIdx) == 0;
308
1.72k
}
309
310
4.00k
void ECCPoint::Lock(void) {
311
4.00k
    locked = true;
312
4.00k
}
313
314
4.17k
void ECCPoint::SetInitialized(void) {
315
4.17k
    initialized = true;
316
4.17k
}
317
318
1.56k
std::optional<component::BignumPair> ECCPoint::ToBignumPair(void) {
319
1.56k
    std::optional<component::BignumPair> ret = std::nullopt;
320
321
1.56k
    wolfCrypt_bignum::Bignum pub_x(GetPtr()->x, ds);
322
323
    /* Pointer is stored in pub_x; lock to prevent UAF */
324
1.56k
    Lock();
325
326
1.56k
    wolfCrypt_bignum::Bignum pub_y(GetPtr()->y, ds);
327
328
1.56k
    std::optional<std::string> pub_x_str, pub_y_str;
329
1.56k
    CF_CHECK_NE(pub_x_str = pub_x.ToDecString(), std::nullopt);
330
1.56k
    CF_CHECK_NE(pub_y_str = pub_y.ToDecString(), std::nullopt);
331
332
1.56k
    ret = { *pub_x_str, *pub_y_str };
333
1.56k
end:
334
335
1.56k
    return ret;
336
1.56k
}
337
338
834
int ECCPoint::Compare(ECCPoint& other) {
339
834
    return wc_ecc_cmp_point(GetPtr(), other.GetPtr());
340
834
}
341
342
865
std::optional<bool> ECCPoint::IsNeg(ECCPoint& other, wolfCrypt_bignum::Bignum& prime) {
343
865
    std::optional<bool> ret = std::nullopt;
344
345
865
    wolfCrypt_bignum::Bignum neg(ds);
346
865
    if ( mp_sub(prime.GetPtr(), other.GetPtr()->y, neg.GetPtr()) == MP_OKAY) {
347
865
        ret = static_cast<bool>(mp_cmp(point->y, neg.GetPtr()) == MP_EQ);
348
865
    }
349
350
865
    return ret;
351
865
}
352
353
985
std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Generic(operation::ECC_PrivateToPublic& op) {
354
985
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
355
985
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
356
985
    wolfCrypt_detail::SetGlobalDs(&ds);
357
358
985
    try {
359
985
        ECCKey key(ds);
360
361
        /* Initialize */
362
985
        {
363
985
            CF_CHECK_EQ(key.SetCurve(op.curveType), true);
364
398
            CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true);
365
349
        }
366
367
        /* Process/Finalize */
368
0
        {
369
349
            auto pub = key.MakePub();
370
349
            CF_CHECK_NE(pub, std::nullopt);
371
372
320
            ret = pub->ToBignumPair();
373
320
        }
374
320
    } catch ( ... ) { }
375
376
985
end:
377
378
985
    wolfCrypt_detail::UnsetGlobalDs();
379
985
    return ret;
380
985
}
381
382
1.07k
std::optional<bool> OpECC_ValidatePubkey_Generic(operation::ECC_ValidatePubkey& op) {
383
1.07k
    std::optional<bool> ret = std::nullopt;
384
1.07k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
385
1.07k
    wolfCrypt_detail::SetGlobalDs(&ds);
386
387
1.07k
    std::optional<int> curveID;
388
389
1.07k
    try {
390
1.07k
        ECCKey key(ds);
391
1.07k
        {
392
1.07k
            const char* name = nullptr;
393
394
1.07k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
395
396
842
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
397
398
707
            WC_CHECK_EQ(wc_ecc_import_raw(
399
645
                        key.GetPtr(),
400
645
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
401
645
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
402
645
                        nullptr,
403
645
                        name), 0);
404
645
            haveAllocFailure = false;
405
645
            ret = wc_ecc_check_key(key.GetPtr()) == 0;
406
645
            if ( *ret == false && haveAllocFailure == true ) {
407
115
                ret = std::nullopt;
408
115
            }
409
645
        }
410
645
    } catch ( ... ) { }
411
412
1.07k
end:
413
414
1.07k
    wolfCrypt_detail::UnsetGlobalDs();
415
1.07k
    return ret;
416
1.07k
}
417
418
1.83k
std::optional<bool> OpECDSA_Verify_Generic(operation::ECDSA_Verify& op) {
419
1.83k
    std::optional<bool> ret = std::nullopt;
420
1.83k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
421
1.83k
    wolfCrypt_detail::SetGlobalDs(&ds);
422
423
1.83k
    std::optional<int> curveID;
424
1.83k
    uint8_t* sig = nullptr;
425
1.83k
    uint8_t* hash = nullptr;
426
1.83k
    word32 sigSz = ECC_MAX_SIG_SIZE;
427
1.83k
    int verify;
428
429
1.83k
    {
430
1.83k
        try {
431
1.83k
            sigSz = ds.Get<uint8_t>();
432
1.83k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
433
434
1.83k
        sig = util::malloc(sigSz);
435
1.83k
    }
436
437
1.83k
    try {
438
1.83k
        ECCKey key(ds);
439
1.83k
        {
440
1.83k
            const char* name = nullptr;
441
442
1.83k
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
443
444
1.74k
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
445
446
1.60k
            WC_CHECK_EQ(wc_ecc_import_raw(
447
1.56k
                        key.GetPtr(),
448
1.56k
                        util::DecToHex(op.signature.pub.first.ToTrimmedString()).c_str(),
449
1.56k
                        util::DecToHex(op.signature.pub.second.ToTrimmedString()).c_str(),
450
1.56k
                        nullptr,
451
1.56k
                        name), 0);
452
1.56k
            WC_CHECK_EQ(wc_ecc_check_key(key.GetPtr()), 0);
453
1.46k
        }
454
455
1.46k
        WC_CHECK_EQ(wc_ecc_rs_to_sig(
456
1.39k
                    util::DecToHex(op.signature.signature.first.ToTrimmedString()).c_str(),
457
1.39k
                    util::DecToHex(op.signature.signature.second.ToTrimmedString()).c_str(),
458
1.39k
                    sig, &sigSz), 0);
459
460
1.39k
        if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
461
1.33k
            const auto CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
462
1.33k
            WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0);
463
1.23k
        } else {
464
59
            std::optional<wc_HashType> hashType;
465
59
            CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt);
466
467
59
            const auto hashSize = wc_HashGetDigestSize(*hashType);
468
59
            hash = util::malloc(hashSize);
469
470
59
            WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0);
471
472
59
            const auto CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType);
473
59
            WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0);
474
59
        }
475
476
1.29k
        ret = verify ? true : false;
477
1.29k
    } catch ( ... ) { }
478
479
1.83k
end:
480
481
1.83k
    util::free(sig);
482
1.83k
    util::free(hash);
483
484
1.83k
    wolfCrypt_detail::UnsetGlobalDs();
485
486
1.83k
    return ret;
487
1.83k
}
488
489
1.82k
std::optional<component::ECDSA_Signature> OpECDSA_Sign_Generic(operation::ECDSA_Sign& op) {
490
1.82k
    std::optional<component::ECDSA_Signature> ret = std::nullopt;
491
1.82k
    if ( op.UseRandomNonce() == false && op.UseSpecifiedNonce() == false ) {
492
71
        return ret;
493
71
    }
494
495
1.75k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
496
1.75k
    wolfCrypt_detail::SetGlobalDs(&ds);
497
498
1.75k
    uint8_t* sig = nullptr;
499
1.75k
    word32 sigSz = ECC_MAX_SIG_SIZE;
500
1.75k
    Buffer CT;
501
1.75k
    uint8_t* hash = nullptr;
502
1.75k
    size_t hashSize = 0;
503
1.75k
    uint8_t* nonce_bytes = nullptr;
504
1.75k
    wolfCrypt_bignum::Bignum nonce(ds), r(ds), s(ds);
505
506
1.75k
    CF_CHECK_NE(op.priv.ToTrimmedString(), "0");
507
508
1.67k
    {
509
1.67k
        try {
510
1.67k
            sigSz = ds.Get<uint8_t>();
511
1.67k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
512
513
1.67k
        sig = util::malloc(sigSz);
514
1.67k
    }
515
516
1.67k
    try {
517
1.67k
        ECCKey key(ds);
518
1.67k
        CF_CHECK_EQ(key.SetCurve(op.curveType), true);
519
1.57k
        CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true);
520
1.55k
        key.GetPtr()->type = ECC_PRIVATEKEY_ONLY;
521
522
1.55k
        if ( op.UseSpecifiedNonce() == true ) {
523
612
            CF_CHECK_EQ(nonce.Set(op.nonce.ToString(ds)), true);
524
525
602
            const size_t nonce_bytes_size = mp_unsigned_bin_size(nonce.GetPtr());
526
527
            /* Convert nonce to byte array */
528
602
            nonce_bytes = util::malloc(nonce_bytes_size);
529
602
            CF_CHECK_EQ(mp_to_unsigned_bin(nonce.GetPtr(), nonce_bytes), 0);
530
531
            /* Set nonce */
532
591
            WC_CHECK_EQ(wc_ecc_sign_set_k(nonce_bytes, nonce_bytes_size, key.GetPtr()), 0);
533
569
        }
534
535
1.51k
        auto pub = key.MakePub();
536
1.51k
        CF_CHECK_NE(pub, std::nullopt);
537
538
1.49k
        if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
539
1.39k
            CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
540
1.39k
        } else {
541
95
            std::optional<wc_HashType> hashType;
542
95
            CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt);
543
544
95
            hashSize = wc_HashGetDigestSize(*hashType);
545
95
            hash = util::malloc(hashSize);
546
547
95
            WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0);
548
549
95
            CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType);
550
95
        }
551
552
        /* Sign */
553
2.79k
        WC_CHECK_EQ(wc_ecc_sign_hash(CT.GetPtr(), CT.GetSize(), sig, &sigSz, wolfCrypt_detail::GetRNG(), key.GetPtr()), 0);
554
555
        /* Verify */
556
2.79k
        {
557
2.79k
            int verify;
558
2.79k
            haveAllocFailure = false;
559
2.79k
            if ( wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()) == 0 && haveAllocFailure == false ) {
560
1.13k
                CF_ASSERT(verify, "Cannot verify generated signature");
561
1.13k
            }
562
2.79k
        }
563
564
1.30k
        CF_CHECK_EQ(DecodeECC_DSA_Sig(sig, sigSz, r.GetPtr(), s.GetPtr()), 0);
565
1.30k
        {
566
1.30k
            std::optional<std::string> r_str, s_str;
567
568
1.30k
            if ( op.curveType.Get() == CF_ECC_CURVE("secp256k1") ) {
569
0
                wolfCrypt_bignum::Bignum SMax(ds);
570
0
                CF_CHECK_EQ(SMax.Set("57896044618658097711785492504343953926418782139537452191302581570759080747168"), true);
571
0
                if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) {
572
0
                    wolfCrypt_bignum::Bignum SSub(ds);
573
0
                    CF_CHECK_EQ(SSub.Set("115792089237316195423570985008687907852837564279074904382605163141518161494337"), true);
574
0
                    CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0);
575
0
                }
576
1.30k
            } else if ( op.curveType.Get() == CF_ECC_CURVE("secp256r1") ) {
577
460
                wolfCrypt_bignum::Bignum SMax(ds);
578
460
                CF_CHECK_EQ(SMax.Set("57896044605178124381348723474703786764998477612067880171211129530534256022184"), true);
579
460
                if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) {
580
255
                    wolfCrypt_bignum::Bignum SSub(ds);
581
255
                    CF_CHECK_EQ(SSub.Set("115792089210356248762697446949407573529996955224135760342422259061068512044369"), true);
582
255
                    CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0);
583
255
                }
584
460
            }
585
586
1.30k
            CF_CHECK_NE(r_str = r.ToDecString(), std::nullopt);
587
1.30k
            CF_CHECK_NE(s_str = s.ToDecString(), std::nullopt);
588
589
1.30k
            const auto pub2 = pub->ToBignumPair();
590
1.30k
            CF_CHECK_NE(pub2, std::nullopt);
591
592
1.30k
            ret = component::ECDSA_Signature({*r_str, *s_str}, *pub2);
593
1.30k
        }
594
1.30k
    } catch ( ... ) { }
595
1.75k
end:
596
597
1.75k
    util::free(sig);
598
1.75k
    util::free(hash);
599
1.75k
    util::free(nonce_bytes);
600
601
1.75k
    wolfCrypt_detail::UnsetGlobalDs();
602
603
1.75k
    return ret;
604
1.67k
}
605
606
475
std::optional<component::Ciphertext> OpECIES_Encrypt_Generic(operation::ECIES_Encrypt& op) {
607
475
    std::optional<component::Ciphertext> ret = std::nullopt;
608
#if !defined(HAVE_ECC_ENCRYPT)
609
    (void)op;
610
#else
611
475
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
612
475
    wolfCrypt_detail::SetGlobalDs(&ds);
613
475
    uint8_t* out = nullptr;
614
615
475
    CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC")));
616
386
    CF_CHECK_EQ(op.iv, std::nullopt);
617
618
376
    try {
619
376
        ECCKey priv(ds), pub(ds);
620
376
        word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF;
621
622
        /* Initialize private key */
623
376
        {
624
376
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
625
354
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
626
337
            CF_CHECK_TRUE(priv.SetRNG());
627
337
        }
628
629
        /* Initialize public key */
630
0
        {
631
337
            std::optional<int> curveID;
632
337
            const char* name = nullptr;
633
634
337
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
635
636
337
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
637
638
337
            WC_CHECK_EQ(wc_ecc_import_raw(
639
324
                        pub.GetPtr(),
640
324
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
641
324
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
642
324
                        nullptr,
643
324
                        name), 0);
644
645
324
            CF_CHECK_TRUE(pub.SetRNG());
646
324
        }
647
648
0
        out = util::malloc(outSz);
649
650
324
        WC_CHECK_EQ(wc_ecc_encrypt(priv.GetPtr(), pub.GetPtr(), op.cleartext.GetPtr(), op.cleartext.GetSize(), out, &outSz, nullptr), 0);
651
652
143
        ret = component::Ciphertext(Buffer(out, outSz));
653
143
    } catch ( ... ) { }
654
655
475
end:
656
475
    util::free(out);
657
658
475
    wolfCrypt_detail::UnsetGlobalDs();
659
475
#endif
660
475
    return ret;
661
376
}
662
663
301
std::optional<component::Cleartext> OpECIES_Decrypt_Generic(operation::ECIES_Decrypt& op) {
664
301
    std::optional<component::Cleartext> ret = std::nullopt;
665
#if !defined(HAVE_ECC_ENCRYPT)
666
    (void)op;
667
#else
668
301
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
669
301
    wolfCrypt_detail::SetGlobalDs(&ds);
670
301
    uint8_t* out = nullptr;
671
672
301
    CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC")));
673
217
    CF_CHECK_EQ(op.iv, std::nullopt);
674
675
207
    try {
676
207
        ECCKey priv(ds), pub(ds);
677
207
        word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF;
678
679
        /* Initialize private key */
680
207
        {
681
207
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
682
184
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
683
173
            CF_CHECK_TRUE(priv.SetRNG());
684
173
        }
685
686
        /* Initialize public key */
687
0
        {
688
173
            std::optional<int> curveID;
689
173
            const char* name = nullptr;
690
691
173
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
692
693
173
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
694
695
173
            WC_CHECK_EQ(wc_ecc_import_raw(
696
166
                        pub.GetPtr(),
697
166
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
698
166
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
699
166
                        nullptr,
700
166
                        name), 0);
701
702
166
            CF_CHECK_TRUE(pub.SetRNG());
703
166
        }
704
705
0
        out = util::malloc(outSz);
706
707
166
        WC_CHECK_EQ(wc_ecc_decrypt(priv.GetPtr(), pub.GetPtr(), op.ciphertext.GetPtr(), op.ciphertext.GetSize(), out, &outSz, nullptr), 0);
708
709
56
        ret = component::Cleartext(Buffer(out, outSz));
710
56
    } catch ( ... ) { }
711
712
301
end:
713
301
    util::free(out);
714
715
301
    wolfCrypt_detail::UnsetGlobalDs();
716
301
#endif
717
301
    return ret;
718
207
}
719
720
233
std::optional<component::Secret> OpECDH_Derive(operation::ECDH_Derive& op) {
721
233
    std::optional<component::Secret> ret = std::nullopt;
722
233
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
723
233
    wolfCrypt_detail::SetGlobalDs(&ds);
724
725
    /* try/catch because ECCKey constructor may throw if allocation fails */
726
233
    try {
727
        /* TODO dynamic size */
728
233
        uint8_t out[1024];
729
233
        word32 outlen = sizeof(out);
730
233
        ECCKey priv(ds), pub(ds);
731
732
        /* Initialize private key */
733
233
        {
734
233
            CF_CHECK_TRUE(priv.SetCurve(op.curveType));
735
173
            CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv));
736
160
            CF_CHECK_TRUE(priv.SetRNG());
737
160
        }
738
739
        /* Initialize public key */
740
0
        {
741
160
            std::optional<int> curveID;
742
160
            const char* name = nullptr;
743
744
160
            CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
745
746
160
            CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr);
747
748
160
            WC_CHECK_EQ(wc_ecc_import_raw(
749
147
                        pub.GetPtr(),
750
147
                        util::DecToHex(op.pub.first.ToTrimmedString()).c_str(),
751
147
                        util::DecToHex(op.pub.second.ToTrimmedString()).c_str(),
752
147
                        nullptr,
753
147
                        name), 0);
754
147
            WC_CHECK_EQ(wc_ecc_check_key(pub.GetPtr()), 0);
755
103
        }
756
757
103
        WC_CHECK_EQ(wc_ecc_shared_secret(priv.GetPtr(), pub.GetPtr(), out, &outlen), 0);
758
759
99
        ret = component::Secret(Buffer(out, outlen));
760
99
    } catch ( ... ) { }
761
762
233
end:
763
233
    wolfCrypt_detail::UnsetGlobalDs();
764
765
233
    return ret;
766
233
}
767
768
1.05k
std::optional<component::ECC_Point> OpECC_Point_Add(operation::ECC_Point_Add& op) {
769
1.05k
    std::optional<component::ECC_Point> ret = std::nullopt;
770
1.05k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
771
1.05k
    wolfCrypt_detail::SetGlobalDs(&ds);
772
773
1.05k
    std::optional<int> curveID;
774
1.05k
    int curveIdx;
775
1.05k
    const ecc_set_type* curve = nullptr;
776
777
1.05k
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
778
779
1.00k
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
780
952
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
781
782
    /* try/catch because ECCPoint constructor may throw if allocation fails */
783
952
    try {
784
952
        ECCPoint res(ds, *curveID), a(ds, *curveID), b(ds, *curveID);
785
952
        wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds);
786
952
        mp_digit mp;
787
952
        bool valid = false;
788
952
        std::optional<bool> is_neg = std::nullopt;
789
790
        /* Set points */
791
952
        CF_CHECK_TRUE(a.Set(op.a));
792
939
        CF_CHECK_TRUE(b.Set(op.b));
793
794
928
        valid = a.CurveCheck() && b.CurveCheck();
795
796
        /* Retrieve curve parameter */
797
928
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
798
928
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
799
800
928
        is_neg = a.IsNeg(b, prime);
801
802
928
        CF_CHECK_TRUE(a.ToProjective(prime));
803
911
        CF_CHECK_TRUE(b.ToProjective(prime));
804
805
897
        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
897
        {
811
897
            bool dbl = false;
812
897
            bool safe = false;
813
814
897
            if ( a.Compare(b) == MP_EQ ) {
815
89
                try { dbl = ds.Get<bool>(); } catch ( ... ) { }
816
89
            }
817
818
#if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL))
819
            try { safe = ds.Get<bool>(); } catch ( ... ) { }
820
#endif
821
822
897
            if ( safe ) {
823
0
#if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
824
0
                CF_UNREACHABLE();
825
#else
826
                int infinity;
827
828
                if ( dbl == true ) {
829
                    WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
830
                } else {
831
                    WC_CHECK_EQ(ecc_projective_add_point_safe(a.GetPtr(), b.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp, &infinity), 0);
832
                }
833
#endif
834
897
            } else {
835
897
                if ( dbl == true ) {
836
18
                    WC_CHECK_EQ(ecc_projective_dbl_point(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
837
879
                } else {
838
879
                    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
820
                    CF_CHECK_FALSE(is_neg && *is_neg);
842
818
                }
843
897
            }
844
845
            /* Lock to prevent exporting the projective point */
846
826
            res.Lock();
847
826
        }
848
0
#endif
849
850
        /* To affine */
851
826
        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
816
        CF_CHECK_TRUE(valid);
855
856
        /* Only return the result if the output point is valid */
857
93
        CF_CHECK_TRUE(res.CurveCheck());
858
859
92
        ret = res.ToBignumPair();
860
92
    } catch ( ... ) { }
861
862
1.05k
end:
863
1.05k
    wolfCrypt_detail::UnsetGlobalDs();
864
865
1.05k
    return ret;
866
952
}
867
868
1.03k
std::optional<component::ECC_Point> OpECC_Point_Mul(operation::ECC_Point_Mul& op) {
869
1.03k
    std::optional<component::ECC_Point> ret = std::nullopt;
870
1.03k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
871
1.03k
    wolfCrypt_detail::SetGlobalDs(&ds);
872
873
1.03k
    std::optional<int> curveID;
874
1.03k
    int curveIdx;
875
1.03k
    const ecc_set_type* curve = nullptr;
876
877
1.03k
    CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt);
878
879
955
    CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID);
880
832
    CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr);
881
882
    /* try/catch because ECCPoint constructor may throw if allocation fails */
883
832
    try {
884
832
        ECCPoint res(ds, *curveID), a(ds, *curveID);
885
832
        wolfCrypt_bignum::Bignum b(ds), Af(ds), prime(ds);
886
832
        bool valid = false;
887
888
        /* Set point */
889
832
        CF_CHECK_TRUE(a.Set(op.a));
890
808
        valid = a.CurveCheck();
891
892
        /* Set multiplier */
893
808
        CF_CHECK_EQ(b.Set(op.b.ToString(ds)), true);
894
895
        /* Retrieve curve parameters */
896
796
        CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true);
897
796
        CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true);
898
899
        /* Multiply */
900
796
        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
571
        CF_CHECK_TRUE(valid);
904
905
98
        ret = res.ToBignumPair();
906
98
    } catch ( ... ) { }
907
908
1.03k
end:
909
1.03k
    wolfCrypt_detail::UnsetGlobalDs();
910
911
1.03k
    return ret;
912
832
}
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
#if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL))
955
            try { safe = ds.Get<bool>(); } catch ( ... ) { }
956
#endif
957
958
0
            if ( safe ) {
959
0
#if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)
960
0
                CF_UNREACHABLE();
961
#else
962
                WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0);
963
#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 */