1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Fail hard if SSL certs or keys cannot be read by user (#2847)

* Fail hard if SSL certs or keys cannot be read by user

Previously if an SSL cert or key could not be read, Puma would bind to
the configured SSL port but not accept any connections. The only
indication that something went awry is an obscure log message:

```
 #<Puma::MiniSSL::SSLError: OpenSSL error: error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher - 193>
```

We now fail hard with an exception if this happens to make it clear
that the permissions need to be fixed.

Relates to https://github.com/puma/puma/issues/1339

* minissl.rb - add check_file method

Co-authored-by: MSP-Greg <Greg.mpls@gmail.com>
This commit is contained in:
Stan Hu 2022-04-02 14:19:21 -07:00 committed by GitHub
parent f7cad9816e
commit f4fb51deb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 7 deletions

View file

@ -214,6 +214,11 @@ module Puma
@cert_pem = nil @cert_pem = nil
end end
def check_file(file, desc)
raise ArgumentError, "#{desc} file '#{file}' does not exist" unless File.exist? file
raise ArgumentError, "#{desc} file '#{file}' is not readable" unless File.readable? file
end
if IS_JRUBY if IS_JRUBY
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair # jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
attr_reader :keystore attr_reader :keystore
@ -221,7 +226,7 @@ module Puma
attr_accessor :ssl_cipher_list attr_accessor :ssl_cipher_list
def keystore=(keystore) def keystore=(keystore)
raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore check_file keystore, 'Keystore'
@keystore = keystore @keystore = keystore
end end
@ -240,17 +245,17 @@ module Puma
attr_accessor :verification_flags attr_accessor :verification_flags
def key=(key) def key=(key)
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key check_file key, 'Key'
@key = key @key = key
end end
def cert=(cert) def cert=(cert)
raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert check_file cert, 'Cert'
@cert = cert @cert = cert
end end
def ca=(ca) def ca=(ca)
raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca check_file ca, 'ca'
@ca = ca @ca = ca
end end

View file

@ -9,21 +9,54 @@ class TestMiniSSL < Minitest::Test
ctx = Puma::MiniSSL::Context.new ctx = Puma::MiniSSL::Context.new
exception = assert_raises(ArgumentError) { ctx.keystore = "/no/such/keystore" } exception = assert_raises(ArgumentError) { ctx.keystore = "/no/such/keystore" }
assert_equal("No such keystore file '/no/such/keystore'", exception.message) assert_equal("Keystore file '/no/such/keystore' does not exist", exception.message)
end
def test_raises_with_unreadable_keystore_file
ctx = Puma::MiniSSL::Context.new
File.stub(:exist?, true) do
File.stub(:readable?, false) do
exception = assert_raises(ArgumentError) { ctx.keystore = "/unreadable/keystore" }
assert_equal("Keystore file '/unreadable/keystore' is not readable", exception.message)
end
end
end end
else else
def test_raises_with_invalid_key_file def test_raises_with_invalid_key_file
ctx = Puma::MiniSSL::Context.new ctx = Puma::MiniSSL::Context.new
exception = assert_raises(ArgumentError) { ctx.key = "/no/such/key" } exception = assert_raises(ArgumentError) { ctx.key = "/no/such/key" }
assert_equal("No such key file '/no/such/key'", exception.message) assert_equal("Key file '/no/such/key' does not exist", exception.message)
end
def test_raises_with_unreadable_key_file
ctx = Puma::MiniSSL::Context.new
File.stub(:exist?, true) do
File.stub(:readable?, false) do
exception = assert_raises(ArgumentError) { ctx.key = "/unreadable/key" }
assert_equal("Key file '/unreadable/key' is not readable", exception.message)
end
end
end end
def test_raises_with_invalid_cert_file def test_raises_with_invalid_cert_file
ctx = Puma::MiniSSL::Context.new ctx = Puma::MiniSSL::Context.new
exception = assert_raises(ArgumentError) { ctx.cert = "/no/such/cert" } exception = assert_raises(ArgumentError) { ctx.cert = "/no/such/cert" }
assert_equal("No such cert file '/no/such/cert'", exception.message) assert_equal("Cert file '/no/such/cert' does not exist", exception.message)
end
def test_raises_with_unreadable_cert_file
ctx = Puma::MiniSSL::Context.new
File.stub(:exist?, true) do
File.stub(:readable?, false) do
exception = assert_raises(ArgumentError) { ctx.key = "/unreadable/cert" }
assert_equal("Key file '/unreadable/cert' is not readable", exception.message)
end
end
end end
def test_raises_with_invalid_key_pem def test_raises_with_invalid_key_pem
@ -33,6 +66,17 @@ class TestMiniSSL < Minitest::Test
assert_equal("'key_pem' is not a String", exception.message) assert_equal("'key_pem' is not a String", exception.message)
end end
def test_raises_with_unreadable_ca_file
ctx = Puma::MiniSSL::Context.new
File.stub(:exist?, true) do
File.stub(:readable?, false) do
exception = assert_raises(ArgumentError) { ctx.ca = "/unreadable/cert" }
assert_equal("ca file '/unreadable/cert' is not readable", exception.message)
end
end
end
def test_raises_with_invalid_cert_pem def test_raises_with_invalid_cert_pem
ctx = Puma::MiniSSL::Context.new ctx = Puma::MiniSSL::Context.new