[前][次][番号順一覧][スレッド一覧]

ruby-changes:72469

From: twkmd12 <ko1@a...>
Date: Sat, 9 Jul 2022 00:31:53 +0900 (JST)
Subject: [ruby-changes:72469] 09daf78fb5 (master): [ruby/openssl] Add 'ciphersuites=' method to allow setting of TLSv1.3 cipher suites along with some unit tests (https://github.com/ruby/openssl/pull/493)

https://git.ruby-lang.org/ruby.git/commit/?id=09daf78fb5

From 09daf78fb59a8b280887ad1120a57776b5d82e17 Mon Sep 17 00:00:00 2001
From: twkmd12 <95775763+twkmd12@u...>
Date: Tue, 1 Feb 2022 04:12:23 -0500
Subject: [ruby/openssl] Add 'ciphersuites=' method to allow setting of TLSv1.3
 cipher suites along with some unit tests
 (https://github.com/ruby/openssl/pull/493)

Add OpenSSL::SSL::SSLContext#ciphersuites= method along with unit tests.

https://github.com/ruby/openssl/commit/12250c7cef
---
 ext/openssl/extconf.rb   |  1 +
 ext/openssl/ossl_ssl.c   | 78 ++++++++++++++++++++++++++++++++----------
 test/openssl/test_ssl.rb | 89 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 150 insertions(+), 18 deletions(-)

diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index d014c60306..cc2b1f8ba2 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -169,6 +169,7 @@ have_func("SSL_CTX_set_post_handshake_auth") https://github.com/ruby/ruby/blob/trunk/ext/openssl/extconf.rb#L169
 
 # added in 1.1.1
 have_func("EVP_PKEY_check")
+have_func("SSL_CTX_set_ciphersuites")
 
 # added in 3.0.0
 openssl_3 =
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 9a0682a7cd..af262d9f56 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -959,27 +959,13 @@ ossl_sslctx_get_ciphers(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L959
     return ary;
 }
 
-/*
- * call-seq:
- *    ctx.ciphers = "cipher1:cipher2:..."
- *    ctx.ciphers = [name, ...]
- *    ctx.ciphers = [[name, version, bits, alg_bits], ...]
- *
- * Sets the list of available cipher suites for this context.  Note in a server
- * context some ciphers require the appropriate certificates.  For example, an
- * RSA cipher suite can only be chosen when an RSA certificate is available.
- */
 static VALUE
-ossl_sslctx_set_ciphers(VALUE self, VALUE v)
+build_cipher_string(VALUE v)
 {
-    SSL_CTX *ctx;
     VALUE str, elem;
     int i;
 
-    rb_check_frozen(self);
-    if (NIL_P(v))
-	return v;
-    else if (RB_TYPE_P(v, T_ARRAY)) {
+    if (RB_TYPE_P(v, T_ARRAY)) {
         str = rb_str_new(0, 0);
         for (i = 0; i < RARRAY_LEN(v); i++) {
             elem = rb_ary_entry(v, i);
@@ -993,14 +979,67 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L979
         StringValue(str);
     }
 
+    return str;
+}
+
+/*
+ * call-seq:
+ *    ctx.ciphers = "cipher1:cipher2:..."
+ *    ctx.ciphers = [name, ...]
+ *    ctx.ciphers = [[name, version, bits, alg_bits], ...]
+ *
+ * Sets the list of available cipher suites for this context.  Note in a server
+ * context some ciphers require the appropriate certificates.  For example, an
+ * RSA cipher suite can only be chosen when an RSA certificate is available.
+ */
+static VALUE
+ossl_sslctx_set_ciphers(VALUE self, VALUE v)
+{
+    SSL_CTX *ctx;
+    VALUE str;
+
+    rb_check_frozen(self);
+    if (NIL_P(v))
+        return v;
+
+    str = build_cipher_string(v);
+
     GetSSLCTX(self, ctx);
-    if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) {
+    if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str)))
         ossl_raise(eSSLError, "SSL_CTX_set_cipher_list");
-    }
 
     return v;
 }
 
+#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
+/*
+ * call-seq:
+ *    ctx.ciphersuites = "cipher1:cipher2:..."
+ *    ctx.ciphersuites = [name, ...]
+ *    ctx.ciphersuites = [[name, version, bits, alg_bits], ...]
+ *
+ * Sets the list of available TLSv1.3 cipher suites for this context.
+ */
+static VALUE
+ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
+{
+    SSL_CTX *ctx;
+    VALUE str;
+
+    rb_check_frozen(self);
+    if (NIL_P(v))
+        return v;
+
+    str = build_cipher_string(v);
+
+    GetSSLCTX(self, ctx);
+    if (!SSL_CTX_set_ciphersuites(ctx, StringValueCStr(str)))
+        ossl_raise(eSSLError, "SSL_CTX_set_ciphersuites");
+
+    return v;
+}
+#endif
+
 #ifndef OPENSSL_NO_DH
 /*
  * call-seq:
@@ -2703,6 +2742,9 @@ Init_ossl_ssl(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L2742
 			     ossl_sslctx_set_minmax_proto_version, 2);
     rb_define_method(cSSLContext, "ciphers",     ossl_sslctx_get_ciphers, 0);
     rb_define_method(cSSLContext, "ciphers=",    ossl_sslctx_set_ciphers, 1);
+#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
+    rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1);
+#endif
 #ifndef OPENSSL_NO_DH
     rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1);
 #endif
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 39964bf493..b3d7cba6e6 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -1569,6 +1569,95 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L1569
     end
   end
 
+  def test_ciphersuites_method_tls_connection
+    ssl_ctx = OpenSSL::SSL::SSLContext.new
+    if !tls13_supported? || !ssl_ctx.respond_to?(:ciphersuites=)
+      pend 'TLS 1.3 not supported'
+    end
+
+    csuite = ['TLS_AES_128_GCM_SHA256', 'TLSv1.3', 128, 128]
+    inputs = [csuite[0], [csuite[0]], [csuite]]
+
+    start_server do |port|
+      inputs.each do |input|
+        cli_ctx = OpenSSL::SSL::SSLContext.new
+        cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION
+        cli_ctx.ciphersuites = input
+
+        server_connect(port, cli_ctx) do |ssl|
+          assert_equal('TLSv1.3', ssl.ssl_version)
+          assert_equal(csuite[0], ssl.cipher[0])
+          ssl.puts('abc'); assert_equal("abc\n", ssl.gets)
+        end
+      end
+    end
+  end
+
+  def test_ciphersuites_method_nil_argument
+    ssl_ctx = OpenSSL::SSL::SSLContext.new
+    pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=)
+
+    assert_nothing_raised { ssl_ctx.ciphersuites = nil }
+  end
+
+  def test_ciphersuites_method_frozen_object
+    ssl_ctx = OpenSSL::SSL::SSLContext.new
+    pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=)
+
+    ssl_ctx.freeze
+    assert_raise(FrozenError) { ssl_ctx.ciphersuites = 'TLS_AES_256_GCM_SHA384' }
+  end
+
+  def test_ciphersuites_method_bogus_csuite
+    ssl_ctx = OpenSSL::SSL::SSLContext.new
+    pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=)
+
+    assert_raise_with_message(
+      OpenSSL::SSL::SSLError,
+      /SSL_CTX_set_ciphersuites: no cipher match/i
+    ) { ssl_ctx.ciphersuites = 'BOGUS' }
+  end
+
+  def test_ciphers_method_tls_connection
+    csuite = ['ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256, 256]
+    inputs = [csuite[0], [csuite[0]], [csuite]]
+
+    start_server do |port|
+      inputs.each do |input|
+        cli_ctx = OpenSSL::SSL::SSLContext.new
+        cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
+        cli_ctx.ciphers = input
+
+        server_connect(port, cli_ctx) do |ssl|
+          assert_equal('TLSv1.2', ssl.ssl_version)
+          assert_equal(csuite[0], ssl.cipher[0])
+          ssl.puts('abc'); assert_equal("abc\n", ssl.gets)
+        end
+      end
+    end
+  end
+
+  def test_ciphers_method_nil_argument
+    ssl_ctx = OpenSSL::SSL::SSLContext.new
+    assert_nothing_raised { ssl_ctx.ciphers = nil }
+  end
+
+  def test_ciphers_method_frozen_object
+    ssl_ctx = OpenSSL::SSL::SSLContext.new
+
+    ssl_ctx.freeze
+    assert_raise(FrozenError) { ssl_ctx.ciphers = 'ECDHE-RSA-AES128-SHA' }
+  end
+
+  def test_ciphers_method_bogus_csuite
+    ssl_ctx = OpenSSL::SSL::SSLContext.new
+
+    assert_raise_with_message(
+      OpenSSL::SSL::SSLError,
+      /SSL_CTX_set_cipher_list: no cipher match/i
+    ) { ssl_ctx.ciphers = 'BOGUS' }
+  end
+
   def test_connect_works_when_setting_dh_callback_to_nil
     ctx_proc = -> ctx {
       ctx.max_version = :TLS1_2
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]