Repository: puma/puma (Ruby)

Issue:
Puma does not load a CA when verification mode is set to :peer
### Steps to reproduce

1) Configure Puma to accept SSL connections:
```
key =  File.expand_path "./certs/my_key.key"
cert = File.expand_path "./certs/my_cert.crt"
ca = File.expand_path "./certs/my_ca.crt"

ssl_bind "0.0.0.0", 9292, :ca => ca, :cert => cert, :key => key, :verify_mode => :peer
```

2) Start Puma, and get the following:
```
 starting in single mode...
* Version 3.6.2 (ruby 2.3.1-p112), codename: Sleepy Sunday Serenity
* Min threads: 5, max threads: 5
* Environment: production
ERROR: Please specify the SSL ca via 'ca='
```

### Expected behavior

Puma should just start and accept TLS connections.

### Actual behavior

Puma exits 1, requesting a CA be specified.

### Why it's happening

If mode is set to verify a peer, it requests a CA:
https://github.com/puma/puma/blob/0912b0cea1576e96ee4e84a84cfff2a80750ecf6/lib/puma/binder.rb#L178

However, the ssl bind method will not attach a CA param to the URL it generates:
https://github.com/puma/puma/blob/master/lib/puma/dsl.rb#L273

If this is a bug and not just me being dumb/wrong, I have no problem submitting a PR to fix it. 

### System configuration

**Ruby version**: ruby 2.3.1p112 (2016-04-26 revision 54768)
**Rails version**: rails (5.0.1)



Discussion:
Looks like a bug.
👍 
temporarily can be fixed by using bind instead of ssl_bind like this:

```
ssl_options = {
  ca: "xxx/yyy.cer",
  cert: "xxx/yyy.crt",
  key: "xxx/yyy.key",
  verify_mode: 'peer',
}

# ssl_bind '0.0.0.0', '443', ssl_options
bind "ssl://0.0.0.0:443?cert=#{ssl_options[:cert]}&key=#{ssl_options[:key]}&verify_mode=#{ssl_options[:verify_mode]}&ca=#{ssl_options[:ca]}"
```
I'd also like to be able to set both ca and verify_mode (when not using Java as well).
Still not working with `ssl_bind` as of latest Puma 3.12.0 (I mention it because the title explicitly states 3.6.2):

https://github.com/puma/puma/blob/v3.12.0/lib/puma/dsl.rb#L286-L295
https://github.com/puma/puma/blob/f7e1e58dcba1e19e470b6eb0c44c33a0722285f6/lib/puma/dsl.rb#L286-L295

Can reproduce:
Puma 4.2.0
Ruby 2.6.3

```rb
# config.rb
key =  File.expand_path "./certs/my_key.key"
cert = File.expand_path "./certs/my_cert.crt"
ca = File.expand_path "./certs/my_ca.crt"

ssl_bind "0.0.0.0", 9292, :ca => ca, :cert => cert, :key => key, :verify_mode => :peer
```

I created three empty files for the certs and then run:

```sh
bundle exec bin/puma -C config.rb test/rackup/hello.ru
```



Patch:
diff --git a/History.md b/History.md
index 468cb401e2..d25f89b78e 100644
--- a/History.md
+++ b/History.md
@@ -6,6 +6,7 @@
 * Bugfixes
   * Fix socket activation of systemd (pre-existing) unix binder files (#1842, #1988)
   * Deal with multiple calls to bind correctly (#1986, #1994, #2006)
+  * Accepts symbols for `verify_mode` (#1222)
 
 ## 4.2.0 / 2019-09-23
 
diff --git a/lib/puma/dsl.rb b/lib/puma/dsl.rb
index 654581b210..102c63d4dc 100644
--- a/lib/puma/dsl.rb
+++ b/lib/puma/dsl.rb
@@ -396,7 +396,7 @@ def threads(min, max)
     #     keystore_pass: password
     #   }
     def ssl_bind(host, port, opts)
-      verify = opts.fetch(:verify_mode, 'none')
+      verify = opts.fetch(:verify_mode, 'none').to_s
       no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
       no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
       ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)


Test patch:
diff --git a/test/test_config.rb b/test/test_config.rb
index 41969f64c4..74eab1f2ae 100644
--- a/test/test_config.rb
+++ b/test/test_config.rb
@@ -97,6 +97,23 @@ def test_ssl_bind_with_cipher_filter
     assert ssl_binding.include?("&ssl_cipher_filter=#{cipher_filter}")
   end
 
+  def test_ssl_bind_with_ca
+    conf = Puma::Configuration.new do |c|
+      c.ssl_bind "0.0.0.0", "9292", {
+        cert: "/path/to/cert",
+        ca: "/path/to/ca",
+        key: "/path/to/key",
+        verify_mode: :peer,
+      }
+    end
+
+    conf.load
+
+    ssl_binding = conf.options[:binds].first
+    assert_match "ca=/path/to/ca", ssl_binding
+    assert_match "verify_mode=peer", ssl_binding
+  end
+
   def test_lowlevel_error_handler_DSL
     conf = Puma::Configuration.new do |c|
       c.load "test/config/app.rb"