summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngela Anderton Andin <ingela@erlang.org>2022-08-02 15:41:19 +0200
committerIngela Anderton Andin <ingela@erlang.org>2022-08-04 15:42:08 +0200
commit936a34615c24ca417eb78c20e0f3b8cbe71f5563 (patch)
treef144cff2a8c717115d49dc65f5e910765b2e6c9d
parentc1f8dd07522f86052249463bd62deeff9d73cf53 (diff)
downloaderlang-936a34615c24ca417eb78c20e0f3b8cbe71f5563.tar.gz
ssl: Handle change cipher spec message in TLS-1.3 middle-box compatibility mode
-rw-r--r--lib/ssl/src/ssl_gen_statem.erl2
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl162
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl5
-rw-r--r--lib/ssl/test/tls_api_SUITE.erl57
4 files changed, 189 insertions, 37 deletions
diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl
index caa6c6742d..a6053e7e3f 100644
--- a/lib/ssl/src/ssl_gen_statem.erl
+++ b/lib/ssl/src/ssl_gen_statem.erl
@@ -709,8 +709,6 @@ handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName,
Connection:handle_protocol_record(TLSorDTLSRecord, StateName, State);
handle_common_event(timeout, hibernate, _, _) ->
{keep_state_and_data, [hibernate]};
-handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName, State) ->
- handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), StateName, State);
handle_common_event({timeout, handshake}, close, _StateName, #state{start_or_recv_from = StartFrom} = State) ->
{stop_and_reply,
{shutdown, user_timeout},
diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
index 19c9a05a2f..a4f0e454f4 100644
--- a/lib/ssl/src/tls_connection_1_3.erl
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -125,6 +125,8 @@
config_error/3,
user_hello/3,
start/3,
+ hello_middlebox_assert/3,
+ hello_retry_middlebox_assert/3,
negotiated/3,
wait_cert/3,
wait_cv/3,
@@ -183,7 +185,7 @@ update_cipher_key(ConnStateName, CS0) ->
%% gen_statem callbacks
%%--------------------------------------------------------------------
callback_mode() ->
- state_functions.
+ [state_functions, state_enter].
init([Role, Sender, Host, Port, Socket, Options, User, CbInfo]) ->
State0 = #state{protocol_specific = Map} = initial_state(Role, Sender,
@@ -220,6 +222,8 @@ code_change(_OldVsn, StateName, State, _) ->
{start, timeout()} | term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
+initial_hello(enter, _, State) ->
+ {keep_state, State};
initial_hello(Type, Event, State) ->
ssl_gen_statem:?FUNCTION_NAME(Type, Event, State).
@@ -228,10 +232,13 @@ initial_hello(Type, Event, State) ->
{start, timeout()} | term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
+config_error(enter, _, State) ->
+ {keep_state, State};
config_error(Type, Event, State) ->
ssl_gen_statem:?FUNCTION_NAME(Type, Event, State).
-
+user_hello(enter, _, State) ->
+ {keep_state, State};
user_hello({call, From}, cancel, State) ->
gen_statem:reply(From, ok),
ssl_gen_statem:handle_own_alert(?ALERT_REC(?FATAL, ?USER_CANCELED, user_canceled),
@@ -255,8 +262,21 @@ user_hello(info, {'DOWN', _, _, _, _} = Event, State) ->
user_hello(_, _, _) ->
{keep_state_and_data, [postpone]}.
-start(internal, #change_cipher_spec{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
+start(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+start(internal = Type, #change_cipher_spec{} = Msg,
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{tls_handshake_history = Hist}} = State) ->
+ case ssl_handshake:init_handshake_history() of
+ Hist -> %% First message must always be client hello
+ ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State);
+ _ ->
+ tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State)
+ end;
+start(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
start(internal, #client_hello{extensions = Extensions} = Hello,
#state{ssl_options = #{handshake := hello},
start_or_recv_from = From,
@@ -297,8 +317,12 @@ start(info, Msg, State) ->
start(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
-negotiated(internal, #change_cipher_spec{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
+negotiated(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+negotiated(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
negotiated(internal, Message, State0) ->
case tls_handshake_1_3:do_negotiated(Message, State0) of
#alert{} = Alert ->
@@ -309,8 +333,12 @@ negotiated(internal, Message, State0) ->
negotiated(info, Msg, State) ->
tls_gen_connection:handle_info(Msg, ?FUNCTION_NAME, State).
-wait_cert(internal, #change_cipher_spec{}, State0) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State0);
+wait_cert(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+wait_cert(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
wait_cert(internal,
#certificate_1_3{} = Certificate, State0) ->
case tls_handshake_1_3:do_wait_cert(Certificate, State0) of
@@ -324,8 +352,12 @@ wait_cert(info, Msg, State) ->
wait_cert(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
-wait_cv(internal, #change_cipher_spec{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_cv(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+wait_cv(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
wait_cv(internal,
#certificate_verify_1_3{} = CertificateVerify, State0) ->
case tls_handshake_1_3:do_wait_cv(CertificateVerify, State0) of
@@ -339,8 +371,12 @@ wait_cv(info, Msg, State) ->
wait_cv(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
-wait_finished(internal, #change_cipher_spec{}, State0) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State0);
+wait_finished(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+wait_finished(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
wait_finished(internal,
#finished{} = Finished, State0) ->
case tls_handshake_1_3:do_wait_finished(Finished, State0) of
@@ -356,34 +392,76 @@ wait_finished(info, Msg, State) ->
wait_finished(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
-
-wait_sh(internal, #change_cipher_spec{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
-wait_sh(internal, #server_hello{extensions = Extensions} = Hello, #state{ssl_options = #{handshake := hello},
- start_or_recv_from = From,
- handshake_env = HsEnv} = State) ->
+wait_sh(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+wait_sh(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
+wait_sh(internal, #server_hello{extensions = Extensions} = Hello,
+ #state{ssl_options = #{handshake := hello},
+ start_or_recv_from = From,
+ handshake_env = HsEnv} = State) ->
{next_state, user_hello,
State#state{start_or_recv_from = undefined,
handshake_env = HsEnv#handshake_env{
hello = Hello}}, [{reply, From, {ok, Extensions}}]};
-wait_sh(internal, #server_hello{} = Hello, State0) ->
+wait_sh(internal, #server_hello{} = Hello,
+ #state{ssl_options = #{middlebox_comp_mode := false}} = State0) ->
case tls_handshake_1_3:do_wait_sh(Hello, State0) of
- #alert{} = Alert ->
+ #alert{} = Alert ->
ssl_gen_statem:handle_own_alert(Alert, wait_sh, State0);
{State1, start, ServerHello} ->
%% hello_retry_request: go to start
- {next_state, start, State1, [{next_event, internal, ServerHello}]};
+ {next_state, start, State1, [{next_event, internal, ServerHello}]};
{State1, wait_ee} ->
- tls_gen_connection:next_event(wait_ee, no_record, State1)
+ tls_gen_connection:next_event(wait_ee, no_record, State1)
+ end;
+wait_sh(internal, #server_hello{} = Hello,
+ #state{ssl_options = #{middlebox_comp_mode := true}, protocol_specific = PS} = State0) ->
+ IsRetry = maps:get(hello_retry, PS, false),
+ case tls_handshake_1_3:do_wait_sh(Hello, State0) of
+ #alert{} = Alert ->
+ ssl_gen_statem:handle_own_alert(Alert, wait_sh, State0);
+ {State1, start, ServerHello} ->
+ %% hello_retry_request: go to start
+ {next_state, hello_retry_middlebox_assert, State1, [{next_event, internal, ServerHello}]};
+ {State1, wait_ee} when IsRetry == true ->
+ tls_gen_connection:next_event(wait_ee, no_record, State1);
+ {State1, wait_ee} when IsRetry == false ->
+ tls_gen_connection:next_event(hello_middlebox_assert, no_record, State1)
end;
wait_sh(info, Msg, State) ->
tls_gen_connection:handle_info(Msg, ?FUNCTION_NAME, State);
wait_sh(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
+hello_middlebox_assert(enter, _, State) ->
+ {keep_state, State};
+hello_middlebox_assert(internal, #change_cipher_spec{}, State) ->
+ tls_gen_connection:next_event(wait_ee, no_record, State);
+hello_middlebox_assert(info, Msg, State) ->
+ tls_gen_connection:handle_info(Msg, ?FUNCTION_NAME, State);
+hello_middlebox_assert(Type, Msg, State) ->
+ ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
-wait_ee(internal, #change_cipher_spec{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
+hello_retry_middlebox_assert(enter, _, State) ->
+ {keep_state, State};
+hello_retry_middlebox_assert(internal, #change_cipher_spec{}, State) ->
+ tls_gen_connection:next_event(start, no_record, State);
+hello_retry_middlebox_assert(internal, #server_hello{}, State) ->
+ tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State, [postpone]);
+hello_retry_middlebox_assert(info, Msg, State) ->
+ tls_gen_connection:handle_info(Msg, ?FUNCTION_NAME, State);
+hello_retry_middlebox_assert(Type, Msg, State) ->
+ ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
+
+wait_ee(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+wait_ee(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
wait_ee(internal, #encrypted_extensions{} = EE, State0) ->
case tls_handshake_1_3:do_wait_ee(EE, State0) of
#alert{} = Alert ->
@@ -396,9 +474,12 @@ wait_ee(info, Msg, State) ->
wait_ee(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
-
-wait_cert_cr(internal, #change_cipher_spec{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_cert_cr(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+wait_cert_cr(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}} = State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
wait_cert_cr(internal, #certificate_1_3{} = Certificate, State0) ->
case tls_handshake_1_3:do_wait_cert_cr(Certificate, State0) of
{#alert{} = Alert, State} ->
@@ -418,8 +499,12 @@ wait_cert_cr(info, Msg, State) ->
wait_cert_cr(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
-wait_eoed(internal, #change_cipher_spec{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_eoed(enter, _, State0) ->
+ State = handle_middlebox(State0),
+ {next_state, ?FUNCTION_NAME, State,[]};
+wait_eoed(internal = Type, #change_cipher_spec{} = Msg,
+ #state{ssl_options = #{middlebox_comp_mode := true}}= State) ->
+ handle_change_cipher_spec(Type, Msg, ?FUNCTION_NAME, State);
wait_eoed(internal, #end_of_early_data{} = EOED, State0) ->
case tls_handshake_1_3:do_wait_eoed(EOED, State0) of
{#alert{} = Alert, State} ->
@@ -432,6 +517,8 @@ wait_eoed(info, Msg, State) ->
wait_eoed(Type, Msg, State) ->
ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
+connection(enter, _, State) ->
+ {keep_state, State};
connection(internal, #new_session_ticket{} = NewSessionTicket, State) ->
handle_new_session_ticket(NewSessionTicket, State),
tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
@@ -455,6 +542,8 @@ connection({call, From}, negotiated_protocol,
connection(Type, Event, State) ->
ssl_gen_statem:?FUNCTION_NAME(Type, Event, State).
+downgrade(enter, _, State) ->
+ {keep_state, State};
downgrade(internal, #new_session_ticket{} = NewSessionTicket, State) ->
_ = handle_new_session_ticket(NewSessionTicket, State),
{next_state, ?FUNCTION_NAME, State};
@@ -591,3 +680,18 @@ init_max_early_data_size(client) ->
init_max_early_data_size(server) ->
ssl_config:get_max_early_data_size().
+handle_middlebox(#state{ssl_options = #{middlebox_comp_mode := true},
+ protocol_specific = PS} = State0) ->
+ State0#state{protocol_specific = PS#{change_cipher_spec => ignore}};
+handle_middlebox(State) ->
+ State.
+
+handle_change_cipher_spec(Type, Msg, StateName, #state{protocol_specific = PS0} = State) ->
+ case maps:get(change_cipher_spec, PS0) of
+ ignore ->
+ PS = PS0#{change_cipher_spec => fail},
+ tls_gen_connection:next_event(StateName, no_record,
+ State#state{protocol_specific = PS});
+ fail ->
+ ssl_gen_statem:handle_common_event(Type, Msg, StateName, State)
+ end.
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index cd48226c87..3e6117735f 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -1128,8 +1128,9 @@ do_wait_eoed(#end_of_early_data{}, State0) ->
%% Upon receiving a message with type server_hello, implementations MUST
%% first examine the Random value and, if it matches this value, process
%% it as described in Section 4.1.4).
-maybe_hello_retry_request(#server_hello{random = ?HELLO_RETRY_REQUEST_RANDOM} = ServerHello, State0) ->
- {error, {State0, start, ServerHello}};
+maybe_hello_retry_request(#server_hello{random = ?HELLO_RETRY_REQUEST_RANDOM} = ServerHello,
+ #state{protocol_specific = PS} = State0) ->
+ {error, {State0#state{protocol_specific = PS#{hello_retry => true}}, start, ServerHello}};
maybe_hello_retry_request(_, _) ->
ok.
diff --git a/lib/ssl/test/tls_api_SUITE.erl b/lib/ssl/test/tls_api_SUITE.erl
index 7e5f312152..c81d29370e 100644
--- a/lib/ssl/test/tls_api_SUITE.erl
+++ b/lib/ssl/test/tls_api_SUITE.erl
@@ -28,6 +28,7 @@
-include_lib("ssl/src/ssl_api.hrl").
-include_lib("ssl/src/tls_handshake.hrl").
-include_lib("ssl/src/ssl_alert.hrl").
+-include_lib("ssl/src/ssl_cipher.hrl").
%% Common test
-export([all/0,
@@ -85,6 +86,10 @@
tls_reject_fake_warning_alert_in_initial_hs/1,
tls_app_data_in_initial_hs_state/0,
tls_app_data_in_initial_hs_state/1,
+ tls_13_reject_change_cipher_spec_as_first_msg/0,
+ tls_13_reject_change_cipher_spec_as_first_msg/1,
+ tls_13_middlebox_reject_change_cipher_spec_as_first_msg/0,
+ tls_13_middlebox_reject_change_cipher_spec_as_first_msg/1,
peername/0,
peername/1,
sockname/0,
@@ -133,7 +138,8 @@ all() ->
groups() ->
[
- {'tlsv1.3', [], api_tests() -- [sockname]},
+ {'tlsv1.3', [], (api_tests() ++ [tls_13_reject_change_cipher_spec_as_first_msg,
+ tls_13_middlebox_reject_change_cipher_spec_as_first_msg]) -- [sockname]},
{'tlsv1.2', [], api_tests()},
{'tlsv1.1', [], api_tests()},
{'tlsv1', [], api_tests()}
@@ -765,16 +771,59 @@ tls_app_data_in_initial_hs_state(Config) when is_list(Config) ->
{ok, Socket} = gen_tcp:connect("localhost", Port, [{active, false}, binary]),
AppData = case Version of
{3, 4} ->
- <<?BYTE(?APPLICATION_DATA), ?BYTE(3), ?BYTE(3), ?UINT16(4), ?BYTE($F), ?BYTE($O), ?BYTE($O), ?BYTE(?APPLICATION_DATA)>>;
+ <<?BYTE(?APPLICATION_DATA), ?BYTE(3), ?BYTE(3), ?UINT16(4), ?BYTE($F),
+ ?BYTE($O), ?BYTE($O), ?BYTE(?APPLICATION_DATA)>>;
_ ->
- <<?BYTE(?APPLICATION_DATA), ?BYTE(Major), ?BYTE(Minor), ?UINT16(3), ?BYTE($F), ?BYTE($O), ?BYTE($O)>>
+ <<?BYTE(?APPLICATION_DATA), ?BYTE(Major), ?BYTE(Minor),
+ ?UINT16(3), ?BYTE($F), ?BYTE($O), ?BYTE($O)>>
end,
gen_tcp:send(Socket, AppData),
- UnexpectedMsgAlert = <<?BYTE(?ALERT), ?BYTE(Major), ?BYTE(Minor), ?UINT16(2), ?BYTE(?FATAL), ?BYTE(?UNEXPECTED_MESSAGE)>>,
+ UnexpectedMsgAlert = <<?BYTE(?ALERT), ?BYTE(Major), ?BYTE(Minor), ?UINT16(2),
+ ?BYTE(?FATAL), ?BYTE(?UNEXPECTED_MESSAGE)>>,
+ {ok, UnexpectedMsgAlert} = gen_tcp:recv(Socket, 7),
+ {error, closed} = gen_tcp:recv(Socket, 0).
+%%--------------------------------------------------------------------
+tls_13_reject_change_cipher_spec_as_first_msg() ->
+ [{doc,"change_cipher_spec messages can be sent in TLS-1.3 middlebox_comp_mode, but can not be sent as first msg"}].
+tls_13_reject_change_cipher_spec_as_first_msg(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{versions, [ssl_test_lib:protocol_version(Config)]} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, Socket} = gen_tcp:connect("localhost", Port, [{active, false}, binary]),
+ ChangeCipherSpec = <<?BYTE(?CHANGE_CIPHER_SPEC), ?BYTE(3), ?BYTE(3),
+ ?UINT16(1), ?BYTE(?CHANGE_CIPHER_SPEC_PROTO)>>,
+ gen_tcp:send(Socket, ChangeCipherSpec),
+ UnexpectedMsgAlert = <<?BYTE(?ALERT), ?BYTE(3), ?BYTE(3), ?UINT16(2),
+ ?BYTE(?FATAL), ?BYTE(?UNEXPECTED_MESSAGE)>>,
{ok, UnexpectedMsgAlert} = gen_tcp:recv(Socket, 7),
{error, closed} = gen_tcp:recv(Socket, 0).
%%--------------------------------------------------------------------
+tls_13_middlebox_reject_change_cipher_spec_as_first_msg() ->
+ [{doc,"change_cipher_spec messages can be sent in TLS-1.3 middlebox_comp_mode, but can not be sent as first msg"}].
+tls_13_middlebox_reject_change_cipher_spec_as_first_msg(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{middlebox_comp_mode, false},
+ {versions, [ssl_test_lib:protocol_version(Config)]}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, Socket} = gen_tcp:connect("localhost", Port, [{active, false}, binary]),
+ ChangeCipherSpec = <<?BYTE(?CHANGE_CIPHER_SPEC), ?BYTE(3), ?BYTE(3),
+ ?UINT16(1), ?BYTE(?CHANGE_CIPHER_SPEC_PROTO)>>,
+ gen_tcp:send(Socket, ChangeCipherSpec),
+ UnexpectedMsgAlert = <<?BYTE(?ALERT), ?BYTE(3), ?BYTE(3), ?UINT16(2),
+ ?BYTE(?FATAL), ?BYTE(?UNEXPECTED_MESSAGE)>>,
+ {ok, UnexpectedMsgAlert} = gen_tcp:recv(Socket, 7),
+ {error, closed} = gen_tcp:recv(Socket, 0).
+%%--------------------------------------------------------------------
peername() ->
[{doc,"Test API function peername/1"}].