aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src')
-rw-r--r--lib/ssl/src/ssl_app.erl7
-rw-r--r--lib/ssl/src/ssl_cipher.erl4
-rw-r--r--lib/ssl/src/ssl_connection.erl365
-rw-r--r--lib/ssl/src/ssl_dist_sup.erl1
-rw-r--r--lib/ssl/src/ssl_handshake.erl2
-rw-r--r--lib/ssl/src/ssl_manager.erl11
-rw-r--r--lib/ssl/src/ssl_record.erl75
-rw-r--r--lib/ssl/src/ssl_record.hrl9
-rw-r--r--lib/ssl/src/ssl_session_cache.erl16
-rw-r--r--lib/ssl/src/ssl_session_cache_api.erl25
-rw-r--r--lib/ssl/src/ssl_sup.erl1
11 files changed, 227 insertions, 289 deletions
diff --git a/lib/ssl/src/ssl_app.erl b/lib/ssl/src/ssl_app.erl
index c9f81726b9..0c475a6d01 100644
--- a/lib/ssl/src/ssl_app.erl
+++ b/lib/ssl/src/ssl_app.erl
@@ -27,16 +27,9 @@
-export([start/2, stop/1]).
-%%--------------------------------------------------------------------
--spec start(normal | {takeover, node()} | {failover, node()}, list()) ->
- ignore | {ok, pid()} | {error, term()}.
-%%--------------------------------------------------------------------
start(_Type, _StartArgs) ->
ssl_sup:start_link().
-%--------------------------------------------------------------------
--spec stop(term())-> ok.
-%%--------------------------------------------------------------------
stop(_State) ->
ok.
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 95a5efd6d0..015265441e 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -166,7 +166,7 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
false ->
%% decryption failed or invalid padding,
%% intentionally break Content to make
- %% sure a packet with a an invalid padding
+ %% sure a packet with invalid padding
%% but otherwise correct data will fail
%% the MAC test later
{<<16#F0, Content/binary>>, Mac, CipherState1}
@@ -523,7 +523,7 @@ hash_size(sha) ->
%%
%% implementation note:
%% We return the original (possibly invalid) PadLength in any case.
-%% A invalid PadLength will be cought by is_correct_padding/2
+%% An invalid PadLength will be caught by is_correct_padding/2
%%
generic_block_cipher_from_bin(T, HashSize) ->
Sz1 = byte_size(T) - 1,
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 0c44d3ae90..28dd0c85d0 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -87,15 +87,17 @@
bytes_to_read, % integer(), # bytes to read in passive mode
user_data_buffer, % binary()
log_alert, % boolean()
- renegotiation, % {boolean(), From | internal | peer}
- recv_during_renegotiation, %boolean()
- send_queue, % queue()
- terminated = false %
+ renegotiation, % {boolean(), From | internal | peer}
+ recv_from, %
+ send_queue, % queue()
+ terminated = false, %
+ allow_renegotiate = true
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
- #'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
+ #'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
+-define(WAIT_TO_ALLOW_RENEGOTIATION, 12000).
-type state_name() :: hello | abbreviated | certify | cipher | connection.
-type gen_fsm_state_return() :: {next_state, state_name(), #state{}} |
@@ -291,10 +293,6 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
%% gen_fsm callbacks
%%====================================================================
%%--------------------------------------------------------------------
--spec init(list()) -> {ok, state_name(), #state{}, timeout()} | {stop, term()}.
-%% Possible return values not used now.
-%% | {ok, state_name(), #state{}} |
-%% ignore
%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
%% gen_fsm:start_link/3,4, this function is called by the new process to
%% initialize.
@@ -322,8 +320,6 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
end.
%%--------------------------------------------------------------------
-%% -spec state_name(event(), #state{}) -> gen_fsm_state_return()
-%%
%% Description:There should be one instance of this function for each
%% possible state name. Whenever a gen_fsm receives an event sent
%% using gen_fsm:send_event/2, the instance of this function with the
@@ -355,15 +351,15 @@ hello(start, #state{host = Host, port = Port, role = client,
Session0#session{session_id = Hello#client_hello.session_id},
tls_handshake_hashes = Hashes1},
{Record, State} = next_record(State1),
- next_state(hello, Record, State);
+ next_state(hello, hello, Record, State);
hello(start, #state{role = server} = State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(hello, hello, Record, State);
hello(#hello_request{}, #state{role = client} = State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(hello, hello, Record, State);
hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression} = Hello,
@@ -426,7 +422,7 @@ hello(Msg, State) ->
%%--------------------------------------------------------------------
abbreviated(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(abbreviated, hello, Record, State);
abbreviated(#finished{verify_data = Data} = Finished,
#state{role = server,
@@ -479,7 +475,7 @@ abbreviated(Msg, State) ->
%%--------------------------------------------------------------------
certify(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(certify, hello, Record, State);
certify(#certificate{asn1_certificates = []},
#state{role = server, negotiated_version = Version,
@@ -487,7 +483,7 @@ certify(#certificate{asn1_certificates = []},
fail_if_no_peer_cert = true}} =
State) ->
Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE),
- handle_own_alert(Alert, Version, certify_certificate, State),
+ handle_own_alert(Alert, Version, certify, State),
{stop, normal, State};
certify(#certificate{asn1_certificates = []},
@@ -496,7 +492,7 @@ certify(#certificate{asn1_certificates = []},
fail_if_no_peer_cert = false}} =
State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = false}),
- next_state(certify, Record, State);
+ next_state(certify, certify, Record, State);
certify(#certificate{} = Cert,
#state{negotiated_version = Version,
@@ -511,7 +507,7 @@ certify(#certificate{} = Cert,
handle_peer_cert(PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false});
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify_certificate, State),
+ handle_own_alert(Alert, Version, certify, State),
{stop, normal, State}
end;
@@ -522,10 +518,9 @@ certify(#server_key_exchange{} = KeyExchangeMsg,
case handle_server_key(KeyExchangeMsg, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
- next_state(certify, Record, State);
+ next_state(certify, certify, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify_server_keyexchange,
- State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -535,7 +530,7 @@ certify(#server_key_exchange{} = Msg,
certify(#certificate_request{}, State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = true}),
- next_state(certify, Record, State);
+ next_state(certify, certify, Record, State);
%% Master secret was determined with help of server-key exchange msg
certify(#server_hello_done{},
@@ -550,8 +545,7 @@ certify(#server_hello_done{},
State = State0#state{connection_states = ConnectionStates1},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_server_hello_done, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -570,8 +564,7 @@ certify(#server_hello_done{},
session = Session},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_server_hello_done, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -588,7 +581,7 @@ certify(#client_key_exchange{exchange_keys = Keys},
certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version), State)
catch
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify_client_key_exchange, State),
+ handle_own_alert(Alert, Version, certify, State),
{stop, normal, State}
end;
@@ -611,10 +604,9 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
State1 = State0#state{connection_states = ConnectionStates,
session = Session},
{Record, State} = next_record(State1),
- next_state(cipher, Record, State);
+ next_state(certify, cipher, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_client_key_exchange, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -626,10 +618,9 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
- next_state(cipher, Record, State);
+ next_state(certify, cipher, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_client_key_exchange, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end.
@@ -639,7 +630,7 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
%%--------------------------------------------------------------------
cipher(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(cipher, hello, Record, State);
cipher(#certificate_verify{signature = Signature},
#state{role = server,
@@ -652,7 +643,7 @@ cipher(#certificate_verify{signature = Signature},
Version, MasterSecret, Hashes) of
valid ->
{Record, State} = next_record(State0),
- next_state(cipher, Record, State);
+ next_state(cipher, cipher, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, cipher, State0),
{stop, normal, State0}
@@ -705,20 +696,32 @@ connection(#hello_request{}, #state{host = Host, port = Port,
{Record, State} = next_record(State0#state{connection_states =
ConnectionStates1,
tls_handshake_hashes = Hashes1}),
- next_state(hello, Record, State);
-connection(#client_hello{} = Hello, #state{role = server} = State) ->
- hello(Hello, State);
-
+ next_state(connection, hello, Record, State);
+connection(#client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) ->
+ %% Mitigate Computational DoS attack
+ %% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
+ %% http://www.thc.org/thc-ssl-dos/ Rather than disabling client
+ %% initiated renegotiation we will disallow many client initiated
+ %% renegotiations immediately after each other.
+ erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
+ hello(Hello, State#state{allow_renegotiate = false});
+
+connection(#client_hello{}, #state{role = server, allow_renegotiate = false,
+ connection_states = ConnectionStates0,
+ socket = Socket, transport_cb = Transport,
+ negotiated_version = Version} = State0) ->
+ Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
+ {BinMsg, ConnectionStates} =
+ encode_alert(Alert, Version, ConnectionStates0),
+ Transport:send(Socket, BinMsg),
+ next_state_connection(connection, State0#state{connection_states = ConnectionStates});
+
connection(timeout, State) ->
{next_state, connection, State, hibernate};
connection(Msg, State) ->
handle_unexpected_message(Msg, connection, State).
%%--------------------------------------------------------------------
--spec handle_event(term(), state_name(), #state{}) -> term().
-%% As it is not currently used gen_fsm_state_return() makes
-%% dialyzer unhappy!
-%%
%% Description: Whenever a gen_fsm receives an event sent using
%% gen_fsm:send_all_state_event/2, this function is called to handle
%% the event. Not currently used!
@@ -727,47 +730,16 @@ handle_event(_Event, StateName, State) ->
{next_state, StateName, State, get_timeout(State)}.
%%--------------------------------------------------------------------
--spec handle_sync_event(term(), from(), state_name(), #state{}) ->
- gen_fsm_state_return() |
- {reply, reply(), state_name(), #state{}} |
- {reply, reply(), state_name(), #state{}, timeout()} |
- {stop, reason(), reply(), #state{}}.
-%%
%% Description: Whenever a gen_fsm receives an event sent using
%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
%% the event.
%%--------------------------------------------------------------------
-handle_sync_event({application_data, Data0}, From, connection,
- #state{socket = Socket,
- negotiated_version = Version,
- transport_cb = Transport,
- connection_states = ConnectionStates0,
- send_queue = SendQueue,
- socket_options = SockOpts,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}}
- = State) ->
+handle_sync_event({application_data, Data}, From, connection, State) ->
%% We should look into having a worker process to do this to
%% parallize send and receive decoding and not block the receiver
%% if sending is overloading the socket.
try
- Data = encode_packet(Data0, SockOpts),
- case encode_data(Data, Version, ConnectionStates0, RenegotiateAt) of
- {Msgs, [], ConnectionStates} ->
- Result = Transport:send(Socket, Msgs),
- {reply, Result,
- connection, State#state{connection_states = ConnectionStates},
- get_timeout(State)};
- {Msgs, RestData, ConnectionStates} ->
- if
- Msgs =/= [] ->
- Transport:send(Socket, Msgs);
- true ->
- ok
- end,
- renegotiate(State#state{connection_states = ConnectionStates,
- send_queue = queue:in_r({From, RestData}, SendQueue),
- renegotiation = {true, internal}})
- end
+ write_application_data(Data, From, State)
catch throw:Error ->
{reply, Error, connection, State, get_timeout(State)}
end;
@@ -824,14 +796,12 @@ handle_sync_event({shutdown, How0}, _, StateName,
end;
handle_sync_event({recv, N}, From, connection = StateName, State0) ->
- passive_receive(State0#state{bytes_to_read = N, from = From}, StateName);
+ passive_receive(State0#state{bytes_to_read = N, recv_from = From}, StateName);
%% Doing renegotiate wait with handling request until renegotiate is
-%% finished. Will be handled by next_state_connection/2.
+%% finished. Will be handled by next_state_is_connection/2.
handle_sync_event({recv, N}, From, StateName, State) ->
- {next_state, StateName,
- State#state{bytes_to_read = N, from = From,
- recv_during_renegotiation = true},
+ {next_state, StateName, State#state{bytes_to_read = N, recv_from = From},
get_timeout(State)};
handle_sync_event({new_user, User}, _From, StateName,
@@ -869,7 +839,7 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
Buffer =:= <<>>, Opts1#socket_options.active =:= false ->
%% Need data, set active once
{Record, State2} = next_record_if_active(State1),
- case next_state(StateName, Record, State2) of
+ case next_state(StateName, StateName, Record, State2) of
{next_state, StateName, State, Timeout} ->
{reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
@@ -879,11 +849,11 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
%% Active once already set
{reply, Reply, StateName, State1, get_timeout(State1)};
true ->
- case application_data(<<>>, State1) of
+ case read_application_data(<<>>, State1) of
Stop = {stop,_,_} ->
Stop;
{Record, State2} ->
- case next_state(StateName, Record, State2) of
+ case next_state(StateName, StateName, Record, State2) of
{next_state, StateName, State, Timeout} ->
{reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
@@ -919,11 +889,6 @@ handle_sync_event(peer_certificate, _, StateName,
{reply, {ok, Cert}, StateName, State, get_timeout(State)}.
%%--------------------------------------------------------------------
--spec handle_info(msg(),state_name(), #state{}) ->
- {next_state, state_name(), #state{}}|
- {next_state, state_name(), #state{}, timeout()} |
- {stop, reason(), #state{}}.
-%%
%% Description: This function is called by a gen_fsm when it receives any
%% other message than a synchronous or asynchronous event
%% (or a system message).
@@ -931,22 +896,18 @@ handle_sync_event(peer_certificate, _, StateName,
%% raw data from TCP, unpack records
handle_info({Protocol, _, Data}, StateName,
- #state{data_tag = Protocol,
- negotiated_version = Version} = State0) ->
+ #state{data_tag = Protocol} = State0) ->
case next_tls_record(Data, State0) of
{Record, State} ->
- next_state(StateName, Record, State);
+ next_state(StateName, StateName, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State0),
+ handle_normal_shutdown(Alert, StateName, State0),
{stop, normal, State0}
end;
-handle_info({CloseTag, Socket}, _StateName,
+handle_info({CloseTag, Socket}, StateName,
#state{socket = Socket, close_tag = CloseTag,
- negotiated_version = Version,
- socket_options = Opts,
- user_application = {_Mon,Pid}, from = From,
- role = Role} = State) ->
+ negotiated_version = Version} = State) ->
%% Note that as of TLS 1.1,
%% failure to properly close a connection no longer requires that a
%% session not be resumed. This is a change from TLS 1.0 to conform
@@ -961,8 +922,7 @@ handle_info({CloseTag, Socket}, _StateName,
%%invalidate_session(Role, Host, Port, Session)
ok
end,
- alert_user(Opts#socket_options.active, Pid, From,
- ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), Role),
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
{stop, normal, State};
handle_info({ErrorTag, Socket, econnaborted}, StateName,
@@ -971,26 +931,26 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName,
alert_user(User, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role),
{stop, normal, State};
-handle_info({ErrorTag, Socket, Reason}, _,
- #state{socket = Socket, from = User,
- role = Role, error_tag = ErrorTag} = State) ->
+handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
+ error_tag = ErrorTag} = State) ->
Report = io_lib:format("SSL: Socket error: ~p ~n", [Reason]),
error_logger:info_report(Report),
- alert_user(User, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role),
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
{stop, normal, State};
handle_info({'DOWN', MonitorRef, _, _, _}, _,
State = #state{user_application={MonitorRef,_Pid}}) ->
{stop, normal, State};
+handle_info(allow_renegotiate, StateName, State) ->
+ {next_state, StateName, State#state{allow_renegotiate = true}, get_timeout(State)};
+
handle_info(Msg, StateName, State) ->
Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]),
error_logger:info_report(Report),
{next_state, StateName, State, get_timeout(State)}.
%%--------------------------------------------------------------------
--spec terminate(reason(), state_name(), #state{}) -> term().
-%%
%% Description:This function is called by a gen_fsm when it is about
%% to terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_fsm terminates with
@@ -1021,8 +981,6 @@ terminate(Reason, _StateName, #state{transport_cb = Transport,
Transport:close(Socket).
%%--------------------------------------------------------------------
--spec code_change(term(), state_name(), #state{}, list()) -> {ok, state_name(), #state{}}.
-%%
%% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
@@ -1218,7 +1176,7 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
{Record, State} = next_record(State1),
- next_state(certify, Record, State).
+ next_state(certify, certify, Record, State).
certify_client(#state{client_certificate_requested = true, role = client,
connection_states = ConnectionStates0,
@@ -1260,8 +1218,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
ignore ->
State;
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State)
-
+ throw(Alert)
end;
verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
@@ -1293,7 +1250,7 @@ do_server_hello(Type, #state{negotiated_version = Version,
ConnectionStates,
tls_handshake_hashes = Hashes},
{Record, State} = next_record(State3),
- next_state(abbreviated, Record, State);
+ next_state(hello, abbreviated, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State1),
{stop, normal, State1}
@@ -1313,7 +1270,7 @@ new_server_hello(#server_hello{cipher_suite = CipherSuite,
cipher_suite = CipherSuite,
compression_method = Compression},
{Record, State} = next_record(State2#state{session = Session}),
- next_state(certify, Record, State)
+ next_state(hello, certify, Record, State)
catch
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State0),
@@ -1325,7 +1282,7 @@ handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0} =
cipher_suite = CipherSuite,
compression_method = Compression},
{Record, State} = next_record(State0#state{session = Session}),
- next_state(certify, Record, State).
+ next_state(hello, certify, Record, State).
handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1340,7 +1297,7 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
next_record(State0#state{
connection_states = ConnectionStates1,
session = Session}),
- next_state(abbreviated, Record, State);
+ next_state(hello, abbreviated, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State0),
{stop, normal, State0}
@@ -1357,10 +1314,10 @@ client_certify_and_key_exchange(#state{negotiated_version = Version} =
client_certificate_requested = false,
tls_handshake_hashes = Hashes},
{Record, State} = next_record(State2),
- next_state(cipher, Record, State)
+ next_state(certify, cipher, Record, State)
catch
- #alert{} = Alert ->
- handle_own_alert(Alert, Version, client_certify_and_key_exchange, State0),
+ throw:#alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end.
@@ -1671,15 +1628,12 @@ encode_packet(Data, #socket_options{packet=Packet}) ->
end.
encode_size_packet(Bin, Size, Max) ->
- Len = byte_size(Bin),
+ Len = erlang:byte_size(Bin),
case Len > Max of
true -> throw({error, {badarg, {packet_to_large, Len, Max}}});
false -> <<Len:Size, Bin/binary>>
end.
-encode_data(Data, Version, ConnectionStates, RenegotiateAt) ->
- ssl_record:encode_data(Data, Version, ConnectionStates, RenegotiateAt).
-
decode_alerts(Bin) ->
decode_alerts(Bin, []).
@@ -1693,20 +1647,20 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
case Buffer of
<<>> ->
{Record, State} = next_record(State0),
- next_state(StateName, Record, State);
+ next_state(StateName, StateName, Record, State);
_ ->
- case application_data(<<>>, State0) of
+ case read_application_data(<<>>, State0) of
Stop = {stop, _, _} ->
Stop;
{Record, State} ->
- next_state(StateName, Record, State)
+ next_state(StateName, StateName, Record, State)
end
end.
-application_data(Data, #state{user_application = {_Mon, Pid},
+read_application_data(Data, #state{user_application = {_Mon, Pid},
socket_options = SOpts,
bytes_to_read = BytesToRead,
- from = From,
+ recv_from = From,
user_data_buffer = Buffer0} = State0) ->
Buffer1 = if
Buffer0 =:= <<>> -> Data;
@@ -1717,7 +1671,7 @@ application_data(Data, #state{user_application = {_Mon, Pid},
{ok, ClientData, Buffer} -> % Send data
SocketOpt = deliver_app_data(SOpts, ClientData, Pid, From),
State = State0#state{user_data_buffer = Buffer,
- from = undefined,
+ recv_from = undefined,
bytes_to_read = 0,
socket_options = SocketOpt
},
@@ -1727,7 +1681,7 @@ application_data(Data, #state{user_application = {_Mon, Pid},
%% Active and empty, get more data
next_record_if_active(State);
true -> %% We have more data
- application_data(<<>>, State)
+ read_application_data(<<>>, State)
end;
{more, Buffer} -> % no reply, we need more data
next_record(State0#state{user_data_buffer = Buffer});
@@ -1736,6 +1690,39 @@ application_data(Data, #state{user_application = {_Mon, Pid},
{stop, normal, State0}
end.
+write_application_data(Data0, From, #state{socket = Socket,
+ negotiated_version = Version,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0,
+ send_queue = SendQueue,
+ socket_options = SockOpts,
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State) ->
+ Data = encode_packet(Data0, SockOpts),
+
+ case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
+ true ->
+ renegotiate(State#state{send_queue = queue:in_r({From, Data}, SendQueue),
+ renegotiation = {true, internal}});
+ false ->
+ {Msgs, ConnectionStates} = ssl_record:encode_data(Data, Version, ConnectionStates0),
+ Result = Transport:send(Socket, Msgs),
+ {reply, Result,
+ connection, State#state{connection_states = ConnectionStates}, get_timeout(State)}
+ end.
+
+time_to_renegotiate(_Data, #connection_states{current_write =
+ #connection_state{sequence_number = Num}}, RenegotiateAt) ->
+
+ %% We could do test:
+ %% is_time_to_renegotiate((erlang:byte_size(_Data) div ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt),
+ %% but we chose to have a some what lower renegotiateAt and a much cheaper test
+ is_time_to_renegotiate(Num, RenegotiateAt).
+
+is_time_to_renegotiate(N, M) when N < M->
+ false;
+is_time_to_renegotiate(_,_) ->
+ true.
+
%% Picks ClientData
get_data(_, _, <<>>) ->
{more, <<>>};
@@ -1837,6 +1824,10 @@ header(N, Binary) ->
send_or_reply(false, _Pid, From, Data) when From =/= undefined ->
gen_fsm:reply(From, Data);
+%% Can happen when handling own alert or tcp error/close and there is
+%% no outstanding gen_fsm sync events
+send_or_reply(false, no_pid, _, _) ->
+ ok;
send_or_reply(_, Pid, _From, Data) ->
send_user(Pid, Data).
@@ -1861,18 +1852,18 @@ handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet | Packets]}
Stop
end.
-next_state(_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
- handle_own_alert(Alert, Version, decipher_error, State),
+next_state(Current,_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
+ handle_own_alert(Alert, Version, Current, State),
{stop, normal, State};
-next_state(Next, no_record, State) ->
+next_state(_,Next, no_record, State) ->
{next_state, Next, State, get_timeout(State)};
-next_state(Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
+next_state(_,Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
Alerts = decode_alerts(EncAlerts),
handle_alerts(Alerts, {next_state, Next, State, get_timeout(State)});
-next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
+next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
State0 = #state{tls_handshake_buffer = Buf0, negotiated_version = Version}) ->
Handle =
fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
@@ -1898,30 +1889,30 @@ next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
try
{Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0),
State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf},
- handle_tls_handshake(Handle, StateName, State)
+ handle_tls_handshake(Handle, Next, State)
catch throw:#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State0),
+ handle_own_alert(Alert, Version, Current, State0),
{stop, normal, State0}
end;
-next_state(StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
- case application_data(Data, State0) of
+next_state(_, StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
+ case read_application_data(Data, State0) of
Stop = {stop,_,_} ->
Stop;
{Record, State} ->
- next_state(StateName, Record, State)
+ next_state(StateName, StateName, Record, State)
end;
-next_state(StateName, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
+next_state(Current, Next, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
_ChangeCipher,
#state{connection_states = ConnectionStates0} = State0) ->
ConnectionStates1 =
ssl_record:activate_pending_connection_state(ConnectionStates0, read),
{Record, State} = next_record(State0#state{connection_states = ConnectionStates1}),
- next_state(StateName, Record, State);
-next_state(StateName, #ssl_tls{type = _Unknown}, State0) ->
+ next_state(Current, Next, Record, State);
+next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
%% Ignore unknown type
{Record, State} = next_record(State0),
- next_state(StateName, Record, State).
+ next_state(Current, Next, Record, State).
next_tls_record(Data, #state{tls_record_buffer = Buf0,
tls_cipher_texts = CT0} = State0) ->
@@ -1960,50 +1951,36 @@ next_state_connection(StateName, #state{send_queue = Queue0,
negotiated_version = Version,
socket = Socket,
transport_cb = Transport,
- connection_states = ConnectionStates0,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}
+ connection_states = ConnectionStates0
} = State) ->
- %% Send queued up data
+ %% Send queued up data that was queued while renegotiating
case queue:out(Queue0) of
{{value, {From, Data}}, Queue} ->
- case encode_data(Data, Version, ConnectionStates0, RenegotiateAt) of
- {Msgs, [], ConnectionStates} ->
- Result = Transport:send(Socket, Msgs),
- gen_fsm:reply(From, Result),
- next_state_connection(StateName,
- State#state{connection_states = ConnectionStates,
- send_queue = Queue});
- %% This is unlikely to happen. User configuration of the
- %% undocumented test option renegotiation_at can make it more likely.
- {Msgs, RestData, ConnectionStates} ->
- if
- Msgs =/= [] ->
- Transport:send(Socket, Msgs);
- true ->
- ok
- end,
- renegotiate(State#state{connection_states = ConnectionStates,
- send_queue = queue:in_r({From, RestData}, Queue),
- renegotiation = {true, internal}})
- end;
+ {Msgs, ConnectionStates} =
+ ssl_record:encode_data(Data, Version, ConnectionStates0),
+ Result = Transport:send(Socket, Msgs),
+ gen_fsm:reply(From, Result),
+ next_state_connection(StateName,
+ State#state{connection_states = ConnectionStates,
+ send_queue = Queue});
{empty, Queue0} ->
- next_state_is_connection(State)
+ next_state_is_connection(StateName, State)
end.
%% In next_state_is_connection/1: clear tls_handshake_hashes,
%% premaster_secret and public_key_info (only needed during handshake)
%% to reduce memory foot print of a connection.
-next_state_is_connection(State =
- #state{recv_during_renegotiation = true, socket_options =
- #socket_options{active = false}}) ->
- passive_receive(State#state{recv_during_renegotiation = false,
- premaster_secret = undefined,
+next_state_is_connection(_, State =
+ #state{recv_from = From,
+ socket_options =
+ #socket_options{active = false}}) when From =/= undefined ->
+ passive_receive(State#state{premaster_secret = undefined,
public_key_info = undefined,
tls_handshake_hashes = {<<>>, <<>>}}, connection);
-next_state_is_connection(State0) ->
+next_state_is_connection(StateName, State0) ->
{Record, State} = next_record_if_active(State0),
- next_state(connection, Record, State#state{premaster_secret = undefined,
+ next_state(StateName, connection, Record, State#state{premaster_secret = undefined,
public_key_info = undefined,
tls_handshake_hashes = {<<>>, <<>>}}).
@@ -2059,7 +2036,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
log_alert = true,
session_cache_cb = SessionCacheCb,
renegotiation = {false, first},
- recv_during_renegotiation = false,
+ recv_from = undefined,
send_queue = queue:new()
}.
@@ -2172,16 +2149,14 @@ handle_alert(#alert{level = ?FATAL} = Alert, StateName,
{stop, normal, State};
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
- StateName, #state{from = From, role = Role,
- user_application = {_Mon, Pid}, socket_options = Opts} = State) ->
- alert_user(StateName, Opts, Pid, From, Alert, Role),
+ StateName, State) ->
+ handle_normal_shutdown(Alert, StateName, State),
{stop, normal, State};
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
- #state{log_alert = Log, renegotiation = {true, internal}, from = From,
- role = Role} = State) ->
+ #state{log_alert = Log, renegotiation = {true, internal}} = State) ->
log_alert(Log, StateName, Alert),
- alert_user(From, Alert, Role),
+ handle_normal_shutdown(Alert, StateName, State),
{stop, normal, State};
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
@@ -2189,13 +2164,13 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert,
log_alert(Log, StateName, Alert),
gen_fsm:reply(From, {error, renegotiation_rejected}),
{Record, State} = next_record(State0),
- next_state(connection, Record, State);
+ next_state(StateName, connection, Record, State);
handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, StateName,
#state{log_alert = Log} = State0) ->
log_alert(Log, StateName, Alert),
{Record, State} = next_record(State0),
- next_state(StateName, Record, State).
+ next_state(StateName, StateName, Record, State).
alert_user(connection, Opts, Pid, From, Alert, Role) ->
alert_user(Opts#socket_options.active, Pid, From, Alert, Role);
@@ -2227,13 +2202,11 @@ log_alert(true, Info, Alert) ->
log_alert(false, _, _) ->
ok.
-handle_own_alert(Alert, Version, Info,
+handle_own_alert(Alert, Version, StateName,
#state{transport_cb = Transport,
socket = Socket,
- from = User,
- role = Role,
connection_states = ConnectionStates,
- log_alert = Log}) ->
+ log_alert = Log} = State) ->
try %% Try to tell the other side
{BinMsg, _} =
encode_alert(Alert, Version, ConnectionStates),
@@ -2243,12 +2216,20 @@ handle_own_alert(Alert, Version, Info,
ignore
end,
try %% Try to tell the local user
- log_alert(Log, Info, Alert),
- alert_user(User, Alert, Role)
+ log_alert(Log, StateName, Alert),
+ handle_normal_shutdown(Alert,StateName, State)
catch _:_ ->
ok
end.
+handle_normal_shutdown(Alert, _, #state{from = User, role = Role, renegotiation = {false, first}}) ->
+ alert_user(User, Alert, Role);
+
+handle_normal_shutdown(Alert, StateName, #state{socket_options = Opts,
+ user_application = {_Mon, Pid},
+ from = User, role = Role}) ->
+ alert_user(StateName, Opts, Pid, User, Alert, Role).
+
handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
handle_own_alert(Alert, Version, {Info, Msg}, State),
@@ -2261,7 +2242,7 @@ make_premaster_secret(_, _) ->
undefined.
mpint_binary(Binary) ->
- Size = byte_size(Binary),
+ Size = erlang:byte_size(Binary),
<<?UINT32(Size), Binary/binary>>.
@@ -2298,7 +2279,7 @@ renegotiate(#state{role = server,
{Record, State} = next_record(State0#state{connection_states =
ConnectionStates,
tls_handshake_hashes = Hs0}),
- next_state(hello, Record, State).
+ next_state(connection, hello, Record, State#state{allow_renegotiate = true}).
notify_senders(SendQueue) ->
lists:foreach(fun({From, _}) ->
diff --git a/lib/ssl/src/ssl_dist_sup.erl b/lib/ssl/src/ssl_dist_sup.erl
index c1912401d7..9d9afb7707 100644
--- a/lib/ssl/src/ssl_dist_sup.erl
+++ b/lib/ssl/src/ssl_dist_sup.erl
@@ -41,7 +41,6 @@ start_link() ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init([]) -> {ok, {SupFlags :: tuple(), [ChildSpec :: tuple()]}}.
init([]) ->
SessionCertManager = session_and_cert_manager_child_spec(),
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 7eb7f44df6..371f475c85 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -447,7 +447,7 @@ server_hello_done() ->
-spec encode_handshake(tls_handshake(), tls_version()) -> iolist().
%%
%% Description: Encode a handshake packet to binary
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------x
encode_handshake(Package, Version) ->
{MsgType, Bin} = enc_hs(Package, Version),
Len = byte_size(Bin),
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 6a44ef8c3e..6389ff03f5 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -51,7 +51,7 @@
session_lifetime,
certificate_db,
session_validation_timer,
- last_delay_timer %% Keep for testing purposes
+ last_delay_timer = {undefined, undefined}%% Keep for testing purposes
}).
-define('24H_in_msec', 8640000).
@@ -427,7 +427,7 @@ delay_time() ->
?CLEAN_SESSION_DB
end.
-invalidate_session(Cache, CacheCb, Key, Session, State) ->
+invalidate_session(Cache, CacheCb, Key, Session, #state{last_delay_timer = LastTimer} = State) ->
case CacheCb:lookup(Cache, Key) of
undefined -> %% Session is already invalidated
{noreply, State};
@@ -441,5 +441,10 @@ invalidate_session(Cache, CacheCb, Key, Session, State) ->
CacheCb:update(Cache, Key, Session#session{is_resumable = false}),
TRef =
erlang:send_after(delay_time(), self(), {delayed_clean_session, Key}),
- {noreply, State#state{last_delay_timer = TRef}}
+ {noreply, State#state{last_delay_timer = last_delay_timer(Key, TRef, LastTimer)}}
end.
+
+last_delay_timer({{_,_},_}, TRef, {LastServer, _}) ->
+ {LastServer, TRef};
+last_delay_timer({_,_}, TRef, {_, LastClient}) ->
+ {TRef, LastClient}.
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 72091fdd5f..830026c825 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -48,7 +48,7 @@
%% Encoding records
-export([encode_handshake/3, encode_alert_record/3,
- encode_change_cipher_spec/2, encode_data/4]).
+ encode_change_cipher_spec/2, encode_data/3]).
%% Decoding
-export([decode_cipher_text/2]).
@@ -503,36 +503,18 @@ decode_cipher_text(CipherText, ConnnectionStates0) ->
Alert
end.
%%--------------------------------------------------------------------
--spec encode_data(iolist(), tls_version(), #connection_states{}, integer()) ->
- {iolist(), iolist(), #connection_states{}}.
+-spec encode_data(binary(), tls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
%%
%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
-encode_data(Frag, Version, ConnectionStates, RenegotiateAt)
- when byte_size(Frag) < (?MAX_PLAIN_TEXT_LENGTH - 2048) ->
- case encode_plain_text(?APPLICATION_DATA,Version,Frag,ConnectionStates, RenegotiateAt) of
- {renegotiate, Data} ->
- {[], Data, ConnectionStates};
- {Msg, CS} ->
- {Msg, [], CS}
- end;
-
-encode_data(Frag, Version, ConnectionStates, RenegotiateAt) when is_binary(Frag) ->
- Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH - 2048),
- encode_data(Data, Version, ConnectionStates, RenegotiateAt);
-
-encode_data(Data, Version, ConnectionStates0, RenegotiateAt) when is_list(Data) ->
- {ConnectionStates, EncodedMsg, NotEncdedData} =
- lists:foldl(fun(B, {CS0, Encoded, Rest}) ->
- case encode_plain_text(?APPLICATION_DATA,
- Version, B, CS0, RenegotiateAt) of
- {renegotiate, NotEnc} ->
- {CS0, Encoded, [NotEnc | Rest]};
- {Enc, CS1} ->
- {CS1, [Enc | Encoded], Rest}
- end
- end, {ConnectionStates0, [], []}, Data),
- {lists:reverse(EncodedMsg), lists:reverse(NotEncdedData), ConnectionStates}.
+encode_data(Frag, Version,
+ #connection_states{current_write = #connection_state{
+ security_parameters =
+ #security_parameters{bulk_cipher_algorithm = BCA}}} =
+ ConnectionStates) ->
+ Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, Version, BCA),
+ encode_iolist(?APPLICATION_DATA, Data, Version, ConnectionStates).
%%--------------------------------------------------------------------
-spec encode_handshake(iolist(), tls_version(), #connection_states{}) ->
@@ -566,6 +548,14 @@ encode_change_cipher_spec(Version, ConnectionStates) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+encode_iolist(Type, Data, Version, ConnectionStates0) ->
+ {ConnectionStates, EncodedMsg} =
+ lists:foldl(fun(Text, {CS0, Encoded}) ->
+ {Enc, CS1} = encode_plain_text(Type, Version, Text, CS0),
+ {CS1, [Enc | Encoded]}
+ end, {ConnectionStates0, []}, Data),
+ {lists:reverse(EncodedMsg), ConnectionStates}.
+
highest_protocol_version() ->
highest_protocol_version(supported_protocol_versions()).
@@ -602,29 +592,23 @@ record_protocol_role(client) ->
record_protocol_role(server) ->
?SERVER.
-split_bin(Bin, ChunkSize) ->
- split_bin(Bin, ChunkSize, []).
+%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are not vulnerable to this attack.
+split_bin(<<FirstByte:8, Rest/binary>>, ChunkSize, Version, BCA) when BCA =/= ?RC4 andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ do_split_bin(Rest, ChunkSize, [[FirstByte]]);
+split_bin(Bin, ChunkSize, _, _) ->
+ do_split_bin(Bin, ChunkSize, []).
-split_bin(<<>>, _, Acc) ->
+do_split_bin(<<>>, _, Acc) ->
lists:reverse(Acc);
-split_bin(Bin, ChunkSize, Acc) ->
+do_split_bin(Bin, ChunkSize, Acc) ->
case Bin of
<<Chunk:ChunkSize/binary, Rest/binary>> ->
- split_bin(Rest, ChunkSize, [Chunk | Acc]);
+ do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
_ ->
lists:reverse(Acc, [Bin])
end.
-encode_plain_text(Type, Version, Data, ConnectionStates, RenegotiateAt) ->
- #connection_states{current_write =
- #connection_state{sequence_number = Num}} = ConnectionStates,
- case renegotiate(Num, RenegotiateAt) of
- false ->
- encode_plain_text(Type, Version, Data, ConnectionStates);
- true ->
- {renegotiate, Data}
- end.
-
encode_plain_text(Type, Version, Data, ConnectionStates) ->
#connection_states{current_write=#connection_state{
compression_state=CompS0,
@@ -637,11 +621,6 @@ encode_plain_text(Type, Version, Data, ConnectionStates) ->
CTBin = encode_tls_cipher_text(Type, Version, CipherText),
{CTBin, ConnectionStates#connection_states{current_write = CS2}}.
-renegotiate(N, M) when N < M->
- false;
-renegotiate(_,_) ->
- true.
-
encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment) ->
Length = erlang:iolist_size(Fragment),
[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment].
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index 5fb0070b91..282d642138 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -70,9 +70,10 @@
-define(MAX_SEQENCE_NUMBER, 18446744073709552000). %% math:pow(2, 64) - 1 = 1.8446744073709552e19
%% Sequence numbers can not wrap so when max is about to be reached we should renegotiate.
%% We will renegotiate a little before so that there will be sequence numbers left
-%% for the rehandshake and a little data.
--define(MARGIN, 100).
--define(DEFAULT_RENEGOTIATE_AT, ?MAX_SEQENCE_NUMBER - ?MARGIN).
+%% for the rehandshake and a little data. Currently we decided to renegotiate a little more
+%% often as we can have a cheaper test to check if it is time to renegotiate. It will still
+%% be fairly seldom.
+-define(DEFAULT_RENEGOTIATE_AT, 268435456). %% math:pow(2, 28)
%% ConnectionEnd
-define(SERVER, 0).
diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl
index 93969f628f..f9bbf905e1 100644
--- a/lib/ssl/src/ssl_session_cache.erl
+++ b/lib/ssl/src/ssl_session_cache.erl
@@ -28,27 +28,19 @@
-export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3,
select_session/2]).
--type key() :: {{host(), inet:port_number()}, session_id()} | {inet:port_number(), session_id()}.
-
%%--------------------------------------------------------------------
--spec init(list()) -> db_handle(). %% Returns reference to the cache (opaque)
-%%
%% Description: Return table reference. Called by ssl_manager process.
%%--------------------------------------------------------------------
init(_) ->
ets:new(cache_name(), [set, protected]).
%%--------------------------------------------------------------------
--spec terminate(db_handle()) -> any().
-%%
%% Description: Handles cache table at termination of ssl manager.
%%--------------------------------------------------------------------
terminate(Cache) ->
ets:delete(Cache).
%%--------------------------------------------------------------------
--spec lookup(db_handle(), key()) -> #session{} | undefined.
-%%
%% Description: Looks up a cach entry. Should be callable from any
%% process.
%%--------------------------------------------------------------------
@@ -61,8 +53,6 @@ lookup(Cache, Key) ->
end.
%%--------------------------------------------------------------------
--spec update(db_handle(), key(), #session{}) -> any().
-%%
%% Description: Caches a new session or updates a already cached one.
%% Will only be called from the ssl_manager process.
%%--------------------------------------------------------------------
@@ -70,8 +60,6 @@ update(Cache, Key, Session) ->
ets:insert(Cache, {Key, Session}).
%%--------------------------------------------------------------------
--spec delete(db_handle(), key()) -> any().
-%%
%% Description: Delets a cache entry.
%% Will only be called from the ssl_manager process.
%%--------------------------------------------------------------------
@@ -79,8 +67,6 @@ delete(Cache, Key) ->
ets:delete(Cache, Key).
%%--------------------------------------------------------------------
--spec foldl(fun(), term(), db_handle()) -> term().
-%%
%% Description: Calls Fun(Elem, AccIn) on successive elements of the
%% cache, starting with AccIn == Acc0. Fun/2 must return a new
%% accumulator which is passed to the next call. The function returns
@@ -91,8 +77,6 @@ foldl(Fun, Acc0, Cache) ->
ets:foldl(Fun, Acc0, Cache).
%%--------------------------------------------------------------------
--spec select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}].
-%%
%% Description: Selects a session that could be reused. Should be callable
%% from any process.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_session_cache_api.erl b/lib/ssl/src/ssl_session_cache_api.erl
index f8416bf327..f2b22b0f1b 100644
--- a/lib/ssl/src/ssl_session_cache_api.erl
+++ b/lib/ssl/src/ssl_session_cache_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,18 +20,15 @@
%%
-module(ssl_session_cache_api).
+-include("ssl_handshake.hrl").
+-include("ssl_internal.hrl").
--export([behaviour_info/1]).
+-type key() :: {{host(), inet:port_number()}, session_id()} | {inet:port_number(), session_id()}.
-behaviour_info(callbacks) ->
- [
- {init, 1},
- {terminate, 1},
- {lookup, 2},
- {update, 3},
- {delete, 2},
- {foldl, 3},
- {select_session, 2}
- ];
-behaviour_info(_) ->
- undefined.
+-callback init(list()) -> db_handle().
+-callback terminate(db_handle()) -> any().
+-callback lookup(db_handle(), key()) -> #session{} | undefined.
+-callback update(db_handle(), key(), #session{}) -> any().
+-callback delete(db_handle(), key()) -> any().
+-callback foldl(fun(), term(), db_handle()) -> term().
+-callback select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}].
diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl
index cb10b1362a..59039a6e0a 100644
--- a/lib/ssl/src/ssl_sup.erl
+++ b/lib/ssl/src/ssl_sup.erl
@@ -41,7 +41,6 @@ start_link() ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init([]) -> {ok, {SupFlags :: tuple(), [ChildSpec :: tuple()]}}.
init([]) ->
%% OLD ssl - moved start to ssl.erl only if old