OSDN Git Service

ruby-1.9.1-rc1
[splhack/AndroidRuby.git] / lib / ruby-1.9.1-rc1 / test / openssl / test_ssl.rb
1 begin
2   require "openssl"
3   require File.join(File.dirname(__FILE__), "utils.rb")
4 rescue LoadError
5 end
6 require "rbconfig"
7 require "socket"
8 require "test/unit"
9 begin
10   loadpath = $:.dup
11   $:.replace($: | [File.expand_path("../ruby", File.dirname(__FILE__))])
12   require 'envutil'
13 ensure
14   $:.replace(loadpath)
15 end
16
17 if defined?(OpenSSL)
18
19 class OpenSSL::TestSSL < Test::Unit::TestCase
20   RUBY = EnvUtil.rubybin
21   SSL_SERVER = File.join(File.dirname(__FILE__), "ssl_server.rb")
22   PORT = 20443
23   ITERATIONS = ($0 == __FILE__) ? 100 : 10
24
25   def setup
26     @ca_key  = OpenSSL::TestUtils::TEST_KEY_RSA2048
27     @svr_key = OpenSSL::TestUtils::TEST_KEY_RSA1024
28     @cli_key = OpenSSL::TestUtils::TEST_KEY_DSA256
29     @ca  = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
30     @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
31     @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
32
33     now = Time.at(Time.now.to_i)
34     ca_exts = [
35       ["basicConstraints","CA:TRUE",true],
36       ["keyUsage","cRLSign,keyCertSign",true],
37     ]
38     ee_exts = [
39       ["keyUsage","keyEncipherment,digitalSignature",true],
40     ]
41     @ca_cert  = issue_cert(@ca, @ca_key, 1, now, now+3600, ca_exts,
42                            nil, nil, OpenSSL::Digest::SHA1.new)
43     @svr_cert = issue_cert(@svr, @svr_key, 2, now, now+1800, ee_exts,
44                            @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
45     @cli_cert = issue_cert(@cli, @cli_key, 3, now, now+1800, ee_exts,
46                            @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
47     @server = nil
48   end
49
50   def teardown
51   end
52
53   def issue_cert(*arg)
54     OpenSSL::TestUtils.issue_cert(*arg)
55   end
56
57   def issue_crl(*arg)
58     OpenSSL::TestUtils.issue_crl(*arg)
59   end
60
61   def readwrite_loop(ctx, ssl)
62     while line = ssl.gets
63       if line =~ /^STARTTLS$/
64         ssl.accept
65         next
66       end
67       ssl.write(line)
68     end
69   rescue OpenSSL::SSL::SSLError
70   rescue IOError
71   ensure
72     ssl.close rescue nil
73   end
74
75   def server_loop(ctx, ssls, server_proc)
76     loop do
77       ssl = nil
78       begin
79         ssl = ssls.accept
80       rescue OpenSSL::SSL::SSLError
81         retry
82       end
83
84       Thread.start do
85         Thread.current.abort_on_exception = true  
86         server_proc.call(ctx, ssl)
87       end
88     end
89   rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED
90   end
91
92   def start_server(port0, verify_mode, start_immediately, args = {}, &block)
93     ctx_proc = args[:ctx_proc]
94     server_proc = args[:server_proc]
95     server_proc ||= method(:readwrite_loop)
96   
97     store = OpenSSL::X509::Store.new
98     store.add_cert(@ca_cert)
99     store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
100     ctx = OpenSSL::SSL::SSLContext.new
101     ctx.cert_store = store
102     #ctx.extra_chain_cert = [ ca_cert ]
103     ctx.cert = @svr_cert
104     ctx.key = @svr_key
105     ctx.verify_mode = verify_mode
106     ctx_proc.call(ctx) if ctx_proc
107
108     Socket.do_not_reverse_lookup = true
109     tcps = nil
110     port = port0
111     begin
112       tcps = TCPServer.new("127.0.0.1", port)
113     rescue Errno::EADDRINUSE
114       port += 1
115       retry
116     end
117
118     ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
119     ssls.start_immediately = start_immediately
120
121     begin
122       server = Thread.new do
123         Thread.current.abort_on_exception = true  
124         server_loop(ctx, ssls, server_proc)
125       end
126
127       $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, pid, port) if $DEBUG
128
129       block.call(server, port.to_i)
130     ensure
131       begin
132         begin
133           tcps.shutdown
134         rescue Errno::ENOTCONN
135           # when `Errno::ENOTCONN: Socket is not connected' on some platforms,
136           # call #close instead of #shutdown.
137           tcps.close
138           tcps = nil
139         end if (tcps)
140         if (server)
141           server.join(5)
142           if server.alive?
143             server.kill
144             server.join
145             flunk("TCPServer was closed and SSLServer is still alive") unless $!
146           end
147         end
148       ensure
149         tcps.close if (tcps)
150       end
151     end
152   end
153
154   def starttls(ssl)
155     ssl.puts("STARTTLS")
156
157     sleep 1   # When this line is eliminated, process on Cygwin blocks
158               # forever at ssl.connect. But I don't know why it does.
159
160     ssl.connect
161   end
162
163   def test_ctx_setup
164     ctx = OpenSSL::SSL::SSLContext.new
165     assert_equal(ctx.setup, true)
166     assert_equal(ctx.setup, nil)
167   end
168
169   def test_connect_and_close
170     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
171       sock = TCPSocket.new("127.0.0.1", port)
172       ssl = OpenSSL::SSL::SSLSocket.new(sock)
173       assert(ssl.connect)
174       ssl.close
175       assert(!sock.closed?)
176       sock.close
177
178       sock = TCPSocket.new("127.0.0.1", port)
179       ssl = OpenSSL::SSL::SSLSocket.new(sock)
180       ssl.sync_close = true  # !!
181       assert(ssl.connect)
182       ssl.close
183       assert(sock.closed?)
184     }
185   end
186
187   def test_read_and_write
188     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
189       sock = TCPSocket.new("127.0.0.1", port)
190       ssl = OpenSSL::SSL::SSLSocket.new(sock)
191       ssl.sync_close = true
192       ssl.connect
193
194       # syswrite and sysread
195       ITERATIONS.times{|i|
196         str = "x" * 100 + "\n"
197         ssl.syswrite(str)
198         assert_equal(str, ssl.sysread(str.size))
199
200         str = "x" * i * 100 + "\n"
201         buf = ""
202         ssl.syswrite(str)
203         assert_equal(buf.object_id, ssl.sysread(str.size, buf).object_id)
204         assert_equal(str, buf)
205       }
206
207       # puts and gets
208       ITERATIONS.times{
209         str = "x" * 100 + "\n"
210         ssl.puts(str)
211         assert_equal(str, ssl.gets)
212
213         str = "x" * 100
214         ssl.puts(str)
215         assert_equal(str, ssl.gets("\n", 100))
216         assert_equal("\n", ssl.gets)
217       }
218
219       # read and write
220       ITERATIONS.times{|i|
221         str = "x" * 100 + "\n"
222         ssl.write(str)
223         assert_equal(str, ssl.read(str.size))
224
225         str = "x" * i * 100 + "\n"
226         buf = ""
227         ssl.write(str)
228         assert_equal(buf.object_id, ssl.read(str.size, buf).object_id)
229         assert_equal(str, buf)
230       }
231
232       ssl.close
233     }
234   end
235
236   def test_client_auth
237     vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
238     start_server(PORT, vflag, true){|server, port|
239       assert_raise(OpenSSL::SSL::SSLError){
240         sock = TCPSocket.new("127.0.0.1", port)
241         ssl = OpenSSL::SSL::SSLSocket.new(sock)
242         ssl.connect
243       }
244
245       ctx = OpenSSL::SSL::SSLContext.new
246       ctx.key = @cli_key
247       ctx.cert = @cli_cert
248       sock = TCPSocket.new("127.0.0.1", port)
249       ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
250       ssl.sync_close = true
251       ssl.connect
252       ssl.puts("foo")
253       assert_equal("foo\n", ssl.gets)
254       ssl.close
255
256       called = nil
257       ctx = OpenSSL::SSL::SSLContext.new
258       ctx.client_cert_cb = Proc.new{ |sslconn|
259         called = true
260         [@cli_cert, @cli_key]
261       }
262       sock = TCPSocket.new("127.0.0.1", port)
263       ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
264       ssl.sync_close = true
265       ssl.connect
266       assert(called)
267       ssl.puts("foo")
268       assert_equal("foo\n", ssl.gets)
269       ssl.close
270     }
271   end
272
273   def test_starttls
274     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port|
275       sock = TCPSocket.new("127.0.0.1", port)
276       ssl = OpenSSL::SSL::SSLSocket.new(sock)
277       ssl.sync_close = true
278       str = "x" * 1000 + "\n"
279
280       ITERATIONS.times{
281         ssl.puts(str)
282         assert_equal(str, ssl.gets)
283       }
284
285       starttls(ssl)
286
287       ITERATIONS.times{
288         ssl.puts(str)
289         assert_equal(str, ssl.gets)
290       }
291
292       ssl.close
293     }
294   end
295
296   def test_parallel
297     GC.start
298     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
299       ssls = []
300       10.times{
301         sock = TCPSocket.new("127.0.0.1", port)
302         ssl = OpenSSL::SSL::SSLSocket.new(sock)
303         ssl.connect
304         ssl.sync_close = true
305         ssls << ssl
306       }
307       str = "x" * 1000 + "\n"
308       ITERATIONS.times{
309         ssls.each{|ssl|
310           ssl.puts(str)
311           assert_equal(str, ssl.gets)
312         }
313       }
314       ssls.each{|ssl| ssl.close }
315     }
316   end
317
318   def test_verify_result
319     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
320       sock = TCPSocket.new("127.0.0.1", port)
321       ctx = OpenSSL::SSL::SSLContext.new
322       ctx.set_params
323       ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
324       assert_raise(OpenSSL::SSL::SSLError){ ssl.connect }
325       assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result)
326
327       sock = TCPSocket.new("127.0.0.1", port)
328       ctx = OpenSSL::SSL::SSLContext.new
329       ctx.set_params(
330         :verify_callback => Proc.new do |preverify_ok, store_ctx|
331           store_ctx.error = OpenSSL::X509::V_OK
332           true
333         end
334       )
335       ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
336       ssl.connect
337       assert_equal(OpenSSL::X509::V_OK, ssl.verify_result)
338
339       sock = TCPSocket.new("127.0.0.1", port)
340       ctx = OpenSSL::SSL::SSLContext.new
341       ctx.set_params(
342         :verify_callback => Proc.new do |preverify_ok, store_ctx|
343           store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION
344           false
345         end
346       )
347       ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
348       assert_raise(OpenSSL::SSL::SSLError){ ssl.connect }
349       assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result)
350     }
351   end
352
353   def test_sslctx_set_params
354     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
355       sock = TCPSocket.new("127.0.0.1", port)
356       ctx = OpenSSL::SSL::SSLContext.new
357       ctx.set_params
358       assert_equal(OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode)
359       assert_equal(OpenSSL::SSL::OP_ALL, ctx.options)
360       ciphers = ctx.ciphers
361       ciphers_versions = ciphers.collect{|_, v, _, _| v }
362       ciphers_names = ciphers.collect{|v, _, _, _| v }
363       assert(ciphers_names.all?{|v| /ADH/ !~ v })
364       assert(ciphers_versions.all?{|v| /SSLv2/ !~ v })
365       ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
366       assert_raise(OpenSSL::SSL::SSLError){ ssl.connect }
367       assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result)
368     }
369   end
370
371   def test_post_connection_check
372     sslerr = OpenSSL::SSL::SSLError
373
374     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
375       sock = TCPSocket.new("127.0.0.1", port)
376       ssl = OpenSSL::SSL::SSLSocket.new(sock)
377       ssl.connect
378       assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")}
379       assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")}
380       assert(ssl.post_connection_check("localhost"))
381       assert_raise(sslerr){ssl.post_connection_check("foo.example.com")}
382
383       cert = ssl.peer_cert
384       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain"))
385       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1"))
386       assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost"))
387       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com"))
388     }
389
390     now = Time.now
391     exts = [
392       ["keyUsage","keyEncipherment,digitalSignature",true],
393       ["subjectAltName","DNS:localhost.localdomain",false],
394       ["subjectAltName","IP:127.0.0.1",false],
395     ]
396     @svr_cert = issue_cert(@svr, @svr_key, 4, now, now+1800, exts,
397                            @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
398     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
399       sock = TCPSocket.new("127.0.0.1", port)
400       ssl = OpenSSL::SSL::SSLSocket.new(sock)
401       ssl.connect
402       assert(ssl.post_connection_check("localhost.localdomain"))
403       assert(ssl.post_connection_check("127.0.0.1"))
404       assert_raise(sslerr){ssl.post_connection_check("localhost")}
405       assert_raise(sslerr){ssl.post_connection_check("foo.example.com")}
406
407       cert = ssl.peer_cert
408       assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain"))
409       assert(OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1"))
410       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost"))
411       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com"))
412     }
413
414     now = Time.now
415     exts = [
416       ["keyUsage","keyEncipherment,digitalSignature",true],
417       ["subjectAltName","DNS:*.localdomain",false],
418     ]
419     @svr_cert = issue_cert(@svr, @svr_key, 5, now, now+1800, exts,
420                            @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
421     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
422       sock = TCPSocket.new("127.0.0.1", port)
423       ssl = OpenSSL::SSL::SSLSocket.new(sock)
424       ssl.connect
425       assert(ssl.post_connection_check("localhost.localdomain"))
426       assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")}
427       assert_raise(sslerr){ssl.post_connection_check("localhost")}
428       assert_raise(sslerr){ssl.post_connection_check("foo.example.com")}
429       cert = ssl.peer_cert
430       assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain"))
431       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1"))
432       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost"))
433       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com"))
434     }
435   end
436
437   def test_client_session
438     last_session = nil
439     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port|
440       2.times do
441         sock = TCPSocket.new("127.0.0.1", port)
442         # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?),
443         # when use default SSLContext. [ruby-dev:36167]
444         ctx = OpenSSL::SSL::SSLContext.new("TLSv1")
445         ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
446         ssl.sync_close = true
447         ssl.session = last_session if last_session
448         ssl.connect
449
450         session = ssl.session
451         if last_session
452           assert(ssl.session_reused?)
453
454           if session.respond_to?(:id)
455             assert_equal(session.id, last_session.id)
456           end
457           assert_equal(session.to_pem, last_session.to_pem)
458           assert_equal(session.to_der, last_session.to_der)
459           # Older version of OpenSSL may not be consistent.  Look up which versions later.
460           assert_equal(session.to_text, last_session.to_text)
461         else
462           assert(!ssl.session_reused?)
463         end
464         last_session = session
465
466         str = "x" * 100 + "\n"
467         ssl.puts(str)
468         assert_equal(str, ssl.gets)
469
470         ssl.close
471       end
472     end
473   end
474
475   def test_server_session
476     connections = 0
477     saved_session = nil
478
479     ctx_proc = Proc.new do |ctx, ssl|
480 # add test for session callbacks here
481     end
482
483     server_proc = Proc.new do |ctx, ssl|
484       session = ssl.session
485       stats = ctx.session_cache_stats
486
487       case connections
488       when 0
489         assert_equal(stats[:cache_num], 1)
490         assert_equal(stats[:cache_hits], 0)
491         assert_equal(stats[:cache_misses], 0)
492         assert(!ssl.session_reused?)
493       when 1
494         assert_equal(stats[:cache_num], 1)
495         assert_equal(stats[:cache_hits], 1)
496         assert_equal(stats[:cache_misses], 0)
497         assert(ssl.session_reused?)
498         ctx.session_remove(session)
499         saved_session = session
500       when 2
501         assert_equal(stats[:cache_num], 1)
502         assert_equal(stats[:cache_hits], 1)
503         assert_equal(stats[:cache_misses], 1)
504         assert(!ssl.session_reused?)
505         ctx.session_add(saved_session)
506       when 3
507         assert_equal(stats[:cache_num], 2)
508         assert_equal(stats[:cache_hits], 2)
509         assert_equal(stats[:cache_misses], 1)
510         assert(ssl.session_reused?)
511         ctx.flush_sessions(Time.now + 5000)
512       when 4
513         assert_equal(stats[:cache_num], 1)
514         assert_equal(stats[:cache_hits], 2)
515         assert_equal(stats[:cache_misses], 2)
516         assert(!ssl.session_reused?)
517         ctx.session_add(saved_session)
518       end
519       connections += 1
520       
521       readwrite_loop(ctx, ssl)
522     end
523
524     first_session = nil
525     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port|
526       10.times do |i|
527         sock = TCPSocket.new("127.0.0.1", port)
528         ctx = OpenSSL::SSL::SSLContext.new
529         if defined?(OpenSSL::SSL::OP_NO_TICKET)
530           # disable RFC4507 support
531           ctx.options = OpenSSL::SSL::OP_NO_TICKET
532         end
533         ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
534         ssl.sync_close = true
535         ssl.session = first_session if first_session
536         ssl.connect
537
538         session = ssl.session
539         if first_session
540           case i
541           when 1; assert(ssl.session_reused?)
542           when 2; assert(!ssl.session_reused?)
543           when 3; assert(ssl.session_reused?)
544           when 4; assert(!ssl.session_reused?)
545           when 5..10; assert(ssl.session_reused?)
546           end
547         end
548         first_session ||= session
549
550         str = "x" * 100 + "\n"
551         ssl.puts(str)
552         assert_equal(str, ssl.gets)
553
554         ssl.close
555       end
556     end
557   end
558 end
559
560 end