Skip to content

Commit

Permalink
Do not set SNI hostname if connecting to IP address
Browse files Browse the repository at this point in the history
RFC 6066, section 3, explicitly disallows the use of an IP address
as an SNI server name.  So check if the connection is being made
to an IP address using the resolv regexps, and do not set an SNI
hostname in that case.

Recent changes to LibreSSL make it more strictly follow RFC 6066,
resulting an s.hostname= raising an error if passed an IP address.
When such verions of LibreSSL are used, this change not only fixes
the net/http tests, it also fixes tests for webrick and open-uri,
which both make SSL connections to 127.0.0.1 using net/http in
their tests.

Avoid warning in the openssl extension by unsetting
@ssl_context.verify_hostname if connecting to an IP address.
Make changes so that the post_connection_check still happens
when connecting to an IP address, which is necessary to keep
checking that the certificate returned includes the IP address,
which one of the tests depends on.

Revert the previous change that modified the regexp used for
checking the error message.
  • Loading branch information
jeremyevans committed Jan 21, 2022
1 parent d2aed67 commit 50c2ac1
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 4 deletions.
24 changes: 21 additions & 3 deletions lib/net/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

require 'net/protocol'
require 'uri'
require 'resolv'
autoload :OpenSSL, 'openssl'

module Net #:nodoc:
Expand Down Expand Up @@ -1036,17 +1037,34 @@ def connect
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }

# 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

debug "starting SSL for #{conn_addr}:#{conn_port}..."
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
s.sync_close = true
# Server Name Indication (SNI) RFC 3546
s.hostname = @address if s.respond_to? :hostname=
s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address

if @ssl_session and
Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
s.session = @ssl_session
end
ssl_socket_connect(s, @open_timeout)
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && @ssl_context.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 Down
2 changes: 1 addition & 1 deletion test/net/http/test_https.rb
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def test_identity_verify_failure
ex = assert_raise(OpenSSL::SSL::SSLError){
http.request_get("/") {|res| }
}
re_msg = /certificate verify failed|hostname \"#{HOST_IP}\" does not match|ssl3 ext invalid servername/
re_msg = /certificate verify failed|hostname \"#{HOST_IP}\" does not match/
assert_match(re_msg, ex.message)
end

Expand Down

0 comments on commit 50c2ac1

Please sign in to comment.