openssl: BN_mod_inverse incorrect result when parameters are aliased

#include <openssl/bn.h>

#define CF_CHECK_NE(expr, res) if ( (expr) == (res) ) { goto end; }

int main(void)
{
    char* str = NULL;
    BIGNUM* a = BN_new();
    BIGNUM* b = BN_new();
    BN_CTX* ctx = BN_CTX_new();
    CF_CHECK_NE(BN_dec2bn(&a, "5193817943"), 0);
    CF_CHECK_NE(BN_dec2bn(&b, "3259122431"), 0);
    CF_CHECK_NE(BN_mod_inverse(b, a, b, ctx), NULL);
    str = BN_bn2dec(b);
    printf("%s\n", str);
end:
    BN_free(a);
    BN_free(b);
    BN_CTX_free(ctx);
    OPENSSL_free(str);
    return 0;
}

This prints 0 but should print 2609653924. Note that in the call to BN_mod_inverse, the result is the same pointer as the modulus. The documentation explicitly states that “r may be the same BIGNUM as a or n.”.

This also affects @davidben and @botovq.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 19 (19 by maintainers)

Commits related to this issue

Most upvoted comments

Yes, I’ve added them to #21124 as separate commits.

If you have such a list, then I think it would be worthwhile. As you note, aliasing is bad – it should either be fixed, return an error or minimally be documented. This is one thing FORTRAN got right grin

The only ones I’ve found so far are BN_mod_exp_simple and BN_mod_sub_quick