httpclient-fixcerts 2.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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