aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2021-02-16 18:21:51 +0900
committerKazuki Yamaguchi <k@rhe.jp>2021-05-25 19:07:56 +0900
commit1e565eba89524d8b05f2560e84e48d09ac3fa1ab (patch)
treeb61b7be7aeade3f21748d5abec1e33be116965e8
parentcde6e4a9a879d47dd35551d15ff7cdcb78e628b0 (diff)
downloadruby-openssl-1e565eba89524d8b05f2560e84e48d09ac3fa1ab.tar.gz
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. https://github.com/openssl/openssl/pull/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.
-rw-r--r--ext/openssl/ossl_bn.c53
-rw-r--r--test/openssl/test_bn.rb23
2 files changed, 76 insertions, 0 deletions
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index bec37299..404c428a 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -1141,6 +1141,42 @@ ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
}
/*
+ * 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')
*/
@@ -1238,6 +1274,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
diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb
index 547d334c..57a050b8 100644
--- a/test/openssl/test_bn.rb
+++ b/test/openssl/test_bn.rb
@@ -281,6 +281,29 @@ class OpenSSL::TestBN < OpenSSL::TestCase
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)
+ 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