From 6253fbea8a7f267e91c3f8c8303297725c8de9d3 Mon Sep 17 00:00:00 2001 From: drbrain Date: Fri, 20 Apr 2012 00:10:09 +0000 Subject: Backport security fixes for RubyGems 1.3.7: * lib/rubygems: Apply the following security fixes to RubyGems 1.3.7: RubyGems now disallows redirection from HTTPS to HTTP. RubyGems now verifies SSL connections. Patch by Hiroshi Nakamura. * test/rubygems: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_2@35407 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- test/rubygems/ca_cert.pem | 45 ++++++++++++++ test/rubygems/ssl_cert.pem | 19 ++++++ test/rubygems/ssl_key.pem | 15 +++++ test/rubygems/test_gem_config_file.rb | 20 ++++++ test/rubygems/test_gem_remote_fetcher.rb | 101 +++++++++++++++++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 test/rubygems/ca_cert.pem create mode 100644 test/rubygems/ssl_cert.pem create mode 100644 test/rubygems/ssl_key.pem (limited to 'test') diff --git a/test/rubygems/ca_cert.pem b/test/rubygems/ca_cert.pem new file mode 100644 index 0000000000..5acdcf8f32 --- /dev/null +++ b/test/rubygems/ca_cert.pem @@ -0,0 +1,45 @@ +-----BEGIN CERTIFICATE----- +MIID0DCCArigAwIBAgIBADANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES +MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X +DTA0MDEzMDAwNDIzMloXDTM2MDEyMjAwNDIzMlowPDELMAkGA1UEBgwCSlAxEjAQ +BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMQswCQYDVQQDDAJDQTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANbv0x42BTKFEQOE+KJ2XmiSdZpR +wjzQLAkPLRnLB98tlzs4xo+y4RyY/rd5TT9UzBJTIhP8CJi5GbS1oXEerQXB3P0d +L5oSSMwGGyuIzgZe5+vZ1kgzQxMEKMMKlzA73rbMd4Jx3u5+jdbP0EDrPYfXSvLY +bS04n2aX7zrN3x5KdDrNBfwBio2/qeaaj4+9OxnwRvYP3WOvqdW0h329eMfHw0pi +JI0drIVdsEqClUV4pebT/F+CPUPkEh/weySgo9wANockkYu5ujw2GbLFcO5LXxxm +dEfcVr3r6t6zOA4bJwL0W/e6LBcrwiG/qPDFErhwtgTLYf6Er67SzLyA66UCAwEA +AaOB3DCB2TAPBgNVHRMBAf8EBTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09w +ZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRJ7Xd380KzBV7f +USKIQ+O/vKbhDzAOBgNVHQ8BAf8EBAMCAQYwZAYDVR0jBF0wW4AUSe13d/NCswVe +31EiiEPjv7ym4Q+hQKQ+MDwxCzAJBgNVBAYMAkpQMRIwEAYDVQQKDAlKSU4uR1Iu +SlAxDDAKBgNVBAsMA1JSUjELMAkGA1UEAwwCQ0GCAQAwDQYJKoZIhvcNAQEFBQAD +ggEBAIu/mfiez5XN5tn2jScgShPgHEFJBR0BTJBZF6xCk0jyqNx/g9HMj2ELCuK+ +r/Y7KFW5c5M3AQ+xWW0ZSc4kvzyTcV7yTVIwj2jZ9ddYMN3nupZFgBK1GB4Y05GY +MJJFRkSu6d/Ph5ypzBVw2YMT/nsOo5VwMUGLgS7YVjU+u/HNWz80J3oO17mNZllj +PvORJcnjwlroDnS58KoJ7GDgejv3ESWADvX1OHLE4cRkiQGeLoEU4pxdCxXRqX0U +PbwIkZN9mXVcrmPHq8MWi4eC/V7hnbZETMHuWhUoiNdOEfsAXr3iP4KjyyRdwc7a +d/xgcK06UVQRL/HbEYGiQL056mc= +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES +MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X +DTA0MDEzMDAwNDMyN1oXDTM1MDEyMjAwNDMyN1owPzELMAkGA1UEBgwCSlAxEjAQ +BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMQ4wDAYDVQQDDAVTdWJDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0Ou7AyRcRXnB/kVHv/6kwe +ANzgg/DyJfsAUqW90m7Lu1nqyug8gK0RBd77yU0w5HOAMHTVSdpjZK0g2sgx4Mb1 +d/213eL9TTl5MRVEChTvQr8q5DVG/8fxPPE7fMI8eOAzd98/NOAChk+80r4Sx7fC +kGVEE1bKwY1MrUsUNjOY2d6t3M4HHV3HX1V8ShuKfsHxgCmLzdI8U+5CnQedFgkm +3e+8tr8IX5RR1wA1Ifw9VadF7OdI/bGMzog/Q8XCLf+WPFjnK7Gcx6JFtzF6Gi4x +4dp1Xl45JYiVvi9zQ132wu8A1pDHhiNgQviyzbP+UjcB/tsOpzBQF8abYzgEkWEC +AwEAAaNyMHAwDwYDVR0TAQH/BAUwAwEB/zAxBglghkgBhvhCAQ0EJBYiUnVieS9P +cGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUlCjXWLsReYzH +LzsxwVnCXmKoB/owCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCJ/OyN +rT8Cq2Y+G2yA/L1EMRvvxwFBqxavqaqHl/6rwsIBFlB3zbqGA/0oec6MAVnYynq4 +c4AcHTjx3bQ/S4r2sNTZq0DH4SYbQzIobx/YW8PjQUJt8KQdKMcwwi7arHP7A/Ha +LKu8eIC2nsUBnP4NhkYSGhbmpJK+PFD0FVtD0ZIRlY/wsnaZNjWWcnWF1/FNuQ4H +ySjIblqVQkPuzebv3Ror6ZnVDukn96Mg7kP4u6zgxOeqlJGRe1M949SS9Vudjl8X +SF4aZUUB9pQGhsqQJVqaz2OlhGOp9D0q54xko/rekjAIcuDjl1mdX4F2WRrzpUmZ +uY/bPeOBYiVsOYVe +-----END CERTIFICATE----- diff --git a/test/rubygems/ssl_cert.pem b/test/rubygems/ssl_cert.pem new file mode 100644 index 0000000000..998ccc5892 --- /dev/null +++ b/test/rubygems/ssl_cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/zCCAeegAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQGDAJKUDES +MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxDjAMBgNVBAMMBVN1YkNB +MB4XDTA0MDEzMTAzMTMxNloXDTMzMDEyMzAzMTMxNlowQzELMAkGA1UEBgwCSlAx +EjAQBgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMRIwEAYDVQQDDAlsb2Nh +bGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANFJTxWqup3nV9dsJAku +p+WaXnPNIzcpAA3qMGZDJTJsfa8Du7ZxTP0XJK5mETttBrn711cJxAuP3KjqnW9S +vtZ9lY2sXJ6Zj62sN5LwG3VVe25dI28yR1EsbHjJ5Zjf9tmggMC6am52dxuHbt5/ +vHo4ngJuKE/U+eeGRivMn6gFAgMBAAGjgYUwgYIwDAYDVR0TAQH/BAIwADAxBglg +hkgBhvhCAQ0EJBYiUnVieS9PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd +BgNVHQ4EFgQUpZIyygD9JxFYHHOTEuWOLbCKfckwCwYDVR0PBAQDAgWgMBMGA1Ud +JQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4IBAQBwAIj5SaBHaA5X31IP +CFCJiep96awfp7RANO0cuUj+ZpGoFn9d6FXY0g+Eg5wAkCNIzZU5NHN9xsdOpnUo +zIBbyTfQEPrge1CMWMvL6uGaoEXytq84VTitF/xBTky4KtTn6+es4/e7jrrzeUXQ +RC46gkHObmDT91RkOEGjHLyld2328jo3DIN/VTHIryDeVHDWjY5dENwpwdkhhm60 +DR9IrNBbXWEe9emtguNXeN0iu1ux0lG1Hc6pWGQxMlRKNvGh0yZB9u5EVe38tOV0 +jQaoNyL7qzcQoXD3Dmbi1p0iRmg/+HngISsz8K7k7MBNVsSclztwgCzTZOBiVtkM +rRlQ +-----END CERTIFICATE----- diff --git a/test/rubygems/ssl_key.pem b/test/rubygems/ssl_key.pem new file mode 100644 index 0000000000..9ba2218a03 --- /dev/null +++ b/test/rubygems/ssl_key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDRSU8Vqrqd51fXbCQJLqflml5zzSM3KQAN6jBmQyUybH2vA7u2 +cUz9FySuZhE7bQa5+9dXCcQLj9yo6p1vUr7WfZWNrFyemY+trDeS8Bt1VXtuXSNv +MkdRLGx4yeWY3/bZoIDAumpudncbh27ef7x6OJ4CbihP1PnnhkYrzJ+oBQIDAQAB +AoGBAIf4CstW2ltQO7+XYGoex7Hh8s9lTSW/G2vu5Hbr1LTHy3fzAvdq8MvVR12O +rk9fa+lU9vhzPc0NMB0GIDZ9GcHuhW5hD1Wg9OSCbTOkZDoH3CAFqonjh4Qfwv5W +IPAFn9KHukdqGXkwEMdErsUaPTy9A1V/aROVEaAY+HJgq/eZAkEA/BP1QMV04WEZ +Oynzz7/lLizJGGxp2AOvEVtqMoycA/Qk+zdKP8ufE0wbmCE3Qd6GoynavsHb6aGK +gQobb8zDZwJBANSK6MrXlrZTtEaeZuyOB4mAmRzGzOUVkUyULUjEx2GDT93ujAma +qm/2d3E+wXAkNSeRpjUmlQXy/2oSqnGvYbMCQQDRM+cYyEcGPUVpWpnj0shrF/QU +9vSot/X1G775EMTyaw6+BtbyNxVgOIu2J+rqGbn3c+b85XqTXOPL0A2RLYkFAkAm +syhSDtE9X55aoWsCNZY/vi+i4rvaFoQ/WleogVQAeGVpdo7/DK9t9YWoFBIqth0L +mGSYFu9ZhvZkvQNV8eYrAkBJ+rOIaLDsmbrgkeDruH+B/9yrm4McDtQ/rgnOGYnH +LjLpLLOrgUxqpzLWe++EwSLwK2//dHO+SPsQJ4xsyQJy +-----END RSA PRIVATE KEY----- diff --git a/test/rubygems/test_gem_config_file.rb b/test/rubygems/test_gem_config_file.rb index b76ff7b180..e331ac333b 100644 --- a/test/rubygems/test_gem_config_file.rb +++ b/test/rubygems/test_gem_config_file.rb @@ -53,6 +53,8 @@ class TestGemConfigFile < RubyGemTestCase fp.puts ":gempath:" fp.puts "- /usr/ruby/1.8/lib/ruby/gems/1.8" fp.puts "- /var/ruby/1.8/gem_home" + fp.puts ":ssl_verify_mode: 0" + fp.puts ":ssl_ca_cert: /etc/ssl/certs" end util_config_file @@ -67,6 +69,8 @@ class TestGemConfigFile < RubyGemTestCase assert_equal '--wrappers', @cfg[:install] assert_equal(['/usr/ruby/1.8/lib/ruby/gems/1.8', '/var/ruby/1.8/gem_home'], @cfg.path) + assert_equal 0, @cfg.ssl_verify_mode + assert_equal '/etc/ssl/certs', @cfg.ssl_ca_cert end def test_initialize_handle_arguments_config_file @@ -279,6 +283,22 @@ class TestGemConfigFile < RubyGemTestCase assert_equal "701229f217cdf23b1344c7b4b54ca97", @cfg.rubygems_api_key end + def test_load_ssl_verify_mode_from_config + File.open @temp_conf, 'w' do |fp| + fp.puts ":ssl_verify_mode: 1" + end + util_config_file + assert_equal(1, @cfg.ssl_verify_mode) + end + + def test_load_ssl_ca_cert_from_config + File.open @temp_conf, 'w' do |fp| + fp.puts ":ssl_ca_cert: /home/me/certs" + end + util_config_file + assert_equal('/home/me/certs', @cfg.ssl_ca_cert) + end + def util_config_file(args = @cfg_args) @cfg = Gem::ConfigFile.new args end diff --git a/test/rubygems/test_gem_remote_fetcher.rb b/test/rubygems/test_gem_remote_fetcher.rb index d6b78dc7cc..1430bd186b 100644 --- a/test/rubygems/test_gem_remote_fetcher.rb +++ b/test/rubygems/test_gem_remote_fetcher.rb @@ -1,6 +1,7 @@ require_relative 'gemutilities' require 'ostruct' require 'webrick' +require 'webrick/https' require 'rubygems/remote_fetcher' require 'rubygems/format' @@ -73,6 +74,8 @@ gems: PROXY_PORT = process_based_port + 100 + $1.to_i * 100 + $2.to_i * 10 + $3.to_i SERVER_PORT = process_based_port + 200 + $1.to_i * 100 + $2.to_i * 10 + $3.to_i + DIR = File.expand_path(File.dirname(__FILE__)) + def setup super self.class.start_servers @@ -632,6 +635,53 @@ gems: end end + def test_ssl_connection + ssl_server = self.class.start_ssl_server + temp_ca_cert = File.join(DIR, 'ca_cert.pem') + with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + + def test_do_not_allow_insecure_ssl_connection_by_default + ssl_server = self.class.start_ssl_server + with_configured_fetcher do |fetcher| + assert_raises Gem::RemoteFetcher::FetchError do + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + end + + def test_ssl_connection_allow_verify_none + ssl_server = self.class.start_ssl_server + with_configured_fetcher(":ssl_verify_mode: 0") do |fetcher| + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") + end + end + + def test_do_not_follow_insecure_redirect + ssl_server = self.class.start_ssl_server + temp_ca_cert = File.join(DIR, 'ca_cert.pem'), + with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher| + assert_raises Gem::RemoteFetcher::FetchError do + fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/insecure_redirect?to=#{@server_uri}") + end + end + end + + def with_configured_fetcher(config_str = nil, &block) + if config_str + temp_conf = File.join @tempdir, '.gemrc' + File.open temp_conf, 'w' do |fp| + fp.puts config_str + end + Gem.configuration = Gem::ConfigFile.new %W[--config-file #{temp_conf}] + end + yield Gem::RemoteFetcher.new + ensure + Gem.configuration = nil + end + def util_stub_connection_for hash def @fetcher.connection= conn @conn = conn @@ -692,6 +742,49 @@ gems: @enable_zip = false end + DIR = File.expand_path(File.dirname(__FILE__)) + DH_PARAM = OpenSSL::PKey::DH.new(128) + + def start_ssl_server(config = {}) + null_logger = NilLog.new + server = WEBrick::HTTPServer.new({ + :Port => 0, + :Logger => null_logger, + :AccessLog => [], + :SSLEnable => true, + :SSLCACertificateFile => File.join(DIR, 'ca_cert.pem'), + :SSLCertificate => cert('ssl_cert.pem'), + :SSLPrivateKey => key('ssl_key.pem'), + :SSLVerifyClient => nil, + :SSLCertName => nil + }.merge(config)) + server.mount_proc("/yaml") { |req, res| + res.body = "--- true\n" + } + server.mount_proc("/insecure_redirect") { |req, res| + res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, req.query['to']) + } + server.ssl_context.tmp_dh_callback = proc { DH_PARAM } + t = Thread.new do + begin + server.start + rescue Exception => ex + abort ex.message + puts "ERROR during server thread: #{ex.message}" + end + end + while server.status != :Running + sleep 0.1 + unless t.alive? + t.join + raise + end + end + server + end + + + private def start_server(port, data) @@ -734,6 +827,14 @@ gems: end sleep 0.2 # Give the servers time to startup end + + def cert(filename) + OpenSSL::X509::Certificate.new(File.read(File.join(DIR, filename))) + end + + def key(filename) + OpenSSL::PKey::RSA.new(File.read(File.join(DIR, filename))) + end end end -- cgit v1.2.3