unixcharles / acme-client

A Ruby client for the letsencrypt's ACME protocol.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SSL connection options seemingly being ignored

andrewhamon opened this issue · comments

I'm trying to use Pebble to perform integration tests that don't rely on the Let's Encrypt staging server.

In order to get this to work, I need to either disable SSL verification, or add the Pebble CA. Neither seems to be working.

If I make a Faraday connection directly, though, using identical connection options as what I used for acme-client, I do not get SSL errors (as expected).

Example:

require 'openssl'
private_key = OpenSSL::PKey::RSA.new(4096)

# Local Pebble endpoint
endpoint = "https://0.0.0.0:14000/"

connection_options = { ssl: { verify: false }, request: { open_timeout: 5, timeout: 5 } }

client = Acme::Client.new(private_key: private_key, endpoint: endpoint, connection_options: connection_options)

client.connection.get

# Traceback (most recent call last):
#        1: from (irb):35
# Faraday::SSLError (SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate))

But it works when using a plain old Faraday connection with no middleware:

connection = Faraday.new endpoint, **connection_options
connection.get

#<Faraday::Response:0x00007f84e45c8508 @on_complete_callbacks=[], @env=#<Faraday::Env @method=:get @body="404 page not found\n" @url=#<URI::HTTPS https://0.0.0.0:14000/> @request=#<Faraday::RequestOptions timeout=5, open_timeout=5> @request_headers={"User-Agent"=>"Faraday v0.14.0"} @ssl=#<Faraday::SSLOptions (empty)> @response=#<Faraday::Response:0x00007f84e45c8508 ...> @response_headers={"content-type"=>"text/plain; charset=utf-8", "x-content-type-options"=>"nosniff", "date"=>"Sat, 10 Feb 2018 20:19:37 GMT", "content-length"=>"19", "connection"=>"close"} @status=404 @reason_phrase="Not Found">>

The only difference between the two is the middleware used:

def connection
@connection ||= Faraday.new(@endpoint, **@connection_options) do |configuration|
configuration.use Acme::Client::FaradayMiddleware, client: self
configuration.adapter Faraday.default_adapter
end
end

I tried replicating this with a dummy middleware, which still works fine:

class DummyMiddleware < Faraday::Middleware
  def call(env)
    @app.call(env)
  end
end

connection = Faraday.new endpoint, **connection_options do |configuration|
  configuration.use DummyMiddleware
  configuration.adapter Faraday.default_adapter
end

connection.get
#<Faraday::Response:0x00007f84e45c8508 @on_complete_callbacks=[], @env=#<Faraday::Env @method=:get @body="404 page not found\n" @url=#<URI::HTTPS https://0.0.0.0:14000/> @request=#<Faraday::RequestOptions timeout=5, open_timeout=5> @request_headers={"User-Agent"=>"Faraday v0.14.0"} @ssl=#<Faraday::SSLOptions (empty)> @response=#<Faraday::Response:0x00007f84e45c8508 ...> @response_headers={"content-type"=>"text/plain; charset=utf-8", "x-content-type-options"=>"nosniff", "date"=>"Sat, 10 Feb 2018 20:19:37 GMT", "content-length"=>"19", "connection"=>"close"} @status=404 @reason_phrase="Not Found">>

My next idea is to try to slowly build up the dummy middleware until it is identical to the middleware used here, but I figured I would gather my thoughts and leave them here first, and see if anyone can even reproduce this.

It seems as though my attempt to use Pebble may be misguided as I think it implements the newer ACME standard 🙂

Still, the issue is perplexing.

Hey @andrewhamon,

You are right. Pebble implement (partially) the newer ACME spec.

I'm developing a new version of the client for ACME v2 on this branch. I write my test against Pebble whenever possible.

To skip the certificate check I do OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE in my spec helper.

I'm not too sure why Faraday seem to not pass the connection options properly. I'll have to investigate that.

I experience a failure to validate the certificate when I talk to the LetsEncrypt staging server.
I would suspect that Faraday is using a different (or no?) set of certificate anchors?

I experience a failure to validate the certificate when I talk to the LetsEncrypt staging server.
I would suspect that Faraday is using a different (or no?) set of certificate anchors?

This problem is solved by setting the connection_options when creating the client:

Acme::Client.new(private_key: acmeprivkey,
                                    directory: server,
                                    connection_options: {
                                      :ssl => {
                                        :ca_file => '/usr/lib/ssl/certs/ca-certificates.crt',
                                        :ca_path => "/usr/lib/ssl/certs"
                                      }
                                    })