diff --git a/ext/puma_http11/mini_ssl.c b/ext/puma_http11/mini_ssl.c index 607f6ea8..6312c60b 100644 --- a/ext/puma_http11/mini_ssl.c +++ b/ext/puma_http11/mini_ssl.c @@ -142,7 +142,7 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) { VALUE obj; SSL_CTX* ctx; SSL* ssl; - int ssl_options; + int min, ssl_options; ms_conn* conn = engine_alloc(self, &obj); @@ -168,6 +168,9 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) { ID sym_no_tlsv1 = rb_intern("no_tlsv1"); VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0); + ID sym_no_tlsv1_1 = rb_intern("no_tlsv1_1"); + VALUE no_tlsv1_1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1_1, 0); + #ifdef HAVE_TLS_SERVER_METHOD ctx = SSL_CTX_new(TLS_server_method()); #else @@ -183,12 +186,36 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) { SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL); } - ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION; + ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION; - if(RTEST(no_tlsv1)) { +#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION + if (RTEST(no_tlsv1_1)) { + min = TLS1_2_VERSION; + } + else if (RTEST(no_tlsv1)) { + min = TLS1_1_VERSION; + } + else { + min = TLS1_VERSION; + } + + SSL_CTX_set_min_proto_version(ctx, min); + + SSL_CTX_set_options(ctx, ssl_options); + +#else + /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */ + ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE; + + if (RTEST(no_tlsv1)) { ssl_options |= SSL_OP_NO_TLSv1; } + if(RTEST(no_tlsv1_1)) { + ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1; + } SSL_CTX_set_options(ctx, ssl_options); +#endif + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); if (!NIL_P(ssl_cipher_filter)) { @@ -458,14 +485,35 @@ void Init_mini_ssl(VALUE puma) { // OpenSSL Build / Runtime/Load versions /* Version of OpenSSL that Puma was compiled with */ - rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT)); + rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT)); #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000 - /* Version of OpenSSL that Puma loaded with */ - rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION))); + /* Version of OpenSSL that Puma loaded with */ + rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION))); #else - rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION))); + rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION))); #endif + +#if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD) + /* True if SSL3 is not available */ + rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue); +#else + rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse); +#endif + +#if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD) + /* True if TLS1 is not available */ + rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue); +#else + rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse); +#endif + +#if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD) + /* True if TLS1_1 is not available */ + rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue); +#else + rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse); +#endif rb_define_singleton_method(mod, "check", noop, 0); diff --git a/lib/puma/minissl.rb b/lib/puma/minissl.rb index aa725af7..f83fdeb1 100644 --- a/lib/puma/minissl.rb +++ b/lib/puma/minissl.rb @@ -176,10 +176,11 @@ module Puma class Context attr_accessor :verify_mode - attr_reader :no_tlsv1 + attr_reader :no_tlsv1, :no_tlsv1_1 def initialize - @no_tlsv1 = false + @no_tlsv1 = false + @no_tlsv1_1 = false end if defined?(JRUBY_VERSION) @@ -219,18 +220,24 @@ module Puma @ca = ca end - def check raise "Key not configured" unless @key raise "Cert not configured" unless @cert end end + # disables TLSv1 def no_tlsv1=(tlsv1) raise ArgumentError, "Invalid value of no_tlsv1" unless ['true', 'false', true, false].include?(tlsv1) @no_tlsv1 = tlsv1 end + # disables TLSv1 and TLSv1.1. Overrides `#no_tlsv1=` + def no_tlsv1_1=(tlsv1_1) + raise ArgumentError, "Invalid value of no_tlsv1" unless ['true', 'false', true, false].include?(tlsv1_1) + @no_tlsv1_1 = tlsv1_1 + end + end VERIFY_NONE = 0