1require_relative "utils" 2 3if defined?(OpenSSL) 4 5class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase 6 def test_session_equals 7 session = OpenSSL::SSL::Session.new <<-SESSION 8-----BEGIN SSL SESSION PARAMETERS----- 9MIIDFgIBAQICAwEEAgA5BCCY3pW6iTkPoD5SENuztz/gZjhvey6XnHbsxd22k0Ol 10dgQw8uaN3hCRnlhoIKPWInCFzrp/tQsDRFs9jDjc9pwpy/oKHmJdQQMQA1g8FYnO 11gpdVoQYCBE52ikKiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B 12AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi 13eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA5MTkwMDE4MTBaFw0xMTA5MTkwMDQ4 14MTBaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 15LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw 16gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB 177JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ 18GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw 19DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQARC7GP7InX1t7VEXz2 20I8RI57S0/HSJL4fDIYP3zFpitHX1PZeo+7XuzMilvPjjBo/ky9Jzo8TYiY+N+JEz 21mY/A/zPA4ZsJ7KYj6/FEdIc/vRlS0CvsbClbNjw1jl/PoB2FLr2b3uuBcZEsyZeP 22yq154ijq37Ajf8K5Mi5FgshoP41BPtRPj+VVf61rv1IcEnNWdDCS6DR4XsaNC+zt 23G6AqCqkytIXWRuDw6n6vYLF3A/tn2sldLo7/scY0PMDNbo63O/LTxkDHmPhSkD68 248m9SsMeTR+RCiDEZWFPVcAH/8mDfi+5k8uN3qS+gOU/PPrmHGgl5ykiSFgqs4v61 25tddwpBAEDjcwMzA5NTYzMTU1MzAwpQMCARM= 26-----END SSL SESSION PARAMETERS----- 27 SESSION 28 29 start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |_, port| 30 ctx = OpenSSL::SSL::SSLContext.new 31 ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT 32 ctx.session_id_context = self.object_id.to_s 33 34 sock = TCPSocket.new '127.0.0.1', port 35 ssl = OpenSSL::SSL::SSLSocket.new sock, ctx 36 ssl.session = session 37 38 assert_equal session, ssl.session 39 sock.close 40 } 41 end 42 43 def test_session 44 start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| 45 sock = TCPSocket.new("127.0.0.1", port) 46 ctx = OpenSSL::SSL::SSLContext.new("TLSv1") 47 ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) 48 ssl.sync_close = true 49 ssl.connect 50 session = ssl.session 51 assert(session == OpenSSL::SSL::Session.new(session.to_pem)) 52 assert(session == OpenSSL::SSL::Session.new(ssl)) 53 assert_equal(300, session.timeout) 54 session.timeout = 5 55 assert_equal(5, session.timeout) 56 assert_not_nil(session.time) 57 # SSL_SESSION_time keeps long value so we can't keep nsec fragment. 58 session.time = t1 = Time.now.to_i 59 assert_equal(Time.at(t1), session.time) 60 if session.respond_to?(:id) 61 assert_not_nil(session.id) 62 end 63 pem = session.to_pem 64 assert_match(/\A-----BEGIN SSL SESSION PARAMETERS-----/, pem) 65 assert_match(/-----END SSL SESSION PARAMETERS-----\Z/, pem) 66 pem.gsub!(/-----(BEGIN|END) SSL SESSION PARAMETERS-----/, '').gsub!(/[\r\n]+/m, '') 67 assert_equal(session.to_der, pem.unpack('m*')[0]) 68 assert_not_nil(session.to_text) 69 ssl.close 70 end 71 end 72 73 DUMMY_SESSION = <<__EOS__ 74-----BEGIN SSL SESSION PARAMETERS----- 75MIIDzQIBAQICAwEEAgA5BCAF219w9ZEV8dNA60cpEGOI34hJtIFbf3bkfzSgMyad 76MQQwyGLbkCxE4OiMLdKKem+pyh8V7ifoP7tCxhdmwoDlJxI1v6nVCjai+FGYuncy 77NNSWoQYCBE4DDWuiAwIBCqOCAo4wggKKMIIBcqADAgECAgECMA0GCSqGSIb3DQEB 78BQUAMD0xEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 79LWxhbmcxCzAJBgNVBAMMAkNBMB4XDTExMDYyMzA5NTQ1MVoXDTExMDYyMzEwMjQ1 80MVowRDETMBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1Ynkt 81bGFuZzESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB 82iQKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7CxaKPERYHs 83k4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/Q3geLv8Z 84D9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQABoxIwEDAO 85BgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBACj5WhoZ/ODVeHpwgq1d 868fW/13ICRYHYpv6dzlWihyqclGxbKMlMnaVCPz+4JaVtMz3QB748KJQgL3Llg3R1 87ek+f+n1MBCMfFFsQXJ2gtLB84zD6UCz8aaCWN5/czJCd7xMz7fRLy3TOIW5boXAU 88zIa8EODk+477K1uznHm286ab0Clv+9d304hwmBZgkzLg6+31Of6d6s0E0rwLGiS2 89sOWYg34Y3r4j8BS9Ak4jzpoLY6cJ0QAKCOJCgmjGr4XHpyXMLbicp3ga1uSbwtVO 90gF/gTfpLhJC+y0EQ5x3Ftl88Cq7ZJuLBDMo/TLIfReJMQu/HlrTT7+LwtneSWGmr 91KkSkAgQApQMCAROqgcMEgcAuDkAVfj6QAJMz9yqTzW5wPFyty7CxUEcwKjUqj5UP 92/Yvky1EkRuM/eQfN7ucY+MUvMqv+R8ZSkHPsnjkBN5ChvZXjrUSZKFVjR4eFVz2V 93jismLEJvIFhQh6pqTroRrOjMfTaM5Lwoytr2FTGobN9rnjIRsXeFQW1HLFbXn7Dh 948uaQkMwIVVSGRB8T7t6z6WIdWruOjCZ6G5ASI5XoqAHwGezhLodZuvJEfsVyCF9y 95j+RBGfCFrrQbBdnkFI/ztgM= 96-----END SSL SESSION PARAMETERS----- 97__EOS__ 98 99 DUMMY_SESSION_NO_EXT = <<-__EOS__ 100-----BEGIN SSL SESSION PARAMETERS----- 101MIIDCAIBAQICAwAEAgA5BCDyAW7rcpzMjDSosH+Tv6sukymeqgq3xQVVMez628A+ 102lAQw9TrKzrIqlHEh6ltuQaqv/Aq83AmaAlogYktZgXAjOGnhX7ifJDNLMuCfQq53 103hPAaoQYCBE4iDeeiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B 104AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi 105eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA3MTYyMjE3MTFaFw0xMTA3MTYyMjQ3 106MTFaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 107LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw 108gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB 1097JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ 110GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw 111DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQA3TRzABRG3kz8jEEYr 112tDQqXgsxwTsLhTT5d1yF0D8uFw+y15hJAJnh6GJHjqhWBrF4zNoTApFo+4iIL6g3 113q9C3mUsxIVAHx41DwZBh/FI7J4FqlAoGOguu7892CNVY3ZZjc3AXMTdKjcNoWPzz 114FCdj5fNT24JMMe+ZdGZK97ChahJsdn/6B3j6ze9NK9mfYEbiJhejGTPLOFVHJCGR 115KYYZ3ZcKhLDr9ql4d7cCo1gBtemrmFQGPui7GttNEqmXqUKvV8mYoa8farf5i7T4 116L6a/gp2cVZTaDIS1HjbJsA/Ag7AajZqiN6LfqShNUVsrMZ+5CoV8EkBDTZPJ9MSr 117a3EqpAIEAKUDAgET 118-----END SSL SESSION PARAMETERS----- 119__EOS__ 120 121 122 def test_session_time 123 sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) 124 sess.time = (now = Time.now) 125 assert_equal(now.to_i, sess.time.to_i) 126 sess.time = 1 127 assert_equal(1, sess.time.to_i) 128 sess.time = 1.2345 129 assert_equal(1, sess.time.to_i) 130 # Can OpenSSL handle t>2038y correctly? Version? 131 sess.time = 2**31 - 1 132 assert_equal(2**31 - 1, sess.time.to_i) 133 end 134 135 def test_session_timeout 136 sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) 137 assert_raise(TypeError) do 138 sess.timeout = Time.now 139 end 140 sess.timeout = 1 141 assert_equal(1, sess.timeout.to_i) 142 sess.timeout = 1.2345 143 assert_equal(1, sess.timeout.to_i) 144 sess.timeout = 2**31 - 1 145 assert_equal(2**31 - 1, sess.timeout.to_i) 146 end 147 148 def test_session_exts_read 149 assert(OpenSSL::SSL::Session.new(DUMMY_SESSION)) 150 end if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x009080bf 151 152 def test_client_session 153 last_session = nil 154 start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| 155 2.times do 156 sock = TCPSocket.new("127.0.0.1", port) 157 # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), 158 # when use default SSLContext. [ruby-dev:36167] 159 ctx = OpenSSL::SSL::SSLContext.new("TLSv1") 160 ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) 161 ssl.sync_close = true 162 ssl.session = last_session if last_session 163 ssl.connect 164 165 session = ssl.session 166 if last_session 167 assert(ssl.session_reused?) 168 169 if session.respond_to?(:id) 170 assert_equal(session.id, last_session.id) 171 end 172 assert_equal(session.to_pem, last_session.to_pem) 173 assert_equal(session.to_der, last_session.to_der) 174 # Older version of OpenSSL may not be consistent. Look up which versions later. 175 assert_equal(session.to_text, last_session.to_text) 176 else 177 assert(!ssl.session_reused?) 178 end 179 last_session = session 180 181 str = "x" * 100 + "\n" 182 ssl.puts(str) 183 assert_equal(str, ssl.gets) 184 185 ssl.close 186 end 187 end 188 end 189 190 def test_server_session 191 connections = 0 192 saved_session = nil 193 194 ctx_proc = Proc.new do |ctx, ssl| 195# add test for session callbacks here 196 end 197 198 server_proc = Proc.new do |ctx, ssl| 199 session = ssl.session 200 stats = ctx.session_cache_stats 201 202 case connections 203 when 0 204 assert_equal(stats[:cache_num], 1) 205 assert_equal(stats[:cache_hits], 0) 206 assert_equal(stats[:cache_misses], 0) 207 assert(!ssl.session_reused?) 208 when 1 209 assert_equal(stats[:cache_num], 1) 210 assert_equal(stats[:cache_hits], 1) 211 assert_equal(stats[:cache_misses], 0) 212 assert(ssl.session_reused?) 213 ctx.session_remove(session) 214 saved_session = session 215 when 2 216 assert_equal(stats[:cache_num], 1) 217 assert_equal(stats[:cache_hits], 1) 218 assert_equal(stats[:cache_misses], 1) 219 assert(!ssl.session_reused?) 220 ctx.session_add(saved_session) 221 when 3 222 assert_equal(stats[:cache_num], 2) 223 assert_equal(stats[:cache_hits], 2) 224 assert_equal(stats[:cache_misses], 1) 225 assert(ssl.session_reused?) 226 ctx.flush_sessions(Time.now + 5000) 227 when 4 228 assert_equal(stats[:cache_num], 1) 229 assert_equal(stats[:cache_hits], 2) 230 assert_equal(stats[:cache_misses], 2) 231 assert(!ssl.session_reused?) 232 ctx.session_add(saved_session) 233 end 234 connections += 1 235 236 readwrite_loop(ctx, ssl) 237 end 238 239 first_session = nil 240 start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| 241 10.times do |i| 242 sock = TCPSocket.new("127.0.0.1", port) 243 ctx = OpenSSL::SSL::SSLContext.new 244 if defined?(OpenSSL::SSL::OP_NO_TICKET) 245 # disable RFC4507 support 246 ctx.options = OpenSSL::SSL::OP_NO_TICKET 247 end 248 ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) 249 ssl.sync_close = true 250 ssl.session = first_session if first_session 251 ssl.connect 252 253 session = ssl.session 254 if first_session 255 case i 256 when 1; assert(ssl.session_reused?) 257 when 2; assert(!ssl.session_reused?) 258 when 3; assert(ssl.session_reused?) 259 when 4; assert(!ssl.session_reused?) 260 when 5..10; assert(ssl.session_reused?) 261 end 262 end 263 first_session ||= session 264 265 str = "x" * 100 + "\n" 266 ssl.puts(str) 267 assert_equal(str, ssl.gets) 268 269 ssl.close 270 end 271 end 272 end 273 274 def test_ctx_client_session_cb 275 called = {} 276 ctx = OpenSSL::SSL::SSLContext.new("SSLv3") 277 ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT 278 279 ctx.session_new_cb = lambda { |ary| 280 sock, sess = ary 281 called[:new] = [sock, sess] 282 } 283 284 ctx.session_remove_cb = lambda { |ary| 285 ctx, sess = ary 286 called[:remove] = [ctx, sess] 287 # any resulting value is OK (ignored) 288 } 289 290 start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| 291 sock = TCPSocket.new("127.0.0.1", port) 292 ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) 293 ssl.sync_close = true 294 ssl.connect 295 assert_equal(1, ctx.session_cache_stats[:cache_num]) 296 assert_equal(1, ctx.session_cache_stats[:connect_good]) 297 assert_equal([ssl, ssl.session], called[:new]) 298 assert(ctx.session_remove(ssl.session)) 299 assert(!ctx.session_remove(ssl.session)) 300 assert_equal([ctx, ssl.session], called[:remove]) 301 ssl.close 302 end 303 end 304 305 def test_ctx_server_session_cb 306 called = {} 307 308 ctx_proc = Proc.new { |ctx, ssl| 309 ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER 310 last_server_session = nil 311 312 # get_cb is called whenever a client proposed to resume a session but 313 # the session could not be found in the internal session cache. 314 ctx.session_get_cb = lambda { |ary| 315 sess, data = ary 316 if last_server_session 317 called[:get2] = [sess, data] 318 last_server_session 319 else 320 called[:get1] = [sess, data] 321 last_server_session = sess 322 nil 323 end 324 } 325 326 ctx.session_new_cb = lambda { |ary| 327 sock, sess = ary 328 called[:new] = [sock, sess] 329 # SSL server doesn't cache sessions so get_cb is called next time. 330 ctx.session_remove(sess) 331 } 332 333 ctx.session_remove_cb = lambda { |ary| 334 ctx, sess = ary 335 called[:remove] = [ctx, sess] 336 } 337 } 338 339 server_proc = Proc.new { |c, ssl| 340 ssl.session 341 c.session_cache_stats 342 readwrite_loop(c, ssl) 343 } 344 start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| 345 last_client_session = nil 346 3.times do 347 sock = TCPSocket.new("127.0.0.1", port) 348 ssl = OpenSSL::SSL::SSLSocket.new(sock, OpenSSL::SSL::SSLContext.new("SSLv3")) 349 ssl.sync_close = true 350 ssl.session = last_client_session if last_client_session 351 ssl.connect 352 last_client_session = ssl.session 353 ssl.close 354 timeout(5) do 355 Thread.pass until called.key?(:new) 356 assert(called.delete(:new)) 357 Thread.pass until called.key?(:remove) 358 assert(called.delete(:remove)) 359 end 360 end 361 end 362 assert(called[:get1]) 363 assert(called[:get2]) 364 end 365end 366 367end 368