httpclient-fixcerts 2.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +98 -0
  3. data/bin/httpclient +77 -0
  4. data/bin/jsonclient +85 -0
  5. data/lib/hexdump.rb +50 -0
  6. data/lib/http-access2/cookie.rb +1 -0
  7. data/lib/http-access2/http.rb +1 -0
  8. data/lib/http-access2.rb +55 -0
  9. data/lib/httpclient/auth.rb +924 -0
  10. data/lib/httpclient/cacert.pem +3952 -0
  11. data/lib/httpclient/cacert1024.pem +3866 -0
  12. data/lib/httpclient/connection.rb +88 -0
  13. data/lib/httpclient/cookie.rb +220 -0
  14. data/lib/httpclient/http.rb +1082 -0
  15. data/lib/httpclient/include_client.rb +85 -0
  16. data/lib/httpclient/jruby_ssl_socket.rb +594 -0
  17. data/lib/httpclient/session.rb +960 -0
  18. data/lib/httpclient/ssl_config.rb +433 -0
  19. data/lib/httpclient/ssl_socket.rb +150 -0
  20. data/lib/httpclient/timeout.rb +140 -0
  21. data/lib/httpclient/util.rb +222 -0
  22. data/lib/httpclient/version.rb +3 -0
  23. data/lib/httpclient/webagent-cookie.rb +459 -0
  24. data/lib/httpclient.rb +1332 -0
  25. data/lib/jsonclient.rb +66 -0
  26. data/lib/oauthclient.rb +111 -0
  27. data/sample/async.rb +8 -0
  28. data/sample/auth.rb +11 -0
  29. data/sample/cookie.rb +18 -0
  30. data/sample/dav.rb +103 -0
  31. data/sample/howto.rb +49 -0
  32. data/sample/jsonclient.rb +67 -0
  33. data/sample/oauth_buzz.rb +57 -0
  34. data/sample/oauth_friendfeed.rb +59 -0
  35. data/sample/oauth_twitter.rb +61 -0
  36. data/sample/ssl/0cert.pem +22 -0
  37. data/sample/ssl/0key.pem +30 -0
  38. data/sample/ssl/1000cert.pem +19 -0
  39. data/sample/ssl/1000key.pem +18 -0
  40. data/sample/ssl/htdocs/index.html +10 -0
  41. data/sample/ssl/ssl_client.rb +22 -0
  42. data/sample/ssl/webrick_httpsd.rb +29 -0
  43. data/sample/stream.rb +21 -0
  44. data/sample/thread.rb +27 -0
  45. data/sample/wcat.rb +21 -0
  46. data/test/ca-chain.pem +44 -0
  47. data/test/ca.cert +23 -0
  48. data/test/client-pass.key +18 -0
  49. data/test/client.cert +19 -0
  50. data/test/client.key +15 -0
  51. data/test/helper.rb +131 -0
  52. data/test/htdigest +1 -0
  53. data/test/htpasswd +2 -0
  54. data/test/jruby_ssl_socket/test_pemutils.rb +32 -0
  55. data/test/runner.rb +2 -0
  56. data/test/server.cert +19 -0
  57. data/test/server.key +15 -0
  58. data/test/sslsvr.rb +65 -0
  59. data/test/subca.cert +21 -0
  60. data/test/test_auth.rb +492 -0
  61. data/test/test_cookie.rb +309 -0
  62. data/test/test_hexdump.rb +14 -0
  63. data/test/test_http-access2.rb +508 -0
  64. data/test/test_httpclient.rb +2145 -0
  65. data/test/test_include_client.rb +52 -0
  66. data/test/test_jsonclient.rb +98 -0
  67. data/test/test_ssl.rb +562 -0
  68. data/test/test_webagent-cookie.rb +465 -0
  69. metadata +124 -0
@@ -0,0 +1,433 @@
1
+ # HTTPClient - HTTP client library.
2
+ # Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+ #
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ class HTTPClient
10
+
11
+ begin
12
+ require 'openssl'
13
+ SSLEnabled = true
14
+ rescue LoadError
15
+ SSLEnabled = false
16
+ end
17
+
18
+ # Represents SSL configuration for HTTPClient instance.
19
+ # The implementation depends on OpenSSL.
20
+ #
21
+ # == Trust Anchor Control
22
+ #
23
+ # SSLConfig loads 'httpclient/cacert.pem' as a trust anchor
24
+ # (trusted certificate(s)) with add_trust_ca in initialization time.
25
+ # This means that HTTPClient instance trusts some CA certificates by default,
26
+ # like Web browsers. 'httpclient/cacert.pem' is downloaded from curl web
27
+ # site by the author and included in released package.
28
+ #
29
+ # On JRuby, HTTPClient uses Java runtime's trusted CA certificates, not
30
+ # cacert.pem by default. You can load cacert.pem by calling
31
+ # SSLConfig#load_trust_ca manually like:
32
+ #
33
+ # HTTPClient.new { self.ssl_config.load_trust_ca }.get("https://...")
34
+ #
35
+ # You may want to change trust anchor by yourself. Call clear_cert_store
36
+ # then add_trust_ca for that purpose.
37
+ class SSLConfig
38
+ include HTTPClient::Util
39
+ if SSLEnabled
40
+ include OpenSSL
41
+
42
+ if defined? JRUBY_VERSION
43
+ module ::OpenSSL
44
+ module X509
45
+ class Store
46
+ attr_reader :_httpclient_cert_store_items
47
+
48
+ # TODO: use prepend instead when we drop JRuby + 1.9.x support
49
+ wrapped = {}
50
+
51
+ wrapped[:initialize] = instance_method(:initialize)
52
+ define_method(:initialize) do |*args|
53
+ wrapped[:initialize].bind(self).call(*args)
54
+ @_httpclient_cert_store_items = [ENV['SSL_CERT_FILE'] || :default]
55
+ end
56
+
57
+ [:add_cert, :add_file, :add_path].each do |m|
58
+ wrapped[m] = instance_method(m)
59
+ define_method(m) do |cert|
60
+ res = wrapped[m].bind(self).call(cert)
61
+ @_httpclient_cert_store_items << cert
62
+ res
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ class << self
72
+ private
73
+ def attr_config(symbol)
74
+ name = symbol.to_s
75
+ ivar_name = "@#{name}"
76
+ define_method(name) {
77
+ instance_variable_get(ivar_name)
78
+ }
79
+ define_method("#{name}=") { |rhs|
80
+ if instance_variable_get(ivar_name) != rhs
81
+ instance_variable_set(ivar_name, rhs)
82
+ change_notify
83
+ end
84
+ }
85
+ symbol
86
+ end
87
+ end
88
+
89
+
90
+ CIPHERS_DEFAULT = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
91
+
92
+ # Which TLS protocol version (also called method) will be used. Defaults
93
+ # to :auto which means that OpenSSL decides (In my tests this resulted
94
+ # with always the highest available protocol being used).
95
+ # String name of OpenSSL's SSL version method name: TLSv1_2, TLSv1_1, TLSv1,
96
+ # SSLv2, SSLv23, SSLv3 or :auto (and nil) to allow version negotiation (default).
97
+ # See {OpenSSL::SSL::SSLContext::METHODS} for a list of available versions
98
+ # in your specific Ruby environment.
99
+ attr_config :ssl_version
100
+ # OpenSSL::X509::Certificate:: certificate for SSL client authentication.
101
+ # nil by default. (no client authentication)
102
+ attr_config :client_cert
103
+ # OpenSSL::PKey::PKey:: private key for SSL client authentication.
104
+ # nil by default. (no client authentication)
105
+ attr_config :client_key
106
+ # OpenSSL::PKey::PKey:: private key pass phrase for client_key.
107
+ # nil by default. (no pass phrase)
108
+ attr_config :client_key_pass
109
+
110
+ # A number which represents OpenSSL's verify mode. Default value is
111
+ # OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.
112
+ attr_config :verify_mode
113
+ # A number of verify depth. Certification path which length is longer than
114
+ # this depth is not allowed.
115
+ # CAUTION: this is OpenSSL specific option and ignored on JRuby.
116
+ attr_config :verify_depth
117
+ # A callback handler for custom certificate verification. nil by default.
118
+ # If the handler is set, handler.call is invoked just after general
119
+ # OpenSSL's verification. handler.call is invoked with 2 arguments,
120
+ # ok and ctx; ok is a result of general OpenSSL's verification. ctx is a
121
+ # OpenSSL::X509::StoreContext.
122
+ attr_config :verify_callback
123
+ # SSL timeout in sec. nil by default.
124
+ attr_config :timeout
125
+ # A number of OpenSSL's SSL options. Default value is
126
+ # OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2
127
+ # CAUTION: this is OpenSSL specific option and ignored on JRuby.
128
+ # Use ssl_version to specify the TLS version you want to use.
129
+ attr_config :options
130
+ # A String of OpenSSL's cipher configuration. Default value is
131
+ # ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH
132
+ # See ciphers(1) man in OpenSSL for more detail.
133
+ attr_config :ciphers
134
+
135
+ # OpenSSL::X509::X509::Store used for verification. You can reset the
136
+ # store with clear_cert_store and set the new store with cert_store=.
137
+ attr_reader :cert_store # don't use if you don't know what it is.
138
+
139
+ # For server side configuration. Ignore this.
140
+ attr_config :client_ca # :nodoc:
141
+
142
+ # These array keeps original files/dirs that was added to @cert_store
143
+ if defined? JRUBY_VERSION
144
+ def cert_store_items; @cert_store._httpclient_cert_store_items; end
145
+ end
146
+ attr_reader :cert_store_crl_items
147
+
148
+ # Creates a SSLConfig.
149
+ def initialize(client)
150
+ return unless SSLEnabled
151
+ @client = client
152
+ @cert_store = X509::Store.new
153
+ @cert_store_crl_items = []
154
+ @client_cert = @client_key = @client_key_pass = @client_ca = nil
155
+ @verify_mode = SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
156
+ @verify_depth = nil
157
+ @verify_callback = nil
158
+ @dest = nil
159
+ @timeout = nil
160
+ @ssl_version = :auto
161
+ # Follow ruby-ossl's definition
162
+ @options = OpenSSL::SSL::OP_ALL
163
+ @options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
164
+ @options |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
165
+ @options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
166
+ @options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
167
+ # OpenSSL 0.9.8 default: "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
168
+ @ciphers = CIPHERS_DEFAULT
169
+ @cacerts_loaded = false
170
+ end
171
+
172
+ # Sets certificate and private key for SSL client authentication.
173
+ # cert_file:: must be a filename of PEM/DER formatted file.
174
+ # key_file:: must be a filename of PEM/DER formatted file. Key must be an
175
+ # RSA key. If you want to use other PKey algorithm,
176
+ # use client_key=.
177
+ #
178
+ # Calling this method resets all existing sessions if value is changed.
179
+ def set_client_cert_file(cert_file, key_file, pass = nil)
180
+ if (@client_cert != cert_file) || (@client_key != key_file) || (@client_key_pass != pass)
181
+ @client_cert, @client_key, @client_key_pass = cert_file, key_file, pass
182
+ change_notify
183
+ end
184
+ end
185
+
186
+ # Sets OpenSSL's default trusted CA certificates. Generally, OpenSSL is
187
+ # configured to use OS's trusted CA certificates located at
188
+ # /etc/pki/certs or /etc/ssl/certs. Unfortunately OpenSSL's Windows build
189
+ # does not work with Windows Certificate Storage.
190
+ #
191
+ # On Windows or when you build OpenSSL manually, you can set the
192
+ # CA certificates directory by SSL_CERT_DIR env variable at runtime.
193
+ #
194
+ # SSL_CERT_DIR=/etc/ssl/certs ruby -rhttpclient -e "..."
195
+ #
196
+ # Calling this method resets all existing sessions.
197
+ def set_default_paths
198
+ @cacerts_loaded = true # avoid lazy override
199
+ @cert_store = X509::Store.new
200
+ @cert_store.set_default_paths
201
+ change_notify
202
+ end
203
+
204
+ # Drops current certificate store (OpenSSL::X509::Store) for SSL and create
205
+ # new one for the next session.
206
+ #
207
+ # Calling this method resets all existing sessions.
208
+ def clear_cert_store
209
+ @cacerts_loaded = true # avoid lazy override
210
+ @cert_store = X509::Store.new
211
+ if defined? JRUBY_VERSION
212
+ @cert_store._httpclient_cert_store_items.clear
213
+ end
214
+ change_notify
215
+ end
216
+
217
+ # Sets new certificate store (OpenSSL::X509::Store).
218
+ # don't use if you don't know what it is.
219
+ #
220
+ # Calling this method resets all existing sessions.
221
+ def cert_store=(cert_store)
222
+ # This is object equality check, since OpenSSL::X509::Store doesn't overload ==
223
+ if !@cacerts_loaded || (@cert_store != cert_store)
224
+ @cacerts_loaded = true # avoid lazy override
225
+ @cert_store = cert_store
226
+ change_notify
227
+ end
228
+ end
229
+
230
+ # Sets trust anchor certificate(s) for verification.
231
+ # trust_ca_file_or_hashed_dir:: a filename of a PEM/DER formatted
232
+ # OpenSSL::X509::Certificate or
233
+ # a 'c-rehash'eddirectory name which stores
234
+ # trusted certificate files.
235
+ #
236
+ # Calling this method resets all existing sessions.
237
+ def add_trust_ca(trust_ca_file_or_hashed_dir)
238
+ unless File.exist?(trust_ca_file_or_hashed_dir)
239
+ trust_ca_file_or_hashed_dir = File.join(File.dirname(__FILE__), trust_ca_file_or_hashed_dir)
240
+ end
241
+ @cacerts_loaded = true # avoid lazy override
242
+ add_trust_ca_to_store(@cert_store, trust_ca_file_or_hashed_dir)
243
+ change_notify
244
+ end
245
+ alias set_trust_ca add_trust_ca
246
+
247
+ def add_trust_ca_to_store(cert_store, trust_ca_file_or_hashed_dir)
248
+ if FileTest.directory?(trust_ca_file_or_hashed_dir)
249
+ cert_store.add_path(trust_ca_file_or_hashed_dir)
250
+ else
251
+ cert_store.add_file(trust_ca_file_or_hashed_dir)
252
+ end
253
+ end
254
+
255
+ # Loads default trust anchors.
256
+ # Calling this method resets all existing sessions.
257
+ def load_trust_ca
258
+ load_cacerts(@cert_store)
259
+ change_notify
260
+ end
261
+
262
+ # Adds CRL for verification.
263
+ # crl:: a OpenSSL::X509::CRL or a filename of a PEM/DER formatted
264
+ # OpenSSL::X509::CRL.
265
+ #
266
+ # On JRuby, instead of setting CRL by yourself you can set following
267
+ # options to let HTTPClient to perform revocation check with CRL and OCSP:
268
+ # -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true
269
+ # ex. jruby -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true app.rb
270
+ #
271
+ # Revoked cert example: https://test-sspev.verisign.com:2443/test-SSPEV-revoked-verisign.html
272
+ #
273
+ # Calling this method resets all existing sessions.
274
+ def add_crl(crl)
275
+ unless crl.is_a?(X509::CRL)
276
+ crl = X509::CRL.new(File.open(crl) { |f| f.read })
277
+ end
278
+ @cert_store.add_crl(crl)
279
+ @cert_store_crl_items << crl
280
+ @cert_store.flags = X509::V_FLAG_CRL_CHECK | X509::V_FLAG_CRL_CHECK_ALL
281
+ change_notify
282
+ end
283
+ alias set_crl add_crl
284
+
285
+ def verify?
286
+ @verify_mode && (@verify_mode & OpenSSL::SSL::VERIFY_PEER != 0)
287
+ end
288
+
289
+ # interfaces for SSLSocket.
290
+ def set_context(ctx) # :nodoc:
291
+ load_trust_ca unless @cacerts_loaded
292
+ @cacerts_loaded = true
293
+ # Verification: Use Store#verify_callback instead of SSLContext#verify*?
294
+ ctx.cert_store = @cert_store
295
+ ctx.verify_mode = @verify_mode
296
+ ctx.verify_depth = @verify_depth if @verify_depth
297
+ ctx.verify_callback = @verify_callback || method(:default_verify_callback)
298
+ # SSL config
299
+ if @client_cert
300
+ ctx.cert = @client_cert.is_a?(X509::Certificate) ? @client_cert :
301
+ X509::Certificate.new(File.open(@client_cert) { |f| f.read })
302
+ end
303
+ if @client_key
304
+ ctx.key = @client_key.is_a?(PKey::PKey) ? @client_key :
305
+ PKey::RSA.new(File.open(@client_key) { |f| f.read }, @client_key_pass)
306
+ end
307
+ ctx.client_ca = @client_ca
308
+ ctx.timeout = @timeout
309
+ ctx.options = @options
310
+ ctx.ciphers = @ciphers
311
+ ctx.ssl_version = @ssl_version unless @ssl_version == :auto
312
+ end
313
+
314
+ # post connection check proc for ruby < 1.8.5.
315
+ # this definition must match with the one in ext/openssl/lib/openssl/ssl.rb
316
+ def post_connection_check(peer_cert, hostname) # :nodoc:
317
+ check_common_name = true
318
+ cert = peer_cert
319
+ cert.extensions.each{|ext|
320
+ next if ext.oid != "subjectAltName"
321
+ ext.value.split(/,\s+/).each{|general_name|
322
+ if /\ADNS:(.*)/ =~ general_name
323
+ check_common_name = false
324
+ reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
325
+ return true if /\A#{reg}\z/i =~ hostname
326
+ elsif /\AIP Address:(.*)/ =~ general_name
327
+ check_common_name = false
328
+ return true if $1 == hostname
329
+ end
330
+ }
331
+ }
332
+ if check_common_name
333
+ cert.subject.to_a.each{|oid, value|
334
+ if oid == "CN"
335
+ reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
336
+ return true if /\A#{reg}\z/i =~ hostname
337
+ end
338
+ }
339
+ end
340
+ raise SSL::SSLError, "hostname was not match with the server certificate"
341
+ end
342
+
343
+ # Default callback for verification: only dumps error.
344
+ def default_verify_callback(is_ok, ctx)
345
+ if $DEBUG
346
+ if is_ok
347
+ warn("ok: #{ctx.current_cert.subject.to_s.dump}")
348
+ else
349
+ warn("ng: #{ctx.current_cert.subject.to_s.dump} at depth #{ctx.error_depth} - #{ctx.error}: #{ctx.error_string} in #{ctx.chain.inspect}")
350
+ end
351
+ warn(ctx.current_cert.to_text)
352
+ warn(ctx.current_cert.to_pem)
353
+ end
354
+ if !is_ok
355
+ depth = ctx.error_depth
356
+ code = ctx.error
357
+ msg = ctx.error_string
358
+ warn("at depth #{depth} - #{code}: #{msg}") if $DEBUG
359
+ end
360
+ is_ok
361
+ end
362
+
363
+ # Sample callback method: CAUTION: does not check CRL/ARL.
364
+ def sample_verify_callback(is_ok, ctx)
365
+ unless is_ok
366
+ depth = ctx.error_depth
367
+ code = ctx.error
368
+ msg = ctx.error_string
369
+ warn("at depth #{depth} - #{code}: #{msg}") if $DEBUG
370
+ return false
371
+ end
372
+
373
+ cert = ctx.current_cert
374
+ self_signed = false
375
+ ca = false
376
+ pathlen = nil
377
+ server_auth = true
378
+ self_signed = (cert.subject.cmp(cert.issuer) == 0)
379
+
380
+ # Check extensions whatever its criticality is. (sample)
381
+ cert.extensions.each do |ex|
382
+ case ex.oid
383
+ when 'basicConstraints'
384
+ /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ex.value
385
+ ca = ($1 == 'TRUE')
386
+ pathlen = $2.to_i
387
+ when 'keyUsage'
388
+ usage = ex.value.split(/\s*,\s*/)
389
+ ca = usage.include?('Certificate Sign')
390
+ server_auth = usage.include?('Key Encipherment')
391
+ when 'extendedKeyUsage'
392
+ usage = ex.value.split(/\s*,\s*/)
393
+ server_auth = usage.include?('Netscape Server Gated Crypto')
394
+ when 'nsCertType'
395
+ usage = ex.value.split(/\s*,\s*/)
396
+ ca = usage.include?('SSL CA')
397
+ server_auth = usage.include?('SSL Server')
398
+ end
399
+ end
400
+
401
+ if self_signed
402
+ warn('self signing CA') if $DEBUG
403
+ return true
404
+ elsif ca
405
+ warn('middle level CA') if $DEBUG
406
+ return true
407
+ elsif server_auth
408
+ warn('for server authentication') if $DEBUG
409
+ return true
410
+ end
411
+
412
+ if pathlen > 2
413
+ warn('pathlen > 2') if $DEBUG
414
+ end
415
+ return false
416
+ end
417
+
418
+ private
419
+
420
+ def change_notify
421
+ @client.reset_all
422
+ nil
423
+ end
424
+
425
+ # Use 2048 bit certs trust anchor
426
+ def load_cacerts(cert_store)
427
+ file = File.join(File.dirname(__FILE__), 'cacert.pem')
428
+ add_trust_ca_to_store(cert_store, file)
429
+ end
430
+ end
431
+
432
+
433
+ end
@@ -0,0 +1,150 @@
1
+ # HTTPClient - HTTP client library.
2
+ # Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+ #
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ require 'httpclient/ssl_config'
10
+
11
+
12
+ class HTTPClient
13
+
14
+ # Wraps up OpenSSL::SSL::SSLSocket and offers debugging features.
15
+ class SSLSocket
16
+ def self.create_socket(session)
17
+ opts = {
18
+ :debug_dev => session.debug_dev
19
+ }
20
+ site = session.proxy || session.dest
21
+ socket = session.create_socket(site.host, site.port)
22
+ begin
23
+ if session.proxy
24
+ session.connect_ssl_proxy(socket, Util.urify(session.dest.to_s))
25
+ end
26
+ new(socket, session.dest, session.ssl_config, opts)
27
+ rescue
28
+ socket.close
29
+ raise
30
+ end
31
+ end
32
+
33
+ def initialize(socket, dest, config, opts = {})
34
+ unless SSLEnabled
35
+ raise ConfigurationError.new('Ruby/OpenSSL module is required')
36
+ end
37
+ @socket = socket
38
+ @config = config
39
+ @ssl_socket = create_openssl_socket(@socket)
40
+ @debug_dev = opts[:debug_dev]
41
+ ssl_connect(dest.host)
42
+ end
43
+
44
+ def peer_cert
45
+ @ssl_socket.peer_cert
46
+ end
47
+
48
+ def close
49
+ @ssl_socket.close
50
+ @socket.close
51
+ end
52
+
53
+ def closed?
54
+ @socket.closed?
55
+ end
56
+
57
+ def eof?
58
+ @ssl_socket.eof?
59
+ end
60
+
61
+ def gets(rs)
62
+ str = @ssl_socket.gets(rs)
63
+ debug(str)
64
+ str
65
+ end
66
+
67
+ def read(size, buf = nil)
68
+ str = @ssl_socket.read(size, buf)
69
+ debug(str)
70
+ str
71
+ end
72
+
73
+ def readpartial(size, buf = nil)
74
+ str = @ssl_socket.readpartial(size, buf)
75
+ debug(str)
76
+ str
77
+ end
78
+
79
+ def <<(str)
80
+ rv = @ssl_socket.write(str)
81
+ debug(str)
82
+ rv
83
+ end
84
+
85
+ def flush
86
+ @ssl_socket.flush
87
+ end
88
+
89
+ def sync
90
+ @ssl_socket.sync
91
+ end
92
+
93
+ def sync=(sync)
94
+ @ssl_socket.sync = sync
95
+ end
96
+
97
+ private
98
+
99
+ def ssl_connect(hostname = nil)
100
+ if hostname && @ssl_socket.respond_to?(:hostname=)
101
+ @ssl_socket.hostname = hostname
102
+ end
103
+ @ssl_socket.connect
104
+ if $DEBUG
105
+ if @ssl_socket.respond_to?(:ssl_version)
106
+ warn("Protocol version: #{@ssl_socket.ssl_version}")
107
+ end
108
+ warn("Cipher: #{@ssl_socket.cipher.inspect}")
109
+ end
110
+ post_connection_check(hostname)
111
+ end
112
+
113
+ def post_connection_check(hostname)
114
+ verify_mode = @config.verify_mode || OpenSSL::SSL::VERIFY_NONE
115
+ if verify_mode == OpenSSL::SSL::VERIFY_NONE
116
+ return
117
+ elsif @ssl_socket.peer_cert.nil? and
118
+ check_mask(verify_mode, OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT)
119
+ raise OpenSSL::SSL::SSLError.new('no peer cert')
120
+ end
121
+ if @ssl_socket.respond_to?(:post_connection_check) and RUBY_VERSION > "1.8.4"
122
+ @ssl_socket.post_connection_check(hostname)
123
+ else
124
+ @config.post_connection_check(@ssl_socket.peer_cert, hostname)
125
+ end
126
+ end
127
+
128
+ def check_mask(value, mask)
129
+ value & mask == mask
130
+ end
131
+
132
+ def create_openssl_socket(socket)
133
+ ssl_socket = nil
134
+ if OpenSSL::SSL.const_defined?("SSLContext")
135
+ ctx = OpenSSL::SSL::SSLContext.new
136
+ @config.set_context(ctx)
137
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
138
+ else
139
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
140
+ @config.set_context(ssl_socket)
141
+ end
142
+ ssl_socket
143
+ end
144
+
145
+ def debug(str)
146
+ @debug_dev << str if @debug_dev && str
147
+ end
148
+ end
149
+
150
+ end