-
Couldn't load subscription status.
- Fork 3k
Description
Describe the bug
We get an unexpected message passed from ssl:send/2 when a TLS1.3 client socket connection, that is configured to use passive mode, is renewing its session keys.
The message we receive is a {Ref, ok}.
Expected behavior
No message should be received by the process sending messages when session keys are renewed.
Affected versions
The OTP versions that are affected by this bug (tested on):
25.3.2.21, 26.2.5.15, 27.3.4.3, 28.1.0.0
Additional context
As stated we use passive mode. We also have a blocking ssl:recv in another process that isn't a controlling process, but I don't think that matters. The minimal reproduction seem to trigger the issue anyway.
To Reproduce
- Prepare certs and keyfiles:
mkdir -p tls
openssl genrsa -out tls/ca.key 4096
openssl req -x509 -new -nodes -key tls/ca.key -sha256 -days 1024 -subj "/C=SE/" -out tls/ca.crt
openssl genrsa -out tls/server.key 4096
openssl req -new -key tls/server.key -subj "/C=SE/CN=localhost/" -out tls/server.csr
openssl x509 -req -in tls/server.csr -CA tls/ca.crt -CAkey tls/ca.key -CAcreateserial -out tls/server.crt -days 500 -sha256
openssl genrsa -out tls/client.key 4096
openssl req -new -sha256 -key tls/client.key -subj "/C=SE/CN=localhost/" | openssl x509 -req -sha256 -CA tls/ca.crt -CAkey tls/ca.key -CAserial tls/ca.txt -CAcreateserial -days 1 -out tls/client.crt
chmod 644 tls/*.key- Start an Erlang shell using a container (and mount certs):
docker run --rm -i -v ./tls:/tls:ro erlang:28.1.0.0-alpine%% Start a simple TLS listener
ssl:start().
server_recv_loop(Socket) ->
case ssl:recv(Socket, 0) of
{ok, _Data} ->
server_recv_loop(Socket);
{error, Reason} ->
io:format(user, "Server error: ~p~n", [Reason])
end.
spawn(fun() ->
{ok, LSocket} = ssl:listen(4000, [{certfile, "tls/server.crt"},
{keyfile, "tls/server.key"},
{reuseaddr, true},
{active, false},
{versions, ['tlsv1.3']},
{verify, verify_none}]),
{ok, TSocket} = ssl:transport_accept(LSocket),
{ok, Socket} = ssl:handshake(TSocket),
server_recv_loop(Socket)
end).Start the client that uses a very low key_update_at value to trigger the problem faster.
The key update seems to give us a {Ref, ok} message
{ok, Socket} = ssl:connect("localhost", 4000, [{active, false}, binary,
{cacertfile, "tls/ca.crt"},
{certfile, "tls/client.crt"},
{keyfile, "tls/client.key"},
{server_name_indication, disable},
{key_update_at, 5000},
{versions, ['tlsv1.3']}], infinity).
client_send_loop(Socket) ->
ssl:send(Socket, "1234567890"),
receive
Msg ->
io:format(user, "Unexpected msg received: ~p~n~n", [Msg]),
ok
after 1 ->
ok
end,
client_send_loop(Socket).
client_send_loop(Socket).Logs received:
Unexpected msg received: {#Ref<0.2397323741.1569456129.138591>,ok}
Unexpected msg received: {#Ref<0.2397323741.1569456129.140081>,ok}
Unexpected msg received: {#Ref<0.2397323741.1569456129.141571>,ok}
Unexpected msg received: {#Ref<0.2397323741.1569456129.143064>,ok}
Unexpected msg received: {#Ref<0.2397323741.1569456129.144554>,ok}