diff options
author | emboss <emboss@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-02-09 17:20:52 +0000 |
---|---|---|
committer | emboss <emboss@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-02-09 17:20:52 +0000 |
commit | 85fd9aadd13fdf685395cf605007e3fcdf40336f (patch) | |
tree | 4d6531199ad2da303e7d74d3855b4abb0fdaa42e | |
parent | 84a48ac725837fee7935b39d45609825c9a4fcc6 (diff) |
* backport r34482 from trunk
* ext/openssl/ossl_ssl.c: Add SSL constants and allow to unset SSL
option to prevent BEAST attack. See [Bug #5353].
In OpenSSL, OP_DONT_INSERT_EMPTY_FRAGMENTS is used to prevent
TLS-CBC-IV vulunerability described at
http://www.openssl.org/~bodo/tls-cbc.txt
It's known issue of TLSv1/SSLv3 but it attracts lots of attention
these days as BEAST attack. (CVE-2011-3389)
Until now ossl sets OP_ALL at SSLContext allocation and call
SSL_CTX_set_options at connection. SSL_CTX_set_options updates the
value by using |= so bits set by OP_ALL cannot be unset afterwards.
This commit changes to call SSL_CTX_set_options only 1 time for each
SSLContext. It sets the specified value if SSLContext#options= are
called and sets OP_ALL if not.
To help users to unset bits in OP_ALL, this commit also adds several
constant to SSL such as
OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS. These constants were
not exposed in Ruby because there's no way to unset bits in OP_ALL
before.
Following is an example to enable 0/n split for BEAST prevention.
ctx.options = OP_ALL & ~OP_DONT_INSERT_EMPTY_FRAGMENTS
* test/openssl/test_ssl.rb: Test above option exists.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_2@34525 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 32 | ||||
-rw-r--r-- | ext/openssl/ossl_ssl.c | 31 | ||||
-rw-r--r-- | test/openssl/test_ssl.rb | 15 |
3 files changed, 65 insertions, 13 deletions
@@ -1,3 +1,35 @@ +Fri Feb 9 02:11:19 2012 Martin Bosslet <Martin.Bosslet@googlemail.com> + + * backport r34482 from trunk + + * ext/openssl/ossl_ssl.c: Add SSL constants and allow to unset SSL + option to prevent BEAST attack. See [Bug #5353]. + + In OpenSSL, OP_DONT_INSERT_EMPTY_FRAGMENTS is used to prevent + TLS-CBC-IV vulunerability described at + http://www.openssl.org/~bodo/tls-cbc.txt + It's known issue of TLSv1/SSLv3 but it attracts lots of attention + these days as BEAST attack. (CVE-2011-3389) + + Until now ossl sets OP_ALL at SSLContext allocation and call + SSL_CTX_set_options at connection. SSL_CTX_set_options updates the + value by using |= so bits set by OP_ALL cannot be unset afterwards. + This commit changes to call SSL_CTX_set_options only 1 time for each + SSLContext. It sets the specified value if SSLContext#options= are + called and sets OP_ALL if not. + + To help users to unset bits in OP_ALL, this commit also adds several + constant to SSL such as + OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS. These constants were + not exposed in Ruby because there's no way to unset bits in OP_ALL + before. + + Following is an example to enable 0/n split for BEAST prevention. + + ctx.options = OP_ALL & ~OP_DONT_INSERT_EMPTY_FRAGMENTS + + * test/openssl/test_ssl.rb: Test above option exists. + Fri Jul 1 11:41:12 2011 NARUSE, Yui <naruse@ruby-lang.org> * string.c (tr_trans): free heap ptr when the str is not embeded. diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 23bfdf3b79..7de1a6bb7a 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -146,7 +146,6 @@ ossl_sslctx_s_alloc(VALUE klass) ossl_raise(eSSLError, "SSL_CTX_new:"); } SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); - SSL_CTX_set_options(ctx, SSL_OP_ALL); return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx); } @@ -628,7 +627,11 @@ ossl_sslctx_setup(VALUE self) if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); val = ossl_sslctx_get_options(self); - if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val)); + if(!NIL_P(val)) { + SSL_CTX_set_options(ctx, NUM2LONG(val)); + } else { + SSL_CTX_set_options(ctx, SSL_OP_ALL); + } rb_obj_freeze(self); val = ossl_sslctx_get_sess_id_ctx(self); @@ -1653,18 +1656,20 @@ Init_ossl_ssl() ossl_ssl_def_const(VERIFY_PEER); ossl_ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT); ossl_ssl_def_const(VERIFY_CLIENT_ONCE); - /* Not introduce constants included in OP_ALL such as... - * ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG); - * ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG); - * ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); - * ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG); - * ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER); - * ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING); - * ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG); - * ossl_ssl_def_const(OP_TLS_D5_BUG); - * ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG); - * ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS); + /* Introduce constants included in OP_ALL. These constants are mostly for + * unset some bits in OP_ALL such as; + * ctx.options = OP_ALL & ~OP_DONT_INSERT_EMPTY_FRAGMENTS */ + ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG); + ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG); + ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); + ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG); + ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER); + ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING); + ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG); + ossl_ssl_def_const(OP_TLS_D5_BUG); + ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG); + ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS); ossl_ssl_def_const(OP_ALL); #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 6b9f335822..42bbfff002 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -670,6 +670,21 @@ __EOS__ end end end + + def test_unset_OP_ALL + ctx_proc = Proc.new { |ctx| + ctx.options = OpenSSL::SSL::OP_ALL & ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS + } + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + ssl.puts('hello') + assert_equal("hello\n", ssl.gets) + ssl.close + } + end end end |