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
data/test/test_ssl.rb ADDED
@@ -0,0 +1,562 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+ require 'webrick/https'
3
+ require 'time'
4
+
5
+
6
+ class TestSSL < Test::Unit::TestCase
7
+ include Helper
8
+
9
+ DIR = File.dirname(File.expand_path(__FILE__))
10
+
11
+ def setup
12
+ super
13
+ @serverpid = @client = nil
14
+ @verify_callback_called = false
15
+ setup_server
16
+ setup_client
17
+ @url = "https://localhost:#{serverport}/hello"
18
+ end
19
+
20
+ def teardown
21
+ super
22
+ end
23
+
24
+ def path(filename)
25
+ File.expand_path(filename, DIR)
26
+ end
27
+
28
+ def test_proxy_ssl
29
+ setup_proxyserver
30
+ escape_noproxy do
31
+ @client.proxy = proxyurl
32
+ @client.ssl_config.set_client_cert_file(path('client.cert'), path('client.key'))
33
+ @client.ssl_config.add_trust_ca(path('ca.cert'))
34
+ @client.ssl_config.add_trust_ca(path('subca.cert'))
35
+ @client.debug_dev = str = ""
36
+ assert_equal(200, @client.get(@url).status)
37
+ assert(/accept/ =~ @proxyio.string, 'proxy is not used')
38
+ assert(/Host: localhost:#{serverport}/ =~ str)
39
+ end
40
+ end
41
+
42
+ def test_options
43
+ cfg = @client.ssl_config
44
+ assert_nil(cfg.client_cert)
45
+ assert_nil(cfg.client_key)
46
+ assert_nil(cfg.client_ca)
47
+ assert_equal(OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT, cfg.verify_mode)
48
+ assert_nil(cfg.verify_callback)
49
+ assert_nil(cfg.timeout)
50
+ expected_options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
51
+ expected_options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
52
+ expected_options |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
53
+ assert_equal(expected_options, cfg.options)
54
+ assert_equal("ALL:!aNULL:!eNULL:!SSLv2", cfg.ciphers)
55
+ assert_instance_of(OpenSSL::X509::Store, cfg.cert_store)
56
+ end
57
+
58
+ unless defined?(HTTPClient::JRubySSLSocket)
59
+ # JRubySSLSocket does not support sync mode.
60
+ def test_sync
61
+ cfg = @client.ssl_config
62
+ cfg.set_client_cert_file(path('client.cert'), path('client.key'))
63
+ cfg.add_trust_ca(path('ca.cert'))
64
+ cfg.add_trust_ca(path('subca.cert'))
65
+ assert_equal("hello", @client.get_content(@url))
66
+
67
+ @client.socket_sync = false
68
+ @client.reset_all
69
+ assert_equal("hello", @client.get_content(@url))
70
+ end
71
+ end
72
+
73
+ def test_debug_dev
74
+ str = @client.debug_dev = ''
75
+ cfg = @client.ssl_config
76
+ cfg.client_cert = path("client.cert")
77
+ cfg.client_key = path("client.key")
78
+ cfg.add_trust_ca(path('ca.cert'))
79
+ cfg.add_trust_ca(path('subca.cert'))
80
+ assert_equal("hello", @client.get_content(@url))
81
+ assert(str.scan(/^hello$/)[0])
82
+ end
83
+
84
+ def test_verification_without_httpclient
85
+ raw_cert = "-----BEGIN CERTIFICATE-----\nMIIDKDCCAhCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES\nMBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X\nDTA0MDEzMTAzMTQ1OFoXDTM1MDEyMzAzMTQ1OFowZTELMAkGA1UEBgwCSlAxEjAQ\nBgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMRAwDgYDVQQDDAdleGFtcGxl\nMSIwIAYJKoZIhvcNAQkBDBNleGFtcGxlQGV4YW1wbGUub3JnMIGfMA0GCSqGSIb3\nDQEBAQUAA4GNADCBiQKBgQDRWssrK8Gyr+500hpLjCGR3+AHL8/hEJM5zKi/MgLW\njTkvsgOwbYwXOiNtAbR9y4/ucDq7EY+cMUMHES4uFaPTcOaAV0aZRmk8AgslN1tQ\ngNS6ew7/Luq3DcVeWkX8PYgR9VG0mD1MPfJ6+IFA5d3vKpdBkBgN4l46jjO0/2Xf\newIDAQABo4GPMIGMMAwGA1UdEwEB/wQCMAAwMQYJYIZIAYb4QgENBCQWIlJ1Ynkv\nT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFOFvay0H7lr2\nxUx6waYEV2bVDYQhMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYI\nKwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADggEBABd2dYWqbDIWf5sWFvslezxJv8gI\nw64KCJBuyJAiDuf+oazr3016kMzAlt97KecLZDusGNagPrq02UX7YMoQFsWJBans\ncDtHrkM0al5r6/WGexNMgtYbNTYzt/IwodISGBgZ6dsOuhznwms+IBsTNDAvWeLP\nlt2tOqD8kEmjwMgn0GDRuKjs4EoboA3kMULb1p9akDV9ZESU3eOtpS5/G5J5msLI\n9WXbYBjcjvkLuJH9VsJhb+R58Vl0ViemvAHhPilSl1SPWVunGhv6FcIkdBEi1k9F\ne8BNMmsEjFiANiIRvpdLRbiGBt0KrKTndVfsmoKCvY48oCOvnzxtahFxfs8=\n-----END CERTIFICATE-----"
86
+ raw_ca_cert = "-----BEGIN CERTIFICATE-----\nMIID0DCCArigAwIBAgIBADANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES\nMBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X\nDTA0MDEzMDAwNDIzMloXDTM2MDEyMjAwNDIzMlowPDELMAkGA1UEBgwCSlAxEjAQ\nBgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMQswCQYDVQQDDAJDQTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANbv0x42BTKFEQOE+KJ2XmiSdZpR\nwjzQLAkPLRnLB98tlzs4xo+y4RyY/rd5TT9UzBJTIhP8CJi5GbS1oXEerQXB3P0d\nL5oSSMwGGyuIzgZe5+vZ1kgzQxMEKMMKlzA73rbMd4Jx3u5+jdbP0EDrPYfXSvLY\nbS04n2aX7zrN3x5KdDrNBfwBio2/qeaaj4+9OxnwRvYP3WOvqdW0h329eMfHw0pi\nJI0drIVdsEqClUV4pebT/F+CPUPkEh/weySgo9wANockkYu5ujw2GbLFcO5LXxxm\ndEfcVr3r6t6zOA4bJwL0W/e6LBcrwiG/qPDFErhwtgTLYf6Er67SzLyA66UCAwEA\nAaOB3DCB2TAPBgNVHRMBAf8EBTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09w\nZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRJ7Xd380KzBV7f\nUSKIQ+O/vKbhDzAOBgNVHQ8BAf8EBAMCAQYwZAYDVR0jBF0wW4AUSe13d/NCswVe\n31EiiEPjv7ym4Q+hQKQ+MDwxCzAJBgNVBAYMAkpQMRIwEAYDVQQKDAlKSU4uR1Iu\nSlAxDDAKBgNVBAsMA1JSUjELMAkGA1UEAwwCQ0GCAQAwDQYJKoZIhvcNAQEFBQAD\nggEBAIu/mfiez5XN5tn2jScgShPgHEFJBR0BTJBZF6xCk0jyqNx/g9HMj2ELCuK+\nr/Y7KFW5c5M3AQ+xWW0ZSc4kvzyTcV7yTVIwj2jZ9ddYMN3nupZFgBK1GB4Y05GY\nMJJFRkSu6d/Ph5ypzBVw2YMT/nsOo5VwMUGLgS7YVjU+u/HNWz80J3oO17mNZllj\nPvORJcnjwlroDnS58KoJ7GDgejv3ESWADvX1OHLE4cRkiQGeLoEU4pxdCxXRqX0U\nPbwIkZN9mXVcrmPHq8MWi4eC/V7hnbZETMHuWhUoiNdOEfsAXr3iP4KjyyRdwc7a\nd/xgcK06UVQRL/HbEYGiQL056mc=\n-----END CERTIFICATE-----"
87
+ ca_cert = ::OpenSSL::X509::Certificate.new(raw_ca_cert)
88
+ cert = ::OpenSSL::X509::Certificate.new(raw_cert)
89
+ store = ::OpenSSL::X509::Store.new
90
+ store.add_cert(ca_cert)
91
+ store.time = Time.new(2017, 01, 01)
92
+ assert(store.verify(cert), "Verify failed: #{store.error_string}, #{store.error}")
93
+ end
94
+
95
+ def test_verification
96
+ cfg = @client.ssl_config
97
+ cfg.verify_callback = method(:verify_callback).to_proc
98
+ begin
99
+ @verify_callback_called = false
100
+ @client.get(@url)
101
+ assert(false)
102
+ rescue OpenSSL::SSL::SSLError => ssle
103
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
104
+ assert(@verify_callback_called)
105
+ end
106
+ #
107
+ cfg.client_cert = path("client.cert")
108
+ cfg.client_key = path("client.key")
109
+ @verify_callback_called = false
110
+ begin
111
+ @client.get(@url)
112
+ assert(false)
113
+ rescue OpenSSL::SSL::SSLError => ssle
114
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
115
+ assert(@verify_callback_called)
116
+ end
117
+ #
118
+ cfg.add_trust_ca(path('ca.cert'))
119
+ @verify_callback_called = false
120
+ begin
121
+ @client.get(@url)
122
+ assert(false)
123
+ rescue OpenSSL::SSL::SSLError => ssle
124
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
125
+ assert(@verify_callback_called)
126
+ end
127
+ #
128
+ cfg.add_trust_ca(path('subca.cert'))
129
+ @verify_callback_called = false
130
+ assert_equal("hello", @client.get_content(@url))
131
+ assert(@verify_callback_called)
132
+ #
133
+ if false
134
+ # JRubySSLSocket does not support depth.
135
+ # Also on travis environment, verify_depth seems to not work properly.
136
+ cfg.verify_depth = 1 # 2 required: root-sub
137
+ @verify_callback_called = false
138
+ begin
139
+ @client.get(@url)
140
+ assert(false, "verify_depth is not supported? #{OpenSSL::OPENSSL_VERSION}")
141
+ rescue OpenSSL::SSL::SSLError => ssle
142
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
143
+ assert(@verify_callback_called)
144
+ end
145
+ #
146
+ cfg.verify_depth = 2 # 2 required: root-sub
147
+ @verify_callback_called = false
148
+ @client.get(@url)
149
+ assert(@verify_callback_called)
150
+ #
151
+ end
152
+ cfg.verify_depth = nil
153
+ cfg.cert_store = OpenSSL::X509::Store.new
154
+ cfg.verify_mode = OpenSSL::SSL::VERIFY_PEER
155
+ begin
156
+ @client.get_content(@url)
157
+ assert(false)
158
+ rescue OpenSSL::SSL::SSLError => ssle
159
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
160
+ end
161
+ #
162
+ cfg.verify_mode = nil
163
+ assert_equal("hello", @client.get_content(@url))
164
+ cfg.verify_mode = OpenSSL::SSL::VERIFY_NONE
165
+ assert_equal("hello", @client.get_content(@url))
166
+ end
167
+
168
+ def test_cert_store
169
+ cfg = @client.ssl_config
170
+ cfg.cert_store.add_cert(cert('ca.cert'))
171
+ begin
172
+ @client.get(@url)
173
+ assert(false)
174
+ rescue OpenSSL::SSL::SSLError => ssle
175
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
176
+ end
177
+ #
178
+ cfg.cert_store.add_cert(cert('subca.cert'))
179
+ assert_equal("hello", @client.get_content(@url))
180
+ cfg.clear_cert_store
181
+ begin
182
+ @client.get(@url)
183
+ assert(false)
184
+ rescue OpenSSL::SSL::SSLError => ssle
185
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
186
+ end
187
+ end
188
+
189
+ if defined?(HTTPClient::JRubySSLSocket)
190
+ def test_ciphers
191
+ cfg = @client.ssl_config
192
+ cfg.set_client_cert_file(path('client.cert'), path('client-pass.key'), 'pass4key')
193
+ cfg.add_trust_ca(path('ca.cert'))
194
+ cfg.add_trust_ca(path('subca.cert'))
195
+ cfg.timeout = 123
196
+ assert_equal("hello", @client.get_content(@url))
197
+ #
198
+ cfg.ciphers = []
199
+ begin
200
+ @client.get(@url)
201
+ assert(false)
202
+ rescue OpenSSL::SSL::SSLError => ssle
203
+ assert_match(/No appropriate protocol/, ssle.message)
204
+ end
205
+ #
206
+ cfg.ciphers = %w(TLS_RSA_WITH_AES_128_CBC_SHA)
207
+ assert_equal("hello", @client.get_content(@url))
208
+ #
209
+ cfg.ciphers = HTTPClient::SSLConfig::CIPHERS_DEFAULT
210
+ assert_equal("hello", @client.get_content(@url))
211
+ end
212
+
213
+ else
214
+
215
+ def test_ciphers
216
+ cfg = @client.ssl_config
217
+ cfg.set_client_cert_file(path('client.cert'), path('client-pass.key'), 'pass4key')
218
+ cfg.add_trust_ca(path('ca.cert'))
219
+ cfg.add_trust_ca(path('subca.cert'))
220
+ cfg.timeout = 123
221
+ assert_equal("hello", @client.get_content(@url))
222
+ #
223
+ cfg.ciphers = "!ALL"
224
+ begin
225
+ @client.get(@url)
226
+ assert(false)
227
+ rescue OpenSSL::SSL::SSLError => ssle
228
+ assert_match(/no cipher match/, ssle.message)
229
+ end
230
+ #
231
+ cfg.ciphers = "ALL"
232
+ assert_equal("hello", @client.get_content(@url))
233
+ #
234
+ cfg.ciphers = "DEFAULT"
235
+ assert_equal("hello", @client.get_content(@url))
236
+ end
237
+ end
238
+
239
+ def test_set_default_paths
240
+ assert_raise(OpenSSL::SSL::SSLError) do
241
+ @client.get(@url)
242
+ end
243
+ escape_env do
244
+ ENV['SSL_CERT_FILE'] = File.join(DIR, 'ca-chain.pem')
245
+ @client.ssl_config.set_default_paths
246
+ @client.get(@url)
247
+ end
248
+ end
249
+
250
+ def test_no_sslv3
251
+ omit('TODO: SSLv3 is not supported in many environments. re-enable when disable TLSv1')
252
+ teardown_server
253
+ setup_server_with_ssl_version(:SSLv3)
254
+ assert_raise(OpenSSL::SSL::SSLError) do
255
+ @client.ssl_config.verify_mode = nil
256
+ @client.get("https://localhost:#{serverport}/hello")
257
+ end
258
+ end
259
+
260
+ def test_allow_tlsv1
261
+ teardown_server
262
+ setup_server_with_ssl_version(:TLSv1)
263
+ assert_nothing_raised do
264
+ @client.ssl_config.verify_mode = nil
265
+ @client.get("https://localhost:#{serverport}/hello")
266
+ end
267
+ end
268
+
269
+ def test_use_higher_TLS
270
+ omit('TODO: it does not pass with Java 7 or old openssl')
271
+ teardown_server
272
+ setup_server_with_ssl_version('TLSv1_2')
273
+ assert_nothing_raised do
274
+ @client.ssl_config.verify_mode = nil
275
+ @client.get("https://localhost:#{serverport}/hello")
276
+ # TODO: should check JRubySSLSocket.ssl_socket.getSession.getProtocol
277
+ # but it's not thread safe. How can I return protocol version to the caller?
278
+ end
279
+ end
280
+
281
+ VERIFY_TEST_CERT_LOCALHOST = OpenSSL::X509::Certificate.new(<<-EOS)
282
+ -----BEGIN CERTIFICATE-----
283
+ MIIB9jCCAV+gAwIBAgIJAIH8Gsm4PcNKMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
284
+ BAMMCWxvY2FsaG9zdDAeFw0xNjA4MTgxMDI2MDVaFw00NDAxMDMxMDI2MDVaMBQx
285
+ EjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
286
+ p7D8q0lcx5EZEV5+zPnQsxrbft5xyhH/MCStbH46DRATGPNSOaLRCG5r8gTKQzpD
287
+ 4swGrQFYe2ienQ+7o4aEHErsXp4O/EmDKeiXWWrMqPr23r3HOBDebuynC/sCwy7N
288
+ epnX9u1VLB03eo+suj4d86OoOF+o11t9ZP+GA29Rsf8CAwEAAaNQME4wHQYDVR0O
289
+ BBYEFIxsJuPVvd5KKFcAvHGSeKSsWiUJMB8GA1UdIwQYMBaAFIxsJuPVvd5KKFcA
290
+ vHGSeKSsWiUJMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEAMJaVCrrM
291
+ SM2I06Vr4BL+jtDFhZh3HmJFEDpwEFQ5Y9hduwdUGRBGCpkuea3fE2FKwWW9gLM1
292
+ w7rFMzYFtCEqm78dJWIU79MRy0wjO4LgtYfoikgBh6JKWuV5ed/+L3sLyLG0ZTtv
293
+ lrD7lzDtXgwvj007PxDoYRp3JwYzKRmTbH8=
294
+ -----END CERTIFICATE-----
295
+ EOS
296
+
297
+ VERIFY_TEST_CERT_FOO_DOMAIN = OpenSSL::X509::Certificate.new(<<-EOS)
298
+ -----BEGIN CERTIFICATE-----
299
+ MIIB8jCCAVugAwIBAgIJAL/od7Whx7VTMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
300
+ BAMMB2Zvby5jb20wHhcNMTYwODE4MTAyMzUyWhcNNDQwMTAzMTAyMzUyWjASMRAw
301
+ DgYDVQQDDAdmb28uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnsPyr
302
+ SVzHkRkRXn7M+dCzGtt+3nHKEf8wJK1sfjoNEBMY81I5otEIbmvyBMpDOkPizAat
303
+ AVh7aJ6dD7ujhoQcSuxeng78SYMp6JdZasyo+vbevcc4EN5u7KcL+wLDLs16mdf2
304
+ 7VUsHTd6j6y6Ph3zo6g4X6jXW31k/4YDb1Gx/wIDAQABo1AwTjAdBgNVHQ4EFgQU
305
+ jGwm49W93kooVwC8cZJ4pKxaJQkwHwYDVR0jBBgwFoAUjGwm49W93kooVwC8cZJ4
306
+ pKxaJQkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCVKTvfxx+yezuR
307
+ 5WpVKw1E9qabKOYFB5TqdHMHreRubMJTaoZC+YzhcCwtyLlAA9+axKINAiMM8T+z
308
+ jjfOHQSa2GS2TaaVDJWmXIgsAlEbjd2BEiQF0LZYGJRG9pyq0WbTV+CyFdrghjcO
309
+ xX/t7OG7NfOG9dhv3J+5SX10S5V5Dg==
310
+ -----END CERTIFICATE-----
311
+ EOS
312
+
313
+ VERIFY_TEST_CERT_ALT_NAME = OpenSSL::X509::Certificate.new(<<-EOS)
314
+ -----BEGIN CERTIFICATE-----
315
+ MIICDDCCAXWgAwIBAgIJAOxXY4nOwxhGMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
316
+ BAMMCWxvY2FsaG9zdDAeFw0xNjA4MTgxMDM0NTJaFw00NDAxMDMxMDM0NTJaMBQx
317
+ EjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
318
+ p7D8q0lcx5EZEV5+zPnQsxrbft5xyhH/MCStbH46DRATGPNSOaLRCG5r8gTKQzpD
319
+ 4swGrQFYe2ienQ+7o4aEHErsXp4O/EmDKeiXWWrMqPr23r3HOBDebuynC/sCwy7N
320
+ epnX9u1VLB03eo+suj4d86OoOF+o11t9ZP+GA29Rsf8CAwEAAaNmMGQwFAYDVR0R
321
+ BA0wC4IJKi5mb28uY29tMB0GA1UdDgQWBBSMbCbj1b3eSihXALxxknikrFolCTAf
322
+ BgNVHSMEGDAWgBSMbCbj1b3eSihXALxxknikrFolCTAMBgNVHRMEBTADAQH/MA0G
323
+ CSqGSIb3DQEBCwUAA4GBADJlKNFuOnsDIhHGW72HuQw4naN6lM3eZE9JJ+UF/XIF
324
+ ghGtgqw+00Yy5wMFc1K2Wm4p5NymmDfC/P1FOe34bpxt9/IWm6mEoIWoodC3N4Cm
325
+ PtnSS1/CRWzVIPGMglTGGDcUc70tfeAWgyTxgcNQd4vTFtnN0f0RDdaXa8kfKMTw
326
+ -----END CERTIFICATE-----
327
+ EOS
328
+
329
+ VERIFY_TEST_PKEY = OpenSSL::PKey::RSA.new(<<-EOS)
330
+ -----BEGIN RSA PRIVATE KEY-----
331
+ MIICXQIBAAKBgQCnsPyrSVzHkRkRXn7M+dCzGtt+3nHKEf8wJK1sfjoNEBMY81I5
332
+ otEIbmvyBMpDOkPizAatAVh7aJ6dD7ujhoQcSuxeng78SYMp6JdZasyo+vbevcc4
333
+ EN5u7KcL+wLDLs16mdf27VUsHTd6j6y6Ph3zo6g4X6jXW31k/4YDb1Gx/wIDAQAB
334
+ AoGAe0RHx+WKtQx8/96VmTl951qzxMPho2etTYd4kAsNwzJwx2N9qu57eBYrdWF+
335
+ CQMYievucFhP4Y+bINtC1Eb6btz9TCUwjCfeIxfGRoFf3cxVmxlsRJJmN1kSZlu1
336
+ yYlcMVuP4noeFIMQBRrt5pyLCx2Z9A01NCQT4Y6VoREBIeECQQDWeNhsL6xkrmdB
337
+ M9+zl+SqHdNKhgKwMdp74+UNnAV9I8GB7bGlOWhc83aqMLgS+JBDFXcmNF/KawTR
338
+ zcnkod5xAkEAyClFgr3lZQSnwUwoA/AOcyW0+H63taaaXS/g8n3H8ENK6kL4ldUx
339
+ IgCk2ekbQ5Y3S2WScIGXNxMOza9MlsOvbwJAPUtoPvMZB+U4KVBT/JXKijvf6QqH
340
+ tidpU8L78XnHr84KPcHa5WeUxgvmvBkUYoebYzC9TrPlNIqFZBi2PJtuYQJBAMda
341
+ E5j7eJT75fhm2RPS6xFT5MH5sw6AOA3HucrJ63AoFVzsBpl0E9NBwO4ndLgDzF6T
342
+ cx4Kc4iuunewuB8QFpECQQCfvsHCjIJ/X4kiqeBzxDq2GR/oDgQkOzY+4H9U7Lwl
343
+ e61RBaxk5OHOA0bLtvJblV6NL72ZEZhX60wAWbrOPhpT
344
+ -----END RSA PRIVATE KEY-----
345
+ EOS
346
+
347
+ def test_post_connection_check
348
+ teardown_server
349
+ setup_server_with_server_cert(nil, VERIFY_TEST_CERT_LOCALHOST, VERIFY_TEST_PKEY)
350
+ file = Tempfile.new('cert')
351
+ File.write(file.path, VERIFY_TEST_CERT_LOCALHOST.to_pem)
352
+ @client.ssl_config.add_trust_ca(file.path)
353
+ assert_nothing_raised do
354
+ @client.get("https://localhost:#{serverport}/hello")
355
+ end
356
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
357
+ assert_nothing_raised do
358
+ @client.get("https://localhost:#{serverport}/hello")
359
+ end
360
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
361
+
362
+ teardown_server
363
+ setup_server_with_server_cert(nil, VERIFY_TEST_CERT_FOO_DOMAIN, VERIFY_TEST_PKEY)
364
+ File.write(file.path, VERIFY_TEST_CERT_FOO_DOMAIN.to_pem)
365
+ @client.ssl_config.add_trust_ca(file.path)
366
+ assert_raises(OpenSSL::SSL::SSLError) do
367
+ @client.get("https://localhost:#{serverport}/hello")
368
+ end
369
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
370
+ assert_nothing_raised do
371
+ @client.get("https://localhost:#{serverport}/hello")
372
+ end
373
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
374
+
375
+ teardown_server
376
+ setup_server_with_server_cert(nil, VERIFY_TEST_CERT_ALT_NAME, VERIFY_TEST_PKEY)
377
+ File.write(file.path, VERIFY_TEST_CERT_ALT_NAME.to_pem)
378
+ @client.ssl_config.add_trust_ca(file.path)
379
+ assert_raises(OpenSSL::SSL::SSLError) do
380
+ @client.get("https://localhost:#{serverport}/hello")
381
+ end
382
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
383
+ assert_nothing_raised do
384
+ @client.get("https://localhost:#{serverport}/hello")
385
+ end
386
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
387
+ end
388
+
389
+ def test_x509_store_add_cert_prepend
390
+ store = OpenSSL::X509::Store.new
391
+ assert_equal(store, store.add_cert(OpenSSL::X509::Certificate.new(VERIFY_TEST_CERT_LOCALHOST)))
392
+ end
393
+
394
+ def test_tcp_keepalive
395
+ @client.tcp_keepalive = true
396
+ @client.ssl_config.add_trust_ca(path('ca-chain.pem'))
397
+ @client.get_content(@url)
398
+
399
+ # expecting HTTP keepalive caches the socket
400
+ session = @client.instance_variable_get(:@session_manager).send(:get_cached_session, HTTPClient::Site.new(URI.parse(@url)))
401
+ socket = session.instance_variable_get(:@socket).instance_variable_get(:@socket)
402
+
403
+ assert_true(session.tcp_keepalive)
404
+ if RUBY_ENGINE == 'jruby'
405
+ assert_true(socket.getKeepAlive())
406
+ else
407
+ assert_equal(Socket::SO_KEEPALIVE, socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE).optname)
408
+ end
409
+ end
410
+
411
+ def test_timeout
412
+ url = "https://localhost:#{serverport}/"
413
+ @client.ssl_config.add_trust_ca(path('ca-chain.pem'))
414
+ assert_equal('sleep', @client.get_content(url + 'sleep?sec=2'))
415
+ @client.receive_timeout = 1
416
+ @client.reset_all
417
+ assert_equal('sleep', @client.get_content(url + 'sleep?sec=0'))
418
+
419
+ start = Time.now
420
+ assert_raise(HTTPClient::ReceiveTimeoutError) do
421
+ @client.get_content(url + 'sleep?sec=5')
422
+ end
423
+ if Time.now - start > 3
424
+ # before #342 it detected timeout when IO was freed
425
+ fail 'timeout does not work'
426
+ end
427
+
428
+ @client.receive_timeout = 3
429
+ @client.reset_all
430
+ assert_equal('sleep', @client.get_content(url + 'sleep?sec=2'))
431
+ end
432
+
433
+ private
434
+
435
+ def cert(filename)
436
+ OpenSSL::X509::Certificate.new(File.read(File.join(DIR, filename)))
437
+ end
438
+
439
+ def key(filename)
440
+ OpenSSL::PKey::RSA.new(File.read(File.join(DIR, filename)))
441
+ end
442
+
443
+ def q(str)
444
+ %Q["#{str}"]
445
+ end
446
+
447
+ def setup_server
448
+ logger = Logger.new(STDERR)
449
+ logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)
450
+ @server = WEBrick::HTTPServer.new(
451
+ :BindAddress => "localhost",
452
+ :Logger => logger,
453
+ :Port => 0,
454
+ :AccessLog => [],
455
+ :DocumentRoot => DIR,
456
+ :SSLEnable => true,
457
+ :SSLCACertificateFile => File.join(DIR, 'ca.cert'),
458
+ :SSLCertificate => cert('server.cert'),
459
+ :SSLPrivateKey => key('server.key'),
460
+ :SSLVerifyClient => nil, #OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT|OpenSSL::SSL::VERIFY_PEER,
461
+ :SSLClientCA => cert('ca.cert'),
462
+ :SSLCertName => nil
463
+ )
464
+ @serverport = @server.config[:Port]
465
+ [:hello, :sleep].each do |sym|
466
+ @server.mount(
467
+ "/#{sym}",
468
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
469
+ )
470
+ end
471
+ @server_thread = start_server_thread(@server)
472
+ end
473
+
474
+ def setup_server_with_ssl_version(ssl_version)
475
+ # JRubyOpenSSL does not support "TLSv1_2" as an known version, and some JCE provides TLS v1.2 as "TLSv1.2" not "TLSv1_2"
476
+ if RUBY_ENGINE == 'jruby' && ['TLSv1_1', 'TLSv1_2'].include?(ssl_version)
477
+ ssl_version = ssl_version.tr('_', '.')
478
+ end
479
+ logger = Logger.new(STDERR)
480
+ logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)
481
+ @server = WEBrick::HTTPServer.new(
482
+ :BindAddress => "localhost",
483
+ :Logger => logger,
484
+ :Port => 0,
485
+ :AccessLog => [],
486
+ :DocumentRoot => DIR,
487
+ :SSLEnable => true,
488
+ :SSLCACertificateFile => File.join(DIR, 'ca.cert'),
489
+ :SSLCertificate => cert('server.cert'),
490
+ :SSLPrivateKey => key('server.key')
491
+ )
492
+ @server.ssl_context.ssl_version = ssl_version
493
+ @serverport = @server.config[:Port]
494
+ [:hello].each do |sym|
495
+ @server.mount(
496
+ "/#{sym}",
497
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
498
+ )
499
+ end
500
+ @server_thread = start_server_thread(@server)
501
+ end
502
+
503
+ def setup_server_with_server_cert(ca_cert, server_cert, server_key)
504
+ logger = Logger.new(STDERR)
505
+ logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)
506
+ @server = WEBrick::HTTPServer.new(
507
+ :BindAddress => "localhost",
508
+ :Logger => logger,
509
+ :Port => 0,
510
+ :AccessLog => [],
511
+ :DocumentRoot => DIR,
512
+ :SSLEnable => true,
513
+ :SSLCACertificateFile => ca_cert,
514
+ :SSLCertificate => server_cert,
515
+ :SSLPrivateKey => server_key,
516
+ :SSLVerifyClient => nil,
517
+ :SSLClientCA => nil,
518
+ :SSLCertName => nil
519
+ )
520
+ @serverport = @server.config[:Port]
521
+ [:hello].each do |sym|
522
+ @server.mount(
523
+ "/#{sym}",
524
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
525
+ )
526
+ end
527
+ @server_thread = start_server_thread(@server)
528
+ end
529
+
530
+ def do_hello(req, res)
531
+ res['content-type'] = 'text/html'
532
+ res.body = "hello"
533
+ end
534
+
535
+ def do_sleep(req, res)
536
+ sec = req.query['sec'].to_i
537
+ sleep sec
538
+ res['content-type'] = 'text/html'
539
+ res.body = "sleep"
540
+ end
541
+
542
+ def start_server_thread(server)
543
+ t = Thread.new {
544
+ Thread.current.abort_on_exception = true
545
+ server.start
546
+ }
547
+ while server.status != :Running
548
+ sleep 0.1
549
+ unless t.alive?
550
+ t.join
551
+ raise
552
+ end
553
+ end
554
+ t
555
+ end
556
+
557
+ def verify_callback(ok, cert)
558
+ @verify_callback_called = true
559
+ p ["client", ok, cert] if $DEBUG
560
+ ok
561
+ end
562
+ end