Coverage Report

Created: 2025-03-09 06:52

/src/cryptofuzz/modules/openssl/bn_ops.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <cryptofuzz/util.h>
2
#include <cryptofuzz/repository.h>
3
#include <fuzzing/datasource/id.hpp>
4
#include <boost/multiprecision/cpp_int.hpp>
5
6
#include "bn_ops.h"
7
8
/* Not included in public headers */
9
#if defined(CRYPTOFUZZ_BORINGSSL)
10
extern "C" {
11
    int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
12
    int bn_div_consttime(BIGNUM *quotient, BIGNUM *remainder, const BIGNUM *numerator, const BIGNUM *divisor, unsigned divisor_min_bits, BN_CTX *ctx);
13
    int bn_lcm_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
14
    uint16_t bn_mod_u16_consttime(const BIGNUM *bn, uint16_t d);
15
    int bn_abs_sub_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
16
    int bn_is_relatively_prime(int *out_relatively_prime, const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx);
17
}
18
#endif
19
20
/* Not included in public headers */
21
#if defined(CRYPTOFUZZ_LIBRESSL)
22
extern "C" {
23
    int BN_gcd_ct(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx);
24
    int bn_isqrt(BIGNUM *out_sqrt, int *out_perfect, const BIGNUM *n, BN_CTX *in_ctx);
25
    int bn_is_perfect_square(int *out_perfect, const BIGNUM *n, BN_CTX *ctx);
26
    int BN_div_ct(BIGNUM *quotient, BIGNUM *remainder, const BIGNUM *numerator, const BIGNUM *divisor, BN_CTX *ctx);
27
    int BN_mod_ct(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
28
    int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
29
            const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
30
    int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1,
31
            const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
32
            BN_CTX *ctx, BN_MONT_CTX *m_ctx);
33
    int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
34
            const BIGNUM *m, BN_CTX *ctx);
35
}
36
#endif
37
38
3.97k
#define GET_WHICH(max) uint8_t which = 0; try { which = ds.Get<uint8_t>(); which %= ((max)+1); } catch ( ... ) { }
39
40
namespace cryptofuzz {
41
namespace module {
42
namespace OpenSSL_bignum {
43
44
104
bool Add::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
45
104
    (void)ctx;
46
104
    bool ret = false;
47
48
104
    GET_WHICH(2);
49
104
    switch ( which ) {
50
45
        case    0:
51
45
            CF_ASSERT_EQ(BN_add(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 1);
52
45
            CF_NORET(bn.CopyResult(res));
53
45
            break;
54
20
        case    1:
55
20
            CF_CHECK_EQ(BN_is_negative(bn[0].GetPtr()), 0);
56
15
            CF_CHECK_EQ(BN_is_negative(bn[1].GetPtr()), 0);
57
14
            CF_ASSERT_EQ(BN_uadd(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 1);
58
14
            break;
59
39
        case    2:
60
39
            {
61
39
                const auto val = bn[1].AsBN_ULONG();
62
39
                CF_CHECK_NE(val, std::nullopt);
63
64
15
                CF_ASSERT_EQ(BN_add_word(bn.GetDestPtr(0), *val), 1);
65
66
15
                CF_CHECK_EQ(res.Set(bn[0]), true);
67
15
            }
68
0
            break;
69
0
        default:
70
0
            goto end;
71
0
            break;
72
104
    }
73
74
74
    ret = true;
75
76
104
end:
77
104
    return ret;
78
74
}
79
80
119
bool Sub::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
81
119
    (void)ctx;
82
119
    bool ret = false;
83
84
119
    GET_WHICH(3);
85
119
    switch ( which ) {
86
28
        case    0:
87
28
            CF_ASSERT_EQ(BN_sub(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 1);
88
28
            CF_NORET(bn.CopyResult(res));
89
28
            break;
90
91
    /* OpenSSL and LibreSSL return a positive value for BN_usub(A,B)
92
     * where A > B
93
     */
94
#if defined(CRYPTOFUZZ_BORINGSSL)
95
        case    1:
96
            CF_CHECK_EQ(BN_is_negative(bn[0].GetPtr()), 0);
97
            CF_CHECK_EQ(BN_is_negative(bn[1].GetPtr()), 0);
98
            CF_CHECK_EQ(BN_usub(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 1);
99
            break;
100
#endif
101
32
        case    2:
102
32
            {
103
32
                const auto val = bn[1].AsBN_ULONG();
104
32
                CF_CHECK_NE(val, std::nullopt);
105
106
10
                CF_ASSERT_EQ(BN_sub_word(bn.GetDestPtr(0), *val), 1);
107
108
10
                CF_CHECK_EQ(res.Set(bn[0]), true);
109
10
            }
110
0
            break;
111
#if defined(CRYPTOFUZZ_BORINGSSL)
112
        case    3:
113
            CF_CHECK_EQ(BN_is_negative(bn[0].GetPtr()), 0);
114
            CF_CHECK_EQ(BN_is_negative(bn[1].GetPtr()), 0);
115
            CF_CHECK_GTE(BN_cmp(bn[0].GetPtr(), bn[1].GetPtr()), 0);
116
            CF_CHECK_EQ(bn_abs_sub_consttime(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
117
            break;
118
#endif
119
59
        default:
120
59
            goto end;
121
59
            break;
122
119
    }
123
124
38
    ret = true;
125
126
119
end:
127
119
    return ret;
128
38
}
129
130
62
bool Mul::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
131
62
    (void)ds;
132
62
    (void)ctx;
133
62
    bool ret = false;
134
135
62
    GET_WHICH(1);
136
62
    switch ( which ) {
137
30
        case    0:
138
30
            CF_ASSERT_EQ(BN_mul(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
139
30
            CF_NORET(bn.CopyResult(res));
140
30
            break;
141
32
        case    1:
142
32
            {
143
32
                const auto val = bn[1].AsBN_ULONG();
144
32
                CF_CHECK_NE(val, std::nullopt);
145
146
7
                CF_ASSERT_EQ(BN_mul_word(bn.GetDestPtr(0), *val), 1);
147
148
7
                CF_CHECK_EQ(res.Set(bn[0]), true);
149
7
            }
150
0
            break;
151
0
        default:
152
0
            goto end;
153
0
            break;
154
62
    }
155
156
37
    ret = true;
157
158
62
end:
159
62
    return ret;
160
37
}
161
162
88
bool Mod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
163
88
    (void)ctx;
164
88
    bool ret = false;
165
166
88
    GET_WHICH(7);
167
88
    switch ( which ) {
168
33
        case    0:
169
33
            CF_ASSERT_EQ_COND(
170
33
                    BN_mod(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()),
171
33
                    1,
172
33
                    BN_is_zero(bn[1].GetPtr()));
173
20
            break;
174
23
        case    1:
175
            /* "BN_mod() corresponds to BN_div() with dv set to NULL" */
176
23
            CF_ASSERT_EQ_COND(
177
23
                    BN_div(nullptr, res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()),
178
23
                    1,
179
23
                    BN_is_zero(bn[1].GetPtr()));
180
13
            break;
181
#if defined(CRYPTOFUZZ_BORINGSSL)
182
        case    2:
183
            {
184
                bool use_divisor_min_bits = false;
185
                try { use_divisor_min_bits = ds. Get<bool>(); } catch ( ... ) { }
186
187
                CF_CHECK_EQ(bn_div_consttime(
188
                            nullptr,
189
                            res.GetDestPtr(),
190
                            bn[0].GetPtr(),
191
                            bn[1].GetPtr(),
192
                            use_divisor_min_bits ? BN_num_bits(bn[1].GetPtrConst()) : 0,
193
                            ctx.GetPtr()), 1);
194
            }
195
            break;
196
        case    3:
197
            CF_NORET(util::HintBignumPow2());
198
            CF_CHECK_EQ(BN_is_pow2(bn[1].GetPtr()), 1);
199
            CF_CHECK_EQ(BN_mod_pow2(res.GetDestPtr(), bn[0].GetPtr(), BN_num_bits(bn[1].GetPtr()) - 1), 1);
200
            break;
201
        case    4:
202
            {
203
                std::optional<uint64_t> v64;
204
205
                /* Convert bn[1] to uint64_t if possible */
206
                CF_CHECK_NE(v64 = bn[1].AsUint64(), std::nullopt);
207
208
                /* Try to convert the uint64_t to uint16_t */
209
                uint16_t v16;
210
                CF_CHECK_EQ(v16 = *v64, *v64);
211
212
                CF_CHECK_GT(v16, 1);
213
214
                /* This condition is imposed by bn_mod_u16_consttime, which
215
                 * triggers an assert failure otherwise
216
                 */
217
                CF_CHECK_LTE(BN_num_bits_word(v16 - 1), 16);
218
219
                /* ret = bn[0] MOD v16 (which is bn[1]) */
220
                const auto ret = bn_mod_u16_consttime(bn[0].GetPtr(), v16);
221
                res.SetUint32(ret);
222
            }
223
            break;
224
#endif
225
13
        case    5:
226
13
            {
227
                /* BN_mod_word handles negative inputs in a different way
228
                 * than other modulo functions
229
                 */
230
13
                CF_CHECK_EQ(BN_is_negative(bn[0].GetPtr()), 0);
231
232
9
                const auto val = bn[1].AsBN_ULONG();
233
9
                CF_CHECK_NE(val, std::nullopt);
234
1
                CF_CHECK_NE(*val, 0);
235
236
0
                const auto ret = BN_mod_word(bn[0].GetPtr(), *val);
237
238
0
                CF_CHECK_TRUE(res.SetWord(ret));
239
0
            }
240
0
            break;
241
#if defined(CRYPTOFUZZ_BORINGSSL)
242
        case    6:
243
            CF_NORET(util::HintBignumPow2());
244
            CF_CHECK_EQ(BN_is_pow2(bn[1].GetPtr()), 1);
245
            CF_CHECK_EQ(BN_nnmod_pow2(res.GetDestPtr(), bn[0].GetPtr(), BN_num_bits(bn[1].GetPtr()) - 1), 1);
246
            break;
247
#endif
248
0
#if defined(CRYPTOFUZZ_LIBRESSL)
249
5
        case    7:
250
5
            CF_ASSERT_EQ_COND(
251
5
                    BN_mod_ct(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()),
252
5
                    1,
253
5
                    BN_is_zero(bn[1].GetPtr()));
254
3
            break;
255
0
#endif
256
14
        default:
257
14
            goto end;
258
14
            break;
259
88
    }
260
261
    /* OpenSSL and derivatives deal with negative inputs
262
     * to Mod differently than some other libraries.
263
     * Compute the result but don't return it.
264
     */
265
36
    if (    !BN_is_negative(bn[0].GetPtr()) &&
266
36
            !BN_is_negative(bn[1].GetPtr()) ) {
267
25
        ret = true;
268
25
    }
269
270
88
end:
271
88
    return ret;
272
36
}
273
274
1.52k
bool ExpMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
275
1.52k
    (void)ctx;
276
1.52k
    bool ret = false;
277
#if defined(CRYPTOFUZZ_OPENSSL_098)
278
    {
279
        Bignum zero(ds);
280
        CF_CHECK_EQ(zero.New(), true);
281
        CF_CHECK_NE(BN_cmp(bn[1].GetPtr(), zero.GetPtr()), 0);
282
        CF_CHECK_NE(BN_cmp(bn[2].GetPtr(), zero.GetPtr()), 0);
283
    }
284
#endif
285
1.52k
    GET_WHICH(6);
286
1.52k
    switch ( which ) {
287
563
        case    0:
288
563
            {
289
                /* Hint to call RSAZ_1024_mod_exp_avx2 */
290
                /* https://github.com/openssl/openssl/blob/128d1c3c0a12fe68175a460e06daf1e0d940f681/crypto/bn/bn_exp.c#L664 */
291
563
                try {
292
563
                    const auto data = ds.GetData(0, 128, 128);
293
563
                    CF_NORET(util::HintBignum(util::BinToDec(data)));
294
563
                } catch ( fuzzing::datasource::Datasource::OutOfData& ) { }
295
563
            }
296
297
563
            {
298
                /* Hint to call RSAZ_512_mod_exp */
299
                /* https://github.com/openssl/openssl/blob/128d1c3c0a12fe68175a460e06daf1e0d940f681/crypto/bn/bn_exp.c#L675 */
300
563
                try {
301
563
                    const auto data = ds.GetData(0, 64, 64);
302
563
                    CF_NORET(util::HintBignum(util::BinToDec(data)));
303
563
                } catch ( fuzzing::datasource::Datasource::OutOfData& ) { }
304
563
            }
305
306
563
            {
307
                /* Hint to find https://boringssl-review.googlesource.com/c/boringssl/+/52825 */
308
                /* (and possibly similar bugs) */
309
563
                const boost::multiprecision::cpp_int v = rand() % 50;
310
563
                const boost::multiprecision::cpp_int h = boost::multiprecision::pow(v, 95 + (rand() % 10));
311
563
                const auto hint = h.str();
312
563
                CF_NORET(util::HintBignum(hint));
313
563
            }
314
315
563
            CF_ASSERT_EQ_COND(
316
563
                    BN_mod_exp_mont_consttime(
317
563
                        res.GetDestPtr(),
318
563
                        bn[0].GetPtr(),
319
563
                        bn[1].GetPtr(),
320
563
                        bn[2].GetPtr(),
321
563
                        ctx.GetPtr(),
322
563
                        nullptr),
323
563
                    1,
324
563
#if !defined(CRYPTOFUZZ_BORINGSSL)
325
563
                    BN_is_zero(bn[2].GetPtr()) || !BN_is_odd(bn[2].GetPtr()));
326
#else
327
                    BN_is_zero(bn[2].GetPtr()) ||
328
                    !BN_is_odd(bn[2].GetPtr()) ||
329
                    BN_cmp(bn[0].GetPtr(), bn[2].GetPtr()) >= 0);
330
#endif
331
141
            break;
332
377
        case    1:
333
377
            CF_ASSERT_EQ_COND(
334
377
                    BN_mod_exp_mont(
335
377
                        res.GetDestPtr(),
336
377
                        bn[0].GetPtr(),
337
377
                        bn[1].GetPtr(),
338
377
                        bn[2].GetPtr(),
339
377
                        ctx.GetPtr(),
340
377
                        nullptr),
341
377
                    1,
342
377
#if !defined(CRYPTOFUZZ_BORINGSSL)
343
377
                    BN_is_zero(bn[2].GetPtr()) || !BN_is_odd(bn[2].GetPtr()));
344
#else
345
                    BN_is_zero(bn[2].GetPtr()) ||
346
                    !BN_is_odd(bn[2].GetPtr()) ||
347
                    BN_cmp(bn[0].GetPtr(), bn[2].GetPtr()) >= 0);
348
#endif
349
146
            break;
350
235
        case    2:
351
235
            CF_ASSERT_EQ_COND(
352
235
                    BN_mod_exp(
353
235
                        res.GetDestPtr(),
354
235
                        bn[0].GetPtr(),
355
235
                        bn[1].GetPtr(),
356
235
                        bn[2].GetPtr(),
357
235
                        ctx.GetPtr()),
358
235
                    1,
359
235
                    BN_is_zero(bn[2].GetPtr()) || !BN_is_odd(bn[2].GetPtr()));
360
223
            break;
361
129
        case    3:
362
129
#if !defined(CRYPTOFUZZ_BORINGSSL)
363
129
            CF_CHECK_EQ(BN_mod_exp_simple(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), ctx.GetPtr()), 1);
364
#else
365
            goto end;
366
#endif
367
113
            break;
368
#if !defined(CRYPTOFUZZ_BORINGSSL) && !defined(CRYPTOFUZZ_LIBRESSL) && !defined(CRYPTOFUZZ_OPENSSL_102) && !defined(CRYPTOFUZZ_OPENSSL_098)
369
        case    4:
370
            {
371
                {
372
                    uint8_t which = 0;
373
374
                    try {
375
                        which = ds.Get<uint8_t>() % 4;
376
                    } catch ( fuzzing::datasource::Datasource::OutOfData& ) { }
377
378
                    int factor_size = 0;
379
380
                    switch ( which ) {
381
                        case    1:
382
                            factor_size = 1024;
383
                            break;
384
                        case    2:
385
                            factor_size = 1536;
386
                            break;
387
                        case    3:
388
                            factor_size = 2048;
389
                            break;
390
                    }
391
392
                    if ( which != 0 ) {
393
                        {
394
                            Bignum hint_base(ds);
395
                            CF_CHECK_TRUE(hint_base.New());
396
                            BN_rand(hint_base.GetDestPtr(), factor_size, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY);
397
                            util::HintBignumOpt(hint_base.ToString());
398
                        }
399
400
                        {
401
                            Bignum hint_exp(ds);
402
                            CF_CHECK_TRUE(hint_exp.New());
403
                            BN_rand(hint_exp.GetDestPtr(), factor_size, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY);
404
                            util::HintBignumOpt(hint_exp.ToString());
405
                        }
406
407
                        {
408
                            Bignum hint_mod(ds);
409
                            CF_CHECK_TRUE(hint_mod.New());
410
                            BN_rand(hint_mod.GetDestPtr(), factor_size, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD);
411
                            util::HintBignumOpt(hint_mod.ToString());
412
                        }
413
                    }
414
                }
415
416
                Bignum r_mont_const_x2_2(ds);
417
                CF_CHECK_TRUE(r_mont_const_x2_2.New());
418
419
                const auto base = bn[0].GetPtr();
420
                const auto exp = bn[1].GetPtr();
421
                const auto mod = bn[2].GetPtr();
422
423
                CF_CHECK_EQ(BN_mod_exp_mont_consttime_x2(
424
                            res.GetDestPtr(),
425
                            base, exp, mod, nullptr,
426
427
                            r_mont_const_x2_2.GetDestPtr(),
428
                            base, exp, mod, nullptr,
429
                            ctx.GetPtr()), 1);
430
            }
431
            break;
432
#endif
433
114
        case    5:
434
114
            {
435
114
                Bignum one(ds);
436
114
                CF_CHECK_EQ(one.New(), true);
437
114
                BN_one(one.GetDestPtr());
438
439
114
                BIGNUM const * a2 = one.GetPtr();
440
114
                BIGNUM const * p2 = BN_is_zero(bn[3].GetPtr()) ? a2 : bn[3].GetPtr();
441
                /* a2^p2 == 1 */
442
443
                /* result = (a1^p1 * a2^p2) % m */
444
114
                CF_CHECK_EQ(BN_mod_exp2_mont(
445
114
                            res.GetDestPtr(),
446
114
                            bn[0].GetPtr(), bn[1].GetPtr(),
447
114
                            a2, p2,
448
114
                            bn[2].GetPtr(),
449
114
                            ctx.GetPtr(), NULL), 1);
450
451
                /* Unlike other exponentation functions,
452
                 * with BN_mod_exp2_mont,
453
                 * exponentiation by 0 doesn't result in 1
454
                 */
455
93
                CF_CHECK_NE(BN_is_zero(bn[1].GetPtr()), 1);
456
85
            }
457
0
            break;
458
88
        case    6:
459
88
            {
460
88
                const auto val = bn[0].AsBN_ULONG();
461
88
                CF_CHECK_NE(val, std::nullopt);
462
64
                CF_CHECK_EQ(BN_mod_exp_mont_word(res.GetDestPtr(), *val, bn[1].GetPtr(), bn[2].GetPtr(), ctx.GetPtr(), nullptr), 1);
463
48
            }
464
0
            break;
465
17
        default:
466
17
            goto end;
467
17
            break;
468
469
1.52k
    }
470
471
756
    ret = true;
472
473
1.52k
end:
474
1.52k
    return ret;
475
756
}
476
477
19
bool Sqr::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
478
19
    (void)ds;
479
19
    bool ret = false;
480
481
19
    CF_ASSERT_EQ(BN_sqr(bn.GetResPtr(), bn[0].GetPtr(), ctx.GetPtr()), 1);
482
19
    CF_NORET(bn.CopyResult(res));
483
484
19
    ret = true;
485
486
19
    return ret;
487
19
}
488
489
362
bool GCD::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
490
362
    (void)ds;
491
362
    bool ret = false;
492
493
362
    GET_WHICH(1);
494
362
    switch ( which ) {
495
265
        case    0:
496
265
            CF_ASSERT_EQ(BN_gcd(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
497
265
            CF_NORET(bn.CopyResult(res));
498
265
            break;
499
0
#if defined(CRYPTOFUZZ_LIBRESSL)
500
97
        case    1:
501
97
            CF_CHECK_EQ(BN_gcd_ct(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
502
66
            break;
503
0
#endif
504
0
        default:
505
0
            goto end;
506
362
    }
507
508
331
    ret = true;
509
510
362
end:
511
362
    return ret;
512
331
}
513
514
51
bool AddMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
515
51
    bool ret = false;
516
517
51
    GET_WHICH(1);
518
51
    switch ( which ) {
519
33
        case    0:
520
33
            CF_ASSERT_EQ_COND(
521
33
                    BN_mod_add(
522
33
                        res.GetDestPtr(),
523
33
                        bn[0].GetPtr(),
524
33
                        bn[1].GetPtr(),
525
33
                        bn[2].GetPtr(),
526
33
                        ctx.GetPtr()),
527
33
                    1,
528
33
                    BN_is_zero(bn[2].GetPtr()));
529
21
            break;
530
18
        case    1:
531
18
            {
532
18
                Bignum zero(ds);
533
18
                CF_CHECK_EQ(zero.New(), true);
534
535
                /* "... may be used if both a and b are non-negative and less than m" */
536
18
                CF_CHECK_GTE(BN_cmp(bn[0].GetPtr(), zero.GetPtr()), 0);
537
11
                CF_CHECK_GTE(BN_cmp(bn[1].GetPtr(), zero.GetPtr()), 0);
538
10
                CF_CHECK_LT(BN_cmp(bn[0].GetPtr(), bn[2].GetPtr()), 0);
539
5
                CF_CHECK_LT(BN_cmp(bn[1].GetPtr(), bn[2].GetPtr()), 0);
540
5
                CF_ASSERT_EQ(
541
5
                        BN_mod_add_quick(
542
5
                            res.GetDestPtr(),
543
5
                            bn[0].GetPtr(),
544
5
                            bn[1].GetPtr(),
545
5
                            bn[2].GetPtr()),
546
5
                        1);
547
5
            }
548
0
            break;
549
0
        default:
550
0
            goto end;
551
0
            break;
552
51
    }
553
554
26
    ret = true;
555
556
51
end:
557
51
    return ret;
558
26
}
559
560
83
bool SubMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
561
83
    bool ret = false;
562
563
83
    GET_WHICH(1);
564
83
    switch ( which ) {
565
47
        case    0:
566
47
            CF_ASSERT_EQ_COND(
567
47
                    BN_mod_sub(
568
47
                        res.GetDestPtr(),
569
47
                        bn[0].GetPtr(),
570
47
                        bn[1].GetPtr(),
571
47
                        bn[2].GetPtr(),
572
47
                        ctx.GetPtr()),
573
47
                    1,
574
47
                    BN_is_zero(bn[2].GetPtr()));
575
37
            break;
576
36
        case    1:
577
36
            {
578
36
                Bignum zero(ds);
579
36
                CF_CHECK_EQ(zero.New(), true);
580
581
                /* "... may be used if both a and b are non-negative and less than m" */
582
36
                CF_CHECK_GTE(BN_cmp(bn[0].GetPtr(), zero.GetPtr()), 0);
583
30
                CF_CHECK_GTE(BN_cmp(bn[1].GetPtr(), zero.GetPtr()), 0);
584
29
                CF_CHECK_LT(BN_cmp(bn[0].GetPtr(), bn[2].GetPtr()), 0);
585
18
                CF_CHECK_LT(BN_cmp(bn[1].GetPtr(), bn[2].GetPtr()), 0);
586
8
                CF_ASSERT_EQ(BN_mod_sub_quick(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr()), 1);
587
8
                break;
588
8
            }
589
            /* bn_mod_sub_fixed_top is disabled because it puts the output bignum
590
             * in a state that is not compatible with the rest of the bignum API.
591
             *
592
             * Discussion: https://github.com/openssl/openssl/issues/14767
593
             */
594
#if 0
595
        case    2:
596
            /*
597
               "BN_mod_sub variant that may be used if both a and b are non-negative,
598
               a is less than m, while b is of same bit width as m. It's implemented
599
               as subtraction followed by two conditional additions."
600
               */
601
602
            CF_CHECK_LT(bn[0].GetPtr(), bn[2].GetPtr());
603
            CF_CHECK_EQ(BN_num_bits(bn[1].GetPtr()), BN_num_bits(bn[2].GetPtr()));
604
            CF_CHECK_EQ(bn_mod_sub_fixed_top(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr()), 1);
605
            break;
606
#endif
607
0
        default:
608
0
            goto end;
609
0
            break;
610
83
    }
611
612
45
    ret = true;
613
614
83
end:
615
83
    return ret;
616
45
}
617
618
59
bool MulMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
619
59
    bool ret = false;
620
#if !defined(CRYPTOFUZZ_LIBRESSL) && !defined(CRYPTOFUZZ_BORINGSSL)
621
    BN_RECP_CTX* recp = nullptr;
622
#endif
623
624
59
    GET_WHICH(2);
625
59
    switch ( which ) {
626
35
        case    0:
627
35
            {
628
35
                BIGNUM* r = bn.GetResPtr();
629
35
                const BIGNUM* a = bn[0].GetPtr();
630
35
                const BIGNUM* b = bn[1].GetPtr();
631
35
                const BIGNUM* m = bn[2].GetPtr();
632
35
                CF_ASSERT_EQ_COND(
633
35
                        BN_mod_mul(
634
35
                            r, a, b, m,
635
35
                            ctx.GetPtr()),
636
35
                        1,
637
                        /* Can fail with zero modulus */
638
35
                        BN_is_zero(m) ||
639
                        /* Aliasing result and modulus is prohibited */
640
35
                        r == m);
641
22
                CF_NORET(bn.CopyResult(res));
642
22
            }
643
0
            break;
644
0
#if !defined(CRYPTOFUZZ_OPENSSL_098)
645
        /* Bug */
646
17
        case    1:
647
17
            {
648
17
                BN_MONT_CTX mont(ds);
649
650
                /* Set mod */
651
17
                CF_CHECK_EQ(BN_MONT_CTX_set(mont.GetPtr(), bn[2].GetPtr(), ctx.GetPtr()), 1);
652
653
6
                Bignum bn0_mont(ds);
654
                /* bn0 to mont */
655
6
                {
656
6
                    CF_CHECK_TRUE(bn0_mont.New());
657
6
                    CF_CHECK_EQ(BN_nnmod(bn0_mont.GetDestPtr(), bn[0].GetPtr(), bn[2].GetPtr(), ctx.GetPtr()), 1);
658
6
                    auto bn0_mont_ptr = bn0_mont.GetDestPtr();
659
6
                    CF_CHECK_EQ(BN_to_montgomery(bn0_mont_ptr, bn0_mont_ptr, mont.GetPtr(), ctx.GetPtr()), 1);
660
6
                }
661
662
0
                Bignum bn1_mont(ds);
663
                /* bn1 to mont */
664
6
                {
665
6
                    CF_CHECK_TRUE(bn1_mont.New());
666
6
                    CF_CHECK_EQ(BN_nnmod(bn1_mont.GetDestPtr(), bn[1].GetPtr(), bn[2].GetPtr(), ctx.GetPtr()), 1);
667
6
                    auto bn1_mont_ptr = bn1_mont.GetDestPtr();
668
6
                    CF_CHECK_EQ(BN_to_montgomery(bn1_mont_ptr, bn1_mont_ptr, mont.GetPtr(), ctx.GetPtr()), 1);
669
6
                }
670
671
                /* mul mod */
672
6
                CF_ASSERT_EQ(BN_mod_mul_montgomery(res.GetDestPtr(), bn0_mont.GetPtr(), bn1_mont.GetPtr(), mont.GetPtr(), ctx.GetPtr()), 1);
673
674
                /* result from mont */
675
6
                auto resPtr = res.GetDestPtr();
676
6
                CF_CHECK_EQ(BN_from_montgomery(resPtr, resPtr, mont.GetPtr(), ctx.GetPtr()), 1);
677
6
            }
678
0
            break;
679
0
#endif
680
#if !defined(CRYPTOFUZZ_LIBRESSL) && !defined(CRYPTOFUZZ_BORINGSSL)
681
        case    2:
682
            {
683
                const bool is_neg = BN_is_negative(bn[0].GetPtr()) ||
684
                    BN_is_negative(bn[1].GetPtr());
685
                CF_CHECK_NE(recp = BN_RECP_CTX_new(), nullptr);
686
                CF_CHECK_EQ(BN_RECP_CTX_set(recp, bn[2].GetPtr(), ctx.GetPtr()), 1);
687
                CF_CHECK_EQ(BN_mod_mul_reciprocal(
688
                            bn.GetResPtr(),
689
                            bn[0].GetPtr(),
690
                            bn[1].GetPtr(),
691
                            recp,
692
                            ctx.GetPtr()), 1);
693
                CF_CHECK_FALSE(is_neg);
694
                CF_NORET(bn.CopyResult(res));
695
            }
696
            break;
697
#endif
698
7
        default:
699
7
            goto end;
700
7
            break;
701
59
    }
702
703
28
    ret = true;
704
705
59
end:
706
#if !defined(CRYPTOFUZZ_LIBRESSL) && !defined(CRYPTOFUZZ_BORINGSSL)
707
    CF_NORET(BN_RECP_CTX_free(recp));
708
#endif
709
710
59
    return ret;
711
28
}
712
713
26
bool SqrMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
714
26
    bool ret = false;
715
716
26
    GET_WHICH(0);
717
26
    switch ( which ) {
718
26
        case    0:
719
26
            CF_ASSERT_EQ_COND(
720
26
                    BN_mod_sqr(
721
26
                        res.GetDestPtr(),
722
26
                        bn[0].GetPtr(),
723
26
                        bn[1].GetPtr(),
724
26
                        ctx.GetPtr()),
725
26
                    1,
726
26
                    BN_is_zero(bn[1].GetPtr()));
727
18
            break;
728
0
        default:
729
0
            goto end;
730
0
            break;
731
26
    }
732
733
18
    ret = true;
734
735
26
end:
736
26
    return ret;
737
18
}
738
739
956
bool InvMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
740
956
    bool ret = false;
741
742
956
    bool fail = false;
743
744
956
    GET_WHICH(2);
745
956
    switch ( which ) {
746
937
        case    0:
747
937
            {
748
937
                BIGNUM* r = bn.GetResPtr();
749
937
                const BIGNUM* a = bn[0].GetPtr();
750
937
                const BIGNUM* n = bn[1].GetPtr();
751
937
                CF_CHECK_NE(r, n);
752
886
                fail = true;
753
886
                CF_CHECK_NE(BN_mod_inverse(r, a, n, ctx.GetPtr()), nullptr);
754
364
                CF_NORET(bn.CopyResult(res));
755
364
                fail = false;
756
364
            }
757
0
            break;
758
#if defined(CRYPTOFUZZ_BORINGSSL)
759
        case    1:
760
            {
761
                int out_no_inverse;
762
                CF_CHECK_LT(BN_cmp(bn[0].GetPtr(), bn[1].GetPtr()), 0);
763
                CF_CHECK_EQ(BN_is_odd(bn[1].GetPtr()), 1);
764
                fail = true;
765
                CF_CHECK_EQ(BN_mod_inverse_odd(res.GetDestPtr(), &out_no_inverse, bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
766
                fail = false;
767
            }
768
            break;
769
        case    2:
770
            {
771
                int out_no_inverse;
772
                BN_MONT_CTX mont(ds);
773
774
                /* Set mod */
775
                CF_CHECK_EQ(BN_MONT_CTX_set(mont.GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
776
777
                /* invmod */
778
                CF_CHECK_EQ(BN_mod_inverse_blinded(res.GetDestPtr(), &out_no_inverse, bn[0].GetPtr(), mont.GetPtr(), ctx.GetPtr()), 1);
779
780
                if ( out_no_inverse ) {
781
                    fail = true;
782
                }
783
            }
784
            break;
785
#endif
786
19
        default:
787
19
            goto end;
788
19
            break;
789
956
    }
790
791
364
    ret = true;
792
793
956
end:
794
956
    if ( fail == true ) {
795
522
        res.Set("0");
796
522
        return true;
797
522
    }
798
799
434
    return ret;
800
956
}
801
802
84
bool Cmp::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
803
84
    (void)ds;
804
84
    (void)ctx;
805
84
    bool ret = false;
806
807
84
    int cmpRes;
808
809
84
    GET_WHICH(2);
810
84
    switch ( which ) {
811
43
        case    0:
812
43
            cmpRes = BN_cmp(bn[0].GetPtr(), bn[1].GetPtr());
813
43
            break;
814
21
        case    1:
815
21
            CF_CHECK_EQ(BN_is_negative(bn[0].GetPtr()), 0);
816
18
            CF_CHECK_EQ(BN_is_negative(bn[1].GetPtr()), 0);
817
17
            cmpRes = BN_ucmp(bn[0].GetPtr(), bn[1].GetPtr());
818
17
            break;
819
#if defined(CRYPTOFUZZ_BORINGSSL)
820
        case    2:
821
            {
822
                auto val = bn[1].AsBN_ULONG();
823
                CF_CHECK_NE(val, std::nullopt);
824
                cmpRes = BN_cmp_word(bn[0].GetPtr(), *val);
825
            }
826
            break;
827
#endif
828
20
        default:
829
20
            goto end;
830
20
            break;
831
84
    }
832
833
60
    if ( cmpRes > 0 ) {
834
19
        cmpRes = 1;
835
41
    } else if ( cmpRes < 0 ) {
836
26
        cmpRes = -1;
837
26
    }
838
839
60
    res.Set( std::to_string(cmpRes) );
840
841
60
    ret = true;
842
843
84
end:
844
84
    return ret;
845
60
}
846
847
175
bool Div::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
848
175
    (void)ds;
849
175
    (void)ctx;
850
175
    bool ret = false;
851
#if !defined(CRYPTOFUZZ_LIBRESSL) && !defined(CRYPTOFUZZ_BORINGSSL)
852
    BN_RECP_CTX* recp = nullptr;
853
#endif
854
855
175
    GET_WHICH(4);
856
175
    switch ( which ) {
857
72
        case    0:
858
72
            CF_ASSERT_EQ_COND(
859
72
                    BN_div(
860
72
                        res.GetDestPtr(),
861
72
                        nullptr,
862
72
                        bn[0].GetPtr(),
863
72
                        bn[1].GetPtr(),
864
72
                        ctx.GetPtr()),
865
72
                    1,
866
72
                    BN_is_zero(bn[1].GetPtr()));
867
62
            break;
868
#if defined(CRYPTOFUZZ_BORINGSSL)
869
        case    1:
870
            {
871
                bool use_divisor_min_bits = false;
872
                try { use_divisor_min_bits = ds. Get<bool>(); } catch ( ... ) { }
873
874
                CF_CHECK_EQ(bn_div_consttime(
875
                            res.GetDestPtr(),
876
                            nullptr,
877
                            bn[0].GetPtr(),
878
                            bn[1].GetPtr(),
879
                            use_divisor_min_bits ? BN_num_bits(bn[1].GetPtrConst()) : 0,
880
                            ctx.GetPtr()), 1);
881
            }
882
            break;
883
#endif
884
47
        case    2:
885
47
            {
886
47
                const auto val = bn[1].AsBN_ULONG();
887
47
                CF_CHECK_NE(val, std::nullopt);
888
889
18
                CF_CHECK_NE(BN_div_word(bn.GetDestPtr(0), *val), (BN_ULONG)-1);
890
15
                CF_CHECK_EQ(res.Set(bn[0]), true);
891
15
            }
892
0
            break;
893
0
#if defined(CRYPTOFUZZ_LIBRESSL)
894
19
        case    3:
895
19
            CF_ASSERT_EQ_COND(
896
19
                    BN_div_ct(
897
19
                        res.GetDestPtr(),
898
19
                        nullptr,
899
19
                        bn[0].GetPtr(),
900
19
                        bn[1].GetPtr(),
901
19
                        ctx.GetPtr()),
902
19
                    1,
903
19
                    BN_is_zero(bn[1].GetPtr()));
904
17
            break;
905
0
#endif
906
#if !defined(CRYPTOFUZZ_LIBRESSL) && !defined(CRYPTOFUZZ_BORINGSSL)
907
        case    4:
908
            {
909
                const bool is_neg = BN_is_negative(bn[0].GetPtr());
910
                CF_CHECK_NE(recp = BN_RECP_CTX_new(), nullptr);
911
                CF_CHECK_EQ(BN_RECP_CTX_set(recp, bn[1].GetPtr(), ctx.GetPtr()), 1);
912
                CF_CHECK_EQ(BN_div_recp(
913
                            res.GetDestPtr(),
914
                            nullptr,
915
                            bn[0].GetPtr(),
916
                            recp,
917
                            ctx.GetPtr()), 1);
918
                CF_CHECK_FALSE(is_neg);
919
            }
920
            break;
921
#endif
922
37
        default:
923
37
            goto end;
924
37
            break;
925
175
    }
926
927
94
    ret = true;
928
929
175
end:
930
#if !defined(CRYPTOFUZZ_LIBRESSL) && !defined(CRYPTOFUZZ_BORINGSSL)
931
    CF_NORET(BN_RECP_CTX_free(recp));
932
#endif
933
934
175
    return ret;
935
94
}
936
937
553
bool IsPrime::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
938
553
    (void)ds;
939
553
    (void)ctx;
940
941
553
#if defined(CRYPTOFUZZ_BORINGSSL) || defined(CRYPTOFUZZ_LIBRESSL)
942
    /* Prevent timeouts */
943
553
    if ( BN_num_bits(bn[0].GetPtr()) > 3000 ) {
944
95
        return false;
945
95
    }
946
947
458
    const int ret = BN_is_prime_ex(bn[0].GetPtr(), 0, nullptr, nullptr);
948
458
    if ( ret == -1 ) {
949
0
        return false;
950
0
    }
951
952
458
    res.Set( std::to_string(ret) );
953
954
458
    return true;
955
#else
956
    (void)res;
957
    (void)bn;
958
    return false;
959
#endif
960
458
}
961
962
143
bool Sqrt::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
963
143
    (void)ds;
964
143
    bool ret = false;
965
966
#if defined(CRYPTOFUZZ_BORINGSSL)
967
    CF_CHECK_EQ(BN_sqrt(res.GetDestPtr(), bn[0].GetPtr(), ctx.GetPtr()), 1);
968
969
    ret = true;
970
971
end:
972
#elif defined(CRYPTOFUZZ_LIBRESSL)
973
143
    int perfect;
974
143
    CF_CHECK_EQ(bn_isqrt(res.GetDestPtr(), &perfect, bn[0].GetPtr(), ctx.GetPtr()), 1);
975
976
136
    ret = true;
977
978
143
end:
979
#else
980
    (void)res;
981
    (void)bn;
982
    (void)ctx;
983
984
#endif
985
143
    return ret;
986
136
}
987
988
18
bool IsNeg::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
989
18
    (void)ds;
990
18
    (void)ctx;
991
992
18
    res.Set( std::to_string(BN_is_negative(bn[0].GetPtr())) );
993
994
18
    return true;
995
18
}
996
997
11
bool IsEq::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
998
11
    (void)ds;
999
11
    (void)ctx;
1000
1001
#if defined(CRYPTOFUZZ_BORINGSSL)
1002
    bool ret = false;
1003
1004
    GET_WHICH(1);
1005
    switch ( which ) {
1006
        case    0:
1007
            res.Set( std::to_string(BN_equal_consttime(bn[0].GetPtr(), bn[1].GetPtr())) );
1008
            break;
1009
        case    1:
1010
            {
1011
                auto val = bn[1].AsBN_ULONG();
1012
                CF_CHECK_NE(val, std::nullopt);
1013
                res.Set( std::to_string(BN_is_word(bn[0].GetPtr(), *val)) );
1014
            }
1015
            break;
1016
        default:
1017
            goto end;
1018
    }
1019
1020
    ret = true;
1021
1022
end:
1023
1024
    return ret;
1025
#else
1026
11
    (void)res;
1027
11
    (void)bn;
1028
11
    return false;
1029
11
#endif
1030
11
}
1031
1032
13
bool IsEven::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1033
13
    (void)ds;
1034
13
    (void)ctx;
1035
1036
13
    res.Set( std::to_string(!BN_is_odd(bn[0].GetPtr())) );
1037
1038
13
    return true;
1039
13
}
1040
1041
3
bool IsOdd::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1042
3
    (void)ds;
1043
3
    (void)ctx;
1044
1045
3
    res.Set( std::to_string(BN_is_odd(bn[0].GetPtr())) );
1046
1047
3
    return true;
1048
3
}
1049
1050
11
bool IsZero::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1051
11
    (void)ds;
1052
11
    (void)ctx;
1053
1054
11
    res.Set( std::to_string(BN_is_zero(bn[0].GetPtr())) );
1055
1056
11
    return true;
1057
11
}
1058
1059
11
bool IsOne::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1060
11
    (void)ds;
1061
11
    (void)ctx;
1062
1063
11
    res.Set( std::to_string(BN_is_one(bn[0].GetPtr())) );
1064
1065
11
    return true;
1066
11
}
1067
1068
861
bool Jacobi::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1069
861
    (void)ds;
1070
861
    bool ret = false;
1071
1072
861
#if !defined(CRYPTOFUZZ_BORINGSSL)
1073
861
    const int jacobi = BN_kronecker(bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr());
1074
#else
1075
    const int jacobi = bn_jacobi(bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr());
1076
#endif
1077
1078
861
    CF_CHECK_NE(jacobi, -2);
1079
1080
861
    res.Set( std::to_string(jacobi) );
1081
1082
861
    ret = true;
1083
861
end:
1084
1085
861
    return ret;
1086
861
}
1087
1088
/* OpenSSL 0.9.8 has memory bugs in these functions */
1089
#if !defined(CRYPTOFUZZ_BORINGSSL) && !defined(CRYPTOFUZZ_OPENSSL_098) && !defined(CRYPTOFUZZ_LIBRESSL)
1090
bool Mod_NIST_192::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1091
    (void)ds;
1092
    bool ret = false;
1093
1094
    CF_ASSERT_EQ(BN_nist_mod_192(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1095
1096
    ret = true;
1097
1098
    return ret;
1099
}
1100
1101
bool Mod_NIST_224::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1102
    (void)ds;
1103
    bool ret = false;
1104
1105
    CF_ASSERT_EQ(BN_nist_mod_224(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1106
1107
    ret = true;
1108
1109
    return ret;
1110
}
1111
1112
bool Mod_NIST_256::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1113
    (void)ds;
1114
    bool ret = false;
1115
1116
    CF_ASSERT_EQ(BN_nist_mod_256(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1117
1118
    ret = true;
1119
1120
    return ret;
1121
}
1122
1123
bool Mod_NIST_384::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1124
    (void)ds;
1125
    bool ret = false;
1126
1127
    CF_ASSERT_EQ(BN_nist_mod_384(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1128
1129
    ret = true;
1130
1131
    return ret;
1132
}
1133
1134
bool Mod_NIST_521::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1135
    (void)ds;
1136
    bool ret = false;
1137
1138
    CF_ASSERT_EQ(BN_nist_mod_521(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1139
1140
    ret = true;
1141
1142
    return ret;
1143
}
1144
#endif
1145
1146
#if 0
1147
bool SqrtMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1148
    /* Disabled due to slowness of primality testing */
1149
#if 0
1150
    (void)ds;
1151
    bool ret = false;
1152
1153
    /* Third parameter to BN_mod_sqrt must be prime */
1154
    CF_CHECK_EQ(BN_is_prime_ex(bn[1].GetPtr(), 64, ctx.GetPtr(), nullptr), 1);
1155
    CF_CHECK_NE(BN_mod_sqrt(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), nullptr);
1156
1157
    ret = true;
1158
1159
end:
1160
    return ret;
1161
#else
1162
    (void)ds;
1163
    (void)res;
1164
    (void)bn;
1165
    (void)ctx;
1166
    return false;
1167
#endif
1168
}
1169
#endif
1170
1171
51
bool SqrtMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1172
51
    (void)ds;
1173
51
    bool ret = false;
1174
51
    bool setzero = true;
1175
1176
51
    CF_CHECK_NE(BN_mod_sqrt(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), nullptr);
1177
37
    {
1178
37
        auto resPtr = res.GetDestPtr();
1179
37
        CF_CHECK_EQ(BN_mod_mul(resPtr, resPtr, resPtr, bn[1].GetPtr(), ctx.GetPtr()), 1);
1180
37
    }
1181
1182
0
    setzero = false;
1183
1184
51
end:
1185
51
    if ( setzero ) {
1186
14
        BN_zero(res.GetDestPtr());
1187
14
    }
1188
1189
51
    ret = true;
1190
1191
51
    return ret;
1192
37
}
1193
1194
#if defined(CRYPTOFUZZ_BORINGSSL)
1195
bool LCM::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1196
    (void)ds;
1197
    bool ret = false;
1198
1199
    CF_CHECK_EQ(bn_lcm_consttime(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1200
1201
    ret = true;
1202
1203
end:
1204
    return ret;
1205
}
1206
#endif
1207
1208
95
bool Exp::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1209
95
    (void)ds;
1210
95
    bool ret = false;
1211
1212
95
    CF_CHECK_EQ(BN_exp(res.GetDestPtr(), bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1213
1214
93
    ret = true;
1215
1216
95
end:
1217
95
    return ret;
1218
93
}
1219
1220
47
bool Abs::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1221
47
    (void)ds;
1222
47
    (void)ctx;
1223
47
    bool ret = false;
1224
1225
47
    if ( BN_is_negative(bn[0].GetPtr()) ) {
1226
34
        Bignum zero(ds);
1227
34
        CF_CHECK_EQ(zero.New(), true);
1228
1229
34
        GET_WHICH(1);
1230
34
        switch ( which ) {
1231
20
            case    0:
1232
20
                CF_ASSERT_EQ(BN_sub(res.GetDestPtr(), zero.GetPtr(), bn[0].GetPtr()), 1);
1233
20
                break;
1234
14
            case    1:
1235
14
                {
1236
14
                    auto bn0 = bn[0].GetPtr();
1237
14
                    CF_ASSERT_EQ(BN_sub(res.GetDestPtr(), bn0, bn0), 1);
1238
14
                }
1239
0
                {
1240
14
                    auto resPtr = res.GetDestPtr();
1241
14
                    CF_ASSERT_EQ(BN_sub(resPtr, resPtr, bn[0].GetPtr()), 1);
1242
14
                }
1243
0
                break;
1244
0
            default:
1245
0
                goto end;
1246
0
                break;
1247
34
        }
1248
34
    } else {
1249
13
        CF_CHECK_NE(BN_copy(res.GetDestPtr(), bn[0].GetPtr()), nullptr);
1250
13
    }
1251
1252
47
    ret = true;
1253
1254
47
end:
1255
47
    return ret;
1256
47
}
1257
1258
28
bool RShift::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1259
28
    (void)ctx;
1260
28
    bool ret = false;
1261
28
    std::optional<int> places;
1262
1263
28
    GET_WHICH(1);
1264
1265
28
    CF_CHECK_NE(places = bn[1].AsInt(), std::nullopt);
1266
1267
23
    switch ( which ) {
1268
19
        case    0:
1269
19
            CF_ASSERT_EQ(BN_rshift(res.GetDestPtr(), bn[0].GetPtr(), *places), 1);
1270
19
            break;
1271
4
        case    1:
1272
4
            if ( *places != 1 ) {
1273
4
                goto end;
1274
4
            }
1275
0
            CF_ASSERT_EQ(BN_rshift1(res.GetDestPtr(), bn[0].GetPtr()), 1);
1276
0
            break;
1277
0
        default:
1278
0
            goto end;
1279
23
    }
1280
1281
19
    ret = true;
1282
1283
28
end:
1284
28
    return ret;
1285
19
}
1286
1287
25
bool LShift1::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1288
25
    (void)ctx;
1289
25
    (void)ds;
1290
25
    bool ret = false;
1291
1292
25
    CF_ASSERT_EQ(BN_lshift1(res.GetDestPtr(), bn[0].GetPtr()), 1);
1293
1294
25
    ret = true;
1295
1296
25
    return ret;
1297
25
}
1298
1299
22
bool SetBit::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1300
22
    (void)ctx;
1301
22
    (void)ds;
1302
22
    bool ret = false;
1303
22
    std::optional<int> pos;
1304
1305
22
    CF_CHECK_NE(pos = bn[1].AsInt(), std::nullopt);
1306
1307
19
    CF_ASSERT_EQ(BN_set_bit(bn.GetDestPtr(0), *pos), 1);
1308
19
    CF_CHECK_NE(BN_copy(res.GetDestPtr(), bn[0].GetPtr()), nullptr);
1309
1310
19
    ret = true;
1311
1312
22
end:
1313
22
    return ret;
1314
19
}
1315
1316
23
bool ClearBit::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1317
23
    (void)ctx;
1318
23
    (void)ds;
1319
23
    bool ret = false;
1320
23
    std::optional<int> pos;
1321
1322
23
    CF_CHECK_NE(pos = bn[1].AsInt(), std::nullopt);
1323
1324
16
    CF_CHECK_EQ(BN_clear_bit(bn.GetDestPtr(0), *pos), 1);
1325
10
    CF_CHECK_NE(BN_copy(res.GetDestPtr(), bn[0].GetPtr()), nullptr);
1326
1327
10
    ret = true;
1328
1329
23
end:
1330
23
    return ret;
1331
10
}
1332
1333
18
bool Bit::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1334
18
    (void)ctx;
1335
18
    (void)ds;
1336
18
    bool ret = false;
1337
18
    std::optional<int> pos;
1338
1339
18
    CF_CHECK_NE(pos = bn[1].AsInt(), std::nullopt);
1340
1341
7
    res.Set( std::to_string(BN_is_bit_set(bn[0].GetPtr(), *pos)) );
1342
1343
7
    ret = true;
1344
1345
18
end:
1346
18
    return ret;
1347
7
}
1348
1349
27
bool CmpAbs::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1350
27
    (void)ctx;
1351
27
    (void)ds;
1352
1353
27
    int cmpRes = BN_ucmp(bn[0].GetPtr(), bn[1].GetPtr());
1354
1355
27
    if ( cmpRes > 0 ) {
1356
9
        cmpRes = 1;
1357
18
    } else if ( cmpRes < 0 ) {
1358
7
        cmpRes = -1;
1359
7
    }
1360
1361
27
    res.Set( std::to_string(cmpRes) );
1362
1363
27
    return true;
1364
27
}
1365
1366
97
bool ModLShift::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1367
97
    (void)ctx;
1368
97
    (void)ds;
1369
97
    bool ret = false;
1370
97
    std::optional<int> places;
1371
1372
97
    GET_WHICH(3);
1373
1374
97
    CF_CHECK_NE(places = bn[1].AsInt(), std::nullopt);
1375
1376
90
    switch ( which ) {
1377
33
        case    0:
1378
33
            CF_CHECK_EQ(BN_mod_lshift(res.GetDestPtr(), bn[0].GetPtr(), *places, bn[2].GetPtr(), ctx.GetPtr()), 1);
1379
21
            break;
1380
27
        case    1:
1381
            /* BN_mod_lshift_quick acts like BN_mod_lshift but requires that a be non-negative and less than m. */
1382
27
            CF_CHECK_EQ(BN_is_negative(bn[0].GetPtr()), 0);
1383
27
            CF_CHECK_LT(BN_cmp(bn[0].GetPtr(), bn[2].GetPtr()), 0);
1384
11
            CF_CHECK_EQ(BN_mod_lshift_quick(res.GetDestPtr(), bn[0].GetPtr(), *places, bn[2].GetPtr()), 1);
1385
11
            break;
1386
10
        case    2:
1387
10
            CF_NORET(util::HintBignum("1"));
1388
10
            CF_CHECK_EQ(*places, 1);
1389
4
            CF_CHECK_EQ(BN_mod_lshift1(res.GetDestPtr(), bn[0].GetPtr(), bn[2].GetPtr(), ctx.GetPtr()), 1);
1390
4
            break;
1391
20
        case    3:
1392
20
            CF_NORET(util::HintBignum("1"));
1393
20
            CF_CHECK_EQ(*places, 1);
1394
            /* BN_mod_lshift1_quick acts like BN_mod_lshift1 but requires that a be non-negative and less than m. */
1395
12
            CF_CHECK_EQ(BN_is_negative(bn[0].GetPtr()), 0);
1396
12
            CF_CHECK_LT(BN_cmp(bn[0].GetPtr(), bn[2].GetPtr()), 0);
1397
6
            CF_CHECK_EQ(BN_mod_lshift1_quick(res.GetDestPtr(), bn[0].GetPtr(), bn[2].GetPtr()), 1);
1398
6
            break;
1399
0
        default:
1400
0
            goto end;
1401
90
    }
1402
1403
42
    ret = true;
1404
1405
97
end:
1406
97
    return ret;
1407
42
}
1408
1409
12
bool IsPow2::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1410
12
    (void)ctx;
1411
12
    (void)ds;
1412
1413
#if defined(CRYPTOFUZZ_BORINGSSL)
1414
    CF_NORET(util::HintBignumPow2());
1415
    res.Set( std::to_string(BN_is_pow2(bn[0].GetPtr())) );
1416
1417
    return true;
1418
#else
1419
12
    (void)res;
1420
12
    (void)bn;
1421
1422
12
    return false;
1423
12
#endif
1424
12
}
1425
1426
12
bool Mask::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1427
12
    (void)ctx;
1428
12
    (void)ds;
1429
12
    bool ret = false;
1430
1431
12
    std::optional<int> places;
1432
1433
12
    CF_CHECK_NE(places = bn[1].AsInt(), std::nullopt);
1434
11
    CF_CHECK_EQ(BN_mask_bits(bn[0].GetDestPtr(), *places), 1);
1435
8
    CF_CHECK_EQ(res.Set(bn[0]), true);
1436
1437
8
    ret = true;
1438
1439
12
end:
1440
12
    return ret;
1441
8
}
1442
1443
1
bool IsCoprime::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1444
#if defined(CRYPTOFUZZ_BORINGSSL)
1445
    (void)ds;
1446
1447
    bool ret = false;
1448
    int out_relatively_prime;
1449
1450
    CF_CHECK_EQ(bn_is_relatively_prime(&out_relatively_prime, bn[0].GetPtr(), bn[1].GetPtr(), ctx.GetPtr()), 1);
1451
    CF_CHECK_EQ(res.Set( std::to_string(out_relatively_prime) ), true);
1452
1453
    ret = true;
1454
end:
1455
    return ret;
1456
#else
1457
1
    (void)ds;
1458
1
    (void)res;
1459
1
    (void)bn;
1460
1
    (void)ctx;
1461
1
    return false;
1462
1
#endif
1463
1
}
1464
1465
122
bool Rand::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1466
122
    (void)ctx;
1467
#if defined(CRYPTOFUZZ_OPENSSL_098)
1468
    (void)bn;
1469
#endif
1470
1471
122
    bool ret = false;
1472
1473
122
    GET_WHICH(3);
1474
122
    switch ( which ) {
1475
0
#if !defined(CRYPTOFUZZ_OPENSSL_098)
1476
21
        case    0:
1477
21
            CF_CHECK_EQ(BN_rand_range(res.GetDestPtr(), bn[0].GetPtr()), 1);
1478
15
            break;
1479
35
        case    1:
1480
35
            CF_CHECK_EQ(BN_pseudo_rand_range(res.GetDestPtr(), bn[0].GetPtr()), 1);
1481
25
            break;
1482
0
#endif
1483
1484
28
        case    2:
1485
28
            {
1486
28
                const auto bits = ds.Get<uint8_t>();
1487
28
                const auto top = ds.Get<uint8_t>();
1488
28
                const auto bottom = ds.Get<uint8_t>();
1489
#if defined(CRYPTOFUZZ_OPENSSL_098)
1490
                /* Bug */
1491
                goto end;
1492
#endif
1493
28
                CF_CHECK_EQ(BN_rand(res.GetDestPtr(), bits, top, bottom), 1);
1494
24
            }
1495
0
            break;
1496
38
        case    3:
1497
38
            {
1498
38
                const auto bits = ds.Get<uint8_t>();
1499
38
                const auto top = ds.Get<uint8_t>();
1500
38
                const auto bottom = ds.Get<uint8_t>();
1501
#if defined(CRYPTOFUZZ_OPENSSL_098)
1502
                /* Bug */
1503
                goto end;
1504
#endif
1505
38
                CF_CHECK_EQ(BN_pseudo_rand(res.GetDestPtr(), bits, top, bottom), 1);
1506
33
            }
1507
0
            break;
1508
0
        default:
1509
0
            ret = false;
1510
0
            break;
1511
122
    }
1512
1513
96
    ret = true;
1514
1515
121
end:
1516
121
    return ret;
1517
96
}
1518
1519
52
bool IsSquare::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1520
52
    (void)ds;
1521
52
    bool ret = false;
1522
1523
52
#if defined(CRYPTOFUZZ_LIBRESSL)
1524
52
    ret = true;
1525
1526
52
    int perfect;
1527
52
    CF_CHECK_EQ(bn_is_perfect_square(&perfect, bn[0].GetPtr(), ctx.GetPtr()), 1);
1528
1529
52
    res.Set( std::to_string(perfect) );
1530
1531
52
    ret = true;
1532
1533
52
end:
1534
#else
1535
    (void)res;
1536
    (void)bn;
1537
    (void)ctx;
1538
1539
#endif
1540
52
    return ret;
1541
52
}
1542
1543
14
bool Neg::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1544
14
    (void)ds;
1545
14
    (void)bn;
1546
14
    (void)ctx;
1547
1548
14
    bool ret = false;
1549
1550
14
    CF_CHECK_NE(BN_copy(res.GetDestPtr(), bn[0].GetPtr()), nullptr);
1551
14
    CF_NORET(BN_set_negative(res.GetDestPtr(), !BN_is_negative(bn[0].GetPtr())));
1552
1553
14
    ret = true;
1554
1555
14
end:
1556
14
    return ret;
1557
14
}
1558
1559
29
bool RandRange::Run(Datasource& ds, Bignum& res, BignumCluster& bn, BN_CTX& ctx) const {
1560
29
    (void)ds;
1561
29
    (void)ctx;
1562
1563
29
    bool ret = false;
1564
1565
29
    CF_CHECK_EQ(BN_is_zero(bn[0].GetPtr()), 1);
1566
12
    CF_CHECK_EQ(BN_rand_range(bn.GetResPtr(), bn[1].GetPtr()), 1);
1567
2
    CF_NORET(bn.CopyResult(res));
1568
1569
2
    ret = true;
1570
29
end:
1571
29
    return ret;
1572
2
}
1573
1574
} /* namespace OpenSSL_bignum */
1575
} /* namespace module */
1576
} /* namespace cryptofuzz */