httpclient-fixcerts 2.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +98 -0
  3. data/bin/httpclient +77 -0
  4. data/bin/jsonclient +85 -0
  5. data/lib/hexdump.rb +50 -0
  6. data/lib/http-access2/cookie.rb +1 -0
  7. data/lib/http-access2/http.rb +1 -0
  8. data/lib/http-access2.rb +55 -0
  9. data/lib/httpclient/auth.rb +924 -0
  10. data/lib/httpclient/cacert.pem +3952 -0
  11. data/lib/httpclient/cacert1024.pem +3866 -0
  12. data/lib/httpclient/connection.rb +88 -0
  13. data/lib/httpclient/cookie.rb +220 -0
  14. data/lib/httpclient/http.rb +1082 -0
  15. data/lib/httpclient/include_client.rb +85 -0
  16. data/lib/httpclient/jruby_ssl_socket.rb +594 -0
  17. data/lib/httpclient/session.rb +960 -0
  18. data/lib/httpclient/ssl_config.rb +433 -0
  19. data/lib/httpclient/ssl_socket.rb +150 -0
  20. data/lib/httpclient/timeout.rb +140 -0
  21. data/lib/httpclient/util.rb +222 -0
  22. data/lib/httpclient/version.rb +3 -0
  23. data/lib/httpclient/webagent-cookie.rb +459 -0
  24. data/lib/httpclient.rb +1332 -0
  25. data/lib/jsonclient.rb +66 -0
  26. data/lib/oauthclient.rb +111 -0
  27. data/sample/async.rb +8 -0
  28. data/sample/auth.rb +11 -0
  29. data/sample/cookie.rb +18 -0
  30. data/sample/dav.rb +103 -0
  31. data/sample/howto.rb +49 -0
  32. data/sample/jsonclient.rb +67 -0
  33. data/sample/oauth_buzz.rb +57 -0
  34. data/sample/oauth_friendfeed.rb +59 -0
  35. data/sample/oauth_twitter.rb +61 -0
  36. data/sample/ssl/0cert.pem +22 -0
  37. data/sample/ssl/0key.pem +30 -0
  38. data/sample/ssl/1000cert.pem +19 -0
  39. data/sample/ssl/1000key.pem +18 -0
  40. data/sample/ssl/htdocs/index.html +10 -0
  41. data/sample/ssl/ssl_client.rb +22 -0
  42. data/sample/ssl/webrick_httpsd.rb +29 -0
  43. data/sample/stream.rb +21 -0
  44. data/sample/thread.rb +27 -0
  45. data/sample/wcat.rb +21 -0
  46. data/test/ca-chain.pem +44 -0
  47. data/test/ca.cert +23 -0
  48. data/test/client-pass.key +18 -0
  49. data/test/client.cert +19 -0
  50. data/test/client.key +15 -0
  51. data/test/helper.rb +131 -0
  52. data/test/htdigest +1 -0
  53. data/test/htpasswd +2 -0
  54. data/test/jruby_ssl_socket/test_pemutils.rb +32 -0
  55. data/test/runner.rb +2 -0
  56. data/test/server.cert +19 -0
  57. data/test/server.key +15 -0
  58. data/test/sslsvr.rb +65 -0
  59. data/test/subca.cert +21 -0
  60. data/test/test_auth.rb +492 -0
  61. data/test/test_cookie.rb +309 -0
  62. data/test/test_hexdump.rb +14 -0
  63. data/test/test_http-access2.rb +508 -0
  64. data/test/test_httpclient.rb +2145 -0
  65. data/test/test_include_client.rb +52 -0
  66. data/test/test_jsonclient.rb +98 -0
  67. data/test/test_ssl.rb +562 -0
  68. data/test/test_webagent-cookie.rb +465 -0
  69. metadata +124 -0
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