summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-08-28 22:20:51 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-09-03 11:22:54 +0900
commit5653599e150bd92d8631858fe6e0def1f9a3c33d (patch)
treea257929b8e5e099f6a9fcd02790d76e065a26597
parent18603949d3161e109803b7c379936c3a487ef8d0 (diff)
downloadruby-openssl-5653599e150bd92d8631858fe6e0def1f9a3c33d.tar.gz
ssl: rework SSLContext#ssl_version=
Reimplement SSLContext#ssl_version= as a wrapper around SSLContext#min_version= and #max_version=. SSLContext#ssl_version= used to call SSL_CTX_set_ssl_version() which replaces the SSL method used for the connections created from the SSL context. This is mainly used for forcing a specific SSL/TLS protocol version. As of OpenSSL 1.1.0, however, use of the version-specific SSL methods such as TLSv1_method() is deprecated. Follow the current recommendation -- to use the generic SSL method always and to control the supported version range by SSL_CTX_set_{min,max}_proto_version(). Actually, we have already started doing a similar thing when the extension is compiled with OpenSSL 1.1.0. OpenSSL::SSL::SSLContext::METHODS, which contained the possible names of SSL methods, is not useful anymore. It is now deprecate_constant-ed.
-rw-r--r--ext/openssl/extconf.rb5
-rw-r--r--ext/openssl/ossl_ssl.c95
-rw-r--r--lib/openssl/ssl.rb45
-rw-r--r--test/test_ssl.rb11
4 files changed, 56 insertions, 100 deletions
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 0f099fc3..5212903b 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -104,11 +104,6 @@ end
Logging::message "=== Checking for OpenSSL features... ===\n"
# compile options
-
-# SSLv2 and SSLv3 may be removed in future versions of OpenSSL, and even macros
-# like OPENSSL_NO_SSL2 may not be defined.
-have_func("SSLv2_method")
-have_func("SSLv3_method")
have_func("RAND_egd")
engines = %w{builtin_engines openbsd_dev_crypto dynamic 4758cca aep atalla chil
cswift nuron sureware ubsec padlock capi gmp gost cryptodev aesni}
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 51683d60..18d5f5e9 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -46,44 +46,6 @@ static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode,
id_i_verify_hostname;
static ID id_i_io, id_i_context, id_i_hostname;
-/*
- * SSLContext class
- */
-static const struct {
- const char *name;
- const SSL_METHOD *(*func)(void);
- int version;
-} ossl_ssl_method_tab[] = {
-#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION)
-#define OSSL_SSL_METHOD_ENTRY(name, version) \
- { #name, TLS_method, version }, \
- { #name"_server", TLS_server_method, version }, \
- { #name"_client", TLS_client_method, version }
-#else
-#define OSSL_SSL_METHOD_ENTRY(name, version) \
- { #name, name##_method, version }, \
- { #name"_server", name##_server_method, version }, \
- { #name"_client", name##_client_method, version }
-#endif
-#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL2_METHOD) && defined(HAVE_SSLV2_METHOD)
- OSSL_SSL_METHOD_ENTRY(SSLv2, SSL2_VERSION),
-#endif
-#if !defined(OPENSSL_NO_SSL3) && !defined(OPENSSL_NO_SSL3_METHOD) && defined(HAVE_SSLV3_METHOD)
- OSSL_SSL_METHOD_ENTRY(SSLv3, SSL3_VERSION),
-#endif
-#if !defined(OPENSSL_NO_TLS1) && !defined(OPENSSL_NO_TLS1_METHOD)
- OSSL_SSL_METHOD_ENTRY(TLSv1, TLS1_VERSION),
-#endif
-#if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_1_METHOD)
- OSSL_SSL_METHOD_ENTRY(TLSv1_1, TLS1_1_VERSION),
-#endif
-#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_2_METHOD)
- OSSL_SSL_METHOD_ENTRY(TLSv1_2, TLS1_2_VERSION),
-#endif
- OSSL_SSL_METHOD_ENTRY(SSLv23, 0),
-#undef OSSL_SSL_METHOD_ENTRY
-};
-
static int ossl_ssl_ex_vcb_idx;
static int ossl_ssl_ex_ptr_idx;
static int ossl_sslctx_ex_ptr_idx;
@@ -148,51 +110,6 @@ ossl_sslctx_s_alloc(VALUE klass)
return obj;
}
-/*
- * call-seq:
- * ctx.ssl_version = :TLSv1
- * ctx.ssl_version = "SSLv23_client"
- *
- * Sets the SSL/TLS protocol version for the context. This forces connections to
- * use only the specified protocol version.
- *
- * You can get a list of valid versions with OpenSSL::SSL::SSLContext::METHODS
- */
-static VALUE
-ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
-{
- SSL_CTX *ctx;
- const char *s;
- VALUE m = ssl_method;
- int i;
-
- GetSSLCTX(self, ctx);
- if (RB_TYPE_P(ssl_method, T_SYMBOL))
- m = rb_sym2str(ssl_method);
- s = StringValueCStr(m);
- for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
- if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) {
-#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION)
- int version = ossl_ssl_method_tab[i].version;
-#endif
- const SSL_METHOD *method = ossl_ssl_method_tab[i].func();
-
- if (SSL_CTX_set_ssl_version(ctx, method) != 1)
- ossl_raise(eSSLError, "SSL_CTX_set_ssl_version");
-
-#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION)
- if (!SSL_CTX_set_min_proto_version(ctx, version))
- ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version");
- if (!SSL_CTX_set_max_proto_version(ctx, version))
- ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version");
-#endif
- return ssl_method;
- }
- }
-
- ossl_raise(rb_eArgError, "unknown SSL method `%"PRIsVALUE"'.", m);
-}
-
static int
parse_proto_version(VALUE str)
{
@@ -2333,9 +2250,6 @@ ossl_ssl_tmp_key(VALUE self)
void
Init_ossl_ssl(void)
{
- int i;
- VALUE ary;
-
#if 0
mOSSL = rb_define_module("OpenSSL");
eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
@@ -2632,7 +2546,6 @@ Init_ossl_ssl(void)
rb_define_alias(cSSLContext, "ssl_timeout", "timeout");
rb_define_alias(cSSLContext, "ssl_timeout=", "timeout=");
- rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1);
rb_define_private_method(cSSLContext, "set_minmax_proto_version",
ossl_sslctx_set_minmax_proto_version, 2);
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
@@ -2702,14 +2615,6 @@ Init_ossl_ssl(void)
rb_define_method(cSSLContext, "options", ossl_sslctx_get_options, 0);
rb_define_method(cSSLContext, "options=", ossl_sslctx_set_options, 1);
- ary = rb_ary_new2(numberof(ossl_ssl_method_tab));
- for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
- rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name)));
- }
- rb_obj_freeze(ary);
- /* The list of available SSL/TLS methods */
- rb_define_const(cSSLContext, "METHODS", ary);
-
/*
* Document-class: OpenSSL::SSL::SSLSocket
*/
diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb
index 04238a4e..a628648e 100644
--- a/lib/openssl/ssl.rb
+++ b/lib/openssl/ssl.rb
@@ -181,6 +181,51 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
set_minmax_proto_version(@min_proto_version ||= nil, version)
@max_proto_version = version
end
+
+ # call-seq:
+ # ctx.ssl_version = :TLSv1
+ # ctx.ssl_version = "SSLv23"
+ #
+ # Sets the SSL/TLS protocol version for the context. This forces
+ # connections to use only the specified protocol version. This is
+ # deprecated and only provided for backwards compatibility. Use
+ # #min_version= and #max_version= instead.
+ #
+ # === History
+ # As the name hints, this used to call the SSL_CTX_set_ssl_version()
+ # function which sets the SSL method used for connections created from
+ # the context. As of Ruby/OpenSSL 2.1, this accessor method is
+ # implemented to call #min_version= and #max_version= instead.
+ def ssl_version=(meth)
+ meth = meth.to_s if meth.is_a?(Symbol)
+ if /(?<type>_client|_server)\z/ =~ meth
+ meth = $`
+ if $VERBOSE
+ warn "#{caller(1)[0]}: method type #{type.inspect} is ignored"
+ end
+ end
+ version = METHODS_MAP[meth.intern] or
+ raise ArgumentError, "unknown SSL method `%s'" % meth
+ set_minmax_proto_version(version, version)
+ @min_proto_version = @max_proto_version = version
+ end
+
+ METHODS_MAP = {
+ SSLv23: 0,
+ SSLv2: OpenSSL::SSL::SSL2_VERSION,
+ SSLv3: OpenSSL::SSL::SSL3_VERSION,
+ TLSv1: OpenSSL::SSL::TLS1_VERSION,
+ TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION,
+ TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION,
+ }.freeze
+ private_constant :METHODS_MAP
+
+ # The list of available SSL/TLS methods. This constant is only provided
+ # for backwards compatibility.
+ METHODS = METHODS_MAP.flat_map { |name,|
+ [name, :"#{name}_client", :"#{name}_server"]
+ }.freeze
+ deprecate_constant :METHODS
end
module SocketForwarder
diff --git a/test/test_ssl.rb b/test/test_ssl.rb
index 0bf2352c..3f17ab0d 100644
--- a/test/test_ssl.rb
+++ b/test/test_ssl.rb
@@ -969,6 +969,17 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
end
+ def test_ssl_methods_constant
+ EnvUtil.suppress_warning { # Deprecated in v2.1.0
+ base = [:TLSv1_2, :TLSv1_1, :TLSv1, :SSLv3, :SSLv2, :SSLv23]
+ base.each do |name|
+ assert_include OpenSSL::SSL::SSLContext::METHODS, name
+ assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_client"
+ assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_server"
+ end
+ }
+ end
+
def test_renegotiation_cb
num_handshakes = 0
renegotiation_cb = Proc.new { |ssl| num_handshakes += 1 }