httpclient 2.1.5 → 2.8.3

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +85 -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.rb +6 -4
  7. data/lib/httpclient/auth.rb +575 -173
  8. data/lib/httpclient/cacert.pem +3952 -0
  9. data/lib/httpclient/cacert1024.pem +3866 -0
  10. data/lib/httpclient/connection.rb +6 -2
  11. data/lib/httpclient/cookie.rb +162 -504
  12. data/lib/httpclient/http.rb +334 -119
  13. data/lib/httpclient/include_client.rb +85 -0
  14. data/lib/httpclient/jruby_ssl_socket.rb +588 -0
  15. data/lib/httpclient/session.rb +385 -288
  16. data/lib/httpclient/ssl_config.rb +195 -155
  17. data/lib/httpclient/ssl_socket.rb +150 -0
  18. data/lib/httpclient/timeout.rb +14 -10
  19. data/lib/httpclient/util.rb +142 -6
  20. data/lib/httpclient/version.rb +3 -0
  21. data/lib/httpclient/webagent-cookie.rb +459 -0
  22. data/lib/httpclient.rb +509 -202
  23. data/lib/jsonclient.rb +63 -0
  24. data/lib/oauthclient.rb +111 -0
  25. data/sample/async.rb +8 -0
  26. data/sample/auth.rb +11 -0
  27. data/sample/cookie.rb +18 -0
  28. data/sample/dav.rb +103 -0
  29. data/sample/howto.rb +49 -0
  30. data/sample/jsonclient.rb +67 -0
  31. data/sample/oauth_buzz.rb +57 -0
  32. data/sample/oauth_friendfeed.rb +59 -0
  33. data/sample/oauth_twitter.rb +61 -0
  34. data/sample/ssl/0cert.pem +22 -0
  35. data/sample/ssl/0key.pem +30 -0
  36. data/sample/ssl/1000cert.pem +19 -0
  37. data/sample/ssl/1000key.pem +18 -0
  38. data/sample/ssl/htdocs/index.html +10 -0
  39. data/sample/ssl/ssl_client.rb +22 -0
  40. data/sample/ssl/webrick_httpsd.rb +29 -0
  41. data/sample/stream.rb +21 -0
  42. data/sample/thread.rb +27 -0
  43. data/sample/wcat.rb +21 -0
  44. data/test/ca-chain.pem +44 -0
  45. data/test/ca.cert +23 -0
  46. data/test/client-pass.key +18 -0
  47. data/test/client.cert +19 -0
  48. data/test/client.key +15 -0
  49. data/test/helper.rb +131 -0
  50. data/test/htdigest +1 -0
  51. data/test/htpasswd +2 -0
  52. data/test/jruby_ssl_socket/test_pemutils.rb +32 -0
  53. data/test/runner.rb +2 -0
  54. data/test/server.cert +19 -0
  55. data/test/server.key +15 -0
  56. data/test/sslsvr.rb +65 -0
  57. data/test/subca.cert +21 -0
  58. data/test/test_auth.rb +492 -0
  59. data/test/test_cookie.rb +309 -0
  60. data/test/test_hexdump.rb +14 -0
  61. data/test/test_http-access2.rb +508 -0
  62. data/test/test_httpclient.rb +2145 -0
  63. data/test/test_include_client.rb +52 -0
  64. data/test/test_jsonclient.rb +80 -0
  65. data/test/test_ssl.rb +559 -0
  66. data/test/test_webagent-cookie.rb +465 -0
  67. metadata +85 -44
  68. data/lib/httpclient/auth.rb.orig +0 -513
  69. data/lib/httpclient/cacert.p7s +0 -1579
  70. data/lib/httpclient.rb.orig +0 -1020
  71. data/lib/tags +0 -908
@@ -1,5 +1,5 @@
1
1
  # HTTPClient - HTTP client library.
2
- # Copyright (C) 2000-2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
2
+ # Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
3
  #
4
4
  # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
5
  # redistribute it and/or modify it under the same terms of Ruby's license;
@@ -20,88 +20,149 @@ class HTTPClient
20
20
  #
21
21
  # == Trust Anchor Control
22
22
  #
23
- # SSLConfig loads 'httpclient/cacert.p7s' as a trust anchor
24
- # (trusted certificate(s)) with set_trust_ca in initialization time.
23
+ # SSLConfig loads 'httpclient/cacert.pem' as a trust anchor
24
+ # (trusted certificate(s)) with add_trust_ca in initialization time.
25
25
  # This means that HTTPClient instance trusts some CA certificates by default,
26
- # like Web browsers. 'httpclient/cacert.p7s' is created by the author and
27
- # included in released package.
26
+ # like Web browsers. 'httpclient/cacert.pem' is downloaded from curl web
27
+ # site by the author and included in released package.
28
28
  #
29
- # 'cacert.p7s' is automatically generated from JDK 1.6.
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://...")
30
34
  #
31
35
  # You may want to change trust anchor by yourself. Call clear_cert_store
32
- # then set_trust_ca for that purpose.
36
+ # then add_trust_ca for that purpose.
33
37
  class SSLConfig
34
- include OpenSSL if SSLEnabled
38
+ include HTTPClient::Util
39
+ if SSLEnabled
40
+ include OpenSSL
41
+
42
+ module ::OpenSSL
43
+ module X509
44
+ class Store
45
+ attr_reader :_httpclient_cert_store_items
46
+
47
+ # TODO: use prepend instead when we drop JRuby + 1.9.x support
48
+ wrapped = {}
49
+
50
+ wrapped[:initialize] = instance_method(:initialize)
51
+ define_method(:initialize) do |*args|
52
+ wrapped[:initialize].bind(self).call(*args)
53
+ @_httpclient_cert_store_items = [ENV['SSL_CERT_FILE'] || :default]
54
+ end
55
+
56
+ [:add_cert, :add_file, :add_path].each do |m|
57
+ wrapped[m] = instance_method(m)
58
+ define_method(m) do |cert|
59
+ res = wrapped[m].bind(self).call(cert)
60
+ @_httpclient_cert_store_items << cert
61
+ res
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ class << self
70
+ private
71
+ def attr_config(symbol)
72
+ name = symbol.to_s
73
+ ivar_name = "@#{name}"
74
+ define_method(name) {
75
+ instance_variable_get(ivar_name)
76
+ }
77
+ define_method("#{name}=") { |rhs|
78
+ if instance_variable_get(ivar_name) != rhs
79
+ instance_variable_set(ivar_name, rhs)
80
+ change_notify
81
+ end
82
+ }
83
+ symbol
84
+ end
85
+ end
86
+
87
+
88
+ CIPHERS_DEFAULT = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
35
89
 
36
- # OpenSSL::X509::Certificate:: certificate for SSL client authenticateion.
37
- # nil by default. (no client authenticateion)
38
- attr_reader :client_cert
90
+ # Which TLS protocol version (also called method) will be used. Defaults
91
+ # to :auto which means that OpenSSL decides (In my tests this resulted
92
+ # with always the highest available protocol being used).
93
+ # String name of OpenSSL's SSL version method name: TLSv1_2, TLSv1_1, TLSv1,
94
+ # SSLv2, SSLv23, SSLv3 or :auto (and nil) to allow version negotiation (default).
95
+ # See {OpenSSL::SSL::SSLContext::METHODS} for a list of available versions
96
+ # in your specific Ruby environment.
97
+ attr_config :ssl_version
98
+ # OpenSSL::X509::Certificate:: certificate for SSL client authentication.
99
+ # nil by default. (no client authentication)
100
+ attr_config :client_cert
39
101
  # OpenSSL::PKey::PKey:: private key for SSL client authentication.
40
- # nil by default. (no client authenticateion)
41
- attr_reader :client_key
102
+ # nil by default. (no client authentication)
103
+ attr_config :client_key
104
+ # OpenSSL::PKey::PKey:: private key pass phrase for client_key.
105
+ # nil by default. (no pass phrase)
106
+ attr_config :client_key_pass
42
107
 
43
108
  # A number which represents OpenSSL's verify mode. Default value is
44
109
  # OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.
45
- attr_reader :verify_mode
110
+ attr_config :verify_mode
46
111
  # A number of verify depth. Certification path which length is longer than
47
112
  # this depth is not allowed.
48
- attr_reader :verify_depth
113
+ # CAUTION: this is OpenSSL specific option and ignored on JRuby.
114
+ attr_config :verify_depth
49
115
  # A callback handler for custom certificate verification. nil by default.
50
116
  # If the handler is set, handler.call is invoked just after general
51
117
  # OpenSSL's verification. handler.call is invoked with 2 arguments,
52
118
  # ok and ctx; ok is a result of general OpenSSL's verification. ctx is a
53
119
  # OpenSSL::X509::StoreContext.
54
- attr_reader :verify_callback
120
+ attr_config :verify_callback
55
121
  # SSL timeout in sec. nil by default.
56
- attr_reader :timeout
122
+ attr_config :timeout
57
123
  # A number of OpenSSL's SSL options. Default value is
58
124
  # OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2
59
- attr_reader :options
125
+ # CAUTION: this is OpenSSL specific option and ignored on JRuby.
126
+ # Use ssl_version to specify the TLS version you want to use.
127
+ attr_config :options
60
128
  # A String of OpenSSL's cipher configuration. Default value is
61
129
  # ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH
62
130
  # See ciphers(1) man in OpenSSL for more detail.
63
- attr_reader :ciphers
131
+ attr_config :ciphers
64
132
 
65
133
  # OpenSSL::X509::X509::Store used for verification. You can reset the
66
134
  # store with clear_cert_store and set the new store with cert_store=.
67
135
  attr_reader :cert_store # don't use if you don't know what it is.
68
136
 
69
137
  # For server side configuration. Ignore this.
70
- attr_reader :client_ca # :nodoc:
138
+ attr_config :client_ca # :nodoc:
139
+
140
+ # These array keeps original files/dirs that was added to @cert_store
141
+ def cert_store_items; @cert_store._httpclient_cert_store_items; end
142
+ attr_reader :cert_store_crl_items
71
143
 
72
144
  # Creates a SSLConfig.
73
145
  def initialize(client)
74
146
  return unless SSLEnabled
75
147
  @client = client
76
148
  @cert_store = X509::Store.new
77
- @client_cert = @client_key = @client_ca = nil
149
+ @cert_store_crl_items = []
150
+ @client_cert = @client_key = @client_key_pass = @client_ca = nil
78
151
  @verify_mode = SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
79
152
  @verify_depth = nil
80
153
  @verify_callback = nil
81
154
  @dest = nil
82
155
  @timeout = nil
83
- @options = defined?(SSL::OP_ALL) ? SSL::OP_ALL | SSL::OP_NO_SSLv2 : nil
84
- @ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
85
- load_cacerts
86
- end
87
-
88
- # Sets certificate (OpenSSL::X509::Certificate) for SSL client
89
- # authentication.
90
- # client_key and client_cert must be a pair.
91
- #
92
- # Calling this method resets all existing sessions.
93
- def client_cert=(client_cert)
94
- @client_cert = client_cert
95
- change_notify
96
- end
97
-
98
- # Sets private key (OpenSSL::PKey::PKey) for SSL client authentication.
99
- # client_key and client_cert must be a pair.
100
- #
101
- # Calling this method resets all existing sessions.
102
- def client_key=(client_key)
103
- @client_key = client_key
104
- change_notify
156
+ @ssl_version = :auto
157
+ # Follow ruby-ossl's definition
158
+ @options = OpenSSL::SSL::OP_ALL
159
+ @options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
160
+ @options |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
161
+ @options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
162
+ @options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
163
+ # OpenSSL 0.9.8 default: "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
164
+ @ciphers = CIPHERS_DEFAULT
165
+ @cacerts_loaded = false
105
166
  end
106
167
 
107
168
  # Sets certificate and private key for SSL client authentication.
@@ -110,10 +171,29 @@ class HTTPClient
110
171
  # RSA key. If you want to use other PKey algorithm,
111
172
  # use client_key=.
112
173
  #
174
+ # Calling this method resets all existing sessions if value is changed.
175
+ def set_client_cert_file(cert_file, key_file, pass = nil)
176
+ if (@client_cert != cert_file) || (@client_key != key_file) || (@client_key_pass != pass)
177
+ @client_cert, @client_key, @client_key_pass = cert_file, key_file, pass
178
+ change_notify
179
+ end
180
+ end
181
+
182
+ # Sets OpenSSL's default trusted CA certificates. Generally, OpenSSL is
183
+ # configured to use OS's trusted CA certificates located at
184
+ # /etc/pki/certs or /etc/ssl/certs. Unfortunately OpenSSL's Windows build
185
+ # does not work with Windows Certificate Storage.
186
+ #
187
+ # On Windows or when you build OpenSSL manually, you can set the
188
+ # CA certificates directory by SSL_CERT_DIR env variable at runtime.
189
+ #
190
+ # SSL_CERT_DIR=/etc/ssl/certs ruby -rhttpclient -e "..."
191
+ #
113
192
  # Calling this method resets all existing sessions.
114
- def set_client_cert_file(cert_file, key_file)
115
- @client_cert = X509::Certificate.new(File.open(cert_file).read)
116
- @client_key = PKey::RSA.new(File.open(key_file).read)
193
+ def set_default_paths
194
+ @cacerts_loaded = true # avoid lazy override
195
+ @cert_store = X509::Store.new
196
+ @cert_store.set_default_paths
117
197
  change_notify
118
198
  end
119
199
 
@@ -122,7 +202,9 @@ class HTTPClient
122
202
  #
123
203
  # Calling this method resets all existing sessions.
124
204
  def clear_cert_store
205
+ @cacerts_loaded = true # avoid lazy override
125
206
  @cert_store = X509::Store.new
207
+ @cert_store._httpclient_cert_store_items.clear
126
208
  change_notify
127
209
  end
128
210
 
@@ -131,8 +213,12 @@ class HTTPClient
131
213
  #
132
214
  # Calling this method resets all existing sessions.
133
215
  def cert_store=(cert_store)
134
- @cert_store = cert_store
135
- change_notify
216
+ # This is object equality check, since OpenSSL::X509::Store doesn't overload ==
217
+ if !@cacerts_loaded || (@cert_store != cert_store)
218
+ @cacerts_loaded = true # avoid lazy override
219
+ @cert_store = cert_store
220
+ change_notify
221
+ end
136
222
  end
137
223
 
138
224
  # Sets trust anchor certificate(s) for verification.
@@ -142,99 +228,81 @@ class HTTPClient
142
228
  # trusted certificate files.
143
229
  #
144
230
  # Calling this method resets all existing sessions.
145
- def set_trust_ca(trust_ca_file_or_hashed_dir)
146
- if FileTest.directory?(trust_ca_file_or_hashed_dir)
147
- @cert_store.add_path(trust_ca_file_or_hashed_dir)
148
- else
149
- @cert_store.add_file(trust_ca_file_or_hashed_dir)
231
+ def add_trust_ca(trust_ca_file_or_hashed_dir)
232
+ unless File.exist?(trust_ca_file_or_hashed_dir)
233
+ trust_ca_file_or_hashed_dir = File.join(File.dirname(__FILE__), trust_ca_file_or_hashed_dir)
150
234
  end
235
+ @cacerts_loaded = true # avoid lazy override
236
+ add_trust_ca_to_store(@cert_store, trust_ca_file_or_hashed_dir)
151
237
  change_notify
152
238
  end
239
+ alias set_trust_ca add_trust_ca
153
240
 
154
- # Adds CRL for verification.
155
- # crl:: a OpenSSL::X509::CRL or a filename of a PEM/DER formatted
156
- # OpenSSL::X509::CRL.
157
- #
158
- # Calling this method resets all existing sessions.
159
- def set_crl(crl)
160
- unless crl.is_a?(X509::CRL)
161
- crl = X509::CRL.new(File.open(crl).read)
241
+ def add_trust_ca_to_store(cert_store, trust_ca_file_or_hashed_dir)
242
+ if FileTest.directory?(trust_ca_file_or_hashed_dir)
243
+ cert_store.add_path(trust_ca_file_or_hashed_dir)
244
+ else
245
+ cert_store.add_file(trust_ca_file_or_hashed_dir)
162
246
  end
163
- @cert_store.add_crl(crl)
164
- @cert_store.flags = X509::V_FLAG_CRL_CHECK | X509::V_FLAG_CRL_CHECK_ALL
165
- change_notify
166
- end
167
-
168
- # Sets verify mode of OpenSSL. New value must be a combination of
169
- # constants OpenSSL::SSL::VERIFY_*
170
- #
171
- # Calling this method resets all existing sessions.
172
- def verify_mode=(verify_mode)
173
- @verify_mode = verify_mode
174
- change_notify
175
- end
176
-
177
- # Sets verify depth. New value must be a number.
178
- #
179
- # Calling this method resets all existing sessions.
180
- def verify_depth=(verify_depth)
181
- @verify_depth = verify_depth
182
- change_notify
183
247
  end
184
248
 
185
- # Sets callback handler for custom certificate verification.
186
- # See verify_callback.
187
- #
249
+ # Loads default trust anchors.
188
250
  # Calling this method resets all existing sessions.
189
- def verify_callback=(verify_callback)
190
- @verify_callback = verify_callback
251
+ def load_trust_ca
252
+ load_cacerts(@cert_store)
191
253
  change_notify
192
254
  end
193
255
 
194
- # Sets SSL timeout in sec.
256
+ # Adds CRL for verification.
257
+ # crl:: a OpenSSL::X509::CRL or a filename of a PEM/DER formatted
258
+ # OpenSSL::X509::CRL.
195
259
  #
196
- # Calling this method resets all existing sessions.
197
- def timeout=(timeout)
198
- @timeout = timeout
199
- change_notify
200
- end
201
-
202
- # Sets SSL options. New value must be a combination of # constants
203
- # OpenSSL::SSL::OP_*
260
+ # On JRuby, instead of setting CRL by yourself you can set following
261
+ # options to let HTTPClient to perform revocation check with CRL and OCSP:
262
+ # -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true
263
+ # ex. jruby -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true app.rb
204
264
  #
205
- # Calling this method resets all existing sessions.
206
- def options=(options)
207
- @options = options
208
- change_notify
209
- end
210
-
211
- # Sets cipher configuration. New value must be a String.
265
+ # Revoked cert example: https://test-sspev.verisign.com:2443/test-SSPEV-revoked-verisign.html
212
266
  #
213
267
  # Calling this method resets all existing sessions.
214
- def ciphers=(ciphers)
215
- @ciphers = ciphers
268
+ def add_crl(crl)
269
+ unless crl.is_a?(X509::CRL)
270
+ crl = X509::CRL.new(File.open(crl) { |f| f.read })
271
+ end
272
+ @cert_store.add_crl(crl)
273
+ @cert_store_crl_items << crl
274
+ @cert_store.flags = X509::V_FLAG_CRL_CHECK | X509::V_FLAG_CRL_CHECK_ALL
216
275
  change_notify
217
276
  end
277
+ alias set_crl add_crl
218
278
 
219
- def client_ca=(client_ca) # :nodoc:
220
- @client_ca = client_ca
221
- change_notify
279
+ def verify?
280
+ @verify_mode && (@verify_mode & OpenSSL::SSL::VERIFY_PEER != 0)
222
281
  end
223
282
 
224
- # interfaces for SSLSocketWrap.
283
+ # interfaces for SSLSocket.
225
284
  def set_context(ctx) # :nodoc:
285
+ load_trust_ca unless @cacerts_loaded
286
+ @cacerts_loaded = true
226
287
  # Verification: Use Store#verify_callback instead of SSLContext#verify*?
227
288
  ctx.cert_store = @cert_store
228
289
  ctx.verify_mode = @verify_mode
229
290
  ctx.verify_depth = @verify_depth if @verify_depth
230
291
  ctx.verify_callback = @verify_callback || method(:default_verify_callback)
231
292
  # SSL config
232
- ctx.cert = @client_cert
233
- ctx.key = @client_key
293
+ if @client_cert
294
+ ctx.cert = @client_cert.is_a?(X509::Certificate) ? @client_cert :
295
+ X509::Certificate.new(File.open(@client_cert) { |f| f.read })
296
+ end
297
+ if @client_key
298
+ ctx.key = @client_key.is_a?(PKey::PKey) ? @client_key :
299
+ PKey::RSA.new(File.open(@client_key) { |f| f.read }, @client_key_pass)
300
+ end
234
301
  ctx.client_ca = @client_ca
235
302
  ctx.timeout = @timeout
236
303
  ctx.options = @options
237
304
  ctx.ciphers = @ciphers
305
+ ctx.ssl_version = @ssl_version unless @ssl_version == :auto
238
306
  end
239
307
 
240
308
  # post connection check proc for ruby < 1.8.5.
@@ -269,13 +337,19 @@ class HTTPClient
269
337
  # Default callback for verification: only dumps error.
270
338
  def default_verify_callback(is_ok, ctx)
271
339
  if $DEBUG
272
- puts "#{ is_ok ? 'ok' : 'ng' }: #{ctx.current_cert.subject}"
340
+ if is_ok
341
+ warn("ok: #{ctx.current_cert.subject.to_s.dump}")
342
+ else
343
+ warn("ng: #{ctx.current_cert.subject.to_s.dump} at depth #{ctx.error_depth} - #{ctx.error}: #{ctx.error_string} in #{ctx.chain.inspect}")
344
+ end
345
+ warn(ctx.current_cert.to_text)
346
+ warn(ctx.current_cert.to_pem)
273
347
  end
274
348
  if !is_ok
275
349
  depth = ctx.error_depth
276
350
  code = ctx.error
277
351
  msg = ctx.error_string
278
- STDERR.puts "at depth #{depth} - #{code}: #{msg}"
352
+ warn("at depth #{depth} - #{code}: #{msg}") if $DEBUG
279
353
  end
280
354
  is_ok
281
355
  end
@@ -286,7 +360,7 @@ class HTTPClient
286
360
  depth = ctx.error_depth
287
361
  code = ctx.error
288
362
  msg = ctx.error_string
289
- STDERR.puts "at depth #{depth} - #{code}: #{msg}" if $DEBUG
363
+ warn("at depth #{depth} - #{code}: #{msg}") if $DEBUG
290
364
  return false
291
365
  end
292
366
 
@@ -319,13 +393,13 @@ class HTTPClient
319
393
  end
320
394
 
321
395
  if self_signed
322
- STDERR.puts 'self signing CA' if $DEBUG
396
+ warn('self signing CA') if $DEBUG
323
397
  return true
324
398
  elsif ca
325
- STDERR.puts 'middle level CA' if $DEBUG
399
+ warn('middle level CA') if $DEBUG
326
400
  return true
327
401
  elsif server_auth
328
- STDERR.puts 'for server authentication' if $DEBUG
402
+ warn('for server authentication') if $DEBUG
329
403
  return true
330
404
  end
331
405
 
@@ -336,47 +410,13 @@ class HTTPClient
336
410
 
337
411
  def change_notify
338
412
  @client.reset_all
413
+ nil
339
414
  end
340
415
 
341
- def load_cacerts
342
- file = File.join(File.dirname(__FILE__), 'cacert.p7s')
343
- if File.exist?(file)
344
- dist_cert =<<__DIST_CERT__
345
- -----BEGIN CERTIFICATE-----
346
- MIID/TCCAuWgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBLMQswCQYDVQQGEwJKUDER
347
- MA8GA1UECgwIY3Rvci5vcmcxFDASBgNVBAsMC0RldmVsb3BtZW50MRMwEQYDVQQD
348
- DApodHRwY2xpZW50MB4XDTA5MDUyMTEyMzkwNVoXDTM3MTIzMTIzNTk1OVowSzEL
349
- MAkGA1UEBhMCSlAxETAPBgNVBAoMCGN0b3Iub3JnMRQwEgYDVQQLDAtEZXZlbG9w
350
- bWVudDETMBEGA1UEAwwKaHR0cGNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEP
351
- ADCCAQoCggEBAM2PlkdTH97zvIHoPIMj87wnNvpqIQUD7L/hlysO0XBsmR/XZUeU
352
- ZKB10JQqMXviWpTnU9KU6xGTx3EI4wfd2dpLwH/d4d7K4LngW1kY7kJlZeJhakno
353
- GzQ40RSI9WkQ0R9KOE888f7OkTBafcL8UyWFVIMhQBw2d9iNl4Jc69QojayCDoSX
354
- XbbEP0n8yi7HwIU3RFuX6DtMpOx4/1K7Z002ccOGJ3J9kHgeDQSQtF42cQYC7qj2
355
- 67I/OQgnB7ycxTCP0E7bdXQg+zqsngrhaoNn/+I+CoO7nD4t4uQ+B4agALh4PPxs
356
- bQD9MCL+VurNGLYv0HVd+ZlLblpddC9PLTsCAwEAAaOB6zCB6DAPBgNVHRMBAf8E
357
- BTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09wZW5TU0wgR2VuZXJhdGVkIENl
358
- cnRpZmljYXRlMB0GA1UdDgQWBBRAnB6XlMoOcm7HVAw+JWxY205PHTAOBgNVHQ8B
359
- Af8EBAMCAQYwcwYDVR0jBGwwaoAUQJwel5TKDnJux1QMPiVsWNtOTx2hT6RNMEsx
360
- CzAJBgNVBAYTAkpQMREwDwYDVQQKDAhjdG9yLm9yZzEUMBIGA1UECwwLRGV2ZWxv
361
- cG1lbnQxEzARBgNVBAMMCmh0dHBjbGllbnSCAQEwDQYJKoZIhvcNAQENBQADggEB
362
- ABVFepybD5XqsBnOn/oDHvK0xAPMF4Ap4Ht1yMQLObg8paVhANSdqIevPlCr/mPL
363
- DRjcy+J1fCnE6lCfsfLdTgAjirqt8pm92NccxmJ8hTmMd3LWC1n+eYWaolqTCVRM
364
- Bpe8UY9enyXrFoudHlr9epr18E6As6VrCSfpXFZkD9WHVSWpzkB3qATu5qcDCzCH
365
- bI0755Mdm/1hKJCD4l69h3J3OhRIEUPJfHnPvM5wtiyC2dcE9itwE/wdVzBJeIBX
366
- JQm+Qj+K8qXcRTzZZGIBjw2n46xJgW6YncNCHU/WWfNCYwdkngHS/aN8IbEjhCwf
367
- viXFisVrDN/+pZZGMf67ZaY=
368
- -----END CERTIFICATE-----
369
- __DIST_CERT__
370
- p7 = PKCS7.read_smime(File.open(file) { |f| f.read })
371
- selfcert = X509::Certificate.new(dist_cert)
372
- store = X509::Store.new
373
- store.add_cert(selfcert)
374
- if (p7.verify(nil, store, p7.data, 0))
375
- set_trust_ca(file)
376
- else
377
- STDERR.puts("cacerts: #{file} loading failed")
378
- end
379
- end
416
+ # Use 2048 bit certs trust anchor
417
+ def load_cacerts(cert_store)
418
+ file = File.join(File.dirname(__FILE__), 'cacert.pem')
419
+ add_trust_ca_to_store(cert_store, file)
380
420
  end
381
421
  end
382
422
 
@@ -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