Skip to content

Commit

Permalink
Refactor renegotiation data in connection states
Browse files Browse the repository at this point in the history
Reduce memory of the state record.
  • Loading branch information
dgud committed Feb 1, 2024
1 parent 3c7091d commit e5bf7a8
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 139 deletions.
6 changes: 3 additions & 3 deletions lib/ssl/src/dtls_record.erl
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,9 @@ initial_connection_state(ConnectionEnd) ->
replay_window => init_replay_window(),
cipher_state => undefined,
mac_secret => undefined,
secure_renegotiation => undefined,
client_verify_data => undefined,
server_verify_data => undefined
reneg => #{secure_renegotiation => undefined,
client_verify_data => undefined,
server_verify_data => undefined}
}.

get_dtls_records_aux({DataTag, StateName, _, Versions} = Vinfo,
Expand Down
40 changes: 16 additions & 24 deletions lib/ssl/src/ssl_handshake.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3619,30 +3619,25 @@ max_frag_enum(undefined) ->
renegotiation_info(_, client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(_RecordCB, server, ConnectionStates, false) ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
case maps:get(secure_renegotiation, ConnectionState) of
true ->
case ssl_record:current_connection_state(ConnectionStates, read) of
#{reneg := #{secure_renegotiation := true}} ->
#renegotiation_info{renegotiated_connection = ?byte(0)};
false ->
#renegotiation_info{renegotiated_connection = undefined}
end;
renegotiation_info(_RecordCB, client, ConnectionStates, true) ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
case maps:get(secure_renegotiation, ConnectionState) of
true ->
Data = maps:get(client_verify_data, ConnectionState),
case ssl_record:current_connection_state(ConnectionStates, read) of
#{reneg := #{secure_renegotiation := true, client_verify_data := Data}} ->
#renegotiation_info{renegotiated_connection = Data};
false ->
#renegotiation_info{renegotiated_connection = undefined}
end;

renegotiation_info(_RecordCB, server, ConnectionStates, true) ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
case maps:get(secure_renegotiation, ConnectionState) of
true ->
CData = maps:get(client_verify_data, ConnectionState),
SData = maps:get(server_verify_data, ConnectionState),
#renegotiation_info{renegotiated_connection = <<CData/binary, SData/binary>>};
case ssl_record:current_connection_state(ConnectionStates, read) of
#{reneg := #{secure_renegotiation := true,
client_verify_data := CData,
server_verify_data := SData}} ->
#renegotiation_info{renegotiated_connection = <<CData/binary, SData/binary>>};
false ->
#renegotiation_info{renegotiated_connection = undefined}
end.
Expand All @@ -3664,9 +3659,8 @@ handle_renegotiation_info(_, _RecordCB, _, undefined, ConnectionStates, false, _

handle_renegotiation_info(_, _RecordCB, client, #renegotiation_info{renegotiated_connection = ClientServerVerify},
ConnectionStates, true, _, _) ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
CData = maps:get(client_verify_data, ConnectionState),
SData = maps:get(server_verify_data, ConnectionState),
#{reneg := ReNeg} = ssl_record:current_connection_state(ConnectionStates, read),
#{client_verify_data := CData, server_verify_data := SData} = ReNeg,
case <<CData/binary, SData/binary>> == ClientServerVerify of
true ->
{ok, ConnectionStates};
Expand All @@ -3680,12 +3674,10 @@ handle_renegotiation_info(_, _RecordCB, server, #renegotiation_info{renegotiated
true ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv}));
false ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
Data = maps:get(client_verify_data, ConnectionState),
case Data == ClientVerify of
true ->
case ssl_record:current_connection_state(ConnectionStates, read) of
#{reneg := #{client_verify_data := ClientVerify}} ->
{ok, ConnectionStates};
false ->
_ ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, server_renegotiation))
end
end;
Expand All @@ -3701,8 +3693,8 @@ handle_renegotiation_info(_, RecordCB, server, undefined, ConnectionStates, true
end.

handle_renegotiation_info(_RecordCB, ConnectionStates, SecureRenegotation) ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
case {SecureRenegotation, maps:get(secure_renegotiation, ConnectionState)} of
#{reneg := #{secure_renegotiation := SR}} = ssl_record:current_connection_state(ConnectionStates, read),
case {SecureRenegotation, SR} of
{_, true} ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, already_secure));
{true, false} ->
Expand Down
168 changes: 75 additions & 93 deletions lib/ssl/src/ssl_record.erl
Original file line number Diff line number Diff line change
Expand Up @@ -99,25 +99,24 @@ pending_connection_state(ConnectionStates, write) ->
activate_pending_connection_state(#{current_read := Current,
pending_read := Pending} = States,
read, Connection) ->
#{secure_renegotiation := SecureRenegotation} = Current,
#{security_parameters := SecParams} = Pending,
NewCurrent = Pending#{sequence_number => 0},
ConnectionEnd = SecParams#security_parameters.connection_end,
EmptyPending = Connection:empty_connection_state(ConnectionEnd),
NewPending = EmptyPending#{secure_renegotiation => SecureRenegotation},
States#{current_read => NewCurrent,
pending_read => NewPending};
{NewCurrent, NewPending} = activate_pending_connection_state_1(Current, Pending, Connection),
States#{current_read => NewCurrent, pending_read => NewPending};
activate_pending_connection_state(#{current_write := Current,
pending_write := Pending} = States,
write, Connection) ->
NewCurrent = Pending#{sequence_number => 0},
#{secure_renegotiation := SecureRenegotation} = Current,
{NewCurrent, NewPending} = activate_pending_connection_state_1(Current, Pending, Connection),
States#{current_write => NewCurrent, pending_write => NewPending}.

activate_pending_connection_state_1(Current, Pending, Connection) ->
#{reneg := #{secure_renegotiation := SecReNeg}} = Current,
Update = fun(#{reneg := ReNeg} = Cs) ->
Cs#{reneg := ReNeg#{secure_renegotiation := SecReNeg}}
end,
#{security_parameters := SecParams} = Pending,
NewCurrent = Pending#{sequence_number => 0},
ConnectionEnd = SecParams#security_parameters.connection_end,
EmptyPending = Connection:empty_connection_state(ConnectionEnd),
NewPending = EmptyPending#{secure_renegotiation => SecureRenegotation},
States#{current_write => NewCurrent,
pending_write => NewPending}.
{NewCurrent, Update(EmptyPending)}.

%%--------------------------------------------------------------------
-spec step_encryption_state(#state{}) -> #state{}.
Expand Down Expand Up @@ -197,19 +196,19 @@ set_master_secret(MasterSecret,
%%
%% Description: Set secure_renegotiation in pending connection states
%%--------------------------------------------------------------------
set_renegotiation_flag(Flag, #{current_read := CurrentRead0,
current_write := CurrentWrite0,
pending_read := PendingRead0,
pending_write := PendingWrite0}
= ConnectionStates) ->
CurrentRead = CurrentRead0#{secure_renegotiation => Flag},
CurrentWrite = CurrentWrite0#{secure_renegotiation => Flag},
PendingRead = PendingRead0#{secure_renegotiation => Flag},
PendingWrite = PendingWrite0#{secure_renegotiation => Flag},
ConnectionStates#{current_read => CurrentRead,
current_write => CurrentWrite,
pending_read => PendingRead,
pending_write => PendingWrite}.
set_renegotiation_flag(Flag, #{current_read := CurrentRead,
current_write := CurrentWrite,
pending_read := PendingRead,
pending_write := PendingWrite}
= ConnectionStates)
when is_boolean(Flag) ->
Update = fun(#{reneg := ReNeg} = CS) ->
CS#{reneg := ReNeg#{secure_renegotiation := Flag}}
end,
ConnectionStates#{current_read => Update(CurrentRead),
current_write => Update(CurrentWrite),
pending_read => Update(PendingRead),
pending_write => Update(PendingWrite)}.

%%--------------------------------------------------------------------
-spec set_max_fragment_length(term(), connection_states()) -> connection_states().
Expand All @@ -234,83 +233,66 @@ set_max_fragment_length(_,ConnectionStates) ->
%%
%% Description: Set verify data in connection states.
%%--------------------------------------------------------------------
set_client_verify_data(current_read, Data,
#{current_read := CurrentRead0,
pending_write := PendingWrite0}
= ConnectionStates) ->
CurrentRead = CurrentRead0#{client_verify_data => Data},
PendingWrite = PendingWrite0#{client_verify_data => Data},
ConnectionStates#{current_read => CurrentRead,
pending_write => PendingWrite};
set_client_verify_data(current_write, Data,
#{pending_read := PendingRead0,
current_write := CurrentWrite0}
= ConnectionStates) ->
PendingRead = PendingRead0#{client_verify_data => Data},
CurrentWrite = CurrentWrite0#{client_verify_data => Data},
ConnectionStates#{pending_read => PendingRead,
current_write => CurrentWrite};
set_client_verify_data(current_both, Data,
#{current_read := CurrentRead0,
current_write := CurrentWrite0}
= ConnectionStates) ->
CurrentRead = CurrentRead0#{client_verify_data => Data},
CurrentWrite = CurrentWrite0#{client_verify_data => Data},
ConnectionStates#{current_read => CurrentRead,
current_write => CurrentWrite}.
set_client_verify_data(What, Data, ConnectionStates) ->
Update = fun(#{reneg := ReNeg} = CS) ->
CS#{reneg := ReNeg#{client_verify_data := Data}}
end,
case What of
current_read ->
#{current_read := CurrentRead, pending_write := PendingWrite} = ConnectionStates,
ConnectionStates#{current_read => Update(CurrentRead),
pending_write => Update(PendingWrite)};
current_write ->
#{pending_read := PendingRead, current_write := CurrentWrite} = ConnectionStates,
ConnectionStates#{pending_read => Update(PendingRead),
current_write => Update(CurrentWrite)};
current_both ->
#{current_read := CurrentRead, current_write := CurrentWrite} = ConnectionStates,
ConnectionStates#{current_read => Update(CurrentRead),
current_write => Update(CurrentWrite)}
end.
%%--------------------------------------------------------------------
-spec set_server_verify_data(current_read | current_write | current_both,
binary(), connection_states())->
connection_states().
%%
%% Description: Set verify data in pending connection states.
%%--------------------------------------------------------------------
set_server_verify_data(current_write, Data,
#{pending_read := PendingRead0,
current_write := CurrentWrite0}
= ConnectionStates) ->
PendingRead = PendingRead0#{server_verify_data => Data},
CurrentWrite = CurrentWrite0#{server_verify_data => Data},
ConnectionStates#{pending_read => PendingRead,
current_write => CurrentWrite};

set_server_verify_data(current_read, Data,
#{current_read := CurrentRead0,
pending_write := PendingWrite0}
= ConnectionStates) ->
CurrentRead = CurrentRead0#{server_verify_data => Data},
PendingWrite = PendingWrite0#{server_verify_data => Data},
ConnectionStates#{current_read => CurrentRead,
pending_write => PendingWrite};

set_server_verify_data(current_both, Data,
#{current_read := CurrentRead0,
current_write := CurrentWrite0}
= ConnectionStates) ->
CurrentRead = CurrentRead0#{server_verify_data => Data},
CurrentWrite = CurrentWrite0#{server_verify_data => Data},
ConnectionStates#{current_read => CurrentRead,
current_write => CurrentWrite}.
set_server_verify_data(What, Data, ConnectionStates) ->
Update = fun(#{reneg := ReNeg} = CS) ->
CS#{reneg := ReNeg#{server_verify_data := Data}}
end,
case What of
current_write ->
#{pending_read := PendingRead, current_write := CurrentWrite} = ConnectionStates,
ConnectionStates#{pending_read => Update(PendingRead),
current_write => Update(CurrentWrite)};
current_read ->
#{current_read := CurrentRead, pending_write := PendingWrite} = ConnectionStates,
ConnectionStates#{current_read => Update(CurrentRead),
pending_write => Update(PendingWrite)};
current_both ->
#{current_read := CurrentRead, current_write := CurrentWrite} = ConnectionStates,
ConnectionStates#{current_read => Update(CurrentRead),
current_write => Update(CurrentWrite)}
end.
%%--------------------------------------------------------------------
-spec set_pending_cipher_state(connection_states(), #cipher_state{},
#cipher_state{}, client | server) ->
connection_states().
%%
%% Description: Set the cipher state in the specified pending connection state.
%%--------------------------------------------------------------------
set_pending_cipher_state(#{pending_read := Read,
pending_write := Write} = States,
ClientState, ServerState, server) ->
States#{
pending_read => Read#{cipher_state => ClientState},
pending_write => Write#{cipher_state => ServerState}};

set_pending_cipher_state(#{pending_read := Read,
pending_write := Write} = States,
ClientState, ServerState, client) ->
States#{
pending_read => Read#{cipher_state => ServerState},
pending_write => Write#{cipher_state => ClientState}}.
set_pending_cipher_state(#{pending_read := Read, pending_write := Write} = States,
ClientState, ServerState, Role) ->
case Role of
server ->
States#{pending_read => Read#{cipher_state => ClientState},
pending_write => Write#{cipher_state => ServerState}};
client ->
States#{pending_read => Read#{cipher_state => ServerState},
pending_write => Write#{cipher_state => ClientState}}
end.

%%====================================================================
%% Payload encryption/decryption
Expand Down Expand Up @@ -434,12 +416,12 @@ empty_connection_state(ConnectionEnd, Version, MaxEarlyDataSize) ->
#{security_parameters => SecParams,
cipher_state => undefined,
mac_secret => undefined,
secure_renegotiation => undefined,
client_verify_data => undefined,
server_verify_data => undefined,
pending_early_data_size => MaxEarlyDataSize,
trial_decryption => false,
early_data_accepted => false
early_data_accepted => false,
reneg => #{secure_renegotiation => undefined,
client_verify_data => undefined,
server_verify_data => undefined}
}.

init_security_parameters(?CLIENT, Version) ->
Expand Down
8 changes: 4 additions & 4 deletions lib/ssl/src/ssl_record.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
%% cipher_state,
%% mac_secret,
%% sequence_number,
%% %% RFC 5746
%% secure_renegotiation,
%% client_verify_data,
%% server_verify_data,
%% reneg = %% RFC 5746
%% #{secure_renegotiation,
%% client_verify_data,
%% server_verify_data},
%% %% How to do BEAST mitigation?
%% beast_mitigation
%% }).
Expand Down
8 changes: 4 additions & 4 deletions lib/ssl/src/tls_record.erl
Original file line number Diff line number Diff line change
Expand Up @@ -460,12 +460,12 @@ initial_connection_state(ConnectionEnd, MaxEarlyDataSize) ->
sequence_number => 0,
cipher_state => undefined,
mac_secret => undefined,
secure_renegotiation => undefined,
client_verify_data => undefined,
server_verify_data => undefined,
pending_early_data_size => MaxEarlyDataSize,
trial_decryption => false,
early_data_expected => false
early_data_expected => false,
reneg => #{secure_renegotiation => undefined,
client_verify_data => undefined,
server_verify_data => undefined}
}.

%% Used by logging to recreate the received bytes
Expand Down
2 changes: 1 addition & 1 deletion lib/ssl/test/ssl_npn_hello_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ create_connection_states() ->
cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA
}
},
current_read => #{secure_renegotiation => false
current_read => #{reneg => #{secure_renegotiation => false}
}
}.

Expand Down
13 changes: 9 additions & 4 deletions lib/ssl/test/ssl_session_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -760,9 +760,13 @@ client_hello(Random) ->

connection_states(Random) ->
#{current_write =>
#{beast_mitigation => one_n_minus_one,cipher_state => undefined,
client_verify_data => undefined,
mac_secret => undefined,secure_renegotiation => undefined,
#{beast_mitigation => one_n_minus_one,
cipher_state => undefined,
mac_secret => undefined,
reneg => #{secure_renegotiation => undefined,
client_verify_data => undefined,
server_verify_data => undefined
},
security_parameters =>
#security_parameters{
cipher_suite = <<0,0>>,
Expand All @@ -778,7 +782,8 @@ connection_states(Random) ->
resumption_master_secret = undefined,
client_random = Random,
server_random = undefined},
sequence_number => 0,server_verify_data => undefined,max_fragment_length => undefined}}.
sequence_number => 0,
max_fragment_length => undefined}}.



Expand Down
Loading

0 comments on commit e5bf7a8

Please sign in to comment.