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
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
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
attr_reader :keystore
@ -221,7 +226,7 @@ module Puma
attr_accessor :ssl_cipher_list
def keystore=(keystore)
raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
check_file keystore, 'Keystore'
@keystore = keystore
end
@ -240,17 +245,17 @@ module Puma
attr_accessor :verification_flags
def key=(key)
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
check_file key, 'Key'
@key = key
end
def cert=(cert)
raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
check_file cert, 'Cert'
@cert = cert
end
def ca=(ca)
raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca
check_file ca, 'ca'
@ca = ca
end

View File

@ -9,21 +9,54 @@ class TestMiniSSL < Minitest::Test
ctx = Puma::MiniSSL::Context.new
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
else
def test_raises_with_invalid_key_file
ctx = Puma::MiniSSL::Context.new
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
def test_raises_with_invalid_cert_file
ctx = Puma::MiniSSL::Context.new
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
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)
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
ctx = Puma::MiniSSL::Context.new