From 7fca46547f3259b68e6cd1d228b40658cfc07552 Mon Sep 17 00:00:00 2001 From: Matt Pasquini Date: Fri, 17 Jul 2020 08:44:41 -0700 Subject: [PATCH] SSL min_version/max_version support --- lib/httpclient/jruby_ssl_socket.rb | 2 ++ lib/httpclient/ssl_config.rb | 17 ++++++++++++-- test/test_ssl.rb | 36 ++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/lib/httpclient/jruby_ssl_socket.rb b/lib/httpclient/jruby_ssl_socket.rb index 1a0db8ea..2ff41993 100644 --- a/lib/httpclient/jruby_ssl_socket.rb +++ b/lib/httpclient/jruby_ssl_socket.rb @@ -489,6 +489,8 @@ def initialize(socket, dest, config, opts = {}) @ssl_socket = create_ssl_socket(socket, dest, config, opts) ssl_version = java_ssl_version(config) @ssl_socket.setEnabledProtocols([ssl_version].to_java(java.lang.String)) if ssl_version != DEFAULT_SSL_PROTOCOL + @ssl_socket.setEnabledProtocols([min_version].to_java(java.lang.String)) if min_version + @ssl_socket.setEnabledProtocols([max_version].to_java(java.lang.String)) if max_version if config.ciphers != SSLConfig::CIPHERS_DEFAULT @ssl_socket.setEnabledCipherSuites(config.ciphers.to_java(java.lang.String)) end diff --git a/lib/httpclient/ssl_config.rb b/lib/httpclient/ssl_config.rb index f6e7ce92..714117fe 100644 --- a/lib/httpclient/ssl_config.rb +++ b/lib/httpclient/ssl_config.rb @@ -93,8 +93,17 @@ def attr_config(symbol) # String name of OpenSSL's SSL version method name: TLSv1_2, TLSv1_1, TLSv1, # SSLv2, SSLv23, SSLv3 or :auto (and nil) to allow version negotiation (default). # See {OpenSSL::SSL::SSLContext::METHODS} for a list of available versions - # in your specific Ruby environment. + # in your specific Ruby environment. This is + # deprecated and only provided for backwards compatibility. Use + # #min_version= and #max_version= instead. attr_config :ssl_version + # Sets the upper bound on the supported SSL/TLS protocol version. + # See min_version for possible values. + attr_config :max_version + # Sets the lower bound on the supported SSL/TLS protocol version. + # The version may be specified by an integer constant named + # OpenSSL::SSL::*_VERSION, a Symbol, or +nil+ which means "any version". + attr_config :min_version # OpenSSL::X509::Certificate:: certificate for SSL client authentication. # nil by default. (no client authentication) attr_config :client_cert @@ -123,7 +132,7 @@ def attr_config(symbol) # A number of OpenSSL's SSL options. Default value is # OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2 # CAUTION: this is OpenSSL specific option and ignored on JRuby. - # Use ssl_version to specify the TLS version you want to use. + # Use min_version and max_version to specify the TLS versions you want to use. attr_config :options # A String of OpenSSL's cipher configuration. Default value is # ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH @@ -154,6 +163,8 @@ def initialize(client) @dest = nil @timeout = nil @ssl_version = :auto + @max_version = nil + @min_version = nil # Follow ruby-ossl's definition @options = OpenSSL::SSL::OP_ALL @options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS) @@ -303,6 +314,8 @@ def set_context(ctx) # :nodoc: ctx.options = @options ctx.ciphers = @ciphers ctx.ssl_version = @ssl_version unless @ssl_version == :auto + ctx.min_version = @min_version if @min_version + ctx.max_version = @max_version if @max_version end # post connection check proc for ruby < 1.8.5. diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 1966b86c..75a60602 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -265,6 +265,15 @@ def test_allow_tlsv1 end end + def test_allow_with_min_max + teardown_server + setup_server_with_min_and_max_version(:TLS1_2) + assert_nothing_raised do + @client.ssl_config.verify_mode = nil + @client.get("https://localhost:#{serverport}/hello") + end + end + def test_use_higher_TLS omit('TODO: it does not pass with Java 7 or old openssl ') teardown_server @@ -499,6 +508,33 @@ def setup_server_with_ssl_version(ssl_version) @server_thread = start_server_thread(@server) end + def setup_server_with_min_and_max_version(version) + logger = Logger.new(STDERR) + logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level) + @server = WEBrick::HTTPServer.new( + :BindAddress => "localhost", + :Logger => logger, + :Port => 0, + :AccessLog => [], + :DocumentRoot => DIR, + :SSLEnable => true, + :SSLCACertificateFile => File.join(DIR, 'ca.cert'), + :SSLCertificate => cert('server.cert'), + :SSLPrivateKey => key('server.key') + ) + @server.ssl_context.min_version = version + @server.ssl_context.max_version = version + + @serverport = @server.config[:Port] + [:hello].each do |sym| + @server.mount( + "/#{sym}", + WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc) + ) + end + @server_thread = start_server_thread(@server) + end + def setup_server_with_server_cert(ca_cert, server_cert, server_key) logger = Logger.new(STDERR) logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)