File add-support-for-disabling-TLSv1.0.patch of Package rubygem-puma.16022
From 04e159acd87e2eb6937d0a209804af1fafd513c1 Mon Sep 17 00:00:00 2001
From: dmaiocchi <dmaiocchi@suse.com>
Date: Fri, 31 Jul 2020 17:42:41 +0200
Subject: [PATCH] add support for disabling TLSv1.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Many organizations run their applications using in environments that fall into
scope of PCI-DSS compliance audits. One of the requirements set out by standard
is to migrate to more secure protocols if possible.
PCI Security Standards council has advised to migrate away from TLSv1.0 over
last few years and recently set a migration deadline of 30 June 2018 (see [1]
for more details).
Change proposed in this commit gives an user option to disable `TLSv1.0` during
bind, while still leaving the `TLSv1.1` and `TLSv1.2` enabled. `SSLv2` and
`SSLv3` are permanently disabled (as they should).
Default behaviour is not changed if the `no_tls` option is not defined.
[1]: https://blog.pcisecuritystandards.org/are-you-ready-for-30-june-2018-sayin-goodbye-to-ssl-early-tls
---
README.md | 6 ++++++
ext/puma_http11/mini_ssl.c | 23 +++++++++++++++++++--
ext/puma_http11/org/jruby/puma/MiniSSL.java | 8 ++++++-
lib/puma/binder.rb | 2 ++
lib/puma/dsl.rb | 5 +++--
lib/puma/minissl.rb | 12 +++++++++++
6 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 6c1d0ac4..bd8d93e6 100644
--- a/README.md
+++ b/README.md
@@ -162,6 +162,12 @@ Need a bit of security? Use SSL sockets:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
```
+Don't want to use insecure TLSv1.0 ?
+
+```
+$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&no_tlsv1=true'
+```
+
### Control/Status Server
Puma has a built-in status/control app that can be used to query and control Puma itself.
diff --git a/ext/puma_http11/mini_ssl.c b/ext/puma_http11/mini_ssl.c
index cac1aa93..b2549cf1 100644
--- a/ext/puma_http11/mini_ssl.c
+++ b/ext/puma_http11/mini_ssl.c
@@ -142,6 +142,7 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
VALUE obj;
SSL_CTX* ctx;
SSL* ssl;
+ int ssl_options;
ms_conn* conn = engine_alloc(self, &obj);
@@ -161,6 +162,13 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
ID sym_verify_mode = rb_intern("verify_mode");
VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
+ ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
+ VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
+
+ ID sym_no_tlsv1 = rb_intern("no_tlsv1");
+ VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0);
+
+
ctx = SSL_CTX_new(SSLv23_server_method());
conn->ctx = ctx;
@@ -172,10 +180,21 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
}
- SSL_CTX_set_options(ctx, 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_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
+
+ if(RTEST(no_tlsv1)) {
+ ssl_options |= SSL_OP_NO_TLSv1;
+ }
+ SSL_CTX_set_options(ctx, ssl_options);
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
- SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
+ if (!NIL_P(ssl_cipher_filter)) {
+ StringValue(ssl_cipher_filter);
+ SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
+ }
+ else {
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
+ }
DH *dh = get_dh1024();
SSL_CTX_set_tmp_dh(ctx, dh);
diff --git a/ext/puma_http11/org/jruby/puma/MiniSSL.java b/ext/puma_http11/org/jruby/puma/MiniSSL.java
index c3b5d63f..830e5699 100644
--- a/ext/puma_http11/org/jruby/puma/MiniSSL.java
+++ b/ext/puma_http11/org/jruby/puma/MiniSSL.java
@@ -158,7 +158,13 @@ public class MiniSSL extends RubyObject {
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
engine = sslCtx.createSSLEngine();
- String[] protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
+ String[] protocols;
+ if(miniSSLContext.callMethod(threadContext, "no_tlsv1").isTrue()) {
+ protocols = new String[] { "TLSv1.1", "TLSv1.2" };
+ } else {
+ protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
+ }
+
engine.setEnabledProtocols(protocols);
engine.setUseClientMode(false);
diff --git a/lib/puma/binder.rb b/lib/puma/binder.rb
index 7c68eebe..5a2c618c 100644
--- a/lib/puma/binder.rb
+++ b/lib/puma/binder.rb
@@ -184,6 +184,8 @@ module Puma
ctx.ca = params['ca'] if params['ca']
end
+ ctx.no_tlsv1 = true if params['no_tlsv1'] == 'true'
+
if params['verify_mode']
ctx.verify_mode = case params['verify_mode']
when "peer"
diff --git a/lib/puma/dsl.rb b/lib/puma/dsl.rb
index 220c4f73..8f78afba 100644
--- a/lib/puma/dsl.rb
+++ b/lib/puma/dsl.rb
@@ -285,12 +285,13 @@ module Puma
def ssl_bind(host, port, opts)
verify = opts.fetch(:verify_mode, 'none')
+ no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
if defined?(JRUBY_VERSION)
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}"
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}"
else
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&verify_mode=#{verify}"
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}"
end
end
diff --git a/lib/puma/minissl.rb b/lib/puma/minissl.rb
index a65c1c64..aebfa888 100644
--- a/lib/puma/minissl.rb
+++ b/lib/puma/minissl.rb
@@ -175,6 +175,11 @@ module Puma
class Context
attr_accessor :verify_mode
+ attr_reader :no_tlsv1
+
+ def initialize
+ @no_tlsv1 = false
+ end
if defined?(JRUBY_VERSION)
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
@@ -211,11 +216,18 @@ module Puma
@ca = ca
end
+
def check
raise "Key not configured" unless @key
raise "Cert not configured" unless @cert
end
end
+
+ def no_tlsv1=(tlsv1)
+ raise ArgumentError, "Invalid value of no_tlsv1" unless ['true', 'false', true, false].include?(tlsv1)
+ @no_tlsv1 = tlsv1
+ end
+
end
VERIFY_NONE = 0
--
2.26.2