Hi! I have an issue with a Ranch listener with client verification. In short, when using tls 1.2 it works as expected, but when using tls 1.3 clients always receive {:ok, socket}, even when the handshake process fails (i would have expected to receive {:error, {tls_alert, …}}. However, when trying to send to this socket, {:error, :closed} is received. Below is an example.
Listener:
def start_listener(opts) do
versions = Keyword.get(opts, :versions)
verify_fun = Keyword.get(opts, :verify_fun)
key = key()
cacerts = cacerts()
crt = cert()
socket_opts =
[
cacerts: cacerts,
key: key,
cert: crt,
versions: versions,
verify: :verify_peer,
fail_if_no_peer_cert: true,
verify_fun: {verify_fun, []},
port: 49665,
ciphers: :ssl.cipher_suites(:all,:'tlsv1.2') ++ :ssl.cipher_suites(:all,:'tlsv1.3')
]
opts = %{
connection_type: :supervisor,
socket_opts: socket_opts,
}
{:ok, _} = :ranch.start_listener(:Tls, :ranch_ssl, opts, Prot, cert_verification: true)
end
Client connection:
def connect(tls_versions) do
client_ca_cert = client_ca_cert()
{client_cert, client_key} = generate_cert()
:ssl.connect(
{127, 0, 0, 1},
49_665,
[
versions: tls_versions,
ciphers: :ssl.cipher_suites(:all,:'tlsv1.2') ++ :ssl.cipher_suites(:all,:'tlsv1.3'),
cacerts: [client_ca_cert],
key: {:RSAPrivateKey, client_key},
cert: client_cert,
]
)
end
When i try to connect with TLS 1.2 and a verify function that is guaranteed to fail it works as expected:
iex(1)> Listener.start_listener([versions: [:"tlsv1.2"], verify_fun: fn(_c, _r, _s) -> {:fail, :internal_error} end])
{:ok, #PID<0.207.0>}
iex(2)> Listener.connect([:"tlsv1.2"])
11:40:44.558 [warn] Description: 'Authenticity is not established by certificate path validation'
Reason: 'Option {verify, verify_peer} and cacertfile/cacerts is missing'
11:40:44.607 [info] TLS :server: In state :certify at ssl_handshake.erl:2017 generated SERVER ALERT: Fatal - Handshake Failure
- :internal_error
11:40:44.617 [info] TLS :client: In state :cipher received SERVER ALERT: Fatal - Handshake Failure
{:error,
{:tls_alert,
{:handshake_failure,
'TLS client: In state cipher received SERVER ALERT: Fatal - Handshake Failure\n'}}}
However, when doing the same with TLS 1.3, i get the successful message. It seems to be received before the handshake has failed:
iex(1)> Listener.start_listener([versions: [:"tlsv1.3"], verify_fun: fn(_c, _r, _s) -> {:fail, :internal_error} end])
{:ok, #PID<0.221.0>}
iex(2)> Listener.connect([:"tlsv1.3"])
11:42:51.559 [warn] Description: 'Authenticity is not established by certificate path validation'
Reason: 'Option {verify, verify_peer} and cacertfile/cacerts is missing'
{:ok,
{:sslsocket, {:gen_tcp, #Port<0.7>, :tls_connection, :undefined},
[#PID<0.240.0>, #PID<0.238.0>]}}
iex(3)>
11:42:51.640 [info] TLS :server: In state :wait_cert at ssl_handshake.erl:2017 generated SERVER ALERT: Fatal - Handshake Failure
- :internal_error
11:42:51.665 [info] TLS :client: In state :connection received SERVER ALERT: Fatal - Handshake Failure