diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index d3270f31f..5716e6f10 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -527,10 +527,18 @@ ossl_fips_mode_set(VALUE self, VALUE enabled) static VALUE ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2) { - const unsigned char *p1 = (const unsigned char *)StringValuePtr(str1); - const unsigned char *p2 = (const unsigned char *)StringValuePtr(str2); - long len1 = RSTRING_LEN(str1); - long len2 = RSTRING_LEN(str2); + const unsigned char *p1; + const unsigned char *p2; + long len1; + long len2; + + StringValue(str1); + StringValue(str2); + + p1 = (const unsigned char *)RSTRING_PTR(str1); + p2 = (const unsigned char *)RSTRING_PTR(str2); + len1 = RSTRING_LEN(str1); + len2 = RSTRING_LEN(str2); if (len1 != len2) { ossl_raise(rb_eArgError, "inputs must be of equal length"); diff --git a/test/openssl/test_ossl.rb b/test/openssl/test_ossl.rb index 51262985f..1b9bde53e 100644 --- a/test/openssl/test_ossl.rb +++ b/test/openssl/test_ossl.rb @@ -24,6 +24,16 @@ def test_fixed_length_secure_compare assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bbbb") } end + def test_fixed_length_secure_compare_uaf + str1 = "A" * 1000000 + evil_obj = Object.new + evil_obj.define_singleton_method(:to_str) do + str1.replace("C" * 1000000) + "B" * 1000000 + end + assert_false(OpenSSL.fixed_length_secure_compare(str1, evil_obj)) + end + def test_secure_compare assert_false(OpenSSL.secure_compare("aaa", "a")) assert_false(OpenSSL.secure_compare("aaa", "aa"))