aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-05-31 23:25:07 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-06-06 11:29:39 +0900
commit62e5c73e03eb780a23d551672bea7ec92b0047ac (patch)
treeda0b603f4e3c45d55b5e85e65d8a5e0a4c258ca9
parent3d47d055b304de38da732ee9895933580ed98bd6 (diff)
downloadruby-62e5c73e03eb780a23d551672bea7ec92b0047ac.tar.gz
ext/openssl: add SSLContext#security_level, #security_level=
OpenSSL 1.1.0 introduced "security level" and these methods deal with it. This patch includes many test changes: setting the level to 0. The default security level is 1 and this prohibits aNULL ciphers.
-rw-r--r--ext/openssl/extconf.rb1
-rw-r--r--ext/openssl/ossl_ssl.c62
-rw-r--r--test/openssl/test_pair.rb12
-rw-r--r--test/openssl/test_ssl.rb12
-rw-r--r--test/openssl/utils.rb1
5 files changed, 88 insertions, 0 deletions
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index f5a6d8e87c..0b93aacbb2 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -146,6 +146,7 @@ have_func("SSL_SESSION_up_ref")
have_func("EVP_PKEY_up_ref")
OpenSSL.check_func_or_macro("SSL_CTX_set_tmp_ecdh_callback", "openssl/ssl.h") # removed
OpenSSL.check_func_or_macro("SSL_CTX_set_min_proto_version", "openssl/ssl.h")
+have_func("SSL_CTX_get_security_level")
Logging::message "=== Checking done. ===\n"
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index f0b8d80cb4..d9dd4b5c9f 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -1074,6 +1074,66 @@ ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
#endif
/*
+ * call-seq:
+ * ctx.security_level => 0, .., 5
+ *
+ * The security level for this context. This is new in OpenSSL 1.1.0 and
+ * always returns 0 if using older OpenSSL.
+ */
+static VALUE
+ossl_sslctx_get_security_level(VALUE self)
+{
+ SSL_CTX *ctx;
+ int i;
+
+ GetSSLCTX(self, ctx);
+ if (!ctx) {
+ rb_warning("SSL_CTX is not initialized.");
+ return Qnil;
+ }
+
+#if defined(HAVE_SSL_CTX_GET_SECURITY_LEVEL)
+ i = SSL_CTX_get_security_level(ctx);
+#else
+ i = 0;
+#endif
+ return INT2FIX(i);
+}
+
+/*
+ * call-seq:
+ * ctx.security_level = 0
+ * ctx.security_level = 5
+ *
+ * Sets the security level for this context. This is new in OpenSSL 1.1.0.
+ * If using older OpenSSL, setting a value other than 0 raises
+ * NotImplementedError.
+ *
+ * See the manpage of SSL_CTX_set_security_level(3) for details.
+ */
+static VALUE
+ossl_sslctx_set_security_level(VALUE self, VALUE v)
+{
+ SSL_CTX *ctx;
+
+ rb_check_frozen(self);
+
+ GetSSLCTX(self, ctx);
+ if (!ctx)
+ ossl_raise(eSSLError, "SSL_CTX is not initialized.");
+
+#if defined(HAVE_SSL_CTX_GET_SECURITY_LEVEL)
+ SSL_CTX_set_security_level(ctx, NUM2INT(v));
+#else
+ if (NUM2INT(v) != 0)
+ ossl_raise(rb_eNotImpError, "setting security level != 0 is not "
+ "supported in this version of OpenSSL");
+#endif
+
+ return v;
+}
+
+/*
* call-seq:
* ctx.session_add(session) -> true | false
*
@@ -2388,6 +2448,8 @@ Init_ossl_ssl(void)
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
+ rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0);
+ rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1);
rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb
index 86aa2798d7..4d4de1de9e 100644
--- a/test/openssl/test_pair.rb
+++ b/test/openssl/test_pair.rb
@@ -12,6 +12,7 @@ module OpenSSL::SSLPairM
port = 0
ctx = OpenSSL::SSL::SSLContext.new()
ctx.ciphers = "ADH"
+ ctx.security_level = 0
ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 }
tcps = create_tcp_server(host, port)
ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
@@ -22,6 +23,7 @@ module OpenSSL::SSLPairM
host = "127.0.0.1"
ctx = OpenSSL::SSL::SSLContext.new()
ctx.ciphers = "ADH"
+ ctx.security_level = 0
s = create_tcp_client(host, port)
ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
ssl.connect
@@ -324,6 +326,7 @@ module OpenSSL::TestPairM
def test_connect_works_when_setting_dh_callback_to_nil
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "DH"
+ ctx2.security_level = 0
ctx2.tmp_dh_callback = nil
sock1, sock2 = tcp_pair
s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
@@ -331,6 +334,7 @@ module OpenSSL::TestPairM
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "DH"
+ ctx1.security_level = 0
ctx1.tmp_dh_callback = nil
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
t = Thread.new { s1.connect }
@@ -350,12 +354,14 @@ module OpenSSL::TestPairM
def test_connect_without_setting_dh_callback
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "DH"
+ ctx2.security_level = 0
sock1, sock2 = tcp_pair
s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
accepted = s2.accept_nonblock(exception: false)
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "DH"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
t = Thread.new { s1.connect }
@@ -426,11 +432,13 @@ module OpenSSL::TestPairM
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "ECDH"
ctx1.ecdh_curves = "P-384:P-521"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "ECDH"
ctx2.ecdh_curves = "P-256:P-384"
+ ctx2.security_level = 0
s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
th = Thread.new { s1.accept }
@@ -451,6 +459,7 @@ module OpenSSL::TestPairM
def test_connect_accept_nonblock_no_exception
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "ADH"
+ ctx2.security_level = 0
ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 }
sock1, sock2 = tcp_pair
@@ -461,6 +470,7 @@ module OpenSSL::TestPairM
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "ADH"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
th = Thread.new do
rets = []
@@ -499,6 +509,7 @@ module OpenSSL::TestPairM
def test_connect_accept_nonblock
ctx = OpenSSL::SSL::SSLContext.new()
ctx.ciphers = "ADH"
+ ctx.security_level = 0
ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 }
sock1, sock2 = tcp_pair
@@ -522,6 +533,7 @@ module OpenSSL::TestPairM
sleep 0.1
ctx = OpenSSL::SSL::SSLContext.new()
ctx.ciphers = "ADH"
+ ctx.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx)
begin
sleep 0.2
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 9a717a4256..51f9e3d62d 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -424,6 +424,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
start_server(OpenSSL::SSL::VERIFY_NONE, true, {use_anon_cipher: true}){|server, port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.ciphers = "aNULL"
+ ctx.security_level = 0
server_connect(port, ctx) { |ssl|
msg = "Peer verification enabled, but no certificate received. Anonymous cipher suite " \
"ADH-AES256-GCM-SHA384 was negotiated. Anonymous suites must be disabled to use peer verification."
@@ -687,6 +688,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx3 = OpenSSL::SSL::SSLContext.new
ctx3.ciphers = "DH"
+ ctx3.security_level = 0
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "DH"
@@ -698,6 +700,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "DH"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
s1.hostname = hostname
@@ -720,6 +723,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "DH"
+ ctx2.security_level = 0
ctx2.servername_cb = lambda { |args| Object.new }
sock1, sock2 = socketpair
@@ -728,6 +732,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "DH"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
s1.hostname = hostname
@@ -752,6 +757,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx3 = OpenSSL::SSL::SSLContext.new
ctx3.ciphers = "DH"
+ ctx3.security_level = 0
assert_not_predicate ctx3, :frozen?
ctx2 = OpenSSL::SSL::SSLContext.new
@@ -764,6 +770,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "DH"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
s1.hostname = hostname
@@ -785,6 +792,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "DH"
+ ctx2.security_level = 0
ctx2.servername_cb = lambda { |args| nil }
sock1, sock2 = socketpair
@@ -793,6 +801,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "DH"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
s1.hostname = hostname
@@ -815,6 +824,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ciphers = "DH"
+ ctx2.security_level = 0
ctx2.servername_cb = lambda do |args|
cb_socket = args[0]
lambda_called = args[1]
@@ -827,6 +837,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ciphers = "DH"
+ ctx1.security_level = 0
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
s1.hostname = hostname
@@ -1171,6 +1182,7 @@ end
# test it doesn't cause a segmentation fault
ctx = OpenSSL::SSL::SSLContext.new
ctx.ciphers = "aNULL"
+ ctx.security_level = 0
sock1, sock2 = socketpair
ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx)
diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
index 82a018aabb..dff5b0cf4d 100644
--- a/test/openssl/utils.rb
+++ b/test/openssl/utils.rb
@@ -277,6 +277,7 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
ctx = OpenSSL::SSL::SSLContext.new
ctx.ciphers = "ADH-AES256-GCM-SHA384" if use_anon_cipher
+ ctx.security_level = 0 if use_anon_cipher
ctx.cert_store = store
#ctx.extra_chain_cert = [ ca_cert ]
ctx.cert = @svr_cert