httpclient 2.1.5 → 2.8.3

Sign up to get free protection for your applications and to get access to all the features.
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