Skip to content

Commit

Permalink
Add OpenSSL::BN#set_flags and #get_flags
Browse files Browse the repository at this point in the history
Also, OpenSSL::BN::CONSTTIME is added.

OpenSSL itself had a feature that was vulnerable against a side-channel
attack. The OpenSSL authors determined that it was not a security issue,
and they have already fixed the issue by using BN_set_flags.

openssl/openssl#13888

If a Ruby OpenSSL user was faced with a similar issue, they couldn't
prevent the issue because Ruby OpenSSL lacks a wrapper to BN_set_flags.
For the case, this change introduces the wrapper.
  • Loading branch information
mame committed Feb 17, 2021
1 parent f2d0046 commit 15aa6b3
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
53 changes: 53 additions & 0 deletions ext/openssl/ossl_bn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,42 @@ ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
return Qnil;
}

/*
* call-seq:
* bn.get_flags(flags) => flags
*
* Returns the flags on the BN object.
* The argument is used as a bit mask.
*
* === Parameters
* * _flags_ - integer
*/
static VALUE
ossl_bn_get_flags(VALUE self, VALUE arg)
{
BIGNUM *bn;
GetBN(self, bn);

return INT2NUM(BN_get_flags(bn, NUM2INT(arg)));
}

/*
* call-seq:
* bn.set_flags(flags) => nil
*
* Enables the flags on the BN object.
* Currently, the flags argument can contain zero of OpenSSL::BN::CONSTTIME.
*/
static VALUE
ossl_bn_set_flags(VALUE self, VALUE arg)
{
BIGNUM *bn;
GetBN(self, bn);

BN_set_flags(bn, NUM2INT(arg));
return Qnil;
}

/*
* INIT
* (NOTE: ordering of methods is the same as in 'man bn')
Expand Down Expand Up @@ -1176,6 +1212,23 @@ Init_ossl_bn(void)
/* lshift1 - DON'T IMPL. */
/* rshift1 - DON'T IMPL. */

rb_define_method(cBN, "get_flags", ossl_bn_get_flags, 1);
rb_define_method(cBN, "set_flags", ossl_bn_set_flags, 1);

#ifdef BN_FLG_CONSTTIME
rb_define_const(cBN, "CONSTTIME", INT2NUM(BN_FLG_CONSTTIME));
#endif
/* BN_FLG_MALLOCED and BN_FLG_STATIC_DATA seems for C programming.
* Allowing them leads to memory leak.
* So, for now, they are not exported
#ifdef BN_FLG_MALLOCED
rb_define_const(cBN, "MALLOCED", INT2NUM(BN_FLG_MALLOCED));
#endif
#ifdef BN_FLG_STATIC_DATA
rb_define_const(cBN, "STATIC_DATA", INT2NUM(BN_FLG_STATIC_DATA));
#endif
*/

/*
* bn2bin
* bin2bn
Expand Down
24 changes: 24 additions & 0 deletions test/openssl/test_bn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,30 @@ def test_argument_error
bug15760 = '[ruby-core:92231] [Bug #15760]'
assert_raise(ArgumentError, bug15760) { OpenSSL::BN.new(nil, 2) }
end

def test_get_flags_and_set_flags
e = OpenSSL::BN.new(999)

assert_equal(0, e.get_flags(OpenSSL::BN::CONSTTIME))

e.set_flags(OpenSSL::BN::CONSTTIME)
assert_equal(OpenSSL::BN::CONSTTIME, e.get_flags(OpenSSL::BN::CONSTTIME))

b = OpenSSL::BN.new(2)
m = OpenSSL::BN.new(99)
assert_equal("17", b.mod_exp(e, m).to_s)

# mod_exp fails when m is even and any argument has CONSTTIME flag
m = OpenSSL::BN.new(98)
assert_raise(OpenSSL::BNError) do
b.mod_exp(e, m)
raise OpenSSL::BNError if !OpenSSL.errors.empty?
end

# It looks like flags cannot be removed once enabled
e.set_flags(0)
assert_equal(4, e.get_flags(OpenSSL::BN::CONSTTIME))
end
end

end

0 comments on commit 15aa6b3

Please sign in to comment.