mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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:
parent
d657d4feb3
commit
45acd59d2d
5 changed files with 218 additions and 36 deletions
|
@ -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
|
||||
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)
|
||||
def readwrite_loop(ctx, ssl)
|
||||
while line = ssl.gets
|
||||
if line =~ /^STARTTLS$/
|
||||
ssl.accept
|
||||
next
|
||||
end
|
||||
block.call(server, port.to_i)
|
||||
ssl.write(line)
|
||||
end
|
||||
rescue OpenSSL::SSL::SSLError
|
||||
rescue IOError
|
||||
ensure
|
||||
if server
|
||||
Process.kill(:KILL, pid)
|
||||
server.close
|
||||
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
|
||||
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
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue