mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-11-27 00:03:01 -05:00
fixing cerfificate hostname validation callback
This commit is contained in:
parent
0b7dbb8cfa
commit
2ecfde95d8
@ -18,6 +18,8 @@ AllCops:
|
|||||||
- 'vendor/**/*'
|
- 'vendor/**/*'
|
||||||
- 'www/**/*'
|
- 'www/**/*'
|
||||||
- 'lib/httpx/extensions.rb'
|
- 'lib/httpx/extensions.rb'
|
||||||
|
# Do not lint ffi block, for openssl parity
|
||||||
|
- 'lib/httpx/io/tls/*.rb'
|
||||||
|
|
||||||
Metrics/ClassLength:
|
Metrics/ClassLength:
|
||||||
Max: 400
|
Max: 400
|
||||||
|
|||||||
@ -36,4 +36,3 @@ Style/Documentation:
|
|||||||
|
|
||||||
Naming/AccessorMethodName:
|
Naming/AccessorMethodName:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ module HTTPX
|
|||||||
# signals TLS invalid status / shutdown.
|
# signals TLS invalid status / shutdown.
|
||||||
def close_cb(msg = nil)
|
def close_cb(msg = nil)
|
||||||
log { "TLS Error: #{msg}, closing" }
|
log { "TLS Error: #{msg}, closing" }
|
||||||
raise TLSError, msg || "TLS Error"
|
raise TLSError, "TLSError: certificate verify failed (#{msg})"
|
||||||
end
|
end
|
||||||
|
|
||||||
# TLS callback.
|
# TLS callback.
|
||||||
|
|||||||
@ -15,19 +15,28 @@ module HTTPX
|
|||||||
|
|
||||||
bio_out = SSL.BIO_new(SSL.BIO_s_mem)
|
bio_out = SSL.BIO_new(SSL.BIO_s_mem)
|
||||||
ret = SSL.PEM_write_bio_X509(bio_out, x509)
|
ret = SSL.PEM_write_bio_X509(bio_out, x509)
|
||||||
unless ret
|
if ret
|
||||||
|
len = SSL.BIO_pending(bio_out)
|
||||||
|
buffer = FFI::MemoryPointer.new(:char, len, false)
|
||||||
|
size = SSL.BIO_read(bio_out, buffer, len)
|
||||||
|
|
||||||
|
# THis is the callback into the ruby class
|
||||||
|
cert = buffer.read_string(size)
|
||||||
SSL.BIO_free(bio_out)
|
SSL.BIO_free(bio_out)
|
||||||
raise "Error reading certificate"
|
# InstanceLookup[ssl.address].verify(cert) || preverify_ok.zero? ? 1 : 0
|
||||||
|
box = InstanceLookup[ssl.address]
|
||||||
|
hostname_verify = box.verify(cert)
|
||||||
|
if hostname_verify
|
||||||
|
1
|
||||||
|
else
|
||||||
|
SSL.X509_STORE_CTX_set_error(x509_store, SSL::X509_V_ERR_HOSTNAME_MISMATCH)
|
||||||
|
0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
SSL.BIO_free(bio_out)
|
||||||
|
SSL.X509_STORE_CTX_set_error(x509_store, SSL::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)
|
||||||
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
len = SSL.BIO_pending(bio_out)
|
|
||||||
buffer = FFI::MemoryPointer.new(:char, len, false)
|
|
||||||
size = SSL.BIO_read(bio_out, buffer, len)
|
|
||||||
|
|
||||||
# THis is the callback into the ruby class
|
|
||||||
cert = buffer.read_string(size)
|
|
||||||
SSL.BIO_free(bio_out)
|
|
||||||
InstanceLookup[ssl.address].verify(cert) || preverify_ok.zero? ? 1 : 0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :is_server, :context, :handshake_completed, :hosts, :ssl_version, :cipher, :verify_peer
|
attr_reader :is_server, :context, :handshake_completed, :hosts, :ssl_version, :cipher, :verify_peer
|
||||||
|
|||||||
@ -60,9 +60,9 @@ module HTTPX
|
|||||||
set_alpn_negotiation(options[:protocols])
|
set_alpn_negotiation(options[:protocols])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def cleanup
|
def cleanup
|
||||||
return unless @ssl_ctx
|
return unless @ssl_ctx
|
||||||
|
|
||||||
SSL.SSL_CTX_free(@ssl_ctx)
|
SSL.SSL_CTX_free(@ssl_ctx)
|
||||||
@ssl_ctx = nil
|
@ssl_ctx = nil
|
||||||
end
|
end
|
||||||
@ -101,9 +101,9 @@ module HTTPX
|
|||||||
|
|
||||||
def set_min_version(version)
|
def set_min_version(version)
|
||||||
return unless version
|
return unless version
|
||||||
|
|
||||||
num = SSL.const_get("#{version}_VERSION")
|
num = SSL.const_get("#{version}_VERSION")
|
||||||
SSL.SSL_CTX_set_min_proto_version(@ssl_ctx, num) == 1
|
SSL.SSL_CTX_set_min_proto_version(@ssl_ctx, num) == 1
|
||||||
puts "version done"
|
|
||||||
rescue NameError
|
rescue NameError
|
||||||
raise Error, "#{version} is unsupported"
|
raise Error, "#{version} is unsupported"
|
||||||
end
|
end
|
||||||
@ -124,7 +124,6 @@ module HTTPX
|
|||||||
else
|
else
|
||||||
protocols = Context.build_alpn_string(protocols)
|
protocols = Context.build_alpn_string(protocols)
|
||||||
@alpn_set = SSL.SSL_CTX_set_alpn_protos(@ssl_ctx, protocols, protocols.length) == 0
|
@alpn_set = SSL.SSL_CTX_set_alpn_protos(@ssl_ctx, protocols, protocols.length) == 0
|
||||||
puts "alpn protocols: #{protocols}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|||||||
@ -148,16 +148,21 @@ module HTTPX
|
|||||||
attach_function :SSL_set_ex_data, %i[ssl int string], :int
|
attach_function :SSL_set_ex_data, %i[ssl int string], :int
|
||||||
callback :verify_callback, %i[int x509], :int
|
callback :verify_callback, %i[int x509], :int
|
||||||
attach_function :SSL_set_verify, %i[ssl int verify_callback], :void
|
attach_function :SSL_set_verify, %i[ssl int verify_callback], :void
|
||||||
|
attach_function :SSL_CTX_set_verify, %i[ssl int verify_callback], :void
|
||||||
attach_function :SSL_get_verify_result, %i[ssl], :long
|
attach_function :SSL_get_verify_result, %i[ssl], :long
|
||||||
attach_function :SSL_connect, [:ssl], :int
|
attach_function :SSL_connect, [:ssl], :int
|
||||||
|
|
||||||
# Verify callback
|
# Verify callback
|
||||||
|
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2
|
||||||
|
X509_V_ERR_HOSTNAME_MISMATCH = 62
|
||||||
|
X509_V_ERR_CERT_REJECTED = 28
|
||||||
attach_function :X509_STORE_CTX_get_current_cert, [:pointer], :x509
|
attach_function :X509_STORE_CTX_get_current_cert, [:pointer], :x509
|
||||||
attach_function :SSL_get_ex_data_X509_STORE_CTX_idx, [], :int
|
attach_function :SSL_get_ex_data_X509_STORE_CTX_idx, [], :int
|
||||||
attach_function :X509_STORE_CTX_get_ex_data, %i[pointer int], :ssl
|
attach_function :X509_STORE_CTX_get_ex_data, %i[pointer int], :ssl
|
||||||
attach_function :X509_STORE_CTX_get_error_depth, %i[x509], :int
|
attach_function :X509_STORE_CTX_get_error_depth, %i[x509], :int
|
||||||
attach_function :PEM_write_bio_X509, %i[bio x509], :bool
|
attach_function :PEM_write_bio_X509, %i[bio x509], :bool
|
||||||
attach_function :X509_verify_cert_error_string, %i[long], :string
|
attach_function :X509_verify_cert_error_string, %i[long], :string
|
||||||
|
attach_function :X509_STORE_CTX_set_error, %i[ssl_ctx long], :void
|
||||||
|
|
||||||
# SSL Context Class
|
# SSL Context Class
|
||||||
# OpenSSL before 1.1.0 do not have these methods
|
# OpenSSL before 1.1.0 do not have these methods
|
||||||
@ -230,7 +235,7 @@ module HTTPX
|
|||||||
|
|
||||||
def self.SSL_set_tlsext_host_name(ssl, host_name)
|
def self.SSL_set_tlsext_host_name(ssl, host_name)
|
||||||
name_ptr = FFI::MemoryPointer.from_string(host_name)
|
name_ptr = FFI::MemoryPointer.from_string(host_name)
|
||||||
raise Error, "error setting SNI hostname" if SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name_ptr) == 0
|
raise Error, "error setting SNI hostname" if SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name_ptr).zero?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Server Name Indication (SNI) Support
|
# Server Name Indication (SNI) Support
|
||||||
@ -286,7 +291,7 @@ module HTTPX
|
|||||||
# Deconstructor
|
# Deconstructor
|
||||||
attach_function :SSL_CTX_free, [:ssl_ctx], :void
|
attach_function :SSL_CTX_free, [:ssl_ctx], :void
|
||||||
|
|
||||||
PrivateMaterials = <<~keystr
|
PrivateMaterials = <<~KEYSTR
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIICXAIBAAKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxwVDWV
|
MIICXAIBAAKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxwVDWV
|
||||||
Igdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t39hJ/
|
Igdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t39hJ/
|
||||||
@ -325,7 +330,7 @@ module HTTPX
|
|||||||
Df6hTAs7H3MWww62ddvR8l07AWfSzSP5L6mDsbvq7EmQsmPODwb6C+i2aF3EDL8j
|
Df6hTAs7H3MWww62ddvR8l07AWfSzSP5L6mDsbvq7EmQsmPODwb6C+i2aF3EDL8j
|
||||||
uw73m4YIGI0Zw2XdBpiOGkx2H56Kya6mJJe/5XORZedh1wpI7zki01tHYbcy
|
uw73m4YIGI0Zw2XdBpiOGkx2H56Kya6mJJe/5XORZedh1wpI7zki01tHYbcy
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
keystr
|
KEYSTR
|
||||||
|
|
||||||
BuiltinPasswdCB = FFI::Function.new(:int, %i[pointer int int pointer]) do |buffer, _len, _flag, _data|
|
BuiltinPasswdCB = FFI::Function.new(:int, %i[pointer int int pointer]) do |buffer, _len, _flag, _data|
|
||||||
buffer.write_string("kittycat")
|
buffer.write_string("kittycat")
|
||||||
|
|||||||
@ -112,7 +112,8 @@ class HTTPSTest < Minitest::Test
|
|||||||
uri = build_uri("/get")
|
uri = build_uri("/get")
|
||||||
response = HTTPX.with(ssl: { hostname: "great-gatsby.com" }).get(uri)
|
response = HTTPX.with(ssl: { hostname: "great-gatsby.com" }).get(uri)
|
||||||
assert response.is_a?(HTTPX::ErrorResponse), "response should contain errors"
|
assert response.is_a?(HTTPX::ErrorResponse), "response should contain errors"
|
||||||
assert response.error.message.include?("certificate verify failed")
|
assert response.error.message.include?("certificate verify failed"),
|
||||||
|
"unexpected error: #{response.error.message}"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user