Skip to content

Commit

Permalink
ssl: Move packet encoding to user process
Browse files Browse the repository at this point in the history
While at it disallow setting packet via setopts for dtls connections.
  • Loading branch information
dgud committed Nov 5, 2024
1 parent c4813fd commit a1ac0c0
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 76 deletions.
58 changes: 36 additions & 22 deletions lib/ssl/src/ssl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2551,9 +2551,19 @@ closed.
send(#sslsocket{payload_sender = Sender,
connection_cb = dtls_gen_connection}, Data) when is_pid(Sender) ->
ssl_gen_statem:send(Sender, Data);
send(#sslsocket{payload_sender = Sender,
connection_cb = tls_gen_connection}, Data) when is_pid(Sender) ->
tls_sender:send_data(Sender, erlang:iolist_to_iovec(Data));
send(#sslsocket{payload_sender = Sender, tab = Tab,
connection_cb = tls_gen_connection}, Data0) when is_pid(Sender) ->
try
Packet = ets:lookup_element(Tab, {socket_options, packet}, 2),
case encode_packet(Packet, Data0) of
{error, _} = Error ->
Error;
Data ->
tls_sender:send_data(Sender, erlang:iolist_to_iovec(Data))
end
catch error:badarg ->
{error, closed}
end;
send(#sslsocket{listener_config = #config{connection_cb = dtls_gen_connection}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
send(#sslsocket{socket_handle = ListenSocket,
Expand Down Expand Up @@ -3130,31 +3140,21 @@ getopts(#sslsocket{}, OptionTags) ->
SslSocket :: sslsocket(),
Options :: [gen_tcp:option()].
%%--------------------------------------------------------------------
setopts(#sslsocket{connection_handler = Controller}, [{active, _}] = Active) when is_pid(Controller) ->
setopts(#sslsocket{connection_handler = Controller}, [{active, _}] = Active)
when is_pid(Controller) ->
ssl_gen_statem:set_opts(Controller, Active);
setopts(#sslsocket{connection_handler = Controller, payload_sender = Sender,
connection_cb = tls_gen_connection}, Options0) when is_pid(Controller), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Options0) of
setopts(#sslsocket{connection_handler = Controller, connection_cb = tls_gen_connection}, Options0)
when is_pid(Controller), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Options0) of
Options ->
case proplists:get_value(packet, Options, undefined) of
undefined ->
ssl_gen_statem:set_opts(Controller, Options);
PacketOpt ->
case tls_sender:setopts(Sender, [{packet, PacketOpt}]) of
ok ->
ssl_gen_statem:set_opts(Controller, Options);
Error ->
Error
end
end
ssl_gen_statem:set_opts(Controller, Options)
catch
_:_ ->
{error, {options, {not_a_proplist, Options0}}}
end;
setopts(#sslsocket{connection_handler = Controller}, Options0) when is_pid(Controller), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Options0) of
setopts(#sslsocket{connection_handler = Controller}, Options0)
when is_pid(Controller), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Options0) of
Options ->
ssl_gen_statem:set_opts(Controller, Options)
catch
Expand Down Expand Up @@ -5229,6 +5229,20 @@ unambiguous_path(Value) ->
end,
validate_filename(UP, cacertfile).

-compile({inline, encode_packet/2}).
encode_packet(Packet, Data) ->
Len = iolist_size(Data),
case Packet of
1 when Len < (1 bsl 8) -> [<<Len:8>>|Data];
2 when Len < (1 bsl 16) -> [<<Len:16>>|Data];
4 when Len < (1 bsl 32) -> [<<Len:32>>|Data];
N when N =:= 1; N =:= 2; N =:= 4 ->
{error,
{badarg, {packet_to_large, Len, (1 bsl (Packet bsl 3)) - 1}}};
_ ->
Data
end.

%%%################################################################
%%%#
%%%# Tracing
Expand Down
51 changes: 26 additions & 25 deletions lib/ssl/src/ssl_gen_statem.erl
Original file line number Diff line number Diff line change
Expand Up @@ -842,9 +842,10 @@ handle_call({set_opts, Opts0}, From, StateName,
transport_cb = Transport},
connection_env =
#connection_env{user_application = {_Mon, Pid}},
socket_options = Opts1
socket_options = Opts1,
tab = Tab
} = State0) ->
{Reply, Opts} = set_socket_opts(Connection, Transport, Socket, Opts0, Opts1, []),
{Reply, Opts} = set_socket_opts(Connection, Transport, Socket, Tab, Opts0, Opts1, []),
case {proplists:lookup(active, Opts0), Opts} of
{{_, N}, #socket_options{active=false}} when is_integer(N) ->
send_user(Pid,{ssl_passive,UserSocket});
Expand Down Expand Up @@ -1966,9 +1967,9 @@ get_socket_opts(Connection, Transport, Socket, [Tag | Tags], SockOpts, Acc) ->
get_socket_opts(_,_, _,Opts, _,_) ->
{error, {options, {socket_options, Opts, function_clause}}}.

set_socket_opts(_,_,_, [], SockOpts, []) ->
set_socket_opts(_,_,_, _Tab, [], SockOpts, []) ->
{ok, SockOpts};
set_socket_opts(ConnectionCb, Transport, Socket, [], SockOpts, Other) ->
set_socket_opts(ConnectionCb, Transport, Socket, _Tab, [], SockOpts, Other) ->
%% Set non emulated options
try ConnectionCb:setopts(Transport, Socket, Other) of
ok ->
Expand All @@ -1981,11 +1982,11 @@ set_socket_opts(ConnectionCb, Transport, Socket, [], SockOpts, Other) ->
{{error, {options, {socket_options, Other, Error}}}, SockOpts}
end;

set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active}| Opts], SockOpts, Other)
set_socket_opts(ConnectionCb, Transport, Socket, Tab, [{active, Active}| Opts], SockOpts, Other)
when Active == once; Active == true; Active == false ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts,
SockOpts#socket_options{active = Active}, Other);
set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active1} = Opt| Opts],
set_socket_opts(ConnectionCb, Transport, Socket, Tab, [{active, Active1} = Opt| Opts],
SockOpts=#socket_options{active = Active0}, Other)
when Active1 >= -32768, Active1 =< 32767 ->
Active = if
Expand All @@ -2006,19 +2007,19 @@ set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active1} = Opt| Opts]
error ->
{{error, {options, {socket_options, Opt}} }, SockOpts};
_ ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts,
SockOpts#socket_options{active = Active}, Other)
end;
set_socket_opts(_,_, _, [{active, _} = Opt| _], SockOpts, _) ->
set_socket_opts(_,_, _, _Tab, [{active, _} = Opt| _], SockOpts, _) ->
{{error, {options, {socket_options, Opt}} }, SockOpts};

set_socket_opts(ConnectionCb, Transport,Socket, [{mode, Mode}| Opts], SockOpts, Other)
set_socket_opts(ConnectionCb, Transport, Socket, Tab, [{mode, Mode}| Opts], SockOpts, Other)
when Mode == list; Mode == binary ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts,
SockOpts#socket_options{mode = Mode}, Other);
set_socket_opts(_, _, _, [{mode, _} = Opt| _], SockOpts, _) ->
set_socket_opts(_, _, _, _Tab, [{mode, _} = Opt| _], SockOpts, _) ->
{{error, {options, {socket_options, Opt}}}, SockOpts};
set_socket_opts(ConnectionCb, Transport,Socket, [{packet, Packet}| Opts], SockOpts, Other)
set_socket_opts(tls_gen_connection, Transport, Socket, Tab, [{packet, Packet}| Opts], SockOpts, Other)
when Packet == raw;
Packet == 0;
Packet == 1;
Expand All @@ -2034,30 +2035,30 @@ set_socket_opts(ConnectionCb, Transport,Socket, [{packet, Packet}| Opts], SockOp
Packet == httph;
Packet == http_bin;
Packet == httph_bin ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
true = ets:insert(Tab, {{socket_options, packet}, Packet}),
set_socket_opts(tls_gen_connection, Transport, Socket, Tab, Opts,
SockOpts#socket_options{packet = Packet}, Other);
set_socket_opts(_, _, _, [{packet, _} = Opt| _], SockOpts, _) ->
set_socket_opts(_, _, _, _Tab, [{packet, _} = Opt| _], SockOpts, _) ->
{{error, {options, {socket_options, Opt}}}, SockOpts};
set_socket_opts(ConnectionCb, Transport, Socket, [{header, Header}| Opts], SockOpts, Other)
set_socket_opts(tls_gen_connection, Transport, Socket, Tab, [{header, Header}| Opts], SockOpts, Other)
when is_integer(Header) ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
set_socket_opts(tls_gen_connection, Transport, Socket, Tab, Opts,
SockOpts#socket_options{header = Header}, Other);
set_socket_opts(_, _, _, [{header, _} = Opt| _], SockOpts, _) ->
set_socket_opts(_, _, _, _Tab, [{header, _} = Opt| _], SockOpts, _) ->
{{error,{options, {socket_options, Opt}}}, SockOpts};
set_socket_opts(ConnectionCb, Transport,Socket, [{packet_size, Size}| Opts], SockOpts, Other) when is_integer(Size) ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
set_socket_opts(tls_gen_connection, Transport,Socket, Tab, [{packet_size, Size}| Opts], SockOpts, Other)
when is_integer(Size) ->
set_socket_opts(tls_gen_connection, Transport, Socket, Tab, Opts,
SockOpts#socket_options{packet_size = Size}, Other);
set_socket_opts(_,_, _, [{packet_size, _} = Opt| _], SockOpts, _) ->
set_socket_opts(_,_, _, _Tab, [{packet_size, _} = Opt| _], SockOpts, _) ->
{{error, {options, {socket_options, Opt}} }, SockOpts};
set_socket_opts(ConnectionCb, Transport, Socket, [Opt | Opts], SockOpts, Other) ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts, SockOpts, [Opt | Other]).
set_socket_opts(ConnectionCb, Transport, Socket, Tab, [Opt | Opts], SockOpts, Other) ->
set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts, SockOpts, [Opt | Other]).

ssl_options_list(SslOptions) ->
L = maps:to_list(SslOptions),
ssl_options_list(L, []).



ssl_options_list([], Acc) ->
lists:reverse(Acc);
%% Skip internal options, only return user options
Expand Down
2 changes: 2 additions & 0 deletions lib/ssl/src/tls_dtls_gen_connection.erl
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ initial_state(Role, Sender, Tab, Host, Port, Socket, {SSLOptions, SocketOptions,

SslSocket = tls_socket:socket([self(),Sender], CbModule, Socket, tls_gen_connection, Tab, Trackers),

true = ets:insert(Tab, {{socket_options, packet}, SocketOptions#socket_options.packet}),

InitStatEnv = #static_env{
role = Role,
user_socket = SslSocket,
Expand Down
2 changes: 2 additions & 0 deletions lib/ssl/src/tls_gen_connection_1_3.erl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ initial_state(Role, Sender, Tab, Host, Port, Socket,
UserMonitor = erlang:monitor(process, User),
SslSocket = tls_socket:socket([self(),Sender], CbModule, Socket, tls_gen_connection, Tab, Trackers),

true = ets:insert(Tab, {{socket_options, packet}, SocketOptions#socket_options.packet}),

InitStatEnv = #static_env{
role = Role,
user_socket = SslSocket,
Expand Down
25 changes: 2 additions & 23 deletions lib/ssl/src/tls_sender.erl
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,8 @@ init(_, _, _) ->
StateData :: term()) ->
gen_statem:event_handler_result(atom()).
%%--------------------------------------------------------------------
connection({call, From}, {application_data, AppData},
#data{static = #static{socket_options = #socket_options{packet = Packet}}} =
StateData) ->
case encode_packet(Packet, AppData) of
{error, _} = Error ->
{next_state, connection, StateData, [{reply, From, Error}]};
Data ->
send_application_data(Data, From, connection, StateData)
end;
connection({call, From}, {application_data, Data}, StateData) ->
send_application_data(Data, From, connection, StateData);
connection({call, From}, {post_handshake_data, HSData}, StateData) ->
send_post_handshake_data(HSData, From, connection, StateData);
connection({call, From}, {ack_alert, #alert{} = Alert}, StateData0) ->
Expand Down Expand Up @@ -611,20 +604,6 @@ key_update_at(?TLS_1_3, _, KeyUpdateAt) ->
key_update_at(_, _, KeyUpdateAt) ->
KeyUpdateAt.

-compile({inline, encode_packet/2}).
encode_packet(Packet, Data) ->
Len = iolist_size(Data),
case Packet of
1 when Len < (1 bsl 8) -> [<<Len:8>>|Data];
2 when Len < (1 bsl 16) -> [<<Len:16>>|Data];
4 when Len < (1 bsl 32) -> [<<Len:32>>|Data];
N when N =:= 1; N =:= 2; N =:= 4 ->
{error,
{badarg, {packet_to_large, Len, (1 bsl (Packet bsl 3)) - 1}}};
_ ->
Data
end.

set_opts(SocketOptions, [{packet, N}]) ->
SocketOptions#socket_options{packet = N}.

Expand Down
19 changes: 13 additions & 6 deletions lib/ssl/test/ssl_packet_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2546,18 +2546,25 @@ client_reject_packet_opt(Config, PacketOpt) ->

Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, no_result_msg ,[]}},
{mfa, {ssl_test_lib, no_result, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ServerNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, no_result_msg, []}},
{options, [PacketOpt |
ClientOpts]}]),

ssl_test_lib:check_result(Client, {error, {options, {not_supported, PacketOpt}}}).
{mfa, {ssl_test_lib, no_result, []}},
{options, [PacketOpt | ClientOpts]}]),

ok = ssl_test_lib:check_result(Client, {error, {options, {not_supported, PacketOpt}}}),

Client2 = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl, setopts, [[PacketOpt]]}},
{options, ClientOpts}]),
ssl_test_lib:check_result(Client2, {error, {options, {socket_options, PacketOpt}}}),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client2).

send_switch_packet(SslSocket, Data, NextPacket) ->
spawn(fun() -> ssl:send(SslSocket, Data) end),
Expand Down

0 comments on commit a1ac0c0

Please sign in to comment.