/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 */ |