ftw 0.0.41 → 0.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ceb0fdc8f63693a96433f7417afb19330140af2
4
- data.tar.gz: e037a78814a02848e72c92da450b338d0d190737
3
+ metadata.gz: 33fab2173e9d5a55d01c5be096be99b4a6e4c9b6
4
+ data.tar.gz: 2d5d057c20fc4bec7705143ba4010d9162623d1f
5
5
  SHA512:
6
- metadata.gz: a683de29fb0919b548d7162198943bc164fc35b66d8f8ec6d750fbe51808c3cf8078591ae3e2ccc256b0cc80d2a07153f933b9e73e66f819b1908d15337399e3
7
- data.tar.gz: 5b210be8cfd33f284b5355cc2832b5ccdc1fbe464f081710c5e90f813424e1844eaddb2b3f1f5832ae74eee2a37c5c9c34c5ff4d13f21511a4b32a5b97439335
6
+ metadata.gz: 1cd81a35b4289d5c5f3c7aa566d4de5e4192ad2ac8343d7c74d3a13fc695ad6c719254395375448262da6ee13697ce2a066f63eaab32c069e185a4b7d8ee2c9c
7
+ data.tar.gz: 437f27db19fd9616dcec6db39d97f02e336ab0d5edeaebff14e785a70d85988a41a8a72bbd2075ccbbd2f4ce9532321277b49730a49894bd1e87681ca5c6eedd
@@ -445,8 +445,9 @@ class FTW::Agent
445
445
  @logger.error("Error in certificate_verify call", :exception => e)
446
446
  end
447
447
  end
448
- connection.secure(:certificate_store => certificate_store,
449
- :verify_callback => verify_callback)
448
+ ciphers = SSL_CIPHER_MAP[configuration[SSL_CIPHERS]] || configuration[SSL_CIPHERS]
449
+ connection.secure(:certificate_store => certificate_store, :verify_callback => verify_callback,
450
+ :ciphers => ciphers, :version => configuration[SSL_VERSION])
450
451
  end # if secure
451
452
 
452
453
  return connection, nil
@@ -12,6 +12,20 @@ module FTW::Agent::Configuration
12
12
  # SSL: Use the system's global default certs?
13
13
  SSL_USE_DEFAULT_CERTS = "ssl.use-default-certs".freeze
14
14
 
15
+ # SSL cipher strings
16
+ SSL_CIPHERS = "ssl.ciphers".freeze
17
+
18
+ SSL_CIPHER_MAP = {
19
+ # https://wiki.mozilla.org/Security/Server_Side_TLS
20
+ "MOZILLA_MODERN" => "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK",
21
+ "MOZILLA_INTERMEDIATE" => "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA",
22
+ "MOZILLA_OLD" => "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
23
+ }
24
+
25
+ SSL_CIPHER_DEFAULT = SSL_CIPHER_MAP["MOZILLA_MODERN"]
26
+
27
+ SSL_VERSION = "ssl.version"
28
+
15
29
  private
16
30
 
17
31
  # Get the configuration hash
@@ -27,6 +41,8 @@ module FTW::Agent::Configuration
27
41
  REDIRECTION_LIMIT => 20,
28
42
  SSL_TRUST_STORE => File.join(home, "ssl-trust.db"),
29
43
  SSL_USE_DEFAULT_CERTS => true,
44
+ SSL_CIPHERS => SSL_CIPHER_DEFAULT,
45
+ SSL_VERSION => "TLSv1.1",
30
46
  }
31
47
  end # def default_configuration
32
48
 
@@ -40,6 +40,9 @@ class FTW::Connection
40
40
  # Secure setup timed out
41
41
  class SecureHandshakeTimeout < StandardError; end
42
42
 
43
+ # Invalid connection configuration
44
+ class InvalidConfiguration < StandardError; end
45
+
43
46
  private
44
47
 
45
48
  # A new network connection.
@@ -315,13 +318,20 @@ class FTW::Connection
315
318
  #
316
319
  # * :certificate_store, an OpenSSL::X509::Store
317
320
  # * :timeout, a timeout threshold in seconds.
321
+ # * :ciphers, an OpenSSL ciphers string, see `openssl ciphers` manual for details.
322
+ # * :version, any of: SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2
323
+ #
324
+ # Notes:
325
+ # * Version may depend on your platform (openssl compilation settings, JVM
326
+ # version, export restrictions, etc)
318
327
  def secure(options=nil)
319
328
  # Skip this if we're already secure.
320
329
  return if secured?
321
330
 
322
331
  defaults = {
323
332
  :timeout => nil,
324
- #:certificate_store => OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
333
+ :ciphers => FTW::Agent::Configuration::SSL_CIPHER_MAP["MOZILLA_MODERN"],
334
+ :version => "TLSv1.1"
325
335
  }
326
336
  settings = defaults.merge(options) unless options.nil?
327
337
 
@@ -334,7 +344,7 @@ class FTW::Connection
334
344
 
335
345
  # ruby-core is refusing to patch ruby's default openssl settings to be more
336
346
  # secure, so let's fix that here. The next few lines setting options and
337
- # ciphers come from jmhodges proposed patch
347
+ # ciphers come from jmhodges' proposed patch
338
348
  ssloptions = OpenSSL::SSL::OP_ALL
339
349
  if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
340
350
  ssloptions &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS
@@ -342,8 +352,15 @@ class FTW::Connection
342
352
  if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
343
353
  ssloptions |= OpenSSL::SSL::OP_NO_COMPRESSION
344
354
  end
355
+ # https://github.com/jruby/jruby/issues/1874
356
+ version = OpenSSL::SSL::SSLContext::METHODS.find { |x| x.to_s.gsub("_",".") == settings[:version] }
357
+ raise InvalidConfiguration, "Invalid SSL/TLS version '#{settings[:version]}'" if version.nil?
358
+ sslcontext.ssl_version = version
359
+
360
+ # We have to set ciphers *after* setting ssl_version because setting
361
+ # ssl_version will reset the cipher set.
345
362
  sslcontext.options = ssloptions
346
- sslcontext.ciphers = "DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2"
363
+ sslcontext.ciphers = settings[:ciphers]
347
364
 
348
365
  sslcontext.verify_callback = proc do |*args|
349
366
  @logger.debug("Verify peer via FTW::Connection#secure", :callback => settings[:verify_callback])
@@ -351,16 +368,17 @@ class FTW::Connection
351
368
  settings[:verify_callback].call(*args)
352
369
  end
353
370
  end
354
- sslcontext.cert_store = options[:certificate_store]
371
+ sslcontext.cert_store = settings[:certificate_store]
372
+
355
373
  @socket = OpenSSL::SSL::SSLSocket.new(@socket, sslcontext)
356
374
 
357
375
  # TODO(sissel): Set up local certificat/key stuff. This is required for
358
376
  # server-side ssl operation, I think.
359
377
 
360
378
  if client?
361
- do_secure(:connect_nonblock, options[:timeout])
379
+ do_secure(:connect_nonblock, settings[:timeout])
362
380
  else
363
- do_secure(:accept_nonblock, options[:timeout])
381
+ do_secure(:accept_nonblock, settings[:timeout])
364
382
  end
365
383
  end # def secure
366
384
 
@@ -109,7 +109,7 @@ module FTW::Protocol
109
109
  def write_all(io, string)
110
110
  while string.bytesize > 0
111
111
  w = io.write(string)
112
- string = string[w..-1]
112
+ string = string.byteslice(w..-1)
113
113
  end
114
114
  end # def write_all
115
115
 
@@ -26,6 +26,7 @@ class FTW::Server
26
26
  addresses = [addresses] if !addresses.is_a?(Array)
27
27
  dns = FTW::DNS.singleton
28
28
 
29
+ @control_lock = Mutex.new
29
30
  @sockets = {}
30
31
 
31
32
  failures = []
@@ -78,14 +79,23 @@ class FTW::Server
78
79
  failures += local_failures
79
80
  end
80
81
 
82
+ # This allows us to interrupt the #each_connection's select() later
83
+ # when anyone calls stop()
84
+ @stopper = IO.pipe
85
+
81
86
  # Abort if there were failures
82
87
  raise ServerSetupFailure.new(failures) if failures.any?
83
88
  end # def initialize
84
89
 
85
90
  # Stop serving.
86
91
  def stop
87
- @sockets.each do |name, socket|
88
- socket.close
92
+ @stopper[1].syswrite(".")
93
+ @stopper[1].close()
94
+ @control_lock.synchronize do
95
+ @sockets.each do |name, socket|
96
+ socket.close
97
+ end
98
+ @sockets.clear
89
99
  end
90
100
  end # def stop
91
101
 
@@ -93,14 +103,17 @@ class FTW::Server
93
103
  def each_connection(&block)
94
104
  # TODO(sissel): Select on all sockets
95
105
  # TODO(sissel): Accept and yield to the block
106
+ stopper = @stopper[0]
96
107
  while true
97
- sockets = @sockets.values
98
- read, write, error = IO.select(sockets, nil, nil, nil)
99
- read.each do |serversocket|
100
- #p serversocket.methods.sort
101
- socket, addrinfo = serversocket.accept
102
- connection = FTW::Connection.from_io(socket)
103
- yield connection
108
+ @control_lock.synchronize do
109
+ sockets = @sockets.values + [stopper]
110
+ read, write, error = IO.select(sockets, nil, nil, nil)
111
+ break if read.include?(stopper)
112
+ read.each do |serversocket|
113
+ socket, addrinfo = serversocket.accept
114
+ connection = FTW::Connection.from_io(socket)
115
+ yield connection
116
+ end
104
117
  end
105
118
  end
106
119
  end # def each_connection
@@ -3,5 +3,5 @@ require "ftw/namespace"
3
3
  # :nodoc:
4
4
  module FTW
5
5
  # The version of this library
6
- VERSION = "0.0.41"
6
+ VERSION = "0.0.42"
7
7
  end
@@ -76,4 +76,17 @@ describe FTW::Protocol do
76
76
  assert_equal( output.io.string, "12\r\nSome example input\r\n0\r\n\r\n")
77
77
  end
78
78
 
79
+ test "writing non ascii characters" do
80
+ protocol = Object.new
81
+ protocol.extend FTW::Protocol
82
+
83
+ output = StringIO.new
84
+ input = "è".force_encoding(Encoding::UTF_8)
85
+
86
+ protocol.write_http_body(input, output, true)
87
+
88
+ output.rewind
89
+ assert_equal( output.string, "2\r\nè\r\n0\r\n\r\n")
90
+ end
91
+
79
92
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ftw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.41
4
+ version: 0.0.42
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Sissel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-13 00:00:00.000000000 Z
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cabin
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: http_parser.rb
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.5.3
33
+ version: '0.6'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.5.3
40
+ version: '0.6'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: addressable
43
43
  requirement: !ruby/object:Gem::Requirement