Coverage Report

Created: 2022-08-24 06:31

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