diff --git a/ruby-2.6.0-fix-test-failure-with-TLS-1.3.patch b/ruby-2.6.0-fix-test-failure-with-TLS-1.3.patch new file mode 100644 index 0000000..3e62a5b --- /dev/null +++ b/ruby-2.6.0-fix-test-failure-with-TLS-1.3.patch @@ -0,0 +1,203 @@ +From 6fcc6c0efc42d1c6325cf4bb0ca16e2a448cdbed Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 6 Aug 2018 20:51:42 +0900 +Subject: [PATCH] test/test_ssl: fix test failure with TLS 1.3 + +SSL_connect() on the client side may return before SSL_accept() on +server side returns. This will fix test failures with OpenSSL's current +master. +--- + test/openssl/test_ssl.rb | 45 ++++++++++++++++++++++++++-------------- + test/openssl/test_ssl_session.rb | 1 + + 2 files changed, 31 insertions(+), 15 deletions(-) + +diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb +index 7bb32adf..408c7d82 100644 +--- a/test/openssl/test_ssl.rb ++++ b/test/openssl/test_ssl.rb +@@ -47,6 +47,8 @@ def test_ssl_with_server_cert + 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 +@@ -157,6 +159,7 @@ def test_sync_close + 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 +@@ -168,6 +171,7 @@ def test_sync_close + 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 +@@ -259,7 +263,10 @@ def test_client_ca + client_ca_from_server = sslconn.client_ca + [@cli_cert, @cli_key] + end +- server_connect(port, ctx) { |ssl| assert_equal([@ca], client_ca_from_server) } ++ server_connect(port, ctx) { |ssl| ++ assert_equal([@ca], client_ca_from_server) ++ ssl.puts "abc"; assert_equal "abc\n", ssl.gets ++ } + } + end + +@@ -356,21 +363,16 @@ def test_verify_result + } + + start_server { |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 + true + end +- ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) +- ssl.sync_close = true +- begin +- ssl.connect ++ server_connect(port, ctx) { |ssl| + assert_equal(OpenSSL::X509::V_OK, ssl.verify_result) +- ensure +- ssl.close +- end ++ ssl.puts "abc"; assert_equal "abc\n", ssl.gets ++ } + } + + start_server(ignore_listener_error: true) { |port| +@@ -455,6 +457,8 @@ def test_post_connection_check + + 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")) +@@ -476,6 +482,8 @@ def test_post_connection_check + @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")} +@@ -496,6 +502,8 @@ def test_post_connection_check + @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")} +@@ -722,6 +730,8 @@ def test_tlsext_hostname + 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 +@@ -733,6 +743,8 @@ def test_tlsext_hostname + 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 +@@ -805,7 +817,8 @@ def test_verify_hostname_on_connect + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.hostname = name + if expected_ok +- assert_nothing_raised { ssl.connect } ++ ssl.connect ++ ssl.puts "abc"; assert_equal "abc\n", ssl.gets + else + assert_handshake_error { ssl.connect } + end +@@ -1086,6 +1099,7 @@ def test_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 +@@ -1104,6 +1118,7 @@ def test_alpn_protocol_selection_ary + 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 +@@ -1226,14 +1241,11 @@ def test_npn_selected_protocol_too_long + end + + def test_close_after_socket_close +- server_proc = proc { |ctx, ssl| +- # Do nothing +- } +- start_server(server_proc: server_proc) { |port| ++ start_server { |port| + 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 + sock.close + assert_nothing_raised do + ssl.close +@@ -1298,6 +1310,7 @@ def test_get_ephemeral_key + 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 +@@ -1440,6 +1453,7 @@ def test_ecdh_curves + 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) +@@ -1455,6 +1469,7 @@ def test_ecdh_curves + + 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 +diff --git a/test/openssl/test_ssl_session.rb b/test/openssl/test_ssl_session.rb +index 6db0c2d1..78b160ed 100644 +--- a/test/openssl/test_ssl_session.rb ++++ b/test/openssl/test_ssl_session.rb +@@ -113,6 +113,7 @@ 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 + } + } diff --git a/ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with-TLS-1.3.patch b/ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with-TLS-1.3.patch new file mode 100644 index 0000000..707dbd7 --- /dev/null +++ b/ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with-TLS-1.3.patch @@ -0,0 +1,157 @@ +From 1dfc377ae3b174b043d3f0ed36de57b0296b34d0 Mon Sep 17 00:00:00 2001 +From: rhe +Date: Wed, 8 Aug 2018 14:13:55 +0000 +Subject: [PATCH] net/http, net/ftp: fix session resumption with TLS 1.3 + +When TLS 1.3 is in use, the session ticket may not have been sent yet +even though a handshake has finished. Also, the ticket could change if +multiple session ticket messages are sent by the server. Use +SSLContext#session_new_cb instead of calling SSLSocket#session +immediately after a handshake. This way also works with earlier protocol +versions. + +git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64234 b2dd03c8-39d4-4d8f-98ff-823fe69b080e +--- + lib/net/ftp.rb | 5 ++++- + lib/net/http.rb | 7 +++++-- + test/net/http/test_https.rb | 35 ++++++++++------------------------- + 3 files changed, 19 insertions(+), 28 deletions(-) + +diff --git a/lib/net/ftp.rb b/lib/net/ftp.rb +index c3ee47ef4d36..9902f9dc657a 100644 +--- a/lib/net/ftp.rb ++++ b/lib/net/ftp.rb +@@ -230,6 +230,10 @@ def initialize(host = nil, user_or_options = {}, passwd = nil, acct = nil) + if defined?(VerifyCallbackProc) + @ssl_context.verify_callback = VerifyCallbackProc + end ++ @ssl_context.session_cache_mode = ++ OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT | ++ OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE ++ @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess } + @ssl_session = nil + if options[:private_data_connection].nil? + @private_data_connection = true +@@ -349,7 +353,6 @@ def start_tls_session(sock) + if @ssl_context.verify_mode != VERIFY_NONE + ssl_sock.post_connection_check(@host) + end +- @ssl_session = ssl_sock.session + return ssl_sock + end + private :start_tls_session +diff --git a/lib/net/http.rb b/lib/net/http.rb +index 281b15cedff0..683a884f5dbe 100644 +--- a/lib/net/http.rb ++++ b/lib/net/http.rb +@@ -983,6 +983,10 @@ def connect + end + @ssl_context = OpenSSL::SSL::SSLContext.new + @ssl_context.set_params(ssl_parameters) ++ @ssl_context.session_cache_mode = ++ OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT | ++ OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE ++ @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess } + D "starting SSL for #{conn_address}:#{conn_port}..." + s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) + s.sync_close = true +@@ -990,13 +994,12 @@ def connect + s.hostname = @address if s.respond_to? :hostname= + if @ssl_session and + Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout +- s.session = @ssl_session if @ssl_session ++ s.session = @ssl_session + end + ssl_socket_connect(s, @open_timeout) + if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE + s.post_connection_check(@address) + end +- @ssl_session = s.session + D "SSL established" + end + @socket = BufferedIO.new(s, read_timeout: @read_timeout, +diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb +index 8004d5c5f29f..a5182a1fe9db 100644 +--- a/test/net/http/test_https.rb ++++ b/test/net/http/test_https.rb +@@ -71,20 +71,11 @@ def test_session_reuse + http.get("/") + http.finish + +- http.start +- http.get("/") +- http.finish # three times due to possible bug in OpenSSL 0.9.8 +- +- sid = http.instance_variable_get(:@ssl_session).id +- + http.start + http.get("/") + + socket = http.instance_variable_get(:@socket).io +- +- assert socket.session_reused? +- +- assert_equal sid, http.instance_variable_get(:@ssl_session).id ++ assert_equal true, socket.session_reused? + + http.finish + rescue SystemCallError +@@ -101,16 +92,12 @@ def test_session_reuse_but_expire + http.get("/") + http.finish + +- sid = http.instance_variable_get(:@ssl_session).id +- + http.start + http.get("/") + + socket = http.instance_variable_get(:@socket).io + assert_equal false, socket.session_reused? + +- assert_not_equal sid, http.instance_variable_get(:@ssl_session).id +- + http.finish + rescue SystemCallError + skip $! +@@ -160,15 +147,16 @@ def test_certificate_verify_failure + end + + def test_identity_verify_failure ++ # the certificate's subject has CN=localhost + http = Net::HTTP.new("127.0.0.1", config("port")) + http.use_ssl = true +- http.verify_callback = Proc.new do |preverify_ok, store_ctx| +- true +- end ++ http.cert_store = TEST_STORE ++ @log_tester = lambda {|_| } + ex = assert_raise(OpenSSL::SSL::SSLError){ + http.request_get("/") {|res| } + } +- assert_match(/hostname \"127.0.0.1\" does not match/, ex.message) ++ re_msg = /certificate verify failed|hostname \"127.0.0.1\" does not match/ ++ assert_match(re_msg, ex.message) + end + + def test_timeout_during_SSL_handshake +@@ -193,16 +181,13 @@ def test_timeout_during_SSL_handshake + end + + def test_min_version +- http = Net::HTTP.new("127.0.0.1", config("port")) ++ http = Net::HTTP.new("localhost", config("port")) + http.use_ssl = true + http.min_version = :TLS1 +- http.verify_callback = Proc.new do |preverify_ok, store_ctx| +- true +- end +- ex = assert_raise(OpenSSL::SSL::SSLError){ +- http.request_get("/") {|res| } ++ http.cert_store = TEST_STORE ++ http.request_get("/") {|res| ++ assert_equal($test_net_http_data, res.body) + } +- assert_match(/hostname \"127.0.0.1\" does not match/, ex.message) + end + + def test_max_version diff --git a/ruby.spec b/ruby.spec index 995855f..2caa398 100644 --- a/ruby.spec +++ b/ruby.spec @@ -21,7 +21,7 @@ %endif -%global release 96 +%global release 97 %{!?release_string:%global release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory three, since the @@ -148,6 +148,10 @@ Patch16: ruby-2.5.1-Avoid-need-of-C++-compiler-to-pass-the-test-suite.patch # Fix some OpenSSL 1.1.1 test failures. # https://github.com/ruby/openssl/pull/202 Patch17: ruby-2.5.1-Test-fixes-for-OpenSSL-1.1.1.patch +# https://github.com/ruby/openssl/pull/209 +Patch18: ruby-2.6.0-fix-test-failure-with-TLS-1.3.patch +# https://github.com/ruby/ruby/commit/1dfc377ae3b174b043d3f0ed36de57b0296b34d0 +Patch19: ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with-TLS-1.3.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -534,6 +538,8 @@ rm -rf ext/fiddle/libffi* %patch15 -p1 %patch16 -p1 %patch17 -p1 +%patch18 -p1 +%patch19 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -759,10 +765,10 @@ sed -i '/def test_mdns_each_address$/,/^ end$/ s/^/#/' test/resolv/test_mdns.rb # For now, disable some OpenSSL tests incompatible with OpenSSL 1.1.1: # https://github.com/ruby/openssl/issues/207 -mv test/openssl/test_ssl.rb{,.disabled} -DISABLE_TESTS="$DISABLE_TESTS -n !/test_resumption/" -DISABLE_TESTS="$DISABLE_TESTS -n !/test_\(identity_verify_failure\|min_version\|session_reuse\)/" +DISABLE_TESTS="$DISABLE_TESTS -n !/test_\(add_certificate\|minmax_version\|options_disable_versions\|set_params_min_version\)/" DISABLE_TESTS="$DISABLE_TESTS -n !/test_do_not_allow_invalid_client_cert_auth_connection/" +# https://github.com/ruby/openssl/issues/208 +DISABLE_TESTS="$DISABLE_TESTS -n !/^test_constants$/" make check TESTS="-v $DISABLE_TESTS" @@ -1083,6 +1089,9 @@ make check TESTS="-v $DISABLE_TESTS" %{gem_dir}/specifications/xmlrpc-%{xmlrpc_version}.gemspec %changelog +* Mon Aug 13 2018 Vít Ondruch - 2.5.1-97 +- Fix TLS 1.3 issues. + * Tue Jul 31 2018 Florian Weimer - 2.5.1-96 - Rebuild with fixed binutils