Bignum to Unsigned Long Conversion is Incorrect
marquitos0119 opened this issue · comments
While running cryptofuzz against openssl-3.0, I encountered an input that caused the program to crash. After further investigation, the 2 functions being called are in the ExpMod::Run class, specifically BN_mod_exp_mont_word and BN_mod_exp_mont_consttime.
Both of these functions take in 3 numbers, but BN_mod_exp_mont_consttime takes them in BIGNUM format, whereas BN_mod_exp_mont_word takes 1 unsigned long and 2 BIGNUMS:
int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
So, bn[0] gets converted to a ulong, and investigating with gdb shows that the conversion failed. In this case, bn[0] was 0000000000000013536853764361904580 and the output ulong is 14150647586910952635.
Later, during the result comparison, cryptofuzz fails as the 2 results are different. And in fact they are, since one input value varied between the 2 operations.
If I just trim the leading zero's and use 13536853764361904580, I get the same result as in BN_mod_exp_mont_consttime. Maybe the leading zero's could be trimmed before the BIGNUM->ulong conversion?
Which platform is this, s390x?
It's probably due to
cryptofuzz/modules/openssl/bn_ops.h
Lines 95 to 108 in e9487bd
13536853764361904580 is 14150647586910952635 backwards (in hex). Can you try replacing it with something like
#if (defined(__s390__) || defined(__s390x__) || defined(__zarch__))
/* Manual reversing is required because
* BN_bn2lebinpad is not supported by BoringSSL.
*
* TODO This must be omitted on big-endian platforms.
*/
v =
((v & 0xFF00000000000000) >> 56) |
((v & 0x00FF000000000000) >> 40) |
((v & 0x0000FF0000000000) >> 24) |
((v & 0x000000FF00000000) >> 8) |
((v & 0x00000000FF000000) << 8) |
((v & 0x0000000000FF0000) << 24) |
((v & 0x000000000000FF00) << 40) |
((v & 0x00000000000000FF) << 56);
#endif
And see if that works? The zero padding shouldn't matter.
Ah that seems to be exactly the issue. Let me try that out
That was easy enough. Submitted PR #40 to close this.
Since you are testing on s390x, I have some really large corpora for bignum, like one with ~750K ExpMod inputs. I can send you those if you want?
Sure, there's definitely plenty of space for it :)
Ok, I'll e-mail you at your IBM address, ok?
Sounds good. Thanks
Done, let me know if you run into any other issues.
Manual reversing is required because BN_bn2lebinpad is not supported by BoringSSL.
Would it be helpful if I added BN_bn2lebinpad to BoringSSL? Although BN_get_u64 or BN_get_word might be what you actually want here.
Thanks @davidben , i'll try BN_get_u64.