Class: Excon::SSLSocket
Constant Summary collapse
- HAVE_NONBLOCK =
[:connect_nonblock, :read_nonblock, :write_nonblock].all? do |m| OpenSSL::SSL::SSLSocket.public_method_defined?(m) end
Constants inherited from Socket
Excon::Socket::CONNECT_RETRY_EXCEPTION_CLASSES, Excon::Socket::OPERATION_TO_TIMEOUT, Excon::Socket::READ_RETRY_EXCEPTION_CLASSES, Excon::Socket::WRITE_RETRY_EXCEPTION_CLASSES
Constants included from Utils
Utils::CONTROL, Utils::DELIMS, Utils::ESCAPED, Utils::NONASCII, Utils::UNESCAPED, Utils::UNWISE
Instance Attribute Summary
Attributes inherited from Socket
Instance Method Summary collapse
-
#initialize(data = {}) ⇒ SSLSocket
constructor
A new instance of SSLSocket.
Methods inherited from Socket
#local_address, #local_port, #params, #params=, #read, #readline, #write
Methods included from Utils
#binary_encode, #connection_uri, #default_port?, #escape_uri, #headers_hash_to_s, #port_string, #query_string, #redact, #request_uri, #split_header_value, #unescape_form, #unescape_uri
Constructor Details
#initialize(data = {}) ⇒ SSLSocket
Returns a new instance of SSLSocket.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/excon/ssl_socket.rb', line 8 def initialize(data = {}) @port = data[:port] || 443 super # create ssl context ssl_context = OpenSSL::SSL::SSLContext.new # set the security level before setting other parameters affected by it if @data[:ssl_security_level] ssl_context.security_level = @data[:ssl_security_level] end # disable less secure options, when supported = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS) &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS end if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) |= OpenSSL::SSL::OP_NO_COMPRESSION end ssl_context. = ssl_context.ciphers = @data[:ciphers] if @data[:ssl_version] ssl_context.ssl_version = @data[:ssl_version] end if @data[:ssl_min_version] ssl_context.min_version = @data[:ssl_min_version] end if @data[:ssl_max_version] ssl_context.max_version = @data[:ssl_max_version] end if @data[:ssl_verify_peer] # turn verification on ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER if (ca_file = @data[:ssl_ca_file] || ENV['SSL_CERT_FILE']) ssl_context.ca_file = ca_file end if (ca_path = @data[:ssl_ca_path] || ENV['SSL_CERT_DIR']) ssl_context.ca_path = ca_path end if (cert_store = @data[:ssl_cert_store]) ssl_context.cert_store = cert_store end if cert_store.nil? ssl_context.cert_store = OpenSSL::X509::Store.new ssl_context.cert_store.set_default_paths end # no defaults, fallback to bundled unless ca_file || ca_path || cert_store # workaround issue #257 (JRUBY-6970) ca_file = DEFAULT_CA_FILE ca_file = ca_file.gsub(/^jar:/, '') if ca_file =~ /^jar:file:\// begin ssl_context.cert_store.add_file(ca_file) rescue Excon.display_warning("Excon unable to add file to cert store, ignoring: #{ca_file}\n[#{$!.class}] #{$!.}") end end if (verify_callback = @data[:ssl_verify_callback]) ssl_context.verify_callback = verify_callback end else # turn verification off ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE end # Verify certificate hostname if supported (ruby >= 2.4.0) ssl_context.verify_hostname = @data[:ssl_verify_hostname] if ssl_context.respond_to?(:verify_hostname=) if client_cert_data && client_key_data ssl_context.cert = OpenSSL::X509::Certificate.new client_cert_data if OpenSSL::PKey.respond_to? :read ssl_context.key = OpenSSL::PKey.read(client_key_data, client_key_pass) else ssl_context.key = OpenSSL::PKey::RSA.new(client_key_data, client_key_pass) end if client_chain_data && OpenSSL::X509::Certificate.respond_to?(:load) ssl_context.extra_chain_cert = OpenSSL::X509::Certificate.load(client_chain_data) elsif client_chain_data certs = client_chain_data.scan(/-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/) ssl_context.extra_chain_cert = certs.map do |cert| OpenSSL::X509::Certificate.new(cert) end end elsif @data.key?(:certificate) && @data.key?(:private_key) ssl_context.cert = OpenSSL::X509::Certificate.new(@data[:certificate]) if OpenSSL::PKey.respond_to? :read ssl_context.key = OpenSSL::PKey.read(@data[:private_key], client_key_pass) else ssl_context.key = OpenSSL::PKey::RSA.new(@data[:private_key], client_key_pass) end end if @data[:proxy] request = "CONNECT #{@data[:host]}#{port_string(@data)}#{Excon::HTTP_1_1}" \ "Host: #{@data[:host]}#{port_string(@data)}#{Excon::CR_NL}" if @data[:proxy].has_key?(:user) || @data[:proxy].has_key?(:password) user, pass = Utils.unescape_form(@data[:proxy][:user].to_s), Utils.unescape_form(@data[:proxy][:password].to_s) auth = ["#{user}:#{pass}"].pack('m').delete(Excon::CR_NL) request += "Proxy-Authorization: Basic #{auth}#{Excon::CR_NL}" end request += "Proxy-Connection: Keep-Alive#{Excon::CR_NL}" if @data[:ssl_proxy_headers] request << Utils.headers_hash_to_s(@data[:ssl_proxy_headers]) end request += Excon::CR_NL # write out the proxy setup request @socket.write(request) # eat the proxy's connection response response = Excon::Response.parse(self, :expects => 200, :method => 'CONNECT') if response[:response][:status] != 200 raise(Excon::Errors::ProxyConnectionError.new("proxy connection could not be established", request, response)) end end # convert Socket to OpenSSL::SSL::SSLSocket @socket = OpenSSL::SSL::SSLSocket.new(@socket, ssl_context) @socket.sync_close = true # Server Name Indication (SNI) RFC 3546 if @socket.respond_to?(:hostname=) @socket.hostname = @data[:ssl_verify_peer_host] || @data[:host] end begin if @nonblock begin @socket.connect_nonblock rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable select_with_timeout(@socket, :connect_read) && retry rescue IO::WaitWritable select_with_timeout(@socket, :connect_write) && retry end else @socket.connect end rescue Errno::ETIMEDOUT, Timeout::Error raise Excon::Errors::Timeout.new('connect timeout reached') end # verify connection if @data[:ssl_verify_peer] @socket.post_connection_check(@data[:ssl_verify_peer_host] || @data[:host]) end end |