Skip to content

[Feature #19641] Enable to pass SSLContext to Net::HTTP #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 50 additions & 37 deletions lib/net/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1583,11 +1583,15 @@ def do_start
end
private :do_start

def ssl_context=(context)
@user_provided_ssl_context = context
end

def connect
if use_ssl?
# reference early to load OpenSSL before connecting,
# as OpenSSL may take time to load.
@ssl_context = OpenSSL::SSL::SSLContext.new
@ssl_context ||= prepare_ssl_context(@user_provided_ssl_context)
end

if proxy? then
Expand Down Expand Up @@ -1627,41 +1631,7 @@ def connect
# assuming nothing left in buffers after successful CONNECT response
end

ssl_parameters = Hash.new
iv_list = instance_variables
SSL_IVNAMES.each_with_index do |ivname, i|
if iv_list.include?(ivname)
value = instance_variable_get(ivname)
unless value.nil?
ssl_parameters[SSL_ATTRIBUTES[i]] = value
end
end
end
@ssl_context.set_params(ssl_parameters)
unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
@ssl_context.session_cache_mode =
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
end
if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
end

# Still do the post_connection_check below even if connecting
# to IP address
verify_hostname = @ssl_context.verify_hostname

# Server Name Indication (SNI) RFC 3546/6066
case @address
when Resolv::IPv4::Regex, Resolv::IPv6::Regex
# don't set SNI, as IP addresses in SNI is not valid
# per RFC 6066, section 3.

# Avoid openssl warning
@ssl_context.verify_hostname = false
else
ssl_host_address = @address
end
ssl_host_address = @address if !address_is_ip?

debug "starting SSL for #{conn_addr}:#{conn_port}..."
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
Expand All @@ -1673,7 +1643,7 @@ def connect
s.session = @ssl_session
end
ssl_socket_connect(s, @open_timeout)
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && @verify_hostname
s.post_connection_check(@address)
end
debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
Expand All @@ -1693,6 +1663,49 @@ def connect
end
private :connect

def prepare_ssl_context(context)
context ||= OpenSSL::SSL::SSLContext.new
ssl_parameters = Hash.new
iv_list = instance_variables
SSL_IVNAMES.each_with_index do |ivname, i|
if iv_list.include?(ivname)
value = instance_variable_get(ivname)
unless value.nil?
ssl_parameters[SSL_ATTRIBUTES[i]] = value
end
end
end
context.set_params(ssl_parameters)

unless context.session_cache_mode.nil? # a dummy method on JRuby
context.session_cache_mode =
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
end
if context.respond_to?(:session_new_cb) # not implemented under JRuby
context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
end

# Still do the post_connection_check below even if connecting
# to IP address
@verify_hostname = context.verify_hostname

# Server Name Indication (SNI) RFC 3546/6066
if address_is_ip?
# don't set SNI, as IP addresses in SNI is not valid
# per RFC 6066, section 3.

# Avoid openssl warning
context.verify_hostname = false
end

context
end

def address_is_ip?
Resolv::IPv4::Regex.match(@address) || Resolv::IPv6::Regex.match(@address)
end

def on_connect
end
private :on_connect
Expand Down
11 changes: 11 additions & 0 deletions test/net/http/test_https.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,4 +307,15 @@ def test_max_version
assert_match(re_msg, ex.message)
end

def test_ssl_context
http = Net::HTTP.new(HOST, config("port"))
http.use_ssl = true
ssl_context = OpenSSL::SSL::SSLContext.new
ssl_context.min_version = :TLS1
http.ssl_context = ssl_context
http.cert_store = TEST_STORE
http.request_get("/") {|res|
assert_equal($test_net_http_data, res.body)
}
end
end if defined?(OpenSSL::SSL)