diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/test_asn1.rb | 3 | ||||
-rw-r--r-- | test/test_bn.rb | 4 | ||||
-rw-r--r-- | test/test_buffering.rb | 5 | ||||
-rw-r--r-- | test/test_cipher.rb | 3 | ||||
-rw-r--r-- | test/test_config.rb | 10 | ||||
-rw-r--r-- | test/test_digest.rb | 6 | ||||
-rw-r--r-- | test/test_engine.rb | 6 | ||||
-rw-r--r-- | test/test_fips.rb | 5 | ||||
-rw-r--r-- | test/test_hmac.rb | 4 | ||||
-rw-r--r-- | test/test_kdf.rb | 4 | ||||
-rw-r--r-- | test/test_ns_spki.rb | 4 | ||||
-rw-r--r-- | test/test_ocsp.rb | 6 | ||||
-rw-r--r-- | test/test_pair.rb | 129 | ||||
-rw-r--r-- | test/test_pkcs12.rb | 5 | ||||
-rw-r--r-- | test/test_pkcs7.rb | 4 | ||||
-rw-r--r-- | test/test_pkey_dh.rb | 4 | ||||
-rw-r--r-- | test/test_pkey_dsa.rb | 5 | ||||
-rw-r--r-- | test/test_pkey_ec.rb | 2 | ||||
-rw-r--r-- | test/test_pkey_rsa.rb | 7 | ||||
-rw-r--r-- | test/test_random.rb | 4 | ||||
-rw-r--r-- | test/test_ssl.rb | 431 | ||||
-rw-r--r-- | test/test_ssl_session.rb | 403 | ||||
-rw-r--r-- | test/test_x509attr.rb | 4 | ||||
-rw-r--r-- | test/test_x509cert.rb | 4 | ||||
-rw-r--r-- | test/test_x509crl.rb | 4 | ||||
-rw-r--r-- | test/test_x509ext.rb | 4 | ||||
-rw-r--r-- | test/test_x509name.rb | 4 | ||||
-rw-r--r-- | test/test_x509req.rb | 4 | ||||
-rw-r--r-- | test/test_x509store.rb | 6 | ||||
-rw-r--r-- | test/ut_eof.rb | 4 | ||||
-rw-r--r-- | test/utils.rb | 312 |
31 files changed, 731 insertions, 669 deletions
diff --git a/test/test_asn1.rb b/test/test_asn1.rb index 9ac6b9be..3e7f8c13 100644 --- a/test/test_asn1.rb +++ b/test/test_asn1.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false 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") @@ -677,5 +679,6 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase end assert_equal(:UNIVERSAL, asn1.tag_class) end +end end diff --git a/test/test_bn.rb b/test/test_bn.rb index 02c53f39..77390286 100644 --- a/test/test_bn.rb +++ b/test/test_bn.rb @@ -3,6 +3,8 @@ require_relative 'utils' require "prime" +if defined?(OpenSSL) + class OpenSSL::TestBN < OpenSSL::TestCase def setup super @@ -270,3 +272,5 @@ class OpenSSL::TestBN < OpenSSL::TestCase assert_equal(0, @e1.ucmp(-999)) end end + +end diff --git a/test/test_buffering.rb b/test/test_buffering.rb index 73cfa9d8..c85a6f02 100644 --- a/test/test_buffering.rb +++ b/test/test_buffering.rb @@ -1,9 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -require 'stringio' -class OpenSSL::TestBuffering < OpenSSL::TestCase +if defined?(OpenSSL) +class OpenSSL::TestBuffering < OpenSSL::TestCase class IO include OpenSSL::Buffering @@ -85,5 +85,6 @@ class OpenSSL::TestBuffering < OpenSSL::TestCase end assert_equal([97, 98, 99], res) end +end end diff --git a/test/test_cipher.rb b/test/test_cipher.rb index ce64fbb9..d87dedf7 100644 --- a/test/test_cipher.rb +++ b/test/test_cipher.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestCipher < OpenSSL::TestCase module Helper def has_cipher?(name) @@ -308,5 +310,6 @@ class OpenSSL::TestCipher < OpenSSL::TestCase kwargs.each {|k, v| cipher.send(:"#{k}=", v) } end end +end end diff --git a/test/test_config.rb b/test/test_config.rb index 42f9d3c5..8096375c 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestConfig < OpenSSL::TestCase def setup super @@ -171,7 +173,7 @@ __EOC__ def test_value # suppress deprecation warnings - OpenSSL::TestUtils.silent do + 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')) @@ -184,7 +186,7 @@ __EOC__ end def test_value_ENV - OpenSSL::TestUtils.silent do + 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)) @@ -199,7 +201,7 @@ __EOC__ end def test_section - OpenSSL::TestUtils.silent do + 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')) @@ -298,3 +300,5 @@ __EOC__ assert_not_equal(@it.sections.sort, c.sections.sort) end end + +end diff --git a/test/test_digest.rb b/test/test_digest.rb index e81d618d..2cb878b6 100644 --- a/test/test_digest.rb +++ b/test/test_digest.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestDigest < OpenSSL::TestCase def setup super @@ -53,7 +55,7 @@ class OpenSSL::TestDigest < OpenSSL::TestCase def test_digest_constants algs = %w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512) - if OpenSSL::OPENSSL_VERSION_NUMBER < 0x10100000 + if !libressl? && !openssl?(1, 1, 0) algs += %w(DSS1 SHA) end algs.each do |alg| @@ -115,3 +117,5 @@ class OpenSSL::TestDigest < OpenSSL::TestCase assert_not_nil(d) end end + +end diff --git a/test/test_engine.rb b/test/test_engine.rb index a987f267..4f3973a7 100644 --- a/test/test_engine.rb +++ b/test/test_engine.rb @@ -1,8 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -class OpenSSL::TestEngine < OpenSSL::TestCase +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") @@ -95,5 +96,6 @@ class OpenSSL::TestEngine < OpenSSL::TestCase cipher.update(data) + cipher.final end end +end -end if defined?(OpenSSL::Engine) +end diff --git a/test/test_fips.rb b/test/test_fips.rb index e96c5c07..a4ab87f3 100644 --- a/test/test_fips.rb +++ b/test/test_fips.rb @@ -1,8 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -class OpenSSL::TestFIPS < OpenSSL::TestCase +if defined?(OpenSSL) +class OpenSSL::TestFIPS < OpenSSL::TestCase def test_fips_mode_is_reentrant OpenSSL.fips_mode = false OpenSSL.fips_mode = false @@ -18,3 +19,5 @@ class OpenSSL::TestFIPS < OpenSSL::TestCase end end end + +end diff --git a/test/test_hmac.rb b/test/test_hmac.rb index 86857ba0..831a5b6b 100644 --- a/test/test_hmac.rb +++ b/test/test_hmac.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestHMAC < OpenSSL::TestCase def test_hmac # RFC 2202 2. Test Cases for HMAC-MD5 @@ -38,3 +40,5 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase assert_equal first, second end end + +end diff --git a/test/test_kdf.rb b/test/test_kdf.rb index 9346be7c..d91fa3cf 100644 --- a/test/test_kdf.rb +++ b/test/test_kdf.rb @@ -1,8 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -class OpenSSL::TestKDF < OpenSSL::TestCase +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")) @@ -135,5 +136,6 @@ class OpenSSL::TestKDF < OpenSSL::TestCase 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 index 4905fba4..aa1e6182 100644 --- a/test/test_ns_spki.rb +++ b/test/test_ns_spki.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestNSSPI < OpenSSL::TestCase def setup super @@ -47,3 +49,5 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) end end + +end diff --git a/test/test_ocsp.rb b/test/test_ocsp.rb index 25e052ae..9d48496d 100644 --- a/test/test_ocsp.rb +++ b/test/test_ocsp.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestOCSP < OpenSSL::TestCase def setup super @@ -120,7 +122,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) ret = req.verify([@cert], store) - if ret || OpenSSL::OPENSSL_VERSION =~ /OpenSSL/ && OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 + if ret || openssl?(1, 0, 2) || libressl?(2, 4, 2) assert_equal true, ret else # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when @@ -307,3 +309,5 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal res.to_der, res.dup.to_der end end + +end diff --git a/test/test_pair.rb b/test/test_pair.rb index a462891d..89cf41a8 100644 --- a/test/test_pair.rb +++ b/test/test_pair.rb @@ -1,59 +1,45 @@ # frozen_string_literal: false require_relative 'utils' - -require 'socket' require_relative 'ut_eof' +if defined?(OpenSSL) + module OpenSSL::SSLPairM - def server - host = "127.0.0.1" - port = 0 - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } - tcps = create_tcp_server(host, port) - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - return ssls + 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("rsa1024") + @svr_cert = issue_cert(svr_dn, @svr_key, 1, ee_exts, nil, nil) end - def client(port) + def ssl_pair host = "127.0.0.1" - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 - s = create_tcp_client(host, port) - ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) - ssl.connect - ssl.sync_close = true - ssl - end + tcps = create_tcp_server(host, 0) + port = tcps.connect_address.ip_port - def ssl_pair - ssls = server 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("dh1024") } + ssls = OpenSSL::SSL::SSLServer.new(tcps, sctx) ns = ssls.accept ssls.close ns } - port = ssls.to_io.local_address.ip_port - c = client(port) + + tcpc = create_tcp_client(host, port) + c = OpenSSL::SSL::SSLSocket.new(tcpc) + c.connect s = th.value - if block_given? - begin - yield c, s - ensure - c.close unless c.closed? - s.close unless s.closed? - end - else - return c, s - end + + yield c, s ensure - if th&.alive? - th.kill - th.join - end + tcpc&.close + tcps&.close + s&.close end end @@ -83,23 +69,27 @@ end module OpenSSL::TestEOF1M def open_file(content) - s1, s2 = ssl_pair - th = Thread.new { s2 << content; s2.close } - yield s1 - ensure - th.join if th - s1.close + 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) - s1, s2 = ssl_pair - th = Thread.new { s1 << content; s1.close } - yield s2 - ensure - th.join if th - s2.close + ssl_pair { |s1, s2| + begin + th = Thread.new { s1 << content; s1.close } + yield s2 + ensure + th&.join + end + } end end @@ -187,6 +177,27 @@ module OpenSSL::TestPairM } 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 @@ -352,8 +363,8 @@ module OpenSSL::TestPairM def test_connect_accept_nonblock_no_exception ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "ADH" - ctx2.security_level = 0 + ctx2.cert = @svr_cert + ctx2.key = @svr_key ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } sock1, sock2 = tcp_pair @@ -363,8 +374,6 @@ module OpenSSL::TestPairM assert_equal :wait_readable, accepted ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "ADH" - ctx1.security_level = 0 s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) th = Thread.new do rets = [] @@ -402,8 +411,8 @@ module OpenSSL::TestPairM def test_connect_accept_nonblock ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 + ctx.cert = @svr_cert + ctx.key = @svr_key ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } sock1, sock2 = tcp_pair @@ -426,8 +435,6 @@ module OpenSSL::TestPairM sleep 0.1 ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx) begin sleep 0.2 @@ -487,3 +494,5 @@ 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 index 2a3b47f4..de8e35ed 100644 --- a/test/test_pkcs12.rb +++ b/test/test_pkcs12.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + module OpenSSL class TestPKCS12 < OpenSSL::TestCase def setup @@ -305,6 +307,7 @@ Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== end false end - end end + +end diff --git a/test/test_pkcs7.rb b/test/test_pkcs7.rb index 5320cc38..149d3b9b 100644 --- a/test/test_pkcs7.rb +++ b/test/test_pkcs7.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestPKCS7 < OpenSSL::TestCase def setup super @@ -279,3 +281,5 @@ END assert_equal(pki_message_content_pem, p7enc.to_pem) end end + +end diff --git a/test/test_pkey_dh.rb b/test/test_pkey_dh.rb index e7e76f97..77cdb0ab 100644 --- a/test/test_pkey_dh.rb +++ b/test/test_pkey_dh.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH) + class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase NEW_KEYLEN = 256 @@ -97,3 +99,5 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase check_component(expected, key, [:p, :q, :g, :pub_key, :priv_key]) end end + +end diff --git a/test/test_pkey_dsa.rb b/test/test_pkey_dsa.rb index 52ff8579..d6519498 100644 --- a/test/test_pkey_dsa.rb +++ b/test/test_pkey_dsa.rb @@ -1,6 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -require 'base64' + +if defined?(OpenSSL) && defined?(OpenSSL::PKey::DSA) class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase def test_private @@ -195,3 +196,5 @@ fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ== check_component(expected, key, [:p, :q, :g, :pub_key, :priv_key]) end end + +end diff --git a/test/test_pkey_ec.rb b/test/test_pkey_ec.rb index 2944f5c2..713c649a 100644 --- a/test/test_pkey_ec.rb +++ b/test/test_pkey_ec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::PKey::EC) +if defined?(OpenSSL) && defined?(OpenSSL::PKey::EC) class OpenSSL::TestEC < OpenSSL::PKeyTestCase def test_ec_key diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index fed5aa9d..49ab3792 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -1,6 +1,7 @@ # frozen_string_literal: false -require_relative 'utils' -require 'base64' +require_relative "utils" + +if defined?(OpenSSL) class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase def test_padding @@ -267,3 +268,5 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase check_component(expected, key, [:n, :e, :d, :p, :q, :dmp1, :dmq1, :iqmp]) end end + +end diff --git a/test/test_random.rb b/test/test_random.rb index dd72d84d..d5a37454 100644 --- a/test/test_random.rb +++ b/test/test_random.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestRandom < OpenSSL::TestCase def test_random_bytes assert_equal("", OpenSSL::Random.random_bytes(0)) @@ -13,3 +15,5 @@ class OpenSSL::TestRandom < OpenSSL::TestCase assert_equal(12, OpenSSL::Random.pseudo_bytes(12).bytesize) end if OpenSSL::Random.methods.include?(:pseudo_bytes) end + +end diff --git a/test/test_ssl.rb b/test/test_ssl.rb index a519c6af..fd4afa69 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -1,8 +1,9 @@ # frozen_string_literal: false require_relative "utils" -class OpenSSL::TestSSL < OpenSSL::SSLTestCase +if defined?(OpenSSL) +class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_ctx_options ctx = OpenSSL::SSL::SSLContext.new @@ -33,7 +34,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase readwrite_loop(ctx, ssl) } - start_server(ctx_proc: ctx_proc, server_proc: server_proc) { |server, port| + 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 @@ -54,7 +55,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_sysread_and_syswrite - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| str = "x" * 100 + "\n" ssl.syswrite(str) @@ -70,7 +71,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_sync_close - start_server { |server, port| + start_server { |port| begin sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) @@ -95,7 +96,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_copy_stream - start_server do |server, port| + start_server do |port| server_connect(port) do |ssl| IO.pipe do |r, w| str = "hello world\n" @@ -110,21 +111,16 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase 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) { |server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - begin - assert_handshake_error { ssl.connect } - ensure - ssl.close - end + 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) { |server, port| + start_server(verify_mode: vflag) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.key = @cli_key ctx.cert = @cli_cert @@ -151,19 +147,21 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase 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 |server, port| + 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) { } + 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) } + assert_handshake_error { + server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } + } end end @@ -173,7 +171,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag, ctx_proc: ctx_proc) { |server, port| + 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| @@ -185,8 +183,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_read_nonblock_without_session - OpenSSL::TestUtils.silent do - start_server(start_immediately: false) { |server, port| + 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 @@ -204,26 +202,21 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_starttls server_proc = -> (ctx, ssl) { - begin - while line = ssl.gets - if line =~ /^STARTTLS$/ - ssl.write("x") - ssl.flush - ssl.accept - next - end - ssl.write(line) + while line = ssl.gets + if line =~ /^STARTTLS$/ + ssl.write("x") + ssl.flush + ssl.accept + break end - rescue OpenSSL::SSL::SSLError - rescue IOError - ensure - ssl.close rescue nil + 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) { |server, port| + server_proc: server_proc) { |port| begin sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) @@ -246,7 +239,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_parallel - start_server { |server, port| + start_server { |port| ssls = [] 10.times{ sock = TCPSocket.new("127.0.0.1", port) @@ -267,7 +260,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_verify_result - start_server(ignore_listener_error: true) { |server, port| + 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 @@ -281,7 +274,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end } - start_server { |server, port| + start_server { |port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER @@ -299,7 +292,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end } - start_server(ignore_listener_error: true) { |server, port| + 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 @@ -319,7 +312,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_exception_in_verify_callback_is_ignored - start_server(ignore_listener_error: true) { |server, port| + 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 @@ -330,7 +323,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true begin - OpenSSL::TestUtils.silent do + EnvUtil.suppress_warning do # SSLError, not RuntimeError assert_raise(OpenSSL::SSL::SSLError) { ssl.connect } end @@ -355,13 +348,17 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase 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) { |server, port| + 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| @@ -375,7 +372,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_post_connection_check sslerr = OpenSSL::SSL::SSLError - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} @@ -396,7 +393,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ["subjectAltName","IP:127.0.0.1",false], ] @svr_cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| assert(ssl.post_connection_check("localhost.localdomain")) assert(ssl.post_connection_check("127.0.0.1")) @@ -416,7 +413,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ["subjectAltName","DNS:*.localdomain",false], ] @svr_cert = issue_cert(@svr, @svr_key, 5, exts, @ca_cert, @ca_key) - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| assert(ssl.post_connection_check("localhost.localdomain")) assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} @@ -619,48 +616,44 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_tlsext_hostname - ctx3 = OpenSSL::SSL::SSLContext.new - ctx3.ciphers = "ADH" - ctx3.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } - ctx3.security_level = 0 - assert_not_predicate ctx3, :frozen? + fooctx = OpenSSL::SSL::SSLContext.new + fooctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } + fooctx.cert = @cli_cert + fooctx.key = @cli_key - ctx_proc = -> ctx { - ctx.ciphers = "ALL:!aNULL" + ctx_proc = proc { |ctx| ctx.servername_cb = proc { |ssl, servername| case servername when "foo.example.com" - ctx3 + fooctx when "bar.example.com" nil else - raise "unknown hostname" + raise "unreachable" end } } - start_server(ctx_proc: ctx_proc) do |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ciphers = "ALL" - ctx.security_level = 0 - + start_server(ctx_proc: ctx_proc) do |port| sock = TCPSocket.new("127.0.0.1", port) begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.hostname = "foo.example.com" ssl.connect - assert_match (/^ADH-/), ssl.cipher[0], "the context returned by servername_cb is used" - assert_predicate ctx3, :frozen? + assert_equal @cli_cert.serial, ssl.peer_cert.serial + assert_predicate fooctx, :frozen? ensure + ssl&.close sock.close end sock = TCPSocket.new("127.0.0.1", port) begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.hostname = "bar.example.com" ssl.connect - assert_not_match (/^A(EC)?DH-/), ssl.cipher[0], "the original context is used" + assert_equal @svr_cert.serial, ssl.peer_cert.serial ensure + ssl&.close sock.close end end @@ -670,9 +663,9 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase hostname = 'example.org' ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "aNULL" + ctx2.cert = @svr_cert + ctx2.key = @svr_key ctx2.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } - ctx2.security_level = 0 ctx2.servername_cb = lambda { |args| Object.new } sock1, sock2 = socketpair @@ -680,8 +673,6 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "aNULL" - ctx1.security_level = 0 s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) s1.hostname = hostname @@ -712,7 +703,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ctx.key = @svr_key } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |server, port| + 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 @@ -746,7 +737,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_connect_certificate_verify_failed_exception_message - start_server(ignore_listener_error: true) { |server, port| + start_server(ignore_listener_error: true) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.set_params assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { @@ -758,7 +749,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase 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) { |server, port| + 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 @@ -769,31 +760,6 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end - def test_multibyte_read_write - #German a umlaut - auml = [%w{ C3 A4 }.join('')].pack('H*') - auml.force_encoding(Encoding::UTF_8) - - [10, 1000, 100000].each {|i| - str = nil - num_written = nil - server_proc = Proc.new {|ctx, ssl| - cmp = ssl.read - raw_size = cmp.size - cmp.force_encoding(Encoding::UTF_8) - assert_equal(str, cmp) - assert_equal(num_written, raw_size) - ssl.close - } - start_server(server_proc: server_proc) { |server, port| - server_connect(port) { |ssl| - str = auml * i - num_written = ssl.write(str) - } - } - } - end - def test_unset_OP_ALL ctx_proc = Proc.new { |ctx| # If OP_DONT_INSERT_EMPTY_FRAGMENTS is not defined, this test is @@ -801,7 +767,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase # But it also degrades gracefully, so keep it ctx.options = OpenSSL::SSL::OP_ALL } - start_server(ctx_proc: ctx_proc) { |server, port| + start_server(ctx_proc: ctx_proc) { |port| server_connect(port) { |ssl| ssl.puts('hello') assert_equal("hello\n", ssl.gets) @@ -813,7 +779,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) && OpenSSL::SSL::SSLContex def test_forbid_ssl_v3_for_client ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3 } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :SSLv3 assert_handshake_error { server_connect(port, ctx) } @@ -821,7 +787,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) && OpenSSL::SSL::SSLContex end def test_forbid_ssl_v3_from_server - start_server_version(:SSLv3) { |server, port| + start_server_version(:SSLv3) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3 assert_handshake_error { server_connect(port, ctx) } @@ -833,14 +799,15 @@ end if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) def test_tls_v1_1 - start_server_version(:TLSv1_1) { |server, port| - server_connect(port) { |ssl| assert_equal("TLSv1.1", ssl.ssl_version) } + start_server_version(:TLSv1_1) { |port| + ctx = OpenSSL::SSL::SSLContext.new(:TLSv1_1) + server_connect(port, ctx) { |ssl| assert_equal("TLSv1.1", ssl.ssl_version) } } end def test_forbid_tls_v1_for_client ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1 } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1 assert_handshake_error { server_connect(port, ctx) } @@ -848,7 +815,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) && OpenSSL::SSL::SSLCont end def test_forbid_tls_v1_from_server - start_server_version(:TLSv1) { |server, port| + start_server_version(:TLSv1) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1 assert_handshake_error { server_connect(port, ctx) } @@ -860,7 +827,7 @@ end if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) def test_tls_v1_2 - start_server_version(:TLSv1_2) { |server, port| + start_server_version(:TLSv1_2) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1_2_client server_connect(port, ctx) { |ssl| assert_equal("TLSv1.2", ssl.ssl_version) } @@ -869,7 +836,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLCont def test_forbid_tls_v1_1_for_client ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_1 } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1_1 assert_handshake_error { server_connect(port, ctx) } @@ -877,7 +844,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLCont end def test_forbid_tls_v1_1_from_server - start_server_version(:TLSv1_1) { |server, port| + start_server_version(:TLSv1_1) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_1 assert_handshake_error { server_connect(port, ctx) } @@ -886,7 +853,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLCont def test_forbid_tls_v1_2_for_client ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_2 } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1_2 assert_handshake_error { server_connect(port, ctx) } @@ -894,7 +861,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLCont end def test_forbid_tls_v1_2_from_server - start_server_version(:TLSv1_2) { |server, port| + start_server_version(:TLSv1_2) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_2 assert_handshake_error { server_connect(port, ctx) } @@ -907,14 +874,14 @@ end 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) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| server_connect(port) { |ssl| assert_equal(1, num_handshakes) } } end -if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 +if openssl?(1, 0, 2) || libressl? def test_alpn_protocol_selection_ary advertised = ["http/1.1", "spdy/2"] ctx_proc = Proc.new { |ctx| @@ -923,7 +890,7 @@ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 } ctx.alpn_protocols = advertised } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.alpn_protocols = advertised server_connect(port, ctx) { |ssl| @@ -936,14 +903,12 @@ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 sock1, sock2 = socketpair ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "aNULL" - ctx1.security_level = 0 + ctx1.cert = @svr_cert + ctx1.key = @svr_key ctx1.alpn_select_cb = -> (protocols) { nil } ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "aNULL" - ctx2.security_level = 0 ctx2.alpn_protocols = ["http/1.1"] ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) @@ -962,13 +927,14 @@ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 end end -if OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - # NPN may be disabled by OpenSSL configure option - 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) + advertised = ["http/1.1", "spdy/2"] - ctx_proc = Proc.new { |ctx| ctx.npn_protocols = advertised } - start_server_version(:SSLv23, ctx_proc) { |server, port| + 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) } @@ -982,13 +948,17 @@ if OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) 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) + 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(:SSLv23, ctx_proc) { |server, port| + 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) } @@ -1002,8 +972,12 @@ if OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) 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) + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } - start_server_version(:SSLv23, ctx_proc) { |server, port| + 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) } @@ -1011,8 +985,12 @@ if OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) 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) + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["a" * 256] } - start_server_version(:SSLv23, ctx_proc) { |server, port| + 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) } @@ -1020,32 +998,23 @@ if OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) 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) + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } - start_server_version(:SSLv23, ctx_proc) { |server, port| + 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 -end - - def test_invalid_shutdown_by_gc - assert_nothing_raised { - start_server { |server, port| - 10.times { - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - GC.start - ssl.connect - sock.close - } - } - } - end - def test_close_after_socket_close - start_server { |server, port| + server_proc = proc { |ctx, ssl| + # Do nothing + } + start_server(server_proc: server_proc) { |port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true @@ -1066,69 +1035,72 @@ end } end - def test_close_and_socket_close_while_connecting - # test it doesn't cause a segmentation fault - ctx = OpenSSL::SSL::SSLContext.new - ctx.ciphers = "aNULL" - ctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } - ctx.security_level = 0 - - sock1, sock2 = socketpair - ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx) - ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx) + 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 - t = Thread.new { ssl1.connect } - ssl2.accept + 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 - ssl1.close - sock1.close - t.value rescue nil - ensure - ssl1.close if ssl1 - ssl2.close if ssl2 - sock1.close if sock1 - sock2.close if sock2 - 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 - def test_get_ephemeral_key - return unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key) - pkey = OpenSSL::PKey - ciphers = { - 'ECDHE-RSA-AES128-SHA' => (pkey::EC if defined?(pkey::EC)), - 'DHE-RSA-AES128-SHA' => (pkey::DH if defined?(pkey::DH)), - 'AES128-SHA' => nil - } - conf_proc = Proc.new { |ctx| ctx.ciphers = 'ALL' } - start_server(ctx_proc: conf_proc) do |server, port| - ciphers.each do |cipher, ephemeral| + 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 - begin - ctx.ciphers = cipher - rescue OpenSSL::SSL::SSLError => e - next if /no cipher match/ =~ e.message - raise - end - server_connect(port, ctx) do |ssl| - if ephemeral - assert_instance_of(ephemeral, ssl.tmp_key) - else - assert_nil(ssl.tmp_key) - end - end + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + server_connect(port, ctx) { |ssl| + assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key + } end end end def test_dh_callback + pend "TLS 1.2 is not supported" unless tls12_supported? + called = false ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 ctx.ciphers = "DH:!NULL" ctx.tmp_dh_callback = ->(*args) { called = true Fixtures.pkey_dh("dh1024") } } - start_server(ctx_proc: ctx_proc) do |server, port| + 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) @@ -1139,11 +1111,14 @@ 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 |server, port| + start_server(ctx_proc: ctx_proc) do |port| EnvUtil.suppress_warning { # uses default callback assert_nothing_raised { server_connect(port) { } @@ -1152,73 +1127,53 @@ end end end - def test_ecdh_callback - return unless OpenSSL::SSL::SSLContext.instance_methods.include?(:tmp_ecdh_callback) + 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) + EnvUtil.suppress_warning do # tmp_ecdh_callback is deprecated (2016-05) - begin - called = false - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "ECDH" - # OpenSSL 1.1.0 doesn't have tmp_ecdh_callback so this shouldn't be required - ctx2.security_level = 0 - ctx2.tmp_ecdh_callback = ->(*args) { + called = false + ctx_proc = -> ctx { + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + ctx.tmp_ecdh_callback = -> (*args) { called = true OpenSSL::PKey::EC.new "prime256v1" } - - sock1, sock2 = socketpair - - s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "ECDH" - ctx1.security_level = 0 - - s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) - th = Thread.new do - s1.connect - end - - s2.accept - assert called, 'ecdh callback should be called' - rescue OpenSSL::SSL::SSLError => e - if e.message =~ /no cipher match/ - pend "ECDH cipher not supported." - else - raise e - end - ensure - th.join if th - s1.close if s1 - s2.close if s2 - sock1.close if sock1 - sock2.close if sock2 + } + 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 { - begin - ctx.ciphers = "ECDH:!NULL" - rescue OpenSSL::SSL::SSLError - pend "ECDH is not enabled in this OpenSSL" if $!.message =~ /no cipher match/ - raise - end + # 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 |server, port| + 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| - assert ssl.cipher[0].start_with?("ECDH"), "ECDH should be used" - if ssl.respond_to?(:tmp_key) + 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 } - if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 && - !OpenSSL::OPENSSL_VERSION.include?("LibreSSL") + if openssl?(1, 0, 2) || libressl?(2, 5, 1) ctx = OpenSSL::SSL::SSLContext.new ctx.ecdh_curves = "P-256" @@ -1267,7 +1222,7 @@ end def test_freeze_calls_setup bug = "[ruby/openssl#85]" - start_server(ignore_listener_error: true) { |server, port| + start_server(ignore_listener_error: true) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.freeze @@ -1293,7 +1248,7 @@ end ) end - def server_connect(port, ctx=nil) + 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 @@ -1315,3 +1270,5 @@ end } end end + +end diff --git a/test/test_ssl_session.rb b/test/test_ssl_session.rb index f89732ab..199f722e 100644 --- a/test/test_ssl_session.rb +++ b/test/test_ssl_session.rb @@ -1,55 +1,15 @@ # frozen_string_literal: false require_relative "utils" -class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase - def test_session_equals - session = OpenSSL::SSL::Session.new <<-SESSION ------BEGIN SSL SESSION PARAMETERS----- -MIIDFgIBAQICAwEEAgA5BCCY3pW6iTkPoD5SENuztz/gZjhvey6XnHbsxd22k0Ol -dgQw8uaN3hCRnlhoIKPWInCFzrp/tQsDRFs9jDjc9pwpy/oKHmJdQQMQA1g8FYnO -gpdVoQYCBE52ikKiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B -AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi -eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA5MTkwMDE4MTBaFw0xMTA5MTkwMDQ4 -MTBaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 -LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB -7JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ -GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw -DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQARC7GP7InX1t7VEXz2 -I8RI57S0/HSJL4fDIYP3zFpitHX1PZeo+7XuzMilvPjjBo/ky9Jzo8TYiY+N+JEz -mY/A/zPA4ZsJ7KYj6/FEdIc/vRlS0CvsbClbNjw1jl/PoB2FLr2b3uuBcZEsyZeP -yq154ijq37Ajf8K5Mi5FgshoP41BPtRPj+VVf61rv1IcEnNWdDCS6DR4XsaNC+zt -G6AqCqkytIXWRuDw6n6vYLF3A/tn2sldLo7/scY0PMDNbo63O/LTxkDHmPhSkD68 -8m9SsMeTR+RCiDEZWFPVcAH/8mDfi+5k8uN3qS+gOU/PPrmHGgl5ykiSFgqs4v61 -tddwpBAEDjcwMzA5NTYzMTU1MzAwpQMCARM= ------END SSL SESSION PARAMETERS----- - SESSION - - start_server(ignore_listener_error: true) { |_, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT - ctx.session_id_context = self.object_id.to_s - - sock = TCPSocket.new '127.0.0.1', port - begin - ssl = OpenSSL::SSL::SSLSocket.new sock, ctx - ssl.session = session - - assert_equal session, ssl.session - ensure - sock.close - end - } - end +if defined?(OpenSSL) +class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase def test_session - Timeout.timeout(5) do - start_server do |server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect + 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)) @@ -66,8 +26,7 @@ tddwpBAEDjcwMzA5NTYzMTU1MzAwpQMCARM= 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) - ssl.close - end + } end end @@ -150,220 +109,243 @@ __EOS__ assert(OpenSSL::SSL::Session.new(DUMMY_SESSION)) end - def test_client_session - last_session = nil - start_server do |server, port| - 2.times do - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = last_session if last_session - ssl.connect + def test_resumption + non_resumable = nil + start_server { |port| + server_connect_with_session(port, nil, nil) { |ssl| + non_resumable = ssl.session + } + } - session = ssl.session - if last_session - assert(ssl.session_reused?) - assert_equal(session.id, last_session.id) - assert_equal(session.to_pem, last_session.to_pem) - assert_equal(session.to_der, last_session.to_der) - # Older version of OpenSSL may not be consistent. Look up which versions later. - assert_equal(session.to_text, last_session.to_text) - else - assert(!ssl.session_reused?) - end - last_session = 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 + } - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) + server_connect_with_session(port, nil, non_resumable) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + } - ssl.close - end + 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 - connections = 0 - saved_session = nil + def test_server_session_cache + pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = Proc.new do |ctx, ssl| -# add test for session callbacks here + 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| - session = ssl.session stats = ctx.session_cache_stats case connections when 0 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 0) - assert_equal(stats[:cache_misses], 0) - assert(!ssl.session_reused?) + 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(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 0) - assert(ssl.session_reused?) - ctx.session_remove(session) - saved_session = session.to_der + 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(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 1) - assert(!ssl.session_reused?) - ctx.session_add(OpenSSL::SSL::Session.new(saved_session)) + 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(stats[:cache_num], 2) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 1) - assert(ssl.session_reused?) + 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(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 2) - assert(!ssl.session_reused?) - ctx.session_add(OpenSSL::SSL::Session.new(saved_session)) + 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 - connections += 1 readwrite_loop(ctx, ssl) end - first_session = nil - start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |server, port| + start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port| + first_session = nil 10.times do |i| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - # disable RFC4507 support - ctx.options = OpenSSL::SSL::OP_NO_TICKET - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = first_session if first_session - ssl.connect - - session = ssl.session - if first_session - case i - when 1; assert(ssl.session_reused?) - when 2; assert(!ssl.session_reused?) - when 3; assert(ssl.session_reused?) - when 4; assert(!ssl.session_reused?) - when 5..10; assert(ssl.session_reused?) + connections = i + server_connect_with_session(port, nil, 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 - first_session ||= session - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close + } end end end def test_ctx_client_session_cb - 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] - } + pend "TLS 1.2 is not supported" unless tls12_supported? - ctx.session_remove_cb = lambda { |ary| - ctx, sess = ary - called[:remove] = [ctx, sess] - # any resulting value is OK (ignored) - } + 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] + } + ctx.session_remove_cb = lambda { |ary| + ctx, sess = ary + called[:remove] = [ctx, sess] + # any resulting value is OK (ignored) + } - start_server do |server, port| - sock = TCPSocket.new("127.0.0.1", port) - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect + 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)) assert_equal([ctx, ssl.session], called[:remove]) - ssl.close - ensure - sock.close if !sock.closed? - end + } end end def test_ctx_server_session_cb - called = {} + pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = Proc.new { |ctx, ssl| - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER - ctx.options = OpenSSL::SSL::OP_NO_TICKET - last_server_session = nil + connections = nil + called = {} + 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 - if last_server_session - called[:get2] = [sess, data] - last_server_session + _sess, data = ary + called[:get] = data + + if connections == 2 + last_server_session.dup else - called[:get1] = [sess, data] - last_server_session = sess nil end } ctx.session_new_cb = lambda { |ary| - sock, sess = ary - called[:new] = [sock, sess] - # SSL server doesn't cache sessions so get_cb is called next time. - ctx.session_remove(sess) + _sock, sess = ary + called[:new] = sess + last_server_session = sess } ctx.session_remove_cb = lambda { |ary| - ctx, sess = ary - called[:remove] = [ctx, sess] + _ctx, sess = ary + called[:remove] = sess } } - - server_proc = Proc.new { |c, ssl| - ssl.session - c.session_cache_stats - readwrite_loop(c, ssl) - } - start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |server, port| - last_client_session = nil - 3.times do - sock = TCPSocket.new("127.0.0.1", port) - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, OpenSSL::SSL::SSLContext.new()) - ssl.sync_close = true - ssl.session = last_client_session if last_client_session - ssl.connect - last_client_session = ssl.session - ssl.close - Timeout.timeout(5) do - Thread.pass until called.key?(:new) - assert(called.delete(:new)) - Thread.pass until called.key?(:remove) - assert(called.delete(:remove)) - end - ensure - sock.close if !sock.closed? + start_server(ctx_proc: ctx_proc) do |port| + connections = 0 + sess0 = 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 + } + assert_nil called[:get] + assert_not_nil called[:new] + assert_equal sess0.id, called[:new].id + assert_nil called[:remove] + called.clear + + # Internal cache hit + connections = 1 + server_connect_with_session(port, nil, 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] + assert_nil called[:remove] + called.clear + + sctx.flush_sessions(Time.now + 10000) + assert_not_nil called[:remove] + assert_equal sess0.id, called[:remove].id + called.clear + + # External cache hit + connections = 2 + sess2 = server_connect_with_session(port, nil, 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 - 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] + assert_nil called[:remove] + called.clear + + sctx.flush_sessions(Time.now + 10000) + assert_not_nil called[:remove] + assert_equal sess0.id, called[:remove].id + called.clear + + # Cache miss + connections = 3 + sess3 = server_connect_with_session(port, nil, 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 + assert_nil called[:remove] end - assert(called[:get1]) - assert(called[:get2]) end def test_dup @@ -371,4 +353,21 @@ __EOS__ 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_x509attr.rb b/test/test_x509attr.rb index 249c1593..108162f4 100644 --- a/test/test_x509attr.rb +++ b/test/test_x509attr.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestX509Attribute < OpenSSL::TestCase def test_new ef = OpenSSL::X509::ExtensionFactory.new @@ -61,3 +63,5 @@ class OpenSSL::TestX509Attribute < OpenSSL::TestCase assert_equal(attr.to_der, attr.dup.to_der) end end + +end diff --git a/test/test_x509cert.rb b/test/test_x509cert.rb index 5a992119..289994d1 100644 --- a/test/test_x509cert.rb +++ b/test/test_x509cert.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestX509Certificate < OpenSSL::TestCase def setup super @@ -175,3 +177,5 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase false end end + +end diff --git a/test/test_x509crl.rb b/test/test_x509crl.rb index fd7b562a..1914a651 100644 --- a/test/test_x509crl.rb +++ b/test/test_x509crl.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestX509CRL < OpenSSL::TestCase def setup super @@ -203,3 +205,5 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase false end end + +end diff --git a/test/test_x509ext.rb b/test/test_x509ext.rb index d9cde1bd..f384a25e 100644 --- a/test/test_x509ext.rb +++ b/test/test_x509ext.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestX509Extension < OpenSSL::TestCase def setup super @@ -74,3 +76,5 @@ class OpenSSL::TestX509Extension < OpenSSL::TestCase assert_equal(ext.to_der, ext.dup.to_der) end end + +end diff --git a/test/test_x509name.rb b/test/test_x509name.rb index b2196628..2f77f20b 100644 --- a/test/test_x509name.rb +++ b/test/test_x509name.rb @@ -2,6 +2,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestX509Name < OpenSSL::TestCase def setup super @@ -403,3 +405,5 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase assert_equal(name.to_der, name.dup.to_der) end end + +end diff --git a/test/test_x509req.rb b/test/test_x509req.rb index 88156220..a21d45da 100644 --- a/test/test_x509req.rb +++ b/test/test_x509req.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestX509Request < OpenSSL::TestCase def setup super @@ -147,3 +149,5 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase false end end + +end diff --git a/test/test_x509store.rb b/test/test_x509store.rb index 0009813d..6412249b 100644 --- a/test/test_x509store.rb +++ b/test/test_x509store.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestX509Store < OpenSSL::TestCase def setup super @@ -207,7 +209,7 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase end def test_set_errors - return if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000 + return if openssl?(1, 1, 0) || libressl? now = Time.now ca1_cert = issue_cert(@ca1, @rsa2048, 1, [], nil, nil) store = OpenSSL::X509::Store.new @@ -235,3 +237,5 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase assert_raise(NoMethodError) { ctx.dup } end end + +end diff --git a/test/ut_eof.rb b/test/ut_eof.rb index 6de41c4a..bd62fd50 100644 --- a/test/ut_eof.rb +++ b/test/ut_eof.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require 'test/unit' +if defined?(OpenSSL) + module OpenSSL::TestEOF def test_eof_0 open_file("") {|f| @@ -127,3 +129,5 @@ module OpenSSL::TestEOF end end end + +end diff --git a/test/utils.rb b/test/utils.rb index 54f75f25..a5dd38c2 100644 --- a/test/utils.rb +++ b/test/utils.rb @@ -30,11 +30,12 @@ if ENV["OSSL_MDEBUG"] == "1" end require "test/unit" -require 'tempfile' -require "rbconfig" +require "tempfile" require "socket" require "envutil" +if defined?(OpenSSL) + module OpenSSL::TestUtils module Fixtures module_function @@ -117,183 +118,188 @@ module OpenSSL::TestUtils OpenSSL::Digest::SHA1.hexdigest(pkvalue).scan(/../).join(":").upcase end - def silent - begin - back, $VERBOSE = $VERBOSE, nil - yield - ensure - $VERBOSE = back - 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 - class OpenSSL::TestCase < Test::Unit::TestCase - include OpenSSL::TestUtils - extend OpenSSL::TestUtils + 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 - def setup - if ENV["OSSL_GC_STRESS"] == "1" - GC.stress = true - end - end +class OpenSSL::TestCase < Test::Unit::TestCase + include OpenSSL::TestUtils + extend OpenSSL::TestUtils - def teardown - if ENV["OSSL_GC_STRESS"] == "1" - GC.stress = false - end - # OpenSSL error stack must be empty - assert_equal([], OpenSSL.errors) + def setup + if ENV["OSSL_GC_STRESS"] == "1" + GC.stress = true end end - class OpenSSL::SSLTestCase < OpenSSL::TestCase - RUBY = EnvUtil.rubybin - ITERATIONS = ($0 == __FILE__) ? 100 : 10 - - def setup - super - @ca_key = Fixtures.pkey("rsa2048") - @svr_key = Fixtures.pkey("rsa1024") - @cli_key = Fixtures.pkey("dsa1024") - @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 + def teardown + if ENV["OSSL_GC_STRESS"] == "1" + GC.stress = false end + # OpenSSL error stack must be empty + assert_equal([], OpenSSL.errors) + end +end - def readwrite_loop(ctx, ssl) - while line = ssl.gets - ssl.write(line) - end - rescue OpenSSL::SSL::SSLError - rescue IOError - ensure - ssl.close rescue nil - end +class OpenSSL::SSLTestCase < OpenSSL::TestCase + RUBY = EnvUtil.rubybin + ITERATIONS = ($0 == __FILE__) ? 100 : 10 - def server_loop(ctx, ssls, stop_pipe_r, ignore_listener_error, server_proc, threads) - loop do - ssl = nil - begin - readable, = IO.select([ssls, stop_pipe_r]) - if readable.include? stop_pipe_r - return - end - ssl = ssls.accept - rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET - if ignore_listener_error - retry - else - raise - end - end + def setup + super + @ca_key = Fixtures.pkey("rsa2048") + @svr_key = Fixtures.pkey("rsa1024") + @cli_key = Fixtures.pkey("rsa2048") + @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 - th = Thread.start do - server_proc.call(ctx, ssl) - end - threads << th - end - rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET - if !ignore_listener_error - raise - end + def tls12_supported? + OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) + 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), - 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("dh1024") } - begin - ctx.ecdh_curves = "P-256" - rescue NotImplementedError - end - ctx.verify_mode = verify_mode - ctx_proc.call(ctx) if ctx_proc + def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true, + ctx_proc: nil, server_proc: method(:readwrite_loop), + 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("dh1024") } + 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 - Socket.do_not_reverse_lookup = true - tcps = nil - 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 - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - ssls.start_immediately = start_immediately + threads = [] + begin + server_thread = Thread.new do + begin + loop do + begin + readable, = IO.select([ssls, stop_pipe_r]) + break if readable.include? stop_pipe_r + ssl = ssls.accept + rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL, + Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET + retry if ignore_listener_error + raise + end - threads = [] - begin - server = Thread.new do - begin - server_loop(ctx, ssls, stop_pipe_r, ignore_listener_error, server_proc, threads) - ensure - tcps.close + th = Thread.new do + begin + server_proc.call(ctx, ssl) + ensure + ssl.close + end + true + end + threads << th end + ensure + tcps.close end - threads.unshift server - - $stderr.printf("SSL server started: pid=%d port=%d\n", $$, port) if $DEBUG + end - client = Thread.new do - begin - block.call(server, port.to_i) - ensure - stop_pipe_w.close - end + client_thread = Thread.new do + begin + block.call(port) + ensure + # Stop accepting new connection + stop_pipe_w.close + server_thread.join end - threads.unshift client - ensure - assert_join_threads(threads) end - } - end + threads.unshift client_thread + ensure + # Terminate existing connections. If a thread did 'pend', re-raise it. + pend = nil + threads.each { |th| + begin + th.join(10) or + th.raise(RuntimeError, "[start_server] thread did not exit in 10 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 +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 + 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 - 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 + raise "unknown key type" end end end end + +end |