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 +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGES.md +8 -0
- data/Gemfile +3 -0
- data/lib/http/client.rb +7 -2
- data/lib/http/version.rb +1 -1
- data/spec/http/client_spec.rb +34 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/black_hole.rb +5 -0
- data/spec/support/create_certs.rb +57 -0
- data/spec/support/dummy_server.rb +52 -0
- data/spec/support/dummy_server/servlet.rb +30 -0
- data/spec/support/servers/config.rb +13 -0
- data/spec/support/servers/runner.rb +17 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4030eeaf2d60cda70af573153fe436493061181
|
4
|
+
data.tar.gz: 8c81614a50e7510eb06a0b48ddd8b140da557b88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71658b9dc31eb01d62e038c6f7a4e193aa030360ad65d146a5fa3ab03c563c163b9fd688f9a2496b640a143f3658a21b74bc791301b701aaa4c972250995c608
|
7
|
+
data.tar.gz: 59254dd112aa7e6405b56ddc5901c564d942fdd8e12e913e1a4b6b1f64faf79257432ad85f4b6385b8b4a3f8b45ce732e36839fc78ac53f91bf9cd2bce5f66de
|
data/.rubocop.yml
CHANGED
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
data/spec/http/client_spec.rb
CHANGED
@@ -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,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,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.
|
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:
|
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
|