http 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of http might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbf54512a5beb049b061b0ba6fa9cff6599fdd03
4
- data.tar.gz: 27cd308a2ca24d95b09ea54cffc47ede483b7842
3
+ metadata.gz: d4030eeaf2d60cda70af573153fe436493061181
4
+ data.tar.gz: 8c81614a50e7510eb06a0b48ddd8b140da557b88
5
5
  SHA512:
6
- metadata.gz: 9f51593e3ecef81acc55ca3941b978c63011979ab2933409f57fe3272ae061553a32d72abfa219946ee0ba6d465157159b7e7fddcac29b4e9ebda3d1fa096fff
7
- data.tar.gz: fd396a2f0ea79ee4014844c71de5bf97cb40bd60feef0e733b51adf16f76be3dadbbde7a58a09025ba6e641abc0676f5c66887dc649f0a415c54934f9eeabbec
6
+ metadata.gz: 71658b9dc31eb01d62e038c6f7a4e193aa030360ad65d146a5fa3ab03c563c163b9fd688f9a2496b640a143f3658a21b74bc791301b701aaa4c972250995c608
7
+ data.tar.gz: 59254dd112aa7e6405b56ddc5901c564d942fdd8e12e913e1a4b6b1f64faf79257432ad85f4b6385b8b4a3f8b45ce732e36839fc78ac53f91bf9cd2bce5f66de
data/.rubocop.yml CHANGED
@@ -15,7 +15,7 @@ MethodLength:
15
15
 
16
16
  ClassLength:
17
17
  CountComments: false
18
- Max: 100
18
+ Max: 110
19
19
 
20
20
  CyclomaticComplexity:
21
21
  Max: 13 # TODO: lower to 6
data/CHANGES.md CHANGED
@@ -1,3 +1,11 @@
1
+ 0.6.4 (2015-03-25)
2
+ ------------------
3
+
4
+ * SECURITY FIX: http.rb failed to call the `#post_connection_check` method on
5
+ SSL connections. This method implements hostname verification, and without it
6
+ `http.rb` was vulnerable to MitM attacks. The problem was corrected by calling
7
+ `#post_connection_check` (CVE-2015-1828) (@zanker, backported by @nicoolas25)
8
+
1
9
  0.6.3 (2014-11-14)
2
10
  ------------------
3
11
 
data/Gemfile CHANGED
@@ -25,6 +25,9 @@ group :test do
25
25
  gem 'rubocop', '~> 0.24.0', :platforms => [:ruby_19, :ruby_20, :ruby_21]
26
26
  gem 'simplecov', '>= 0.9'
27
27
  gem 'yardstick'
28
+ gem 'certificate_authority'
29
+ gem 'activemodel', '~> 3.0'
30
+ gem 'i18n', '~> 0.6.0'
28
31
  end
29
32
 
30
33
  # Specify your gem's dependencies in http.gemspec
data/lib/http/client.rb CHANGED
@@ -51,7 +51,7 @@ module HTTP
51
51
 
52
52
  # TODO: keep-alive support
53
53
  @socket = options[:socket_class].open(req.socket_host, req.socket_port)
54
- @socket = start_tls(@socket, options) if uri.is_a?(URI::HTTPS)
54
+ @socket = start_tls(@socket, uri.host, options) if uri.is_a?(URI::HTTPS)
55
55
 
56
56
  req.stream @socket
57
57
 
@@ -86,12 +86,17 @@ module HTTP
86
86
  private
87
87
 
88
88
  # Initialize TLS connection
89
- def start_tls(socket, options)
89
+ def start_tls(socket, host, options)
90
90
  # TODO: abstract away SSLContexts so we can use other TLS libraries
91
91
  context = options[:ssl_context] || OpenSSL::SSL::SSLContext.new
92
92
  socket = options[:ssl_socket_class].new(socket, context)
93
93
 
94
94
  socket.connect
95
+
96
+ if context.verify_mode == OpenSSL::SSL::VERIFY_PEER
97
+ socket.post_connection_check(host)
98
+ end
99
+
95
100
  socket
96
101
  end
97
102
 
data/lib/http/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module HTTP
2
- VERSION = '0.6.3'
2
+ VERSION = '0.6.4'
3
3
  end
@@ -1,7 +1,9 @@
1
1
  require 'spec_helper'
2
+ require 'support/dummy_server'
2
3
 
3
4
  describe HTTP::Client do
4
5
  let(:test_endpoint) { "http://127.0.0.1:#{ExampleService::PORT}" }
6
+ run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
5
7
 
6
8
  StubbedClient = Class.new(HTTP::Client) do
7
9
  def perform(request, options)
@@ -144,6 +146,38 @@ describe HTTP::Client do
144
146
  end
145
147
  end
146
148
 
149
+ describe 'SSL' do
150
+ let(:client) do
151
+ described_class.new(
152
+ :ssl_context => OpenSSL::SSL::SSLContext.new.tap do |context|
153
+ context.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
154
+
155
+ context.verify_mode = OpenSSL::SSL::VERIFY_PEER
156
+ context.ca_file = File.join(certs_dir, 'ca.crt')
157
+ context.cert = OpenSSL::X509::Certificate.new(
158
+ File.read(File.join(certs_dir, 'client.crt'))
159
+ )
160
+ context.key = OpenSSL::PKey::RSA.new(
161
+ File.read(File.join(certs_dir, 'client.key'))
162
+ )
163
+ context
164
+ end
165
+ )
166
+ end
167
+
168
+ it 'works via SSL' do
169
+ response = client.get(dummy_ssl.endpoint)
170
+ expect(response.body.to_s).to eq('<!doctype html>')
171
+ end
172
+
173
+ context 'with a mismatch host' do
174
+ it 'errors' do
175
+ expect { client.get(dummy_ssl.endpoint.gsub('127.0.0.1', 'localhost')) }
176
+ .to raise_error(OpenSSL::SSL::SSLError, /does not match/)
177
+ end
178
+ end
179
+ end
180
+
147
181
  describe '#perform' do
148
182
  let(:client) { described_class.new }
149
183
 
data/spec/spec_helper.rb CHANGED
@@ -14,6 +14,13 @@ require 'http'
14
14
  require 'support/example_server'
15
15
  require 'support/proxy_server'
16
16
 
17
+ # Allow testing against a SSL server
18
+ def certs_dir
19
+ Pathname.new File.expand_path('../../tmp/certs', __FILE__)
20
+ end
21
+
22
+ require 'support/create_certs'
23
+
17
24
  RSpec.configure do |config|
18
25
  config.expect_with :rspec do |c|
19
26
  c.syntax = :expect
@@ -0,0 +1,5 @@
1
+ module BlackHole
2
+ def self.method_missing(*)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,57 @@
1
+ require 'fileutils'
2
+ require 'certificate_authority'
3
+
4
+ FileUtils.mkdir_p(certs_dir)
5
+
6
+ #
7
+ # Certificate Authority
8
+ #
9
+
10
+ ca = CertificateAuthority::Certificate.new
11
+
12
+ ca.subject.common_name = 'honestachmed.com'
13
+ ca.serial_number.number = 1
14
+ ca.key_material.generate_key
15
+ ca.signing_entity = true
16
+
17
+ ca.sign! 'extensions' => {'keyUsage' => {'usage' => %w[critical keyCertSign]}}
18
+
19
+ ca_cert_path = File.join(certs_dir, 'ca.crt')
20
+ ca_key_path = File.join(certs_dir, 'ca.key')
21
+
22
+ File.write ca_cert_path, ca.to_pem
23
+ File.write ca_key_path, ca.key_material.private_key.to_pem
24
+
25
+ #
26
+ # Server Certificate
27
+ #
28
+
29
+ server_cert = CertificateAuthority::Certificate.new
30
+ server_cert.subject.common_name = '127.0.0.1'
31
+ server_cert.serial_number.number = 1
32
+ server_cert.key_material.generate_key
33
+ server_cert.parent = ca
34
+ server_cert.sign!
35
+
36
+ server_cert_path = File.join(certs_dir, 'server.crt')
37
+ server_key_path = File.join(certs_dir, 'server.key')
38
+
39
+ File.write server_cert_path, server_cert.to_pem
40
+ File.write server_key_path, server_cert.key_material.private_key.to_pem
41
+
42
+ #
43
+ # Client Certificate
44
+ #
45
+
46
+ client_cert = CertificateAuthority::Certificate.new
47
+ client_cert.subject.common_name = '127.0.0.1'
48
+ client_cert.serial_number.number = 1
49
+ client_cert.key_material.generate_key
50
+ client_cert.parent = ca
51
+ client_cert.sign!
52
+
53
+ client_cert_path = File.join(certs_dir, 'client.crt')
54
+ client_key_path = File.join(certs_dir, 'client.key')
55
+
56
+ File.write client_cert_path, client_cert.to_pem
57
+ File.write client_key_path, client_cert.key_material.private_key.to_pem
@@ -0,0 +1,52 @@
1
+ require 'webrick'
2
+ require 'webrick/ssl'
3
+
4
+ require 'support/black_hole'
5
+ require 'support/dummy_server/servlet'
6
+ require 'support/servers/config'
7
+ require 'support/servers/runner'
8
+
9
+ class DummyServer < WEBrick::HTTPServer
10
+ include ServerConfig
11
+
12
+ CONFIG = {
13
+ :BindAddress => '127.0.0.1',
14
+ :Port => 0,
15
+ :AccessLog => BlackHole,
16
+ :Logger => BlackHole
17
+ }.freeze
18
+
19
+ def initialize(options = {})
20
+ if options[:ssl]
21
+ override_config = {
22
+ :SSLEnable => true,
23
+ :SSLStartImmediately => true
24
+ }
25
+ else
26
+ override_config = {}
27
+ end
28
+
29
+ super CONFIG.merge(override_config)
30
+
31
+ mount('/', Servlet)
32
+ end
33
+
34
+ def endpoint
35
+ "#{ssl? ? 'https' : 'http'}://#{addr}:#{port}"
36
+ end
37
+
38
+ def ssl_context
39
+ @ssl_context ||= begin
40
+ context = OpenSSL::SSL::SSLContext.new
41
+ context.verify_mode = OpenSSL::SSL::VERIFY_PEER
42
+ context.key = OpenSSL::PKey::RSA.new(
43
+ File.read(File.join(certs_dir, 'server.key'))
44
+ )
45
+ context.cert = OpenSSL::X509::Certificate.new(
46
+ File.read(File.join(certs_dir, 'server.crt'))
47
+ )
48
+ context.ca_file = File.join(certs_dir, 'ca.crt')
49
+ context
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,30 @@
1
+ class DummyServer < WEBrick::HTTPServer
2
+ class Servlet < WEBrick::HTTPServlet::AbstractServlet
3
+ def not_found(_req, res)
4
+ res.status = 404
5
+ res.body = 'Not Found'
6
+ end
7
+
8
+ def self.handlers
9
+ @handlers ||= {}
10
+ end
11
+
12
+ %w[get post head].each do |method|
13
+ class_eval <<-RUBY, __FILE__, __LINE__
14
+ def self.#{method}(path, &block)
15
+ handlers["#{method}:\#{path}"] = block
16
+ end
17
+ def do_#{method.upcase}(req, res)
18
+ handler = self.class.handlers["#{method}:\#{req.path}"]
19
+ return instance_exec(req, res, &handler) if handler
20
+ not_found
21
+ end
22
+ RUBY
23
+ end
24
+
25
+ get '/' do |_req, res|
26
+ res.status = 200
27
+ res.body = '<!doctype html>'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ module ServerConfig
2
+ def ssl?
3
+ !!config[:SSLEnable]
4
+ end
5
+
6
+ def addr
7
+ config[:BindAddress]
8
+ end
9
+
10
+ def port
11
+ config[:Port]
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module ServerRunner
2
+ def run_server(name, &block)
3
+ let! name do
4
+ server = block.call
5
+
6
+ Thread.new { server.start }
7
+
8
+ server
9
+ end
10
+
11
+ after do
12
+ send(name).shutdown
13
+ end
14
+ end
15
+ end
16
+
17
+ RSpec.configure { |c| c.extend ServerRunner }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-14 00:00:00.000000000 Z
12
+ date: 2015-03-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: http_parser.rb
@@ -109,8 +109,14 @@ files:
109
109
  - spec/http/response_spec.rb
110
110
  - spec/http_spec.rb
111
111
  - spec/spec_helper.rb
112
+ - spec/support/black_hole.rb
113
+ - spec/support/create_certs.rb
114
+ - spec/support/dummy_server.rb
115
+ - spec/support/dummy_server/servlet.rb
112
116
  - spec/support/example_server.rb
113
117
  - spec/support/proxy_server.rb
118
+ - spec/support/servers/config.rb
119
+ - spec/support/servers/runner.rb
114
120
  homepage: https://github.com/tarcieri/http
115
121
  licenses:
116
122
  - MIT