* ext/openssl/ossl_ssl.c: Switch stats hash key from string to symbol.

New method SSLContext#setup to aid C extension writers.
* test/openssl/test_ssl.rb: Add tests for new method and sessions.
  Use threads for ssl server instead of forking.
* ext/openssl/ossl_version.h: Bump version.
* ext/openssl/ossl_x509ext.c: Fix warnings.
* test/openssl/utils.rb: Fix warnings.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16111 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
technorama 2008-04-20 22:32:06 +00:00
Родитель d657d4feb3
Коммит 45acd59d2d
5 изменённых файлов: 218 добавлений и 36 удалений

Просмотреть файл

@ -446,6 +446,14 @@ ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg)
return i;
}
/*
* call-seq:
* ctx.setup => Qtrue # first time
* ctx.setup => nil # thereafter
*
* This method is called automatically when a new SSLSocket is created.
* Normally you do not need to call this method (unless you are writing an extension in C).
*/
static VALUE
ossl_sslctx_setup(VALUE self)
{
@ -779,18 +787,18 @@ ossl_sslctx_get_session_cache_stats(VALUE self)
Data_Get_Struct(self, SSL_CTX, ctx);
hash = rb_hash_new();
rb_hash_aset(hash, rb_str_new2("cache_num"), LONG2NUM(SSL_CTX_sess_number(ctx)));
rb_hash_aset(hash, rb_str_new2("connect"), LONG2NUM(SSL_CTX_sess_connect(ctx)));
rb_hash_aset(hash, rb_str_new2("connect_good"), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
rb_hash_aset(hash, rb_str_new2("connect_renegotiate"), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
rb_hash_aset(hash, rb_str_new2("accept"), LONG2NUM(SSL_CTX_sess_accept(ctx)));
rb_hash_aset(hash, rb_str_new2("accept_good"), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
rb_hash_aset(hash, rb_str_new2("accept_renegotiate"), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
rb_hash_aset(hash, rb_str_new2("cache_hits"), LONG2NUM(SSL_CTX_sess_hits(ctx)));
rb_hash_aset(hash, rb_str_new2("cb_hits"), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
rb_hash_aset(hash, rb_str_new2("cache_misses"), LONG2NUM(SSL_CTX_sess_misses(ctx)));
rb_hash_aset(hash, rb_str_new2("cache_full"), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
rb_hash_aset(hash, rb_str_new2("timeouts"), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));
return hash;
}
@ -1347,6 +1355,8 @@ Init_ossl_ssl()
mSSL = rb_define_module_under(mOSSL, "SSL");
eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
Init_ossl_ssl_session();
/* class SSLContext
*
* The following attributes are available but don't show up in rdoc.
@ -1365,6 +1375,8 @@ Init_ossl_ssl()
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF));
rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */

Просмотреть файл

@ -11,6 +11,6 @@
#if !defined(_OSSL_VERSION_H_)
#define _OSSL_VERSION_H_
#define OSSL_VERSION "1.0.0"
#define OSSL_VERSION "1.1.0"
#endif /* _OSSL_VERSION_H_ */

Просмотреть файл

@ -110,6 +110,7 @@ ossl_x509extfactory_alloc(VALUE klass)
VALUE obj;
MakeX509ExtFactory(klass, obj, ctx);
rb_iv_set(obj, "@config", Qnil);
return obj;
}

Просмотреть файл

@ -58,29 +58,78 @@ class OpenSSL::TestSSL < Test::Unit::TestCase
OpenSSL::TestUtils.issue_crl(*arg)
end
def start_server(port0, verify_mode, start_immediately, &block)
server = nil
def readwrite_loop(ctx, ssl)
while line = ssl.gets
if line =~ /^STARTTLS$/
ssl.accept
next
end
ssl.write(line)
end
rescue OpenSSL::SSL::SSLError
rescue IOError
ensure
ssl.close rescue nil
end
def server_loop(ctx, ssls, server_proc)
loop do
ssl = nil
begin
ssl = ssls.accept
rescue OpenSSL::SSL::SSLError
retry
end
Thread.start do
Thread.current.abort_on_exception = true
server_proc.call(ctx, ssl)
end
end
rescue Errno::EBADF, IOError
end
def start_server(port0, verify_mode, start_immediately, args = {}, &block)
ctx_proc = args[:ctx_proc]
server_proc = args[:server_proc]
server_proc ||= method(:readwrite_loop)
store = OpenSSL::X509::Store.new
store.add_cert(@ca_cert)
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
ctx = OpenSSL::SSL::SSLContext.new
ctx.cert_store = store
#ctx.extra_chain_cert = [ ca_cert ]
ctx.cert = @svr_cert
ctx.key = @svr_key
ctx.verify_mode = verify_mode
ctx_proc.call(ctx) if ctx_proc
Socket.do_not_reverse_lookup = true
tcps = nil
port = port0
begin
cmd = [RUBY]
cmd << "-d" if $DEBUG
cmd << SSL_SERVER << port0.to_s << verify_mode.to_s
cmd << (start_immediately ? "yes" : "no")
server = IO.popen(cmd, "w+")
server.write(@ca_cert.to_pem)
server.write(@svr_cert.to_pem)
server.write(@svr_key.to_pem)
pid = Integer(server.gets)
if port = server.gets
if $DEBUG
$stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, pid, port)
end
block.call(server, port.to_i)
tcps = TCPServer.new("127.0.0.1", port)
rescue Errno::EADDRINUSE
port += 1
retry
end
ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
ssls.start_immediately = start_immediately
begin
server = Thread.new do
Thread.current.abort_on_exception = true
server_loop(ctx, ssls, server_proc)
end
$stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, pid, port) if $DEBUG
block.call(server, port.to_i)
ensure
if server
Process.kill(:KILL, pid)
server.close
end
tcps.close if (tcps)
server.join if (server)
end
end
@ -93,6 +142,12 @@ class OpenSSL::TestSSL < Test::Unit::TestCase
ssl.connect
end
def test_ctx_setup
ctx = OpenSSL::SSL::SSLContext.new
assert_equal(ctx.setup, true)
assert_equal(ctx.setup, nil)
end
def test_connect_and_close
start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
sock = TCPSocket.new("127.0.0.1", port)
@ -182,7 +237,7 @@ class OpenSSL::TestSSL < Test::Unit::TestCase
called = nil
ctx = OpenSSL::SSL::SSLContext.new
ctx.client_cert_cb = Proc.new{|ssl|
ctx.client_cert_cb = Proc.new{ |sslconn|
called = true
[@cli_cert, @cli_key]
}
@ -360,6 +415,120 @@ class OpenSSL::TestSSL < Test::Unit::TestCase
assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com"))
}
end
def test_client_session
last_session = nil
start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port|
2.times do
sock = TCPSocket.new("127.0.0.1", port)
ssl = OpenSSL::SSL::SSLSocket.new(sock)
ssl.sync_close = true
ssl.session = last_session if last_session
ssl.connect
session = ssl.session
if last_session
assert(ssl.session_reused?)
if session.respond_to?(:id)
assert_equal(session.id, last_session.id)
end
assert_equal(session.to_pem, last_session.to_pem)
assert_equal(session.to_der, last_session.to_der)
# Older version of OpenSSL may not be consistent. Look up which versions later.
assert_equal(session.to_text, last_session.to_text)
else
assert(!ssl.session_reused?)
end
last_session = session
str = "x" * 100 + "\n"
ssl.puts(str)
assert_equal(str, ssl.gets)
ssl.close
end
end
end
def test_server_session
connections = 0
saved_session = nil
ctx_proc = Proc.new do |ctx, ssl|
# add test for session callbacks here
end
server_proc = Proc.new do |ctx, ssl|
session = ssl.session
stats = ctx.session_cache_stats
case connections
when 0
assert_equal(stats[:cache_num], 1)
assert_equal(stats[:cache_hits], 0)
assert_equal(stats[:cache_misses], 0)
assert(!ssl.session_reused?)
when 1
assert_equal(stats[:cache_num], 1)
assert_equal(stats[:cache_hits], 1)
assert_equal(stats[:cache_misses], 0)
assert(ssl.session_reused?)
ctx.session_remove(session)
saved_session = session
when 2
assert_equal(stats[:cache_num], 1)
assert_equal(stats[:cache_hits], 1)
assert_equal(stats[:cache_misses], 1)
assert(!ssl.session_reused?)
ctx.session_add(saved_session)
when 3
assert_equal(stats[:cache_num], 2)
assert_equal(stats[:cache_hits], 2)
assert_equal(stats[:cache_misses], 1)
assert(ssl.session_reused?)
ctx.flush_sessions(Time.now + 5000)
when 4
assert_equal(stats[:cache_num], 1)
assert_equal(stats[:cache_hits], 2)
assert_equal(stats[:cache_misses], 2)
assert(!ssl.session_reused?)
ctx.session_add(saved_session)
end
connections += 1
readwrite_loop(ctx, ssl)
end
first_session = nil
start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port|
10.times do |i|
sock = TCPSocket.new("127.0.0.1", port)
ssl = OpenSSL::SSL::SSLSocket.new(sock)
ssl.sync_close = true
ssl.session = first_session if first_session
ssl.connect
session = ssl.session
if first_session
case i
when 1; assert(ssl.session_reused?)
when 2; assert(!ssl.session_reused?)
when 3; assert(ssl.session_reused?)
when 4; assert(!ssl.session_reused?)
when 5..10; assert(ssl.session_reused?)
end
end
first_session ||= session
str = "x" * 100 + "\n"
ssl.puts(str)
assert_equal(str, ssl.gets)
ssl.close
end
end
end
end
end

Просмотреть файл

@ -103,9 +103,9 @@ Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S
crl.version = 1
crl.last_update = lastup
crl.next_update = nextup
revoke_info.each{|serial, time, reason_code|
revoke_info.each{|rserial, time, reason_code|
revoked = OpenSSL::X509::Revoked.new
revoked.serial = serial
revoked.serial = rserial
revoked.time = time
enum = OpenSSL::ASN1::Enumerated(reason_code)
ext = OpenSSL::X509::Extension.new("CRLReason", enum)