Skip to content

Commit 1e565eb

Browse files
mamerhenium
authored andcommitted
Add OpenSSL::BN#set_flags and #get_flags
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.
1 parent cde6e4a commit 1e565eb

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

ext/openssl/ossl_bn.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,42 @@ ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
11401140
return Qnil;
11411141
}
11421142

1143+
/*
1144+
* call-seq:
1145+
* bn.get_flags(flags) => flags
1146+
*
1147+
* Returns the flags on the BN object.
1148+
* The argument is used as a bit mask.
1149+
*
1150+
* === Parameters
1151+
* * _flags_ - integer
1152+
*/
1153+
static VALUE
1154+
ossl_bn_get_flags(VALUE self, VALUE arg)
1155+
{
1156+
BIGNUM *bn;
1157+
GetBN(self, bn);
1158+
1159+
return INT2NUM(BN_get_flags(bn, NUM2INT(arg)));
1160+
}
1161+
1162+
/*
1163+
* call-seq:
1164+
* bn.set_flags(flags) => nil
1165+
*
1166+
* Enables the flags on the BN object.
1167+
* Currently, the flags argument can contain zero of OpenSSL::BN::CONSTTIME.
1168+
*/
1169+
static VALUE
1170+
ossl_bn_set_flags(VALUE self, VALUE arg)
1171+
{
1172+
BIGNUM *bn;
1173+
GetBN(self, bn);
1174+
1175+
BN_set_flags(bn, NUM2INT(arg));
1176+
return Qnil;
1177+
}
1178+
11431179
/*
11441180
* INIT
11451181
* (NOTE: ordering of methods is the same as in 'man bn')
@@ -1238,6 +1274,23 @@ Init_ossl_bn(void)
12381274
/* lshift1 - DON'T IMPL. */
12391275
/* rshift1 - DON'T IMPL. */
12401276

1277+
rb_define_method(cBN, "get_flags", ossl_bn_get_flags, 1);
1278+
rb_define_method(cBN, "set_flags", ossl_bn_set_flags, 1);
1279+
1280+
#ifdef BN_FLG_CONSTTIME
1281+
rb_define_const(cBN, "CONSTTIME", INT2NUM(BN_FLG_CONSTTIME));
1282+
#endif
1283+
/* BN_FLG_MALLOCED and BN_FLG_STATIC_DATA seems for C programming.
1284+
* Allowing them leads to memory leak.
1285+
* So, for now, they are not exported
1286+
#ifdef BN_FLG_MALLOCED
1287+
rb_define_const(cBN, "MALLOCED", INT2NUM(BN_FLG_MALLOCED));
1288+
#endif
1289+
#ifdef BN_FLG_STATIC_DATA
1290+
rb_define_const(cBN, "STATIC_DATA", INT2NUM(BN_FLG_STATIC_DATA));
1291+
#endif
1292+
*/
1293+
12411294
/*
12421295
* bn2bin
12431296
* bin2bn

test/openssl/test_bn.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,29 @@ def test_argument_error
281281
bug15760 = '[ruby-core:92231] [Bug #15760]'
282282
assert_raise(ArgumentError, bug15760) { OpenSSL::BN.new(nil, 2) }
283283
end
284+
285+
def test_get_flags_and_set_flags
286+
e = OpenSSL::BN.new(999)
287+
288+
assert_equal(0, e.get_flags(OpenSSL::BN::CONSTTIME))
289+
290+
e.set_flags(OpenSSL::BN::CONSTTIME)
291+
assert_equal(OpenSSL::BN::CONSTTIME, e.get_flags(OpenSSL::BN::CONSTTIME))
292+
293+
b = OpenSSL::BN.new(2)
294+
m = OpenSSL::BN.new(99)
295+
assert_equal("17", b.mod_exp(e, m).to_s)
296+
297+
# mod_exp fails when m is even and any argument has CONSTTIME flag
298+
m = OpenSSL::BN.new(98)
299+
assert_raise(OpenSSL::BNError) do
300+
b.mod_exp(e, m)
301+
end
302+
303+
# It looks like flags cannot be removed once enabled
304+
e.set_flags(0)
305+
assert_equal(4, e.get_flags(OpenSSL::BN::CONSTTIME))
306+
end
284307
end
285308

286309
end

0 commit comments

Comments
 (0)