ruby-changes:2880
From: ko1@a...
Date: 21 Dec 2007 01:21:38 +0900
Subject: [ruby-changes:2880] gotoyuzo - Ruby:r14371 (trunk): * lib/net/http.rb (Net::HTTP#connect): use
gotoyuzo 2007-12-21 01:21:22 +0900 (Fri, 21 Dec 2007) New Revision: 14371 Added files: trunk/test/net/http/test_https.rb Modified files: trunk/ChangeLog trunk/lib/net/http.rb trunk/lib/net/https.rb trunk/test/net/http/utils.rb Log: * lib/net/http.rb (Net::HTTP#connect): use OpenSSL::SSL::SSLContext.build instead of SSLContext.new (default verify mode is now OpenSSL::SSL::VERIFY_PEER). * lib/net/https.rb: SSL parameters are defined by attr_accessor. * test/net/http/test_https.rb: add test for HTTPS features. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/net/http/utils.rb?r1=14371&r2=14370 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/net/https.rb?r1=14371&r2=14370 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14371&r2=14370 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/net/http/test_https.rb?revision=14371&view=markup http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/net/http.rb?r1=14371&r2=14370 Index: ChangeLog =================================================================== --- ChangeLog (revision 14370) +++ ChangeLog (revision 14371) @@ -1,3 +1,13 @@ +Fri Dec 21 01:20:56 2007 GOTOU Yuuzou <gotoyuzo@n...> + + * lib/net/http.rb (Net::HTTP#connect): use + OpenSSL::SSL::SSLContext.build instead of SSLContext.new (default + verify mode is now OpenSSL::SSL::VERIFY_PEER). + + * lib/net/https.rb: SSL parameters are defined by attr_accessor. + + * test/net/http/test_https.rb: add test for HTTPS features. + Fri Dec 21 01:11:37 2007 GOTOU Yuuzou <gotoyuzo@n...> * io.c (select_internal): should return original value. Index: lib/net/http.rb =================================================================== --- lib/net/http.rb (revision 14370) +++ lib/net/http.rb (revision 14371) @@ -575,10 +575,13 @@ s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) } D "opened" if use_ssl? - unless @ssl_context.verify_mode - warn "warning: peer certificate won't be verified in this SSL session" - @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE + ssl_parameters = Hash.new + SSL_ATTRIBUTES.each do |name| + if value = instance_variable_get("@#{name}") + ssl_parameters[name] = value + end end + @ssl_context = OpenSSL::SSL::SSLContext.build(ssl_parameters) s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) s.sync_close = true end Index: lib/net/https.rb =================================================================== --- lib/net/https.rb (revision 14370) +++ lib/net/https.rb (revision 14371) @@ -102,70 +102,35 @@ require 'openssl' module Net - class HTTP remove_method :use_ssl? def use_ssl? @use_ssl end - alias use_ssl use_ssl? # for backward compatibility - # Turn on/off SSL. # This flag must be set before starting session. # If you change use_ssl value after session started, # a Net::HTTP object raises IOError. def use_ssl=(flag) flag = (flag ? true : false) - raise IOError, "use_ssl value changed, but session already started" \ - if started? and @use_ssl != flag - if flag and not @ssl_context - @ssl_context = OpenSSL::SSL::SSLContext.new + if started? and @use_ssl != flag + raise IOError, "use_ssl value changed, but session already started" end @use_ssl = flag end - def self.ssl_context_accessor(name) - module_eval(<<-End, __FILE__, __LINE__ + 1) - def #{name} - return nil unless @ssl_context - @ssl_context.#{name} - end + SSL_ATTRIBUTES = %w( + ssl_version key cert ca_file ca_path cert_store ciphers + verify_mode verify_callback verify_depth ssl_timeout + ) + attr_accessor *SSL_ATTRIBUTES - def #{name}=(val) - @ssl_context ||= OpenSSL::SSL::SSLContext.new - @ssl_context.#{name} = val - end - End - end - - ssl_context_accessor :key - ssl_context_accessor :cert - ssl_context_accessor :ca_file - ssl_context_accessor :ca_path - ssl_context_accessor :verify_mode - ssl_context_accessor :verify_callback - ssl_context_accessor :verify_depth - ssl_context_accessor :cert_store - - def ssl_timeout - return nil unless @ssl_context - @ssl_context.timeout - end - - def ssl_timeout=(sec) - raise ArgumentError, 'Net::HTTP#ssl_timeout= called but use_ssl=false' \ - unless use_ssl? - @ssl_context ||= OpenSSL::SSL::SSLContext.new - @ssl_context.timeout = sec - end - - alias timeout= ssl_timeout= # for backward compatibility - def peer_cert - return nil if not use_ssl? or not @socket + if not use_ssl? or not @socket + return nil + end @socket.io.peer_cert end end - end Index: test/net/http/utils.rb =================================================================== --- test/net/http/utils.rb (revision 14370) +++ test/net/http/utils.rb (revision 14371) @@ -1,4 +1,9 @@ require 'webrick' +begin + require "webrick/https" +rescue LoadError + # SSL features cannot be tested +end require 'webrick/httpservlet/abstract' module TestNetHTTPUtils @@ -35,14 +40,22 @@ end def spawn_server - @server = WEBrick::HTTPServer.new( + server_config = { :BindAddress => config('host'), :Port => config('port'), :Logger => WEBrick::Log.new(NullWriter.new), :AccessLog => [], :ShutdownSocketWithoutClose => true, - :ServerType => Thread - ) + :ServerType => Thread, + } + if defined?(OpenSSL) and config('ssl_enable') + server_config.update({ + :SSLEnable => true, + :SSLCertificate => config('ssl_certificate'), + :SSLPrivateKey => config('ssl_private_key'), + }) + end + @server = WEBrick::HTTPServer.new(server_config) @server.mount('/', Servlet) @server.start n_try_max = 5 Index: test/net/http/test_https.rb =================================================================== --- test/net/http/test_https.rb (revision 0) +++ test/net/http/test_https.rb (revision 14371) @@ -0,0 +1,97 @@ +require "test/unit" +begin + require 'net/https' +rescue LoadError + # should skip this test +end +require 'stringio' +require File.expand_path("utils", File.dirname(__FILE__)) +require File.expand_path("../../openssl/utils", File.dirname(__FILE__)) + +class TestNetHTTPS < Test::Unit::TestCase + include TestNetHTTPUtils + + subject = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + exts = [ + ["keyUsage", "keyEncipherment,digitalSignature", true], + ] + key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + cert = OpenSSL::TestUtils.issue_cert( + subject, key, 1, Time.now, Time.now + 3600, exts, + nil, nil, OpenSSL::Digest::SHA1.new + ) + + CONFIG = { + 'host' => '127.0.0.1', + 'port' => 10081, + 'proxy_host' => nil, + 'proxy_port' => nil, + 'ssl_enable' => true, + 'ssl_certificate' => cert, + 'ssl_private_key' => key, + } + + def test_get + http = Net::HTTP.new("localhost", config("port")) + http.use_ssl = true + http.verify_callback = Proc.new do |preverify_ok, store_ctx| + store_ctx.current_cert.to_der == config('ssl_certificate').to_der + end + http.request_get("/") {|res| + assert_equal($test_net_http_data, res.body) + } + end + + def test_post + http = Net::HTTP.new("localhost", config("port")) + http.use_ssl = true + http.verify_callback = Proc.new do |preverify_ok, store_ctx| + store_ctx.current_cert.to_der == config('ssl_certificate').to_der + end + data = config('ssl_private_key').to_der + http.request_post("/", data) {|res| + assert_equal(data, res.body) + } + end + + if ENV["RUBY_OPENSSL_TEST_ALL"] + def test_verify + http = Net::HTTP.new("ssl.netlab.jp", 443) + http.use_ssl = true + assert( + http.request_head("/"){|res| }, + "The system may not have default CA certificate store." + ) + end + end + + def test_verify_none + http = Net::HTTP.new("localhost", config("port")) + http.use_ssl = true + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + http.request_get("/") {|res| + assert_equal($test_net_http_data, res.body) + } + end + + def test_certificate_verify_failure + http = Net::HTTP.new("localhost", config("port")) + http.use_ssl = true + ex = assert_raise(OpenSSL::SSL::SSLError){ + http.request_get("/") {|res| } + } + assert_match(/certificate verify failed/, ex.message) + end + + def test_identity_verify_failure + http = Net::HTTP.new("127.0.0.1", config("port")) + http.use_ssl = true + http.verify_callback = Proc.new do |preverify_ok, store_ctx| + store_ctx.current_cert.to_der == config('ssl_certificate').to_der + end + ex = assert_raise(OpenSSL::SSL::SSLError){ + http.request_get("/") {|res| } + } + assert_match(/hostname was not match/, ex.message) + end +end if defined?(OpenSSL) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml