mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
[SSL] Add ability to set verification flags (#2490)
Any number of verification flags supported by OpenSSL can be set ( https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_hostflags.html#VERIFICATION-FLAGS
This commit is contained in:
parent
b364a5da34
commit
d2f9d6de7b
8 changed files with 108 additions and 3 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
* Features
|
||||
* Your feature goes here <Most recent on the top, like GitHub> (#Github Number)
|
||||
* Add ability to set OpenSSL verification flags (MRI only) ([#2490])
|
||||
* Uses `flush` after writing messages to avoid mutating $stdout and $stderr using `sync=true` ([#2486])
|
||||
* Fail build if compiling extensions raises warnings on GH Actions ([#1953])
|
||||
* Add MAKE_WARNINGS_INTO_ERRORS environment variable to toggle whether a build should treat all warnings into errors or not ([#1953])
|
||||
|
|
17
README.md
17
README.md
|
@ -212,6 +212,23 @@ Disable TLS v1 with the `no_tlsv1` option:
|
|||
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&no_tlsv1=true'
|
||||
```
|
||||
|
||||
#### Controlling OpenSSL Verification Flags
|
||||
|
||||
To enable verification flags offered by OpenSSL, use `verification_flags` (not available for JRuby):
|
||||
|
||||
```
|
||||
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN'
|
||||
```
|
||||
|
||||
You can also set multiple verification flags (by separating them with coma):
|
||||
|
||||
```
|
||||
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN,CRL_CHECK'
|
||||
```
|
||||
|
||||
List of available flags: `USE_CHECK_TIME`, `CRL_CHECK`, `CRL_CHECK_ALL`, `IGNORE_CRITICAL`, `X509_STRICT`, `ALLOW_PROXY_CERTS`, `POLICY_CHECK`, `EXPLICIT_POLICY`, `INHIBIT_ANY`, `INHIBIT_MAP`, `NOTIFY_POLICY`, `EXTENDED_CRL_SUPPORT`, `USE_DELTAS`, `CHECK_SS_SIGNATURE`, `TRUSTED_FIRST`, `SUITEB_128_LOS_ONLY`, `SUITEB_192_LOS`, `SUITEB_128_LOS`, `PARTIAL_CHAIN`, `NO_ALT_CHAINS`, `NO_CHECK_TIME`
|
||||
(see https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_hostflags.html#VERIFICATION-FLAGS).
|
||||
|
||||
### Control/Status Server
|
||||
|
||||
Puma has a built-in status and control app that can be used to query and control Puma.
|
||||
|
|
|
@ -152,8 +152,8 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
|||
int min;
|
||||
#endif
|
||||
int ssl_options;
|
||||
ID sym_key, sym_cert, sym_ca, sym_verify_mode, sym_ssl_cipher_filter, sym_no_tlsv1, sym_no_tlsv1_1;
|
||||
VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1;
|
||||
ID sym_key, sym_cert, sym_ca, sym_verify_mode, sym_ssl_cipher_filter, sym_no_tlsv1, sym_no_tlsv1_1, sym_verification_flags;
|
||||
VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1, verification_flags;
|
||||
DH *dh;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
|
@ -197,6 +197,15 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
|||
SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
|
||||
SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
|
||||
|
||||
sym_verification_flags = rb_intern("verification_flags");
|
||||
verification_flags = rb_funcall(mini_ssl_ctx, sym_verification_flags, 0);
|
||||
|
||||
if (!NIL_P(verification_flags)) {
|
||||
X509_VERIFY_PARAM *param = SSL_CTX_get0_param(ctx);
|
||||
X509_VERIFY_PARAM_set_flags(param, NUM2INT(verification_flags));
|
||||
SSL_CTX_set1_param(ctx, param);
|
||||
}
|
||||
|
||||
if (!NIL_P(ca)) {
|
||||
StringValue(ca);
|
||||
SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
|
||||
|
|
|
@ -51,14 +51,20 @@ module Puma
|
|||
if defined?(JRUBY_VERSION)
|
||||
ssl_cipher_list = opts[:ssl_cipher_list] ?
|
||||
"&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
|
||||
|
||||
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
||||
|
||||
"ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
|
||||
"&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
||||
else
|
||||
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
||||
"&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
|
||||
|
||||
v_flags = (ary = opts[:verification_flags]) ?
|
||||
"&verification_flags=#{Array(ary).join ','}" : nil
|
||||
|
||||
"ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
|
||||
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
||||
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -429,6 +435,7 @@ module Puma
|
|||
# key: path_to_key,
|
||||
# ssl_cipher_filter: cipher_filter, # optional
|
||||
# verify_mode: verify_mode, # default 'none'
|
||||
# verification_flags: flags, # optional, not supported by JRuby
|
||||
# }
|
||||
# @example For JRuby, two keys are required: keystore & keystore_pass.
|
||||
# ssl_bind '127.0.0.1', '9292', {
|
||||
|
|
|
@ -245,6 +245,7 @@ module Puma
|
|||
attr_reader :cert
|
||||
attr_reader :ca
|
||||
attr_accessor :ssl_cipher_filter
|
||||
attr_accessor :verification_flags
|
||||
|
||||
def key=(key)
|
||||
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
|
||||
|
@ -287,6 +288,32 @@ module Puma
|
|||
VERIFY_PEER = 1
|
||||
VERIFY_FAIL_IF_NO_PEER_CERT = 2
|
||||
|
||||
# https://github.com/openssl/openssl/blob/master/include/openssl/x509_vfy.h.in
|
||||
# /* Certificate verify flags */
|
||||
VERIFICATION_FLAGS = {
|
||||
"USE_CHECK_TIME" => 0x2,
|
||||
"CRL_CHECK" => 0x4,
|
||||
"CRL_CHECK_ALL" => 0x8,
|
||||
"IGNORE_CRITICAL" => 0x10,
|
||||
"X509_STRICT" => 0x20,
|
||||
"ALLOW_PROXY_CERTS" => 0x40,
|
||||
"POLICY_CHECK" => 0x80,
|
||||
"EXPLICIT_POLICY" => 0x100,
|
||||
"INHIBIT_ANY" => 0x200,
|
||||
"INHIBIT_MAP" => 0x400,
|
||||
"NOTIFY_POLICY" => 0x800,
|
||||
"EXTENDED_CRL_SUPPORT" => 0x1000,
|
||||
"USE_DELTAS" => 0x2000,
|
||||
"CHECK_SS_SIGNATURE" => 0x4000,
|
||||
"TRUSTED_FIRST" => 0x8000,
|
||||
"SUITEB_128_LOS_ONLY" => 0x10000,
|
||||
"SUITEB_192_LOS" => 0x20000,
|
||||
"SUITEB_128_LOS" => 0x30000,
|
||||
"PARTIAL_CHAIN" => 0x80000,
|
||||
"NO_ALT_CHAINS" => 0x100000,
|
||||
"NO_CHECK_TIME" => 0x200000
|
||||
}.freeze
|
||||
|
||||
class Server
|
||||
def initialize(socket, ctx)
|
||||
@socket = socket
|
||||
|
|
|
@ -62,6 +62,12 @@ module Puma
|
|||
end
|
||||
end
|
||||
|
||||
if params['verification_flags']
|
||||
ctx.verification_flags = params['verification_flags'].split(',').
|
||||
map { |flag| MiniSSL::VERIFICATION_FLAGS.fetch(flag) }.
|
||||
inject { |sum, flag| sum ? sum | flag : flag }
|
||||
end
|
||||
|
||||
ctx
|
||||
end
|
||||
|
||||
|
|
|
@ -453,4 +453,24 @@ class TestBinderMRI < TestBinderBase
|
|||
|
||||
assert_equal ssl_cipher_filter, ssl_context_for_binder.ssl_cipher_filter
|
||||
end
|
||||
|
||||
def test_binder_parses_ssl_verification_flags_one
|
||||
skip 'No ssl support' unless ::Puma::HAS_SSL
|
||||
|
||||
input = "&verification_flags=TRUSTED_FIRST"
|
||||
|
||||
@binder.parse ["ssl://0.0.0.0?#{ssl_query}#{input}"], @events
|
||||
|
||||
assert_equal 0x8000, ssl_context_for_binder.verification_flags
|
||||
end
|
||||
|
||||
def test_binder_parses_ssl_verification_flags_multiple
|
||||
skip 'No ssl support' unless ::Puma::HAS_SSL
|
||||
|
||||
input = "&verification_flags=TRUSTED_FIRST,NO_CHECK_TIME"
|
||||
|
||||
@binder.parse ["ssl://0.0.0.0?#{ssl_query}#{input}"], @events
|
||||
|
||||
assert_equal 0x8000 | 0x200000, ssl_context_for_binder.verification_flags
|
||||
end
|
||||
end unless ::Puma::IS_JRUBY
|
||||
|
|
|
@ -141,6 +141,24 @@ class TestConfigFile < TestConfigFileBase
|
|||
assert ssl_binding.include?("&ssl_cipher_filter=#{cipher_filter}")
|
||||
end
|
||||
|
||||
def test_ssl_bind_with_verification_flags
|
||||
skip_on :jruby
|
||||
skip 'No ssl support' unless ::Puma::HAS_SSL
|
||||
|
||||
conf = Puma::Configuration.new do |c|
|
||||
c.ssl_bind "0.0.0.0", "9292", {
|
||||
cert: "cert",
|
||||
key: "key",
|
||||
verification_flags: ["TRUSTED_FIRST", "NO_CHECK_TIME"]
|
||||
}
|
||||
end
|
||||
|
||||
conf.load
|
||||
|
||||
ssl_binding = conf.options[:binds].first
|
||||
assert ssl_binding.include?("&verification_flags=TRUSTED_FIRST,NO_CHECK_TIME")
|
||||
end
|
||||
|
||||
def test_ssl_bind_with_ca
|
||||
skip 'No ssl support' unless ::Puma::HAS_SSL
|
||||
conf = Puma::Configuration.new do |c|
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue