From 25e6db3e3cb52c1a81e1e4a958a8d520a996812e Mon Sep 17 00:00:00 2001 From: emboss Date: Fri, 31 Aug 2012 09:47:36 +0000 Subject: * ext/openssl/extconf.rb: Check existence of OPENSSL_NPN_NEGOTIATED. ext/ossl_ssl.c: Support Next Protocol Negotiation. Protocols to be advertised by the server can be set in the SSLContext by using SSLContext#npn_protocols=, protocol selection on the client is supported by providing a selection callback with SSLContext#npn_select_cb. The protocol that was finally negotiated is available through SSL#npn_protocol. test/openssl/test_ssl.rb: Add tests for Next Protocol Negotiation. NEWS: add news about NPN support. [Feature #6503] [ruby-core:45272] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36871 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- test/openssl/test_ssl.rb | 85 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 9 deletions(-) (limited to 'test/openssl') diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index b72e75ed41..74c7af52f8 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -411,7 +411,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase # different OpenSSL versions react differently when being faced with a # SSL/TLS version that has been marked as forbidden, therefore either of # these may be raised - FORBIDDEN_PROTOCOL_ERRORS = [OpenSSL::SSL::SSLError, Errno::ECONNRESET] + HANDSHAKE_ERRORS = [OpenSSL::SSL::SSLError, Errno::ECONNRESET] if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1 @@ -420,7 +420,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1 start_server_version(:SSLv23, ctx_proc) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :SSLv3 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end @@ -428,7 +428,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1 start_server_version(:SSLv3) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end @@ -447,7 +447,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_1 start_server_version(:SSLv23, ctx_proc) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end @@ -455,7 +455,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_1 start_server_version(:TLSv1) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end @@ -474,7 +474,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_2 start_server_version(:SSLv23, ctx_proc) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1_1 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) @@ -482,7 +482,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_2 start_server_version(:TLSv1_1) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_1 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) @@ -491,7 +491,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_2 start_server_version(:SSLv23, ctx_proc) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1_2 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) @@ -499,7 +499,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_2 start_server_version(:TLSv1_2) { |server, port| ctx = OpenSSL::SSL::SSLContext.new ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_2 - assert_raise(*FORBIDDEN_PROTOCOL_ERRORS) { server_connect(port, ctx) } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } } end if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) @@ -516,6 +516,73 @@ end } end +if OpenSSL::OPENSSL_VERSION_NUMBER > 0x10001000 + + def test_npn_protocol_selection_ary + advertised = ["http/1.1", "spdy/2"] + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = advertised } + start_server_version(:SSLv23, ctx_proc) { |server, 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 + 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| + 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 + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } + start_server_version(:SSLv23, ctx_proc) { |server, 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 + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["a" * 256] } + start_server_version(:SSLv23, ctx_proc) { |server, port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.npn_select_cb = -> (protocols) { protocols.first } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } + } + end + + def test_npn_selected_protocol_too_long + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } + start_server_version(:SSLv23, ctx_proc) { |server, port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.npn_select_cb = -> (protocols) { "a" * 256 } + assert_raise(*HANDSHAKE_ERRORS) { server_connect(port, ctx) } + } + end + +end + private def start_server_version(version, ctx_proc=nil, server_proc=nil, &blk) -- cgit v1.2.3