Merge pull request #1478 from eallison91/dev/ssl_cipher_support

Dev/ssl cipher support
This commit is contained in:
Evan Phoenix 2018-05-09 16:00:52 -07:00 committed by GitHub
commit e4255d03fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 2 deletions

View File

@ -157,10 +157,20 @@ $ puma -b 'unix:///var/run/puma.sock?umask=0111'
```
Need a bit of security? Use SSL sockets:
```
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
```
#### Controlling SSL Cipher Suites
Need to use or avoid specific SSL cipher suites? Use ssl_cipher_filter or ssl_cipher_list options.
#####Ruby:
```
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_filter=!aNULL:AES+SHA'
```
#####JRuby:
```
$ puma -b 'ssl://127.0.0.1:9292?keystore=path_to_keystore&keystore-pass=keystore_password&ssl_cipher_list=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA'
```
See https://www.openssl.org/docs/man1.0.2/apps/ciphers.html for cipher filter format and full list of cipher suites.
### Control/Status Server

View File

@ -161,6 +161,9 @@ 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);
ctx = SSL_CTX_new(SSLv23_server_method());
conn->ctx = ctx;
@ -175,7 +178,13 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
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_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);

View File

@ -170,6 +170,12 @@ public class MiniSSL extends RubyObject {
engine.setNeedClientAuth(true);
}
IRubyObject sslCipherListObject = miniSSLContext.callMethod(threadContext, "ssl_cipher_list");
if (!sslCipherListObject.isNil()) {
String[] sslCipherList = sslCipherListObject.convertToString().asJavaString().split(",");
engine.setEnabledCipherSuites(sslCipherList);
}
SSLSession session = engine.getSession();
inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());

View File

@ -162,6 +162,7 @@ module Puma
end
ctx.keystore_pass = params['keystore-pass']
ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
else
unless params['key']
@events.error "Please specify the SSL key via 'key='"
@ -182,6 +183,7 @@ module Puma
end
ctx.ca = params['ca'] if params['ca']
ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
end
if params['verify_mode']
@ -313,6 +315,7 @@ module Puma
s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
s.listen backlog
ssl = MiniSSL::Server.new s, ctx
env = @proto_env.dup
env[HTTPS_KEY] = HTTPS

View File

@ -180,6 +180,7 @@ module Puma
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
attr_reader :keystore
attr_accessor :keystore_pass
attr_accessor :ssl_cipher_list
def keystore=(keystore)
raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
@ -195,6 +196,7 @@ module Puma
attr_reader :key
attr_reader :cert
attr_reader :ca
attr_accessor :ssl_cipher_filter
def key=(key)
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key

View File

@ -28,4 +28,32 @@ class TestBinder < Minitest::Test
assert_equal [], @binder.listeners
end
def test_binder_parses_ssl_cipher_filter
skip_on_appveyor
skip_on_jruby
key = File.expand_path "../../examples/puma/puma_keypair.pem", __FILE__
cert = File.expand_path "../../examples/puma/cert_puma.pem", __FILE__
ssl_cipher_filter = "AES@STRENGTH"
@binder.parse(["ssl://0.0.0.0?key=#{key}&cert=#{cert}&ssl_cipher_filter=#{ssl_cipher_filter}"], @events)
ssl = @binder.instance_variable_get(:@ios)[0]
ctx = ssl.instance_variable_get(:@ctx)
assert_equal(ssl_cipher_filter, ctx.ssl_cipher_filter)
end
def test_binder_parses_jruby_ssl_options
skip unless Puma.jruby?
keystore = File.expand_path "../../examples/puma/keystore.jks", __FILE__
ssl_cipher_list = "TLS_DHE_RSA_WITH_DES_CBC_SHA,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"
@binder.parse(["ssl://0.0.0.0?keystore=#{keystore}&ssl_cipher_list=#{ssl_cipher_list}"], @events)
ssl= @binder.instance_variable_get(:@ios)[0]
ctx = ssl.instance_variable_get(:@ctx)
assert_equal(keystore, ctx.keystore)
assert_equal(ssl_cipher_list, ctx.ssl_cipher_list)
end
end