1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/openssl/test_ossl.rb
Yusuke Endoh 01138f5853 Make OpenSSL::OSSL#test_memcmp_timing robust
The test was too fragile.  Actually, it fails on one of our CIs
immediately after it was merged to ruby/ruby.

https://gist.github.com/ko1/7ea4a5826641f79e2f9e041d83e45dba#file-brlog-trunk_clang_40-20200216-101730-L532-L535
https://gist.github.com/ko1/1c657746092b871359d8bf9e0ad28921#file-brlog-trunk-test4-20200216-104518-L473-L476

* Two measurements, a-b and a-c, must be interative instead of
  sequential; the execution time will be easily affected by disturbance
  (say, cron job or some external process invoked during measurement)

* The comparison of the two results must be relative instead of
  absolute; slow machine may take several tens of seconds for each
  execution, and one delta second is too small.  The test cases of a, b,
  and c are very extreme, so if the target method has a bug, the two
  execution times would be very different.  So I think it is enough to
  check if the difference is less than 10 times.

This change is the same as https://github.com/ruby/openssl/pull/332
2020-02-16 19:55:19 +09:00

65 lines
2.7 KiB
Ruby

# frozen_string_literal: true
require_relative "utils"
require 'benchmark'
if defined?(OpenSSL)
class OpenSSL::OSSL < OpenSSL::SSLTestCase
def test_fixed_length_secure_compare
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "a") }
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aa") }
assert OpenSSL.fixed_length_secure_compare("aaa", "aaa")
assert OpenSSL.fixed_length_secure_compare(
OpenSSL::Digest::SHA256.digest("aaa"), OpenSSL::Digest::SHA256.digest("aaa")
)
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aaaa") }
refute OpenSSL.fixed_length_secure_compare("aaa", "baa")
refute OpenSSL.fixed_length_secure_compare("aaa", "aba")
refute OpenSSL.fixed_length_secure_compare("aaa", "aab")
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aaab") }
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "b") }
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bb") }
refute OpenSSL.fixed_length_secure_compare("aaa", "bbb")
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bbbb") }
end
def test_secure_compare
refute OpenSSL.secure_compare("aaa", "a")
refute OpenSSL.secure_compare("aaa", "aa")
assert OpenSSL.secure_compare("aaa", "aaa")
refute OpenSSL.secure_compare("aaa", "aaaa")
refute OpenSSL.secure_compare("aaa", "baa")
refute OpenSSL.secure_compare("aaa", "aba")
refute OpenSSL.secure_compare("aaa", "aab")
refute OpenSSL.secure_compare("aaa", "aaab")
refute OpenSSL.secure_compare("aaa", "b")
refute OpenSSL.secure_compare("aaa", "bb")
refute OpenSSL.secure_compare("aaa", "bbb")
refute OpenSSL.secure_compare("aaa", "bbbb")
end
def test_memcmp_timing
# Ensure using fixed_length_secure_compare takes almost exactly the same amount of time to compare two different strings.
# Regular string comparison will short-circuit on the first non-matching character, failing this test.
# NOTE: this test may be susceptible to noise if the system running the tests is otherwise under load.
a = "x" * 512_000
b = "#{a}y"
c = "y#{a}"
a = "#{a}x"
a_b_time = a_c_time = 0
100.times do
a_b_time += Benchmark.measure { 100.times { OpenSSL.fixed_length_secure_compare(a, b) } }.real
a_c_time += Benchmark.measure { 100.times { OpenSSL.fixed_length_secure_compare(a, c) } }.real
end
assert_operator(a_b_time, :<, a_c_time * 10, "fixed_length_secure_compare timing test failed")
assert_operator(a_c_time, :<, a_b_time * 10, "fixed_length_secure_compare timing test failed")
end
end
end