Plug_cowboy and https: self-signed certificate is rejected by browsers and curl

Hi! My self-signed certificate is rejected by browsers and curl.

The problem:

On curl I get the error: curl: (52) Empty reply from server from curl.
Firefox warns me that the certificate is self-signed, I click to continue and it never gets a response. Chromium gives similar results.

On the terminal I sometimes get:

[info]  ['TLS', 32, 'server', 58, 32, 73, 110, 32, 115, 116, 97, 11
6, 101, 32, 'abbreviated', 32, 'received CLIENT ALERT: Fatal - Certificate Unkno
wn', 10]  

What does work:

Everything works fine with plain http. When using the cowboy interface directly the results are the same, plain http works, https doesn’t. I was able to successfully setup self-signed certificates with Nginx, they were not the ones generated by mix x509.gen.selfsigned (see below) but they also did not work with plug_cowboy or cowboy.
I think the problem might be that I’m not passing a cacertfile parameter (for a self-signed certificate authority that signs my certificate), but I don’t know how to generate that.

The setup:

All on a single machine, with a fresh mix project created only for this.

I generated a self-signed certificate with: mix x509.gen.selfsigned, it was put in the default location: priv/cert/. It appears that the default hostname it uses is localhostbut I tried passing a specific name too, only to get the same result.

I’m on Debian 10 amd64;

Erlang/OTP 21 [erts-10.2.4] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1]

Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help)

My plug is in lib/https_tests.ex:

defmodule HttpsTests do
  import Plug.Conn

  def init(options) do
    # initialize options
    options
  end

  def call(conn, _opts) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_resp(200, "Hello world")
  end
end

My lib/https_tests/application.ex:

defmodule HttpsTests.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      {Plug.Cowboy, scheme: :https, plug: HttpsTests, 
       options: [
	 port: 4001,
	 cipher_suite: :strong,
	 certfile: "priv/cert/selfsigned.pem",
	 keyfile: "priv/cert/selfsigned_key.pem",
	 otp_app: :https_tests
       ]}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: HttpsTests.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Thanks!

can you post the full set of deps, I’d like to try this out.

hm, I tried a bunch of things and couldn’t figure it out. You shouldn’t need a cacertfile since it’s self-signed. However, even if it’s self signed you shouldn’t have this problem. As it turns out, on my machine I have a different error:

[info] TLS :server: In state :hello at tls_record.erl:539 generated SERVER ALERT: Fatal - Unexpected Message
 - {:unsupported_record_type, 71}

did you try running curl -k localhost:4001 ?

It looks to me like the issue may not be with the certificate itself but with the TLS handshake or the connection after the handshake completes. Can you show the output of curl -v -k https://localhost:4001/?

Are you using plug_cowboy 1.0 or 2.0 (in other words, Cowboy 1 with HTTP/1 only, or Cowboy 2 with support for HTTP/2)?

Also I noticed you’re using OTP 21.2.6. You may want to try with 22.3 or 23.0: the ssl application is frequently updated, but not all fixes are back ported to older releases.

@ityonemo Are you also on OTP 21?
@voltone I’m installing Debian Testing to try a newer OTP.

Deps:

  defp deps do
    [
      {:plug_cowboy, "~> 2.0"},
      {:x509, "~> 0.8.1"}
    ]
  end

Everything else in mix.exs is what mix new https_tests --sup generates.

curl -v -k https://localhost:4001/ and curl -v -k --http2 https://localhost:4001/ give the same result, since client and server choose the highest protocol version both speak.
curl -v -k --https1.1 https://localhost:4001/ gives a slightly different result but still doesn’t work.

Results for HTTP2:
(Scroll down for HTTP1.1)
Those last lines are very weird and I did not get the terminal [info] messages this time:

* Expire in 0 ms for 6 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 1 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
* Expire in 0 ms for 1 (transfer 0x55f679702f50)
*   Trying ::1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55f679702f50)
* Expire in 200 ms for 4 (transfer 0x55f679702f50)
* connect to ::1 port 4001 failed: Conexão recusada
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55f679702f50)
* Connected to localhost (127.0.0.1) port 4001 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=Self-signed test certificate
*  start date: Oct 19 03:26:42 2020 GMT
*  expire date: Nov 18 03:31:42 2021 GMT
*  issuer: CN=Self-signed test certificate
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55f679702f50)
> GET / HTTP/2
> Host: localhost:4001
> User-Agent: curl/7.64.0
> Accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 4294967295)!
* TLSv1.2 (IN), TLS alert, close notify (256):
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

Results for HTTP1.1:

* Expire in 0 ms for 6 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 1 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
* Expire in 0 ms for 1 (transfer 0x55c89a3acf50)
*   Trying ::1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55c89a3acf50)
* Expire in 200 ms for 4 (transfer 0x55c89a3acf50)
* connect to ::1 port 4001 failed: Conexão recusada
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55c89a3acf50)
* Connected to localhost (127.0.0.1) port 4001 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=Self-signed test certificate
*  start date: Oct 19 03:26:42 2020 GMT
*  expire date: Nov 18 03:31:42 2021 GMT
*  issuer: CN=Self-signed test certificate
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> GET / HTTP/1.1
> Host: localhost:4001
> User-Agent: curl/7.64.0
> Accept: */*
> 
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

Both of these appear to fail after the TLS handshake completes. So I still don’t think the issue is with the certificate. But for now I have no idea what is causing it…

At this point what I would do is trace the ssl socket. I’m not at my PC right now, but something like this should do it:

iex> :dbg.tracer
iex> :dbg.p(:all, :call)
iex> :dbg.tp(:ssl, :recv, :cx)
iex> :dbg.tp(:ssl, :send, :cx)

(Wow, that was painful to type in mobile, fighting autocorrect)

That should show you if Cowboy is receiving from and writing to the socket

Looks fine right?

iex(1)> :dbg.tracer
{:ok, #PID<0.104.0>}
iex(2)> :dbg.p(:all, :call)
{:ok, [{:matched, :nonode@nohost, 54}]}
iex(3)> :dbg.tp(:ssl, :recv, :cx)
{:ok, [{:matched, :nonode@nohost, 2}, {:saved, :cx}]}
iex(4)> :dbg.tp(:ssl, :send, :cx)
{:ok, [{:matched, :nonode@nohost, 1}, {:saved, :cx}]}
iex(5)> 

I finished installing Debian Testing with OTP 23, will post results in about a hour.

EDIT: Do I have to do something more besides running the debug commands?

Yes, that’s the tracer setup, and it looks ok. Now make a request and see if anything gets printed

I got the following with curl:
(seems ok I guess?)

iex(2)> :dbg.tracer                                                                                                                                                               
{:ok, #PID<0.330.0>}
iex(3)> :dbg.p(:all, :call)
{:ok, [{:matched, :nonode@nohost, 221}]}
iex(4)> :dbg.tp(:ssl, :recv, :cx)
{:ok, [{:matched, :nonode@nohost, 2}, {:saved, :cx}]}
iex(5)> :dbg.tp(:ssl, :send, :cx)
{:ok, [{:matched, :nonode@nohost, 1}, {:saved, :cx}]}
iex(6)> Plug.Cowboy.https HttpsTests, [], [port: 8080, cipher_suite: :strong, certfile: "priv/cert/selfsigned.pem", keyfile: "priv/cert/selfsigned_key.pem", otp_app: :https_tests
...(6)> ]
{:ok, #PID<0.337.0>}
iex(7)> (<0.445.0>) call ssl:send({sslsocket,{gen_tcp,#Port<0.9>,tls_connection,<0.340.0>},                                                                                       
           [<0.443.0>,<0.442.0>]},[<<0,0,0,4,0,0,0,0,0>>,[]]) ({cowboy_http2,
                                                                init,10})
(<0.445.0>) returned from ssl:send/2 -> ok

My binary HTTP/2 frame layer is a bit rusty but this doesn’t look at all like a response is being sent. Can you try with HTTP/1.1? It will be a bit easier to reason about, especially while I’m away from my PC

I get nothing on iex, curl -v -k --http1.1 https://localhost:8080/ gives the same response.

* Expire in 0 ms for 6 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 1 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
* Expire in 0 ms for 1 (transfer 0x55b2d405cf50)
*   Trying ::1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55b2d405cf50)
* Expire in 200 ms for 4 (transfer 0x55b2d405cf50)
* connect to ::1 port 8080 failed: Conexão recusada
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55b2d405cf50)
* Connected to localhost (127.0.0.1) port 8080 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=Self-signed test certificate
*  start date: Oct 19 03:26:42 2020 GMT
*  expire date: Nov 18 03:31:42 2021 GMT
*  issuer: CN=Self-signed test certificate
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.0
> Accept: */*
> 
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

It works on OTP 23! It works with the x509 cert and the openssl one.
Thank you very much, both of you!

@voltone I had to use the certificate generated on the other machine, x509 does not work on OTP 23. I get:

$ mix x509.gen.selfsigned
==> x509
Compiling 22 files (.ex)

== Compilation error in file lib/x509/asn1.ex ==
** (RuntimeError) error parsing file /usr/lib/erlang/lib/public_key-1.9.1/include/OTP-PUB-KEY.hrl, got: {:error, :enoent}                                                         
    (elixir 1.10.3) lib/record/extractor.ex:84: Record.Extractor.read_file/2
    (elixir 1.10.3) lib/record/extractor.ex:50: Record.Extractor.extract_record/2
    lib/x509/asn1.ex:70: anonymous fn/1 in :elixir_compiler_5.__MODULE__/1
    (elixir 1.10.3) lib/enum.ex:783: Enum."-each/2-lists^foreach/1-0-"/2
    (elixir 1.10.3) lib/enum.ex:783: Enum.each/2
    lib/x509/asn1.ex:57: (module)
could not compile dependency :x509, "mix compile" failed. You can recompile this dependency with "mix deps.compile x509", update it with "mix deps.update x509" or clean it with "mix deps.clean x509"

Do you want me to open a bug report or is that a known issue?

EDIT: Everything works when using cowboy directly too.

I guess you’ll need to install the erlang-dev package to make the necessary header files available.

In general I recommend against installing Erlang (and Elixir) from OS package repos: they tend to upgrade very slowly, and are often split into sub-packages that can lead to unexpected errors, as you have seen. I personally use ASDF or pre-built binaries from Hex (but no Debian there, yet)

Oh, and you can avoid the x509 dependency: the mix phx.gen.cert task that comes with Phoenix does the same thing (it was extracted from an early version of the x509 package)

I’m getting the exact same error in a newly-generated phoenix live-view app using pow and pow_assent with mint and castore dependencies added for HTTP/2 and SSL support.

The app was properly configured using the generators from phoenix, pow and pow_assent and everything works as expected without SSL.

I’ve also tried making pow_assent use :httpc instead of mint and added the recommended :certifi and :ssl_verify_fun dependencies from the readme to no avail - I get the same error.

I’m on arch linux with OTP 23.

1 Like