From 060764d398a2b096fd50fe344ab7c26255656c61 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 17 Feb 2020 09:14:03 +0900 Subject: Fixed inconsistency directory structure with ruby/ruby repo --- test/envutil.rb | 339 ------- test/fixtures/chain/dh512.pem | 4 - test/fixtures/chain/server.crt | 13 - test/fixtures/chain/server.csr | 11 - test/fixtures/chain/server.key | 15 - test/fixtures/pkey/dh-1.pem | 13 - test/fixtures/pkey/dh1024.pem | 5 - test/fixtures/pkey/dsa1024.pem | 12 - test/fixtures/pkey/dsa256.pem | 8 - test/fixtures/pkey/dsa512.pem | 8 - test/fixtures/pkey/p256.pem | 5 - test/fixtures/pkey/rsa-1.pem | 51 - test/fixtures/pkey/rsa-2.pem | 51 - test/fixtures/pkey/rsa-3.pem | 51 - test/fixtures/pkey/rsa1024.pem | 15 - test/fixtures/pkey/rsa2048.pem | 27 - test/openssl/envutil.rb | 339 +++++++ test/openssl/fixtures/chain/dh512.pem | 4 + test/openssl/fixtures/chain/server.crt | 13 + test/openssl/fixtures/chain/server.csr | 11 + test/openssl/fixtures/chain/server.key | 15 + test/openssl/fixtures/pkey/dh-1.pem | 13 + test/openssl/fixtures/pkey/dh1024.pem | 5 + test/openssl/fixtures/pkey/dsa1024.pem | 12 + test/openssl/fixtures/pkey/dsa256.pem | 8 + test/openssl/fixtures/pkey/dsa512.pem | 8 + test/openssl/fixtures/pkey/p256.pem | 5 + test/openssl/fixtures/pkey/rsa-1.pem | 51 + test/openssl/fixtures/pkey/rsa-2.pem | 51 + test/openssl/fixtures/pkey/rsa-3.pem | 51 + test/openssl/fixtures/pkey/rsa1024.pem | 15 + test/openssl/fixtures/pkey/rsa2048.pem | 27 + test/openssl/test_asn1.rb | 720 ++++++++++++++ test/openssl/test_bn.rb | 286 ++++++ test/openssl/test_buffering.rb | 97 ++ test/openssl/test_cipher.rb | 340 +++++++ test/openssl/test_config.rb | 304 ++++++ test/openssl/test_digest.rb | 140 +++ test/openssl/test_engine.rb | 97 ++ test/openssl/test_fips.rb | 30 + test/openssl/test_hmac.rb | 54 + test/openssl/test_kdf.rb | 183 ++++ test/openssl/test_ns_spki.rb | 53 + test/openssl/test_ocsp.rb | 311 ++++++ test/openssl/test_ossl.rb | 65 ++ test/openssl/test_pair.rb | 523 ++++++++++ test/openssl/test_pkcs12.rb | 313 ++++++ test/openssl/test_pkcs7.rb | 309 ++++++ test/openssl/test_pkey_dh.rb | 103 ++ test/openssl/test_pkey_dsa.rb | 200 ++++ test/openssl/test_pkey_ec.rb | 374 +++++++ test/openssl/test_pkey_rsa.rb | 452 +++++++++ test/openssl/test_random.rb | 19 + test/openssl/test_ssl.rb | 1693 ++++++++++++++++++++++++++++++++ test/openssl/test_ssl_session.rb | 400 ++++++++ test/openssl/test_ts.rb | 667 +++++++++++++ test/openssl/test_x509attr.rb | 94 ++ test/openssl/test_x509cert.rb | 288 ++++++ test/openssl/test_x509crl.rb | 284 ++++++ test/openssl/test_x509ext.rb | 104 ++ test/openssl/test_x509name.rb | 469 +++++++++ test/openssl/test_x509req.rb | 170 ++++ test/openssl/test_x509store.rb | 241 +++++ test/openssl/ut_eof.rb | 133 +++ test/openssl/utils.rb | 397 ++++++++ test/test_asn1.rb | 720 -------------- test/test_bn.rb | 286 ------ test/test_buffering.rb | 97 -- test/test_cipher.rb | 340 ------- test/test_config.rb | 304 ------ test/test_digest.rb | 140 --- test/test_engine.rb | 97 -- test/test_fips.rb | 30 - test/test_hmac.rb | 54 - test/test_kdf.rb | 183 ---- test/test_ns_spki.rb | 53 - test/test_ocsp.rb | 311 ------ test/test_ossl.rb | 65 -- test/test_pair.rb | 523 ---------- test/test_pkcs12.rb | 313 ------ test/test_pkcs7.rb | 309 ------ test/test_pkey_dh.rb | 103 -- test/test_pkey_dsa.rb | 200 ---- test/test_pkey_ec.rb | 374 ------- test/test_pkey_rsa.rb | 452 --------- test/test_random.rb | 19 - test/test_ssl.rb | 1693 -------------------------------- test/test_ssl_session.rb | 400 -------- test/test_ts.rb | 667 ------------- test/test_x509attr.rb | 94 -- test/test_x509cert.rb | 288 ------ test/test_x509crl.rb | 284 ------ test/test_x509ext.rb | 104 -- test/test_x509name.rb | 469 --------- test/test_x509req.rb | 170 ---- test/test_x509store.rb | 241 ----- test/ut_eof.rb | 133 --- test/utils.rb | 397 -------- 98 files changed, 10541 insertions(+), 10541 deletions(-) delete mode 100644 test/envutil.rb delete mode 100644 test/fixtures/chain/dh512.pem delete mode 100644 test/fixtures/chain/server.crt delete mode 100644 test/fixtures/chain/server.csr delete mode 100644 test/fixtures/chain/server.key delete mode 100644 test/fixtures/pkey/dh-1.pem delete mode 100644 test/fixtures/pkey/dh1024.pem delete mode 100644 test/fixtures/pkey/dsa1024.pem delete mode 100644 test/fixtures/pkey/dsa256.pem delete mode 100644 test/fixtures/pkey/dsa512.pem delete mode 100644 test/fixtures/pkey/p256.pem delete mode 100644 test/fixtures/pkey/rsa-1.pem delete mode 100644 test/fixtures/pkey/rsa-2.pem delete mode 100644 test/fixtures/pkey/rsa-3.pem delete mode 100644 test/fixtures/pkey/rsa1024.pem delete mode 100644 test/fixtures/pkey/rsa2048.pem create mode 100644 test/openssl/envutil.rb create mode 100644 test/openssl/fixtures/chain/dh512.pem create mode 100644 test/openssl/fixtures/chain/server.crt create mode 100644 test/openssl/fixtures/chain/server.csr create mode 100644 test/openssl/fixtures/chain/server.key create mode 100644 test/openssl/fixtures/pkey/dh-1.pem create mode 100644 test/openssl/fixtures/pkey/dh1024.pem create mode 100644 test/openssl/fixtures/pkey/dsa1024.pem create mode 100644 test/openssl/fixtures/pkey/dsa256.pem create mode 100644 test/openssl/fixtures/pkey/dsa512.pem create mode 100644 test/openssl/fixtures/pkey/p256.pem create mode 100644 test/openssl/fixtures/pkey/rsa-1.pem create mode 100644 test/openssl/fixtures/pkey/rsa-2.pem create mode 100644 test/openssl/fixtures/pkey/rsa-3.pem create mode 100644 test/openssl/fixtures/pkey/rsa1024.pem create mode 100644 test/openssl/fixtures/pkey/rsa2048.pem create mode 100644 test/openssl/test_asn1.rb create mode 100644 test/openssl/test_bn.rb create mode 100644 test/openssl/test_buffering.rb create mode 100644 test/openssl/test_cipher.rb create mode 100644 test/openssl/test_config.rb create mode 100644 test/openssl/test_digest.rb create mode 100644 test/openssl/test_engine.rb create mode 100644 test/openssl/test_fips.rb create mode 100644 test/openssl/test_hmac.rb create mode 100644 test/openssl/test_kdf.rb create mode 100644 test/openssl/test_ns_spki.rb create mode 100644 test/openssl/test_ocsp.rb create mode 100644 test/openssl/test_ossl.rb create mode 100644 test/openssl/test_pair.rb create mode 100644 test/openssl/test_pkcs12.rb create mode 100644 test/openssl/test_pkcs7.rb create mode 100644 test/openssl/test_pkey_dh.rb create mode 100644 test/openssl/test_pkey_dsa.rb create mode 100644 test/openssl/test_pkey_ec.rb create mode 100644 test/openssl/test_pkey_rsa.rb create mode 100644 test/openssl/test_random.rb create mode 100644 test/openssl/test_ssl.rb create mode 100644 test/openssl/test_ssl_session.rb create mode 100644 test/openssl/test_ts.rb create mode 100644 test/openssl/test_x509attr.rb create mode 100644 test/openssl/test_x509cert.rb create mode 100644 test/openssl/test_x509crl.rb create mode 100644 test/openssl/test_x509ext.rb create mode 100644 test/openssl/test_x509name.rb create mode 100644 test/openssl/test_x509req.rb create mode 100644 test/openssl/test_x509store.rb create mode 100644 test/openssl/ut_eof.rb create mode 100644 test/openssl/utils.rb delete mode 100644 test/test_asn1.rb delete mode 100644 test/test_bn.rb delete mode 100644 test/test_buffering.rb delete mode 100644 test/test_cipher.rb delete mode 100644 test/test_config.rb delete mode 100644 test/test_digest.rb delete mode 100644 test/test_engine.rb delete mode 100644 test/test_fips.rb delete mode 100644 test/test_hmac.rb delete mode 100644 test/test_kdf.rb delete mode 100644 test/test_ns_spki.rb delete mode 100644 test/test_ocsp.rb delete mode 100644 test/test_ossl.rb delete mode 100644 test/test_pair.rb delete mode 100644 test/test_pkcs12.rb delete mode 100644 test/test_pkcs7.rb delete mode 100644 test/test_pkey_dh.rb delete mode 100644 test/test_pkey_dsa.rb delete mode 100644 test/test_pkey_ec.rb delete mode 100644 test/test_pkey_rsa.rb delete mode 100644 test/test_random.rb delete mode 100644 test/test_ssl.rb delete mode 100644 test/test_ssl_session.rb delete mode 100644 test/test_ts.rb delete mode 100644 test/test_x509attr.rb delete mode 100644 test/test_x509cert.rb delete mode 100644 test/test_x509crl.rb delete mode 100644 test/test_x509ext.rb delete mode 100644 test/test_x509name.rb delete mode 100644 test/test_x509req.rb delete mode 100644 test/test_x509store.rb delete mode 100644 test/ut_eof.rb delete mode 100644 test/utils.rb (limited to 'test') diff --git a/test/envutil.rb b/test/envutil.rb deleted file mode 100644 index 05d6fe27..00000000 --- a/test/envutil.rb +++ /dev/null @@ -1,339 +0,0 @@ -# -*- coding: us-ascii -*- -require "timeout" -require "rbconfig" -require "pp" - -module EnvUtil - def rubybin - ENV["RUBY"] || RbConfig.ruby - end - module_function :rubybin - - LANG_ENVS = %w"LANG LC_ALL LC_CTYPE" - - def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false, - encoding: nil, timeout: 10, reprieve: 1, - stdout_filter: nil, stderr_filter: nil, - rubybin: EnvUtil.rubybin, - **opt) - in_c, in_p = IO.pipe - out_p, out_c = IO.pipe if capture_stdout - err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout - opt[:in] = in_c - opt[:out] = out_c if capture_stdout - opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr - if encoding - out_p.set_encoding(encoding) if out_p - err_p.set_encoding(encoding) if err_p - end - c = "C" - child_env = {} - LANG_ENVS.each {|lc| child_env[lc] = c} - if Array === args and Hash === args.first - child_env.update(args.shift) - end - args = [args] if args.kind_of?(String) - pid = spawn(child_env, rubybin, *args, **opt) - in_c.close - out_c.close if capture_stdout - err_c.close if capture_stderr && capture_stderr != :merge_to_stdout - if block_given? - return yield in_p, out_p, err_p, pid - else - th_stdout = Thread.new { out_p.read } if capture_stdout - th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout - in_p.write stdin_data.to_str unless stdin_data.empty? - in_p.close - if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout)) - stdout = th_stdout.value if capture_stdout - stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout - else - signal = /mswin|mingw/ =~ RUBY_PLATFORM ? :KILL : :TERM - case pgroup = opt[:pgroup] - when 0, true - pgroup = -pid - when nil, false - pgroup = pid - end - begin - Process.kill signal, pgroup - Timeout.timeout((reprieve unless signal == :KILL)) do - Process.wait(pid) - end - rescue Errno::ESRCH - break - rescue Timeout::Error - raise if signal == :KILL - signal = :KILL - else - break - end while true - bt = caller_locations - raise Timeout::Error, "execution of #{bt.shift.label} expired", bt.map(&:to_s) - end - out_p.close if capture_stdout - err_p.close if capture_stderr && capture_stderr != :merge_to_stdout - Process.wait pid - status = $? - stdout = stdout_filter.call(stdout) if stdout_filter - stderr = stderr_filter.call(stderr) if stderr_filter - return stdout, stderr, status - end - ensure - [th_stdout, th_stderr].each do |th| - th.kill if th - end - [in_c, in_p, out_c, out_p, err_c, err_p].each do |io| - io.close if io && !io.closed? - end - [th_stdout, th_stderr].each do |th| - th.join if th - end - end - module_function :invoke_ruby - - def verbose_warning - class << (stderr = "".dup) - alias write << - end - stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true - yield stderr - return $stderr - ensure - stderr, $stderr, $VERBOSE = $stderr, stderr, verbose - end - module_function :verbose_warning - - def suppress_warning - verbose, $VERBOSE = $VERBOSE, nil - yield - ensure - $VERBOSE = verbose - end - module_function :suppress_warning - - if /darwin/ =~ RUBY_PLATFORM - DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports") - DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S' - def self.diagnostic_reports(signame, cmd, pid, now) - return unless %w[ABRT QUIT SEGV ILL].include?(signame) - cmd = File.basename(cmd) - path = DIAGNOSTIC_REPORTS_PATH - timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT - pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.crash" - first = true - 30.times do - first ? (first = false) : sleep(0.1) - Dir.glob(pat) do |name| - log = File.read(name) rescue next - if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log - File.unlink(name) - File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil - return log - end - end - end - nil - end - else - def self.diagnostic_reports(signame, cmd, pid, now) - end - end -end - -module Test - module Unit - module Assertions - FailDesc = proc do |status, message = "", out = ""| - pid = status.pid - now = Time.now - faildesc = proc do - if signo = status.termsig - signame = Signal.signame(signo) - sigdesc = "signal #{signo}" - end - log = EnvUtil.diagnostic_reports(signame, EnvUtil.rubybin, pid, now) - if signame - sigdesc = "SIG#{signame} (#{sigdesc})" - end - if status.coredump? - sigdesc << " (core dumped)" - end - full_message = '' - if message and !message.empty? - full_message << message << "\n" - end - full_message << "pid #{pid} killed by #{sigdesc}" - if out and !out.empty? - full_message << "\n#{out.gsub(/^/, '| ')}" - full_message << "\n" if /\n\z/ !~ full_message - end - if log - full_message << "\n#{log.gsub(/^/, '| ')}" - end - full_message - end - faildesc - end - - ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV") - - def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt) - unless file and line - loc, = caller_locations(1,1) - file ||= loc.path - line ||= loc.lineno - end - line -= 6 # lines until src - src = < marshal_error - ignore_stderr = nil - end - if res.is_a?(String) - pend res - elsif res - if bt = res.backtrace - bt.each do |l| - l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"} - end - bt.concat(caller) - else - res.set_backtrace(caller) - end - raise res - end - - # really is it succeed? - unless ignore_stderr - # the body of assert_separately must not output anything to detect error - assert_equal("", stderr, "assert_separately failed with error message") - end - assert_equal(0, status, "assert_separately failed: '#{stderr}'") - raise marshal_error if marshal_error - end - - def assert_warning(pat, msg = nil) - stderr = EnvUtil.verbose_warning { - yield - } - if Regexp === pat - assert_match pat, stderr, msg - else - assert_equal pat, stderr, msg - end - end - - def message msg = nil, ending = ".", &default - proc { - msg = msg.call.chomp(".") if Proc === msg - custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty? - "#{custom_message}#{default.call}#{ending}" - } - end - - # threads should respond to shift method. - # Array can be used. - def assert_join_threads(threads, message = nil) - errs = [] - values = [] - while th = threads.shift - begin - values << th.value - rescue Exception - errs << [th, $!] - end - end - if !errs.empty? - msg = "exceptions on #{errs.length} threads:\n" + - errs.map {|t, err| - "#{t.inspect}:\n" + - err.backtrace.map.with_index {|line, i| - if i == 0 - "#{line}: #{err.message} (#{err.class})" - else - "\tfrom #{line}" - end - }.join("\n") - }.join("\n---\n") - if message - msg = "#{message}\n#{msg}" - end - raise Test::Unit::AssertionFailedError, msg - end - values - end - - def mu_pp(obj) #:nodoc: - obj.pretty_inspect.chomp - end - - # :call-seq: - # assert_raise_with_message(exception, expected, msg = nil, &block) - # - #Tests if the given block raises an exception with the expected - #message. - # - # assert_raise_with_message(RuntimeError, "foo") do - # nil #Fails, no Exceptions are raised - # end - # - # assert_raise_with_message(RuntimeError, "foo") do - # raise ArgumentError, "foo" #Fails, different Exception is raised - # end - # - # assert_raise_with_message(RuntimeError, "foo") do - # raise "bar" #Fails, RuntimeError is raised but the message differs - # end - # - # assert_raise_with_message(RuntimeError, "foo") do - # raise "foo" #Raises RuntimeError with the message, so assertion succeeds - # end - def assert_raise_with_message(exception, expected, msg = nil, &block) - case expected - when String - assert = :assert_equal - when Regexp - assert = :assert_match - else - raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}" - end - - ex = m = nil - ex = assert_raise(exception, msg || "Exception(#{exception}) with message matches to #{expected.inspect}") do - yield - end - m = ex.message - msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"} - - if assert == :assert_equal - assert_equal(expected, m, msg) - else - msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp m}" } - assert expected =~ m, msg - block.binding.eval("proc{|_|$~=_}").call($~) - end - ex - end - end - end -end diff --git a/test/fixtures/chain/dh512.pem b/test/fixtures/chain/dh512.pem deleted file mode 100644 index fec138c7..00000000 --- a/test/fixtures/chain/dh512.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN DH PARAMETERS----- -MEYCQQCjDVzTg9C4u43MV0TKDGsBuYdChrPMczr4IYjy+jHQvXm2DDadNNWBIDau -4zNtwfLCg2gMwOc7t18m4Ten/NOLAgEC ------END DH PARAMETERS----- diff --git a/test/fixtures/chain/server.crt b/test/fixtures/chain/server.crt deleted file mode 100644 index d6b814f4..00000000 --- a/test/fixtures/chain/server.crt +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICATCCAWoCCQDbxIRGgXeWaDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJO -WjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTE5MDYxMzA1MDU0MloXDTI5MDYxMDA1MDU0MlowRTELMAkG -A1UEBhMCTloxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA29Vu -Y6m8pRrsXxUhlK2BX48CDChr8D53SqZozcQI26BCm+05TBnQxKAHOknR3y/ige2U -2zftSwbSoK/zKUC8o5pKVL+l36anDEnZ6RWc9Z9CvmaCFjlcP4nXZO+yD1Is/jCy -KqGGC8lQ920VXOCFflJj6AWg88+4C3GLjxJe6bMCAwEAATANBgkqhkiG9w0BAQsF -AAOBgQCDaqKGBkYxNxnv37vEKp7zi/cov8LvEsZaAD1pcSU+ysBiBes/B7a/Qjcj -PTZsH/hedn9mVynLkjc7LrztUWngTeW9gk5EB9YSwJdPhwLntV1TdaBlf/tu0n/c -s7QxaZhFMUyo1Eof28zXVHhs1OEhlSjwJ8lxuC3vBE4F1BjSNQ== ------END CERTIFICATE----- diff --git a/test/fixtures/chain/server.csr b/test/fixtures/chain/server.csr deleted file mode 100644 index 51b38e33..00000000 --- a/test/fixtures/chain/server.csr +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBhDCB7gIBADBFMQswCQYDVQQGEwJOWjETMBEGA1UECAwKU29tZS1TdGF0ZTEh -MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDb1W5jqbylGuxfFSGUrYFfjwIMKGvwPndKpmjNxAjboEKb -7TlMGdDEoAc6SdHfL+KB7ZTbN+1LBtKgr/MpQLyjmkpUv6XfpqcMSdnpFZz1n0K+ -ZoIWOVw/iddk77IPUiz+MLIqoYYLyVD3bRVc4IV+UmPoBaDzz7gLcYuPEl7pswID -AQABoAAwDQYJKoZIhvcNAQELBQADgYEAONaTWYVfyMmd8irCtognRoM4tFF4xvDg -PTcnHjVb/6oPPMU+mtQVD9qNf8SOdhNuYVTZ61mDLQGeq45CLM5qWjZkqFPHnngf -ajfZRE7Y3vA8ZaWFvsTJYcU+R3/FRS0XnFYj99+q9Yi3JExSY+arElyAW3tFYlcs -RWOCk1pT2Yc= ------END CERTIFICATE REQUEST----- diff --git a/test/fixtures/chain/server.key b/test/fixtures/chain/server.key deleted file mode 100644 index 9590235d..00000000 --- a/test/fixtures/chain/server.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDb1W5jqbylGuxfFSGUrYFfjwIMKGvwPndKpmjNxAjboEKb7TlM -GdDEoAc6SdHfL+KB7ZTbN+1LBtKgr/MpQLyjmkpUv6XfpqcMSdnpFZz1n0K+ZoIW -OVw/iddk77IPUiz+MLIqoYYLyVD3bRVc4IV+UmPoBaDzz7gLcYuPEl7pswIDAQAB -AoGAGO+q5+83ENtu+JIjDwRnanmEV/C13biYO4WI2d5kytTw+VL9bt52yfcFGt2I -yvJZlTdn7T340svhVIzg3ksTmp1xQk3zh6zR00zQy45kYwY8uyd8Xfh2IsnpByoc -h2jWVX6LSqi1Iy3RxanHmMYPSMy15otsjwlwnnTAHLnnvzECQQDvw3TL90DucQSD -S0h6DWAGakaiOMhY/PpFbTsjzw+uG+Up65tpz4QqPbsXfoReeK0CQIuyE/LlYoJl -VOlIsL6HAkEA6rh4zsWi6KVTGa7qd5x70TEgxeMMAW1qUbak1THxeZTFYnyvucBz -i+VQvHEVnCadhVpHIwbBNUeOyS5DXjj6dQJAA0Caf/3Noq5jykgmJomx6MReSusM -RLDB0FlH+Rdg9hKozCXHCOtoto350LrFnuZyKlqnynWc0OHCNQ+uzm6fVwJAbtyW -YsNCQLPlXhoZsEj+yj10B0NH5lyxfMrRa8jdDtnPqMbPkOJvMMIssfSPimNKvzN2 -qfqEww97R1ZMh3JOCQJBAIIwGHBN5rDGIb4CgR+PLsh8bve1X+gO8UnOYJXa/Uzx -gAXE0uzHNH6rNSG0V/IQnFYlSHpNJGgcdSl+MZNLldQ= ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/dh-1.pem b/test/fixtures/pkey/dh-1.pem deleted file mode 100644 index 3340a6a1..00000000 --- a/test/fixtures/pkey/dh-1.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIICCAKCAgEAvRzXYxY6L2DjeYmm1eowtMDu1it3j+VwFr6s6PRWzc1apMtztr9G -xZ2mYndUAJLgNLO3n2fUDCYVMB6ZkcekW8Siocof3xWiMA6wqZ6uw0dsE3q7ZX+6 -TLjgSjaXeGvjutvuEwVrFeaUi83bMgfXN8ToxIQVprIF35sYFt6fpbFATKfW7qqi -P1pQkjmCskU4tztaWvlLh0qg85wuQGnpJaQT3gS30378i0IGbA0EBvJcSpTHYbLa -nsdI9bfN/ZVgeolVMNMU9/n8R8vRhNPcHuciFwaqS656q+HavCIyxw/LfjSwwFvR -TngCn0wytRErkzFIXnRKckh8/BpI4S+0+l1NkOwG4WJ55KJ/9OOdZW5o/QCp2bDi -E0JN1EP/gkSom/prq8JR/yEqtsy99uc5nUxPmzv0IgdcFHZEfiQU7iRggEbx7qfQ -Ve55XksmmJInmpCy1bSabAEgIKp8Ckt5KLYZ0RgTXUhcEpsxEo6cuAwoSJT5o4Rp -yG3xow2ozPcqZkvb+d2CHj1sc54w9BVFAjVANEKmRil/9WKz14bu3wxEhOPqC54n -QojjLcoXSoT66ZUOQnYxTSiLtzoKGPy8cAVPbkBrXz2u2sj5gcvr1JjoGjdHm9/3 -qnqC8fsTz8UndKNIQC337o4K0833bQMzRGl1/qjbAPit2B7E3b6xTZMCAQI= ------END DH PARAMETERS----- diff --git a/test/fixtures/pkey/dh1024.pem b/test/fixtures/pkey/dh1024.pem deleted file mode 100644 index f99c757f..00000000 --- a/test/fixtures/pkey/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAKnKQ8MNK6nYZzLrrcuTsLxuiJGXoOO5gT+tljOTbHBuiktdMTITzIY0 -pFxIvjG05D7HoBZQfrR0c92NGWPkAiCkhQKB8JCbPVzwNLDy6DZ0pmofDKrEsYHG -AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC ------END DH PARAMETERS----- diff --git a/test/fixtures/pkey/dsa1024.pem b/test/fixtures/pkey/dsa1024.pem deleted file mode 100644 index 1bf49889..00000000 --- a/test/fixtures/pkey/dsa1024.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBugIBAAKBgQCH9aAoXvWWThIjkA6D+nI1F9ksF9iDq594rkiGNOT9sPDOdB+n -D+qeeeeloRlj19ymCSADPI0ZLRgkchkAEnY2RnqnhHOjVf/roGgRbW+iQDMbQ9wa -/pvc6/fAbsu1goE1hBYjm98/sZEeXavj8tR56IXnjF1b6Nx0+sgeUKFKEQIVAMiz -4BJUFeTtddyM4uadBM7HKLPRAoGAZdLBSYNGiij7vAjesF5mGUKTIgPd+JKuBEDx -OaBclsgfdoyoF/TMOkIty+PVlYD+//Vl2xnoUEIRaMXHwHfm0r2xUX++oeRaSScg -YizJdUxe5jvBuBszGPRc/mGpb9YvP0sB+FL1KmuxYmdODfCe51zl8uM/CVhouJ3w -DjmRGscCgYAuFlfC7p+e8huCKydfcv/beftqjewiOPpQ3u5uI6KPCtCJPpDhs3+4 -IihH2cPsAlqwGF4tlibW1+/z/OZ1AZinPK3y7b2jSJASEaPeEltVzB92hcd1khk2 -jTYcmSsV4VddplOPK9czytR/GbbibxsrhhgZUbd8LPbvIgaiadJ1PgIUBnJ/5vN2 -CVArsEzlPUCbohPvZnE= ------END DSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/dsa256.pem b/test/fixtures/pkey/dsa256.pem deleted file mode 100644 index d9a407f7..00000000 --- a/test/fixtures/pkey/dsa256.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE -9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed -AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM -3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT -b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn -ISNX5cMzFHRW3Q== ------END DSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/dsa512.pem b/test/fixtures/pkey/dsa512.pem deleted file mode 100644 index 962c41cc..00000000 --- a/test/fixtures/pkey/dsa512.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok -RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D -AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR -S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++ -Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S -55jreJD3Se3slps= ------END DSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/p256.pem b/test/fixtures/pkey/p256.pem deleted file mode 100644 index 97c97d9f..00000000 --- a/test/fixtures/pkey/p256.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 -AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt -CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== ------END EC PRIVATE KEY----- diff --git a/test/fixtures/pkey/rsa-1.pem b/test/fixtures/pkey/rsa-1.pem deleted file mode 100644 index bd5a624f..00000000 --- a/test/fixtures/pkey/rsa-1.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJJwIBAAKCAgEArIEJUYZrXhMfUXXdl2gLcXrRB4ciWNEeXt5UVLG0nPhygZwJ -xis8tOrjXOJEpUXUsfgF35pQiJLD4T9/Vp3zLFtMOOQjOR3AxjIelbH9KPyGFEr9 -TcPtsJ24zhcG7RbwOGXR4iIcDaTx+bCLSAd7BjG3XHQtyeepGGRZkGyGUvXjPorH -XP+dQjQnMd09wv0GMZSqQ06PedUUKQ4PJRfMCP+mwjFP+rB3NZuThF0CsNmpoixg -GdoQ591Yrf5rf2Bs848JrYdqJlKlBL6rTFf2glHiC+mE5YRny7RZtv/qIkyUNotV -ce1cE0GFrRmCpw9bqulDDcgKjFkhihTg4Voq0UYdJ6Alg7Ur4JerKTfyCaRGF27V -fh/g2A2/6Vu8xKYYwTAwLn+Tvkx9OTVZ1t15wM7Ma8hHowNoO0g/lWkeltgHLMji -rmeuIYQ20BQmdx2RRgWKl57D0wO/N0HIR+Bm4vcBoNPgMlk9g5WHA6idHR8TLxOr -dMMmTiWfefB0/FzGXBv7DuuzHN3+urdCvG1QIMFQ06kHXhr4rC28KbWIxg+PJGM8 -oGNEGtGWAOvi4Ov+BVsIdbD5Sfyb4nY3L9qqPl6TxRxMWTKsYCYx11jC8civCzOu -yL1z+wgIICJ6iGzrfYf6C2BiNV3BC1YCtp2XsG+AooIxCwjL2CP/54MuRnUCAwEA -AQKCAgAP4+8M0HoRd2d6JIZeDRqIwIyCygLy9Yh7qrVP+/KsRwKdR9dqps73x29c -Pgeexdj67+Lynw9uFT7v/95mBzTAUESsNO+9sizw1OsWVQgB/4kGU4YT5Ml/bHf6 -nApqSqOkPlTgJM46v4f+vTGHWBEQGAJRBO62250q/wt1D1osSDQ/rZ8BxRYiZBV8 -NWocDRzF8nDgtFrpGSS7R21DuHZ2Gb6twscgS6MfkA49sieuTM6gfr/3gavu/+fM -V1Rlrmc65GE61++CSjijQEEdTjkJ9isBd+hjEBhTnnBpOBfEQxOgFqOvU/MYXv/G -W0Q6yWJjUwt3OIcoOImrY5L3j0vERneA1Alweqsbws3fXXMjA+jhLxlJqjPvSAKc -POi7xu7QCJjSSLAzHSDPdmGmfzlrbdWS1h0mrC5YZYOyToLajfnmAlXNNrytnePg -JV9/1136ZFrJyEi1JVN3kyrC+1iVd1E+lWK0U1UQ6/25tJvKFc1I+xToaUbK10UN -ycXib7p2Zsc/+ZMlPRgCxWmpIHmKhnwbO7vtRunnnc6wzhvlQQNHWlIvkyQukV50 -6k/bzWw0M6A98B4oCICIcxcpS3njDlHyL7NlkCD+/OfZp6X3RZF/m4grmA2doebz -glsaNMyGHFrpHkHq19Y63Y4jtBdW/XuBv06Cnr4r3BXdjEzzwQKCAQEA5bj737Nk -ZLA0UgzVVvY67MTserTOECIt4i37nULjRQwsSFiz0AWFOBwUCBJ5N2qDEelbf0Fa -t4VzrphryEgzLz/95ZXi+oxw1liqCHi8iHeU2wSclDtx2jKv2q7bFvFSaH4CKC4N -zBJNfP92kdXuAjXkbK/jWwr64fLNh/2KFWUAmrYmtGfnOjjyL+yZhPxBatztE58q -/T61pkvP9NiLfrr7Xq8fnzrwqGERhXKueyoK6ig9ZJPZ2VTykMUUvNYJJ7OYQZru -EYA3zkuEZifqmjgF57Bgg7dkkIh285TzH3CNf3MCMTmjlWVyHjlyeSPYgISB9Mys -VKKQth+SvYcChQKCAQEAwDyCcolA7+bQBfECs6GXi7RYy2YSlx562S5vhjSlY9Ko -WiwVJWviF7uSBdZRnGUKoPv4K4LV34o2lJpSSTi5Xgp7FH986VdGePe3p4hcXSIZ -NtsKImLVLnEjrmkZExfQl7p0MkcU/LheCf/eEZVp0Z84O54WCs6GRm9wHYIUyrag -9FREqqxTRVNhQQ2EDVGq1slREdwB+aygE76axK/qosk0RaoLzGZiMn4Sb8bpJxXO -mee+ftq5bayVltfR0DhC8eHkcPPFeQMll1g+ML7HbINwHTr01ONm3cFUO4zOLBOO -ws/+vtNfiv6S/lO1RQSRoiApbENBLdSc3V8Cy70PMQKCAQBOcZN4uP5gL5c+KWm0 -T1KhxUDnSdRPyAwY/xC7i7qlullovvlv4GK0XUot03kXBkUJmcEHvF5o6qYtCZlM -g/MOgHCHtF4Upl5lo1M0n13pz8PB4lpBd+cR1lscdrcTp4Y3bkf4RnmppNpXA7kO -ZZnnoVWGE620ShSPkWTDuj0rvxisu+SNmClqRUXWPZnSwnzoK9a86443efF3fs3d -UxCXTuxFUdGfgvXo2XStOBMCtcGSYflM3fv27b4C13mUXhY0O2yTgn8m9LyZsknc -xGalENpbWmwqrjYl8KOF2+gFZV68FZ67Bm6otkJ4ta80VJw6joT9/eIe6IA34KIw -G+ktAoIBAFRuPxzvC4ZSaasyX21l25mQbC9pdWDKEkqxCmp3VOyy6R4xnlgBOhwS -VeAacV2vQyvRfv4dSLIVkkNSRDHEqCWVlNk75TDXFCytIAyE54xAHbLqIVlY7yim -qHVB07F/FC6PxdkPPziAAU2DA5XVedSHibslg6jbbD4jU6qiJ1+hNrAZEs+jQC+C -n4Ri20y+Qbp0URb2+icemnARlwgr+3HjzQGL3gK4NQjYNmDBjEWOXl9aWWB90FNL -KahGwfAhxcVW4W56opCzwR7nsujV4eDXGba83itidRuQfd5pyWOyc1E86TYGwD/b -79OkEElv6Ea8uXTDVS075GmWATRapQECggEAd9ZAbyT+KouTfi2e6yLOosxSZfns -eF06QAJi5n9GOtdfK5fqdmHJqJI7wbubCnd0oxPeL71lRjrOAMXufaQRdZtfXSMn -B1TljteNrh1en5xF451rCPR/Y6tNKBvIKnhy1waO27/vA+ovXrm17iR9rRuGZ29i -IurlKA6z/96UdrSdpqITTCyTjSOBYg34f49ueGjlpL4+8HJq2wor4Cb1Sbv8ErqA -bsQ/Jz+KIGUiuFCfNa6d6McPRXIrGgzpprXgfimkV3nj49QyrnuCF/Pc4psGgIaN -l3EiGXzRt/55K7DQVadtbcjo9zREac8QnDD6dS/gOfJ82L7frQfMpNWgQA== ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/rsa-2.pem b/test/fixtures/pkey/rsa-2.pem deleted file mode 100644 index e4fd4f43..00000000 --- a/test/fixtures/pkey/rsa-2.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEA1HUbx825tG7+/ulC5DpDogzXqM2/KmeCwGXZY4XjiWa+Zj7b -ECkZwQh7zxFUsPixGqQKJSyFwCogdaPzYTRNtqKKaw/IWS0um1PTn4C4/9atbIsf -HVKu/fWg4VrZL+ixFIZxa8Z6pvTB2omMcx+uEzbXPsO01i1pHf7MaWBxUDGFyC9P -lASJBfFZAf2Ar1H99OTS4SP+gxM9Kk5tcc22r8uFiqqbhJmQNSDApdHvT1zSZxAc -T1BFEZqfmR0B0UegPyJc/9hW0dYpB9JjR29UaZRSta3LUMpqltoOF5bzaKVgMuBm -Qy79xJ71LjGp8bKhgRaWXyPsDzAC0MQlOW6En0v8LK8fntivJEvw9PNOMcZ8oMTn -no0NeVt32HiQJW8LIVo7dOLVFtguSBMWUVe8mdKbuIIULD6JlSYke9Ob6andUhzO -U79m/aRWs2yjD6o5QAktjFBARdPgcpTdWfppc8xpJUkQgRmVhINoIMT9W6Wl898E -P4aPx6mRV/k05ellN3zRgd9tx5dyNuj3RBaNmR47cAVvGYRQgtH9bQYs6jtf0oer -A5yIYEKspNRlZZJKKrQdLflQFOEwjQJyZnTk7Mp0y21wOuEGgZBexew55/hUJDC2 -mQ8CqjV4ki/Mm3z6Cw3jXIMNBJkH7oveBGSX0S9bF8A/73oOCU3W/LkORxECAwEA -AQKCAgBLK7RMmYmfQbaPUtEMF2FesNSNMV72DfHBSUgFYpYDQ4sSeiLgMOqf1fSY -azVf+F4RYwED7iDUwRMDDKNMPUlR2WjIQKlOhCH9a0dxJAZQ3xA1W3QC2AJ6cLIf -ihlWTip5bKgszekPsYH1ZL2A7jCVM84ssuoE7cRHjKOelTUCfsMq9TJe2MvyglZP -0fX6EjSctWm3pxiiH+iAU4d9wJ9my8fQLFUiMYNIiPIguYrGtbzsIlMh7PDDLcZS -UmUWOxWDwRDOpSjyzadu0Q23dLiVMpmhFoDdcQENptFdn1c4K2tCFQuZscKwEt4F -HiVXEzD5j5hcyUT4irA0VXImQ+hAH3oSDmn7wyHvyOg0bDZpUZXEHXb83Vvo54/d -Fb4AOUva1dwhjci8CTEMxCENMy/CLilRv46AeHbOX8KMPM7BnRSJPptvTTh/qB9C -HI5hxfkO+EOYnu0kUlxhJfrqG86H4IS+zA8HWiSEGxQteMjUQfgJoBzJ94YChpzo -ePpKSpjxxl1PNNWKxWM3yUvlKmI2lNl6YNC8JpF2wVg4VvYkG7iVjleeRg21ay89 -NCVMF98n3MI5jdzfDKACnuYxg7sw+gjMy8PSoFvQ5pvHuBBOpa8tho6vk7bLJixT -QY5uXMNQaO6OwpkBssKpnuXhIJzDhO48nSjJ5nUEuadPH1nGwQKCAQEA7twrUIMi -Vqze/X6VyfEBnX+n3ZyQHLGqUv/ww1ZOOHmSW5ceC4GxHa8EPDjoh9NEjYffwGq9 -bfQh9Gntjk5gFipT/SfPrIhbPt59HthUqVvOGgSErCmn0vhsa0+ROpVi4K2WHS7O -7SEwnoCWd6p1omon2olVY0ODlMH4neCx/ZuKV8SRMREubABlL8/MLp37AkgKarTY -tewd0lpaZMvsjOhr1zVCGUUBxy87Fc7OKAcoQY8//0r8VMH7Jlga7F2PKVPzqRKf -tjeW5jMAuRxTqtEdIeclJZwvUMxvb23BbBE+mtvKpXv69TB3DK8T1YIkhW2CidZW -lad4MESC+QFNbQKCAQEA47PtULM/0ZFdE+PDDHOa2kJ2arm94sVIqF2168ZLXR69 -NkvCWfjkUPDeejINCx7XQgk0d/+5BCvrJpcM7lE4XfnYVNtPpct1el6eTfaOcPU8 -wAMsnq5n9Mxt02U+XRPtEqGk+lt0KLPDDSG88Z7jPmfftigLyPH6i/ZJyRUETlGk -rGnWSx/LFUxQU5aBa2jUCjKOKa+OOk2jGg50A5Cmk26v9sA/ksOHisMjfdIpZc9P -r4R0IteDDD5awlkWTF++5u1GpgU2yav4uan0wzY8OWYFzVyceA6+wffEcoplLm82 -CPd/qJOB5HHkjoM+CJgfumFxlNtdowKvKNUxpoQNtQKCAQEAh3ugofFPp+Q0M4r6 -gWnPZbuDxsLIR05K8vszYEjy4zup1YO4ygQNJ24fM91/n5Mo/jJEqwqgWd6w58ax -tRclj00BCMXtGMrbHqTqSXWhR9LH66AGdPTHuXWpYZDnKliTlic/z1u+iWhbAHyl -XEj2omIeKunc4gnod5cyYrKRouz3omLfi/pX33C19FGkWgjH2HpuViowBbhhDfCr -9yJoEWC/0njl/hlTMdzLYcpEyxWMMuuC/FZXG+hPgWdWFh3XVzTEL3Fd3+hWEkp5 -rYWwu2ITaSiHvHaDrAvZZVXW8WoynXnvzr+tECgmTq57zI4eEwSTl4VY5VfxZ0dl -FsIzXQKCAQBC07GYd6MJPGJWzgeWhe8yk0Lxu6WRAll6oFYd5kqD/9uELePSSAup -/actsbbGRrziMpVlinWgVctjvf0bjFbArezhqqPLgtTtnwtS0kOnvzGfIM9dms4D -uGObISGWa5yuVSZ4G5MRxwA9wGMVfo4u6Iltin868FmZ7iRlkXd8DNYJi95KmgAe -NhF1FrzQ6ykf/QpgDZfuYI63vPorea6JonieMHn39s622OJ3sNBZguheGL+E4j8h -vsMgOskijQ8X8xdC7lDQC1qqEsk06ZvvNJQLW1zIl3tArhjHjPp5EEaJhym+Ldx3 -UT3E3Zu9JfhZ2PNevqrShp0lnLw/pI3pAoIBAAUMz5Lj6V9ftsl1pTa8WDFeBJW0 -Wa5AT1BZg/ip2uq2NLPnA5JWcD+v682fRSvIj1pU0DRi6VsXlzhs+1q3+sgqiXGz -u2ArFylh8TvC1gXUctXKZz/M3Rqr6aSNoejUGLmvHre+ja/k6Zwmu6ePtB7dL50d -6+xMTYquS4gLbrbSLcEu3iBAAnvRLreXK4KguPxaBdICB7v7epdpAKe3Z7hp/sst -eJj1+6KRdlcmt8fh5MPkBBXa6I/9XGmX5UEo7q4wAxeM9nuFWY3watz/EO9LiO6P -LmqUSWL65m4cX0VZPvhYEsHppKi1eoWGlHqS4Af5+aIXi2alu2iljQFeA+Q= ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/rsa-3.pem b/test/fixtures/pkey/rsa-3.pem deleted file mode 100644 index 6c9c9ced..00000000 --- a/test/fixtures/pkey/rsa-3.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEAzn+YCcOh7BIRzrb7TEuhQLD545+/Fx/zCYO3l+y/8ogUxMTg -LG5HrcXlX3JP796ie90/GHIf8/lwczVhP1jk/keYjkwoTYDt477R7KRcJPyGqHRr -qLp7AnZxtz3JLNboTgO3bAYzlvtsSKU/R3oehBbGHzEWCP2UEYj/Kky0zpcjkhZU -jiErr9ARPq8+dOGqBf+CE2NLKYC1bu8hZe9AddvvN2SvfMN6uhJtEGZO1k8tScwf -AyvPJ1Po/6z08pzMAgfBUCE95waAVeYJWIOlnNB4eEievzlXdPB9vEt8OOwtWfQX -V8xyMsoKeAW05s413E0eTYx1aulFXdWwG2mWEBRtNzKF1iBudlg1a3x1zThWi1pY -jW5vROvoWZMCbl9bYQ/LxOCVqDoUl86+NPEGeuESMzm5NvOQA2e0Ty5wphnt9M19 -Wcc8neBhb6iCGqYzxWNvUYXZWUv1+/MrPHKyJuv7MSivwtctfp8SacUGxkd6T+u6 -V6ntHf3qtN/5pAmni6nzUTgjC65MS0LEhi/RTzwafkIfifeJH7/LqFtjrursuwua -+p9lkACck/J5TpzaAfLroFQuepP8qgeq1cpD5Iii56IJ+FPSnkvesHuRUmZIkhtR -VVsVqMaNPv/Uzc02bOaRXWP4auUY91mDKx/FDmORa9YCDQxMkKke05SWQ90CAwEA -AQKCAgA0+B/c6VTgxGXS+7cMhB3yBTOkgva2jNh/6Uyv6Of345ZIPyQt4X/7gFbt -G9qLcjWFxmQH9kZiA+snclrmr/vVijIE1l5EOz1KfUlGBYcpaal1DqALIQKqyA01 -buDq4pmmYWesiw6yvP2yyMipohav1VOu7p1zYvCXaufhRtneYICcWaQI7VNSfvHd -fYBs5PIDJd6M8Jx4Ie7obOjJSAzl7qu3LtmhDFev4Ugeu8+fQ6IfWv/dhWBW+zw6 -UXhnv3bJUonw7wX8+/rxjdd54BMcXZF5cU9fR+s6MPJf2ZEc3OBpQaa3O9dTVeZH -kVctGVpRj2qlg9EewoWro0PQVE5Mjah+mdFhPAHWoGl1xht6xJmg0uHYxMCzbUSz -7NSS3knR0qieFvsp5ESY72i7DnQsbhbn6mTuYdVtm9bphxifAWCP3jFdft/bjtSF -4yuPI7Qga+3m0B8QhtbWhEzPVon6NyiY7qfa6qllp0opEbw2hE22uGFFNJo2mpPa -pe9VwARtD0IyfeklE7KrBEwV8NjTaAipZTZODw0w/dt4K3dOiePDl3pPWjmERpVg -Lkw7XSCMtu5X87I1BbfOYbQhOXksPY+W9Asf6ETBeIZ8bD6Iypuk2ssool1lukqv -yq1Y8gbR9B2x91ftYwXgzqBSvd8PFNsaXWLD3nrai2G1vb81lQKCAQEA6W02eZcN -7wJfkqNokcuqhc5OKXH14gVIRV+KocG6f3vg88wrCg5J2GqNhBFuwVrafJjRenm6 -C8zWdneeyrl6cztgbaySw7kXnqFdTBiuOT8bhiG5NTPjDQ109EucaTbZU9KUXk6k -ChPlr4G6IPrONpvi/9BvDDZLZkwR6uIg1kFWBy9kZaxFUEIug02hrbkTpPtnEUrO -r3nG0QL/D0vf+bm4YHIVRMH2O2ZTTWexMw9XlfCe1+WjbJ+PS35QRCRDcRdWHXDb -HnIFIAajtH5LtaJLgWUYq3B25WkQYtbHmFkm94sp/G4trb8JIJGzVO8cj9t6KeAT -LG+tk8OqplqsYwKCAQEA4ne81KXx8VNwsKVFqwmiDIoi1q3beNa2hoXdzAMrnYdj -iLxbfCVgrKPav9hdfXPBncHaNlGsd2G5W1a1UsOr128lTdfBsgm1RVPhVMKvo3fl -yUnWajtAR1q3tVEUhuFlbJ/RHEtxJaGrzudYCPWQiYhydpDgSckbxD8PuElEgFBX -O91vnWZEjMsxrABWiZNBxmtBUEv+fjUU/9USYzO4sN79UeD1+ZuBxPFwscsRcjLr -bPgZWOwiywH6UmQ+DJTzeu0wJ6jgPoy/pgEujsbPDz1wNos6NhA/RQv31QeX33/B -7/F5XKNmbJ2AFb/B+xTaTQPg0pjT5Exm+HrNU5OivwKCAQEAsLLVi9FG4OiBBHXi -UItFuChljoYPxVqOTMV4Id6OmLZjoOmqouASElsGaTTxDDkEL1FXMUk4Bnq21dLT -R06EXPpTknISX0qbkJ9CCrqcGAWnhi+9DYMLmvPW1p7t9c9pUESVv5X0IxTQx7yB -8zkoJLp4aYGUrj/jb7qhzZYDmWy3/JRpgXWYupp+rzJy8xiowDj22mYwczDRyaJl -BWVAVL+7zHZPl07kYC6jXHLj9mzktkIBXBkfTriyNkmV5R82VkN+Eqc9l5xkOMwN -3DHGieYjFf47YHuv5RVVLBy91puWHckgrU+SEHYOKLNidybSDivsHArdOMQJN1Pk -uCznVQKCAQAYY7DQbfa6eLQAMixomSb8lrvdxueGAgmyPyR93jGKS5Rqm2521ket -EBB07MZUxmyposDvbKhYSwv9TD9G5I/TKcMouP3BQM5m4vu3dygXQMhcfzk6Q5tO -k/SI8Gx3gjq8EhIhK/bJiLnKFJwkit3AEhPRtRSSnbgB0JDO1gUslHpwlg55MxRa -3V9CGN84/cTtq4tjLGwCB5F1Y+sRB/byBXHeqY2UDi1Rmnb6jtYYKGe2WpnQO84b -cuEUknskO75lFLpE6ykLU3koVaQ/+CVAjOtS1He2btWBiCJurNysU0P9pVHeqjJT -rDqpHPe1JK/F74783zyir5+/Tuph/9pdAoIBAANPdFRQkJVH8K6iuhxQk6vFqiYB -MUxpIVeLonD0p9TgMdezVNESht/AIutc0+5wabM45XuDWFRTuonvcE8lckv2Ux3a -AvSsamjuesxw2YmkEtzZouVqDU0+oxppQJiwBG3MiaHX9F5IfnK6YmQ6xPwZ6MXi -9feq1jR4KOc1ZrHtRMNgjnBWEFWroGe3FHgV7O133hpMSshRFmwcbE0nAaDr82U9 -sl8dclDjEKBxaqjAeNajOr+BU0w0AAwWXL7dt/ctG2QClcj9wqbEfsXnOR10h4AI -rqkcvQrOLbTwcrOD/6R1rQfQXtEHKf1maThxosootAQZXdf6jxU3oonx3tU= ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/rsa1024.pem b/test/fixtures/pkey/rsa1024.pem deleted file mode 100644 index 464de074..00000000 --- a/test/fixtures/pkey/rsa1024.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx -aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/ -Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB -AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0 -maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T -gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572 -74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE -JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX -sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII -8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA -wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi -qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD -dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA== ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/pkey/rsa2048.pem b/test/fixtures/pkey/rsa2048.pem deleted file mode 100644 index ac89cd88..00000000 --- a/test/fixtures/pkey/rsa2048.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN -s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign -4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D -kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl -NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J -DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb -I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq -PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V -seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0 -Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc -VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW -wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G -0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj -XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb -aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n -h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw -Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k -IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb -v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId -U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr -vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS -Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC -9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41 -gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG -4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw== ------END RSA PRIVATE KEY----- diff --git a/test/openssl/envutil.rb b/test/openssl/envutil.rb new file mode 100644 index 00000000..05d6fe27 --- /dev/null +++ b/test/openssl/envutil.rb @@ -0,0 +1,339 @@ +# -*- coding: us-ascii -*- +require "timeout" +require "rbconfig" +require "pp" + +module EnvUtil + def rubybin + ENV["RUBY"] || RbConfig.ruby + end + module_function :rubybin + + LANG_ENVS = %w"LANG LC_ALL LC_CTYPE" + + def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false, + encoding: nil, timeout: 10, reprieve: 1, + stdout_filter: nil, stderr_filter: nil, + rubybin: EnvUtil.rubybin, + **opt) + in_c, in_p = IO.pipe + out_p, out_c = IO.pipe if capture_stdout + err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout + opt[:in] = in_c + opt[:out] = out_c if capture_stdout + opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr + if encoding + out_p.set_encoding(encoding) if out_p + err_p.set_encoding(encoding) if err_p + end + c = "C" + child_env = {} + LANG_ENVS.each {|lc| child_env[lc] = c} + if Array === args and Hash === args.first + child_env.update(args.shift) + end + args = [args] if args.kind_of?(String) + pid = spawn(child_env, rubybin, *args, **opt) + in_c.close + out_c.close if capture_stdout + err_c.close if capture_stderr && capture_stderr != :merge_to_stdout + if block_given? + return yield in_p, out_p, err_p, pid + else + th_stdout = Thread.new { out_p.read } if capture_stdout + th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout + in_p.write stdin_data.to_str unless stdin_data.empty? + in_p.close + if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout)) + stdout = th_stdout.value if capture_stdout + stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout + else + signal = /mswin|mingw/ =~ RUBY_PLATFORM ? :KILL : :TERM + case pgroup = opt[:pgroup] + when 0, true + pgroup = -pid + when nil, false + pgroup = pid + end + begin + Process.kill signal, pgroup + Timeout.timeout((reprieve unless signal == :KILL)) do + Process.wait(pid) + end + rescue Errno::ESRCH + break + rescue Timeout::Error + raise if signal == :KILL + signal = :KILL + else + break + end while true + bt = caller_locations + raise Timeout::Error, "execution of #{bt.shift.label} expired", bt.map(&:to_s) + end + out_p.close if capture_stdout + err_p.close if capture_stderr && capture_stderr != :merge_to_stdout + Process.wait pid + status = $? + stdout = stdout_filter.call(stdout) if stdout_filter + stderr = stderr_filter.call(stderr) if stderr_filter + return stdout, stderr, status + end + ensure + [th_stdout, th_stderr].each do |th| + th.kill if th + end + [in_c, in_p, out_c, out_p, err_c, err_p].each do |io| + io.close if io && !io.closed? + end + [th_stdout, th_stderr].each do |th| + th.join if th + end + end + module_function :invoke_ruby + + def verbose_warning + class << (stderr = "".dup) + alias write << + end + stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true + yield stderr + return $stderr + ensure + stderr, $stderr, $VERBOSE = $stderr, stderr, verbose + end + module_function :verbose_warning + + def suppress_warning + verbose, $VERBOSE = $VERBOSE, nil + yield + ensure + $VERBOSE = verbose + end + module_function :suppress_warning + + if /darwin/ =~ RUBY_PLATFORM + DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports") + DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S' + def self.diagnostic_reports(signame, cmd, pid, now) + return unless %w[ABRT QUIT SEGV ILL].include?(signame) + cmd = File.basename(cmd) + path = DIAGNOSTIC_REPORTS_PATH + timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT + pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.crash" + first = true + 30.times do + first ? (first = false) : sleep(0.1) + Dir.glob(pat) do |name| + log = File.read(name) rescue next + if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log + File.unlink(name) + File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil + return log + end + end + end + nil + end + else + def self.diagnostic_reports(signame, cmd, pid, now) + end + end +end + +module Test + module Unit + module Assertions + FailDesc = proc do |status, message = "", out = ""| + pid = status.pid + now = Time.now + faildesc = proc do + if signo = status.termsig + signame = Signal.signame(signo) + sigdesc = "signal #{signo}" + end + log = EnvUtil.diagnostic_reports(signame, EnvUtil.rubybin, pid, now) + if signame + sigdesc = "SIG#{signame} (#{sigdesc})" + end + if status.coredump? + sigdesc << " (core dumped)" + end + full_message = '' + if message and !message.empty? + full_message << message << "\n" + end + full_message << "pid #{pid} killed by #{sigdesc}" + if out and !out.empty? + full_message << "\n#{out.gsub(/^/, '| ')}" + full_message << "\n" if /\n\z/ !~ full_message + end + if log + full_message << "\n#{log.gsub(/^/, '| ')}" + end + full_message + end + faildesc + end + + ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV") + + def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt) + unless file and line + loc, = caller_locations(1,1) + file ||= loc.path + line ||= loc.lineno + end + line -= 6 # lines until src + src = < marshal_error + ignore_stderr = nil + end + if res.is_a?(String) + pend res + elsif res + if bt = res.backtrace + bt.each do |l| + l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"} + end + bt.concat(caller) + else + res.set_backtrace(caller) + end + raise res + end + + # really is it succeed? + unless ignore_stderr + # the body of assert_separately must not output anything to detect error + assert_equal("", stderr, "assert_separately failed with error message") + end + assert_equal(0, status, "assert_separately failed: '#{stderr}'") + raise marshal_error if marshal_error + end + + def assert_warning(pat, msg = nil) + stderr = EnvUtil.verbose_warning { + yield + } + if Regexp === pat + assert_match pat, stderr, msg + else + assert_equal pat, stderr, msg + end + end + + def message msg = nil, ending = ".", &default + proc { + msg = msg.call.chomp(".") if Proc === msg + custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty? + "#{custom_message}#{default.call}#{ending}" + } + end + + # threads should respond to shift method. + # Array can be used. + def assert_join_threads(threads, message = nil) + errs = [] + values = [] + while th = threads.shift + begin + values << th.value + rescue Exception + errs << [th, $!] + end + end + if !errs.empty? + msg = "exceptions on #{errs.length} threads:\n" + + errs.map {|t, err| + "#{t.inspect}:\n" + + err.backtrace.map.with_index {|line, i| + if i == 0 + "#{line}: #{err.message} (#{err.class})" + else + "\tfrom #{line}" + end + }.join("\n") + }.join("\n---\n") + if message + msg = "#{message}\n#{msg}" + end + raise Test::Unit::AssertionFailedError, msg + end + values + end + + def mu_pp(obj) #:nodoc: + obj.pretty_inspect.chomp + end + + # :call-seq: + # assert_raise_with_message(exception, expected, msg = nil, &block) + # + #Tests if the given block raises an exception with the expected + #message. + # + # assert_raise_with_message(RuntimeError, "foo") do + # nil #Fails, no Exceptions are raised + # end + # + # assert_raise_with_message(RuntimeError, "foo") do + # raise ArgumentError, "foo" #Fails, different Exception is raised + # end + # + # assert_raise_with_message(RuntimeError, "foo") do + # raise "bar" #Fails, RuntimeError is raised but the message differs + # end + # + # assert_raise_with_message(RuntimeError, "foo") do + # raise "foo" #Raises RuntimeError with the message, so assertion succeeds + # end + def assert_raise_with_message(exception, expected, msg = nil, &block) + case expected + when String + assert = :assert_equal + when Regexp + assert = :assert_match + else + raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}" + end + + ex = m = nil + ex = assert_raise(exception, msg || "Exception(#{exception}) with message matches to #{expected.inspect}") do + yield + end + m = ex.message + msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"} + + if assert == :assert_equal + assert_equal(expected, m, msg) + else + msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp m}" } + assert expected =~ m, msg + block.binding.eval("proc{|_|$~=_}").call($~) + end + ex + end + end + end +end diff --git a/test/openssl/fixtures/chain/dh512.pem b/test/openssl/fixtures/chain/dh512.pem new file mode 100644 index 00000000..fec138c7 --- /dev/null +++ b/test/openssl/fixtures/chain/dh512.pem @@ -0,0 +1,4 @@ +-----BEGIN DH PARAMETERS----- +MEYCQQCjDVzTg9C4u43MV0TKDGsBuYdChrPMczr4IYjy+jHQvXm2DDadNNWBIDau +4zNtwfLCg2gMwOc7t18m4Ten/NOLAgEC +-----END DH PARAMETERS----- diff --git a/test/openssl/fixtures/chain/server.crt b/test/openssl/fixtures/chain/server.crt new file mode 100644 index 00000000..d6b814f4 --- /dev/null +++ b/test/openssl/fixtures/chain/server.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICATCCAWoCCQDbxIRGgXeWaDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJO +WjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE5MDYxMzA1MDU0MloXDTI5MDYxMDA1MDU0MlowRTELMAkG +A1UEBhMCTloxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA29Vu +Y6m8pRrsXxUhlK2BX48CDChr8D53SqZozcQI26BCm+05TBnQxKAHOknR3y/ige2U +2zftSwbSoK/zKUC8o5pKVL+l36anDEnZ6RWc9Z9CvmaCFjlcP4nXZO+yD1Is/jCy +KqGGC8lQ920VXOCFflJj6AWg88+4C3GLjxJe6bMCAwEAATANBgkqhkiG9w0BAQsF +AAOBgQCDaqKGBkYxNxnv37vEKp7zi/cov8LvEsZaAD1pcSU+ysBiBes/B7a/Qjcj +PTZsH/hedn9mVynLkjc7LrztUWngTeW9gk5EB9YSwJdPhwLntV1TdaBlf/tu0n/c +s7QxaZhFMUyo1Eof28zXVHhs1OEhlSjwJ8lxuC3vBE4F1BjSNQ== +-----END CERTIFICATE----- diff --git a/test/openssl/fixtures/chain/server.csr b/test/openssl/fixtures/chain/server.csr new file mode 100644 index 00000000..51b38e33 --- /dev/null +++ b/test/openssl/fixtures/chain/server.csr @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBhDCB7gIBADBFMQswCQYDVQQGEwJOWjETMBEGA1UECAwKU29tZS1TdGF0ZTEh +MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDb1W5jqbylGuxfFSGUrYFfjwIMKGvwPndKpmjNxAjboEKb +7TlMGdDEoAc6SdHfL+KB7ZTbN+1LBtKgr/MpQLyjmkpUv6XfpqcMSdnpFZz1n0K+ +ZoIWOVw/iddk77IPUiz+MLIqoYYLyVD3bRVc4IV+UmPoBaDzz7gLcYuPEl7pswID +AQABoAAwDQYJKoZIhvcNAQELBQADgYEAONaTWYVfyMmd8irCtognRoM4tFF4xvDg +PTcnHjVb/6oPPMU+mtQVD9qNf8SOdhNuYVTZ61mDLQGeq45CLM5qWjZkqFPHnngf +ajfZRE7Y3vA8ZaWFvsTJYcU+R3/FRS0XnFYj99+q9Yi3JExSY+arElyAW3tFYlcs +RWOCk1pT2Yc= +-----END CERTIFICATE REQUEST----- diff --git a/test/openssl/fixtures/chain/server.key b/test/openssl/fixtures/chain/server.key new file mode 100644 index 00000000..9590235d --- /dev/null +++ b/test/openssl/fixtures/chain/server.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDb1W5jqbylGuxfFSGUrYFfjwIMKGvwPndKpmjNxAjboEKb7TlM +GdDEoAc6SdHfL+KB7ZTbN+1LBtKgr/MpQLyjmkpUv6XfpqcMSdnpFZz1n0K+ZoIW +OVw/iddk77IPUiz+MLIqoYYLyVD3bRVc4IV+UmPoBaDzz7gLcYuPEl7pswIDAQAB +AoGAGO+q5+83ENtu+JIjDwRnanmEV/C13biYO4WI2d5kytTw+VL9bt52yfcFGt2I +yvJZlTdn7T340svhVIzg3ksTmp1xQk3zh6zR00zQy45kYwY8uyd8Xfh2IsnpByoc +h2jWVX6LSqi1Iy3RxanHmMYPSMy15otsjwlwnnTAHLnnvzECQQDvw3TL90DucQSD +S0h6DWAGakaiOMhY/PpFbTsjzw+uG+Up65tpz4QqPbsXfoReeK0CQIuyE/LlYoJl +VOlIsL6HAkEA6rh4zsWi6KVTGa7qd5x70TEgxeMMAW1qUbak1THxeZTFYnyvucBz +i+VQvHEVnCadhVpHIwbBNUeOyS5DXjj6dQJAA0Caf/3Noq5jykgmJomx6MReSusM +RLDB0FlH+Rdg9hKozCXHCOtoto350LrFnuZyKlqnynWc0OHCNQ+uzm6fVwJAbtyW +YsNCQLPlXhoZsEj+yj10B0NH5lyxfMrRa8jdDtnPqMbPkOJvMMIssfSPimNKvzN2 +qfqEww97R1ZMh3JOCQJBAIIwGHBN5rDGIb4CgR+PLsh8bve1X+gO8UnOYJXa/Uzx +gAXE0uzHNH6rNSG0V/IQnFYlSHpNJGgcdSl+MZNLldQ= +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/dh-1.pem b/test/openssl/fixtures/pkey/dh-1.pem new file mode 100644 index 00000000..3340a6a1 --- /dev/null +++ b/test/openssl/fixtures/pkey/dh-1.pem @@ -0,0 +1,13 @@ +-----BEGIN DH PARAMETERS----- +MIICCAKCAgEAvRzXYxY6L2DjeYmm1eowtMDu1it3j+VwFr6s6PRWzc1apMtztr9G +xZ2mYndUAJLgNLO3n2fUDCYVMB6ZkcekW8Siocof3xWiMA6wqZ6uw0dsE3q7ZX+6 +TLjgSjaXeGvjutvuEwVrFeaUi83bMgfXN8ToxIQVprIF35sYFt6fpbFATKfW7qqi +P1pQkjmCskU4tztaWvlLh0qg85wuQGnpJaQT3gS30378i0IGbA0EBvJcSpTHYbLa +nsdI9bfN/ZVgeolVMNMU9/n8R8vRhNPcHuciFwaqS656q+HavCIyxw/LfjSwwFvR +TngCn0wytRErkzFIXnRKckh8/BpI4S+0+l1NkOwG4WJ55KJ/9OOdZW5o/QCp2bDi +E0JN1EP/gkSom/prq8JR/yEqtsy99uc5nUxPmzv0IgdcFHZEfiQU7iRggEbx7qfQ +Ve55XksmmJInmpCy1bSabAEgIKp8Ckt5KLYZ0RgTXUhcEpsxEo6cuAwoSJT5o4Rp +yG3xow2ozPcqZkvb+d2CHj1sc54w9BVFAjVANEKmRil/9WKz14bu3wxEhOPqC54n +QojjLcoXSoT66ZUOQnYxTSiLtzoKGPy8cAVPbkBrXz2u2sj5gcvr1JjoGjdHm9/3 +qnqC8fsTz8UndKNIQC337o4K0833bQMzRGl1/qjbAPit2B7E3b6xTZMCAQI= +-----END DH PARAMETERS----- diff --git a/test/openssl/fixtures/pkey/dh1024.pem b/test/openssl/fixtures/pkey/dh1024.pem new file mode 100644 index 00000000..f99c757f --- /dev/null +++ b/test/openssl/fixtures/pkey/dh1024.pem @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAKnKQ8MNK6nYZzLrrcuTsLxuiJGXoOO5gT+tljOTbHBuiktdMTITzIY0 +pFxIvjG05D7HoBZQfrR0c92NGWPkAiCkhQKB8JCbPVzwNLDy6DZ0pmofDKrEsYHG +AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC +-----END DH PARAMETERS----- diff --git a/test/openssl/fixtures/pkey/dsa1024.pem b/test/openssl/fixtures/pkey/dsa1024.pem new file mode 100644 index 00000000..1bf49889 --- /dev/null +++ b/test/openssl/fixtures/pkey/dsa1024.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBugIBAAKBgQCH9aAoXvWWThIjkA6D+nI1F9ksF9iDq594rkiGNOT9sPDOdB+n +D+qeeeeloRlj19ymCSADPI0ZLRgkchkAEnY2RnqnhHOjVf/roGgRbW+iQDMbQ9wa +/pvc6/fAbsu1goE1hBYjm98/sZEeXavj8tR56IXnjF1b6Nx0+sgeUKFKEQIVAMiz +4BJUFeTtddyM4uadBM7HKLPRAoGAZdLBSYNGiij7vAjesF5mGUKTIgPd+JKuBEDx +OaBclsgfdoyoF/TMOkIty+PVlYD+//Vl2xnoUEIRaMXHwHfm0r2xUX++oeRaSScg +YizJdUxe5jvBuBszGPRc/mGpb9YvP0sB+FL1KmuxYmdODfCe51zl8uM/CVhouJ3w +DjmRGscCgYAuFlfC7p+e8huCKydfcv/beftqjewiOPpQ3u5uI6KPCtCJPpDhs3+4 +IihH2cPsAlqwGF4tlibW1+/z/OZ1AZinPK3y7b2jSJASEaPeEltVzB92hcd1khk2 +jTYcmSsV4VddplOPK9czytR/GbbibxsrhhgZUbd8LPbvIgaiadJ1PgIUBnJ/5vN2 +CVArsEzlPUCbohPvZnE= +-----END DSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/dsa256.pem b/test/openssl/fixtures/pkey/dsa256.pem new file mode 100644 index 00000000..d9a407f7 --- /dev/null +++ b/test/openssl/fixtures/pkey/dsa256.pem @@ -0,0 +1,8 @@ +-----BEGIN DSA PRIVATE KEY----- +MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE +9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed +AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM +3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT +b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn +ISNX5cMzFHRW3Q== +-----END DSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/dsa512.pem b/test/openssl/fixtures/pkey/dsa512.pem new file mode 100644 index 00000000..962c41cc --- /dev/null +++ b/test/openssl/fixtures/pkey/dsa512.pem @@ -0,0 +1,8 @@ +-----BEGIN DSA PRIVATE KEY----- +MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok +RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D +AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR +S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++ +Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S +55jreJD3Se3slps= +-----END DSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/p256.pem b/test/openssl/fixtures/pkey/p256.pem new file mode 100644 index 00000000..97c97d9f --- /dev/null +++ b/test/openssl/fixtures/pkey/p256.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 +AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt +CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== +-----END EC PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/rsa-1.pem b/test/openssl/fixtures/pkey/rsa-1.pem new file mode 100644 index 00000000..bd5a624f --- /dev/null +++ b/test/openssl/fixtures/pkey/rsa-1.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJJwIBAAKCAgEArIEJUYZrXhMfUXXdl2gLcXrRB4ciWNEeXt5UVLG0nPhygZwJ +xis8tOrjXOJEpUXUsfgF35pQiJLD4T9/Vp3zLFtMOOQjOR3AxjIelbH9KPyGFEr9 +TcPtsJ24zhcG7RbwOGXR4iIcDaTx+bCLSAd7BjG3XHQtyeepGGRZkGyGUvXjPorH +XP+dQjQnMd09wv0GMZSqQ06PedUUKQ4PJRfMCP+mwjFP+rB3NZuThF0CsNmpoixg +GdoQ591Yrf5rf2Bs848JrYdqJlKlBL6rTFf2glHiC+mE5YRny7RZtv/qIkyUNotV +ce1cE0GFrRmCpw9bqulDDcgKjFkhihTg4Voq0UYdJ6Alg7Ur4JerKTfyCaRGF27V +fh/g2A2/6Vu8xKYYwTAwLn+Tvkx9OTVZ1t15wM7Ma8hHowNoO0g/lWkeltgHLMji +rmeuIYQ20BQmdx2RRgWKl57D0wO/N0HIR+Bm4vcBoNPgMlk9g5WHA6idHR8TLxOr +dMMmTiWfefB0/FzGXBv7DuuzHN3+urdCvG1QIMFQ06kHXhr4rC28KbWIxg+PJGM8 +oGNEGtGWAOvi4Ov+BVsIdbD5Sfyb4nY3L9qqPl6TxRxMWTKsYCYx11jC8civCzOu +yL1z+wgIICJ6iGzrfYf6C2BiNV3BC1YCtp2XsG+AooIxCwjL2CP/54MuRnUCAwEA +AQKCAgAP4+8M0HoRd2d6JIZeDRqIwIyCygLy9Yh7qrVP+/KsRwKdR9dqps73x29c +Pgeexdj67+Lynw9uFT7v/95mBzTAUESsNO+9sizw1OsWVQgB/4kGU4YT5Ml/bHf6 +nApqSqOkPlTgJM46v4f+vTGHWBEQGAJRBO62250q/wt1D1osSDQ/rZ8BxRYiZBV8 +NWocDRzF8nDgtFrpGSS7R21DuHZ2Gb6twscgS6MfkA49sieuTM6gfr/3gavu/+fM +V1Rlrmc65GE61++CSjijQEEdTjkJ9isBd+hjEBhTnnBpOBfEQxOgFqOvU/MYXv/G +W0Q6yWJjUwt3OIcoOImrY5L3j0vERneA1Alweqsbws3fXXMjA+jhLxlJqjPvSAKc +POi7xu7QCJjSSLAzHSDPdmGmfzlrbdWS1h0mrC5YZYOyToLajfnmAlXNNrytnePg +JV9/1136ZFrJyEi1JVN3kyrC+1iVd1E+lWK0U1UQ6/25tJvKFc1I+xToaUbK10UN +ycXib7p2Zsc/+ZMlPRgCxWmpIHmKhnwbO7vtRunnnc6wzhvlQQNHWlIvkyQukV50 +6k/bzWw0M6A98B4oCICIcxcpS3njDlHyL7NlkCD+/OfZp6X3RZF/m4grmA2doebz +glsaNMyGHFrpHkHq19Y63Y4jtBdW/XuBv06Cnr4r3BXdjEzzwQKCAQEA5bj737Nk +ZLA0UgzVVvY67MTserTOECIt4i37nULjRQwsSFiz0AWFOBwUCBJ5N2qDEelbf0Fa +t4VzrphryEgzLz/95ZXi+oxw1liqCHi8iHeU2wSclDtx2jKv2q7bFvFSaH4CKC4N +zBJNfP92kdXuAjXkbK/jWwr64fLNh/2KFWUAmrYmtGfnOjjyL+yZhPxBatztE58q +/T61pkvP9NiLfrr7Xq8fnzrwqGERhXKueyoK6ig9ZJPZ2VTykMUUvNYJJ7OYQZru +EYA3zkuEZifqmjgF57Bgg7dkkIh285TzH3CNf3MCMTmjlWVyHjlyeSPYgISB9Mys +VKKQth+SvYcChQKCAQEAwDyCcolA7+bQBfECs6GXi7RYy2YSlx562S5vhjSlY9Ko +WiwVJWviF7uSBdZRnGUKoPv4K4LV34o2lJpSSTi5Xgp7FH986VdGePe3p4hcXSIZ +NtsKImLVLnEjrmkZExfQl7p0MkcU/LheCf/eEZVp0Z84O54WCs6GRm9wHYIUyrag +9FREqqxTRVNhQQ2EDVGq1slREdwB+aygE76axK/qosk0RaoLzGZiMn4Sb8bpJxXO +mee+ftq5bayVltfR0DhC8eHkcPPFeQMll1g+ML7HbINwHTr01ONm3cFUO4zOLBOO +ws/+vtNfiv6S/lO1RQSRoiApbENBLdSc3V8Cy70PMQKCAQBOcZN4uP5gL5c+KWm0 +T1KhxUDnSdRPyAwY/xC7i7qlullovvlv4GK0XUot03kXBkUJmcEHvF5o6qYtCZlM +g/MOgHCHtF4Upl5lo1M0n13pz8PB4lpBd+cR1lscdrcTp4Y3bkf4RnmppNpXA7kO +ZZnnoVWGE620ShSPkWTDuj0rvxisu+SNmClqRUXWPZnSwnzoK9a86443efF3fs3d +UxCXTuxFUdGfgvXo2XStOBMCtcGSYflM3fv27b4C13mUXhY0O2yTgn8m9LyZsknc +xGalENpbWmwqrjYl8KOF2+gFZV68FZ67Bm6otkJ4ta80VJw6joT9/eIe6IA34KIw +G+ktAoIBAFRuPxzvC4ZSaasyX21l25mQbC9pdWDKEkqxCmp3VOyy6R4xnlgBOhwS +VeAacV2vQyvRfv4dSLIVkkNSRDHEqCWVlNk75TDXFCytIAyE54xAHbLqIVlY7yim +qHVB07F/FC6PxdkPPziAAU2DA5XVedSHibslg6jbbD4jU6qiJ1+hNrAZEs+jQC+C +n4Ri20y+Qbp0URb2+icemnARlwgr+3HjzQGL3gK4NQjYNmDBjEWOXl9aWWB90FNL +KahGwfAhxcVW4W56opCzwR7nsujV4eDXGba83itidRuQfd5pyWOyc1E86TYGwD/b +79OkEElv6Ea8uXTDVS075GmWATRapQECggEAd9ZAbyT+KouTfi2e6yLOosxSZfns +eF06QAJi5n9GOtdfK5fqdmHJqJI7wbubCnd0oxPeL71lRjrOAMXufaQRdZtfXSMn +B1TljteNrh1en5xF451rCPR/Y6tNKBvIKnhy1waO27/vA+ovXrm17iR9rRuGZ29i +IurlKA6z/96UdrSdpqITTCyTjSOBYg34f49ueGjlpL4+8HJq2wor4Cb1Sbv8ErqA +bsQ/Jz+KIGUiuFCfNa6d6McPRXIrGgzpprXgfimkV3nj49QyrnuCF/Pc4psGgIaN +l3EiGXzRt/55K7DQVadtbcjo9zREac8QnDD6dS/gOfJ82L7frQfMpNWgQA== +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/rsa-2.pem b/test/openssl/fixtures/pkey/rsa-2.pem new file mode 100644 index 00000000..e4fd4f43 --- /dev/null +++ b/test/openssl/fixtures/pkey/rsa-2.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEA1HUbx825tG7+/ulC5DpDogzXqM2/KmeCwGXZY4XjiWa+Zj7b +ECkZwQh7zxFUsPixGqQKJSyFwCogdaPzYTRNtqKKaw/IWS0um1PTn4C4/9atbIsf +HVKu/fWg4VrZL+ixFIZxa8Z6pvTB2omMcx+uEzbXPsO01i1pHf7MaWBxUDGFyC9P +lASJBfFZAf2Ar1H99OTS4SP+gxM9Kk5tcc22r8uFiqqbhJmQNSDApdHvT1zSZxAc +T1BFEZqfmR0B0UegPyJc/9hW0dYpB9JjR29UaZRSta3LUMpqltoOF5bzaKVgMuBm +Qy79xJ71LjGp8bKhgRaWXyPsDzAC0MQlOW6En0v8LK8fntivJEvw9PNOMcZ8oMTn +no0NeVt32HiQJW8LIVo7dOLVFtguSBMWUVe8mdKbuIIULD6JlSYke9Ob6andUhzO +U79m/aRWs2yjD6o5QAktjFBARdPgcpTdWfppc8xpJUkQgRmVhINoIMT9W6Wl898E +P4aPx6mRV/k05ellN3zRgd9tx5dyNuj3RBaNmR47cAVvGYRQgtH9bQYs6jtf0oer +A5yIYEKspNRlZZJKKrQdLflQFOEwjQJyZnTk7Mp0y21wOuEGgZBexew55/hUJDC2 +mQ8CqjV4ki/Mm3z6Cw3jXIMNBJkH7oveBGSX0S9bF8A/73oOCU3W/LkORxECAwEA +AQKCAgBLK7RMmYmfQbaPUtEMF2FesNSNMV72DfHBSUgFYpYDQ4sSeiLgMOqf1fSY +azVf+F4RYwED7iDUwRMDDKNMPUlR2WjIQKlOhCH9a0dxJAZQ3xA1W3QC2AJ6cLIf +ihlWTip5bKgszekPsYH1ZL2A7jCVM84ssuoE7cRHjKOelTUCfsMq9TJe2MvyglZP +0fX6EjSctWm3pxiiH+iAU4d9wJ9my8fQLFUiMYNIiPIguYrGtbzsIlMh7PDDLcZS +UmUWOxWDwRDOpSjyzadu0Q23dLiVMpmhFoDdcQENptFdn1c4K2tCFQuZscKwEt4F +HiVXEzD5j5hcyUT4irA0VXImQ+hAH3oSDmn7wyHvyOg0bDZpUZXEHXb83Vvo54/d +Fb4AOUva1dwhjci8CTEMxCENMy/CLilRv46AeHbOX8KMPM7BnRSJPptvTTh/qB9C +HI5hxfkO+EOYnu0kUlxhJfrqG86H4IS+zA8HWiSEGxQteMjUQfgJoBzJ94YChpzo +ePpKSpjxxl1PNNWKxWM3yUvlKmI2lNl6YNC8JpF2wVg4VvYkG7iVjleeRg21ay89 +NCVMF98n3MI5jdzfDKACnuYxg7sw+gjMy8PSoFvQ5pvHuBBOpa8tho6vk7bLJixT +QY5uXMNQaO6OwpkBssKpnuXhIJzDhO48nSjJ5nUEuadPH1nGwQKCAQEA7twrUIMi +Vqze/X6VyfEBnX+n3ZyQHLGqUv/ww1ZOOHmSW5ceC4GxHa8EPDjoh9NEjYffwGq9 +bfQh9Gntjk5gFipT/SfPrIhbPt59HthUqVvOGgSErCmn0vhsa0+ROpVi4K2WHS7O +7SEwnoCWd6p1omon2olVY0ODlMH4neCx/ZuKV8SRMREubABlL8/MLp37AkgKarTY +tewd0lpaZMvsjOhr1zVCGUUBxy87Fc7OKAcoQY8//0r8VMH7Jlga7F2PKVPzqRKf +tjeW5jMAuRxTqtEdIeclJZwvUMxvb23BbBE+mtvKpXv69TB3DK8T1YIkhW2CidZW +lad4MESC+QFNbQKCAQEA47PtULM/0ZFdE+PDDHOa2kJ2arm94sVIqF2168ZLXR69 +NkvCWfjkUPDeejINCx7XQgk0d/+5BCvrJpcM7lE4XfnYVNtPpct1el6eTfaOcPU8 +wAMsnq5n9Mxt02U+XRPtEqGk+lt0KLPDDSG88Z7jPmfftigLyPH6i/ZJyRUETlGk +rGnWSx/LFUxQU5aBa2jUCjKOKa+OOk2jGg50A5Cmk26v9sA/ksOHisMjfdIpZc9P +r4R0IteDDD5awlkWTF++5u1GpgU2yav4uan0wzY8OWYFzVyceA6+wffEcoplLm82 +CPd/qJOB5HHkjoM+CJgfumFxlNtdowKvKNUxpoQNtQKCAQEAh3ugofFPp+Q0M4r6 +gWnPZbuDxsLIR05K8vszYEjy4zup1YO4ygQNJ24fM91/n5Mo/jJEqwqgWd6w58ax +tRclj00BCMXtGMrbHqTqSXWhR9LH66AGdPTHuXWpYZDnKliTlic/z1u+iWhbAHyl +XEj2omIeKunc4gnod5cyYrKRouz3omLfi/pX33C19FGkWgjH2HpuViowBbhhDfCr +9yJoEWC/0njl/hlTMdzLYcpEyxWMMuuC/FZXG+hPgWdWFh3XVzTEL3Fd3+hWEkp5 +rYWwu2ITaSiHvHaDrAvZZVXW8WoynXnvzr+tECgmTq57zI4eEwSTl4VY5VfxZ0dl +FsIzXQKCAQBC07GYd6MJPGJWzgeWhe8yk0Lxu6WRAll6oFYd5kqD/9uELePSSAup +/actsbbGRrziMpVlinWgVctjvf0bjFbArezhqqPLgtTtnwtS0kOnvzGfIM9dms4D +uGObISGWa5yuVSZ4G5MRxwA9wGMVfo4u6Iltin868FmZ7iRlkXd8DNYJi95KmgAe +NhF1FrzQ6ykf/QpgDZfuYI63vPorea6JonieMHn39s622OJ3sNBZguheGL+E4j8h +vsMgOskijQ8X8xdC7lDQC1qqEsk06ZvvNJQLW1zIl3tArhjHjPp5EEaJhym+Ldx3 +UT3E3Zu9JfhZ2PNevqrShp0lnLw/pI3pAoIBAAUMz5Lj6V9ftsl1pTa8WDFeBJW0 +Wa5AT1BZg/ip2uq2NLPnA5JWcD+v682fRSvIj1pU0DRi6VsXlzhs+1q3+sgqiXGz +u2ArFylh8TvC1gXUctXKZz/M3Rqr6aSNoejUGLmvHre+ja/k6Zwmu6ePtB7dL50d +6+xMTYquS4gLbrbSLcEu3iBAAnvRLreXK4KguPxaBdICB7v7epdpAKe3Z7hp/sst +eJj1+6KRdlcmt8fh5MPkBBXa6I/9XGmX5UEo7q4wAxeM9nuFWY3watz/EO9LiO6P +LmqUSWL65m4cX0VZPvhYEsHppKi1eoWGlHqS4Af5+aIXi2alu2iljQFeA+Q= +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/rsa-3.pem b/test/openssl/fixtures/pkey/rsa-3.pem new file mode 100644 index 00000000..6c9c9ced --- /dev/null +++ b/test/openssl/fixtures/pkey/rsa-3.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAzn+YCcOh7BIRzrb7TEuhQLD545+/Fx/zCYO3l+y/8ogUxMTg +LG5HrcXlX3JP796ie90/GHIf8/lwczVhP1jk/keYjkwoTYDt477R7KRcJPyGqHRr +qLp7AnZxtz3JLNboTgO3bAYzlvtsSKU/R3oehBbGHzEWCP2UEYj/Kky0zpcjkhZU +jiErr9ARPq8+dOGqBf+CE2NLKYC1bu8hZe9AddvvN2SvfMN6uhJtEGZO1k8tScwf +AyvPJ1Po/6z08pzMAgfBUCE95waAVeYJWIOlnNB4eEievzlXdPB9vEt8OOwtWfQX +V8xyMsoKeAW05s413E0eTYx1aulFXdWwG2mWEBRtNzKF1iBudlg1a3x1zThWi1pY +jW5vROvoWZMCbl9bYQ/LxOCVqDoUl86+NPEGeuESMzm5NvOQA2e0Ty5wphnt9M19 +Wcc8neBhb6iCGqYzxWNvUYXZWUv1+/MrPHKyJuv7MSivwtctfp8SacUGxkd6T+u6 +V6ntHf3qtN/5pAmni6nzUTgjC65MS0LEhi/RTzwafkIfifeJH7/LqFtjrursuwua ++p9lkACck/J5TpzaAfLroFQuepP8qgeq1cpD5Iii56IJ+FPSnkvesHuRUmZIkhtR +VVsVqMaNPv/Uzc02bOaRXWP4auUY91mDKx/FDmORa9YCDQxMkKke05SWQ90CAwEA +AQKCAgA0+B/c6VTgxGXS+7cMhB3yBTOkgva2jNh/6Uyv6Of345ZIPyQt4X/7gFbt +G9qLcjWFxmQH9kZiA+snclrmr/vVijIE1l5EOz1KfUlGBYcpaal1DqALIQKqyA01 +buDq4pmmYWesiw6yvP2yyMipohav1VOu7p1zYvCXaufhRtneYICcWaQI7VNSfvHd +fYBs5PIDJd6M8Jx4Ie7obOjJSAzl7qu3LtmhDFev4Ugeu8+fQ6IfWv/dhWBW+zw6 +UXhnv3bJUonw7wX8+/rxjdd54BMcXZF5cU9fR+s6MPJf2ZEc3OBpQaa3O9dTVeZH +kVctGVpRj2qlg9EewoWro0PQVE5Mjah+mdFhPAHWoGl1xht6xJmg0uHYxMCzbUSz +7NSS3knR0qieFvsp5ESY72i7DnQsbhbn6mTuYdVtm9bphxifAWCP3jFdft/bjtSF +4yuPI7Qga+3m0B8QhtbWhEzPVon6NyiY7qfa6qllp0opEbw2hE22uGFFNJo2mpPa +pe9VwARtD0IyfeklE7KrBEwV8NjTaAipZTZODw0w/dt4K3dOiePDl3pPWjmERpVg +Lkw7XSCMtu5X87I1BbfOYbQhOXksPY+W9Asf6ETBeIZ8bD6Iypuk2ssool1lukqv +yq1Y8gbR9B2x91ftYwXgzqBSvd8PFNsaXWLD3nrai2G1vb81lQKCAQEA6W02eZcN +7wJfkqNokcuqhc5OKXH14gVIRV+KocG6f3vg88wrCg5J2GqNhBFuwVrafJjRenm6 +C8zWdneeyrl6cztgbaySw7kXnqFdTBiuOT8bhiG5NTPjDQ109EucaTbZU9KUXk6k +ChPlr4G6IPrONpvi/9BvDDZLZkwR6uIg1kFWBy9kZaxFUEIug02hrbkTpPtnEUrO +r3nG0QL/D0vf+bm4YHIVRMH2O2ZTTWexMw9XlfCe1+WjbJ+PS35QRCRDcRdWHXDb +HnIFIAajtH5LtaJLgWUYq3B25WkQYtbHmFkm94sp/G4trb8JIJGzVO8cj9t6KeAT +LG+tk8OqplqsYwKCAQEA4ne81KXx8VNwsKVFqwmiDIoi1q3beNa2hoXdzAMrnYdj +iLxbfCVgrKPav9hdfXPBncHaNlGsd2G5W1a1UsOr128lTdfBsgm1RVPhVMKvo3fl +yUnWajtAR1q3tVEUhuFlbJ/RHEtxJaGrzudYCPWQiYhydpDgSckbxD8PuElEgFBX +O91vnWZEjMsxrABWiZNBxmtBUEv+fjUU/9USYzO4sN79UeD1+ZuBxPFwscsRcjLr +bPgZWOwiywH6UmQ+DJTzeu0wJ6jgPoy/pgEujsbPDz1wNos6NhA/RQv31QeX33/B +7/F5XKNmbJ2AFb/B+xTaTQPg0pjT5Exm+HrNU5OivwKCAQEAsLLVi9FG4OiBBHXi +UItFuChljoYPxVqOTMV4Id6OmLZjoOmqouASElsGaTTxDDkEL1FXMUk4Bnq21dLT +R06EXPpTknISX0qbkJ9CCrqcGAWnhi+9DYMLmvPW1p7t9c9pUESVv5X0IxTQx7yB +8zkoJLp4aYGUrj/jb7qhzZYDmWy3/JRpgXWYupp+rzJy8xiowDj22mYwczDRyaJl +BWVAVL+7zHZPl07kYC6jXHLj9mzktkIBXBkfTriyNkmV5R82VkN+Eqc9l5xkOMwN +3DHGieYjFf47YHuv5RVVLBy91puWHckgrU+SEHYOKLNidybSDivsHArdOMQJN1Pk +uCznVQKCAQAYY7DQbfa6eLQAMixomSb8lrvdxueGAgmyPyR93jGKS5Rqm2521ket +EBB07MZUxmyposDvbKhYSwv9TD9G5I/TKcMouP3BQM5m4vu3dygXQMhcfzk6Q5tO +k/SI8Gx3gjq8EhIhK/bJiLnKFJwkit3AEhPRtRSSnbgB0JDO1gUslHpwlg55MxRa +3V9CGN84/cTtq4tjLGwCB5F1Y+sRB/byBXHeqY2UDi1Rmnb6jtYYKGe2WpnQO84b +cuEUknskO75lFLpE6ykLU3koVaQ/+CVAjOtS1He2btWBiCJurNysU0P9pVHeqjJT +rDqpHPe1JK/F74783zyir5+/Tuph/9pdAoIBAANPdFRQkJVH8K6iuhxQk6vFqiYB +MUxpIVeLonD0p9TgMdezVNESht/AIutc0+5wabM45XuDWFRTuonvcE8lckv2Ux3a +AvSsamjuesxw2YmkEtzZouVqDU0+oxppQJiwBG3MiaHX9F5IfnK6YmQ6xPwZ6MXi +9feq1jR4KOc1ZrHtRMNgjnBWEFWroGe3FHgV7O133hpMSshRFmwcbE0nAaDr82U9 +sl8dclDjEKBxaqjAeNajOr+BU0w0AAwWXL7dt/ctG2QClcj9wqbEfsXnOR10h4AI +rqkcvQrOLbTwcrOD/6R1rQfQXtEHKf1maThxosootAQZXdf6jxU3oonx3tU= +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/rsa1024.pem b/test/openssl/fixtures/pkey/rsa1024.pem new file mode 100644 index 00000000..464de074 --- /dev/null +++ b/test/openssl/fixtures/pkey/rsa1024.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx +aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/ +Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB +AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0 +maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T +gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572 +74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE +JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX +sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII +8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA +wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi +qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD +dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA== +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/rsa2048.pem b/test/openssl/fixtures/pkey/rsa2048.pem new file mode 100644 index 00000000..ac89cd88 --- /dev/null +++ b/test/openssl/fixtures/pkey/rsa2048.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN +s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign +4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D +kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl +NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J +DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb +I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq +PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V +seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0 +Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc +VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW +wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G +0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj +XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb +aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n +h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw +Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k +IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb +v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId +U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr +vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS +Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC +9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41 +gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG +4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw== +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb new file mode 100644 index 00000000..5f457551 --- /dev/null +++ b/test/openssl/test_asn1.rb @@ -0,0 +1,720 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestASN1 < OpenSSL::TestCase + def test_decode_x509_certificate + subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") + key = Fixtures.pkey("rsa1024") + now = Time.at(Time.now.to_i) # suppress usec + s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf + exts = [ + ["basicConstraints","CA:TRUE,pathlen:1",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ] + dgst = OpenSSL::Digest::SHA1.new + cert = OpenSSL::TestUtils.issue_cert( + subj, key, s, exts, nil, nil, digest: dgst, not_before: now, not_after: now+3600) + + + asn1 = OpenSSL::ASN1.decode(cert) + assert_equal(OpenSSL::ASN1::Sequence, asn1.class) + assert_equal(3, asn1.value.size) + tbs_cert, sig_alg, sig_val = *asn1.value + + assert_equal(OpenSSL::ASN1::Sequence, tbs_cert.class) + assert_equal(8, tbs_cert.value.size) + + version = tbs_cert.value[0] + assert_equal(:CONTEXT_SPECIFIC, version.tag_class) + assert_equal(0, version.tag) + assert_equal(1, version.value.size) + assert_equal(OpenSSL::ASN1::Integer, version.value[0].class) + assert_equal(2, version.value[0].value) + + serial = tbs_cert.value[1] + assert_equal(OpenSSL::ASN1::Integer, serial.class) + assert_equal(0xdeadbeafdeadbeafdeadbeafdeadbeaf, serial.value) + + sig = tbs_cert.value[2] + assert_equal(OpenSSL::ASN1::Sequence, sig.class) + assert_equal(2, sig.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class) + assert_equal("1.2.840.113549.1.1.5", sig.value[0].oid) + assert_equal(OpenSSL::ASN1::Null, sig.value[1].class) + + dn = tbs_cert.value[3] # issuer + assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) + assert_equal(OpenSSL::ASN1::Sequence, dn.class) + assert_equal(3, dn.value.size) + assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) + assert_equal(1, dn.value[0].value.size) + assert_equal(1, dn.value[1].value.size) + assert_equal(1, dn.value[2].value.size) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) + assert_equal(2, dn.value[0].value[0].value.size) + assert_equal(2, dn.value[1].value[0].value.size) + assert_equal(2, dn.value[2].value[0].value.size) + oid, value = *dn.value[0].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("org", value.value) + oid, value = *dn.value[1].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("ruby-lang", value.value) + oid, value = *dn.value[2].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("2.5.4.3", oid.oid) + assert_equal(OpenSSL::ASN1::UTF8String, value.class) + assert_equal("TestCA", value.value) + + validity = tbs_cert.value[4] + assert_equal(OpenSSL::ASN1::Sequence, validity.class) + assert_equal(2, validity.value.size) + assert_equal(OpenSSL::ASN1::UTCTime, validity.value[0].class) + assert_equal(now, validity.value[0].value) + assert_equal(OpenSSL::ASN1::UTCTime, validity.value[1].class) + assert_equal(now+3600, validity.value[1].value) + + dn = tbs_cert.value[5] # subject + assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) + assert_equal(OpenSSL::ASN1::Sequence, dn.class) + assert_equal(3, dn.value.size) + assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) + assert_equal(1, dn.value[0].value.size) + assert_equal(1, dn.value[1].value.size) + assert_equal(1, dn.value[2].value.size) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) + assert_equal(2, dn.value[0].value[0].value.size) + assert_equal(2, dn.value[1].value[0].value.size) + assert_equal(2, dn.value[2].value[0].value.size) + oid, value = *dn.value[0].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("org", value.value) + oid, value = *dn.value[1].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("ruby-lang", value.value) + oid, value = *dn.value[2].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("2.5.4.3", oid.oid) + assert_equal(OpenSSL::ASN1::UTF8String, value.class) + assert_equal("TestCA", value.value) + + pkey = tbs_cert.value[6] + assert_equal(OpenSSL::ASN1::Sequence, pkey.class) + assert_equal(2, pkey.value.size) + assert_equal(OpenSSL::ASN1::Sequence, pkey.value[0].class) + assert_equal(2, pkey.value[0].value.size) + assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) + assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) + assert_equal(OpenSSL::ASN1::BitString, pkey.value[1].class) + assert_equal(0, pkey.value[1].unused_bits) + spkey = OpenSSL::ASN1.decode(pkey.value[1].value) + assert_equal(OpenSSL::ASN1::Sequence, spkey.class) + assert_equal(2, spkey.value.size) + assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class) + assert_equal(cert.public_key.n, spkey.value[0].value) + assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class) + assert_equal(cert.public_key.e, spkey.value[1].value) + + extensions = tbs_cert.value[7] + assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class) + assert_equal(3, extensions.tag) + assert_equal(1, extensions.value.size) + assert_equal(OpenSSL::ASN1::Sequence, extensions.value[0].class) + assert_equal(3, extensions.value[0].value.size) + + ext = extensions.value[0].value[0] # basicConstraints + assert_equal(OpenSSL::ASN1::Sequence, ext.class) + assert_equal(3, ext.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) + assert_equal("2.5.29.19", ext.value[0].oid) + assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) + assert_equal(true, ext.value[1].value) + assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) + extv = OpenSSL::ASN1.decode(ext.value[2].value) + assert_equal(OpenSSL::ASN1::Sequence, extv.class) + assert_equal(2, extv.value.size) + assert_equal(OpenSSL::ASN1::Boolean, extv.value[0].class) + assert_equal(true, extv.value[0].value) + assert_equal(OpenSSL::ASN1::Integer, extv.value[1].class) + assert_equal(1, extv.value[1].value) + + ext = extensions.value[0].value[1] # keyUsage + assert_equal(OpenSSL::ASN1::Sequence, ext.class) + assert_equal(3, ext.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) + assert_equal("2.5.29.15", ext.value[0].oid) + assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) + assert_equal(true, ext.value[1].value) + assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) + extv = OpenSSL::ASN1.decode(ext.value[2].value) + assert_equal(OpenSSL::ASN1::BitString, extv.class) + str = +"\000"; str[0] = 0b00000110.chr + assert_equal(str, extv.value) + + ext = extensions.value[0].value[2] # subjetKeyIdentifier + assert_equal(OpenSSL::ASN1::Sequence, ext.class) + assert_equal(2, ext.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) + assert_equal("2.5.29.14", ext.value[0].oid) + assert_equal(OpenSSL::ASN1::OctetString, ext.value[1].class) + extv = OpenSSL::ASN1.decode(ext.value[1].value) + assert_equal(OpenSSL::ASN1::OctetString, extv.class) + sha1 = OpenSSL::Digest::SHA1.new + sha1.update(pkey.value[1].value) + assert_equal(sha1.digest, extv.value) + + assert_equal(OpenSSL::ASN1::Sequence, sig_alg.class) + assert_equal(2, sig_alg.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) + assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) + assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class) + + assert_equal(OpenSSL::ASN1::BitString, sig_val.class) + cululated_sig = key.sign(OpenSSL::Digest::SHA1.new, tbs_cert.to_der) + assert_equal(cululated_sig, sig_val.value) + end + + def test_decode_all + raw = B(%w{ 02 01 01 02 01 02 02 01 03 }) + ary = OpenSSL::ASN1.decode_all(raw) + assert_equal(3, ary.size) + ary.each_with_index do |asn1, i| + assert_universal(OpenSSL::ASN1::INTEGER, asn1) + assert_equal(i + 1, asn1.value) + end + end + + def test_object_id_register + oid = "1.2.34.56789" + pend "OID 1.2.34.56789 is already registered" if OpenSSL::ASN1::ObjectId(oid).sn + assert_equal true, OpenSSL::ASN1::ObjectId.register(oid, "ossl-test-sn", "ossl-test-ln") + obj = OpenSSL::ASN1::ObjectId(oid) + assert_equal oid, obj.oid + assert_equal "ossl-test-sn", obj.sn + assert_equal "ossl-test-ln", obj.ln + obj = encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId("ossl-test-ln") + assert_equal "ossl-test-sn", obj.value + end + + def test_end_of_content + encode_decode_test B(%w{ 00 00 }), OpenSSL::ASN1::EndOfContent.new + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 00 01 00 })) + } + end + + def test_boolean + encode_decode_test B(%w{ 01 01 00 }), OpenSSL::ASN1::Boolean.new(false) + encode_decode_test B(%w{ 01 01 FF }), OpenSSL::ASN1::Boolean.new(true) + decode_test B(%w{ 01 01 01 }), OpenSSL::ASN1::Boolean.new(true) + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 01 02 00 00 })) + } + end + + def test_integer + encode_decode_test B(%w{ 02 01 00 }), OpenSSL::ASN1::Integer.new(0) + encode_decode_test B(%w{ 02 01 48 }), OpenSSL::ASN1::Integer.new(72) + encode_decode_test B(%w{ 02 02 00 80 }), OpenSSL::ASN1::Integer.new(128) + encode_decode_test B(%w{ 02 01 81 }), OpenSSL::ASN1::Integer.new(-127) + encode_decode_test B(%w{ 02 01 80 }), OpenSSL::ASN1::Integer.new(-128) + encode_decode_test B(%w{ 02 01 FF }), OpenSSL::ASN1::Integer.new(-1) + encode_decode_test B(%w{ 02 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(2 ** 64) + encode_decode_test B(%w{ 02 09 FF 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(-(2 ** 64)) + # FIXME: OpenSSL < 1.1.0 does not fail + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 02 02 00 7F })) + # } + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 02 02 FF 80 })) + # } + end + + def test_enumerated + encode_decode_test B(%w{ 0A 01 00 }), OpenSSL::ASN1::Enumerated.new(0) + encode_decode_test B(%w{ 0A 01 48 }), OpenSSL::ASN1::Enumerated.new(72) + encode_decode_test B(%w{ 0A 02 00 80 }), OpenSSL::ASN1::Enumerated.new(128) + encode_decode_test B(%w{ 0A 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Enumerated.new(2 ** 64) + end + + def test_bitstring + encode_decode_test B(%w{ 03 01 00 }), OpenSSL::ASN1::BitString.new(B(%w{})) + encode_decode_test B(%w{ 03 02 00 01 }), OpenSSL::ASN1::BitString.new(B(%w{ 01 })) + obj = OpenSSL::ASN1::BitString.new(B(%w{ F0 })) + obj.unused_bits = 4 + encode_decode_test B(%w{ 03 02 04 F0 }), obj + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 03 00 })) + } + # OpenSSL < OpenSSL_1_0_1k and LibreSSL ignore the error + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 03 03 08 FF 00 })) + # } + # OpenSSL does not seem to prohibit this, though X.690 8.6.2.3 (15/08) does + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 03 01 04 })) + # } + assert_raise(OpenSSL::ASN1::ASN1Error) { + obj = OpenSSL::ASN1::BitString.new(B(%w{ FF FF })) + obj.unused_bits = 8 + obj.to_der + } + end + + def test_string_basic + test = -> (tag, klass) { + encode_decode_test tag.chr + B(%w{ 00 }), klass.new(B(%w{})) + encode_decode_test tag.chr + B(%w{ 02 00 01 }), klass.new(B(%w{ 00 01 })) + } + test.(4, OpenSSL::ASN1::OctetString) + test.(12, OpenSSL::ASN1::UTF8String) + test.(18, OpenSSL::ASN1::NumericString) + test.(19, OpenSSL::ASN1::PrintableString) + test.(20, OpenSSL::ASN1::T61String) + test.(21, OpenSSL::ASN1::VideotexString) + test.(22, OpenSSL::ASN1::IA5String) + test.(25, OpenSSL::ASN1::GraphicString) + test.(26, OpenSSL::ASN1::ISO64String) + test.(27, OpenSSL::ASN1::GeneralString) + test.(28, OpenSSL::ASN1::UniversalString) + test.(30, OpenSSL::ASN1::BMPString) + end + + def test_null + encode_decode_test B(%w{ 05 00 }), OpenSSL::ASN1::Null.new(nil) + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 05 01 00 })) + } + end + + def test_object_identifier + encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new("0.0".b) + encode_decode_test B(%w{ 06 01 28 }), OpenSSL::ASN1::ObjectId.new("1.0".b) + encode_decode_test B(%w{ 06 03 88 37 03 }), OpenSSL::ASN1::ObjectId.new("2.999.3".b) + encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId.new("1.2.34.56789".b) + obj = encode_decode_test B(%w{ 06 09 60 86 48 01 65 03 04 02 01 }), OpenSSL::ASN1::ObjectId.new("sha256") + assert_equal "2.16.840.1.101.3.4.2.1", obj.oid + assert_equal "SHA256", obj.sn + assert_equal "sha256", obj.ln + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 06 00 })) + } + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 06 01 80 })) + } + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("3.0".b).to_der } + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("0.40".b).to_der } + + begin + oid = (0...100).to_a.join(".").b + obj = OpenSSL::ASN1::ObjectId.new(oid) + assert_equal oid, obj.oid + rescue OpenSSL::ASN1::ASN1Error + pend "OBJ_obj2txt() not working (LibreSSL?)" if $!.message =~ /OBJ_obj2txt/ + raise + end + + aki = [ + OpenSSL::ASN1::ObjectId.new("authorityKeyIdentifier"), + OpenSSL::ASN1::ObjectId.new("X509v3 Authority Key Identifier"), + OpenSSL::ASN1::ObjectId.new("2.5.29.35") + ] + + ski = [ + OpenSSL::ASN1::ObjectId.new("subjectKeyIdentifier"), + OpenSSL::ASN1::ObjectId.new("X509v3 Subject Key Identifier"), + OpenSSL::ASN1::ObjectId.new("2.5.29.14") + ] + + aki.each do |a| + aki.each do |b| + assert a == b + end + + ski.each do |b| + refute a == b + end + end + + assert_raise(TypeError) { + OpenSSL::ASN1::ObjectId.new("authorityKeyIdentifier") == nil + } + end + + def test_sequence + encode_decode_test B(%w{ 30 00 }), OpenSSL::ASN1::Sequence.new([]) + encode_decode_test B(%w{ 30 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::Sequence.new([]), + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) + ]) + + expected = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) + expected.indefinite_length = true + encode_decode_test B(%w{ 30 80 04 01 00 00 00 }), expected + + # OpenSSL::ASN1::EndOfContent can only be at the end + obj = OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::EndOfContent.new, + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), + OpenSSL::ASN1::EndOfContent.new, + ]) + obj.indefinite_length = true + assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } + + # The last EOC in value is ignored if indefinite length form is used + expected = OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), + OpenSSL::ASN1::EndOfContent.new + ]) + expected.indefinite_length = true + encode_test B(%w{ 30 80 04 01 00 00 00 }), expected + end + + def test_set + encode_decode_test B(%w{ 31 00 }), OpenSSL::ASN1::Set.new([]) + encode_decode_test B(%w{ 31 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Set.new([ + OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::Sequence.new([]), + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) + ]) + expected = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) + expected.indefinite_length = true + encode_decode_test B(%w{ 31 80 04 01 00 00 00 }), expected + end + + def test_utctime + encode_decode_test B(%w{ 17 0D }) + "160908234339Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39)) + # Seconds is omitted + decode_test B(%w{ 17 0B }) + "1609082343Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 0)) + begin + # possible range of UTCTime is 1969-2068 currently + encode_decode_test B(%w{ 17 0D }) + "690908234339Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(1969, 9, 8, 23, 43, 39)) + rescue OpenSSL::ASN1::ASN1Error + pend "No negative time_t support?" + end + # not implemented + # decode_test B(%w{ 17 11 }) + "500908234339+0930".b, + # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 39, "+09:30")) + # decode_test B(%w{ 17 0F }) + "5009082343-0930".b, + # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 0, "-09:30")) + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b) + # } + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b) + # } + end + + def test_generalizedtime + encode_decode_test B(%w{ 18 0F }) + "20161208193429Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29)) + encode_decode_test B(%w{ 18 0F }) + "99990908234339Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39)) + decode_test B(%w{ 18 0D }) + "201612081934Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0)) + # not implemented + # decode_test B(%w{ 18 13 }) + "20161208193439+0930".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, "+09:30")) + # decode_test B(%w{ 18 11 }) + "201612081934-0930".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:30")) + # decode_test B(%w{ 18 11 }) + "201612081934-09".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:00")) + # decode_test B(%w{ 18 0D }) + "2016120819.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) + # decode_test B(%w{ 18 0D }) + "2016120819,5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) + # decode_test B(%w{ 18 0F }) + "201612081934.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 30)) + # decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5)) + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 18 0D }) + "201612081934Y".b) + # } + end + + def test_basic_asn1data + encode_test B(%w{ 00 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 0, :UNIVERSAL) + encode_test B(%w{ 01 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :UNIVERSAL) + encode_decode_test B(%w{ 41 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :APPLICATION) + encode_decode_test B(%w{ 81 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :CONTEXT_SPECIFIC) + encode_decode_test B(%w{ C1 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :PRIVATE) + encode_decode_test B(%w{ 1F 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 32, :UNIVERSAL) + encode_decode_test B(%w{ 1F C0 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 8224, :UNIVERSAL) + encode_decode_test B(%w{ 41 02 AB CD }), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :APPLICATION) + encode_decode_test B(%w{ 41 81 80 } + %w{ AB CD } * 64), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 64), 1, :APPLICATION) + encode_decode_test B(%w{ 41 82 01 00 } + %w{ AB CD } * 128), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 128), 1, :APPLICATION) + encode_decode_test B(%w{ 61 00 }), OpenSSL::ASN1::ASN1Data.new([], 1, :APPLICATION) + obj = OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE)], 1, :APPLICATION) + obj.indefinite_length = true + encode_decode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::ASN1Data.new([ + OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE), + OpenSSL::ASN1::EndOfContent.new + ], 1, :APPLICATION) + obj.indefinite_length = true + encode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :UNIVERSAL) + obj.indefinite_length = true + assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } + end + + def test_basic_primitive + encode_test B(%w{ 00 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 0) + encode_test B(%w{ 01 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :UNIVERSAL) + encode_test B(%w{ 81 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 01 02 AB CD }), OpenSSL::ASN1::Primitive.new(B(%w{ AB CD }), 1) + assert_raise(TypeError) { OpenSSL::ASN1::Primitive.new([], 1).to_der } + + prim = OpenSSL::ASN1::Integer.new(50) + assert_equal false, prim.indefinite_length + assert_not_respond_to prim, :indefinite_length= + end + + def test_basic_constructed + octet_string = OpenSSL::ASN1::OctetString.new(B(%w{ AB CD })) + encode_test B(%w{ 20 00 }), OpenSSL::ASN1::Constructive.new([], 0) + encode_test B(%w{ 21 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :UNIVERSAL) + encode_test B(%w{ A1 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 21 04 04 02 AB CD }), OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj = OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj.indefinite_length = true + encode_decode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::Constructive.new([octet_string, OpenSSL::ASN1::EndOfContent.new], 1) + obj.indefinite_length = true + encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj + end + + def test_prim_explicit_tagging + oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) + encode_test B(%w{ A0 03 04 01 61 }), oct_str + oct_str2 = OpenSSL::ASN1::OctetString.new("a", 1, :EXPLICIT, :APPLICATION) + encode_test B(%w{ 61 03 04 01 61 }), oct_str2 + + decoded = OpenSSL::ASN1.decode(oct_str2.to_der) + assert_equal :APPLICATION, decoded.tag_class + assert_equal 1, decoded.tag + assert_equal 1, decoded.value.size + inner = decoded.value[0] + assert_equal OpenSSL::ASN1::OctetString, inner.class + assert_equal B(%w{ 61 }), inner.value + end + + def test_prim_implicit_tagging + int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) + encode_test B(%w{ 80 01 01 }), int + int2 = OpenSSL::ASN1::Integer.new(1, 1, :IMPLICIT, :APPLICATION) + encode_test B(%w{ 41 01 01 }), int2 + decoded = OpenSSL::ASN1.decode(int2.to_der) + assert_equal :APPLICATION, decoded.tag_class + assert_equal 1, decoded.tag + assert_equal B(%w{ 01 }), decoded.value + + # Special behavior: Encoding universal types with non-default 'tag' + # attribute and nil tagging method. + int3 = OpenSSL::ASN1::Integer.new(1, 1) + encode_test B(%w{ 01 01 01 }), int3 + end + + def test_cons_explicit_tagging + content = [ OpenSSL::ASN1::PrintableString.new('abc') ] + seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) + encode_test B(%w{ A2 07 30 05 13 03 61 62 63 }), seq + seq2 = OpenSSL::ASN1::Sequence.new(content, 3, :EXPLICIT, :APPLICATION) + encode_test B(%w{ 63 07 30 05 13 03 61 62 63 }), seq2 + + content3 = [ OpenSSL::ASN1::PrintableString.new('abc'), + OpenSSL::ASN1::EndOfContent.new() ] + seq3 = OpenSSL::ASN1::Sequence.new(content3, 2, :EXPLICIT) + seq3.indefinite_length = true + encode_test B(%w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 }), seq3 + end + + def test_cons_implicit_tagging + content = [ OpenSSL::ASN1::Null.new(nil) ] + seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) + encode_test B(%w{ A1 02 05 00 }), seq + seq2 = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT, :APPLICATION) + encode_test B(%w{ 61 02 05 00 }), seq2 + + content3 = [ OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::EndOfContent.new() ] + seq3 = OpenSSL::ASN1::Sequence.new(content3, 1, :IMPLICIT) + seq3.indefinite_length = true + encode_test B(%w{ A1 80 05 00 00 00 }), seq3 + + # Special behavior: Encoding universal types with non-default 'tag' + # attribute and nil tagging method. + seq4 = OpenSSL::ASN1::Sequence.new([], 1) + encode_test B(%w{ 21 00 }), seq4 + end + + def test_octet_string_constructed_tagging + octets = [ OpenSSL::ASN1::OctetString.new('aaa') ] + cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT) + encode_test B(%w{ A0 05 04 03 61 61 61 }), cons + + octets = [ OpenSSL::ASN1::OctetString.new('aaa'), + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT) + cons.indefinite_length = true + encode_test B(%w{ A0 80 04 03 61 61 61 00 00 }), cons + end + + def test_recursive_octet_string_indefinite_length + octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"), + OpenSSL::ASN1::EndOfContent.new() ] + octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"), + OpenSSL::ASN1::EndOfContent.new() ] + container1 = OpenSSL::ASN1::Constructive.new(octets_sub1, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) + container1.indefinite_length = true + container2 = OpenSSL::ASN1::Constructive.new(octets_sub2, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) + container2.indefinite_length = true + octets3 = OpenSSL::ASN1::OctetString.new("\x03") + + octets = [ container1, container2, octets3, + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Constructive.new(octets, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) + cons.indefinite_length = true + raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + + def test_recursive_octet_string_parse + raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) + asn1 = OpenSSL::ASN1.decode(raw) + assert_equal(OpenSSL::ASN1::Constructive, asn1.class) + assert_universal(OpenSSL::ASN1::OCTET_STRING, asn1) + assert_equal(true, asn1.indefinite_length) + assert_equal(3, asn1.value.size) + nested1 = asn1.value[0] + assert_equal(OpenSSL::ASN1::Constructive, nested1.class) + assert_universal(OpenSSL::ASN1::OCTET_STRING, nested1) + assert_equal(true, nested1.indefinite_length) + assert_equal(1, nested1.value.size) + oct1 = nested1.value[0] + assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1) + assert_equal(false, oct1.indefinite_length) + nested2 = asn1.value[1] + assert_equal(OpenSSL::ASN1::Constructive, nested2.class) + assert_universal(OpenSSL::ASN1::OCTET_STRING, nested2) + assert_equal(true, nested2.indefinite_length) + assert_equal(1, nested2.value.size) + oct2 = nested2.value[0] + assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2) + assert_equal(false, oct2.indefinite_length) + oct3 = asn1.value[2] + assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3) + assert_equal(false, oct3.indefinite_length) + end + + def test_decode_constructed_overread + test = %w{ 31 06 31 02 30 02 05 00 } + # ^ <- invalid + raw = [test.join].pack("H*") + ret = [] + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.traverse(raw) { |x| ret << x } + } + assert_equal 2, ret.size + assert_equal 17, ret[0][6] + assert_equal 17, ret[1][6] + + test = %w{ 31 80 30 03 00 00 } + # ^ <- invalid + raw = [test.join].pack("H*") + ret = [] + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.traverse(raw) { |x| ret << x } + } + assert_equal 1, ret.size + assert_equal 17, ret[0][6] + end + + def test_constructive_each + data = [OpenSSL::ASN1::Integer.new(0), OpenSSL::ASN1::Integer.new(1)] + seq = OpenSSL::ASN1::Sequence.new data + + assert_equal data, seq.entries + end + + # Very time consuming test. + # def test_gc_stress + # assert_ruby_status(['--disable-gems', '-eGC.stress=true', '-erequire "openssl.so"']) + # end + + private + + def B(ary) + [ary.join].pack("H*") + end + + def assert_asn1_equal(a, b) + assert_equal a.class, b.class + assert_equal a.tag, b.tag + assert_equal a.tag_class, b.tag_class + assert_equal a.indefinite_length, b.indefinite_length + assert_equal a.unused_bits, b.unused_bits if a.respond_to?(:unused_bits) + case a.value + when Array + a.value.each_with_index { |ai, i| + assert_asn1_equal ai, b.value[i] + } + else + if OpenSSL::ASN1::ObjectId === a + assert_equal a.oid, b.oid + else + assert_equal a.value, b.value + end + end + assert_equal a.to_der, b.to_der + end + + def encode_test(der, obj) + assert_equal der, obj.to_der + end + + def decode_test(der, obj) + decoded = OpenSSL::ASN1.decode(der) + assert_asn1_equal obj, decoded + decoded + end + + def encode_decode_test(der, obj) + encode_test(der, obj) + decode_test(der, obj) + end + + def assert_universal(tag, asn1) + assert_equal(tag, asn1.tag) + if asn1.respond_to?(:tagging) + assert_nil(asn1.tagging) + end + assert_equal(:UNIVERSAL, asn1.tag_class) + end +end + +end diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb new file mode 100644 index 00000000..547d334c --- /dev/null +++ b/test/openssl/test_bn.rb @@ -0,0 +1,286 @@ +# coding: us-ascii +# frozen_string_literal: true +require_relative 'utils' +require "prime" + +if defined?(OpenSSL) + +class OpenSSL::TestBN < OpenSSL::TestCase + def setup + super + @e1 = OpenSSL::BN.new(999.to_s(16), 16) # OpenSSL::BN.new(str, 16) must be most stable + @e2 = OpenSSL::BN.new("-" + 999.to_s(16), 16) + @e3 = OpenSSL::BN.new((2**107-1).to_s(16), 16) + @e4 = OpenSSL::BN.new("-" + (2**107-1).to_s(16), 16) + end + + def test_new + assert_raise(ArgumentError) { OpenSSL::BN.new } + assert_raise(ArgumentError) { OpenSSL::BN.new(nil) } + assert_raise(ArgumentError) { OpenSSL::BN.new(nil, 2) } + + assert_equal(@e1, OpenSSL::BN.new("999")) + assert_equal(@e1, OpenSSL::BN.new("999", 10)) + assert_equal(@e1, OpenSSL::BN.new("\x03\xE7", 2)) + assert_equal(@e1, OpenSSL::BN.new("\x00\x00\x00\x02\x03\xE7", 0)) + assert_equal(@e2, OpenSSL::BN.new("-999")) + assert_equal(@e2, OpenSSL::BN.new("-999", 10)) + assert_equal(@e2, OpenSSL::BN.new("\x00\x00\x00\x02\x83\xE7", 0)) + assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s)) + assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s, 10)) + assert_equal(@e3, OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2)) + assert_equal(@e3, OpenSSL::BN.new("\x00\x00\x00\x0E\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) + assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s)) + assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s, 10)) + assert_equal(@e4, OpenSSL::BN.new("\x00\x00\x00\x0E\x87\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) + + e1copy = OpenSSL::BN.new(@e1) + assert_equal(@e1, e1copy) + e1copy.clear_bit!(0) #=> 998 + assert_not_equal(@e1, e1copy) + + assert_equal(@e1, OpenSSL::BN.new(999)) + assert_equal(@e2, OpenSSL::BN.new(-999)) + assert_equal(@e3, OpenSSL::BN.new(2**107-1)) + assert_equal(@e4, OpenSSL::BN.new(-(2**107-1))) + + assert_equal(@e1, 999.to_bn) + assert_equal(@e2, -999.to_bn) + assert_equal(@e3, (2**107-1).to_bn) + assert_equal(@e4, (-(2**107-1)).to_bn) + end + + def test_to_str + assert_equal("999", @e1.to_s(10)) + assert_equal("-999", @e2.to_s(10)) + assert_equal((2**107-1).to_s, @e3.to_s(10)) + assert_equal((-(2**107-1)).to_s, @e4.to_s(10)) + assert_equal("999", @e1.to_s) + + assert_equal("03E7", @e1.to_s(16)) + assert_equal("-03E7", @e2.to_s(16)) + assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e3.to_s(16)) + assert_equal("-07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e4.to_s(16)) + + assert_equal("\x03\xe7", @e1.to_s(2)) + assert_equal("\x03\xe7", @e2.to_s(2)) + assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(2)) + assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(2)) + + assert_equal("\x00\x00\x00\x02\x03\xe7", @e1.to_s(0)) + assert_equal("\x00\x00\x00\x02\x83\xe7", @e2.to_s(0)) + assert_equal("\x00\x00\x00\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(0)) + assert_equal("\x00\x00\x00\x0e\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(0)) + end + + def test_to_int + assert_equal(999, @e1.to_i) + assert_equal(-999, @e2.to_i) + assert_equal(2**107-1, @e3.to_i) + assert_equal(-(2**107-1), @e4.to_i) + + assert_equal(999, @e1.to_int) + end + + def test_coerce + assert_equal(["", "-999"], @e2.coerce("")) + assert_equal([1000, -999], @e2.coerce(1000)) + assert_raise(TypeError) { @e2.coerce(Class.new.new) } + end + + def test_zero_p + assert_equal(true, 0.to_bn.zero?) + assert_equal(false, 1.to_bn.zero?) + end + + def test_one_p + assert_equal(true, 1.to_bn.one?) + assert_equal(false, 2.to_bn.one?) + end + + def test_odd_p + assert_equal(true, 1.to_bn.odd?) + assert_equal(false, 2.to_bn.odd?) + end + + def test_negative_p + assert_equal(false, 0.to_bn.negative?) + assert_equal(false, @e1.negative?) + assert_equal(true, @e2.negative?) + end + + def test_sqr + assert_equal(1, 1.to_bn.sqr) + assert_equal(100, 10.to_bn.sqr) + end + + def test_four_ops + assert_equal(3, 1.to_bn + 2) + assert_equal(-1, 1.to_bn + -2) + assert_equal(-1, 1.to_bn - 2) + assert_equal(3, 1.to_bn - -2) + assert_equal(2, 1.to_bn * 2) + assert_equal(-2, 1.to_bn * -2) + assert_equal([0, 1], 1.to_bn / 2) + assert_equal([2, 0], 2.to_bn / 1) + assert_raise(OpenSSL::BNError) { 1.to_bn / 0 } + end + + def test_unary_plus_minus + assert_equal(999, +@e1) + assert_equal(-999, +@e2) + assert_equal(-999, -@e1) + assert_equal(+999, -@e2) + end + + def test_mod + assert_equal(1, 1.to_bn % 2) + assert_equal(0, 2.to_bn % 1) + assert_equal(-2, -2.to_bn % 7) + end + + def test_exp + assert_equal(1, 1.to_bn ** 5) + assert_equal(32, 2.to_bn ** 5) + end + + def test_gcd + assert_equal(1, 7.to_bn.gcd(5)) + assert_equal(8, 24.to_bn.gcd(16)) + end + + def test_mod_sqr + assert_equal(4, 3.to_bn.mod_sqr(5)) + assert_equal(0, 59.to_bn.mod_sqr(59)) + end + + def test_mod_inverse + assert_equal(2, 3.to_bn.mod_inverse(5)) + assert_raise(OpenSSL::BNError) { 3.to_bn.mod_inverse(6) } + end + + def test_mod_add + assert_equal(1, 3.to_bn.mod_add(5, 7)) + assert_equal(2, 3.to_bn.mod_add(5, 3)) + assert_equal(5, 3.to_bn.mod_add(-5, 7)) + end + + def test_mod_sub + assert_equal(1, 11.to_bn.mod_sub(3, 7)) + assert_equal(2, 11.to_bn.mod_sub(3, 3)) + assert_equal(5, 3.to_bn.mod_sub(5, 7)) + end + + def test_mod_mul + assert_equal(1, 2.to_bn.mod_mul(4, 7)) + assert_equal(5, 2.to_bn.mod_mul(-1, 7)) + end + + def test_mod_exp + assert_equal(1, 3.to_bn.mod_exp(2, 8)) + assert_equal(4, 2.to_bn.mod_exp(5, 7)) + end + + def test_bit_operations + e = 0b10010010.to_bn + assert_equal(0b10010011, e.set_bit!(0)) + assert_equal(0b10010011, e.set_bit!(1)) + assert_equal(0b1010010011, e.set_bit!(9)) + + e = 0b10010010.to_bn + assert_equal(0b10010010, e.clear_bit!(0)) + assert_equal(0b10010000, e.clear_bit!(1)) + + e = 0b10010010.to_bn + assert_equal(0b10010010, e.mask_bits!(8)) + assert_equal(0b10, e.mask_bits!(3)) + + e = 0b10010010.to_bn + assert_equal(false, e.bit_set?(0)) + assert_equal(true, e.bit_set?(1)) + assert_equal(false, e.bit_set?(1000)) + + e = 0b10010010.to_bn + assert_equal(0b1001001000, e << 2) + assert_equal(0b10010010, e) + assert_equal(0b1001001000, e.lshift!(2)) + assert_equal(0b1001001000, e) + + e = 0b10010010.to_bn + assert_equal(0b100100, e >> 2) + assert_equal(0b10010010, e) + assert_equal(0b100100, e.rshift!(2)) + assert_equal(0b100100, e) + end + + def test_random + 10.times { + r1 = OpenSSL::BN.rand(8) + assert_include(128..255, r1) + r2 = OpenSSL::BN.rand(8, -1) + assert_include(0..255, r2) + r3 = OpenSSL::BN.rand(8, 1) + assert_include(192..255, r3) + r4 = OpenSSL::BN.rand(8, 1, true) + assert_include(192..255, r4) + assert_equal(true, r4.odd?) + + r5 = OpenSSL::BN.rand_range(256) + assert_include(0..255, r5) + } + end + + def test_prime + p1 = OpenSSL::BN.generate_prime(32) + assert_include(0...2**32, p1) + assert_equal(true, Prime.prime?(p1.to_i)) + p2 = OpenSSL::BN.generate_prime(32, true) + assert_equal(true, Prime.prime?((p2.to_i - 1) / 2)) + p3 = OpenSSL::BN.generate_prime(32, false, 4) + assert_equal(1, p3 % 4) + p4 = OpenSSL::BN.generate_prime(32, false, 4, 3) + assert_equal(3, p4 % 4) + + assert_equal(true, p1.prime?) + assert_equal(true, p2.prime?) + assert_equal(true, p3.prime?) + assert_equal(true, p4.prime?) + assert_equal(true, @e3.prime?) + assert_equal(true, @e3.prime_fasttest?) + end + + def test_num_bits_bytes + assert_equal(10, @e1.num_bits) + assert_equal(2, @e1.num_bytes) + assert_equal(107, @e3.num_bits) + assert_equal(14, @e3.num_bytes) + assert_equal(0, 0.to_bn.num_bits) + assert_equal(0, 0.to_bn.num_bytes) + assert_equal(9, -256.to_bn.num_bits) + assert_equal(2, -256.to_bn.num_bytes) + end + + def test_comparison + assert_equal(false, @e1 == nil) + assert_equal(false, @e1 == -999) + assert_equal(true, @e1 == 999) + assert_equal(true, @e1 == 999.to_bn) + assert_equal(false, @e1.eql?(nil)) + assert_equal(false, @e1.eql?(999)) + assert_equal(true, @e1.eql?(999.to_bn)) + assert_equal(@e1.hash, 999.to_bn.hash) + assert_not_equal(@e1.hash, @e3.hash) + assert_equal(0, @e1.cmp(999)) + assert_equal(1, @e1.cmp(-999)) + assert_equal(0, @e1.ucmp(999)) + assert_equal(0, @e1.ucmp(-999)) + assert_instance_of(String, @e1.hash.to_s) + end + + def test_argument_error + bug15760 = '[ruby-core:92231] [Bug #15760]' + assert_raise(ArgumentError, bug15760) { OpenSSL::BN.new(nil, 2) } + end +end + +end diff --git a/test/openssl/test_buffering.rb b/test/openssl/test_buffering.rb new file mode 100644 index 00000000..7575c5b4 --- /dev/null +++ b/test/openssl/test_buffering.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestBuffering < OpenSSL::TestCase + class IO + include OpenSSL::Buffering + + attr_accessor :sync + + def initialize + @io = Buffer.new + def @io.sync + true + end + + super + + @sync = false + end + + def string + @io + end + + def sysread(size) + str = @io.slice!(0, size) + raise EOFError if str.empty? + str + end + + def syswrite(str) + @io << str + str.size + end + end + + def setup + super + @io = IO.new + end + + def test_encoding + @io.write '😊' + @io.flush + + assert_equal @io.string.encoding, Encoding::BINARY + end + + def test_flush + @io.write 'a' + + assert_not_predicate @io, :sync + assert_empty @io.string + + assert_equal @io, @io.flush + + assert_not_predicate @io, :sync + assert_equal 'a', @io.string + end + + def test_flush_error + @io.write 'a' + + assert_not_predicate @io, :sync + assert_empty @io.string + + def @io.syswrite *a + raise SystemCallError, 'fail' + end + + assert_raise SystemCallError do + @io.flush + end + + assert_not_predicate @io, :sync, 'sync must not change' + end + + def test_getc + @io.syswrite('abc') + assert_equal(?a, @io.getc) + assert_equal(?b, @io.getc) + assert_equal(?c, @io.getc) + end + + def test_each_byte + @io.syswrite('abc') + res = [] + @io.each_byte do |c| + res << c + end + assert_equal([97, 98, 99], res) + end +end + +end diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb new file mode 100644 index 00000000..f6ec4980 --- /dev/null +++ b/test/openssl/test_cipher.rb @@ -0,0 +1,340 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestCipher < OpenSSL::TestCase + module Helper + def has_cipher?(name) + @ciphers ||= OpenSSL::Cipher.ciphers + @ciphers.include?(name) + end + end + include Helper + extend Helper + + def test_encrypt_decrypt + # NIST SP 800-38A F.2.1 + key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*") + iv = ["000102030405060708090a0b0c0d0e0f"].pack("H*") + pt = ["6bc1bee22e409f96e93d7e117393172a" \ + "ae2d8a571e03ac9c9eb76fac45af8e51"].pack("H*") + ct = ["7649abac8119b246cee98e9b12e9197d" \ + "5086cb9b507219ee95db113a917678b2"].pack("H*") + cipher = new_encryptor("aes-128-cbc", key: key, iv: iv, padding: 0) + assert_equal ct, cipher.update(pt) << cipher.final + cipher = new_decryptor("aes-128-cbc", key: key, iv: iv, padding: 0) + assert_equal pt, cipher.update(ct) << cipher.final + end + + def test_pkcs5_keyivgen + pass = "\x00" * 8 + salt = "\x01" * 8 + num = 2048 + pt = "data to be encrypted" + cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt + cipher.pkcs5_keyivgen(pass, salt, num, "MD5") + s1 = cipher.update(pt) << cipher.final + + d1 = num.times.inject(pass + salt) {|out, _| OpenSSL::Digest::MD5.digest(out) } + d2 = num.times.inject(d1 + pass + salt) {|out, _| OpenSSL::Digest::MD5.digest(out) } + key = (d1 + d2)[0, 24] + iv = (d1 + d2)[24, 8] + cipher = new_encryptor("DES-EDE3-CBC", key: key, iv: iv) + s2 = cipher.update(pt) << cipher.final + + assert_equal s1, s2 + + cipher2 = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt + assert_raise(ArgumentError) { cipher2.pkcs5_keyivgen(pass, salt, -1, "MD5") } + end + + def test_info + cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt + assert_equal "DES-EDE3-CBC", cipher.name + assert_equal 24, cipher.key_len + assert_equal 8, cipher.iv_len + end + + def test_dup + cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt + assert_equal cipher.name, cipher.dup.name + cipher.encrypt + cipher.random_key + cipher.random_iv + tmpc = cipher.dup + s1 = cipher.update("data") + cipher.final + s2 = tmpc.update("data") + tmpc.final + assert_equal(s1, s2, "encrypt dup") + end + + def test_reset + cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt + cipher.encrypt + cipher.random_key + cipher.random_iv + s1 = cipher.update("data") + cipher.final + cipher.reset + s2 = cipher.update("data") + cipher.final + assert_equal(s1, s2, "encrypt reset") + end + + def test_key_iv_set + cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt + assert_raise(ArgumentError) { cipher.key = "\x01" * 23 } + assert_nothing_raised { cipher.key = "\x01" * 24 } + assert_raise(ArgumentError) { cipher.key = "\x01" * 25 } + assert_raise(ArgumentError) { cipher.iv = "\x01" * 7 } + assert_nothing_raised { cipher.iv = "\x01" * 8 } + assert_raise(ArgumentError) { cipher.iv = "\x01" * 9 } + end + + def test_random_key_iv + data = "data" + s1, s2 = 2.times.map do + cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt + cipher.random_key + cipher.iv = "\x01" * 16 + cipher.update(data) << cipher.final + end + assert_not_equal s1, s2 + + s1, s2 = 2.times.map do + cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt + cipher.key = "\x01" * 16 + cipher.random_iv + cipher.update(data) << cipher.final + end + assert_not_equal s1, s2 + end + + def test_empty_data + cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt + cipher.random_key + assert_raise(ArgumentError) { cipher.update("") } + end + + def test_initialize + cipher = OpenSSL::Cipher.new("DES-EDE3-CBC") + assert_raise(RuntimeError) { cipher.__send__(:initialize, "DES-EDE3-CBC") } + assert_raise(RuntimeError) { OpenSSL::Cipher.allocate.final } + end + + def test_ctr_if_exists + # NIST SP 800-38A F.5.1 + key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*") + iv = ["f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"].pack("H*") + pt = ["6bc1bee22e409f96e93d7e117393172a" \ + "ae2d8a571e03ac9c9eb76fac45af8e51"].pack("H*") + ct = ["874d6191b620e3261bef6864990db6ce" \ + "9806f66b7970fdff8617187bb9fffdff"].pack("H*") + cipher = new_encryptor("aes-128-ctr", key: key, iv: iv, padding: 0) + assert_equal ct, cipher.update(pt) << cipher.final + cipher = new_decryptor("aes-128-ctr", key: key, iv: iv, padding: 0) + assert_equal pt, cipher.update(ct) << cipher.final + end + + def test_ciphers + OpenSSL::Cipher.ciphers.each{|name| + next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name + begin + assert_kind_of(OpenSSL::Cipher, OpenSSL::Cipher.new(name)) + rescue OpenSSL::Cipher::CipherError => e + raise unless /wrap/ =~ name and /wrap mode not allowed/ =~ e.message + end + } + end + + def test_AES + pt = File.read(__FILE__) + %w(ECB CBC CFB OFB).each{|mode| + c1 = OpenSSL::Cipher::AES256.new(mode) + c1.encrypt + c1.pkcs5_keyivgen("passwd") + ct = c1.update(pt) + c1.final + + c2 = OpenSSL::Cipher::AES256.new(mode) + c2.decrypt + c2.pkcs5_keyivgen("passwd") + assert_equal(pt, c2.update(ct) + c2.final) + } + end + + def test_update_raise_if_key_not_set + assert_raise(OpenSSL::Cipher::CipherError) do + # it caused OpenSSL SEGV by uninitialized key [Bug #2768] + OpenSSL::Cipher::AES128.new("ECB").update "." * 17 + end + end + + def test_authenticated + cipher = OpenSSL::Cipher.new('aes-128-gcm') + assert_predicate(cipher, :authenticated?) + cipher = OpenSSL::Cipher.new('aes-128-cbc') + assert_not_predicate(cipher, :authenticated?) + end + + def test_aes_gcm + # GCM spec Appendix B Test Case 4 + key = ["feffe9928665731c6d6a8f9467308308"].pack("H*") + iv = ["cafebabefacedbaddecaf888"].pack("H*") + aad = ["feedfacedeadbeeffeedfacedeadbeef" \ + "abaddad2"].pack("H*") + pt = ["d9313225f88406e5a55909c5aff5269a" \ + "86a7a9531534f7da2e4c303d8a318a72" \ + "1c3c0c95956809532fcf0e2449a6b525" \ + "b16aedf5aa0de657ba637b39"].pack("H*") + ct = ["42831ec2217774244b7221b784d0d49c" \ + "e3aa212f2c02a4e035c17e2329aca12e" \ + "21d514b25466931c7d8f6a5aac84aa05" \ + "1ba30b396a0aac973d58e091"].pack("H*") + tag = ["5bc94fbc3221a5db94fae95ae7121a47"].pack("H*") + + cipher = new_encryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad) + assert_equal ct, cipher.update(pt) << cipher.final + assert_equal tag, cipher.auth_tag + cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad) + assert_equal pt, cipher.update(ct) << cipher.final + + # truncated tag is accepted + cipher = new_encryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad) + assert_equal ct, cipher.update(pt) << cipher.final + assert_equal tag[0, 8], cipher.auth_tag(8) + cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag[0, 8], auth_data: aad) + assert_equal pt, cipher.update(ct) << cipher.final + + # wrong tag is rejected + tag2 = tag.dup + tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff) + cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag2, auth_data: aad) + cipher.update(ct) + assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } + + # wrong aad is rejected + aad2 = aad[0..-2] << aad[-1].succ + cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad2) + cipher.update(ct) + assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } + + # wrong ciphertext is rejected + ct2 = ct[0..-2] << ct[-1].succ + cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad) + cipher.update(ct2) + assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } + end + + def test_aes_gcm_variable_iv_len + # GCM spec Appendix B Test Case 5 + key = ["feffe9928665731c6d6a8f9467308308"].pack("H*") + iv = ["cafebabefacedbad"].pack("H*") + aad = ["feedfacedeadbeeffeedfacedeadbeef" \ + "abaddad2"].pack("H*") + pt = ["d9313225f88406e5a55909c5aff5269a" \ + "86a7a9531534f7da2e4c303d8a318a72" \ + "1c3c0c95956809532fcf0e2449a6b525" \ + "b16aedf5aa0de657ba637b39"].pack("H*") + ct = ["61353b4c2806934a777ff51fa22a4755" \ + "699b2a714fcdc6f83766e5f97b6c7423" \ + "73806900e49f24b22b097544d4896b42" \ + "4989b5e1ebac0f07c23f4598"].pack("H*") + tag = ["3612d2e79e3b0785561be14aaca2fccb"].pack("H*") + + cipher = new_encryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_data: aad) + assert_equal ct, cipher.update(pt) << cipher.final + assert_equal tag, cipher.auth_tag + cipher = new_decryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_tag: tag, auth_data: aad) + assert_equal pt, cipher.update(ct) << cipher.final + end + + def test_aes_ocb_tag_len + # RFC 7253 Appendix A; the second sample + key = ["000102030405060708090A0B0C0D0E0F"].pack("H*") + iv = ["BBAA99887766554433221101"].pack("H*") + aad = ["0001020304050607"].pack("H*") + pt = ["0001020304050607"].pack("H*") + ct = ["6820B3657B6F615A"].pack("H*") + tag = ["5725BDA0D3B4EB3A257C9AF1F8F03009"].pack("H*") + + cipher = new_encryptor("aes-128-ocb", key: key, iv: iv, auth_data: aad) + assert_equal ct, cipher.update(pt) << cipher.final + assert_equal tag, cipher.auth_tag + cipher = new_decryptor("aes-128-ocb", key: key, iv: iv, auth_tag: tag, auth_data: aad) + assert_equal pt, cipher.update(ct) << cipher.final + + # RFC 7253 Appendix A; with 96 bits tag length + key = ["0F0E0D0C0B0A09080706050403020100"].pack("H*") + iv = ["BBAA9988776655443322110D"].pack("H*") + aad = ["000102030405060708090A0B0C0D0E0F1011121314151617" \ + "18191A1B1C1D1E1F2021222324252627"].pack("H*") + pt = ["000102030405060708090A0B0C0D0E0F1011121314151617" \ + "18191A1B1C1D1E1F2021222324252627"].pack("H*") + ct = ["1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1" \ + "A0124B0A55BAE884ED93481529C76B6A"].pack("H*") + tag = ["D0C515F4D1CDD4FDAC4F02AA"].pack("H*") + + cipher = new_encryptor("aes-128-ocb", auth_tag_len: 12, key: key, iv: iv, auth_data: aad) + assert_equal ct, cipher.update(pt) << cipher.final + assert_equal tag, cipher.auth_tag + cipher = new_decryptor("aes-128-ocb", auth_tag_len: 12, key: key, iv: iv, auth_tag: tag, auth_data: aad) + assert_equal pt, cipher.update(ct) << cipher.final + + end if has_cipher?("aes-128-ocb") + + def test_aes_gcm_key_iv_order_issue + pt = "[ruby/openssl#49]" + cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt + cipher.key = "x" * 16 + cipher.iv = "a" * 12 + ct1 = cipher.update(pt) << cipher.final + tag1 = cipher.auth_tag + + cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt + cipher.iv = "a" * 12 + cipher.key = "x" * 16 + ct2 = cipher.update(pt) << cipher.final + tag2 = cipher.auth_tag + + assert_equal ct1, ct2 + assert_equal tag1, tag2 + end + + def test_non_aead_cipher_set_auth_data + assert_raise(OpenSSL::Cipher::CipherError) { + cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt + cipher.auth_data = "123" + } + end + + def test_crypt_after_key + key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*") + %w'ecb cbc cfb ctr gcm'.each do |c| + cipher = OpenSSL::Cipher.new("aes-128-#{c}") + cipher.key = key + cipher.encrypt + assert_raise(OpenSSL::Cipher::CipherError) { cipher.update("") } + + cipher = OpenSSL::Cipher.new("aes-128-#{c}") + cipher.key = key + cipher.decrypt + assert_raise(OpenSSL::Cipher::CipherError) { cipher.update("") } + end + end + + private + + def new_encryptor(algo, **kwargs) + OpenSSL::Cipher.new(algo).tap do |cipher| + cipher.encrypt + kwargs.each {|k, v| cipher.send(:"#{k}=", v) } + end + end + + def new_decryptor(algo, **kwargs) + OpenSSL::Cipher.new(algo).tap do |cipher| + cipher.decrypt + kwargs.each {|k, v| cipher.send(:"#{k}=", v) } + end + end +end + +end diff --git a/test/openssl/test_config.rb b/test/openssl/test_config.rb new file mode 100644 index 00000000..dba66b08 --- /dev/null +++ b/test/openssl/test_config.rb @@ -0,0 +1,304 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestConfig < OpenSSL::TestCase + def setup + super + file = Tempfile.open("openssl.cnf") + file << <<__EOD__ +HOME = . +[ ca ] +default_ca = CA_default +[ CA_default ] +dir = ./demoCA +certs = ./certs +__EOD__ + file.close + @tmpfile = file + @it = OpenSSL::Config.new(file.path) + end + + def teardown + super + @tmpfile.close! + end + + def test_constants + assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE)) + config_file = OpenSSL::Config::DEFAULT_CONFIG_FILE + pend "DEFAULT_CONFIG_FILE may return a wrong path on your platforms. [Bug #6830]" unless File.readable?(config_file) + assert_nothing_raised do + OpenSSL::Config.load(config_file) + end + end + + def test_s_parse + c = OpenSSL::Config.parse('') + assert_equal("[ default ]\n\n", c.to_s) + c = OpenSSL::Config.parse(@it.to_s) + assert_equal(['CA_default', 'ca', 'default'], c.sections.sort) + end + + def test_s_parse_format + c = OpenSSL::Config.parse(<<__EOC__) + baz =qx\t # "baz = qx" + +foo::bar = baz # shortcut section::key format + default::bar = baz # ditto +a=\t \t # "a = ": trailing spaces are ignored + =b # " = b": empty key + =c # " = c": empty key (override the above line) + d= # "c = ": trailing comment is ignored + +sq = 'foo''b\\'ar' + dq ="foo""''\\"" + dq2 = foo""bar +esc=a\\r\\n\\b\\tb +foo\\bar = foo\\b\\\\ar +foo\\bar::foo\\bar = baz +[default1 default2]\t\t # space is allowed in section name + fo =b ar # space allowed in value +[emptysection] + [doller ] +foo=bar +bar = $(foo) +baz = 123$(default::bar)456${foo}798 +qux = ${baz} +quxx = $qux.$qux +__EOC__ + assert_equal(['default', 'default1 default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort) + assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort) + assert_equal('c', c['default']['']) + assert_equal('', c['default']['a']) + assert_equal('qx', c['default']['baz']) + assert_equal('', c['default']['d']) + assert_equal('baz', c['default']['bar']) + assert_equal("foob'ar", c['default']['sq']) + assert_equal("foo''\"", c['default']['dq']) + assert_equal("foobar", c['default']['dq2']) + assert_equal("a\r\n\b\tb", c['default']['esc']) + assert_equal("foo\b\\ar", c['default']['foo\\bar']) + assert_equal('baz', c['foo']['bar']) + assert_equal('baz', c['foo\\bar']['foo\\bar']) + assert_equal('b ar', c['default1 default2']['fo']) + + # dolloer + assert_equal('bar', c['doller']['foo']) + assert_equal('bar', c['doller']['bar']) + assert_equal('123baz456bar798', c['doller']['baz']) + assert_equal('123baz456bar798', c['doller']['qux']) + assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx']) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse("foo = $bar") + end + assert_equal("error in line 1: variable has no value", excn.message) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse("foo = $(bar") + end + assert_equal("error in line 1: no close brace", excn.message) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse("f o =b ar # no space in key") + end + assert_equal("error in line 1: missing equal sign", excn.message) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse(<<__EOC__) +# comment 1 # comments + +# + # comment 2 +\t#comment 3 + [second ]\t +[third # section not terminated +__EOC__ + end + assert_equal("error in line 7: missing close square bracket", excn.message) + end + + def test_s_load + # alias of new + c = OpenSSL::Config.load + assert_equal("", c.to_s) + assert_equal([], c.sections) + # + Tempfile.create("openssl.cnf") {|file| + file.close + c = OpenSSL::Config.load(file.path) + assert_equal("[ default ]\n\n", c.to_s) + assert_equal(['default'], c.sections) + } + end + + def test_initialize + c = OpenSSL::Config.new + assert_equal("", c.to_s) + assert_equal([], c.sections) + end + + def test_initialize_with_empty_file + Tempfile.create("openssl.cnf") {|file| + file.close + c = OpenSSL::Config.new(file.path) + assert_equal("[ default ]\n\n", c.to_s) + assert_equal(['default'], c.sections) + } + end + + def test_initialize_with_example_file + assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) + end + + def test_get_value + assert_equal('CA_default', @it.get_value('ca', 'default_ca')) + assert_equal(nil, @it.get_value('ca', 'no such key')) + assert_equal(nil, @it.get_value('no such section', 'no such key')) + assert_equal('.', @it.get_value('', 'HOME')) + assert_raise(TypeError) do + @it.get_value(nil, 'HOME') # not allowed unlike Config#value + end + # fallback to 'default' ugly... + assert_equal('.', @it.get_value('unknown', 'HOME')) + end + + def test_get_value_ENV + key = ENV.keys.first + assert_not_nil(key) # make sure we have at least one ENV var. + assert_equal(ENV[key], @it.get_value('ENV', key)) + end + + def test_value + # suppress deprecation warnings + EnvUtil.suppress_warning do + assert_equal('CA_default', @it.value('ca', 'default_ca')) + assert_equal(nil, @it.value('ca', 'no such key')) + assert_equal(nil, @it.value('no such section', 'no such key')) + assert_equal('.', @it.value('', 'HOME')) + assert_equal('.', @it.value(nil, 'HOME')) + assert_equal('.', @it.value('HOME')) + # fallback to 'default' ugly... + assert_equal('.', @it.value('unknown', 'HOME')) + end + end + + def test_value_ENV + EnvUtil.suppress_warning do + key = ENV.keys.first + assert_not_nil(key) # make sure we have at least one ENV var. + assert_equal(ENV[key], @it.value('ENV', key)) + end + end + + def test_aref + assert_equal({'HOME' => '.'}, @it['default']) + assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default']) + assert_equal({}, @it['no_such_section']) + assert_equal({}, @it['']) + end + + def test_section + EnvUtil.suppress_warning do + assert_equal({'HOME' => '.'}, @it.section('default')) + assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default')) + assert_equal({}, @it.section('no_such_section')) + assert_equal({}, @it.section('')) + end + end + + def test_sections + assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) + @it['new_section'] = {'foo' => 'bar'} + assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) + @it['new_section'] = {} + assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) + end + + def test_add_value + c = OpenSSL::Config.new + assert_equal("", c.to_s) + # add key + c.add_value('default', 'foo', 'bar') + assert_equal("[ default ]\nfoo=bar\n\n", c.to_s) + # add another key + c.add_value('default', 'baz', 'qux') + assert_equal('bar', c['default']['foo']) + assert_equal('qux', c['default']['baz']) + # update the value + c.add_value('default', 'baz', 'quxxx') + assert_equal('bar', c['default']['foo']) + assert_equal('quxxx', c['default']['baz']) + # add section and key + c.add_value('section', 'foo', 'bar') + assert_equal('bar', c['default']['foo']) + assert_equal('quxxx', c['default']['baz']) + assert_equal('bar', c['section']['foo']) + end + + def test_aset + @it['foo'] = {'bar' => 'baz'} + assert_equal({'bar' => 'baz'}, @it['foo']) + @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'} + assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) + + # OpenSSL::Config is add only for now. + @it['foo'] = {'foo' => 'foo'} + assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) + # you cannot override or remove any section and key. + @it['foo'] = {} + assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) + end + + def test_each + # each returns [section, key, value] array. + ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] } + assert_equal(4, ary.size) + assert_equal('CA_default', ary[0][0]) + assert_equal('CA_default', ary[1][0]) + assert_equal(["ca", "default_ca", "CA_default"], ary[2]) + assert_equal(["default", "HOME", "."], ary[3]) + end + + def test_to_s + c = OpenSSL::Config.parse("[empty]\n") + assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s) + end + + def test_inspect + assert_match(/#/, @it.inspect) + end + + def test_freeze + c = OpenSSL::Config.new + c['foo'] = [['key', 'value']] + c.freeze + + bug = '[ruby-core:18377]' + # RuntimeError for 1.9, TypeError for 1.8 + e = assert_raise(TypeError, bug) do + c['foo'] = [['key', 'wrong']] + end + assert_match(/can't modify/, e.message, bug) + end + + def test_dup + assert(!@it.sections.empty?) + c = @it.dup + assert_equal(@it.sections.sort, c.sections.sort) + @it['newsection'] = {'a' => 'b'} + assert_not_equal(@it.sections.sort, c.sections.sort) + end + + def test_clone + assert(!@it.sections.empty?) + c = @it.clone + assert_equal(@it.sections.sort, c.sections.sort) + @it['newsection'] = {'a' => 'b'} + assert_not_equal(@it.sections.sort, c.sections.sort) + end +end + +end diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb new file mode 100644 index 00000000..e47fc0a3 --- /dev/null +++ b/test/openssl/test_digest.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestDigest < OpenSSL::TestCase + def setup + super + @d1 = OpenSSL::Digest.new("MD5") + @d2 = OpenSSL::Digest::MD5.new + end + + def test_digest + null_hex = "d41d8cd98f00b204e9800998ecf8427e" + null_bin = [null_hex].pack("H*") + data = "DATA" + hex = "e44f9e348e41cb272efa87387728571b" + bin = [hex].pack("H*") + assert_equal(null_bin, @d1.digest) + assert_equal(null_hex, @d1.hexdigest) + @d1 << data + assert_equal(bin, @d1.digest) + assert_equal(hex, @d1.hexdigest) + assert_equal(bin, OpenSSL::Digest::MD5.digest(data)) + assert_equal(hex, OpenSSL::Digest::MD5.hexdigest(data)) + end + + def test_eql + assert(@d1 == @d2, "==") + d = @d1.clone + assert(d == @d1, "clone") + end + + def test_info + assert_equal("MD5", @d1.name, "name") + assert_equal("MD5", @d2.name, "name") + assert_equal(16, @d1.size, "size") + end + + def test_dup + @d1.update("DATA") + assert_equal(@d1.name, @d1.dup.name, "dup") + assert_equal(@d1.name, @d1.clone.name, "clone") + assert_equal(@d1.digest, @d1.clone.digest, "clone .digest") + end + + def test_reset + @d1.update("DATA") + dig1 = @d1.digest + @d1.reset + @d1.update("DATA") + dig2 = @d1.digest + assert_equal(dig1, dig2, "reset") + end + + def test_required_digests + algorithms = OpenSSL::Digest::ALGORITHMS + required = %w{MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512} + + required.each do |name| + assert_include(algorithms, name) + end + end + + def test_digest_constants + algorithms = OpenSSL::Digest::ALGORITHMS + + algorithms.each do |name| + assert_not_nil(OpenSSL::Digest.new(name)) + klass = OpenSSL::Digest.const_get(name.tr('-', '_')) + assert_not_nil(klass.new) + end + end + + def test_digest_by_oid_and_name + check_digest(OpenSSL::ASN1::ObjectId.new("MD5")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA1")) + end + + def encode16(str) + str.unpack("H*").first + end + + def test_sha2 + sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" + sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" + sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" + sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" + + assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) + assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) + assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) + assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) + + assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) + assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) + assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) + assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) + end + + def test_sha3 + pend "SHA3 is not implemented" unless OpenSSL::Digest.const_defined?(:SHA3_224) + s224 = '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7' + s256 = 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a' + s384 = '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004' + s512 = 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26' + assert_equal(OpenSSL::Digest::SHA3_224.hexdigest(""), s224) + assert_equal(OpenSSL::Digest::SHA3_256.hexdigest(""), s256) + assert_equal(OpenSSL::Digest::SHA3_384.hexdigest(""), s384) + assert_equal(OpenSSL::Digest::SHA3_512.hexdigest(""), s512) + end + + def test_digest_by_oid_and_name_sha2 + check_digest(OpenSSL::ASN1::ObjectId.new("SHA224")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA256")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA384")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA512")) + end + + def test_openssl_digest + assert_equal OpenSSL::Digest::MD5, OpenSSL::Digest("MD5") + + assert_raise NameError do + OpenSSL::Digest("no such digest") + end + end + + private + + def check_digest(oid) + d = OpenSSL::Digest.new(oid.sn) + assert_not_nil(d) + d = OpenSSL::Digest.new(oid.ln) + assert_not_nil(d) + d = OpenSSL::Digest.new(oid.oid) + assert_not_nil(d) + end +end + +end diff --git a/test/openssl/test_engine.rb b/test/openssl/test_engine.rb new file mode 100644 index 00000000..232ba866 --- /dev/null +++ b/test/openssl/test_engine.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) && defined?(OpenSSL::Engine) + +class OpenSSL::TestEngine < OpenSSL::TestCase + def test_engines_free # [ruby-dev:44173] + with_openssl <<-'end;' + OpenSSL::Engine.load("openssl") + OpenSSL::Engine.engines + OpenSSL::Engine.engines + end; + end + + def test_openssl_engine_builtin + with_openssl <<-'end;' + orig = OpenSSL::Engine.engines + pend "'openssl' is already loaded" if orig.any? { |e| e.id == "openssl" } + engine = OpenSSL::Engine.load("openssl") + assert_equal(true, engine) + assert_equal(1, OpenSSL::Engine.engines.size - orig.size) + end; + end + + def test_openssl_engine_by_id_string + with_openssl <<-'end;' + orig = OpenSSL::Engine.engines + pend "'openssl' is already loaded" if orig.any? { |e| e.id == "openssl" } + engine = get_engine + assert_not_nil(engine) + assert_equal(1, OpenSSL::Engine.engines.size - orig.size) + end; + end + + def test_openssl_engine_id_name_inspect + with_openssl <<-'end;' + engine = get_engine + assert_equal("openssl", engine.id) + assert_not_nil(engine.name) + assert_not_nil(engine.inspect) + end; + end + + def test_openssl_engine_digest_sha1 + with_openssl <<-'end;' + engine = get_engine + digest = engine.digest("SHA1") + assert_not_nil(digest) + data = "test" + assert_equal(OpenSSL::Digest::SHA1.digest(data), digest.digest(data)) + end; + end + + def test_openssl_engine_cipher_rc4 + begin + OpenSSL::Cipher.new("rc4") + rescue OpenSSL::Cipher::CipherError + pend "RC4 is not supported" + end + + with_openssl(<<-'end;', ignore_stderr: true) + engine = get_engine + algo = "RC4" + data = "a" * 1000 + key = OpenSSL::Random.random_bytes(16) + encrypted = crypt_data(data, key, :encrypt) { engine.cipher(algo) } + decrypted = crypt_data(encrypted, key, :decrypt) { OpenSSL::Cipher.new(algo) } + assert_equal(data, decrypted) + end; + end + + private + + # this is required because OpenSSL::Engine methods change global state + def with_openssl(code, **opts) + assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;", **opts) + require #{__FILE__.dump} + include OpenSSL::TestEngine::Utils + #{code} + end; + end + + module Utils + def get_engine + OpenSSL::Engine.by_id("openssl") + end + + def crypt_data(data, key, mode) + cipher = yield + cipher.send mode + cipher.key = key + cipher.update(data) + cipher.final + end + end +end + +end diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb new file mode 100644 index 00000000..8cd474f9 --- /dev/null +++ b/test/openssl/test_fips.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestFIPS < OpenSSL::TestCase + def test_fips_mode_is_reentrant + OpenSSL.fips_mode = false + OpenSSL.fips_mode = false + end + + def test_fips_mode_get + return unless OpenSSL::OPENSSL_FIPS + assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;") + require #{__FILE__.dump} + + begin + OpenSSL.fips_mode = true + assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true" + + OpenSSL.fips_mode = false + assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false" + rescue OpenSSL::OpenSSLError + pend "Could not set FIPS mode (OpenSSL::OpenSSLError: \#$!); skipping" + end + end; + end +end + +end diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb new file mode 100644 index 00000000..9cb3c5a8 --- /dev/null +++ b/test/openssl/test_hmac.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestHMAC < OpenSSL::TestCase + def test_hmac + # RFC 2202 2. Test Cases for HMAC-MD5 + hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "MD5") + hmac.update("Hi There") + assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), hmac.digest + assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hmac.hexdigest + + # RFC 4231 4.2. Test Case 1 + hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "SHA224") + hmac.update("Hi There") + assert_equal ["896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"].pack("H*"), hmac.digest + assert_equal "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", hmac.hexdigest + end + + def test_dup + h1 = OpenSSL::HMAC.new("KEY", "MD5") + h1.update("DATA") + h = h1.dup + assert_equal(h1.digest, h.digest, "dup digest") + end + + def test_binary_update + data = "Lücíllé: Bût... yøü sáîd hé wås âlrîght.\nDr. Físhmån: Yés. Hé's løst hîs léft hånd, sø hé's gøîng tø bé åll rîght" + hmac = OpenSSL::HMAC.new("qShkcwN92rsM9nHfdnP4ugcVU2iI7iM/trovs01ZWok", "SHA256") + result = hmac.update(data).hexdigest + assert_equal "a13984b929a07912e4e21c5720876a8e150d6f67f854437206e7f86547248396", result + end + + def test_reset_keep_key + h1 = OpenSSL::HMAC.new("KEY", "MD5") + first = h1.update("test").hexdigest + h1.reset + second = h1.update("test").hexdigest + assert_equal first, second + end + + def test_eq + h1 = OpenSSL::HMAC.new("KEY", "MD5") + h2 = OpenSSL::HMAC.new("KEY", OpenSSL::Digest.new("MD5")) + h3 = OpenSSL::HMAC.new("FOO", "MD5") + + assert_equal h1, h2 + refute_equal h1, h2.digest + refute_equal h1, h3 + end +end + +end diff --git a/test/openssl/test_kdf.rb b/test/openssl/test_kdf.rb new file mode 100644 index 00000000..f4790c96 --- /dev/null +++ b/test/openssl/test_kdf.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestKDF < OpenSSL::TestCase + def test_pkcs5_pbkdf2_hmac_compatibility + expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt", iterations: 1, length: 20, hash: "sha1") + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt", 1, 20, "sha1")) + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", 1, 20)) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 + p ="password" + s = "salt" + c = 1 + dk_len = 20 + raw = %w{ 0c 60 c8 0f 96 1f 0e 71 + f3 a9 b5 24 af 60 12 06 + 2f e0 37 a6 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 + p ="password" + s = "salt" + c = 2 + dk_len = 20 + raw = %w{ ea 6c 01 4d c7 2d 6f 8c + cd 1e d9 2a ce 1d 41 f0 + d8 de 89 57 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 + p ="password" + s = "salt" + c = 4096 + dk_len = 20 + raw = %w{ 4b 00 79 01 b7 65 48 9a + be ad 49 d9 26 f7 21 d0 + 65 a4 29 c1 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + +# takes too long! +# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20 +# p ="password" +# s = "salt" +# c = 16777216 +# dk_len = 20 +# raw = %w{ ee fe 3d 61 cd 4d a4 e4 +# e9 94 5b 3d 6b a2 15 8c +# 26 34 e9 84 } +# expected = [raw.join('')].pack('H*') +# value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") +# assert_equal(expected, value) +# end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 + p ="passwordPASSWORDpassword" + s = "saltSALTsaltSALTsaltSALTsaltSALTsalt" + c = 4096 + dk_len = 25 + + raw = %w{ 3d 2e ec 4f e4 1c 84 9b + 80 c8 d8 36 62 c0 e4 4a + 8b 29 1a 96 4c f2 f0 70 + 38 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 + p ="pass\0word" + s = "sa\0lt" + c = 4096 + dk_len = 16 + raw = %w{ 56 fa 6a a7 55 48 09 9d + cc 37 d7 f0 34 25 e0 c3 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha256_c_20000_len_32 + #unfortunately no official test vectors available yet for SHA-2 + p ="password" + s = OpenSSL::Random.random_bytes(16) + c = 20000 + dk_len = 32 + value1 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") + value2 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") + assert_equal(value1, value2) + end + + def test_scrypt_rfc7914_first + pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + pass = "" + salt = "" + n = 16 + r = 1 + p = 1 + dklen = 64 + expected = B(%w{ 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 + f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 + fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 + e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 }) + assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) + end + + def test_scrypt_rfc7914_second + pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + pass = "password" + salt = "NaCl" + n = 1024 + r = 8 + p = 16 + dklen = 64 + expected = B(%w{ fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe + 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 + 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da + c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 }) + assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) + end + + def test_hkdf_rfc5869_test_case_1 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha256" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + salt = B("000102030405060708090a0b0c") + info = B("f0f1f2f3f4f5f6f7f8f9") + l = 42 + + okm = B("3cb25f25faacd57a90434f64d0362f2a" \ + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" \ + "34007208d5b887185865") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + def test_hkdf_rfc5869_test_case_3 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha256" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + salt = B("") + info = B("") + l = 42 + + okm = B("8da4e775a563c18f715f802a063c5a31" \ + "b8a11f5c5ee1879ec3454e5f3c738d2d" \ + "9d201395faa4b61a96c8") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + def test_hkdf_rfc5869_test_case_4 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha1" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b") + salt = B("000102030405060708090a0b0c") + info = B("f0f1f2f3f4f5f6f7f8f9") + l = 42 + + okm = B("085a01ea1b10f36933068b56efa5ad81" \ + "a4f14b822f5b091568a9cdd4f155fda2" \ + "c22e422478d305f3f896") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + private + + def B(ary) + [Array(ary).join].pack("H*") + end +end + +end diff --git a/test/openssl/test_ns_spki.rb b/test/openssl/test_ns_spki.rb new file mode 100644 index 00000000..052507de --- /dev/null +++ b/test/openssl/test_ns_spki.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestNSSPI < OpenSSL::TestCase + def setup + super + # This request data is adopt from the specification of + # "Netscape Extensions for User Key Generation". + # -- http://wp.netscape.com/eng/security/comm4-keygen.html + @b64 = +"MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV" + @b64 << "WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID" + @b64 << "AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S" + @b64 << "r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW" + @b64 << "i0//rgBvmco=" + end + + def test_build_data + key1 = Fixtures.pkey("rsa1024") + key2 = Fixtures.pkey("rsa2048") + spki = OpenSSL::Netscape::SPKI.new + spki.challenge = "RandomString" + spki.public_key = key1.public_key + spki.sign(key1, OpenSSL::Digest::SHA1.new) + assert(spki.verify(spki.public_key)) + assert(spki.verify(key1.public_key)) + assert(!spki.verify(key2.public_key)) + + der = spki.to_der + spki = OpenSSL::Netscape::SPKI.new(der) + assert_equal("RandomString", spki.challenge) + assert_equal(key1.public_key.to_der, spki.public_key.to_der) + assert(spki.verify(spki.public_key)) + assert_not_nil(spki.to_text) + end + + def test_decode_data + spki = OpenSSL::Netscape::SPKI.new(@b64) + assert_equal(@b64, spki.to_pem) + assert_equal(@b64.unpack("m").first, spki.to_der) + assert_equal("MozillaIsMyFriend", spki.challenge) + assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) + + spki = OpenSSL::Netscape::SPKI.new(@b64.unpack("m").first) + assert_equal(@b64, spki.to_pem) + assert_equal(@b64.unpack("m").first, spki.to_der) + assert_equal("MozillaIsMyFriend", spki.challenge) + assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) + end +end + +end diff --git a/test/openssl/test_ocsp.rb b/test/openssl/test_ocsp.rb new file mode 100644 index 00000000..a490a153 --- /dev/null +++ b/test/openssl/test_ocsp.rb @@ -0,0 +1,311 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestOCSP < OpenSSL::TestCase + def setup + super + # @ca_cert + # | + # @cert + # |----------| + # @cert2 @ocsp_cert + + ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") + @ca_key = Fixtures.pkey("rsa1024") + ca_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["keyUsage", "cRLSign,keyCertSign", true], + ] + @ca_cert = OpenSSL::TestUtils.issue_cert( + ca_subj, @ca_key, 1, ca_exts, nil, nil) + + cert_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA2") + @cert_key = Fixtures.pkey("rsa1024") + cert_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["keyUsage", "cRLSign,keyCertSign", true], + ] + @cert = OpenSSL::TestUtils.issue_cert( + cert_subj, @cert_key, 5, cert_exts, @ca_cert, @ca_key) + + cert2_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert") + @cert2_key = Fixtures.pkey("rsa1024") + cert2_exts = [ + ] + @cert2 = OpenSSL::TestUtils.issue_cert( + cert2_subj, @cert2_key, 10, cert2_exts, @cert, @cert_key) + + ocsp_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCAOCSP") + @ocsp_key = Fixtures.pkey("rsa2048") + ocsp_exts = [ + ["extendedKeyUsage", "OCSPSigning", true], + ] + @ocsp_cert = OpenSSL::TestUtils.issue_cert( + ocsp_subj, @ocsp_key, 100, ocsp_exts, @cert, @cert_key) + end + + def test_new_certificate_id + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + assert_kind_of OpenSSL::OCSP::CertificateId, cid + assert_equal @cert.serial, cid.serial + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new) + assert_kind_of OpenSSL::OCSP::CertificateId, cid + assert_equal @cert.serial, cid.serial + end + + def test_certificate_id_issuer_name_hash + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + assert_equal OpenSSL::Digest::SHA1.hexdigest(@cert.issuer.to_der), cid.issuer_name_hash + assert_equal "d91f736ac4dc3242f0fb9b77a3149bd83c5c43d0", cid.issuer_name_hash + end + + def test_certificate_id_issuer_key_hash + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + assert_equal OpenSSL::Digest::SHA1.hexdigest(OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), cid.issuer_key_hash + assert_equal "d1fef9fbf8ae1bc160cbfa03e2596dd873089213", cid.issuer_key_hash + end + + def test_certificate_id_hash_algorithm + cid_sha1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + cid_sha256 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new) + assert_equal "sha1", cid_sha1.hash_algorithm + assert_equal "sha256", cid_sha256.hash_algorithm + end + + def test_certificate_id_der + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + der = cid.to_der + asn1 = OpenSSL::ASN1.decode(der) + # hash algorithm defaults to SHA-1 + assert_equal OpenSSL::ASN1.ObjectId("SHA1").to_der, asn1.value[0].value[0].to_der + assert_equal [cid.issuer_name_hash].pack("H*"), asn1.value[1].value + assert_equal [cid.issuer_key_hash].pack("H*"), asn1.value[2].value + assert_equal @cert.serial, asn1.value[3].value + assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der + assert_equal der, OpenSSL::OCSP::CertificateId.new(asn1).to_der + end + + def test_certificate_id_dup + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + assert_equal cid.to_der, cid.dup.to_der + end + + def test_request_der + request = OpenSSL::OCSP::Request.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + request.add_certid(cid) + request.sign(@cert, @cert_key, [@ca_cert], 0) + asn1 = OpenSSL::ASN1.decode(request.to_der) + assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der + assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der + assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der + assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der + assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der + end + + def test_request_sign_verify + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + store = OpenSSL::X509::Store.new.add_cert(@ca_cert) + + # with signer cert + req = OpenSSL::OCSP::Request.new.add_certid(cid) + req.sign(@cert, @cert_key, []) + assert_equal true, req.verify([], store) + + # without signer cert + req = OpenSSL::OCSP::Request.new.add_certid(cid) + req.sign(@cert, @cert_key, nil) + assert_equal false, req.verify([@cert2], store) + assert_equal false, req.verify([], store) # no signer + assert_equal false, req.verify([], store, OpenSSL::OCSP::NOVERIFY) + + assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) + ret = req.verify([@cert], store) + if ret || openssl?(1, 0, 2) + assert_equal true, ret + else + # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when + # OCSP_NOINTERN is not specified. + # fixed by OpenSSL 1.0.1j, 1.0.2 + pend "RT2560: ocsp_req_find_signer" + end + + # not signed + req = OpenSSL::OCSP::Request.new.add_certid(cid) + assert_equal false, req.verify([], store) + end + + def test_request_is_signed + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + req = OpenSSL::OCSP::Request.new + req.add_certid(cid) + assert_equal false, req.signed? + assert_equal false, OpenSSL::OCSP::Request.new(req.to_der).signed? + req.sign(@cert, @cert_key, []) + assert_equal true, req.signed? + assert_equal true, OpenSSL::OCSP::Request.new(req.to_der).signed? + end + + def test_request_nonce + req0 = OpenSSL::OCSP::Request.new + req1 = OpenSSL::OCSP::Request.new.add_nonce("NONCE") + req2 = OpenSSL::OCSP::Request.new.add_nonce("ABCDE") + bres = OpenSSL::OCSP::BasicResponse.new + assert_equal 2, req0.check_nonce(bres) + bres.copy_nonce(req1) + assert_equal 3, req0.check_nonce(bres) + assert_equal 1, req1.check_nonce(bres) + bres.add_nonce("NONCE") + assert_equal 1, req1.check_nonce(bres) + assert_equal 0, req2.check_nonce(bres) + end + + def test_request_dup + request = OpenSSL::OCSP::Request.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + request.add_certid(cid) + assert_equal request.to_der, request.dup.to_der + end + + def test_basic_response_der + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) + bres.add_nonce("NONCE") + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) + der = bres.to_der + asn1 = OpenSSL::ASN1.decode(der) + assert_equal OpenSSL::ASN1.Sequence([@ocsp_cert, @ca_cert]).to_der, asn1.value[3].value[0].to_der + assert_equal der, OpenSSL::OCSP::BasicResponse.new(der).to_der + rescue TypeError + if /GENERALIZEDTIME/ =~ $!.message + pend "OCSP_basic_sign() is broken" + else + raise + end + end + + def test_basic_response_sign_verify + store = OpenSSL::X509::Store.new.add_cert(@ca_cert) + + # signed by CA + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, "SHA256") + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, []) + bres.sign(@ca_cert, @ca_key, nil, 0, "SHA256") + assert_equal false, bres.verify([], store) # signer not found + assert_equal true, bres.verify([@ca_cert], store) + bres.sign(@ca_cert, @ca_key, [], 0, "SHA256") + assert_equal true, bres.verify([], store) + + # signed by OCSP signer + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert2, @cert) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, []) + bres.sign(@ocsp_cert, @ocsp_key, [@cert]) + assert_equal true, bres.verify([], store) + assert_equal false, bres.verify([], store, OpenSSL::OCSP::NOCHAIN) + # OpenSSL had a bug on this; test that our workaround works + bres.sign(@ocsp_cert, @ocsp_key, []) + assert_equal true, bres.verify([@cert], store) + end + + def test_basic_response_dup + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) + assert_equal bres.to_der, bres.dup.to_der + end + + def test_basic_response_response_operations + bres = OpenSSL::OCSP::BasicResponse.new + now = Time.at(Time.now.to_i) + cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest::SHA1.new) + cid3 = OpenSSL::OCSP::CertificateId.new(@ca_cert, @ca_cert, OpenSSL::Digest::SHA1.new) + bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil) + bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, []) + + assert_equal 2, bres.responses.size + single = bres.responses.first + assert_equal cid1.to_der, single.certid.to_der + assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, single.cert_status + assert_equal OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, single.revocation_reason + assert_equal now - 400, single.revocation_time + assert_in_delta (now - 301), single.this_update, 1 + assert_equal nil, single.next_update + assert_equal [], single.extensions + + assert_equal cid2.to_der, bres.find_response(cid2).certid.to_der + assert_equal nil, bres.find_response(cid3) + end + + def test_single_response_der + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, nil) + single = bres.responses[0] + der = single.to_der + asn1 = OpenSSL::ASN1.decode(der) + assert_equal :CONTEXT_SPECIFIC, asn1.value[1].tag_class + assert_equal 0, asn1.value[1].tag # good + assert_equal der, OpenSSL::OCSP::SingleResponse.new(der).to_der + end + + def test_single_response_check_validity + bres = OpenSSL::OCSP::BasicResponse.new + cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest::SHA1.new) + bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, -50, []) + bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, []) + bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil) + + single1 = bres.responses[0] + assert_equal false, single1.check_validity + assert_equal false, single1.check_validity(30) + assert_equal true, single1.check_validity(60) + single2 = bres.responses[1] + assert_equal true, single2.check_validity + assert_equal true, single2.check_validity(0, 500) + assert_equal false, single2.check_validity(0, 200) + single3 = bres.responses[2] + assert_equal false, single3.check_validity + end + + def test_response + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) + bres.sign(@ocsp_cert, @ocsp_key, []) + res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) + + assert_equal bres.to_der, res.basic.to_der + assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, res.status + end + + def test_response_der + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) + res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) + der = res.to_der + asn1 = OpenSSL::ASN1.decode(der) + assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, asn1.value[0].value + assert_equal OpenSSL::ASN1.ObjectId("basicOCSPResponse").to_der, asn1.value[1].value[0].value[0].to_der + assert_equal bres.to_der, asn1.value[1].value[0].value[1].value + assert_equal der, OpenSSL::OCSP::Response.new(der).to_der + end + + def test_response_dup + bres = OpenSSL::OCSP::BasicResponse.new + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) + res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) + assert_equal res.to_der, res.dup.to_der + end +end + +end diff --git a/test/openssl/test_ossl.rb b/test/openssl/test_ossl.rb new file mode 100644 index 00000000..f83e8136 --- /dev/null +++ b/test/openssl/test_ossl.rb @@ -0,0 +1,65 @@ +# 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 diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb new file mode 100644 index 00000000..e9cf98df --- /dev/null +++ b/test/openssl/test_pair.rb @@ -0,0 +1,523 @@ +# frozen_string_literal: true +require_relative 'utils' +require_relative 'ut_eof' + +if defined?(OpenSSL) + +module OpenSSL::SSLPairM + def setup + svr_dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + ee_exts = [ + ["keyUsage", "keyEncipherment,digitalSignature", true], + ] + @svr_key = OpenSSL::TestUtils::Fixtures.pkey("rsa-1") + @svr_cert = issue_cert(svr_dn, @svr_key, 1, ee_exts, nil, nil) + end + + def ssl_pair + host = "127.0.0.1" + tcps = create_tcp_server(host, 0) + port = tcps.connect_address.ip_port + + th = Thread.new { + sctx = OpenSSL::SSL::SSLContext.new + sctx.cert = @svr_cert + sctx.key = @svr_key + sctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } + sctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION + ssls = OpenSSL::SSL::SSLServer.new(tcps, sctx) + ns = ssls.accept + ssls.close + ns + } + + tcpc = create_tcp_client(host, port) + c = OpenSSL::SSL::SSLSocket.new(tcpc) + c.connect + s = th.value + + yield c, s + ensure + tcpc&.close + tcps&.close + s&.close + end +end + +module OpenSSL::SSLPair + include OpenSSL::SSLPairM + + def create_tcp_server(host, port) + TCPServer.new(host, port) + end + + def create_tcp_client(host, port) + TCPSocket.new(host, port) + end +end + +module OpenSSL::SSLPairLowlevelSocket + include OpenSSL::SSLPairM + + def create_tcp_server(host, port) + Addrinfo.tcp(host, port).listen + end + + def create_tcp_client(host, port) + Addrinfo.tcp(host, port).connect + end +end + +module OpenSSL::TestEOF1M + def open_file(content) + ssl_pair { |s1, s2| + begin + th = Thread.new { s2 << content; s2.close } + yield s1 + ensure + th&.join + end + } + end +end + +module OpenSSL::TestEOF2M + def open_file(content) + ssl_pair { |s1, s2| + begin + th = Thread.new { s1 << content; s1.close } + yield s2 + ensure + th&.join + end + } + end +end + +module OpenSSL::TestPairM + def test_getc + ssl_pair {|s1, s2| + s1 << "a" + assert_equal(?a, s2.getc) + } + end + + def test_gets + ssl_pair {|s1, s2| + s1 << "abc\n\n$def123ghi" + s1.close + ret = s2.gets + assert_equal Encoding::BINARY, ret.encoding + assert_equal "abc\n", ret + assert_equal "\n$", s2.gets("$") + assert_equal "def123", s2.gets(/\d+/) + assert_equal "ghi", s2.gets + assert_equal nil, s2.gets + } + end + + def test_gets_eof_limit + ssl_pair {|s1, s2| + s1.write("hello") + s1.close # trigger EOF + assert_match "hello", s2.gets("\n", 6), "[ruby-core:70149] [Bug #11400]" + } + end + + def test_readpartial + ssl_pair {|s1, s2| + s2.write "a\nbcd" + assert_equal("a\n", s1.gets) + result = String.new + result << s1.readpartial(10) until result.length == 3 + assert_equal("bcd", result) + s2.write "efg" + result = String.new + result << s1.readpartial(10) until result.length == 3 + assert_equal("efg", result) + s2.close + assert_raise(EOFError) { s1.readpartial(10) } + assert_raise(EOFError) { s1.readpartial(10) } + assert_equal("", s1.readpartial(0)) + } + end + + def test_readall + ssl_pair {|s1, s2| + s2.close + assert_equal("", s1.read) + } + end + + def test_readline + ssl_pair {|s1, s2| + s2.close + assert_raise(EOFError) { s1.readline } + } + end + + def test_puts_meta + ssl_pair {|s1, s2| + begin + old = $/ + $/ = '*' + s1.puts 'a' + ensure + $/ = old + end + s1.close + assert_equal("a\n", s2.read) + } + end + + def test_puts_empty + ssl_pair {|s1, s2| + s1.puts + s1.close + assert_equal("\n", s2.read) + } + end + + def test_multibyte_read_write + # German a umlaut + auml = [%w{ C3 A4 }.join('')].pack('H*') + auml.force_encoding(Encoding::UTF_8) + bsize = auml.bytesize + + ssl_pair { |s1, s2| + assert_equal bsize, s1.write(auml) + read = s2.read(bsize) + assert_equal Encoding::ASCII_8BIT, read.encoding + assert_equal bsize, read.bytesize + assert_equal auml, read.force_encoding(Encoding::UTF_8) + + s1.puts(auml) + read = s2.gets + assert_equal Encoding::ASCII_8BIT, read.encoding + assert_equal bsize + 1, read.bytesize + assert_equal auml + "\n", read.force_encoding(Encoding::UTF_8) + } + end + + def test_read_nonblock + ssl_pair {|s1, s2| + err = nil + assert_raise(OpenSSL::SSL::SSLErrorWaitReadable) { + begin + s2.read_nonblock(10) + ensure + err = $! + end + } + assert_kind_of(IO::WaitReadable, err) + s1.write "abc\ndef\n" + IO.select([s2]) + assert_equal("ab", s2.read_nonblock(2)) + assert_equal("c\n", s2.gets) + ret = nil + assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10) } + assert_equal("def\n", ret) + s1.close + IO.select([s2]) + assert_raise(EOFError) { s2.read_nonblock(10) } + } + end + + def test_read_nonblock_no_exception + ssl_pair {|s1, s2| + assert_equal :wait_readable, s2.read_nonblock(10, exception: false) + s1.write "abc\ndef\n" + IO.select([s2]) + assert_equal("ab", s2.read_nonblock(2, exception: false)) + assert_equal("c\n", s2.gets) + ret = nil + assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10, exception: false) } + assert_equal("def\n", ret) + s1.close + IO.select([s2]) + assert_equal(nil, s2.read_nonblock(10, exception: false)) + } + end + + def test_read_with_outbuf + ssl_pair { |s1, s2| + s1.write("abc\n") + buf = String.new + ret = s2.read(2, buf) + assert_same ret, buf + assert_equal "ab", ret + + buf = +"garbage" + ret = s2.read(2, buf) + assert_same ret, buf + assert_equal "c\n", ret + + buf = +"garbage" + assert_equal :wait_readable, s2.read_nonblock(100, buf, exception: false) + assert_equal "", buf + + s1.close + buf = +"garbage" + assert_equal nil, s2.read(100, buf) + assert_equal "", buf + } + end + + def test_write_nonblock + ssl_pair {|s1, s2| + assert_equal 3, s1.write_nonblock("foo") + assert_equal "foo", s2.read(3) + + data = "x" * 16384 + written = 0 + while true + begin + written += s1.write_nonblock(data) + rescue IO::WaitWritable, IO::WaitReadable + break + end + end + assert written > 0 + assert_equal written, s2.read(written).bytesize + } + end + + def test_write_nonblock_no_exceptions + ssl_pair {|s1, s2| + assert_equal 3, s1.write_nonblock("foo", exception: false) + assert_equal "foo", s2.read(3) + + data = "x" * 16384 + written = 0 + while true + case ret = s1.write_nonblock(data, exception: false) + when :wait_readable, :wait_writable + break + else + written += ret + end + end + assert written > 0 + assert_equal written, s2.read(written).bytesize + } + end + + def test_write_nonblock_with_buffered_data + ssl_pair {|s1, s2| + s1.write "foo" + s1.write_nonblock("bar") + s1.write "baz" + s1.close + assert_equal("foobarbaz", s2.read) + } + end + + def test_write_nonblock_with_buffered_data_no_exceptions + ssl_pair {|s1, s2| + s1.write "foo" + s1.write_nonblock("bar", exception: false) + s1.write "baz" + s1.close + assert_equal("foobarbaz", s2.read) + } + end + + def test_write_nonblock_retry + ssl_pair {|s1, s2| + # fill up a socket so we hit EAGAIN + written = String.new + n = 0 + buf = 'a' * 4099 + case ret = s1.write_nonblock(buf, exception: false) + when :wait_readable then break + when :wait_writable then break + when Integer + written << buf + n += ret + exp = buf.bytesize + if ret != exp + buf = buf.byteslice(ret, exp - ret) + end + end while true + assert_kind_of Symbol, ret + + # make more space for subsequent write: + readed = s2.read(n) + assert_equal written, readed + + # this fails if SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is missing: + buf2 = Marshal.load(Marshal.dump(buf)) + assert_kind_of Integer, s1.write_nonblock(buf2, exception: false) + } + end + + def test_write_zero + ssl_pair {|s1, s2| + assert_equal 0, s2.write_nonblock('', exception: false) + assert_kind_of Symbol, s1.read_nonblock(1, exception: false) + assert_equal 0, s2.syswrite('') + assert_kind_of Symbol, s1.read_nonblock(1, exception: false) + assert_equal 0, s2.write('') + assert_kind_of Symbol, s1.read_nonblock(1, exception: false) + } + end + + def test_write_multiple_arguments + ssl_pair {|s1, s2| + str1 = "foo"; str2 = "bar" + assert_equal 6, s1.write(str1, str2) + s1.close + assert_equal "foobar", s2.read + } + end + + def test_partial_tls_record_read_nonblock + ssl_pair { |s1, s2| + # the beginning of a TLS record + s1.io.write("\x17") + # should raise a IO::WaitReadable since a full TLS record is not available + # for reading + assert_raise(IO::WaitReadable) { s2.read_nonblock(1) } + } + end + + def tcp_pair + host = "127.0.0.1" + serv = TCPServer.new(host, 0) + port = serv.connect_address.ip_port + sock1 = TCPSocket.new(host, port) + sock2 = serv.accept + serv.close + [sock1, sock2] + ensure + serv.close if serv && !serv.closed? + end + + def test_connect_accept_nonblock_no_exception + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.cert = @svr_cert + ctx2.key = @svr_key + ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } + + sock1, sock2 = tcp_pair + + s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) + accepted = s2.accept_nonblock(exception: false) + assert_equal :wait_readable, accepted + + ctx1 = OpenSSL::SSL::SSLContext.new + s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) + th = Thread.new do + rets = [] + begin + rv = s1.connect_nonblock(exception: false) + rets << rv + case rv + when :wait_writable + IO.select(nil, [s1], nil, 5) + when :wait_readable + IO.select([s1], nil, nil, 5) + end + end until rv == s1 + rets + end + + until th.join(0.01) + accepted = s2.accept_nonblock(exception: false) + assert_include([s2, :wait_readable, :wait_writable ], accepted) + end + + rets = th.value + assert_instance_of Array, rets + rets.each do |rv| + assert_include([s1, :wait_readable, :wait_writable ], rv) + end + ensure + th.join if th + s1.close if s1 + s2.close if s2 + sock1.close if sock1 + sock2.close if sock2 + accepted.close if accepted.respond_to?(:close) + end + + def test_connect_accept_nonblock + ctx = OpenSSL::SSL::SSLContext.new + ctx.cert = @svr_cert + ctx.key = @svr_key + ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } + + sock1, sock2 = tcp_pair + + th = Thread.new { + s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx) + 5.times { + begin + break s2.accept_nonblock + rescue IO::WaitReadable + IO.select([s2], nil, nil, 1) + rescue IO::WaitWritable + IO.select(nil, [s2], nil, 1) + end + sleep 0.2 + } + } + + s1 = OpenSSL::SSL::SSLSocket.new(sock1) + 5.times { + begin + break s1.connect_nonblock + rescue IO::WaitReadable + IO.select([s1], nil, nil, 1) + rescue IO::WaitWritable + IO.select(nil, [s1], nil, 1) + end + sleep 0.2 + } + + s2 = th.value + + s1.print "a\ndef" + assert_equal("a\n", s2.gets) + ensure + sock1&.close + sock2&.close + th&.join + end +end + +class OpenSSL::TestEOF1 < OpenSSL::TestCase + include OpenSSL::TestEOF + include OpenSSL::SSLPair + include OpenSSL::TestEOF1M +end + +class OpenSSL::TestEOF1LowlevelSocket < OpenSSL::TestCase + include OpenSSL::TestEOF + include OpenSSL::SSLPairLowlevelSocket + include OpenSSL::TestEOF1M +end + +class OpenSSL::TestEOF2 < OpenSSL::TestCase + include OpenSSL::TestEOF + include OpenSSL::SSLPair + include OpenSSL::TestEOF2M +end + +class OpenSSL::TestEOF2LowlevelSocket < OpenSSL::TestCase + include OpenSSL::TestEOF + include OpenSSL::SSLPairLowlevelSocket + include OpenSSL::TestEOF2M +end + +class OpenSSL::TestPair < OpenSSL::TestCase + include OpenSSL::SSLPair + include OpenSSL::TestPairM +end + +class OpenSSL::TestPairLowlevelSocket < OpenSSL::TestCase + include OpenSSL::SSLPairLowlevelSocket + include OpenSSL::TestPairM +end + +end diff --git a/test/openssl/test_pkcs12.rb b/test/openssl/test_pkcs12.rb new file mode 100644 index 00000000..fdbe753b --- /dev/null +++ b/test/openssl/test_pkcs12.rb @@ -0,0 +1,313 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +module OpenSSL + class TestPKCS12 < OpenSSL::TestCase + def setup + super + ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + @cacert = issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) + + inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA") + inter_ca_key = OpenSSL::PKey.read <<-_EOS_ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDp7hIG0SFMG/VWv1dBUWziAPrNmkMXJgTCAoB7jffzRtyyN04K +oq/89HAszTMStZoMigQURfokzKsjpUp8OYCAEsBtt9d5zPndWMz/gHN73GrXk3LT +ZsxEn7Xv5Da+Y9F/Hx2QZUHarV5cdZixq2NbzWGwrToogOQMh2pxN3Z/0wIDAQAB +AoGBAJysUyx3olpsGzv3OMRJeahASbmsSKTXVLZvoIefxOINosBFpCIhZccAG6UV +5c/xCvS89xBw8aD15uUfziw3AuT8QPEtHCgfSjeT7aWzBfYswEgOW4XPuWr7EeI9 +iNHGD6z+hCN/IQr7FiEBgTp6A+i/hffcSdR83fHWKyb4M7TRAkEA+y4BNd668HmC +G5MPRx25n6LixuBxrNp1umfjEI6UZgEFVpYOg4agNuimN6NqM253kcTR94QNTUs5 +Kj3EhG1YWwJBAO5rUjiOyCNVX2WUQrOMYK/c1lU7fvrkdygXkvIGkhsPoNRzLPeA +HGJszKtrKD8bNihWpWNIyqKRHfKVD7yXT+kCQGCAhVCIGTRoypcDghwljHqLnysf +ci0h5ZdPcIqc7ODfxYhFsJ/Rql5ONgYsT5Ig/+lOQAkjf+TRYM4c2xKx2/8CQBvG +jv6dy70qDgIUgqzONtlmHeYyFzn9cdBO5sShdVYHvRHjFSMEXsosqK9zvW2UqvuK +FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3 +Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= +-----END RSA PRIVATE KEY----- + _EOS_ + @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, Fixtures.pkey("rsa2048")) + + exts = [ + ["keyUsage","digitalSignature",true], + ["subjectKeyIdentifier","hash",false], + ] + ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate") + @mykey = Fixtures.pkey("rsa1024") + @mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key) + end + + def test_create + pkcs12 = OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, + @mycert + ) + assert_equal @mycert.to_der, pkcs12.certificate.to_der + assert_equal @mykey.to_der, pkcs12.key.to_der + assert_nil pkcs12.ca_certs + end + + def test_create_no_pass + pkcs12 = OpenSSL::PKCS12.create( + nil, + "hello", + @mykey, + @mycert + ) + assert_equal @mycert.to_der, pkcs12.certificate.to_der + assert_equal @mykey.to_der, pkcs12.key.to_der + assert_nil pkcs12.ca_certs + + decoded = OpenSSL::PKCS12.new(pkcs12.to_der) + assert_cert @mycert, decoded.certificate + end + + def test_create_with_chain + chain = [@inter_cacert, @cacert] + + pkcs12 = OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, + @mycert, + chain + ) + assert_equal chain, pkcs12.ca_certs + end + + def test_create_with_chain_decode + chain = [@cacert, @inter_cacert] + + passwd = "omg" + + pkcs12 = OpenSSL::PKCS12.create( + passwd, + "hello", + @mykey, + @mycert, + chain + ) + + decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd) + assert_equal chain.size, decoded.ca_certs.size + assert_include_cert @cacert, decoded.ca_certs + assert_include_cert @inter_cacert, decoded.ca_certs + assert_cert @mycert, decoded.certificate + assert_equal @mykey.to_der, decoded.key.to_der + end + + def test_create_with_bad_nid + assert_raise(ArgumentError) do + OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, + @mycert, + [], + "foo" + ) + end + end + + def test_create_with_itr + OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, + @mycert, + [], + nil, + nil, + 2048 + ) + + assert_raise(TypeError) do + OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, + @mycert, + [], + nil, + nil, + "omg" + ) + end + end + + def test_create_with_mac_itr + OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, + @mycert, + [], + nil, + nil, + nil, + 2048 + ) + + assert_raise(TypeError) do + OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, + @mycert, + [], + nil, + nil, + nil, + "omg" + ) + end + end + + def test_new_with_one_key_and_one_cert + # generated with: + # openssl version #=> OpenSSL 1.0.2h 3 May 2016 + # openssl pkcs12 -in <@mycert> -inkey -export -out + str = <<~EOF.unpack("m").first +MIIGQQIBAzCCBgcGCSqGSIb3DQEHAaCCBfgEggX0MIIF8DCCAu8GCSqGSIb3DQEH +BqCCAuAwggLcAgEAMIIC1QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIeZPM +Rh6KiXgCAggAgIICqL6O+LCZmBzdIg6mozPF3FpY0hVbWHvTNMiDHieW3CrAanhN +YCH2/wHqH8WpFpEWwF0qEEXAWjHsIlYB4Cfqo6b7XpuZe5eVESsjNTOTMF1JCUJj +A6iNefXmCFLync1JK5LUodRDhTlKLU1WPK20X9X4vuEwHn8wt5RUb8P0E+Xh6rpS +XC4LkZKT45zF3cJa/n5+dW65ohVGNVnF9D1bCNEKHMOllK1V9omutQ9slW88hpga +LGiFsJoFOb/ESGb78KO+bd6zbX1MdKdBV+WD6t1uF/cgU65y+2A4nXs1urda+MJ7 +7iVqiB7Vnc9cANTbAkTSGNyoUDVM/NZde782/8IvddLAzUZ2EftoRDke6PvuBOVL +ljBhNWmdamrtBqzuzVZCRdWq44KZkF2Xoc9asepwIkdVmntzQF7f1Z+Ta5yg6HFp +xnr7CuM+MlHEShXkMgYtHnwAq10fDMSXIvjhi/AA5XUAusDO3D+hbtcRDcJ4uUes +dm5dhQE2qJ02Ysn4aH3o1F3RYNOzrxejHJwl0D2TCE8Ww2X342xib57+z9u03ufj +jswhiMKxy67f1LhUMq3XrT3uV6kCVXk/KUOUPcXPlPVNA5JmZeFhMp6GrtB5xJJ9 +wwBZD8UL5A2U2Mxi2OZsdUBv8eo3jnjZ284aFpt+mCjIHrLW5O0jwY8OCwSlYUoY +IY00wlabX0s82kBcIQNZbC1RSV2267ro/7A0MClc8YQ/zWN0FKY6apgtUkHJI1cL +1dc77mhnjETjwW94iLMDFy4zQfVu7IfCBqOBzygRNnqqUG66UhTs1xFnWM0mWXl/ +Zh9+AMpbRLIPaKCktIjl5juzzm+KEgkhD+707XRCFIGUYGP5bSHzGaz8PK9hj0u1 +E2SpZHUvYOcawmxtA7pmpSxl5uQjMIIC+QYJKoZIhvcNAQcBoIIC6gSCAuYwggLi +MIIC3gYLKoZIhvcNAQwKAQKgggKmMIICojAcBgoqhkiG9w0BDAEDMA4ECKB338m8 +qSzHAgIIAASCAoACFhJeqA3xx+s1qIH6udNQYY5hAL6oz7SXoGwFhDiceSyJjmAD +Dby9XWM0bPl1Gj5nqdsuI/lAM++fJeoETk+rxw8q6Ofk2zUaRRE39qgpwBwSk44o +0SAFJ6bzHpc5CFh6sZmDaUX5Lm9GtjnGFmmsPTSJT5an5JuJ9WczGBEd0nSBQhJq +xHbTGZiN8i3SXcIH531Sub+CBIFWy5lyCKgDYh/kgJFGQAaWUOjLI+7dCEESonXn +F3Jh2uPbnDF9MGJyAFoNgWFhgSpi1cf6AUi87GY4Oyur88ddJ1o0D0Kz2uw8/bpG +s3O4PYnIW5naZ8mozzbnYByEFk7PoTwM7VhoFBfYNtBoAI8+hBnPY/Y71YUojEXf +SeX6QbtkIANfzS1XuFNKElShC3DPQIHpKzaatEsfxHfP+8VOav6zcn4mioao7NHA +x7Dp6R1enFGoQOq4UNjBT8YjnkG5vW8zQHW2dAHLTJBq6x2Fzm/4Pjo/8vM1FiGl +BQdW5vfDeJ/l6NgQm3xR9ka2E2HaDqIcj1zWbN8jy/bHPFJYuF/HH8MBV/ngMIXE +vFEW/ToYv8eif0+EpUtzBsCKD4a7qYYYh87RmEVoQU96q6m+UbhpD2WztYfAPkfo +OSL9j2QHhVczhL7OAgqNeM95pOsjA9YMe7exTeqK31LYnTX8oH8WJD1xGbRSJYgu +SY6PQbumcJkc/TFPn0GeVUpiDdf83SeG50lo/i7UKQi2l1hi5Y51fQhnBnyMr68D +llSZEvSWqfDxBJkBpeg6PIYvkTpEwKRJpVQoM3uYvdqVSSnW6rydqIb+snfOrlhd +f+xCtq9xr+kHeTSqLIDRRAnMfgFRhY3IBlj6MSUwIwYJKoZIhvcNAQkVMRYEFBdb +8XGWehZ6oPj56Pf/uId46M9AMDEwITAJBgUrDgMCGgUABBRvSCB04/f8f13pp2PF +vyl2WuMdEwQIMWFFphPkIUICAggA + EOF + p12 = OpenSSL::PKCS12.new(str, "abc123") + + assert_equal @mykey.to_der, p12.key.to_der + assert_equal @mycert.subject.to_der, p12.certificate.subject.to_der + assert_equal [], Array(p12.ca_certs) + end + + def test_new_with_no_keys + # generated with: + # openssl pkcs12 -in <@mycert> -nokeys -export -out + str = <<~EOF.unpack("m").first +MIIDHAIBAzCCAuIGCSqGSIb3DQEHAaCCAtMEggLPMIICyzCCAscGCSqGSIb3DQEH +BqCCArgwggK0AgEAMIICrQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIX4+W +irqwH40CAggAgIICgOaCyo+5+6IOVoGCCL80c50bkkzAwqdXxvkKExJSdcJz2uMU +0gRrKnZEjL5wrUsN8RwZu8DvgQTEhNEkKsUgM7AWainmN/EnwohIdHZAHpm6WD67 +I9kLGp0/DHrqZrV9P2dLfhXLUSQE8PI0tqZPZ8UEABhizkViw4eISTkrOUN7pGbN +Qtx/oqgitXDuX2polbxYYDwt9vfHZhykHoKgew26SeJyZfeMs/WZ6olEI4cQUAFr +mvYGuC1AxEGTo9ERmU8Pm16j9Hr9PFk50WYe+rnk9oX3wJogQ7XUWS5kYf7XRycd +NDkNiwV/ts94bbuaGZp1YA6I48FXpIc8b5fX7t9tY0umGaWy0bARe1L7o0Y89EPe +lMg25rOM7j3uPtFG8whbSfdETSy57UxzzTcJ6UwexeaK6wb2jqEmj5AOoPLWeaX0 +LyOAszR3v7OPAcjIDYZGdrbb3MZ2f2vo2pdQfu9698BrWhXuM7Odh73RLhJVreNI +aezNOAtPyBlvGiBQBGTzRIYHSLL5Y5aVj2vWLAa7hjm5qTL5C5mFdDIo6TkEMr6I +OsexNQofEGs19kr8nARXDlcbEimk2VsPj4efQC2CEXZNzURsKca82pa62MJ8WosB +DTFd8X06zZZ4nED50vLopZvyW4fyW60lELwOyThAdG8UchoAaz2baqP0K4de44yM +Y5/yPFDu4+GoimipJfbiYviRwbzkBxYW8+958ILh0RtagLbvIGxbpaym9PqGjOzx +ShNXjLK2aAFZsEizQ8kd09quJHU/ogq2cUXdqqhmOqPnUWrJVi/VCoRB3Pv1/lE4 +mrUgr2YZ11rYvBw6g5XvNvFcSc53OKyV7SLn0dwwMTAhMAkGBSsOAwIaBQAEFEWP +1WRQykaoD4uJCpTx/wv0SLLBBAiDKI26LJK7xgICCAA= + EOF + p12 = OpenSSL::PKCS12.new(str, "abc123") + + assert_equal nil, p12.key + assert_equal nil, p12.certificate + assert_equal 1, p12.ca_certs.size + assert_equal @mycert.subject.to_der, p12.ca_certs[0].subject.to_der + end + + def test_new_with_no_certs + # generated with: + # openssl pkcs12 -inkey -nocerts -export -out + str = <<~EOF.unpack("m").first +MIIDJwIBAzCCAu0GCSqGSIb3DQEHAaCCAt4EggLaMIIC1jCCAtIGCSqGSIb3DQEH +AaCCAsMEggK/MIICuzCCArcGCyqGSIb3DQEMCgECoIICpjCCAqIwHAYKKoZIhvcN +AQwBAzAOBAg6AaYnJs84SwICCAAEggKAQzZH+fWSpcQYD1J7PsGSune85A++fLCQ +V7tacp2iv95GJkxwYmfTP176pJdgs00mceB9UJ/u9EX5nD0djdjjQjwo6sgKjY0q +cpVhZw8CMxw7kBD2dhtui0zT8z5hy03LePxsjEKsGiSbeVeeGbSfw/I6AAYbv+Uh +O/YPBGumeHj/D2WKnfsHJLQ9GAV3H6dv5VKYNxjciK7f/JEyZCuUQGIN64QFHDhJ +7fzLqd/ul3FZzJZO6a+dwvcgux09SKVXDRSeFmRCEX4b486iWhJJVspCo9P2KNne +ORrpybr3ZSwxyoICmjyo8gj0OSnEfdx9790Ej1takPqSA1wIdSdBLekbZqB0RBQg +DEuPOsXNo3QFi8ji1vu0WBRJZZSNC2hr5NL6lNR+DKxG8yzDll2j4W4BBIp22mAE +7QRX7kVxu17QJXQhOUac4Dd1qXmzebP8t6xkAxD9L7BWEN5OdiXWwSWGjVjMBneX +nYObi/3UT/aVc5WHMHK2BhCI1bwH51E6yZh06d5m0TQpYGUTWDJdWGBSrp3A+8jN +N2PMQkWBFrXP3smHoTEN4oZC4FWiPsIEyAkQsfKRhcV9lGKl2Xgq54ROTFLnwKoj +Z3zJScnq9qmNzvVZSMmDLkjLyDq0pxRxGKBvgouKkWY7VFFIwwBIJM39iDJ5NbBY +i1AQFTRsRSsZrNVPasCXrIq7bhMoJZb/YZOGBLNyJVqKUoYXhtwsajzSq54VlWft +JxsPayEd4Vi6O9EU1ahnj6qFEZiKFzsicgK2J1Rb8cYagrp0XWjHW0SBn5GVUWCg +GUokSFG/0JTdeYTo/sQuG4qNgJkOolRjpeI48Fciq5VUWLvVdKioXzAxMCEwCQYF +Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== + EOF + p12 = OpenSSL::PKCS12.new(str, "abc123") + + assert_equal @mykey.to_der, p12.key.to_der + assert_equal nil, p12.certificate + assert_equal [], Array(p12.ca_certs) + end + + def test_dup + p12 = OpenSSL::PKCS12.create("pass", "name", @mykey, @mycert) + assert_equal p12.to_der, p12.dup.to_der + end + + private + def assert_cert expected, actual + [ + :subject, + :issuer, + :serial, + :not_before, + :not_after, + ].each do |attribute| + assert_equal expected.send(attribute), actual.send(attribute) + end + assert_equal expected.to_der, actual.to_der + end + + def assert_include_cert cert, ary + der = cert.to_der + ary.each do |candidate| + if candidate.to_der == der + return true + end + end + false + end + end +end + +end diff --git a/test/openssl/test_pkcs7.rb b/test/openssl/test_pkcs7.rb new file mode 100644 index 00000000..d0d9dcaf --- /dev/null +++ b/test/openssl/test_pkcs7.rb @@ -0,0 +1,309 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestPKCS7 < OpenSSL::TestCase + def setup + super + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") + ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") + + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + @ca_cert = issue_cert(ca, @rsa2048, 1, ca_exts, nil, nil) + ee_exts = [ + ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], + ["authorityKeyIdentifier","keyid:always",false], + ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], + ] + @ee1_cert = issue_cert(ee1, @rsa1024, 2, ee_exts, @ca_cert, @rsa2048) + @ee2_cert = issue_cert(ee2, @rsa1024, 3, ee_exts, @ca_cert, @rsa2048) + end + + def test_signed + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ca_certs = [@ca_cert] + + data = "aaaaa\r\nbbbbb\r\nccccc\r\n" + tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + certs = p7.certificates + signers = p7.signers + assert(p7.verify([], store)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) + assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) + assert_equal(1, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + + # Normally OpenSSL tries to translate the supplied content into canonical + # MIME format (e.g. a newline character is converted into CR+LF). + # If the content is a binary, PKCS7::BINARY flag should be used. + + data = "aaaaa\nbbbbb\nccccc\n" + flag = OpenSSL::PKCS7::BINARY + tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + certs = p7.certificates + signers = p7.signers + assert(p7.verify([], store)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) + assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) + assert_equal(1, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + + # A signed-data which have multiple signatures can be created + # through the following steps. + # 1. create two signed-data + # 2. copy signerInfo and certificate from one to another + + tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, [], flag) + tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @rsa1024, data, [], flag) + tmp1.add_signer(tmp2.signers[0]) + tmp1.add_certificate(@ee2_cert) + + p7 = OpenSSL::PKCS7.new(tmp1.to_der) + certs = p7.certificates + signers = p7.signers + assert(p7.verify([], store)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(2, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + assert_equal(@ee2_cert.serial, signers[1].serial) + assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s) + end + + def test_detached_sign + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ca_certs = [@ca_cert] + + data = "aaaaa\nbbbbb\nccccc\n" + flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED + tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + assert_nothing_raised do + OpenSSL::ASN1.decode(p7) + end + + certs = p7.certificates + signers = p7.signers + assert(!p7.verify([], store)) + assert(p7.verify([], store, data)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) + assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) + assert_equal(1, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + end + + def test_enveloped + certs = [@ee1_cert, @ee2_cert] + cipher = OpenSSL::Cipher::AES.new("128-CBC") + data = "aaaaa\nbbbbb\nccccc\n" + + tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + recip = p7.recipients + assert_equal(:enveloped, p7.type) + assert_equal(2, recip.size) + + assert_equal(@ca_cert.subject.to_s, recip[0].issuer.to_s) + assert_equal(2, recip[0].serial) + assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) + + assert_equal(@ca_cert.subject.to_s, recip[1].issuer.to_s) + assert_equal(3, recip[1].serial) + assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert)) + + assert_equal(data, p7.decrypt(@rsa1024)) + end + + def test_graceful_parsing_failure #[ruby-core:43250] + contents = File.read(__FILE__) + assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) } + end + + def test_set_type_signed + p7 = OpenSSL::PKCS7.new + p7.type = "signed" + assert_equal(:signed, p7.type) + end + + def test_set_type_data + p7 = OpenSSL::PKCS7.new + p7.type = "data" + assert_equal(:data, p7.type) + end + + def test_set_type_signed_and_enveloped + p7 = OpenSSL::PKCS7.new + p7.type = "signedAndEnveloped" + assert_equal(:signedAndEnveloped, p7.type) + end + + def test_set_type_enveloped + p7 = OpenSSL::PKCS7.new + p7.type = "enveloped" + assert_equal(:enveloped, p7.type) + end + + def test_set_type_encrypted + p7 = OpenSSL::PKCS7.new + p7.type = "encrypted" + assert_equal(:encrypted, p7.type) + end + + def test_smime + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ca_certs = [@ca_cert] + + data = "aaaaa\r\nbbbbb\r\nccccc\r\n" + tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + smime = OpenSSL::PKCS7.write_smime(p7) + assert_equal(true, smime.start_with?(< ctx { + ctx.cert = @svr_cert + ctx.key = @svr_key + ctx.extra_chain_cert = [@ca_cert] + } + server_proc = -> (ctx, ssl) { + assert_equal @svr_cert.to_der, ssl.cert.to_der + assert_equal nil, ssl.peer_cert + + readwrite_loop(ctx, ssl) + } + start_server(ctx_proc: ctx_proc, server_proc: server_proc) { |port| + begin + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.connect + + assert_equal sock, ssl.io + assert_equal nil, ssl.cert + assert_equal @svr_cert.to_der, ssl.peer_cert.to_der + assert_equal 2, ssl.peer_cert_chain.size + assert_equal @svr_cert.to_der, ssl.peer_cert_chain[0].to_der + assert_equal @ca_cert.to_der, ssl.peer_cert_chain[1].to_der + + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + sock&.close + end + } + end + + def test_socket_open + start_server { |port| + begin + ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port) + ssl.sync_close = true + ssl.connect + + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + end + } + end + + def test_socket_open_with_context + start_server { |port| + begin + ctx = OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, context: ctx) + ssl.sync_close = true + ssl.connect + + assert_equal ssl.context, ctx + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + end + } + end + + def test_socket_open_with_local_address_port_context + start_server { |port| + begin + ctx = OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, "127.0.0.1", 8000, context: ctx) + ssl.sync_close = true + ssl.connect + + assert_equal ssl.context, ctx + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + end + } + end + + def test_add_certificate + ctx_proc = -> ctx { + # Unset values set by start_server + ctx.cert = ctx.key = ctx.extra_chain_cert = nil + ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA + } + start_server(ctx_proc: ctx_proc) do |port| + server_connect(port) { |ssl| + assert_equal @svr_cert.subject, ssl.peer_cert.subject + assert_equal [@svr_cert.subject, @ca_cert.subject], + ssl.peer_cert_chain.map(&:subject) + + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + end + end + + def test_add_certificate_multiple_certs + pend "EC is not supported" unless defined?(OpenSSL::PKey::EC) + pend "TLS 1.2 is not supported" unless tls12_supported? + + # SSL_CTX_set0_chain() is needed for setting multiple certificate chains + add0_chain_supported = openssl?(1, 0, 2) + + if add0_chain_supported + ca2_key = Fixtures.pkey("rsa2048") + ca2_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["keyUsage", "cRLSign, keyCertSign", true], + ] + ca2_dn = OpenSSL::X509::Name.parse_rfc2253("CN=CA2") + ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil) + else + # Use the same CA as @svr_cert + ca2_key = @ca_key; ca2_cert = @ca_cert + end + + ecdsa_key = Fixtures.pkey("p256") + exts = [ + ["keyUsage", "digitalSignature", false], + ] + ecdsa_dn = OpenSSL::X509::Name.parse_rfc2253("CN=localhost2") + ecdsa_cert = issue_cert(ecdsa_dn, ecdsa_key, 456, exts, ca2_cert, ca2_key) + + if !add0_chain_supported + # Testing the warning emitted when 'extra' chain is replaced + tctx = OpenSSL::SSL::SSLContext.new + tctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) + assert_warning(/set0_chain/) { + tctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) + } + end + + ctx_proc = -> ctx { + # Unset values set by start_server + ctx.cert = ctx.key = ctx.extra_chain_cert = nil + ctx.ecdh_curves = "P-256" unless openssl?(1, 0, 2) + ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA + EnvUtil.suppress_warning do # !add0_chain_supported + ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) + end + } + start_server(ctx_proc: ctx_proc) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = :TLS1_2 # TODO: We need this to force certificate type + ctx.ciphers = "aECDSA" + server_connect(port, ctx) { |ssl| + assert_equal ecdsa_cert.subject, ssl.peer_cert.subject + assert_equal [ecdsa_cert.subject, ca2_cert.subject], + ssl.peer_cert_chain.map(&:subject) + } + + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = :TLS1_2 + ctx.ciphers = "aRSA" + server_connect(port, ctx) { |ssl| + assert_equal @svr_cert.subject, ssl.peer_cert.subject + assert_equal [@svr_cert.subject, @ca_cert.subject], + ssl.peer_cert_chain.map(&:subject) + } + end + end + + def test_add_certificate_chain_file + ctx = OpenSSL::SSL::SSLContext.new + assert ctx.add_certificate_chain_file(Fixtures.file_path("chain", "server.crt")) + end + + def test_sysread_and_syswrite + start_server { |port| + server_connect(port) { |ssl| + str = +("x" * 100 + "\n") + ssl.syswrite(str) + newstr = ssl.sysread(str.bytesize) + assert_equal(str, newstr) + + buf = String.new + ssl.syswrite(str) + assert_same buf, ssl.sysread(str.size, buf) + assert_equal(str, buf) + } + } + end + + # TODO fix this test + # def test_sysread_nonblock_and_syswrite_nonblock_keywords + # start_server do |port| + # server_connect(port) do |ssl| + # assert_warning("") do + # ssl.send(:syswrite_nonblock, "12", exception: false) + # ssl.send(:sysread_nonblock, 1, exception: false) rescue nil + # ssl.send(:sysread_nonblock, 1, String.new, exception: false) rescue nil + # end + # end + # end + # end + + def test_sync_close + start_server do |port| + begin + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ssl.close + assert_not_predicate sock, :closed? + ensure + sock&.close + end + + begin + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true # !! + ssl.connect + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ssl.close + assert_predicate sock, :closed? + ensure + sock&.close + end + end + end + + def test_copy_stream + start_server do |port| + server_connect(port) do |ssl| + IO.pipe do |r, w| + str = "hello world\n" + w.write(str) + IO.copy_stream(r, ssl, str.bytesize) + IO.copy_stream(ssl, w, str.bytesize) + assert_equal str, r.read(str.bytesize) + end + end + end + end + + def test_client_auth_failure + vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + start_server(verify_mode: vflag, ignore_listener_error: true) { |port| + assert_handshake_error { + server_connect(port) { |ssl| ssl.puts("abc"); ssl.gets } + } + } + end + + def test_client_auth_success + vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + start_server(verify_mode: vflag) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.key = @cli_key + ctx.cert = @cli_cert + + server_connect(port, ctx) { |ssl| + ssl.puts("foo") + assert_equal("foo\n", ssl.gets) + } + + called = nil + ctx = OpenSSL::SSL::SSLContext.new + ctx.client_cert_cb = Proc.new{ |sslconn| + called = true + [@cli_cert, @cli_key] + } + + server_connect(port, ctx) { |ssl| + assert(called) + ssl.puts("foo") + assert_equal("foo\n", ssl.gets) + } + } + end + + def test_client_auth_public_key + vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + start_server(verify_mode: vflag, ignore_listener_error: true) do |port| + assert_raise(ArgumentError) { + ctx = OpenSSL::SSL::SSLContext.new + ctx.key = @cli_key.public_key + ctx.cert = @cli_cert + server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } + } + + ctx = OpenSSL::SSL::SSLContext.new + ctx.client_cert_cb = Proc.new{ |ssl| + [@cli_cert, @cli_key.public_key] + } + assert_handshake_error { + server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } + } + end + end + + def test_client_ca + ctx_proc = Proc.new do |ctx| + ctx.client_ca = [@ca_cert] + end + + vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + start_server(verify_mode: vflag, ctx_proc: ctx_proc) { |port| + ctx = OpenSSL::SSL::SSLContext.new + client_ca_from_server = nil + ctx.client_cert_cb = Proc.new do |sslconn| + client_ca_from_server = sslconn.client_ca + [@cli_cert, @cli_key] + end + server_connect(port, ctx) { |ssl| + assert_equal([@ca], client_ca_from_server) + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + } + end + + def test_read_nonblock_without_session + EnvUtil.suppress_warning do + start_server(start_immediately: false) { |port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + + assert_equal :wait_readable, ssl.read_nonblock(100, exception: false) + ssl.write("abc\n") + IO.select [ssl] + assert_equal('a', ssl.read_nonblock(1)) + assert_equal("bc\n", ssl.read_nonblock(100)) + assert_equal :wait_readable, ssl.read_nonblock(100, exception: false) + ssl.close + } + end + end + + def test_starttls + server_proc = -> (ctx, ssl) { + while line = ssl.gets + if line =~ /^STARTTLS$/ + ssl.write("x") + ssl.flush + ssl.accept + break + end + ssl.write(line) + end + readwrite_loop(ctx, ssl) + } + + EnvUtil.suppress_warning do # read/write on not started session + start_server(start_immediately: false, + server_proc: server_proc) { |port| + begin + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + + ssl.puts "plaintext" + assert_equal "plaintext\n", ssl.gets + + ssl.puts("STARTTLS") + ssl.read(1) + ssl.connect + + ssl.puts "over-tls" + assert_equal "over-tls\n", ssl.gets + ensure + ssl&.close + sock&.close + end + } + end + end + + def test_parallel + start_server { |port| + ssls = [] + 10.times{ + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + ssl.sync_close = true + ssls << ssl + } + str = "x" * 1000 + "\n" + ITERATIONS.times{ + ssls.each{|ssl| + ssl.puts(str) + assert_equal(str, ssl.gets) + } + } + ssls.each{|ssl| ssl.close } + } + end + + def test_verify_result + start_server(ignore_listener_error: true) { |port| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + begin + assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } + assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) + ensure + ssl.close + end + } + + start_server { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ctx.verify_callback = Proc.new do |preverify_ok, store_ctx| + store_ctx.error = OpenSSL::X509::V_OK + true + end + server_connect(port, ctx) { |ssl| + assert_equal(OpenSSL::X509::V_OK, ssl.verify_result) + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + } + + start_server(ignore_listener_error: true) { |port| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ctx.verify_callback = Proc.new do |preverify_ok, store_ctx| + store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION + false + end + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + begin + assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } + assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result) + ensure + ssl.close + end + } + end + + def test_exception_in_verify_callback_is_ignored + start_server(ignore_listener_error: true) { |port| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ctx.verify_callback = Proc.new do |preverify_ok, store_ctx| + store_ctx.error = OpenSSL::X509::V_OK + raise RuntimeError + end + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + begin + EnvUtil.suppress_warning do + # SSLError, not RuntimeError + assert_raise(OpenSSL::SSL::SSLError) { ssl.connect } + end + assert_equal(OpenSSL::X509::V_ERR_CERT_REJECTED, ssl.verify_result) + ensure + ssl.close + end + } + end + + def test_finished_messages + server_finished = nil + server_peer_finished = nil + client_finished = nil + client_peer_finished = nil + + start_server(accept_proc: proc { |server| + server_finished = server.finished_message + server_peer_finished = server.peer_finished_message + }) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE + server_connect(port, ctx) { |ssl| + client_finished = ssl.finished_message + client_peer_finished = ssl.peer_finished_message + sleep 0.05 + ssl.send :stop + } + } + assert_equal(server_finished, client_peer_finished) + assert_equal(server_peer_finished, client_finished) + end + + def test_sslctx_set_params + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params + + assert_equal OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode + ciphers_names = ctx.ciphers.collect{|v, _, _, _| v } + assert ciphers_names.all?{|v| /A(EC)?DH/ !~ v }, "anon ciphers are disabled" + assert ciphers_names.all?{|v| /(RC4|MD5|EXP|DES(?!-EDE|-CBC3))/ !~ v }, "weak ciphers are disabled" + assert_equal 0, ctx.options & OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS + assert_equal OpenSSL::SSL::OP_NO_COMPRESSION, + ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION + end + + def test_post_connect_check_with_anon_ciphers + pend "TLS 1.2 is not supported" unless tls12_supported? + + ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "aNULL" + ctx.security_level = 0 + } + + start_server(ctx_proc: ctx_proc) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "aNULL" + ctx.security_level = 0 + server_connect(port, ctx) { |ssl| + assert_raise_with_message(OpenSSL::SSL::SSLError, /anonymous cipher suite/i) { + ssl.post_connection_check("localhost.localdomain") + } + } + } + end + + def test_post_connection_check + sslerr = OpenSSL::SSL::SSLError + + start_server { |port| + server_connect(port) { |ssl| + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + + assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} + assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} + assert(ssl.post_connection_check("localhost")) + assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} + + cert = ssl.peer_cert + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) + assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) + } + } + + exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ["subjectAltName","DNS:localhost.localdomain",false], + ["subjectAltName","IP:127.0.0.1",false], + ] + @svr_cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) + start_server { |port| + server_connect(port) { |ssl| + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + + assert(ssl.post_connection_check("localhost.localdomain")) + assert(ssl.post_connection_check("127.0.0.1")) + assert_raise(sslerr){ssl.post_connection_check("localhost")} + assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} + + cert = ssl.peer_cert + assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) + assert(OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) + } + } + + exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ["subjectAltName","DNS:*.localdomain",false], + ] + @svr_cert = issue_cert(@svr, @svr_key, 5, exts, @ca_cert, @ca_key) + start_server { |port| + server_connect(port) { |ssl| + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + + assert(ssl.post_connection_check("localhost.localdomain")) + assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} + assert_raise(sslerr){ssl.post_connection_check("localhost")} + assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} + cert = ssl.peer_cert + assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) + } + } + end + + def test_verify_certificate_identity + [true, false].each do |criticality| + cert = create_null_byte_SAN_certificate(criticality) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, 'www.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, "www.example.com\0.evil.com")) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.255')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.1')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '13::17')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '13::18')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '13:0:0:0:0:0:0:17')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '44:0:0:0:0:0:0:17')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '0013:0000:0000:0000:0000:0000:0000:0017')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '1313:0000:0000:0000:0000:0000:0000:0017')) + end + end + + def test_verify_hostname + assert_equal(true, OpenSSL::SSL.verify_hostname("www.example.com", "*.example.com")) + assert_equal(false, OpenSSL::SSL.verify_hostname("www.subdomain.example.com", "*.example.com")) + end + + def test_verify_wildcard + assert_equal(false, OpenSSL::SSL.verify_wildcard("foo", "x*")) + assert_equal(true, OpenSSL::SSL.verify_wildcard("foo", "foo")) + assert_equal(true, OpenSSL::SSL.verify_wildcard("foo", "f*")) + assert_equal(true, OpenSSL::SSL.verify_wildcard("foo", "*")) + assert_equal(false, OpenSSL::SSL.verify_wildcard("abc*bcd", "abcd")) + assert_equal(false, OpenSSL::SSL.verify_wildcard("xn--qdk4b9b", "x*")) + assert_equal(false, OpenSSL::SSL.verify_wildcard("xn--qdk4b9b", "*--qdk4b9b")) + assert_equal(true, OpenSSL::SSL.verify_wildcard("xn--qdk4b9b", "xn--qdk4b9b")) + end + + # Comments in this test is excerpted from http://tools.ietf.org/html/rfc6125#page-27 + def test_post_connection_check_wildcard_san + # case-insensitive ASCII comparison + # RFC 6125, section 6.4.1 + # + # "..matching of the reference identifier against the presented identifier + # is performed by comparing the set of domain name labels using a + # case-insensitive ASCII comparison, as clarified by [DNS-CASE] (e.g., + # "WWW.Example.Com" would be lower-cased to "www.example.com" for + # comparison purposes) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*.example.com'), 'www.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*.Example.COM'), 'www.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*.example.com'), 'WWW.Example.COM')) + # 1. The client SHOULD NOT attempt to match a presented identifier in + # which the wildcard character comprises a label other than the + # left-most label (e.g., do not match bar.*.example.net). + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:www.*.com'), 'www.example.com')) + # 2. If the wildcard character is the only character of the left-most + # label in the presented identifier, the client SHOULD NOT compare + # against anything but the left-most label of the reference + # identifier (e.g., *.example.com would match foo.example.com but + # not bar.foo.example.com or example.com). + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*.example.com'), 'foo.example.com')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*.example.com'), 'bar.foo.example.com')) + # 3. The client MAY match a presented identifier in which the wildcard + # character is not the only character of the label (e.g., + # baz*.example.net and *baz.example.net and b*z.example.net would + # be taken to match baz1.example.net and foobaz.example.net and + # buzz.example.net, respectively). ... + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:baz*.example.com'), 'baz1.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*baz.example.com'), 'foobaz.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:b*z.example.com'), 'buzz.example.com')) + # Section 6.4.3 of RFC6125 states that client should NOT match identifier + # where wildcard is other than left-most label. + # + # Also implicitly mentions the wildcard character only in singular form, + # and discourages matching against more than one wildcard. + # + # See RFC 6125, section 7.2, subitem 2. + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*b*.example.com'), 'abc.example.com')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*b*.example.com'), 'ab.example.com')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*b*.example.com'), 'bc.example.com')) + # ... However, the client SHOULD NOT + # attempt to match a presented identifier where the wildcard + # character is embedded within an A-label or U-label [IDNA-DEFS] of + # an internationalized domain name [IDNA-PROTO]. + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:xn*.example.com'), 'xn1ca.example.com')) + # part of A-label + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:xn--*.example.com'), 'xn--1ca.example.com')) + # part of U-label + # dNSName in RFC5280 is an IA5String so U-label should NOT be allowed + # regardless of wildcard. + # + # See Section 7.2 of RFC 5280: + # IA5String is limited to the set of ASCII characters. + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:á*.example.com'), 'á1.example.com')) + end + + def test_post_connection_check_wildcard_cn + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*.example.com'), 'www.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*.Example.COM'), 'www.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*.example.com'), 'WWW.Example.COM')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('www.*.com'), 'www.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*.example.com'), 'foo.example.com')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*.example.com'), 'bar.foo.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('baz*.example.com'), 'baz1.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*baz.example.com'), 'foobaz.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('b*z.example.com'), 'buzz.example.com')) + # Section 6.4.3 of RFC6125 states that client should NOT match identifier + # where wildcard is other than left-most label. + # + # Also implicitly mentions the wildcard character only in singular form, + # and discourages matching against more than one wildcard. + # + # See RFC 6125, section 7.2, subitem 2. + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*b*.example.com'), 'abc.example.com')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*b*.example.com'), 'ab.example.com')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('*b*.example.com'), 'bc.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('xn*.example.com'), 'xn1ca.example.com')) + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('xn--*.example.com'), 'xn--1ca.example.com')) + # part of U-label + # Subject in RFC5280 states case-insensitive ASCII comparison. + # + # See Section 7.2 of RFC 5280: + # IA5String is limited to the set of ASCII characters. + assert_equal(false, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_name('á*.example.com'), 'á1.example.com')) + end + + def create_cert_with_san(san) + ef = OpenSSL::X509::ExtensionFactory.new + cert = OpenSSL::X509::Certificate.new + cert.subject = OpenSSL::X509::Name.parse("/DC=some/DC=site/CN=Some Site") + ext = ef.create_ext('subjectAltName', san) + cert.add_extension(ext) + cert + end + + def create_cert_with_name(name) + cert = OpenSSL::X509::Certificate.new + cert.subject = OpenSSL::X509::Name.new([['DC', 'some'], ['DC', 'site'], ['CN', name]]) + cert + end + + + # Create NULL byte SAN certificate + def create_null_byte_SAN_certificate(critical = false) + ef = OpenSSL::X509::ExtensionFactory.new + cert = OpenSSL::X509::Certificate.new + cert.subject = OpenSSL::X509::Name.parse "/DC=some/DC=site/CN=Some Site" + ext = ef.create_ext('subjectAltName', 'DNS:placeholder,IP:192.168.7.1,IP:13::17', critical) + ext_asn1 = OpenSSL::ASN1.decode(ext.to_der) + san_list_der = ext_asn1.value.reduce(nil) { |memo,val| val.tag == 4 ? val.value : memo } + san_list_asn1 = OpenSSL::ASN1.decode(san_list_der) + san_list_asn1.value[0].value = "www.example.com\0.evil.com" + pos = critical ? 2 : 1 + ext_asn1.value[pos].value = san_list_asn1.to_der + real_ext = OpenSSL::X509::Extension.new ext_asn1 + cert.add_extension(real_ext) + cert + end + + def socketpair + if defined? UNIXSocket + UNIXSocket.pair + else + Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0) + end + end + + def test_tlsext_hostname + fooctx = OpenSSL::SSL::SSLContext.new + fooctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } + fooctx.cert = @cli_cert + fooctx.key = @cli_key + + ctx_proc = proc { |ctx| + ctx.servername_cb = proc { |ssl, servername| + case servername + when "foo.example.com" + fooctx + when "bar.example.com" + nil + else + raise "unreachable" + end + } + } + start_server(ctx_proc: ctx_proc) do |port| + sock = TCPSocket.new("127.0.0.1", port) + begin + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.hostname = "foo.example.com" + ssl.connect + assert_equal @cli_cert.serial, ssl.peer_cert.serial + assert_predicate fooctx, :frozen? + + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + sock.close + end + + sock = TCPSocket.new("127.0.0.1", port) + begin + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.hostname = "bar.example.com" + ssl.connect + assert_equal @svr_cert.serial, ssl.peer_cert.serial + + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + sock.close + end + end + end + + def test_servername_cb_raises_an_exception_on_unknown_objects + hostname = 'example.org' + + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.cert = @svr_cert + ctx2.key = @svr_key + ctx2.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } + ctx2.servername_cb = lambda { |args| Object.new } + + sock1, sock2 = socketpair + + s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) + + ctx1 = OpenSSL::SSL::SSLContext.new + + s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) + s1.hostname = hostname + t = Thread.new { + assert_raise(OpenSSL::SSL::SSLError) do + s1.connect + end + } + + assert_raise(ArgumentError) do + s2.accept + end + + assert t.join + ensure + sock1.close if sock1 + sock2.close if sock2 + end + + def test_verify_hostname_on_connect + ctx_proc = proc { |ctx| + exts = [ + ["keyUsage", "keyEncipherment,digitalSignature", true], + ["subjectAltName", "DNS:a.example.com,DNS:*.b.example.com," \ + "DNS:c*.example.com,DNS:d.*.example.com"], + ] + ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) + ctx.key = @svr_key + } + + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_hostname = true + ctx.cert_store = OpenSSL::X509::Store.new + ctx.cert_store.add_cert(@ca_cert) + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + + [ + ["a.example.com", true], + ["A.Example.Com", true], + ["x.example.com", false], + ["b.example.com", false], + ["x.b.example.com", true], + ["cx.example.com", true], + ["d.x.example.com", false], + ].each do |name, expected_ok| + begin + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.hostname = name + if expected_ok + ssl.connect + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + else + assert_handshake_error { ssl.connect } + end + ensure + ssl.close if ssl + sock.close if sock + end + end + end + end + + def test_connect_certificate_verify_failed_exception_message + start_server(ignore_listener_error: true) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params + assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { + server_connect(port, ctx) + } + } + + ctx_proc = proc { |ctx| + ctx.cert = issue_cert(@svr, @svr_key, 30, [], @ca_cert, @ca_key, + not_before: Time.now-100, not_after: Time.now-10) + } + start_server(ignore_listener_error: true, ctx_proc: ctx_proc) { |port| + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params(cert_store: store) + assert_raise_with_message(OpenSSL::SSL::SSLError, /expired/) { + server_connect(port, ctx) + } + } + end + + def test_unset_OP_ALL + ctx_proc = Proc.new { |ctx| + # If OP_DONT_INSERT_EMPTY_FRAGMENTS is not defined, this test is + # redundant because the default options already are equal to OP_ALL. + # But it also degrades gracefully, so keep it + ctx.options = OpenSSL::SSL::OP_ALL + } + start_server(ctx_proc: ctx_proc) { |port| + server_connect(port) { |ssl| + ssl.puts('hello') + assert_equal("hello\n", ssl.gets) + } + } + end + + def check_supported_protocol_versions + possible_versions = [ + OpenSSL::SSL::SSL3_VERSION, + OpenSSL::SSL::TLS1_VERSION, + OpenSSL::SSL::TLS1_1_VERSION, + OpenSSL::SSL::TLS1_2_VERSION, + # OpenSSL 1.1.1 + defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION, + ].compact + + # Prepare for testing & do sanity check + supported = [] + possible_versions.each do |ver| + catch(:unsupported) { + ctx_proc = proc { |ctx| + begin + ctx.min_version = ctx.max_version = ver + rescue ArgumentError, OpenSSL::SSL::SSLError + throw :unsupported + end + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| + begin + server_connect(port) { |ssl| + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET + else + supported << ver + end + end + } + end + assert_not_empty supported + + supported + end + + def test_set_params_min_version + supported = check_supported_protocol_versions + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + + if supported.include?(OpenSSL::SSL::SSL3_VERSION) + # SSLContext#set_params properly disables SSL 3.0 by default + ctx_proc = proc { |ctx| + ctx.min_version = ctx.max_version = OpenSSL::SSL::SSL3_VERSION + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params(cert_store: store, verify_hostname: false) + assert_handshake_error { server_connect(port, ctx) { } } + } + end + end + + def test_minmax_version + supported = check_supported_protocol_versions + + # name: The string that would be returned by SSL_get_version() + # method: The version-specific method name (if any) + vmap = { + OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, + OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, + OpenSSL::SSL::TLS1_VERSION => { name: "TLSv1", method: "TLSv1" }, + OpenSSL::SSL::TLS1_1_VERSION => { name: "TLSv1.1", method: "TLSv1_1" }, + OpenSSL::SSL::TLS1_2_VERSION => { name: "TLSv1.2", method: "TLSv1_2" }, + # OpenSSL 1.1.1 + defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION => + { name: "TLSv1.3", method: nil }, + } + + # Server enables a single version + supported.each do |ver| + ctx_proc = proc { |ctx| ctx.min_version = ctx.max_version = ver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client enables a single version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = cver + if ver == cver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx1) { } } + end + + # There is no version-specific SSL methods for TLS 1.3 + if cver <= OpenSSL::SSL::TLS1_2_VERSION + # Client enables a single version using #ssl_version= + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.ssl_version = vmap[cver][:method] + if ver == cver + server_connect(port, ctx2) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx2) { } } + end + end + end + + # Client enables all supported versions + ctx3 = OpenSSL::SSL::SSLContext.new + ctx3.min_version = ctx3.max_version = nil + server_connect(port, ctx3) { |ssl| + assert_equal vmap[ver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + } + end + + if supported.size == 1 + pend "More than one protocol version must be supported" + end + + # Server sets min_version (earliest is disabled) + sver = supported[1] + ctx_proc = proc { |ctx| ctx.min_version = sver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client sets min_version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = cver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[supported.last][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + + # Client sets max_version + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.max_version = cver + if cver >= sver + server_connect(port, ctx2) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx2) { } } + end + end + } + + # Server sets max_version (latest is disabled) + sver = supported[-2] + ctx_proc = proc { |ctx| ctx.max_version = sver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client sets min_version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = cver + if cver <= sver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[sver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx1) { } } + end + + # Client sets max_version + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.max_version = cver + server_connect(port, ctx2) { |ssl| + if cver >= sver + assert_equal vmap[sver][:name], ssl.ssl_version + else + assert_equal vmap[cver][:name], ssl.ssl_version + end + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + end + } + end + + def test_options_disable_versions + # Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0. + supported = check_supported_protocol_versions + + if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) && + supported.include?(OpenSSL::SSL::TLS1_2_VERSION) + # Server disables ~ TLS 1.1 + ctx_proc = proc { |ctx| + ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | + OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client only supports TLS 1.1 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION + assert_handshake_error { server_connect(port, ctx1) { } } + + # Client only supports TLS 1.2 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION + assert_nothing_raised { server_connect(port, ctx2) { } } + } + + # Server only supports TLS 1.1 + ctx_proc = proc { |ctx| + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client disables TLS 1.1 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1 + assert_handshake_error { server_connect(port, ctx1) { } } + + # Client disables TLS 1.2 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2 + assert_nothing_raised { server_connect(port, ctx2) { } } + } + else + pend "TLS 1.1 and TLS 1.2 must be supported; skipping" + end + end + + def test_ssl_methods_constant + EnvUtil.suppress_warning { # Deprecated in v2.1.0 + base = [:TLSv1_2, :TLSv1_1, :TLSv1, :SSLv3, :SSLv2, :SSLv23] + base.each do |name| + assert_include OpenSSL::SSL::SSLContext::METHODS, name + assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_client" + assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_server" + end + } + end + + def test_renegotiation_cb + num_handshakes = 0 + renegotiation_cb = Proc.new { |ssl| num_handshakes += 1 } + ctx_proc = Proc.new { |ctx| ctx.renegotiation_cb = renegotiation_cb } + start_server_version(:SSLv23, ctx_proc) { |port| + server_connect(port) { |ssl| + assert_equal(1, num_handshakes) + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + } + end + +if openssl?(1, 0, 2) || libressl? + def test_alpn_protocol_selection_ary + advertised = ["http/1.1", "spdy/2"] + ctx_proc = Proc.new { |ctx| + ctx.alpn_select_cb = -> (protocols) { + protocols.first + } + ctx.alpn_protocols = advertised + } + start_server_version(:SSLv23, ctx_proc) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.alpn_protocols = advertised + server_connect(port, ctx) { |ssl| + assert_equal(advertised.first, ssl.alpn_protocol) + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + } + end + + def test_alpn_protocol_selection_cancel + sock1, sock2 = socketpair + + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.cert = @svr_cert + ctx1.key = @svr_key + ctx1.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } + ctx1.alpn_select_cb = -> (protocols) { nil } + ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) + + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.alpn_protocols = ["http/1.1"] + ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) + + t = Thread.new { + ssl2.connect_nonblock(exception: false) + } + assert_raise_with_message(TypeError, /nil/) { ssl1.accept } + t.join + ensure + sock1&.close + sock2&.close + ssl1&.close + ssl2&.close + t&.kill + t&.join + end +end + + def test_npn_protocol_selection_ary + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + + advertised = ["http/1.1", "spdy/2"] + ctx_proc = proc { |ctx| ctx.npn_protocols = advertised } + start_server_version(:TLSv1_2, ctx_proc) { |port| + selector = lambda { |which| + ctx = OpenSSL::SSL::SSLContext.new + ctx.npn_select_cb = -> (protocols) { protocols.send(which) } + server_connect(port, ctx) { |ssl| + assert_equal(advertised.send(which), ssl.npn_protocol) + } + } + selector.call(:first) + selector.call(:last) + } + end + + def test_npn_protocol_selection_enum + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + + advertised = Object.new + def advertised.each + yield "http/1.1" + yield "spdy/2" + end + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = advertised } + start_server_version(:TLSv1_2, ctx_proc) { |port| + selector = lambda { |selected, which| + ctx = OpenSSL::SSL::SSLContext.new + ctx.npn_select_cb = -> (protocols) { protocols.to_a.send(which) } + server_connect(port, ctx) { |ssl| + assert_equal(selected, ssl.npn_protocol) + } + } + selector.call("http/1.1", :first) + selector.call("spdy/2", :last) + } + end + + def test_npn_protocol_selection_cancel + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } + start_server_version(:TLSv1_2, ctx_proc) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.npn_select_cb = -> (protocols) { raise RuntimeError.new } + assert_raise(RuntimeError) { server_connect(port, ctx) } + } + end + + def test_npn_advertised_protocol_too_long + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["a" * 256] } + start_server_version(:TLSv1_2, ctx_proc) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.npn_select_cb = -> (protocols) { protocols.first } + assert_handshake_error { server_connect(port, ctx) } + } + end + + def test_npn_selected_protocol_too_long + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } + start_server_version(:TLSv1_2, ctx_proc) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.npn_select_cb = -> (protocols) { "a" * 256 } + assert_handshake_error { server_connect(port, ctx) } + } + end + + def test_close_after_socket_close + start_server { |port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + sock.close + assert_nothing_raised do + ssl.close + end + } + end + + def test_sync_close_without_connect + Socket.open(:INET, :STREAM) {|s| + ssl = OpenSSL::SSL::SSLSocket.new(s) + ssl.sync_close = true + ssl.close + assert(s.closed?) + } + end + + def test_get_ephemeral_key + # OpenSSL >= 1.0.2 + unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key) + pend "SSL_get_server_tmp_key() is not supported" + end + + if tls12_supported? + # kRSA + ctx_proc1 = proc { |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "kRSA" + } + start_server(ctx_proc: ctx_proc1) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "kRSA" + server_connect(port, ctx) { |ssl| assert_nil ssl.tmp_key } + end + end + + if defined?(OpenSSL::PKey::DH) && tls12_supported? + # DHE + # TODO: How to test this with TLS 1.3? + ctx_proc2 = proc { |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "EDH" + } + start_server(ctx_proc: ctx_proc2) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "EDH" + server_connect(port, ctx) { |ssl| + assert_instance_of OpenSSL::PKey::DH, ssl.tmp_key + } + end + end + + if defined?(OpenSSL::PKey::EC) + # ECDHE + ctx_proc3 = proc { |ctx| + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + ctx.ecdh_curves = "P-256" + } + start_server(ctx_proc: ctx_proc3) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + server_connect(port, ctx) { |ssl| + assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + end + end + end + + def test_fallback_scsv + pend "Fallback SCSV is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:enable_fallback_scsv) + + start_server do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + # Here is OK + # TLS1.2 supported and this is what we ask the first time + server_connect(port, ctx) + end + + ctx_proc = proc { |ctx| + ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + } + start_server(ctx_proc: ctx_proc) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.enable_fallback_scsv + ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + # Here is OK too + # TLS1.2 not supported, fallback to TLS1.1 and signaling the fallback + # Server doesn't support better, so connection OK + server_connect(port, ctx) + end + + # Here is not OK + # TLS1.2 is supported, fallback to TLS1.1 (downgrade attack) and signaling the fallback + # Server support better, so refuse the connection + sock1, sock2 = socketpair + begin + # This test is for the downgrade protection mechanism of TLS1.2. + # This is why ctx1 bounds max_version == TLS1.2. + # Otherwise, this test fails when using openssl 1.1.1 (or later) that supports TLS1.3. + # TODO: We may need another test for TLS1.3 because it seems to have a different mechanism. + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION + s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) + + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.enable_fallback_scsv + ctx2.max_version = OpenSSL::SSL::TLS1_1_VERSION + s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) + t = Thread.new { + assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { + s2.connect + } + } + assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { + s1.accept + } + t.join + ensure + sock1.close + sock2.close + end + end + + def test_dh_callback + pend "TLS 1.2 is not supported" unless tls12_supported? + + dh = Fixtures.pkey("dh-1") + called = false + ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "DH:!NULL" + ctx.tmp_dh_callback = ->(*args) { + called = true + dh + } + } + start_server(ctx_proc: ctx_proc) do |port| + server_connect(port) { |ssl| + assert called, "dh callback should be called" + if ssl.respond_to?(:tmp_key) + assert_equal dh.to_der, ssl.tmp_key.to_der + end + } + end + end + + def test_connect_works_when_setting_dh_callback_to_nil + pend "TLS 1.2 is not supported" unless tls12_supported? + + ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "DH:!NULL" # use DH + ctx.tmp_dh_callback = nil + } + start_server(ctx_proc: ctx_proc) do |port| + EnvUtil.suppress_warning { # uses default callback + assert_nothing_raised { + server_connect(port) { } + } + } + end + end + + def test_tmp_ecdh_callback + pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) + pend "tmp_ecdh_callback is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:tmp_ecdh_callback) + pend "LibreSSL 2.6 has broken SSL_CTX_set_tmp_ecdh_callback()" \ + if libressl?(2, 6, 1) + + EnvUtil.suppress_warning do # tmp_ecdh_callback is deprecated (2016-05) + called = false + ctx_proc = -> ctx { + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + ctx.tmp_ecdh_callback = -> (*args) { + called = true + OpenSSL::PKey::EC.new "prime256v1" + } + } + start_server(ctx_proc: ctx_proc) do |port| + server_connect(port) { |s| + assert called, "tmp_ecdh_callback should be called" + } + end + end + end + + def test_ecdh_curves + pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) + + ctx_proc = -> ctx { + # Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3 + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + ctx.ecdh_curves = "P-384:P-521" + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ecdh_curves = "P-256:P-384" # disable P-521 for OpenSSL >= 1.0.2 + + server_connect(port, ctx) { |ssl| + cs = ssl.cipher[0] + if /\ATLS/ =~ cs # Is TLS 1.3 is used? + assert_equal "secp384r1", ssl.tmp_key.group.curve_name + else + assert_match (/\AECDH/), cs + if ssl.respond_to?(:tmp_key) + assert_equal "secp384r1", ssl.tmp_key.group.curve_name + end + end + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + + if openssl?(1, 0, 2) || libressl?(2, 5, 1) + ctx = OpenSSL::SSL::SSLContext.new + ctx.ecdh_curves = "P-256" + + assert_raise(OpenSSL::SSL::SSLError) { + server_connect(port, ctx) { } + } + + ctx = OpenSSL::SSL::SSLContext.new + ctx.ecdh_curves = "P-521:P-384" + + server_connect(port, ctx) { |ssl| + assert_equal "secp521r1", ssl.tmp_key.group.curve_name + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + end + end + end + + def test_security_level + ctx = OpenSSL::SSL::SSLContext.new + begin + ctx.security_level = 1 + rescue NotImplementedError + assert_equal(0, ctx.security_level) + return + end + assert_equal(1, ctx.security_level) + + dsa512 = Fixtures.pkey("dsa512") + dsa512_cert = issue_cert(@svr, dsa512, 50, [], @ca_cert, @ca_key) + rsa1024 = Fixtures.pkey("rsa1024") + rsa1024_cert = issue_cert(@svr, rsa1024, 51, [], @ca_cert, @ca_key) + + assert_raise(OpenSSL::SSL::SSLError) { + # 512 bit DSA key is rejected because it offers < 80 bits of security + ctx.add_certificate(dsa512_cert, dsa512) + } + assert_nothing_raised { + ctx.add_certificate(rsa1024_cert, rsa1024) + } + ctx.security_level = 2 + assert_raise(OpenSSL::SSL::SSLError) { + # < 112 bits of security + ctx.add_certificate(rsa1024_cert, rsa1024) + } + end + + def test_dup + ctx = OpenSSL::SSL::SSLContext.new + sock1, sock2 = socketpair + ssl = OpenSSL::SSL::SSLSocket.new(sock1, ctx) + + assert_raise(NoMethodError) { ctx.dup } + assert_raise(NoMethodError) { ssl.dup } + ensure + ssl.close if ssl + sock1.close + sock2.close + end + + def test_freeze_calls_setup + bug = "[ruby/openssl#85]" + start_server(ignore_listener_error: true) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ctx.freeze + assert_raise(OpenSSL::SSL::SSLError, bug) { + server_connect(port, ctx) + } + } + end + + def test_fileno + ctx = OpenSSL::SSL::SSLContext.new + sock1, sock2 = socketpair + + socket = OpenSSL::SSL::SSLSocket.new(sock1) + server = OpenSSL::SSL::SSLServer.new(sock2, ctx) + + assert_equal socket.fileno, socket.to_io.fileno + assert_equal server.fileno, server.to_io.fileno + ensure + sock1.close + sock2.close + end + + private + + def start_server_version(version, ctx_proc = nil, + server_proc = method(:readwrite_loop), &blk) + ctx_wrap = Proc.new { |ctx| + ctx.ssl_version = version + ctx_proc.call(ctx) if ctx_proc + } + start_server( + ctx_proc: ctx_wrap, + server_proc: server_proc, + ignore_listener_error: true, + &blk + ) + end + + def server_connect(port, ctx = nil) + sock = TCPSocket.new("127.0.0.1", port) + ssl = ctx ? OpenSSL::SSL::SSLSocket.new(sock, ctx) : OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + yield ssl if block_given? + ensure + if ssl + ssl.close + elsif sock + sock.close + end + end + + def assert_handshake_error + # different OpenSSL versions react differently when facing a SSL/TLS version + # that has been marked as forbidden, therefore any of these may be raised + assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::EPIPE) { + yield + } + end +end + +end diff --git a/test/openssl/test_ssl_session.rb b/test/openssl/test_ssl_session.rb new file mode 100644 index 00000000..89726d44 --- /dev/null +++ b/test/openssl/test_ssl_session.rb @@ -0,0 +1,400 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase + def test_session + pend "TLS 1.2 is not supported" unless tls12_supported? + + ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } + start_server(ctx_proc: ctx_proc) do |port| + server_connect_with_session(port, nil, nil) { |ssl| + session = ssl.session + assert(session == OpenSSL::SSL::Session.new(session.to_pem)) + assert(session == OpenSSL::SSL::Session.new(ssl)) + session.timeout = 5 + assert_equal(5, session.timeout) + assert_not_nil(session.time) + # SSL_SESSION_time keeps long value so we can't keep nsec fragment. + session.time = t1 = Time.now.to_i + assert_equal(Time.at(t1), session.time) + assert_not_nil(session.id) + pem = session.to_pem + assert_match(/\A-----BEGIN SSL SESSION PARAMETERS-----/, pem) + assert_match(/-----END SSL SESSION PARAMETERS-----\Z/, pem) + pem.gsub!(/-----(BEGIN|END) SSL SESSION PARAMETERS-----/, '').gsub!(/[\r\n]+/m, '') + assert_equal(session.to_der, pem.unpack('m*')[0]) + assert_not_nil(session.to_text) + } + end + end + + DUMMY_SESSION = <<__EOS__ +-----BEGIN SSL SESSION PARAMETERS----- +MIIDzQIBAQICAwEEAgA5BCAF219w9ZEV8dNA60cpEGOI34hJtIFbf3bkfzSgMyad +MQQwyGLbkCxE4OiMLdKKem+pyh8V7ifoP7tCxhdmwoDlJxI1v6nVCjai+FGYuncy +NNSWoQYCBE4DDWuiAwIBCqOCAo4wggKKMIIBcqADAgECAgECMA0GCSqGSIb3DQEB +BQUAMD0xEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 +LWxhbmcxCzAJBgNVBAMMAkNBMB4XDTExMDYyMzA5NTQ1MVoXDTExMDYyMzEwMjQ1 +MVowRDETMBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1Ynkt +bGFuZzESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7CxaKPERYHs +k4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/Q3geLv8Z +D9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQABoxIwEDAO +BgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBACj5WhoZ/ODVeHpwgq1d +8fW/13ICRYHYpv6dzlWihyqclGxbKMlMnaVCPz+4JaVtMz3QB748KJQgL3Llg3R1 +ek+f+n1MBCMfFFsQXJ2gtLB84zD6UCz8aaCWN5/czJCd7xMz7fRLy3TOIW5boXAU +zIa8EODk+477K1uznHm286ab0Clv+9d304hwmBZgkzLg6+31Of6d6s0E0rwLGiS2 +sOWYg34Y3r4j8BS9Ak4jzpoLY6cJ0QAKCOJCgmjGr4XHpyXMLbicp3ga1uSbwtVO +gF/gTfpLhJC+y0EQ5x3Ftl88Cq7ZJuLBDMo/TLIfReJMQu/HlrTT7+LwtneSWGmr +KkSkAgQApQMCAROqgcMEgcAuDkAVfj6QAJMz9yqTzW5wPFyty7CxUEcwKjUqj5UP +/Yvky1EkRuM/eQfN7ucY+MUvMqv+R8ZSkHPsnjkBN5ChvZXjrUSZKFVjR4eFVz2V +jismLEJvIFhQh6pqTroRrOjMfTaM5Lwoytr2FTGobN9rnjIRsXeFQW1HLFbXn7Dh +8uaQkMwIVVSGRB8T7t6z6WIdWruOjCZ6G5ASI5XoqAHwGezhLodZuvJEfsVyCF9y +j+RBGfCFrrQbBdnkFI/ztgM= +-----END SSL SESSION PARAMETERS----- +__EOS__ + + DUMMY_SESSION_NO_EXT = <<-__EOS__ +-----BEGIN SSL SESSION PARAMETERS----- +MIIDCAIBAQICAwAEAgA5BCDyAW7rcpzMjDSosH+Tv6sukymeqgq3xQVVMez628A+ +lAQw9TrKzrIqlHEh6ltuQaqv/Aq83AmaAlogYktZgXAjOGnhX7ifJDNLMuCfQq53 +hPAaoQYCBE4iDeeiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B +AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi +eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA3MTYyMjE3MTFaFw0xMTA3MTYyMjQ3 +MTFaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 +LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB +7JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ +GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw +DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQA3TRzABRG3kz8jEEYr +tDQqXgsxwTsLhTT5d1yF0D8uFw+y15hJAJnh6GJHjqhWBrF4zNoTApFo+4iIL6g3 +q9C3mUsxIVAHx41DwZBh/FI7J4FqlAoGOguu7892CNVY3ZZjc3AXMTdKjcNoWPzz +FCdj5fNT24JMMe+ZdGZK97ChahJsdn/6B3j6ze9NK9mfYEbiJhejGTPLOFVHJCGR +KYYZ3ZcKhLDr9ql4d7cCo1gBtemrmFQGPui7GttNEqmXqUKvV8mYoa8farf5i7T4 +L6a/gp2cVZTaDIS1HjbJsA/Ag7AajZqiN6LfqShNUVsrMZ+5CoV8EkBDTZPJ9MSr +a3EqpAIEAKUDAgET +-----END SSL SESSION PARAMETERS----- +__EOS__ + + + def test_session_time + sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) + sess.time = (now = Time.now) + assert_equal(now.to_i, sess.time.to_i) + sess.time = 1 + assert_equal(1, sess.time.to_i) + sess.time = 1.2345 + assert_equal(1, sess.time.to_i) + # Can OpenSSL handle t>2038y correctly? Version? + sess.time = 2**31 - 1 + assert_equal(2**31 - 1, sess.time.to_i) + end + + def test_session_timeout + sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) + assert_raise(TypeError) do + sess.timeout = Time.now + end + sess.timeout = 1 + assert_equal(1, sess.timeout.to_i) + sess.timeout = 1.2345 + assert_equal(1, sess.timeout.to_i) + sess.timeout = 2**31 - 1 + assert_equal(2**31 - 1, sess.timeout.to_i) + end + + def test_session_exts_read + assert(OpenSSL::SSL::Session.new(DUMMY_SESSION)) + end + + def test_resumption + non_resumable = nil + start_server { |port| + server_connect_with_session(port, nil, nil) { |ssl| + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + non_resumable = ssl.session + } + } + + ctx_proc = proc { |ctx| + ctx.options &= ~OpenSSL::SSL::OP_NO_TICKET + # Disable server-side session cache which is enabled by default + ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF + } + start_server(ctx_proc: ctx_proc) do |port| + sess1 = server_connect_with_session(port, nil, nil) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + ssl.session + } + + server_connect_with_session(port, nil, non_resumable) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + } + + server_connect_with_session(port, nil, sess1) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal true, ssl.session_reused? + } + end + end + + def test_server_session_cache + pend "TLS 1.2 is not supported" unless tls12_supported? + + ctx_proc = Proc.new do |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.options |= OpenSSL::SSL::OP_NO_TICKET + end + + connections = nil + saved_session = nil + server_proc = Proc.new do |ctx, ssl| + stats = ctx.session_cache_stats + + case connections + when 0 + assert_equal false, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 0, stats[:cache_hits] + assert_equal 0, stats[:cache_misses] + when 1 + assert_equal true, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 1, stats[:cache_hits] + assert_equal 0, stats[:cache_misses] + + saved_session = ssl.session + assert_equal true, ctx.session_remove(ssl.session) + when 2 + assert_equal false, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 1, stats[:cache_hits] + assert_equal 1, stats[:cache_misses] + + assert_equal true, ctx.session_add(saved_session.dup) + when 3 + assert_equal true, ssl.session_reused? + assert_equal 2, stats[:cache_num] + assert_equal 2, stats[:cache_hits] + assert_equal 1, stats[:cache_misses] + + ctx.flush_sessions(Time.now + 10000) + when 4 + assert_equal false, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 2, stats[:cache_hits] + assert_equal 2, stats[:cache_misses] + + assert_equal true, ctx.session_add(saved_session.dup) + end + + readwrite_loop(ctx, ssl) + end + + start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port| + first_session = nil + 10.times do |i| + connections = i + cctx = OpenSSL::SSL::SSLContext.new + cctx.ssl_version = :TLSv1_2 + server_connect_with_session(port, cctx, first_session) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + first_session ||= ssl.session + + case connections + when 0; + when 1; assert_equal true, ssl.session_reused? + when 2; assert_equal false, ssl.session_reused? + when 3; assert_equal true, ssl.session_reused? + when 4; assert_equal false, ssl.session_reused? + when 5..9; assert_equal true, ssl.session_reused? + end + } + end + end + end + + # Skipping tests that use session_remove_cb by default because it may cause + # deadlock. + TEST_SESSION_REMOVE_CB = ENV["OSSL_TEST_ALL"] == "1" + + def test_ctx_client_session_cb + pend "TLS 1.2 is not supported" unless tls12_supported? + + ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } + start_server(ctx_proc: ctx_proc) do |port| + called = {} + ctx = OpenSSL::SSL::SSLContext.new + ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT + ctx.session_new_cb = lambda { |ary| + sock, sess = ary + called[:new] = [sock, sess] + } + if TEST_SESSION_REMOVE_CB + ctx.session_remove_cb = lambda { |ary| + ctx, sess = ary + called[:remove] = [ctx, sess] + # any resulting value is OK (ignored) + } + end + + server_connect_with_session(port, ctx, nil) { |ssl| + assert_equal(1, ctx.session_cache_stats[:cache_num]) + assert_equal(1, ctx.session_cache_stats[:connect_good]) + assert_equal([ssl, ssl.session], called[:new]) + assert(ctx.session_remove(ssl.session)) + assert(!ctx.session_remove(ssl.session)) + if TEST_SESSION_REMOVE_CB + assert_equal([ctx, ssl.session], called[:remove]) + end + } + end + end + + def test_ctx_server_session_cb + pend "TLS 1.2 is not supported" unless tls12_supported? + + connections = nil + called = {} + cctx = OpenSSL::SSL::SSLContext.new + cctx.ssl_version = :TLSv1_2 + sctx = nil + ctx_proc = Proc.new { |ctx| + sctx = ctx + ctx.ssl_version = :TLSv1_2 + ctx.options |= OpenSSL::SSL::OP_NO_TICKET + + # get_cb is called whenever a client proposed to resume a session but + # the session could not be found in the internal session cache. + last_server_session = nil + ctx.session_get_cb = lambda { |ary| + _sess, data = ary + called[:get] = data + + if connections == 2 + last_server_session.dup + else + nil + end + } + + ctx.session_new_cb = lambda { |ary| + _sock, sess = ary + called[:new] = sess + last_server_session = sess + } + + if TEST_SESSION_REMOVE_CB + ctx.session_remove_cb = lambda { |ary| + _ctx, sess = ary + called[:remove] = sess + } + end + } + start_server(ctx_proc: ctx_proc) do |port| + connections = 0 + sess0 = server_connect_with_session(port, cctx, nil) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + ssl.session + } + assert_nil called[:get] + assert_not_nil called[:new] + assert_equal sess0.id, called[:new].id + if TEST_SESSION_REMOVE_CB + assert_nil called[:remove] + end + called.clear + + # Internal cache hit + connections = 1 + server_connect_with_session(port, cctx, sess0.dup) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal true, ssl.session_reused? + ssl.session + } + assert_nil called[:get] + assert_nil called[:new] + if TEST_SESSION_REMOVE_CB + assert_nil called[:remove] + end + called.clear + + sctx.flush_sessions(Time.now + 10000) + if TEST_SESSION_REMOVE_CB + assert_not_nil called[:remove] + assert_equal sess0.id, called[:remove].id + end + called.clear + + # External cache hit + connections = 2 + sess2 = server_connect_with_session(port, cctx, sess0.dup) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + if !ssl.session_reused? && openssl?(1, 1, 0) && !openssl?(1, 1, 0, 7) + # OpenSSL >= 1.1.0, < 1.1.0g + pend "External session cache is not working; " \ + "see https://github.com/openssl/openssl/pull/4014" + end + assert_equal true, ssl.session_reused? + ssl.session + } + assert_equal sess0.id, sess2.id + assert_equal sess0.id, called[:get] + assert_nil called[:new] + if TEST_SESSION_REMOVE_CB + assert_nil called[:remove] + end + called.clear + + sctx.flush_sessions(Time.now + 10000) + if TEST_SESSION_REMOVE_CB + assert_not_nil called[:remove] + assert_equal sess0.id, called[:remove].id + end + called.clear + + # Cache miss + connections = 3 + sess3 = server_connect_with_session(port, cctx, sess0.dup) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + ssl.session + } + assert_not_equal sess0.id, sess3.id + assert_equal sess0.id, called[:get] + assert_not_nil called[:new] + assert_equal sess3.id, called[:new].id + if TEST_SESSION_REMOVE_CB + assert_nil called[:remove] + end + end + end + + def test_dup + sess_orig = OpenSSL::SSL::Session.new(DUMMY_SESSION) + sess_dup = sess_orig.dup + assert_equal(sess_orig.to_der, sess_dup.to_der) + end + + private + + def server_connect_with_session(port, ctx = nil, sess = nil) + sock = TCPSocket.new("127.0.0.1", port) + ctx ||= OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.session = sess if sess + ssl.sync_close = true + ssl.connect + yield ssl if block_given? + ensure + ssl&.close + sock&.close + end +end + +end diff --git a/test/openssl/test_ts.rb b/test/openssl/test_ts.rb new file mode 100644 index 00000000..c57f08cf --- /dev/null +++ b/test/openssl/test_ts.rb @@ -0,0 +1,667 @@ +require_relative "utils" + +if defined?(OpenSSL) && defined?(OpenSSL::Timestamp) + +class OpenSSL::TestTimestamp < OpenSSL::TestCase + def intermediate_key + @intermediate_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCcyODxH+oTrr7l7MITWcGaYnnBma6vidCCJjuSzZpaRmXZHAyH +0YcY4ttC0BdJ4uV+cE05IySVC7tyvVfFb8gFQ6XJV+AEktP+XkLbcxZgj9d2NVu1 +ziXdI+ldXkPnMhyWpMS5E7SD6gflv9NhUYEsmAGsUgdK6LDmm2W2/4TlewIDAQAB +AoGAYgx6KDFWONLqjW3f/Sv/mGYHUNykUyDzpcD1Npyf797gqMMSzwlo3FZa2tC6 +D7n23XirwpTItvEsW9gvgMikJDPlThAeGLZ+L0UbVNNBHVxGP998Nda1kxqKvhRE +pfZCKc7PLM9ZXc6jBTmgxdcAYfVCCVUoa2mEf9Ktr3BlI4kCQQDQAM09+wHDXGKP +o2UnCwCazGtyGU2r0QCzHlh9BVY+KD2KjjhuWh86rEbdWN7hEW23Je1vXIhuM6Pa +/Ccd+XYnAkEAwPZ91PK6idEONeGQ4I3dyMKV2SbaUjfq3MDL4iIQPQPuj7QsBO/5 +3Nf9ReSUUTRFCUVwoC8k4Z1KAJhR/K/ejQJANE7PTnPuGJQGETs09+GTcFpR9uqY +FspDk8fg1ufdrVnvSAXF+TJewiGK3KU5v33jinhWQngRsyz3Wt2odKhEZwJACbjh +oicQqvzzgFd7GzVKpWDYd/ZzLY1PsgusuhoJQ2m9TVRAm4cTycLAKhNYPbcqe0sa +X5fAffWU0u7ZwqeByQJAOUAbYET4RU3iymAvAIDFj8LiQnizG9t5Ty3HXlijKQYv +y8gsvWd4CdxwOPatWpBUX9L7IXcMJmD44xXTUvpbfQ== +-----END RSA PRIVATE KEY----- +_end_of_pem_ + end + + def ee_key + @ee_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQDA6eB5r2O5KOKNbKMBhzadl43lgpwqq28m+G0gH38kKCL1f3o9 +P8xUZm7sZqcWEervZMSSXMGBV9DgeoSR+U6FMJywgQGx/JNRx7wZTMNym3PvgLkl +xCXh6ZA0/xbtJtcNI+UUv0ENBkTIuUWBhkAf3jQclAr9aQ0ktYBuHAcRcQIDAQAB +AoGAKNhcAuezwZx6e18pFEXAtpVEIfgJgK9TlXi8AjUpAkrNPBWFmDpN1QDrM3p4 +nh+lEpLPW/3vqqchPqYyM4YJraMLpS3KUG+s7+m9QIia0ri2WV5Cig7WL+Tl9p7K +b3oi2Aj/wti8GfOLFQXOQQ4Ea4GoCv2Sxe0GZR39UBxzTsECQQD1zuVIwBvqU2YR +8innsoa+j4u2hulRmQO6Zgpzj5vyRYfA9uZxQ9nKbfJvzuWwUv+UzyS9RqxarqrP +5nQw5EmVAkEAyOmJg6+AfGrgvSWfSpXEds/WA/sHziCO3rE4/sd6cnDc6XcTgeMs +mT8Z3kAYGpqFDew5orUylPfJJa+PUueJbQJAY+gkvw3+Cp69FLw1lgu0wo07fwOU +n2qu3jsNMm0DOFRUWfTAMvcd9S385L7WEnWZldUfnKK1+OGXYYrMXPbchQJAChU2 +UoaHQzc16iguM1cK0g+iJPb/MEgQA3sPajHmokGpxIm2T+lvvo0dJjs/Om6QyN8X +EWRYkoNQ8/Q4lCeMjQJAfvDIGtyqF4PieFHYgluQAv5pGgYpakdc8SYyeRH9NKey +GaL27FRs4fRWf9OmxPhUVgIyGzLGXrueemvQUDHObA== +-----END RSA PRIVATE KEY----- +_end_of_pem_ + end + + def ca_cert + @ca_cert ||= OpenSSL::Certs.ca_cert + end + + def ca_store + @ca_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(ca_cert) } + end + + def ts_cert_direct + @ts_cert_direct ||= OpenSSL::Certs.ts_cert_direct(ee_key, ca_cert) + end + + def intermediate_cert + @intermediate_cert ||= OpenSSL::Certs.intermediate_cert(intermediate_key, ca_cert) + end + + def intermediate_store + @intermediate_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(intermediate_cert) } + end + + def ts_cert_ee + @ts_cert_ee ||= OpenSSL::Certs.ts_cert_ee(ee_key, intermediate_cert, intermediate_key) + end + + def test_create_request + req = OpenSSL::Timestamp::Request.new + assert_equal(true, req.cert_requested?) + assert_equal(1, req.version) + assert_nil(req.algorithm) + assert_equal("", req.message_imprint) + assert_nil(req.policy_id) + assert_nil(req.nonce) + end + + def test_request_mandatory_fields + req = OpenSSL::Timestamp::Request.new + assert_raise(OpenSSL::Timestamp::TimestampError) do + tmp = req.to_der + pp OpenSSL::ASN1.decode(tmp) + end + req.algorithm = "sha1" + assert_raise(OpenSSL::Timestamp::TimestampError) do + req.to_der + end + req.message_imprint = OpenSSL::Digest::SHA1.new.digest("data") + req.to_der + end + + def test_request_assignment + req = OpenSSL::Timestamp::Request.new + + req.version = 2 + assert_equal(2, req.version) + assert_raise(TypeError) { req.version = nil } + assert_raise(TypeError) { req.version = "foo" } + + req.algorithm = "SHA1" + assert_equal("SHA1", req.algorithm) + assert_raise(TypeError) { req.algorithm = nil } + assert_raise(OpenSSL::ASN1::ASN1Error) { req.algorithm = "xxx" } + + req.message_imprint = "test" + assert_equal("test", req.message_imprint) + assert_raise(TypeError) { req.message_imprint = nil } + + req.policy_id = "1.2.3.4.5" + assert_equal("1.2.3.4.5", req.policy_id) + assert_raise(TypeError) { req.policy_id = 123 } + assert_raise(TypeError) { req.policy_id = nil } + + req.nonce = 42 + assert_equal(42, req.nonce) + assert_raise(TypeError) { req.nonce = "foo" } + assert_raise(TypeError) { req.nonce = nil } + + req.cert_requested = false + assert_equal(false, req.cert_requested?) + req.cert_requested = nil + assert_equal(false, req.cert_requested?) + req.cert_requested = 123 + assert_equal(true, req.cert_requested?) + req.cert_requested = "asdf" + assert_equal(true, req.cert_requested?) + end + + def test_request_serialization + req = OpenSSL::Timestamp::Request.new + + req.version = 2 + req.algorithm = "SHA1" + req.message_imprint = "test" + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + req.cert_requested = true + + req = OpenSSL::Timestamp::Request.new(req.to_der) + + assert_equal(2, req.version) + assert_equal("SHA1", req.algorithm) + assert_equal("test", req.message_imprint) + assert_equal("1.2.3.4.5", req.policy_id) + assert_equal(42, req.nonce) + assert_equal(true, req.cert_requested?) + + end + + def test_request_re_assignment + #tests whether the potential 'freeing' of previous values in C works properly + req = OpenSSL::Timestamp::Request.new + req.version = 2 + req.version = 3 + req.algorithm = "SHA1" + req.algorithm = "SHA256" + req.message_imprint = "test" + req.message_imprint = "test2" + req.policy_id = "1.2.3.4.5" + req.policy_id = "1.2.3.4.6" + req.nonce = 42 + req.nonce = 24 + req.cert_requested = false + req.cert_requested = true + req.to_der + end + + def test_request_encode_decode + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + qer = OpenSSL::Timestamp::Request.new(req.to_der) + assert_equal(1, qer.version) + assert_equal("SHA1", qer.algorithm) + assert_equal(digest, qer.message_imprint) + assert_equal("1.2.3.4.5", qer.policy_id) + assert_equal(42, qer.nonce) + + #put OpenSSL::ASN1.decode inbetween + qer2 = OpenSSL::Timestamp::Request.new(OpenSSL::ASN1.decode(req.to_der)) + assert_equal(1, qer2.version) + assert_equal("SHA1", qer2.algorithm) + assert_equal(digest, qer2.message_imprint) + assert_equal("1.2.3.4.5", qer2.policy_id) + assert_equal(42, qer2.nonce) + end + + def test_response_constants + assert_equal(0, OpenSSL::Timestamp::Response::GRANTED) + assert_equal(1, OpenSSL::Timestamp::Response::GRANTED_WITH_MODS) + assert_equal(2, OpenSSL::Timestamp::Response::REJECTION) + assert_equal(3, OpenSSL::Timestamp::Response::WAITING) + assert_equal(4, OpenSSL::Timestamp::Response::REVOCATION_WARNING) + assert_equal(5, OpenSSL::Timestamp::Response::REVOCATION_NOTIFICATION) + end + + def test_response_creation + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + + fac = OpenSSL::Timestamp::Factory.new + time = Time.now + fac.gen_time = time + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + resp = OpenSSL::Timestamp::Response.new(resp) + assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) + assert_nil(resp.failure_info) + assert_equal([], resp.status_text) + assert_equal(1, resp.token_info.version) + assert_equal("1.2.3.4.5", resp.token_info.policy_id) + assert_equal("SHA1", resp.token_info.algorithm) + assert_equal(digest, resp.token_info.message_imprint) + assert_equal(1, resp.token_info.serial_number) + assert_equal(time.to_i, resp.token_info.gen_time.to_i) + assert_equal(false, resp.token_info.ordering) + assert_nil(resp.token_info.nonce) + assert_cert(ts_cert_ee, resp.tsa_certificate) + #compare PKCS7 + token = OpenSSL::ASN1.decode(resp.to_der).value[1] + assert_equal(token.to_der, resp.token.to_der) + end + + def test_response_mandatory_fields + fac = OpenSSL::Timestamp::Factory.new + req = OpenSSL::Timestamp::Request.new + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + req.algorithm = "sha1" + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + req.message_imprint = OpenSSL::Digest::SHA1.new.digest("data") + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + fac.gen_time = Time.now + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + fac.default_policy_id = "1.2.3.4.5" + assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status + fac.default_policy_id = nil + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + req.policy_id = "1.2.3.4.5" + assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status + end + + def test_response_allowed_digests + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + req.message_imprint = OpenSSL::Digest::SHA1.digest("test") + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.default_policy_id = "1.2.3.4.6" + + # None allowed by default + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status + + # Explicitly allow SHA1 (string) + fac.allowed_digests = ["sha1"] + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status + + # Explicitly allow SHA1 (object) + fac.allowed_digests = [OpenSSL::Digest::SHA1.new] + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status + + # Others not allowed + req.algorithm = "SHA256" + req.message_imprint = OpenSSL::Digest::SHA256.digest("test") + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status + + # Non-Array + fac.allowed_digests = 123 + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status + + # Non-String, non-Digest Array element + fac.allowed_digests = ["sha1", OpenSSL::Digest::SHA1.new, 123] + assert_raise(TypeError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + end + + def test_response_default_policy + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.default_policy_id = "1.2.3.4.6" + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) + assert_equal("1.2.3.4.6", resp.token_info.policy_id) + end + + def test_response_bad_purpose + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, intermediate_cert, req) + end + end + + def test_no_cert_requested + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.cert_requested = false + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.default_policy_id = "1.2.3.4.5" + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) + assert_nil(resp.tsa_certificate) + end + + def test_response_no_policy_defined + assert_raise(OpenSSL::Timestamp::TimestampError) do + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + end + + def test_verify_ee_no_req + assert_raise(TypeError) do + ts, _ = timestamp_ee + ts.verify(nil, ca_cert) + end + end + + def test_verify_ee_no_store + assert_raise(TypeError) do + ts, req = timestamp_ee + ts.verify(req, nil) + end + end + + def test_verify_ee_wrong_root_no_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + ts.verify(req, intermediate_store) + end + end + + def test_verify_ee_wrong_root_wrong_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + ts.verify(req, intermediate_store, [ca_cert]) + end + end + + def test_verify_ee_nonce_mismatch + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + req.nonce = 1 + ts.verify(req, ca_store, [intermediate_cert]) + end + end + + def test_verify_ee_intermediate_missing + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + ts.verify(req, ca_store) + end + end + + def test_verify_ee_intermediate + ts, req = timestamp_ee + ts.verify(req, ca_store, [intermediate_cert]) + end + + def test_verify_ee_intermediate_type_error + ts, req = timestamp_ee + assert_raise(TypeError) { ts.verify(req, [ca_cert], 123) } + end + + def test_verify_ee_def_policy + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.default_policy_id = "1.2.3.4.5" + + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + ts.verify(req, ca_store, [intermediate_cert]) + end + + def test_verify_direct + ts, req = timestamp_direct + ts.verify(req, ca_store) + end + + def test_verify_direct_redundant_untrusted + ts, req = timestamp_direct + ts.verify(req, ca_store, [ts.tsa_certificate, ts.tsa_certificate]) + end + + def test_verify_direct_unrelated_untrusted + ts, req = timestamp_direct + ts.verify(req, ca_store, [intermediate_cert]) + end + + def test_verify_direct_wrong_root + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_direct + ts.verify(req, intermediate_store) + end + end + + def test_verify_direct_no_cert_no_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_direct_no_cert + ts.verify(req, ca_store) + end + end + + def test_verify_ee_no_cert + ts, req = timestamp_ee_no_cert + ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]) + end + + def test_verify_ee_no_cert_no_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee_no_cert + ts.verify(req, ca_store, [ts_cert_ee]) + end + end + + def test_verify_ee_additional_certs_array + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.additional_certs = [intermediate_cert] + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(2, ts.token.certificates.size) + fac.additional_certs = nil + ts.verify(req, ca_store) + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(1, ts.token.certificates.size) + end + + def test_verify_ee_additional_certs_with_root + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.additional_certs = [intermediate_cert, ca_cert] + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(3, ts.token.certificates.size) + ts.verify(req, ca_store) + end + + def test_verify_ee_cert_inclusion_not_requested + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.nonce = 42 + req.cert_requested = false + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + #needed because the Request contained no policy identifier + fac.default_policy_id = '1.2.3.4.5' + fac.additional_certs = [ ts_cert_ee, intermediate_cert ] + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_nil(ts.token.certificates) #since cert_requested? == false + ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]) + end + + def test_reusable + #test if req and faq are reusable, i.e. the internal + #CTX_free methods don't mess up e.g. the certificates + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.additional_certs = [ intermediate_cert ] + ts1 = fac.create_timestamp(ee_key, ts_cert_ee, req) + ts1.verify(req, ca_store) + ts2 = fac.create_timestamp(ee_key, ts_cert_ee, req) + ts2.verify(req, ca_store) + refute_nil(ts1.tsa_certificate) + refute_nil(ts2.tsa_certificate) + end + + def test_token_info_creation + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = OpenSSL::BN.new(123) + + fac = OpenSSL::Timestamp::Factory.new + time = Time.now + fac.gen_time = time + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + info = resp.token_info + info = OpenSSL::Timestamp::TokenInfo.new(info.to_der) + + assert_equal(1, info.version) + assert_equal("1.2.3.4.5", info.policy_id) + assert_equal("SHA1", info.algorithm) + assert_equal(digest, info.message_imprint) + assert_equal(1, info.serial_number) + assert_equal(time.to_i, info.gen_time.to_i) + assert_equal(false, info.ordering) + assert_equal(123, info.nonce) + end + + private + + def assert_cert expected, actual + assert_equal expected.to_der, actual.to_der + end + + def timestamp_ee + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_ee, req), req + end + + def timestamp_ee_no_cert + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + req.cert_requested = false + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_ee, req), req + end + + def timestamp_direct + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_direct, req), req + end + + def timestamp_direct_no_cert + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + req.cert_requested = false + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_direct, req), req + end +end + +end diff --git a/test/openssl/test_x509attr.rb b/test/openssl/test_x509attr.rb new file mode 100644 index 00000000..2919d23d --- /dev/null +++ b/test/openssl/test_x509attr.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestX509Attribute < OpenSSL::TestCase + def test_new + ef = OpenSSL::X509::ExtensionFactory.new + val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ + ef.create_extension("keyUsage", "keyCertSign", true) + ])]) + attr = OpenSSL::X509::Attribute.new("extReq", val) + assert_equal("extReq", attr.oid) + assert_equal(val.to_der, attr.value.to_der) + + attr = OpenSSL::X509::Attribute.new("1.2.840.113549.1.9.14", val) + assert_equal("extReq", attr.oid) + end + + def test_from_der + # oid: challengePassword, values: Set[UTF8String<"abc123">] + test_der = "\x30\x15\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x07\x31\x08" \ + "\x0c\x06\x61\x62\x63\x31\x32\x33".b + attr = OpenSSL::X509::Attribute.new(test_der) + assert_equal(test_der, attr.to_der) + assert_equal("challengePassword", attr.oid) + assert_equal("abc123", attr.value.value[0].value) + end + + def test_to_der + ef = OpenSSL::X509::ExtensionFactory.new + val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ + ef.create_extension("keyUsage", "keyCertSign", true) + ])]) + attr = OpenSSL::X509::Attribute.new("extReq", val) + expected = OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::ObjectId.new("extReq"), + val + ]) + assert_equal(expected.to_der, attr.to_der) + end + + def test_invalid_value + # should not change the original value + test_der = "\x30\x15\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x07\x31\x08" \ + "\x0c\x06\x61\x62\x63\x31\x32\x33".b + attr = OpenSSL::X509::Attribute.new(test_der) + assert_raise(TypeError) { + attr.value = "1234" + } + assert_equal(test_der, attr.to_der) + assert_raise(OpenSSL::X509::AttributeError) { + attr.oid = "abc123" + } + assert_equal(test_der, attr.to_der) + end + + def test_dup + val = OpenSSL::ASN1::Set([ + OpenSSL::ASN1::UTF8String("abc123") + ]) + attr = OpenSSL::X509::Attribute.new("challengePassword", val) + assert_equal(attr.to_der, attr.dup.to_der) + end + + def test_eq + val1 = OpenSSL::ASN1::Set([ + OpenSSL::ASN1::UTF8String("abc123") + ]) + attr1 = OpenSSL::X509::Attribute.new("challengePassword", val1) + attr2 = OpenSSL::X509::Attribute.new("challengePassword", val1) + ef = OpenSSL::X509::ExtensionFactory.new + val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ + ef.create_extension("keyUsage", "keyCertSign", true) + ])]) + attr3 = OpenSSL::X509::Attribute.new("extReq", val2) + + assert_equal false, attr1 == 12345 + assert_equal true, attr1 == attr2 + assert_equal false, attr1 == attr3 + end + + def test_marshal + val = OpenSSL::ASN1::Set([ + OpenSSL::ASN1::UTF8String("abc123") + ]) + attr = OpenSSL::X509::Attribute.new("challengePassword", val) + deserialized = Marshal.load(Marshal.dump(attr)) + + assert_equal attr.to_der, deserialized.to_der + end +end + +end diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb new file mode 100644 index 00000000..ed0758a6 --- /dev/null +++ b/test/openssl/test_x509cert.rb @@ -0,0 +1,288 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestX509Certificate < OpenSSL::TestCase + def setup + super + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") + end + + def test_serial + [1, 2**32, 2**100].each{|s| + cert = issue_cert(@ca, @rsa2048, s, [], nil, nil) + assert_equal(s, cert.serial) + cert = OpenSSL::X509::Certificate.new(cert.to_der) + assert_equal(s, cert.serial) + } + end + + def test_public_key + exts = [ + ["basicConstraints","CA:TRUE",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + + [ + @rsa1024, @rsa2048, @dsa256, @dsa512, + ].each{|pk| + cert = issue_cert(@ca, pk, 1, exts, nil, nil) + assert_equal(cert.extensions.sort_by(&:to_s)[2].value, + OpenSSL::TestUtils.get_subject_key_id(cert)) + cert = OpenSSL::X509::Certificate.new(cert.to_der) + assert_equal(cert.extensions.sort_by(&:to_s)[2].value, + OpenSSL::TestUtils.get_subject_key_id(cert)) + } + end + + def test_validity + now = Time.at(Time.now.to_i + 0.9) + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, + not_before: now, not_after: now+3600) + assert_equal(Time.at(now.to_i), cert.not_before) + assert_equal(Time.at(now.to_i+3600), cert.not_after) + + now = Time.at(now.to_i) + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, + not_before: now, not_after: now+3600) + assert_equal(now.getutc, cert.not_before) + assert_equal((now+3600).getutc, cert.not_after) + + now = Time.at(0) + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, + not_before: now, not_after: now) + assert_equal(now.getutc, cert.not_before) + assert_equal(now.getutc, cert.not_after) + + now = Time.at(0x7fffffff) + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, + not_before: now, not_after: now) + assert_equal(now.getutc, cert.not_before) + assert_equal(now.getutc, cert.not_after) + end + + def test_extension + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","issuer:always,keyid:always",false], + ] + ca_cert = issue_cert(@ca, @rsa2048, 1, ca_exts, nil, nil) + keyid = get_subject_key_id(ca_cert.to_der, hex: false) + assert_equal keyid, ca_cert.authority_key_identifier + assert_equal keyid, ca_cert.subject_key_identifier + ca_cert.extensions.each_with_index{|ext, i| + assert_equal(ca_exts[i].first, ext.oid) + assert_equal(ca_exts[i].last, ext.critical?) + } + + ee1_exts = [ + ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","issuer:always,keyid:always",false], + ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], + ["subjectAltName","email:ee1@ruby-lang.org",false], + ["authorityInfoAccess","caIssuers;URI:http://www.example.com/caIssuers,OCSP;URI:http://www.example.com/ocsp",false], + ] + ee1_cert = issue_cert(@ee1, @rsa1024, 2, ee1_exts, ca_cert, @rsa2048) + assert_equal(ca_cert.subject.to_der, ee1_cert.issuer.to_der) + ee1_cert.extensions.each_with_index{|ext, i| + assert_equal(ee1_exts[i].first, ext.oid) + assert_equal(ee1_exts[i].last, ext.critical?) + } + assert_nil(ee1_cert.crl_uris) + + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(<<~_cnf_) + [crlDistPts] + URI.1 = http://www.example.com/crl + URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary + _cnf_ + cdp_cert = generate_cert(@ee1, @rsa1024, 3, ca_cert) + ef.subject_certificate = cdp_cert + cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "@crlDistPts")) + cdp_cert.sign(@rsa2048, "sha256") + assert_equal( + ["http://www.example.com/crl", "ldap://ldap.example.com/cn=ca?certificateRevocationList;binary"], + cdp_cert.crl_uris + ) + + ef = OpenSSL::X509::ExtensionFactory.new + aia_cert = generate_cert(@ee1, @rsa1024, 4, ca_cert) + ef.subject_certificate = aia_cert + aia_cert.add_extension( + ef.create_extension( + "authorityInfoAccess", + "caIssuers;URI:http://www.example.com/caIssuers," \ + "caIssuers;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary," \ + "OCSP;URI:http://www.example.com/ocsp," \ + "OCSP;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary", + false + ) + ) + aia_cert.sign(@rsa2048, "sha256") + assert_equal( + ["http://www.example.com/caIssuers", "ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary"], + aia_cert.ca_issuer_uris + ) + assert_equal( + ["http://www.example.com/ocsp", "ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary"], + aia_cert.ocsp_uris + ) + + no_exts_cert = issue_cert(@ca, @rsa2048, 5, [], nil, nil) + assert_equal nil, no_exts_cert.authority_key_identifier + assert_equal nil, no_exts_cert.subject_key_identifier + assert_equal nil, no_exts_cert.crl_uris + assert_equal nil, no_exts_cert.ca_issuer_uris + assert_equal nil, no_exts_cert.ocsp_uris + end + + def test_invalid_extension + integer = OpenSSL::ASN1::Integer.new(0) + invalid_exts_cert = generate_cert(@ee1, @rsa1024, 1, nil) + ["subjectKeyIdentifier", "authorityKeyIdentifier", "crlDistributionPoints", "authorityInfoAccess"].each do |ext| + invalid_exts_cert.add_extension( + OpenSSL::X509::Extension.new(ext, integer.to_der) + ) + end + + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.authority_key_identifier + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.subject_key_identifier + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.crl_uris + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.ca_issuer_uris + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.ocsp_uris + } + end + + def test_sign_and_verify_rsa_sha1 + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "sha1") + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(true, cert.verify(@rsa2048)) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) + cert.serial = 2 + assert_equal(false, cert.verify(@rsa2048)) + end + + def test_sign_and_verify_rsa_md5 + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "md5") + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(true, cert.verify(@rsa2048)) + + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) + cert.subject = @ee1 + assert_equal(false, cert.verify(@rsa2048)) + rescue OpenSSL::X509::CertificateError # RHEL7 disables MD5 + end + + def test_sign_and_verify_dsa + cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) + assert_equal(false, certificate_error_returns_false { cert.verify(@rsa1024) }) + assert_equal(false, certificate_error_returns_false { cert.verify(@rsa2048) }) + assert_equal(false, cert.verify(@dsa256)) + assert_equal(true, cert.verify(@dsa512)) + cert.not_after = Time.now + assert_equal(false, cert.verify(@dsa512)) + end + + def test_sign_and_verify_rsa_dss1 + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: OpenSSL::Digest::DSS1.new) + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(true, cert.verify(@rsa2048)) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) + cert.subject = @ee1 + assert_equal(false, cert.verify(@rsa2048)) + rescue OpenSSL::X509::CertificateError + end if defined?(OpenSSL::Digest::DSS1) + + def test_sign_and_verify_dsa_md5 + assert_raise(OpenSSL::X509::CertificateError){ + issue_cert(@ca, @dsa512, 1, [], nil, nil, digest: "md5") + } + end + + def test_dsa_with_sha2 + cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha256") + assert_equal("dsa_with_SHA256", cert.signature_algorithm) + # TODO: need more tests for dsa + sha2 + + # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) + cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1") + assert_equal("dsaWithSHA1", cert.signature_algorithm) + end + + def test_check_private_key + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + assert_equal(true, cert.check_private_key(@rsa2048)) + end + + def test_read_from_file + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + Tempfile.create("cert") { |f| + f << cert.to_pem + f.rewind + assert_equal cert.to_der, OpenSSL::X509::Certificate.new(f).to_der + } + end + + def test_eq + now = Time.now + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil, + not_before: now, not_after: now + 3600) + cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + digest: "sha512", not_before: now, not_after: now + 3600) + + assert_equal false, cert1 == 12345 + assert_equal true, cert1 == cert2 + assert_equal false, cert1 == cert3 + assert_equal false, cert1 == cert4 + assert_equal false, cert3 == cert4 + end + + def test_marshal + now = Time.now + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil, + not_before: now, not_after: now + 3600) + cert = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + deserialized = Marshal.load(Marshal.dump(cert)) + + assert_equal cert.to_der, deserialized.to_der + end + + private + + def certificate_error_returns_false + yield + rescue OpenSSL::X509::CertificateError + false + end +end + +end diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb new file mode 100644 index 00000000..a6d0adc5 --- /dev/null +++ b/test/openssl/test_x509crl.rb @@ -0,0 +1,284 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestX509CRL < OpenSSL::TestCase + def setup + super + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") + @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") + end + + def test_basic + now = Time.at(Time.now.to_i) + + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl([], 1, now, now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_equal(1, crl.version) + assert_equal(cert.issuer.to_der, crl.issuer.to_der) + assert_equal(now, crl.last_update) + assert_equal(now+1600, crl.next_update) + + crl = OpenSSL::X509::CRL.new(crl.to_der) + assert_equal(1, crl.version) + assert_equal(cert.issuer.to_der, crl.issuer.to_der) + assert_equal(now, crl.last_update) + assert_equal(now+1600, crl.next_update) + end + + def test_revoked + + # CRLReason ::= ENUMERATED { + # unspecified (0), + # keyCompromise (1), + # cACompromise (2), + # affiliationChanged (3), + # superseded (4), + # cessationOfOperation (5), + # certificateHold (6), + # removeFromCRL (8), + # privilegeWithdrawn (9), + # aACompromise (10) } + + now = Time.at(Time.now.to_i) + revoke_info = [ + [1, Time.at(0), 1], + [2, Time.at(0x7fffffff), 2], + [3, now, 3], + [4, now, 4], + [5, now, 5], + ] + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoked = crl.revoked + assert_equal(5, revoked.size) + assert_equal(1, revoked[0].serial) + assert_equal(2, revoked[1].serial) + assert_equal(3, revoked[2].serial) + assert_equal(4, revoked[3].serial) + assert_equal(5, revoked[4].serial) + + assert_equal(Time.at(0), revoked[0].time) + assert_equal(Time.at(0x7fffffff), revoked[1].time) + assert_equal(now, revoked[2].time) + assert_equal(now, revoked[3].time) + assert_equal(now, revoked[4].time) + + assert_equal("CRLReason", revoked[0].extensions[0].oid) + assert_equal("CRLReason", revoked[1].extensions[0].oid) + assert_equal("CRLReason", revoked[2].extensions[0].oid) + assert_equal("CRLReason", revoked[3].extensions[0].oid) + assert_equal("CRLReason", revoked[4].extensions[0].oid) + + assert_equal("Key Compromise", revoked[0].extensions[0].value) + assert_equal("CA Compromise", revoked[1].extensions[0].value) + assert_equal("Affiliation Changed", revoked[2].extensions[0].value) + assert_equal("Superseded", revoked[3].extensions[0].value) + assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) + + assert_equal(false, revoked[0].extensions[0].critical?) + assert_equal(false, revoked[1].extensions[0].critical?) + assert_equal(false, revoked[2].extensions[0].critical?) + assert_equal(false, revoked[3].extensions[0].critical?) + assert_equal(false, revoked[4].extensions[0].critical?) + + assert_equal("Key Compromise", revoked[0].extensions[0].value) + assert_equal("CA Compromise", revoked[1].extensions[0].value) + assert_equal("Affiliation Changed", revoked[2].extensions[0].value) + assert_equal("Superseded", revoked[3].extensions[0].value) + assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) + + revoke_info = (1..1000).collect{|i| [i, now, 0] } + crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoked = crl.revoked + assert_equal(1000, revoked.size) + assert_equal(1, revoked[0].serial) + assert_equal(1000, revoked[999].serial) + + crl.revoked = revoked + revoked2 = crl.revoked + assert_equal(revoked.map(&:serial), revoked2.map(&:serial)) + end + + def test_extension + cert_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["subjectKeyIdentifier", "hash", false], + ["authorityKeyIdentifier", "keyid:always", false], + ["subjectAltName", "email:xyzzy@ruby-lang.org", false], + ["keyUsage", "cRLSign, keyCertSign", true], + ] + crl_exts = [ + ["authorityKeyIdentifier", "issuer:always,keyid:always", false], + ["issuerAltName", "issuer:copy", false], + ] + + cert = issue_cert(@ca, @rsa2048, 1, cert_exts, nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts, + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + exts = crl.extensions + assert_equal(3, exts.size) + assert_equal("1", exts[0].value) + assert_equal("crlNumber", exts[0].oid) + assert_equal(false, exts[0].critical?) + + expected_keyid = OpenSSL::TestUtils.get_subject_key_id(cert, hex: false) + assert_equal expected_keyid, crl.authority_key_identifier + + assert_equal("authorityKeyIdentifier", exts[1].oid) + keyid = OpenSSL::TestUtils.get_subject_key_id(cert) + assert_match(/^keyid:#{keyid}/, exts[1].value) + assert_equal(false, exts[1].critical?) + + assert_equal("issuerAltName", exts[2].oid) + assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) + assert_equal(false, exts[2].critical?) + + crl = OpenSSL::X509::CRL.new(crl.to_der) + exts = crl.extensions + assert_equal(3, exts.size) + assert_equal("1", exts[0].value) + assert_equal("crlNumber", exts[0].oid) + assert_equal(false, exts[0].critical?) + + assert_equal("authorityKeyIdentifier", exts[1].oid) + keyid = OpenSSL::TestUtils.get_subject_key_id(cert) + assert_match(/^keyid:#{keyid}/, exts[1].value) + assert_equal(false, exts[1].critical?) + + assert_equal("issuerAltName", exts[2].oid) + assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) + assert_equal(false, exts[2].critical?) + + no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_equal nil, no_ext_crl.authority_key_identifier + end + + def test_crlnumber + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_match(1.to_s, crl.extensions[0].value) + assert_match(/X509v3 CRL Number:\s+#{1}/m, crl.to_text) + + crl = issue_crl([], 2**32, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_match((2**32).to_s, crl.extensions[0].value) + assert_match(/X509v3 CRL Number:\s+#{2**32}/m, crl.to_text) + + crl = issue_crl([], 2**100, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text) + assert_match((2**100).to_s, crl.extensions[0].value) + end + + def test_sign_and_verify + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_equal(false, crl.verify(@rsa1024)) + assert_equal(true, crl.verify(@rsa2048)) + assert_equal(false, crl_error_returns_false { crl.verify(@dsa256) }) + assert_equal(false, crl_error_returns_false { crl.verify(@dsa512) }) + crl.version = 0 + assert_equal(false, crl.verify(@rsa2048)) + + cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @dsa512, OpenSSL::Digest::SHA1.new) + assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) }) + assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) }) + assert_equal(false, crl.verify(@dsa256)) + assert_equal(true, crl.verify(@dsa512)) + crl.version = 0 + assert_equal(false, crl.verify(@dsa512)) + end + + def test_revoked_to_der + # revokedCertificates SEQUENCE OF SEQUENCE { + # userCertificate CertificateSerialNumber, + # revocationDate Time, + # crlEntryExtensions Extensions OPTIONAL + # -- if present, version MUST be v2 + # } OPTIONAL, + + now = Time.utc(2000, 1, 1) + rev1 = OpenSSL::X509::Revoked.new + rev1.serial = 123 + rev1.time = now + ext = OpenSSL::X509::Extension.new("CRLReason", OpenSSL::ASN1::Enumerated(1)) + rev1.extensions = [ext] + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(123), + OpenSSL::ASN1::UTCTime(now), + OpenSSL::ASN1::Sequence([ext.to_der]) + ]) + + assert_equal asn1.to_der, rev1.to_der + end + + def test_eq + now = Time.now + + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil) + crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256") + rev1 = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 1 + rev.time = now + } + crl1.add_revoked(rev1) + crl2 = OpenSSL::X509::CRL.new(crl1.to_der) + + # CRL + assert_equal false, crl1 == 12345 + assert_equal true, crl1 == crl2 + rev2 = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 2 + rev.time = now + } + crl2.add_revoked(rev2) + assert_equal false, crl1 == crl2 + + # Revoked + assert_equal false, rev1 == 12345 + assert_equal true, rev1 == crl2.revoked[0] + assert_equal false, rev1 == crl2.revoked[1] + assert_equal true, rev2 == crl2.revoked[1] + end + + def test_marshal + now = Time.now + + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil) + crl = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256") + rev = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 1 + rev.time = now + } + crl.add_revoked(rev) + deserialized = Marshal.load(Marshal.dump(crl)) + + assert_equal crl.to_der, deserialized.to_der + assert_equal crl.revoked[0].to_der, deserialized.revoked[0].to_der + end + + private + + def crl_error_returns_false + yield + rescue OpenSSL::X509::CRLError + false + end +end + +end diff --git a/test/openssl/test_x509ext.rb b/test/openssl/test_x509ext.rb new file mode 100644 index 00000000..7ad010d1 --- /dev/null +++ b/test/openssl/test_x509ext.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestX509Extension < OpenSSL::TestCase + def setup + super + @basic_constraints_value = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Boolean(true), # CA + OpenSSL::ASN1::Integer(2) # pathlen + ]) + @basic_constraints = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId("basicConstraints"), + OpenSSL::ASN1::Boolean(true), + OpenSSL::ASN1::OctetString(@basic_constraints_value.to_der), + ]) + end + + def test_new + ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + assert_equal("basicConstraints", ext.oid) + assert_equal(true, ext.critical?) + assert_equal("CA:TRUE, pathlen:2", ext.value) + + ext = OpenSSL::X509::Extension.new("2.5.29.19", + @basic_constraints_value.to_der, true) + assert_equal(@basic_constraints.to_der, ext.to_der) + end + + def test_create_by_factory + ef = OpenSSL::X509::ExtensionFactory.new + + bc = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + assert_equal(@basic_constraints.to_der, bc.to_der) + + bc = ef.create_extension("basicConstraints", "CA:TRUE, pathlen:2", true) + assert_equal(@basic_constraints.to_der, bc.to_der) + + ef.config = OpenSSL::Config.parse(<<-_end_of_cnf_) + [crlDistPts] + URI.1 = http://www.example.com/crl + URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary + + [certPolicies] + policyIdentifier = 2.23.140.1.2.1 + CPS.1 = http://cps.example.com + _end_of_cnf_ + + cdp = ef.create_extension("crlDistributionPoints", "@crlDistPts") + assert_equal(false, cdp.critical?) + assert_equal("crlDistributionPoints", cdp.oid) + assert_match(%{URI:http://www\.example\.com/crl}, cdp.value) + assert_match( + %r{URI:ldap://ldap\.example\.com/cn=ca\?certificateRevocationList;binary}, + cdp.value) + + cdp = ef.create_extension("crlDistributionPoints", "critical, @crlDistPts") + assert_equal(true, cdp.critical?) + assert_equal("crlDistributionPoints", cdp.oid) + assert_match(%{URI:http://www.example.com/crl}, cdp.value) + assert_match( + %r{URI:ldap://ldap.example.com/cn=ca\?certificateRevocationList;binary}, + cdp.value) + + cp = ef.create_extension("certificatePolicies", "@certPolicies") + assert_equal(false, cp.critical?) + assert_equal("certificatePolicies", cp.oid) + assert_match(%r{2.23.140.1.2.1}, cp.value) + assert_match(%r{http://cps.example.com}, cp.value) + end + + def test_dup + ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + assert_equal(@basic_constraints.to_der, ext.to_der) + assert_equal(ext.to_der, ext.dup.to_der) + end + + def test_eq + ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + ef = OpenSSL::X509::ExtensionFactory.new + ext2 = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + ext3 = ef.create_extension("basicConstraints", "critical, CA:TRUE") + + assert_equal false, ext1 == 12345 + assert_equal true, ext1 == ext2 + assert_equal false, ext1 == ext3 + end + + def test_marshal + ef = OpenSSL::X509::ExtensionFactory.new + ext = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + deserialized = Marshal.load(Marshal.dump(ext)) + + assert_equal ext.to_der, deserialized.to_der + end + + def test_value_der + ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + assert_equal @basic_constraints_value.to_der, ext.value_der + end +end + +end diff --git a/test/openssl/test_x509name.rb b/test/openssl/test_x509name.rb new file mode 100644 index 00000000..4ec5db20 --- /dev/null +++ b/test/openssl/test_x509name.rb @@ -0,0 +1,469 @@ +# coding: ASCII-8BIT +# frozen_string_literal: true +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestX509Name < OpenSSL::TestCase + def setup + super + @obj_type_tmpl = Hash.new(OpenSSL::ASN1::PRINTABLESTRING) + @obj_type_tmpl.update(OpenSSL::X509::Name::OBJECT_TYPE_TEMPLATE) + end + + def test_s_new + dn = [ ["C", "JP"], ["O", "example"], ["CN", "www.example.jp"] ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal("C", ary[0][0]) + assert_equal("O", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("JP", ary[0][1]) + assert_equal("example", ary[1][1]) + assert_equal("www.example.jp", ary[2][1]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + + dn = [ + ["countryName", "JP"], + ["organizationName", "example"], + ["commonName", "www.example.jp"] + ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal("C", ary[0][0]) + assert_equal("O", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("JP", ary[0][1]) + assert_equal("example", ary[1][1]) + assert_equal("www.example.jp", ary[2][1]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + + name = OpenSSL::X509::Name.new(dn, @obj_type_tmpl) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + + dn = [ + ["countryName", "JP", OpenSSL::ASN1::PRINTABLESTRING], + ["organizationName", "example", OpenSSL::ASN1::PRINTABLESTRING], + ["commonName", "www.example.jp", OpenSSL::ASN1::PRINTABLESTRING] + ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ["serialNumber", "123"], + ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) + assert_equal("DC", ary[0][0]) + assert_equal("DC", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("emailAddress", ary[3][0]) + assert_equal("serialNumber", ary[4][0]) + assert_equal("org", ary[0][1]) + assert_equal("ruby-lang", ary[1][1]) + assert_equal("GOTOU Yuuzou", ary[2][1]) + assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) + assert_equal("123", ary[4][1]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) + + name_from_der = OpenSSL::X509::Name.new(name.to_der) + assert_equal(name_from_der.to_s, name.to_s) + assert_equal(name_from_der.to_a, name.to_a) + assert_equal(name_from_der.to_der, name.to_der) + end + + def test_unrecognized_oid + dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.1", "Unknown OID 1"], + ["1.1.2.3.5.8.13.21.34", "Unknown OID 2"], + ["C", "US"], + ["postalCode", "60602"], + ["ST", "Illinois"], + ["L", "Chicago"], + #["street", "123 Fake St"], + ["O", "Some Company LLC"], + ["CN", "mydomain.com"] ] + + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + #assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/street=123 Fake St/O=Some Company LLC/CN=mydomain.com", name.to_s) + assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/O=Some Company LLC/CN=mydomain.com", name.to_s) + assert_equal("1.2.3.4.5.6.7.8.9.7.5.3.1", ary[0][0]) + assert_equal("1.1.2.3.5.8.13.21.34", ary[1][0]) + assert_equal("C", ary[2][0]) + assert_equal("postalCode", ary[3][0]) + assert_equal("ST", ary[4][0]) + assert_equal("L", ary[5][0]) + #assert_equal("street", ary[6][0]) + assert_equal("O", ary[6][0]) + assert_equal("CN", ary[7][0]) + assert_equal("Unknown OID 1", ary[0][1]) + assert_equal("Unknown OID 2", ary[1][1]) + assert_equal("US", ary[2][1]) + assert_equal("60602", ary[3][1]) + assert_equal("Illinois", ary[4][1]) + assert_equal("Chicago", ary[5][1]) + #assert_equal("123 Fake St", ary[6][1]) + assert_equal("Some Company LLC", ary[6][1]) + assert_equal("mydomain.com", ary[7][1]) + end + + def test_unrecognized_oid_parse_encode_equality + dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.2", "Unknown OID1"], + ["1.1.2.3.5.8.13.21.35", "Unknown OID2"], + ["C", "US"], + ["postalCode", "60602"], + ["ST", "Illinois"], + ["L", "Chicago"], + #["street", "123 Fake St"], + ["O", "Some Company LLC"], + ["CN", "mydomain.com"] ] + + name1 = OpenSSL::X509::Name.new(dn) + name2 = OpenSSL::X509::Name.parse(name1.to_s) + assert_equal(name1.to_s, name2.to_s) + assert_equal(name1.to_a, name2.to_a) + end + + def test_s_parse + dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org/1.2.3.4.5.6=A=BCD" + name = OpenSSL::X509::Name.parse(dn) + assert_equal(dn, name.to_s) + ary = name.to_a + assert_equal [ + ["DC", "org", OpenSSL::ASN1::IA5STRING], + ["DC", "ruby-lang", OpenSSL::ASN1::IA5STRING], + ["CN", "www.ruby-lang.org", OpenSSL::ASN1::UTF8STRING], + ["1.2.3.4.5.6", "A=BCD", OpenSSL::ASN1::UTF8STRING], + ], ary + + dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org, 1.2.3.4.5.6=A=BCD" + name = OpenSSL::X509::Name.parse(dn2) + assert_equal(dn, name.to_s) + assert_equal ary, name.to_a + + name = OpenSSL::X509::Name.parse(dn2, @obj_type_tmpl) + ary = name.to_a + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[3][2]) + end + + def test_s_parse_rfc2253 + scanner = OpenSSL::X509::Name::RFC2253DN.method(:scan) + + assert_equal([["C", "JP"]], scanner.call("C=JP")) + assert_equal([ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ], + scanner.call( + "emailAddress=gotoyuzo@ruby-lang.org,CN=GOTOU Yuuzou,"+ + "DC=ruby-lang,DC=org") + ) + + u8 = OpenSSL::ASN1::UTF8STRING + assert_equal([ + ["DC", "org"], + ["DC", "ruby-lang"], + ["O", ",=+<>#;"], + ["O", ",=+<>#;"], + ["OU", ""], + ["OU", ""], + ["L", "aaa=\"bbb, ccc\""], + ["L", "aaa=\"bbb, ccc\""], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265", u8], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], + ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], + ["1.2.840.113549.1.9.1", "gotoyuzo@ruby-lang.org"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ], + scanner.call( + "emailAddress=gotoyuzo@ruby-lang.org," + + "1.2.840.113549.1.9.1=gotoyuzo@ruby-lang.org," + + 'CN=GOTOU \"gotoyuzo\" Yuuzou,' + + 'CN="GOTOU \"gotoyuzo\" Yuuzou",' + + '2.5.4.3=GOTOU\,\20Yuuzou,' + + '2.5.4.3=GOTOU\, Yuuzou,' + + '2.5.4.3="GOTOU, Yuuzou",' + + '2.5.4.3="GOTOU\, Yuuzou",' + + "CN=#0C0CE5BE8CE897A4E8A395E894B5," + + 'CN=\E5\BE\8C\E8\97\A4\E8\A3\95\E8\94\B5,' + + "CN=\"\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5\"," + + "CN=\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5," + + 'L=aaa\=\"bbb\, ccc\",' + + 'L="aaa=\"bbb, ccc\"",' + + 'OU=,' + + 'OU="",' + + 'O=\,\=\+\<\>\#\;,' + + 'O=",=+<>#;",' + + "DC=ruby-lang," + + "DC=org") + ) + + [ + "DC=org+DC=jp", + "DC=org,DC=ruby-lang+DC=rubyist,DC=www" + ].each{|dn| + ex = scanner.call(dn) rescue $! + dn_r = Regexp.escape(dn) + assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message) + } + + [ + ["DC=org,DC=exapmle,CN", "CN"], + ["DC=org,DC=example,", ""], + ["DC=org,DC=exapmle,CN=www.example.org;", "CN=www.example.org;"], + ["DC=org,DC=exapmle,CN=#www.example.org", "CN=#www.example.org"], + ["DC=org,DC=exapmle,CN=#777777.example.org", "CN=#777777.example.org"], + ["DC=org,DC=exapmle,CN=\"www.example\".org", "CN=\"www.example\".org"], + ["DC=org,DC=exapmle,CN=www.\"example.org\"", "CN=www.\"example.org\""], + ["DC=org,DC=exapmle,CN=www.\"example\".org", "CN=www.\"example\".org"], + ].each{|dn, msg| + ex = scanner.call(dn) rescue $! + assert_match(/^malformed RDN: .*=>#{Regexp.escape(msg)}/, ex.message) + } + + dn = "CN=www.ruby-lang.org,DC=ruby-lang,DC=org" + name = OpenSSL::X509::Name.parse_rfc2253(dn) + assert_equal(dn, name.to_s(OpenSSL::X509::Name::RFC2253)) + ary = name.to_a + assert_equal("DC", ary[0][0]) + assert_equal("DC", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("org", ary[0][1]) + assert_equal("ruby-lang", ary[1][1]) + assert_equal("www.ruby-lang.org", ary[2][1]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + end + + def test_add_entry + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ["serialNumber", "123"], + ] + name = OpenSSL::X509::Name.new + dn.each{|attr| name.add_entry(*attr) } + ary = name.to_a + assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) + assert_equal("DC", ary[0][0]) + assert_equal("DC", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("emailAddress", ary[3][0]) + assert_equal("serialNumber", ary[4][0]) + assert_equal("org", ary[0][1]) + assert_equal("ruby-lang", ary[1][1]) + assert_equal("GOTOU Yuuzou", ary[2][1]) + assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) + assert_equal("123", ary[4][1]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) + end + + def test_add_entry_street + # openssl/crypto/objects/obj_mac.h 1.83 + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ["serialNumber", "123"], + ["street", "Namiki"], + ] + name = OpenSSL::X509::Name.new + dn.each{|attr| name.add_entry(*attr) } + ary = name.to_a + assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123/street=Namiki", name.to_s) + assert_equal("Namiki", ary[5][1]) + end + + def test_add_entry_placing + der = %w{ 30 2A + 31 12 + 30 10 06 03 55 04 0A 0C 09 72 75 62 79 2D 6C 61 6E 67 + 31 14 + 30 08 06 03 55 04 0B 0C 01 61 + 30 08 06 03 55 04 0B 0C 01 62 } + orig = OpenSSL::X509::Name.new([der.join].pack("H*")) + assert_equal("OU=b+OU=a,O=ruby-lang", orig.to_s(OpenSSL::X509::Name::RFC2253)) + # Skip for now; they do not work + # + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 0, set: 0) + # assert_equal("OU=b+OU=a,O=ruby-lang,CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 0, set: 1) + # assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: 1, set: -1) + assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 1, set: 0) + # assert_equal("OU=b+OU=a,CN=unya,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: 1, set: 1) + assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: -1, set: -1) + assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: -1, set: 0) + assert_equal("CN=unya,OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + end + + def test_to_s + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "フー, バー"], + ] + name = OpenSSL::X509::Name.new + dn.each { |x| name.add_entry(*x) } + + assert_equal "/DC=org/DC=ruby-lang/" \ + "CN=\\xE3\\x83\\x95\\xE3\\x83\\xBC, \\xE3\\x83\\x90\\xE3\\x83\\xBC", + name.to_s + # OpenSSL escapes characters with MSB by default + assert_equal \ + "CN=\\E3\\83\\95\\E3\\83\\BC\\, \\E3\\83\\90\\E3\\83\\BC," \ + "DC=ruby-lang,DC=org", + name.to_s(OpenSSL::X509::Name::RFC2253) + assert_equal "DC = org, DC = ruby-lang, " \ + "CN = \"\\E3\\83\\95\\E3\\83\\BC, \\E3\\83\\90\\E3\\83\\BC\"", + name.to_s(OpenSSL::X509::Name::ONELINE) + + empty = OpenSSL::X509::Name.new + assert_equal "", empty.to_s + assert_equal "", empty.to_s(OpenSSL::X509::Name::COMPAT) + assert_equal "", empty.to_s(OpenSSL::X509::Name::RFC2253) + assert_equal "", empty.to_s(OpenSSL::X509::Name::ONELINE) + end + + def test_to_utf8 + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "フー, バー"], + ] + name = OpenSSL::X509::Name.new + dn.each { |x| name.add_entry(*x) } + + str = name.to_utf8 + expected = String.new("CN=フー\\, バー,DC=ruby-lang,DC=org").force_encoding("UTF-8") + assert_equal expected, str + assert_equal Encoding.find("UTF-8"), str.encoding + + empty = OpenSSL::X509::Name.new + assert_equal "", empty.to_utf8 + end + + def test_equals2 + n1 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' + n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' + + assert_equal n1, n2 + + assert_equal(false, n1 == 'abc') + assert_equal(false, n2 == nil) + end + + def test_spaceship + n1 = OpenSSL::X509::Name.new([["CN", "a"]]) + n2 = OpenSSL::X509::Name.new([["CN", "a"]]) + n3 = OpenSSL::X509::Name.new([["CN", "ab"]]) + + assert_equal(0, n1 <=> n2) + assert_equal(-1, n1 <=> n3) + assert_equal(0, n2 <=> n1) + assert_equal(-1, n2 <=> n3) + assert_equal(1, n3 <=> n1) + assert_equal(1, n3 <=> n2) + assert_equal(nil, n1 <=> 'abc') + assert_equal(nil, n2 <=> 123) + assert_equal(nil, n3 <=> nil) + end + + def name_hash(name) + # OpenSSL 1.0.0 uses SHA1 for canonical encoding (not just a der) of + # X509Name for X509_NAME_hash. + name.respond_to?(:hash_old) ? name.hash_old : name.hash + end + + def test_hash + dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" + name = OpenSSL::X509::Name.parse(dn) + d = OpenSSL::Digest::MD5.digest(name.to_der) + expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 + assert_equal(expected, name_hash(name)) + # + dn = "/DC=org/DC=ruby-lang/CN=baz.ruby-lang.org" + name = OpenSSL::X509::Name.parse(dn) + d = OpenSSL::Digest::MD5.digest(name.to_der) + expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 + assert_equal(expected, name_hash(name)) + end + + def test_equality + name0 = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "bar.ruby-lang.org"]]) + name1 = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "bar.ruby-lang.org"]]) + name2 = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "baz.ruby-lang.org"]]) + assert_equal true, name0 == name1 + assert_equal true, name0.eql?(name1) + assert_equal false, name0 == name2 + assert_equal false, name0.eql?(name2) + end + + def test_marshal + name = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "bar.ruby-lang.org"]]) + deserialized = Marshal.load(Marshal.dump(name)) + + assert_equal name.to_der, deserialized.to_der + end + + def test_dup + name = OpenSSL::X509::Name.parse("/CN=ruby-lang.org") + assert_equal(name.to_der, name.dup.to_der) + end +end + +end diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb new file mode 100644 index 00000000..bace06b3 --- /dev/null +++ b/test/openssl/test_x509req.rb @@ -0,0 +1,170 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestX509Request < OpenSSL::TestCase + def setup + super + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") + @dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou") + end + + def issue_csr(ver, dn, key, digest) + req = OpenSSL::X509::Request.new + req.version = ver + req.subject = dn + req.public_key = key.public_key + req.sign(key, digest) + req + end + + def test_public_key + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) + assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + end + + def test_version + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(0, req.version) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(0, req.version) + + req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(1, req.version) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(1, req.version) + end + + def test_subject + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(@dn.to_der, req.subject.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@dn.to_der, req.subject.to_der) + end + + def create_ext_req(exts) + ef = OpenSSL::X509::ExtensionFactory.new + exts = exts.collect{|e| ef.create_extension(*e) } + return OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)]) + end + + def get_ext_req(ext_req_value) + set = OpenSSL::ASN1.decode(ext_req_value) + seq = set.value[0] + seq.value.collect{|asn1ext| + OpenSSL::X509::Extension.new(asn1ext).to_a + } + end + + def test_attr + exts = [ + ["keyUsage", "Digital Signature, Key Encipherment", true], + ["subjectAltName", "email:gotoyuzo@ruby-lang.org", false], + ] + attrval = create_ext_req(exts) + attrs = [ + OpenSSL::X509::Attribute.new("extReq", attrval), + OpenSSL::X509::Attribute.new("msExtReq", attrval), + ] + + req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + attrs.each{|attr| req0.add_attribute(attr) } + req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + req1.attributes = attrs + assert_equal(req0.to_der, req1.to_der) + + attrs = req0.attributes + assert_equal(2, attrs.size) + assert_equal("extReq", attrs[0].oid) + assert_equal("msExtReq", attrs[1].oid) + assert_equal(exts, get_ext_req(attrs[0].value)) + assert_equal(exts, get_ext_req(attrs[1].value)) + + req = OpenSSL::X509::Request.new(req0.to_der) + attrs = req.attributes + assert_equal(2, attrs.size) + assert_equal("extReq", attrs[0].oid) + assert_equal("msExtReq", attrs[1].oid) + assert_equal(exts, get_ext_req(attrs[0].value)) + assert_equal(exts, get_ext_req(attrs[1].value)) + end + + def test_sign_and_verify_rsa_sha1 + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(true, req.verify(@rsa1024)) + assert_equal(false, req.verify(@rsa2048)) + assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) + assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) + req.version = 1 + assert_equal(false, req.verify(@rsa1024)) + end + + def test_sign_and_verify_rsa_md5 + req = issue_csr(0, @dn, @rsa2048, OpenSSL::Digest::MD5.new) + assert_equal(false, req.verify(@rsa1024)) + assert_equal(true, req.verify(@rsa2048)) + assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) + assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) + req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBar") + assert_equal(false, req.verify(@rsa2048)) + rescue OpenSSL::X509::RequestError # RHEL7 disables MD5 + end + + def test_sign_and_verify_dsa + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) + assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) + assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) + assert_equal(false, req.verify(@dsa256)) + assert_equal(true, req.verify(@dsa512)) + req.public_key = @rsa1024.public_key + assert_equal(false, req.verify(@dsa512)) + end + + def test_sign_and_verify_dsa_md5 + assert_raise(OpenSSL::X509::RequestError){ + issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } + end + + def test_dup + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(req.to_der, req.dup.to_der) + end + + def test_eq + req1 = issue_csr(0, @dn, @rsa1024, "sha1") + req2 = issue_csr(0, @dn, @rsa1024, "sha1") + req3 = issue_csr(0, @dn, @rsa1024, "sha256") + + assert_equal false, req1 == 12345 + assert_equal true, req1 == req2 + assert_equal false, req1 == req3 + end + + def test_marshal + req = issue_csr(0, @dn, @rsa1024, "sha256") + deserialized = Marshal.load(Marshal.dump(req)) + + assert_equal req.to_der, deserialized.to_der + end + + private + + def request_error_returns_false + yield + rescue OpenSSL::X509::RequestError + false + end +end + +end diff --git a/test/openssl/test_x509store.rb b/test/openssl/test_x509store.rb new file mode 100644 index 00000000..8223c9b7 --- /dev/null +++ b/test/openssl/test_x509store.rb @@ -0,0 +1,241 @@ +# frozen_string_literal: true +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestX509Store < OpenSSL::TestCase + def setup + super + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") + @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1") + @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2") + @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") + @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") + end + + def test_nosegv_on_cleanup + cert = OpenSSL::X509::Certificate.new + store = OpenSSL::X509::Store.new + ctx = OpenSSL::X509::StoreContext.new(store, cert, []) + EnvUtil.suppress_warning do + ctx.cleanup + end + ctx.verify + end + + def test_add_file + ca_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["keyUsage", "cRLSign,keyCertSign", true], + ] + cert1 = issue_cert(@ca1, @rsa1024, 1, ca_exts, nil, nil) + cert2 = issue_cert(@ca2, @rsa2048, 1, ca_exts, nil, nil) + tmpfile = Tempfile.open { |f| f << cert1.to_pem << cert2.to_pem; f } + + store = OpenSSL::X509::Store.new + assert_equal false, store.verify(cert1) + assert_equal false, store.verify(cert2) + store.add_file(tmpfile.path) + assert_equal true, store.verify(cert1) + assert_equal true, store.verify(cert2) + + # OpenSSL < 1.1.1 leaks an error on a duplicate certificate + assert_nothing_raised { store.add_file(tmpfile.path) } + assert_equal [], OpenSSL.errors + ensure + tmpfile and tmpfile.close! + end + + def test_verify + # OpenSSL uses time(2) while Time.now uses clock_gettime(CLOCK_REALTIME), + # and there may be difference. + now = Time.now - 3 + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","cRLSign,keyCertSign",true], + ] + ee_exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ] + ca1_cert = issue_cert(@ca1, @rsa2048, 1, ca_exts, nil, nil) + ca2_cert = issue_cert(@ca2, @rsa1024, 2, ca_exts, ca1_cert, @rsa2048, + not_after: now+1800) + ee1_cert = issue_cert(@ee1, @dsa256, 10, ee_exts, ca2_cert, @rsa1024) + ee2_cert = issue_cert(@ee2, @dsa512, 20, ee_exts, ca2_cert, @rsa1024) + ee3_cert = issue_cert(@ee2, @dsa512, 30, ee_exts, ca2_cert, @rsa1024, + not_before: now-100, not_after: now-1) + ee4_cert = issue_cert(@ee2, @dsa512, 40, ee_exts, ca2_cert, @rsa1024, + not_before: now+1000, not_after: now+2000,) + + revoke_info = [] + crl1 = issue_crl(revoke_info, 1, now, now+1800, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoke_info = [ [2, now, 1], ] + crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoke_info = [ [20, now, 1], ] + crl2 = issue_crl(revoke_info, 1, now, now+1800, [], + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + revoke_info = [] + crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [], + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + + assert_equal(true, ca1_cert.verify(ca1_cert.public_key)) # self signed + assert_equal(true, ca2_cert.verify(ca1_cert.public_key)) # issued by ca1 + assert_equal(true, ee1_cert.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, ee2_cert.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, ee3_cert.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, crl1.verify(ca1_cert.public_key)) # issued by ca1 + assert_equal(true, crl1_2.verify(ca1_cert.public_key)) # issued by ca1 + assert_equal(true, crl2.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, crl2_2.verify(ca2_cert.public_key)) # issued by ca2 + + store = OpenSSL::X509::Store.new + assert_equal(false, store.verify(ca1_cert)) + assert_not_equal(OpenSSL::X509::V_OK, store.error) + + assert_equal(false, store.verify(ca2_cert)) + assert_not_equal(OpenSSL::X509::V_OK, store.error) + + store.add_cert(ca1_cert) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(OpenSSL::X509::V_OK, store.error) + assert_equal("ok", store.error_string) + chain = store.chain + assert_equal(2, chain.size) + assert_equal(@ca2.to_der, chain[0].subject.to_der) + assert_equal(@ca1.to_der, chain[1].subject.to_der) + + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + assert_equal(false, store.verify(ca2_cert)) + assert_not_equal(OpenSSL::X509::V_OK, store.error) + + store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN + assert_equal(true, store.verify(ca2_cert)) + assert_equal(OpenSSL::X509::V_OK, store.error) + + store.add_cert(ca2_cert) + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + assert_equal(true, store.verify(ee1_cert)) + assert_equal(true, store.verify(ee2_cert)) + assert_equal(OpenSSL::X509::V_OK, store.error) + assert_equal("ok", store.error_string) + chain = store.chain + assert_equal(3, chain.size) + assert_equal(@ee2.to_der, chain[0].subject.to_der) + assert_equal(@ca2.to_der, chain[1].subject.to_der) + assert_equal(@ca1.to_der, chain[2].subject.to_der) + assert_equal(false, store.verify(ee3_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + assert_match(/expire/i, store.error_string) + assert_equal(false, store.verify(ee4_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) + assert_match(/not yet valid/i, store.error_string) + + store = OpenSSL::X509::Store.new + store.add_cert(ca1_cert) + store.add_cert(ca2_cert) + store.time = now + 1500 + assert_equal(true, store.verify(ca1_cert)) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(true, store.verify(ee4_cert)) + store.time = now + 1900 + assert_equal(true, store.verify(ca1_cert)) + assert_equal(false, store.verify(ca2_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + assert_equal(false, store.verify(ee4_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + store.time = now + 4000 + assert_equal(false, store.verify(ee1_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + assert_equal(false, store.verify(ee4_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + + # the underlying X509 struct caches the result of the last + # verification for signature and not-before. so the following code + # rebuilds new objects to avoid site effect. + store.time = Time.now - 4000 + assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ca2_cert))) + assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) + assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ee1_cert))) + assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) + + store = OpenSSL::X509::Store.new + store.purpose = OpenSSL::X509::PURPOSE_ANY + store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK + store.add_cert(ca1_cert) + store.add_crl(crl1) # revoke no cert + store.add_crl(crl2) # revoke ee2_cert + assert_equal(true, store.verify(ca1_cert)) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(true, store.verify(ee1_cert, [ca2_cert])) + assert_equal(false, store.verify(ee2_cert, [ca2_cert])) + + store = OpenSSL::X509::Store.new + store.purpose = OpenSSL::X509::PURPOSE_ANY + store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK + store.add_cert(ca1_cert) + store.add_crl(crl1_2) # revoke ca2_cert + store.add_crl(crl2) # revoke ee2_cert + assert_equal(true, store.verify(ca1_cert)) + assert_equal(false, store.verify(ca2_cert)) + assert_equal(true, store.verify(ee1_cert, [ca2_cert]), + "This test is expected to be success with OpenSSL 0.9.7c or later.") + assert_equal(false, store.verify(ee2_cert, [ca2_cert])) + + store.flags = + OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL + assert_equal(true, store.verify(ca1_cert)) + assert_equal(false, store.verify(ca2_cert)) + assert_equal(false, store.verify(ee1_cert, [ca2_cert])) + assert_equal(false, store.verify(ee2_cert, [ca2_cert])) + + store = OpenSSL::X509::Store.new + store.purpose = OpenSSL::X509::PURPOSE_ANY + store.flags = + OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL + store.add_cert(ca1_cert) + store.add_cert(ca2_cert) + store.add_crl(crl1) + store.add_crl(crl2_2) # issued by ca2 but expired. + assert_equal(true, store.verify(ca1_cert)) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(false, store.verify(ee1_cert)) + assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error) + assert_equal(false, store.verify(ee2_cert)) + end + + def test_set_errors + return if openssl?(1, 1, 0) || libressl? + now = Time.now + ca1_cert = issue_cert(@ca1, @rsa2048, 1, [], nil, nil) + store = OpenSSL::X509::Store.new + store.add_cert(ca1_cert) + assert_raise(OpenSSL::X509::StoreError){ + store.add_cert(ca1_cert) # add same certificate twice + } + + revoke_info = [] + crl1 = issue_crl(revoke_info, 1, now, now+1800, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoke_info = [ [2, now, 1], ] + crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + store.add_crl(crl1) + assert_raise(OpenSSL::X509::StoreError){ + store.add_crl(crl2) # add CRL issued by same CA twice. + } + end + + def test_dup + store = OpenSSL::X509::Store.new + assert_raise(NoMethodError) { store.dup } + ctx = OpenSSL::X509::StoreContext.new(store) + assert_raise(NoMethodError) { ctx.dup } + end +end + +end diff --git a/test/openssl/ut_eof.rb b/test/openssl/ut_eof.rb new file mode 100644 index 00000000..cf1f2d42 --- /dev/null +++ b/test/openssl/ut_eof.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true +require 'test/unit' + +if defined?(OpenSSL) + +module OpenSSL::TestEOF + def test_eof_0 + open_file("") {|f| + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + } + open_file("") {|f| + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("") {|f| + s = +"x" + assert_equal("", f.read(nil, s)) + assert_equal("", s) + } + open_file("") {|f| + s = +"x" + assert_nil(f.read(10, s)) + assert_equal("", s) + } + end + + def test_eof_0_rw + return unless respond_to? :open_file_rw + open_file_rw("") {|f| + assert_equal("", f.read) + assert_equal("", f.read) + assert_equal(0, f.syswrite("")) + assert_equal("", f.read) + } + end + + def test_eof_1 + open_file("a") {|f| + assert_equal("", f.read(0)) + assert_equal("a", f.read(1)) + assert_equal("" , f.read(0)) + assert_equal("" , f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + } + open_file("a") {|f| + assert_equal("a", f.read(1)) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read(2)) + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read) + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read(2)) + assert_equal("", f.read) + assert_equal("", f.read) + } + open_file("a") {|f| + assert_equal("a", f.read) + assert_equal("", f.read(0)) + } + open_file("a") {|f| + s = +"x" + assert_equal("a", f.read(nil, s)) + assert_equal("a", s) + } + open_file("a") {|f| + s = +"x" + assert_equal("a", f.read(10, s)) + assert_equal("a", s) + } + end + + def test_eof_2 + open_file("") {|f| + assert_equal("", f.read) + assert_predicate(f, :eof?) + } + end + + def test_eof_3 + open_file("") {|f| + assert_predicate(f, :eof?) + } + end + + module Seek + def open_file_seek(content, pos) + open_file(content) do |f| + f.seek(pos) + yield f + end + end + + def test_eof_0_seek + open_file_seek("", 10) {|f| + assert_equal(10, f.pos) + assert_equal("", f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read) + } + end + + def test_eof_1_seek + open_file_seek("a", 10) {|f| + assert_equal("", f.read) + assert_equal("", f.read) + } + open_file_seek("a", 1) {|f| + assert_equal("", f.read) + assert_equal("", f.read) + } + end + end +end + +end diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb new file mode 100644 index 00000000..acece979 --- /dev/null +++ b/test/openssl/utils.rb @@ -0,0 +1,397 @@ +# frozen_string_literal: true +begin + require "openssl" + + # Disable FIPS mode for tests for installations + # where FIPS mode would be enabled by default. + # Has no effect on all other installations. + OpenSSL.fips_mode=false +rescue LoadError +end + +# Compile OpenSSL with crypto-mdebug and run this test suite with OSSL_MDEBUG=1 +# environment variable to enable memory leak check. +if ENV["OSSL_MDEBUG"] == "1" + if OpenSSL.respond_to?(:print_mem_leaks) + OpenSSL.mem_check_start + + END { + GC.start + case OpenSSL.print_mem_leaks + when nil + warn "mdebug: check what is printed" + when true + raise "mdebug: memory leaks detected" + end + } + else + warn "OSSL_MDEBUG=1 is specified but OpenSSL is not built with crypto-mdebug" + end +end + +require "test/unit" +require "tempfile" +require "socket" +require "envutil" + +if defined?(OpenSSL) + +module OpenSSL::TestUtils + module Fixtures + module_function + + def pkey(name) + OpenSSL::PKey.read(read_file("pkey", name)) + rescue OpenSSL::PKey::PKeyError + # TODO: DH parameters can be read by OpenSSL::PKey.read atm + OpenSSL::PKey::DH.new(read_file("pkey", name)) + end + + def read_file(category, name) + @file_cache ||= {} + @file_cache[[category, name]] ||= + File.read(File.join(__dir__, "fixtures", category, name + ".pem")) + end + + def file_path(category, name) + File.join(__dir__, "fixtures", category, name) + end + end + + module_function + + def generate_cert(dn, key, serial, issuer, + not_before: nil, not_after: nil) + cert = OpenSSL::X509::Certificate.new + issuer = cert unless issuer + cert.version = 2 + cert.serial = serial + cert.subject = dn + cert.issuer = issuer.subject + cert.public_key = key + now = Time.now + cert.not_before = not_before || now - 3600 + cert.not_after = not_after || now + 3600 + cert + end + + + def issue_cert(dn, key, serial, extensions, issuer, issuer_key, + not_before: nil, not_after: nil, digest: "sha256") + cert = generate_cert(dn, key, serial, issuer, + not_before: not_before, not_after: not_after) + issuer = cert unless issuer + issuer_key = key unless issuer_key + ef = OpenSSL::X509::ExtensionFactory.new + ef.subject_certificate = cert + ef.issuer_certificate = issuer + extensions.each{|oid, value, critical| + cert.add_extension(ef.create_extension(oid, value, critical)) + } + cert.sign(issuer_key, digest) + cert + end + + def issue_crl(revoke_info, serial, lastup, nextup, extensions, + issuer, issuer_key, digest) + crl = OpenSSL::X509::CRL.new + crl.issuer = issuer.subject + crl.version = 1 + crl.last_update = lastup + crl.next_update = nextup + revoke_info.each{|rserial, time, reason_code| + revoked = OpenSSL::X509::Revoked.new + revoked.serial = rserial + revoked.time = time + enum = OpenSSL::ASN1::Enumerated(reason_code) + ext = OpenSSL::X509::Extension.new("CRLReason", enum) + revoked.add_extension(ext) + crl.add_revoked(revoked) + } + ef = OpenSSL::X509::ExtensionFactory.new + ef.issuer_certificate = issuer + ef.crl = crl + crlnum = OpenSSL::ASN1::Integer(serial) + crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum)) + extensions.each{|oid, value, critical| + crl.add_extension(ef.create_extension(oid, value, critical)) + } + crl.sign(issuer_key, digest) + crl + end + + def get_subject_key_id(cert, hex: true) + asn1_cert = OpenSSL::ASN1.decode(cert) + tbscert = asn1_cert.value[0] + pkinfo = tbscert.value[6] + publickey = pkinfo.value[1] + pkvalue = publickey.value + digest = OpenSSL::Digest::SHA1.digest(pkvalue) + if hex + digest.unpack("H2"*20).join(":").upcase + else + digest + end + end + + def openssl?(major = nil, minor = nil, fix = nil, patch = 0) + return false if OpenSSL::OPENSSL_VERSION.include?("LibreSSL") + return true unless major + OpenSSL::OPENSSL_VERSION_NUMBER >= + major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10 + end + + def libressl?(major = nil, minor = nil, fix = nil) + version = OpenSSL::OPENSSL_VERSION.scan(/LibreSSL (\d+)\.(\d+)\.(\d+).*/)[0] + return false unless version + !major || (version.map(&:to_i) <=> [major, minor, fix]) >= 0 + end +end + +class OpenSSL::TestCase < Test::Unit::TestCase + include OpenSSL::TestUtils + extend OpenSSL::TestUtils + + def setup + if ENV["OSSL_GC_STRESS"] == "1" + GC.stress = true + end + end + + def teardown + if ENV["OSSL_GC_STRESS"] == "1" + GC.stress = false + end + # OpenSSL error stack must be empty + assert_equal([], OpenSSL.errors) + end +end + +class OpenSSL::SSLTestCase < OpenSSL::TestCase + RUBY = EnvUtil.rubybin + ITERATIONS = ($0 == __FILE__) ? 100 : 10 + + def setup + super + @ca_key = Fixtures.pkey("rsa-1") + @svr_key = Fixtures.pkey("rsa-2") + @cli_key = Fixtures.pkey("rsa-3") + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","cRLSign,keyCertSign",true], + ] + ee_exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ] + @ca_cert = issue_cert(@ca, @ca_key, 1, ca_exts, nil, nil) + @svr_cert = issue_cert(@svr, @svr_key, 2, ee_exts, @ca_cert, @ca_key) + @cli_cert = issue_cert(@cli, @cli_key, 3, ee_exts, @ca_cert, @ca_key) + @server = nil + end + + def tls12_supported? + ctx = OpenSSL::SSL::SSLContext.new + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + true + rescue + end + + def readwrite_loop(ctx, ssl) + while line = ssl.gets + ssl.write(line) + end + end + + def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true, + ctx_proc: nil, server_proc: method(:readwrite_loop), + accept_proc: proc{}, + ignore_listener_error: false, &block) + IO.pipe {|stop_pipe_r, stop_pipe_w| + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + ctx = OpenSSL::SSL::SSLContext.new + ctx.cert_store = store + ctx.cert = @svr_cert + ctx.key = @svr_key + ctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } + ctx.verify_mode = verify_mode + ctx_proc.call(ctx) if ctx_proc + + Socket.do_not_reverse_lookup = true + tcps = TCPServer.new("127.0.0.1", 0) + port = tcps.connect_address.ip_port + + ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) + ssls.start_immediately = start_immediately + + threads = [] + begin + server_thread = Thread.new do + if Thread.method_defined?(:report_on_exception=) # Ruby >= 2.4 + Thread.current.report_on_exception = false + end + + begin + loop do + begin + readable, = IO.select([ssls, stop_pipe_r]) + break if readable.include? stop_pipe_r + ssl = ssls.accept + accept_proc.call(ssl) + rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL, + Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET + retry if ignore_listener_error + raise + end + + th = Thread.new do + if Thread.method_defined?(:report_on_exception=) + Thread.current.report_on_exception = false + end + + begin + server_proc.call(ctx, ssl) + ensure + ssl.close + end + true + end + threads << th + end + ensure + tcps.close + end + end + + client_thread = Thread.new do + if Thread.method_defined?(:report_on_exception=) + Thread.current.report_on_exception = false + end + + begin + block.call(port) + ensure + # Stop accepting new connection + stop_pipe_w.close + server_thread.join + end + end + threads.unshift client_thread + ensure + # Terminate existing connections. If a thread did 'pend', re-raise it. + pend = nil + threads.each { |th| + begin + timeout = EnvUtil.apply_timeout_scale(30) + th.join(timeout) or + th.raise(RuntimeError, "[start_server] thread did not exit in #{timeout} secs") + rescue (defined?(MiniTest::Skip) ? MiniTest::Skip : Test::Unit::PendedError) + # MiniTest::Skip is for the Ruby tree + pend = $! + rescue Exception + end + } + raise pend if pend + assert_join_threads(threads) + end + } + end +end + +class OpenSSL::PKeyTestCase < OpenSSL::TestCase + def check_component(base, test, keys) + keys.each { |comp| + assert_equal base.send(comp), test.send(comp) + } + end + + def dup_public(key) + case key + when OpenSSL::PKey::RSA + rsa = OpenSSL::PKey::RSA.new + rsa.set_key(key.n, key.e, nil) + rsa + when OpenSSL::PKey::DSA + dsa = OpenSSL::PKey::DSA.new + dsa.set_pqg(key.p, key.q, key.g) + dsa.set_key(key.pub_key, nil) + dsa + when OpenSSL::PKey::DH + dh = OpenSSL::PKey::DH.new + dh.set_pqg(key.p, nil, key.g) + dh + else + if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key + ec = OpenSSL::PKey::EC.new(key.group) + ec.public_key = key.public_key + ec + else + raise "unknown key type" + end + end + end +end + +module OpenSSL::Certs + include OpenSSL::TestUtils + + module_function + + def ca_cert + ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Timestamp Root CA") + + ca_exts = [ + ["basicConstraints","CA:TRUE,pathlen:1",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + OpenSSL::TestUtils.issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) + end + + def ts_cert_direct(key, ca_cert) + dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server Direct") + + exts = [ + ["basicConstraints","CA:FALSE",true], + ["keyUsage","digitalSignature, nonRepudiation", true], + ["subjectKeyIdentifier", "hash",false], + ["authorityKeyIdentifier","keyid,issuer", false], + ["extendedKeyUsage", "timeStamping", true] + ] + + OpenSSL::TestUtils.issue_cert(dn, key, 2, exts, ca_cert, Fixtures.pkey("rsa2048")) + end + + def intermediate_cert(key, ca_cert) + dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Timestamp Intermediate CA") + + exts = [ + ["basicConstraints","CA:TRUE,pathlen:0",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + + OpenSSL::TestUtils.issue_cert(dn, key, 3, exts, ca_cert, Fixtures.pkey("rsa2048")) + end + + def ts_cert_ee(key, intermediate, im_key) + dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server End Entity") + + exts = [ + ["keyUsage","digitalSignature, nonRepudiation", true], + ["subjectKeyIdentifier", "hash",false], + ["authorityKeyIdentifier","keyid,issuer", false], + ["extendedKeyUsage", "timeStamping", true] + ] + + OpenSSL::TestUtils.issue_cert(dn, key, 4, exts, intermediate, im_key) + end +end + +end diff --git a/test/test_asn1.rb b/test/test_asn1.rb deleted file mode 100644 index 5f457551..00000000 --- a/test/test_asn1.rb +++ /dev/null @@ -1,720 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestASN1 < OpenSSL::TestCase - def test_decode_x509_certificate - subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") - key = Fixtures.pkey("rsa1024") - now = Time.at(Time.now.to_i) # suppress usec - s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf - exts = [ - ["basicConstraints","CA:TRUE,pathlen:1",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ] - dgst = OpenSSL::Digest::SHA1.new - cert = OpenSSL::TestUtils.issue_cert( - subj, key, s, exts, nil, nil, digest: dgst, not_before: now, not_after: now+3600) - - - asn1 = OpenSSL::ASN1.decode(cert) - assert_equal(OpenSSL::ASN1::Sequence, asn1.class) - assert_equal(3, asn1.value.size) - tbs_cert, sig_alg, sig_val = *asn1.value - - assert_equal(OpenSSL::ASN1::Sequence, tbs_cert.class) - assert_equal(8, tbs_cert.value.size) - - version = tbs_cert.value[0] - assert_equal(:CONTEXT_SPECIFIC, version.tag_class) - assert_equal(0, version.tag) - assert_equal(1, version.value.size) - assert_equal(OpenSSL::ASN1::Integer, version.value[0].class) - assert_equal(2, version.value[0].value) - - serial = tbs_cert.value[1] - assert_equal(OpenSSL::ASN1::Integer, serial.class) - assert_equal(0xdeadbeafdeadbeafdeadbeafdeadbeaf, serial.value) - - sig = tbs_cert.value[2] - assert_equal(OpenSSL::ASN1::Sequence, sig.class) - assert_equal(2, sig.value.size) - assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class) - assert_equal("1.2.840.113549.1.1.5", sig.value[0].oid) - assert_equal(OpenSSL::ASN1::Null, sig.value[1].class) - - dn = tbs_cert.value[3] # issuer - assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) - assert_equal(OpenSSL::ASN1::Sequence, dn.class) - assert_equal(3, dn.value.size) - assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) - assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) - assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) - assert_equal(1, dn.value[0].value.size) - assert_equal(1, dn.value[1].value.size) - assert_equal(1, dn.value[2].value.size) - assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) - assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) - assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) - assert_equal(2, dn.value[0].value[0].value.size) - assert_equal(2, dn.value[1].value[0].value.size) - assert_equal(2, dn.value[2].value[0].value.size) - oid, value = *dn.value[0].value[0].value - assert_equal(OpenSSL::ASN1::ObjectId, oid.class) - assert_equal("0.9.2342.19200300.100.1.25", oid.oid) - assert_equal(OpenSSL::ASN1::IA5String, value.class) - assert_equal("org", value.value) - oid, value = *dn.value[1].value[0].value - assert_equal(OpenSSL::ASN1::ObjectId, oid.class) - assert_equal("0.9.2342.19200300.100.1.25", oid.oid) - assert_equal(OpenSSL::ASN1::IA5String, value.class) - assert_equal("ruby-lang", value.value) - oid, value = *dn.value[2].value[0].value - assert_equal(OpenSSL::ASN1::ObjectId, oid.class) - assert_equal("2.5.4.3", oid.oid) - assert_equal(OpenSSL::ASN1::UTF8String, value.class) - assert_equal("TestCA", value.value) - - validity = tbs_cert.value[4] - assert_equal(OpenSSL::ASN1::Sequence, validity.class) - assert_equal(2, validity.value.size) - assert_equal(OpenSSL::ASN1::UTCTime, validity.value[0].class) - assert_equal(now, validity.value[0].value) - assert_equal(OpenSSL::ASN1::UTCTime, validity.value[1].class) - assert_equal(now+3600, validity.value[1].value) - - dn = tbs_cert.value[5] # subject - assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) - assert_equal(OpenSSL::ASN1::Sequence, dn.class) - assert_equal(3, dn.value.size) - assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) - assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) - assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) - assert_equal(1, dn.value[0].value.size) - assert_equal(1, dn.value[1].value.size) - assert_equal(1, dn.value[2].value.size) - assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) - assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) - assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) - assert_equal(2, dn.value[0].value[0].value.size) - assert_equal(2, dn.value[1].value[0].value.size) - assert_equal(2, dn.value[2].value[0].value.size) - oid, value = *dn.value[0].value[0].value - assert_equal(OpenSSL::ASN1::ObjectId, oid.class) - assert_equal("0.9.2342.19200300.100.1.25", oid.oid) - assert_equal(OpenSSL::ASN1::IA5String, value.class) - assert_equal("org", value.value) - oid, value = *dn.value[1].value[0].value - assert_equal(OpenSSL::ASN1::ObjectId, oid.class) - assert_equal("0.9.2342.19200300.100.1.25", oid.oid) - assert_equal(OpenSSL::ASN1::IA5String, value.class) - assert_equal("ruby-lang", value.value) - oid, value = *dn.value[2].value[0].value - assert_equal(OpenSSL::ASN1::ObjectId, oid.class) - assert_equal("2.5.4.3", oid.oid) - assert_equal(OpenSSL::ASN1::UTF8String, value.class) - assert_equal("TestCA", value.value) - - pkey = tbs_cert.value[6] - assert_equal(OpenSSL::ASN1::Sequence, pkey.class) - assert_equal(2, pkey.value.size) - assert_equal(OpenSSL::ASN1::Sequence, pkey.value[0].class) - assert_equal(2, pkey.value[0].value.size) - assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) - assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) - assert_equal(OpenSSL::ASN1::BitString, pkey.value[1].class) - assert_equal(0, pkey.value[1].unused_bits) - spkey = OpenSSL::ASN1.decode(pkey.value[1].value) - assert_equal(OpenSSL::ASN1::Sequence, spkey.class) - assert_equal(2, spkey.value.size) - assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class) - assert_equal(cert.public_key.n, spkey.value[0].value) - assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class) - assert_equal(cert.public_key.e, spkey.value[1].value) - - extensions = tbs_cert.value[7] - assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class) - assert_equal(3, extensions.tag) - assert_equal(1, extensions.value.size) - assert_equal(OpenSSL::ASN1::Sequence, extensions.value[0].class) - assert_equal(3, extensions.value[0].value.size) - - ext = extensions.value[0].value[0] # basicConstraints - assert_equal(OpenSSL::ASN1::Sequence, ext.class) - assert_equal(3, ext.value.size) - assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) - assert_equal("2.5.29.19", ext.value[0].oid) - assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) - assert_equal(true, ext.value[1].value) - assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) - extv = OpenSSL::ASN1.decode(ext.value[2].value) - assert_equal(OpenSSL::ASN1::Sequence, extv.class) - assert_equal(2, extv.value.size) - assert_equal(OpenSSL::ASN1::Boolean, extv.value[0].class) - assert_equal(true, extv.value[0].value) - assert_equal(OpenSSL::ASN1::Integer, extv.value[1].class) - assert_equal(1, extv.value[1].value) - - ext = extensions.value[0].value[1] # keyUsage - assert_equal(OpenSSL::ASN1::Sequence, ext.class) - assert_equal(3, ext.value.size) - assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) - assert_equal("2.5.29.15", ext.value[0].oid) - assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) - assert_equal(true, ext.value[1].value) - assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) - extv = OpenSSL::ASN1.decode(ext.value[2].value) - assert_equal(OpenSSL::ASN1::BitString, extv.class) - str = +"\000"; str[0] = 0b00000110.chr - assert_equal(str, extv.value) - - ext = extensions.value[0].value[2] # subjetKeyIdentifier - assert_equal(OpenSSL::ASN1::Sequence, ext.class) - assert_equal(2, ext.value.size) - assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) - assert_equal("2.5.29.14", ext.value[0].oid) - assert_equal(OpenSSL::ASN1::OctetString, ext.value[1].class) - extv = OpenSSL::ASN1.decode(ext.value[1].value) - assert_equal(OpenSSL::ASN1::OctetString, extv.class) - sha1 = OpenSSL::Digest::SHA1.new - sha1.update(pkey.value[1].value) - assert_equal(sha1.digest, extv.value) - - assert_equal(OpenSSL::ASN1::Sequence, sig_alg.class) - assert_equal(2, sig_alg.value.size) - assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) - assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) - assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class) - - assert_equal(OpenSSL::ASN1::BitString, sig_val.class) - cululated_sig = key.sign(OpenSSL::Digest::SHA1.new, tbs_cert.to_der) - assert_equal(cululated_sig, sig_val.value) - end - - def test_decode_all - raw = B(%w{ 02 01 01 02 01 02 02 01 03 }) - ary = OpenSSL::ASN1.decode_all(raw) - assert_equal(3, ary.size) - ary.each_with_index do |asn1, i| - assert_universal(OpenSSL::ASN1::INTEGER, asn1) - assert_equal(i + 1, asn1.value) - end - end - - def test_object_id_register - oid = "1.2.34.56789" - pend "OID 1.2.34.56789 is already registered" if OpenSSL::ASN1::ObjectId(oid).sn - assert_equal true, OpenSSL::ASN1::ObjectId.register(oid, "ossl-test-sn", "ossl-test-ln") - obj = OpenSSL::ASN1::ObjectId(oid) - assert_equal oid, obj.oid - assert_equal "ossl-test-sn", obj.sn - assert_equal "ossl-test-ln", obj.ln - obj = encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId("ossl-test-ln") - assert_equal "ossl-test-sn", obj.value - end - - def test_end_of_content - encode_decode_test B(%w{ 00 00 }), OpenSSL::ASN1::EndOfContent.new - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.decode(B(%w{ 00 01 00 })) - } - end - - def test_boolean - encode_decode_test B(%w{ 01 01 00 }), OpenSSL::ASN1::Boolean.new(false) - encode_decode_test B(%w{ 01 01 FF }), OpenSSL::ASN1::Boolean.new(true) - decode_test B(%w{ 01 01 01 }), OpenSSL::ASN1::Boolean.new(true) - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.decode(B(%w{ 01 02 00 00 })) - } - end - - def test_integer - encode_decode_test B(%w{ 02 01 00 }), OpenSSL::ASN1::Integer.new(0) - encode_decode_test B(%w{ 02 01 48 }), OpenSSL::ASN1::Integer.new(72) - encode_decode_test B(%w{ 02 02 00 80 }), OpenSSL::ASN1::Integer.new(128) - encode_decode_test B(%w{ 02 01 81 }), OpenSSL::ASN1::Integer.new(-127) - encode_decode_test B(%w{ 02 01 80 }), OpenSSL::ASN1::Integer.new(-128) - encode_decode_test B(%w{ 02 01 FF }), OpenSSL::ASN1::Integer.new(-1) - encode_decode_test B(%w{ 02 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(2 ** 64) - encode_decode_test B(%w{ 02 09 FF 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(-(2 ** 64)) - # FIXME: OpenSSL < 1.1.0 does not fail - # assert_raise(OpenSSL::ASN1::ASN1Error) { - # OpenSSL::ASN1.decode(B(%w{ 02 02 00 7F })) - # } - # assert_raise(OpenSSL::ASN1::ASN1Error) { - # OpenSSL::ASN1.decode(B(%w{ 02 02 FF 80 })) - # } - end - - def test_enumerated - encode_decode_test B(%w{ 0A 01 00 }), OpenSSL::ASN1::Enumerated.new(0) - encode_decode_test B(%w{ 0A 01 48 }), OpenSSL::ASN1::Enumerated.new(72) - encode_decode_test B(%w{ 0A 02 00 80 }), OpenSSL::ASN1::Enumerated.new(128) - encode_decode_test B(%w{ 0A 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Enumerated.new(2 ** 64) - end - - def test_bitstring - encode_decode_test B(%w{ 03 01 00 }), OpenSSL::ASN1::BitString.new(B(%w{})) - encode_decode_test B(%w{ 03 02 00 01 }), OpenSSL::ASN1::BitString.new(B(%w{ 01 })) - obj = OpenSSL::ASN1::BitString.new(B(%w{ F0 })) - obj.unused_bits = 4 - encode_decode_test B(%w{ 03 02 04 F0 }), obj - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.decode(B(%w{ 03 00 })) - } - # OpenSSL < OpenSSL_1_0_1k and LibreSSL ignore the error - # assert_raise(OpenSSL::ASN1::ASN1Error) { - # OpenSSL::ASN1.decode(B(%w{ 03 03 08 FF 00 })) - # } - # OpenSSL does not seem to prohibit this, though X.690 8.6.2.3 (15/08) does - # assert_raise(OpenSSL::ASN1::ASN1Error) { - # OpenSSL::ASN1.decode(B(%w{ 03 01 04 })) - # } - assert_raise(OpenSSL::ASN1::ASN1Error) { - obj = OpenSSL::ASN1::BitString.new(B(%w{ FF FF })) - obj.unused_bits = 8 - obj.to_der - } - end - - def test_string_basic - test = -> (tag, klass) { - encode_decode_test tag.chr + B(%w{ 00 }), klass.new(B(%w{})) - encode_decode_test tag.chr + B(%w{ 02 00 01 }), klass.new(B(%w{ 00 01 })) - } - test.(4, OpenSSL::ASN1::OctetString) - test.(12, OpenSSL::ASN1::UTF8String) - test.(18, OpenSSL::ASN1::NumericString) - test.(19, OpenSSL::ASN1::PrintableString) - test.(20, OpenSSL::ASN1::T61String) - test.(21, OpenSSL::ASN1::VideotexString) - test.(22, OpenSSL::ASN1::IA5String) - test.(25, OpenSSL::ASN1::GraphicString) - test.(26, OpenSSL::ASN1::ISO64String) - test.(27, OpenSSL::ASN1::GeneralString) - test.(28, OpenSSL::ASN1::UniversalString) - test.(30, OpenSSL::ASN1::BMPString) - end - - def test_null - encode_decode_test B(%w{ 05 00 }), OpenSSL::ASN1::Null.new(nil) - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.decode(B(%w{ 05 01 00 })) - } - end - - def test_object_identifier - encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new("0.0".b) - encode_decode_test B(%w{ 06 01 28 }), OpenSSL::ASN1::ObjectId.new("1.0".b) - encode_decode_test B(%w{ 06 03 88 37 03 }), OpenSSL::ASN1::ObjectId.new("2.999.3".b) - encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId.new("1.2.34.56789".b) - obj = encode_decode_test B(%w{ 06 09 60 86 48 01 65 03 04 02 01 }), OpenSSL::ASN1::ObjectId.new("sha256") - assert_equal "2.16.840.1.101.3.4.2.1", obj.oid - assert_equal "SHA256", obj.sn - assert_equal "sha256", obj.ln - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.decode(B(%w{ 06 00 })) - } - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.decode(B(%w{ 06 01 80 })) - } - assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("3.0".b).to_der } - assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("0.40".b).to_der } - - begin - oid = (0...100).to_a.join(".").b - obj = OpenSSL::ASN1::ObjectId.new(oid) - assert_equal oid, obj.oid - rescue OpenSSL::ASN1::ASN1Error - pend "OBJ_obj2txt() not working (LibreSSL?)" if $!.message =~ /OBJ_obj2txt/ - raise - end - - aki = [ - OpenSSL::ASN1::ObjectId.new("authorityKeyIdentifier"), - OpenSSL::ASN1::ObjectId.new("X509v3 Authority Key Identifier"), - OpenSSL::ASN1::ObjectId.new("2.5.29.35") - ] - - ski = [ - OpenSSL::ASN1::ObjectId.new("subjectKeyIdentifier"), - OpenSSL::ASN1::ObjectId.new("X509v3 Subject Key Identifier"), - OpenSSL::ASN1::ObjectId.new("2.5.29.14") - ] - - aki.each do |a| - aki.each do |b| - assert a == b - end - - ski.each do |b| - refute a == b - end - end - - assert_raise(TypeError) { - OpenSSL::ASN1::ObjectId.new("authorityKeyIdentifier") == nil - } - end - - def test_sequence - encode_decode_test B(%w{ 30 00 }), OpenSSL::ASN1::Sequence.new([]) - encode_decode_test B(%w{ 30 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Sequence.new([ - OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::Sequence.new([]), - OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) - ]) - - expected = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) - expected.indefinite_length = true - encode_decode_test B(%w{ 30 80 04 01 00 00 00 }), expected - - # OpenSSL::ASN1::EndOfContent can only be at the end - obj = OpenSSL::ASN1::Sequence.new([ - OpenSSL::ASN1::EndOfContent.new, - OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), - OpenSSL::ASN1::EndOfContent.new, - ]) - obj.indefinite_length = true - assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } - - # The last EOC in value is ignored if indefinite length form is used - expected = OpenSSL::ASN1::Sequence.new([ - OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), - OpenSSL::ASN1::EndOfContent.new - ]) - expected.indefinite_length = true - encode_test B(%w{ 30 80 04 01 00 00 00 }), expected - end - - def test_set - encode_decode_test B(%w{ 31 00 }), OpenSSL::ASN1::Set.new([]) - encode_decode_test B(%w{ 31 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Set.new([ - OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::Sequence.new([]), - OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) - ]) - expected = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) - expected.indefinite_length = true - encode_decode_test B(%w{ 31 80 04 01 00 00 00 }), expected - end - - def test_utctime - encode_decode_test B(%w{ 17 0D }) + "160908234339Z".b, - OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39)) - # Seconds is omitted - decode_test B(%w{ 17 0B }) + "1609082343Z".b, - OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 0)) - begin - # possible range of UTCTime is 1969-2068 currently - encode_decode_test B(%w{ 17 0D }) + "690908234339Z".b, - OpenSSL::ASN1::UTCTime.new(Time.utc(1969, 9, 8, 23, 43, 39)) - rescue OpenSSL::ASN1::ASN1Error - pend "No negative time_t support?" - end - # not implemented - # decode_test B(%w{ 17 11 }) + "500908234339+0930".b, - # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 39, "+09:30")) - # decode_test B(%w{ 17 0F }) + "5009082343-0930".b, - # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 0, "-09:30")) - # assert_raise(OpenSSL::ASN1::ASN1Error) { - # OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b) - # } - # assert_raise(OpenSSL::ASN1::ASN1Error) { - # OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b) - # } - end - - def test_generalizedtime - encode_decode_test B(%w{ 18 0F }) + "20161208193429Z".b, - OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29)) - encode_decode_test B(%w{ 18 0F }) + "99990908234339Z".b, - OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39)) - decode_test B(%w{ 18 0D }) + "201612081934Z".b, - OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0)) - # not implemented - # decode_test B(%w{ 18 13 }) + "20161208193439+0930".b, - # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, "+09:30")) - # decode_test B(%w{ 18 11 }) + "201612081934-0930".b, - # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:30")) - # decode_test B(%w{ 18 11 }) + "201612081934-09".b, - # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:00")) - # decode_test B(%w{ 18 0D }) + "2016120819.5Z".b, - # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) - # decode_test B(%w{ 18 0D }) + "2016120819,5Z".b, - # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) - # decode_test B(%w{ 18 0F }) + "201612081934.5Z".b, - # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 30)) - # decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b, - # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5)) - # assert_raise(OpenSSL::ASN1::ASN1Error) { - # OpenSSL::ASN1.decode(B(%w{ 18 0D }) + "201612081934Y".b) - # } - end - - def test_basic_asn1data - encode_test B(%w{ 00 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 0, :UNIVERSAL) - encode_test B(%w{ 01 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :UNIVERSAL) - encode_decode_test B(%w{ 41 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :APPLICATION) - encode_decode_test B(%w{ 81 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :CONTEXT_SPECIFIC) - encode_decode_test B(%w{ C1 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :PRIVATE) - encode_decode_test B(%w{ 1F 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 32, :UNIVERSAL) - encode_decode_test B(%w{ 1F C0 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 8224, :UNIVERSAL) - encode_decode_test B(%w{ 41 02 AB CD }), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :APPLICATION) - encode_decode_test B(%w{ 41 81 80 } + %w{ AB CD } * 64), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 64), 1, :APPLICATION) - encode_decode_test B(%w{ 41 82 01 00 } + %w{ AB CD } * 128), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 128), 1, :APPLICATION) - encode_decode_test B(%w{ 61 00 }), OpenSSL::ASN1::ASN1Data.new([], 1, :APPLICATION) - obj = OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE)], 1, :APPLICATION) - obj.indefinite_length = true - encode_decode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj - obj = OpenSSL::ASN1::ASN1Data.new([ - OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE), - OpenSSL::ASN1::EndOfContent.new - ], 1, :APPLICATION) - obj.indefinite_length = true - encode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj - obj = OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :UNIVERSAL) - obj.indefinite_length = true - assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } - end - - def test_basic_primitive - encode_test B(%w{ 00 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 0) - encode_test B(%w{ 01 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :UNIVERSAL) - encode_test B(%w{ 81 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :CONTEXT_SPECIFIC) - encode_test B(%w{ 01 02 AB CD }), OpenSSL::ASN1::Primitive.new(B(%w{ AB CD }), 1) - assert_raise(TypeError) { OpenSSL::ASN1::Primitive.new([], 1).to_der } - - prim = OpenSSL::ASN1::Integer.new(50) - assert_equal false, prim.indefinite_length - assert_not_respond_to prim, :indefinite_length= - end - - def test_basic_constructed - octet_string = OpenSSL::ASN1::OctetString.new(B(%w{ AB CD })) - encode_test B(%w{ 20 00 }), OpenSSL::ASN1::Constructive.new([], 0) - encode_test B(%w{ 21 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :UNIVERSAL) - encode_test B(%w{ A1 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :CONTEXT_SPECIFIC) - encode_test B(%w{ 21 04 04 02 AB CD }), OpenSSL::ASN1::Constructive.new([octet_string], 1) - obj = OpenSSL::ASN1::Constructive.new([octet_string], 1) - obj.indefinite_length = true - encode_decode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj - obj = OpenSSL::ASN1::Constructive.new([octet_string, OpenSSL::ASN1::EndOfContent.new], 1) - obj.indefinite_length = true - encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj - end - - def test_prim_explicit_tagging - oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) - encode_test B(%w{ A0 03 04 01 61 }), oct_str - oct_str2 = OpenSSL::ASN1::OctetString.new("a", 1, :EXPLICIT, :APPLICATION) - encode_test B(%w{ 61 03 04 01 61 }), oct_str2 - - decoded = OpenSSL::ASN1.decode(oct_str2.to_der) - assert_equal :APPLICATION, decoded.tag_class - assert_equal 1, decoded.tag - assert_equal 1, decoded.value.size - inner = decoded.value[0] - assert_equal OpenSSL::ASN1::OctetString, inner.class - assert_equal B(%w{ 61 }), inner.value - end - - def test_prim_implicit_tagging - int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) - encode_test B(%w{ 80 01 01 }), int - int2 = OpenSSL::ASN1::Integer.new(1, 1, :IMPLICIT, :APPLICATION) - encode_test B(%w{ 41 01 01 }), int2 - decoded = OpenSSL::ASN1.decode(int2.to_der) - assert_equal :APPLICATION, decoded.tag_class - assert_equal 1, decoded.tag - assert_equal B(%w{ 01 }), decoded.value - - # Special behavior: Encoding universal types with non-default 'tag' - # attribute and nil tagging method. - int3 = OpenSSL::ASN1::Integer.new(1, 1) - encode_test B(%w{ 01 01 01 }), int3 - end - - def test_cons_explicit_tagging - content = [ OpenSSL::ASN1::PrintableString.new('abc') ] - seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) - encode_test B(%w{ A2 07 30 05 13 03 61 62 63 }), seq - seq2 = OpenSSL::ASN1::Sequence.new(content, 3, :EXPLICIT, :APPLICATION) - encode_test B(%w{ 63 07 30 05 13 03 61 62 63 }), seq2 - - content3 = [ OpenSSL::ASN1::PrintableString.new('abc'), - OpenSSL::ASN1::EndOfContent.new() ] - seq3 = OpenSSL::ASN1::Sequence.new(content3, 2, :EXPLICIT) - seq3.indefinite_length = true - encode_test B(%w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 }), seq3 - end - - def test_cons_implicit_tagging - content = [ OpenSSL::ASN1::Null.new(nil) ] - seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) - encode_test B(%w{ A1 02 05 00 }), seq - seq2 = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT, :APPLICATION) - encode_test B(%w{ 61 02 05 00 }), seq2 - - content3 = [ OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::EndOfContent.new() ] - seq3 = OpenSSL::ASN1::Sequence.new(content3, 1, :IMPLICIT) - seq3.indefinite_length = true - encode_test B(%w{ A1 80 05 00 00 00 }), seq3 - - # Special behavior: Encoding universal types with non-default 'tag' - # attribute and nil tagging method. - seq4 = OpenSSL::ASN1::Sequence.new([], 1) - encode_test B(%w{ 21 00 }), seq4 - end - - def test_octet_string_constructed_tagging - octets = [ OpenSSL::ASN1::OctetString.new('aaa') ] - cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT) - encode_test B(%w{ A0 05 04 03 61 61 61 }), cons - - octets = [ OpenSSL::ASN1::OctetString.new('aaa'), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT) - cons.indefinite_length = true - encode_test B(%w{ A0 80 04 03 61 61 61 00 00 }), cons - end - - def test_recursive_octet_string_indefinite_length - octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"), - OpenSSL::ASN1::EndOfContent.new() ] - octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"), - OpenSSL::ASN1::EndOfContent.new() ] - container1 = OpenSSL::ASN1::Constructive.new(octets_sub1, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - container1.indefinite_length = true - container2 = OpenSSL::ASN1::Constructive.new(octets_sub2, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - container2.indefinite_length = true - octets3 = OpenSSL::ASN1::OctetString.new("\x03") - - octets = [ container1, container2, octets3, - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new(octets, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - cons.indefinite_length = true - raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - - def test_recursive_octet_string_parse - raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(OpenSSL::ASN1::Constructive, asn1.class) - assert_universal(OpenSSL::ASN1::OCTET_STRING, asn1) - assert_equal(true, asn1.indefinite_length) - assert_equal(3, asn1.value.size) - nested1 = asn1.value[0] - assert_equal(OpenSSL::ASN1::Constructive, nested1.class) - assert_universal(OpenSSL::ASN1::OCTET_STRING, nested1) - assert_equal(true, nested1.indefinite_length) - assert_equal(1, nested1.value.size) - oct1 = nested1.value[0] - assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1) - assert_equal(false, oct1.indefinite_length) - nested2 = asn1.value[1] - assert_equal(OpenSSL::ASN1::Constructive, nested2.class) - assert_universal(OpenSSL::ASN1::OCTET_STRING, nested2) - assert_equal(true, nested2.indefinite_length) - assert_equal(1, nested2.value.size) - oct2 = nested2.value[0] - assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2) - assert_equal(false, oct2.indefinite_length) - oct3 = asn1.value[2] - assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3) - assert_equal(false, oct3.indefinite_length) - end - - def test_decode_constructed_overread - test = %w{ 31 06 31 02 30 02 05 00 } - # ^ <- invalid - raw = [test.join].pack("H*") - ret = [] - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.traverse(raw) { |x| ret << x } - } - assert_equal 2, ret.size - assert_equal 17, ret[0][6] - assert_equal 17, ret[1][6] - - test = %w{ 31 80 30 03 00 00 } - # ^ <- invalid - raw = [test.join].pack("H*") - ret = [] - assert_raise(OpenSSL::ASN1::ASN1Error) { - OpenSSL::ASN1.traverse(raw) { |x| ret << x } - } - assert_equal 1, ret.size - assert_equal 17, ret[0][6] - end - - def test_constructive_each - data = [OpenSSL::ASN1::Integer.new(0), OpenSSL::ASN1::Integer.new(1)] - seq = OpenSSL::ASN1::Sequence.new data - - assert_equal data, seq.entries - end - - # Very time consuming test. - # def test_gc_stress - # assert_ruby_status(['--disable-gems', '-eGC.stress=true', '-erequire "openssl.so"']) - # end - - private - - def B(ary) - [ary.join].pack("H*") - end - - def assert_asn1_equal(a, b) - assert_equal a.class, b.class - assert_equal a.tag, b.tag - assert_equal a.tag_class, b.tag_class - assert_equal a.indefinite_length, b.indefinite_length - assert_equal a.unused_bits, b.unused_bits if a.respond_to?(:unused_bits) - case a.value - when Array - a.value.each_with_index { |ai, i| - assert_asn1_equal ai, b.value[i] - } - else - if OpenSSL::ASN1::ObjectId === a - assert_equal a.oid, b.oid - else - assert_equal a.value, b.value - end - end - assert_equal a.to_der, b.to_der - end - - def encode_test(der, obj) - assert_equal der, obj.to_der - end - - def decode_test(der, obj) - decoded = OpenSSL::ASN1.decode(der) - assert_asn1_equal obj, decoded - decoded - end - - def encode_decode_test(der, obj) - encode_test(der, obj) - decode_test(der, obj) - end - - def assert_universal(tag, asn1) - assert_equal(tag, asn1.tag) - if asn1.respond_to?(:tagging) - assert_nil(asn1.tagging) - end - assert_equal(:UNIVERSAL, asn1.tag_class) - end -end - -end diff --git a/test/test_bn.rb b/test/test_bn.rb deleted file mode 100644 index 547d334c..00000000 --- a/test/test_bn.rb +++ /dev/null @@ -1,286 +0,0 @@ -# coding: us-ascii -# frozen_string_literal: true -require_relative 'utils' -require "prime" - -if defined?(OpenSSL) - -class OpenSSL::TestBN < OpenSSL::TestCase - def setup - super - @e1 = OpenSSL::BN.new(999.to_s(16), 16) # OpenSSL::BN.new(str, 16) must be most stable - @e2 = OpenSSL::BN.new("-" + 999.to_s(16), 16) - @e3 = OpenSSL::BN.new((2**107-1).to_s(16), 16) - @e4 = OpenSSL::BN.new("-" + (2**107-1).to_s(16), 16) - end - - def test_new - assert_raise(ArgumentError) { OpenSSL::BN.new } - assert_raise(ArgumentError) { OpenSSL::BN.new(nil) } - assert_raise(ArgumentError) { OpenSSL::BN.new(nil, 2) } - - assert_equal(@e1, OpenSSL::BN.new("999")) - assert_equal(@e1, OpenSSL::BN.new("999", 10)) - assert_equal(@e1, OpenSSL::BN.new("\x03\xE7", 2)) - assert_equal(@e1, OpenSSL::BN.new("\x00\x00\x00\x02\x03\xE7", 0)) - assert_equal(@e2, OpenSSL::BN.new("-999")) - assert_equal(@e2, OpenSSL::BN.new("-999", 10)) - assert_equal(@e2, OpenSSL::BN.new("\x00\x00\x00\x02\x83\xE7", 0)) - assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s)) - assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s, 10)) - assert_equal(@e3, OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2)) - assert_equal(@e3, OpenSSL::BN.new("\x00\x00\x00\x0E\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) - assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s)) - assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s, 10)) - assert_equal(@e4, OpenSSL::BN.new("\x00\x00\x00\x0E\x87\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) - - e1copy = OpenSSL::BN.new(@e1) - assert_equal(@e1, e1copy) - e1copy.clear_bit!(0) #=> 998 - assert_not_equal(@e1, e1copy) - - assert_equal(@e1, OpenSSL::BN.new(999)) - assert_equal(@e2, OpenSSL::BN.new(-999)) - assert_equal(@e3, OpenSSL::BN.new(2**107-1)) - assert_equal(@e4, OpenSSL::BN.new(-(2**107-1))) - - assert_equal(@e1, 999.to_bn) - assert_equal(@e2, -999.to_bn) - assert_equal(@e3, (2**107-1).to_bn) - assert_equal(@e4, (-(2**107-1)).to_bn) - end - - def test_to_str - assert_equal("999", @e1.to_s(10)) - assert_equal("-999", @e2.to_s(10)) - assert_equal((2**107-1).to_s, @e3.to_s(10)) - assert_equal((-(2**107-1)).to_s, @e4.to_s(10)) - assert_equal("999", @e1.to_s) - - assert_equal("03E7", @e1.to_s(16)) - assert_equal("-03E7", @e2.to_s(16)) - assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e3.to_s(16)) - assert_equal("-07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e4.to_s(16)) - - assert_equal("\x03\xe7", @e1.to_s(2)) - assert_equal("\x03\xe7", @e2.to_s(2)) - assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(2)) - assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(2)) - - assert_equal("\x00\x00\x00\x02\x03\xe7", @e1.to_s(0)) - assert_equal("\x00\x00\x00\x02\x83\xe7", @e2.to_s(0)) - assert_equal("\x00\x00\x00\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(0)) - assert_equal("\x00\x00\x00\x0e\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(0)) - end - - def test_to_int - assert_equal(999, @e1.to_i) - assert_equal(-999, @e2.to_i) - assert_equal(2**107-1, @e3.to_i) - assert_equal(-(2**107-1), @e4.to_i) - - assert_equal(999, @e1.to_int) - end - - def test_coerce - assert_equal(["", "-999"], @e2.coerce("")) - assert_equal([1000, -999], @e2.coerce(1000)) - assert_raise(TypeError) { @e2.coerce(Class.new.new) } - end - - def test_zero_p - assert_equal(true, 0.to_bn.zero?) - assert_equal(false, 1.to_bn.zero?) - end - - def test_one_p - assert_equal(true, 1.to_bn.one?) - assert_equal(false, 2.to_bn.one?) - end - - def test_odd_p - assert_equal(true, 1.to_bn.odd?) - assert_equal(false, 2.to_bn.odd?) - end - - def test_negative_p - assert_equal(false, 0.to_bn.negative?) - assert_equal(false, @e1.negative?) - assert_equal(true, @e2.negative?) - end - - def test_sqr - assert_equal(1, 1.to_bn.sqr) - assert_equal(100, 10.to_bn.sqr) - end - - def test_four_ops - assert_equal(3, 1.to_bn + 2) - assert_equal(-1, 1.to_bn + -2) - assert_equal(-1, 1.to_bn - 2) - assert_equal(3, 1.to_bn - -2) - assert_equal(2, 1.to_bn * 2) - assert_equal(-2, 1.to_bn * -2) - assert_equal([0, 1], 1.to_bn / 2) - assert_equal([2, 0], 2.to_bn / 1) - assert_raise(OpenSSL::BNError) { 1.to_bn / 0 } - end - - def test_unary_plus_minus - assert_equal(999, +@e1) - assert_equal(-999, +@e2) - assert_equal(-999, -@e1) - assert_equal(+999, -@e2) - end - - def test_mod - assert_equal(1, 1.to_bn % 2) - assert_equal(0, 2.to_bn % 1) - assert_equal(-2, -2.to_bn % 7) - end - - def test_exp - assert_equal(1, 1.to_bn ** 5) - assert_equal(32, 2.to_bn ** 5) - end - - def test_gcd - assert_equal(1, 7.to_bn.gcd(5)) - assert_equal(8, 24.to_bn.gcd(16)) - end - - def test_mod_sqr - assert_equal(4, 3.to_bn.mod_sqr(5)) - assert_equal(0, 59.to_bn.mod_sqr(59)) - end - - def test_mod_inverse - assert_equal(2, 3.to_bn.mod_inverse(5)) - assert_raise(OpenSSL::BNError) { 3.to_bn.mod_inverse(6) } - end - - def test_mod_add - assert_equal(1, 3.to_bn.mod_add(5, 7)) - assert_equal(2, 3.to_bn.mod_add(5, 3)) - assert_equal(5, 3.to_bn.mod_add(-5, 7)) - end - - def test_mod_sub - assert_equal(1, 11.to_bn.mod_sub(3, 7)) - assert_equal(2, 11.to_bn.mod_sub(3, 3)) - assert_equal(5, 3.to_bn.mod_sub(5, 7)) - end - - def test_mod_mul - assert_equal(1, 2.to_bn.mod_mul(4, 7)) - assert_equal(5, 2.to_bn.mod_mul(-1, 7)) - end - - def test_mod_exp - assert_equal(1, 3.to_bn.mod_exp(2, 8)) - assert_equal(4, 2.to_bn.mod_exp(5, 7)) - end - - def test_bit_operations - e = 0b10010010.to_bn - assert_equal(0b10010011, e.set_bit!(0)) - assert_equal(0b10010011, e.set_bit!(1)) - assert_equal(0b1010010011, e.set_bit!(9)) - - e = 0b10010010.to_bn - assert_equal(0b10010010, e.clear_bit!(0)) - assert_equal(0b10010000, e.clear_bit!(1)) - - e = 0b10010010.to_bn - assert_equal(0b10010010, e.mask_bits!(8)) - assert_equal(0b10, e.mask_bits!(3)) - - e = 0b10010010.to_bn - assert_equal(false, e.bit_set?(0)) - assert_equal(true, e.bit_set?(1)) - assert_equal(false, e.bit_set?(1000)) - - e = 0b10010010.to_bn - assert_equal(0b1001001000, e << 2) - assert_equal(0b10010010, e) - assert_equal(0b1001001000, e.lshift!(2)) - assert_equal(0b1001001000, e) - - e = 0b10010010.to_bn - assert_equal(0b100100, e >> 2) - assert_equal(0b10010010, e) - assert_equal(0b100100, e.rshift!(2)) - assert_equal(0b100100, e) - end - - def test_random - 10.times { - r1 = OpenSSL::BN.rand(8) - assert_include(128..255, r1) - r2 = OpenSSL::BN.rand(8, -1) - assert_include(0..255, r2) - r3 = OpenSSL::BN.rand(8, 1) - assert_include(192..255, r3) - r4 = OpenSSL::BN.rand(8, 1, true) - assert_include(192..255, r4) - assert_equal(true, r4.odd?) - - r5 = OpenSSL::BN.rand_range(256) - assert_include(0..255, r5) - } - end - - def test_prime - p1 = OpenSSL::BN.generate_prime(32) - assert_include(0...2**32, p1) - assert_equal(true, Prime.prime?(p1.to_i)) - p2 = OpenSSL::BN.generate_prime(32, true) - assert_equal(true, Prime.prime?((p2.to_i - 1) / 2)) - p3 = OpenSSL::BN.generate_prime(32, false, 4) - assert_equal(1, p3 % 4) - p4 = OpenSSL::BN.generate_prime(32, false, 4, 3) - assert_equal(3, p4 % 4) - - assert_equal(true, p1.prime?) - assert_equal(true, p2.prime?) - assert_equal(true, p3.prime?) - assert_equal(true, p4.prime?) - assert_equal(true, @e3.prime?) - assert_equal(true, @e3.prime_fasttest?) - end - - def test_num_bits_bytes - assert_equal(10, @e1.num_bits) - assert_equal(2, @e1.num_bytes) - assert_equal(107, @e3.num_bits) - assert_equal(14, @e3.num_bytes) - assert_equal(0, 0.to_bn.num_bits) - assert_equal(0, 0.to_bn.num_bytes) - assert_equal(9, -256.to_bn.num_bits) - assert_equal(2, -256.to_bn.num_bytes) - end - - def test_comparison - assert_equal(false, @e1 == nil) - assert_equal(false, @e1 == -999) - assert_equal(true, @e1 == 999) - assert_equal(true, @e1 == 999.to_bn) - assert_equal(false, @e1.eql?(nil)) - assert_equal(false, @e1.eql?(999)) - assert_equal(true, @e1.eql?(999.to_bn)) - assert_equal(@e1.hash, 999.to_bn.hash) - assert_not_equal(@e1.hash, @e3.hash) - assert_equal(0, @e1.cmp(999)) - assert_equal(1, @e1.cmp(-999)) - assert_equal(0, @e1.ucmp(999)) - assert_equal(0, @e1.ucmp(-999)) - assert_instance_of(String, @e1.hash.to_s) - end - - def test_argument_error - bug15760 = '[ruby-core:92231] [Bug #15760]' - assert_raise(ArgumentError, bug15760) { OpenSSL::BN.new(nil, 2) } - end -end - -end diff --git a/test/test_buffering.rb b/test/test_buffering.rb deleted file mode 100644 index 7575c5b4..00000000 --- a/test/test_buffering.rb +++ /dev/null @@ -1,97 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestBuffering < OpenSSL::TestCase - class IO - include OpenSSL::Buffering - - attr_accessor :sync - - def initialize - @io = Buffer.new - def @io.sync - true - end - - super - - @sync = false - end - - def string - @io - end - - def sysread(size) - str = @io.slice!(0, size) - raise EOFError if str.empty? - str - end - - def syswrite(str) - @io << str - str.size - end - end - - def setup - super - @io = IO.new - end - - def test_encoding - @io.write '😊' - @io.flush - - assert_equal @io.string.encoding, Encoding::BINARY - end - - def test_flush - @io.write 'a' - - assert_not_predicate @io, :sync - assert_empty @io.string - - assert_equal @io, @io.flush - - assert_not_predicate @io, :sync - assert_equal 'a', @io.string - end - - def test_flush_error - @io.write 'a' - - assert_not_predicate @io, :sync - assert_empty @io.string - - def @io.syswrite *a - raise SystemCallError, 'fail' - end - - assert_raise SystemCallError do - @io.flush - end - - assert_not_predicate @io, :sync, 'sync must not change' - end - - def test_getc - @io.syswrite('abc') - assert_equal(?a, @io.getc) - assert_equal(?b, @io.getc) - assert_equal(?c, @io.getc) - end - - def test_each_byte - @io.syswrite('abc') - res = [] - @io.each_byte do |c| - res << c - end - assert_equal([97, 98, 99], res) - end -end - -end diff --git a/test/test_cipher.rb b/test/test_cipher.rb deleted file mode 100644 index f6ec4980..00000000 --- a/test/test_cipher.rb +++ /dev/null @@ -1,340 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestCipher < OpenSSL::TestCase - module Helper - def has_cipher?(name) - @ciphers ||= OpenSSL::Cipher.ciphers - @ciphers.include?(name) - end - end - include Helper - extend Helper - - def test_encrypt_decrypt - # NIST SP 800-38A F.2.1 - key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*") - iv = ["000102030405060708090a0b0c0d0e0f"].pack("H*") - pt = ["6bc1bee22e409f96e93d7e117393172a" \ - "ae2d8a571e03ac9c9eb76fac45af8e51"].pack("H*") - ct = ["7649abac8119b246cee98e9b12e9197d" \ - "5086cb9b507219ee95db113a917678b2"].pack("H*") - cipher = new_encryptor("aes-128-cbc", key: key, iv: iv, padding: 0) - assert_equal ct, cipher.update(pt) << cipher.final - cipher = new_decryptor("aes-128-cbc", key: key, iv: iv, padding: 0) - assert_equal pt, cipher.update(ct) << cipher.final - end - - def test_pkcs5_keyivgen - pass = "\x00" * 8 - salt = "\x01" * 8 - num = 2048 - pt = "data to be encrypted" - cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt - cipher.pkcs5_keyivgen(pass, salt, num, "MD5") - s1 = cipher.update(pt) << cipher.final - - d1 = num.times.inject(pass + salt) {|out, _| OpenSSL::Digest::MD5.digest(out) } - d2 = num.times.inject(d1 + pass + salt) {|out, _| OpenSSL::Digest::MD5.digest(out) } - key = (d1 + d2)[0, 24] - iv = (d1 + d2)[24, 8] - cipher = new_encryptor("DES-EDE3-CBC", key: key, iv: iv) - s2 = cipher.update(pt) << cipher.final - - assert_equal s1, s2 - - cipher2 = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt - assert_raise(ArgumentError) { cipher2.pkcs5_keyivgen(pass, salt, -1, "MD5") } - end - - def test_info - cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt - assert_equal "DES-EDE3-CBC", cipher.name - assert_equal 24, cipher.key_len - assert_equal 8, cipher.iv_len - end - - def test_dup - cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt - assert_equal cipher.name, cipher.dup.name - cipher.encrypt - cipher.random_key - cipher.random_iv - tmpc = cipher.dup - s1 = cipher.update("data") + cipher.final - s2 = tmpc.update("data") + tmpc.final - assert_equal(s1, s2, "encrypt dup") - end - - def test_reset - cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt - cipher.encrypt - cipher.random_key - cipher.random_iv - s1 = cipher.update("data") + cipher.final - cipher.reset - s2 = cipher.update("data") + cipher.final - assert_equal(s1, s2, "encrypt reset") - end - - def test_key_iv_set - cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt - assert_raise(ArgumentError) { cipher.key = "\x01" * 23 } - assert_nothing_raised { cipher.key = "\x01" * 24 } - assert_raise(ArgumentError) { cipher.key = "\x01" * 25 } - assert_raise(ArgumentError) { cipher.iv = "\x01" * 7 } - assert_nothing_raised { cipher.iv = "\x01" * 8 } - assert_raise(ArgumentError) { cipher.iv = "\x01" * 9 } - end - - def test_random_key_iv - data = "data" - s1, s2 = 2.times.map do - cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt - cipher.random_key - cipher.iv = "\x01" * 16 - cipher.update(data) << cipher.final - end - assert_not_equal s1, s2 - - s1, s2 = 2.times.map do - cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt - cipher.key = "\x01" * 16 - cipher.random_iv - cipher.update(data) << cipher.final - end - assert_not_equal s1, s2 - end - - def test_empty_data - cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt - cipher.random_key - assert_raise(ArgumentError) { cipher.update("") } - end - - def test_initialize - cipher = OpenSSL::Cipher.new("DES-EDE3-CBC") - assert_raise(RuntimeError) { cipher.__send__(:initialize, "DES-EDE3-CBC") } - assert_raise(RuntimeError) { OpenSSL::Cipher.allocate.final } - end - - def test_ctr_if_exists - # NIST SP 800-38A F.5.1 - key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*") - iv = ["f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"].pack("H*") - pt = ["6bc1bee22e409f96e93d7e117393172a" \ - "ae2d8a571e03ac9c9eb76fac45af8e51"].pack("H*") - ct = ["874d6191b620e3261bef6864990db6ce" \ - "9806f66b7970fdff8617187bb9fffdff"].pack("H*") - cipher = new_encryptor("aes-128-ctr", key: key, iv: iv, padding: 0) - assert_equal ct, cipher.update(pt) << cipher.final - cipher = new_decryptor("aes-128-ctr", key: key, iv: iv, padding: 0) - assert_equal pt, cipher.update(ct) << cipher.final - end - - def test_ciphers - OpenSSL::Cipher.ciphers.each{|name| - next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name - begin - assert_kind_of(OpenSSL::Cipher, OpenSSL::Cipher.new(name)) - rescue OpenSSL::Cipher::CipherError => e - raise unless /wrap/ =~ name and /wrap mode not allowed/ =~ e.message - end - } - end - - def test_AES - pt = File.read(__FILE__) - %w(ECB CBC CFB OFB).each{|mode| - c1 = OpenSSL::Cipher::AES256.new(mode) - c1.encrypt - c1.pkcs5_keyivgen("passwd") - ct = c1.update(pt) + c1.final - - c2 = OpenSSL::Cipher::AES256.new(mode) - c2.decrypt - c2.pkcs5_keyivgen("passwd") - assert_equal(pt, c2.update(ct) + c2.final) - } - end - - def test_update_raise_if_key_not_set - assert_raise(OpenSSL::Cipher::CipherError) do - # it caused OpenSSL SEGV by uninitialized key [Bug #2768] - OpenSSL::Cipher::AES128.new("ECB").update "." * 17 - end - end - - def test_authenticated - cipher = OpenSSL::Cipher.new('aes-128-gcm') - assert_predicate(cipher, :authenticated?) - cipher = OpenSSL::Cipher.new('aes-128-cbc') - assert_not_predicate(cipher, :authenticated?) - end - - def test_aes_gcm - # GCM spec Appendix B Test Case 4 - key = ["feffe9928665731c6d6a8f9467308308"].pack("H*") - iv = ["cafebabefacedbaddecaf888"].pack("H*") - aad = ["feedfacedeadbeeffeedfacedeadbeef" \ - "abaddad2"].pack("H*") - pt = ["d9313225f88406e5a55909c5aff5269a" \ - "86a7a9531534f7da2e4c303d8a318a72" \ - "1c3c0c95956809532fcf0e2449a6b525" \ - "b16aedf5aa0de657ba637b39"].pack("H*") - ct = ["42831ec2217774244b7221b784d0d49c" \ - "e3aa212f2c02a4e035c17e2329aca12e" \ - "21d514b25466931c7d8f6a5aac84aa05" \ - "1ba30b396a0aac973d58e091"].pack("H*") - tag = ["5bc94fbc3221a5db94fae95ae7121a47"].pack("H*") - - cipher = new_encryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad) - assert_equal ct, cipher.update(pt) << cipher.final - assert_equal tag, cipher.auth_tag - cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad) - assert_equal pt, cipher.update(ct) << cipher.final - - # truncated tag is accepted - cipher = new_encryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad) - assert_equal ct, cipher.update(pt) << cipher.final - assert_equal tag[0, 8], cipher.auth_tag(8) - cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag[0, 8], auth_data: aad) - assert_equal pt, cipher.update(ct) << cipher.final - - # wrong tag is rejected - tag2 = tag.dup - tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff) - cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag2, auth_data: aad) - cipher.update(ct) - assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } - - # wrong aad is rejected - aad2 = aad[0..-2] << aad[-1].succ - cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad2) - cipher.update(ct) - assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } - - # wrong ciphertext is rejected - ct2 = ct[0..-2] << ct[-1].succ - cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad) - cipher.update(ct2) - assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } - end - - def test_aes_gcm_variable_iv_len - # GCM spec Appendix B Test Case 5 - key = ["feffe9928665731c6d6a8f9467308308"].pack("H*") - iv = ["cafebabefacedbad"].pack("H*") - aad = ["feedfacedeadbeeffeedfacedeadbeef" \ - "abaddad2"].pack("H*") - pt = ["d9313225f88406e5a55909c5aff5269a" \ - "86a7a9531534f7da2e4c303d8a318a72" \ - "1c3c0c95956809532fcf0e2449a6b525" \ - "b16aedf5aa0de657ba637b39"].pack("H*") - ct = ["61353b4c2806934a777ff51fa22a4755" \ - "699b2a714fcdc6f83766e5f97b6c7423" \ - "73806900e49f24b22b097544d4896b42" \ - "4989b5e1ebac0f07c23f4598"].pack("H*") - tag = ["3612d2e79e3b0785561be14aaca2fccb"].pack("H*") - - cipher = new_encryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_data: aad) - assert_equal ct, cipher.update(pt) << cipher.final - assert_equal tag, cipher.auth_tag - cipher = new_decryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_tag: tag, auth_data: aad) - assert_equal pt, cipher.update(ct) << cipher.final - end - - def test_aes_ocb_tag_len - # RFC 7253 Appendix A; the second sample - key = ["000102030405060708090A0B0C0D0E0F"].pack("H*") - iv = ["BBAA99887766554433221101"].pack("H*") - aad = ["0001020304050607"].pack("H*") - pt = ["0001020304050607"].pack("H*") - ct = ["6820B3657B6F615A"].pack("H*") - tag = ["5725BDA0D3B4EB3A257C9AF1F8F03009"].pack("H*") - - cipher = new_encryptor("aes-128-ocb", key: key, iv: iv, auth_data: aad) - assert_equal ct, cipher.update(pt) << cipher.final - assert_equal tag, cipher.auth_tag - cipher = new_decryptor("aes-128-ocb", key: key, iv: iv, auth_tag: tag, auth_data: aad) - assert_equal pt, cipher.update(ct) << cipher.final - - # RFC 7253 Appendix A; with 96 bits tag length - key = ["0F0E0D0C0B0A09080706050403020100"].pack("H*") - iv = ["BBAA9988776655443322110D"].pack("H*") - aad = ["000102030405060708090A0B0C0D0E0F1011121314151617" \ - "18191A1B1C1D1E1F2021222324252627"].pack("H*") - pt = ["000102030405060708090A0B0C0D0E0F1011121314151617" \ - "18191A1B1C1D1E1F2021222324252627"].pack("H*") - ct = ["1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1" \ - "A0124B0A55BAE884ED93481529C76B6A"].pack("H*") - tag = ["D0C515F4D1CDD4FDAC4F02AA"].pack("H*") - - cipher = new_encryptor("aes-128-ocb", auth_tag_len: 12, key: key, iv: iv, auth_data: aad) - assert_equal ct, cipher.update(pt) << cipher.final - assert_equal tag, cipher.auth_tag - cipher = new_decryptor("aes-128-ocb", auth_tag_len: 12, key: key, iv: iv, auth_tag: tag, auth_data: aad) - assert_equal pt, cipher.update(ct) << cipher.final - - end if has_cipher?("aes-128-ocb") - - def test_aes_gcm_key_iv_order_issue - pt = "[ruby/openssl#49]" - cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt - cipher.key = "x" * 16 - cipher.iv = "a" * 12 - ct1 = cipher.update(pt) << cipher.final - tag1 = cipher.auth_tag - - cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt - cipher.iv = "a" * 12 - cipher.key = "x" * 16 - ct2 = cipher.update(pt) << cipher.final - tag2 = cipher.auth_tag - - assert_equal ct1, ct2 - assert_equal tag1, tag2 - end - - def test_non_aead_cipher_set_auth_data - assert_raise(OpenSSL::Cipher::CipherError) { - cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt - cipher.auth_data = "123" - } - end - - def test_crypt_after_key - key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*") - %w'ecb cbc cfb ctr gcm'.each do |c| - cipher = OpenSSL::Cipher.new("aes-128-#{c}") - cipher.key = key - cipher.encrypt - assert_raise(OpenSSL::Cipher::CipherError) { cipher.update("") } - - cipher = OpenSSL::Cipher.new("aes-128-#{c}") - cipher.key = key - cipher.decrypt - assert_raise(OpenSSL::Cipher::CipherError) { cipher.update("") } - end - end - - private - - def new_encryptor(algo, **kwargs) - OpenSSL::Cipher.new(algo).tap do |cipher| - cipher.encrypt - kwargs.each {|k, v| cipher.send(:"#{k}=", v) } - end - end - - def new_decryptor(algo, **kwargs) - OpenSSL::Cipher.new(algo).tap do |cipher| - cipher.decrypt - kwargs.each {|k, v| cipher.send(:"#{k}=", v) } - end - end -end - -end diff --git a/test/test_config.rb b/test/test_config.rb deleted file mode 100644 index dba66b08..00000000 --- a/test/test_config.rb +++ /dev/null @@ -1,304 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestConfig < OpenSSL::TestCase - def setup - super - file = Tempfile.open("openssl.cnf") - file << <<__EOD__ -HOME = . -[ ca ] -default_ca = CA_default -[ CA_default ] -dir = ./demoCA -certs = ./certs -__EOD__ - file.close - @tmpfile = file - @it = OpenSSL::Config.new(file.path) - end - - def teardown - super - @tmpfile.close! - end - - def test_constants - assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE)) - config_file = OpenSSL::Config::DEFAULT_CONFIG_FILE - pend "DEFAULT_CONFIG_FILE may return a wrong path on your platforms. [Bug #6830]" unless File.readable?(config_file) - assert_nothing_raised do - OpenSSL::Config.load(config_file) - end - end - - def test_s_parse - c = OpenSSL::Config.parse('') - assert_equal("[ default ]\n\n", c.to_s) - c = OpenSSL::Config.parse(@it.to_s) - assert_equal(['CA_default', 'ca', 'default'], c.sections.sort) - end - - def test_s_parse_format - c = OpenSSL::Config.parse(<<__EOC__) - baz =qx\t # "baz = qx" - -foo::bar = baz # shortcut section::key format - default::bar = baz # ditto -a=\t \t # "a = ": trailing spaces are ignored - =b # " = b": empty key - =c # " = c": empty key (override the above line) - d= # "c = ": trailing comment is ignored - -sq = 'foo''b\\'ar' - dq ="foo""''\\"" - dq2 = foo""bar -esc=a\\r\\n\\b\\tb -foo\\bar = foo\\b\\\\ar -foo\\bar::foo\\bar = baz -[default1 default2]\t\t # space is allowed in section name - fo =b ar # space allowed in value -[emptysection] - [doller ] -foo=bar -bar = $(foo) -baz = 123$(default::bar)456${foo}798 -qux = ${baz} -quxx = $qux.$qux -__EOC__ - assert_equal(['default', 'default1 default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort) - assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort) - assert_equal('c', c['default']['']) - assert_equal('', c['default']['a']) - assert_equal('qx', c['default']['baz']) - assert_equal('', c['default']['d']) - assert_equal('baz', c['default']['bar']) - assert_equal("foob'ar", c['default']['sq']) - assert_equal("foo''\"", c['default']['dq']) - assert_equal("foobar", c['default']['dq2']) - assert_equal("a\r\n\b\tb", c['default']['esc']) - assert_equal("foo\b\\ar", c['default']['foo\\bar']) - assert_equal('baz', c['foo']['bar']) - assert_equal('baz', c['foo\\bar']['foo\\bar']) - assert_equal('b ar', c['default1 default2']['fo']) - - # dolloer - assert_equal('bar', c['doller']['foo']) - assert_equal('bar', c['doller']['bar']) - assert_equal('123baz456bar798', c['doller']['baz']) - assert_equal('123baz456bar798', c['doller']['qux']) - assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx']) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("foo = $bar") - end - assert_equal("error in line 1: variable has no value", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("foo = $(bar") - end - assert_equal("error in line 1: no close brace", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("f o =b ar # no space in key") - end - assert_equal("error in line 1: missing equal sign", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse(<<__EOC__) -# comment 1 # comments - -# - # comment 2 -\t#comment 3 - [second ]\t -[third # section not terminated -__EOC__ - end - assert_equal("error in line 7: missing close square bracket", excn.message) - end - - def test_s_load - # alias of new - c = OpenSSL::Config.load - assert_equal("", c.to_s) - assert_equal([], c.sections) - # - Tempfile.create("openssl.cnf") {|file| - file.close - c = OpenSSL::Config.load(file.path) - assert_equal("[ default ]\n\n", c.to_s) - assert_equal(['default'], c.sections) - } - end - - def test_initialize - c = OpenSSL::Config.new - assert_equal("", c.to_s) - assert_equal([], c.sections) - end - - def test_initialize_with_empty_file - Tempfile.create("openssl.cnf") {|file| - file.close - c = OpenSSL::Config.new(file.path) - assert_equal("[ default ]\n\n", c.to_s) - assert_equal(['default'], c.sections) - } - end - - def test_initialize_with_example_file - assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) - end - - def test_get_value - assert_equal('CA_default', @it.get_value('ca', 'default_ca')) - assert_equal(nil, @it.get_value('ca', 'no such key')) - assert_equal(nil, @it.get_value('no such section', 'no such key')) - assert_equal('.', @it.get_value('', 'HOME')) - assert_raise(TypeError) do - @it.get_value(nil, 'HOME') # not allowed unlike Config#value - end - # fallback to 'default' ugly... - assert_equal('.', @it.get_value('unknown', 'HOME')) - end - - def test_get_value_ENV - key = ENV.keys.first - assert_not_nil(key) # make sure we have at least one ENV var. - assert_equal(ENV[key], @it.get_value('ENV', key)) - end - - def test_value - # suppress deprecation warnings - EnvUtil.suppress_warning do - assert_equal('CA_default', @it.value('ca', 'default_ca')) - assert_equal(nil, @it.value('ca', 'no such key')) - assert_equal(nil, @it.value('no such section', 'no such key')) - assert_equal('.', @it.value('', 'HOME')) - assert_equal('.', @it.value(nil, 'HOME')) - assert_equal('.', @it.value('HOME')) - # fallback to 'default' ugly... - assert_equal('.', @it.value('unknown', 'HOME')) - end - end - - def test_value_ENV - EnvUtil.suppress_warning do - key = ENV.keys.first - assert_not_nil(key) # make sure we have at least one ENV var. - assert_equal(ENV[key], @it.value('ENV', key)) - end - end - - def test_aref - assert_equal({'HOME' => '.'}, @it['default']) - assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default']) - assert_equal({}, @it['no_such_section']) - assert_equal({}, @it['']) - end - - def test_section - EnvUtil.suppress_warning do - assert_equal({'HOME' => '.'}, @it.section('default')) - assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default')) - assert_equal({}, @it.section('no_such_section')) - assert_equal({}, @it.section('')) - end - end - - def test_sections - assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) - @it['new_section'] = {'foo' => 'bar'} - assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) - @it['new_section'] = {} - assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) - end - - def test_add_value - c = OpenSSL::Config.new - assert_equal("", c.to_s) - # add key - c.add_value('default', 'foo', 'bar') - assert_equal("[ default ]\nfoo=bar\n\n", c.to_s) - # add another key - c.add_value('default', 'baz', 'qux') - assert_equal('bar', c['default']['foo']) - assert_equal('qux', c['default']['baz']) - # update the value - c.add_value('default', 'baz', 'quxxx') - assert_equal('bar', c['default']['foo']) - assert_equal('quxxx', c['default']['baz']) - # add section and key - c.add_value('section', 'foo', 'bar') - assert_equal('bar', c['default']['foo']) - assert_equal('quxxx', c['default']['baz']) - assert_equal('bar', c['section']['foo']) - end - - def test_aset - @it['foo'] = {'bar' => 'baz'} - assert_equal({'bar' => 'baz'}, @it['foo']) - @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'} - assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - - # OpenSSL::Config is add only for now. - @it['foo'] = {'foo' => 'foo'} - assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - # you cannot override or remove any section and key. - @it['foo'] = {} - assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - end - - def test_each - # each returns [section, key, value] array. - ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] } - assert_equal(4, ary.size) - assert_equal('CA_default', ary[0][0]) - assert_equal('CA_default', ary[1][0]) - assert_equal(["ca", "default_ca", "CA_default"], ary[2]) - assert_equal(["default", "HOME", "."], ary[3]) - end - - def test_to_s - c = OpenSSL::Config.parse("[empty]\n") - assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s) - end - - def test_inspect - assert_match(/#/, @it.inspect) - end - - def test_freeze - c = OpenSSL::Config.new - c['foo'] = [['key', 'value']] - c.freeze - - bug = '[ruby-core:18377]' - # RuntimeError for 1.9, TypeError for 1.8 - e = assert_raise(TypeError, bug) do - c['foo'] = [['key', 'wrong']] - end - assert_match(/can't modify/, e.message, bug) - end - - def test_dup - assert(!@it.sections.empty?) - c = @it.dup - assert_equal(@it.sections.sort, c.sections.sort) - @it['newsection'] = {'a' => 'b'} - assert_not_equal(@it.sections.sort, c.sections.sort) - end - - def test_clone - assert(!@it.sections.empty?) - c = @it.clone - assert_equal(@it.sections.sort, c.sections.sort) - @it['newsection'] = {'a' => 'b'} - assert_not_equal(@it.sections.sort, c.sections.sort) - end -end - -end diff --git a/test/test_digest.rb b/test/test_digest.rb deleted file mode 100644 index e47fc0a3..00000000 --- a/test/test_digest.rb +++ /dev/null @@ -1,140 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestDigest < OpenSSL::TestCase - def setup - super - @d1 = OpenSSL::Digest.new("MD5") - @d2 = OpenSSL::Digest::MD5.new - end - - def test_digest - null_hex = "d41d8cd98f00b204e9800998ecf8427e" - null_bin = [null_hex].pack("H*") - data = "DATA" - hex = "e44f9e348e41cb272efa87387728571b" - bin = [hex].pack("H*") - assert_equal(null_bin, @d1.digest) - assert_equal(null_hex, @d1.hexdigest) - @d1 << data - assert_equal(bin, @d1.digest) - assert_equal(hex, @d1.hexdigest) - assert_equal(bin, OpenSSL::Digest::MD5.digest(data)) - assert_equal(hex, OpenSSL::Digest::MD5.hexdigest(data)) - end - - def test_eql - assert(@d1 == @d2, "==") - d = @d1.clone - assert(d == @d1, "clone") - end - - def test_info - assert_equal("MD5", @d1.name, "name") - assert_equal("MD5", @d2.name, "name") - assert_equal(16, @d1.size, "size") - end - - def test_dup - @d1.update("DATA") - assert_equal(@d1.name, @d1.dup.name, "dup") - assert_equal(@d1.name, @d1.clone.name, "clone") - assert_equal(@d1.digest, @d1.clone.digest, "clone .digest") - end - - def test_reset - @d1.update("DATA") - dig1 = @d1.digest - @d1.reset - @d1.update("DATA") - dig2 = @d1.digest - assert_equal(dig1, dig2, "reset") - end - - def test_required_digests - algorithms = OpenSSL::Digest::ALGORITHMS - required = %w{MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512} - - required.each do |name| - assert_include(algorithms, name) - end - end - - def test_digest_constants - algorithms = OpenSSL::Digest::ALGORITHMS - - algorithms.each do |name| - assert_not_nil(OpenSSL::Digest.new(name)) - klass = OpenSSL::Digest.const_get(name.tr('-', '_')) - assert_not_nil(klass.new) - end - end - - def test_digest_by_oid_and_name - check_digest(OpenSSL::ASN1::ObjectId.new("MD5")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA1")) - end - - def encode16(str) - str.unpack("H*").first - end - - def test_sha2 - sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" - sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" - sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" - sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" - - assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) - assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) - assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) - assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) - - assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) - assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) - assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) - assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) - end - - def test_sha3 - pend "SHA3 is not implemented" unless OpenSSL::Digest.const_defined?(:SHA3_224) - s224 = '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7' - s256 = 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a' - s384 = '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004' - s512 = 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26' - assert_equal(OpenSSL::Digest::SHA3_224.hexdigest(""), s224) - assert_equal(OpenSSL::Digest::SHA3_256.hexdigest(""), s256) - assert_equal(OpenSSL::Digest::SHA3_384.hexdigest(""), s384) - assert_equal(OpenSSL::Digest::SHA3_512.hexdigest(""), s512) - end - - def test_digest_by_oid_and_name_sha2 - check_digest(OpenSSL::ASN1::ObjectId.new("SHA224")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA256")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA384")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA512")) - end - - def test_openssl_digest - assert_equal OpenSSL::Digest::MD5, OpenSSL::Digest("MD5") - - assert_raise NameError do - OpenSSL::Digest("no such digest") - end - end - - private - - def check_digest(oid) - d = OpenSSL::Digest.new(oid.sn) - assert_not_nil(d) - d = OpenSSL::Digest.new(oid.ln) - assert_not_nil(d) - d = OpenSSL::Digest.new(oid.oid) - assert_not_nil(d) - end -end - -end diff --git a/test/test_engine.rb b/test/test_engine.rb deleted file mode 100644 index 232ba866..00000000 --- a/test/test_engine.rb +++ /dev/null @@ -1,97 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) && defined?(OpenSSL::Engine) - -class OpenSSL::TestEngine < OpenSSL::TestCase - def test_engines_free # [ruby-dev:44173] - with_openssl <<-'end;' - OpenSSL::Engine.load("openssl") - OpenSSL::Engine.engines - OpenSSL::Engine.engines - end; - end - - def test_openssl_engine_builtin - with_openssl <<-'end;' - orig = OpenSSL::Engine.engines - pend "'openssl' is already loaded" if orig.any? { |e| e.id == "openssl" } - engine = OpenSSL::Engine.load("openssl") - assert_equal(true, engine) - assert_equal(1, OpenSSL::Engine.engines.size - orig.size) - end; - end - - def test_openssl_engine_by_id_string - with_openssl <<-'end;' - orig = OpenSSL::Engine.engines - pend "'openssl' is already loaded" if orig.any? { |e| e.id == "openssl" } - engine = get_engine - assert_not_nil(engine) - assert_equal(1, OpenSSL::Engine.engines.size - orig.size) - end; - end - - def test_openssl_engine_id_name_inspect - with_openssl <<-'end;' - engine = get_engine - assert_equal("openssl", engine.id) - assert_not_nil(engine.name) - assert_not_nil(engine.inspect) - end; - end - - def test_openssl_engine_digest_sha1 - with_openssl <<-'end;' - engine = get_engine - digest = engine.digest("SHA1") - assert_not_nil(digest) - data = "test" - assert_equal(OpenSSL::Digest::SHA1.digest(data), digest.digest(data)) - end; - end - - def test_openssl_engine_cipher_rc4 - begin - OpenSSL::Cipher.new("rc4") - rescue OpenSSL::Cipher::CipherError - pend "RC4 is not supported" - end - - with_openssl(<<-'end;', ignore_stderr: true) - engine = get_engine - algo = "RC4" - data = "a" * 1000 - key = OpenSSL::Random.random_bytes(16) - encrypted = crypt_data(data, key, :encrypt) { engine.cipher(algo) } - decrypted = crypt_data(encrypted, key, :decrypt) { OpenSSL::Cipher.new(algo) } - assert_equal(data, decrypted) - end; - end - - private - - # this is required because OpenSSL::Engine methods change global state - def with_openssl(code, **opts) - assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;", **opts) - require #{__FILE__.dump} - include OpenSSL::TestEngine::Utils - #{code} - end; - end - - module Utils - def get_engine - OpenSSL::Engine.by_id("openssl") - end - - def crypt_data(data, key, mode) - cipher = yield - cipher.send mode - cipher.key = key - cipher.update(data) + cipher.final - end - end -end - -end diff --git a/test/test_fips.rb b/test/test_fips.rb deleted file mode 100644 index 8cd474f9..00000000 --- a/test/test_fips.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestFIPS < OpenSSL::TestCase - def test_fips_mode_is_reentrant - OpenSSL.fips_mode = false - OpenSSL.fips_mode = false - end - - def test_fips_mode_get - return unless OpenSSL::OPENSSL_FIPS - assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;") - require #{__FILE__.dump} - - begin - OpenSSL.fips_mode = true - assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true" - - OpenSSL.fips_mode = false - assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false" - rescue OpenSSL::OpenSSLError - pend "Could not set FIPS mode (OpenSSL::OpenSSLError: \#$!); skipping" - end - end; - end -end - -end diff --git a/test/test_hmac.rb b/test/test_hmac.rb deleted file mode 100644 index 9cb3c5a8..00000000 --- a/test/test_hmac.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestHMAC < OpenSSL::TestCase - def test_hmac - # RFC 2202 2. Test Cases for HMAC-MD5 - hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "MD5") - hmac.update("Hi There") - assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), hmac.digest - assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hmac.hexdigest - - # RFC 4231 4.2. Test Case 1 - hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "SHA224") - hmac.update("Hi There") - assert_equal ["896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"].pack("H*"), hmac.digest - assert_equal "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", hmac.hexdigest - end - - def test_dup - h1 = OpenSSL::HMAC.new("KEY", "MD5") - h1.update("DATA") - h = h1.dup - assert_equal(h1.digest, h.digest, "dup digest") - end - - def test_binary_update - data = "Lücíllé: Bût... yøü sáîd hé wås âlrîght.\nDr. Físhmån: Yés. Hé's løst hîs léft hånd, sø hé's gøîng tø bé åll rîght" - hmac = OpenSSL::HMAC.new("qShkcwN92rsM9nHfdnP4ugcVU2iI7iM/trovs01ZWok", "SHA256") - result = hmac.update(data).hexdigest - assert_equal "a13984b929a07912e4e21c5720876a8e150d6f67f854437206e7f86547248396", result - end - - def test_reset_keep_key - h1 = OpenSSL::HMAC.new("KEY", "MD5") - first = h1.update("test").hexdigest - h1.reset - second = h1.update("test").hexdigest - assert_equal first, second - end - - def test_eq - h1 = OpenSSL::HMAC.new("KEY", "MD5") - h2 = OpenSSL::HMAC.new("KEY", OpenSSL::Digest.new("MD5")) - h3 = OpenSSL::HMAC.new("FOO", "MD5") - - assert_equal h1, h2 - refute_equal h1, h2.digest - refute_equal h1, h3 - end -end - -end diff --git a/test/test_kdf.rb b/test/test_kdf.rb deleted file mode 100644 index f4790c96..00000000 --- a/test/test_kdf.rb +++ /dev/null @@ -1,183 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestKDF < OpenSSL::TestCase - def test_pkcs5_pbkdf2_hmac_compatibility - expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt", iterations: 1, length: 20, hash: "sha1") - assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt", 1, 20, "sha1")) - assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", 1, 20)) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 - p ="password" - s = "salt" - c = 1 - dk_len = 20 - raw = %w{ 0c 60 c8 0f 96 1f 0e 71 - f3 a9 b5 24 af 60 12 06 - 2f e0 37 a6 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 - p ="password" - s = "salt" - c = 2 - dk_len = 20 - raw = %w{ ea 6c 01 4d c7 2d 6f 8c - cd 1e d9 2a ce 1d 41 f0 - d8 de 89 57 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 - p ="password" - s = "salt" - c = 4096 - dk_len = 20 - raw = %w{ 4b 00 79 01 b7 65 48 9a - be ad 49 d9 26 f7 21 d0 - 65 a4 29 c1 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - -# takes too long! -# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20 -# p ="password" -# s = "salt" -# c = 16777216 -# dk_len = 20 -# raw = %w{ ee fe 3d 61 cd 4d a4 e4 -# e9 94 5b 3d 6b a2 15 8c -# 26 34 e9 84 } -# expected = [raw.join('')].pack('H*') -# value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") -# assert_equal(expected, value) -# end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 - p ="passwordPASSWORDpassword" - s = "saltSALTsaltSALTsaltSALTsaltSALTsalt" - c = 4096 - dk_len = 25 - - raw = %w{ 3d 2e ec 4f e4 1c 84 9b - 80 c8 d8 36 62 c0 e4 4a - 8b 29 1a 96 4c f2 f0 70 - 38 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 - p ="pass\0word" - s = "sa\0lt" - c = 4096 - dk_len = 16 - raw = %w{ 56 fa 6a a7 55 48 09 9d - cc 37 d7 f0 34 25 e0 c3 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha256_c_20000_len_32 - #unfortunately no official test vectors available yet for SHA-2 - p ="password" - s = OpenSSL::Random.random_bytes(16) - c = 20000 - dk_len = 32 - value1 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") - value2 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") - assert_equal(value1, value2) - end - - def test_scrypt_rfc7914_first - pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 - pass = "" - salt = "" - n = 16 - r = 1 - p = 1 - dklen = 64 - expected = B(%w{ 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 - f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 - fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 - e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 }) - assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) - end - - def test_scrypt_rfc7914_second - pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 - pass = "password" - salt = "NaCl" - n = 1024 - r = 8 - p = 16 - dklen = 64 - expected = B(%w{ fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe - 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 - 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da - c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 }) - assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) - end - - def test_hkdf_rfc5869_test_case_1 - pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 - hash = "sha256" - ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") - salt = B("000102030405060708090a0b0c") - info = B("f0f1f2f3f4f5f6f7f8f9") - l = 42 - - okm = B("3cb25f25faacd57a90434f64d0362f2a" \ - "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" \ - "34007208d5b887185865") - assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) - end - - def test_hkdf_rfc5869_test_case_3 - pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 - hash = "sha256" - ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") - salt = B("") - info = B("") - l = 42 - - okm = B("8da4e775a563c18f715f802a063c5a31" \ - "b8a11f5c5ee1879ec3454e5f3c738d2d" \ - "9d201395faa4b61a96c8") - assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) - end - - def test_hkdf_rfc5869_test_case_4 - pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 - hash = "sha1" - ikm = B("0b0b0b0b0b0b0b0b0b0b0b") - salt = B("000102030405060708090a0b0c") - info = B("f0f1f2f3f4f5f6f7f8f9") - l = 42 - - okm = B("085a01ea1b10f36933068b56efa5ad81" \ - "a4f14b822f5b091568a9cdd4f155fda2" \ - "c22e422478d305f3f896") - assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) - end - - private - - def B(ary) - [Array(ary).join].pack("H*") - end -end - -end diff --git a/test/test_ns_spki.rb b/test/test_ns_spki.rb deleted file mode 100644 index 052507de..00000000 --- a/test/test_ns_spki.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestNSSPI < OpenSSL::TestCase - def setup - super - # This request data is adopt from the specification of - # "Netscape Extensions for User Key Generation". - # -- http://wp.netscape.com/eng/security/comm4-keygen.html - @b64 = +"MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV" - @b64 << "WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID" - @b64 << "AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S" - @b64 << "r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW" - @b64 << "i0//rgBvmco=" - end - - def test_build_data - key1 = Fixtures.pkey("rsa1024") - key2 = Fixtures.pkey("rsa2048") - spki = OpenSSL::Netscape::SPKI.new - spki.challenge = "RandomString" - spki.public_key = key1.public_key - spki.sign(key1, OpenSSL::Digest::SHA1.new) - assert(spki.verify(spki.public_key)) - assert(spki.verify(key1.public_key)) - assert(!spki.verify(key2.public_key)) - - der = spki.to_der - spki = OpenSSL::Netscape::SPKI.new(der) - assert_equal("RandomString", spki.challenge) - assert_equal(key1.public_key.to_der, spki.public_key.to_der) - assert(spki.verify(spki.public_key)) - assert_not_nil(spki.to_text) - end - - def test_decode_data - spki = OpenSSL::Netscape::SPKI.new(@b64) - assert_equal(@b64, spki.to_pem) - assert_equal(@b64.unpack("m").first, spki.to_der) - assert_equal("MozillaIsMyFriend", spki.challenge) - assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) - - spki = OpenSSL::Netscape::SPKI.new(@b64.unpack("m").first) - assert_equal(@b64, spki.to_pem) - assert_equal(@b64.unpack("m").first, spki.to_der) - assert_equal("MozillaIsMyFriend", spki.challenge) - assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) - end -end - -end diff --git a/test/test_ocsp.rb b/test/test_ocsp.rb deleted file mode 100644 index a490a153..00000000 --- a/test/test_ocsp.rb +++ /dev/null @@ -1,311 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestOCSP < OpenSSL::TestCase - def setup - super - # @ca_cert - # | - # @cert - # |----------| - # @cert2 @ocsp_cert - - ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") - @ca_key = Fixtures.pkey("rsa1024") - ca_exts = [ - ["basicConstraints", "CA:TRUE", true], - ["keyUsage", "cRLSign,keyCertSign", true], - ] - @ca_cert = OpenSSL::TestUtils.issue_cert( - ca_subj, @ca_key, 1, ca_exts, nil, nil) - - cert_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA2") - @cert_key = Fixtures.pkey("rsa1024") - cert_exts = [ - ["basicConstraints", "CA:TRUE", true], - ["keyUsage", "cRLSign,keyCertSign", true], - ] - @cert = OpenSSL::TestUtils.issue_cert( - cert_subj, @cert_key, 5, cert_exts, @ca_cert, @ca_key) - - cert2_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert") - @cert2_key = Fixtures.pkey("rsa1024") - cert2_exts = [ - ] - @cert2 = OpenSSL::TestUtils.issue_cert( - cert2_subj, @cert2_key, 10, cert2_exts, @cert, @cert_key) - - ocsp_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCAOCSP") - @ocsp_key = Fixtures.pkey("rsa2048") - ocsp_exts = [ - ["extendedKeyUsage", "OCSPSigning", true], - ] - @ocsp_cert = OpenSSL::TestUtils.issue_cert( - ocsp_subj, @ocsp_key, 100, ocsp_exts, @cert, @cert_key) - end - - def test_new_certificate_id - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - assert_kind_of OpenSSL::OCSP::CertificateId, cid - assert_equal @cert.serial, cid.serial - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new) - assert_kind_of OpenSSL::OCSP::CertificateId, cid - assert_equal @cert.serial, cid.serial - end - - def test_certificate_id_issuer_name_hash - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - assert_equal OpenSSL::Digest::SHA1.hexdigest(@cert.issuer.to_der), cid.issuer_name_hash - assert_equal "d91f736ac4dc3242f0fb9b77a3149bd83c5c43d0", cid.issuer_name_hash - end - - def test_certificate_id_issuer_key_hash - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - assert_equal OpenSSL::Digest::SHA1.hexdigest(OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), cid.issuer_key_hash - assert_equal "d1fef9fbf8ae1bc160cbfa03e2596dd873089213", cid.issuer_key_hash - end - - def test_certificate_id_hash_algorithm - cid_sha1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - cid_sha256 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new) - assert_equal "sha1", cid_sha1.hash_algorithm - assert_equal "sha256", cid_sha256.hash_algorithm - end - - def test_certificate_id_der - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - der = cid.to_der - asn1 = OpenSSL::ASN1.decode(der) - # hash algorithm defaults to SHA-1 - assert_equal OpenSSL::ASN1.ObjectId("SHA1").to_der, asn1.value[0].value[0].to_der - assert_equal [cid.issuer_name_hash].pack("H*"), asn1.value[1].value - assert_equal [cid.issuer_key_hash].pack("H*"), asn1.value[2].value - assert_equal @cert.serial, asn1.value[3].value - assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der - assert_equal der, OpenSSL::OCSP::CertificateId.new(asn1).to_der - end - - def test_certificate_id_dup - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - assert_equal cid.to_der, cid.dup.to_der - end - - def test_request_der - request = OpenSSL::OCSP::Request.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - request.add_certid(cid) - request.sign(@cert, @cert_key, [@ca_cert], 0) - asn1 = OpenSSL::ASN1.decode(request.to_der) - assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der - assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der - assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der - assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der - assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der - end - - def test_request_sign_verify - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - store = OpenSSL::X509::Store.new.add_cert(@ca_cert) - - # with signer cert - req = OpenSSL::OCSP::Request.new.add_certid(cid) - req.sign(@cert, @cert_key, []) - assert_equal true, req.verify([], store) - - # without signer cert - req = OpenSSL::OCSP::Request.new.add_certid(cid) - req.sign(@cert, @cert_key, nil) - assert_equal false, req.verify([@cert2], store) - assert_equal false, req.verify([], store) # no signer - assert_equal false, req.verify([], store, OpenSSL::OCSP::NOVERIFY) - - assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) - ret = req.verify([@cert], store) - if ret || openssl?(1, 0, 2) - assert_equal true, ret - else - # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when - # OCSP_NOINTERN is not specified. - # fixed by OpenSSL 1.0.1j, 1.0.2 - pend "RT2560: ocsp_req_find_signer" - end - - # not signed - req = OpenSSL::OCSP::Request.new.add_certid(cid) - assert_equal false, req.verify([], store) - end - - def test_request_is_signed - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - req = OpenSSL::OCSP::Request.new - req.add_certid(cid) - assert_equal false, req.signed? - assert_equal false, OpenSSL::OCSP::Request.new(req.to_der).signed? - req.sign(@cert, @cert_key, []) - assert_equal true, req.signed? - assert_equal true, OpenSSL::OCSP::Request.new(req.to_der).signed? - end - - def test_request_nonce - req0 = OpenSSL::OCSP::Request.new - req1 = OpenSSL::OCSP::Request.new.add_nonce("NONCE") - req2 = OpenSSL::OCSP::Request.new.add_nonce("ABCDE") - bres = OpenSSL::OCSP::BasicResponse.new - assert_equal 2, req0.check_nonce(bres) - bres.copy_nonce(req1) - assert_equal 3, req0.check_nonce(bres) - assert_equal 1, req1.check_nonce(bres) - bres.add_nonce("NONCE") - assert_equal 1, req1.check_nonce(bres) - assert_equal 0, req2.check_nonce(bres) - end - - def test_request_dup - request = OpenSSL::OCSP::Request.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - request.add_certid(cid) - assert_equal request.to_der, request.dup.to_der - end - - def test_basic_response_der - bres = OpenSSL::OCSP::BasicResponse.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) - bres.add_nonce("NONCE") - bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) - der = bres.to_der - asn1 = OpenSSL::ASN1.decode(der) - assert_equal OpenSSL::ASN1.Sequence([@ocsp_cert, @ca_cert]).to_der, asn1.value[3].value[0].to_der - assert_equal der, OpenSSL::OCSP::BasicResponse.new(der).to_der - rescue TypeError - if /GENERALIZEDTIME/ =~ $!.message - pend "OCSP_basic_sign() is broken" - else - raise - end - end - - def test_basic_response_sign_verify - store = OpenSSL::X509::Store.new.add_cert(@ca_cert) - - # signed by CA - bres = OpenSSL::OCSP::BasicResponse.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, "SHA256") - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, []) - bres.sign(@ca_cert, @ca_key, nil, 0, "SHA256") - assert_equal false, bres.verify([], store) # signer not found - assert_equal true, bres.verify([@ca_cert], store) - bres.sign(@ca_cert, @ca_key, [], 0, "SHA256") - assert_equal true, bres.verify([], store) - - # signed by OCSP signer - bres = OpenSSL::OCSP::BasicResponse.new - cid = OpenSSL::OCSP::CertificateId.new(@cert2, @cert) - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, []) - bres.sign(@ocsp_cert, @ocsp_key, [@cert]) - assert_equal true, bres.verify([], store) - assert_equal false, bres.verify([], store, OpenSSL::OCSP::NOCHAIN) - # OpenSSL had a bug on this; test that our workaround works - bres.sign(@ocsp_cert, @ocsp_key, []) - assert_equal true, bres.verify([@cert], store) - end - - def test_basic_response_dup - bres = OpenSSL::OCSP::BasicResponse.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) - bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) - assert_equal bres.to_der, bres.dup.to_der - end - - def test_basic_response_response_operations - bres = OpenSSL::OCSP::BasicResponse.new - now = Time.at(Time.now.to_i) - cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest::SHA1.new) - cid3 = OpenSSL::OCSP::CertificateId.new(@ca_cert, @ca_cert, OpenSSL::Digest::SHA1.new) - bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil) - bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, []) - - assert_equal 2, bres.responses.size - single = bres.responses.first - assert_equal cid1.to_der, single.certid.to_der - assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, single.cert_status - assert_equal OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, single.revocation_reason - assert_equal now - 400, single.revocation_time - assert_in_delta (now - 301), single.this_update, 1 - assert_equal nil, single.next_update - assert_equal [], single.extensions - - assert_equal cid2.to_der, bres.find_response(cid2).certid.to_der - assert_equal nil, bres.find_response(cid3) - end - - def test_single_response_der - bres = OpenSSL::OCSP::BasicResponse.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, nil) - single = bres.responses[0] - der = single.to_der - asn1 = OpenSSL::ASN1.decode(der) - assert_equal :CONTEXT_SPECIFIC, asn1.value[1].tag_class - assert_equal 0, asn1.value[1].tag # good - assert_equal der, OpenSSL::OCSP::SingleResponse.new(der).to_der - end - - def test_single_response_check_validity - bres = OpenSSL::OCSP::BasicResponse.new - cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest::SHA1.new) - bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, -50, []) - bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, []) - bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil) - - single1 = bres.responses[0] - assert_equal false, single1.check_validity - assert_equal false, single1.check_validity(30) - assert_equal true, single1.check_validity(60) - single2 = bres.responses[1] - assert_equal true, single2.check_validity - assert_equal true, single2.check_validity(0, 500) - assert_equal false, single2.check_validity(0, 200) - single3 = bres.responses[2] - assert_equal false, single3.check_validity - end - - def test_response - bres = OpenSSL::OCSP::BasicResponse.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) - bres.sign(@ocsp_cert, @ocsp_key, []) - res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) - - assert_equal bres.to_der, res.basic.to_der - assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, res.status - end - - def test_response_der - bres = OpenSSL::OCSP::BasicResponse.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) - bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) - res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) - der = res.to_der - asn1 = OpenSSL::ASN1.decode(der) - assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, asn1.value[0].value - assert_equal OpenSSL::ASN1.ObjectId("basicOCSPResponse").to_der, asn1.value[1].value[0].value[0].to_der - assert_equal bres.to_der, asn1.value[1].value[0].value[1].value - assert_equal der, OpenSSL::OCSP::Response.new(der).to_der - end - - def test_response_dup - bres = OpenSSL::OCSP::BasicResponse.new - bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) - res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) - assert_equal res.to_der, res.dup.to_der - end -end - -end diff --git a/test/test_ossl.rb b/test/test_ossl.rb deleted file mode 100644 index f83e8136..00000000 --- a/test/test_ossl.rb +++ /dev/null @@ -1,65 +0,0 @@ -# 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 diff --git a/test/test_pair.rb b/test/test_pair.rb deleted file mode 100644 index e9cf98df..00000000 --- a/test/test_pair.rb +++ /dev/null @@ -1,523 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' -require_relative 'ut_eof' - -if defined?(OpenSSL) - -module OpenSSL::SSLPairM - def setup - svr_dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") - ee_exts = [ - ["keyUsage", "keyEncipherment,digitalSignature", true], - ] - @svr_key = OpenSSL::TestUtils::Fixtures.pkey("rsa-1") - @svr_cert = issue_cert(svr_dn, @svr_key, 1, ee_exts, nil, nil) - end - - def ssl_pair - host = "127.0.0.1" - tcps = create_tcp_server(host, 0) - port = tcps.connect_address.ip_port - - th = Thread.new { - sctx = OpenSSL::SSL::SSLContext.new - sctx.cert = @svr_cert - sctx.key = @svr_key - sctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } - sctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION - ssls = OpenSSL::SSL::SSLServer.new(tcps, sctx) - ns = ssls.accept - ssls.close - ns - } - - tcpc = create_tcp_client(host, port) - c = OpenSSL::SSL::SSLSocket.new(tcpc) - c.connect - s = th.value - - yield c, s - ensure - tcpc&.close - tcps&.close - s&.close - end -end - -module OpenSSL::SSLPair - include OpenSSL::SSLPairM - - def create_tcp_server(host, port) - TCPServer.new(host, port) - end - - def create_tcp_client(host, port) - TCPSocket.new(host, port) - end -end - -module OpenSSL::SSLPairLowlevelSocket - include OpenSSL::SSLPairM - - def create_tcp_server(host, port) - Addrinfo.tcp(host, port).listen - end - - def create_tcp_client(host, port) - Addrinfo.tcp(host, port).connect - end -end - -module OpenSSL::TestEOF1M - def open_file(content) - ssl_pair { |s1, s2| - begin - th = Thread.new { s2 << content; s2.close } - yield s1 - ensure - th&.join - end - } - end -end - -module OpenSSL::TestEOF2M - def open_file(content) - ssl_pair { |s1, s2| - begin - th = Thread.new { s1 << content; s1.close } - yield s2 - ensure - th&.join - end - } - end -end - -module OpenSSL::TestPairM - def test_getc - ssl_pair {|s1, s2| - s1 << "a" - assert_equal(?a, s2.getc) - } - end - - def test_gets - ssl_pair {|s1, s2| - s1 << "abc\n\n$def123ghi" - s1.close - ret = s2.gets - assert_equal Encoding::BINARY, ret.encoding - assert_equal "abc\n", ret - assert_equal "\n$", s2.gets("$") - assert_equal "def123", s2.gets(/\d+/) - assert_equal "ghi", s2.gets - assert_equal nil, s2.gets - } - end - - def test_gets_eof_limit - ssl_pair {|s1, s2| - s1.write("hello") - s1.close # trigger EOF - assert_match "hello", s2.gets("\n", 6), "[ruby-core:70149] [Bug #11400]" - } - end - - def test_readpartial - ssl_pair {|s1, s2| - s2.write "a\nbcd" - assert_equal("a\n", s1.gets) - result = String.new - result << s1.readpartial(10) until result.length == 3 - assert_equal("bcd", result) - s2.write "efg" - result = String.new - result << s1.readpartial(10) until result.length == 3 - assert_equal("efg", result) - s2.close - assert_raise(EOFError) { s1.readpartial(10) } - assert_raise(EOFError) { s1.readpartial(10) } - assert_equal("", s1.readpartial(0)) - } - end - - def test_readall - ssl_pair {|s1, s2| - s2.close - assert_equal("", s1.read) - } - end - - def test_readline - ssl_pair {|s1, s2| - s2.close - assert_raise(EOFError) { s1.readline } - } - end - - def test_puts_meta - ssl_pair {|s1, s2| - begin - old = $/ - $/ = '*' - s1.puts 'a' - ensure - $/ = old - end - s1.close - assert_equal("a\n", s2.read) - } - end - - def test_puts_empty - ssl_pair {|s1, s2| - s1.puts - s1.close - assert_equal("\n", s2.read) - } - end - - def test_multibyte_read_write - # German a umlaut - auml = [%w{ C3 A4 }.join('')].pack('H*') - auml.force_encoding(Encoding::UTF_8) - bsize = auml.bytesize - - ssl_pair { |s1, s2| - assert_equal bsize, s1.write(auml) - read = s2.read(bsize) - assert_equal Encoding::ASCII_8BIT, read.encoding - assert_equal bsize, read.bytesize - assert_equal auml, read.force_encoding(Encoding::UTF_8) - - s1.puts(auml) - read = s2.gets - assert_equal Encoding::ASCII_8BIT, read.encoding - assert_equal bsize + 1, read.bytesize - assert_equal auml + "\n", read.force_encoding(Encoding::UTF_8) - } - end - - def test_read_nonblock - ssl_pair {|s1, s2| - err = nil - assert_raise(OpenSSL::SSL::SSLErrorWaitReadable) { - begin - s2.read_nonblock(10) - ensure - err = $! - end - } - assert_kind_of(IO::WaitReadable, err) - s1.write "abc\ndef\n" - IO.select([s2]) - assert_equal("ab", s2.read_nonblock(2)) - assert_equal("c\n", s2.gets) - ret = nil - assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10) } - assert_equal("def\n", ret) - s1.close - IO.select([s2]) - assert_raise(EOFError) { s2.read_nonblock(10) } - } - end - - def test_read_nonblock_no_exception - ssl_pair {|s1, s2| - assert_equal :wait_readable, s2.read_nonblock(10, exception: false) - s1.write "abc\ndef\n" - IO.select([s2]) - assert_equal("ab", s2.read_nonblock(2, exception: false)) - assert_equal("c\n", s2.gets) - ret = nil - assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10, exception: false) } - assert_equal("def\n", ret) - s1.close - IO.select([s2]) - assert_equal(nil, s2.read_nonblock(10, exception: false)) - } - end - - def test_read_with_outbuf - ssl_pair { |s1, s2| - s1.write("abc\n") - buf = String.new - ret = s2.read(2, buf) - assert_same ret, buf - assert_equal "ab", ret - - buf = +"garbage" - ret = s2.read(2, buf) - assert_same ret, buf - assert_equal "c\n", ret - - buf = +"garbage" - assert_equal :wait_readable, s2.read_nonblock(100, buf, exception: false) - assert_equal "", buf - - s1.close - buf = +"garbage" - assert_equal nil, s2.read(100, buf) - assert_equal "", buf - } - end - - def test_write_nonblock - ssl_pair {|s1, s2| - assert_equal 3, s1.write_nonblock("foo") - assert_equal "foo", s2.read(3) - - data = "x" * 16384 - written = 0 - while true - begin - written += s1.write_nonblock(data) - rescue IO::WaitWritable, IO::WaitReadable - break - end - end - assert written > 0 - assert_equal written, s2.read(written).bytesize - } - end - - def test_write_nonblock_no_exceptions - ssl_pair {|s1, s2| - assert_equal 3, s1.write_nonblock("foo", exception: false) - assert_equal "foo", s2.read(3) - - data = "x" * 16384 - written = 0 - while true - case ret = s1.write_nonblock(data, exception: false) - when :wait_readable, :wait_writable - break - else - written += ret - end - end - assert written > 0 - assert_equal written, s2.read(written).bytesize - } - end - - def test_write_nonblock_with_buffered_data - ssl_pair {|s1, s2| - s1.write "foo" - s1.write_nonblock("bar") - s1.write "baz" - s1.close - assert_equal("foobarbaz", s2.read) - } - end - - def test_write_nonblock_with_buffered_data_no_exceptions - ssl_pair {|s1, s2| - s1.write "foo" - s1.write_nonblock("bar", exception: false) - s1.write "baz" - s1.close - assert_equal("foobarbaz", s2.read) - } - end - - def test_write_nonblock_retry - ssl_pair {|s1, s2| - # fill up a socket so we hit EAGAIN - written = String.new - n = 0 - buf = 'a' * 4099 - case ret = s1.write_nonblock(buf, exception: false) - when :wait_readable then break - when :wait_writable then break - when Integer - written << buf - n += ret - exp = buf.bytesize - if ret != exp - buf = buf.byteslice(ret, exp - ret) - end - end while true - assert_kind_of Symbol, ret - - # make more space for subsequent write: - readed = s2.read(n) - assert_equal written, readed - - # this fails if SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is missing: - buf2 = Marshal.load(Marshal.dump(buf)) - assert_kind_of Integer, s1.write_nonblock(buf2, exception: false) - } - end - - def test_write_zero - ssl_pair {|s1, s2| - assert_equal 0, s2.write_nonblock('', exception: false) - assert_kind_of Symbol, s1.read_nonblock(1, exception: false) - assert_equal 0, s2.syswrite('') - assert_kind_of Symbol, s1.read_nonblock(1, exception: false) - assert_equal 0, s2.write('') - assert_kind_of Symbol, s1.read_nonblock(1, exception: false) - } - end - - def test_write_multiple_arguments - ssl_pair {|s1, s2| - str1 = "foo"; str2 = "bar" - assert_equal 6, s1.write(str1, str2) - s1.close - assert_equal "foobar", s2.read - } - end - - def test_partial_tls_record_read_nonblock - ssl_pair { |s1, s2| - # the beginning of a TLS record - s1.io.write("\x17") - # should raise a IO::WaitReadable since a full TLS record is not available - # for reading - assert_raise(IO::WaitReadable) { s2.read_nonblock(1) } - } - end - - def tcp_pair - host = "127.0.0.1" - serv = TCPServer.new(host, 0) - port = serv.connect_address.ip_port - sock1 = TCPSocket.new(host, port) - sock2 = serv.accept - serv.close - [sock1, sock2] - ensure - serv.close if serv && !serv.closed? - end - - def test_connect_accept_nonblock_no_exception - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.cert = @svr_cert - ctx2.key = @svr_key - ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } - - sock1, sock2 = tcp_pair - - s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) - accepted = s2.accept_nonblock(exception: false) - assert_equal :wait_readable, accepted - - ctx1 = OpenSSL::SSL::SSLContext.new - s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) - th = Thread.new do - rets = [] - begin - rv = s1.connect_nonblock(exception: false) - rets << rv - case rv - when :wait_writable - IO.select(nil, [s1], nil, 5) - when :wait_readable - IO.select([s1], nil, nil, 5) - end - end until rv == s1 - rets - end - - until th.join(0.01) - accepted = s2.accept_nonblock(exception: false) - assert_include([s2, :wait_readable, :wait_writable ], accepted) - end - - rets = th.value - assert_instance_of Array, rets - rets.each do |rv| - assert_include([s1, :wait_readable, :wait_writable ], rv) - end - ensure - th.join if th - s1.close if s1 - s2.close if s2 - sock1.close if sock1 - sock2.close if sock2 - accepted.close if accepted.respond_to?(:close) - end - - def test_connect_accept_nonblock - ctx = OpenSSL::SSL::SSLContext.new - ctx.cert = @svr_cert - ctx.key = @svr_key - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } - - sock1, sock2 = tcp_pair - - th = Thread.new { - s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx) - 5.times { - begin - break s2.accept_nonblock - rescue IO::WaitReadable - IO.select([s2], nil, nil, 1) - rescue IO::WaitWritable - IO.select(nil, [s2], nil, 1) - end - sleep 0.2 - } - } - - s1 = OpenSSL::SSL::SSLSocket.new(sock1) - 5.times { - begin - break s1.connect_nonblock - rescue IO::WaitReadable - IO.select([s1], nil, nil, 1) - rescue IO::WaitWritable - IO.select(nil, [s1], nil, 1) - end - sleep 0.2 - } - - s2 = th.value - - s1.print "a\ndef" - assert_equal("a\n", s2.gets) - ensure - sock1&.close - sock2&.close - th&.join - end -end - -class OpenSSL::TestEOF1 < OpenSSL::TestCase - include OpenSSL::TestEOF - include OpenSSL::SSLPair - include OpenSSL::TestEOF1M -end - -class OpenSSL::TestEOF1LowlevelSocket < OpenSSL::TestCase - include OpenSSL::TestEOF - include OpenSSL::SSLPairLowlevelSocket - include OpenSSL::TestEOF1M -end - -class OpenSSL::TestEOF2 < OpenSSL::TestCase - include OpenSSL::TestEOF - include OpenSSL::SSLPair - include OpenSSL::TestEOF2M -end - -class OpenSSL::TestEOF2LowlevelSocket < OpenSSL::TestCase - include OpenSSL::TestEOF - include OpenSSL::SSLPairLowlevelSocket - include OpenSSL::TestEOF2M -end - -class OpenSSL::TestPair < OpenSSL::TestCase - include OpenSSL::SSLPair - include OpenSSL::TestPairM -end - -class OpenSSL::TestPairLowlevelSocket < OpenSSL::TestCase - include OpenSSL::SSLPairLowlevelSocket - include OpenSSL::TestPairM -end - -end diff --git a/test/test_pkcs12.rb b/test/test_pkcs12.rb deleted file mode 100644 index fdbe753b..00000000 --- a/test/test_pkcs12.rb +++ /dev/null @@ -1,313 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -module OpenSSL - class TestPKCS12 < OpenSSL::TestCase - def setup - super - ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], - ] - @cacert = issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) - - inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA") - inter_ca_key = OpenSSL::PKey.read <<-_EOS_ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDp7hIG0SFMG/VWv1dBUWziAPrNmkMXJgTCAoB7jffzRtyyN04K -oq/89HAszTMStZoMigQURfokzKsjpUp8OYCAEsBtt9d5zPndWMz/gHN73GrXk3LT -ZsxEn7Xv5Da+Y9F/Hx2QZUHarV5cdZixq2NbzWGwrToogOQMh2pxN3Z/0wIDAQAB -AoGBAJysUyx3olpsGzv3OMRJeahASbmsSKTXVLZvoIefxOINosBFpCIhZccAG6UV -5c/xCvS89xBw8aD15uUfziw3AuT8QPEtHCgfSjeT7aWzBfYswEgOW4XPuWr7EeI9 -iNHGD6z+hCN/IQr7FiEBgTp6A+i/hffcSdR83fHWKyb4M7TRAkEA+y4BNd668HmC -G5MPRx25n6LixuBxrNp1umfjEI6UZgEFVpYOg4agNuimN6NqM253kcTR94QNTUs5 -Kj3EhG1YWwJBAO5rUjiOyCNVX2WUQrOMYK/c1lU7fvrkdygXkvIGkhsPoNRzLPeA -HGJszKtrKD8bNihWpWNIyqKRHfKVD7yXT+kCQGCAhVCIGTRoypcDghwljHqLnysf -ci0h5ZdPcIqc7ODfxYhFsJ/Rql5ONgYsT5Ig/+lOQAkjf+TRYM4c2xKx2/8CQBvG -jv6dy70qDgIUgqzONtlmHeYyFzn9cdBO5sShdVYHvRHjFSMEXsosqK9zvW2UqvuK -FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3 -Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= ------END RSA PRIVATE KEY----- - _EOS_ - @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, Fixtures.pkey("rsa2048")) - - exts = [ - ["keyUsage","digitalSignature",true], - ["subjectKeyIdentifier","hash",false], - ] - ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate") - @mykey = Fixtures.pkey("rsa1024") - @mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key) - end - - def test_create - pkcs12 = OpenSSL::PKCS12.create( - "omg", - "hello", - @mykey, - @mycert - ) - assert_equal @mycert.to_der, pkcs12.certificate.to_der - assert_equal @mykey.to_der, pkcs12.key.to_der - assert_nil pkcs12.ca_certs - end - - def test_create_no_pass - pkcs12 = OpenSSL::PKCS12.create( - nil, - "hello", - @mykey, - @mycert - ) - assert_equal @mycert.to_der, pkcs12.certificate.to_der - assert_equal @mykey.to_der, pkcs12.key.to_der - assert_nil pkcs12.ca_certs - - decoded = OpenSSL::PKCS12.new(pkcs12.to_der) - assert_cert @mycert, decoded.certificate - end - - def test_create_with_chain - chain = [@inter_cacert, @cacert] - - pkcs12 = OpenSSL::PKCS12.create( - "omg", - "hello", - @mykey, - @mycert, - chain - ) - assert_equal chain, pkcs12.ca_certs - end - - def test_create_with_chain_decode - chain = [@cacert, @inter_cacert] - - passwd = "omg" - - pkcs12 = OpenSSL::PKCS12.create( - passwd, - "hello", - @mykey, - @mycert, - chain - ) - - decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd) - assert_equal chain.size, decoded.ca_certs.size - assert_include_cert @cacert, decoded.ca_certs - assert_include_cert @inter_cacert, decoded.ca_certs - assert_cert @mycert, decoded.certificate - assert_equal @mykey.to_der, decoded.key.to_der - end - - def test_create_with_bad_nid - assert_raise(ArgumentError) do - OpenSSL::PKCS12.create( - "omg", - "hello", - @mykey, - @mycert, - [], - "foo" - ) - end - end - - def test_create_with_itr - OpenSSL::PKCS12.create( - "omg", - "hello", - @mykey, - @mycert, - [], - nil, - nil, - 2048 - ) - - assert_raise(TypeError) do - OpenSSL::PKCS12.create( - "omg", - "hello", - @mykey, - @mycert, - [], - nil, - nil, - "omg" - ) - end - end - - def test_create_with_mac_itr - OpenSSL::PKCS12.create( - "omg", - "hello", - @mykey, - @mycert, - [], - nil, - nil, - nil, - 2048 - ) - - assert_raise(TypeError) do - OpenSSL::PKCS12.create( - "omg", - "hello", - @mykey, - @mycert, - [], - nil, - nil, - nil, - "omg" - ) - end - end - - def test_new_with_one_key_and_one_cert - # generated with: - # openssl version #=> OpenSSL 1.0.2h 3 May 2016 - # openssl pkcs12 -in <@mycert> -inkey -export -out - str = <<~EOF.unpack("m").first -MIIGQQIBAzCCBgcGCSqGSIb3DQEHAaCCBfgEggX0MIIF8DCCAu8GCSqGSIb3DQEH -BqCCAuAwggLcAgEAMIIC1QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIeZPM -Rh6KiXgCAggAgIICqL6O+LCZmBzdIg6mozPF3FpY0hVbWHvTNMiDHieW3CrAanhN -YCH2/wHqH8WpFpEWwF0qEEXAWjHsIlYB4Cfqo6b7XpuZe5eVESsjNTOTMF1JCUJj -A6iNefXmCFLync1JK5LUodRDhTlKLU1WPK20X9X4vuEwHn8wt5RUb8P0E+Xh6rpS -XC4LkZKT45zF3cJa/n5+dW65ohVGNVnF9D1bCNEKHMOllK1V9omutQ9slW88hpga -LGiFsJoFOb/ESGb78KO+bd6zbX1MdKdBV+WD6t1uF/cgU65y+2A4nXs1urda+MJ7 -7iVqiB7Vnc9cANTbAkTSGNyoUDVM/NZde782/8IvddLAzUZ2EftoRDke6PvuBOVL -ljBhNWmdamrtBqzuzVZCRdWq44KZkF2Xoc9asepwIkdVmntzQF7f1Z+Ta5yg6HFp -xnr7CuM+MlHEShXkMgYtHnwAq10fDMSXIvjhi/AA5XUAusDO3D+hbtcRDcJ4uUes -dm5dhQE2qJ02Ysn4aH3o1F3RYNOzrxejHJwl0D2TCE8Ww2X342xib57+z9u03ufj -jswhiMKxy67f1LhUMq3XrT3uV6kCVXk/KUOUPcXPlPVNA5JmZeFhMp6GrtB5xJJ9 -wwBZD8UL5A2U2Mxi2OZsdUBv8eo3jnjZ284aFpt+mCjIHrLW5O0jwY8OCwSlYUoY -IY00wlabX0s82kBcIQNZbC1RSV2267ro/7A0MClc8YQ/zWN0FKY6apgtUkHJI1cL -1dc77mhnjETjwW94iLMDFy4zQfVu7IfCBqOBzygRNnqqUG66UhTs1xFnWM0mWXl/ -Zh9+AMpbRLIPaKCktIjl5juzzm+KEgkhD+707XRCFIGUYGP5bSHzGaz8PK9hj0u1 -E2SpZHUvYOcawmxtA7pmpSxl5uQjMIIC+QYJKoZIhvcNAQcBoIIC6gSCAuYwggLi -MIIC3gYLKoZIhvcNAQwKAQKgggKmMIICojAcBgoqhkiG9w0BDAEDMA4ECKB338m8 -qSzHAgIIAASCAoACFhJeqA3xx+s1qIH6udNQYY5hAL6oz7SXoGwFhDiceSyJjmAD -Dby9XWM0bPl1Gj5nqdsuI/lAM++fJeoETk+rxw8q6Ofk2zUaRRE39qgpwBwSk44o -0SAFJ6bzHpc5CFh6sZmDaUX5Lm9GtjnGFmmsPTSJT5an5JuJ9WczGBEd0nSBQhJq -xHbTGZiN8i3SXcIH531Sub+CBIFWy5lyCKgDYh/kgJFGQAaWUOjLI+7dCEESonXn -F3Jh2uPbnDF9MGJyAFoNgWFhgSpi1cf6AUi87GY4Oyur88ddJ1o0D0Kz2uw8/bpG -s3O4PYnIW5naZ8mozzbnYByEFk7PoTwM7VhoFBfYNtBoAI8+hBnPY/Y71YUojEXf -SeX6QbtkIANfzS1XuFNKElShC3DPQIHpKzaatEsfxHfP+8VOav6zcn4mioao7NHA -x7Dp6R1enFGoQOq4UNjBT8YjnkG5vW8zQHW2dAHLTJBq6x2Fzm/4Pjo/8vM1FiGl -BQdW5vfDeJ/l6NgQm3xR9ka2E2HaDqIcj1zWbN8jy/bHPFJYuF/HH8MBV/ngMIXE -vFEW/ToYv8eif0+EpUtzBsCKD4a7qYYYh87RmEVoQU96q6m+UbhpD2WztYfAPkfo -OSL9j2QHhVczhL7OAgqNeM95pOsjA9YMe7exTeqK31LYnTX8oH8WJD1xGbRSJYgu -SY6PQbumcJkc/TFPn0GeVUpiDdf83SeG50lo/i7UKQi2l1hi5Y51fQhnBnyMr68D -llSZEvSWqfDxBJkBpeg6PIYvkTpEwKRJpVQoM3uYvdqVSSnW6rydqIb+snfOrlhd -f+xCtq9xr+kHeTSqLIDRRAnMfgFRhY3IBlj6MSUwIwYJKoZIhvcNAQkVMRYEFBdb -8XGWehZ6oPj56Pf/uId46M9AMDEwITAJBgUrDgMCGgUABBRvSCB04/f8f13pp2PF -vyl2WuMdEwQIMWFFphPkIUICAggA - EOF - p12 = OpenSSL::PKCS12.new(str, "abc123") - - assert_equal @mykey.to_der, p12.key.to_der - assert_equal @mycert.subject.to_der, p12.certificate.subject.to_der - assert_equal [], Array(p12.ca_certs) - end - - def test_new_with_no_keys - # generated with: - # openssl pkcs12 -in <@mycert> -nokeys -export -out - str = <<~EOF.unpack("m").first -MIIDHAIBAzCCAuIGCSqGSIb3DQEHAaCCAtMEggLPMIICyzCCAscGCSqGSIb3DQEH -BqCCArgwggK0AgEAMIICrQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIX4+W -irqwH40CAggAgIICgOaCyo+5+6IOVoGCCL80c50bkkzAwqdXxvkKExJSdcJz2uMU -0gRrKnZEjL5wrUsN8RwZu8DvgQTEhNEkKsUgM7AWainmN/EnwohIdHZAHpm6WD67 -I9kLGp0/DHrqZrV9P2dLfhXLUSQE8PI0tqZPZ8UEABhizkViw4eISTkrOUN7pGbN -Qtx/oqgitXDuX2polbxYYDwt9vfHZhykHoKgew26SeJyZfeMs/WZ6olEI4cQUAFr -mvYGuC1AxEGTo9ERmU8Pm16j9Hr9PFk50WYe+rnk9oX3wJogQ7XUWS5kYf7XRycd -NDkNiwV/ts94bbuaGZp1YA6I48FXpIc8b5fX7t9tY0umGaWy0bARe1L7o0Y89EPe -lMg25rOM7j3uPtFG8whbSfdETSy57UxzzTcJ6UwexeaK6wb2jqEmj5AOoPLWeaX0 -LyOAszR3v7OPAcjIDYZGdrbb3MZ2f2vo2pdQfu9698BrWhXuM7Odh73RLhJVreNI -aezNOAtPyBlvGiBQBGTzRIYHSLL5Y5aVj2vWLAa7hjm5qTL5C5mFdDIo6TkEMr6I -OsexNQofEGs19kr8nARXDlcbEimk2VsPj4efQC2CEXZNzURsKca82pa62MJ8WosB -DTFd8X06zZZ4nED50vLopZvyW4fyW60lELwOyThAdG8UchoAaz2baqP0K4de44yM -Y5/yPFDu4+GoimipJfbiYviRwbzkBxYW8+958ILh0RtagLbvIGxbpaym9PqGjOzx -ShNXjLK2aAFZsEizQ8kd09quJHU/ogq2cUXdqqhmOqPnUWrJVi/VCoRB3Pv1/lE4 -mrUgr2YZ11rYvBw6g5XvNvFcSc53OKyV7SLn0dwwMTAhMAkGBSsOAwIaBQAEFEWP -1WRQykaoD4uJCpTx/wv0SLLBBAiDKI26LJK7xgICCAA= - EOF - p12 = OpenSSL::PKCS12.new(str, "abc123") - - assert_equal nil, p12.key - assert_equal nil, p12.certificate - assert_equal 1, p12.ca_certs.size - assert_equal @mycert.subject.to_der, p12.ca_certs[0].subject.to_der - end - - def test_new_with_no_certs - # generated with: - # openssl pkcs12 -inkey -nocerts -export -out - str = <<~EOF.unpack("m").first -MIIDJwIBAzCCAu0GCSqGSIb3DQEHAaCCAt4EggLaMIIC1jCCAtIGCSqGSIb3DQEH -AaCCAsMEggK/MIICuzCCArcGCyqGSIb3DQEMCgECoIICpjCCAqIwHAYKKoZIhvcN -AQwBAzAOBAg6AaYnJs84SwICCAAEggKAQzZH+fWSpcQYD1J7PsGSune85A++fLCQ -V7tacp2iv95GJkxwYmfTP176pJdgs00mceB9UJ/u9EX5nD0djdjjQjwo6sgKjY0q -cpVhZw8CMxw7kBD2dhtui0zT8z5hy03LePxsjEKsGiSbeVeeGbSfw/I6AAYbv+Uh -O/YPBGumeHj/D2WKnfsHJLQ9GAV3H6dv5VKYNxjciK7f/JEyZCuUQGIN64QFHDhJ -7fzLqd/ul3FZzJZO6a+dwvcgux09SKVXDRSeFmRCEX4b486iWhJJVspCo9P2KNne -ORrpybr3ZSwxyoICmjyo8gj0OSnEfdx9790Ej1takPqSA1wIdSdBLekbZqB0RBQg -DEuPOsXNo3QFi8ji1vu0WBRJZZSNC2hr5NL6lNR+DKxG8yzDll2j4W4BBIp22mAE -7QRX7kVxu17QJXQhOUac4Dd1qXmzebP8t6xkAxD9L7BWEN5OdiXWwSWGjVjMBneX -nYObi/3UT/aVc5WHMHK2BhCI1bwH51E6yZh06d5m0TQpYGUTWDJdWGBSrp3A+8jN -N2PMQkWBFrXP3smHoTEN4oZC4FWiPsIEyAkQsfKRhcV9lGKl2Xgq54ROTFLnwKoj -Z3zJScnq9qmNzvVZSMmDLkjLyDq0pxRxGKBvgouKkWY7VFFIwwBIJM39iDJ5NbBY -i1AQFTRsRSsZrNVPasCXrIq7bhMoJZb/YZOGBLNyJVqKUoYXhtwsajzSq54VlWft -JxsPayEd4Vi6O9EU1ahnj6qFEZiKFzsicgK2J1Rb8cYagrp0XWjHW0SBn5GVUWCg -GUokSFG/0JTdeYTo/sQuG4qNgJkOolRjpeI48Fciq5VUWLvVdKioXzAxMCEwCQYF -Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== - EOF - p12 = OpenSSL::PKCS12.new(str, "abc123") - - assert_equal @mykey.to_der, p12.key.to_der - assert_equal nil, p12.certificate - assert_equal [], Array(p12.ca_certs) - end - - def test_dup - p12 = OpenSSL::PKCS12.create("pass", "name", @mykey, @mycert) - assert_equal p12.to_der, p12.dup.to_der - end - - private - def assert_cert expected, actual - [ - :subject, - :issuer, - :serial, - :not_before, - :not_after, - ].each do |attribute| - assert_equal expected.send(attribute), actual.send(attribute) - end - assert_equal expected.to_der, actual.to_der - end - - def assert_include_cert cert, ary - der = cert.to_der - ary.each do |candidate| - if candidate.to_der == der - return true - end - end - false - end - end -end - -end diff --git a/test/test_pkcs7.rb b/test/test_pkcs7.rb deleted file mode 100644 index d0d9dcaf..00000000 --- a/test/test_pkcs7.rb +++ /dev/null @@ -1,309 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestPKCS7 < OpenSSL::TestCase - def setup - super - @rsa1024 = Fixtures.pkey("rsa1024") - @rsa2048 = Fixtures.pkey("rsa2048") - ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") - ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") - - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], - ] - @ca_cert = issue_cert(ca, @rsa2048, 1, ca_exts, nil, nil) - ee_exts = [ - ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], - ["authorityKeyIdentifier","keyid:always",false], - ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], - ] - @ee1_cert = issue_cert(ee1, @rsa1024, 2, ee_exts, @ca_cert, @rsa2048) - @ee2_cert = issue_cert(ee2, @rsa1024, 3, ee_exts, @ca_cert, @rsa2048) - end - - def test_signed - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ca_certs = [@ca_cert] - - data = "aaaaa\r\nbbbbb\r\nccccc\r\n" - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - - # Normally OpenSSL tries to translate the supplied content into canonical - # MIME format (e.g. a newline character is converted into CR+LF). - # If the content is a binary, PKCS7::BINARY flag should be used. - - data = "aaaaa\nbbbbb\nccccc\n" - flag = OpenSSL::PKCS7::BINARY - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - - # A signed-data which have multiple signatures can be created - # through the following steps. - # 1. create two signed-data - # 2. copy signerInfo and certificate from one to another - - tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, [], flag) - tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @rsa1024, data, [], flag) - tmp1.add_signer(tmp2.signers[0]) - tmp1.add_certificate(@ee2_cert) - - p7 = OpenSSL::PKCS7.new(tmp1.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(2, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - assert_equal(@ee2_cert.serial, signers[1].serial) - assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s) - end - - def test_detached_sign - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ca_certs = [@ca_cert] - - data = "aaaaa\nbbbbb\nccccc\n" - flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - assert_nothing_raised do - OpenSSL::ASN1.decode(p7) - end - - certs = p7.certificates - signers = p7.signers - assert(!p7.verify([], store)) - assert(p7.verify([], store, data)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - end - - def test_enveloped - certs = [@ee1_cert, @ee2_cert] - cipher = OpenSSL::Cipher::AES.new("128-CBC") - data = "aaaaa\nbbbbb\nccccc\n" - - tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - recip = p7.recipients - assert_equal(:enveloped, p7.type) - assert_equal(2, recip.size) - - assert_equal(@ca_cert.subject.to_s, recip[0].issuer.to_s) - assert_equal(2, recip[0].serial) - assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) - - assert_equal(@ca_cert.subject.to_s, recip[1].issuer.to_s) - assert_equal(3, recip[1].serial) - assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert)) - - assert_equal(data, p7.decrypt(@rsa1024)) - end - - def test_graceful_parsing_failure #[ruby-core:43250] - contents = File.read(__FILE__) - assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) } - end - - def test_set_type_signed - p7 = OpenSSL::PKCS7.new - p7.type = "signed" - assert_equal(:signed, p7.type) - end - - def test_set_type_data - p7 = OpenSSL::PKCS7.new - p7.type = "data" - assert_equal(:data, p7.type) - end - - def test_set_type_signed_and_enveloped - p7 = OpenSSL::PKCS7.new - p7.type = "signedAndEnveloped" - assert_equal(:signedAndEnveloped, p7.type) - end - - def test_set_type_enveloped - p7 = OpenSSL::PKCS7.new - p7.type = "enveloped" - assert_equal(:enveloped, p7.type) - end - - def test_set_type_encrypted - p7 = OpenSSL::PKCS7.new - p7.type = "encrypted" - assert_equal(:encrypted, p7.type) - end - - def test_smime - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ca_certs = [@ca_cert] - - data = "aaaaa\r\nbbbbb\r\nccccc\r\n" - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - smime = OpenSSL::PKCS7.write_smime(p7) - assert_equal(true, smime.start_with?(< ctx { - ctx.cert = @svr_cert - ctx.key = @svr_key - ctx.extra_chain_cert = [@ca_cert] - } - server_proc = -> (ctx, ssl) { - assert_equal @svr_cert.to_der, ssl.cert.to_der - assert_equal nil, ssl.peer_cert - - readwrite_loop(ctx, ssl) - } - start_server(ctx_proc: ctx_proc, server_proc: server_proc) { |port| - begin - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.connect - - assert_equal sock, ssl.io - assert_equal nil, ssl.cert - assert_equal @svr_cert.to_der, ssl.peer_cert.to_der - assert_equal 2, ssl.peer_cert_chain.size - assert_equal @svr_cert.to_der, ssl.peer_cert_chain[0].to_der - assert_equal @ca_cert.to_der, ssl.peer_cert_chain[1].to_der - - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ensure - ssl&.close - sock&.close - end - } - end - - def test_socket_open - start_server { |port| - begin - ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port) - ssl.sync_close = true - ssl.connect - - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ensure - ssl&.close - end - } - end - - def test_socket_open_with_context - start_server { |port| - begin - ctx = OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, context: ctx) - ssl.sync_close = true - ssl.connect - - assert_equal ssl.context, ctx - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ensure - ssl&.close - end - } - end - - def test_socket_open_with_local_address_port_context - start_server { |port| - begin - ctx = OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, "127.0.0.1", 8000, context: ctx) - ssl.sync_close = true - ssl.connect - - assert_equal ssl.context, ctx - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ensure - ssl&.close - end - } - end - - def test_add_certificate - ctx_proc = -> ctx { - # Unset values set by start_server - ctx.cert = ctx.key = ctx.extra_chain_cert = nil - ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA - } - start_server(ctx_proc: ctx_proc) do |port| - server_connect(port) { |ssl| - assert_equal @svr_cert.subject, ssl.peer_cert.subject - assert_equal [@svr_cert.subject, @ca_cert.subject], - ssl.peer_cert_chain.map(&:subject) - - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - end - end - - def test_add_certificate_multiple_certs - pend "EC is not supported" unless defined?(OpenSSL::PKey::EC) - pend "TLS 1.2 is not supported" unless tls12_supported? - - # SSL_CTX_set0_chain() is needed for setting multiple certificate chains - add0_chain_supported = openssl?(1, 0, 2) - - if add0_chain_supported - ca2_key = Fixtures.pkey("rsa2048") - ca2_exts = [ - ["basicConstraints", "CA:TRUE", true], - ["keyUsage", "cRLSign, keyCertSign", true], - ] - ca2_dn = OpenSSL::X509::Name.parse_rfc2253("CN=CA2") - ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil) - else - # Use the same CA as @svr_cert - ca2_key = @ca_key; ca2_cert = @ca_cert - end - - ecdsa_key = Fixtures.pkey("p256") - exts = [ - ["keyUsage", "digitalSignature", false], - ] - ecdsa_dn = OpenSSL::X509::Name.parse_rfc2253("CN=localhost2") - ecdsa_cert = issue_cert(ecdsa_dn, ecdsa_key, 456, exts, ca2_cert, ca2_key) - - if !add0_chain_supported - # Testing the warning emitted when 'extra' chain is replaced - tctx = OpenSSL::SSL::SSLContext.new - tctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) - assert_warning(/set0_chain/) { - tctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) - } - end - - ctx_proc = -> ctx { - # Unset values set by start_server - ctx.cert = ctx.key = ctx.extra_chain_cert = nil - ctx.ecdh_curves = "P-256" unless openssl?(1, 0, 2) - ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA - EnvUtil.suppress_warning do # !add0_chain_supported - ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) - end - } - start_server(ctx_proc: ctx_proc) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.max_version = :TLS1_2 # TODO: We need this to force certificate type - ctx.ciphers = "aECDSA" - server_connect(port, ctx) { |ssl| - assert_equal ecdsa_cert.subject, ssl.peer_cert.subject - assert_equal [ecdsa_cert.subject, ca2_cert.subject], - ssl.peer_cert_chain.map(&:subject) - } - - ctx = OpenSSL::SSL::SSLContext.new - ctx.max_version = :TLS1_2 - ctx.ciphers = "aRSA" - server_connect(port, ctx) { |ssl| - assert_equal @svr_cert.subject, ssl.peer_cert.subject - assert_equal [@svr_cert.subject, @ca_cert.subject], - ssl.peer_cert_chain.map(&:subject) - } - end - end - - def test_add_certificate_chain_file - ctx = OpenSSL::SSL::SSLContext.new - assert ctx.add_certificate_chain_file(Fixtures.file_path("chain", "server.crt")) - end - - def test_sysread_and_syswrite - start_server { |port| - server_connect(port) { |ssl| - str = +("x" * 100 + "\n") - ssl.syswrite(str) - newstr = ssl.sysread(str.bytesize) - assert_equal(str, newstr) - - buf = String.new - ssl.syswrite(str) - assert_same buf, ssl.sysread(str.size, buf) - assert_equal(str, buf) - } - } - end - - # TODO fix this test - # def test_sysread_nonblock_and_syswrite_nonblock_keywords - # start_server do |port| - # server_connect(port) do |ssl| - # assert_warning("") do - # ssl.send(:syswrite_nonblock, "12", exception: false) - # ssl.send(:sysread_nonblock, 1, exception: false) rescue nil - # ssl.send(:sysread_nonblock, 1, String.new, exception: false) rescue nil - # end - # end - # end - # end - - def test_sync_close - start_server do |port| - begin - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ssl.close - assert_not_predicate sock, :closed? - ensure - sock&.close - end - - begin - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true # !! - ssl.connect - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ssl.close - assert_predicate sock, :closed? - ensure - sock&.close - end - end - end - - def test_copy_stream - start_server do |port| - server_connect(port) do |ssl| - IO.pipe do |r, w| - str = "hello world\n" - w.write(str) - IO.copy_stream(r, ssl, str.bytesize) - IO.copy_stream(ssl, w, str.bytesize) - assert_equal str, r.read(str.bytesize) - end - end - end - end - - def test_client_auth_failure - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag, ignore_listener_error: true) { |port| - assert_handshake_error { - server_connect(port) { |ssl| ssl.puts("abc"); ssl.gets } - } - } - end - - def test_client_auth_success - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.key = @cli_key - ctx.cert = @cli_cert - - server_connect(port, ctx) { |ssl| - ssl.puts("foo") - assert_equal("foo\n", ssl.gets) - } - - called = nil - ctx = OpenSSL::SSL::SSLContext.new - ctx.client_cert_cb = Proc.new{ |sslconn| - called = true - [@cli_cert, @cli_key] - } - - server_connect(port, ctx) { |ssl| - assert(called) - ssl.puts("foo") - assert_equal("foo\n", ssl.gets) - } - } - end - - def test_client_auth_public_key - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag, ignore_listener_error: true) do |port| - assert_raise(ArgumentError) { - ctx = OpenSSL::SSL::SSLContext.new - ctx.key = @cli_key.public_key - ctx.cert = @cli_cert - server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } - } - - ctx = OpenSSL::SSL::SSLContext.new - ctx.client_cert_cb = Proc.new{ |ssl| - [@cli_cert, @cli_key.public_key] - } - assert_handshake_error { - server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } - } - end - end - - def test_client_ca - ctx_proc = Proc.new do |ctx| - ctx.client_ca = [@ca_cert] - end - - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag, ctx_proc: ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - client_ca_from_server = nil - ctx.client_cert_cb = Proc.new do |sslconn| - client_ca_from_server = sslconn.client_ca - [@cli_cert, @cli_key] - end - server_connect(port, ctx) { |ssl| - assert_equal([@ca], client_ca_from_server) - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - } - end - - def test_read_nonblock_without_session - EnvUtil.suppress_warning do - start_server(start_immediately: false) { |port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - - assert_equal :wait_readable, ssl.read_nonblock(100, exception: false) - ssl.write("abc\n") - IO.select [ssl] - assert_equal('a', ssl.read_nonblock(1)) - assert_equal("bc\n", ssl.read_nonblock(100)) - assert_equal :wait_readable, ssl.read_nonblock(100, exception: false) - ssl.close - } - end - end - - def test_starttls - server_proc = -> (ctx, ssl) { - while line = ssl.gets - if line =~ /^STARTTLS$/ - ssl.write("x") - ssl.flush - ssl.accept - break - end - ssl.write(line) - end - readwrite_loop(ctx, ssl) - } - - EnvUtil.suppress_warning do # read/write on not started session - start_server(start_immediately: false, - server_proc: server_proc) { |port| - begin - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - - ssl.puts "plaintext" - assert_equal "plaintext\n", ssl.gets - - ssl.puts("STARTTLS") - ssl.read(1) - ssl.connect - - ssl.puts "over-tls" - assert_equal "over-tls\n", ssl.gets - ensure - ssl&.close - sock&.close - end - } - end - end - - def test_parallel - start_server { |port| - ssls = [] - 10.times{ - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - ssl.sync_close = true - ssls << ssl - } - str = "x" * 1000 + "\n" - ITERATIONS.times{ - ssls.each{|ssl| - ssl.puts(str) - assert_equal(str, ssl.gets) - } - } - ssls.each{|ssl| ssl.close } - } - end - - def test_verify_result - start_server(ignore_listener_error: true) { |port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - begin - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) - ensure - ssl.close - end - } - - start_server { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER - ctx.verify_callback = Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_OK - true - end - server_connect(port, ctx) { |ssl| - assert_equal(OpenSSL::X509::V_OK, ssl.verify_result) - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - } - - start_server(ignore_listener_error: true) { |port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER - ctx.verify_callback = Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION - false - end - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - begin - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result) - ensure - ssl.close - end - } - end - - def test_exception_in_verify_callback_is_ignored - start_server(ignore_listener_error: true) { |port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER - ctx.verify_callback = Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_OK - raise RuntimeError - end - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - begin - EnvUtil.suppress_warning do - # SSLError, not RuntimeError - assert_raise(OpenSSL::SSL::SSLError) { ssl.connect } - end - assert_equal(OpenSSL::X509::V_ERR_CERT_REJECTED, ssl.verify_result) - ensure - ssl.close - end - } - end - - def test_finished_messages - server_finished = nil - server_peer_finished = nil - client_finished = nil - client_peer_finished = nil - - start_server(accept_proc: proc { |server| - server_finished = server.finished_message - server_peer_finished = server.peer_finished_message - }) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE - server_connect(port, ctx) { |ssl| - client_finished = ssl.finished_message - client_peer_finished = ssl.peer_finished_message - sleep 0.05 - ssl.send :stop - } - } - assert_equal(server_finished, client_peer_finished) - assert_equal(server_peer_finished, client_finished) - end - - def test_sslctx_set_params - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - - assert_equal OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode - ciphers_names = ctx.ciphers.collect{|v, _, _, _| v } - assert ciphers_names.all?{|v| /A(EC)?DH/ !~ v }, "anon ciphers are disabled" - assert ciphers_names.all?{|v| /(RC4|MD5|EXP|DES(?!-EDE|-CBC3))/ !~ v }, "weak ciphers are disabled" - assert_equal 0, ctx.options & OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS - assert_equal OpenSSL::SSL::OP_NO_COMPRESSION, - ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION - end - - def test_post_connect_check_with_anon_ciphers - pend "TLS 1.2 is not supported" unless tls12_supported? - - ctx_proc = -> ctx { - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "aNULL" - ctx.security_level = 0 - } - - start_server(ctx_proc: ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "aNULL" - ctx.security_level = 0 - server_connect(port, ctx) { |ssl| - assert_raise_with_message(OpenSSL::SSL::SSLError, /anonymous cipher suite/i) { - ssl.post_connection_check("localhost.localdomain") - } - } - } - end - - def test_post_connection_check - sslerr = OpenSSL::SSL::SSLError - - start_server { |port| - server_connect(port) { |ssl| - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - - assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} - assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} - assert(ssl.post_connection_check("localhost")) - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - - cert = ssl.peer_cert - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - } - - exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ["subjectAltName","DNS:localhost.localdomain",false], - ["subjectAltName","IP:127.0.0.1",false], - ] - @svr_cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) - start_server { |port| - server_connect(port) { |ssl| - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - - assert(ssl.post_connection_check("localhost.localdomain")) - assert(ssl.post_connection_check("127.0.0.1")) - assert_raise(sslerr){ssl.post_connection_check("localhost")} - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - - cert = ssl.peer_cert - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - } - - exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ["subjectAltName","DNS:*.localdomain",false], - ] - @svr_cert = issue_cert(@svr, @svr_key, 5, exts, @ca_cert, @ca_key) - start_server { |port| - server_connect(port) { |ssl| - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - - assert(ssl.post_connection_check("localhost.localdomain")) - assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} - assert_raise(sslerr){ssl.post_connection_check("localhost")} - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - cert = ssl.peer_cert - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - } - end - - def test_verify_certificate_identity - [true, false].each do |criticality| - cert = create_null_byte_SAN_certificate(criticality) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, 'www.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, "www.example.com\0.evil.com")) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.255')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.1')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '13::17')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '13::18')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '13:0:0:0:0:0:0:17')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '44:0:0:0:0:0:0:17')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '0013:0000:0000:0000:0000:0000:0000:0017')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '1313:0000:0000:0000:0000:0000:0000:0017')) - end - end - - def test_verify_hostname - assert_equal(true, OpenSSL::SSL.verify_hostname("www.example.com", "*.example.com")) - assert_equal(false, OpenSSL::SSL.verify_hostname("www.subdomain.example.com", "*.example.com")) - end - - def test_verify_wildcard - assert_equal(false, OpenSSL::SSL.verify_wildcard("foo", "x*")) - assert_equal(true, OpenSSL::SSL.verify_wildcard("foo", "foo")) - assert_equal(true, OpenSSL::SSL.verify_wildcard("foo", "f*")) - assert_equal(true, OpenSSL::SSL.verify_wildcard("foo", "*")) - assert_equal(false, OpenSSL::SSL.verify_wildcard("abc*bcd", "abcd")) - assert_equal(false, OpenSSL::SSL.verify_wildcard("xn--qdk4b9b", "x*")) - assert_equal(false, OpenSSL::SSL.verify_wildcard("xn--qdk4b9b", "*--qdk4b9b")) - assert_equal(true, OpenSSL::SSL.verify_wildcard("xn--qdk4b9b", "xn--qdk4b9b")) - end - - # Comments in this test is excerpted from http://tools.ietf.org/html/rfc6125#page-27 - def test_post_connection_check_wildcard_san - # case-insensitive ASCII comparison - # RFC 6125, section 6.4.1 - # - # "..matching of the reference identifier against the presented identifier - # is performed by comparing the set of domain name labels using a - # case-insensitive ASCII comparison, as clarified by [DNS-CASE] (e.g., - # "WWW.Example.Com" would be lower-cased to "www.example.com" for - # comparison purposes) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*.example.com'), 'www.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*.Example.COM'), 'www.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*.example.com'), 'WWW.Example.COM')) - # 1. The client SHOULD NOT attempt to match a presented identifier in - # which the wildcard character comprises a label other than the - # left-most label (e.g., do not match bar.*.example.net). - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:www.*.com'), 'www.example.com')) - # 2. If the wildcard character is the only character of the left-most - # label in the presented identifier, the client SHOULD NOT compare - # against anything but the left-most label of the reference - # identifier (e.g., *.example.com would match foo.example.com but - # not bar.foo.example.com or example.com). - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*.example.com'), 'foo.example.com')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*.example.com'), 'bar.foo.example.com')) - # 3. The client MAY match a presented identifier in which the wildcard - # character is not the only character of the label (e.g., - # baz*.example.net and *baz.example.net and b*z.example.net would - # be taken to match baz1.example.net and foobaz.example.net and - # buzz.example.net, respectively). ... - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:baz*.example.com'), 'baz1.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*baz.example.com'), 'foobaz.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:b*z.example.com'), 'buzz.example.com')) - # Section 6.4.3 of RFC6125 states that client should NOT match identifier - # where wildcard is other than left-most label. - # - # Also implicitly mentions the wildcard character only in singular form, - # and discourages matching against more than one wildcard. - # - # See RFC 6125, section 7.2, subitem 2. - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*b*.example.com'), 'abc.example.com')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*b*.example.com'), 'ab.example.com')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:*b*.example.com'), 'bc.example.com')) - # ... However, the client SHOULD NOT - # attempt to match a presented identifier where the wildcard - # character is embedded within an A-label or U-label [IDNA-DEFS] of - # an internationalized domain name [IDNA-PROTO]. - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:xn*.example.com'), 'xn1ca.example.com')) - # part of A-label - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:xn--*.example.com'), 'xn--1ca.example.com')) - # part of U-label - # dNSName in RFC5280 is an IA5String so U-label should NOT be allowed - # regardless of wildcard. - # - # See Section 7.2 of RFC 5280: - # IA5String is limited to the set of ASCII characters. - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_san('DNS:á*.example.com'), 'á1.example.com')) - end - - def test_post_connection_check_wildcard_cn - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*.example.com'), 'www.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*.Example.COM'), 'www.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*.example.com'), 'WWW.Example.COM')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('www.*.com'), 'www.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*.example.com'), 'foo.example.com')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*.example.com'), 'bar.foo.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('baz*.example.com'), 'baz1.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*baz.example.com'), 'foobaz.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('b*z.example.com'), 'buzz.example.com')) - # Section 6.4.3 of RFC6125 states that client should NOT match identifier - # where wildcard is other than left-most label. - # - # Also implicitly mentions the wildcard character only in singular form, - # and discourages matching against more than one wildcard. - # - # See RFC 6125, section 7.2, subitem 2. - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*b*.example.com'), 'abc.example.com')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*b*.example.com'), 'ab.example.com')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('*b*.example.com'), 'bc.example.com')) - assert_equal(true, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('xn*.example.com'), 'xn1ca.example.com')) - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('xn--*.example.com'), 'xn--1ca.example.com')) - # part of U-label - # Subject in RFC5280 states case-insensitive ASCII comparison. - # - # See Section 7.2 of RFC 5280: - # IA5String is limited to the set of ASCII characters. - assert_equal(false, OpenSSL::SSL.verify_certificate_identity( - create_cert_with_name('á*.example.com'), 'á1.example.com')) - end - - def create_cert_with_san(san) - ef = OpenSSL::X509::ExtensionFactory.new - cert = OpenSSL::X509::Certificate.new - cert.subject = OpenSSL::X509::Name.parse("/DC=some/DC=site/CN=Some Site") - ext = ef.create_ext('subjectAltName', san) - cert.add_extension(ext) - cert - end - - def create_cert_with_name(name) - cert = OpenSSL::X509::Certificate.new - cert.subject = OpenSSL::X509::Name.new([['DC', 'some'], ['DC', 'site'], ['CN', name]]) - cert - end - - - # Create NULL byte SAN certificate - def create_null_byte_SAN_certificate(critical = false) - ef = OpenSSL::X509::ExtensionFactory.new - cert = OpenSSL::X509::Certificate.new - cert.subject = OpenSSL::X509::Name.parse "/DC=some/DC=site/CN=Some Site" - ext = ef.create_ext('subjectAltName', 'DNS:placeholder,IP:192.168.7.1,IP:13::17', critical) - ext_asn1 = OpenSSL::ASN1.decode(ext.to_der) - san_list_der = ext_asn1.value.reduce(nil) { |memo,val| val.tag == 4 ? val.value : memo } - san_list_asn1 = OpenSSL::ASN1.decode(san_list_der) - san_list_asn1.value[0].value = "www.example.com\0.evil.com" - pos = critical ? 2 : 1 - ext_asn1.value[pos].value = san_list_asn1.to_der - real_ext = OpenSSL::X509::Extension.new ext_asn1 - cert.add_extension(real_ext) - cert - end - - def socketpair - if defined? UNIXSocket - UNIXSocket.pair - else - Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0) - end - end - - def test_tlsext_hostname - fooctx = OpenSSL::SSL::SSLContext.new - fooctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } - fooctx.cert = @cli_cert - fooctx.key = @cli_key - - ctx_proc = proc { |ctx| - ctx.servername_cb = proc { |ssl, servername| - case servername - when "foo.example.com" - fooctx - when "bar.example.com" - nil - else - raise "unreachable" - end - } - } - start_server(ctx_proc: ctx_proc) do |port| - sock = TCPSocket.new("127.0.0.1", port) - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.hostname = "foo.example.com" - ssl.connect - assert_equal @cli_cert.serial, ssl.peer_cert.serial - assert_predicate fooctx, :frozen? - - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ensure - ssl&.close - sock.close - end - - sock = TCPSocket.new("127.0.0.1", port) - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.hostname = "bar.example.com" - ssl.connect - assert_equal @svr_cert.serial, ssl.peer_cert.serial - - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - ensure - ssl&.close - sock.close - end - end - end - - def test_servername_cb_raises_an_exception_on_unknown_objects - hostname = 'example.org' - - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.cert = @svr_cert - ctx2.key = @svr_key - ctx2.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } - ctx2.servername_cb = lambda { |args| Object.new } - - sock1, sock2 = socketpair - - s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) - - ctx1 = OpenSSL::SSL::SSLContext.new - - s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) - s1.hostname = hostname - t = Thread.new { - assert_raise(OpenSSL::SSL::SSLError) do - s1.connect - end - } - - assert_raise(ArgumentError) do - s2.accept - end - - assert t.join - ensure - sock1.close if sock1 - sock2.close if sock2 - end - - def test_verify_hostname_on_connect - ctx_proc = proc { |ctx| - exts = [ - ["keyUsage", "keyEncipherment,digitalSignature", true], - ["subjectAltName", "DNS:a.example.com,DNS:*.b.example.com," \ - "DNS:c*.example.com,DNS:d.*.example.com"], - ] - ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) - ctx.key = @svr_key - } - - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_hostname = true - ctx.cert_store = OpenSSL::X509::Store.new - ctx.cert_store.add_cert(@ca_cert) - ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER - - [ - ["a.example.com", true], - ["A.Example.Com", true], - ["x.example.com", false], - ["b.example.com", false], - ["x.b.example.com", true], - ["cx.example.com", true], - ["d.x.example.com", false], - ].each do |name, expected_ok| - begin - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.hostname = name - if expected_ok - ssl.connect - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - else - assert_handshake_error { ssl.connect } - end - ensure - ssl.close if ssl - sock.close if sock - end - end - end - end - - def test_connect_certificate_verify_failed_exception_message - start_server(ignore_listener_error: true) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { - server_connect(port, ctx) - } - } - - ctx_proc = proc { |ctx| - ctx.cert = issue_cert(@svr, @svr_key, 30, [], @ca_cert, @ca_key, - not_before: Time.now-100, not_after: Time.now-10) - } - start_server(ignore_listener_error: true, ctx_proc: ctx_proc) { |port| - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params(cert_store: store) - assert_raise_with_message(OpenSSL::SSL::SSLError, /expired/) { - server_connect(port, ctx) - } - } - end - - def test_unset_OP_ALL - ctx_proc = Proc.new { |ctx| - # If OP_DONT_INSERT_EMPTY_FRAGMENTS is not defined, this test is - # redundant because the default options already are equal to OP_ALL. - # But it also degrades gracefully, so keep it - ctx.options = OpenSSL::SSL::OP_ALL - } - start_server(ctx_proc: ctx_proc) { |port| - server_connect(port) { |ssl| - ssl.puts('hello') - assert_equal("hello\n", ssl.gets) - } - } - end - - def check_supported_protocol_versions - possible_versions = [ - OpenSSL::SSL::SSL3_VERSION, - OpenSSL::SSL::TLS1_VERSION, - OpenSSL::SSL::TLS1_1_VERSION, - OpenSSL::SSL::TLS1_2_VERSION, - # OpenSSL 1.1.1 - defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION, - ].compact - - # Prepare for testing & do sanity check - supported = [] - possible_versions.each do |ver| - catch(:unsupported) { - ctx_proc = proc { |ctx| - begin - ctx.min_version = ctx.max_version = ver - rescue ArgumentError, OpenSSL::SSL::SSLError - throw :unsupported - end - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| - begin - server_connect(port) { |ssl| - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET - else - supported << ver - end - end - } - end - assert_not_empty supported - - supported - end - - def test_set_params_min_version - supported = check_supported_protocol_versions - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - - if supported.include?(OpenSSL::SSL::SSL3_VERSION) - # SSLContext#set_params properly disables SSL 3.0 by default - ctx_proc = proc { |ctx| - ctx.min_version = ctx.max_version = OpenSSL::SSL::SSL3_VERSION - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params(cert_store: store, verify_hostname: false) - assert_handshake_error { server_connect(port, ctx) { } } - } - end - end - - def test_minmax_version - supported = check_supported_protocol_versions - - # name: The string that would be returned by SSL_get_version() - # method: The version-specific method name (if any) - vmap = { - OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, - OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, - OpenSSL::SSL::TLS1_VERSION => { name: "TLSv1", method: "TLSv1" }, - OpenSSL::SSL::TLS1_1_VERSION => { name: "TLSv1.1", method: "TLSv1_1" }, - OpenSSL::SSL::TLS1_2_VERSION => { name: "TLSv1.2", method: "TLSv1_2" }, - # OpenSSL 1.1.1 - defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION => - { name: "TLSv1.3", method: nil }, - } - - # Server enables a single version - supported.each do |ver| - ctx_proc = proc { |ctx| ctx.min_version = ctx.max_version = ver } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - supported.each do |cver| - # Client enables a single version - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.min_version = ctx1.max_version = cver - if ver == cver - server_connect(port, ctx1) { |ssl| - assert_equal vmap[cver][:name], ssl.ssl_version - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - else - assert_handshake_error { server_connect(port, ctx1) { } } - end - - # There is no version-specific SSL methods for TLS 1.3 - if cver <= OpenSSL::SSL::TLS1_2_VERSION - # Client enables a single version using #ssl_version= - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ssl_version = vmap[cver][:method] - if ver == cver - server_connect(port, ctx2) { |ssl| - assert_equal vmap[cver][:name], ssl.ssl_version - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - else - assert_handshake_error { server_connect(port, ctx2) { } } - end - end - end - - # Client enables all supported versions - ctx3 = OpenSSL::SSL::SSLContext.new - ctx3.min_version = ctx3.max_version = nil - server_connect(port, ctx3) { |ssl| - assert_equal vmap[ver][:name], ssl.ssl_version - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - } - end - - if supported.size == 1 - pend "More than one protocol version must be supported" - end - - # Server sets min_version (earliest is disabled) - sver = supported[1] - ctx_proc = proc { |ctx| ctx.min_version = sver } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - supported.each do |cver| - # Client sets min_version - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.min_version = cver - server_connect(port, ctx1) { |ssl| - assert_equal vmap[supported.last][:name], ssl.ssl_version - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - - # Client sets max_version - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.max_version = cver - if cver >= sver - server_connect(port, ctx2) { |ssl| - assert_equal vmap[cver][:name], ssl.ssl_version - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - else - assert_handshake_error { server_connect(port, ctx2) { } } - end - end - } - - # Server sets max_version (latest is disabled) - sver = supported[-2] - ctx_proc = proc { |ctx| ctx.max_version = sver } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - supported.each do |cver| - # Client sets min_version - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.min_version = cver - if cver <= sver - server_connect(port, ctx1) { |ssl| - assert_equal vmap[sver][:name], ssl.ssl_version - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - else - assert_handshake_error { server_connect(port, ctx1) { } } - end - - # Client sets max_version - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.max_version = cver - server_connect(port, ctx2) { |ssl| - if cver >= sver - assert_equal vmap[sver][:name], ssl.ssl_version - else - assert_equal vmap[cver][:name], ssl.ssl_version - end - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - end - } - end - - def test_options_disable_versions - # Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0. - supported = check_supported_protocol_versions - - if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) && - supported.include?(OpenSSL::SSL::TLS1_2_VERSION) - # Server disables ~ TLS 1.1 - ctx_proc = proc { |ctx| - ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | - OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - # Client only supports TLS 1.1 - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION - assert_handshake_error { server_connect(port, ctx1) { } } - - # Client only supports TLS 1.2 - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION - assert_nothing_raised { server_connect(port, ctx2) { } } - } - - # Server only supports TLS 1.1 - ctx_proc = proc { |ctx| - ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - # Client disables TLS 1.1 - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1 - assert_handshake_error { server_connect(port, ctx1) { } } - - # Client disables TLS 1.2 - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2 - assert_nothing_raised { server_connect(port, ctx2) { } } - } - else - pend "TLS 1.1 and TLS 1.2 must be supported; skipping" - end - end - - def test_ssl_methods_constant - EnvUtil.suppress_warning { # Deprecated in v2.1.0 - base = [:TLSv1_2, :TLSv1_1, :TLSv1, :SSLv3, :SSLv2, :SSLv23] - base.each do |name| - assert_include OpenSSL::SSL::SSLContext::METHODS, name - assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_client" - assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_server" - end - } - end - - def test_renegotiation_cb - num_handshakes = 0 - renegotiation_cb = Proc.new { |ssl| num_handshakes += 1 } - ctx_proc = Proc.new { |ctx| ctx.renegotiation_cb = renegotiation_cb } - start_server_version(:SSLv23, ctx_proc) { |port| - server_connect(port) { |ssl| - assert_equal(1, num_handshakes) - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - } - end - -if openssl?(1, 0, 2) || libressl? - def test_alpn_protocol_selection_ary - advertised = ["http/1.1", "spdy/2"] - ctx_proc = Proc.new { |ctx| - ctx.alpn_select_cb = -> (protocols) { - protocols.first - } - ctx.alpn_protocols = advertised - } - start_server_version(:SSLv23, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.alpn_protocols = advertised - server_connect(port, ctx) { |ssl| - assert_equal(advertised.first, ssl.alpn_protocol) - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - } - end - - def test_alpn_protocol_selection_cancel - sock1, sock2 = socketpair - - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.cert = @svr_cert - ctx1.key = @svr_key - ctx1.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } - ctx1.alpn_select_cb = -> (protocols) { nil } - ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) - - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.alpn_protocols = ["http/1.1"] - ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) - - t = Thread.new { - ssl2.connect_nonblock(exception: false) - } - assert_raise_with_message(TypeError, /nil/) { ssl1.accept } - t.join - ensure - sock1&.close - sock2&.close - ssl1&.close - ssl2&.close - t&.kill - t&.join - end -end - - def test_npn_protocol_selection_ary - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) - - advertised = ["http/1.1", "spdy/2"] - ctx_proc = proc { |ctx| ctx.npn_protocols = advertised } - start_server_version(:TLSv1_2, ctx_proc) { |port| - selector = lambda { |which| - ctx = OpenSSL::SSL::SSLContext.new - ctx.npn_select_cb = -> (protocols) { protocols.send(which) } - server_connect(port, ctx) { |ssl| - assert_equal(advertised.send(which), ssl.npn_protocol) - } - } - selector.call(:first) - selector.call(:last) - } - end - - def test_npn_protocol_selection_enum - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) - - advertised = Object.new - def advertised.each - yield "http/1.1" - yield "spdy/2" - end - ctx_proc = Proc.new { |ctx| ctx.npn_protocols = advertised } - start_server_version(:TLSv1_2, ctx_proc) { |port| - selector = lambda { |selected, which| - ctx = OpenSSL::SSL::SSLContext.new - ctx.npn_select_cb = -> (protocols) { protocols.to_a.send(which) } - server_connect(port, ctx) { |ssl| - assert_equal(selected, ssl.npn_protocol) - } - } - selector.call("http/1.1", :first) - selector.call("spdy/2", :last) - } - end - - def test_npn_protocol_selection_cancel - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) - - ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } - start_server_version(:TLSv1_2, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.npn_select_cb = -> (protocols) { raise RuntimeError.new } - assert_raise(RuntimeError) { server_connect(port, ctx) } - } - end - - def test_npn_advertised_protocol_too_long - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) - - ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["a" * 256] } - start_server_version(:TLSv1_2, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.npn_select_cb = -> (protocols) { protocols.first } - assert_handshake_error { server_connect(port, ctx) } - } - end - - def test_npn_selected_protocol_too_long - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) - - ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } - start_server_version(:TLSv1_2, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.npn_select_cb = -> (protocols) { "a" * 256 } - assert_handshake_error { server_connect(port, ctx) } - } - end - - def test_close_after_socket_close - start_server { |port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - sock.close - assert_nothing_raised do - ssl.close - end - } - end - - def test_sync_close_without_connect - Socket.open(:INET, :STREAM) {|s| - ssl = OpenSSL::SSL::SSLSocket.new(s) - ssl.sync_close = true - ssl.close - assert(s.closed?) - } - end - - def test_get_ephemeral_key - # OpenSSL >= 1.0.2 - unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key) - pend "SSL_get_server_tmp_key() is not supported" - end - - if tls12_supported? - # kRSA - ctx_proc1 = proc { |ctx| - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "kRSA" - } - start_server(ctx_proc: ctx_proc1) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "kRSA" - server_connect(port, ctx) { |ssl| assert_nil ssl.tmp_key } - end - end - - if defined?(OpenSSL::PKey::DH) && tls12_supported? - # DHE - # TODO: How to test this with TLS 1.3? - ctx_proc2 = proc { |ctx| - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "EDH" - } - start_server(ctx_proc: ctx_proc2) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "EDH" - server_connect(port, ctx) { |ssl| - assert_instance_of OpenSSL::PKey::DH, ssl.tmp_key - } - end - end - - if defined?(OpenSSL::PKey::EC) - # ECDHE - ctx_proc3 = proc { |ctx| - ctx.ciphers = "DEFAULT:!kRSA:!kEDH" - ctx.ecdh_curves = "P-256" - } - start_server(ctx_proc: ctx_proc3) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ciphers = "DEFAULT:!kRSA:!kEDH" - server_connect(port, ctx) { |ssl| - assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - end - end - end - - def test_fallback_scsv - pend "Fallback SCSV is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:enable_fallback_scsv) - - start_server do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION - # Here is OK - # TLS1.2 supported and this is what we ask the first time - server_connect(port, ctx) - end - - ctx_proc = proc { |ctx| - ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION - } - start_server(ctx_proc: ctx_proc) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.enable_fallback_scsv - ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION - # Here is OK too - # TLS1.2 not supported, fallback to TLS1.1 and signaling the fallback - # Server doesn't support better, so connection OK - server_connect(port, ctx) - end - - # Here is not OK - # TLS1.2 is supported, fallback to TLS1.1 (downgrade attack) and signaling the fallback - # Server support better, so refuse the connection - sock1, sock2 = socketpair - begin - # This test is for the downgrade protection mechanism of TLS1.2. - # This is why ctx1 bounds max_version == TLS1.2. - # Otherwise, this test fails when using openssl 1.1.1 (or later) that supports TLS1.3. - # TODO: We may need another test for TLS1.3 because it seems to have a different mechanism. - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION - s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) - - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.enable_fallback_scsv - ctx2.max_version = OpenSSL::SSL::TLS1_1_VERSION - s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) - t = Thread.new { - assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { - s2.connect - } - } - assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { - s1.accept - } - t.join - ensure - sock1.close - sock2.close - end - end - - def test_dh_callback - pend "TLS 1.2 is not supported" unless tls12_supported? - - dh = Fixtures.pkey("dh-1") - called = false - ctx_proc = -> ctx { - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "DH:!NULL" - ctx.tmp_dh_callback = ->(*args) { - called = true - dh - } - } - start_server(ctx_proc: ctx_proc) do |port| - server_connect(port) { |ssl| - assert called, "dh callback should be called" - if ssl.respond_to?(:tmp_key) - assert_equal dh.to_der, ssl.tmp_key.to_der - end - } - end - end - - def test_connect_works_when_setting_dh_callback_to_nil - pend "TLS 1.2 is not supported" unless tls12_supported? - - ctx_proc = -> ctx { - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "DH:!NULL" # use DH - ctx.tmp_dh_callback = nil - } - start_server(ctx_proc: ctx_proc) do |port| - EnvUtil.suppress_warning { # uses default callback - assert_nothing_raised { - server_connect(port) { } - } - } - end - end - - def test_tmp_ecdh_callback - pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) - pend "tmp_ecdh_callback is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:tmp_ecdh_callback) - pend "LibreSSL 2.6 has broken SSL_CTX_set_tmp_ecdh_callback()" \ - if libressl?(2, 6, 1) - - EnvUtil.suppress_warning do # tmp_ecdh_callback is deprecated (2016-05) - called = false - ctx_proc = -> ctx { - ctx.ciphers = "DEFAULT:!kRSA:!kEDH" - ctx.tmp_ecdh_callback = -> (*args) { - called = true - OpenSSL::PKey::EC.new "prime256v1" - } - } - start_server(ctx_proc: ctx_proc) do |port| - server_connect(port) { |s| - assert called, "tmp_ecdh_callback should be called" - } - end - end - end - - def test_ecdh_curves - pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) - - ctx_proc = -> ctx { - # Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3 - ctx.ciphers = "DEFAULT:!kRSA:!kEDH" - ctx.ecdh_curves = "P-384:P-521" - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ecdh_curves = "P-256:P-384" # disable P-521 for OpenSSL >= 1.0.2 - - server_connect(port, ctx) { |ssl| - cs = ssl.cipher[0] - if /\ATLS/ =~ cs # Is TLS 1.3 is used? - assert_equal "secp384r1", ssl.tmp_key.group.curve_name - else - assert_match (/\AECDH/), cs - if ssl.respond_to?(:tmp_key) - assert_equal "secp384r1", ssl.tmp_key.group.curve_name - end - end - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - - if openssl?(1, 0, 2) || libressl?(2, 5, 1) - ctx = OpenSSL::SSL::SSLContext.new - ctx.ecdh_curves = "P-256" - - assert_raise(OpenSSL::SSL::SSLError) { - server_connect(port, ctx) { } - } - - ctx = OpenSSL::SSL::SSLContext.new - ctx.ecdh_curves = "P-521:P-384" - - server_connect(port, ctx) { |ssl| - assert_equal "secp521r1", ssl.tmp_key.group.curve_name - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - end - end - end - - def test_security_level - ctx = OpenSSL::SSL::SSLContext.new - begin - ctx.security_level = 1 - rescue NotImplementedError - assert_equal(0, ctx.security_level) - return - end - assert_equal(1, ctx.security_level) - - dsa512 = Fixtures.pkey("dsa512") - dsa512_cert = issue_cert(@svr, dsa512, 50, [], @ca_cert, @ca_key) - rsa1024 = Fixtures.pkey("rsa1024") - rsa1024_cert = issue_cert(@svr, rsa1024, 51, [], @ca_cert, @ca_key) - - assert_raise(OpenSSL::SSL::SSLError) { - # 512 bit DSA key is rejected because it offers < 80 bits of security - ctx.add_certificate(dsa512_cert, dsa512) - } - assert_nothing_raised { - ctx.add_certificate(rsa1024_cert, rsa1024) - } - ctx.security_level = 2 - assert_raise(OpenSSL::SSL::SSLError) { - # < 112 bits of security - ctx.add_certificate(rsa1024_cert, rsa1024) - } - end - - def test_dup - ctx = OpenSSL::SSL::SSLContext.new - sock1, sock2 = socketpair - ssl = OpenSSL::SSL::SSLSocket.new(sock1, ctx) - - assert_raise(NoMethodError) { ctx.dup } - assert_raise(NoMethodError) { ssl.dup } - ensure - ssl.close if ssl - sock1.close - sock2.close - end - - def test_freeze_calls_setup - bug = "[ruby/openssl#85]" - start_server(ignore_listener_error: true) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER - ctx.freeze - assert_raise(OpenSSL::SSL::SSLError, bug) { - server_connect(port, ctx) - } - } - end - - def test_fileno - ctx = OpenSSL::SSL::SSLContext.new - sock1, sock2 = socketpair - - socket = OpenSSL::SSL::SSLSocket.new(sock1) - server = OpenSSL::SSL::SSLServer.new(sock2, ctx) - - assert_equal socket.fileno, socket.to_io.fileno - assert_equal server.fileno, server.to_io.fileno - ensure - sock1.close - sock2.close - end - - private - - def start_server_version(version, ctx_proc = nil, - server_proc = method(:readwrite_loop), &blk) - ctx_wrap = Proc.new { |ctx| - ctx.ssl_version = version - ctx_proc.call(ctx) if ctx_proc - } - start_server( - ctx_proc: ctx_wrap, - server_proc: server_proc, - ignore_listener_error: true, - &blk - ) - end - - def server_connect(port, ctx = nil) - sock = TCPSocket.new("127.0.0.1", port) - ssl = ctx ? OpenSSL::SSL::SSLSocket.new(sock, ctx) : OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - ssl.connect - yield ssl if block_given? - ensure - if ssl - ssl.close - elsif sock - sock.close - end - end - - def assert_handshake_error - # different OpenSSL versions react differently when facing a SSL/TLS version - # that has been marked as forbidden, therefore any of these may be raised - assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::EPIPE) { - yield - } - end -end - -end diff --git a/test/test_ssl_session.rb b/test/test_ssl_session.rb deleted file mode 100644 index 89726d44..00000000 --- a/test/test_ssl_session.rb +++ /dev/null @@ -1,400 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase - def test_session - pend "TLS 1.2 is not supported" unless tls12_supported? - - ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } - start_server(ctx_proc: ctx_proc) do |port| - server_connect_with_session(port, nil, nil) { |ssl| - session = ssl.session - assert(session == OpenSSL::SSL::Session.new(session.to_pem)) - assert(session == OpenSSL::SSL::Session.new(ssl)) - session.timeout = 5 - assert_equal(5, session.timeout) - assert_not_nil(session.time) - # SSL_SESSION_time keeps long value so we can't keep nsec fragment. - session.time = t1 = Time.now.to_i - assert_equal(Time.at(t1), session.time) - assert_not_nil(session.id) - pem = session.to_pem - assert_match(/\A-----BEGIN SSL SESSION PARAMETERS-----/, pem) - assert_match(/-----END SSL SESSION PARAMETERS-----\Z/, pem) - pem.gsub!(/-----(BEGIN|END) SSL SESSION PARAMETERS-----/, '').gsub!(/[\r\n]+/m, '') - assert_equal(session.to_der, pem.unpack('m*')[0]) - assert_not_nil(session.to_text) - } - end - end - - DUMMY_SESSION = <<__EOS__ ------BEGIN SSL SESSION PARAMETERS----- -MIIDzQIBAQICAwEEAgA5BCAF219w9ZEV8dNA60cpEGOI34hJtIFbf3bkfzSgMyad -MQQwyGLbkCxE4OiMLdKKem+pyh8V7ifoP7tCxhdmwoDlJxI1v6nVCjai+FGYuncy -NNSWoQYCBE4DDWuiAwIBCqOCAo4wggKKMIIBcqADAgECAgECMA0GCSqGSIb3DQEB -BQUAMD0xEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 -LWxhbmcxCzAJBgNVBAMMAkNBMB4XDTExMDYyMzA5NTQ1MVoXDTExMDYyMzEwMjQ1 -MVowRDETMBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1Ynkt -bGFuZzESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7CxaKPERYHs -k4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/Q3geLv8Z -D9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQABoxIwEDAO -BgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBACj5WhoZ/ODVeHpwgq1d -8fW/13ICRYHYpv6dzlWihyqclGxbKMlMnaVCPz+4JaVtMz3QB748KJQgL3Llg3R1 -ek+f+n1MBCMfFFsQXJ2gtLB84zD6UCz8aaCWN5/czJCd7xMz7fRLy3TOIW5boXAU -zIa8EODk+477K1uznHm286ab0Clv+9d304hwmBZgkzLg6+31Of6d6s0E0rwLGiS2 -sOWYg34Y3r4j8BS9Ak4jzpoLY6cJ0QAKCOJCgmjGr4XHpyXMLbicp3ga1uSbwtVO -gF/gTfpLhJC+y0EQ5x3Ftl88Cq7ZJuLBDMo/TLIfReJMQu/HlrTT7+LwtneSWGmr -KkSkAgQApQMCAROqgcMEgcAuDkAVfj6QAJMz9yqTzW5wPFyty7CxUEcwKjUqj5UP -/Yvky1EkRuM/eQfN7ucY+MUvMqv+R8ZSkHPsnjkBN5ChvZXjrUSZKFVjR4eFVz2V -jismLEJvIFhQh6pqTroRrOjMfTaM5Lwoytr2FTGobN9rnjIRsXeFQW1HLFbXn7Dh -8uaQkMwIVVSGRB8T7t6z6WIdWruOjCZ6G5ASI5XoqAHwGezhLodZuvJEfsVyCF9y -j+RBGfCFrrQbBdnkFI/ztgM= ------END SSL SESSION PARAMETERS----- -__EOS__ - - DUMMY_SESSION_NO_EXT = <<-__EOS__ ------BEGIN SSL SESSION PARAMETERS----- -MIIDCAIBAQICAwAEAgA5BCDyAW7rcpzMjDSosH+Tv6sukymeqgq3xQVVMez628A+ -lAQw9TrKzrIqlHEh6ltuQaqv/Aq83AmaAlogYktZgXAjOGnhX7ifJDNLMuCfQq53 -hPAaoQYCBE4iDeeiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B -AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi -eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA3MTYyMjE3MTFaFw0xMTA3MTYyMjQ3 -MTFaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 -LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB -7JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ -GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw -DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQA3TRzABRG3kz8jEEYr -tDQqXgsxwTsLhTT5d1yF0D8uFw+y15hJAJnh6GJHjqhWBrF4zNoTApFo+4iIL6g3 -q9C3mUsxIVAHx41DwZBh/FI7J4FqlAoGOguu7892CNVY3ZZjc3AXMTdKjcNoWPzz -FCdj5fNT24JMMe+ZdGZK97ChahJsdn/6B3j6ze9NK9mfYEbiJhejGTPLOFVHJCGR -KYYZ3ZcKhLDr9ql4d7cCo1gBtemrmFQGPui7GttNEqmXqUKvV8mYoa8farf5i7T4 -L6a/gp2cVZTaDIS1HjbJsA/Ag7AajZqiN6LfqShNUVsrMZ+5CoV8EkBDTZPJ9MSr -a3EqpAIEAKUDAgET ------END SSL SESSION PARAMETERS----- -__EOS__ - - - def test_session_time - sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) - sess.time = (now = Time.now) - assert_equal(now.to_i, sess.time.to_i) - sess.time = 1 - assert_equal(1, sess.time.to_i) - sess.time = 1.2345 - assert_equal(1, sess.time.to_i) - # Can OpenSSL handle t>2038y correctly? Version? - sess.time = 2**31 - 1 - assert_equal(2**31 - 1, sess.time.to_i) - end - - def test_session_timeout - sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) - assert_raise(TypeError) do - sess.timeout = Time.now - end - sess.timeout = 1 - assert_equal(1, sess.timeout.to_i) - sess.timeout = 1.2345 - assert_equal(1, sess.timeout.to_i) - sess.timeout = 2**31 - 1 - assert_equal(2**31 - 1, sess.timeout.to_i) - end - - def test_session_exts_read - assert(OpenSSL::SSL::Session.new(DUMMY_SESSION)) - end - - def test_resumption - non_resumable = nil - start_server { |port| - server_connect_with_session(port, nil, nil) { |ssl| - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - non_resumable = ssl.session - } - } - - ctx_proc = proc { |ctx| - ctx.options &= ~OpenSSL::SSL::OP_NO_TICKET - # Disable server-side session cache which is enabled by default - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF - } - start_server(ctx_proc: ctx_proc) do |port| - sess1 = server_connect_with_session(port, nil, nil) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - assert_equal false, ssl.session_reused? - ssl.session - } - - server_connect_with_session(port, nil, non_resumable) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - assert_equal false, ssl.session_reused? - } - - server_connect_with_session(port, nil, sess1) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - assert_equal true, ssl.session_reused? - } - end - end - - def test_server_session_cache - pend "TLS 1.2 is not supported" unless tls12_supported? - - ctx_proc = Proc.new do |ctx| - ctx.ssl_version = :TLSv1_2 - ctx.options |= OpenSSL::SSL::OP_NO_TICKET - end - - connections = nil - saved_session = nil - server_proc = Proc.new do |ctx, ssl| - stats = ctx.session_cache_stats - - case connections - when 0 - assert_equal false, ssl.session_reused? - assert_equal 1, stats[:cache_num] - assert_equal 0, stats[:cache_hits] - assert_equal 0, stats[:cache_misses] - when 1 - assert_equal true, ssl.session_reused? - assert_equal 1, stats[:cache_num] - assert_equal 1, stats[:cache_hits] - assert_equal 0, stats[:cache_misses] - - saved_session = ssl.session - assert_equal true, ctx.session_remove(ssl.session) - when 2 - assert_equal false, ssl.session_reused? - assert_equal 1, stats[:cache_num] - assert_equal 1, stats[:cache_hits] - assert_equal 1, stats[:cache_misses] - - assert_equal true, ctx.session_add(saved_session.dup) - when 3 - assert_equal true, ssl.session_reused? - assert_equal 2, stats[:cache_num] - assert_equal 2, stats[:cache_hits] - assert_equal 1, stats[:cache_misses] - - ctx.flush_sessions(Time.now + 10000) - when 4 - assert_equal false, ssl.session_reused? - assert_equal 1, stats[:cache_num] - assert_equal 2, stats[:cache_hits] - assert_equal 2, stats[:cache_misses] - - assert_equal true, ctx.session_add(saved_session.dup) - end - - readwrite_loop(ctx, ssl) - end - - start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port| - first_session = nil - 10.times do |i| - connections = i - cctx = OpenSSL::SSL::SSLContext.new - cctx.ssl_version = :TLSv1_2 - server_connect_with_session(port, cctx, first_session) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - first_session ||= ssl.session - - case connections - when 0; - when 1; assert_equal true, ssl.session_reused? - when 2; assert_equal false, ssl.session_reused? - when 3; assert_equal true, ssl.session_reused? - when 4; assert_equal false, ssl.session_reused? - when 5..9; assert_equal true, ssl.session_reused? - end - } - end - end - end - - # Skipping tests that use session_remove_cb by default because it may cause - # deadlock. - TEST_SESSION_REMOVE_CB = ENV["OSSL_TEST_ALL"] == "1" - - def test_ctx_client_session_cb - pend "TLS 1.2 is not supported" unless tls12_supported? - - ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } - start_server(ctx_proc: ctx_proc) do |port| - called = {} - ctx = OpenSSL::SSL::SSLContext.new - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT - ctx.session_new_cb = lambda { |ary| - sock, sess = ary - called[:new] = [sock, sess] - } - if TEST_SESSION_REMOVE_CB - ctx.session_remove_cb = lambda { |ary| - ctx, sess = ary - called[:remove] = [ctx, sess] - # any resulting value is OK (ignored) - } - end - - server_connect_with_session(port, ctx, nil) { |ssl| - assert_equal(1, ctx.session_cache_stats[:cache_num]) - assert_equal(1, ctx.session_cache_stats[:connect_good]) - assert_equal([ssl, ssl.session], called[:new]) - assert(ctx.session_remove(ssl.session)) - assert(!ctx.session_remove(ssl.session)) - if TEST_SESSION_REMOVE_CB - assert_equal([ctx, ssl.session], called[:remove]) - end - } - end - end - - def test_ctx_server_session_cb - pend "TLS 1.2 is not supported" unless tls12_supported? - - connections = nil - called = {} - cctx = OpenSSL::SSL::SSLContext.new - cctx.ssl_version = :TLSv1_2 - sctx = nil - ctx_proc = Proc.new { |ctx| - sctx = ctx - ctx.ssl_version = :TLSv1_2 - ctx.options |= OpenSSL::SSL::OP_NO_TICKET - - # get_cb is called whenever a client proposed to resume a session but - # the session could not be found in the internal session cache. - last_server_session = nil - ctx.session_get_cb = lambda { |ary| - _sess, data = ary - called[:get] = data - - if connections == 2 - last_server_session.dup - else - nil - end - } - - ctx.session_new_cb = lambda { |ary| - _sock, sess = ary - called[:new] = sess - last_server_session = sess - } - - if TEST_SESSION_REMOVE_CB - ctx.session_remove_cb = lambda { |ary| - _ctx, sess = ary - called[:remove] = sess - } - end - } - start_server(ctx_proc: ctx_proc) do |port| - connections = 0 - sess0 = server_connect_with_session(port, cctx, nil) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - assert_equal false, ssl.session_reused? - ssl.session - } - assert_nil called[:get] - assert_not_nil called[:new] - assert_equal sess0.id, called[:new].id - if TEST_SESSION_REMOVE_CB - assert_nil called[:remove] - end - called.clear - - # Internal cache hit - connections = 1 - server_connect_with_session(port, cctx, sess0.dup) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - assert_equal true, ssl.session_reused? - ssl.session - } - assert_nil called[:get] - assert_nil called[:new] - if TEST_SESSION_REMOVE_CB - assert_nil called[:remove] - end - called.clear - - sctx.flush_sessions(Time.now + 10000) - if TEST_SESSION_REMOVE_CB - assert_not_nil called[:remove] - assert_equal sess0.id, called[:remove].id - end - called.clear - - # External cache hit - connections = 2 - sess2 = server_connect_with_session(port, cctx, sess0.dup) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - if !ssl.session_reused? && openssl?(1, 1, 0) && !openssl?(1, 1, 0, 7) - # OpenSSL >= 1.1.0, < 1.1.0g - pend "External session cache is not working; " \ - "see https://github.com/openssl/openssl/pull/4014" - end - assert_equal true, ssl.session_reused? - ssl.session - } - assert_equal sess0.id, sess2.id - assert_equal sess0.id, called[:get] - assert_nil called[:new] - if TEST_SESSION_REMOVE_CB - assert_nil called[:remove] - end - called.clear - - sctx.flush_sessions(Time.now + 10000) - if TEST_SESSION_REMOVE_CB - assert_not_nil called[:remove] - assert_equal sess0.id, called[:remove].id - end - called.clear - - # Cache miss - connections = 3 - sess3 = server_connect_with_session(port, cctx, sess0.dup) { |ssl| - ssl.puts("abc"); assert_equal "abc\n", ssl.gets - assert_equal false, ssl.session_reused? - ssl.session - } - assert_not_equal sess0.id, sess3.id - assert_equal sess0.id, called[:get] - assert_not_nil called[:new] - assert_equal sess3.id, called[:new].id - if TEST_SESSION_REMOVE_CB - assert_nil called[:remove] - end - end - end - - def test_dup - sess_orig = OpenSSL::SSL::Session.new(DUMMY_SESSION) - sess_dup = sess_orig.dup - assert_equal(sess_orig.to_der, sess_dup.to_der) - end - - private - - def server_connect_with_session(port, ctx = nil, sess = nil) - sock = TCPSocket.new("127.0.0.1", port) - ctx ||= OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.session = sess if sess - ssl.sync_close = true - ssl.connect - yield ssl if block_given? - ensure - ssl&.close - sock&.close - end -end - -end diff --git a/test/test_ts.rb b/test/test_ts.rb deleted file mode 100644 index c57f08cf..00000000 --- a/test/test_ts.rb +++ /dev/null @@ -1,667 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) && defined?(OpenSSL::Timestamp) - -class OpenSSL::TestTimestamp < OpenSSL::TestCase - def intermediate_key - @intermediate_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQCcyODxH+oTrr7l7MITWcGaYnnBma6vidCCJjuSzZpaRmXZHAyH -0YcY4ttC0BdJ4uV+cE05IySVC7tyvVfFb8gFQ6XJV+AEktP+XkLbcxZgj9d2NVu1 -ziXdI+ldXkPnMhyWpMS5E7SD6gflv9NhUYEsmAGsUgdK6LDmm2W2/4TlewIDAQAB -AoGAYgx6KDFWONLqjW3f/Sv/mGYHUNykUyDzpcD1Npyf797gqMMSzwlo3FZa2tC6 -D7n23XirwpTItvEsW9gvgMikJDPlThAeGLZ+L0UbVNNBHVxGP998Nda1kxqKvhRE -pfZCKc7PLM9ZXc6jBTmgxdcAYfVCCVUoa2mEf9Ktr3BlI4kCQQDQAM09+wHDXGKP -o2UnCwCazGtyGU2r0QCzHlh9BVY+KD2KjjhuWh86rEbdWN7hEW23Je1vXIhuM6Pa -/Ccd+XYnAkEAwPZ91PK6idEONeGQ4I3dyMKV2SbaUjfq3MDL4iIQPQPuj7QsBO/5 -3Nf9ReSUUTRFCUVwoC8k4Z1KAJhR/K/ejQJANE7PTnPuGJQGETs09+GTcFpR9uqY -FspDk8fg1ufdrVnvSAXF+TJewiGK3KU5v33jinhWQngRsyz3Wt2odKhEZwJACbjh -oicQqvzzgFd7GzVKpWDYd/ZzLY1PsgusuhoJQ2m9TVRAm4cTycLAKhNYPbcqe0sa -X5fAffWU0u7ZwqeByQJAOUAbYET4RU3iymAvAIDFj8LiQnizG9t5Ty3HXlijKQYv -y8gsvWd4CdxwOPatWpBUX9L7IXcMJmD44xXTUvpbfQ== ------END RSA PRIVATE KEY----- -_end_of_pem_ - end - - def ee_key - @ee_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDA6eB5r2O5KOKNbKMBhzadl43lgpwqq28m+G0gH38kKCL1f3o9 -P8xUZm7sZqcWEervZMSSXMGBV9DgeoSR+U6FMJywgQGx/JNRx7wZTMNym3PvgLkl -xCXh6ZA0/xbtJtcNI+UUv0ENBkTIuUWBhkAf3jQclAr9aQ0ktYBuHAcRcQIDAQAB -AoGAKNhcAuezwZx6e18pFEXAtpVEIfgJgK9TlXi8AjUpAkrNPBWFmDpN1QDrM3p4 -nh+lEpLPW/3vqqchPqYyM4YJraMLpS3KUG+s7+m9QIia0ri2WV5Cig7WL+Tl9p7K -b3oi2Aj/wti8GfOLFQXOQQ4Ea4GoCv2Sxe0GZR39UBxzTsECQQD1zuVIwBvqU2YR -8innsoa+j4u2hulRmQO6Zgpzj5vyRYfA9uZxQ9nKbfJvzuWwUv+UzyS9RqxarqrP -5nQw5EmVAkEAyOmJg6+AfGrgvSWfSpXEds/WA/sHziCO3rE4/sd6cnDc6XcTgeMs -mT8Z3kAYGpqFDew5orUylPfJJa+PUueJbQJAY+gkvw3+Cp69FLw1lgu0wo07fwOU -n2qu3jsNMm0DOFRUWfTAMvcd9S385L7WEnWZldUfnKK1+OGXYYrMXPbchQJAChU2 -UoaHQzc16iguM1cK0g+iJPb/MEgQA3sPajHmokGpxIm2T+lvvo0dJjs/Om6QyN8X -EWRYkoNQ8/Q4lCeMjQJAfvDIGtyqF4PieFHYgluQAv5pGgYpakdc8SYyeRH9NKey -GaL27FRs4fRWf9OmxPhUVgIyGzLGXrueemvQUDHObA== ------END RSA PRIVATE KEY----- -_end_of_pem_ - end - - def ca_cert - @ca_cert ||= OpenSSL::Certs.ca_cert - end - - def ca_store - @ca_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(ca_cert) } - end - - def ts_cert_direct - @ts_cert_direct ||= OpenSSL::Certs.ts_cert_direct(ee_key, ca_cert) - end - - def intermediate_cert - @intermediate_cert ||= OpenSSL::Certs.intermediate_cert(intermediate_key, ca_cert) - end - - def intermediate_store - @intermediate_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(intermediate_cert) } - end - - def ts_cert_ee - @ts_cert_ee ||= OpenSSL::Certs.ts_cert_ee(ee_key, intermediate_cert, intermediate_key) - end - - def test_create_request - req = OpenSSL::Timestamp::Request.new - assert_equal(true, req.cert_requested?) - assert_equal(1, req.version) - assert_nil(req.algorithm) - assert_equal("", req.message_imprint) - assert_nil(req.policy_id) - assert_nil(req.nonce) - end - - def test_request_mandatory_fields - req = OpenSSL::Timestamp::Request.new - assert_raise(OpenSSL::Timestamp::TimestampError) do - tmp = req.to_der - pp OpenSSL::ASN1.decode(tmp) - end - req.algorithm = "sha1" - assert_raise(OpenSSL::Timestamp::TimestampError) do - req.to_der - end - req.message_imprint = OpenSSL::Digest::SHA1.new.digest("data") - req.to_der - end - - def test_request_assignment - req = OpenSSL::Timestamp::Request.new - - req.version = 2 - assert_equal(2, req.version) - assert_raise(TypeError) { req.version = nil } - assert_raise(TypeError) { req.version = "foo" } - - req.algorithm = "SHA1" - assert_equal("SHA1", req.algorithm) - assert_raise(TypeError) { req.algorithm = nil } - assert_raise(OpenSSL::ASN1::ASN1Error) { req.algorithm = "xxx" } - - req.message_imprint = "test" - assert_equal("test", req.message_imprint) - assert_raise(TypeError) { req.message_imprint = nil } - - req.policy_id = "1.2.3.4.5" - assert_equal("1.2.3.4.5", req.policy_id) - assert_raise(TypeError) { req.policy_id = 123 } - assert_raise(TypeError) { req.policy_id = nil } - - req.nonce = 42 - assert_equal(42, req.nonce) - assert_raise(TypeError) { req.nonce = "foo" } - assert_raise(TypeError) { req.nonce = nil } - - req.cert_requested = false - assert_equal(false, req.cert_requested?) - req.cert_requested = nil - assert_equal(false, req.cert_requested?) - req.cert_requested = 123 - assert_equal(true, req.cert_requested?) - req.cert_requested = "asdf" - assert_equal(true, req.cert_requested?) - end - - def test_request_serialization - req = OpenSSL::Timestamp::Request.new - - req.version = 2 - req.algorithm = "SHA1" - req.message_imprint = "test" - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - req.cert_requested = true - - req = OpenSSL::Timestamp::Request.new(req.to_der) - - assert_equal(2, req.version) - assert_equal("SHA1", req.algorithm) - assert_equal("test", req.message_imprint) - assert_equal("1.2.3.4.5", req.policy_id) - assert_equal(42, req.nonce) - assert_equal(true, req.cert_requested?) - - end - - def test_request_re_assignment - #tests whether the potential 'freeing' of previous values in C works properly - req = OpenSSL::Timestamp::Request.new - req.version = 2 - req.version = 3 - req.algorithm = "SHA1" - req.algorithm = "SHA256" - req.message_imprint = "test" - req.message_imprint = "test2" - req.policy_id = "1.2.3.4.5" - req.policy_id = "1.2.3.4.6" - req.nonce = 42 - req.nonce = 24 - req.cert_requested = false - req.cert_requested = true - req.to_der - end - - def test_request_encode_decode - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - - qer = OpenSSL::Timestamp::Request.new(req.to_der) - assert_equal(1, qer.version) - assert_equal("SHA1", qer.algorithm) - assert_equal(digest, qer.message_imprint) - assert_equal("1.2.3.4.5", qer.policy_id) - assert_equal(42, qer.nonce) - - #put OpenSSL::ASN1.decode inbetween - qer2 = OpenSSL::Timestamp::Request.new(OpenSSL::ASN1.decode(req.to_der)) - assert_equal(1, qer2.version) - assert_equal("SHA1", qer2.algorithm) - assert_equal(digest, qer2.message_imprint) - assert_equal("1.2.3.4.5", qer2.policy_id) - assert_equal(42, qer2.nonce) - end - - def test_response_constants - assert_equal(0, OpenSSL::Timestamp::Response::GRANTED) - assert_equal(1, OpenSSL::Timestamp::Response::GRANTED_WITH_MODS) - assert_equal(2, OpenSSL::Timestamp::Response::REJECTION) - assert_equal(3, OpenSSL::Timestamp::Response::WAITING) - assert_equal(4, OpenSSL::Timestamp::Response::REVOCATION_WARNING) - assert_equal(5, OpenSSL::Timestamp::Response::REVOCATION_NOTIFICATION) - end - - def test_response_creation - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - - fac = OpenSSL::Timestamp::Factory.new - time = Time.now - fac.gen_time = time - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - resp = OpenSSL::Timestamp::Response.new(resp) - assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) - assert_nil(resp.failure_info) - assert_equal([], resp.status_text) - assert_equal(1, resp.token_info.version) - assert_equal("1.2.3.4.5", resp.token_info.policy_id) - assert_equal("SHA1", resp.token_info.algorithm) - assert_equal(digest, resp.token_info.message_imprint) - assert_equal(1, resp.token_info.serial_number) - assert_equal(time.to_i, resp.token_info.gen_time.to_i) - assert_equal(false, resp.token_info.ordering) - assert_nil(resp.token_info.nonce) - assert_cert(ts_cert_ee, resp.tsa_certificate) - #compare PKCS7 - token = OpenSSL::ASN1.decode(resp.to_der).value[1] - assert_equal(token.to_der, resp.token.to_der) - end - - def test_response_mandatory_fields - fac = OpenSSL::Timestamp::Factory.new - req = OpenSSL::Timestamp::Request.new - assert_raise(OpenSSL::Timestamp::TimestampError) do - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - req.algorithm = "sha1" - assert_raise(OpenSSL::Timestamp::TimestampError) do - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - req.message_imprint = OpenSSL::Digest::SHA1.new.digest("data") - assert_raise(OpenSSL::Timestamp::TimestampError) do - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - fac.gen_time = Time.now - assert_raise(OpenSSL::Timestamp::TimestampError) do - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - assert_raise(OpenSSL::Timestamp::TimestampError) do - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - fac.default_policy_id = "1.2.3.4.5" - assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status - fac.default_policy_id = nil - assert_raise(OpenSSL::Timestamp::TimestampError) do - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - req.policy_id = "1.2.3.4.5" - assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status - end - - def test_response_allowed_digests - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - req.message_imprint = OpenSSL::Digest::SHA1.digest("test") - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.default_policy_id = "1.2.3.4.6" - - # None allowed by default - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status - - # Explicitly allow SHA1 (string) - fac.allowed_digests = ["sha1"] - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status - - # Explicitly allow SHA1 (object) - fac.allowed_digests = [OpenSSL::Digest::SHA1.new] - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status - - # Others not allowed - req.algorithm = "SHA256" - req.message_imprint = OpenSSL::Digest::SHA256.digest("test") - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status - - # Non-Array - fac.allowed_digests = 123 - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status - - # Non-String, non-Digest Array element - fac.allowed_digests = ["sha1", OpenSSL::Digest::SHA1.new, 123] - assert_raise(TypeError) do - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - end - - def test_response_default_policy - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - fac.default_policy_id = "1.2.3.4.6" - - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) - assert_equal("1.2.3.4.6", resp.token_info.policy_id) - end - - def test_response_bad_purpose - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - - - assert_raise(OpenSSL::Timestamp::TimestampError) do - fac.create_timestamp(ee_key, intermediate_cert, req) - end - end - - def test_no_cert_requested - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.cert_requested = false - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - fac.default_policy_id = "1.2.3.4.5" - - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) - assert_nil(resp.tsa_certificate) - end - - def test_response_no_policy_defined - assert_raise(OpenSSL::Timestamp::TimestampError) do - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - - fac.create_timestamp(ee_key, ts_cert_ee, req) - end - end - - def test_verify_ee_no_req - assert_raise(TypeError) do - ts, _ = timestamp_ee - ts.verify(nil, ca_cert) - end - end - - def test_verify_ee_no_store - assert_raise(TypeError) do - ts, req = timestamp_ee - ts.verify(req, nil) - end - end - - def test_verify_ee_wrong_root_no_intermediate - assert_raise(OpenSSL::Timestamp::TimestampError) do - ts, req = timestamp_ee - ts.verify(req, intermediate_store) - end - end - - def test_verify_ee_wrong_root_wrong_intermediate - assert_raise(OpenSSL::Timestamp::TimestampError) do - ts, req = timestamp_ee - ts.verify(req, intermediate_store, [ca_cert]) - end - end - - def test_verify_ee_nonce_mismatch - assert_raise(OpenSSL::Timestamp::TimestampError) do - ts, req = timestamp_ee - req.nonce = 1 - ts.verify(req, ca_store, [intermediate_cert]) - end - end - - def test_verify_ee_intermediate_missing - assert_raise(OpenSSL::Timestamp::TimestampError) do - ts, req = timestamp_ee - ts.verify(req, ca_store) - end - end - - def test_verify_ee_intermediate - ts, req = timestamp_ee - ts.verify(req, ca_store, [intermediate_cert]) - end - - def test_verify_ee_intermediate_type_error - ts, req = timestamp_ee - assert_raise(TypeError) { ts.verify(req, [ca_cert], 123) } - end - - def test_verify_ee_def_policy - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.nonce = 42 - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - fac.default_policy_id = "1.2.3.4.5" - - ts = fac.create_timestamp(ee_key, ts_cert_ee, req) - ts.verify(req, ca_store, [intermediate_cert]) - end - - def test_verify_direct - ts, req = timestamp_direct - ts.verify(req, ca_store) - end - - def test_verify_direct_redundant_untrusted - ts, req = timestamp_direct - ts.verify(req, ca_store, [ts.tsa_certificate, ts.tsa_certificate]) - end - - def test_verify_direct_unrelated_untrusted - ts, req = timestamp_direct - ts.verify(req, ca_store, [intermediate_cert]) - end - - def test_verify_direct_wrong_root - assert_raise(OpenSSL::Timestamp::TimestampError) do - ts, req = timestamp_direct - ts.verify(req, intermediate_store) - end - end - - def test_verify_direct_no_cert_no_intermediate - assert_raise(OpenSSL::Timestamp::TimestampError) do - ts, req = timestamp_direct_no_cert - ts.verify(req, ca_store) - end - end - - def test_verify_ee_no_cert - ts, req = timestamp_ee_no_cert - ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]) - end - - def test_verify_ee_no_cert_no_intermediate - assert_raise(OpenSSL::Timestamp::TimestampError) do - ts, req = timestamp_ee_no_cert - ts.verify(req, ca_store, [ts_cert_ee]) - end - end - - def test_verify_ee_additional_certs_array - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - fac.additional_certs = [intermediate_cert] - ts = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal(2, ts.token.certificates.size) - fac.additional_certs = nil - ts.verify(req, ca_store) - ts = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal(1, ts.token.certificates.size) - end - - def test_verify_ee_additional_certs_with_root - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - fac.additional_certs = [intermediate_cert, ca_cert] - ts = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_equal(3, ts.token.certificates.size) - ts.verify(req, ca_store) - end - - def test_verify_ee_cert_inclusion_not_requested - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.nonce = 42 - req.cert_requested = false - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - #needed because the Request contained no policy identifier - fac.default_policy_id = '1.2.3.4.5' - fac.additional_certs = [ ts_cert_ee, intermediate_cert ] - ts = fac.create_timestamp(ee_key, ts_cert_ee, req) - assert_nil(ts.token.certificates) #since cert_requested? == false - ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]) - end - - def test_reusable - #test if req and faq are reusable, i.e. the internal - #CTX_free methods don't mess up e.g. the certificates - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - fac.additional_certs = [ intermediate_cert ] - ts1 = fac.create_timestamp(ee_key, ts_cert_ee, req) - ts1.verify(req, ca_store) - ts2 = fac.create_timestamp(ee_key, ts_cert_ee, req) - ts2.verify(req, ca_store) - refute_nil(ts1.tsa_certificate) - refute_nil(ts2.tsa_certificate) - end - - def test_token_info_creation - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = OpenSSL::BN.new(123) - - fac = OpenSSL::Timestamp::Factory.new - time = Time.now - fac.gen_time = time - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - - resp = fac.create_timestamp(ee_key, ts_cert_ee, req) - info = resp.token_info - info = OpenSSL::Timestamp::TokenInfo.new(info.to_der) - - assert_equal(1, info.version) - assert_equal("1.2.3.4.5", info.policy_id) - assert_equal("SHA1", info.algorithm) - assert_equal(digest, info.message_imprint) - assert_equal(1, info.serial_number) - assert_equal(time.to_i, info.gen_time.to_i) - assert_equal(false, info.ordering) - assert_equal(123, info.nonce) - end - - private - - def assert_cert expected, actual - assert_equal expected.to_der, actual.to_der - end - - def timestamp_ee - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - return fac.create_timestamp(ee_key, ts_cert_ee, req), req - end - - def timestamp_ee_no_cert - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - req.cert_requested = false - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - return fac.create_timestamp(ee_key, ts_cert_ee, req), req - end - - def timestamp_direct - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - return fac.create_timestamp(ee_key, ts_cert_direct, req), req - end - - def timestamp_direct_no_cert - req = OpenSSL::Timestamp::Request.new - req.algorithm = "SHA1" - digest = OpenSSL::Digest::SHA1.new.digest("test") - req.message_imprint = digest - req.policy_id = "1.2.3.4.5" - req.nonce = 42 - req.cert_requested = false - - fac = OpenSSL::Timestamp::Factory.new - fac.gen_time = Time.now - fac.serial_number = 1 - fac.allowed_digests = ["sha1"] - return fac.create_timestamp(ee_key, ts_cert_direct, req), req - end -end - -end diff --git a/test/test_x509attr.rb b/test/test_x509attr.rb deleted file mode 100644 index 2919d23d..00000000 --- a/test/test_x509attr.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestX509Attribute < OpenSSL::TestCase - def test_new - ef = OpenSSL::X509::ExtensionFactory.new - val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ - ef.create_extension("keyUsage", "keyCertSign", true) - ])]) - attr = OpenSSL::X509::Attribute.new("extReq", val) - assert_equal("extReq", attr.oid) - assert_equal(val.to_der, attr.value.to_der) - - attr = OpenSSL::X509::Attribute.new("1.2.840.113549.1.9.14", val) - assert_equal("extReq", attr.oid) - end - - def test_from_der - # oid: challengePassword, values: Set[UTF8String<"abc123">] - test_der = "\x30\x15\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x07\x31\x08" \ - "\x0c\x06\x61\x62\x63\x31\x32\x33".b - attr = OpenSSL::X509::Attribute.new(test_der) - assert_equal(test_der, attr.to_der) - assert_equal("challengePassword", attr.oid) - assert_equal("abc123", attr.value.value[0].value) - end - - def test_to_der - ef = OpenSSL::X509::ExtensionFactory.new - val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ - ef.create_extension("keyUsage", "keyCertSign", true) - ])]) - attr = OpenSSL::X509::Attribute.new("extReq", val) - expected = OpenSSL::ASN1::Sequence.new([ - OpenSSL::ASN1::ObjectId.new("extReq"), - val - ]) - assert_equal(expected.to_der, attr.to_der) - end - - def test_invalid_value - # should not change the original value - test_der = "\x30\x15\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x07\x31\x08" \ - "\x0c\x06\x61\x62\x63\x31\x32\x33".b - attr = OpenSSL::X509::Attribute.new(test_der) - assert_raise(TypeError) { - attr.value = "1234" - } - assert_equal(test_der, attr.to_der) - assert_raise(OpenSSL::X509::AttributeError) { - attr.oid = "abc123" - } - assert_equal(test_der, attr.to_der) - end - - def test_dup - val = OpenSSL::ASN1::Set([ - OpenSSL::ASN1::UTF8String("abc123") - ]) - attr = OpenSSL::X509::Attribute.new("challengePassword", val) - assert_equal(attr.to_der, attr.dup.to_der) - end - - def test_eq - val1 = OpenSSL::ASN1::Set([ - OpenSSL::ASN1::UTF8String("abc123") - ]) - attr1 = OpenSSL::X509::Attribute.new("challengePassword", val1) - attr2 = OpenSSL::X509::Attribute.new("challengePassword", val1) - ef = OpenSSL::X509::ExtensionFactory.new - val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ - ef.create_extension("keyUsage", "keyCertSign", true) - ])]) - attr3 = OpenSSL::X509::Attribute.new("extReq", val2) - - assert_equal false, attr1 == 12345 - assert_equal true, attr1 == attr2 - assert_equal false, attr1 == attr3 - end - - def test_marshal - val = OpenSSL::ASN1::Set([ - OpenSSL::ASN1::UTF8String("abc123") - ]) - attr = OpenSSL::X509::Attribute.new("challengePassword", val) - deserialized = Marshal.load(Marshal.dump(attr)) - - assert_equal attr.to_der, deserialized.to_der - end -end - -end diff --git a/test/test_x509cert.rb b/test/test_x509cert.rb deleted file mode 100644 index ed0758a6..00000000 --- a/test/test_x509cert.rb +++ /dev/null @@ -1,288 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestX509Certificate < OpenSSL::TestCase - def setup - super - @rsa1024 = Fixtures.pkey("rsa1024") - @rsa2048 = Fixtures.pkey("rsa2048") - @dsa256 = Fixtures.pkey("dsa256") - @dsa512 = Fixtures.pkey("dsa512") - @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") - end - - def test_serial - [1, 2**32, 2**100].each{|s| - cert = issue_cert(@ca, @rsa2048, s, [], nil, nil) - assert_equal(s, cert.serial) - cert = OpenSSL::X509::Certificate.new(cert.to_der) - assert_equal(s, cert.serial) - } - end - - def test_public_key - exts = [ - ["basicConstraints","CA:TRUE",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], - ] - - [ - @rsa1024, @rsa2048, @dsa256, @dsa512, - ].each{|pk| - cert = issue_cert(@ca, pk, 1, exts, nil, nil) - assert_equal(cert.extensions.sort_by(&:to_s)[2].value, - OpenSSL::TestUtils.get_subject_key_id(cert)) - cert = OpenSSL::X509::Certificate.new(cert.to_der) - assert_equal(cert.extensions.sort_by(&:to_s)[2].value, - OpenSSL::TestUtils.get_subject_key_id(cert)) - } - end - - def test_validity - now = Time.at(Time.now.to_i + 0.9) - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, - not_before: now, not_after: now+3600) - assert_equal(Time.at(now.to_i), cert.not_before) - assert_equal(Time.at(now.to_i+3600), cert.not_after) - - now = Time.at(now.to_i) - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, - not_before: now, not_after: now+3600) - assert_equal(now.getutc, cert.not_before) - assert_equal((now+3600).getutc, cert.not_after) - - now = Time.at(0) - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, - not_before: now, not_after: now) - assert_equal(now.getutc, cert.not_before) - assert_equal(now.getutc, cert.not_after) - - now = Time.at(0x7fffffff) - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, - not_before: now, not_after: now) - assert_equal(now.getutc, cert.not_before) - assert_equal(now.getutc, cert.not_after) - end - - def test_extension - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","issuer:always,keyid:always",false], - ] - ca_cert = issue_cert(@ca, @rsa2048, 1, ca_exts, nil, nil) - keyid = get_subject_key_id(ca_cert.to_der, hex: false) - assert_equal keyid, ca_cert.authority_key_identifier - assert_equal keyid, ca_cert.subject_key_identifier - ca_cert.extensions.each_with_index{|ext, i| - assert_equal(ca_exts[i].first, ext.oid) - assert_equal(ca_exts[i].last, ext.critical?) - } - - ee1_exts = [ - ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","issuer:always,keyid:always",false], - ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], - ["subjectAltName","email:ee1@ruby-lang.org",false], - ["authorityInfoAccess","caIssuers;URI:http://www.example.com/caIssuers,OCSP;URI:http://www.example.com/ocsp",false], - ] - ee1_cert = issue_cert(@ee1, @rsa1024, 2, ee1_exts, ca_cert, @rsa2048) - assert_equal(ca_cert.subject.to_der, ee1_cert.issuer.to_der) - ee1_cert.extensions.each_with_index{|ext, i| - assert_equal(ee1_exts[i].first, ext.oid) - assert_equal(ee1_exts[i].last, ext.critical?) - } - assert_nil(ee1_cert.crl_uris) - - ef = OpenSSL::X509::ExtensionFactory.new - ef.config = OpenSSL::Config.parse(<<~_cnf_) - [crlDistPts] - URI.1 = http://www.example.com/crl - URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary - _cnf_ - cdp_cert = generate_cert(@ee1, @rsa1024, 3, ca_cert) - ef.subject_certificate = cdp_cert - cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "@crlDistPts")) - cdp_cert.sign(@rsa2048, "sha256") - assert_equal( - ["http://www.example.com/crl", "ldap://ldap.example.com/cn=ca?certificateRevocationList;binary"], - cdp_cert.crl_uris - ) - - ef = OpenSSL::X509::ExtensionFactory.new - aia_cert = generate_cert(@ee1, @rsa1024, 4, ca_cert) - ef.subject_certificate = aia_cert - aia_cert.add_extension( - ef.create_extension( - "authorityInfoAccess", - "caIssuers;URI:http://www.example.com/caIssuers," \ - "caIssuers;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary," \ - "OCSP;URI:http://www.example.com/ocsp," \ - "OCSP;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary", - false - ) - ) - aia_cert.sign(@rsa2048, "sha256") - assert_equal( - ["http://www.example.com/caIssuers", "ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary"], - aia_cert.ca_issuer_uris - ) - assert_equal( - ["http://www.example.com/ocsp", "ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary"], - aia_cert.ocsp_uris - ) - - no_exts_cert = issue_cert(@ca, @rsa2048, 5, [], nil, nil) - assert_equal nil, no_exts_cert.authority_key_identifier - assert_equal nil, no_exts_cert.subject_key_identifier - assert_equal nil, no_exts_cert.crl_uris - assert_equal nil, no_exts_cert.ca_issuer_uris - assert_equal nil, no_exts_cert.ocsp_uris - end - - def test_invalid_extension - integer = OpenSSL::ASN1::Integer.new(0) - invalid_exts_cert = generate_cert(@ee1, @rsa1024, 1, nil) - ["subjectKeyIdentifier", "authorityKeyIdentifier", "crlDistributionPoints", "authorityInfoAccess"].each do |ext| - invalid_exts_cert.add_extension( - OpenSSL::X509::Extension.new(ext, integer.to_der) - ) - end - - assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { - invalid_exts_cert.authority_key_identifier - } - assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { - invalid_exts_cert.subject_key_identifier - } - assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { - invalid_exts_cert.crl_uris - } - assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { - invalid_exts_cert.ca_issuer_uris - } - assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { - invalid_exts_cert.ocsp_uris - } - end - - def test_sign_and_verify_rsa_sha1 - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "sha1") - assert_equal(false, cert.verify(@rsa1024)) - assert_equal(true, cert.verify(@rsa2048)) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) - cert.serial = 2 - assert_equal(false, cert.verify(@rsa2048)) - end - - def test_sign_and_verify_rsa_md5 - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "md5") - assert_equal(false, cert.verify(@rsa1024)) - assert_equal(true, cert.verify(@rsa2048)) - - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) - cert.subject = @ee1 - assert_equal(false, cert.verify(@rsa2048)) - rescue OpenSSL::X509::CertificateError # RHEL7 disables MD5 - end - - def test_sign_and_verify_dsa - cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) - assert_equal(false, certificate_error_returns_false { cert.verify(@rsa1024) }) - assert_equal(false, certificate_error_returns_false { cert.verify(@rsa2048) }) - assert_equal(false, cert.verify(@dsa256)) - assert_equal(true, cert.verify(@dsa512)) - cert.not_after = Time.now - assert_equal(false, cert.verify(@dsa512)) - end - - def test_sign_and_verify_rsa_dss1 - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: OpenSSL::Digest::DSS1.new) - assert_equal(false, cert.verify(@rsa1024)) - assert_equal(true, cert.verify(@rsa2048)) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) - cert.subject = @ee1 - assert_equal(false, cert.verify(@rsa2048)) - rescue OpenSSL::X509::CertificateError - end if defined?(OpenSSL::Digest::DSS1) - - def test_sign_and_verify_dsa_md5 - assert_raise(OpenSSL::X509::CertificateError){ - issue_cert(@ca, @dsa512, 1, [], nil, nil, digest: "md5") - } - end - - def test_dsa_with_sha2 - cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha256") - assert_equal("dsa_with_SHA256", cert.signature_algorithm) - # TODO: need more tests for dsa + sha2 - - # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) - cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1") - assert_equal("dsaWithSHA1", cert.signature_algorithm) - end - - def test_check_private_key - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) - assert_equal(true, cert.check_private_key(@rsa2048)) - end - - def test_read_from_file - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) - Tempfile.create("cert") { |f| - f << cert.to_pem - f.rewind - assert_equal cert.to_der, OpenSSL::X509::Certificate.new(f).to_der - } - end - - def test_eq - now = Time.now - cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil, - not_before: now, not_after: now + 3600) - cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, - not_before: now, not_after: now + 3600) - cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, - not_before: now, not_after: now + 3600) - cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024, - not_before: now, not_after: now + 3600) - cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, - digest: "sha512", not_before: now, not_after: now + 3600) - - assert_equal false, cert1 == 12345 - assert_equal true, cert1 == cert2 - assert_equal false, cert1 == cert3 - assert_equal false, cert1 == cert4 - assert_equal false, cert3 == cert4 - end - - def test_marshal - now = Time.now - cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil, - not_before: now, not_after: now + 3600) - cert = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, - not_before: now, not_after: now + 3600) - deserialized = Marshal.load(Marshal.dump(cert)) - - assert_equal cert.to_der, deserialized.to_der - end - - private - - def certificate_error_returns_false - yield - rescue OpenSSL::X509::CertificateError - false - end -end - -end diff --git a/test/test_x509crl.rb b/test/test_x509crl.rb deleted file mode 100644 index a6d0adc5..00000000 --- a/test/test_x509crl.rb +++ /dev/null @@ -1,284 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestX509CRL < OpenSSL::TestCase - def setup - super - @rsa1024 = Fixtures.pkey("rsa1024") - @rsa2048 = Fixtures.pkey("rsa2048") - @dsa256 = Fixtures.pkey("dsa256") - @dsa512 = Fixtures.pkey("dsa512") - @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") - @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") - end - - def test_basic - now = Time.at(Time.now.to_i) - - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) - crl = issue_crl([], 1, now, now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - assert_equal(1, crl.version) - assert_equal(cert.issuer.to_der, crl.issuer.to_der) - assert_equal(now, crl.last_update) - assert_equal(now+1600, crl.next_update) - - crl = OpenSSL::X509::CRL.new(crl.to_der) - assert_equal(1, crl.version) - assert_equal(cert.issuer.to_der, crl.issuer.to_der) - assert_equal(now, crl.last_update) - assert_equal(now+1600, crl.next_update) - end - - def test_revoked - - # CRLReason ::= ENUMERATED { - # unspecified (0), - # keyCompromise (1), - # cACompromise (2), - # affiliationChanged (3), - # superseded (4), - # cessationOfOperation (5), - # certificateHold (6), - # removeFromCRL (8), - # privilegeWithdrawn (9), - # aACompromise (10) } - - now = Time.at(Time.now.to_i) - revoke_info = [ - [1, Time.at(0), 1], - [2, Time.at(0x7fffffff), 2], - [3, now, 3], - [4, now, 4], - [5, now, 5], - ] - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) - crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoked = crl.revoked - assert_equal(5, revoked.size) - assert_equal(1, revoked[0].serial) - assert_equal(2, revoked[1].serial) - assert_equal(3, revoked[2].serial) - assert_equal(4, revoked[3].serial) - assert_equal(5, revoked[4].serial) - - assert_equal(Time.at(0), revoked[0].time) - assert_equal(Time.at(0x7fffffff), revoked[1].time) - assert_equal(now, revoked[2].time) - assert_equal(now, revoked[3].time) - assert_equal(now, revoked[4].time) - - assert_equal("CRLReason", revoked[0].extensions[0].oid) - assert_equal("CRLReason", revoked[1].extensions[0].oid) - assert_equal("CRLReason", revoked[2].extensions[0].oid) - assert_equal("CRLReason", revoked[3].extensions[0].oid) - assert_equal("CRLReason", revoked[4].extensions[0].oid) - - assert_equal("Key Compromise", revoked[0].extensions[0].value) - assert_equal("CA Compromise", revoked[1].extensions[0].value) - assert_equal("Affiliation Changed", revoked[2].extensions[0].value) - assert_equal("Superseded", revoked[3].extensions[0].value) - assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) - - assert_equal(false, revoked[0].extensions[0].critical?) - assert_equal(false, revoked[1].extensions[0].critical?) - assert_equal(false, revoked[2].extensions[0].critical?) - assert_equal(false, revoked[3].extensions[0].critical?) - assert_equal(false, revoked[4].extensions[0].critical?) - - assert_equal("Key Compromise", revoked[0].extensions[0].value) - assert_equal("CA Compromise", revoked[1].extensions[0].value) - assert_equal("Affiliation Changed", revoked[2].extensions[0].value) - assert_equal("Superseded", revoked[3].extensions[0].value) - assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) - - revoke_info = (1..1000).collect{|i| [i, now, 0] } - crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoked = crl.revoked - assert_equal(1000, revoked.size) - assert_equal(1, revoked[0].serial) - assert_equal(1000, revoked[999].serial) - - crl.revoked = revoked - revoked2 = crl.revoked - assert_equal(revoked.map(&:serial), revoked2.map(&:serial)) - end - - def test_extension - cert_exts = [ - ["basicConstraints", "CA:TRUE", true], - ["subjectKeyIdentifier", "hash", false], - ["authorityKeyIdentifier", "keyid:always", false], - ["subjectAltName", "email:xyzzy@ruby-lang.org", false], - ["keyUsage", "cRLSign, keyCertSign", true], - ] - crl_exts = [ - ["authorityKeyIdentifier", "issuer:always,keyid:always", false], - ["issuerAltName", "issuer:copy", false], - ] - - cert = issue_cert(@ca, @rsa2048, 1, cert_exts, nil, nil) - crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts, - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - exts = crl.extensions - assert_equal(3, exts.size) - assert_equal("1", exts[0].value) - assert_equal("crlNumber", exts[0].oid) - assert_equal(false, exts[0].critical?) - - expected_keyid = OpenSSL::TestUtils.get_subject_key_id(cert, hex: false) - assert_equal expected_keyid, crl.authority_key_identifier - - assert_equal("authorityKeyIdentifier", exts[1].oid) - keyid = OpenSSL::TestUtils.get_subject_key_id(cert) - assert_match(/^keyid:#{keyid}/, exts[1].value) - assert_equal(false, exts[1].critical?) - - assert_equal("issuerAltName", exts[2].oid) - assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) - assert_equal(false, exts[2].critical?) - - crl = OpenSSL::X509::CRL.new(crl.to_der) - exts = crl.extensions - assert_equal(3, exts.size) - assert_equal("1", exts[0].value) - assert_equal("crlNumber", exts[0].oid) - assert_equal(false, exts[0].critical?) - - assert_equal("authorityKeyIdentifier", exts[1].oid) - keyid = OpenSSL::TestUtils.get_subject_key_id(cert) - assert_match(/^keyid:#{keyid}/, exts[1].value) - assert_equal(false, exts[1].critical?) - - assert_equal("issuerAltName", exts[2].oid) - assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) - assert_equal(false, exts[2].critical?) - - no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - assert_equal nil, no_ext_crl.authority_key_identifier - end - - def test_crlnumber - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) - crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - assert_match(1.to_s, crl.extensions[0].value) - assert_match(/X509v3 CRL Number:\s+#{1}/m, crl.to_text) - - crl = issue_crl([], 2**32, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - assert_match((2**32).to_s, crl.extensions[0].value) - assert_match(/X509v3 CRL Number:\s+#{2**32}/m, crl.to_text) - - crl = issue_crl([], 2**100, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text) - assert_match((2**100).to_s, crl.extensions[0].value) - end - - def test_sign_and_verify - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) - crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest::SHA1.new) - assert_equal(false, crl.verify(@rsa1024)) - assert_equal(true, crl.verify(@rsa2048)) - assert_equal(false, crl_error_returns_false { crl.verify(@dsa256) }) - assert_equal(false, crl_error_returns_false { crl.verify(@dsa512) }) - crl.version = 0 - assert_equal(false, crl.verify(@rsa2048)) - - cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) - crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @dsa512, OpenSSL::Digest::SHA1.new) - assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) }) - assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) }) - assert_equal(false, crl.verify(@dsa256)) - assert_equal(true, crl.verify(@dsa512)) - crl.version = 0 - assert_equal(false, crl.verify(@dsa512)) - end - - def test_revoked_to_der - # revokedCertificates SEQUENCE OF SEQUENCE { - # userCertificate CertificateSerialNumber, - # revocationDate Time, - # crlEntryExtensions Extensions OPTIONAL - # -- if present, version MUST be v2 - # } OPTIONAL, - - now = Time.utc(2000, 1, 1) - rev1 = OpenSSL::X509::Revoked.new - rev1.serial = 123 - rev1.time = now - ext = OpenSSL::X509::Extension.new("CRLReason", OpenSSL::ASN1::Enumerated(1)) - rev1.extensions = [ext] - asn1 = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Integer(123), - OpenSSL::ASN1::UTCTime(now), - OpenSSL::ASN1::Sequence([ext.to_der]) - ]) - - assert_equal asn1.to_der, rev1.to_der - end - - def test_eq - now = Time.now - - cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil) - crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256") - rev1 = OpenSSL::X509::Revoked.new.tap { |rev| - rev.serial = 1 - rev.time = now - } - crl1.add_revoked(rev1) - crl2 = OpenSSL::X509::CRL.new(crl1.to_der) - - # CRL - assert_equal false, crl1 == 12345 - assert_equal true, crl1 == crl2 - rev2 = OpenSSL::X509::Revoked.new.tap { |rev| - rev.serial = 2 - rev.time = now - } - crl2.add_revoked(rev2) - assert_equal false, crl1 == crl2 - - # Revoked - assert_equal false, rev1 == 12345 - assert_equal true, rev1 == crl2.revoked[0] - assert_equal false, rev1 == crl2.revoked[1] - assert_equal true, rev2 == crl2.revoked[1] - end - - def test_marshal - now = Time.now - - cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil) - crl = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256") - rev = OpenSSL::X509::Revoked.new.tap { |rev| - rev.serial = 1 - rev.time = now - } - crl.add_revoked(rev) - deserialized = Marshal.load(Marshal.dump(crl)) - - assert_equal crl.to_der, deserialized.to_der - assert_equal crl.revoked[0].to_der, deserialized.revoked[0].to_der - end - - private - - def crl_error_returns_false - yield - rescue OpenSSL::X509::CRLError - false - end -end - -end diff --git a/test/test_x509ext.rb b/test/test_x509ext.rb deleted file mode 100644 index 7ad010d1..00000000 --- a/test/test_x509ext.rb +++ /dev/null @@ -1,104 +0,0 @@ -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestX509Extension < OpenSSL::TestCase - def setup - super - @basic_constraints_value = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Boolean(true), # CA - OpenSSL::ASN1::Integer(2) # pathlen - ]) - @basic_constraints = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::ObjectId("basicConstraints"), - OpenSSL::ASN1::Boolean(true), - OpenSSL::ASN1::OctetString(@basic_constraints_value.to_der), - ]) - end - - def test_new - ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) - assert_equal("basicConstraints", ext.oid) - assert_equal(true, ext.critical?) - assert_equal("CA:TRUE, pathlen:2", ext.value) - - ext = OpenSSL::X509::Extension.new("2.5.29.19", - @basic_constraints_value.to_der, true) - assert_equal(@basic_constraints.to_der, ext.to_der) - end - - def test_create_by_factory - ef = OpenSSL::X509::ExtensionFactory.new - - bc = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") - assert_equal(@basic_constraints.to_der, bc.to_der) - - bc = ef.create_extension("basicConstraints", "CA:TRUE, pathlen:2", true) - assert_equal(@basic_constraints.to_der, bc.to_der) - - ef.config = OpenSSL::Config.parse(<<-_end_of_cnf_) - [crlDistPts] - URI.1 = http://www.example.com/crl - URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary - - [certPolicies] - policyIdentifier = 2.23.140.1.2.1 - CPS.1 = http://cps.example.com - _end_of_cnf_ - - cdp = ef.create_extension("crlDistributionPoints", "@crlDistPts") - assert_equal(false, cdp.critical?) - assert_equal("crlDistributionPoints", cdp.oid) - assert_match(%{URI:http://www\.example\.com/crl}, cdp.value) - assert_match( - %r{URI:ldap://ldap\.example\.com/cn=ca\?certificateRevocationList;binary}, - cdp.value) - - cdp = ef.create_extension("crlDistributionPoints", "critical, @crlDistPts") - assert_equal(true, cdp.critical?) - assert_equal("crlDistributionPoints", cdp.oid) - assert_match(%{URI:http://www.example.com/crl}, cdp.value) - assert_match( - %r{URI:ldap://ldap.example.com/cn=ca\?certificateRevocationList;binary}, - cdp.value) - - cp = ef.create_extension("certificatePolicies", "@certPolicies") - assert_equal(false, cp.critical?) - assert_equal("certificatePolicies", cp.oid) - assert_match(%r{2.23.140.1.2.1}, cp.value) - assert_match(%r{http://cps.example.com}, cp.value) - end - - def test_dup - ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) - assert_equal(@basic_constraints.to_der, ext.to_der) - assert_equal(ext.to_der, ext.dup.to_der) - end - - def test_eq - ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der) - ef = OpenSSL::X509::ExtensionFactory.new - ext2 = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") - ext3 = ef.create_extension("basicConstraints", "critical, CA:TRUE") - - assert_equal false, ext1 == 12345 - assert_equal true, ext1 == ext2 - assert_equal false, ext1 == ext3 - end - - def test_marshal - ef = OpenSSL::X509::ExtensionFactory.new - ext = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") - deserialized = Marshal.load(Marshal.dump(ext)) - - assert_equal ext.to_der, deserialized.to_der - end - - def test_value_der - ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) - assert_equal @basic_constraints_value.to_der, ext.value_der - end -end - -end diff --git a/test/test_x509name.rb b/test/test_x509name.rb deleted file mode 100644 index 4ec5db20..00000000 --- a/test/test_x509name.rb +++ /dev/null @@ -1,469 +0,0 @@ -# coding: ASCII-8BIT -# frozen_string_literal: true -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestX509Name < OpenSSL::TestCase - def setup - super - @obj_type_tmpl = Hash.new(OpenSSL::ASN1::PRINTABLESTRING) - @obj_type_tmpl.update(OpenSSL::X509::Name::OBJECT_TYPE_TEMPLATE) - end - - def test_s_new - dn = [ ["C", "JP"], ["O", "example"], ["CN", "www.example.jp"] ] - name = OpenSSL::X509::Name.new(dn) - ary = name.to_a - assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) - assert_equal("C", ary[0][0]) - assert_equal("O", ary[1][0]) - assert_equal("CN", ary[2][0]) - assert_equal("JP", ary[0][1]) - assert_equal("example", ary[1][1]) - assert_equal("www.example.jp", ary[2][1]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) - - dn = [ - ["countryName", "JP"], - ["organizationName", "example"], - ["commonName", "www.example.jp"] - ] - name = OpenSSL::X509::Name.new(dn) - ary = name.to_a - assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) - assert_equal("C", ary[0][0]) - assert_equal("O", ary[1][0]) - assert_equal("CN", ary[2][0]) - assert_equal("JP", ary[0][1]) - assert_equal("example", ary[1][1]) - assert_equal("www.example.jp", ary[2][1]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) - - name = OpenSSL::X509::Name.new(dn, @obj_type_tmpl) - ary = name.to_a - assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) - - dn = [ - ["countryName", "JP", OpenSSL::ASN1::PRINTABLESTRING], - ["organizationName", "example", OpenSSL::ASN1::PRINTABLESTRING], - ["commonName", "www.example.jp", OpenSSL::ASN1::PRINTABLESTRING] - ] - name = OpenSSL::X509::Name.new(dn) - ary = name.to_a - assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) - - dn = [ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "GOTOU Yuuzou"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ["serialNumber", "123"], - ] - name = OpenSSL::X509::Name.new(dn) - ary = name.to_a - assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) - assert_equal("DC", ary[0][0]) - assert_equal("DC", ary[1][0]) - assert_equal("CN", ary[2][0]) - assert_equal("emailAddress", ary[3][0]) - assert_equal("serialNumber", ary[4][0]) - assert_equal("org", ary[0][1]) - assert_equal("ruby-lang", ary[1][1]) - assert_equal("GOTOU Yuuzou", ary[2][1]) - assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) - assert_equal("123", ary[4][1]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) - - name_from_der = OpenSSL::X509::Name.new(name.to_der) - assert_equal(name_from_der.to_s, name.to_s) - assert_equal(name_from_der.to_a, name.to_a) - assert_equal(name_from_der.to_der, name.to_der) - end - - def test_unrecognized_oid - dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.1", "Unknown OID 1"], - ["1.1.2.3.5.8.13.21.34", "Unknown OID 2"], - ["C", "US"], - ["postalCode", "60602"], - ["ST", "Illinois"], - ["L", "Chicago"], - #["street", "123 Fake St"], - ["O", "Some Company LLC"], - ["CN", "mydomain.com"] ] - - name = OpenSSL::X509::Name.new(dn) - ary = name.to_a - #assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/street=123 Fake St/O=Some Company LLC/CN=mydomain.com", name.to_s) - assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/O=Some Company LLC/CN=mydomain.com", name.to_s) - assert_equal("1.2.3.4.5.6.7.8.9.7.5.3.1", ary[0][0]) - assert_equal("1.1.2.3.5.8.13.21.34", ary[1][0]) - assert_equal("C", ary[2][0]) - assert_equal("postalCode", ary[3][0]) - assert_equal("ST", ary[4][0]) - assert_equal("L", ary[5][0]) - #assert_equal("street", ary[6][0]) - assert_equal("O", ary[6][0]) - assert_equal("CN", ary[7][0]) - assert_equal("Unknown OID 1", ary[0][1]) - assert_equal("Unknown OID 2", ary[1][1]) - assert_equal("US", ary[2][1]) - assert_equal("60602", ary[3][1]) - assert_equal("Illinois", ary[4][1]) - assert_equal("Chicago", ary[5][1]) - #assert_equal("123 Fake St", ary[6][1]) - assert_equal("Some Company LLC", ary[6][1]) - assert_equal("mydomain.com", ary[7][1]) - end - - def test_unrecognized_oid_parse_encode_equality - dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.2", "Unknown OID1"], - ["1.1.2.3.5.8.13.21.35", "Unknown OID2"], - ["C", "US"], - ["postalCode", "60602"], - ["ST", "Illinois"], - ["L", "Chicago"], - #["street", "123 Fake St"], - ["O", "Some Company LLC"], - ["CN", "mydomain.com"] ] - - name1 = OpenSSL::X509::Name.new(dn) - name2 = OpenSSL::X509::Name.parse(name1.to_s) - assert_equal(name1.to_s, name2.to_s) - assert_equal(name1.to_a, name2.to_a) - end - - def test_s_parse - dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org/1.2.3.4.5.6=A=BCD" - name = OpenSSL::X509::Name.parse(dn) - assert_equal(dn, name.to_s) - ary = name.to_a - assert_equal [ - ["DC", "org", OpenSSL::ASN1::IA5STRING], - ["DC", "ruby-lang", OpenSSL::ASN1::IA5STRING], - ["CN", "www.ruby-lang.org", OpenSSL::ASN1::UTF8STRING], - ["1.2.3.4.5.6", "A=BCD", OpenSSL::ASN1::UTF8STRING], - ], ary - - dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org, 1.2.3.4.5.6=A=BCD" - name = OpenSSL::X509::Name.parse(dn2) - assert_equal(dn, name.to_s) - assert_equal ary, name.to_a - - name = OpenSSL::X509::Name.parse(dn2, @obj_type_tmpl) - ary = name.to_a - assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[3][2]) - end - - def test_s_parse_rfc2253 - scanner = OpenSSL::X509::Name::RFC2253DN.method(:scan) - - assert_equal([["C", "JP"]], scanner.call("C=JP")) - assert_equal([ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "GOTOU Yuuzou"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ], - scanner.call( - "emailAddress=gotoyuzo@ruby-lang.org,CN=GOTOU Yuuzou,"+ - "DC=ruby-lang,DC=org") - ) - - u8 = OpenSSL::ASN1::UTF8STRING - assert_equal([ - ["DC", "org"], - ["DC", "ruby-lang"], - ["O", ",=+<>#;"], - ["O", ",=+<>#;"], - ["OU", ""], - ["OU", ""], - ["L", "aaa=\"bbb, ccc\""], - ["L", "aaa=\"bbb, ccc\""], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265", u8], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], - ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], - ["1.2.840.113549.1.9.1", "gotoyuzo@ruby-lang.org"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ], - scanner.call( - "emailAddress=gotoyuzo@ruby-lang.org," + - "1.2.840.113549.1.9.1=gotoyuzo@ruby-lang.org," + - 'CN=GOTOU \"gotoyuzo\" Yuuzou,' + - 'CN="GOTOU \"gotoyuzo\" Yuuzou",' + - '2.5.4.3=GOTOU\,\20Yuuzou,' + - '2.5.4.3=GOTOU\, Yuuzou,' + - '2.5.4.3="GOTOU, Yuuzou",' + - '2.5.4.3="GOTOU\, Yuuzou",' + - "CN=#0C0CE5BE8CE897A4E8A395E894B5," + - 'CN=\E5\BE\8C\E8\97\A4\E8\A3\95\E8\94\B5,' + - "CN=\"\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5\"," + - "CN=\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5," + - 'L=aaa\=\"bbb\, ccc\",' + - 'L="aaa=\"bbb, ccc\"",' + - 'OU=,' + - 'OU="",' + - 'O=\,\=\+\<\>\#\;,' + - 'O=",=+<>#;",' + - "DC=ruby-lang," + - "DC=org") - ) - - [ - "DC=org+DC=jp", - "DC=org,DC=ruby-lang+DC=rubyist,DC=www" - ].each{|dn| - ex = scanner.call(dn) rescue $! - dn_r = Regexp.escape(dn) - assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message) - } - - [ - ["DC=org,DC=exapmle,CN", "CN"], - ["DC=org,DC=example,", ""], - ["DC=org,DC=exapmle,CN=www.example.org;", "CN=www.example.org;"], - ["DC=org,DC=exapmle,CN=#www.example.org", "CN=#www.example.org"], - ["DC=org,DC=exapmle,CN=#777777.example.org", "CN=#777777.example.org"], - ["DC=org,DC=exapmle,CN=\"www.example\".org", "CN=\"www.example\".org"], - ["DC=org,DC=exapmle,CN=www.\"example.org\"", "CN=www.\"example.org\""], - ["DC=org,DC=exapmle,CN=www.\"example\".org", "CN=www.\"example\".org"], - ].each{|dn, msg| - ex = scanner.call(dn) rescue $! - assert_match(/^malformed RDN: .*=>#{Regexp.escape(msg)}/, ex.message) - } - - dn = "CN=www.ruby-lang.org,DC=ruby-lang,DC=org" - name = OpenSSL::X509::Name.parse_rfc2253(dn) - assert_equal(dn, name.to_s(OpenSSL::X509::Name::RFC2253)) - ary = name.to_a - assert_equal("DC", ary[0][0]) - assert_equal("DC", ary[1][0]) - assert_equal("CN", ary[2][0]) - assert_equal("org", ary[0][1]) - assert_equal("ruby-lang", ary[1][1]) - assert_equal("www.ruby-lang.org", ary[2][1]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) - end - - def test_add_entry - dn = [ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "GOTOU Yuuzou"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ["serialNumber", "123"], - ] - name = OpenSSL::X509::Name.new - dn.each{|attr| name.add_entry(*attr) } - ary = name.to_a - assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) - assert_equal("DC", ary[0][0]) - assert_equal("DC", ary[1][0]) - assert_equal("CN", ary[2][0]) - assert_equal("emailAddress", ary[3][0]) - assert_equal("serialNumber", ary[4][0]) - assert_equal("org", ary[0][1]) - assert_equal("ruby-lang", ary[1][1]) - assert_equal("GOTOU Yuuzou", ary[2][1]) - assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) - assert_equal("123", ary[4][1]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) - assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) - end - - def test_add_entry_street - # openssl/crypto/objects/obj_mac.h 1.83 - dn = [ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "GOTOU Yuuzou"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ["serialNumber", "123"], - ["street", "Namiki"], - ] - name = OpenSSL::X509::Name.new - dn.each{|attr| name.add_entry(*attr) } - ary = name.to_a - assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123/street=Namiki", name.to_s) - assert_equal("Namiki", ary[5][1]) - end - - def test_add_entry_placing - der = %w{ 30 2A - 31 12 - 30 10 06 03 55 04 0A 0C 09 72 75 62 79 2D 6C 61 6E 67 - 31 14 - 30 08 06 03 55 04 0B 0C 01 61 - 30 08 06 03 55 04 0B 0C 01 62 } - orig = OpenSSL::X509::Name.new([der.join].pack("H*")) - assert_equal("OU=b+OU=a,O=ruby-lang", orig.to_s(OpenSSL::X509::Name::RFC2253)) - # Skip for now; they do not work - # - # dn = orig.dup - # dn.add_entry("CN", "unya", loc: 0, set: 0) - # assert_equal("OU=b+OU=a,O=ruby-lang,CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) - # dn = orig.dup - # dn.add_entry("CN", "unya", loc: 0, set: 1) - # assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) - dn = orig.dup - dn.add_entry("CN", "unya", loc: 1, set: -1) - assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) - # dn = orig.dup - # dn.add_entry("CN", "unya", loc: 1, set: 0) - # assert_equal("OU=b+OU=a,CN=unya,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) - dn = orig.dup - dn.add_entry("CN", "unya", loc: 1, set: 1) - assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) - dn = orig.dup - dn.add_entry("CN", "unya", loc: -1, set: -1) - assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) - dn = orig.dup - dn.add_entry("CN", "unya", loc: -1, set: 0) - assert_equal("CN=unya,OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) - end - - def test_to_s - dn = [ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "フー, バー"], - ] - name = OpenSSL::X509::Name.new - dn.each { |x| name.add_entry(*x) } - - assert_equal "/DC=org/DC=ruby-lang/" \ - "CN=\\xE3\\x83\\x95\\xE3\\x83\\xBC, \\xE3\\x83\\x90\\xE3\\x83\\xBC", - name.to_s - # OpenSSL escapes characters with MSB by default - assert_equal \ - "CN=\\E3\\83\\95\\E3\\83\\BC\\, \\E3\\83\\90\\E3\\83\\BC," \ - "DC=ruby-lang,DC=org", - name.to_s(OpenSSL::X509::Name::RFC2253) - assert_equal "DC = org, DC = ruby-lang, " \ - "CN = \"\\E3\\83\\95\\E3\\83\\BC, \\E3\\83\\90\\E3\\83\\BC\"", - name.to_s(OpenSSL::X509::Name::ONELINE) - - empty = OpenSSL::X509::Name.new - assert_equal "", empty.to_s - assert_equal "", empty.to_s(OpenSSL::X509::Name::COMPAT) - assert_equal "", empty.to_s(OpenSSL::X509::Name::RFC2253) - assert_equal "", empty.to_s(OpenSSL::X509::Name::ONELINE) - end - - def test_to_utf8 - dn = [ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "フー, バー"], - ] - name = OpenSSL::X509::Name.new - dn.each { |x| name.add_entry(*x) } - - str = name.to_utf8 - expected = String.new("CN=フー\\, バー,DC=ruby-lang,DC=org").force_encoding("UTF-8") - assert_equal expected, str - assert_equal Encoding.find("UTF-8"), str.encoding - - empty = OpenSSL::X509::Name.new - assert_equal "", empty.to_utf8 - end - - def test_equals2 - n1 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' - n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' - - assert_equal n1, n2 - - assert_equal(false, n1 == 'abc') - assert_equal(false, n2 == nil) - end - - def test_spaceship - n1 = OpenSSL::X509::Name.new([["CN", "a"]]) - n2 = OpenSSL::X509::Name.new([["CN", "a"]]) - n3 = OpenSSL::X509::Name.new([["CN", "ab"]]) - - assert_equal(0, n1 <=> n2) - assert_equal(-1, n1 <=> n3) - assert_equal(0, n2 <=> n1) - assert_equal(-1, n2 <=> n3) - assert_equal(1, n3 <=> n1) - assert_equal(1, n3 <=> n2) - assert_equal(nil, n1 <=> 'abc') - assert_equal(nil, n2 <=> 123) - assert_equal(nil, n3 <=> nil) - end - - def name_hash(name) - # OpenSSL 1.0.0 uses SHA1 for canonical encoding (not just a der) of - # X509Name for X509_NAME_hash. - name.respond_to?(:hash_old) ? name.hash_old : name.hash - end - - def test_hash - dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" - name = OpenSSL::X509::Name.parse(dn) - d = OpenSSL::Digest::MD5.digest(name.to_der) - expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 - assert_equal(expected, name_hash(name)) - # - dn = "/DC=org/DC=ruby-lang/CN=baz.ruby-lang.org" - name = OpenSSL::X509::Name.parse(dn) - d = OpenSSL::Digest::MD5.digest(name.to_der) - expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 - assert_equal(expected, name_hash(name)) - end - - def test_equality - name0 = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "bar.ruby-lang.org"]]) - name1 = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "bar.ruby-lang.org"]]) - name2 = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "baz.ruby-lang.org"]]) - assert_equal true, name0 == name1 - assert_equal true, name0.eql?(name1) - assert_equal false, name0 == name2 - assert_equal false, name0.eql?(name2) - end - - def test_marshal - name = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "bar.ruby-lang.org"]]) - deserialized = Marshal.load(Marshal.dump(name)) - - assert_equal name.to_der, deserialized.to_der - end - - def test_dup - name = OpenSSL::X509::Name.parse("/CN=ruby-lang.org") - assert_equal(name.to_der, name.dup.to_der) - end -end - -end diff --git a/test/test_x509req.rb b/test/test_x509req.rb deleted file mode 100644 index bace06b3..00000000 --- a/test/test_x509req.rb +++ /dev/null @@ -1,170 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestX509Request < OpenSSL::TestCase - def setup - super - @rsa1024 = Fixtures.pkey("rsa1024") - @rsa2048 = Fixtures.pkey("rsa2048") - @dsa256 = Fixtures.pkey("dsa256") - @dsa512 = Fixtures.pkey("dsa512") - @dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou") - end - - def issue_csr(ver, dn, key, digest) - req = OpenSSL::X509::Request.new - req.version = ver - req.subject = dn - req.public_key = key.public_key - req.sign(key, digest) - req - end - - def test_public_key - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) - req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) - - req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) - assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) - req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) - end - - def test_version - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - assert_equal(0, req.version) - req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(0, req.version) - - req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - assert_equal(1, req.version) - req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(1, req.version) - end - - def test_subject - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - assert_equal(@dn.to_der, req.subject.to_der) - req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(@dn.to_der, req.subject.to_der) - end - - def create_ext_req(exts) - ef = OpenSSL::X509::ExtensionFactory.new - exts = exts.collect{|e| ef.create_extension(*e) } - return OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)]) - end - - def get_ext_req(ext_req_value) - set = OpenSSL::ASN1.decode(ext_req_value) - seq = set.value[0] - seq.value.collect{|asn1ext| - OpenSSL::X509::Extension.new(asn1ext).to_a - } - end - - def test_attr - exts = [ - ["keyUsage", "Digital Signature, Key Encipherment", true], - ["subjectAltName", "email:gotoyuzo@ruby-lang.org", false], - ] - attrval = create_ext_req(exts) - attrs = [ - OpenSSL::X509::Attribute.new("extReq", attrval), - OpenSSL::X509::Attribute.new("msExtReq", attrval), - ] - - req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - attrs.each{|attr| req0.add_attribute(attr) } - req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - req1.attributes = attrs - assert_equal(req0.to_der, req1.to_der) - - attrs = req0.attributes - assert_equal(2, attrs.size) - assert_equal("extReq", attrs[0].oid) - assert_equal("msExtReq", attrs[1].oid) - assert_equal(exts, get_ext_req(attrs[0].value)) - assert_equal(exts, get_ext_req(attrs[1].value)) - - req = OpenSSL::X509::Request.new(req0.to_der) - attrs = req.attributes - assert_equal(2, attrs.size) - assert_equal("extReq", attrs[0].oid) - assert_equal("msExtReq", attrs[1].oid) - assert_equal(exts, get_ext_req(attrs[0].value)) - assert_equal(exts, get_ext_req(attrs[1].value)) - end - - def test_sign_and_verify_rsa_sha1 - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - assert_equal(true, req.verify(@rsa1024)) - assert_equal(false, req.verify(@rsa2048)) - assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) - req.version = 1 - assert_equal(false, req.verify(@rsa1024)) - end - - def test_sign_and_verify_rsa_md5 - req = issue_csr(0, @dn, @rsa2048, OpenSSL::Digest::MD5.new) - assert_equal(false, req.verify(@rsa1024)) - assert_equal(true, req.verify(@rsa2048)) - assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) - req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBar") - assert_equal(false, req.verify(@rsa2048)) - rescue OpenSSL::X509::RequestError # RHEL7 disables MD5 - end - - def test_sign_and_verify_dsa - req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) - assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) - assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) - assert_equal(false, req.verify(@dsa256)) - assert_equal(true, req.verify(@dsa512)) - req.public_key = @rsa1024.public_key - assert_equal(false, req.verify(@dsa512)) - end - - def test_sign_and_verify_dsa_md5 - assert_raise(OpenSSL::X509::RequestError){ - issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } - end - - def test_dup - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - assert_equal(req.to_der, req.dup.to_der) - end - - def test_eq - req1 = issue_csr(0, @dn, @rsa1024, "sha1") - req2 = issue_csr(0, @dn, @rsa1024, "sha1") - req3 = issue_csr(0, @dn, @rsa1024, "sha256") - - assert_equal false, req1 == 12345 - assert_equal true, req1 == req2 - assert_equal false, req1 == req3 - end - - def test_marshal - req = issue_csr(0, @dn, @rsa1024, "sha256") - deserialized = Marshal.load(Marshal.dump(req)) - - assert_equal req.to_der, deserialized.to_der - end - - private - - def request_error_returns_false - yield - rescue OpenSSL::X509::RequestError - false - end -end - -end diff --git a/test/test_x509store.rb b/test/test_x509store.rb deleted file mode 100644 index 8223c9b7..00000000 --- a/test/test_x509store.rb +++ /dev/null @@ -1,241 +0,0 @@ -# frozen_string_literal: true -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestX509Store < OpenSSL::TestCase - def setup - super - @rsa1024 = Fixtures.pkey("rsa1024") - @rsa2048 = Fixtures.pkey("rsa2048") - @dsa256 = Fixtures.pkey("dsa256") - @dsa512 = Fixtures.pkey("dsa512") - @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1") - @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2") - @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") - @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") - end - - def test_nosegv_on_cleanup - cert = OpenSSL::X509::Certificate.new - store = OpenSSL::X509::Store.new - ctx = OpenSSL::X509::StoreContext.new(store, cert, []) - EnvUtil.suppress_warning do - ctx.cleanup - end - ctx.verify - end - - def test_add_file - ca_exts = [ - ["basicConstraints", "CA:TRUE", true], - ["keyUsage", "cRLSign,keyCertSign", true], - ] - cert1 = issue_cert(@ca1, @rsa1024, 1, ca_exts, nil, nil) - cert2 = issue_cert(@ca2, @rsa2048, 1, ca_exts, nil, nil) - tmpfile = Tempfile.open { |f| f << cert1.to_pem << cert2.to_pem; f } - - store = OpenSSL::X509::Store.new - assert_equal false, store.verify(cert1) - assert_equal false, store.verify(cert2) - store.add_file(tmpfile.path) - assert_equal true, store.verify(cert1) - assert_equal true, store.verify(cert2) - - # OpenSSL < 1.1.1 leaks an error on a duplicate certificate - assert_nothing_raised { store.add_file(tmpfile.path) } - assert_equal [], OpenSSL.errors - ensure - tmpfile and tmpfile.close! - end - - def test_verify - # OpenSSL uses time(2) while Time.now uses clock_gettime(CLOCK_REALTIME), - # and there may be difference. - now = Time.now - 3 - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","cRLSign,keyCertSign",true], - ] - ee_exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ] - ca1_cert = issue_cert(@ca1, @rsa2048, 1, ca_exts, nil, nil) - ca2_cert = issue_cert(@ca2, @rsa1024, 2, ca_exts, ca1_cert, @rsa2048, - not_after: now+1800) - ee1_cert = issue_cert(@ee1, @dsa256, 10, ee_exts, ca2_cert, @rsa1024) - ee2_cert = issue_cert(@ee2, @dsa512, 20, ee_exts, ca2_cert, @rsa1024) - ee3_cert = issue_cert(@ee2, @dsa512, 30, ee_exts, ca2_cert, @rsa1024, - not_before: now-100, not_after: now-1) - ee4_cert = issue_cert(@ee2, @dsa512, 40, ee_exts, ca2_cert, @rsa1024, - not_before: now+1000, not_after: now+2000,) - - revoke_info = [] - crl1 = issue_crl(revoke_info, 1, now, now+1800, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoke_info = [ [2, now, 1], ] - crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoke_info = [ [20, now, 1], ] - crl2 = issue_crl(revoke_info, 1, now, now+1800, [], - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - revoke_info = [] - crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [], - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - - assert_equal(true, ca1_cert.verify(ca1_cert.public_key)) # self signed - assert_equal(true, ca2_cert.verify(ca1_cert.public_key)) # issued by ca1 - assert_equal(true, ee1_cert.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, ee2_cert.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, ee3_cert.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, crl1.verify(ca1_cert.public_key)) # issued by ca1 - assert_equal(true, crl1_2.verify(ca1_cert.public_key)) # issued by ca1 - assert_equal(true, crl2.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, crl2_2.verify(ca2_cert.public_key)) # issued by ca2 - - store = OpenSSL::X509::Store.new - assert_equal(false, store.verify(ca1_cert)) - assert_not_equal(OpenSSL::X509::V_OK, store.error) - - assert_equal(false, store.verify(ca2_cert)) - assert_not_equal(OpenSSL::X509::V_OK, store.error) - - store.add_cert(ca1_cert) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(OpenSSL::X509::V_OK, store.error) - assert_equal("ok", store.error_string) - chain = store.chain - assert_equal(2, chain.size) - assert_equal(@ca2.to_der, chain[0].subject.to_der) - assert_equal(@ca1.to_der, chain[1].subject.to_der) - - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(false, store.verify(ca2_cert)) - assert_not_equal(OpenSSL::X509::V_OK, store.error) - - store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN - assert_equal(true, store.verify(ca2_cert)) - assert_equal(OpenSSL::X509::V_OK, store.error) - - store.add_cert(ca2_cert) - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(true, store.verify(ee1_cert)) - assert_equal(true, store.verify(ee2_cert)) - assert_equal(OpenSSL::X509::V_OK, store.error) - assert_equal("ok", store.error_string) - chain = store.chain - assert_equal(3, chain.size) - assert_equal(@ee2.to_der, chain[0].subject.to_der) - assert_equal(@ca2.to_der, chain[1].subject.to_der) - assert_equal(@ca1.to_der, chain[2].subject.to_der) - assert_equal(false, store.verify(ee3_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - assert_match(/expire/i, store.error_string) - assert_equal(false, store.verify(ee4_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) - assert_match(/not yet valid/i, store.error_string) - - store = OpenSSL::X509::Store.new - store.add_cert(ca1_cert) - store.add_cert(ca2_cert) - store.time = now + 1500 - assert_equal(true, store.verify(ca1_cert)) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(true, store.verify(ee4_cert)) - store.time = now + 1900 - assert_equal(true, store.verify(ca1_cert)) - assert_equal(false, store.verify(ca2_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - assert_equal(false, store.verify(ee4_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - store.time = now + 4000 - assert_equal(false, store.verify(ee1_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - assert_equal(false, store.verify(ee4_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - - # the underlying X509 struct caches the result of the last - # verification for signature and not-before. so the following code - # rebuilds new objects to avoid site effect. - store.time = Time.now - 4000 - assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ca2_cert))) - assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) - assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ee1_cert))) - assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) - - store = OpenSSL::X509::Store.new - store.purpose = OpenSSL::X509::PURPOSE_ANY - store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK - store.add_cert(ca1_cert) - store.add_crl(crl1) # revoke no cert - store.add_crl(crl2) # revoke ee2_cert - assert_equal(true, store.verify(ca1_cert)) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(true, store.verify(ee1_cert, [ca2_cert])) - assert_equal(false, store.verify(ee2_cert, [ca2_cert])) - - store = OpenSSL::X509::Store.new - store.purpose = OpenSSL::X509::PURPOSE_ANY - store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK - store.add_cert(ca1_cert) - store.add_crl(crl1_2) # revoke ca2_cert - store.add_crl(crl2) # revoke ee2_cert - assert_equal(true, store.verify(ca1_cert)) - assert_equal(false, store.verify(ca2_cert)) - assert_equal(true, store.verify(ee1_cert, [ca2_cert]), - "This test is expected to be success with OpenSSL 0.9.7c or later.") - assert_equal(false, store.verify(ee2_cert, [ca2_cert])) - - store.flags = - OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL - assert_equal(true, store.verify(ca1_cert)) - assert_equal(false, store.verify(ca2_cert)) - assert_equal(false, store.verify(ee1_cert, [ca2_cert])) - assert_equal(false, store.verify(ee2_cert, [ca2_cert])) - - store = OpenSSL::X509::Store.new - store.purpose = OpenSSL::X509::PURPOSE_ANY - store.flags = - OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL - store.add_cert(ca1_cert) - store.add_cert(ca2_cert) - store.add_crl(crl1) - store.add_crl(crl2_2) # issued by ca2 but expired. - assert_equal(true, store.verify(ca1_cert)) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(false, store.verify(ee1_cert)) - assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error) - assert_equal(false, store.verify(ee2_cert)) - end - - def test_set_errors - return if openssl?(1, 1, 0) || libressl? - now = Time.now - ca1_cert = issue_cert(@ca1, @rsa2048, 1, [], nil, nil) - store = OpenSSL::X509::Store.new - store.add_cert(ca1_cert) - assert_raise(OpenSSL::X509::StoreError){ - store.add_cert(ca1_cert) # add same certificate twice - } - - revoke_info = [] - crl1 = issue_crl(revoke_info, 1, now, now+1800, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoke_info = [ [2, now, 1], ] - crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - store.add_crl(crl1) - assert_raise(OpenSSL::X509::StoreError){ - store.add_crl(crl2) # add CRL issued by same CA twice. - } - end - - def test_dup - store = OpenSSL::X509::Store.new - assert_raise(NoMethodError) { store.dup } - ctx = OpenSSL::X509::StoreContext.new(store) - assert_raise(NoMethodError) { ctx.dup } - end -end - -end diff --git a/test/ut_eof.rb b/test/ut_eof.rb deleted file mode 100644 index cf1f2d42..00000000 --- a/test/ut_eof.rb +++ /dev/null @@ -1,133 +0,0 @@ -# frozen_string_literal: true -require 'test/unit' - -if defined?(OpenSSL) - -module OpenSSL::TestEOF - def test_eof_0 - open_file("") {|f| - assert_equal("", f.read(0)) - assert_equal("", f.read(0)) - assert_equal("", f.read) - assert_equal("", f.read(0)) - assert_equal("", f.read(0)) - } - open_file("") {|f| - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("") {|f| - s = +"x" - assert_equal("", f.read(nil, s)) - assert_equal("", s) - } - open_file("") {|f| - s = +"x" - assert_nil(f.read(10, s)) - assert_equal("", s) - } - end - - def test_eof_0_rw - return unless respond_to? :open_file_rw - open_file_rw("") {|f| - assert_equal("", f.read) - assert_equal("", f.read) - assert_equal(0, f.syswrite("")) - assert_equal("", f.read) - } - end - - def test_eof_1 - open_file("a") {|f| - assert_equal("", f.read(0)) - assert_equal("a", f.read(1)) - assert_equal("" , f.read(0)) - assert_equal("" , f.read(0)) - assert_equal("", f.read) - assert_equal("", f.read(0)) - assert_equal("", f.read(0)) - } - open_file("a") {|f| - assert_equal("a", f.read(1)) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read(2)) - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read) - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read(2)) - assert_equal("", f.read) - assert_equal("", f.read) - } - open_file("a") {|f| - assert_equal("a", f.read) - assert_equal("", f.read(0)) - } - open_file("a") {|f| - s = +"x" - assert_equal("a", f.read(nil, s)) - assert_equal("a", s) - } - open_file("a") {|f| - s = +"x" - assert_equal("a", f.read(10, s)) - assert_equal("a", s) - } - end - - def test_eof_2 - open_file("") {|f| - assert_equal("", f.read) - assert_predicate(f, :eof?) - } - end - - def test_eof_3 - open_file("") {|f| - assert_predicate(f, :eof?) - } - end - - module Seek - def open_file_seek(content, pos) - open_file(content) do |f| - f.seek(pos) - yield f - end - end - - def test_eof_0_seek - open_file_seek("", 10) {|f| - assert_equal(10, f.pos) - assert_equal("", f.read(0)) - assert_equal("", f.read) - assert_equal("", f.read(0)) - assert_equal("", f.read) - } - end - - def test_eof_1_seek - open_file_seek("a", 10) {|f| - assert_equal("", f.read) - assert_equal("", f.read) - } - open_file_seek("a", 1) {|f| - assert_equal("", f.read) - assert_equal("", f.read) - } - end - end -end - -end diff --git a/test/utils.rb b/test/utils.rb deleted file mode 100644 index acece979..00000000 --- a/test/utils.rb +++ /dev/null @@ -1,397 +0,0 @@ -# frozen_string_literal: true -begin - require "openssl" - - # Disable FIPS mode for tests for installations - # where FIPS mode would be enabled by default. - # Has no effect on all other installations. - OpenSSL.fips_mode=false -rescue LoadError -end - -# Compile OpenSSL with crypto-mdebug and run this test suite with OSSL_MDEBUG=1 -# environment variable to enable memory leak check. -if ENV["OSSL_MDEBUG"] == "1" - if OpenSSL.respond_to?(:print_mem_leaks) - OpenSSL.mem_check_start - - END { - GC.start - case OpenSSL.print_mem_leaks - when nil - warn "mdebug: check what is printed" - when true - raise "mdebug: memory leaks detected" - end - } - else - warn "OSSL_MDEBUG=1 is specified but OpenSSL is not built with crypto-mdebug" - end -end - -require "test/unit" -require "tempfile" -require "socket" -require "envutil" - -if defined?(OpenSSL) - -module OpenSSL::TestUtils - module Fixtures - module_function - - def pkey(name) - OpenSSL::PKey.read(read_file("pkey", name)) - rescue OpenSSL::PKey::PKeyError - # TODO: DH parameters can be read by OpenSSL::PKey.read atm - OpenSSL::PKey::DH.new(read_file("pkey", name)) - end - - def read_file(category, name) - @file_cache ||= {} - @file_cache[[category, name]] ||= - File.read(File.join(__dir__, "fixtures", category, name + ".pem")) - end - - def file_path(category, name) - File.join(__dir__, "fixtures", category, name) - end - end - - module_function - - def generate_cert(dn, key, serial, issuer, - not_before: nil, not_after: nil) - cert = OpenSSL::X509::Certificate.new - issuer = cert unless issuer - cert.version = 2 - cert.serial = serial - cert.subject = dn - cert.issuer = issuer.subject - cert.public_key = key - now = Time.now - cert.not_before = not_before || now - 3600 - cert.not_after = not_after || now + 3600 - cert - end - - - def issue_cert(dn, key, serial, extensions, issuer, issuer_key, - not_before: nil, not_after: nil, digest: "sha256") - cert = generate_cert(dn, key, serial, issuer, - not_before: not_before, not_after: not_after) - issuer = cert unless issuer - issuer_key = key unless issuer_key - ef = OpenSSL::X509::ExtensionFactory.new - ef.subject_certificate = cert - ef.issuer_certificate = issuer - extensions.each{|oid, value, critical| - cert.add_extension(ef.create_extension(oid, value, critical)) - } - cert.sign(issuer_key, digest) - cert - end - - def issue_crl(revoke_info, serial, lastup, nextup, extensions, - issuer, issuer_key, digest) - crl = OpenSSL::X509::CRL.new - crl.issuer = issuer.subject - crl.version = 1 - crl.last_update = lastup - crl.next_update = nextup - revoke_info.each{|rserial, time, reason_code| - revoked = OpenSSL::X509::Revoked.new - revoked.serial = rserial - revoked.time = time - enum = OpenSSL::ASN1::Enumerated(reason_code) - ext = OpenSSL::X509::Extension.new("CRLReason", enum) - revoked.add_extension(ext) - crl.add_revoked(revoked) - } - ef = OpenSSL::X509::ExtensionFactory.new - ef.issuer_certificate = issuer - ef.crl = crl - crlnum = OpenSSL::ASN1::Integer(serial) - crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum)) - extensions.each{|oid, value, critical| - crl.add_extension(ef.create_extension(oid, value, critical)) - } - crl.sign(issuer_key, digest) - crl - end - - def get_subject_key_id(cert, hex: true) - asn1_cert = OpenSSL::ASN1.decode(cert) - tbscert = asn1_cert.value[0] - pkinfo = tbscert.value[6] - publickey = pkinfo.value[1] - pkvalue = publickey.value - digest = OpenSSL::Digest::SHA1.digest(pkvalue) - if hex - digest.unpack("H2"*20).join(":").upcase - else - digest - end - end - - def openssl?(major = nil, minor = nil, fix = nil, patch = 0) - return false if OpenSSL::OPENSSL_VERSION.include?("LibreSSL") - return true unless major - OpenSSL::OPENSSL_VERSION_NUMBER >= - major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10 - end - - def libressl?(major = nil, minor = nil, fix = nil) - version = OpenSSL::OPENSSL_VERSION.scan(/LibreSSL (\d+)\.(\d+)\.(\d+).*/)[0] - return false unless version - !major || (version.map(&:to_i) <=> [major, minor, fix]) >= 0 - end -end - -class OpenSSL::TestCase < Test::Unit::TestCase - include OpenSSL::TestUtils - extend OpenSSL::TestUtils - - def setup - if ENV["OSSL_GC_STRESS"] == "1" - GC.stress = true - end - end - - def teardown - if ENV["OSSL_GC_STRESS"] == "1" - GC.stress = false - end - # OpenSSL error stack must be empty - assert_equal([], OpenSSL.errors) - end -end - -class OpenSSL::SSLTestCase < OpenSSL::TestCase - RUBY = EnvUtil.rubybin - ITERATIONS = ($0 == __FILE__) ? 100 : 10 - - def setup - super - @ca_key = Fixtures.pkey("rsa-1") - @svr_key = Fixtures.pkey("rsa-2") - @cli_key = Fixtures.pkey("rsa-3") - @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") - @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","cRLSign,keyCertSign",true], - ] - ee_exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ] - @ca_cert = issue_cert(@ca, @ca_key, 1, ca_exts, nil, nil) - @svr_cert = issue_cert(@svr, @svr_key, 2, ee_exts, @ca_cert, @ca_key) - @cli_cert = issue_cert(@cli, @cli_key, 3, ee_exts, @ca_cert, @ca_key) - @server = nil - end - - def tls12_supported? - ctx = OpenSSL::SSL::SSLContext.new - ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION - true - rescue - end - - def readwrite_loop(ctx, ssl) - while line = ssl.gets - ssl.write(line) - end - end - - def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true, - ctx_proc: nil, server_proc: method(:readwrite_loop), - accept_proc: proc{}, - ignore_listener_error: false, &block) - IO.pipe {|stop_pipe_r, stop_pipe_w| - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - ctx = OpenSSL::SSL::SSLContext.new - ctx.cert_store = store - ctx.cert = @svr_cert - ctx.key = @svr_key - ctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } - ctx.verify_mode = verify_mode - ctx_proc.call(ctx) if ctx_proc - - Socket.do_not_reverse_lookup = true - tcps = TCPServer.new("127.0.0.1", 0) - port = tcps.connect_address.ip_port - - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - ssls.start_immediately = start_immediately - - threads = [] - begin - server_thread = Thread.new do - if Thread.method_defined?(:report_on_exception=) # Ruby >= 2.4 - Thread.current.report_on_exception = false - end - - begin - loop do - begin - readable, = IO.select([ssls, stop_pipe_r]) - break if readable.include? stop_pipe_r - ssl = ssls.accept - accept_proc.call(ssl) - rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL, - Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET - retry if ignore_listener_error - raise - end - - th = Thread.new do - if Thread.method_defined?(:report_on_exception=) - Thread.current.report_on_exception = false - end - - begin - server_proc.call(ctx, ssl) - ensure - ssl.close - end - true - end - threads << th - end - ensure - tcps.close - end - end - - client_thread = Thread.new do - if Thread.method_defined?(:report_on_exception=) - Thread.current.report_on_exception = false - end - - begin - block.call(port) - ensure - # Stop accepting new connection - stop_pipe_w.close - server_thread.join - end - end - threads.unshift client_thread - ensure - # Terminate existing connections. If a thread did 'pend', re-raise it. - pend = nil - threads.each { |th| - begin - timeout = EnvUtil.apply_timeout_scale(30) - th.join(timeout) or - th.raise(RuntimeError, "[start_server] thread did not exit in #{timeout} secs") - rescue (defined?(MiniTest::Skip) ? MiniTest::Skip : Test::Unit::PendedError) - # MiniTest::Skip is for the Ruby tree - pend = $! - rescue Exception - end - } - raise pend if pend - assert_join_threads(threads) - end - } - end -end - -class OpenSSL::PKeyTestCase < OpenSSL::TestCase - def check_component(base, test, keys) - keys.each { |comp| - assert_equal base.send(comp), test.send(comp) - } - end - - def dup_public(key) - case key - when OpenSSL::PKey::RSA - rsa = OpenSSL::PKey::RSA.new - rsa.set_key(key.n, key.e, nil) - rsa - when OpenSSL::PKey::DSA - dsa = OpenSSL::PKey::DSA.new - dsa.set_pqg(key.p, key.q, key.g) - dsa.set_key(key.pub_key, nil) - dsa - when OpenSSL::PKey::DH - dh = OpenSSL::PKey::DH.new - dh.set_pqg(key.p, nil, key.g) - dh - else - if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key - ec = OpenSSL::PKey::EC.new(key.group) - ec.public_key = key.public_key - ec - else - raise "unknown key type" - end - end - end -end - -module OpenSSL::Certs - include OpenSSL::TestUtils - - module_function - - def ca_cert - ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Timestamp Root CA") - - ca_exts = [ - ["basicConstraints","CA:TRUE,pathlen:1",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], - ] - OpenSSL::TestUtils.issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) - end - - def ts_cert_direct(key, ca_cert) - dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server Direct") - - exts = [ - ["basicConstraints","CA:FALSE",true], - ["keyUsage","digitalSignature, nonRepudiation", true], - ["subjectKeyIdentifier", "hash",false], - ["authorityKeyIdentifier","keyid,issuer", false], - ["extendedKeyUsage", "timeStamping", true] - ] - - OpenSSL::TestUtils.issue_cert(dn, key, 2, exts, ca_cert, Fixtures.pkey("rsa2048")) - end - - def intermediate_cert(key, ca_cert) - dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Timestamp Intermediate CA") - - exts = [ - ["basicConstraints","CA:TRUE,pathlen:0",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], - ] - - OpenSSL::TestUtils.issue_cert(dn, key, 3, exts, ca_cert, Fixtures.pkey("rsa2048")) - end - - def ts_cert_ee(key, intermediate, im_key) - dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server End Entity") - - exts = [ - ["keyUsage","digitalSignature, nonRepudiation", true], - ["subjectKeyIdentifier", "hash",false], - ["authorityKeyIdentifier","keyid,issuer", false], - ["extendedKeyUsage", "timeStamping", true] - ] - - OpenSSL::TestUtils.issue_cert(dn, key, 4, exts, intermediate, im_key) - end -end - -end -- cgit v1.2.3